diff --git a/apps/web-tss/src/components/features/ShareMenu/AccessDropdown.tsx b/apps/web-tss/src/components/features/ShareMenu/AccessDropdown.tsx index 0eeedc125..5bf6e0ed6 100644 --- a/apps/web-tss/src/components/features/ShareMenu/AccessDropdown.tsx +++ b/apps/web-tss/src/components/features/ShareMenu/AccessDropdown.tsx @@ -1,7 +1,7 @@ import type { ShareAssetType, ShareRole, WorkspaceShareRole } from '@buster/server-shared/share'; import last from 'lodash/last'; import React, { useMemo } from 'react'; -import type { DropdownItem } from '@/components/ui/dropdown'; +import type { IDropdownItem } from '@/components/ui/dropdown'; import { Dropdown } from '@/components/ui/dropdown'; import { ChevronDown } from '@/components/ui/icons/NucleoIconFilled'; import { Paragraph, Text } from '@/components/ui/typography'; @@ -39,7 +39,7 @@ export const AccessDropdown: React.FC = React.memo( const items = useMemo(() => { const isWorkspace = props.type === 'workspace'; - const baseItems: DropdownItem[] = [ + const baseItems: IDropdownItem[] = [ ...(isWorkspace ? workspaceItems : itemsRecord[assetType] || []), ]; @@ -133,7 +133,7 @@ export const AccessDropdown: React.FC = React.memo( AccessDropdown.displayName = 'AccessDropdown'; -const metricItems: DropdownItem[] = [ +const metricItems: IDropdownItem[] = [ { value: 'full_access', label: 'Full access', @@ -151,7 +151,7 @@ const metricItems: DropdownItem[] = [ }, ]; -const dashboardItems: DropdownItem[] = [ +const dashboardItems: IDropdownItem[] = [ { value: 'full_access', label: 'Full access', @@ -169,7 +169,7 @@ const dashboardItems: DropdownItem[] = [ }, ]; -const collectionItems: DropdownItem[] = [ +const collectionItems: IDropdownItem[] = [ { value: 'full_access', label: 'Full access', @@ -187,7 +187,7 @@ const collectionItems: DropdownItem[] = [ }, ]; -const reportItems: DropdownItem[] = [ +const reportItems: IDropdownItem[] = [ { value: 'full_access', label: 'Full access', @@ -205,7 +205,7 @@ const reportItems: DropdownItem[] = [ }, ]; -const workspaceItems: DropdownItem[] = [ +const workspaceItems: IDropdownItem[] = [ { value: 'full_access', label: 'Full access', @@ -228,7 +228,7 @@ const workspaceItems: DropdownItem[] = [ }, ]; -const itemsRecord: Record[]> = { +const itemsRecord: Record[]> = { dashboard: dashboardItems, metric: metricItems, collection: collectionItems, @@ -236,15 +236,15 @@ const itemsRecord: Record[]> = { report: reportItems, }; -const OWNER_ITEM: DropdownItem = { +const OWNER_ITEM: IDropdownItem = { value: 'owner', label: 'Owner', secondaryLabel: 'Owner of the asset.', }; -const WORKSPACE_NOT_SHARED_ITEM: DropdownItem = last( +const WORKSPACE_NOT_SHARED_ITEM: IDropdownItem = last( workspaceItems -) as DropdownItem; +) as IDropdownItem; const FooterContent = React.memo(() => { return ( diff --git a/apps/web-tss/src/components/features/ShareMenu/ShareMenuContentEmbed.tsx b/apps/web-tss/src/components/features/ShareMenu/ShareMenuContentEmbed.tsx index 39eebfbc3..2a454e721 100644 --- a/apps/web-tss/src/components/features/ShareMenu/ShareMenuContentEmbed.tsx +++ b/apps/web-tss/src/components/features/ShareMenu/ShareMenuContentEmbed.tsx @@ -8,40 +8,61 @@ import { Link } from '@/components/ui/icons'; import { Input } from '@/components/ui/inputs'; import { Text } from '@/components/ui/typography'; import { useBusterNotifications } from '@/context/BusterNotifications'; -import { useMemoizedFn } from '@/hooks'; import { cn } from '@/lib/classMerge'; -import { BusterRoutes, createBusterRoute } from '@/routes'; +import { useBuildLocation } from '../../../context/Routes/useRouteBuilder'; import type { ShareMenuContentBodyProps } from './ShareMenuContentBody'; export const ShareMenuContentEmbed: React.FC = React.memo( ({ className, assetType, assetId }) => { + const buildLocation = useBuildLocation(); const { openSuccessMessage } = useBusterNotifications(); const embedURL = useMemo(() => { - let url = ''; - if (assetType === 'metric') { - url = createBusterRoute({ - route: BusterRoutes.EMBED_METRIC_ID, - metricId: assetId, - }); + return buildLocation({ + to: '/embed/metric/$metricId', + params: { + metricId: assetId, + }, + }).href; } if (assetType === 'dashboard') { - url = createBusterRoute({ - route: BusterRoutes.EMBED_DASHBOARD_ID, - dashboardId: assetId, - }); + return buildLocation({ + to: '/embed/dashboard/$dashboardId', + params: { + dashboardId: assetId, + }, + }).href; } - return url; - }, [assetType, assetId]); + if (assetType === 'report') { + return buildLocation({ + to: '/embed/report/$reportId', + params: { + reportId: assetId, + }, + }).href; + } - const onCopyLink = useMemoizedFn(() => { + if (assetType === 'chat') { + return ''; + } + + if (assetType === 'collection') { + return ''; + } + + const _exhaustiveCheck: never = assetType; + + return ''; + }, [assetType, assetId, buildLocation]); + + const onCopyLink = () => { const url = window.location.origin + embedURL; navigator.clipboard.writeText(url); openSuccessMessage('Link copied to clipboard'); - }); + }; return (
@@ -73,7 +94,7 @@ export const ShareMenuContentEmbedFooter = ({ const { mutateAsync: onShareCollection } = useUpdateCollectionShare(); const { openSuccessMessage } = useBusterNotifications(); - const onPublish = useMemoizedFn(async () => { + const onPublish = async () => { const payload: Parameters[0] = { id: assetId, params: { @@ -88,7 +109,7 @@ export const ShareMenuContentEmbedFooter = ({ await onShareCollection(payload); } openSuccessMessage('Succuessfully published'); - }); + }; return (
diff --git a/apps/web-tss/src/components/features/ShareMenu/ShareMenuTopBar.tsx b/apps/web-tss/src/components/features/ShareMenu/ShareMenuTopBar.tsx index 1b5efd4d4..8c4f2ec70 100644 --- a/apps/web-tss/src/components/features/ShareMenu/ShareMenuTopBar.tsx +++ b/apps/web-tss/src/components/features/ShareMenu/ShareMenuTopBar.tsx @@ -2,7 +2,6 @@ import type { ShareAssetType } from '@buster/server-shared/share'; import React, { useMemo } from 'react'; import type { SegmentedItem } from '@/components/ui/segmented'; import { AppSegmented } from '@/components/ui/segmented'; -import { useMemoizedFn } from '@/hooks'; import { CopyLinkButton } from './CopyLinkButton'; export enum ShareMenuTopBarOptions { @@ -41,9 +40,9 @@ export const ShareMenuTopBar: React.FC<{ .map((o) => ({ ...o, show: undefined })); }, [assetType, canEditPermissions]); - const onChange = useMemoizedFn((v: SegmentedItem) => { + const onChange = (v: SegmentedItem) => { onChangeSelectedOption(v.value); - }); + }; return (
diff --git a/apps/web-tss/src/components/features/ShareMenu/WorkspaceAvatar.stories.tsx b/apps/web-tss/src/components/features/ShareMenu/WorkspaceAvatar.stories.tsx index a18c719a0..3879e894d 100644 --- a/apps/web-tss/src/components/features/ShareMenu/WorkspaceAvatar.stories.tsx +++ b/apps/web-tss/src/components/features/ShareMenu/WorkspaceAvatar.stories.tsx @@ -1,4 +1,4 @@ -import type { Meta, StoryObj } from '@storybook/nextjs'; +import type { Meta, StoryObj } from '@storybook/react-vite'; import { WorkspaceAvatar } from './WorkspaceAvatar'; const meta: Meta = { diff --git a/apps/web-tss/src/components/features/metrics/StatusBadgeIndicator/useStatusDropdownContent.tsx b/apps/web-tss/src/components/features/metrics/StatusBadgeIndicator/useStatusDropdownContent.tsx index 535231900..f85300210 100644 --- a/apps/web-tss/src/components/features/metrics/StatusBadgeIndicator/useStatusDropdownContent.tsx +++ b/apps/web-tss/src/components/features/metrics/StatusBadgeIndicator/useStatusDropdownContent.tsx @@ -1,6 +1,6 @@ import type { VerificationStatus } from '@buster/server-shared/share'; import { useMemo } from 'react'; -import type { DropdownItem, DropdownProps } from '@/components/ui/dropdown'; +import type { DropdownProps, IDropdownItem } from '@/components/ui/dropdown'; import { getTooltipText } from './helpers'; import { StatusBadgeIndicator } from './StatusBadgeIndicator'; @@ -27,7 +27,7 @@ export const useStatusDropdownContent = ({ 'showIndex' | 'items' | 'emptyStateText' | 'menuHeader' | 'selectType' > => { const items = useMemo(() => { - return statuses.map>((status) => { + return statuses.map>((status) => { const requiresAdmin = requiresAdminItems.includes(status); return { label: getTooltipText(status), diff --git a/apps/web-tss/src/components/features/metrics/ThreeDotMenu.tsx b/apps/web-tss/src/components/features/metrics/ThreeDotMenu.tsx index 4c3a4d804..5851ac657 100644 --- a/apps/web-tss/src/components/features/metrics/ThreeDotMenu.tsx +++ b/apps/web-tss/src/components/features/metrics/ThreeDotMenu.tsx @@ -1,6 +1,6 @@ import React, { useMemo } from 'react'; import { useGetMetric } from '@/api/buster_rest/metrics'; -import { DropdownContent, type IDropdownItem } from '@/components/ui/dropdown'; +import { DropdownContent, type IDropdownItem, type IDropdownItems } from '@/components/ui/dropdown'; import { History, Star, WandSparkle } from '@/components/ui/icons'; import { Star as StarFilled } from '@/components/ui/icons/NucleoIconFilled'; import { FollowUpWithAssetContent } from '../assets/FollowUpWithAsset'; @@ -51,7 +51,7 @@ export const useFavoriteMetricSelectMenu = ({ metricId }: { metricId: string }) name: name || '', }); - const item: DropdownItem = useMemo( + const item: IDropdownItem = useMemo( () => ({ label: isFavorited ? 'Remove from favorites' : 'Add to favorites', value: 'add-to-favorites', @@ -65,7 +65,7 @@ export const useFavoriteMetricSelectMenu = ({ metricId }: { metricId: string }) return item; }; -export const useMetricDrilldownItem = ({ metricId }: { metricId: string }): DropdownItem => { +export const useMetricDrilldownItem = ({ metricId }: { metricId: string }): IDropdownItem => { return useMemo( () => ({ value: 'drilldown', diff --git a/apps/web-tss/src/components/features/sidebars/SidebarPrimary/getFavoriteRoute.ts b/apps/web-tss/src/components/features/sidebars/SidebarPrimary/getFavoriteRoute.ts index 1abcabea4..a87835fa0 100644 --- a/apps/web-tss/src/components/features/sidebars/SidebarPrimary/getFavoriteRoute.ts +++ b/apps/web-tss/src/components/features/sidebars/SidebarPrimary/getFavoriteRoute.ts @@ -1,45 +1,53 @@ import type { UserFavorite } from '@buster/server-shared/user'; -import type { OptionsTo } from '@/types/routes'; +import type { RegisteredRouter } from '@tanstack/react-router'; +import { defineLink } from '@/lib/routes'; -export const getFavoriteRoute = (favorite: Pick): OptionsTo => { +export const getFavoriteRoute = < + TRouter extends RegisteredRouter = RegisteredRouter, + TOptions = unknown, + TFrom extends string = string, +>( + favorite: Pick +) => { if (favorite.asset_type === 'chat') { - return { + return defineLink({ to: '/app/chats/$chatId', - params: { chatId: favorite.id }, - } as const satisfies OptionsTo; + params: { chatId: '123' }, + }); } if (favorite.asset_type === 'metric') { - return { + return defineLink({ to: '/app/metrics/$metricId', params: { metricId: favorite.id }, - } as const satisfies OptionsTo; + }); } if (favorite.asset_type === 'dashboard') { - return { + return defineLink({ to: '/app/dashboards/$dashboardId', params: { dashboardId: favorite.id }, - } as const satisfies OptionsTo; + }); } if (favorite.asset_type === 'collection') { - return { + return defineLink({ to: '/app/collections/$collectionId', params: { collectionId: favorite.id }, - } as const satisfies OptionsTo; + }); } if (favorite.asset_type === 'report') { - return { + return defineLink({ to: '/app/reports/$reportId', params: { reportId: favorite.id }, - } as const satisfies OptionsTo; + }); } const _exhaustiveCheck: never = favorite.asset_type; - return { + + return defineLink({ to: '/app/chats/$chatId', params: { chatId: favorite.id }, - } as const satisfies OptionsTo; + }); }; diff --git a/apps/web-tss/src/components/features/sidebars/SidebarPrimary/useFavoritesSidebarPanel.tsx b/apps/web-tss/src/components/features/sidebars/SidebarPrimary/useFavoritesSidebarPanel.tsx index 6f9a4100e..064d35890 100644 --- a/apps/web-tss/src/components/features/sidebars/SidebarPrimary/useFavoritesSidebarPanel.tsx +++ b/apps/web-tss/src/components/features/sidebars/SidebarPrimary/useFavoritesSidebarPanel.tsx @@ -1,4 +1,4 @@ -import { type LinkProps, useMatchRoute } from '@tanstack/react-router'; +import { useMatchRoute } from '@tanstack/react-router'; import { useMemo } from 'react'; import { useDeleteUserFavorite, @@ -6,9 +6,11 @@ import { useUpdateUserFavorites, } from '@/api/buster_rest/users'; import { assetTypeToIcon } from '@/components/features/icons/assetIcons'; -import type { ISidebarGroup, ISidebarItem } from '@/components/ui/sidebar'; +import type { ISidebarGroup } from '@/components/ui/sidebar'; import { useMount } from '@/hooks/useMount'; import { assetParamsToRoute } from '@/lib/assets/assetParamsToRoute'; + +import { createSidebarItem } from '../../../ui/sidebar/create-sidebar-item'; import { getFavoriteRoute } from './getFavoriteRoute'; export const useFavoriteSidebarPanel = (): ISidebarGroup | null => { @@ -29,18 +31,17 @@ export const useFavoriteSidebarPanel = (): ISidebarGroup | null => { id: 'favorites', isSortable: true, onItemsReorder: updateUserFavorites, - items: favorites.map((favorite) => { + items: favorites.map((favorite) => { const Icon = assetTypeToIcon(favorite.asset_type); - const route = getFavoriteRoute(favorite); - // const isActive = !!matcher({ ...route, fuzzy: true } as Parameters[0]); - return { + const link = getFavoriteRoute(favorite); + + return createSidebarItem({ label: favorite.name, icon: , - route, + link, id: favorite.id, - preload: 'intent', onRemove: () => deleteUserFavorite([favorite.id]), - }; + }); }), } satisfies ISidebarGroup; }, [favorites, matcher, deleteUserFavorite]); diff --git a/apps/web-tss/src/components/features/versionHistory/VersionHistoryPanel.tsx b/apps/web-tss/src/components/features/versionHistory/VersionHistoryPanel.tsx index 232269734..dcf455169 100644 --- a/apps/web-tss/src/components/features/versionHistory/VersionHistoryPanel.tsx +++ b/apps/web-tss/src/components/features/versionHistory/VersionHistoryPanel.tsx @@ -1,35 +1,31 @@ -import Link from 'next/link'; +import { Link } from '@tanstack/react-router'; import React, { useCallback, useMemo, useRef } from 'react'; import { Button } from '@/components/ui/buttons'; import { History, Xmark } from '@/components/ui/icons'; -import { Check3 } from '@/components/ui/icons/NucleoIconFilled'; -import { AppPageLayout } from '@/components/ui/layouts'; +import Check3 from '@/components/ui/icons/NucleoIconFilled/check-3'; +import { AppPageLayout } from '@/components/ui/layouts/AppPageLayout'; import { CircleSpinnerLoader } from '@/components/ui/loaders'; import { AppTooltip } from '@/components/ui/tooltip'; import { Text } from '@/components/ui/typography'; -import { useGetFileLink } from '@/context/Assets/useGetFileLink'; -import { useMemoizedFn, useMount } from '@/hooks'; -import { useChatLayoutContextSelector } from '@/layouts/ChatLayout'; -import { useCloseVersionHistory } from '@/layouts/ChatLayout/FileContainer/FileContainerHeader/FileContainerHeaderVersionHistory'; -import { timeFromNow, timeout } from '@/lib'; +import { useMemoizedFn } from '@/hooks/useMemoizedFn'; +import { useMount } from '@/hooks/useMount'; import { cn } from '@/lib/classMerge'; -import { useListVersionHistories } from './useListVersionHistories'; +import { timeFromNow } from '@/lib/date'; +import { timeout } from '@/lib/timeout'; export const VersionHistoryPanel = React.memo( ({ assetId, type }: { assetId: string; type: 'metric' | 'dashboard' }) => { - const chatId = useChatLayoutContextSelector((x) => x.chatId); - const { - listItems, - onPrefetchAsset, - restoringVersion, - currentVersionNumber, - selectedQueryVersion, - onClickRestoreVersion, - } = useListVersionHistories({ - assetId, - type, - }); - const { getFileLink } = useGetFileLink(); + // const { + // listItems, + // onPrefetchAsset, + // restoringVersion, + // currentVersionNumber, + // selectedQueryVersion, + // onClickRestoreVersion, + // } = useListVersionHistories({ + // assetId, + // type, + // }); const bodyRef = useRef(null); @@ -51,7 +47,8 @@ export const VersionHistoryPanel = React.memo( headerBorderVariant="ghost" >
- {listItems?.map((item) => ( + TODO + {/* {listItems?.map((item) => ( - ))} + ))} */}
); } ); -const ListItem = React.memo( - ({ - version_number, - updated_at, - selected, - showRestoreButton, - link, - restoringVersion, - onClickRestoreVersion, - onPrefetchAsset, - }: { - version_number: number; - updated_at: string; - selected: boolean; - showRestoreButton: boolean; - restoringVersion: number | null; - onClickRestoreVersion: (versionNumber: number) => void; - onPrefetchAsset: (versionNumber: number, link: string) => Promise; - link: string; - }) => { - const routePrefetchTimeoutRef = useRef(); +// const ListItem = React.memo( +// ({ +// version_number, +// updated_at, +// selected, +// showRestoreButton, +// link, +// restoringVersion, +// onClickRestoreVersion, +// onPrefetchAsset, +// }: { +// version_number: number; +// updated_at: string; +// selected: boolean; +// showRestoreButton: boolean; +// restoringVersion: number | null; +// onClickRestoreVersion: (versionNumber: number) => void; +// onPrefetchAsset: (versionNumber: number, link: string) => Promise; +// link: string; +// }) => { +// const routePrefetchTimeoutRef = useRef(null); - const onHoverLink = useMemoizedFn(() => { - // Prefetch route after 50ms - routePrefetchTimeoutRef.current = setTimeout(() => { - onPrefetchAsset(version_number, link); - }, 125); - }); +// const onHoverLink = useMemoizedFn(() => { +// // Prefetch route after 50ms +// routePrefetchTimeoutRef.current = setTimeout(() => { +// onPrefetchAsset(version_number, link); +// }, 125); +// }); - const onHoverEnd = useCallback(() => { - if (routePrefetchTimeoutRef.current) { - clearTimeout(routePrefetchTimeoutRef.current); - } - }, []); +// const onHoverEnd = useCallback(() => { +// if (routePrefetchTimeoutRef.current) { +// clearTimeout(routePrefetchTimeoutRef.current); +// } +// }, []); - const isRestoringVersion = restoringVersion === version_number; +// const isRestoringVersion = restoringVersion === version_number; - return ( - -
-
- {`Version ${version_number}`} - - {timeFromNow(updated_at, false)} - -
+// return ( +// +//
+//
+// {`Version ${version_number}`} +// +// {timeFromNow(updated_at, false)} +// +//
-
- {showRestoreButton && ( - - - - )} +// e.stopPropagation(); +// e.preventDefault(); +// onClickRestoreVersion(version_number); +// }} +// className={cn( +// 'hover:bg-gray-light/20 hover:text-foreground -mr-1 cursor-pointer rounded p-1 opacity-0 group-hover:block group-hover:opacity-100', +// isRestoringVersion && 'cursor-not-allowed opacity-100!' +// )} +// > +// {isRestoringVersion ? : } +// +// +// )} - {selected && ( -
- -
- )} -
-
- - ); - } -); -ListItem.displayName = 'ListItem'; +// {selected && ( +//
+// +//
+// )} +//
+//
+// +// ); +// } +// ); +// ListItem.displayName = 'ListItem'; const PanelHeader = React.memo(() => { - const { href } = useCloseVersionHistory(); - return (
Version history - + {/*
); }); diff --git a/apps/web-tss/src/components/features/versionHistory/index.ts b/apps/web-tss/src/components/features/versionHistory/index.ts index ea18ce5e3..aa4fbfead 100644 --- a/apps/web-tss/src/components/features/versionHistory/index.ts +++ b/apps/web-tss/src/components/features/versionHistory/index.ts @@ -1,2 +1 @@ -export * from './useListVersionHistories'; export * from './VersionHistoryPanel'; diff --git a/apps/web-tss/src/components/ui/breadcrumb/Breadcrumb.stories.tsx b/apps/web-tss/src/components/ui/breadcrumb/Breadcrumb.stories.tsx index 3c67f5406..77ee562e8 100644 --- a/apps/web-tss/src/components/ui/breadcrumb/Breadcrumb.stories.tsx +++ b/apps/web-tss/src/components/ui/breadcrumb/Breadcrumb.stories.tsx @@ -1,5 +1,6 @@ import type { Meta, StoryObj } from '@storybook/react-vite'; import { Breadcrumb } from './Breadcrumb'; +import { createBreadcrumbItem } from './create-breadcrumb'; const meta: Meta = { title: 'UI/Breadcrumb', @@ -16,8 +17,8 @@ type Story = StoryObj; export const Default: Story = { args: { items: [ - { label: 'Home', route: { to: '/app/home' } }, - { label: 'Datasets', route: { to: '/app/datasets' } }, + { label: 'Home', link: { to: '/app/home' } }, + { label: 'Datasets', link: { to: '/app/datasets' } }, { label: 'Current Dataset' }, ], }, @@ -26,13 +27,13 @@ export const Default: Story = { export const WithDropdown: Story = { args: { items: [ - { label: 'Home', route: { to: '/app/home' } }, + { label: 'Home', link: { to: '/app/home' } }, { label: null, dropdown: [ - { label: 'Dataset A', route: { to: '/app/datasets' } }, - { label: 'Dataset B', route: { to: '/app/datasets' } }, - { label: 'Dataset C', route: { to: '/app/datasets' } }, + { label: 'Dataset A', link: { to: '/app/datasets' } }, + { label: 'Dataset B', link: { to: '/app/datasets' } }, + { label: 'Dataset C', link: { to: '/app/datasets' } }, ], }, { label: 'Current Dataset' }, @@ -43,9 +44,12 @@ export const WithDropdown: Story = { export const CustomActiveIndex: Story = { args: { items: [ - { label: 'Home', route: { to: '/app/home' } }, - { label: 'Datasets', route: { to: '/app/datasets' } }, - { label: 'Settings', route: { to: '/app/chats/$chatId', params: { chatId: '123' } } }, + { label: 'Home', link: { to: '/app/home' } }, + { label: 'Datasets', link: { to: '/app/datasets' } }, + createBreadcrumbItem({ + label: 'Settings', + link: { to: '/app/chats/$chatId', params: { chatId: '123' } }, + }), { label: 'Profile' }, ], activeIndex: 2, diff --git a/apps/web-tss/src/components/ui/buttons/BackButton.tsx b/apps/web-tss/src/components/ui/buttons/BackButton.tsx index 6b71dd514..4dc476c67 100644 --- a/apps/web-tss/src/components/ui/buttons/BackButton.tsx +++ b/apps/web-tss/src/components/ui/buttons/BackButton.tsx @@ -1,7 +1,7 @@ import { Link, type LinkProps } from '@tanstack/react-router'; import * as React from 'react'; import { cn } from '@/lib/classMerge'; -import type { OptionsTo } from '@/types/routes'; +import type { ILinkProps } from '@/types/routes'; import { ChevronLeft } from '../icons'; import { Button } from './Button'; @@ -11,7 +11,7 @@ interface BackButtonProps { size?: 'medium' | 'large'; className?: string; style?: React.CSSProperties; - linkUrl?: OptionsTo; + linkUrl?: ILinkProps; activeProps?: LinkProps['activeProps']; activeOptions?: LinkProps['activeOptions']; } diff --git a/apps/web-tss/src/components/ui/dropdown/Dropdown.stories.tsx b/apps/web-tss/src/components/ui/dropdown/Dropdown.stories.tsx index b8d8b8a09..f6b86b6f9 100644 --- a/apps/web-tss/src/components/ui/dropdown/Dropdown.stories.tsx +++ b/apps/web-tss/src/components/ui/dropdown/Dropdown.stories.tsx @@ -6,7 +6,8 @@ import React from 'react'; import { fn } from 'storybook/test'; import { Button } from '../buttons/Button'; import { PaintRoller, Star, Storage } from '../icons'; -import { Dropdown, type DropdownItems } from './Dropdown'; +import { Dropdown } from './Dropdown'; +import type { IDropdownItems } from './dropdown-items.types'; const meta: Meta = { title: 'UI/Dropdowns/Dropdown', @@ -249,7 +250,7 @@ export const WithSelectionMultiple: Story = { render: () => { const [selectedIds, setSelectedIds] = React.useState>(new Set(['3'])); - const items: DropdownItems = [ + const items: IDropdownItems = [ { value: '1', label: 'Option 1', @@ -464,7 +465,7 @@ export const WithLinksAndMultipleSelection: Story = { render: () => { const [selectedIds, setSelectedIds] = React.useState>(new Set(['2'])); - const items: DropdownItems = [ + const items: IDropdownItems = [ { value: '1', label: 'Documentation Home', diff --git a/apps/web-tss/src/components/ui/list/BusterList/BusterListRowComponent.tsx b/apps/web-tss/src/components/ui/list/BusterList/BusterListRowComponent.tsx index 78398c995..704d5601b 100644 --- a/apps/web-tss/src/components/ui/list/BusterList/BusterListRowComponent.tsx +++ b/apps/web-tss/src/components/ui/list/BusterList/BusterListRowComponent.tsx @@ -3,7 +3,7 @@ import get from 'lodash/get'; import React, { useMemo } from 'react'; import { useMemoizedFn } from '@/hooks/useMemoizedFn'; import { cn } from '@/lib/classMerge'; -import type { OptionsTo } from '@/types/routes'; +import type { ILinkProps } from '@/types/routes'; import { CheckboxColumn } from './CheckboxColumn'; import { HEIGHT_OF_ROW } from './config'; import type { BusterListColumn, BusterListProps, BusterListRowItem } from './interfaces'; @@ -160,7 +160,7 @@ const BusterListCellComponent = ({ const LinkWrapper: React.FC< { - link?: OptionsTo; + link?: ILinkProps; children: React.ReactNode; } & LinkProps > = ({ link, children, preload, preloadDelay, activeOptions }) => { diff --git a/apps/web-tss/src/components/ui/list/ListEmptyStateWithButton.tsx b/apps/web-tss/src/components/ui/list/ListEmptyStateWithButton.tsx index 473f942c9..770ed3449 100644 --- a/apps/web-tss/src/components/ui/list/ListEmptyStateWithButton.tsx +++ b/apps/web-tss/src/components/ui/list/ListEmptyStateWithButton.tsx @@ -3,7 +3,7 @@ import React from 'react'; import { Button } from '@/components/ui/buttons'; import { Plus } from '@/components/ui/icons'; import { Paragraph, Title } from '@/components/ui/typography'; -import type { OptionsTo } from '@/types/routes'; +import type { ILinkProps } from '@/types/routes'; export const ListEmptyStateWithButton: React.FC<{ isAdmin?: boolean; @@ -14,7 +14,7 @@ export const ListEmptyStateWithButton: React.FC<{ buttonPrefix?: React.ReactNode; buttonSuffix?: React.ReactNode; loading?: boolean; - link?: OptionsTo | string; + link?: ILinkProps | string; linkButtonTarget?: '_blank' | '_self'; }> = React.memo( ({ @@ -66,7 +66,7 @@ export const ListEmptyStateWithButton: React.FC<{ const ButtonWrapper: React.FC<{ children: React.ReactNode; - link?: OptionsTo | string; + link?: ILinkProps | string; target?: '_blank' | '_self'; }> = ({ children, link, target }) => { if (!link) return <>{children}; diff --git a/apps/web-tss/src/components/ui/sidebar/create-sidebar-item.ts b/apps/web-tss/src/components/ui/sidebar/create-sidebar-item.ts index 8f5e5db3a..e6fc6621b 100644 --- a/apps/web-tss/src/components/ui/sidebar/create-sidebar-item.ts +++ b/apps/web-tss/src/components/ui/sidebar/create-sidebar-item.ts @@ -1,14 +1,13 @@ import type { RegisteredRouter } from '@tanstack/react-router'; +import { defineLink } from '../../../lib/routes'; import type { ISidebarGroup, ISidebarItem, ISidebarList } from './interfaces'; export function createSidebarItem< TRouter extends RegisteredRouter, TOptions, TFrom extends string = string, ->( - item: ISidebarItem & { show?: boolean } -): ISidebarItem & { show?: boolean } { - return item; +>(item: ISidebarItem & { show?: boolean }) { + return item as ISidebarItem & { show?: boolean }; } /** @@ -40,3 +39,21 @@ export function createSidebarGroup< >(items: ISidebarGroup): ISidebarGroup { return items; } + +const test = createSidebarItem({ + label: 'Test', + id: '123', + link: { + to: '/app/chats/$chatId', + params: { chatId: '123' }, + }, +}); + +const test123 = createSidebarItem({ + label: 'Test', + id: '123', + link: defineLink({ + to: '/app/chats/$chatId', + params: { chatId: '123' }, + }), +}); diff --git a/apps/web-tss/src/components/ui/sidebar/interfaces.ts b/apps/web-tss/src/components/ui/sidebar/interfaces.ts index 3b77404fc..558bebbb4 100644 --- a/apps/web-tss/src/components/ui/sidebar/interfaces.ts +++ b/apps/web-tss/src/components/ui/sidebar/interfaces.ts @@ -1,6 +1,6 @@ -import type { RegisteredRouter, ValidateLinkOptions } from '@tanstack/react-router'; +import type { RegisteredRouter } from '@tanstack/react-router'; import type React from 'react'; -import type { ILinkOptions } from '@/types/routes'; +import type { ILinkProps } from '@/types/routes'; // Base properties shared by all sidebar items type ISidebarItemBase = { @@ -22,7 +22,7 @@ export type ISidebarItem< > = ISidebarItemBase & ( | { - link: ValidateLinkOptions & ILinkOptions; + link: ILinkProps; } | { link?: never; diff --git a/apps/web-tss/src/lib/routes/index.ts b/apps/web-tss/src/lib/routes/index.ts index fe173d827..c13e45e41 100644 --- a/apps/web-tss/src/lib/routes/index.ts +++ b/apps/web-tss/src/lib/routes/index.ts @@ -1,12 +1,11 @@ import type { RegisteredRouter, ValidateLinkOptions } from '@tanstack/react-router'; +import type { ILinkProps } from '@/types/routes'; export function defineLink< TRouter extends RegisteredRouter, TOptions, TFrom extends string = string, ->( - link: ValidateLinkOptions -): ValidateLinkOptions { +>(link: ILinkProps): ILinkProps { return link; }