mirror of https://github.com/buster-so/buster.git
277 lines
8.8 KiB
TypeScript
277 lines
8.8 KiB
TypeScript
import {
|
|
useAddDashboardToCollection,
|
|
useDeleteDashboards,
|
|
useGetDashboard,
|
|
useRemoveDashboardFromCollection
|
|
} from '@/api/buster_rest/dashboards';
|
|
import { DropdownContent, DropdownItem, DropdownItems } from '@/components/ui/dropdown';
|
|
import {
|
|
Trash,
|
|
Dots,
|
|
Pencil,
|
|
History,
|
|
Star,
|
|
ShareRight,
|
|
Plus,
|
|
Filter
|
|
} from '@/components/ui/icons';
|
|
import { Star as StarFilled } from '@/components/ui/icons/NucleoIconFilled';
|
|
import { useBusterNotifications } from '@/context/BusterNotifications';
|
|
import { useChatLayoutContextSelector } from '@/layouts/ChatLayout/ChatLayoutContext';
|
|
import { useMemo } from 'react';
|
|
import { Dropdown } from '@/components/ui/dropdown';
|
|
import { Button } from '@/components/ui/buttons';
|
|
import React from 'react';
|
|
import { timeFromNow } from '@/lib/date';
|
|
import { ASSET_ICONS } from '@/components/features/config/assetIcons';
|
|
import { useMemoizedFn } from '@/hooks';
|
|
import { useSaveToCollectionsDropdownContent } from '@/components/features/dropdowns/SaveToCollectionsDropdown';
|
|
import { ShareAssetType } from '@/api/asset_interfaces/share';
|
|
import { useFavoriteStar } from '@/components/features/list/FavoriteStar';
|
|
import { timeout } from '@/lib';
|
|
import { ShareMenuContent } from '@/components/features/ShareMenu/ShareMenuContent';
|
|
import { DASHBOARD_TITLE_INPUT_ID } from '@/controllers/DashboardController/DashboardViewDashboardController/DashboardEditTitle';
|
|
import { canEdit, canFilter, getIsEffectiveOwner } from '@/lib/share';
|
|
import { getShareAssetConfig } from '@/components/features/ShareMenu/helpers';
|
|
import { useDashboardContentStore } from '@/context/Dashboards';
|
|
|
|
export const DashboardThreeDotMenu = React.memo(({ dashboardId }: { dashboardId: string }) => {
|
|
const versionHistoryItems = useVersionHistorySelectMenu({ dashboardId });
|
|
const collectionSelectMenu = useCollectionSelectMenu({ dashboardId });
|
|
const favoriteDashboard = useFavoriteDashboardSelectMenu({ dashboardId });
|
|
const deleteDashboardMenu = useDeleteDashboardSelectMenu({ dashboardId });
|
|
const renameDashboardMenu = useRenameDashboardSelectMenu({ dashboardId });
|
|
const shareMenu = useShareMenuSelectMenu({ dashboardId });
|
|
const addContentToDashboardMenu = useAddContentToDashboardSelectMenu();
|
|
const filterDashboardMenu = useFilterDashboardSelectMenu();
|
|
const { data: permission } = useGetDashboard({ id: dashboardId }, (x) => x.permission);
|
|
const isOwner = getIsEffectiveOwner(permission);
|
|
const isFilter = canFilter(permission);
|
|
const isEditor = canEdit(permission);
|
|
|
|
const items: DropdownItems = useMemo(
|
|
() => [
|
|
isFilter && filterDashboardMenu,
|
|
isEditor && addContentToDashboardMenu,
|
|
{ type: 'divider' },
|
|
isOwner && shareMenu,
|
|
collectionSelectMenu,
|
|
favoriteDashboard,
|
|
versionHistoryItems,
|
|
{ type: 'divider' },
|
|
isEditor && renameDashboardMenu,
|
|
isOwner && deleteDashboardMenu
|
|
],
|
|
[
|
|
filterDashboardMenu,
|
|
addContentToDashboardMenu,
|
|
shareMenu,
|
|
collectionSelectMenu,
|
|
favoriteDashboard,
|
|
versionHistoryItems,
|
|
renameDashboardMenu,
|
|
deleteDashboardMenu
|
|
]
|
|
);
|
|
|
|
return (
|
|
<Dropdown items={items} side="bottom" align="end" contentClassName="max-h-fit" modal>
|
|
<Button prefix={<Dots />} variant="ghost" />
|
|
</Dropdown>
|
|
);
|
|
});
|
|
DashboardThreeDotMenu.displayName = 'ThreeDotMenuButton';
|
|
|
|
const useVersionHistorySelectMenu = ({ dashboardId }: { dashboardId: string }) => {
|
|
const DEFAULT_VERSION_HISTORY_ITEMS: DropdownItems = [];
|
|
const { data } = useGetDashboard({ id: dashboardId }, (x) => ({
|
|
versions: x?.dashboard?.versions,
|
|
version_number: x?.dashboard?.version_number
|
|
}));
|
|
const { versions, version_number } = data || {};
|
|
|
|
const versionHistoryItems: DropdownItems = useMemo(() => {
|
|
return (
|
|
versions?.map((x) => ({
|
|
label: `Version ${x.version_number}`,
|
|
secondaryLabel: timeFromNow(x.updated_at, false),
|
|
value: x.version_number.toString(),
|
|
selected: x.version_number === version_number
|
|
})) || DEFAULT_VERSION_HISTORY_ITEMS
|
|
);
|
|
}, [versions, version_number]);
|
|
|
|
return useMemo(
|
|
() => ({
|
|
label: 'Version history',
|
|
value: 'version-history',
|
|
icon: <History />,
|
|
items: versionHistoryItems
|
|
}),
|
|
[versionHistoryItems]
|
|
);
|
|
};
|
|
|
|
const useCollectionSelectMenu = ({ dashboardId }: { dashboardId: string }) => {
|
|
const { mutateAsync: saveDashboardToCollection } = useAddDashboardToCollection();
|
|
const { mutateAsync: removeDashboardFromCollection } = useRemoveDashboardFromCollection();
|
|
const { data: collections } = useGetDashboard({ id: dashboardId }, (x) => x.collections);
|
|
const { openInfoMessage } = useBusterNotifications();
|
|
|
|
const selectedCollections = useMemo(() => {
|
|
return collections?.map((x) => x.id) || [];
|
|
}, [collections]);
|
|
|
|
const onSaveToCollection = useMemoizedFn(async (collectionIds: string[]) => {
|
|
await saveDashboardToCollection({ dashboardIds: [dashboardId], collectionIds });
|
|
openInfoMessage('Dashboard saved to collections');
|
|
});
|
|
|
|
const onRemoveFromCollection = useMemoizedFn(async (collectionId: string) => {
|
|
await removeDashboardFromCollection({
|
|
dashboardIds: [dashboardId],
|
|
collectionIds: [collectionId]
|
|
});
|
|
openInfoMessage('Dashboard removed from collections');
|
|
});
|
|
|
|
const { modal, ...dropdownProps } = useSaveToCollectionsDropdownContent({
|
|
onSaveToCollection,
|
|
onRemoveFromCollection,
|
|
selectedCollections
|
|
});
|
|
|
|
const collectionSubMenu = useMemo(() => {
|
|
return <DropdownContent {...dropdownProps} />;
|
|
}, [dropdownProps]);
|
|
|
|
const collectionDropdownItem: DropdownItem = useMemo(
|
|
() => ({
|
|
label: 'Add to collection',
|
|
value: 'add-to-collection',
|
|
icon: <ASSET_ICONS.collectionAdd />,
|
|
items: [
|
|
<React.Fragment key="collection-sub-menu">
|
|
{collectionSubMenu} {modal}
|
|
</React.Fragment>
|
|
]
|
|
}),
|
|
[collectionSubMenu]
|
|
);
|
|
|
|
return collectionDropdownItem;
|
|
};
|
|
|
|
const useFavoriteDashboardSelectMenu = ({ dashboardId }: { dashboardId: string }) => {
|
|
const { data: title } = useGetDashboard({ id: dashboardId }, (x) => x?.dashboard?.name);
|
|
const { isFavorited, onFavoriteClick } = useFavoriteStar({
|
|
id: dashboardId,
|
|
type: ShareAssetType.DASHBOARD,
|
|
name: title || ''
|
|
});
|
|
|
|
const item: DropdownItem = useMemo(
|
|
() => ({
|
|
label: isFavorited ? 'Remove from favorites' : 'Add to favorites',
|
|
value: 'add-to-favorites',
|
|
icon: isFavorited ? <StarFilled /> : <Star />,
|
|
onClick: onFavoriteClick
|
|
}),
|
|
[isFavorited, onFavoriteClick]
|
|
);
|
|
|
|
return item;
|
|
};
|
|
|
|
const useDeleteDashboardSelectMenu = ({ dashboardId }: { dashboardId: string }) => {
|
|
const { mutateAsync: deleteDashboard } = useDeleteDashboards();
|
|
|
|
return useMemo(
|
|
() => ({
|
|
label: 'Delete dashboard',
|
|
value: 'delete-dashboard',
|
|
icon: <Trash />,
|
|
onClick: async () => {
|
|
await deleteDashboard({ dashboardId });
|
|
}
|
|
}),
|
|
[dashboardId]
|
|
);
|
|
};
|
|
|
|
const useRenameDashboardSelectMenu = ({ dashboardId }: { dashboardId: string }) => {
|
|
const onSetFileView = useChatLayoutContextSelector((x) => x.onSetFileView);
|
|
return useMemo(
|
|
() => ({
|
|
label: 'Rename dashboard',
|
|
value: 'rename-dashboard',
|
|
icon: <Pencil />,
|
|
onClick: async () => {
|
|
onSetFileView({ fileView: 'dashboard', fileId: dashboardId });
|
|
await timeout(125);
|
|
const input = document.getElementById(DASHBOARD_TITLE_INPUT_ID) as HTMLInputElement;
|
|
if (input) {
|
|
input.focus();
|
|
input.select();
|
|
}
|
|
}
|
|
}),
|
|
[dashboardId]
|
|
);
|
|
};
|
|
|
|
export const useShareMenuSelectMenu = ({ dashboardId }: { dashboardId: string }) => {
|
|
const { data: dashboard } = useGetDashboard({ id: dashboardId }, getShareAssetConfig);
|
|
const isOwner = getIsEffectiveOwner(dashboard?.permission);
|
|
|
|
return useMemo(
|
|
() => ({
|
|
label: 'Share',
|
|
value: 'share-dashboard',
|
|
icon: <ShareRight />,
|
|
disabled: !isOwner,
|
|
items: isOwner
|
|
? [
|
|
<ShareMenuContent
|
|
key={dashboardId}
|
|
shareAssetConfig={dashboard!}
|
|
assetId={dashboardId}
|
|
assetType={ShareAssetType.DASHBOARD}
|
|
/>
|
|
]
|
|
: undefined
|
|
}),
|
|
[dashboardId]
|
|
);
|
|
};
|
|
|
|
const useAddContentToDashboardSelectMenu = () => {
|
|
const onOpenAddContentModal = useDashboardContentStore((x) => x.onOpenAddContentModal);
|
|
|
|
return useMemo(
|
|
() => ({
|
|
label: 'Add content',
|
|
value: 'add-content',
|
|
icon: <Plus />,
|
|
onClick: onOpenAddContentModal
|
|
}),
|
|
[onOpenAddContentModal]
|
|
);
|
|
};
|
|
|
|
const useFilterDashboardSelectMenu = () => {
|
|
return useMemo(
|
|
() => ({
|
|
label: 'Filter dashboard',
|
|
value: 'filter-dashboard',
|
|
icon: <Filter />,
|
|
items: [
|
|
<div className="p-2" key="coming-soon">
|
|
Coming soon...
|
|
</div>
|
|
]
|
|
}),
|
|
[]
|
|
);
|
|
};
|