remove additional context layers for dashboard

This commit is contained in:
Nate Kelley 2025-03-12 17:12:27 -06:00
parent 76254339e9
commit ee6686448d
No known key found for this signature in database
GPG Key ID: FD90372AB8D98B4F
17 changed files with 96 additions and 175 deletions

View File

@ -6,19 +6,27 @@ import {
dashboardsUpdateDashboard,
dashboardsDeleteDashboard
} from './requests';
import type {
DashboardsListRequest,
DashboardCreateRequest,
DashboardUpdateRequest,
DashboardDeleteRequest
} from '@/api/request_interfaces/dashboards/interfaces';
import type { DashboardsListRequest } from '@/api/request_interfaces/dashboards/interfaces';
import { dashboardQueryKeys } from '@/api/query_keys/dashboard';
import { BusterDashboard } from '@/api/asset_interfaces/dashboard';
import { useMemo } from 'react';
import { useMemoizedFn } from '@/hooks';
import { useBusterNotifications } from '@/context/BusterNotifications';
export const useGetDashboardsList = (
params: Omit<DashboardsListRequest, 'page_token' | 'page_size'>
) => {
const filters = useMemo(() => {
return {
...params,
page_token: 0,
page_size: 3000
};
}, [params]);
export const useGetDashboardsList = (params: DashboardsListRequest) => {
return useQuery({
...dashboardQueryKeys.dashboardGetList(params),
queryFn: () => dashboardsGetList(params)
...dashboardQueryKeys.dashboardGetList(filters),
queryFn: () => dashboardsGetList(filters)
});
};
@ -68,12 +76,44 @@ export const useUpdateDashboard = () => {
export const useDeleteDashboards = () => {
const queryClient = useQueryClient();
const { openConfirmModal } = useBusterNotifications();
const onDeleteDashboard = useMemoizedFn(
async ({
dashboardId,
ignoreConfirm
}: {
dashboardId: string | string[];
ignoreConfirm?: boolean;
}) => {
const method = () => {
const ids = typeof dashboardId === 'string' ? [dashboardId] : dashboardId;
dashboardsDeleteDashboard({ ids });
};
if (ignoreConfirm) {
return method();
}
return await openConfirmModal({
title: 'Delete Dashboard',
content: 'Are you sure you want to delete this dashboard?',
onOk: () => {
method();
},
useReject: true
});
}
);
return useMutation({
mutationFn: dashboardsDeleteDashboard,
mutationFn: onDeleteDashboard,
onMutate: (variables) => {
const queryKey = dashboardQueryKeys.dashboardGetList({}).queryKey;
queryClient.setQueryData(queryKey, (v) => {
return v?.filter((t) => !variables.ids.includes(t.id)) || [];
const ids =
typeof variables.dashboardId === 'string'
? [variables.dashboardId]
: variables.dashboardId;
return v?.filter((t) => !ids.includes(t.id)) || [];
});
}
});

View File

@ -8,7 +8,9 @@ import { DashboardsListRequest } from '../request_interfaces/dashboards/interfac
const dashboardGetList = (filters: Omit<DashboardsListRequest, 'page_token' | 'page_size'>) =>
queryOptions<BusterDashboardListItem[]>({
queryKey: ['dashboard', 'list', filters] as const,
staleTime: 10 * 1000
staleTime: 10 * 1000,
initialData: [],
initialDataUpdatedAt: 0
});
const dashboardGetDashboard = (dashboardId: string) =>

View File

@ -39,7 +39,7 @@ export interface DashboardUnsubscribeRequest {
*/
export interface DashboardCreateRequest {
/** The name of the dashboard */
name: string;
name?: string;
/** Optional description of the dashboard */
description?: string | null;
}

View File

@ -1,8 +1,4 @@
import { useAppLayoutContextSelector } from '@/context/BusterAppLayout';
import {
useBusterDashboardContextSelector,
useBusterDashboardListByFilter
} from '@/context/Dashboards';
import { useMemoizedFn } from '@/hooks';
import React, { useMemo, useState } from 'react';
import { BusterRoutes, createBusterRoute } from '@/routes/busterRoutes';
@ -11,6 +7,7 @@ import { Dropdown, type DropdownProps } from '@/components/ui/dropdown/Dropdown'
import { AppTooltip } from '@/components/ui/tooltip';
import { Plus } from '@/components/ui/icons';
import type { BusterMetric, BusterDashboardListItem } from '@/api/asset_interfaces';
import { useCreateDashboard, useGetDashboardsList } from '@/api/buster_rest/dashboards';
export const SaveToDashboardDropdown: React.FC<{
children: React.ReactNode;
@ -18,10 +15,9 @@ export const SaveToDashboardDropdown: React.FC<{
onSaveToDashboard: (dashboardId: string[]) => Promise<void>;
onRemoveFromDashboard: (dashboardId: string) => void;
}> = ({ children, onRemoveFromDashboard, onSaveToDashboard, selectedDashboards }) => {
const onCreateNewDashboard = useBusterDashboardContextSelector((x) => x.onCreateNewDashboard);
const isCreatingDashboard = useBusterDashboardContextSelector((x) => x.isCreatingDashboard);
const { mutateAsync: createDashboard, isPending: isCreatingDashboard } = useCreateDashboard();
const onChangePage = useAppLayoutContextSelector((x) => x.onChangePage);
const { list: dashboardsList } = useBusterDashboardListByFilter({});
const { data: dashboardsList } = useGetDashboardsList({});
const [showDropdown, setShowDropdown] = useState(false);
@ -53,22 +49,13 @@ export const SaveToDashboardDropdown: React.FC<{
);
const onClickNewDashboardButton = useMemoizedFn(async () => {
const res = await onCreateNewDashboard({
rerouteToDashboard: false
});
const res = await createDashboard({});
if (res?.id) {
await onSaveToDashboard([res.id]);
// await saveMetricToDashboard({
// metricId,
// dashboardIds: [res.id]
// });
}
if (res?.id) {
if (res?.dashboard?.id) {
await onSaveToDashboard([res.dashboard.id]);
onChangePage({
route: BusterRoutes.APP_DASHBOARD_ID,
dashboardId: res.id
dashboardId: res.dashboard.id
});
}

View File

@ -5,7 +5,6 @@ import { useMemoizedFn } from '@/hooks';
import { createContext, useContextSelector } from 'use-context-selector';
import { queryKeys } from '@/api/query_keys';
import { useDashboardAssosciations } from './useDashboardAssosciations';
import { useDashboardCreate } from './useDashboardCreate';
import { useDashboardUpdateConfig } from './useDashboardUpdateConfig';
import { useQueryClient } from '@tanstack/react-query';
@ -27,13 +26,8 @@ export const useBusterDashboards = () => {
updateDashboardMutation
});
const dashboardCreate = useDashboardCreate({
onUpdateDashboard
});
return {
...dashboardAssosciations,
...dashboardCreate,
...dashboardUpdateConfig,
getDashboardMemoized
};

View File

@ -1,25 +0,0 @@
import { BusterDashboard, VerificationStatus } from '@/api/asset_interfaces';
export const defaultBusterDashboard: BusterDashboard = {
id: '',
config: {
rows: []
},
created_at: '',
deleted_at: '',
description: '',
name: '',
updated_at: '',
created_by: '',
updated_by: '',
public_expiry_date: null,
publicly_accessible: false,
password_secret_id: null,
sharingKey: '',
public_enabled_by: '',
status: VerificationStatus.NOT_REQUESTED,
public_password: null,
version_number: 1,
file: '',
file_name: ''
};

View File

@ -1,66 +0,0 @@
import { useBusterNotifications } from '@/context/BusterNotifications';
import { BusterRoutes } from '@/routes/busterRoutes';
import { useMemoizedFn } from '@/hooks';
import { useQueryClient } from '@tanstack/react-query';
import { useAppLayoutContextSelector } from '@/context/BusterAppLayout';
import { useCreateDashboard, useDeleteDashboards } from '@/api/buster_rest/dashboards';
export const useDashboardCreate = ({}: {}) => {
const onChangePage = useAppLayoutContextSelector((x) => x.onChangePage);
const queryClient = useQueryClient();
const { mutateAsync: deleteDashboard, isPending: isDeletingDashboard } = useDeleteDashboards();
const { openConfirmModal } = useBusterNotifications();
const { mutateAsync: createDashboard, isPending: isCreatingDashboard } = useCreateDashboard();
const onCreateNewDashboard = useMemoizedFn(
async (newDashboard: {
name?: string;
description?: string | null;
rerouteToDashboard?: boolean;
}) => {
if (isCreatingDashboard) {
return;
}
const { rerouteToDashboard, ...rest } = newDashboard;
const res = await createDashboard({ ...rest, name: rest.name || '' });
if (rerouteToDashboard) {
onChangePage({
route: BusterRoutes.APP_DASHBOARD_ID,
dashboardId: res.dashboard.id
});
}
return res.dashboard;
}
);
const onDeleteDashboard = useMemoizedFn(
async (dashboardId: string | string[], ignoreConfirm?: boolean) => {
const method = () => {
const ids = typeof dashboardId === 'string' ? [dashboardId] : dashboardId;
deleteDashboard({ ids });
};
if (ignoreConfirm) {
return method();
}
return await openConfirmModal({
title: 'Delete Dashboard',
content: 'Are you sure you want to delete this dashboard?',
onOk: () => {
method();
},
useReject: true
});
}
);
return {
onCreateNewDashboard,
isCreatingDashboard,
onDeleteDashboard,
isDeletingDashboard
};
};

View File

@ -5,7 +5,6 @@ import {
} from '@/api/asset_interfaces';
import { useMemoizedFn } from '@/hooks';
import { create } from 'mutative';
import { useQueryClient } from '@tanstack/react-query';
import { useUpdateDashboard } from '@/api/buster_rest/dashboards';
import type { DashboardUpdateRequest } from '@/api/request_interfaces/dashboards/interfaces';

View File

@ -1 +0,0 @@
export * from './useBusterDashboardListByFilter';

View File

@ -1,17 +0,0 @@
import { useGetDashboardsList } from '@/api/buster_rest/dashboards';
import { DashboardsListRequest } from '@/api/request_interfaces/dashboards/interfaces';
export const useBusterDashboardListByFilter = (
filters: Omit<DashboardsListRequest, 'page_token' | 'page_size'>
) => {
const { data: dashboardsList, isFetched: isFetchedDashboardsList } = useGetDashboardsList({
...filters,
page_token: 0,
page_size: 3000
});
return {
list: dashboardsList,
isFetchedDashboardsList
};
};

View File

@ -1,3 +1,2 @@
export * from './DashboardProvider';
export * from './DashboardListProvider';
export * from './DashboardIndividualProvider';

View File

@ -9,6 +9,8 @@ import { AppSegmented, SegmentedItem } from '@/components/ui/segmented';
import { useMemoizedFn } from '@/hooks';
import { Plus } from '@/components/ui/icons';
import type { DashboardsListRequest } from '@/api/request_interfaces/dashboards';
import { useCreateDashboard } from '@/api/buster_rest/dashboards';
import { useAppLayoutContextSelector } from '@/context/BusterAppLayout';
export const DashboardHeader: React.FC<{
dashboardFilters: {
@ -20,12 +22,8 @@ export const DashboardHeader: React.FC<{
only_my_dashboards?: boolean;
}) => void;
}> = React.memo(({ dashboardFilters, onSetDashboardListFilters }) => {
const onCreateNewDashboard = useBusterDashboardContextSelector(
(state) => state.onCreateNewDashboard
);
const isCreatingDashboard = useBusterDashboardContextSelector(
(state) => state.isCreatingDashboard
);
const { mutateAsync: createDashboard, isPending: isCreatingDashboard } = useCreateDashboard();
const onChangePage = useAppLayoutContextSelector((x) => x.onChangePage);
const dashboardTitle = 'Dashboards';
const showFilters = true;
@ -42,7 +40,13 @@ export const DashboardHeader: React.FC<{
);
const onClickNewDashboardButton = useMemoizedFn(async () => {
await onCreateNewDashboard({ rerouteToDashboard: true });
const res = await createDashboard({});
if (res?.dashboard?.id) {
onChangePage({
route: BusterRoutes.APP_DASHBOARD_ID,
dashboardId: res.dashboard.id
});
}
});
return (

View File

@ -1,7 +1,6 @@
'use client';
import React, { useMemo, useState } from 'react';
import { useBusterDashboardContextSelector } from '@/context/Dashboards';
import { Avatar } from '@/components/ui/avatar';
import { formatDate } from '@/lib';
import {
@ -15,6 +14,8 @@ import { useMemoizedFn } from '@/hooks';
import { DashboardSelectedOptionPopup } from './DashboardSelectedPopup';
import type { BusterDashboardListItem } from '@/api/asset_interfaces';
import { getShareStatus } from '@/components/features/metrics/StatusBadgeIndicator/helpers';
import { useCreateDashboard } from '@/api/buster_rest/dashboards';
import { useAppLayoutContextSelector } from '@/context/BusterAppLayout';
const columns: BusterListColumn[] = [
{
@ -58,12 +59,8 @@ export const DashboardListContent: React.FC<{
dashboardsList: BusterDashboardListItem[];
className?: string;
}> = React.memo(({ loading, dashboardsList, className = '' }) => {
const onCreateNewDashboard = useBusterDashboardContextSelector(
(state) => state.onCreateNewDashboard
);
const isCreatingDashboard = useBusterDashboardContextSelector(
(state) => state.isCreatingDashboard
);
const { mutateAsync: createDashboard, isPending: isCreatingDashboard } = useCreateDashboard();
const onChangePage = useAppLayoutContextSelector((x) => x.onChangePage);
const [selectedDashboardIds, setSelectedDashboardIds] = useState<string[]>([]);
const rows: BusterListRow[] = useMemo(() => {
@ -80,7 +77,13 @@ export const DashboardListContent: React.FC<{
}, [dashboardsList]);
const onClickEmptyState = useMemoizedFn(async () => {
await onCreateNewDashboard({ rerouteToDashboard: true });
const res = await createDashboard({});
if (res?.dashboard?.id) {
onChangePage({
route: BusterRoutes.APP_DASHBOARD_ID,
dashboardId: res.dashboard.id
});
}
});
return (

View File

@ -3,15 +3,16 @@
import React, { useState } from 'react';
import { DashboardHeader } from './DashboardHeader';
import { DashboardListContent } from './DashboardListContent';
import { useBusterDashboardListByFilter } from '@/context/Dashboards';
import { AppPageLayout } from '@/components/ui/layouts';
import { useGetDashboardsList } from '@/api/buster_rest/dashboards';
export const DashboardListController: React.FC = () => {
const [dashboardListFilters, setDashboardListFilters] = useState<{
shared_with_me?: boolean;
only_my_dashboards?: boolean;
}>({});
const { list, isFetchedDashboardsList } = useBusterDashboardListByFilter(dashboardListFilters);
const { data: dashboardsList, isFetched: isFetchedDashboardsList } =
useGetDashboardsList(dashboardListFilters);
return (
<AppPageLayout
@ -21,7 +22,7 @@ export const DashboardListController: React.FC = () => {
onSetDashboardListFilters={setDashboardListFilters}
/>
}>
<DashboardListContent loading={!isFetchedDashboardsList} dashboardsList={list || []} />
<DashboardListContent loading={!isFetchedDashboardsList} dashboardsList={dashboardsList} />
</AppPageLayout>
);
};

View File

@ -2,7 +2,6 @@ import React, { useState } from 'react';
import { BusterListSelectedOptionPopupContainer } from '@/components/ui/list';
import { Dropdown, DropdownItems } from '@/components/ui/dropdown';
import { Button } from '@/components/ui/buttons';
import { useUserConfigContextSelector } from '@/context/Users';
import { useMemoizedFn } from '@/hooks';
import { useBusterNotifications } from '@/context/BusterNotifications';
import { SaveToCollectionsDropdown } from '@/components/features/dropdowns/SaveToCollectionsDropdown';
@ -15,6 +14,7 @@ import {
useGetUserFavorites
} from '@/api/buster_rest/users';
import { ShareAssetType } from '@/api/asset_interfaces/share';
import { useDeleteDashboards } from '@/api/buster_rest/dashboards';
export const DashboardSelectedOptionPopup: React.FC<{
selectedRowKeys: string[];
@ -100,7 +100,7 @@ const DeleteButton: React.FC<{
selectedRowKeys: string[];
onSelectChange: (selectedRowKeys: string[]) => void;
}> = ({ selectedRowKeys, onSelectChange }) => {
const onDeleteDashboard = useBusterDashboardContextSelector((state) => state.onDeleteDashboard);
const { mutateAsync: deleteDashboard, isPending: isDeletingDashboard } = useDeleteDashboards();
const { openConfirmModal } = useBusterNotifications();
const onDeleteClick = useMemoizedFn(async () => {
@ -108,7 +108,7 @@ const DeleteButton: React.FC<{
title: 'Delete dashboard',
content: 'Are you sure you want to delete these dashboards?',
onOk: async () => {
await onDeleteDashboard(selectedRowKeys, true);
await deleteDashboard({ dashboardId: selectedRowKeys });
onSelectChange([]);
}
});

View File

@ -13,6 +13,7 @@ import { Dots, Plus, Trash } from '@/components/ui/icons';
import { useBusterDashboardContextSelector } from '@/context/Dashboards';
import { useAppLayoutContextSelector } from '@/context/BusterAppLayout';
import { BusterRoutes } from '@/routes';
import { useDeleteDashboards } from '@/api/buster_rest/dashboards';
export const DashboardContainerHeaderButtons: React.FC<FileContainerButtonsProps> = React.memo(
() => {
@ -50,7 +51,7 @@ const AddContentToDashboardButton = React.memo(() => {
AddContentToDashboardButton.displayName = 'AddContentToDashboardButton';
const ThreeDotMenu = React.memo(({ dashboardId }: { dashboardId: string }) => {
const onDeleteDashboard = useBusterDashboardContextSelector((x) => x.onDeleteDashboard);
const { mutateAsync: deleteDashboard, isPending: isDeletingDashboard } = useDeleteDashboards();
const onChangePage = useAppLayoutContextSelector((x) => x.onChangePage);
const items: DropdownItems = useMemo(() => {
@ -60,12 +61,12 @@ const ThreeDotMenu = React.memo(({ dashboardId }: { dashboardId: string }) => {
value: 'delete',
icon: <Trash />,
onClick: async () => {
await onDeleteDashboard(dashboardId);
await deleteDashboard({ dashboardId });
onChangePage({ route: BusterRoutes.APP_DASHBOARDS });
}
}
];
}, [dashboardId, onDeleteDashboard, onChangePage]);
}, [dashboardId, deleteDashboard, onChangePage]);
return (
<Dropdown items={items}>

View File

@ -4,7 +4,7 @@ import {
VerificationStatus
} from '@/api/asset_interfaces';
import { ShareRole } from '@/api/asset_interfaces';
import { createMockMetric } from '../../../mocks/metric';
import { createMockMetric } from './metric';
interface DashboardMockResponse {
dashboard: BusterDashboard;