link options update

This commit is contained in:
Nate Kelley 2025-08-19 11:11:57 -06:00
parent 9c09a22c74
commit 26108e8029
No known key found for this signature in database
GPG Key ID: FD90372AB8D98B4F
9 changed files with 126 additions and 91 deletions

View File

@ -49,22 +49,21 @@ const topItems: ISidebarList = {
{
label: 'Home',
icon: <House4 />,
route: { to: '/app/home' },
route: { to: '/app/home', preload: 'viewport', preloadDelay: 1000 },
id: '/app/home',
preload: 'viewport',
preloadDelay: 1000,
},
{
label: 'Chat history',
icon: <ASSET_ICONS.chats />,
route: { to: '/app/chats' },
id: '/app/chats/',
preload: 'viewport',
preloadDelay: 2000,
activeOptions: {
exact: true,
route: {
to: '/app/chats',
preload: 'viewport',
preloadDelay: 2000,
activeOptions: {
exact: true,
},
},
activeProps: {},
id: '/app/chats/',
},
],
};
@ -76,33 +75,26 @@ const yourStuff: ISidebarGroup = {
{
label: 'Metrics',
icon: <ASSET_ICONS.metrics />,
route: { to: '/app/metrics' },
route: { to: '/app/metrics', preload: 'intent', preloadDelay: 1000 },
id: '/app/metrics',
preload: 'intent',
preloadDelay: 1000,
},
{
label: 'Dashboards',
icon: <ASSET_ICONS.dashboards />,
route: { to: '/app/dashboards' },
route: { to: '/app/dashboards', preload: 'intent', preloadDelay: 1000 },
id: '/app/dashboards/',
preload: 'intent',
preloadDelay: 1000,
},
{
label: 'Collections',
icon: <ASSET_ICONS.collections />,
route: { to: '/app/collections' },
route: { to: '/app/collections', preload: 'intent', preloadDelay: 1000 },
id: '/app/collections/',
preload: 'intent',
preloadDelay: 1000,
},
{
label: 'Reports',
icon: <ASSET_ICONS.reports />,
route: { to: '/app/reports' },
route: { to: '/app/reports', preload: 'intent', preloadDelay: 1000 },
id: '/app/reports/',
preload: 'intent',
},
] satisfies (ISidebarItem & { show?: boolean })[],
};
@ -114,10 +106,9 @@ const adminTools: ISidebarGroup = {
{
label: 'Logs',
icon: <UnorderedList2 />,
route: { to: '/app/logs' },
route: { to: '/app/logs', preload: 'viewport', preloadDelay: 1000 },
id: '/app/logs/',
collapsedTooltip: 'Logs',
preload: 'viewport',
},
{
label: 'Datasets',

View File

@ -1,4 +1,4 @@
import { useMatchRoute } from '@tanstack/react-router';
import { type LinkProps, useMatchRoute } from '@tanstack/react-router';
import { useMemo } from 'react';
import {
useDeleteUserFavorite,

View File

@ -1,6 +1,11 @@
import type { ActiveOptions, LinkProps } from '@tanstack/react-router';
import type {
ActiveOptions,
LinkProps,
RegisteredRouter,
ValidateLinkOptions,
} from '@tanstack/react-router';
import type React from 'react';
import type { OptionsTo } from '@/types/routes';
import type { LinkOptionsTo, OptionsTo } from '@/types/routes';
// Base properties shared by all sidebar items
type ISidebarItemBase = {
@ -15,15 +20,13 @@ type ISidebarItemBase = {
};
// Discriminated union: either has a route (with optional activeOptions) or no route at all
export type ISidebarItem = ISidebarItemBase &
export type ISidebarItem<
TRouter extends RegisteredRouter = RegisteredRouter,
TOptions = unknown,
> = ISidebarItemBase &
(
| {
route: OptionsTo;
preload?: LinkProps['preload'];
preloadDelay?: LinkProps['preloadDelay'];
activeProps?: LinkProps['activeProps'];
preloadIntentProximity?: LinkProps['preloadIntentProximity'];
activeOptions?: ActiveOptions; // Only allowed when route is provided
route: LinkOptionsTo;
}
| {
route?: never;

View File

@ -1,13 +1,15 @@
import type { AssetType } from '@buster/server-shared/assets';
import type { QueryClient } from '@tanstack/react-query';
import {
BeforeLoadContextOptions,
type AnyRoute,
type BeforeLoadContextOptions,
type BeforeLoadContextParameter,
type BeforeLoadFn,
redirect,
} from '@tanstack/react-router';
import { z } from 'zod';
import { prefetchGetMetric } from '@/api/buster_rest/metrics';
import type { AppRouterContext } from '@/router';
import type { FileRouteTypes } from '@/routeTree.gen';
export const validateSearch = z.object({

View File

@ -1,4 +1,3 @@
import type { AssetType } from '@buster/server-shared/assets';
import type { FileRouteTypes } from '@/routeTree.gen';
import type { OptionsTo } from '@/types/routes';

View File

@ -1,54 +0,0 @@
import type { FileRouteTypes } from '@/routeTree.gen';
import type { OptionsTo, OptionsToBase } from '@/types/routes';
/**
* Creates a type-safe route object that can be passed to testNavigate
* This function helps ensure that route creation is type-safe
*
* @example
* const route = createRoute({
* to: '/app/chats/$chatId',
* params: {
* chatId: '123'
* }
* });
* testNavigate(route);
*
* @example
* // Use it in a function to return type-safe navigation options
* const createMyRoute = () => {
* return createRoute({
* to: '/app/chats/$chatId',
* params: {
* chatId: '123'
* }
* });
* };
*/
export function createRoute(options: OptionsTo): OptionsTo {
return options;
}
/**
* Factory function to create route builders for specific routes
* This provides even more type safety by locking in the route path
*
* @example
* const createChatRoute = createRouteFactory('/app/chats/$chatId');
* const route = createChatRoute({ chatId: '123' });
*/
export function createRouteFactory<
TTo extends FileRouteTypes['to'],
TFrom extends FileRouteTypes['to'] = '/',
>(to: TTo) {
return (
params: OptionsToBase<TFrom, TTo> extends { params: infer P } ? P : never,
options?: Omit<OptionsToBase<TFrom, TTo>, 'to' | 'params'>
): OptionsTo<TFrom, TTo> => {
return {
to,
params,
...options,
} as OptionsTo<TFrom, TTo>;
};
}

View File

@ -0,0 +1,75 @@
import {
Link,
type LinkProps,
type RegisteredRouter,
type ValidateLinkOptions,
} from '@tanstack/react-router';
import type { OptionsTo } from '@/types/routes';
/**
* Creates a type-safe route object that can be passed to testNavigate
* This function helps ensure that route creation is type-safe
*
* @example
* const route = createRoute({
* to: '/app/chats/$chatId',
* params: {
* chatId: '123'
* }
* });
* testNavigate(route);
*
* @example
* // Use it in a function to return type-safe navigation options
* const createMyRoute = () => {
* return createRoute({
* to: '/app/chats/$chatId',
* params: {
* chatId: '123'
* }
* });
* };
*/
export function createRoute(options: OptionsTo): OptionsTo {
return options;
}
//I am not super in love with this one. Tanstack has it in their docs..,
export function createLinkOptions<TOptions>(
options: ValidateLinkOptions<RegisteredRouter, TOptions>
) {
return options;
}
// function createLinkOptions<TOptions>(options: ValidateLinkOptions<RegisteredRouter, TOptions>) {
// return options;
// }
// function createLinkProps(options: LinkProps) {
// return options;
// }
// createRoute({
// to: '/app/chats/$chatId',
// params: { chatId: '123', reportId: '456' },
// });
// createLinkOptions({
// to: '/app/chats/$chatId',
// params: { chatId: '123', reportId: '456' },
// });
// createLinkProps({
// to: '/app/chats/$chatId',
// params: { reporhtId: '456' },
// });
// const TestComponent = () => {
// return (
// <Link to="/app/chats/$chatId" params={{ chatId: '123', reportId: '456' }}>
// <div>
// <h1>Test</h1>
// </div>
// </Link>
// );
// };

View File

@ -1,5 +1,5 @@
import type { FileRouteTypes } from '@/routeTree.gen';
import type { OptionsTo, OptionsToBase } from '@/types/routes';
import type { OptionsToBase } from '@/types/routes';
/**
* Converts navigation options to a URL string (href)

View File

@ -1,4 +1,9 @@
import type { NavigateOptions, RegisteredRouter } from '@tanstack/react-router';
import type {
LinkOptions,
LinkProps,
NavigateOptions,
RegisteredRouter,
} from '@tanstack/react-router';
import type { FileRouteTypes } from '@/routeTree.gen';
/**
@ -41,3 +46,17 @@ export type OptionsTo<
: { params?: never }) &
Omit<OptionsToBase<TFrom, K, TMaskFrom, TMaskTo>, 'to' | 'params'>;
}[FileRouteTypes['to']];
export type LinkOptionsTo = OptionsTo &
Pick<
LinkOptions,
| 'preload'
| 'preloadDelay'
| 'activeOptions'
| 'preloadIntentProximity'
| 'unsafeRelative'
| 'ignoreBlocker'
| 'disabled'
| 'reloadDocument'
| 'target'
>;