Compare commits

...

2 Commits

Author SHA1 Message Date
Ryan Laurie
3ca810a923 use RTK for current user 2024-09-23 17:21:36 -06:00
Ryan Laurie
3c40be9a25 use current user api instead of search to check for models 2024-09-19 15:43:21 -05:00
10 changed files with 62 additions and 40 deletions

View File

@@ -36,6 +36,10 @@ export interface User extends BaseUser {
} | null;
}
export interface CurrentUser extends User {
has_model: boolean;
}
export interface UserListResult {
id: UserId;
first_name: string | null;

View File

@@ -1,5 +1,7 @@
import { updateCurrentUser } from "metabase/redux/user";
import type {
CreateUserRequest,
CurrentUser,
ListUsersRequest,
ListUsersResponse,
UpdatePasswordRequest,
@@ -43,6 +45,20 @@ export const userApi = Api.injectEndpoints({
}),
providesTags: user => (user ? provideUserTags(user) : []),
}),
getCurrentUser: builder.query<CurrentUser, void>({
query: () => ({
method: "GET",
url: "/api/user/current",
}),
providesTags: user => (user ? provideUserTags(user) : []),
onCacheEntryAdded: async (_, { dispatch, cacheDataLoaded }) => {
// lots of stuff relies on the currentUser global state, so let's also update it there
const response = await cacheDataLoaded;
if (response.data) {
dispatch(updateCurrentUser(response.data));
}
},
}),
createUser: builder.mutation<User, CreateUserRequest>({
query: body => ({
method: "POST",
@@ -92,6 +108,7 @@ export const {
useListUsersQuery,
useListUserRecipientsQuery,
useGetUserQuery,
useGetCurrentUserQuery,
useCreateUserMutation,
useUpdatePasswordMutation,
useDeactivateUserMutation,

View File

@@ -4,3 +4,4 @@ export * from "./use-docs-url";
export * from "./use-locale";
export * from "./use-notification-channels";
export * from "./use-has-token-feature";
export * from "./use-has-model";

View File

@@ -0,0 +1,11 @@
import { skipToken, useGetCurrentUserQuery } from "metabase/api";
// check if the user has access to any model
export const useHasModel = (
{ enabled }: { enabled?: boolean } = { enabled: true },
) => {
const { data: currentUser } = useGetCurrentUserQuery(
enabled ? undefined : skipToken,
);
return !!currentUser?.has_model;
};

View File

@@ -3,6 +3,7 @@ import type { ReactNode } from "react";
import { useMemo } from "react";
import { t } from "ttag";
import { useHasModel } from "metabase/common/hooks";
import EntityMenu from "metabase/components/EntityMenu";
import { useDispatch, useSelector } from "metabase/lib/redux";
import * as Urls from "metabase/lib/urls";
@@ -16,7 +17,6 @@ export interface NewItemMenuProps {
trigger?: ReactNode;
triggerIcon?: string;
triggerTooltip?: string;
hasModels: boolean;
hasDataAccess: boolean;
hasNativeWrite: boolean;
hasDatabaseWithJsonEngine: boolean;
@@ -40,7 +40,6 @@ const NewItemMenu = ({
trigger,
triggerIcon,
triggerTooltip,
hasModels,
hasDataAccess,
hasNativeWrite,
hasDatabaseWithJsonEngine,
@@ -53,6 +52,8 @@ const NewItemMenu = ({
getSetting(state, "last-used-native-database-id"),
);
const hasModels = useHasModel();
const menuItems = useMemo(() => {
const items: NewMenuItem[] = [];

View File

@@ -4,7 +4,6 @@ import _ from "underscore";
import NewItemMenu from "metabase/components/NewItemMenu";
import Databases from "metabase/entities/databases";
import Search from "metabase/entities/search";
import { closeNavbar } from "metabase/redux/app";
import {
getHasDataAccess,
@@ -42,12 +41,5 @@ export default _.compose(
Databases.loadList({
loadingAndErrorWrapper: false,
}),
Search.loadList({
// Checking if there is at least one model,
// so we can decide if "Action" option should be shown
query: { models: ["dataset"], limit: 1 },
loadingAndErrorWrapper: false,
listName: "models",
}),
connect(mapStateToProps, mapDispatchToProps),
)(NewItemMenu);

View File

@@ -2,10 +2,7 @@ import { useEffect } from "react";
import { replace } from "react-router-redux";
import { t } from "ttag";
import {
useDatabaseListQuery,
useSearchListQuery,
} from "metabase/common/hooks";
import { useDatabaseListQuery, useHasModel } from "metabase/common/hooks";
import { useHomepageDashboard } from "metabase/common/hooks/use-homepage-dashboard";
import LoadingAndErrorWrapper from "metabase/components/LoadingAndErrorWrapper";
import { useDispatch, useSelector } from "metabase/lib/redux";
@@ -14,18 +11,15 @@ import { updateUserSetting } from "metabase/redux/settings";
import { addUndo } from "metabase/redux/undo";
import { getHasDismissedCustomHomePageToast } from "metabase/selectors/app";
import type Database from "metabase-lib/v1/metadata/Database";
import type { CollectionItem } from "metabase-types/api";
import { getIsMetabotEnabled } from "../../selectors";
import { HomeContent } from "../HomeContent";
import { HomeLayout } from "../HomeLayout";
const SEARCH_QUERY = { models: ["dataset" as const], limit: 1 };
export const HomePage = (): JSX.Element => {
const {
databases,
models,
hasModels,
isMetabotEnabled,
isLoading: isLoadingMetabot,
error,
@@ -41,7 +35,9 @@ export const HomePage = (): JSX.Element => {
}
return (
<HomeLayout hasMetabot={getHasMetabot(databases, models, isMetabotEnabled)}>
<HomeLayout
hasMetabot={getHasMetabot(databases, hasModels, isMetabotEnabled)}
>
<HomeContent />
</HomeLayout>
);
@@ -52,26 +48,25 @@ const useMetabot = () => {
const databaseListQuery = useDatabaseListQuery({
enabled: isMetabotEnabled,
});
const searchListQuery = useSearchListQuery({
query: SEARCH_QUERY,
const hasModels = useHasModel({
enabled: isMetabotEnabled,
});
return {
databases: databaseListQuery.data ?? [],
models: searchListQuery.data ?? [],
hasModels,
isMetabotEnabled,
isLoading: databaseListQuery.isLoading || searchListQuery.isLoading,
error: databaseListQuery.error ?? searchListQuery.error,
isLoading: databaseListQuery.isLoading,
error: databaseListQuery.error,
};
};
const getHasMetabot = (
databases: Database[],
models: CollectionItem[],
hasModels: boolean,
isMetabotEnabled: boolean,
) => {
const hasModels = models.length > 0;
const hasSupportedDatabases = databases.some(canUseMetabotOnDatabase);
return hasModels && hasSupportedDatabases && isMetabotEnabled;
};

View File

@@ -4,10 +4,7 @@ import type { WithRouterProps } from "react-router";
import { push } from "react-router-redux";
import { t } from "ttag";
import {
useDatabaseListQuery,
useSearchListQuery,
} from "metabase/common/hooks";
import { useDatabaseListQuery, useHasModel } from "metabase/common/hooks";
import Collections from "metabase/entities/collections/collections";
import { useDispatch, useSelector } from "metabase/lib/redux";
import * as Urls from "metabase/lib/urls";
@@ -30,16 +27,13 @@ export const useCommandPaletteBasicActions = ({
const { data: databases = [] } = useDatabaseListQuery({
enabled: isLoggedIn,
});
const { data: models = [] } = useSearchListQuery({
query: { models: ["dataset"], limit: 1 },
enabled: isLoggedIn,
});
const hasModels = useHasModel({ enabled: isLoggedIn });
const hasDataAccess = getHasDataAccess(databases);
const hasNativeWrite = getHasNativeWrite(databases);
const hasDatabaseWithActionsEnabled =
getHasDatabaseWithActionsEnabled(databases);
const hasModels = models.length > 0;
const openNewModal = useCallback(
(modalId: string) => {

View File

@@ -1,17 +1,17 @@
import { createAction, createReducer } from "@reduxjs/toolkit";
import { userApi } from "metabase/api/user";
import Dashboards from "metabase/entities/dashboards";
import Users from "metabase/entities/users";
import { createAsyncThunk } from "metabase/lib/redux";
import { CLOSE_QB_NEWB_MODAL } from "metabase/query_builder/actions";
import { UserApi } from "metabase/services";
import type { User } from "metabase-types/api";
import type { CurrentUser, User } from "metabase-types/api";
export const refreshCurrentUser = createAsyncThunk(
"metabase/user/REFRESH_CURRENT_USER",
async (_, { fulfillWithValue }) => {
async (_, { dispatch, fulfillWithValue }) => {
try {
return UserApi.current();
await dispatch(userApi.endpoints.getCurrentUser.initiate());
} catch (e) {
return fulfillWithValue(null);
}
@@ -27,6 +27,11 @@ export const loadCurrentUser = createAsyncThunk(
},
);
// update current user with provided value
export const updateCurrentUser = createAction<CurrentUser>(
"metabase/user/UPDATE_CURRENT_USER",
);
export const clearCurrentUser = createAction(
"metabase/user/CLEAR_CURRENT_USER",
);
@@ -61,5 +66,8 @@ export const currentUser = createReducer<User | null>(null, builder => {
) {
state.custom_homepage = null;
}
})
.addCase(updateCurrentUser, (_state, { payload: currentUser }) => {
return currentUser;
});
});

View File

@@ -429,7 +429,6 @@ export const SetupApi = {
export const UserApi = {
list: GET("/api/user/recipients"),
current: GET("/api/user/current"),
update_qbnewb: PUT("/api/user/:id/modal/qbnewb"),
};