open in metric page should collapse the menu

This commit is contained in:
Nate Kelley 2025-04-16 11:12:40 -06:00
parent 24c561a07a
commit 7f970b4e9a
No known key found for this signature in database
GPG Key ID: FD90372AB8D98B4F
7 changed files with 130 additions and 101 deletions

View File

@ -13,7 +13,6 @@ import { AppTooltip } from '@/components/ui/tooltip';
import Link from 'next/link';
import { useGetFileLink } from '@/context/Assets/useGetFileLink';
import { useChatLayoutContextSelector } from '@/layouts/ChatLayout';
import { useRouter } from 'next/navigation';
import { useCallback } from 'react';
export const VersionHistoryPanel = React.memo(

View File

@ -242,7 +242,7 @@ export const DropdownContent = <T,>({
}}>
{hasShownItem ? (
<>
{selectedItems.map((item) => {
{selectedItems.map((item, index) => {
// Only increment index for selectable items
if ((item as DropdownItem).value && !(item as DropdownItem).items) {
hotkeyIndex++;
@ -250,7 +250,7 @@ export const DropdownContent = <T,>({
return (
<DropdownItemSelector
key={dropdownItemKey(item, hotkeyIndex)}
key={dropdownItemKey(item, index)}
item={item}
index={hotkeyIndex}
selectType={selectType}
@ -264,7 +264,7 @@ export const DropdownContent = <T,>({
{selectedItems.length > 0 && <DropdownMenuSeparator />}
{dropdownItems.map((item) => {
{dropdownItems.map((item, index) => {
// Only increment index for selectable items
if ((item as DropdownItem).value && !(item as DropdownItem).items) {
hotkeyIndex++;
@ -272,7 +272,7 @@ export const DropdownContent = <T,>({
return (
<DropdownItemSelector
key={dropdownItemKey(item, hotkeyIndex)}
key={dropdownItemKey(item, index)}
item={item}
index={hotkeyIndex}
selectType={selectType}

View File

@ -27,7 +27,6 @@ export const useAutoChangeLayout = ({
const secondaryView = useChatLayoutContextSelector((x) => x.secondaryView);
const dashboardVersionNumber = useChatLayoutContextSelector((x) => x.dashboardVersionNumber);
const metricVersionNumber = useChatLayoutContextSelector((x) => x.metricVersionNumber);
const isVersionHistoryMode = useChatLayoutContextSelector((x) => x.isVersionHistoryMode);
const isCompletedStream = useGetChatMessage(lastMessageId, (x) => x?.isCompletedStream);
const getInitialChatFileHref = useGetInitialChatFile();

View File

@ -92,7 +92,9 @@ export const useLayoutConfig = ({
return;
}
if (secondaryView) {
if (!chatId) {
animateOpenSplitter('right');
} else if (secondaryView) {
animateOpenSplitter('right');
//if the chat is open, we need to wait for the splitter to close before opening the secondary view
@ -192,7 +194,7 @@ export const useLayoutConfig = ({
fileView,
secondaryView: secondaryViewFromSelected
});
}, [metricId, secondaryView, dashboardId, currentRoute]);
}, [metricId, secondaryView, chatId, dashboardId, currentRoute]);
return {
selectedLayout,

View File

@ -17,11 +17,15 @@ import { canEdit, getIsEffectiveOwner } from '@/lib/share';
import Link from 'next/link';
import { assetParamsToRoute } from '@/lib/assets';
import { useAppLayoutContextSelector } from '@/context/BusterAppLayout';
import { useIsMetricReadOnly } from '@/context/Metrics/useIsMetricReadOnly';
export const MetricContainerHeaderButtons: React.FC<FileContainerButtonsProps> = React.memo(() => {
const selectedLayout = useChatLayoutContextSelector((x) => x.selectedLayout);
const selectedFileId = useChatIndividualContextSelector((x) => x.selectedFileId)!;
const metricId = selectedFileId;
const metricId = useChatIndividualContextSelector((x) => x.selectedFileId)!;
const metricVersionNumber = useChatLayoutContextSelector((x) => x.metricVersionNumber);
const { isViewingOldVersion } = useIsMetricReadOnly({
metricId: metricId || ''
});
const { error: metricError, data: permission } = useGetMetric(
{ id: metricId },
{ select: (x) => x.permission }
@ -35,12 +39,16 @@ export const MetricContainerHeaderButtons: React.FC<FileContainerButtonsProps> =
return (
<FileButtonContainer>
{isEditor && <EditChartButton metricId={metricId} />}
{isEffectiveOwner && <EditSQLButton metricId={metricId} />}
{isEditor && !isViewingOldVersion && <EditChartButton metricId={metricId} />}
{isEffectiveOwner && !isViewingOldVersion && <EditSQLButton metricId={metricId} />}
<SaveToCollectionButton metricId={metricId} />
<SaveToDashboardButton metricId={metricId} />
{isEffectiveOwner && <ShareMetricButton metricId={metricId} />}
<ThreeDotMenuButton metricId={metricId} />
{isEffectiveOwner && !isViewingOldVersion && <ShareMetricButton metricId={metricId} />}
<ThreeDotMenuButton
metricId={metricId}
isViewingOldVersion={isViewingOldVersion}
versionNumber={metricVersionNumber}
/>
<HideButtonContainer show={selectedLayout === 'file-only'}>
<CreateChatButton assetId={metricId} assetType="metric" />
</HideButtonContainer>
@ -55,8 +63,8 @@ const EditChartButton = React.memo(({ metricId }: { metricId: string }) => {
(x) => x.selectedFileViewSecondary
);
const onChangePage = useAppLayoutContextSelector((x) => x.onChangePage);
const onChangeQueryParams = useAppLayoutContextSelector((x) => x.onChangeQueryParams);
const chatId = useChatIndividualContextSelector((x) => x.chatId);
const metricVersionNumber = useChatLayoutContextSelector((x) => x.metricVersionNumber);
const editableSecondaryView: MetricFileViewSecondary = 'chart-edit';
const isSelectedView = selectedFileViewSecondary === editableSecondaryView;
@ -66,7 +74,8 @@ const EditChartButton = React.memo(({ metricId }: { metricId: string }) => {
chatId,
assetId: metricId,
type: 'metric',
secondaryView: null
secondaryView: null,
versionNumber: metricVersionNumber
});
}
@ -74,9 +83,10 @@ const EditChartButton = React.memo(({ metricId }: { metricId: string }) => {
chatId,
assetId: metricId,
type: 'metric',
secondaryView: 'chart-edit'
secondaryView: 'chart-edit',
versionNumber: metricVersionNumber
});
}, [chatId, metricId, isSelectedView]);
}, [chatId, metricId, isSelectedView, metricVersionNumber]);
const onClickButton = useMemoizedFn(() => {
onChangePage(href, { shallow: true });
@ -108,6 +118,7 @@ const EditSQLButton = React.memo(({ metricId }: { metricId: string }) => {
);
const onSetFileView = useChatLayoutContextSelector((x) => x.onSetFileView);
const chatId = useChatIndividualContextSelector((x) => x.chatId);
const metricVersionNumber = useChatLayoutContextSelector((x) => x.metricVersionNumber);
const editableSecondaryView: MetricFileViewSecondary = 'sql-edit';
const isSelectedView = selectedFileViewSecondary === editableSecondaryView;
@ -116,9 +127,10 @@ const EditSQLButton = React.memo(({ metricId }: { metricId: string }) => {
chatId,
assetId: metricId,
type: 'metric',
secondaryView: 'sql-edit'
secondaryView: 'sql-edit',
versionNumber: metricVersionNumber
});
}, [chatId, metricId]);
}, [chatId, metricId, metricVersionNumber]);
const onClickButton = useMemoizedFn(() => {
const secondaryView = isSelectedView ? null : editableSecondaryView;
@ -147,8 +159,3 @@ const SaveToDashboardButton = React.memo(({ metricId }: { metricId: string }) =>
return <SaveMetricToDashboardButton metricIds={[metricId]} />;
});
SaveToDashboardButton.displayName = 'SaveToDashboardButton';
const ShareMetricButtonLocal = React.memo(({ metricId }: { metricId: string }) => {
return <ShareMetricButton metricId={metricId} />;
});
ShareMetricButtonLocal.displayName = 'ShareMetricButtonLocal';

View File

@ -56,82 +56,92 @@ import { BusterRoutes, createBusterRoute } from '@/routes';
import { useListVersionDropdownItems } from '@/components/features/versionHistory/useListVersionDropdownItems';
import { useChatIndividualContextSelector } from '@/layouts/ChatLayout/ChatContext';
export const ThreeDotMenuButton = React.memo(({ metricId }: { metricId: string }) => {
const chatId = useChatIndividualContextSelector((x) => x.chatId);
const { openSuccessMessage } = useBusterNotifications();
const { data: permission } = useGetMetric({ id: metricId }, { select: (x) => x.permission });
const openFullScreenMetric = useOpenFullScreenMetric({ metricId });
const onSetSelectedFile = useChatLayoutContextSelector((x) => x.onSetSelectedFile);
const dashboardSelectMenu = useDashboardSelectMenu({ metricId });
const versionHistoryItems = useVersionHistorySelectMenu({ metricId });
const collectionSelectMenu = useCollectionSelectMenu({ metricId });
const statusSelectMenu = useStatusSelectMenu({ metricId });
const favoriteMetric = useFavoriteMetricSelectMenu({ metricId });
const editChartMenu = useEditChartSelectMenu();
const resultsViewMenu = useResultsViewSelectMenu();
const sqlEditorMenu = useSQLEditorSelectMenu();
const downloadCSVMenu = useDownloadCSVSelectMenu({ metricId });
const downloadPNGMenu = useDownloadPNGSelectMenu({ metricId });
const deleteMetricMenu = useDeleteMetricSelectMenu({ metricId });
const renameMetricMenu = useRenameMetricSelectMenu({ metricId });
const shareMenu = useShareMenuSelectMenu({ metricId });
export const ThreeDotMenuButton = React.memo(
({
metricId,
isViewingOldVersion,
versionNumber
}: {
metricId: string;
isViewingOldVersion: boolean;
versionNumber: number | undefined;
}) => {
const chatId = useChatIndividualContextSelector((x) => x.chatId);
const { openSuccessMessage } = useBusterNotifications();
const { data: permission } = useGetMetric({ id: metricId }, { select: (x) => x.permission });
const openFullScreenMetric = useOpenFullScreenMetric({ metricId, versionNumber });
const onSetSelectedFile = useChatLayoutContextSelector((x) => x.onSetSelectedFile);
const dashboardSelectMenu = useDashboardSelectMenu({ metricId });
const versionHistoryItems = useVersionHistorySelectMenu({ metricId });
const collectionSelectMenu = useCollectionSelectMenu({ metricId });
const statusSelectMenu = useStatusSelectMenu({ metricId });
const favoriteMetric = useFavoriteMetricSelectMenu({ metricId });
const editChartMenu = useEditChartSelectMenu();
const resultsViewMenu = useResultsViewSelectMenu();
const sqlEditorMenu = useSQLEditorSelectMenu();
const downloadCSVMenu = useDownloadCSVSelectMenu({ metricId });
const downloadPNGMenu = useDownloadPNGSelectMenu({ metricId });
const deleteMetricMenu = useDeleteMetricSelectMenu({ metricId });
const renameMetricMenu = useRenameMetricSelectMenu({ metricId });
const shareMenu = useShareMenuSelectMenu({ metricId });
const isEditor = canEdit(permission);
const isOwnerEffective = getIsEffectiveOwner(permission);
const isOwner = getIsOwner(permission);
const isEditor = canEdit(permission);
const isOwnerEffective = getIsEffectiveOwner(permission);
const isOwner = getIsOwner(permission);
const items: DropdownItems = useMemo(
() =>
const items: DropdownItems = useMemo(
() =>
[
chatId && openFullScreenMetric,
isOwnerEffective && !isViewingOldVersion && shareMenu,
isEditor && !isViewingOldVersion && statusSelectMenu,
{ type: 'divider' },
!isViewingOldVersion && dashboardSelectMenu,
!isViewingOldVersion && collectionSelectMenu,
!isViewingOldVersion && favoriteMetric,
{ type: 'divider' },
isEditor && !isViewingOldVersion && editChartMenu,
!isViewingOldVersion && resultsViewMenu,
!isViewingOldVersion && sqlEditorMenu,
isEditor && versionHistoryItems,
{ type: 'divider' },
downloadCSVMenu,
downloadPNGMenu,
{ type: 'divider' },
isEditor && !isViewingOldVersion && renameMetricMenu,
isOwner && !isViewingOldVersion && deleteMetricMenu
].filter(Boolean) as DropdownItems,
[
chatId && openFullScreenMetric,
isOwnerEffective && shareMenu,
isEditor && statusSelectMenu,
{ type: 'divider' },
chatId,
openFullScreenMetric,
isEditor,
isOwner,
isOwnerEffective,
renameMetricMenu,
dashboardSelectMenu,
collectionSelectMenu,
favoriteMetric,
{ type: 'divider' },
isEditor && editChartMenu,
resultsViewMenu,
sqlEditorMenu,
isEditor && versionHistoryItems,
{ type: 'divider' },
deleteMetricMenu,
downloadCSVMenu,
downloadPNGMenu,
{ type: 'divider' },
isEditor && renameMetricMenu,
isOwner && deleteMetricMenu
].filter(Boolean) as DropdownItems,
[
chatId,
openFullScreenMetric,
isEditor,
isOwner,
isOwnerEffective,
renameMetricMenu,
dashboardSelectMenu,
deleteMetricMenu,
downloadCSVMenu,
downloadPNGMenu,
openSuccessMessage,
onSetSelectedFile,
versionHistoryItems,
favoriteMetric,
statusSelectMenu,
collectionSelectMenu,
editChartMenu,
resultsViewMenu,
sqlEditorMenu,
shareMenu
]
);
openSuccessMessage,
onSetSelectedFile,
versionHistoryItems,
favoriteMetric,
statusSelectMenu,
collectionSelectMenu,
editChartMenu,
resultsViewMenu,
sqlEditorMenu,
shareMenu
]
);
return (
<Dropdown items={items} side="bottom" align="end" contentClassName="max-h-fit" modal>
<Button prefix={<Dots />} variant="ghost" />
</Dropdown>
);
});
return (
<Dropdown items={items} side="bottom" align="end" contentClassName="max-h-fit" modal>
<Button prefix={<Dots />} variant="ghost" />
</Dropdown>
);
}
);
ThreeDotMenuButton.displayName = 'ThreeDotMenuButton';
const useDashboardSelectMenu = ({ metricId }: { metricId: string }) => {
@ -499,17 +509,29 @@ export const useShareMenuSelectMenu = ({ metricId }: { metricId: string }) => {
);
};
const useOpenFullScreenMetric = ({ metricId }: { metricId: string }) => {
const useOpenFullScreenMetric = ({
metricId,
versionNumber
}: {
metricId: string;
versionNumber: number | undefined;
}) => {
return useMemo(
() => ({
label: 'Open in metric page',
value: 'open-in-full-screen',
icon: <ArrowUpRight />,
link: createBusterRoute({
route: BusterRoutes.APP_METRIC_ID_CHART,
metricId
})
link: versionNumber
? createBusterRoute({
route: BusterRoutes.APP_METRIC_ID_VERSION_NUMBER,
metricId,
versionNumber
})
: createBusterRoute({
route: BusterRoutes.APP_METRIC_ID_CHART,
metricId
})
}),
[metricId]
[metricId, versionNumber]
);
};

View File

@ -57,7 +57,6 @@ export type BusterAppRoutesWithArgs = {
[BusterAppRoutes.APP_METRIC_ID_CHART]: {
route: BusterAppRoutes.APP_METRIC_ID_CHART;
metricId: string;
versionNumber?: number;
secondaryView?: MetricFileViewSecondary;
};
[BusterAppRoutes.APP_METRIC_ID_VERSION_NUMBER]: {
@ -132,6 +131,7 @@ export type BusterAppRoutesWithArgs = {
route: BusterAppRoutes.APP_CHAT_ID_METRIC_ID_CHART;
chatId: string;
metricId: string;
versionNumber?: number;
secondaryView?: MetricFileViewSecondary;
};
[BusterAppRoutes.APP_CHAT_ID_METRIC_ID_VERSION_NUMBER]: {