update dashboard links

This commit is contained in:
Nate Kelley 2025-07-07 11:37:25 -06:00
parent 48678dd226
commit 9d5850cc07
No known key found for this signature in database
GPG Key ID: FD90372AB8D98B4F
14 changed files with 143 additions and 157 deletions

View File

@ -6,5 +6,8 @@
},
"[css]": {
"editor.defaultFormatter": "esbenp.prettier-vscode"
},
"[typescript]": {
"editor.defaultFormatter": "esbenp.prettier-vscode"
}
}

View File

@ -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",

View File

@ -46,14 +46,14 @@ const topItems = (
{
label: 'Home',
icon: <House4 />,
route: BusterRoutes.APP_HOME,
route: createBusterRoute({ route: BusterRoutes.APP_HOME }),
id: BusterRoutes.APP_HOME,
active: currentParentRoute === BusterRoutes.APP_HOME
},
{
label: 'Chat history',
icon: <ASSET_ICONS.chats />,
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: <ASSET_ICONS.metrics />,
route: BusterRoutes.APP_METRIC,
route: createBusterRoute({ route: BusterRoutes.APP_METRIC }),
id: BusterRoutes.APP_METRIC,
active: isActiveCheck('metric', BusterRoutes.APP_METRIC)
},
{
label: 'Dashboards',
icon: <ASSET_ICONS.dashboards />,
route: BusterRoutes.APP_DASHBOARDS,
route: createBusterRoute({ route: BusterRoutes.APP_DASHBOARDS }),
id: BusterRoutes.APP_DASHBOARDS,
active: isActiveCheck('dashboard', BusterRoutes.APP_DASHBOARDS)
},
{
label: 'Collections',
icon: <ASSET_ICONS.collections />,
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: <UnorderedList2 />,
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: <Table />,
route: BusterRoutes.APP_DATASETS,
route: createBusterRoute({ route: BusterRoutes.APP_DATASETS }),
id: BusterRoutes.APP_DATASETS,
collapsedTooltip: 'Datasets'
}

View File

@ -40,10 +40,11 @@ export const DashboardContentController: React.FC<{
metrics = DEFAULT_EMPTY_METRICS,
onUpdateDashboardConfig
}) => {
const [draggingId, setDraggingId] = useState<string | null>(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<string | null>(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}
/>
)
};

View File

@ -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);

View File

@ -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);

View File

@ -32,6 +32,8 @@ const MetricSegments: React.FC<FileContainerSegmentProps> = 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<FileView>[] = React.useMemo(() => {
@ -44,6 +46,8 @@ const MetricSegments: React.FC<FileContainerSegmentProps> = React.memo(
chatId,
dashboardId,
assetId: metricId,
metricVersionNumber: metricVersionNumber,
dashboardVersionNumber,
type: 'metric'
})
},
@ -55,6 +59,8 @@ const MetricSegments: React.FC<FileContainerSegmentProps> = React.memo(
chatId,
dashboardId,
assetId: metricId,
metricVersionNumber,
dashboardVersionNumber,
type: 'metric'
})
},
@ -66,11 +72,13 @@ const MetricSegments: React.FC<FileContainerSegmentProps> = React.memo(
chatId,
dashboardId,
assetId: metricId,
metricVersionNumber,
dashboardVersionNumber,
type: 'metric'
})
}
];
}, [chatId, error, metricId, dashboardId]);
}, [chatId, error, metricId, dashboardId, metricVersionNumber, dashboardVersionNumber]);
return <AppSegmented type="button" options={segmentOptions} value={selectedFileView} />;
}

View File

@ -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'
});

View File

@ -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<UnionOfFileTypes, 'metric' | 'dashboard'>;
@ -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
});

View File

@ -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'
);
});
});
});

View File

@ -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<DashboardRouteParams, 'type'>) => {
const baseParams = { dashboardVersionNumber, dashboardId, secondaryView };
const dashboardVersionNumber = _dashboardVersionNumber || versionNumber;
const baseParams = { dashboardVersionNumber, dashboardId, secondaryView, metricVersionNumber };
if (page === 'dashboard') {
if (chatId) {

View File

@ -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<MetricRouteParams, 'type'>) => {
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)

View File

@ -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;

View File

@ -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