From 9d5850cc073f8996ecf81f65917dd8691dfcd87d Mon Sep 17 00:00:00 2001 From: Nate Kelley Date: Mon, 7 Jul 2025 11:37:25 -0600 Subject: [PATCH] update dashboard links --- apps/web/.vscode/settings.json | 3 + apps/web/package.json | 2 +- .../features/sidebars/SidebarPrimary.tsx | 14 +- .../DashboardContentController.tsx | 11 +- .../DashboardMetricItem.tsx | 16 +- .../MetricThreeDotMenu.tsx | 4 +- .../MetricContainerHeaderSegment.tsx | 10 +- .../src/lib/assets/assetParamsToRoute.test.ts | 22 ++- apps/web/src/lib/assets/assetParamsToRoute.ts | 27 +++- .../lib/assets/createDashboardRoute.test.ts | 142 +++++++----------- .../src/lib/assets/createDashboardRoute.ts | 11 +- apps/web/src/lib/assets/createMetricRoute.ts | 11 +- .../routes/busterRoutes/busterAppRoutes.ts | 6 +- pnpm-lock.yaml | 21 +-- 14 files changed, 143 insertions(+), 157 deletions(-) diff --git a/apps/web/.vscode/settings.json b/apps/web/.vscode/settings.json index 76eb03196..20801b7a2 100644 --- a/apps/web/.vscode/settings.json +++ b/apps/web/.vscode/settings.json @@ -6,5 +6,8 @@ }, "[css]": { "editor.defaultFormatter": "esbenp.prettier-vscode" + }, + "[typescript]": { + "editor.defaultFormatter": "esbenp.prettier-vscode" } } diff --git a/apps/web/package.json b/apps/web/package.json index 78813a41f..a5961b715 100644 --- a/apps/web/package.json +++ b/apps/web/package.json @@ -33,7 +33,7 @@ "@dnd-kit/sortable": "^10.0.0", "@dnd-kit/utilities": "^3.2.2", "@electric-sql/client": "^1.0.6", - "@electric-sql/react": "^1.0.5", + "@electric-sql/react": "^1.0.6", "@faker-js/faker": "^9.9.0", "@llm-ui/code": "^0.13.3", "@llm-ui/markdown": "^0.13.3", diff --git a/apps/web/src/components/features/sidebars/SidebarPrimary.tsx b/apps/web/src/components/features/sidebars/SidebarPrimary.tsx index 23c3eaf13..9aae0a6c5 100644 --- a/apps/web/src/components/features/sidebars/SidebarPrimary.tsx +++ b/apps/web/src/components/features/sidebars/SidebarPrimary.tsx @@ -46,14 +46,14 @@ const topItems = ( { label: 'Home', icon: , - route: BusterRoutes.APP_HOME, + route: createBusterRoute({ route: BusterRoutes.APP_HOME }), id: BusterRoutes.APP_HOME, active: currentParentRoute === BusterRoutes.APP_HOME }, { label: 'Chat history', icon: , - route: BusterRoutes.APP_CHAT, + route: createBusterRoute({ route: BusterRoutes.APP_CHAT }), id: BusterRoutes.APP_CHAT, active: isActiveCheck('chat', BusterRoutes.APP_CHAT) } @@ -75,21 +75,21 @@ const yourStuff = ( { label: 'Metrics', icon: , - route: BusterRoutes.APP_METRIC, + route: createBusterRoute({ route: BusterRoutes.APP_METRIC }), id: BusterRoutes.APP_METRIC, active: isActiveCheck('metric', BusterRoutes.APP_METRIC) }, { label: 'Dashboards', icon: , - route: BusterRoutes.APP_DASHBOARDS, + route: createBusterRoute({ route: BusterRoutes.APP_DASHBOARDS }), id: BusterRoutes.APP_DASHBOARDS, active: isActiveCheck('dashboard', BusterRoutes.APP_DASHBOARDS) }, { label: 'Collections', icon: , - route: BusterRoutes.APP_COLLECTIONS, + route: createBusterRoute({ route: BusterRoutes.APP_COLLECTIONS }), id: BusterRoutes.APP_COLLECTIONS, active: isActiveCheck('collection', BusterRoutes.APP_COLLECTIONS) } @@ -104,7 +104,7 @@ const adminTools = (currentParentRoute: BusterRoutes): ISidebarGroup => ({ { label: 'Logs', icon: , - route: BusterRoutes.APP_LOGS, + route: createBusterRoute({ route: BusterRoutes.APP_LOGS }), id: BusterRoutes.APP_LOGS, collapsedTooltip: 'Logs' }, @@ -117,7 +117,7 @@ const adminTools = (currentParentRoute: BusterRoutes): ISidebarGroup => ({ { label: 'Datasets', icon: , - route: BusterRoutes.APP_DATASETS, + route: createBusterRoute({ route: BusterRoutes.APP_DATASETS }), id: BusterRoutes.APP_DATASETS, collapsedTooltip: 'Datasets' } diff --git a/apps/web/src/controllers/DashboardController/DashboardViewDashboardController/DashboardContentController/DashboardContentController.tsx b/apps/web/src/controllers/DashboardController/DashboardViewDashboardController/DashboardContentController/DashboardContentController.tsx index 580bffa3d..eebb3a94c 100644 --- a/apps/web/src/controllers/DashboardController/DashboardViewDashboardController/DashboardContentController/DashboardContentController.tsx +++ b/apps/web/src/controllers/DashboardController/DashboardViewDashboardController/DashboardContentController/DashboardContentController.tsx @@ -40,10 +40,11 @@ export const DashboardContentController: React.FC<{ metrics = DEFAULT_EMPTY_METRICS, onUpdateDashboardConfig }) => { + const [draggingId, setDraggingId] = useState(null); + const dashboardVersionNumber = dashboard?.version_number; const dashboardConfig = dashboard?.config || DEFAULT_EMPTY_CONFIG; const configRows = dashboardConfig?.rows || DEFAULT_EMPTY_ROWS; const hasMetrics = !isEmpty(metrics); - const [draggingId, setDraggingId] = useState(null); const numberOfMetrics = Object.values(metrics).length; const remapMetrics = useMemo(() => { @@ -65,7 +66,8 @@ export const DashboardContentController: React.FC<{ isDragOverlay numberOfMetrics={numberOfMetrics} chatId={undefined} - versionNumber={metrics[draggingId]?.version_number} + dashboardVersionNumber={dashboardVersionNumber} + metricVersionNumber={metrics[draggingId]?.version_number} /> ) ); @@ -79,7 +81,7 @@ export const DashboardContentController: React.FC<{ ...row, items: row.items.map((item) => { const selectedMetric = metrics[item.id]; - const versionNumber = selectedMetric.version_number; + const metricVersionNumber = selectedMetric.version_number; return { ...item, @@ -91,7 +93,8 @@ export const DashboardContentController: React.FC<{ readOnly={readOnly} chatId={chatId} numberOfMetrics={numberOfMetrics} - versionNumber={versionNumber} + metricVersionNumber={metricVersionNumber} + dashboardVersionNumber={dashboardVersionNumber} /> ) }; diff --git a/apps/web/src/controllers/DashboardController/DashboardViewDashboardController/DashboardContentController/DashboardMetricItem/DashboardMetricItem.tsx b/apps/web/src/controllers/DashboardController/DashboardViewDashboardController/DashboardContentController/DashboardMetricItem/DashboardMetricItem.tsx index 45e573a96..31b8da77a 100644 --- a/apps/web/src/controllers/DashboardController/DashboardViewDashboardController/DashboardContentController/DashboardMetricItem/DashboardMetricItem.tsx +++ b/apps/web/src/controllers/DashboardController/DashboardViewDashboardController/DashboardContentController/DashboardMetricItem/DashboardMetricItem.tsx @@ -5,14 +5,14 @@ import { Card, CardHeader } from '@/components/ui/card/CardBase'; import { BusterChart } from '@/components/ui/charts/BusterChart'; import { useMemoizedFn } from '@/hooks'; import { cn } from '@/lib/classMerge'; -import { BusterRoutes, createBusterRoute } from '@/routes'; import { MetricTitle } from './MetricTitle'; import { useDashboardMetric } from './useDashboardMetric'; import { assetParamsToRoute } from '@/lib/assets'; const DashboardMetricItemBase: React.FC<{ metricId: string; - versionNumber: number | undefined; + metricVersionNumber: number | undefined; + dashboardVersionNumber: number | undefined; chatId: string | undefined; dashboardId: string; numberOfMetrics: number; @@ -22,12 +22,13 @@ const DashboardMetricItemBase: React.FC<{ }> = ({ readOnly, dashboardId, - versionNumber, + metricVersionNumber, className = '', metricId, isDragOverlay = false, numberOfMetrics, - chatId + chatId, + dashboardVersionNumber }) => { const { conatinerRef, @@ -39,7 +40,7 @@ const DashboardMetricItemBase: React.FC<{ isFetchedMetricData, metricError, metricDataError - } = useDashboardMetric({ metricId, versionNumber }); + } = useDashboardMetric({ metricId, versionNumber: metricVersionNumber }); const loadingMetricData = !!metric && !isFetchedMetricData; const chartOptions = metric?.chart_config; @@ -61,9 +62,10 @@ const DashboardMetricItemBase: React.FC<{ assetId: metricId, chatId, dashboardId, - page: 'chart' + page: 'chart', + metricVersionNumber }); - }, [metricId, chatId, dashboardId]); + }, [metricId, chatId, dashboardId, metricVersionNumber]); const onInitialAnimationEndPreflight = useMemoizedFn(() => { setInitialAnimationEnded(metricId); diff --git a/apps/web/src/layouts/ChatLayout/FileContainer/FileContainerHeader/MetricContainerHeaderButtons/MetricThreeDotMenu.tsx b/apps/web/src/layouts/ChatLayout/FileContainer/FileContainerHeader/MetricContainerHeaderButtons/MetricThreeDotMenu.tsx index 282820ec3..423b5e8c4 100644 --- a/apps/web/src/layouts/ChatLayout/FileContainer/FileContainerHeader/MetricContainerHeaderButtons/MetricThreeDotMenu.tsx +++ b/apps/web/src/layouts/ChatLayout/FileContainer/FileContainerHeader/MetricContainerHeaderButtons/MetricThreeDotMenu.tsx @@ -71,10 +71,8 @@ export const ThreeDotMenuButton = React.memo( 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 }); @@ -89,6 +87,8 @@ export const ThreeDotMenuButton = React.memo( const renameMetricMenu = useRenameMetricSelectMenu({ metricId }); const shareMenu = useShareMenuSelectMenu({ metricId }); + console.log(permission); + const isEditor = canEdit(permission); const isOwnerEffective = getIsEffectiveOwner(permission); const isOwner = getIsOwner(permission); diff --git a/apps/web/src/layouts/ChatLayout/FileContainer/FileContainerHeader/MetricContainerHeaderSegment.tsx b/apps/web/src/layouts/ChatLayout/FileContainer/FileContainerHeader/MetricContainerHeaderSegment.tsx index fab434ef4..ffffa1d1e 100644 --- a/apps/web/src/layouts/ChatLayout/FileContainer/FileContainerHeader/MetricContainerHeaderSegment.tsx +++ b/apps/web/src/layouts/ChatLayout/FileContainer/FileContainerHeader/MetricContainerHeaderSegment.tsx @@ -32,6 +32,8 @@ const MetricSegments: React.FC = React.memo( ({ selectedFileView, chatId }) => { const metricId = useChatLayoutContextSelector((x) => x.metricId) || ''; const dashboardId = useChatLayoutContextSelector((x) => x.dashboardId) || ''; + const metricVersionNumber = useChatLayoutContextSelector((x) => x.metricVersionNumber); + const dashboardVersionNumber = useChatLayoutContextSelector((x) => x.dashboardVersionNumber); const { error } = useGetMetric({ id: metricId }); const segmentOptions: SegmentedItem[] = React.useMemo(() => { @@ -44,6 +46,8 @@ const MetricSegments: React.FC = React.memo( chatId, dashboardId, assetId: metricId, + metricVersionNumber: metricVersionNumber, + dashboardVersionNumber, type: 'metric' }) }, @@ -55,6 +59,8 @@ const MetricSegments: React.FC = React.memo( chatId, dashboardId, assetId: metricId, + metricVersionNumber, + dashboardVersionNumber, type: 'metric' }) }, @@ -66,11 +72,13 @@ const MetricSegments: React.FC = React.memo( chatId, dashboardId, assetId: metricId, + metricVersionNumber, + dashboardVersionNumber, type: 'metric' }) } ]; - }, [chatId, error, metricId, dashboardId]); + }, [chatId, error, metricId, dashboardId, metricVersionNumber, dashboardVersionNumber]); return ; } diff --git a/apps/web/src/lib/assets/assetParamsToRoute.test.ts b/apps/web/src/lib/assets/assetParamsToRoute.test.ts index 3afcf4f53..7a8bbdf3e 100644 --- a/apps/web/src/lib/assets/assetParamsToRoute.test.ts +++ b/apps/web/src/lib/assets/assetParamsToRoute.test.ts @@ -6,15 +6,13 @@ import { createDashboardRoute } from './createDashboardRoute'; import { createReasoningRoute } from './createReasoningRoute'; import { createDatasetRoute } from './createDatasetRoute'; -// Mock all the route creation functions -vi.mock('@/routes/busterRoutes', () => ({ - BusterRoutes: { - APP_CHAT_ID: '/app/chats/:chatId', - APP_COLLECTIONS_ID: '/app/collections/:collectionId', - APP_TERMS_ID: '/app/terms/:termId' - }, - createBusterRoute: vi.fn() -})); +vi.mock('@/routes/busterRoutes', async () => { + const actual = await vi.importActual('@/routes/busterRoutes'); + return { + ...actual, + createBusterRoute: vi.fn() + }; +}); vi.mock('./createMetricRoute', () => ({ createMetricRoute: vi.fn() @@ -92,7 +90,7 @@ describe('assetParamsToRoute', () => { assetId: 'metric-123', chatId: 'chat-456', secondaryView: 'chart-edit', - versionNumber: 2, + metricVersionNumber: 2, page: 'chart' }); expect(result).toBe('/mock/metric/route'); @@ -122,7 +120,7 @@ describe('assetParamsToRoute', () => { assetId: 'dashboard-123', chatId: 'chat-456', type: 'dashboard', - versionNumber: 3, + dashboardVersionNumber: 3, page: 'file', secondaryView: 'version-history' }); @@ -130,7 +128,7 @@ describe('assetParamsToRoute', () => { expect(mockCreateDashboardRoute).toHaveBeenCalledWith({ assetId: 'dashboard-123', chatId: 'chat-456', - versionNumber: 3, + dashboardVersionNumber: 3, page: 'file', secondaryView: 'version-history' }); diff --git a/apps/web/src/lib/assets/assetParamsToRoute.ts b/apps/web/src/lib/assets/assetParamsToRoute.ts index 4e506f812..6fb7009e8 100644 --- a/apps/web/src/lib/assets/assetParamsToRoute.ts +++ b/apps/web/src/lib/assets/assetParamsToRoute.ts @@ -13,9 +13,13 @@ import { createDatasetRoute } from './createDatasetRoute'; type UnionOfFileTypes = FileType | ReasoningFileType | ReasoingMessage_ThoughtFileType; type OtherRouteParams = { - assetId: string | undefined; chatId: string | undefined; - versionNumber?: number; + assetId: string | undefined; //will first try and use metricId assuming it is a metric, then dashboardId assuming it is a dashboard, then assetId + metricId?: string; //if this is provided, it will be used instead of assetId + dashboardId?: string; //if this is provided, it will be used instead of assetId + versionNumber?: number; //will first try and use metricVersionNumber assuming it is a metric, then dashboardVersionNumber assuming it is a dashboard, then versionNumber + metricVersionNumber?: number; //if this is provided, it will be used instead of versionNumber + dashboardVersionNumber?: number; //if this is provided, it will be used instead of versionNumber page?: undefined; secondaryView?: undefined | null | string; type: Exclude; @@ -27,10 +31,14 @@ export const assetParamsToRoute = ({ chatId, assetId, type, - versionNumber, page, - secondaryView + secondaryView, + ...rest }: BaseParams): string => { + const { versionNumber } = rest as OtherRouteParams; + const { metricVersionNumber, dashboardVersionNumber } = rest as MetricRouteParams; + const { metricId, dashboardId } = rest as OtherRouteParams; + if (!assetId && chatId) { return createBusterRoute({ route: BusterRoutes.APP_CHAT_ID, @@ -44,19 +52,22 @@ export const assetParamsToRoute = ({ if (type === 'metric') { return createMetricRoute({ - assetId, + assetId: metricId || assetId, + metricVersionNumber: metricVersionNumber || versionNumber, chatId, secondaryView: secondaryView as MetricFileViewSecondary, - versionNumber, + dashboardVersionNumber, + dashboardId, page: page as MetricRouteParams['page'] }); } if (type === 'dashboard') { return createDashboardRoute({ - assetId, + assetId: dashboardId || assetId, + dashboardVersionNumber: dashboardVersionNumber || versionNumber, + metricVersionNumber, chatId, - versionNumber, page, secondaryView: secondaryView as DashboardFileViewSecondary }); diff --git a/apps/web/src/lib/assets/createDashboardRoute.test.ts b/apps/web/src/lib/assets/createDashboardRoute.test.ts index 9b5b43c75..a47526247 100644 --- a/apps/web/src/lib/assets/createDashboardRoute.test.ts +++ b/apps/web/src/lib/assets/createDashboardRoute.test.ts @@ -6,16 +6,7 @@ import { BusterRoutes } from '@/routes/busterRoutes'; vi.mock('@/routes/busterRoutes', async () => { const actual = await vi.importActual('@/routes/busterRoutes'); return { - ...actual, - createBusterRoute: vi.fn((params) => { - // Simple mock implementation that returns a string representation - const { route, ...args } = params; - const queryParams = Object.entries(args) - .filter(([_, value]) => value !== undefined) - .map(([key, value]) => `${key}=${value}`) - .join('&'); - return queryParams ? `${route}?${queryParams}` : route; - }) + ...actual }; }); @@ -30,29 +21,28 @@ describe('createDashboardRoute', () => { assetId: 'dashboard-123', chatId: 'chat-456', secondaryView: 'version-history', - versionNumber: 5, + dashboardVersionNumber: 5, page: 'dashboard' }); - expect(result).toContain(BusterRoutes.APP_CHAT_ID_DASHBOARD_ID); - expect(result).toContain('chatId=chat-456'); - expect(result).toContain('dashboardId=dashboard-123'); - expect(result).toContain('dashboardVersionNumber=5'); - expect(result).toContain('secondaryView=version-history'); + console.log('result', result); + + expect(result).toBe( + '/app/chats/chat-456/dashboards/dashboard-123?secondary_view=version-history&dashboard_version_number=5' + ); }); it('should create chat dashboard route with version number only', () => { const result = createDashboardRoute({ assetId: 'dashboard-123', chatId: 'chat-456', - versionNumber: 3, + dashboardVersionNumber: 3, page: 'dashboard' }); - expect(result).toContain(BusterRoutes.APP_CHAT_ID_DASHBOARD_ID); - expect(result).toContain('chatId=chat-456'); - expect(result).toContain('dashboardId=dashboard-123'); - expect(result).toContain('dashboardVersionNumber=3'); + expect(result).toBe( + '/app/chats/chat-456/dashboards/dashboard-123?dashboard_version_number=3' + ); }); it('should create chat dashboard route with version-history secondary view', () => { @@ -63,10 +53,9 @@ describe('createDashboardRoute', () => { page: 'dashboard' }); - expect(result).toContain(BusterRoutes.APP_CHAT_ID_DASHBOARD_ID); - expect(result).toContain('chatId=chat-456'); - expect(result).toContain('dashboardId=dashboard-123'); - expect(result).toContain('secondaryView=version-history'); + expect(result).toBe( + '/app/chats/chat-456/dashboards/dashboard-123?secondary_view=version-history' + ); }); it('should create chat dashboard route with minimal parameters', () => { @@ -76,21 +65,17 @@ describe('createDashboardRoute', () => { page: 'dashboard' }); - expect(result).toContain(BusterRoutes.APP_CHAT_ID_DASHBOARD_ID); - expect(result).toContain('chatId=chat-456'); - expect(result).toContain('dashboardId=dashboard-123'); + expect(result).toBe('/app/chats/chat-456/dashboards/dashboard-123'); }); it('should create non-chat dashboard route with version number', () => { const result = createDashboardRoute({ assetId: 'dashboard-123', - versionNumber: 7, + dashboardVersionNumber: 7, page: 'dashboard' }); - expect(result).toContain(BusterRoutes.APP_DASHBOARD_ID); - expect(result).toContain('dashboardId=dashboard-123'); - expect(result).toContain('dashboardVersionNumber=7'); + expect(result).toBe('/app/dashboards/dashboard-123?dashboard_version_number=7'); }); it('should create non-chat dashboard route with version-history secondary view', () => { @@ -100,9 +85,7 @@ describe('createDashboardRoute', () => { page: 'dashboard' }); - expect(result).toContain(BusterRoutes.APP_DASHBOARD_ID); - expect(result).toContain('dashboardId=dashboard-123'); - expect(result).toContain('secondaryView=version-history'); + expect(result).toBe('/app/dashboards/dashboard-123?secondary_view=version-history'); }); it('should create non-chat dashboard route with minimal parameters', () => { @@ -111,8 +94,7 @@ describe('createDashboardRoute', () => { page: 'dashboard' }); - expect(result).toContain(BusterRoutes.APP_DASHBOARD_ID); - expect(result).toContain('dashboardId=dashboard-123'); + expect(result).toBe('/app/dashboards/dashboard-123'); }); }); @@ -121,14 +103,13 @@ describe('createDashboardRoute', () => { const result = createDashboardRoute({ assetId: 'dashboard-123', chatId: 'chat-456', - versionNumber: 2, + dashboardVersionNumber: 2, page: 'file' }); - expect(result).toContain(BusterRoutes.APP_CHAT_ID_DASHBOARD_ID); - expect(result).toContain('chatId=chat-456'); - expect(result).toContain('dashboardId=dashboard-123'); - expect(result).toContain('dashboardVersionNumber=2'); + expect(result).toBe( + '/app/chats/chat-456/dashboards/dashboard-123?dashboard_version_number=2' + ); }); it('should create chat dashboard file route with version-history secondary view', () => { @@ -139,10 +120,9 @@ describe('createDashboardRoute', () => { page: 'file' }); - expect(result).toContain(BusterRoutes.APP_CHAT_ID_DASHBOARD_ID); - expect(result).toContain('chatId=chat-456'); - expect(result).toContain('dashboardId=dashboard-123'); - expect(result).toContain('secondaryView=version-history'); + expect(result).toBe( + '/app/chats/chat-456/dashboards/dashboard-123?secondary_view=version-history' + ); }); it('should create chat dashboard file route without version number', () => { @@ -152,21 +132,17 @@ describe('createDashboardRoute', () => { page: 'file' }); - expect(result).toContain(BusterRoutes.APP_CHAT_ID_DASHBOARD_ID); - expect(result).toContain('chatId=chat-456'); - expect(result).toContain('dashboardId=dashboard-123'); + expect(result).toBe('/app/chats/chat-456/dashboards/dashboard-123'); }); it('should create non-chat dashboard file route with version number', () => { const result = createDashboardRoute({ assetId: 'dashboard-123', - versionNumber: 8, + dashboardVersionNumber: 8, page: 'file' }); - expect(result).toContain(BusterRoutes.APP_DASHBOARD_ID); - expect(result).toContain('dashboardId=dashboard-123'); - expect(result).toContain('dashboardVersionNumber=8'); + expect(result).toBe('/app/dashboards/dashboard-123?dashboard_version_number=8'); }); it('should create non-chat dashboard file route without version number', () => { @@ -175,8 +151,7 @@ describe('createDashboardRoute', () => { page: 'file' }); - expect(result).toContain(BusterRoutes.APP_DASHBOARD_ID); - expect(result).toContain('dashboardId=dashboard-123'); + expect(result).toBe('/app/dashboards/dashboard-123'); }); }); @@ -188,9 +163,7 @@ describe('createDashboardRoute', () => { page: undefined }); - expect(result).toContain(BusterRoutes.APP_CHAT_ID_DASHBOARD_ID); - expect(result).toContain('chatId=chat-456'); - expect(result).toContain('dashboardId=dashboard-123'); + expect(result).toBe('/app/chats/chat-456/dashboards/dashboard-123'); }); it('should handle undefined secondary view in chat context', () => { @@ -201,9 +174,7 @@ describe('createDashboardRoute', () => { page: 'dashboard' }); - expect(result).toContain(BusterRoutes.APP_CHAT_ID_DASHBOARD_ID); - expect(result).toContain('chatId=chat-456'); - expect(result).toContain('dashboardId=dashboard-123'); + expect(result).toBe('/app/chats/chat-456/dashboards/dashboard-123'); }); it('should handle undefined secondary view in non-chat context', () => { @@ -213,8 +184,7 @@ describe('createDashboardRoute', () => { page: 'dashboard' }); - expect(result).toContain(BusterRoutes.APP_DASHBOARD_ID); - expect(result).toContain('dashboardId=dashboard-123'); + expect(result).toBe('/app/dashboards/dashboard-123'); }); it('should handle undefined page value', () => { @@ -224,9 +194,7 @@ describe('createDashboardRoute', () => { page: undefined }); - expect(result).toContain(BusterRoutes.APP_CHAT_ID_DASHBOARD_ID); - expect(result).toContain('chatId=chat-456'); - expect(result).toContain('dashboardId=dashboard-123'); + expect(result).toBe('/app/chats/chat-456/dashboards/dashboard-123'); }); }); @@ -238,52 +206,46 @@ describe('createDashboardRoute', () => { secondaryView: undefined, versionNumber: undefined, page: 'dashboard' - }); + } as any); - expect(result).toContain(BusterRoutes.APP_DASHBOARD_ID); - expect(result).toContain('dashboardId=dashboard-123'); + expect(result).toBe('/app/dashboards/dashboard-123'); }); it('should handle version number 1', () => { const result = createDashboardRoute({ assetId: 'dashboard-123', chatId: 'chat-456', - versionNumber: 1, + dashboardVersionNumber: 1, page: 'dashboard' }); - expect(result).toContain(BusterRoutes.APP_CHAT_ID_DASHBOARD_ID); - expect(result).toContain('chatId=chat-456'); - expect(result).toContain('dashboardId=dashboard-123'); - expect(result).toContain('dashboardVersionNumber=1'); + expect(result).toBe( + '/app/chats/chat-456/dashboards/dashboard-123?dashboard_version_number=1' + ); }); it('should handle zero version number', () => { const result = createDashboardRoute({ assetId: 'dashboard-123', chatId: 'chat-456', - versionNumber: 0, + dashboardVersionNumber: 0, page: 'dashboard' }); - expect(result).toContain(BusterRoutes.APP_CHAT_ID_DASHBOARD_ID); - expect(result).toContain('chatId=chat-456'); - expect(result).toContain('dashboardId=dashboard-123'); - expect(result).toContain('dashboardVersionNumber=0'); + expect(result).toBe('/app/chats/chat-456/dashboards/dashboard-123'); }); it('should handle large version numbers', () => { const result = createDashboardRoute({ assetId: 'dashboard-123', chatId: 'chat-456', - versionNumber: 999999, + dashboardVersionNumber: 999999, page: 'dashboard' }); - expect(result).toContain(BusterRoutes.APP_CHAT_ID_DASHBOARD_ID); - expect(result).toContain('chatId=chat-456'); - expect(result).toContain('dashboardId=dashboard-123'); - expect(result).toContain('dashboardVersionNumber=999999'); + expect(result).toBe( + '/app/chats/chat-456/dashboards/dashboard-123?dashboard_version_number=999999' + ); }); it('should handle complex dashboard IDs', () => { @@ -293,9 +255,9 @@ describe('createDashboardRoute', () => { page: 'dashboard' }); - expect(result).toContain(BusterRoutes.APP_CHAT_ID_DASHBOARD_ID); - expect(result).toContain('chatId=chat-456'); - expect(result).toContain('dashboardId=dashboard-with-special-chars-123_456-789'); + expect(result).toBe( + '/app/chats/chat-456/dashboards/dashboard-with-special-chars-123_456-789' + ); }); it('should handle complex chat IDs', () => { @@ -305,9 +267,9 @@ describe('createDashboardRoute', () => { page: 'dashboard' }); - expect(result).toContain(BusterRoutes.APP_CHAT_ID_DASHBOARD_ID); - expect(result).toContain('chatId=chat-with-special-chars-456_789-012'); - expect(result).toContain('dashboardId=dashboard-123'); + expect(result).toBe( + '/app/chats/chat-with-special-chars-456_789-012/dashboards/dashboard-123' + ); }); }); }); diff --git a/apps/web/src/lib/assets/createDashboardRoute.ts b/apps/web/src/lib/assets/createDashboardRoute.ts index d3168ff39..63a1166dc 100644 --- a/apps/web/src/lib/assets/createDashboardRoute.ts +++ b/apps/web/src/lib/assets/createDashboardRoute.ts @@ -4,8 +4,10 @@ import type { DashboardFileViewSecondary } from '../../layouts/ChatLayout/ChatLa export type DashboardRouteParams = { assetId: string; chatId?: string; - secondaryView?: DashboardFileViewSecondary; versionNumber?: number; + secondaryView?: DashboardFileViewSecondary; + dashboardVersionNumber?: number; + metricVersionNumber?: number; type: 'dashboard'; page?: 'file' | 'dashboard' | undefined; }; @@ -14,10 +16,13 @@ export const createDashboardRoute = ({ assetId: dashboardId, chatId, secondaryView, - versionNumber: dashboardVersionNumber, + dashboardVersionNumber: _dashboardVersionNumber, + metricVersionNumber, + versionNumber, page = 'dashboard' }: Omit) => { - const baseParams = { dashboardVersionNumber, dashboardId, secondaryView }; + const dashboardVersionNumber = _dashboardVersionNumber || versionNumber; + const baseParams = { dashboardVersionNumber, dashboardId, secondaryView, metricVersionNumber }; if (page === 'dashboard') { if (chatId) { diff --git a/apps/web/src/lib/assets/createMetricRoute.ts b/apps/web/src/lib/assets/createMetricRoute.ts index 8d02ff686..c639637ce 100644 --- a/apps/web/src/lib/assets/createMetricRoute.ts +++ b/apps/web/src/lib/assets/createMetricRoute.ts @@ -6,9 +6,11 @@ export type MetricRouteParams = { dashboardId?: string; chatId?: string; secondaryView?: MetricFileViewSecondary; - versionNumber?: number; + metricVersionNumber?: number; + dashboardVersionNumber?: number; type: 'metric'; page?: 'chart' | 'results' | 'sql' | undefined; + versionNumber?: number; //will first try and use metricVersionNumber assuming it is a metric, then dashboardVersionNumber assuming it is a dashboard, then versionNumber }; export const createMetricRoute = ({ @@ -16,10 +18,13 @@ export const createMetricRoute = ({ chatId, secondaryView, dashboardId, - versionNumber: metricVersionNumber, + metricVersionNumber: _metricVersionNumber, + dashboardVersionNumber, + versionNumber, page = 'chart' }: Omit) => { - const baseParams = { metricVersionNumber, metricId, secondaryView }; + const metricVersionNumber = _metricVersionNumber || versionNumber; + const baseParams = { metricVersionNumber, dashboardVersionNumber, metricId, secondaryView }; if (page === 'chart') { // Check for dashboardId first (requires chatId as well) diff --git a/apps/web/src/routes/busterRoutes/busterAppRoutes.ts b/apps/web/src/routes/busterRoutes/busterAppRoutes.ts index d35f1e397..c09fdcbea 100644 --- a/apps/web/src/routes/busterRoutes/busterAppRoutes.ts +++ b/apps/web/src/routes/busterRoutes/busterAppRoutes.ts @@ -4,11 +4,11 @@ export enum BusterAppRoutes { APP_HOME = '/app/home', APP_COLLECTIONS = '/app/collections', APP_COLLECTIONS_ID = '/app/collections/:collectionId', - APP_METRIC = '/app/metrics?metric_version_number=:metricVersionNumber', + APP_METRIC = '/app/metrics', APP_METRIC_ID_CHART = '/app/metrics/:metricId/chart?secondary_view=:secondaryView&metric_version_number=:metricVersionNumber', APP_METRIC_ID_RESULTS = '/app/metrics/:metricId/results?secondary_view=:secondaryView&metric_version_number=:metricVersionNumber', APP_METRIC_ID_SQL = '/app/metrics/:metricId/sql?metric_version_number=:metricVersionNumber', - APP_DASHBOARDS = '/app/dashboards?dashboard_version_number=:dashboardVersionNumber', + APP_DASHBOARDS = '/app/dashboards', APP_DASHBOARD_ID = '/app/dashboards/:dashboardId?secondary_view=:secondaryView&dashboard_version_number=:dashboardVersionNumber', APP_DASHBOARD_ID_FILE = '/app/dashboards/:dashboardId/file?dashboard_version_number=:dashboardVersionNumber&secondary_view=:secondaryView', APP_LOGS = '/app/logs', @@ -54,7 +54,6 @@ export type BusterAppRoutesWithArgs = { }; [BusterAppRoutes.APP_METRIC]: { route: BusterAppRoutes.APP_METRIC; - metricVersionNumber?: number; }; [BusterAppRoutes.APP_METRIC_ID_CHART]: { route: BusterAppRoutes.APP_METRIC_ID_CHART; @@ -75,7 +74,6 @@ export type BusterAppRoutesWithArgs = { }; [BusterAppRoutes.APP_DASHBOARDS]: { route: BusterAppRoutes.APP_DASHBOARDS; - dashboardVersionNumber?: number; }; [BusterAppRoutes.APP_DASHBOARD_ID]: { route: BusterAppRoutes.APP_DASHBOARD_ID; diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 9b408b5c6..d2650a6fa 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -207,8 +207,8 @@ importers: specifier: ^1.0.6 version: 1.0.6 '@electric-sql/react': - specifier: ^1.0.5 - version: 1.0.5(react@18.3.1) + specifier: ^1.0.6 + version: 1.0.6(react@18.3.1) '@faker-js/faker': specifier: ^9.9.0 version: 9.9.0 @@ -2005,14 +2005,11 @@ packages: '@electric-sql/client@1.0.0-beta.1': resolution: {integrity: sha512-Ei9jN3pDoGzc+a/bGqnB5ajb52IvSv7/n2btuyzUlcOHIR2kM9fqtYTJXPwZYKLkGZlHWlpHgWyRtrinkP2nHg==} - '@electric-sql/client@1.0.5': - resolution: {integrity: sha512-DO7dvfCbZU6k33vr3ymBCXER6kPpoBODoRBru7oI16B4/ZXlxhMBpsmzmd8p9dQrPICCpQm6bBkNI6qI3oUAIQ==} - '@electric-sql/client@1.0.6': resolution: {integrity: sha512-W3vrQhpKeMrOwErnrurC+aXJI8o6g4hSvHdFv10vES4Y+u3zBQoee88otr25GYX8cdleTXlczvh7XQhn4ywRBA==} - '@electric-sql/react@1.0.5': - resolution: {integrity: sha512-mNabbjw0BGV8nw6JUQF6OecQU5IQW8RbJ4SiwQ4LGJ2G0jRIT6cnQsNdXU4amoMnbchRhXFDGb8FJxnEVczn3Q==} + '@electric-sql/react@1.0.6': + resolution: {integrity: sha512-r+45jTP0o4urpn5LF94vIgqcvnBD6MJFi7QwYUjQLVU46gu+43Sudl503Klier10j473emZHIdvrI6FxRWH/Zw==} peerDependencies: react: '>=18.3.1 <20.0.0' peerDependenciesMeta: @@ -13493,21 +13490,15 @@ snapshots: optionalDependencies: '@rollup/rollup-darwin-arm64': 4.44.2 - '@electric-sql/client@1.0.5': - dependencies: - '@microsoft/fetch-event-source': 2.0.1 - optionalDependencies: - '@rollup/rollup-darwin-arm64': 4.44.2 - '@electric-sql/client@1.0.6': dependencies: '@microsoft/fetch-event-source': 2.0.1 optionalDependencies: '@rollup/rollup-darwin-arm64': 4.44.2 - '@electric-sql/react@1.0.5(react@18.3.1)': + '@electric-sql/react@1.0.6(react@18.3.1)': dependencies: - '@electric-sql/client': 1.0.5 + '@electric-sql/client': 1.0.6 use-sync-external-store: 1.5.0(react@18.3.1) optionalDependencies: react: 18.3.1