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