@burdenoff/microfe-cosmicintersection 2026.525.1 → 2026.704.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.js +38 -113
- package/dist/cosmicintersection/CosmicIntersectionRoot.js.map +1 -1
- package/dist/cosmicintersection/CosmicIntersectionRoutes.js +102 -44
- package/dist/cosmicintersection/CosmicIntersectionRoutes.js.map +1 -1
- package/dist/cosmicintersection/api/cosmicApi.js +853 -0
- package/dist/cosmicintersection/api/cosmicApi.js.map +1 -0
- package/dist/cosmicintersection/components/ActionMenu.js +106 -0
- package/dist/cosmicintersection/components/ActionMenu.js.map +1 -0
- package/dist/cosmicintersection/components/EmptyState.js +35 -0
- package/dist/cosmicintersection/components/EmptyState.js.map +1 -0
- package/dist/cosmicintersection/components/EntityFormShell.js +57 -0
- package/dist/cosmicintersection/components/EntityFormShell.js.map +1 -0
- package/dist/cosmicintersection/components/EntityTagsField.js +77 -0
- package/dist/cosmicintersection/components/EntityTagsField.js.map +1 -0
- package/dist/cosmicintersection/components/ErrorState.js +40 -0
- package/dist/cosmicintersection/components/ErrorState.js.map +1 -0
- package/dist/cosmicintersection/components/FileUploadField.js +146 -0
- package/dist/cosmicintersection/components/FileUploadField.js.map +1 -0
- package/dist/cosmicintersection/components/LoadingState.js +23 -0
- package/dist/cosmicintersection/components/LoadingState.js.map +1 -0
- package/dist/cosmicintersection/components/PageLayout.js +46 -0
- package/dist/cosmicintersection/components/PageLayout.js.map +1 -0
- package/dist/cosmicintersection/components/Pagination.js +65 -0
- package/dist/cosmicintersection/components/Pagination.js.map +1 -0
- package/dist/cosmicintersection/components/SafeLink.js +35 -0
- package/dist/cosmicintersection/components/SafeLink.js.map +1 -0
- package/dist/cosmicintersection/components/StatusBadge.js +53 -0
- package/dist/cosmicintersection/components/StatusBadge.js.map +1 -0
- package/dist/cosmicintersection/components/index.js +11 -0
- package/dist/cosmicintersection/context/CosmicIntersectionContext.js +46 -0
- package/dist/cosmicintersection/context/CosmicIntersectionContext.js.map +1 -0
- package/dist/cosmicintersection/index.js +0 -2
- package/dist/cosmicintersection/lib/mutationResult.js +12 -0
- package/dist/cosmicintersection/lib/mutationResult.js.map +1 -0
- package/dist/cosmicintersection/lib/toast.js +36 -0
- package/dist/cosmicintersection/lib/toast.js.map +1 -0
- package/dist/cosmicintersection/pages/access/AccessPage.js +340 -0
- package/dist/cosmicintersection/pages/access/AccessPage.js.map +1 -0
- package/dist/cosmicintersection/pages/analyses/AnalysesPage.js +484 -0
- package/dist/cosmicintersection/pages/analyses/AnalysesPage.js.map +1 -0
- package/dist/cosmicintersection/pages/collections/CollectionDetailPage.js +164 -0
- package/dist/cosmicintersection/pages/collections/CollectionDetailPage.js.map +1 -0
- package/dist/cosmicintersection/pages/collections/CollectionFormPage.js +117 -0
- package/dist/cosmicintersection/pages/collections/CollectionFormPage.js.map +1 -0
- package/dist/cosmicintersection/pages/collections/CollectionsPage.js +103 -0
- package/dist/cosmicintersection/pages/collections/CollectionsPage.js.map +1 -0
- package/dist/cosmicintersection/pages/dashboard/DashboardPage.js +244 -0
- package/dist/cosmicintersection/pages/dashboard/DashboardPage.js.map +1 -0
- package/dist/cosmicintersection/pages/datasets/DatasetDetailPage.js +460 -0
- package/dist/cosmicintersection/pages/datasets/DatasetDetailPage.js.map +1 -0
- package/dist/cosmicintersection/pages/datasets/DatasetFormPage.js +218 -0
- package/dist/cosmicintersection/pages/datasets/DatasetFormPage.js.map +1 -0
- package/dist/cosmicintersection/pages/datasets/DatasetsPage.js +252 -0
- package/dist/cosmicintersection/pages/datasets/DatasetsPage.js.map +1 -0
- package/dist/cosmicintersection/pages/notebooks/NotebookDetailPage.js +393 -0
- package/dist/cosmicintersection/pages/notebooks/NotebookDetailPage.js.map +1 -0
- package/dist/cosmicintersection/pages/notebooks/NotebookFormPage.js +313 -0
- package/dist/cosmicintersection/pages/notebooks/NotebookFormPage.js.map +1 -0
- package/dist/cosmicintersection/pages/notebooks/NotebooksPage.js +203 -0
- package/dist/cosmicintersection/pages/notebooks/NotebooksPage.js.map +1 -0
- package/dist/cosmicintersection/pages/pipelines/PipelineDetailPage.js +244 -0
- package/dist/cosmicintersection/pages/pipelines/PipelineDetailPage.js.map +1 -0
- package/dist/cosmicintersection/pages/pipelines/PipelineFormPage.js +210 -0
- package/dist/cosmicintersection/pages/pipelines/PipelineFormPage.js.map +1 -0
- package/dist/cosmicintersection/pages/pipelines/PipelinesPage.js +193 -0
- package/dist/cosmicintersection/pages/pipelines/PipelinesPage.js.map +1 -0
- package/dist/cosmicintersection/pages/releases/ReleaseFormPage.js +184 -0
- package/dist/cosmicintersection/pages/releases/ReleaseFormPage.js.map +1 -0
- package/dist/cosmicintersection/pages/releases/ReleasesPage.js +368 -0
- package/dist/cosmicintersection/pages/releases/ReleasesPage.js.map +1 -0
- package/dist/cosmicintersection/pages/runs/RunDetailPage.js +375 -0
- package/dist/cosmicintersection/pages/runs/RunDetailPage.js.map +1 -0
- package/dist/cosmicintersection/pages/runs/RunsPage.js +180 -0
- package/dist/cosmicintersection/pages/runs/RunsPage.js.map +1 -0
- package/dist/cosmicintersection/pages/sources/SourceFormPage.js +229 -0
- package/dist/cosmicintersection/pages/sources/SourceFormPage.js.map +1 -0
- package/dist/cosmicintersection/pages/sources/SourcesPage.js +217 -0
- package/dist/cosmicintersection/pages/sources/SourcesPage.js.map +1 -0
- package/dist/cosmicintersection/utils/cn.js +10 -0
- package/dist/cosmicintersection/utils/cn.js.map +1 -0
- package/dist/index.js +2 -4
- package/dist/node_modules/clsx/dist/clsx.js +18 -0
- package/dist/node_modules/clsx/dist/clsx.js.map +1 -0
- package/dist/node_modules/tailwind-merge/dist/bundle-mjs.js +1716 -0
- package/dist/node_modules/tailwind-merge/dist/bundle-mjs.js.map +1 -0
- package/package.json +2 -1
- package/dist/cosmicintersection/pages/AiDiscoveryPage.js +0 -363
- package/dist/cosmicintersection/pages/AiDiscoveryPage.js.map +0 -1
- package/dist/cosmicintersection/pages/DashboardPage.js +0 -306
- package/dist/cosmicintersection/pages/DashboardPage.js.map +0 -1
- package/dist/cosmicintersection/pages/SpaceScienceCitizenPage.js +0 -287
- package/dist/cosmicintersection/pages/SpaceScienceCitizenPage.js.map +0 -1
- package/dist/cosmicintersection/pages/SpaceScienceDataPage.js +0 -385
- package/dist/cosmicintersection/pages/SpaceScienceDataPage.js.map +0 -1
- package/dist/cosmicintersection/pages/SpaceScienceDataPage1.js +0 -420
- package/dist/cosmicintersection/pages/SpaceScienceDataPage1.js.map +0 -1
- package/dist/cosmicintersection/pages/SpaceScienceLearningPage.js +0 -309
- package/dist/cosmicintersection/pages/SpaceScienceLearningPage.js.map +0 -1
- package/dist/cosmicintersection/pages/SpaceScienceLearningPage1.js +0 -361
- package/dist/cosmicintersection/pages/SpaceScienceLearningPage1.js.map +0 -1
- package/dist/cosmicintersection/pages/SpaceSciencePage.js +0 -194
- package/dist/cosmicintersection/pages/SpaceSciencePage.js.map +0 -1
- package/dist/cosmicintersection/pages/SpaceScienceResearchPage.js +0 -290
- package/dist/cosmicintersection/pages/SpaceScienceResearchPage.js.map +0 -1
- package/dist/cosmicintersection/pages/SpaceScienceSimulationPage.js +0 -279
- package/dist/cosmicintersection/pages/SpaceScienceSimulationPage.js.map +0 -1
- package/dist/cosmicintersection/providers/CosmicIntersectionProvider.js +0 -27
- package/dist/cosmicintersection/providers/CosmicIntersectionProvider.js.map +0 -1
- package/dist/cosmicintersection/store/cosmicintersectionStore.js +0 -478
- package/dist/cosmicintersection/store/cosmicintersectionStore.js.map +0 -1
- package/dist/cosmicintersection/utils/i18n.js +0 -15
- package/dist/cosmicintersection/utils/i18n.js.map +0 -1
- package/dist/cosmicintersection/utils/navigation.js +0 -8
- package/dist/cosmicintersection/utils/navigation.js.map +0 -1
|
@@ -0,0 +1,313 @@
|
|
|
1
|
+
import { useCosmicIntersection as e } from "../../context/CosmicIntersectionContext.js";
|
|
2
|
+
import { notify as t } from "../../lib/toast.js";
|
|
3
|
+
import { useCosCreateNotebookMutation as n, useCosDatasetsQuery as r, useCosNotebookQuery as i, useCosUpdateNotebookMutation as a } from "../../api/cosmicApi.js";
|
|
4
|
+
import o from "../../components/EntityFormShell.js";
|
|
5
|
+
import s from "../../components/EntityTagsField.js";
|
|
6
|
+
import c from "../../components/FileUploadField.js";
|
|
7
|
+
import "../../components/index.js";
|
|
8
|
+
import { useState as l } from "react";
|
|
9
|
+
import { jsx as u, jsxs as d } from "react/jsx-runtime";
|
|
10
|
+
import { useParams as f } from "react-router-dom";
|
|
11
|
+
import { Checkbox as p, Input as m, Label as h, Select as g, SelectContent as _, SelectItem as v, SelectTrigger as y, SelectValue as b, Switch as x, Textarea as S } from "@burdenoff/fe-libs/ui";
|
|
12
|
+
//#region src/cosmicintersection/pages/notebooks/NotebookFormPage.tsx
|
|
13
|
+
var C = [
|
|
14
|
+
{
|
|
15
|
+
value: "DRAFT",
|
|
16
|
+
label: "Draft"
|
|
17
|
+
},
|
|
18
|
+
{
|
|
19
|
+
value: "RUNNING",
|
|
20
|
+
label: "Running"
|
|
21
|
+
},
|
|
22
|
+
{
|
|
23
|
+
value: "PUBLISHED",
|
|
24
|
+
label: "Published"
|
|
25
|
+
},
|
|
26
|
+
{
|
|
27
|
+
value: "ARCHIVED",
|
|
28
|
+
label: "Archived"
|
|
29
|
+
}
|
|
30
|
+
], w = {
|
|
31
|
+
title: "",
|
|
32
|
+
description: "",
|
|
33
|
+
runtime: "",
|
|
34
|
+
environment: "",
|
|
35
|
+
datasetIds: [],
|
|
36
|
+
tags: [],
|
|
37
|
+
fileId: "",
|
|
38
|
+
status: "DRAFT",
|
|
39
|
+
isShared: !1,
|
|
40
|
+
shareSlug: ""
|
|
41
|
+
};
|
|
42
|
+
function T(e) {
|
|
43
|
+
let t = e.trim();
|
|
44
|
+
if (!t) return {
|
|
45
|
+
ok: !0,
|
|
46
|
+
value: void 0
|
|
47
|
+
};
|
|
48
|
+
try {
|
|
49
|
+
let e = JSON.parse(t);
|
|
50
|
+
return typeof e != "object" || !e || Array.isArray(e) ? {
|
|
51
|
+
ok: !1,
|
|
52
|
+
error: "Environment must be a JSON object."
|
|
53
|
+
} : {
|
|
54
|
+
ok: !0,
|
|
55
|
+
value: e
|
|
56
|
+
};
|
|
57
|
+
} catch {
|
|
58
|
+
return {
|
|
59
|
+
ok: !1,
|
|
60
|
+
error: "Environment is not valid JSON."
|
|
61
|
+
};
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
function E() {
|
|
65
|
+
let { id: E = "" } = f(), D = !!E, { navigate: O } = e(), { data: k, loading: A } = i(E), { data: j, loading: M } = r({ pagination: {
|
|
66
|
+
limit: 100,
|
|
67
|
+
offset: 0
|
|
68
|
+
} }), [N, { loading: P }] = n(), [F, { loading: I }] = a(), [L, R] = l(w), z = j?.cosListDatasets.items ?? [], B = k?.cosNotebook ?? null, [V, H] = l(null);
|
|
69
|
+
D && B && V !== B.id && (H(B.id), R({
|
|
70
|
+
title: B.title ?? "",
|
|
71
|
+
description: B.description ?? "",
|
|
72
|
+
runtime: B.runtime ?? "",
|
|
73
|
+
environment: B.environment ? JSON.stringify(B.environment, null, 2) : "",
|
|
74
|
+
datasetIds: B.datasetIds ?? [],
|
|
75
|
+
tags: B.tags ?? [],
|
|
76
|
+
fileId: B.file?.id ?? "",
|
|
77
|
+
status: B.status ?? "DRAFT",
|
|
78
|
+
isShared: B.isShared ?? !1,
|
|
79
|
+
shareSlug: B.shareSlug ?? ""
|
|
80
|
+
}));
|
|
81
|
+
let U = (e, t) => R((n) => ({
|
|
82
|
+
...n,
|
|
83
|
+
[e]: t
|
|
84
|
+
})), W = (e) => R((t) => ({
|
|
85
|
+
...t,
|
|
86
|
+
datasetIds: t.datasetIds.includes(e) ? t.datasetIds.filter((t) => t !== e) : [...t.datasetIds, e]
|
|
87
|
+
}));
|
|
88
|
+
return /* @__PURE__ */ d(o, {
|
|
89
|
+
title: D ? "Edit notebook" : "New notebook",
|
|
90
|
+
description: "Set up a computational notebook and link the datasets it analyses.",
|
|
91
|
+
purpose: "Notebooks capture the code and environment behind an analysis. Attach the notebook file, pick which federated datasets it reads, and record the runtime so results are reproducible.",
|
|
92
|
+
backLabel: D ? "Back to notebook" : "Back to notebooks",
|
|
93
|
+
onBack: () => O(D ? `notebooks/${E}` : "notebooks"),
|
|
94
|
+
onSubmit: async (e) => {
|
|
95
|
+
e.preventDefault();
|
|
96
|
+
let n = L.title.trim();
|
|
97
|
+
if (!n) {
|
|
98
|
+
t.error("Title is required", "Give the notebook a descriptive title.");
|
|
99
|
+
return;
|
|
100
|
+
}
|
|
101
|
+
let r = T(L.environment);
|
|
102
|
+
if (!r.ok) {
|
|
103
|
+
t.error("Invalid environment", r.error);
|
|
104
|
+
return;
|
|
105
|
+
}
|
|
106
|
+
if (D) {
|
|
107
|
+
let e = await F({ variables: {
|
|
108
|
+
id: E,
|
|
109
|
+
input: {
|
|
110
|
+
title: n,
|
|
111
|
+
description: L.description.trim() || void 0,
|
|
112
|
+
runtime: L.runtime.trim() || void 0,
|
|
113
|
+
environment: r.value,
|
|
114
|
+
datasetIds: L.datasetIds,
|
|
115
|
+
tags: L.tags,
|
|
116
|
+
status: L.status,
|
|
117
|
+
isShared: L.isShared,
|
|
118
|
+
shareSlug: L.shareSlug.trim() || void 0
|
|
119
|
+
}
|
|
120
|
+
} });
|
|
121
|
+
if (e.error || !e.data?.cosUpdateNotebook) return;
|
|
122
|
+
t.success("Notebook updated", `“${n}” was saved.`), O(`notebooks/${E}`);
|
|
123
|
+
return;
|
|
124
|
+
}
|
|
125
|
+
let i = await N({ variables: { input: {
|
|
126
|
+
title: n,
|
|
127
|
+
description: L.description.trim() || void 0,
|
|
128
|
+
runtime: L.runtime.trim() || void 0,
|
|
129
|
+
environment: r.value,
|
|
130
|
+
datasetIds: L.datasetIds,
|
|
131
|
+
tags: L.tags,
|
|
132
|
+
fileId: L.fileId || void 0
|
|
133
|
+
} } }), a = i.data?.cosCreateNotebook?.id;
|
|
134
|
+
i.error || !a || (t.success("Notebook created", `“${n}” is ready.`), O(`notebooks/${a}`));
|
|
135
|
+
},
|
|
136
|
+
submitLabel: D ? "Save notebook" : "Create notebook",
|
|
137
|
+
saving: P || I,
|
|
138
|
+
submitDisabled: D && A,
|
|
139
|
+
children: [
|
|
140
|
+
/* @__PURE__ */ d("div", {
|
|
141
|
+
className: "grid grid-cols-1 gap-4 md:grid-cols-2",
|
|
142
|
+
children: [/* @__PURE__ */ d("div", {
|
|
143
|
+
className: "space-y-1.5",
|
|
144
|
+
children: [/* @__PURE__ */ u(h, {
|
|
145
|
+
htmlFor: "notebook-title",
|
|
146
|
+
children: "Title"
|
|
147
|
+
}), /* @__PURE__ */ u(m, {
|
|
148
|
+
id: "notebook-title",
|
|
149
|
+
value: L.title,
|
|
150
|
+
onChange: (e) => U("title", e.target.value),
|
|
151
|
+
placeholder: "e.g. Kepler light-curve detrending",
|
|
152
|
+
required: !0
|
|
153
|
+
})]
|
|
154
|
+
}), /* @__PURE__ */ d("div", {
|
|
155
|
+
className: "space-y-1.5",
|
|
156
|
+
children: [/* @__PURE__ */ u(h, {
|
|
157
|
+
htmlFor: "notebook-runtime",
|
|
158
|
+
children: "Runtime"
|
|
159
|
+
}), /* @__PURE__ */ u(m, {
|
|
160
|
+
id: "notebook-runtime",
|
|
161
|
+
value: L.runtime,
|
|
162
|
+
onChange: (e) => U("runtime", e.target.value),
|
|
163
|
+
placeholder: "e.g. python-3.11"
|
|
164
|
+
})]
|
|
165
|
+
})]
|
|
166
|
+
}),
|
|
167
|
+
/* @__PURE__ */ d("div", {
|
|
168
|
+
className: "space-y-1.5",
|
|
169
|
+
children: [/* @__PURE__ */ u(h, {
|
|
170
|
+
htmlFor: "notebook-description",
|
|
171
|
+
children: "Description"
|
|
172
|
+
}), /* @__PURE__ */ u(S, {
|
|
173
|
+
id: "notebook-description",
|
|
174
|
+
value: L.description,
|
|
175
|
+
onChange: (e) => U("description", e.target.value),
|
|
176
|
+
rows: 3,
|
|
177
|
+
placeholder: "What does this notebook do?"
|
|
178
|
+
})]
|
|
179
|
+
}),
|
|
180
|
+
/* @__PURE__ */ d("div", {
|
|
181
|
+
className: "space-y-1.5",
|
|
182
|
+
children: [
|
|
183
|
+
/* @__PURE__ */ u(h, {
|
|
184
|
+
htmlFor: "notebook-environment",
|
|
185
|
+
children: "Environment (JSON)"
|
|
186
|
+
}),
|
|
187
|
+
/* @__PURE__ */ u(S, {
|
|
188
|
+
id: "notebook-environment",
|
|
189
|
+
value: L.environment,
|
|
190
|
+
onChange: (e) => U("environment", e.target.value),
|
|
191
|
+
rows: 4,
|
|
192
|
+
className: "font-mono text-xs",
|
|
193
|
+
placeholder: "{ \"numpy\": \"1.26\", \"astropy\": \"6.0\" }"
|
|
194
|
+
}),
|
|
195
|
+
/* @__PURE__ */ u("p", {
|
|
196
|
+
className: "text-xs text-text-secondary",
|
|
197
|
+
children: "Optional dependency / kernel metadata as a JSON object."
|
|
198
|
+
})
|
|
199
|
+
]
|
|
200
|
+
}),
|
|
201
|
+
/* @__PURE__ */ d("div", {
|
|
202
|
+
className: "space-y-2",
|
|
203
|
+
children: [
|
|
204
|
+
/* @__PURE__ */ u(h, { children: "Linked datasets" }),
|
|
205
|
+
M ? /* @__PURE__ */ u("p", {
|
|
206
|
+
className: "text-sm text-text-secondary",
|
|
207
|
+
children: "Loading datasets…"
|
|
208
|
+
}) : z.length === 0 ? /* @__PURE__ */ u("p", {
|
|
209
|
+
className: "text-sm text-text-secondary",
|
|
210
|
+
children: "No datasets available yet. Create a dataset first to link it here."
|
|
211
|
+
}) : /* @__PURE__ */ u("div", {
|
|
212
|
+
className: "max-h-56 space-y-1 overflow-auto rounded-card border border-border-default bg-bg-sunken p-2",
|
|
213
|
+
children: z.map((e) => /* @__PURE__ */ d("label", {
|
|
214
|
+
className: "flex cursor-pointer items-center gap-3 rounded-button px-2 py-1.5 hover:bg-bg-elevated",
|
|
215
|
+
children: [
|
|
216
|
+
/* @__PURE__ */ u(p, {
|
|
217
|
+
checked: L.datasetIds.includes(e.id),
|
|
218
|
+
onCheckedChange: () => W(e.id),
|
|
219
|
+
"aria-label": `Link ${e.name}`
|
|
220
|
+
}),
|
|
221
|
+
/* @__PURE__ */ u("span", {
|
|
222
|
+
className: "min-w-0 flex-1 truncate text-sm text-text-primary",
|
|
223
|
+
children: e.name
|
|
224
|
+
}),
|
|
225
|
+
/* @__PURE__ */ u("span", {
|
|
226
|
+
className: "text-xs text-text-secondary",
|
|
227
|
+
children: e.status
|
|
228
|
+
})
|
|
229
|
+
]
|
|
230
|
+
}, e.id))
|
|
231
|
+
}),
|
|
232
|
+
L.datasetIds.length > 0 ? /* @__PURE__ */ d("p", {
|
|
233
|
+
className: "text-xs text-text-secondary",
|
|
234
|
+
children: [
|
|
235
|
+
L.datasetIds.length,
|
|
236
|
+
" dataset",
|
|
237
|
+
L.datasetIds.length === 1 ? "" : "s",
|
|
238
|
+
" linked."
|
|
239
|
+
]
|
|
240
|
+
}) : null
|
|
241
|
+
]
|
|
242
|
+
}),
|
|
243
|
+
/* @__PURE__ */ u(s, {
|
|
244
|
+
value: L.tags,
|
|
245
|
+
onChange: (e) => U("tags", e)
|
|
246
|
+
}),
|
|
247
|
+
/* @__PURE__ */ u(c, {
|
|
248
|
+
value: L.fileId,
|
|
249
|
+
onChange: (e) => U("fileId", e),
|
|
250
|
+
label: "Attach notebook file",
|
|
251
|
+
hint: "Upload the notebook artifact (.ipynb or any file). Stored in workspace files."
|
|
252
|
+
}),
|
|
253
|
+
D ? /* @__PURE__ */ d("div", {
|
|
254
|
+
className: "space-y-4 rounded-card border border-border-default bg-bg-sunken p-4",
|
|
255
|
+
children: [
|
|
256
|
+
/* @__PURE__ */ u("p", {
|
|
257
|
+
className: "text-sm font-medium text-text-primary",
|
|
258
|
+
children: "Lifecycle & sharing"
|
|
259
|
+
}),
|
|
260
|
+
/* @__PURE__ */ d("div", {
|
|
261
|
+
className: "grid grid-cols-1 gap-4 md:grid-cols-2",
|
|
262
|
+
children: [/* @__PURE__ */ d("div", {
|
|
263
|
+
className: "space-y-1.5",
|
|
264
|
+
children: [/* @__PURE__ */ u(h, {
|
|
265
|
+
htmlFor: "notebook-status",
|
|
266
|
+
children: "Status"
|
|
267
|
+
}), /* @__PURE__ */ d(g, {
|
|
268
|
+
value: L.status,
|
|
269
|
+
onValueChange: (e) => U("status", e),
|
|
270
|
+
children: [/* @__PURE__ */ u(y, {
|
|
271
|
+
id: "notebook-status",
|
|
272
|
+
"aria-label": "Notebook status",
|
|
273
|
+
children: /* @__PURE__ */ u(b, {})
|
|
274
|
+
}), /* @__PURE__ */ u(_, { children: C.map((e) => /* @__PURE__ */ u(v, {
|
|
275
|
+
value: e.value,
|
|
276
|
+
children: e.label
|
|
277
|
+
}, e.value)) })]
|
|
278
|
+
})]
|
|
279
|
+
}), /* @__PURE__ */ d("div", {
|
|
280
|
+
className: "space-y-1.5",
|
|
281
|
+
children: [/* @__PURE__ */ u(h, {
|
|
282
|
+
htmlFor: "notebook-share-slug",
|
|
283
|
+
children: "Share slug"
|
|
284
|
+
}), /* @__PURE__ */ u(m, {
|
|
285
|
+
id: "notebook-share-slug",
|
|
286
|
+
value: L.shareSlug,
|
|
287
|
+
onChange: (e) => U("shareSlug", e.target.value),
|
|
288
|
+
placeholder: "e.g. kepler-detrend",
|
|
289
|
+
disabled: !L.isShared
|
|
290
|
+
})]
|
|
291
|
+
})]
|
|
292
|
+
}),
|
|
293
|
+
/* @__PURE__ */ d("div", {
|
|
294
|
+
className: "flex items-center gap-3",
|
|
295
|
+
children: [/* @__PURE__ */ u(x, {
|
|
296
|
+
id: "notebook-shared",
|
|
297
|
+
checked: L.isShared,
|
|
298
|
+
onCheckedChange: (e) => U("isShared", e)
|
|
299
|
+
}), /* @__PURE__ */ u(h, {
|
|
300
|
+
htmlFor: "notebook-shared",
|
|
301
|
+
className: "cursor-pointer",
|
|
302
|
+
children: "Shared with the workspace"
|
|
303
|
+
})]
|
|
304
|
+
})
|
|
305
|
+
]
|
|
306
|
+
}) : null
|
|
307
|
+
]
|
|
308
|
+
});
|
|
309
|
+
}
|
|
310
|
+
//#endregion
|
|
311
|
+
export { E as default };
|
|
312
|
+
|
|
313
|
+
//# sourceMappingURL=NotebookFormPage.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"NotebookFormPage.js","names":[],"sources":["../../../../src/cosmicintersection/pages/notebooks/NotebookFormPage.tsx"],"sourcesContent":["/**\n * NotebookFormPage — create / edit a computational notebook.\n *\n * Notebook artifacts (the .ipynb-style file) are NOT stored by this MFE — they\n * live in wspace-files and are attached via FileUploadField, which hands back a\n * `fileId`. Datasets are linked by id (multi-select from `cosListDatasets`),\n * tags use the shared chips editor, and `environment` is free-form JSON. On\n * submit the form calls `cosCreateNotebook` / `cosUpdateNotebook`.\n */\nimport { useState, type FormEvent } from 'react';\nimport { useParams } from 'react-router-dom';\nimport {\n Checkbox,\n Input,\n Label,\n Select,\n SelectContent,\n SelectItem,\n SelectTrigger,\n SelectValue,\n Switch,\n Textarea,\n} from '@burdenoff/fe-libs/ui';\n\nimport {\n useCosCreateNotebookMutation,\n useCosDatasetsQuery,\n useCosNotebookQuery,\n useCosUpdateNotebookMutation,\n type CosCreateNotebookInput,\n type CosNotebookStatus,\n type CosUpdateNotebookInput,\n} from '../../api/cosmicApi';\nimport { EntityFormShell, EntityTagsField, FileUploadField } 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\ninterface FormState {\n title: string;\n description: string;\n runtime: string;\n environment: string;\n datasetIds: string[];\n tags: string[];\n fileId: string;\n status: CosNotebookStatus;\n isShared: boolean;\n shareSlug: string;\n}\n\nconst INITIAL: FormState = {\n title: '',\n description: '',\n runtime: '',\n environment: '',\n datasetIds: [],\n tags: [],\n fileId: '',\n status: 'DRAFT',\n isShared: false,\n shareSlug: '',\n};\n\n/** Parse the optional environment JSON. Returns `undefined` when blank, or an\n * error string when the text is not a valid JSON object. */\nfunction parseEnvironment(\n raw: string\n): { ok: true; value?: Record<string, unknown> } | { ok: false; error: string } {\n const trimmed = raw.trim();\n if (!trimmed) {\n return { ok: true, value: undefined };\n }\n try {\n const parsed: unknown = JSON.parse(trimmed);\n if (typeof parsed !== 'object' || parsed === null || Array.isArray(parsed)) {\n return { ok: false, error: 'Environment must be a JSON object.' };\n }\n return { ok: true, value: parsed as Record<string, unknown> };\n } catch {\n return { ok: false, error: 'Environment is not valid JSON.' };\n }\n}\n\nexport default function NotebookFormPage() {\n const { id = '' } = useParams<{ id: string }>();\n const isEdit = Boolean(id);\n const { navigate } = useCosmicIntersection();\n\n const { data: notebookData, loading: loadingNotebook } = useCosNotebookQuery(id);\n const { data: datasetsData, loading: loadingDatasets } = useCosDatasetsQuery({\n pagination: { limit: 100, offset: 0 },\n });\n const [createNotebook, { loading: creating }] = useCosCreateNotebookMutation();\n const [updateNotebook, { loading: updating }] = useCosUpdateNotebookMutation();\n\n const [form, setForm] = useState<FormState>(INITIAL);\n const datasets = datasetsData?.cosListDatasets.items ?? [];\n\n // Hydrate the form from the fetched notebook exactly once per loaded record,\n // using React's documented \"adjust state while rendering\" pattern (no effect,\n // no cascading render) rather than a setState-in-effect.\n const notebook = notebookData?.cosNotebook ?? null;\n const [hydratedId, setHydratedId] = useState<string | null>(null);\n if (isEdit && notebook && hydratedId !== notebook.id) {\n setHydratedId(notebook.id);\n setForm({\n title: notebook.title ?? '',\n description: notebook.description ?? '',\n runtime: notebook.runtime ?? '',\n environment: notebook.environment ? JSON.stringify(notebook.environment, null, 2) : '',\n datasetIds: notebook.datasetIds ?? [],\n tags: notebook.tags ?? [],\n fileId: notebook.file?.id ?? '',\n status: notebook.status ?? 'DRAFT',\n isShared: notebook.isShared ?? false,\n shareSlug: notebook.shareSlug ?? '',\n });\n }\n\n const setField = <K extends keyof FormState>(key: K, value: FormState[K]) =>\n setForm((prev) => ({ ...prev, [key]: value }));\n\n const toggleDataset = (datasetId: string) =>\n setForm((prev) => ({\n ...prev,\n datasetIds: prev.datasetIds.includes(datasetId)\n ? prev.datasetIds.filter((existing) => existing !== datasetId)\n : [...prev.datasetIds, datasetId],\n }));\n\n const handleSubmit = async (event: FormEvent<HTMLFormElement>) => {\n event.preventDefault();\n\n const title = form.title.trim();\n if (!title) {\n notify.error('Title is required', 'Give the notebook a descriptive title.');\n return;\n }\n\n const env = parseEnvironment(form.environment);\n if (!env.ok) {\n notify.error('Invalid environment', env.error);\n return;\n }\n\n if (isEdit) {\n const input: CosUpdateNotebookInput = {\n title,\n description: form.description.trim() || undefined,\n runtime: form.runtime.trim() || undefined,\n environment: env.value,\n datasetIds: form.datasetIds,\n tags: form.tags,\n status: form.status,\n isShared: form.isShared,\n shareSlug: form.shareSlug.trim() || undefined,\n };\n const response = await updateNotebook({ variables: { id, input } });\n if (response.error || !response.data?.cosUpdateNotebook) {\n return;\n }\n notify.success('Notebook updated', `“${title}” was saved.`);\n navigate(`notebooks/${id}`);\n return;\n }\n\n const input: CosCreateNotebookInput = {\n title,\n description: form.description.trim() || undefined,\n runtime: form.runtime.trim() || undefined,\n environment: env.value,\n datasetIds: form.datasetIds,\n tags: form.tags,\n fileId: form.fileId || undefined,\n };\n const response = await createNotebook({ variables: { input } });\n const createdId = response.data?.cosCreateNotebook?.id;\n if (response.error || !createdId) {\n return;\n }\n notify.success('Notebook created', `“${title}” is ready.`);\n navigate(`notebooks/${createdId}`);\n };\n\n const saving = creating || updating;\n\n return (\n <EntityFormShell\n title={isEdit ? 'Edit notebook' : 'New notebook'}\n description=\"Set up a computational notebook and link the datasets it analyses.\"\n purpose=\"Notebooks capture the code and environment behind an analysis. Attach the notebook file, pick which federated datasets it reads, and record the runtime so results are reproducible.\"\n backLabel={isEdit ? 'Back to notebook' : 'Back to notebooks'}\n onBack={() => navigate(isEdit ? `notebooks/${id}` : 'notebooks')}\n onSubmit={handleSubmit}\n submitLabel={isEdit ? 'Save notebook' : 'Create notebook'}\n saving={saving}\n submitDisabled={isEdit && loadingNotebook}\n >\n <div className=\"grid grid-cols-1 gap-4 md:grid-cols-2\">\n <div className=\"space-y-1.5\">\n <Label htmlFor=\"notebook-title\">Title</Label>\n <Input\n id=\"notebook-title\"\n value={form.title}\n onChange={(event) => setField('title', event.target.value)}\n placeholder=\"e.g. Kepler light-curve detrending\"\n required\n />\n </div>\n <div className=\"space-y-1.5\">\n <Label htmlFor=\"notebook-runtime\">Runtime</Label>\n <Input\n id=\"notebook-runtime\"\n value={form.runtime}\n onChange={(event) => setField('runtime', event.target.value)}\n placeholder=\"e.g. python-3.11\"\n />\n </div>\n </div>\n\n <div className=\"space-y-1.5\">\n <Label htmlFor=\"notebook-description\">Description</Label>\n <Textarea\n id=\"notebook-description\"\n value={form.description}\n onChange={(event) => setField('description', event.target.value)}\n rows={3}\n placeholder=\"What does this notebook do?\"\n />\n </div>\n\n <div className=\"space-y-1.5\">\n <Label htmlFor=\"notebook-environment\">Environment (JSON)</Label>\n <Textarea\n id=\"notebook-environment\"\n value={form.environment}\n onChange={(event) => setField('environment', event.target.value)}\n rows={4}\n className=\"font-mono text-xs\"\n placeholder='{ \"numpy\": \"1.26\", \"astropy\": \"6.0\" }'\n />\n <p className=\"text-xs text-text-secondary\">\n Optional dependency / kernel metadata as a JSON object.\n </p>\n </div>\n\n <div className=\"space-y-2\">\n <Label>Linked datasets</Label>\n {loadingDatasets ? (\n <p className=\"text-sm text-text-secondary\">Loading datasets…</p>\n ) : datasets.length === 0 ? (\n <p className=\"text-sm text-text-secondary\">\n No datasets available yet. Create a dataset first to link it here.\n </p>\n ) : (\n <div className=\"max-h-56 space-y-1 overflow-auto rounded-card border border-border-default bg-bg-sunken p-2\">\n {datasets.map((dataset) => {\n const checked = form.datasetIds.includes(dataset.id);\n return (\n <label\n key={dataset.id}\n className=\"flex cursor-pointer items-center gap-3 rounded-button px-2 py-1.5 hover:bg-bg-elevated\"\n >\n <Checkbox\n checked={checked}\n onCheckedChange={() => toggleDataset(dataset.id)}\n aria-label={`Link ${dataset.name}`}\n />\n <span className=\"min-w-0 flex-1 truncate text-sm text-text-primary\">\n {dataset.name}\n </span>\n <span className=\"text-xs text-text-secondary\">{dataset.status}</span>\n </label>\n );\n })}\n </div>\n )}\n {form.datasetIds.length > 0 ? (\n <p className=\"text-xs text-text-secondary\">\n {form.datasetIds.length} dataset{form.datasetIds.length === 1 ? '' : 's'} linked.\n </p>\n ) : null}\n </div>\n\n <EntityTagsField value={form.tags} onChange={(tags) => setField('tags', tags)} />\n\n <FileUploadField\n value={form.fileId}\n onChange={(fileId) => setField('fileId', fileId)}\n label=\"Attach notebook file\"\n hint=\"Upload the notebook artifact (.ipynb or any file). Stored in workspace files.\"\n />\n\n {isEdit ? (\n <div className=\"space-y-4 rounded-card border border-border-default bg-bg-sunken p-4\">\n <p className=\"text-sm font-medium text-text-primary\">Lifecycle & sharing</p>\n <div className=\"grid grid-cols-1 gap-4 md:grid-cols-2\">\n <div className=\"space-y-1.5\">\n <Label htmlFor=\"notebook-status\">Status</Label>\n <Select\n value={form.status}\n onValueChange={(value) => setField('status', value as CosNotebookStatus)}\n >\n <SelectTrigger id=\"notebook-status\" aria-label=\"Notebook status\">\n <SelectValue />\n </SelectTrigger>\n <SelectContent>\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 <div className=\"space-y-1.5\">\n <Label htmlFor=\"notebook-share-slug\">Share slug</Label>\n <Input\n id=\"notebook-share-slug\"\n value={form.shareSlug}\n onChange={(event) => setField('shareSlug', event.target.value)}\n placeholder=\"e.g. kepler-detrend\"\n disabled={!form.isShared}\n />\n </div>\n </div>\n <div className=\"flex items-center gap-3\">\n <Switch\n id=\"notebook-shared\"\n checked={form.isShared}\n onCheckedChange={(checked) => setField('isShared', checked)}\n />\n <Label htmlFor=\"notebook-shared\" className=\"cursor-pointer\">\n Shared with the workspace\n </Label>\n </div>\n </div>\n ) : null}\n </EntityFormShell>\n );\n}\n"],"mappings":"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"}
|
|
@@ -0,0 +1,203 @@
|
|
|
1
|
+
import { useCosmicIntersection as e } from "../../context/CosmicIntersectionContext.js";
|
|
2
|
+
import { notify as t } from "../../lib/toast.js";
|
|
3
|
+
import { useCosArchiveNotebookMutation as n, useCosNotebooksQuery as r } from "../../api/cosmicApi.js";
|
|
4
|
+
import i from "../../components/ActionMenu.js";
|
|
5
|
+
import a from "../../components/EmptyState.js";
|
|
6
|
+
import o from "../../components/ErrorState.js";
|
|
7
|
+
import s from "../../components/LoadingState.js";
|
|
8
|
+
import c from "../../components/PageLayout.js";
|
|
9
|
+
import l, { usePagination as u } from "../../components/Pagination.js";
|
|
10
|
+
import d from "../../components/StatusBadge.js";
|
|
11
|
+
import "../../components/index.js";
|
|
12
|
+
import { useState as f } from "react";
|
|
13
|
+
import { jsx as p, jsxs as m } from "react/jsx-runtime";
|
|
14
|
+
import { NotebookText as h, Plus as g, Share2 as _ } from "lucide-react";
|
|
15
|
+
import { Badge as v, Button as y, Select as b, SelectContent as x, SelectItem as S, SelectTrigger as C, SelectValue as w, Table as T, TableBody as E, TableCell as D, TableHead as O, TableHeader as k, TableRow as A } from "@burdenoff/fe-libs/ui";
|
|
16
|
+
//#region src/cosmicintersection/pages/notebooks/NotebooksPage.tsx
|
|
17
|
+
var j = [
|
|
18
|
+
{
|
|
19
|
+
value: "DRAFT",
|
|
20
|
+
label: "Draft"
|
|
21
|
+
},
|
|
22
|
+
{
|
|
23
|
+
value: "RUNNING",
|
|
24
|
+
label: "Running"
|
|
25
|
+
},
|
|
26
|
+
{
|
|
27
|
+
value: "PUBLISHED",
|
|
28
|
+
label: "Published"
|
|
29
|
+
},
|
|
30
|
+
{
|
|
31
|
+
value: "ARCHIVED",
|
|
32
|
+
label: "Archived"
|
|
33
|
+
}
|
|
34
|
+
], M = "ALL";
|
|
35
|
+
function N(e) {
|
|
36
|
+
if (!e) return "—";
|
|
37
|
+
let t = new Date(e);
|
|
38
|
+
return Number.isNaN(t.getTime()) ? "—" : t.toLocaleDateString(void 0, {
|
|
39
|
+
year: "numeric",
|
|
40
|
+
month: "short",
|
|
41
|
+
day: "numeric"
|
|
42
|
+
});
|
|
43
|
+
}
|
|
44
|
+
function P() {
|
|
45
|
+
let { navigate: P } = e(), [F, I] = f(void 0), L = u({
|
|
46
|
+
pageSize: 50,
|
|
47
|
+
resetKey: F
|
|
48
|
+
}), { data: R, loading: z, error: B, refetch: V } = r({
|
|
49
|
+
status: F,
|
|
50
|
+
pagination: {
|
|
51
|
+
limit: L.limit,
|
|
52
|
+
offset: L.offset
|
|
53
|
+
}
|
|
54
|
+
}), [H] = n(), U = R?.cosListNotebooks.items ?? [], W = R?.cosListNotebooks.pageInfo, G = async (e) => {
|
|
55
|
+
let n = await H({ variables: { id: e.id } });
|
|
56
|
+
if (n.error) throw Error(n.error.message);
|
|
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 V(), t.success("Notebook archived", `“${e.title}” was archived.`);
|
|
59
|
+
};
|
|
60
|
+
return /* @__PURE__ */ p(c, {
|
|
61
|
+
title: "Notebooks",
|
|
62
|
+
description: "Computational notebooks for running analyses over federated science datasets.",
|
|
63
|
+
actions: /* @__PURE__ */ m(y, {
|
|
64
|
+
type: "button",
|
|
65
|
+
onClick: () => P("notebooks/create"),
|
|
66
|
+
children: [/* @__PURE__ */ p(g, { className: "size-4" }), "New notebook"]
|
|
67
|
+
}),
|
|
68
|
+
children: /* @__PURE__ */ m("div", {
|
|
69
|
+
className: "space-y-4",
|
|
70
|
+
children: [
|
|
71
|
+
/* @__PURE__ */ m("div", {
|
|
72
|
+
className: "flex flex-wrap items-center gap-3",
|
|
73
|
+
children: [/* @__PURE__ */ p("label", {
|
|
74
|
+
className: "text-sm text-text-secondary",
|
|
75
|
+
htmlFor: "notebook-status-filter",
|
|
76
|
+
children: "Status"
|
|
77
|
+
}), /* @__PURE__ */ m(b, {
|
|
78
|
+
value: F ?? M,
|
|
79
|
+
onValueChange: (e) => I(e === M ? void 0 : e),
|
|
80
|
+
children: [/* @__PURE__ */ p(C, {
|
|
81
|
+
id: "notebook-status-filter",
|
|
82
|
+
className: "w-48",
|
|
83
|
+
"aria-label": "Filter by status",
|
|
84
|
+
children: /* @__PURE__ */ p(w, {})
|
|
85
|
+
}), /* @__PURE__ */ m(x, { children: [/* @__PURE__ */ p(S, {
|
|
86
|
+
value: M,
|
|
87
|
+
children: "All statuses"
|
|
88
|
+
}), j.map((e) => /* @__PURE__ */ p(S, {
|
|
89
|
+
value: e.value,
|
|
90
|
+
children: e.label
|
|
91
|
+
}, e.value))] })]
|
|
92
|
+
})]
|
|
93
|
+
}),
|
|
94
|
+
z ? /* @__PURE__ */ p(s, {
|
|
95
|
+
variant: "rows",
|
|
96
|
+
rows: 6,
|
|
97
|
+
label: "Loading notebooks…"
|
|
98
|
+
}) : B ? /* @__PURE__ */ p(o, {
|
|
99
|
+
message: "We could not load your notebooks. Please try again.",
|
|
100
|
+
onRetry: () => void V()
|
|
101
|
+
}) : U.length === 0 ? /* @__PURE__ */ p(a, {
|
|
102
|
+
icon: h,
|
|
103
|
+
title: F ? "No notebooks match this filter." : "No notebooks yet.",
|
|
104
|
+
description: F ? "Try a different status filter." : "Create your first notebook to start analysing federated datasets.",
|
|
105
|
+
action: F ? void 0 : /* @__PURE__ */ m(y, {
|
|
106
|
+
type: "button",
|
|
107
|
+
onClick: () => P("notebooks/create"),
|
|
108
|
+
children: [/* @__PURE__ */ p(g, { className: "size-4" }), "New notebook"]
|
|
109
|
+
})
|
|
110
|
+
}) : /* @__PURE__ */ p("div", {
|
|
111
|
+
className: "rounded-card border border-border-default bg-bg-elevated",
|
|
112
|
+
children: /* @__PURE__ */ m(T, { children: [/* @__PURE__ */ p(k, { children: /* @__PURE__ */ m(A, { children: [
|
|
113
|
+
/* @__PURE__ */ p(O, { children: "Title" }),
|
|
114
|
+
/* @__PURE__ */ p(O, { children: "Status" }),
|
|
115
|
+
/* @__PURE__ */ p(O, { children: "Runtime" }),
|
|
116
|
+
/* @__PURE__ */ p(O, {
|
|
117
|
+
className: "text-right",
|
|
118
|
+
children: "Datasets"
|
|
119
|
+
}),
|
|
120
|
+
/* @__PURE__ */ p(O, { children: "Sharing" }),
|
|
121
|
+
/* @__PURE__ */ p(O, { children: "Tags" }),
|
|
122
|
+
/* @__PURE__ */ p(O, { children: "Updated" }),
|
|
123
|
+
/* @__PURE__ */ p(O, {
|
|
124
|
+
className: "w-12 text-right",
|
|
125
|
+
children: "Actions"
|
|
126
|
+
})
|
|
127
|
+
] }) }), /* @__PURE__ */ p(E, { children: U.map((e) => /* @__PURE__ */ m(A, {
|
|
128
|
+
className: "cursor-pointer",
|
|
129
|
+
onClick: () => P(`notebooks/${e.id}`),
|
|
130
|
+
children: [
|
|
131
|
+
/* @__PURE__ */ p(D, {
|
|
132
|
+
className: "font-medium text-text-primary",
|
|
133
|
+
children: e.title
|
|
134
|
+
}),
|
|
135
|
+
/* @__PURE__ */ p(D, { children: /* @__PURE__ */ p(d, { status: e.status }) }),
|
|
136
|
+
/* @__PURE__ */ p(D, {
|
|
137
|
+
className: "text-text-secondary",
|
|
138
|
+
children: e.runtime ?? "—"
|
|
139
|
+
}),
|
|
140
|
+
/* @__PURE__ */ p(D, {
|
|
141
|
+
className: "text-right tabular-nums text-text-secondary",
|
|
142
|
+
children: e.datasetIds.length
|
|
143
|
+
}),
|
|
144
|
+
/* @__PURE__ */ p(D, { children: e.isShared ? /* @__PURE__ */ m(v, {
|
|
145
|
+
variant: "secondary",
|
|
146
|
+
className: "gap-1",
|
|
147
|
+
children: [/* @__PURE__ */ p(_, {
|
|
148
|
+
className: "size-3",
|
|
149
|
+
"aria-hidden": "true"
|
|
150
|
+
}), "Shared"]
|
|
151
|
+
}) : /* @__PURE__ */ p("span", {
|
|
152
|
+
className: "text-text-secondary",
|
|
153
|
+
children: "Private"
|
|
154
|
+
}) }),
|
|
155
|
+
/* @__PURE__ */ p(D, { children: e.tags.length > 0 ? /* @__PURE__ */ m("div", {
|
|
156
|
+
className: "flex flex-wrap gap-1",
|
|
157
|
+
children: [e.tags.slice(0, 3).map((e) => /* @__PURE__ */ p(v, {
|
|
158
|
+
variant: "outline",
|
|
159
|
+
children: e
|
|
160
|
+
}, e)), e.tags.length > 3 ? /* @__PURE__ */ m("span", {
|
|
161
|
+
className: "text-xs text-text-secondary",
|
|
162
|
+
children: ["+", e.tags.length - 3]
|
|
163
|
+
}) : null]
|
|
164
|
+
}) : /* @__PURE__ */ p("span", {
|
|
165
|
+
className: "text-text-secondary",
|
|
166
|
+
children: "—"
|
|
167
|
+
}) }),
|
|
168
|
+
/* @__PURE__ */ p(D, {
|
|
169
|
+
className: "whitespace-nowrap text-text-secondary",
|
|
170
|
+
children: N(e.updatedAt)
|
|
171
|
+
}),
|
|
172
|
+
/* @__PURE__ */ p(D, {
|
|
173
|
+
className: "text-right",
|
|
174
|
+
children: /* @__PURE__ */ p(i, {
|
|
175
|
+
ariaLabel: `Actions for ${e.title}`,
|
|
176
|
+
entityName: e.title,
|
|
177
|
+
onView: () => P(`notebooks/${e.id}`),
|
|
178
|
+
onEdit: () => P(`notebooks/${e.id}/edit`),
|
|
179
|
+
onDelete: e.status === "ARCHIVED" ? void 0 : () => G(e),
|
|
180
|
+
deleteLabel: "Archive notebook"
|
|
181
|
+
})
|
|
182
|
+
})
|
|
183
|
+
]
|
|
184
|
+
}, e.id)) })] })
|
|
185
|
+
}),
|
|
186
|
+
!z && !B && U.length > 0 ? /* @__PURE__ */ p(l, {
|
|
187
|
+
offset: L.offset,
|
|
188
|
+
limit: L.limit,
|
|
189
|
+
loadedCount: U.length,
|
|
190
|
+
hasMore: W?.hasMore ?? !1,
|
|
191
|
+
onPrev: L.prevPage,
|
|
192
|
+
onNext: L.nextPage,
|
|
193
|
+
itemLabel: "notebooks",
|
|
194
|
+
loading: z
|
|
195
|
+
}) : null
|
|
196
|
+
]
|
|
197
|
+
})
|
|
198
|
+
});
|
|
199
|
+
}
|
|
200
|
+
//#endregion
|
|
201
|
+
export { P as default };
|
|
202
|
+
|
|
203
|
+
//# sourceMappingURL=NotebooksPage.js.map
|
|
@@ -0,0 +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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"}
|