@burdenoff/microfe-cosmicintersection 2026.704.2 → 2026.709.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.
- package/dist/cosmicintersection/CosmicIntersectionRoot.d.ts +15 -0
- package/dist/cosmicintersection/CosmicIntersectionRoot.d.ts.map +1 -0
- package/dist/cosmicintersection/CosmicIntersectionRoutes.d.ts +3 -0
- package/dist/cosmicintersection/CosmicIntersectionRoutes.d.ts.map +1 -0
- package/dist/cosmicintersection/CosmicIntersectionRoutes.js +39 -27
- package/dist/cosmicintersection/CosmicIntersectionRoutes.js.map +1 -1
- package/dist/cosmicintersection/api/cosmicApi.d.ts +728 -0
- package/dist/cosmicintersection/api/cosmicApi.d.ts.map +1 -0
- package/dist/cosmicintersection/api/cosmicApi.js +6 -0
- package/dist/cosmicintersection/api/cosmicApi.js.map +1 -1
- package/dist/cosmicintersection/components/ActionMenu.d.ts +41 -0
- package/dist/cosmicintersection/components/ActionMenu.d.ts.map +1 -0
- package/dist/cosmicintersection/components/ActivityFeedPanel.d.ts +10 -0
- package/dist/cosmicintersection/components/ActivityFeedPanel.d.ts.map +1 -0
- package/dist/cosmicintersection/components/DiscussionPanel.d.ts +14 -0
- package/dist/cosmicintersection/components/DiscussionPanel.d.ts.map +1 -0
- package/dist/cosmicintersection/components/DiscussionPanel.js +9 -9
- package/dist/cosmicintersection/components/EmptyState.d.ts +18 -0
- package/dist/cosmicintersection/components/EmptyState.d.ts.map +1 -0
- package/dist/cosmicintersection/components/EntityFormShell.d.ts +25 -0
- package/dist/cosmicintersection/components/EntityFormShell.d.ts.map +1 -0
- package/dist/cosmicintersection/components/EntityTagsField.d.ts +20 -0
- package/dist/cosmicintersection/components/EntityTagsField.d.ts.map +1 -0
- package/dist/cosmicintersection/components/ErrorState.d.ts +14 -0
- package/dist/cosmicintersection/components/ErrorState.d.ts.map +1 -0
- package/dist/cosmicintersection/components/FacetPanel.d.ts +21 -0
- package/dist/cosmicintersection/components/FacetPanel.d.ts.map +1 -0
- package/dist/cosmicintersection/components/FacetPanel.js +66 -0
- package/dist/cosmicintersection/components/FacetPanel.js.map +1 -0
- package/dist/cosmicintersection/components/FileUploadField.d.ts +35 -0
- package/dist/cosmicintersection/components/FileUploadField.d.ts.map +1 -0
- package/dist/cosmicintersection/components/FileUploadField.js +16 -16
- package/dist/cosmicintersection/components/LineageGraph.d.ts +59 -0
- package/dist/cosmicintersection/components/LineageGraph.d.ts.map +1 -0
- package/dist/cosmicintersection/components/LineageGraph.js +388 -0
- package/dist/cosmicintersection/components/LineageGraph.js.map +1 -0
- package/dist/cosmicintersection/components/LoadingState.d.ts +15 -0
- package/dist/cosmicintersection/components/LoadingState.d.ts.map +1 -0
- package/dist/cosmicintersection/components/PageLayout.d.ts +18 -0
- package/dist/cosmicintersection/components/PageLayout.d.ts.map +1 -0
- package/dist/cosmicintersection/components/Pagination.d.ts +32 -0
- package/dist/cosmicintersection/components/Pagination.d.ts.map +1 -0
- package/dist/cosmicintersection/components/ResultsChart.d.ts +7 -0
- package/dist/cosmicintersection/components/ResultsChart.d.ts.map +1 -0
- package/dist/cosmicintersection/components/ResultsChart.js +329 -0
- package/dist/cosmicintersection/components/ResultsChart.js.map +1 -0
- package/dist/cosmicintersection/components/SafeLink.d.ts +35 -0
- package/dist/cosmicintersection/components/SafeLink.d.ts.map +1 -0
- package/dist/cosmicintersection/components/StatusBadge.d.ts +23 -0
- package/dist/cosmicintersection/components/StatusBadge.d.ts.map +1 -0
- package/dist/cosmicintersection/components/StepDAG.d.ts +20 -0
- package/dist/cosmicintersection/components/StepDAG.d.ts.map +1 -0
- package/dist/cosmicintersection/components/StepDAG.js +104 -0
- package/dist/cosmicintersection/components/StepDAG.js.map +1 -0
- package/dist/cosmicintersection/components/index.d.ts +18 -0
- package/dist/cosmicintersection/components/index.d.ts.map +1 -0
- package/dist/cosmicintersection/context/CosmicIntersectionContext.d.ts +26 -0
- package/dist/cosmicintersection/context/CosmicIntersectionContext.d.ts.map +1 -0
- package/dist/cosmicintersection/index.d.ts +18 -0
- package/dist/cosmicintersection/index.d.ts.map +1 -0
- package/dist/cosmicintersection/lib/mutationResult.d.ts +23 -0
- package/dist/cosmicintersection/lib/mutationResult.d.ts.map +1 -0
- package/dist/cosmicintersection/lib/toast.d.ts +22 -0
- package/dist/cosmicintersection/lib/toast.d.ts.map +1 -0
- package/dist/cosmicintersection/pages/access/AccessPage.d.ts +2 -0
- package/dist/cosmicintersection/pages/access/AccessPage.d.ts.map +1 -0
- package/dist/cosmicintersection/pages/access/AccessPage.js +207 -155
- package/dist/cosmicintersection/pages/access/AccessPage.js.map +1 -1
- package/dist/cosmicintersection/pages/analyses/AnalysesPage.d.ts +2 -0
- package/dist/cosmicintersection/pages/analyses/AnalysesPage.d.ts.map +1 -0
- package/dist/cosmicintersection/pages/analyses/AnalysesPage.js +325 -165
- package/dist/cosmicintersection/pages/analyses/AnalysesPage.js.map +1 -1
- package/dist/cosmicintersection/pages/collections/CollectionDetailPage.d.ts +2 -0
- package/dist/cosmicintersection/pages/collections/CollectionDetailPage.d.ts.map +1 -0
- package/dist/cosmicintersection/pages/collections/CollectionDetailPage.js +138 -93
- package/dist/cosmicintersection/pages/collections/CollectionDetailPage.js.map +1 -1
- package/dist/cosmicintersection/pages/collections/CollectionFormPage.d.ts +2 -0
- package/dist/cosmicintersection/pages/collections/CollectionFormPage.d.ts.map +1 -0
- package/dist/cosmicintersection/pages/collections/CollectionFormPage.js.map +1 -1
- package/dist/cosmicintersection/pages/collections/CollectionsPage.d.ts +2 -0
- package/dist/cosmicintersection/pages/collections/CollectionsPage.d.ts.map +1 -0
- package/dist/cosmicintersection/pages/dashboard/DashboardPage.d.ts +2 -0
- package/dist/cosmicintersection/pages/dashboard/DashboardPage.d.ts.map +1 -0
- package/dist/cosmicintersection/pages/dashboard/DashboardPage.js +26 -15
- package/dist/cosmicintersection/pages/dashboard/DashboardPage.js.map +1 -1
- package/dist/cosmicintersection/pages/datasets/DatasetDetailPage.d.ts +2 -0
- package/dist/cosmicintersection/pages/datasets/DatasetDetailPage.d.ts.map +1 -0
- package/dist/cosmicintersection/pages/datasets/DatasetDetailPage.js +345 -219
- package/dist/cosmicintersection/pages/datasets/DatasetDetailPage.js.map +1 -1
- package/dist/cosmicintersection/pages/datasets/DatasetFormPage.d.ts +2 -0
- package/dist/cosmicintersection/pages/datasets/DatasetFormPage.d.ts.map +1 -0
- package/dist/cosmicintersection/pages/datasets/DatasetsPage.d.ts +2 -0
- package/dist/cosmicintersection/pages/datasets/DatasetsPage.d.ts.map +1 -0
- package/dist/cosmicintersection/pages/datasets/DatasetsPage.js +321 -163
- package/dist/cosmicintersection/pages/datasets/DatasetsPage.js.map +1 -1
- package/dist/cosmicintersection/pages/discovery/DiscoveryPage.d.ts +2 -0
- package/dist/cosmicintersection/pages/discovery/DiscoveryPage.d.ts.map +1 -0
- package/dist/cosmicintersection/pages/discovery/DiscoveryPage.js +358 -0
- package/dist/cosmicintersection/pages/discovery/DiscoveryPage.js.map +1 -0
- package/dist/cosmicintersection/pages/lineage/LineagePage.d.ts +2 -0
- package/dist/cosmicintersection/pages/lineage/LineagePage.d.ts.map +1 -0
- package/dist/cosmicintersection/pages/lineage/LineagePage.js +171 -0
- package/dist/cosmicintersection/pages/lineage/LineagePage.js.map +1 -0
- package/dist/cosmicintersection/pages/notebooks/NotebookDetailPage.d.ts +2 -0
- package/dist/cosmicintersection/pages/notebooks/NotebookDetailPage.d.ts.map +1 -0
- package/dist/cosmicintersection/pages/notebooks/NotebookDetailPage.js +232 -162
- package/dist/cosmicintersection/pages/notebooks/NotebookDetailPage.js.map +1 -1
- package/dist/cosmicintersection/pages/notebooks/NotebookFormPage.d.ts +2 -0
- package/dist/cosmicintersection/pages/notebooks/NotebookFormPage.d.ts.map +1 -0
- package/dist/cosmicintersection/pages/notebooks/NotebooksPage.d.ts +2 -0
- package/dist/cosmicintersection/pages/notebooks/NotebooksPage.d.ts.map +1 -0
- package/dist/cosmicintersection/pages/notebooks/NotebooksPage.js +143 -82
- package/dist/cosmicintersection/pages/notebooks/NotebooksPage.js.map +1 -1
- package/dist/cosmicintersection/pages/pipelines/PipelineDetailPage.d.ts +2 -0
- package/dist/cosmicintersection/pages/pipelines/PipelineDetailPage.d.ts.map +1 -0
- package/dist/cosmicintersection/pages/pipelines/PipelineDetailPage.js +286 -142
- package/dist/cosmicintersection/pages/pipelines/PipelineDetailPage.js.map +1 -1
- package/dist/cosmicintersection/pages/pipelines/PipelineFormPage.d.ts +2 -0
- package/dist/cosmicintersection/pages/pipelines/PipelineFormPage.d.ts.map +1 -0
- package/dist/cosmicintersection/pages/pipelines/PipelineFormPage.js +305 -103
- package/dist/cosmicintersection/pages/pipelines/PipelineFormPage.js.map +1 -1
- package/dist/cosmicintersection/pages/pipelines/PipelinesPage.d.ts +2 -0
- package/dist/cosmicintersection/pages/pipelines/PipelinesPage.d.ts.map +1 -0
- package/dist/cosmicintersection/pages/pipelines/PipelinesPage.js +183 -79
- package/dist/cosmicintersection/pages/pipelines/PipelinesPage.js.map +1 -1
- package/dist/cosmicintersection/pages/releases/ReleaseFormPage.d.ts +2 -0
- package/dist/cosmicintersection/pages/releases/ReleaseFormPage.d.ts.map +1 -0
- package/dist/cosmicintersection/pages/releases/ReleasesPage.d.ts +2 -0
- package/dist/cosmicintersection/pages/releases/ReleasesPage.d.ts.map +1 -0
- package/dist/cosmicintersection/pages/releases/ReleasesPage.js +262 -170
- package/dist/cosmicintersection/pages/releases/ReleasesPage.js.map +1 -1
- package/dist/cosmicintersection/pages/runs/RunDetailPage.d.ts +2 -0
- package/dist/cosmicintersection/pages/runs/RunDetailPage.d.ts.map +1 -0
- package/dist/cosmicintersection/pages/runs/RunDetailPage.js +179 -136
- package/dist/cosmicintersection/pages/runs/RunDetailPage.js.map +1 -1
- package/dist/cosmicintersection/pages/runs/RunsPage.d.ts +2 -0
- package/dist/cosmicintersection/pages/runs/RunsPage.d.ts.map +1 -0
- package/dist/cosmicintersection/pages/runs/RunsPage.js +124 -47
- package/dist/cosmicintersection/pages/runs/RunsPage.js.map +1 -1
- package/dist/cosmicintersection/pages/sources/SourceDetailPage.d.ts +2 -0
- package/dist/cosmicintersection/pages/sources/SourceDetailPage.d.ts.map +1 -0
- package/dist/cosmicintersection/pages/sources/SourceDetailPage.js +114 -85
- package/dist/cosmicintersection/pages/sources/SourceDetailPage.js.map +1 -1
- package/dist/cosmicintersection/pages/sources/SourceFormPage.d.ts +2 -0
- package/dist/cosmicintersection/pages/sources/SourceFormPage.d.ts.map +1 -0
- package/dist/cosmicintersection/pages/sources/SourcesPage.d.ts +2 -0
- package/dist/cosmicintersection/pages/sources/SourcesPage.d.ts.map +1 -0
- package/dist/cosmicintersection/pages/sources/SourcesPage.js +263 -152
- package/dist/cosmicintersection/pages/sources/SourcesPage.js.map +1 -1
- package/dist/cosmicintersection/types/index.d.ts +7 -0
- package/dist/cosmicintersection/types/index.d.ts.map +1 -0
- package/dist/cosmicintersection/utils/cn.d.ts +4 -0
- package/dist/cosmicintersection/utils/cn.d.ts.map +1 -0
- package/dist/cosmicintersection/utils/i18n.d.ts +15 -0
- package/dist/cosmicintersection/utils/i18n.d.ts.map +1 -0
- package/dist/cosmicintersection/utils/navigation.d.ts +2 -0
- package/dist/cosmicintersection/utils/navigation.d.ts.map +1 -0
- package/dist/dev/main.d.ts +2 -0
- package/dist/dev/main.d.ts.map +1 -0
- package/dist/generated/global-operations.d.ts +2 -0
- package/dist/generated/global-operations.d.ts.map +1 -0
- package/dist/generated/global-types.d.ts +18199 -0
- package/dist/generated/global-types.d.ts.map +1 -0
- package/dist/generated/wspace-operations.d.ts +2 -0
- package/dist/generated/wspace-operations.d.ts.map +1 -0
- package/dist/generated/wspace-types.d.ts +43046 -0
- package/dist/generated/wspace-types.d.ts.map +1 -0
- package/dist/index.d.ts +19 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +2 -2
- package/dist/services/assistantApi.d.ts +66 -0
- package/dist/services/assistantApi.d.ts.map +1 -0
- package/dist/services/assistantApi.js +250 -0
- package/dist/services/assistantApi.js.map +1 -0
- package/dist/services/createSandboxAssistantTransport.d.ts +40 -0
- package/dist/services/createSandboxAssistantTransport.d.ts.map +1 -0
- package/dist/services/createSandboxAssistantTransport.js +120 -0
- package/dist/services/createSandboxAssistantTransport.js.map +1 -0
- package/dist/types/assistant.d.ts +48 -0
- package/dist/types/assistant.d.ts.map +1 -0
- package/dist/utils/pageContext.d.ts +28 -0
- package/dist/utils/pageContext.d.ts.map +1 -0
- package/dist/utils/pageContext.js +50 -0
- package/dist/utils/pageContext.js.map +1 -0
- package/package.json +5 -1
- package/dist/cosmicintersection/index.js +0 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"NotebookDetailPage.js","names":[],"sources":["../../../../src/cosmicintersection/pages/notebooks/NotebookDetailPage.tsx"],"sourcesContent":["/**\n * NotebookDetailPage — full record for one notebook.\n *\n * Header renders the notebook's metadata (status, runtime, environment JSON,\n * description, sharing, attached file download). Below it an Analyses section\n * lists `cosListAnalyses(notebookId)` and a \"Run analysis\" dialog kicks off a\n * new `cosRunAnalysis` bound to this notebook. Archive is available from the\n * header action menu. No fabricated data — everything is read from the backend.\n */\nimport { useState, type FormEvent } from 'react';\nimport { useParams } from 'react-router-dom';\nimport {\n Beaker,\n Download,\n FileCode2,\n MessageSquare,\n Pencil,\n Play,\n Share2,\n Sparkles,\n} from 'lucide-react';\nimport {\n Badge,\n Button,\n Dialog,\n DialogContent,\n DialogDescription,\n DialogFooter,\n DialogHeader,\n DialogTitle,\n Input,\n Label,\n Switch,\n Table,\n TableBody,\n TableCell,\n TableHead,\n TableHeader,\n TableRow,\n} from '@burdenoff/fe-libs/ui';\n\nimport {\n useCosAnalysesQuery,\n useCosArchiveNotebookMutation,\n useCosNotebookQuery,\n useCosRunAnalysisMutation,\n type CosAnalysis,\n} from '../../api/cosmicApi';\nimport {\n ActionMenu,\n DiscussionPanel,\n EmptyState,\n ErrorState,\n LoadingState,\n PageLayout,\n StatusBadge,\n useFileDownloadUrl,\n} from '../../components';\nimport { useCosmicIntersection } from '../../context/CosmicIntersectionContext';\nimport { notify } from '../../lib/toast';\n\nfunction formatDateTime(value?: string | null): string {\n if (!value) {\n return '—';\n }\n const date = new Date(value);\n if (Number.isNaN(date.getTime())) {\n return '—';\n }\n return date.toLocaleString(undefined, {\n year: 'numeric',\n month: 'short',\n day: 'numeric',\n hour: '2-digit',\n minute: '2-digit',\n });\n}\n\n/** Renders a presigned download link for an attached wspace-files artifact. */\nfunction FileDownloadLink({ fileId, label }: { fileId: string; label: string }) {\n const { data, loading } = useFileDownloadUrl(fileId);\n const url = data?.getFileDownloadUrl ?? null;\n if (loading) {\n return <span className=\"text-xs text-text-secondary\">Resolving link…</span>;\n }\n if (!url) {\n return <span className=\"text-xs text-text-secondary\">File {fileId}</span>;\n }\n return (\n <a\n href={url}\n target=\"_blank\"\n rel=\"noopener noreferrer\"\n className=\"inline-flex items-center gap-1 text-sm text-text-primary underline-offset-2 hover:underline\"\n >\n <Download className=\"size-3.5\" aria-hidden=\"true\" />\n {label}\n </a>\n );\n}\n\ninterface RunAnalysisDialogProps {\n notebookId: string;\n open: boolean;\n onOpenChange: (open: boolean) => void;\n onCompleted: () => void;\n}\n\n/** Dialog to launch a new analysis on this notebook. */\nfunction RunAnalysisDialog({\n notebookId,\n open,\n onOpenChange,\n onCompleted,\n}: RunAnalysisDialogProps) {\n const [title, setTitle] = useState('');\n const [method, setMethod] = useState('');\n const [aiAssisted, setAiAssisted] = useState(false);\n const [runAnalysis, { loading }] = useCosRunAnalysisMutation();\n\n const reset = () => {\n setTitle('');\n setMethod('');\n setAiAssisted(false);\n };\n\n const handleSubmit = async (event: FormEvent<HTMLFormElement>) => {\n event.preventDefault();\n const trimmed = title.trim();\n if (!trimmed) {\n notify.error('Title is required', 'Give the analysis a descriptive title.');\n return;\n }\n const response = await runAnalysis({\n variables: {\n input: {\n notebookId,\n title: trimmed,\n method: method.trim() || undefined,\n aiAssisted,\n },\n },\n });\n if (response.error || !response.data?.cosRunAnalysis?.id) {\n return;\n }\n notify.success('Analysis started', `“${trimmed}” is now running.`);\n reset();\n onOpenChange(false);\n onCompleted();\n };\n\n return (\n <Dialog\n open={open}\n onOpenChange={(next) => {\n if (!loading) {\n onOpenChange(next);\n }\n }}\n >\n <DialogContent>\n <form onSubmit={handleSubmit} className=\"space-y-4\">\n <DialogHeader>\n <DialogTitle>Run analysis</DialogTitle>\n <DialogDescription>\n Launch a new analysis run against this notebook. It starts in the running state and\n can be completed later with results.\n </DialogDescription>\n </DialogHeader>\n\n <div className=\"space-y-1.5\">\n <Label htmlFor=\"run-analysis-title\">Title</Label>\n <Input\n id=\"run-analysis-title\"\n value={title}\n onChange={(event) => setTitle(event.target.value)}\n placeholder=\"e.g. Period-folding search\"\n required\n />\n </div>\n <div className=\"space-y-1.5\">\n <Label htmlFor=\"run-analysis-method\">Method</Label>\n <Input\n id=\"run-analysis-method\"\n value={method}\n onChange={(event) => setMethod(event.target.value)}\n placeholder=\"e.g. box-least-squares\"\n />\n </div>\n <div className=\"flex items-center gap-3\">\n <Switch\n id=\"run-analysis-ai\"\n checked={aiAssisted}\n onCheckedChange={(checked) => setAiAssisted(checked)}\n />\n <Label htmlFor=\"run-analysis-ai\" className=\"cursor-pointer\">\n AI-assisted analysis\n </Label>\n </div>\n\n <DialogFooter>\n <Button\n type=\"button\"\n variant=\"outline\"\n onClick={() => onOpenChange(false)}\n disabled={loading}\n >\n Cancel\n </Button>\n <Button type=\"submit\" disabled={loading}>\n <Play className=\"size-4\" />\n {loading ? 'Starting…' : 'Run analysis'}\n </Button>\n </DialogFooter>\n </form>\n </DialogContent>\n </Dialog>\n );\n}\n\nexport default function NotebookDetailPage() {\n const { id = '' } = useParams<{ id: string }>();\n const { navigate } = useCosmicIntersection();\n const [runOpen, setRunOpen] = useState(false);\n\n const { data, loading, error, refetch } = useCosNotebookQuery(id);\n const {\n data: analysesData,\n loading: analysesLoading,\n error: analysesError,\n refetch: refetchAnalyses,\n } = useCosAnalysesQuery({ notebookId: id });\n const [archiveNotebook] = useCosArchiveNotebookMutation();\n\n const notebook = data?.cosNotebook ?? null;\n const analyses = analysesData?.cosListAnalyses ?? [];\n\n const handleArchive = async () => {\n if (!notebook) {\n return;\n }\n const response = await archiveNotebook({ variables: { id: notebook.id } });\n if (response.error) {\n throw new Error(response.error.message);\n }\n if (!response.data?.cosArchiveNotebook) {\n notify.error('Could not archive notebook', 'The server did not confirm the change.');\n throw new Error('Archive not confirmed');\n }\n await refetch();\n notify.success('Notebook archived', `“${notebook.title}” was archived.`);\n };\n\n if (loading) {\n return (\n <PageLayout title=\"Notebook\" backPath=\"notebooks\">\n <LoadingState label=\"Loading notebook…\" />\n </PageLayout>\n );\n }\n\n if (error) {\n return (\n <PageLayout title=\"Notebook\" backPath=\"notebooks\">\n <ErrorState\n message=\"We could not load this notebook. Please try again.\"\n onRetry={() => void refetch()}\n />\n </PageLayout>\n );\n }\n\n if (!notebook) {\n return (\n <PageLayout title=\"Notebook\" backPath=\"notebooks\">\n <EmptyState\n icon={FileCode2}\n title=\"Notebook not found.\"\n description=\"This notebook may have been removed or is outside your current scope.\"\n action={\n <Button type=\"button\" onClick={() => navigate('notebooks')}>\n Back to notebooks\n </Button>\n }\n />\n </PageLayout>\n );\n }\n\n const environmentJson =\n notebook.environment && Object.keys(notebook.environment).length > 0\n ? JSON.stringify(notebook.environment, null, 2)\n : null;\n\n const actions = (\n <div className=\"flex items-center gap-2\">\n <Button type=\"button\" onClick={() => setRunOpen(true)}>\n <Play className=\"size-4\" />\n Run analysis\n </Button>\n <Button\n type=\"button\"\n variant=\"outline\"\n onClick={() => navigate(`notebooks/${notebook.id}/edit`)}\n >\n <Pencil className=\"size-4\" />\n Edit\n </Button>\n <ActionMenu\n ariaLabel={`Actions for ${notebook.title}`}\n entityName={notebook.title}\n onDelete={notebook.status === 'ARCHIVED' ? undefined : handleArchive}\n deleteLabel=\"Archive notebook\"\n />\n </div>\n );\n\n return (\n <PageLayout\n title={notebook.title}\n description=\"Notebook detail\"\n backPath=\"notebooks\"\n actions={actions}\n >\n <div className=\"space-y-6\">\n {/* Overview */}\n <section className=\"rounded-card border border-border-default bg-bg-elevated p-6\">\n <div className=\"flex flex-wrap items-center gap-3\">\n <StatusBadge status={notebook.status} />\n {notebook.runtime ? <Badge variant=\"outline\">Runtime: {notebook.runtime}</Badge> : null}\n {notebook.isShared ? (\n <Badge variant=\"secondary\" className=\"gap-1\">\n <Share2 className=\"size-3\" aria-hidden=\"true\" />\n Shared{notebook.shareSlug ? `: ${notebook.shareSlug}` : ''}\n </Badge>\n ) : (\n <Badge variant=\"outline\">Private</Badge>\n )}\n </div>\n\n {notebook.description ? (\n <p className=\"mt-4 text-sm text-text-secondary\">{notebook.description}</p>\n ) : (\n <p className=\"mt-4 text-sm text-text-secondary\">No description provided.</p>\n )}\n\n <dl className=\"mt-6 grid grid-cols-1 gap-4 sm:grid-cols-2 lg:grid-cols-3\">\n <div>\n <dt className=\"text-xs uppercase tracking-wide text-text-secondary\">\n Linked datasets\n </dt>\n <dd className=\"mt-1 text-sm tabular-nums text-text-primary\">\n {notebook.datasetIds.length}\n </dd>\n </div>\n <div>\n <dt className=\"text-xs uppercase tracking-wide text-text-secondary\">Created</dt>\n <dd className=\"mt-1 text-sm text-text-primary\">\n {formatDateTime(notebook.createdAt)}\n </dd>\n </div>\n <div>\n <dt className=\"text-xs uppercase tracking-wide text-text-secondary\">Updated</dt>\n <dd className=\"mt-1 text-sm text-text-primary\">\n {formatDateTime(notebook.updatedAt)}\n </dd>\n </div>\n <div>\n <dt className=\"text-xs uppercase tracking-wide text-text-secondary\">Notebook file</dt>\n <dd className=\"mt-1 text-sm text-text-primary\">\n {notebook.file?.id ? (\n <FileDownloadLink fileId={notebook.file.id} label=\"Download notebook\" />\n ) : (\n <span className=\"text-text-secondary\">No file attached</span>\n )}\n </dd>\n </div>\n </dl>\n\n {notebook.tags.length > 0 ? (\n <div className=\"mt-6\">\n <p className=\"text-xs uppercase tracking-wide text-text-secondary\">Tags</p>\n <div className=\"mt-2 flex flex-wrap gap-2\">\n {notebook.tags.map((tag) => (\n <Badge key={tag} variant=\"outline\">\n {tag}\n </Badge>\n ))}\n </div>\n </div>\n ) : null}\n\n {environmentJson ? (\n <div className=\"mt-6\">\n <p className=\"text-xs uppercase tracking-wide text-text-secondary\">Environment</p>\n <pre className=\"mt-2 max-h-64 overflow-auto rounded-card border border-border-default bg-bg-sunken p-4 font-mono text-xs text-text-primary\">\n {environmentJson}\n </pre>\n </div>\n ) : null}\n\n </section>\n\n {/* Discussion */}\n <section className=\"space-y-4\">\n <div className=\"flex items-center gap-2\">\n <MessageSquare 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-notebook\"\n entityId={notebook.id}\n title={notebook.title}\n widgetKey=\"notebook-discussion\"\n />\n </section>\n\n {/* Analyses */}\n <section className=\"space-y-4\">\n <div className=\"flex flex-wrap items-center justify-between gap-3\">\n <div>\n <h2 className=\"text-lg font-semibold text-text-primary\">Analyses</h2>\n <p className=\"text-sm text-text-secondary\">\n Analysis runs executed against this notebook.\n </p>\n </div>\n <Button type=\"button\" variant=\"outline\" onClick={() => setRunOpen(true)}>\n <Play className=\"size-4\" />\n Run analysis\n </Button>\n </div>\n\n {analysesLoading ? (\n <LoadingState variant=\"rows\" rows={3} label=\"Loading analyses…\" />\n ) : analysesError ? (\n <ErrorState\n message=\"We could not load analyses for this notebook.\"\n onRetry={() => void refetchAnalyses()}\n />\n ) : analyses.length === 0 ? (\n <EmptyState\n icon={Beaker}\n title=\"No analyses yet.\"\n description=\"Run an analysis to generate results and artifacts from this notebook.\"\n action={\n <Button type=\"button\" onClick={() => setRunOpen(true)}>\n <Play className=\"size-4\" />\n Run analysis\n </Button>\n }\n />\n ) : (\n <div className=\"rounded-card border border-border-default bg-bg-elevated\">\n <Table>\n <TableHeader>\n <TableRow>\n <TableHead>Title</TableHead>\n <TableHead>Method</TableHead>\n <TableHead>AI</TableHead>\n <TableHead>Status</TableHead>\n <TableHead>Started</TableHead>\n <TableHead>Output</TableHead>\n </TableRow>\n </TableHeader>\n <TableBody>\n {analyses.map((analysis: CosAnalysis) => (\n <TableRow key={analysis.id}>\n <TableCell className=\"font-medium text-text-primary\">\n {analysis.title}\n </TableCell>\n <TableCell className=\"text-text-secondary\">\n {analysis.method ?? '—'}\n </TableCell>\n <TableCell>\n {analysis.aiAssisted ? (\n <Badge variant=\"secondary\" className=\"gap-1\">\n <Sparkles className=\"size-3\" aria-hidden=\"true\" />\n AI\n </Badge>\n ) : (\n <span className=\"text-text-secondary\">—</span>\n )}\n </TableCell>\n <TableCell>\n <StatusBadge status={analysis.status} />\n </TableCell>\n <TableCell className=\"whitespace-nowrap text-text-secondary\">\n {formatDateTime(analysis.startedAt)}\n </TableCell>\n <TableCell>\n {analysis.outputFile?.id ? (\n <FileDownloadLink fileId={analysis.outputFile.id} label=\"Download\" />\n ) : analysis.results && Object.keys(analysis.results).length > 0 ? (\n <span className=\"text-xs text-text-secondary\">Results recorded</span>\n ) : (\n <span className=\"text-text-secondary\">—</span>\n )}\n </TableCell>\n </TableRow>\n ))}\n </TableBody>\n </Table>\n </div>\n )}\n </section>\n </div>\n\n <RunAnalysisDialog\n notebookId={notebook.id}\n open={runOpen}\n onOpenChange={setRunOpen}\n onCompleted={() => void refetchAnalyses()}\n />\n </PageLayout>\n );\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"NotebookDetailPage.js","names":[],"sources":["../../../../src/cosmicintersection/pages/notebooks/NotebookDetailPage.tsx"],"sourcesContent":["/**\n * NotebookDetailPage — full record for one notebook.\n *\n * Header renders the notebook's metadata (status, runtime, environment JSON,\n * description, sharing, attached file download). Below it an Analyses section\n * lists `cosListAnalyses(notebookId)` and a \"Run analysis\" dialog kicks off a\n * new `cosRunAnalysis` bound to this notebook. Archive is available from the\n * header action menu. No fabricated data — everything is read from the backend.\n */\nimport { useMemo, useState, type FormEvent } from 'react';\nimport { useParams } from 'react-router-dom';\nimport {\n Beaker,\n Database,\n Download,\n FileCode2,\n MessageSquare,\n Pencil,\n Play,\n Share2,\n Sparkles,\n} from 'lucide-react';\nimport {\n Badge,\n Button,\n Dialog,\n DialogContent,\n DialogDescription,\n DialogFooter,\n DialogHeader,\n DialogTitle,\n Input,\n Label,\n Switch,\n Table,\n TableBody,\n TableCell,\n TableHead,\n TableHeader,\n TableRow,\n} from '@burdenoff/fe-libs/ui';\n\nimport {\n useCosAnalysesQuery,\n useCosArchiveNotebookMutation,\n useCosDatasetsQuery,\n useCosNotebookQuery,\n useCosRunAnalysisMutation,\n type CosAnalysis,\n} from '../../api/cosmicApi';\nimport {\n ActionMenu,\n DiscussionPanel,\n EmptyState,\n ErrorState,\n LoadingState,\n PageLayout,\n StatusBadge,\n useFileDownloadUrl,\n} from '../../components';\nimport { useCosmicIntersection } from '../../context/CosmicIntersectionContext';\nimport { notify } from '../../lib/toast';\n\nfunction formatDateTime(value?: string | null): string {\n if (!value) {\n return '—';\n }\n const date = new Date(value);\n if (Number.isNaN(date.getTime())) {\n return '—';\n }\n return date.toLocaleString(undefined, {\n year: 'numeric',\n month: 'short',\n day: 'numeric',\n hour: '2-digit',\n minute: '2-digit',\n });\n}\n\n/** Renders a presigned download link for an attached wspace-files artifact. */\nfunction FileDownloadLink({ fileId, label }: { fileId: string; label: string }) {\n const { data, loading } = useFileDownloadUrl(fileId);\n const url = data?.getFileDownloadUrl ?? null;\n if (loading) {\n return <span className=\"text-xs text-text-secondary\">Resolving link…</span>;\n }\n if (!url) {\n return <span className=\"text-xs text-text-secondary\">File {fileId}</span>;\n }\n return (\n <a\n href={url}\n target=\"_blank\"\n rel=\"noopener noreferrer\"\n className=\"inline-flex items-center gap-1 text-sm text-text-primary underline-offset-2 hover:underline\"\n >\n <Download className=\"size-3.5\" aria-hidden=\"true\" />\n {label}\n </a>\n );\n}\n\ninterface RunAnalysisDialogProps {\n notebookId: string;\n open: boolean;\n onOpenChange: (open: boolean) => void;\n onCompleted: () => void;\n}\n\n/** Dialog to launch a new analysis on this notebook. */\nfunction RunAnalysisDialog({\n notebookId,\n open,\n onOpenChange,\n onCompleted,\n}: RunAnalysisDialogProps) {\n const [title, setTitle] = useState('');\n const [method, setMethod] = useState('');\n const [aiAssisted, setAiAssisted] = useState(false);\n const [runAnalysis, { loading }] = useCosRunAnalysisMutation();\n\n const reset = () => {\n setTitle('');\n setMethod('');\n setAiAssisted(false);\n };\n\n const handleSubmit = async (event: FormEvent<HTMLFormElement>) => {\n event.preventDefault();\n const trimmed = title.trim();\n if (!trimmed) {\n notify.error('Title is required', 'Give the analysis a descriptive title.');\n return;\n }\n const response = await runAnalysis({\n variables: {\n input: {\n notebookId,\n title: trimmed,\n method: method.trim() || undefined,\n aiAssisted,\n },\n },\n });\n if (response.error || !response.data?.cosRunAnalysis?.id) {\n return;\n }\n notify.success('Analysis started', `“${trimmed}” is now running.`);\n reset();\n onOpenChange(false);\n onCompleted();\n };\n\n return (\n <Dialog\n open={open}\n onOpenChange={(next) => {\n if (!loading) {\n onOpenChange(next);\n }\n }}\n >\n <DialogContent>\n <form onSubmit={handleSubmit} className=\"space-y-4\">\n <DialogHeader>\n <DialogTitle>Run analysis</DialogTitle>\n <DialogDescription>\n Launch a new analysis run against this notebook. It starts in the running state and\n can be completed later with results.\n </DialogDescription>\n </DialogHeader>\n\n <div className=\"space-y-1.5\">\n <Label htmlFor=\"run-analysis-title\">Title</Label>\n <Input\n id=\"run-analysis-title\"\n value={title}\n onChange={(event) => setTitle(event.target.value)}\n placeholder=\"e.g. Period-folding search\"\n required\n />\n </div>\n <div className=\"space-y-1.5\">\n <Label htmlFor=\"run-analysis-method\">Method</Label>\n <Input\n id=\"run-analysis-method\"\n value={method}\n onChange={(event) => setMethod(event.target.value)}\n placeholder=\"e.g. box-least-squares\"\n />\n </div>\n <div className=\"flex items-center gap-3\">\n <Switch\n id=\"run-analysis-ai\"\n checked={aiAssisted}\n onCheckedChange={(checked) => setAiAssisted(checked)}\n />\n <Label htmlFor=\"run-analysis-ai\" className=\"cursor-pointer\">\n AI-assisted analysis\n </Label>\n </div>\n\n <DialogFooter>\n <Button\n type=\"button\"\n variant=\"outline\"\n onClick={() => onOpenChange(false)}\n disabled={loading}\n >\n Cancel\n </Button>\n <Button type=\"submit\" disabled={loading}>\n <Play className=\"size-4\" />\n {loading ? 'Starting…' : 'Run analysis'}\n </Button>\n </DialogFooter>\n </form>\n </DialogContent>\n </Dialog>\n );\n}\n\nexport default function NotebookDetailPage() {\n const { id = '' } = useParams<{ id: string }>();\n const { navigate } = useCosmicIntersection();\n const [runOpen, setRunOpen] = useState(false);\n\n const { data, loading, error, refetch } = useCosNotebookQuery(id);\n const {\n data: analysesData,\n loading: analysesLoading,\n error: analysesError,\n refetch: refetchAnalyses,\n } = useCosAnalysesQuery({ notebookId: id });\n // Resolve the notebook's linked dataset UUIDs to human names for chips.\n const { data: datasetsData } = useCosDatasetsQuery({ pagination: { limit: 100, offset: 0 } });\n const [archiveNotebook] = useCosArchiveNotebookMutation();\n\n const notebook = data?.cosNotebook ?? null;\n const analyses = analysesData?.cosListAnalyses ?? [];\n\n const datasetNameById = useMemo(() => {\n const map = new Map<string, string>();\n for (const dataset of datasetsData?.cosListDatasets.items ?? []) {\n map.set(dataset.id, dataset.name);\n }\n return map;\n }, [datasetsData]);\n\n const handleArchive = async () => {\n if (!notebook) {\n return;\n }\n const response = await archiveNotebook({ variables: { id: notebook.id } });\n if (response.error) {\n throw new Error(response.error.message);\n }\n if (!response.data?.cosArchiveNotebook) {\n notify.error('Could not archive notebook', 'The server did not confirm the change.');\n throw new Error('Archive not confirmed');\n }\n await refetch();\n notify.success('Notebook archived', `“${notebook.title}” was archived.`);\n };\n\n if (loading) {\n return (\n <PageLayout title=\"Notebook\" backPath=\"notebooks\">\n <LoadingState label=\"Loading notebook…\" />\n </PageLayout>\n );\n }\n\n if (error) {\n return (\n <PageLayout title=\"Notebook\" backPath=\"notebooks\">\n <ErrorState\n message=\"We could not load this notebook. Please try again.\"\n onRetry={() => void refetch()}\n />\n </PageLayout>\n );\n }\n\n if (!notebook) {\n return (\n <PageLayout title=\"Notebook\" backPath=\"notebooks\">\n <EmptyState\n icon={FileCode2}\n title=\"Notebook not found.\"\n description=\"This notebook may have been removed or is outside your current scope.\"\n action={\n <Button type=\"button\" onClick={() => navigate('notebooks')}>\n Back to notebooks\n </Button>\n }\n />\n </PageLayout>\n );\n }\n\n const environmentJson =\n notebook.environment && Object.keys(notebook.environment).length > 0\n ? JSON.stringify(notebook.environment, null, 2)\n : null;\n\n const actions = (\n <div className=\"flex items-center gap-2\">\n <Button type=\"button\" onClick={() => setRunOpen(true)}>\n <Play className=\"size-4\" />\n Run analysis\n </Button>\n <Button\n type=\"button\"\n variant=\"outline\"\n onClick={() => navigate(`notebooks/${notebook.id}/edit`)}\n >\n <Pencil className=\"size-4\" />\n Edit\n </Button>\n <ActionMenu\n ariaLabel={`Actions for ${notebook.title}`}\n entityName={notebook.title}\n onDelete={notebook.status === 'ARCHIVED' ? undefined : handleArchive}\n deleteLabel=\"Archive notebook\"\n />\n </div>\n );\n\n return (\n <PageLayout\n title={notebook.title}\n description=\"Notebook detail\"\n backPath=\"notebooks\"\n actions={actions}\n >\n <div className=\"space-y-6\">\n {/* Overview */}\n <section className=\"rounded-card border border-border-default bg-bg-elevated p-6\">\n <div className=\"flex flex-wrap items-center gap-3\">\n <StatusBadge status={notebook.status} />\n {notebook.runtime ? <Badge variant=\"outline\">Runtime: {notebook.runtime}</Badge> : null}\n {notebook.isShared ? (\n <Badge variant=\"secondary\" className=\"gap-1\">\n <Share2 className=\"size-3\" aria-hidden=\"true\" />\n Shared{notebook.shareSlug ? `: ${notebook.shareSlug}` : ''}\n </Badge>\n ) : (\n <Badge variant=\"outline\">Private</Badge>\n )}\n </div>\n\n {notebook.description ? (\n <p className=\"mt-4 text-sm text-text-secondary\">{notebook.description}</p>\n ) : (\n <p className=\"mt-4 text-sm text-text-secondary\">No description provided.</p>\n )}\n\n <div className=\"mt-6\">\n <p className=\"text-xs uppercase tracking-wide text-text-secondary\">Linked datasets</p>\n {notebook.datasetIds.length === 0 ? (\n <p className=\"mt-2 text-sm text-text-secondary\">No datasets linked.</p>\n ) : (\n <div className=\"mt-2 flex flex-wrap gap-2\">\n {notebook.datasetIds.map((datasetId) => {\n const name = datasetNameById.get(datasetId);\n return (\n <Button\n key={datasetId}\n type=\"button\"\n variant=\"outline\"\n size=\"sm\"\n className=\"h-auto gap-1.5 px-2.5 py-1\"\n onClick={() => navigate(`datasets/${datasetId}`)}\n >\n <Database className=\"size-3.5 shrink-0\" aria-hidden=\"true\" />\n <span className={name ? 'max-w-[16rem] truncate' : 'font-mono text-xs'}>\n {name ?? datasetId}\n </span>\n </Button>\n );\n })}\n </div>\n )}\n </div>\n\n <dl className=\"mt-6 grid grid-cols-1 gap-4 sm:grid-cols-2 lg:grid-cols-3\">\n <div>\n <dt className=\"text-xs uppercase tracking-wide text-text-secondary\">Created</dt>\n <dd className=\"mt-1 text-sm text-text-primary\">\n {formatDateTime(notebook.createdAt)}\n </dd>\n </div>\n <div>\n <dt className=\"text-xs uppercase tracking-wide text-text-secondary\">Updated</dt>\n <dd className=\"mt-1 text-sm text-text-primary\">\n {formatDateTime(notebook.updatedAt)}\n </dd>\n </div>\n <div>\n <dt className=\"text-xs uppercase tracking-wide text-text-secondary\">Notebook file</dt>\n <dd className=\"mt-1 text-sm text-text-primary\">\n {notebook.file?.id ? (\n <FileDownloadLink fileId={notebook.file.id} label=\"Download notebook\" />\n ) : (\n <span className=\"text-text-secondary\">No file attached</span>\n )}\n </dd>\n </div>\n </dl>\n\n {notebook.tags.length > 0 ? (\n <div className=\"mt-6\">\n <p className=\"text-xs uppercase tracking-wide text-text-secondary\">Tags</p>\n <div className=\"mt-2 flex flex-wrap gap-2\">\n {notebook.tags.map((tag) => (\n <Badge key={tag} variant=\"outline\">\n {tag}\n </Badge>\n ))}\n </div>\n </div>\n ) : null}\n\n {environmentJson ? (\n <div className=\"mt-6\">\n <p className=\"text-xs uppercase tracking-wide text-text-secondary\">Environment</p>\n <pre className=\"mt-2 max-h-64 overflow-auto rounded-card border border-border-default bg-bg-sunken p-4 font-mono text-xs text-text-primary\">\n {environmentJson}\n </pre>\n </div>\n ) : null}\n </section>\n\n {/* Discussion */}\n <section className=\"space-y-4\">\n <div className=\"flex items-center gap-2\">\n <MessageSquare 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-notebook\"\n entityId={notebook.id}\n title={notebook.title}\n widgetKey=\"notebook-discussion\"\n />\n </section>\n\n {/* Analyses */}\n <section className=\"space-y-4\">\n <div className=\"flex flex-wrap items-center justify-between gap-3\">\n <div>\n <h2 className=\"text-lg font-semibold text-text-primary\">Analyses</h2>\n <p className=\"text-sm text-text-secondary\">\n Analysis runs executed against this notebook.\n </p>\n </div>\n <Button type=\"button\" variant=\"outline\" onClick={() => setRunOpen(true)}>\n <Play className=\"size-4\" />\n Run analysis\n </Button>\n </div>\n\n {analysesLoading ? (\n <LoadingState variant=\"rows\" rows={3} label=\"Loading analyses…\" />\n ) : analysesError ? (\n <ErrorState\n message=\"We could not load analyses for this notebook.\"\n onRetry={() => void refetchAnalyses()}\n />\n ) : analyses.length === 0 ? (\n <EmptyState\n icon={Beaker}\n title=\"No analyses yet.\"\n description=\"Run an analysis to generate results and artifacts from this notebook.\"\n action={\n <Button type=\"button\" onClick={() => setRunOpen(true)}>\n <Play className=\"size-4\" />\n Run analysis\n </Button>\n }\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>Title</TableHead>\n <TableHead>Method</TableHead>\n <TableHead>AI</TableHead>\n <TableHead>Status</TableHead>\n <TableHead>Started</TableHead>\n <TableHead>Output</TableHead>\n </TableRow>\n </TableHeader>\n <TableBody>\n {analyses.map((analysis: CosAnalysis) => (\n <TableRow key={analysis.id}>\n <TableCell className=\"font-medium text-text-primary\">\n {analysis.title}\n </TableCell>\n <TableCell className=\"text-text-secondary\">\n {analysis.method ?? '—'}\n </TableCell>\n <TableCell>\n {analysis.aiAssisted ? (\n <Badge variant=\"secondary\" className=\"gap-1\">\n <Sparkles className=\"size-3\" aria-hidden=\"true\" />\n AI\n </Badge>\n ) : (\n <span className=\"text-text-secondary\">—</span>\n )}\n </TableCell>\n <TableCell>\n <StatusBadge status={analysis.status} />\n </TableCell>\n <TableCell className=\"whitespace-nowrap text-text-secondary\">\n {formatDateTime(analysis.startedAt)}\n </TableCell>\n <TableCell>\n {analysis.outputFile?.id ? (\n <FileDownloadLink fileId={analysis.outputFile.id} label=\"Download\" />\n ) : analysis.results && Object.keys(analysis.results).length > 0 ? (\n <span className=\"text-xs text-text-secondary\">Results recorded</span>\n ) : (\n <span className=\"text-text-secondary\">—</span>\n )}\n </TableCell>\n </TableRow>\n ))}\n </TableBody>\n </Table>\n </div>\n\n {/* Mobile card list */}\n <ul className=\"space-y-3 md:hidden\">\n {analyses.map((analysis: CosAnalysis) => (\n <li\n key={analysis.id}\n className=\"space-y-2 rounded-card border border-border-default bg-bg-elevated p-4\"\n >\n <div className=\"flex items-start justify-between gap-3\">\n <div className=\"min-w-0\">\n <p className=\"truncate font-medium text-text-primary\">{analysis.title}</p>\n {analysis.method ? (\n <p className=\"truncate text-xs text-text-secondary\">{analysis.method}</p>\n ) : null}\n </div>\n <StatusBadge status={analysis.status} />\n </div>\n <div className=\"flex flex-wrap items-center gap-2 text-xs text-text-secondary\">\n {analysis.aiAssisted ? (\n <Badge variant=\"secondary\" className=\"gap-1\">\n <Sparkles className=\"size-3\" aria-hidden=\"true\" />\n AI\n </Badge>\n ) : null}\n <span>Started {formatDateTime(analysis.startedAt)}</span>\n </div>\n <div>\n {analysis.outputFile?.id ? (\n <FileDownloadLink fileId={analysis.outputFile.id} label=\"Download\" />\n ) : analysis.results && Object.keys(analysis.results).length > 0 ? (\n <span className=\"text-xs text-text-secondary\">Results recorded</span>\n ) : (\n <span className=\"text-xs text-text-secondary\">No output</span>\n )}\n </div>\n </li>\n ))}\n </ul>\n </>\n )}\n </section>\n </div>\n\n <RunAnalysisDialog\n notebookId={notebook.id}\n open={runOpen}\n onOpenChange={setRunOpen}\n onCompleted={() => void refetchAnalyses()}\n />\n </PageLayout>\n );\n}\n"],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"NotebookFormPage.d.ts","sourceRoot":"","sources":["../../../../src/cosmicintersection/pages/notebooks/NotebookFormPage.tsx"],"names":[],"mappings":"AA0FA,MAAM,CAAC,OAAO,UAAU,gBAAgB,4CAiQvC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"NotebooksPage.d.ts","sourceRoot":"","sources":["../../../../src/cosmicintersection/pages/notebooks/NotebooksPage.tsx"],"names":[],"mappings":"AAkEA,MAAM,CAAC,OAAO,UAAU,aAAa,4CAwQpC"}
|
|
@@ -10,11 +10,11 @@ import l, { usePagination as u } from "../../components/Pagination.js";
|
|
|
10
10
|
import d from "../../components/StatusBadge.js";
|
|
11
11
|
import "../../components/index.js";
|
|
12
12
|
import { useState as f } from "react";
|
|
13
|
-
import {
|
|
14
|
-
import { NotebookText as
|
|
15
|
-
import { Badge as
|
|
13
|
+
import { Fragment as p, jsx as m, jsxs as h } from "react/jsx-runtime";
|
|
14
|
+
import { NotebookText as g, Plus as _, Share2 as v } from "lucide-react";
|
|
15
|
+
import { Badge as y, Button as b, Select as x, SelectContent as S, SelectItem as C, SelectTrigger as w, SelectValue as T, Table as E, TableBody as D, TableCell as O, TableHead as k, TableHeader as A, TableRow as j } from "@burdenoff/fe-libs/ui";
|
|
16
16
|
//#region src/cosmicintersection/pages/notebooks/NotebooksPage.tsx
|
|
17
|
-
var
|
|
17
|
+
var M = [
|
|
18
18
|
{
|
|
19
19
|
value: "DRAFT",
|
|
20
20
|
label: "Draft"
|
|
@@ -31,8 +31,8 @@ var j = [
|
|
|
31
31
|
value: "ARCHIVED",
|
|
32
32
|
label: "Archived"
|
|
33
33
|
}
|
|
34
|
-
],
|
|
35
|
-
function
|
|
34
|
+
], N = "ALL";
|
|
35
|
+
function P(e) {
|
|
36
36
|
if (!e) return "—";
|
|
37
37
|
let t = new Date(e);
|
|
38
38
|
return Number.isNaN(t.getTime()) ? "—" : t.toLocaleDateString(void 0, {
|
|
@@ -41,163 +41,224 @@ function N(e) {
|
|
|
41
41
|
day: "numeric"
|
|
42
42
|
});
|
|
43
43
|
}
|
|
44
|
-
function
|
|
45
|
-
let { navigate:
|
|
44
|
+
function F() {
|
|
45
|
+
let { navigate: F } = e(), [I, L] = f(void 0), R = u({
|
|
46
46
|
pageSize: 50,
|
|
47
|
-
resetKey:
|
|
48
|
-
}), { data:
|
|
49
|
-
status:
|
|
47
|
+
resetKey: I
|
|
48
|
+
}), { data: z, loading: B, error: V, refetch: H } = r({
|
|
49
|
+
status: I,
|
|
50
50
|
pagination: {
|
|
51
|
-
limit:
|
|
52
|
-
offset:
|
|
51
|
+
limit: R.limit,
|
|
52
|
+
offset: R.offset
|
|
53
53
|
}
|
|
54
|
-
}), [
|
|
55
|
-
let n = await
|
|
54
|
+
}), [U] = n(), W = z?.cosListNotebooks.items ?? [], G = z?.cosListNotebooks.pageInfo, K = async (e) => {
|
|
55
|
+
let n = await U({ variables: { id: e.id } });
|
|
56
56
|
if (n.error) throw Error(n.error.message);
|
|
57
57
|
if (!n.data?.cosArchiveNotebook) throw t.error("Could not archive notebook", "The server did not confirm the change."), Error("Archive not confirmed");
|
|
58
|
-
await
|
|
58
|
+
await H(), t.success("Notebook archived", `“${e.title}” was archived.`);
|
|
59
59
|
};
|
|
60
|
-
return /* @__PURE__ */
|
|
60
|
+
return /* @__PURE__ */ m(c, {
|
|
61
61
|
title: "Notebooks",
|
|
62
62
|
description: "Computational notebooks for running analyses over federated science datasets.",
|
|
63
|
-
actions: /* @__PURE__ */
|
|
63
|
+
actions: /* @__PURE__ */ h(b, {
|
|
64
64
|
type: "button",
|
|
65
|
-
onClick: () =>
|
|
66
|
-
children: [/* @__PURE__ */
|
|
65
|
+
onClick: () => F("notebooks/create"),
|
|
66
|
+
children: [/* @__PURE__ */ m(_, { className: "size-4" }), "New notebook"]
|
|
67
67
|
}),
|
|
68
|
-
children: /* @__PURE__ */
|
|
68
|
+
children: /* @__PURE__ */ h("div", {
|
|
69
69
|
className: "space-y-4",
|
|
70
70
|
children: [
|
|
71
|
-
/* @__PURE__ */
|
|
71
|
+
/* @__PURE__ */ h("div", {
|
|
72
72
|
className: "flex flex-wrap items-center gap-3",
|
|
73
|
-
children: [/* @__PURE__ */
|
|
73
|
+
children: [/* @__PURE__ */ m("label", {
|
|
74
74
|
className: "text-sm text-text-secondary",
|
|
75
75
|
htmlFor: "notebook-status-filter",
|
|
76
76
|
children: "Status"
|
|
77
|
-
}), /* @__PURE__ */
|
|
78
|
-
value:
|
|
79
|
-
onValueChange: (e) =>
|
|
80
|
-
children: [/* @__PURE__ */
|
|
77
|
+
}), /* @__PURE__ */ h(x, {
|
|
78
|
+
value: I ?? N,
|
|
79
|
+
onValueChange: (e) => L(e === N ? void 0 : e),
|
|
80
|
+
children: [/* @__PURE__ */ m(w, {
|
|
81
81
|
id: "notebook-status-filter",
|
|
82
82
|
className: "w-48",
|
|
83
83
|
"aria-label": "Filter by status",
|
|
84
|
-
children: /* @__PURE__ */
|
|
85
|
-
}), /* @__PURE__ */
|
|
86
|
-
value:
|
|
84
|
+
children: /* @__PURE__ */ m(T, {})
|
|
85
|
+
}), /* @__PURE__ */ h(S, { children: [/* @__PURE__ */ m(C, {
|
|
86
|
+
value: N,
|
|
87
87
|
children: "All statuses"
|
|
88
|
-
}),
|
|
88
|
+
}), M.map((e) => /* @__PURE__ */ m(C, {
|
|
89
89
|
value: e.value,
|
|
90
90
|
children: e.label
|
|
91
91
|
}, e.value))] })]
|
|
92
92
|
})]
|
|
93
93
|
}),
|
|
94
|
-
|
|
94
|
+
B ? /* @__PURE__ */ m(s, {
|
|
95
95
|
variant: "rows",
|
|
96
96
|
rows: 6,
|
|
97
97
|
label: "Loading notebooks…"
|
|
98
|
-
}) :
|
|
98
|
+
}) : V ? /* @__PURE__ */ m(o, {
|
|
99
99
|
message: "We could not load your notebooks. Please try again.",
|
|
100
|
-
onRetry: () => void
|
|
101
|
-
}) :
|
|
102
|
-
icon:
|
|
103
|
-
title:
|
|
104
|
-
description:
|
|
105
|
-
action:
|
|
100
|
+
onRetry: () => void H()
|
|
101
|
+
}) : W.length === 0 ? /* @__PURE__ */ m(a, {
|
|
102
|
+
icon: g,
|
|
103
|
+
title: I ? "No notebooks match this filter." : "No notebooks yet.",
|
|
104
|
+
description: I ? "Try a different status filter." : "Create your first notebook to start analysing federated datasets.",
|
|
105
|
+
action: I ? void 0 : /* @__PURE__ */ h(b, {
|
|
106
106
|
type: "button",
|
|
107
|
-
onClick: () =>
|
|
108
|
-
children: [/* @__PURE__ */
|
|
107
|
+
onClick: () => F("notebooks/create"),
|
|
108
|
+
children: [/* @__PURE__ */ m(_, { className: "size-4" }), "New notebook"]
|
|
109
109
|
})
|
|
110
|
-
}) : /* @__PURE__ */ p("div", {
|
|
111
|
-
className: "rounded-card border border-border-default bg-bg-elevated",
|
|
112
|
-
children: /* @__PURE__ */
|
|
113
|
-
/* @__PURE__ */
|
|
114
|
-
/* @__PURE__ */
|
|
115
|
-
/* @__PURE__ */
|
|
116
|
-
/* @__PURE__ */
|
|
110
|
+
}) : /* @__PURE__ */ h(p, { children: [/* @__PURE__ */ m("div", {
|
|
111
|
+
className: "hidden rounded-card border border-border-default bg-bg-elevated md:block",
|
|
112
|
+
children: /* @__PURE__ */ h(E, { children: [/* @__PURE__ */ m(A, { children: /* @__PURE__ */ h(j, { children: [
|
|
113
|
+
/* @__PURE__ */ m(k, { children: "Title" }),
|
|
114
|
+
/* @__PURE__ */ m(k, { children: "Status" }),
|
|
115
|
+
/* @__PURE__ */ m(k, { children: "Runtime" }),
|
|
116
|
+
/* @__PURE__ */ m(k, {
|
|
117
117
|
className: "text-right",
|
|
118
118
|
children: "Datasets"
|
|
119
119
|
}),
|
|
120
|
-
/* @__PURE__ */
|
|
121
|
-
/* @__PURE__ */
|
|
122
|
-
/* @__PURE__ */
|
|
123
|
-
/* @__PURE__ */
|
|
120
|
+
/* @__PURE__ */ m(k, { children: "Sharing" }),
|
|
121
|
+
/* @__PURE__ */ m(k, { children: "Tags" }),
|
|
122
|
+
/* @__PURE__ */ m(k, { children: "Updated" }),
|
|
123
|
+
/* @__PURE__ */ m(k, {
|
|
124
124
|
className: "w-12 text-right",
|
|
125
125
|
children: "Actions"
|
|
126
126
|
})
|
|
127
|
-
] }) }), /* @__PURE__ */
|
|
127
|
+
] }) }), /* @__PURE__ */ m(D, { children: W.map((e) => /* @__PURE__ */ h(j, {
|
|
128
128
|
className: "cursor-pointer",
|
|
129
|
-
onClick: () =>
|
|
129
|
+
onClick: () => F(`notebooks/${e.id}`),
|
|
130
130
|
children: [
|
|
131
|
-
/* @__PURE__ */
|
|
131
|
+
/* @__PURE__ */ m(O, {
|
|
132
132
|
className: "font-medium text-text-primary",
|
|
133
133
|
children: e.title
|
|
134
134
|
}),
|
|
135
|
-
/* @__PURE__ */
|
|
136
|
-
/* @__PURE__ */
|
|
135
|
+
/* @__PURE__ */ m(O, { children: /* @__PURE__ */ m(d, { status: e.status }) }),
|
|
136
|
+
/* @__PURE__ */ m(O, {
|
|
137
137
|
className: "text-text-secondary",
|
|
138
138
|
children: e.runtime ?? "—"
|
|
139
139
|
}),
|
|
140
|
-
/* @__PURE__ */
|
|
140
|
+
/* @__PURE__ */ m(O, {
|
|
141
141
|
className: "text-right tabular-nums text-text-secondary",
|
|
142
142
|
children: e.datasetIds.length
|
|
143
143
|
}),
|
|
144
|
-
/* @__PURE__ */
|
|
144
|
+
/* @__PURE__ */ m(O, { children: e.isShared ? /* @__PURE__ */ h(y, {
|
|
145
145
|
variant: "secondary",
|
|
146
146
|
className: "gap-1",
|
|
147
|
-
children: [/* @__PURE__ */
|
|
147
|
+
children: [/* @__PURE__ */ m(v, {
|
|
148
148
|
className: "size-3",
|
|
149
149
|
"aria-hidden": "true"
|
|
150
150
|
}), "Shared"]
|
|
151
|
-
}) : /* @__PURE__ */
|
|
151
|
+
}) : /* @__PURE__ */ m("span", {
|
|
152
152
|
className: "text-text-secondary",
|
|
153
153
|
children: "Private"
|
|
154
154
|
}) }),
|
|
155
|
-
/* @__PURE__ */
|
|
155
|
+
/* @__PURE__ */ m(O, { children: e.tags.length > 0 ? /* @__PURE__ */ h("div", {
|
|
156
156
|
className: "flex flex-wrap gap-1",
|
|
157
|
-
children: [e.tags.slice(0, 3).map((e) => /* @__PURE__ */
|
|
157
|
+
children: [e.tags.slice(0, 3).map((e) => /* @__PURE__ */ m(y, {
|
|
158
158
|
variant: "outline",
|
|
159
159
|
children: e
|
|
160
|
-
}, e)), e.tags.length > 3 ? /* @__PURE__ */
|
|
160
|
+
}, e)), e.tags.length > 3 ? /* @__PURE__ */ h("span", {
|
|
161
161
|
className: "text-xs text-text-secondary",
|
|
162
162
|
children: ["+", e.tags.length - 3]
|
|
163
163
|
}) : null]
|
|
164
|
-
}) : /* @__PURE__ */
|
|
164
|
+
}) : /* @__PURE__ */ m("span", {
|
|
165
165
|
className: "text-text-secondary",
|
|
166
166
|
children: "—"
|
|
167
167
|
}) }),
|
|
168
|
-
/* @__PURE__ */
|
|
168
|
+
/* @__PURE__ */ m(O, {
|
|
169
169
|
className: "whitespace-nowrap text-text-secondary",
|
|
170
|
-
children:
|
|
170
|
+
children: P(e.updatedAt)
|
|
171
171
|
}),
|
|
172
|
-
/* @__PURE__ */
|
|
172
|
+
/* @__PURE__ */ m(O, {
|
|
173
173
|
className: "text-right",
|
|
174
|
-
children: /* @__PURE__ */
|
|
174
|
+
children: /* @__PURE__ */ m(i, {
|
|
175
175
|
ariaLabel: `Actions for ${e.title}`,
|
|
176
176
|
entityName: e.title,
|
|
177
|
-
onView: () =>
|
|
178
|
-
onEdit: () =>
|
|
179
|
-
onDelete: e.status === "ARCHIVED" ? void 0 : () =>
|
|
177
|
+
onView: () => F(`notebooks/${e.id}`),
|
|
178
|
+
onEdit: () => F(`notebooks/${e.id}/edit`),
|
|
179
|
+
onDelete: e.status === "ARCHIVED" ? void 0 : () => K(e),
|
|
180
180
|
deleteLabel: "Archive notebook"
|
|
181
181
|
})
|
|
182
182
|
})
|
|
183
183
|
]
|
|
184
184
|
}, e.id)) })] })
|
|
185
|
-
}),
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
185
|
+
}), /* @__PURE__ */ m("ul", {
|
|
186
|
+
className: "space-y-3 md:hidden",
|
|
187
|
+
children: W.map((e) => /* @__PURE__ */ m("li", {
|
|
188
|
+
className: "rounded-card border border-border-default bg-bg-elevated",
|
|
189
|
+
children: /* @__PURE__ */ h("div", {
|
|
190
|
+
className: "flex items-start justify-between gap-2 p-4",
|
|
191
|
+
children: [/* @__PURE__ */ h("button", {
|
|
192
|
+
type: "button",
|
|
193
|
+
onClick: () => F(`notebooks/${e.id}`),
|
|
194
|
+
className: "min-w-0 flex-1 space-y-2 text-left",
|
|
195
|
+
children: [
|
|
196
|
+
/* @__PURE__ */ h("div", {
|
|
197
|
+
className: "flex flex-wrap items-center gap-2",
|
|
198
|
+
children: [/* @__PURE__ */ m("span", {
|
|
199
|
+
className: "truncate font-medium text-text-primary",
|
|
200
|
+
children: e.title
|
|
201
|
+
}), /* @__PURE__ */ m(d, { status: e.status })]
|
|
202
|
+
}),
|
|
203
|
+
/* @__PURE__ */ h("div", {
|
|
204
|
+
className: "flex flex-wrap items-center gap-x-3 gap-y-1 text-xs text-text-secondary",
|
|
205
|
+
children: [
|
|
206
|
+
/* @__PURE__ */ h("span", { children: ["Runtime: ", e.runtime ?? "—"] }),
|
|
207
|
+
/* @__PURE__ */ h("span", {
|
|
208
|
+
className: "tabular-nums",
|
|
209
|
+
children: [
|
|
210
|
+
e.datasetIds.length,
|
|
211
|
+
" dataset",
|
|
212
|
+
e.datasetIds.length === 1 ? "" : "s"
|
|
213
|
+
]
|
|
214
|
+
}),
|
|
215
|
+
e.isShared ? /* @__PURE__ */ h("span", {
|
|
216
|
+
className: "inline-flex items-center gap-1",
|
|
217
|
+
children: [/* @__PURE__ */ m(v, {
|
|
218
|
+
className: "size-3",
|
|
219
|
+
"aria-hidden": "true"
|
|
220
|
+
}), "Shared"]
|
|
221
|
+
}) : /* @__PURE__ */ m("span", { children: "Private" }),
|
|
222
|
+
/* @__PURE__ */ h("span", { children: ["Updated ", P(e.updatedAt)] })
|
|
223
|
+
]
|
|
224
|
+
}),
|
|
225
|
+
e.tags.length > 0 ? /* @__PURE__ */ h("div", {
|
|
226
|
+
className: "flex flex-wrap gap-1",
|
|
227
|
+
children: [e.tags.slice(0, 4).map((e) => /* @__PURE__ */ m(y, {
|
|
228
|
+
variant: "outline",
|
|
229
|
+
children: e
|
|
230
|
+
}, e)), e.tags.length > 4 ? /* @__PURE__ */ h("span", {
|
|
231
|
+
className: "text-xs text-text-secondary",
|
|
232
|
+
children: ["+", e.tags.length - 4]
|
|
233
|
+
}) : null]
|
|
234
|
+
}) : null
|
|
235
|
+
]
|
|
236
|
+
}), /* @__PURE__ */ m(i, {
|
|
237
|
+
ariaLabel: `Actions for ${e.title}`,
|
|
238
|
+
entityName: e.title,
|
|
239
|
+
onView: () => F(`notebooks/${e.id}`),
|
|
240
|
+
onEdit: () => F(`notebooks/${e.id}/edit`),
|
|
241
|
+
onDelete: e.status === "ARCHIVED" ? void 0 : () => K(e),
|
|
242
|
+
deleteLabel: "Archive notebook"
|
|
243
|
+
})]
|
|
244
|
+
})
|
|
245
|
+
}, e.id))
|
|
246
|
+
})] }),
|
|
247
|
+
!B && !V && W.length > 0 ? /* @__PURE__ */ m(l, {
|
|
248
|
+
offset: R.offset,
|
|
249
|
+
limit: R.limit,
|
|
250
|
+
loadedCount: W.length,
|
|
251
|
+
hasMore: G?.hasMore ?? !1,
|
|
252
|
+
onPrev: R.prevPage,
|
|
253
|
+
onNext: R.nextPage,
|
|
193
254
|
itemLabel: "notebooks",
|
|
194
|
-
loading:
|
|
255
|
+
loading: B
|
|
195
256
|
}) : null
|
|
196
257
|
]
|
|
197
258
|
})
|
|
198
259
|
});
|
|
199
260
|
}
|
|
200
261
|
//#endregion
|
|
201
|
-
export {
|
|
262
|
+
export { F as default };
|
|
202
263
|
|
|
203
264
|
//# sourceMappingURL=NotebooksPage.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"NotebooksPage.js","names":[],"sources":["../../../../src/cosmicintersection/pages/notebooks/NotebooksPage.tsx"],"sourcesContent":["/**\n * NotebooksPage — paginated list of analysis notebooks.\n *\n * Notebooks are computational documents (title, runtime, environment, linked\n * datasets) that scientists run analyses inside. This surface lists them from\n * `cosListNotebooks` with a status filter, per-row View / Edit / Archive\n * actions, and offset pagination. Every value here comes from the backend —\n * there is no fabricated data.\n */\nimport { useState } from 'react';\nimport { NotebookText, Plus, Share2 } from 'lucide-react';\nimport {\n Badge,\n Button,\n Select,\n SelectContent,\n SelectItem,\n SelectTrigger,\n SelectValue,\n Table,\n TableBody,\n TableCell,\n TableHead,\n TableHeader,\n TableRow,\n} from '@burdenoff/fe-libs/ui';\n\nimport {\n useCosArchiveNotebookMutation,\n useCosNotebooksQuery,\n type CosNotebook,\n type CosNotebookStatus,\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\nconst STATUS_OPTIONS: { value: CosNotebookStatus; label: string }[] = [\n { value: 'DRAFT', label: 'Draft' },\n { value: 'RUNNING', label: 'Running' },\n { value: 'PUBLISHED', label: 'Published' },\n { value: 'ARCHIVED', label: 'Archived' },\n];\n\nconst ALL = 'ALL';\n\nfunction formatDate(value?: string | null): string {\n if (!value) {\n return '—';\n }\n const date = new Date(value);\n if (Number.isNaN(date.getTime())) {\n return '—';\n }\n return date.toLocaleDateString(undefined, { year: 'numeric', month: 'short', day: 'numeric' });\n}\n\nexport default function NotebooksPage() {\n const { navigate } = useCosmicIntersection();\n const [statusFilter, setStatusFilter] = useState<CosNotebookStatus | undefined>(undefined);\n const pagination = usePagination({ pageSize: 50, resetKey: statusFilter });\n\n const { data, loading, error, refetch } = useCosNotebooksQuery({\n status: statusFilter,\n pagination: { limit: pagination.limit, offset: pagination.offset },\n });\n const [archiveNotebook] = useCosArchiveNotebookMutation();\n\n const notebooks = data?.cosListNotebooks.items ?? [];\n const pageInfo = data?.cosListNotebooks.pageInfo;\n\n const handleArchive = async (notebook: CosNotebook) => {\n const response = await archiveNotebook({ variables: { id: notebook.id } });\n if (response.error) {\n // onError already surfaced the toast; rethrow so the confirm dialog stays open.\n throw new Error(response.error.message);\n }\n if (!response.data?.cosArchiveNotebook) {\n notify.error('Could not archive notebook', 'The server did not confirm the change.');\n throw new Error('Archive not confirmed');\n }\n await refetch();\n notify.success('Notebook archived', `“${notebook.title}” was archived.`);\n };\n\n const actions = (\n <Button type=\"button\" onClick={() => navigate('notebooks/create')}>\n <Plus className=\"size-4\" />\n New notebook\n </Button>\n );\n\n return (\n <PageLayout\n title=\"Notebooks\"\n description=\"Computational notebooks for running analyses over federated science datasets.\"\n actions={actions}\n >\n <div className=\"space-y-4\">\n <div className=\"flex flex-wrap items-center gap-3\">\n <label className=\"text-sm text-text-secondary\" htmlFor=\"notebook-status-filter\">\n Status\n </label>\n <Select\n value={statusFilter ?? ALL}\n onValueChange={(value) =>\n setStatusFilter(value === ALL ? undefined : (value as CosNotebookStatus))\n }\n >\n <SelectTrigger\n id=\"notebook-status-filter\"\n className=\"w-48\"\n aria-label=\"Filter by status\"\n >\n <SelectValue />\n </SelectTrigger>\n <SelectContent>\n <SelectItem value={ALL}>All statuses</SelectItem>\n {STATUS_OPTIONS.map((option) => (\n <SelectItem key={option.value} value={option.value}>\n {option.label}\n </SelectItem>\n ))}\n </SelectContent>\n </Select>\n </div>\n\n {loading ? (\n <LoadingState variant=\"rows\" rows={6} label=\"Loading notebooks…\" />\n ) : error ? (\n <ErrorState\n message=\"We could not load your notebooks. Please try again.\"\n onRetry={() => void refetch()}\n />\n ) : notebooks.length === 0 ? (\n <EmptyState\n icon={NotebookText}\n title={statusFilter ? 'No notebooks match this filter.' : 'No notebooks yet.'}\n description={\n statusFilter\n ? 'Try a different status filter.'\n : 'Create your first notebook to start analysing federated datasets.'\n }\n action={\n statusFilter ? undefined : (\n <Button type=\"button\" onClick={() => navigate('notebooks/create')}>\n <Plus className=\"size-4\" />\n New notebook\n </Button>\n )\n }\n />\n ) : (\n <div className=\"rounded-card border border-border-default bg-bg-elevated\">\n <Table>\n <TableHeader>\n <TableRow>\n <TableHead>Title</TableHead>\n <TableHead>Status</TableHead>\n <TableHead>Runtime</TableHead>\n <TableHead className=\"text-right\">Datasets</TableHead>\n <TableHead>Sharing</TableHead>\n <TableHead>Tags</TableHead>\n <TableHead>Updated</TableHead>\n <TableHead className=\"w-12 text-right\">Actions</TableHead>\n </TableRow>\n </TableHeader>\n <TableBody>\n {notebooks.map((notebook) => (\n <TableRow\n key={notebook.id}\n className=\"cursor-pointer\"\n onClick={() => navigate(`notebooks/${notebook.id}`)}\n >\n <TableCell className=\"font-medium text-text-primary\">\n {notebook.title}\n </TableCell>\n <TableCell>\n <StatusBadge status={notebook.status} />\n </TableCell>\n <TableCell className=\"text-text-secondary\">{notebook.runtime ?? '—'}</TableCell>\n <TableCell className=\"text-right tabular-nums text-text-secondary\">\n {notebook.datasetIds.length}\n </TableCell>\n <TableCell>\n {notebook.isShared ? (\n <Badge variant=\"secondary\" className=\"gap-1\">\n <Share2 className=\"size-3\" aria-hidden=\"true\" />\n Shared\n </Badge>\n ) : (\n <span className=\"text-text-secondary\">Private</span>\n )}\n </TableCell>\n <TableCell>\n {notebook.tags.length > 0 ? (\n <div className=\"flex flex-wrap gap-1\">\n {notebook.tags.slice(0, 3).map((tag) => (\n <Badge key={tag} variant=\"outline\">\n {tag}\n </Badge>\n ))}\n {notebook.tags.length > 3 ? (\n <span className=\"text-xs text-text-secondary\">\n +{notebook.tags.length - 3}\n </span>\n ) : null}\n </div>\n ) : (\n <span className=\"text-text-secondary\">—</span>\n )}\n </TableCell>\n <TableCell className=\"whitespace-nowrap text-text-secondary\">\n {formatDate(notebook.updatedAt)}\n </TableCell>\n <TableCell className=\"text-right\">\n <ActionMenu\n ariaLabel={`Actions for ${notebook.title}`}\n entityName={notebook.title}\n onView={() => navigate(`notebooks/${notebook.id}`)}\n onEdit={() => navigate(`notebooks/${notebook.id}/edit`)}\n onDelete={\n notebook.status === 'ARCHIVED' ? undefined : () => handleArchive(notebook)\n }\n deleteLabel=\"Archive notebook\"\n />\n </TableCell>\n </TableRow>\n ))}\n </TableBody>\n </Table>\n </div>\n )}\n\n {!loading && !error && notebooks.length > 0 ? (\n <Pagination\n offset={pagination.offset}\n limit={pagination.limit}\n loadedCount={notebooks.length}\n hasMore={pageInfo?.hasMore ?? false}\n onPrev={pagination.prevPage}\n onNext={pagination.nextPage}\n itemLabel=\"notebooks\"\n loading={loading}\n />\n ) : null}\n </div>\n </PageLayout>\n );\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"NotebooksPage.js","names":[],"sources":["../../../../src/cosmicintersection/pages/notebooks/NotebooksPage.tsx"],"sourcesContent":["/**\n * NotebooksPage — paginated list of analysis notebooks.\n *\n * Notebooks are computational documents (title, runtime, environment, linked\n * datasets) that scientists run analyses inside. This surface lists them from\n * `cosListNotebooks` with a status filter, per-row View / Edit / Archive\n * actions, and offset pagination. Every value here comes from the backend —\n * there is no fabricated data.\n */\nimport { useState } from 'react';\nimport { NotebookText, Plus, Share2 } from 'lucide-react';\nimport {\n Badge,\n Button,\n Select,\n SelectContent,\n SelectItem,\n SelectTrigger,\n SelectValue,\n Table,\n TableBody,\n TableCell,\n TableHead,\n TableHeader,\n TableRow,\n} from '@burdenoff/fe-libs/ui';\n\nimport {\n useCosArchiveNotebookMutation,\n useCosNotebooksQuery,\n type CosNotebook,\n type CosNotebookStatus,\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\nconst STATUS_OPTIONS: { value: CosNotebookStatus; label: string }[] = [\n { value: 'DRAFT', label: 'Draft' },\n { value: 'RUNNING', label: 'Running' },\n { value: 'PUBLISHED', label: 'Published' },\n { value: 'ARCHIVED', label: 'Archived' },\n];\n\nconst ALL = 'ALL';\n\nfunction formatDate(value?: string | null): string {\n if (!value) {\n return '—';\n }\n const date = new Date(value);\n if (Number.isNaN(date.getTime())) {\n return '—';\n }\n return date.toLocaleDateString(undefined, { year: 'numeric', month: 'short', day: 'numeric' });\n}\n\nexport default function NotebooksPage() {\n const { navigate } = useCosmicIntersection();\n const [statusFilter, setStatusFilter] = useState<CosNotebookStatus | undefined>(undefined);\n const pagination = usePagination({ pageSize: 50, resetKey: statusFilter });\n\n const { data, loading, error, refetch } = useCosNotebooksQuery({\n status: statusFilter,\n pagination: { limit: pagination.limit, offset: pagination.offset },\n });\n const [archiveNotebook] = useCosArchiveNotebookMutation();\n\n const notebooks = data?.cosListNotebooks.items ?? [];\n const pageInfo = data?.cosListNotebooks.pageInfo;\n\n const handleArchive = async (notebook: CosNotebook) => {\n const response = await archiveNotebook({ variables: { id: notebook.id } });\n if (response.error) {\n // onError already surfaced the toast; rethrow so the confirm dialog stays open.\n throw new Error(response.error.message);\n }\n if (!response.data?.cosArchiveNotebook) {\n notify.error('Could not archive notebook', 'The server did not confirm the change.');\n throw new Error('Archive not confirmed');\n }\n await refetch();\n notify.success('Notebook archived', `“${notebook.title}” was archived.`);\n };\n\n const actions = (\n <Button type=\"button\" onClick={() => navigate('notebooks/create')}>\n <Plus className=\"size-4\" />\n New notebook\n </Button>\n );\n\n return (\n <PageLayout\n title=\"Notebooks\"\n description=\"Computational notebooks for running analyses over federated science datasets.\"\n actions={actions}\n >\n <div className=\"space-y-4\">\n <div className=\"flex flex-wrap items-center gap-3\">\n <label className=\"text-sm text-text-secondary\" htmlFor=\"notebook-status-filter\">\n Status\n </label>\n <Select\n value={statusFilter ?? ALL}\n onValueChange={(value) =>\n setStatusFilter(value === ALL ? undefined : (value as CosNotebookStatus))\n }\n >\n <SelectTrigger\n id=\"notebook-status-filter\"\n className=\"w-48\"\n aria-label=\"Filter by status\"\n >\n <SelectValue />\n </SelectTrigger>\n <SelectContent>\n <SelectItem value={ALL}>All statuses</SelectItem>\n {STATUS_OPTIONS.map((option) => (\n <SelectItem key={option.value} value={option.value}>\n {option.label}\n </SelectItem>\n ))}\n </SelectContent>\n </Select>\n </div>\n\n {loading ? (\n <LoadingState variant=\"rows\" rows={6} label=\"Loading notebooks…\" />\n ) : error ? (\n <ErrorState\n message=\"We could not load your notebooks. Please try again.\"\n onRetry={() => void refetch()}\n />\n ) : notebooks.length === 0 ? (\n <EmptyState\n icon={NotebookText}\n title={statusFilter ? 'No notebooks match this filter.' : 'No notebooks yet.'}\n description={\n statusFilter\n ? 'Try a different status filter.'\n : 'Create your first notebook to start analysing federated datasets.'\n }\n action={\n statusFilter ? undefined : (\n <Button type=\"button\" onClick={() => navigate('notebooks/create')}>\n <Plus className=\"size-4\" />\n New notebook\n </Button>\n )\n }\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>Title</TableHead>\n <TableHead>Status</TableHead>\n <TableHead>Runtime</TableHead>\n <TableHead className=\"text-right\">Datasets</TableHead>\n <TableHead>Sharing</TableHead>\n <TableHead>Tags</TableHead>\n <TableHead>Updated</TableHead>\n <TableHead className=\"w-12 text-right\">Actions</TableHead>\n </TableRow>\n </TableHeader>\n <TableBody>\n {notebooks.map((notebook) => (\n <TableRow\n key={notebook.id}\n className=\"cursor-pointer\"\n onClick={() => navigate(`notebooks/${notebook.id}`)}\n >\n <TableCell className=\"font-medium text-text-primary\">\n {notebook.title}\n </TableCell>\n <TableCell>\n <StatusBadge status={notebook.status} />\n </TableCell>\n <TableCell className=\"text-text-secondary\">\n {notebook.runtime ?? '—'}\n </TableCell>\n <TableCell className=\"text-right tabular-nums text-text-secondary\">\n {notebook.datasetIds.length}\n </TableCell>\n <TableCell>\n {notebook.isShared ? (\n <Badge variant=\"secondary\" className=\"gap-1\">\n <Share2 className=\"size-3\" aria-hidden=\"true\" />\n Shared\n </Badge>\n ) : (\n <span className=\"text-text-secondary\">Private</span>\n )}\n </TableCell>\n <TableCell>\n {notebook.tags.length > 0 ? (\n <div className=\"flex flex-wrap gap-1\">\n {notebook.tags.slice(0, 3).map((tag) => (\n <Badge key={tag} variant=\"outline\">\n {tag}\n </Badge>\n ))}\n {notebook.tags.length > 3 ? (\n <span className=\"text-xs text-text-secondary\">\n +{notebook.tags.length - 3}\n </span>\n ) : null}\n </div>\n ) : (\n <span className=\"text-text-secondary\">—</span>\n )}\n </TableCell>\n <TableCell className=\"whitespace-nowrap text-text-secondary\">\n {formatDate(notebook.updatedAt)}\n </TableCell>\n <TableCell className=\"text-right\">\n <ActionMenu\n ariaLabel={`Actions for ${notebook.title}`}\n entityName={notebook.title}\n onView={() => navigate(`notebooks/${notebook.id}`)}\n onEdit={() => navigate(`notebooks/${notebook.id}/edit`)}\n onDelete={\n notebook.status === 'ARCHIVED'\n ? undefined\n : () => handleArchive(notebook)\n }\n deleteLabel=\"Archive notebook\"\n />\n </TableCell>\n </TableRow>\n ))}\n </TableBody>\n </Table>\n </div>\n\n {/* Mobile card list */}\n <ul className=\"space-y-3 md:hidden\">\n {notebooks.map((notebook) => (\n <li\n key={notebook.id}\n className=\"rounded-card border border-border-default bg-bg-elevated\"\n >\n <div className=\"flex items-start justify-between gap-2 p-4\">\n <button\n type=\"button\"\n onClick={() => navigate(`notebooks/${notebook.id}`)}\n className=\"min-w-0 flex-1 space-y-2 text-left\"\n >\n <div className=\"flex flex-wrap items-center gap-2\">\n <span className=\"truncate font-medium text-text-primary\">\n {notebook.title}\n </span>\n <StatusBadge status={notebook.status} />\n </div>\n <div className=\"flex flex-wrap items-center gap-x-3 gap-y-1 text-xs text-text-secondary\">\n <span>Runtime: {notebook.runtime ?? '—'}</span>\n <span className=\"tabular-nums\">\n {notebook.datasetIds.length} dataset\n {notebook.datasetIds.length === 1 ? '' : 's'}\n </span>\n {notebook.isShared ? (\n <span className=\"inline-flex items-center gap-1\">\n <Share2 className=\"size-3\" aria-hidden=\"true\" />\n Shared\n </span>\n ) : (\n <span>Private</span>\n )}\n <span>Updated {formatDate(notebook.updatedAt)}</span>\n </div>\n {notebook.tags.length > 0 ? (\n <div className=\"flex flex-wrap gap-1\">\n {notebook.tags.slice(0, 4).map((tag) => (\n <Badge key={tag} variant=\"outline\">\n {tag}\n </Badge>\n ))}\n {notebook.tags.length > 4 ? (\n <span className=\"text-xs text-text-secondary\">\n +{notebook.tags.length - 4}\n </span>\n ) : null}\n </div>\n ) : null}\n </button>\n <ActionMenu\n ariaLabel={`Actions for ${notebook.title}`}\n entityName={notebook.title}\n onView={() => navigate(`notebooks/${notebook.id}`)}\n onEdit={() => navigate(`notebooks/${notebook.id}/edit`)}\n onDelete={\n notebook.status === 'ARCHIVED' ? undefined : () => handleArchive(notebook)\n }\n deleteLabel=\"Archive notebook\"\n />\n </div>\n </li>\n ))}\n </ul>\n </>\n )}\n\n {!loading && !error && notebooks.length > 0 ? (\n <Pagination\n offset={pagination.offset}\n limit={pagination.limit}\n loadedCount={notebooks.length}\n hasMore={pageInfo?.hasMore ?? false}\n onPrev={pagination.prevPage}\n onNext={pagination.nextPage}\n itemLabel=\"notebooks\"\n loading={loading}\n />\n ) : null}\n </div>\n </PageLayout>\n );\n}\n"],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"PipelineDetailPage.d.ts","sourceRoot":"","sources":["../../../../src/cosmicintersection/pages/pipelines/PipelineDetailPage.tsx"],"names":[],"mappings":"AAkIA,MAAM,CAAC,OAAO,UAAU,kBAAkB,4CAiYzC"}
|