From 2f2e80e4b4a52115172a32822caf3604e7cc858b Mon Sep 17 00:00:00 2001 From: mbeaulne Date: Tue, 24 Mar 2026 15:50:30 -0400 Subject: [PATCH] Updates revently viewed --- src/hooks/useRecentlyViewed.ts | 23 ++++- .../Dashboard/DashboardRecentlyViewedView.tsx | 86 ++++++++++++++++++- 2 files changed, 106 insertions(+), 3 deletions(-) diff --git a/src/hooks/useRecentlyViewed.ts b/src/hooks/useRecentlyViewed.ts index 2e4d8bff5..a149dfbcd 100644 --- a/src/hooks/useRecentlyViewed.ts +++ b/src/hooks/useRecentlyViewed.ts @@ -1,11 +1,13 @@ +import { useEffect, useState } from "react"; + import { getStorage } from "@/utils/typedStorage"; const RECENTLY_VIEWED_KEY = "Home/recently_viewed"; -const MAX_ITEMS = 5; +const MAX_ITEMS = 10; type RecentlyViewedType = "pipeline" | "run" | "component"; -interface RecentlyViewedItem { +export interface RecentlyViewedItem { type: RecentlyViewedType; id: string; name: string; @@ -46,6 +48,23 @@ function readRecentlyViewed(): RecentlyViewedItem[] { return json ? parseRecentlyViewed(json) : []; } +export function useRecentlyViewed() { + const [recentlyViewed, setRecentlyViewed] = + useState(readRecentlyViewed); + + useEffect(() => { + const handleStorage = (e: StorageEvent) => { + if (e.key === RECENTLY_VIEWED_KEY) { + setRecentlyViewed(readRecentlyViewed()); + } + }; + window.addEventListener("storage", handleStorage); + return () => window.removeEventListener("storage", handleStorage); + }, []); + + return { recentlyViewed }; +} + export function addRecentlyViewed(item: Omit) { const current = readRecentlyViewed(); // Remove any existing entry for the same item, then prepend the fresh one diff --git a/src/routes/Dashboard/DashboardRecentlyViewedView.tsx b/src/routes/Dashboard/DashboardRecentlyViewedView.tsx index c5e97e96c..5ca966544 100644 --- a/src/routes/Dashboard/DashboardRecentlyViewedView.tsx +++ b/src/routes/Dashboard/DashboardRecentlyViewedView.tsx @@ -1,3 +1,87 @@ +import { Link } from "@tanstack/react-router"; + +import { Icon } from "@/components/ui/icon"; +import { BlockStack, InlineStack } from "@/components/ui/layout"; +import { Paragraph, Text } from "@/components/ui/typography"; +import { + type RecentlyViewedItem, + useRecentlyViewed, +} from "@/hooks/useRecentlyViewed"; +import { APP_ROUTES, EDITOR_PATH, RUNS_BASE_PATH } from "@/routes/router"; +import { formatRelativeTime } from "@/utils/date"; + +function getRecentlyViewedUrl(item: RecentlyViewedItem): string { + if (item.type === "pipeline") return `${EDITOR_PATH}/${item.id}`; + if (item.type === "run") return `${RUNS_BASE_PATH}/${item.id}`; + return APP_ROUTES.DASHBOARD_COMPONENTS; +} + +const RecentlyViewedCard = ({ item }: { item: RecentlyViewedItem }) => { + const isPipeline = item.type === "pipeline"; + + return ( + + {/* Type badge */} + + + + + {isPipeline ? "Pipeline" : "Run"} + + + + {formatRelativeTime(new Date(item.viewedAt))} + + + + {/* Name */} + + {item.name} + + + {/* ID */} + + {item.id} + + + ); +}; + export function DashboardRecentlyViewedView() { - return <>placeholder; + const { recentlyViewed } = useRecentlyViewed(); + + return ( + + + Recently Viewed + + + {recentlyViewed.length === 0 ? ( + + Nothing viewed yet. Open a pipeline or run to see it here. + + ) : ( +
+ {recentlyViewed.map((item) => ( + + ))} +
+ )} +
+ ); }