@burdenoff/microfe-cosmicintersection 2026.731.1 → 2026.801.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (27) hide show
  1. package/dist/cosmicintersection/CosmicIntersectionRoutes.js +1 -1
  2. package/dist/cosmicintersection/CosmicIntersectionRoutes.js.map +1 -1
  3. package/dist/cosmicintersection/pages/collections/CollectionDetailPage.js +1 -1
  4. package/dist/cosmicintersection/pages/collections/CollectionDetailPage.js.map +1 -1
  5. package/dist/cosmicintersection/pages/collections/CollectionFormPage.js +1 -1
  6. package/dist/cosmicintersection/pages/collections/CollectionFormPage.js.map +1 -1
  7. package/dist/cosmicintersection/pages/datasets/DatasetDetailPage.js +1 -1
  8. package/dist/cosmicintersection/pages/datasets/DatasetDetailPage.js.map +1 -1
  9. package/dist/cosmicintersection/pages/datasets/DatasetFormPage.js +1 -1
  10. package/dist/cosmicintersection/pages/datasets/DatasetFormPage.js.map +1 -1
  11. package/dist/cosmicintersection/pages/lineage/LineagePage.js +1 -1
  12. package/dist/cosmicintersection/pages/lineage/LineagePage.js.map +1 -1
  13. package/dist/cosmicintersection/pages/notebooks/NotebookDetailPage.js +1 -1
  14. package/dist/cosmicintersection/pages/notebooks/NotebookDetailPage.js.map +1 -1
  15. package/dist/cosmicintersection/pages/notebooks/NotebookFormPage.js +1 -1
  16. package/dist/cosmicintersection/pages/notebooks/NotebookFormPage.js.map +1 -1
  17. package/dist/cosmicintersection/pages/pipelines/PipelineDetailPage.js +1 -1
  18. package/dist/cosmicintersection/pages/pipelines/PipelineDetailPage.js.map +1 -1
  19. package/dist/cosmicintersection/pages/pipelines/PipelineFormPage.js +1 -1
  20. package/dist/cosmicintersection/pages/pipelines/PipelineFormPage.js.map +1 -1
  21. package/dist/cosmicintersection/pages/runs/RunDetailPage.js +1 -1
  22. package/dist/cosmicintersection/pages/runs/RunDetailPage.js.map +1 -1
  23. package/dist/cosmicintersection/pages/sources/SourceDetailPage.js +1 -1
  24. package/dist/cosmicintersection/pages/sources/SourceDetailPage.js.map +1 -1
  25. package/dist/cosmicintersection/pages/sources/SourceFormPage.js +1 -1
  26. package/dist/cosmicintersection/pages/sources/SourceFormPage.js.map +1 -1
  27. package/package.json +3 -3
@@ -1,6 +1,6 @@
1
1
  import { Suspense as e, lazy as t } from "react";
2
2
  import { jsx as n, jsxs as r } from "react/jsx-runtime";
3
- import { Navigate as i, Route as a, Routes as o } from "react-router-dom";
3
+ import { Navigate as i, Route as a, Routes as o } from "react-router";
4
4
  //#region src/cosmicintersection/CosmicIntersectionRoutes.tsx
5
5
  var s = t(() => import("./pages/dashboard/DashboardPage.js")), c = t(() => import("./pages/datasets/DatasetsPage.js")), l = t(() => import("./pages/datasets/DatasetDetailPage.js")), u = t(() => import("./pages/datasets/DatasetFormPage.js")), d = t(() => import("./pages/discovery/DiscoveryPage.js")), f = t(() => import("./pages/lineage/LineagePage.js")), p = t(() => import("./pages/sources/SourcesPage.js")), m = t(() => import("./pages/sources/SourceDetailPage.js")), h = t(() => import("./pages/sources/SourceFormPage.js")), g = t(() => import("./pages/collections/CollectionsPage.js")), _ = t(() => import("./pages/collections/CollectionDetailPage.js")), v = t(() => import("./pages/collections/CollectionFormPage.js")), y = t(() => import("./pages/pipelines/PipelinesPage.js")), b = t(() => import("./pages/pipelines/PipelineDetailPage.js")), x = t(() => import("./pages/pipelines/PipelineFormPage.js")), S = t(() => import("./pages/runs/RunsPage.js")), C = t(() => import("./pages/runs/RunDetailPage.js")), w = t(() => import("./pages/notebooks/NotebooksPage.js")), T = t(() => import("./pages/notebooks/NotebookDetailPage.js")), E = t(() => import("./pages/notebooks/NotebookFormPage.js")), D = t(() => import("./pages/analyses/AnalysesPage.js")), O = t(() => import("./pages/releases/ReleasesPage.js")), k = t(() => import("./pages/releases/ReleaseFormPage.js")), A = t(() => import("./pages/access/AccessPage.js"));
6
6
  function j() {
@@ -1 +1 @@
1
- {"version":3,"file":"CosmicIntersectionRoutes.js","names":[],"sources":["../../src/cosmicintersection/CosmicIntersectionRoutes.tsx"],"sourcesContent":["import { lazy, Suspense } from 'react';\nimport { Navigate, Route, Routes } from 'react-router-dom';\n\n// Canonical page files — all default exports. Page agents overwrite the\n// placeholder stubs in place; these import paths are the contract.\nconst DashboardPage = lazy(() => import('./pages/dashboard/DashboardPage'));\n\nconst DatasetsPage = lazy(() => import('./pages/datasets/DatasetsPage'));\nconst DatasetDetailPage = lazy(() => import('./pages/datasets/DatasetDetailPage'));\nconst DatasetFormPage = lazy(() => import('./pages/datasets/DatasetFormPage'));\n\n// Faceted full-text discovery over the federated catalog.\nconst DiscoveryPage = lazy(() => import('./pages/discovery/DiscoveryPage'));\n\n// Provenance / lineage graph (Source → Dataset → Run → Notebook → Release).\nconst LineagePage = lazy(() => import('./pages/lineage/LineagePage'));\n\nconst SourcesPage = lazy(() => import('./pages/sources/SourcesPage'));\nconst SourceDetailPage = lazy(() => import('./pages/sources/SourceDetailPage'));\nconst SourceFormPage = lazy(() => import('./pages/sources/SourceFormPage'));\n\nconst CollectionsPage = lazy(() => import('./pages/collections/CollectionsPage'));\nconst CollectionDetailPage = lazy(() => import('./pages/collections/CollectionDetailPage'));\nconst CollectionFormPage = lazy(() => import('./pages/collections/CollectionFormPage'));\n\nconst PipelinesPage = lazy(() => import('./pages/pipelines/PipelinesPage'));\nconst PipelineDetailPage = lazy(() => import('./pages/pipelines/PipelineDetailPage'));\nconst PipelineFormPage = lazy(() => import('./pages/pipelines/PipelineFormPage'));\n\nconst RunsPage = lazy(() => import('./pages/runs/RunsPage'));\nconst RunDetailPage = lazy(() => import('./pages/runs/RunDetailPage'));\n\nconst NotebooksPage = lazy(() => import('./pages/notebooks/NotebooksPage'));\nconst NotebookDetailPage = lazy(() => import('./pages/notebooks/NotebookDetailPage'));\nconst NotebookFormPage = lazy(() => import('./pages/notebooks/NotebookFormPage'));\n\nconst AnalysesPage = lazy(() => import('./pages/analyses/AnalysesPage'));\n\nconst ReleasesPage = lazy(() => import('./pages/releases/ReleasesPage'));\nconst ReleaseFormPage = lazy(() => import('./pages/releases/ReleaseFormPage'));\n\nconst AccessPage = lazy(() => import('./pages/access/AccessPage'));\n\nfunction PageLoader() {\n return (\n <div className=\"flex min-h-[320px] items-center justify-center\">\n <div className=\"size-8 animate-spin rounded-full border-2 border-border-default border-t-text-primary\" />\n </div>\n );\n}\n\nexport function CosmicIntersectionRoutes() {\n return (\n <Suspense fallback={<PageLoader />}>\n <Routes>\n <Route index element={<DashboardPage />} />\n\n <Route path=\"discovery\" element={<DiscoveryPage />} />\n\n <Route path=\"lineage\" element={<LineagePage />} />\n <Route path=\"lineage/:datasetId\" element={<LineagePage />} />\n\n <Route path=\"datasets\" element={<DatasetsPage />} />\n <Route path=\"datasets/create\" element={<DatasetFormPage />} />\n <Route path=\"datasets/:id\" element={<DatasetDetailPage />} />\n <Route path=\"datasets/:id/edit\" element={<DatasetFormPage />} />\n\n <Route path=\"sources\" element={<SourcesPage />} />\n <Route path=\"sources/create\" element={<SourceFormPage />} />\n <Route path=\"sources/:id\" element={<SourceDetailPage />} />\n <Route path=\"sources/:id/edit\" element={<SourceFormPage />} />\n\n <Route path=\"collections\" element={<CollectionsPage />} />\n <Route path=\"collections/create\" element={<CollectionFormPage />} />\n <Route path=\"collections/:id\" element={<CollectionDetailPage />} />\n <Route path=\"collections/:id/edit\" element={<CollectionFormPage />} />\n\n <Route path=\"pipelines\" element={<PipelinesPage />} />\n <Route path=\"pipelines/create\" element={<PipelineFormPage />} />\n <Route path=\"pipelines/:id\" element={<PipelineDetailPage />} />\n <Route path=\"pipelines/:id/edit\" element={<PipelineFormPage />} />\n\n <Route path=\"runs\" element={<RunsPage />} />\n <Route path=\"runs/:id\" element={<RunDetailPage />} />\n\n <Route path=\"notebooks\" element={<NotebooksPage />} />\n <Route path=\"notebooks/create\" element={<NotebookFormPage />} />\n <Route path=\"notebooks/:id\" element={<NotebookDetailPage />} />\n <Route path=\"notebooks/:id/edit\" element={<NotebookFormPage />} />\n\n <Route path=\"analyses\" element={<AnalysesPage />} />\n\n <Route path=\"releases\" element={<ReleasesPage />} />\n <Route path=\"releases/create\" element={<ReleaseFormPage />} />\n\n <Route path=\"access\" element={<AccessPage />} />\n\n <Route path=\"*\" element={<Navigate to=\"\" replace />} />\n </Routes>\n </Suspense>\n );\n}\n\nexport default CosmicIntersectionRoutes;\n"],"mappings":"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"}
1
+ {"version":3,"file":"CosmicIntersectionRoutes.js","names":[],"sources":["../../src/cosmicintersection/CosmicIntersectionRoutes.tsx"],"sourcesContent":["import { lazy, Suspense } from 'react';\nimport { Navigate, Route, Routes } from 'react-router';\n\n// Canonical page files — all default exports. Page agents overwrite the\n// placeholder stubs in place; these import paths are the contract.\nconst DashboardPage = lazy(() => import('./pages/dashboard/DashboardPage'));\n\nconst DatasetsPage = lazy(() => import('./pages/datasets/DatasetsPage'));\nconst DatasetDetailPage = lazy(() => import('./pages/datasets/DatasetDetailPage'));\nconst DatasetFormPage = lazy(() => import('./pages/datasets/DatasetFormPage'));\n\n// Faceted full-text discovery over the federated catalog.\nconst DiscoveryPage = lazy(() => import('./pages/discovery/DiscoveryPage'));\n\n// Provenance / lineage graph (Source → Dataset → Run → Notebook → Release).\nconst LineagePage = lazy(() => import('./pages/lineage/LineagePage'));\n\nconst SourcesPage = lazy(() => import('./pages/sources/SourcesPage'));\nconst SourceDetailPage = lazy(() => import('./pages/sources/SourceDetailPage'));\nconst SourceFormPage = lazy(() => import('./pages/sources/SourceFormPage'));\n\nconst CollectionsPage = lazy(() => import('./pages/collections/CollectionsPage'));\nconst CollectionDetailPage = lazy(() => import('./pages/collections/CollectionDetailPage'));\nconst CollectionFormPage = lazy(() => import('./pages/collections/CollectionFormPage'));\n\nconst PipelinesPage = lazy(() => import('./pages/pipelines/PipelinesPage'));\nconst PipelineDetailPage = lazy(() => import('./pages/pipelines/PipelineDetailPage'));\nconst PipelineFormPage = lazy(() => import('./pages/pipelines/PipelineFormPage'));\n\nconst RunsPage = lazy(() => import('./pages/runs/RunsPage'));\nconst RunDetailPage = lazy(() => import('./pages/runs/RunDetailPage'));\n\nconst NotebooksPage = lazy(() => import('./pages/notebooks/NotebooksPage'));\nconst NotebookDetailPage = lazy(() => import('./pages/notebooks/NotebookDetailPage'));\nconst NotebookFormPage = lazy(() => import('./pages/notebooks/NotebookFormPage'));\n\nconst AnalysesPage = lazy(() => import('./pages/analyses/AnalysesPage'));\n\nconst ReleasesPage = lazy(() => import('./pages/releases/ReleasesPage'));\nconst ReleaseFormPage = lazy(() => import('./pages/releases/ReleaseFormPage'));\n\nconst AccessPage = lazy(() => import('./pages/access/AccessPage'));\n\nfunction PageLoader() {\n return (\n <div className=\"flex min-h-[320px] items-center justify-center\">\n <div className=\"size-8 animate-spin rounded-full border-2 border-border-default border-t-text-primary\" />\n </div>\n );\n}\n\nexport function CosmicIntersectionRoutes() {\n return (\n <Suspense fallback={<PageLoader />}>\n <Routes>\n <Route index element={<DashboardPage />} />\n\n <Route path=\"discovery\" element={<DiscoveryPage />} />\n\n <Route path=\"lineage\" element={<LineagePage />} />\n <Route path=\"lineage/:datasetId\" element={<LineagePage />} />\n\n <Route path=\"datasets\" element={<DatasetsPage />} />\n <Route path=\"datasets/create\" element={<DatasetFormPage />} />\n <Route path=\"datasets/:id\" element={<DatasetDetailPage />} />\n <Route path=\"datasets/:id/edit\" element={<DatasetFormPage />} />\n\n <Route path=\"sources\" element={<SourcesPage />} />\n <Route path=\"sources/create\" element={<SourceFormPage />} />\n <Route path=\"sources/:id\" element={<SourceDetailPage />} />\n <Route path=\"sources/:id/edit\" element={<SourceFormPage />} />\n\n <Route path=\"collections\" element={<CollectionsPage />} />\n <Route path=\"collections/create\" element={<CollectionFormPage />} />\n <Route path=\"collections/:id\" element={<CollectionDetailPage />} />\n <Route path=\"collections/:id/edit\" element={<CollectionFormPage />} />\n\n <Route path=\"pipelines\" element={<PipelinesPage />} />\n <Route path=\"pipelines/create\" element={<PipelineFormPage />} />\n <Route path=\"pipelines/:id\" element={<PipelineDetailPage />} />\n <Route path=\"pipelines/:id/edit\" element={<PipelineFormPage />} />\n\n <Route path=\"runs\" element={<RunsPage />} />\n <Route path=\"runs/:id\" element={<RunDetailPage />} />\n\n <Route path=\"notebooks\" element={<NotebooksPage />} />\n <Route path=\"notebooks/create\" element={<NotebookFormPage />} />\n <Route path=\"notebooks/:id\" element={<NotebookDetailPage />} />\n <Route path=\"notebooks/:id/edit\" element={<NotebookFormPage />} />\n\n <Route path=\"analyses\" element={<AnalysesPage />} />\n\n <Route path=\"releases\" element={<ReleasesPage />} />\n <Route path=\"releases/create\" element={<ReleaseFormPage />} />\n\n <Route path=\"access\" element={<AccessPage />} />\n\n <Route path=\"*\" element={<Navigate to=\"\" replace />} />\n </Routes>\n </Suspense>\n );\n}\n\nexport default CosmicIntersectionRoutes;\n"],"mappings":"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"}
@@ -10,7 +10,7 @@ import u, { usePagination as d } from "../../components/Pagination.js";
10
10
  import f from "../../components/StatusBadge.js";
11
11
  import "../../components/index.js";
12
12
  import { Fragment as p, jsx as m, jsxs as h } from "react/jsx-runtime";
13
- import { useParams as g } from "react-router-dom";
13
+ import { useParams as g } from "react-router";
14
14
  import { Database as _, FolderOpen as v, Globe as y, Lock as b, Pencil as x } from "lucide-react";
15
15
  import { Badge as S, Button as C, Table as w, TableBody as T, TableCell as E, TableHead as D, TableHeader as O, TableRow as k } from "@burdenoff/fe-libs/ui";
16
16
  //#region src/cosmicintersection/pages/collections/CollectionDetailPage.tsx
@@ -1 +1 @@
1
- {"version":3,"file":"CollectionDetailPage.js","names":[],"sources":["../../../../src/cosmicintersection/pages/collections/CollectionDetailPage.tsx"],"sourcesContent":["import { useParams } from 'react-router-dom';\nimport { Database, FolderOpen, Globe, Lock, Pencil } from 'lucide-react';\nimport {\n Badge,\n Button,\n Table,\n TableBody,\n TableCell,\n TableHead,\n TableHeader,\n TableRow,\n} from '@burdenoff/fe-libs/ui';\n\nimport {\n useCosArchiveCollectionMutation,\n useCosCollectionQuery,\n useCosDatasetsQuery,\n} from '../../api/cosmicApi';\nimport {\n ActionMenu,\n EmptyState,\n ErrorState,\n LoadingState,\n PageLayout,\n Pagination,\n StatusBadge,\n usePagination,\n} from '../../components';\nimport { useCosmicIntersection } from '../../context/CosmicIntersectionContext';\nimport { notify } from '../../lib/toast';\n\nfunction formatDate(value?: string | null): string {\n if (!value) {\n return '—';\n }\n const parsed = new Date(value);\n if (Number.isNaN(parsed.getTime())) {\n return '—';\n }\n return parsed.toLocaleDateString(undefined, { year: 'numeric', month: 'short', day: 'numeric' });\n}\n\nexport default function CollectionDetailPage() {\n const { id = '' } = useParams<{ id: string }>();\n const { navigate } = useCosmicIntersection();\n\n // Resolve the header from the dedicated single-collection query — works for any\n // collection regardless of list pagination.\n const {\n data: collectionData,\n loading: loadingCollection,\n error: collectionError,\n refetch: refetchCollection,\n } = useCosCollectionQuery(id);\n\n const collection = collectionData?.cosCollection ?? null;\n\n const pagination = usePagination({ pageSize: 20, resetKey: id });\n const {\n data: datasetsData,\n loading: loadingDatasets,\n error: datasetsError,\n refetch: refetchDatasets,\n } = useCosDatasetsQuery({\n collectionId: id,\n pagination: { limit: pagination.limit, offset: pagination.offset },\n });\n\n const datasets = datasetsData?.cosListDatasets.items ?? [];\n const pageInfo = datasetsData?.cosListDatasets.pageInfo;\n\n const [archiveCollection] = useCosArchiveCollectionMutation();\n\n const handleArchive = async () => {\n if (!collection) {\n return;\n }\n const response = await archiveCollection({ variables: { id: collection.id } });\n if (response.error) {\n throw new Error(response.error.message);\n }\n if (!response.data?.cosArchiveCollection) {\n notify.error('Could not archive collection', 'The server did not confirm the change.');\n throw new Error('Archive not confirmed');\n }\n notify.success('Collection archived');\n navigate('collections');\n };\n\n if (loadingCollection) {\n return (\n <PageLayout title=\"Collection\" backPath=\"collections\">\n <LoadingState label=\"Loading collection…\" />\n </PageLayout>\n );\n }\n\n if (collectionError) {\n return (\n <PageLayout title=\"Collection\" backPath=\"collections\">\n <ErrorState message={collectionError.message} onRetry={() => void refetchCollection()} />\n </PageLayout>\n );\n }\n\n if (!collection) {\n return (\n <PageLayout title=\"Collection\" backPath=\"collections\">\n <EmptyState\n icon={FolderOpen}\n title=\"Collection not found\"\n description=\"This collection may have been removed or you may not have access to it.\"\n />\n </PageLayout>\n );\n }\n\n const renderDatasets = () => {\n if (loadingDatasets) {\n return <LoadingState variant=\"rows\" rows={4} label=\"Loading datasets…\" />;\n }\n if (datasetsError) {\n return <ErrorState message={datasetsError.message} onRetry={() => void refetchDatasets()} />;\n }\n if (datasets.length === 0) {\n return (\n <EmptyState\n icon={Database}\n title=\"No datasets in this collection\"\n description=\"Assign a dataset to this collection to see it listed here.\"\n />\n );\n }\n\n return (\n <>\n {/* Desktop / tablet: table */}\n <div className=\"hidden overflow-hidden rounded-card border border-border-default bg-bg-elevated md:block\">\n <Table>\n <TableHeader>\n <TableRow>\n <TableHead>Name</TableHead>\n <TableHead>Status</TableHead>\n <TableHead>Access</TableHead>\n <TableHead>Format</TableHead>\n <TableHead>Updated</TableHead>\n </TableRow>\n </TableHeader>\n <TableBody>\n {datasets.map((dataset) => (\n <TableRow\n key={dataset.id}\n className=\"cursor-pointer\"\n onClick={() => navigate(`datasets/${dataset.id}`)}\n >\n <TableCell className=\"font-medium text-text-primary\">{dataset.name}</TableCell>\n <TableCell>\n <StatusBadge status={dataset.status} />\n </TableCell>\n <TableCell>\n <StatusBadge status={dataset.accessLevel} />\n </TableCell>\n <TableCell className=\"text-sm text-text-secondary\">\n {dataset.format || '—'}\n </TableCell>\n <TableCell className=\"whitespace-nowrap text-sm text-text-secondary\">\n {formatDate(dataset.updatedAt)}\n </TableCell>\n </TableRow>\n ))}\n </TableBody>\n </Table>\n </div>\n\n {/* Mobile: stacked cards */}\n <ul className=\"space-y-3 md:hidden\">\n {datasets.map((dataset) => (\n <li key={dataset.id}>\n <div\n role=\"button\"\n tabIndex={0}\n aria-label={`Open ${dataset.name}`}\n onClick={() => navigate(`datasets/${dataset.id}`)}\n onKeyDown={(event) => {\n if (event.key === 'Enter' || event.key === ' ') {\n event.preventDefault();\n navigate(`datasets/${dataset.id}`);\n }\n }}\n className=\"flex flex-col gap-2 rounded-card border border-border-default bg-bg-elevated p-4 outline-none transition-colors hover:bg-bg-sunken focus-visible:ring-2 focus-visible:ring-border-focus\"\n >\n <p className=\"font-medium text-text-primary\">{dataset.name}</p>\n <div className=\"flex flex-wrap items-center gap-1.5\">\n <StatusBadge status={dataset.status} />\n <StatusBadge status={dataset.accessLevel} />\n </div>\n <div className=\"flex items-center justify-between gap-2 text-xs text-text-secondary\">\n <span>{dataset.format || '—'}</span>\n <span>{formatDate(dataset.updatedAt)}</span>\n </div>\n </div>\n </li>\n ))}\n </ul>\n\n <Pagination\n offset={pagination.offset}\n limit={pagination.limit}\n loadedCount={datasets.length}\n hasMore={pageInfo?.hasMore ?? false}\n onPrev={pagination.prevPage}\n onNext={pagination.nextPage}\n itemLabel=\"datasets\"\n loading={loadingDatasets}\n />\n </>\n );\n };\n\n return (\n <PageLayout\n title={collection.name}\n description={collection.slug ? `/${collection.slug}` : undefined}\n backPath=\"collections\"\n actions={\n <div className=\"flex items-center gap-2\">\n {collection.isPublic ? (\n <Badge\n variant=\"outline\"\n className=\"gap-1 border-status-success-border bg-status-success-bg-subtle text-status-success-text\"\n >\n <Globe className=\"size-3\" aria-hidden=\"true\" />\n Public\n </Badge>\n ) : (\n <Badge variant=\"secondary\" className=\"gap-1\">\n <Lock className=\"size-3\" aria-hidden=\"true\" />\n Private\n </Badge>\n )}\n <Button\n type=\"button\"\n variant=\"outline\"\n onClick={() => navigate(`collections/${collection.id}/edit`)}\n >\n <Pencil className=\"size-4\" />\n Edit\n </Button>\n <ActionMenu\n ariaLabel={`Actions for ${collection.name}`}\n entityName={collection.name}\n onDelete={() => handleArchive()}\n deleteLabel=\"Archive collection\"\n />\n </div>\n }\n >\n <div className=\"space-y-6\">\n <div className=\"rounded-card border border-border-default bg-bg-elevated p-5\">\n <h2 className=\"text-sm font-semibold text-text-primary\">About</h2>\n <p className=\"mt-2 text-sm text-text-secondary\">\n {collection.description ?? 'No description provided.'}\n </p>\n {collection.tags.length > 0 ? (\n <div className=\"mt-4 flex flex-wrap gap-1\">\n {collection.tags.map((tag) => (\n <Badge key={tag} variant=\"outline\" className=\"text-xs\">\n {tag}\n </Badge>\n ))}\n </div>\n ) : null}\n </div>\n\n <div className=\"space-y-3\">\n <div className=\"flex items-center gap-2\">\n <h2 className=\"text-sm font-semibold text-text-primary\">Datasets</h2>\n {!loadingDatasets && !datasetsError && pagination.offset === 0 && !pageInfo?.hasMore ? (\n <Badge variant=\"secondary\" className=\"text-xs\">\n {datasets.length} {datasets.length === 1 ? 'dataset' : 'datasets'}\n </Badge>\n ) : null}\n </div>\n {renderDatasets()}\n </div>\n </div>\n </PageLayout>\n );\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"CollectionDetailPage.js","names":[],"sources":["../../../../src/cosmicintersection/pages/collections/CollectionDetailPage.tsx"],"sourcesContent":["import { useParams } from 'react-router';\nimport { Database, FolderOpen, Globe, Lock, Pencil } from 'lucide-react';\nimport {\n Badge,\n Button,\n Table,\n TableBody,\n TableCell,\n TableHead,\n TableHeader,\n TableRow,\n} from '@burdenoff/fe-libs/ui';\n\nimport {\n useCosArchiveCollectionMutation,\n useCosCollectionQuery,\n useCosDatasetsQuery,\n} from '../../api/cosmicApi';\nimport {\n ActionMenu,\n EmptyState,\n ErrorState,\n LoadingState,\n PageLayout,\n Pagination,\n StatusBadge,\n usePagination,\n} from '../../components';\nimport { useCosmicIntersection } from '../../context/CosmicIntersectionContext';\nimport { notify } from '../../lib/toast';\n\nfunction formatDate(value?: string | null): string {\n if (!value) {\n return '—';\n }\n const parsed = new Date(value);\n if (Number.isNaN(parsed.getTime())) {\n return '—';\n }\n return parsed.toLocaleDateString(undefined, { year: 'numeric', month: 'short', day: 'numeric' });\n}\n\nexport default function CollectionDetailPage() {\n const { id = '' } = useParams<{ id: string }>();\n const { navigate } = useCosmicIntersection();\n\n // Resolve the header from the dedicated single-collection query — works for any\n // collection regardless of list pagination.\n const {\n data: collectionData,\n loading: loadingCollection,\n error: collectionError,\n refetch: refetchCollection,\n } = useCosCollectionQuery(id);\n\n const collection = collectionData?.cosCollection ?? null;\n\n const pagination = usePagination({ pageSize: 20, resetKey: id });\n const {\n data: datasetsData,\n loading: loadingDatasets,\n error: datasetsError,\n refetch: refetchDatasets,\n } = useCosDatasetsQuery({\n collectionId: id,\n pagination: { limit: pagination.limit, offset: pagination.offset },\n });\n\n const datasets = datasetsData?.cosListDatasets.items ?? [];\n const pageInfo = datasetsData?.cosListDatasets.pageInfo;\n\n const [archiveCollection] = useCosArchiveCollectionMutation();\n\n const handleArchive = async () => {\n if (!collection) {\n return;\n }\n const response = await archiveCollection({ variables: { id: collection.id } });\n if (response.error) {\n throw new Error(response.error.message);\n }\n if (!response.data?.cosArchiveCollection) {\n notify.error('Could not archive collection', 'The server did not confirm the change.');\n throw new Error('Archive not confirmed');\n }\n notify.success('Collection archived');\n navigate('collections');\n };\n\n if (loadingCollection) {\n return (\n <PageLayout title=\"Collection\" backPath=\"collections\">\n <LoadingState label=\"Loading collection…\" />\n </PageLayout>\n );\n }\n\n if (collectionError) {\n return (\n <PageLayout title=\"Collection\" backPath=\"collections\">\n <ErrorState message={collectionError.message} onRetry={() => void refetchCollection()} />\n </PageLayout>\n );\n }\n\n if (!collection) {\n return (\n <PageLayout title=\"Collection\" backPath=\"collections\">\n <EmptyState\n icon={FolderOpen}\n title=\"Collection not found\"\n description=\"This collection may have been removed or you may not have access to it.\"\n />\n </PageLayout>\n );\n }\n\n const renderDatasets = () => {\n if (loadingDatasets) {\n return <LoadingState variant=\"rows\" rows={4} label=\"Loading datasets…\" />;\n }\n if (datasetsError) {\n return <ErrorState message={datasetsError.message} onRetry={() => void refetchDatasets()} />;\n }\n if (datasets.length === 0) {\n return (\n <EmptyState\n icon={Database}\n title=\"No datasets in this collection\"\n description=\"Assign a dataset to this collection to see it listed here.\"\n />\n );\n }\n\n return (\n <>\n {/* Desktop / tablet: table */}\n <div className=\"hidden overflow-hidden rounded-card border border-border-default bg-bg-elevated md:block\">\n <Table>\n <TableHeader>\n <TableRow>\n <TableHead>Name</TableHead>\n <TableHead>Status</TableHead>\n <TableHead>Access</TableHead>\n <TableHead>Format</TableHead>\n <TableHead>Updated</TableHead>\n </TableRow>\n </TableHeader>\n <TableBody>\n {datasets.map((dataset) => (\n <TableRow\n key={dataset.id}\n className=\"cursor-pointer\"\n onClick={() => navigate(`datasets/${dataset.id}`)}\n >\n <TableCell className=\"font-medium text-text-primary\">{dataset.name}</TableCell>\n <TableCell>\n <StatusBadge status={dataset.status} />\n </TableCell>\n <TableCell>\n <StatusBadge status={dataset.accessLevel} />\n </TableCell>\n <TableCell className=\"text-sm text-text-secondary\">\n {dataset.format || '—'}\n </TableCell>\n <TableCell className=\"whitespace-nowrap text-sm text-text-secondary\">\n {formatDate(dataset.updatedAt)}\n </TableCell>\n </TableRow>\n ))}\n </TableBody>\n </Table>\n </div>\n\n {/* Mobile: stacked cards */}\n <ul className=\"space-y-3 md:hidden\">\n {datasets.map((dataset) => (\n <li key={dataset.id}>\n <div\n role=\"button\"\n tabIndex={0}\n aria-label={`Open ${dataset.name}`}\n onClick={() => navigate(`datasets/${dataset.id}`)}\n onKeyDown={(event) => {\n if (event.key === 'Enter' || event.key === ' ') {\n event.preventDefault();\n navigate(`datasets/${dataset.id}`);\n }\n }}\n className=\"flex flex-col gap-2 rounded-card border border-border-default bg-bg-elevated p-4 outline-none transition-colors hover:bg-bg-sunken focus-visible:ring-2 focus-visible:ring-border-focus\"\n >\n <p className=\"font-medium text-text-primary\">{dataset.name}</p>\n <div className=\"flex flex-wrap items-center gap-1.5\">\n <StatusBadge status={dataset.status} />\n <StatusBadge status={dataset.accessLevel} />\n </div>\n <div className=\"flex items-center justify-between gap-2 text-xs text-text-secondary\">\n <span>{dataset.format || '—'}</span>\n <span>{formatDate(dataset.updatedAt)}</span>\n </div>\n </div>\n </li>\n ))}\n </ul>\n\n <Pagination\n offset={pagination.offset}\n limit={pagination.limit}\n loadedCount={datasets.length}\n hasMore={pageInfo?.hasMore ?? false}\n onPrev={pagination.prevPage}\n onNext={pagination.nextPage}\n itemLabel=\"datasets\"\n loading={loadingDatasets}\n />\n </>\n );\n };\n\n return (\n <PageLayout\n title={collection.name}\n description={collection.slug ? `/${collection.slug}` : undefined}\n backPath=\"collections\"\n actions={\n <div className=\"flex items-center gap-2\">\n {collection.isPublic ? (\n <Badge\n variant=\"outline\"\n className=\"gap-1 border-status-success-border bg-status-success-bg-subtle text-status-success-text\"\n >\n <Globe className=\"size-3\" aria-hidden=\"true\" />\n Public\n </Badge>\n ) : (\n <Badge variant=\"secondary\" className=\"gap-1\">\n <Lock className=\"size-3\" aria-hidden=\"true\" />\n Private\n </Badge>\n )}\n <Button\n type=\"button\"\n variant=\"outline\"\n onClick={() => navigate(`collections/${collection.id}/edit`)}\n >\n <Pencil className=\"size-4\" />\n Edit\n </Button>\n <ActionMenu\n ariaLabel={`Actions for ${collection.name}`}\n entityName={collection.name}\n onDelete={() => handleArchive()}\n deleteLabel=\"Archive collection\"\n />\n </div>\n }\n >\n <div className=\"space-y-6\">\n <div className=\"rounded-card border border-border-default bg-bg-elevated p-5\">\n <h2 className=\"text-sm font-semibold text-text-primary\">About</h2>\n <p className=\"mt-2 text-sm text-text-secondary\">\n {collection.description ?? 'No description provided.'}\n </p>\n {collection.tags.length > 0 ? (\n <div className=\"mt-4 flex flex-wrap gap-1\">\n {collection.tags.map((tag) => (\n <Badge key={tag} variant=\"outline\" className=\"text-xs\">\n {tag}\n </Badge>\n ))}\n </div>\n ) : null}\n </div>\n\n <div className=\"space-y-3\">\n <div className=\"flex items-center gap-2\">\n <h2 className=\"text-sm font-semibold text-text-primary\">Datasets</h2>\n {!loadingDatasets && !datasetsError && pagination.offset === 0 && !pageInfo?.hasMore ? (\n <Badge variant=\"secondary\" className=\"text-xs\">\n {datasets.length} {datasets.length === 1 ? 'dataset' : 'datasets'}\n </Badge>\n ) : null}\n </div>\n {renderDatasets()}\n </div>\n </div>\n </PageLayout>\n );\n}\n"],"mappings":"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"}
@@ -7,7 +7,7 @@ import s from "../../components/EntityTagsField.js";
7
7
  import "../../components/index.js";
8
8
  import { useMemo as c, useState as l } from "react";
9
9
  import { jsx as u, jsxs as d } from "react/jsx-runtime";
10
- import { useParams as f } from "react-router-dom";
10
+ import { useParams as f } from "react-router";
11
11
  import { Input as p, Switch as m, Textarea as h } from "@burdenoff/fe-libs/ui";
12
12
  //#region src/cosmicintersection/pages/collections/CollectionFormPage.tsx
13
13
  var g = {
@@ -1 +1 @@
1
- {"version":3,"file":"CollectionFormPage.js","names":[],"sources":["../../../../src/cosmicintersection/pages/collections/CollectionFormPage.tsx"],"sourcesContent":["import { useMemo, useState } from 'react';\nimport { useParams } from 'react-router-dom';\nimport { Input, Switch, Textarea } from '@burdenoff/fe-libs/ui';\n\nimport {\n useCosCollectionQuery,\n useCosCreateCollectionMutation,\n useCosUpdateCollectionMutation,\n type CosCreateCollectionInput,\n type CosUpdateCollectionInput,\n} from '../../api/cosmicApi';\nimport { EntityFormShell, EntityTagsField, LoadingState } from '../../components';\nimport { useCosmicIntersection } from '../../context/CosmicIntersectionContext';\nimport { notify } from '../../lib/toast';\n\ninterface CollectionFormState {\n name: string;\n slug: string;\n description: string;\n isPublic: boolean;\n tags: string[];\n}\n\nconst INITIAL_STATE: CollectionFormState = {\n name: '',\n slug: '',\n description: '',\n isPublic: false,\n tags: [],\n};\n\nconst fieldLabelClass = 'block space-y-1.5 text-sm';\nconst fieldSpanClass = 'font-medium text-text-primary';\n\nexport default function CollectionFormPage() {\n const { id = '' } = useParams<{ id: string }>();\n const isEdit = useMemo(() => Boolean(id), [id]);\n const { navigate } = useCosmicIntersection();\n\n const { data, loading: loadingCollection } = useCosCollectionQuery(id);\n const [createCollection, { loading: creating }] = useCosCreateCollectionMutation();\n const [updateCollection, { loading: updating }] = useCosUpdateCollectionMutation();\n\n const [form, setForm] = useState<CollectionFormState>(INITIAL_STATE);\n\n // Hydrate once the collection loads in edit mode. Derive-state-during-render\n // (keyed on the loaded id) rather than an effect, per platform lint.\n const [loadedId, setLoadedId] = useState<string | null>(null);\n if (isEdit && data?.cosCollection && loadedId !== data.cosCollection.id) {\n const collection = data.cosCollection;\n setLoadedId(collection.id);\n setForm({\n name: collection.name ?? '',\n slug: collection.slug ?? '',\n description: collection.description ?? '',\n isPublic: collection.isPublic,\n tags: collection.tags ?? [],\n });\n }\n\n const onChange = <K extends keyof CollectionFormState>(\n field: K,\n value: CollectionFormState[K]\n ) => {\n setForm((prev) => ({ ...prev, [field]: value }));\n };\n\n const saving = creating || updating;\n\n const onSubmit = async (event: React.FormEvent<HTMLFormElement>) => {\n event.preventDefault();\n\n if (!form.name.trim()) {\n notify.error('Name is required', 'Give this collection a recognizable name.');\n return;\n }\n\n if (isEdit) {\n const input: CosUpdateCollectionInput = {\n name: form.name.trim(),\n slug: form.slug.trim() || undefined,\n description: form.description.trim() || undefined,\n isPublic: form.isPublic,\n tags: form.tags,\n };\n const response = await updateCollection({ variables: { id, input } });\n if (response.data?.cosUpdateCollection?.id) {\n notify.success('Collection updated');\n navigate(`collections/${id}`);\n }\n return;\n }\n\n const input: CosCreateCollectionInput = {\n name: form.name.trim(),\n slug: form.slug.trim() || undefined,\n description: form.description.trim() || undefined,\n isPublic: form.isPublic,\n tags: form.tags,\n };\n const response = await createCollection({ variables: { input } });\n const created = response.data?.cosCreateCollection;\n if (created?.id) {\n notify.success('Collection created');\n navigate(`collections/${created.id}`);\n }\n };\n\n if (isEdit && loadingCollection && !data?.cosCollection) {\n return <LoadingState label=\"Loading collection…\" />;\n }\n\n return (\n <EntityFormShell\n title={isEdit ? 'Edit collection' : 'New collection'}\n description=\"Group related datasets into a shareable, themed collection.\"\n purpose=\"Collections curate datasets by mission, survey or research theme so collaborators can browse a coherent set instead of a flat list. Mark a collection public to make it discoverable across the workspace.\"\n backLabel={isEdit ? 'Back to collection' : 'Back to collections'}\n onBack={() => navigate(isEdit ? `collections/${id}` : 'collections')}\n onSubmit={(event) => void onSubmit(event)}\n submitLabel={isEdit ? 'Save collection' : 'Create collection'}\n saving={saving}\n >\n <div className=\"grid grid-cols-1 gap-4 md:grid-cols-2\">\n <label className={fieldLabelClass}>\n <span className={fieldSpanClass}>Name</span>\n <Input\n value={form.name}\n onChange={(event) => onChange('name', event.target.value)}\n placeholder=\"e.g. Kepler Mission Data\"\n required\n />\n </label>\n <label className={fieldLabelClass}>\n <span className={fieldSpanClass}>Slug</span>\n <Input\n value={form.slug}\n onChange={(event) => onChange('slug', event.target.value)}\n placeholder=\"kepler-mission\"\n />\n <span className=\"text-xs text-text-secondary\">\n Optional URL-friendly identifier for sharing.\n </span>\n </label>\n </div>\n\n <label className={fieldLabelClass}>\n <span className={fieldSpanClass}>Description</span>\n <Textarea\n value={form.description}\n onChange={(event) => onChange('description', event.target.value)}\n rows={3}\n placeholder=\"What this collection groups together and who it is for.\"\n />\n </label>\n\n <div className=\"flex items-center justify-between gap-4 rounded-card border border-border-default bg-bg-sunken px-4 py-3\">\n <div>\n <p className=\"text-sm font-medium text-text-primary\">Public collection</p>\n <p className=\"text-xs text-text-secondary\">\n Make this collection discoverable across the workspace.\n </p>\n </div>\n <Switch\n checked={form.isPublic}\n onCheckedChange={(checked) => onChange('isPublic', checked)}\n aria-label=\"Public collection\"\n />\n </div>\n\n <EntityTagsField\n value={form.tags}\n onChange={(tags) => onChange('tags', tags)}\n disabled={saving}\n />\n </EntityFormShell>\n );\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"CollectionFormPage.js","names":[],"sources":["../../../../src/cosmicintersection/pages/collections/CollectionFormPage.tsx"],"sourcesContent":["import { useMemo, useState } from 'react';\nimport { useParams } from 'react-router';\nimport { Input, Switch, Textarea } from '@burdenoff/fe-libs/ui';\n\nimport {\n useCosCollectionQuery,\n useCosCreateCollectionMutation,\n useCosUpdateCollectionMutation,\n type CosCreateCollectionInput,\n type CosUpdateCollectionInput,\n} from '../../api/cosmicApi';\nimport { EntityFormShell, EntityTagsField, LoadingState } from '../../components';\nimport { useCosmicIntersection } from '../../context/CosmicIntersectionContext';\nimport { notify } from '../../lib/toast';\n\ninterface CollectionFormState {\n name: string;\n slug: string;\n description: string;\n isPublic: boolean;\n tags: string[];\n}\n\nconst INITIAL_STATE: CollectionFormState = {\n name: '',\n slug: '',\n description: '',\n isPublic: false,\n tags: [],\n};\n\nconst fieldLabelClass = 'block space-y-1.5 text-sm';\nconst fieldSpanClass = 'font-medium text-text-primary';\n\nexport default function CollectionFormPage() {\n const { id = '' } = useParams<{ id: string }>();\n const isEdit = useMemo(() => Boolean(id), [id]);\n const { navigate } = useCosmicIntersection();\n\n const { data, loading: loadingCollection } = useCosCollectionQuery(id);\n const [createCollection, { loading: creating }] = useCosCreateCollectionMutation();\n const [updateCollection, { loading: updating }] = useCosUpdateCollectionMutation();\n\n const [form, setForm] = useState<CollectionFormState>(INITIAL_STATE);\n\n // Hydrate once the collection loads in edit mode. Derive-state-during-render\n // (keyed on the loaded id) rather than an effect, per platform lint.\n const [loadedId, setLoadedId] = useState<string | null>(null);\n if (isEdit && data?.cosCollection && loadedId !== data.cosCollection.id) {\n const collection = data.cosCollection;\n setLoadedId(collection.id);\n setForm({\n name: collection.name ?? '',\n slug: collection.slug ?? '',\n description: collection.description ?? '',\n isPublic: collection.isPublic,\n tags: collection.tags ?? [],\n });\n }\n\n const onChange = <K extends keyof CollectionFormState>(\n field: K,\n value: CollectionFormState[K]\n ) => {\n setForm((prev) => ({ ...prev, [field]: value }));\n };\n\n const saving = creating || updating;\n\n const onSubmit = async (event: React.FormEvent<HTMLFormElement>) => {\n event.preventDefault();\n\n if (!form.name.trim()) {\n notify.error('Name is required', 'Give this collection a recognizable name.');\n return;\n }\n\n if (isEdit) {\n const input: CosUpdateCollectionInput = {\n name: form.name.trim(),\n slug: form.slug.trim() || undefined,\n description: form.description.trim() || undefined,\n isPublic: form.isPublic,\n tags: form.tags,\n };\n const response = await updateCollection({ variables: { id, input } });\n if (response.data?.cosUpdateCollection?.id) {\n notify.success('Collection updated');\n navigate(`collections/${id}`);\n }\n return;\n }\n\n const input: CosCreateCollectionInput = {\n name: form.name.trim(),\n slug: form.slug.trim() || undefined,\n description: form.description.trim() || undefined,\n isPublic: form.isPublic,\n tags: form.tags,\n };\n const response = await createCollection({ variables: { input } });\n const created = response.data?.cosCreateCollection;\n if (created?.id) {\n notify.success('Collection created');\n navigate(`collections/${created.id}`);\n }\n };\n\n if (isEdit && loadingCollection && !data?.cosCollection) {\n return <LoadingState label=\"Loading collection…\" />;\n }\n\n return (\n <EntityFormShell\n title={isEdit ? 'Edit collection' : 'New collection'}\n description=\"Group related datasets into a shareable, themed collection.\"\n purpose=\"Collections curate datasets by mission, survey or research theme so collaborators can browse a coherent set instead of a flat list. Mark a collection public to make it discoverable across the workspace.\"\n backLabel={isEdit ? 'Back to collection' : 'Back to collections'}\n onBack={() => navigate(isEdit ? `collections/${id}` : 'collections')}\n onSubmit={(event) => void onSubmit(event)}\n submitLabel={isEdit ? 'Save collection' : 'Create collection'}\n saving={saving}\n >\n <div className=\"grid grid-cols-1 gap-4 md:grid-cols-2\">\n <label className={fieldLabelClass}>\n <span className={fieldSpanClass}>Name</span>\n <Input\n value={form.name}\n onChange={(event) => onChange('name', event.target.value)}\n placeholder=\"e.g. Kepler Mission Data\"\n required\n />\n </label>\n <label className={fieldLabelClass}>\n <span className={fieldSpanClass}>Slug</span>\n <Input\n value={form.slug}\n onChange={(event) => onChange('slug', event.target.value)}\n placeholder=\"kepler-mission\"\n />\n <span className=\"text-xs text-text-secondary\">\n Optional URL-friendly identifier for sharing.\n </span>\n </label>\n </div>\n\n <label className={fieldLabelClass}>\n <span className={fieldSpanClass}>Description</span>\n <Textarea\n value={form.description}\n onChange={(event) => onChange('description', event.target.value)}\n rows={3}\n placeholder=\"What this collection groups together and who it is for.\"\n />\n </label>\n\n <div className=\"flex items-center justify-between gap-4 rounded-card border border-border-default bg-bg-sunken px-4 py-3\">\n <div>\n <p className=\"text-sm font-medium text-text-primary\">Public collection</p>\n <p className=\"text-xs text-text-secondary\">\n Make this collection discoverable across the workspace.\n </p>\n </div>\n <Switch\n checked={form.isPublic}\n onCheckedChange={(checked) => onChange('isPublic', checked)}\n aria-label=\"Public collection\"\n />\n </div>\n\n <EntityTagsField\n value={form.tags}\n onChange={(tags) => onChange('tags', tags)}\n disabled={saving}\n />\n </EntityFormShell>\n );\n}\n"],"mappings":"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"}
@@ -15,7 +15,7 @@ import "../../components/index.js";
15
15
  import fe, { buildDatasetLineage as pe } from "../../components/LineageGraph.js";
16
16
  import { useMemo as me, useState as u } from "react";
17
17
  import { Fragment as he, jsx as d, jsxs as f } from "react/jsx-runtime";
18
- import { useParams as ge } from "react-router-dom";
18
+ import { useParams as ge } from "react-router";
19
19
  import { ArrowRight as _e, Boxes as ve, Columns3 as p, Database as ye, Download as be, GitBranch as xe, History as Se, MessagesSquare as Ce, Pencil as we, Plus as Te, Radar as Ee, Share2 as De } from "lucide-react";
20
20
  import { Badge as m, Button as h, Checkbox as Oe, Dialog as ke, DialogContent as Ae, DialogDescription as je, DialogFooter as Me, DialogHeader as Ne, DialogTitle as Pe, Input as g, Label as _, Select as Fe, SelectContent as Ie, SelectItem as Le, SelectTrigger as Re, SelectValue as ze, Table as Be, TableBody as Ve, TableCell as v, TableHead as y, TableHeader as He, TableRow as b, Textarea as Ue } from "@burdenoff/fe-libs/ui";
21
21
  //#region src/cosmicintersection/pages/datasets/DatasetDetailPage.tsx
@@ -1 +1 @@
1
- {"version":3,"file":"DatasetDetailPage.js","names":[],"sources":["../../../../src/cosmicintersection/pages/datasets/DatasetDetailPage.tsx"],"sourcesContent":["import { useMemo, useState } from 'react';\nimport { useParams } from 'react-router-dom';\nimport {\n ArrowRight,\n Boxes,\n Columns3,\n Database,\n Download,\n GitBranch,\n History,\n MessagesSquare,\n Pencil,\n Plus,\n Radar,\n Share2,\n} from 'lucide-react';\nimport {\n Badge,\n Button,\n Checkbox,\n Dialog,\n DialogContent,\n DialogDescription,\n DialogFooter,\n DialogHeader,\n DialogTitle,\n Input,\n Label,\n Select,\n SelectContent,\n SelectItem,\n SelectTrigger,\n SelectValue,\n Table,\n TableBody,\n TableCell,\n TableHead,\n TableHeader,\n TableRow,\n Textarea,\n} from '@burdenoff/fe-libs/ui';\n\nimport {\n useCosAddSchemaFieldMutation,\n useCosAnalysesQuery,\n useCosArchiveDatasetMutation,\n useCosDatasetQuery,\n useCosNotebooksQuery,\n useCosPublishDatasetMutation,\n useCosReleasesQuery,\n useCosRunsQuery,\n useCosUpdateDatasetMutation,\n type CosCollection,\n type CosFieldType,\n type CosSource,\n} from '../../api/cosmicApi';\nimport {\n ActionMenu,\n ActivityFeedPanel,\n DiscussionPanel,\n EmptyState,\n EntityTagsField,\n ErrorState,\n LoadingState,\n PageLayout,\n StatusBadge,\n formatEnumLabel,\n useFileDownloadUrl,\n} from '../../components';\nimport {\n LineageGraph,\n buildDatasetLineage,\n type LineageDataPools,\n} from '../../components/LineageGraph';\nimport { useCosmicIntersection } from '../../context/CosmicIntersectionContext';\nimport { notify } from '../../lib/toast';\n\nconst FIELD_TYPES: CosFieldType[] = [\n 'STRING',\n 'INTEGER',\n 'FLOAT',\n 'BOOLEAN',\n 'TIMESTAMP',\n 'COORDINATE',\n 'SPECTRUM',\n 'GEOMETRY',\n 'IMAGE_REF',\n 'JSON',\n];\n\nfunction formatBytes(raw: string | null | undefined): string {\n if (!raw) {\n return '—';\n }\n const bytes = Number(raw);\n if (!Number.isFinite(bytes) || bytes <= 0) {\n return '—';\n }\n const units = ['B', 'KB', 'MB', 'GB', 'TB', 'PB'];\n let value = bytes;\n let unit = 0;\n while (value >= 1024 && unit < units.length - 1) {\n value /= 1024;\n unit += 1;\n }\n return `${value >= 10 || unit === 0 ? Math.round(value) : value.toFixed(1)} ${units[unit]}`;\n}\n\nfunction formatDateTime(raw: string | null | undefined): string {\n if (!raw) {\n return '—';\n }\n const date = new Date(raw);\n return Number.isNaN(date.getTime()) ? '—' : date.toLocaleString();\n}\n\nfunction MetaTile({ label, value }: { label: string; value: React.ReactNode }) {\n return (\n <div className=\"rounded-card border border-border-default bg-bg-elevated p-4\">\n <p className=\"text-xs font-medium uppercase tracking-wide text-text-secondary\">{label}</p>\n <div className=\"mt-1 text-sm text-text-primary\">{value}</div>\n </div>\n );\n}\n\nexport default function DatasetDetailPage() {\n const { id = '' } = useParams<{ id: string }>();\n const { navigate } = useCosmicIntersection();\n\n const { data, loading, error, refetch } = useCosDatasetQuery(id);\n const dataset = data?.cosDataset ?? null;\n\n const download = useFileDownloadUrl(dataset?.file?.id);\n const downloadUrl = download.data?.getFileDownloadUrl ?? null;\n\n const [publishDataset, { loading: publishing }] = useCosPublishDatasetMutation();\n const [archiveDataset] = useCosArchiveDatasetMutation();\n const [updateDataset, { loading: savingTags }] = useCosUpdateDatasetMutation();\n const [addSchemaField, { loading: addingField }] = useCosAddSchemaFieldMutation();\n\n // Lineage inputs — fetched as lists and filtered client-side to this dataset,\n // then folded into a provenance model by the shared builder. No new backend.\n const analysesQuery = useCosAnalysesQuery({ datasetId: id });\n const runsQuery = useCosRunsQuery({ pagination: { limit: 100, offset: 0 } });\n const notebooksQuery = useCosNotebooksQuery({ pagination: { limit: 100, offset: 0 } });\n const releasesQuery = useCosReleasesQuery({ pagination: { limit: 100, offset: 0 } });\n\n const lineageDataset = data?.cosDataset ?? null;\n const lineageModel = useMemo(() => {\n if (!lineageDataset) {\n return { nodes: [], edges: [] };\n }\n const sourcesById = new Map<string, CosSource>();\n if (lineageDataset.source) {\n sourcesById.set(lineageDataset.source.id, lineageDataset.source);\n }\n const collectionsById = new Map<string, CosCollection>();\n if (lineageDataset.collection) {\n collectionsById.set(lineageDataset.collection.id, lineageDataset.collection);\n }\n const pools: LineageDataPools = {\n datasetsById: new Map([[lineageDataset.id, lineageDataset]]),\n sourcesById,\n collectionsById,\n runs: (runsQuery.data?.cosListRuns?.items ?? []).filter(\n (run) => run.datasetId === lineageDataset.id\n ),\n notebooks: (notebooksQuery.data?.cosListNotebooks?.items ?? []).filter((notebook) =>\n notebook.datasetIds.includes(lineageDataset.id)\n ),\n analyses: analysesQuery.data?.cosListAnalyses ?? [],\n releases: (releasesQuery.data?.cosListReleases?.items ?? []).filter((release) =>\n release.datasetIds.includes(lineageDataset.id)\n ),\n };\n return buildDatasetLineage(lineageDataset.id, pools);\n }, [lineageDataset, runsQuery.data, notebooksQuery.data, analysesQuery.data, releasesQuery.data]);\n const lineageListsLoading =\n runsQuery.loading || notebooksQuery.loading || analysesQuery.loading || releasesQuery.loading;\n\n // Local, dirty-tracked copy of the tags array so we persist explicitly. Re-sync\n // from the server whenever the dataset (or its updatedAt, after a save) changes\n // — the documented derive-state-during-render pattern, no effect needed.\n const [tags, setTags] = useState<string[]>([]);\n const [syncedKey, setSyncedKey] = useState<string | null>(null);\n const datasetKey = dataset ? `${dataset.id}:${dataset.updatedAt}` : null;\n if (datasetKey && datasetKey !== syncedKey) {\n setSyncedKey(datasetKey);\n setTags(dataset?.tags ?? []);\n }\n const tagsDirty =\n dataset != null &&\n (tags.length !== dataset.tags.length || tags.some((tag, i) => tag !== dataset.tags[i]));\n\n // Add-schema-field dialog state.\n const [fieldOpen, setFieldOpen] = useState(false);\n const [fieldName, setFieldName] = useState('');\n const [fieldType, setFieldType] = useState<CosFieldType>('STRING');\n const [fieldUnit, setFieldUnit] = useState('');\n const [fieldDescription, setFieldDescription] = useState('');\n const [fieldProvenance, setFieldProvenance] = useState('');\n const [fieldNullable, setFieldNullable] = useState(true);\n\n const resetFieldForm = () => {\n setFieldName('');\n setFieldType('STRING');\n setFieldUnit('');\n setFieldDescription('');\n setFieldProvenance('');\n setFieldNullable(true);\n };\n\n const setFieldOpenAndReset = (open: boolean) => {\n setFieldOpen(open);\n if (!open) {\n resetFieldForm();\n }\n };\n\n if (loading) {\n return (\n <PageLayout title=\"Dataset\" backPath=\"datasets\">\n <LoadingState label=\"Loading dataset…\" />\n </PageLayout>\n );\n }\n\n if (error) {\n return (\n <PageLayout title=\"Dataset\" backPath=\"datasets\">\n <ErrorState message=\"We could not load this dataset.\" onRetry={() => void refetch()} />\n </PageLayout>\n );\n }\n\n if (!dataset) {\n return (\n <PageLayout title=\"Dataset\" backPath=\"datasets\">\n <EmptyState\n icon={Database}\n title=\"Dataset not found.\"\n description=\"This dataset may have been removed or is outside your current scope.\"\n action={\n <Button type=\"button\" onClick={() => navigate('datasets')}>\n Back to datasets\n </Button>\n }\n />\n </PageLayout>\n );\n }\n\n const schemaFields = [...(dataset.schemaFields ?? [])].sort((a, b) => a.position - b.position);\n const canPublish = dataset.status !== 'AVAILABLE' && dataset.status !== 'ARCHIVED';\n\n const handlePublish = async () => {\n const response = await publishDataset({ variables: { id: dataset.id } });\n if (response.data?.cosPublishDataset) {\n notify.success('Dataset published', `“${dataset.name}” is now available.`);\n await refetch();\n }\n };\n\n const handleArchive = async () => {\n const response = await archiveDataset({ variables: { id: dataset.id } });\n if (response.error) {\n throw new Error(response.error.message);\n }\n if (!response.data?.cosArchiveDataset) {\n notify.error('Could not archive dataset', 'The server did not confirm the change.');\n throw new Error('Archive not confirmed');\n }\n notify.success('Dataset archived');\n navigate('datasets');\n };\n\n const handleSaveTags = async () => {\n const response = await updateDataset({ variables: { id: dataset.id, input: { tags } } });\n if (response.data?.cosUpdateDataset) {\n notify.success('Tags updated');\n await refetch();\n }\n };\n\n const handleAddField = async () => {\n if (!fieldName.trim()) {\n notify.error('Field name is required');\n return;\n }\n const response = await addSchemaField({\n variables: {\n input: {\n datasetId: dataset.id,\n name: fieldName.trim(),\n fieldType,\n unit: fieldUnit.trim() || undefined,\n description: fieldDescription.trim() || undefined,\n provenance: fieldProvenance.trim() || undefined,\n nullable: fieldNullable,\n },\n },\n });\n if (response.data?.cosAddSchemaField) {\n notify.success('Schema field added');\n setFieldOpenAndReset(false);\n await refetch();\n }\n };\n\n return (\n <PageLayout\n title={dataset.name}\n description={dataset.description ?? undefined}\n backPath=\"datasets\"\n actions={\n <div className=\"flex flex-wrap items-center justify-end gap-2\">\n <Button\n type=\"button\"\n variant=\"outline\"\n onClick={() => navigate(`datasets/${dataset.id}/edit`)}\n >\n <Pencil className=\"size-4\" />\n Edit\n </Button>\n {canPublish ? (\n <Button type=\"button\" onClick={() => void handlePublish()} disabled={publishing}>\n {publishing ? 'Publishing…' : 'Publish'}\n </Button>\n ) : null}\n <ActionMenu\n ariaLabel={`Actions for ${dataset.name}`}\n entityName={dataset.name}\n onDelete={() => handleArchive()}\n deleteLabel=\"Archive dataset\"\n />\n </div>\n }\n >\n <div className=\"space-y-6\">\n {/* Status + key facts */}\n <div className=\"flex flex-wrap items-center gap-2\">\n <StatusBadge status={dataset.status} />\n <StatusBadge status={dataset.accessLevel} label={formatEnumLabel(dataset.accessLevel)} />\n <span\n className=\"inline-flex items-center gap-1.5 rounded-full border border-border-default bg-bg-elevated px-2.5 py-0.5 text-xs font-medium\"\n title=\"Current dataset version\"\n >\n <GitBranch className=\"size-3.5 text-text-tertiary\" aria-hidden=\"true\" />\n <span className=\"text-text-primary\">v{dataset.version}</span>\n <span className=\"text-text-tertiary\">· current</span>\n </span>\n </div>\n\n <div className=\"grid grid-cols-1 gap-3 sm:grid-cols-2 lg:grid-cols-4\">\n <MetaTile\n label=\"Source\"\n value={\n dataset.source ? (\n <button\n type=\"button\"\n onClick={() => navigate(`sources/${dataset.source?.id}`)}\n className=\"inline-flex items-center gap-1.5 text-text-primary underline-offset-2 hover:underline\"\n >\n <Radar className=\"size-4 text-text-secondary\" aria-hidden=\"true\" />\n {dataset.source.name}\n </button>\n ) : (\n <span className=\"text-text-secondary\">Not linked</span>\n )\n }\n />\n <MetaTile\n label=\"Collection\"\n value={\n dataset.collection ? (\n <button\n type=\"button\"\n onClick={() => navigate(`collections/${dataset.collection?.id}`)}\n className=\"inline-flex items-center gap-1.5 text-text-primary underline-offset-2 hover:underline\"\n >\n <Boxes className=\"size-4 text-text-secondary\" aria-hidden=\"true\" />\n {dataset.collection.name}\n </button>\n ) : (\n <span className=\"text-text-secondary\">Not in a collection</span>\n )\n }\n />\n <MetaTile label=\"Format\" value={<span>{dataset.format || 'Not specified'}</span>} />\n <MetaTile\n label=\"Size\"\n value={\n <span className=\"tabular-nums\">\n {formatBytes(dataset.sizeBytes)}\n {Number(dataset.rowCount) > 0 ? (\n <span className=\"text-text-secondary\">\n {' '}\n · {Number(dataset.rowCount).toLocaleString()} rows\n </span>\n ) : null}\n </span>\n }\n />\n <MetaTile label=\"Ingested\" value={<span>{formatDateTime(dataset.ingestedAt)}</span>} />\n <MetaTile label=\"Created\" value={<span>{formatDateTime(dataset.createdAt)}</span>} />\n <MetaTile label=\"Updated\" value={<span>{formatDateTime(dataset.updatedAt)}</span>} />\n <MetaTile\n label=\"Artifact\"\n value={\n dataset.file ? (\n downloadUrl ? (\n <a\n href={downloadUrl}\n target=\"_blank\"\n rel=\"noopener noreferrer\"\n className=\"inline-flex items-center gap-1.5 text-text-primary underline-offset-2 hover:underline\"\n >\n <Download className=\"size-4\" aria-hidden=\"true\" />\n Download file\n </a>\n ) : (\n <span className=\"text-text-secondary\">Resolving link…</span>\n )\n ) : (\n <span className=\"text-text-secondary\">No file attached</span>\n )\n }\n />\n </div>\n\n {/* Lineage / provenance */}\n <section className=\"space-y-3\">\n <div className=\"flex items-center justify-between gap-3\">\n <div className=\"flex items-center gap-2\">\n <Share2 className=\"size-5 text-text-secondary\" aria-hidden=\"true\" />\n <h2 className=\"text-lg font-semibold text-text-primary\">Lineage</h2>\n </div>\n <button\n type=\"button\"\n onClick={() => navigate(`lineage/${dataset.id}`)}\n className=\"inline-flex items-center gap-1 rounded-button text-sm font-medium text-text-link underline-offset-2 hover:underline focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-border-focus\"\n >\n View full lineage\n <ArrowRight className=\"size-4\" aria-hidden=\"true\" />\n </button>\n </div>\n {lineageListsLoading && lineageModel.nodes.length <= 1 ? (\n <LoadingState label=\"Building lineage…\" />\n ) : lineageModel.nodes.length <= 1 ? (\n <div className=\"rounded-card border border-dashed border-border-default bg-bg-sunken p-6 text-sm text-text-secondary\">\n No upstream or downstream provenance is linked to this dataset yet. Connect a source,\n run a pipeline, attach a notebook, or publish a release to build its lineage.\n </div>\n ) : (\n <LineageGraph model={lineageModel} mode=\"compact\" onNavigate={navigate} />\n )}\n </section>\n\n {/* Schema fields */}\n <section className=\"space-y-3\">\n <div className=\"flex items-center justify-between gap-3\">\n <div className=\"flex items-center gap-2\">\n <Columns3 className=\"size-5 text-text-secondary\" aria-hidden=\"true\" />\n <h2 className=\"text-lg font-semibold text-text-primary\">Schema fields</h2>\n </div>\n <Button\n type=\"button\"\n variant=\"outline\"\n size=\"sm\"\n onClick={() => setFieldOpenAndReset(true)}\n >\n <Plus className=\"size-4\" />\n Add field\n </Button>\n </div>\n\n {schemaFields.length === 0 ? (\n <EmptyState\n icon={Columns3}\n title=\"No schema fields yet.\"\n description=\"Describe the columns in this dataset so consumers know what each field means.\"\n />\n ) : (\n <>\n {/* Desktop table */}\n <div className=\"hidden rounded-card border border-border-default bg-bg-elevated md:block\">\n <Table>\n <TableHeader>\n <TableRow>\n <TableHead>Name</TableHead>\n <TableHead>Type</TableHead>\n <TableHead>Unit</TableHead>\n <TableHead>Nullable</TableHead>\n <TableHead>Provenance</TableHead>\n </TableRow>\n </TableHeader>\n <TableBody>\n {schemaFields.map((field) => (\n <TableRow key={field.id}>\n <TableCell>\n <span className=\"font-medium text-text-primary\">{field.name}</span>\n {field.description ? (\n <p className=\"mt-0.5 line-clamp-1 max-w-xs text-xs text-text-secondary\">\n {field.description}\n </p>\n ) : null}\n </TableCell>\n <TableCell>\n <Badge variant=\"secondary\">{formatEnumLabel(field.fieldType)}</Badge>\n </TableCell>\n <TableCell className=\"text-sm text-text-secondary\">\n {field.unit || '—'}\n </TableCell>\n <TableCell className=\"text-sm text-text-secondary\">\n {field.nullable ? 'Yes' : 'No'}\n </TableCell>\n <TableCell className=\"text-sm text-text-secondary\">\n {field.provenance || '—'}\n </TableCell>\n </TableRow>\n ))}\n </TableBody>\n </Table>\n </div>\n\n {/* Mobile card list */}\n <div className=\"space-y-2 md:hidden\">\n {schemaFields.map((field) => (\n <div\n key={field.id}\n className=\"rounded-card border border-border-default bg-bg-elevated p-3\"\n >\n <div className=\"flex items-start justify-between gap-2\">\n <span className=\"font-medium text-text-primary\">{field.name}</span>\n <Badge variant=\"secondary\">{formatEnumLabel(field.fieldType)}</Badge>\n </div>\n {field.description ? (\n <p className=\"mt-1 text-xs text-text-secondary\">{field.description}</p>\n ) : null}\n <dl className=\"mt-2 grid grid-cols-2 gap-2 text-xs\">\n <div>\n <dt className=\"text-text-tertiary\">Unit</dt>\n <dd className=\"text-text-secondary\">{field.unit || '—'}</dd>\n </div>\n <div>\n <dt className=\"text-text-tertiary\">Nullable</dt>\n <dd className=\"text-text-secondary\">{field.nullable ? 'Yes' : 'No'}</dd>\n </div>\n <div className=\"col-span-2\">\n <dt className=\"text-text-tertiary\">Provenance</dt>\n <dd className=\"text-text-secondary\">{field.provenance || '—'}</dd>\n </div>\n </dl>\n </div>\n ))}\n </div>\n </>\n )}\n </section>\n\n {/* Tags */}\n <section className=\"space-y-3 rounded-card border border-border-default bg-bg-elevated p-5\">\n <EntityTagsField value={tags} onChange={setTags} label=\"Dataset tags\" />\n {tagsDirty ? (\n <div className=\"flex justify-end\">\n <Button\n type=\"button\"\n size=\"sm\"\n onClick={() => void handleSaveTags()}\n disabled={savingTags}\n >\n {savingTags ? 'Saving…' : 'Save tags'}\n </Button>\n </div>\n ) : null}\n </section>\n\n {/* Activity / history */}\n <section className=\"space-y-3\">\n <div className=\"flex items-center gap-2\">\n <History className=\"size-5 text-text-secondary\" aria-hidden=\"true\" />\n <h2 className=\"text-lg font-semibold text-text-primary\">Activity</h2>\n </div>\n <ActivityFeedPanel resourceId={dataset.id} resourceType=\"cosmicintersection-dataset\" />\n </section>\n\n {/* Discussion */}\n <section className=\"space-y-3\">\n <div className=\"flex items-center gap-2\">\n <MessagesSquare className=\"size-5 text-text-secondary\" aria-hidden=\"true\" />\n <h2 className=\"text-lg font-semibold text-text-primary\">Discussion</h2>\n </div>\n <DiscussionPanel\n entityType=\"cosmicintersection-dataset\"\n entityId={dataset.id}\n title={dataset.name}\n widgetKey=\"dataset-discussion\"\n />\n </section>\n </div>\n\n {/* Add schema field dialog */}\n <Dialog open={fieldOpen} onOpenChange={setFieldOpenAndReset}>\n <DialogContent>\n <DialogHeader>\n <DialogTitle>Add schema field</DialogTitle>\n <DialogDescription>\n Document a column in “{dataset.name}” — its type, unit and provenance.\n </DialogDescription>\n </DialogHeader>\n\n <div className=\"space-y-4\">\n <div className=\"space-y-1.5\">\n <Label htmlFor=\"cos-field-name\">Name</Label>\n <Input\n id=\"cos-field-name\"\n value={fieldName}\n onChange={(event) => setFieldName(event.target.value)}\n placeholder=\"e.g. right_ascension\"\n required\n />\n </div>\n\n <div className=\"grid grid-cols-1 gap-4 sm:grid-cols-2\">\n <div className=\"space-y-1.5\">\n <Label htmlFor=\"cos-field-type\">Type</Label>\n <Select\n value={fieldType}\n onValueChange={(value) => setFieldType(value as CosFieldType)}\n >\n <SelectTrigger id=\"cos-field-type\" aria-label=\"Field type\">\n <SelectValue />\n </SelectTrigger>\n <SelectContent>\n {FIELD_TYPES.map((type) => (\n <SelectItem key={type} value={type}>\n {formatEnumLabel(type)}\n </SelectItem>\n ))}\n </SelectContent>\n </Select>\n </div>\n <div className=\"space-y-1.5\">\n <Label htmlFor=\"cos-field-unit\">Unit</Label>\n <Input\n id=\"cos-field-unit\"\n value={fieldUnit}\n onChange={(event) => setFieldUnit(event.target.value)}\n placeholder=\"e.g. deg, mag, Jy\"\n />\n </div>\n </div>\n\n <div className=\"space-y-1.5\">\n <Label htmlFor=\"cos-field-desc\">Description</Label>\n <Textarea\n id=\"cos-field-desc\"\n value={fieldDescription}\n onChange={(event) => setFieldDescription(event.target.value)}\n rows={2}\n />\n </div>\n\n <div className=\"space-y-1.5\">\n <Label htmlFor=\"cos-field-prov\">Provenance</Label>\n <Input\n id=\"cos-field-prov\"\n value={fieldProvenance}\n onChange={(event) => setFieldProvenance(event.target.value)}\n placeholder=\"Where this field comes from\"\n />\n </div>\n\n <label className=\"flex items-center gap-2 text-sm text-text-primary\">\n <Checkbox\n checked={fieldNullable}\n onCheckedChange={(checked) => setFieldNullable(checked === true)}\n />\n Nullable (may contain empty values)\n </label>\n </div>\n\n <DialogFooter>\n <Button\n type=\"button\"\n variant=\"outline\"\n onClick={() => setFieldOpenAndReset(false)}\n disabled={addingField}\n >\n Cancel\n </Button>\n <Button type=\"button\" onClick={() => void handleAddField()} disabled={addingField}>\n {addingField ? 'Adding…' : 'Add field'}\n </Button>\n </DialogFooter>\n </DialogContent>\n </Dialog>\n </PageLayout>\n );\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"DatasetDetailPage.js","names":[],"sources":["../../../../src/cosmicintersection/pages/datasets/DatasetDetailPage.tsx"],"sourcesContent":["import { useMemo, useState } from 'react';\nimport { useParams } from 'react-router';\nimport {\n ArrowRight,\n Boxes,\n Columns3,\n Database,\n Download,\n GitBranch,\n History,\n MessagesSquare,\n Pencil,\n Plus,\n Radar,\n Share2,\n} from 'lucide-react';\nimport {\n Badge,\n Button,\n Checkbox,\n Dialog,\n DialogContent,\n DialogDescription,\n DialogFooter,\n DialogHeader,\n DialogTitle,\n Input,\n Label,\n Select,\n SelectContent,\n SelectItem,\n SelectTrigger,\n SelectValue,\n Table,\n TableBody,\n TableCell,\n TableHead,\n TableHeader,\n TableRow,\n Textarea,\n} from '@burdenoff/fe-libs/ui';\n\nimport {\n useCosAddSchemaFieldMutation,\n useCosAnalysesQuery,\n useCosArchiveDatasetMutation,\n useCosDatasetQuery,\n useCosNotebooksQuery,\n useCosPublishDatasetMutation,\n useCosReleasesQuery,\n useCosRunsQuery,\n useCosUpdateDatasetMutation,\n type CosCollection,\n type CosFieldType,\n type CosSource,\n} from '../../api/cosmicApi';\nimport {\n ActionMenu,\n ActivityFeedPanel,\n DiscussionPanel,\n EmptyState,\n EntityTagsField,\n ErrorState,\n LoadingState,\n PageLayout,\n StatusBadge,\n formatEnumLabel,\n useFileDownloadUrl,\n} from '../../components';\nimport {\n LineageGraph,\n buildDatasetLineage,\n type LineageDataPools,\n} from '../../components/LineageGraph';\nimport { useCosmicIntersection } from '../../context/CosmicIntersectionContext';\nimport { notify } from '../../lib/toast';\n\nconst FIELD_TYPES: CosFieldType[] = [\n 'STRING',\n 'INTEGER',\n 'FLOAT',\n 'BOOLEAN',\n 'TIMESTAMP',\n 'COORDINATE',\n 'SPECTRUM',\n 'GEOMETRY',\n 'IMAGE_REF',\n 'JSON',\n];\n\nfunction formatBytes(raw: string | null | undefined): string {\n if (!raw) {\n return '—';\n }\n const bytes = Number(raw);\n if (!Number.isFinite(bytes) || bytes <= 0) {\n return '—';\n }\n const units = ['B', 'KB', 'MB', 'GB', 'TB', 'PB'];\n let value = bytes;\n let unit = 0;\n while (value >= 1024 && unit < units.length - 1) {\n value /= 1024;\n unit += 1;\n }\n return `${value >= 10 || unit === 0 ? Math.round(value) : value.toFixed(1)} ${units[unit]}`;\n}\n\nfunction formatDateTime(raw: string | null | undefined): string {\n if (!raw) {\n return '—';\n }\n const date = new Date(raw);\n return Number.isNaN(date.getTime()) ? '—' : date.toLocaleString();\n}\n\nfunction MetaTile({ label, value }: { label: string; value: React.ReactNode }) {\n return (\n <div className=\"rounded-card border border-border-default bg-bg-elevated p-4\">\n <p className=\"text-xs font-medium uppercase tracking-wide text-text-secondary\">{label}</p>\n <div className=\"mt-1 text-sm text-text-primary\">{value}</div>\n </div>\n );\n}\n\nexport default function DatasetDetailPage() {\n const { id = '' } = useParams<{ id: string }>();\n const { navigate } = useCosmicIntersection();\n\n const { data, loading, error, refetch } = useCosDatasetQuery(id);\n const dataset = data?.cosDataset ?? null;\n\n const download = useFileDownloadUrl(dataset?.file?.id);\n const downloadUrl = download.data?.getFileDownloadUrl ?? null;\n\n const [publishDataset, { loading: publishing }] = useCosPublishDatasetMutation();\n const [archiveDataset] = useCosArchiveDatasetMutation();\n const [updateDataset, { loading: savingTags }] = useCosUpdateDatasetMutation();\n const [addSchemaField, { loading: addingField }] = useCosAddSchemaFieldMutation();\n\n // Lineage inputs — fetched as lists and filtered client-side to this dataset,\n // then folded into a provenance model by the shared builder. No new backend.\n const analysesQuery = useCosAnalysesQuery({ datasetId: id });\n const runsQuery = useCosRunsQuery({ pagination: { limit: 100, offset: 0 } });\n const notebooksQuery = useCosNotebooksQuery({ pagination: { limit: 100, offset: 0 } });\n const releasesQuery = useCosReleasesQuery({ pagination: { limit: 100, offset: 0 } });\n\n const lineageDataset = data?.cosDataset ?? null;\n const lineageModel = useMemo(() => {\n if (!lineageDataset) {\n return { nodes: [], edges: [] };\n }\n const sourcesById = new Map<string, CosSource>();\n if (lineageDataset.source) {\n sourcesById.set(lineageDataset.source.id, lineageDataset.source);\n }\n const collectionsById = new Map<string, CosCollection>();\n if (lineageDataset.collection) {\n collectionsById.set(lineageDataset.collection.id, lineageDataset.collection);\n }\n const pools: LineageDataPools = {\n datasetsById: new Map([[lineageDataset.id, lineageDataset]]),\n sourcesById,\n collectionsById,\n runs: (runsQuery.data?.cosListRuns?.items ?? []).filter(\n (run) => run.datasetId === lineageDataset.id\n ),\n notebooks: (notebooksQuery.data?.cosListNotebooks?.items ?? []).filter((notebook) =>\n notebook.datasetIds.includes(lineageDataset.id)\n ),\n analyses: analysesQuery.data?.cosListAnalyses ?? [],\n releases: (releasesQuery.data?.cosListReleases?.items ?? []).filter((release) =>\n release.datasetIds.includes(lineageDataset.id)\n ),\n };\n return buildDatasetLineage(lineageDataset.id, pools);\n }, [lineageDataset, runsQuery.data, notebooksQuery.data, analysesQuery.data, releasesQuery.data]);\n const lineageListsLoading =\n runsQuery.loading || notebooksQuery.loading || analysesQuery.loading || releasesQuery.loading;\n\n // Local, dirty-tracked copy of the tags array so we persist explicitly. Re-sync\n // from the server whenever the dataset (or its updatedAt, after a save) changes\n // — the documented derive-state-during-render pattern, no effect needed.\n const [tags, setTags] = useState<string[]>([]);\n const [syncedKey, setSyncedKey] = useState<string | null>(null);\n const datasetKey = dataset ? `${dataset.id}:${dataset.updatedAt}` : null;\n if (datasetKey && datasetKey !== syncedKey) {\n setSyncedKey(datasetKey);\n setTags(dataset?.tags ?? []);\n }\n const tagsDirty =\n dataset != null &&\n (tags.length !== dataset.tags.length || tags.some((tag, i) => tag !== dataset.tags[i]));\n\n // Add-schema-field dialog state.\n const [fieldOpen, setFieldOpen] = useState(false);\n const [fieldName, setFieldName] = useState('');\n const [fieldType, setFieldType] = useState<CosFieldType>('STRING');\n const [fieldUnit, setFieldUnit] = useState('');\n const [fieldDescription, setFieldDescription] = useState('');\n const [fieldProvenance, setFieldProvenance] = useState('');\n const [fieldNullable, setFieldNullable] = useState(true);\n\n const resetFieldForm = () => {\n setFieldName('');\n setFieldType('STRING');\n setFieldUnit('');\n setFieldDescription('');\n setFieldProvenance('');\n setFieldNullable(true);\n };\n\n const setFieldOpenAndReset = (open: boolean) => {\n setFieldOpen(open);\n if (!open) {\n resetFieldForm();\n }\n };\n\n if (loading) {\n return (\n <PageLayout title=\"Dataset\" backPath=\"datasets\">\n <LoadingState label=\"Loading dataset…\" />\n </PageLayout>\n );\n }\n\n if (error) {\n return (\n <PageLayout title=\"Dataset\" backPath=\"datasets\">\n <ErrorState message=\"We could not load this dataset.\" onRetry={() => void refetch()} />\n </PageLayout>\n );\n }\n\n if (!dataset) {\n return (\n <PageLayout title=\"Dataset\" backPath=\"datasets\">\n <EmptyState\n icon={Database}\n title=\"Dataset not found.\"\n description=\"This dataset may have been removed or is outside your current scope.\"\n action={\n <Button type=\"button\" onClick={() => navigate('datasets')}>\n Back to datasets\n </Button>\n }\n />\n </PageLayout>\n );\n }\n\n const schemaFields = [...(dataset.schemaFields ?? [])].sort((a, b) => a.position - b.position);\n const canPublish = dataset.status !== 'AVAILABLE' && dataset.status !== 'ARCHIVED';\n\n const handlePublish = async () => {\n const response = await publishDataset({ variables: { id: dataset.id } });\n if (response.data?.cosPublishDataset) {\n notify.success('Dataset published', `“${dataset.name}” is now available.`);\n await refetch();\n }\n };\n\n const handleArchive = async () => {\n const response = await archiveDataset({ variables: { id: dataset.id } });\n if (response.error) {\n throw new Error(response.error.message);\n }\n if (!response.data?.cosArchiveDataset) {\n notify.error('Could not archive dataset', 'The server did not confirm the change.');\n throw new Error('Archive not confirmed');\n }\n notify.success('Dataset archived');\n navigate('datasets');\n };\n\n const handleSaveTags = async () => {\n const response = await updateDataset({ variables: { id: dataset.id, input: { tags } } });\n if (response.data?.cosUpdateDataset) {\n notify.success('Tags updated');\n await refetch();\n }\n };\n\n const handleAddField = async () => {\n if (!fieldName.trim()) {\n notify.error('Field name is required');\n return;\n }\n const response = await addSchemaField({\n variables: {\n input: {\n datasetId: dataset.id,\n name: fieldName.trim(),\n fieldType,\n unit: fieldUnit.trim() || undefined,\n description: fieldDescription.trim() || undefined,\n provenance: fieldProvenance.trim() || undefined,\n nullable: fieldNullable,\n },\n },\n });\n if (response.data?.cosAddSchemaField) {\n notify.success('Schema field added');\n setFieldOpenAndReset(false);\n await refetch();\n }\n };\n\n return (\n <PageLayout\n title={dataset.name}\n description={dataset.description ?? undefined}\n backPath=\"datasets\"\n actions={\n <div className=\"flex flex-wrap items-center justify-end gap-2\">\n <Button\n type=\"button\"\n variant=\"outline\"\n onClick={() => navigate(`datasets/${dataset.id}/edit`)}\n >\n <Pencil className=\"size-4\" />\n Edit\n </Button>\n {canPublish ? (\n <Button type=\"button\" onClick={() => void handlePublish()} disabled={publishing}>\n {publishing ? 'Publishing…' : 'Publish'}\n </Button>\n ) : null}\n <ActionMenu\n ariaLabel={`Actions for ${dataset.name}`}\n entityName={dataset.name}\n onDelete={() => handleArchive()}\n deleteLabel=\"Archive dataset\"\n />\n </div>\n }\n >\n <div className=\"space-y-6\">\n {/* Status + key facts */}\n <div className=\"flex flex-wrap items-center gap-2\">\n <StatusBadge status={dataset.status} />\n <StatusBadge status={dataset.accessLevel} label={formatEnumLabel(dataset.accessLevel)} />\n <span\n className=\"inline-flex items-center gap-1.5 rounded-full border border-border-default bg-bg-elevated px-2.5 py-0.5 text-xs font-medium\"\n title=\"Current dataset version\"\n >\n <GitBranch className=\"size-3.5 text-text-tertiary\" aria-hidden=\"true\" />\n <span className=\"text-text-primary\">v{dataset.version}</span>\n <span className=\"text-text-tertiary\">· current</span>\n </span>\n </div>\n\n <div className=\"grid grid-cols-1 gap-3 sm:grid-cols-2 lg:grid-cols-4\">\n <MetaTile\n label=\"Source\"\n value={\n dataset.source ? (\n <button\n type=\"button\"\n onClick={() => navigate(`sources/${dataset.source?.id}`)}\n className=\"inline-flex items-center gap-1.5 text-text-primary underline-offset-2 hover:underline\"\n >\n <Radar className=\"size-4 text-text-secondary\" aria-hidden=\"true\" />\n {dataset.source.name}\n </button>\n ) : (\n <span className=\"text-text-secondary\">Not linked</span>\n )\n }\n />\n <MetaTile\n label=\"Collection\"\n value={\n dataset.collection ? (\n <button\n type=\"button\"\n onClick={() => navigate(`collections/${dataset.collection?.id}`)}\n className=\"inline-flex items-center gap-1.5 text-text-primary underline-offset-2 hover:underline\"\n >\n <Boxes className=\"size-4 text-text-secondary\" aria-hidden=\"true\" />\n {dataset.collection.name}\n </button>\n ) : (\n <span className=\"text-text-secondary\">Not in a collection</span>\n )\n }\n />\n <MetaTile label=\"Format\" value={<span>{dataset.format || 'Not specified'}</span>} />\n <MetaTile\n label=\"Size\"\n value={\n <span className=\"tabular-nums\">\n {formatBytes(dataset.sizeBytes)}\n {Number(dataset.rowCount) > 0 ? (\n <span className=\"text-text-secondary\">\n {' '}\n · {Number(dataset.rowCount).toLocaleString()} rows\n </span>\n ) : null}\n </span>\n }\n />\n <MetaTile label=\"Ingested\" value={<span>{formatDateTime(dataset.ingestedAt)}</span>} />\n <MetaTile label=\"Created\" value={<span>{formatDateTime(dataset.createdAt)}</span>} />\n <MetaTile label=\"Updated\" value={<span>{formatDateTime(dataset.updatedAt)}</span>} />\n <MetaTile\n label=\"Artifact\"\n value={\n dataset.file ? (\n downloadUrl ? (\n <a\n href={downloadUrl}\n target=\"_blank\"\n rel=\"noopener noreferrer\"\n className=\"inline-flex items-center gap-1.5 text-text-primary underline-offset-2 hover:underline\"\n >\n <Download className=\"size-4\" aria-hidden=\"true\" />\n Download file\n </a>\n ) : (\n <span className=\"text-text-secondary\">Resolving link…</span>\n )\n ) : (\n <span className=\"text-text-secondary\">No file attached</span>\n )\n }\n />\n </div>\n\n {/* Lineage / provenance */}\n <section className=\"space-y-3\">\n <div className=\"flex items-center justify-between gap-3\">\n <div className=\"flex items-center gap-2\">\n <Share2 className=\"size-5 text-text-secondary\" aria-hidden=\"true\" />\n <h2 className=\"text-lg font-semibold text-text-primary\">Lineage</h2>\n </div>\n <button\n type=\"button\"\n onClick={() => navigate(`lineage/${dataset.id}`)}\n className=\"inline-flex items-center gap-1 rounded-button text-sm font-medium text-text-link underline-offset-2 hover:underline focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-border-focus\"\n >\n View full lineage\n <ArrowRight className=\"size-4\" aria-hidden=\"true\" />\n </button>\n </div>\n {lineageListsLoading && lineageModel.nodes.length <= 1 ? (\n <LoadingState label=\"Building lineage…\" />\n ) : lineageModel.nodes.length <= 1 ? (\n <div className=\"rounded-card border border-dashed border-border-default bg-bg-sunken p-6 text-sm text-text-secondary\">\n No upstream or downstream provenance is linked to this dataset yet. Connect a source,\n run a pipeline, attach a notebook, or publish a release to build its lineage.\n </div>\n ) : (\n <LineageGraph model={lineageModel} mode=\"compact\" onNavigate={navigate} />\n )}\n </section>\n\n {/* Schema fields */}\n <section className=\"space-y-3\">\n <div className=\"flex items-center justify-between gap-3\">\n <div className=\"flex items-center gap-2\">\n <Columns3 className=\"size-5 text-text-secondary\" aria-hidden=\"true\" />\n <h2 className=\"text-lg font-semibold text-text-primary\">Schema fields</h2>\n </div>\n <Button\n type=\"button\"\n variant=\"outline\"\n size=\"sm\"\n onClick={() => setFieldOpenAndReset(true)}\n >\n <Plus className=\"size-4\" />\n Add field\n </Button>\n </div>\n\n {schemaFields.length === 0 ? (\n <EmptyState\n icon={Columns3}\n title=\"No schema fields yet.\"\n description=\"Describe the columns in this dataset so consumers know what each field means.\"\n />\n ) : (\n <>\n {/* Desktop table */}\n <div className=\"hidden rounded-card border border-border-default bg-bg-elevated md:block\">\n <Table>\n <TableHeader>\n <TableRow>\n <TableHead>Name</TableHead>\n <TableHead>Type</TableHead>\n <TableHead>Unit</TableHead>\n <TableHead>Nullable</TableHead>\n <TableHead>Provenance</TableHead>\n </TableRow>\n </TableHeader>\n <TableBody>\n {schemaFields.map((field) => (\n <TableRow key={field.id}>\n <TableCell>\n <span className=\"font-medium text-text-primary\">{field.name}</span>\n {field.description ? (\n <p className=\"mt-0.5 line-clamp-1 max-w-xs text-xs text-text-secondary\">\n {field.description}\n </p>\n ) : null}\n </TableCell>\n <TableCell>\n <Badge variant=\"secondary\">{formatEnumLabel(field.fieldType)}</Badge>\n </TableCell>\n <TableCell className=\"text-sm text-text-secondary\">\n {field.unit || '—'}\n </TableCell>\n <TableCell className=\"text-sm text-text-secondary\">\n {field.nullable ? 'Yes' : 'No'}\n </TableCell>\n <TableCell className=\"text-sm text-text-secondary\">\n {field.provenance || '—'}\n </TableCell>\n </TableRow>\n ))}\n </TableBody>\n </Table>\n </div>\n\n {/* Mobile card list */}\n <div className=\"space-y-2 md:hidden\">\n {schemaFields.map((field) => (\n <div\n key={field.id}\n className=\"rounded-card border border-border-default bg-bg-elevated p-3\"\n >\n <div className=\"flex items-start justify-between gap-2\">\n <span className=\"font-medium text-text-primary\">{field.name}</span>\n <Badge variant=\"secondary\">{formatEnumLabel(field.fieldType)}</Badge>\n </div>\n {field.description ? (\n <p className=\"mt-1 text-xs text-text-secondary\">{field.description}</p>\n ) : null}\n <dl className=\"mt-2 grid grid-cols-2 gap-2 text-xs\">\n <div>\n <dt className=\"text-text-tertiary\">Unit</dt>\n <dd className=\"text-text-secondary\">{field.unit || '—'}</dd>\n </div>\n <div>\n <dt className=\"text-text-tertiary\">Nullable</dt>\n <dd className=\"text-text-secondary\">{field.nullable ? 'Yes' : 'No'}</dd>\n </div>\n <div className=\"col-span-2\">\n <dt className=\"text-text-tertiary\">Provenance</dt>\n <dd className=\"text-text-secondary\">{field.provenance || '—'}</dd>\n </div>\n </dl>\n </div>\n ))}\n </div>\n </>\n )}\n </section>\n\n {/* Tags */}\n <section className=\"space-y-3 rounded-card border border-border-default bg-bg-elevated p-5\">\n <EntityTagsField value={tags} onChange={setTags} label=\"Dataset tags\" />\n {tagsDirty ? (\n <div className=\"flex justify-end\">\n <Button\n type=\"button\"\n size=\"sm\"\n onClick={() => void handleSaveTags()}\n disabled={savingTags}\n >\n {savingTags ? 'Saving…' : 'Save tags'}\n </Button>\n </div>\n ) : null}\n </section>\n\n {/* Activity / history */}\n <section className=\"space-y-3\">\n <div className=\"flex items-center gap-2\">\n <History className=\"size-5 text-text-secondary\" aria-hidden=\"true\" />\n <h2 className=\"text-lg font-semibold text-text-primary\">Activity</h2>\n </div>\n <ActivityFeedPanel resourceId={dataset.id} resourceType=\"cosmicintersection-dataset\" />\n </section>\n\n {/* Discussion */}\n <section className=\"space-y-3\">\n <div className=\"flex items-center gap-2\">\n <MessagesSquare className=\"size-5 text-text-secondary\" aria-hidden=\"true\" />\n <h2 className=\"text-lg font-semibold text-text-primary\">Discussion</h2>\n </div>\n <DiscussionPanel\n entityType=\"cosmicintersection-dataset\"\n entityId={dataset.id}\n title={dataset.name}\n widgetKey=\"dataset-discussion\"\n />\n </section>\n </div>\n\n {/* Add schema field dialog */}\n <Dialog open={fieldOpen} onOpenChange={setFieldOpenAndReset}>\n <DialogContent>\n <DialogHeader>\n <DialogTitle>Add schema field</DialogTitle>\n <DialogDescription>\n Document a column in “{dataset.name}” — its type, unit and provenance.\n </DialogDescription>\n </DialogHeader>\n\n <div className=\"space-y-4\">\n <div className=\"space-y-1.5\">\n <Label htmlFor=\"cos-field-name\">Name</Label>\n <Input\n id=\"cos-field-name\"\n value={fieldName}\n onChange={(event) => setFieldName(event.target.value)}\n placeholder=\"e.g. right_ascension\"\n required\n />\n </div>\n\n <div className=\"grid grid-cols-1 gap-4 sm:grid-cols-2\">\n <div className=\"space-y-1.5\">\n <Label htmlFor=\"cos-field-type\">Type</Label>\n <Select\n value={fieldType}\n onValueChange={(value) => setFieldType(value as CosFieldType)}\n >\n <SelectTrigger id=\"cos-field-type\" aria-label=\"Field type\">\n <SelectValue />\n </SelectTrigger>\n <SelectContent>\n {FIELD_TYPES.map((type) => (\n <SelectItem key={type} value={type}>\n {formatEnumLabel(type)}\n </SelectItem>\n ))}\n </SelectContent>\n </Select>\n </div>\n <div className=\"space-y-1.5\">\n <Label htmlFor=\"cos-field-unit\">Unit</Label>\n <Input\n id=\"cos-field-unit\"\n value={fieldUnit}\n onChange={(event) => setFieldUnit(event.target.value)}\n placeholder=\"e.g. deg, mag, Jy\"\n />\n </div>\n </div>\n\n <div className=\"space-y-1.5\">\n <Label htmlFor=\"cos-field-desc\">Description</Label>\n <Textarea\n id=\"cos-field-desc\"\n value={fieldDescription}\n onChange={(event) => setFieldDescription(event.target.value)}\n rows={2}\n />\n </div>\n\n <div className=\"space-y-1.5\">\n <Label htmlFor=\"cos-field-prov\">Provenance</Label>\n <Input\n id=\"cos-field-prov\"\n value={fieldProvenance}\n onChange={(event) => setFieldProvenance(event.target.value)}\n placeholder=\"Where this field comes from\"\n />\n </div>\n\n <label className=\"flex items-center gap-2 text-sm text-text-primary\">\n <Checkbox\n checked={fieldNullable}\n onCheckedChange={(checked) => setFieldNullable(checked === true)}\n />\n Nullable (may contain empty values)\n </label>\n </div>\n\n <DialogFooter>\n <Button\n type=\"button\"\n variant=\"outline\"\n onClick={() => setFieldOpenAndReset(false)}\n disabled={addingField}\n >\n Cancel\n </Button>\n <Button type=\"button\" onClick={() => void handleAddField()} disabled={addingField}>\n {addingField ? 'Adding…' : 'Add field'}\n </Button>\n </DialogFooter>\n </DialogContent>\n </Dialog>\n </PageLayout>\n );\n}\n"],"mappings":"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"}
@@ -9,7 +9,7 @@ import { formatEnumLabel as d } from "../../components/StatusBadge.js";
9
9
  import "../../components/index.js";
10
10
  import { useMemo as f, useState as p } from "react";
11
11
  import { jsx as m, jsxs as h } from "react/jsx-runtime";
12
- import { useParams as g } from "react-router-dom";
12
+ import { useParams as g } from "react-router";
13
13
  import { Input as _, Label as v, Select as y, SelectContent as b, SelectItem as x, SelectTrigger as S, SelectValue as C, Textarea as w } from "@burdenoff/fe-libs/ui";
14
14
  //#region src/cosmicintersection/pages/datasets/DatasetFormPage.tsx
15
15
  var T = [
@@ -1 +1 @@
1
- {"version":3,"file":"DatasetFormPage.js","names":[],"sources":["../../../../src/cosmicintersection/pages/datasets/DatasetFormPage.tsx"],"sourcesContent":["import { useMemo, useState } from 'react';\nimport { useParams } from 'react-router-dom';\nimport {\n Input,\n Label,\n Select,\n SelectContent,\n SelectItem,\n SelectTrigger,\n SelectValue,\n Textarea,\n} from '@burdenoff/fe-libs/ui';\n\nimport {\n useCosCollectionsQuery,\n useCosCreateDatasetMutation,\n useCosDatasetQuery,\n useCosSourcesQuery,\n useCosUpdateDatasetMutation,\n type CosAccessLevel,\n type CosCreateDatasetInput,\n type CosUpdateDatasetInput,\n} from '../../api/cosmicApi';\nimport {\n EntityFormShell,\n FileUploadField,\n EntityTagsField,\n LoadingState,\n formatEnumLabel,\n} from '../../components';\nimport { useCosmicIntersection } from '../../context/CosmicIntersectionContext';\nimport { notify } from '../../lib/toast';\n\nconst ACCESS_LEVELS: CosAccessLevel[] = ['PUBLIC', 'WORKSPACE', 'RESTRICTED', 'EMBARGOED'];\n\nconst NONE = '__none__';\n\ninterface DatasetFormState {\n name: string;\n description: string;\n format: string;\n accessLevel: CosAccessLevel;\n sourceId: string;\n collectionId: string;\n tags: string[];\n fileId: string;\n}\n\nconst initialState: DatasetFormState = {\n name: '',\n description: '',\n format: '',\n accessLevel: 'WORKSPACE',\n sourceId: NONE,\n collectionId: NONE,\n tags: [],\n fileId: '',\n};\n\nexport default function DatasetFormPage() {\n const { id = '' } = useParams<{ id: string }>();\n const isEdit = useMemo(() => Boolean(id), [id]);\n const { navigate } = useCosmicIntersection();\n\n const { data, loading: loadingDataset } = useCosDatasetQuery(id);\n const sourcesQuery = useCosSourcesQuery({ pagination: { limit: 100, offset: 0 } });\n const collectionsQuery = useCosCollectionsQuery();\n\n const [createDataset, { loading: creating }] = useCosCreateDatasetMutation();\n const [updateDataset, { loading: updating }] = useCosUpdateDatasetMutation();\n\n const [form, setForm] = useState<DatasetFormState>(initialState);\n\n // Hydrate the form once the dataset loads in edit mode. Derive-state-during-\n // render (keyed on the loaded id) rather than an effect, per platform lint.\n const [loadedId, setLoadedId] = useState<string | null>(null);\n if (isEdit && data?.cosDataset && loadedId !== data.cosDataset.id) {\n const ds = data.cosDataset;\n setLoadedId(ds.id);\n setForm({\n name: ds.name ?? '',\n description: ds.description ?? '',\n format: ds.format ?? '',\n accessLevel: ds.accessLevel ?? 'WORKSPACE',\n sourceId: ds.sourceId ?? NONE,\n collectionId: ds.collectionId ?? NONE,\n tags: ds.tags ?? [],\n fileId: ds.file?.id ?? '',\n });\n }\n\n const setField = <K extends keyof DatasetFormState>(field: K, value: DatasetFormState[K]) => {\n setForm((prev) => ({ ...prev, [field]: value }));\n };\n\n const sources = sourcesQuery.data?.cosListSources?.items ?? [];\n const collections = collectionsQuery.data?.cosListCollections ?? [];\n const isSaving = creating || updating;\n\n const onSubmit = async (event: React.FormEvent<HTMLFormElement>) => {\n event.preventDefault();\n if (!form.name.trim()) {\n notify.error('Name is required');\n return;\n }\n\n if (isEdit) {\n // CosUpdateDatasetInput does not accept sourceId/fileId — those are set at\n // creation time and are read-only afterwards.\n const input: CosUpdateDatasetInput = {\n name: form.name.trim(),\n description: form.description.trim() || undefined,\n format: form.format.trim() || undefined,\n accessLevel: form.accessLevel,\n collectionId: form.collectionId === NONE ? undefined : form.collectionId,\n tags: form.tags,\n };\n const response = await updateDataset({ variables: { id, input } });\n if (response.data?.cosUpdateDataset) {\n notify.success('Dataset updated');\n navigate(`datasets/${id}`);\n }\n return;\n }\n\n const input: CosCreateDatasetInput = {\n name: form.name.trim(),\n description: form.description.trim() || undefined,\n format: form.format.trim() || undefined,\n accessLevel: form.accessLevel,\n sourceId: form.sourceId === NONE ? undefined : form.sourceId,\n collectionId: form.collectionId === NONE ? undefined : form.collectionId,\n tags: form.tags,\n fileId: form.fileId || undefined,\n };\n const response = await createDataset({ variables: { input } });\n const createdId = response.data?.cosCreateDataset?.id;\n if (createdId) {\n notify.success('Dataset created');\n navigate(`datasets/${createdId}`);\n }\n };\n\n if (isEdit && loadingDataset && !data?.cosDataset) {\n return <LoadingState label=\"Loading dataset…\" />;\n }\n\n return (\n <EntityFormShell\n title={isEdit ? 'Edit dataset' : 'New dataset'}\n description=\"Register a federated science dataset with its access level, source and schema.\"\n purpose=\"Datasets are the core unit of federation — catalog the data once, describe where it comes from and how it can be accessed, then reuse it across pipelines, notebooks and releases.\"\n backLabel=\"Back to datasets\"\n onBack={() => navigate(isEdit ? `datasets/${id}` : 'datasets')}\n onSubmit={onSubmit}\n submitLabel={isEdit ? 'Save dataset' : 'Create dataset'}\n saving={isSaving}\n submitDisabled={!form.name.trim()}\n >\n <div className=\"grid grid-cols-1 gap-4 md:grid-cols-2\">\n <div className=\"space-y-1.5 md:col-span-2\">\n <Label htmlFor=\"cos-ds-name\">Name</Label>\n <Input\n id=\"cos-ds-name\"\n value={form.name}\n onChange={(event) => setField('name', event.target.value)}\n placeholder=\"e.g. Kepler DR3 light curves\"\n required\n />\n </div>\n\n <div className=\"space-y-1.5 md:col-span-2\">\n <Label htmlFor=\"cos-ds-desc\">Description</Label>\n <Textarea\n id=\"cos-ds-desc\"\n value={form.description}\n onChange={(event) => setField('description', event.target.value)}\n rows={3}\n placeholder=\"What this dataset contains and how it was produced.\"\n />\n </div>\n\n <div className=\"space-y-1.5\">\n <Label htmlFor=\"cos-ds-format\">Format</Label>\n <Input\n id=\"cos-ds-format\"\n value={form.format}\n onChange={(event) => setField('format', event.target.value)}\n placeholder=\"e.g. FITS, Parquet, CSV\"\n />\n </div>\n\n <div className=\"space-y-1.5\">\n <Label htmlFor=\"cos-ds-access\">Access level</Label>\n <Select\n value={form.accessLevel}\n onValueChange={(value) => setField('accessLevel', value as CosAccessLevel)}\n >\n <SelectTrigger id=\"cos-ds-access\" aria-label=\"Access level\">\n <SelectValue />\n </SelectTrigger>\n <SelectContent>\n {ACCESS_LEVELS.map((level) => (\n <SelectItem key={level} value={level}>\n {formatEnumLabel(level)}\n </SelectItem>\n ))}\n </SelectContent>\n </Select>\n </div>\n\n {!isEdit ? (\n <div className=\"space-y-1.5\">\n <Label htmlFor=\"cos-ds-source\">Source</Label>\n <Select value={form.sourceId} onValueChange={(value) => setField('sourceId', value)}>\n <SelectTrigger id=\"cos-ds-source\" aria-label=\"Source\">\n <SelectValue />\n </SelectTrigger>\n <SelectContent>\n <SelectItem value={NONE}>No source</SelectItem>\n {sources.map((source) => (\n <SelectItem key={source.id} value={source.id}>\n {source.name}\n </SelectItem>\n ))}\n </SelectContent>\n </Select>\n </div>\n ) : null}\n\n <div className=\"space-y-1.5\">\n <Label htmlFor=\"cos-ds-collection\">Collection</Label>\n <Select\n value={form.collectionId}\n onValueChange={(value) => setField('collectionId', value)}\n >\n <SelectTrigger id=\"cos-ds-collection\" aria-label=\"Collection\">\n <SelectValue />\n </SelectTrigger>\n <SelectContent>\n <SelectItem value={NONE}>No collection</SelectItem>\n {collections.map((collection) => (\n <SelectItem key={collection.id} value={collection.id}>\n {collection.name}\n </SelectItem>\n ))}\n </SelectContent>\n </Select>\n </div>\n </div>\n\n <EntityTagsField value={form.tags} onChange={(tags) => setField('tags', tags)} label=\"Tags\" />\n\n {!isEdit ? (\n <div className=\"space-y-1.5\">\n <Label>Data file</Label>\n <FileUploadField\n value={form.fileId}\n onChange={(fileId) => setField('fileId', fileId)}\n label=\"Upload data file\"\n hint=\"Optional — attach the dataset blob (stored in workspace files).\"\n />\n </div>\n ) : null}\n </EntityFormShell>\n );\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"DatasetFormPage.js","names":[],"sources":["../../../../src/cosmicintersection/pages/datasets/DatasetFormPage.tsx"],"sourcesContent":["import { useMemo, useState } from 'react';\nimport { useParams } from 'react-router';\nimport {\n Input,\n Label,\n Select,\n SelectContent,\n SelectItem,\n SelectTrigger,\n SelectValue,\n Textarea,\n} from '@burdenoff/fe-libs/ui';\n\nimport {\n useCosCollectionsQuery,\n useCosCreateDatasetMutation,\n useCosDatasetQuery,\n useCosSourcesQuery,\n useCosUpdateDatasetMutation,\n type CosAccessLevel,\n type CosCreateDatasetInput,\n type CosUpdateDatasetInput,\n} from '../../api/cosmicApi';\nimport {\n EntityFormShell,\n FileUploadField,\n EntityTagsField,\n LoadingState,\n formatEnumLabel,\n} from '../../components';\nimport { useCosmicIntersection } from '../../context/CosmicIntersectionContext';\nimport { notify } from '../../lib/toast';\n\nconst ACCESS_LEVELS: CosAccessLevel[] = ['PUBLIC', 'WORKSPACE', 'RESTRICTED', 'EMBARGOED'];\n\nconst NONE = '__none__';\n\ninterface DatasetFormState {\n name: string;\n description: string;\n format: string;\n accessLevel: CosAccessLevel;\n sourceId: string;\n collectionId: string;\n tags: string[];\n fileId: string;\n}\n\nconst initialState: DatasetFormState = {\n name: '',\n description: '',\n format: '',\n accessLevel: 'WORKSPACE',\n sourceId: NONE,\n collectionId: NONE,\n tags: [],\n fileId: '',\n};\n\nexport default function DatasetFormPage() {\n const { id = '' } = useParams<{ id: string }>();\n const isEdit = useMemo(() => Boolean(id), [id]);\n const { navigate } = useCosmicIntersection();\n\n const { data, loading: loadingDataset } = useCosDatasetQuery(id);\n const sourcesQuery = useCosSourcesQuery({ pagination: { limit: 100, offset: 0 } });\n const collectionsQuery = useCosCollectionsQuery();\n\n const [createDataset, { loading: creating }] = useCosCreateDatasetMutation();\n const [updateDataset, { loading: updating }] = useCosUpdateDatasetMutation();\n\n const [form, setForm] = useState<DatasetFormState>(initialState);\n\n // Hydrate the form once the dataset loads in edit mode. Derive-state-during-\n // render (keyed on the loaded id) rather than an effect, per platform lint.\n const [loadedId, setLoadedId] = useState<string | null>(null);\n if (isEdit && data?.cosDataset && loadedId !== data.cosDataset.id) {\n const ds = data.cosDataset;\n setLoadedId(ds.id);\n setForm({\n name: ds.name ?? '',\n description: ds.description ?? '',\n format: ds.format ?? '',\n accessLevel: ds.accessLevel ?? 'WORKSPACE',\n sourceId: ds.sourceId ?? NONE,\n collectionId: ds.collectionId ?? NONE,\n tags: ds.tags ?? [],\n fileId: ds.file?.id ?? '',\n });\n }\n\n const setField = <K extends keyof DatasetFormState>(field: K, value: DatasetFormState[K]) => {\n setForm((prev) => ({ ...prev, [field]: value }));\n };\n\n const sources = sourcesQuery.data?.cosListSources?.items ?? [];\n const collections = collectionsQuery.data?.cosListCollections ?? [];\n const isSaving = creating || updating;\n\n const onSubmit = async (event: React.FormEvent<HTMLFormElement>) => {\n event.preventDefault();\n if (!form.name.trim()) {\n notify.error('Name is required');\n return;\n }\n\n if (isEdit) {\n // CosUpdateDatasetInput does not accept sourceId/fileId — those are set at\n // creation time and are read-only afterwards.\n const input: CosUpdateDatasetInput = {\n name: form.name.trim(),\n description: form.description.trim() || undefined,\n format: form.format.trim() || undefined,\n accessLevel: form.accessLevel,\n collectionId: form.collectionId === NONE ? undefined : form.collectionId,\n tags: form.tags,\n };\n const response = await updateDataset({ variables: { id, input } });\n if (response.data?.cosUpdateDataset) {\n notify.success('Dataset updated');\n navigate(`datasets/${id}`);\n }\n return;\n }\n\n const input: CosCreateDatasetInput = {\n name: form.name.trim(),\n description: form.description.trim() || undefined,\n format: form.format.trim() || undefined,\n accessLevel: form.accessLevel,\n sourceId: form.sourceId === NONE ? undefined : form.sourceId,\n collectionId: form.collectionId === NONE ? undefined : form.collectionId,\n tags: form.tags,\n fileId: form.fileId || undefined,\n };\n const response = await createDataset({ variables: { input } });\n const createdId = response.data?.cosCreateDataset?.id;\n if (createdId) {\n notify.success('Dataset created');\n navigate(`datasets/${createdId}`);\n }\n };\n\n if (isEdit && loadingDataset && !data?.cosDataset) {\n return <LoadingState label=\"Loading dataset…\" />;\n }\n\n return (\n <EntityFormShell\n title={isEdit ? 'Edit dataset' : 'New dataset'}\n description=\"Register a federated science dataset with its access level, source and schema.\"\n purpose=\"Datasets are the core unit of federation — catalog the data once, describe where it comes from and how it can be accessed, then reuse it across pipelines, notebooks and releases.\"\n backLabel=\"Back to datasets\"\n onBack={() => navigate(isEdit ? `datasets/${id}` : 'datasets')}\n onSubmit={onSubmit}\n submitLabel={isEdit ? 'Save dataset' : 'Create dataset'}\n saving={isSaving}\n submitDisabled={!form.name.trim()}\n >\n <div className=\"grid grid-cols-1 gap-4 md:grid-cols-2\">\n <div className=\"space-y-1.5 md:col-span-2\">\n <Label htmlFor=\"cos-ds-name\">Name</Label>\n <Input\n id=\"cos-ds-name\"\n value={form.name}\n onChange={(event) => setField('name', event.target.value)}\n placeholder=\"e.g. Kepler DR3 light curves\"\n required\n />\n </div>\n\n <div className=\"space-y-1.5 md:col-span-2\">\n <Label htmlFor=\"cos-ds-desc\">Description</Label>\n <Textarea\n id=\"cos-ds-desc\"\n value={form.description}\n onChange={(event) => setField('description', event.target.value)}\n rows={3}\n placeholder=\"What this dataset contains and how it was produced.\"\n />\n </div>\n\n <div className=\"space-y-1.5\">\n <Label htmlFor=\"cos-ds-format\">Format</Label>\n <Input\n id=\"cos-ds-format\"\n value={form.format}\n onChange={(event) => setField('format', event.target.value)}\n placeholder=\"e.g. FITS, Parquet, CSV\"\n />\n </div>\n\n <div className=\"space-y-1.5\">\n <Label htmlFor=\"cos-ds-access\">Access level</Label>\n <Select\n value={form.accessLevel}\n onValueChange={(value) => setField('accessLevel', value as CosAccessLevel)}\n >\n <SelectTrigger id=\"cos-ds-access\" aria-label=\"Access level\">\n <SelectValue />\n </SelectTrigger>\n <SelectContent>\n {ACCESS_LEVELS.map((level) => (\n <SelectItem key={level} value={level}>\n {formatEnumLabel(level)}\n </SelectItem>\n ))}\n </SelectContent>\n </Select>\n </div>\n\n {!isEdit ? (\n <div className=\"space-y-1.5\">\n <Label htmlFor=\"cos-ds-source\">Source</Label>\n <Select value={form.sourceId} onValueChange={(value) => setField('sourceId', value)}>\n <SelectTrigger id=\"cos-ds-source\" aria-label=\"Source\">\n <SelectValue />\n </SelectTrigger>\n <SelectContent>\n <SelectItem value={NONE}>No source</SelectItem>\n {sources.map((source) => (\n <SelectItem key={source.id} value={source.id}>\n {source.name}\n </SelectItem>\n ))}\n </SelectContent>\n </Select>\n </div>\n ) : null}\n\n <div className=\"space-y-1.5\">\n <Label htmlFor=\"cos-ds-collection\">Collection</Label>\n <Select\n value={form.collectionId}\n onValueChange={(value) => setField('collectionId', value)}\n >\n <SelectTrigger id=\"cos-ds-collection\" aria-label=\"Collection\">\n <SelectValue />\n </SelectTrigger>\n <SelectContent>\n <SelectItem value={NONE}>No collection</SelectItem>\n {collections.map((collection) => (\n <SelectItem key={collection.id} value={collection.id}>\n {collection.name}\n </SelectItem>\n ))}\n </SelectContent>\n </Select>\n </div>\n </div>\n\n <EntityTagsField value={form.tags} onChange={(tags) => setField('tags', tags)} label=\"Tags\" />\n\n {!isEdit ? (\n <div className=\"space-y-1.5\">\n <Label>Data file</Label>\n <FileUploadField\n value={form.fileId}\n onChange={(fileId) => setField('fileId', fileId)}\n label=\"Upload data file\"\n hint=\"Optional — attach the dataset blob (stored in workspace files).\"\n />\n </div>\n ) : null}\n </EntityFormShell>\n );\n}\n"],"mappings":"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"}
@@ -8,7 +8,7 @@ import "../../components/index.js";
8
8
  import l, { buildDatasetLineage as u, buildReleaseLineage as d } from "../../components/LineageGraph.js";
9
9
  import { useMemo as f, useState as p } from "react";
10
10
  import { jsx as m, jsxs as h } from "react/jsx-runtime";
11
- import { useParams as g } from "react-router-dom";
11
+ import { useParams as g } from "react-router";
12
12
  import { Info as ie, Share2 as _, Workflow as v } from "lucide-react";
13
13
  import { Select as y, SelectContent as b, SelectItem as x, SelectTrigger as S, SelectValue as C } from "@burdenoff/fe-libs/ui";
14
14
  //#region src/cosmicintersection/pages/lineage/LineagePage.tsx
@@ -1 +1 @@
1
- {"version":3,"file":"LineagePage.js","names":[],"sources":["../../../../src/cosmicintersection/pages/lineage/LineagePage.tsx"],"sourcesContent":["import { useMemo, useState } from 'react';\nimport { useParams } from 'react-router-dom';\nimport { Info, Share2, Workflow } from 'lucide-react';\nimport {\n Select,\n SelectContent,\n SelectItem,\n SelectTrigger,\n SelectValue,\n} from '@burdenoff/fe-libs/ui';\n\nimport {\n useCosCollectionsQuery,\n useCosDatasetsQuery,\n useCosNotebooksQuery,\n useCosPipelinesQuery,\n useCosReleasesQuery,\n useCosRunsQuery,\n useCosAnalysesQuery,\n useCosSourcesQuery,\n} from '../../api/cosmicApi';\nimport { EmptyState, ErrorState, LoadingState, PageLayout } from '../../components';\nimport {\n LineageGraph,\n buildDatasetLineage,\n buildReleaseLineage,\n type LineageDataPools,\n} from '../../components/LineageGraph';\nimport { useCosmicIntersection } from '../../context/CosmicIntersectionContext';\n\ntype RootKind = 'dataset' | 'release';\n\nconst PAGE_LIMIT = 100;\n\nexport default function LineagePage() {\n const { navigate } = useCosmicIntersection();\n // Optional deep-link: /lineage/:datasetId preselects that dataset as the root.\n const { datasetId: routeDatasetId } = useParams<{ datasetId?: string }>();\n\n const datasetsQuery = useCosDatasetsQuery({ pagination: { limit: PAGE_LIMIT, offset: 0 } });\n const releasesQuery = useCosReleasesQuery({ pagination: { limit: PAGE_LIMIT, offset: 0 } });\n const sourcesQuery = useCosSourcesQuery({ pagination: { limit: PAGE_LIMIT, offset: 0 } });\n const collectionsQuery = useCosCollectionsQuery();\n const runsQuery = useCosRunsQuery({ pagination: { limit: PAGE_LIMIT, offset: 0 } });\n const notebooksQuery = useCosNotebooksQuery({ pagination: { limit: PAGE_LIMIT, offset: 0 } });\n const analysesQuery = useCosAnalysesQuery({});\n const pipelinesQuery = useCosPipelinesQuery({ pagination: { limit: PAGE_LIMIT, offset: 0 } });\n\n const datasets = useMemo(\n () => datasetsQuery.data?.cosListDatasets?.items ?? [],\n [datasetsQuery.data]\n );\n const releases = useMemo(\n () => releasesQuery.data?.cosListReleases?.items ?? [],\n [releasesQuery.data]\n );\n const sources = useMemo(\n () => sourcesQuery.data?.cosListSources?.items ?? [],\n [sourcesQuery.data]\n );\n const collections = useMemo(\n () => collectionsQuery.data?.cosListCollections ?? [],\n [collectionsQuery.data]\n );\n const runs = useMemo(() => runsQuery.data?.cosListRuns?.items ?? [], [runsQuery.data]);\n const notebooks = useMemo(\n () => notebooksQuery.data?.cosListNotebooks?.items ?? [],\n [notebooksQuery.data]\n );\n const analyses = useMemo(() => analysesQuery.data?.cosListAnalyses ?? [], [analysesQuery.data]);\n const pipelines = useMemo(\n () => pipelinesQuery.data?.cosListPipelines?.items ?? [],\n [pipelinesQuery.data]\n );\n\n const pools: LineageDataPools = useMemo(\n () => ({\n datasetsById: new Map(datasets.map((item) => [item.id, item])),\n sourcesById: new Map(sources.map((item) => [item.id, item])),\n collectionsById: new Map(collections.map((item) => [item.id, item])),\n runs,\n notebooks,\n analyses,\n releases,\n pipelinesById: new Map(pipelines.map((item) => [item.id, item])),\n }),\n [datasets, sources, collections, runs, notebooks, analyses, releases, pipelines]\n );\n\n const [rootKind, setRootKind] = useState<RootKind>('dataset');\n const [selectedId, setSelectedId] = useState<string>(routeDatasetId ?? '');\n\n // Auto-select the first available root of the current kind once lists load —\n // the documented derive-state-during-render pattern (no effect required).\n const options = rootKind === 'dataset' ? datasets : releases;\n const firstOption = options[0]?.id ?? '';\n const selectionValid = options.some((item) => item.id === selectedId);\n if (!selectionValid && firstOption) {\n setSelectedId(firstOption);\n }\n const activeId = selectionValid ? selectedId : firstOption;\n\n const model = useMemo(() => {\n if (!activeId) {\n return { nodes: [], edges: [] };\n }\n return rootKind === 'dataset'\n ? buildDatasetLineage(activeId, pools)\n : buildReleaseLineage(activeId, pools);\n }, [activeId, rootKind, pools]);\n\n const primaryLoading =\n (datasetsQuery.loading && datasets.length === 0) ||\n (releasesQuery.loading && releases.length === 0);\n const primaryError = datasetsQuery.error || releasesQuery.error;\n\n const handleKindChange = (value: string) => {\n setRootKind(value as RootKind);\n setSelectedId('');\n };\n\n const activeLabel =\n rootKind === 'dataset'\n ? datasets.find((item) => item.id === activeId)?.name\n : releases.find((item) => item.id === activeId)?.title;\n\n return (\n <PageLayout\n title=\"Lineage\"\n description=\"Trace any result from raw observation to citable release.\"\n >\n <div className=\"space-y-6\">\n {/* Root picker */}\n <div className=\"flex flex-col gap-3 rounded-card border border-border-default bg-bg-elevated p-4 sm:flex-row sm:items-end\">\n <label className=\"space-y-1 text-sm\">\n <span className=\"block font-medium text-text-primary\">Trace from</span>\n <Select value={rootKind} onValueChange={handleKindChange}>\n <SelectTrigger aria-label=\"Root entity kind\" className=\"w-full sm:w-44\">\n <SelectValue />\n </SelectTrigger>\n <SelectContent>\n <SelectItem value=\"dataset\">Dataset</SelectItem>\n <SelectItem value=\"release\">Release</SelectItem>\n </SelectContent>\n </Select>\n </label>\n\n <label className=\"space-y-1 text-sm sm:flex-1\">\n <span className=\"block font-medium text-text-primary\">\n {rootKind === 'dataset' ? 'Dataset' : 'Release'}\n </span>\n <Select value={activeId} onValueChange={setSelectedId} disabled={options.length === 0}>\n <SelectTrigger aria-label={`Select ${rootKind}`} className=\"w-full sm:max-w-md\">\n <SelectValue\n placeholder={\n options.length === 0 ? `No ${rootKind}s available` : `Select a ${rootKind}`\n }\n />\n </SelectTrigger>\n <SelectContent>\n {options.map((item) => (\n <SelectItem key={item.id} value={item.id}>\n {rootKind === 'dataset'\n ? (item as (typeof datasets)[number]).name\n : (item as (typeof releases)[number]).title}\n </SelectItem>\n ))}\n </SelectContent>\n </Select>\n </label>\n </div>\n\n {primaryError ? (\n <ErrorState\n message=\"We could not load lineage data. Please try again.\"\n onRetry={() => {\n void datasetsQuery.refetch();\n void releasesQuery.refetch();\n }}\n />\n ) : primaryLoading ? (\n <LoadingState label=\"Loading lineage…\" />\n ) : datasets.length === 0 && releases.length === 0 ? (\n <EmptyState\n icon={Workflow}\n title=\"Nothing to trace yet.\"\n description=\"Register a dataset or publish a release to build a provenance graph from raw observation to citable output.\"\n action={\n <button\n type=\"button\"\n onClick={() => navigate('datasets')}\n className=\"text-sm font-medium text-text-link underline-offset-2 hover:underline\"\n >\n Go to datasets\n </button>\n }\n />\n ) : model.nodes.length === 0 ? (\n <EmptyState\n icon={Share2}\n title={`Select a ${rootKind} to trace`}\n description=\"Choose a root above to render its provenance graph.\"\n />\n ) : (\n <div className=\"space-y-4\">\n {activeLabel ? (\n <div className=\"flex items-center gap-2 text-sm text-text-secondary\">\n <Share2 className=\"size-4 text-text-tertiary\" aria-hidden=\"true\" />\n <span>\n Provenance for{' '}\n <span className=\"font-medium text-text-primary\">{activeLabel}</span>\n </span>\n </div>\n ) : null}\n\n <LineageGraph model={model} mode=\"full\" onNavigate={navigate} />\n\n <p className=\"flex items-start gap-2 text-xs text-text-tertiary\">\n <Info className=\"mt-0.5 size-3.5 shrink-0\" aria-hidden=\"true\" />\n <span>\n This graph is derived live from your workspace&rsquo;s cos entities. Connected runs,\n notebooks, analyses and releases are matched across the {PAGE_LIMIT} most recent\n records of each type; older items may not appear.\n </span>\n </p>\n </div>\n )}\n </div>\n </PageLayout>\n );\n}\n"],"mappings":";;;;;;;;;;;;;;AAgCA,IAAM,IAAa;AAEnB,SAAwB,IAAc;CACpC,IAAM,EAAE,gBAAa,EAAsB,GAErC,EAAE,WAAW,MAAmB,EAAkC,GAElE,IAAgB,EAAoB,EAAE,YAAY;EAAE,OAAO;EAAY,QAAQ;CAAE,EAAE,CAAC,GACpF,IAAgB,EAAoB,EAAE,YAAY;EAAE,OAAO;EAAY,QAAQ;CAAE,EAAE,CAAC,GACpF,IAAe,GAAmB,EAAE,YAAY;EAAE,OAAO;EAAY,QAAQ;CAAE,EAAE,CAAC,GAClF,IAAmB,GAAuB,GAC1C,IAAY,EAAgB,EAAE,YAAY;EAAE,OAAO;EAAY,QAAQ;CAAE,EAAE,CAAC,GAC5E,IAAiB,EAAqB,EAAE,YAAY;EAAE,OAAO;EAAY,QAAQ;CAAE,EAAE,CAAC,GACtF,IAAgB,EAAoB,CAAC,CAAC,GACtC,IAAiB,EAAqB,EAAE,YAAY;EAAE,OAAO;EAAY,QAAQ;CAAE,EAAE,CAAC,GAEtF,IAAW,QACT,EAAc,MAAM,iBAAiB,SAAS,CAAC,GACrD,CAAC,EAAc,IAAI,CACrB,GACM,IAAW,QACT,EAAc,MAAM,iBAAiB,SAAS,CAAC,GACrD,CAAC,EAAc,IAAI,CACrB,GACM,IAAU,QACR,EAAa,MAAM,gBAAgB,SAAS,CAAC,GACnD,CAAC,EAAa,IAAI,CACpB,GACM,IAAc,QACZ,EAAiB,MAAM,sBAAsB,CAAC,GACpD,CAAC,EAAiB,IAAI,CACxB,GACM,IAAO,QAAc,EAAU,MAAM,aAAa,SAAS,CAAC,GAAG,CAAC,EAAU,IAAI,CAAC,GAC/E,IAAY,QACV,EAAe,MAAM,kBAAkB,SAAS,CAAC,GACvD,CAAC,EAAe,IAAI,CACtB,GACM,IAAW,QAAc,EAAc,MAAM,mBAAmB,CAAC,GAAG,CAAC,EAAc,IAAI,CAAC,GACxF,IAAY,QACV,EAAe,MAAM,kBAAkB,SAAS,CAAC,GACvD,CAAC,EAAe,IAAI,CACtB,GAEM,IAA0B,SACvB;EACL,cAAc,IAAI,IAAI,EAAS,KAAK,MAAS,CAAC,EAAK,IAAI,CAAI,CAAC,CAAC;EAC7D,aAAa,IAAI,IAAI,EAAQ,KAAK,MAAS,CAAC,EAAK,IAAI,CAAI,CAAC,CAAC;EAC3D,iBAAiB,IAAI,IAAI,EAAY,KAAK,MAAS,CAAC,EAAK,IAAI,CAAI,CAAC,CAAC;EACnE;EACA;EACA;EACA;EACA,eAAe,IAAI,IAAI,EAAU,KAAK,MAAS,CAAC,EAAK,IAAI,CAAI,CAAC,CAAC;CACjE,IACA;EAAC;EAAU;EAAS;EAAa;EAAM;EAAW;EAAU;EAAU;CAAS,CACjF,GAEM,CAAC,GAAU,KAAe,EAAmB,SAAS,GACtD,CAAC,GAAY,KAAiB,EAAiB,KAAkB,EAAE,GAInE,IAAU,MAAa,YAAY,IAAW,GAC9C,IAAc,EAAQ,IAAI,MAAM,IAChC,IAAiB,EAAQ,MAAM,MAAS,EAAK,OAAO,CAAU;CACpE,AAAI,CAAC,KAAkB,KACrB,EAAc,CAAW;CAE3B,IAAM,IAAW,IAAiB,IAAa,GAEzC,IAAQ,QACP,IAGE,MAAa,YAChB,EAAoB,GAAU,CAAK,IACnC,EAAoB,GAAU,CAAK,IAJ9B;EAAE,OAAO,CAAC;EAAG,OAAO,CAAC;CAAE,GAK/B;EAAC;EAAU;EAAU;CAAK,CAAC,GAExB,KACH,EAAc,WAAW,EAAS,WAAW,KAC7C,EAAc,WAAW,EAAS,WAAW,GAC1C,KAAe,EAAc,SAAS,EAAc,OAEpD,MAAoB,MAAkB;EAE1C,AADA,EAAY,CAAiB,GAC7B,EAAc,EAAE;CAClB,GAEM,IACJ,MAAa,YACT,EAAS,MAAM,MAAS,EAAK,OAAO,CAAQ,GAAG,OAC/C,EAAS,MAAM,MAAS,EAAK,OAAO,CAAQ,GAAG;CAErD,OACE,kBAAC,GAAD;EACE,OAAM;EACN,aAAY;YAEZ,kBAAC,OAAD;GAAK,WAAU;aAAf,CAEE,kBAAC,OAAD;IAAK,WAAU;cAAf,CACE,kBAAC,SAAD;KAAO,WAAU;eAAjB,CACE,kBAAC,QAAD;MAAM,WAAU;gBAAsC;KAAgB,CAAA,GACtE,kBAAC,GAAD;MAAQ,OAAO;MAAU,eAAe;gBAAxC,CACE,kBAAC,GAAD;OAAe,cAAW;OAAmB,WAAU;iBACrD,kBAAC,GAAD,CAAc,CAAA;MACD,CAAA,GACf,kBAAC,GAAD,EAAA,UAAA,CACE,kBAAC,GAAD;OAAY,OAAM;iBAAU;MAAmB,CAAA,GAC/C,kBAAC,GAAD;OAAY,OAAM;iBAAU;MAAmB,CAAA,CAClC,EAAA,CAAA,CACT;OACH;QAEP,kBAAC,SAAD;KAAO,WAAU;eAAjB,CACE,kBAAC,QAAD;MAAM,WAAU;gBACb,MAAa,YAAY,YAAY;KAClC,CAAA,GACN,kBAAC,GAAD;MAAQ,OAAO;MAAU,eAAe;MAAe,UAAU,EAAQ,WAAW;gBAApF,CACE,kBAAC,GAAD;OAAe,cAAY,UAAU;OAAY,WAAU;iBACzD,kBAAC,GAAD,EACE,aACE,EAAQ,WAAW,IAAI,MAAM,EAAS,eAAe,YAAY,IAEpE,CAAA;MACY,CAAA,GACf,kBAAC,GAAD,EAAA,UACG,EAAQ,KAAK,MACZ,kBAAC,GAAD;OAA0B,OAAO,EAAK;iBACnC,MAAa,YACT,EAAmC,OACnC,EAAmC;MAC9B,GAJK,EAAK,EAIV,CACb,EACY,CAAA,CACT;OACH;MACJ;OAEJ,KACC,kBAAC,IAAD;IACE,SAAQ;IACR,eAAe;KAEb,AADA,EAAmB,QAAQ,GAC3B,EAAmB,QAAQ;IAC7B;GACD,CAAA,IACC,KACF,kBAAC,IAAD,EAAc,OAAM,mBAAoB,CAAA,IACtC,EAAS,WAAW,KAAK,EAAS,WAAW,IAC/C,kBAAC,GAAD;IACE,MAAM;IACN,OAAM;IACN,aAAY;IACZ,QACE,kBAAC,UAAD;KACE,MAAK;KACL,eAAe,EAAS,UAAU;KAClC,WAAU;eACX;IAEO,CAAA;GAEX,CAAA,IACC,EAAM,MAAM,WAAW,IACzB,kBAAC,GAAD;IACE,MAAM;IACN,OAAO,YAAY,EAAS;IAC5B,aAAY;GACb,CAAA,IAED,kBAAC,OAAD;IAAK,WAAU;cAAf;KACG,IACC,kBAAC,OAAD;MAAK,WAAU;gBAAf,CACE,kBAAC,GAAD;OAAQ,WAAU;OAA4B,eAAY;MAAQ,CAAA,GAClE,kBAAC,QAAD,EAAA,UAAA;OAAM;OACW;OACf,kBAAC,QAAD;QAAM,WAAU;kBAAiC;OAAkB,CAAA;MAC/D,EAAA,CAAA,CACH;UACH;KAEJ,kBAAC,GAAD;MAAqB;MAAO,MAAK;MAAO,YAAY;KAAW,CAAA;KAE/D,kBAAC,KAAD;MAAG,WAAU;gBAAb,CACE,kBAAC,IAAD;OAAM,WAAU;OAA2B,eAAY;MAAQ,CAAA,GAC/D,kBAAC,QAAD,EAAA,UAAA;OAAM;OAEqD;OAAW;MAEhE,EAAA,CAAA,CACL;;IACA;KAEJ;;CACK,CAAA;AAEhB"}
1
+ {"version":3,"file":"LineagePage.js","names":[],"sources":["../../../../src/cosmicintersection/pages/lineage/LineagePage.tsx"],"sourcesContent":["import { useMemo, useState } from 'react';\nimport { useParams } from 'react-router';\nimport { Info, Share2, Workflow } from 'lucide-react';\nimport {\n Select,\n SelectContent,\n SelectItem,\n SelectTrigger,\n SelectValue,\n} from '@burdenoff/fe-libs/ui';\n\nimport {\n useCosCollectionsQuery,\n useCosDatasetsQuery,\n useCosNotebooksQuery,\n useCosPipelinesQuery,\n useCosReleasesQuery,\n useCosRunsQuery,\n useCosAnalysesQuery,\n useCosSourcesQuery,\n} from '../../api/cosmicApi';\nimport { EmptyState, ErrorState, LoadingState, PageLayout } from '../../components';\nimport {\n LineageGraph,\n buildDatasetLineage,\n buildReleaseLineage,\n type LineageDataPools,\n} from '../../components/LineageGraph';\nimport { useCosmicIntersection } from '../../context/CosmicIntersectionContext';\n\ntype RootKind = 'dataset' | 'release';\n\nconst PAGE_LIMIT = 100;\n\nexport default function LineagePage() {\n const { navigate } = useCosmicIntersection();\n // Optional deep-link: /lineage/:datasetId preselects that dataset as the root.\n const { datasetId: routeDatasetId } = useParams<{ datasetId?: string }>();\n\n const datasetsQuery = useCosDatasetsQuery({ pagination: { limit: PAGE_LIMIT, offset: 0 } });\n const releasesQuery = useCosReleasesQuery({ pagination: { limit: PAGE_LIMIT, offset: 0 } });\n const sourcesQuery = useCosSourcesQuery({ pagination: { limit: PAGE_LIMIT, offset: 0 } });\n const collectionsQuery = useCosCollectionsQuery();\n const runsQuery = useCosRunsQuery({ pagination: { limit: PAGE_LIMIT, offset: 0 } });\n const notebooksQuery = useCosNotebooksQuery({ pagination: { limit: PAGE_LIMIT, offset: 0 } });\n const analysesQuery = useCosAnalysesQuery({});\n const pipelinesQuery = useCosPipelinesQuery({ pagination: { limit: PAGE_LIMIT, offset: 0 } });\n\n const datasets = useMemo(\n () => datasetsQuery.data?.cosListDatasets?.items ?? [],\n [datasetsQuery.data]\n );\n const releases = useMemo(\n () => releasesQuery.data?.cosListReleases?.items ?? [],\n [releasesQuery.data]\n );\n const sources = useMemo(\n () => sourcesQuery.data?.cosListSources?.items ?? [],\n [sourcesQuery.data]\n );\n const collections = useMemo(\n () => collectionsQuery.data?.cosListCollections ?? [],\n [collectionsQuery.data]\n );\n const runs = useMemo(() => runsQuery.data?.cosListRuns?.items ?? [], [runsQuery.data]);\n const notebooks = useMemo(\n () => notebooksQuery.data?.cosListNotebooks?.items ?? [],\n [notebooksQuery.data]\n );\n const analyses = useMemo(() => analysesQuery.data?.cosListAnalyses ?? [], [analysesQuery.data]);\n const pipelines = useMemo(\n () => pipelinesQuery.data?.cosListPipelines?.items ?? [],\n [pipelinesQuery.data]\n );\n\n const pools: LineageDataPools = useMemo(\n () => ({\n datasetsById: new Map(datasets.map((item) => [item.id, item])),\n sourcesById: new Map(sources.map((item) => [item.id, item])),\n collectionsById: new Map(collections.map((item) => [item.id, item])),\n runs,\n notebooks,\n analyses,\n releases,\n pipelinesById: new Map(pipelines.map((item) => [item.id, item])),\n }),\n [datasets, sources, collections, runs, notebooks, analyses, releases, pipelines]\n );\n\n const [rootKind, setRootKind] = useState<RootKind>('dataset');\n const [selectedId, setSelectedId] = useState<string>(routeDatasetId ?? '');\n\n // Auto-select the first available root of the current kind once lists load —\n // the documented derive-state-during-render pattern (no effect required).\n const options = rootKind === 'dataset' ? datasets : releases;\n const firstOption = options[0]?.id ?? '';\n const selectionValid = options.some((item) => item.id === selectedId);\n if (!selectionValid && firstOption) {\n setSelectedId(firstOption);\n }\n const activeId = selectionValid ? selectedId : firstOption;\n\n const model = useMemo(() => {\n if (!activeId) {\n return { nodes: [], edges: [] };\n }\n return rootKind === 'dataset'\n ? buildDatasetLineage(activeId, pools)\n : buildReleaseLineage(activeId, pools);\n }, [activeId, rootKind, pools]);\n\n const primaryLoading =\n (datasetsQuery.loading && datasets.length === 0) ||\n (releasesQuery.loading && releases.length === 0);\n const primaryError = datasetsQuery.error || releasesQuery.error;\n\n const handleKindChange = (value: string) => {\n setRootKind(value as RootKind);\n setSelectedId('');\n };\n\n const activeLabel =\n rootKind === 'dataset'\n ? datasets.find((item) => item.id === activeId)?.name\n : releases.find((item) => item.id === activeId)?.title;\n\n return (\n <PageLayout\n title=\"Lineage\"\n description=\"Trace any result from raw observation to citable release.\"\n >\n <div className=\"space-y-6\">\n {/* Root picker */}\n <div className=\"flex flex-col gap-3 rounded-card border border-border-default bg-bg-elevated p-4 sm:flex-row sm:items-end\">\n <label className=\"space-y-1 text-sm\">\n <span className=\"block font-medium text-text-primary\">Trace from</span>\n <Select value={rootKind} onValueChange={handleKindChange}>\n <SelectTrigger aria-label=\"Root entity kind\" className=\"w-full sm:w-44\">\n <SelectValue />\n </SelectTrigger>\n <SelectContent>\n <SelectItem value=\"dataset\">Dataset</SelectItem>\n <SelectItem value=\"release\">Release</SelectItem>\n </SelectContent>\n </Select>\n </label>\n\n <label className=\"space-y-1 text-sm sm:flex-1\">\n <span className=\"block font-medium text-text-primary\">\n {rootKind === 'dataset' ? 'Dataset' : 'Release'}\n </span>\n <Select value={activeId} onValueChange={setSelectedId} disabled={options.length === 0}>\n <SelectTrigger aria-label={`Select ${rootKind}`} className=\"w-full sm:max-w-md\">\n <SelectValue\n placeholder={\n options.length === 0 ? `No ${rootKind}s available` : `Select a ${rootKind}`\n }\n />\n </SelectTrigger>\n <SelectContent>\n {options.map((item) => (\n <SelectItem key={item.id} value={item.id}>\n {rootKind === 'dataset'\n ? (item as (typeof datasets)[number]).name\n : (item as (typeof releases)[number]).title}\n </SelectItem>\n ))}\n </SelectContent>\n </Select>\n </label>\n </div>\n\n {primaryError ? (\n <ErrorState\n message=\"We could not load lineage data. Please try again.\"\n onRetry={() => {\n void datasetsQuery.refetch();\n void releasesQuery.refetch();\n }}\n />\n ) : primaryLoading ? (\n <LoadingState label=\"Loading lineage…\" />\n ) : datasets.length === 0 && releases.length === 0 ? (\n <EmptyState\n icon={Workflow}\n title=\"Nothing to trace yet.\"\n description=\"Register a dataset or publish a release to build a provenance graph from raw observation to citable output.\"\n action={\n <button\n type=\"button\"\n onClick={() => navigate('datasets')}\n className=\"text-sm font-medium text-text-link underline-offset-2 hover:underline\"\n >\n Go to datasets\n </button>\n }\n />\n ) : model.nodes.length === 0 ? (\n <EmptyState\n icon={Share2}\n title={`Select a ${rootKind} to trace`}\n description=\"Choose a root above to render its provenance graph.\"\n />\n ) : (\n <div className=\"space-y-4\">\n {activeLabel ? (\n <div className=\"flex items-center gap-2 text-sm text-text-secondary\">\n <Share2 className=\"size-4 text-text-tertiary\" aria-hidden=\"true\" />\n <span>\n Provenance for{' '}\n <span className=\"font-medium text-text-primary\">{activeLabel}</span>\n </span>\n </div>\n ) : null}\n\n <LineageGraph model={model} mode=\"full\" onNavigate={navigate} />\n\n <p className=\"flex items-start gap-2 text-xs text-text-tertiary\">\n <Info className=\"mt-0.5 size-3.5 shrink-0\" aria-hidden=\"true\" />\n <span>\n This graph is derived live from your workspace&rsquo;s cos entities. Connected runs,\n notebooks, analyses and releases are matched across the {PAGE_LIMIT} most recent\n records of each type; older items may not appear.\n </span>\n </p>\n </div>\n )}\n </div>\n </PageLayout>\n );\n}\n"],"mappings":"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"}