diff --git a/src/hooks/useRecentlyViewed.ts b/src/hooks/useRecentlyViewed.ts index c582ad3ba..40dc1d781 100644 --- a/src/hooks/useRecentlyViewed.ts +++ b/src/hooks/useRecentlyViewed.ts @@ -3,11 +3,11 @@ import { useCallback, useSyncExternalStore } 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; diff --git a/src/routes/Dashboard/DashboardRecentlyViewedView.tsx b/src/routes/Dashboard/DashboardRecentlyViewedView.tsx index c5e97e96c..d6c2f1fb2 100644 --- a/src/routes/Dashboard/DashboardRecentlyViewedView.tsx +++ b/src/routes/Dashboard/DashboardRecentlyViewedView.tsx @@ -1,3 +1,98 @@ +import { useNavigate } from "@tanstack/react-router"; +import { GitBranch, Play } from "lucide-react"; + +import { BlockStack, InlineStack } from "@/components/ui/layout"; +import { Paragraph, Text } from "@/components/ui/typography"; +import { + type RecentlyViewedItem, + useRecentlyViewed, +} from "@/hooks/useRecentlyViewed"; +import { EDITOR_PATH, RUNS_BASE_PATH } from "@/routes/router"; + +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 "/"; +} + +function formatRelativeTime(viewedAt: number): string { + const diff = Date.now() - viewedAt; + const minutes = Math.floor(diff / 60_000); + if (minutes < 1) return "just now"; + if (minutes < 60) return `${minutes}m ago`; + const hours = Math.floor(minutes / 60); + if (hours < 24) return `${hours}h ago`; + const days = Math.floor(hours / 24); + return `${days}d ago`; +} + +const RecentlyViewedCard = ({ item }: { item: RecentlyViewedItem }) => { + const navigate = useNavigate(); + const isPipeline = item.type === "pipeline"; + + return ( +
navigate({ to: getRecentlyViewedUrl(item) })} + className={`flex flex-col gap-2 p-3 border rounded-lg cursor-pointer transition-colors ${ + isPipeline + ? "bg-violet-50/40 hover:bg-violet-50 border-violet-100" + : "bg-emerald-50/40 hover:bg-emerald-50 border-emerald-100" + }`} + > + {/* Type badge */} + + + {isPipeline ? ( + + ) : ( + + )} + + {isPipeline ? "Pipeline" : "Run"} + + + + {formatRelativeTime(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) => ( + + ))} +
+ )} +
+ ); }