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 Link from 'next/link';
import { useGetFileLink } from '@/context/Assets/useGetFileLink'; import { useGetFileLink } from '@/context/Assets/useGetFileLink';
import { useChatLayoutContextSelector } from '@/layouts/ChatLayout'; import { useChatLayoutContextSelector } from '@/layouts/ChatLayout';
import { useRouter } from 'next/navigation';
import { useCallback } from 'react'; import { useCallback } from 'react';
export const VersionHistoryPanel = React.memo( export const VersionHistoryPanel = React.memo(

View File

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

View File

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

View File

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

View File

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

View File

@ -56,11 +56,20 @@ import { BusterRoutes, createBusterRoute } from '@/routes';
import { useListVersionDropdownItems } from '@/components/features/versionHistory/useListVersionDropdownItems'; import { useListVersionDropdownItems } from '@/components/features/versionHistory/useListVersionDropdownItems';
import { useChatIndividualContextSelector } from '@/layouts/ChatLayout/ChatContext'; import { useChatIndividualContextSelector } from '@/layouts/ChatLayout/ChatContext';
export const ThreeDotMenuButton = React.memo(({ metricId }: { metricId: string }) => { export const ThreeDotMenuButton = React.memo(
({
metricId,
isViewingOldVersion,
versionNumber
}: {
metricId: string;
isViewingOldVersion: boolean;
versionNumber: number | undefined;
}) => {
const chatId = useChatIndividualContextSelector((x) => x.chatId); const chatId = useChatIndividualContextSelector((x) => x.chatId);
const { openSuccessMessage } = useBusterNotifications(); const { openSuccessMessage } = useBusterNotifications();
const { data: permission } = useGetMetric({ id: metricId }, { select: (x) => x.permission }); const { data: permission } = useGetMetric({ id: metricId }, { select: (x) => x.permission });
const openFullScreenMetric = useOpenFullScreenMetric({ metricId }); const openFullScreenMetric = useOpenFullScreenMetric({ metricId, versionNumber });
const onSetSelectedFile = useChatLayoutContextSelector((x) => x.onSetSelectedFile); const onSetSelectedFile = useChatLayoutContextSelector((x) => x.onSetSelectedFile);
const dashboardSelectMenu = useDashboardSelectMenu({ metricId }); const dashboardSelectMenu = useDashboardSelectMenu({ metricId });
const versionHistoryItems = useVersionHistorySelectMenu({ metricId }); const versionHistoryItems = useVersionHistorySelectMenu({ metricId });
@ -84,23 +93,23 @@ export const ThreeDotMenuButton = React.memo(({ metricId }: { metricId: string }
() => () =>
[ [
chatId && openFullScreenMetric, chatId && openFullScreenMetric,
isOwnerEffective && shareMenu, isOwnerEffective && !isViewingOldVersion && shareMenu,
isEditor && statusSelectMenu, isEditor && !isViewingOldVersion && statusSelectMenu,
{ type: 'divider' }, { type: 'divider' },
dashboardSelectMenu, !isViewingOldVersion && dashboardSelectMenu,
collectionSelectMenu, !isViewingOldVersion && collectionSelectMenu,
favoriteMetric, !isViewingOldVersion && favoriteMetric,
{ type: 'divider' }, { type: 'divider' },
isEditor && editChartMenu, isEditor && !isViewingOldVersion && editChartMenu,
resultsViewMenu, !isViewingOldVersion && resultsViewMenu,
sqlEditorMenu, !isViewingOldVersion && sqlEditorMenu,
isEditor && versionHistoryItems, isEditor && versionHistoryItems,
{ type: 'divider' }, { type: 'divider' },
downloadCSVMenu, downloadCSVMenu,
downloadPNGMenu, downloadPNGMenu,
{ type: 'divider' }, { type: 'divider' },
isEditor && renameMetricMenu, isEditor && !isViewingOldVersion && renameMetricMenu,
isOwner && deleteMetricMenu isOwner && !isViewingOldVersion && deleteMetricMenu
].filter(Boolean) as DropdownItems, ].filter(Boolean) as DropdownItems,
[ [
chatId, chatId,
@ -131,7 +140,8 @@ export const ThreeDotMenuButton = React.memo(({ metricId }: { metricId: string }
<Button prefix={<Dots />} variant="ghost" /> <Button prefix={<Dots />} variant="ghost" />
</Dropdown> </Dropdown>
); );
}); }
);
ThreeDotMenuButton.displayName = 'ThreeDotMenuButton'; ThreeDotMenuButton.displayName = 'ThreeDotMenuButton';
const useDashboardSelectMenu = ({ metricId }: { metricId: string }) => { 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( return useMemo(
() => ({ () => ({
label: 'Open in metric page', label: 'Open in metric page',
value: 'open-in-full-screen', value: 'open-in-full-screen',
icon: <ArrowUpRight />, icon: <ArrowUpRight />,
link: createBusterRoute({ link: versionNumber
? createBusterRoute({
route: BusterRoutes.APP_METRIC_ID_VERSION_NUMBER,
metricId,
versionNumber
})
: createBusterRoute({
route: BusterRoutes.APP_METRIC_ID_CHART, route: BusterRoutes.APP_METRIC_ID_CHART,
metricId metricId
}) })
}), }),
[metricId] [metricId, versionNumber]
); );
}; };

View File

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