@burdenoff/microfe-cosmicintersection 2026.704.1 → 2026.704.2
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/CosmicIntersectionRoutes.js +31 -23
- package/dist/cosmicintersection/CosmicIntersectionRoutes.js.map +1 -1
- package/dist/cosmicintersection/api/cosmicApi.js +131 -66
- package/dist/cosmicintersection/api/cosmicApi.js.map +1 -1
- package/dist/cosmicintersection/components/ActivityFeedPanel.js +68 -0
- package/dist/cosmicintersection/components/ActivityFeedPanel.js.map +1 -0
- package/dist/cosmicintersection/components/DiscussionPanel.js +57 -0
- package/dist/cosmicintersection/components/DiscussionPanel.js.map +1 -0
- package/dist/cosmicintersection/components/index.js +5 -3
- package/dist/cosmicintersection/pages/access/AccessPage.js +24 -17
- package/dist/cosmicintersection/pages/access/AccessPage.js.map +1 -1
- package/dist/cosmicintersection/pages/analyses/AnalysesPage.js +12 -12
- package/dist/cosmicintersection/pages/collections/CollectionDetailPage.js +109 -96
- package/dist/cosmicintersection/pages/collections/CollectionDetailPage.js.map +1 -1
- package/dist/cosmicintersection/pages/collections/CollectionFormPage.js +87 -61
- package/dist/cosmicintersection/pages/collections/CollectionFormPage.js.map +1 -1
- package/dist/cosmicintersection/pages/collections/CollectionsPage.js +51 -42
- package/dist/cosmicintersection/pages/collections/CollectionsPage.js.map +1 -1
- package/dist/cosmicintersection/pages/dashboard/DashboardPage.js +5 -3
- package/dist/cosmicintersection/pages/dashboard/DashboardPage.js.map +1 -1
- package/dist/cosmicintersection/pages/datasets/DatasetDetailPage.js +172 -152
- package/dist/cosmicintersection/pages/datasets/DatasetDetailPage.js.map +1 -1
- package/dist/cosmicintersection/pages/datasets/DatasetFormPage.js +7 -7
- package/dist/cosmicintersection/pages/notebooks/NotebookDetailPage.js +205 -196
- package/dist/cosmicintersection/pages/notebooks/NotebookDetailPage.js.map +1 -1
- package/dist/cosmicintersection/pages/releases/ReleasesPage.js +211 -161
- package/dist/cosmicintersection/pages/releases/ReleasesPage.js.map +1 -1
- package/dist/cosmicintersection/pages/runs/RunDetailPage.js +113 -108
- package/dist/cosmicintersection/pages/runs/RunDetailPage.js.map +1 -1
- package/dist/cosmicintersection/pages/runs/RunsPage.js +86 -101
- package/dist/cosmicintersection/pages/runs/RunsPage.js.map +1 -1
- package/dist/cosmicintersection/pages/sources/SourceDetailPage.js +205 -0
- package/dist/cosmicintersection/pages/sources/SourceDetailPage.js.map +1 -0
- package/dist/cosmicintersection/pages/sources/SourcesPage.js +110 -104
- package/dist/cosmicintersection/pages/sources/SourcesPage.js.map +1 -1
- package/package.json +1 -1
|
@@ -4,10 +4,10 @@ import { useCosAnalysesQuery as n, useCosArchiveNotebookMutation as r, useCosNot
|
|
|
4
4
|
import o from "../../components/ActionMenu.js";
|
|
5
5
|
import s from "../../components/EmptyState.js";
|
|
6
6
|
import c from "../../components/ErrorState.js";
|
|
7
|
-
import
|
|
8
|
-
import u from "../../components/
|
|
9
|
-
import d from "../../components/
|
|
10
|
-
import f from "../../components/
|
|
7
|
+
import l from "../../components/LoadingState.js";
|
|
8
|
+
import u from "../../components/DiscussionPanel.js";
|
|
9
|
+
import { useFileDownloadUrl as d } from "../../components/FileUploadField.js";
|
|
10
|
+
import f from "../../components/PageLayout.js";
|
|
11
11
|
import p from "../../components/StatusBadge.js";
|
|
12
12
|
import "../../components/index.js";
|
|
13
13
|
import { useState as m } from "react";
|
|
@@ -28,7 +28,7 @@ function U(e) {
|
|
|
28
28
|
});
|
|
29
29
|
}
|
|
30
30
|
function W({ fileId: e, label: t }) {
|
|
31
|
-
let { data: n, loading: r } =
|
|
31
|
+
let { data: n, loading: r } = d(e), i = n?.getFileDownloadUrl ?? null;
|
|
32
32
|
return r ? /* @__PURE__ */ h("span", {
|
|
33
33
|
className: "text-xs text-text-secondary",
|
|
34
34
|
children: "Resolving link…"
|
|
@@ -127,19 +127,19 @@ function G({ notebookId: e, open: n, onOpenChange: r, onCompleted: i }) {
|
|
|
127
127
|
});
|
|
128
128
|
}
|
|
129
129
|
function K() {
|
|
130
|
-
let { id: a = "" } = _(), { navigate:
|
|
130
|
+
let { id: a = "" } = _(), { navigate: d } = e(), [y, O] = m(!1), { data: k, loading: A, error: j, refetch: M } = i(a), { data: N, loading: P, error: F, refetch: I } = n({ notebookId: a }), [K] = r(), q = k?.cosNotebook ?? null, J = N?.cosListAnalyses ?? [], Y = async () => {
|
|
131
131
|
if (!q) return;
|
|
132
132
|
let e = await K({ variables: { id: q.id } });
|
|
133
133
|
if (e.error) throw Error(e.error.message);
|
|
134
134
|
if (!e.data?.cosArchiveNotebook) throw t.error("Could not archive notebook", "The server did not confirm the change."), Error("Archive not confirmed");
|
|
135
135
|
await M(), t.success("Notebook archived", `“${q.title}” was archived.`);
|
|
136
136
|
};
|
|
137
|
-
if (A) return /* @__PURE__ */ h(
|
|
137
|
+
if (A) return /* @__PURE__ */ h(f, {
|
|
138
138
|
title: "Notebook",
|
|
139
139
|
backPath: "notebooks",
|
|
140
|
-
children: /* @__PURE__ */ h(
|
|
140
|
+
children: /* @__PURE__ */ h(l, { label: "Loading notebook…" })
|
|
141
141
|
});
|
|
142
|
-
if (j) return /* @__PURE__ */ h(
|
|
142
|
+
if (j) return /* @__PURE__ */ h(f, {
|
|
143
143
|
title: "Notebook",
|
|
144
144
|
backPath: "notebooks",
|
|
145
145
|
children: /* @__PURE__ */ h(c, {
|
|
@@ -147,7 +147,7 @@ function K() {
|
|
|
147
147
|
onRetry: () => void M()
|
|
148
148
|
})
|
|
149
149
|
});
|
|
150
|
-
if (!q) return /* @__PURE__ */ h(
|
|
150
|
+
if (!q) return /* @__PURE__ */ h(f, {
|
|
151
151
|
title: "Notebook",
|
|
152
152
|
backPath: "notebooks",
|
|
153
153
|
children: /* @__PURE__ */ h(s, {
|
|
@@ -156,7 +156,7 @@ function K() {
|
|
|
156
156
|
description: "This notebook may have been removed or is outside your current scope.",
|
|
157
157
|
action: /* @__PURE__ */ h(D, {
|
|
158
158
|
type: "button",
|
|
159
|
-
onClick: () =>
|
|
159
|
+
onClick: () => d("notebooks"),
|
|
160
160
|
children: "Back to notebooks"
|
|
161
161
|
})
|
|
162
162
|
})
|
|
@@ -172,213 +172,222 @@ function K() {
|
|
|
172
172
|
/* @__PURE__ */ g(D, {
|
|
173
173
|
type: "button",
|
|
174
174
|
variant: "outline",
|
|
175
|
-
onClick: () =>
|
|
175
|
+
onClick: () => d(`notebooks/${q.id}/edit`),
|
|
176
176
|
children: [/* @__PURE__ */ h(S, { className: "size-4" }), "Edit"]
|
|
177
177
|
}),
|
|
178
178
|
/* @__PURE__ */ h(o, {
|
|
179
179
|
ariaLabel: `Actions for ${q.title}`,
|
|
180
180
|
entityName: q.title,
|
|
181
|
-
onEdit: () => l(`notebooks/${q.id}/edit`),
|
|
182
181
|
onDelete: q.status === "ARCHIVED" ? void 0 : Y,
|
|
183
182
|
deleteLabel: "Archive notebook"
|
|
184
183
|
})
|
|
185
184
|
]
|
|
186
185
|
});
|
|
187
|
-
return /* @__PURE__ */ g(
|
|
186
|
+
return /* @__PURE__ */ g(f, {
|
|
188
187
|
title: q.title,
|
|
189
188
|
description: "Notebook detail",
|
|
190
189
|
backPath: "notebooks",
|
|
191
190
|
actions: Z,
|
|
192
191
|
children: [/* @__PURE__ */ g("div", {
|
|
193
192
|
className: "space-y-6",
|
|
194
|
-
children: [
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
193
|
+
children: [
|
|
194
|
+
/* @__PURE__ */ g("section", {
|
|
195
|
+
className: "rounded-card border border-border-default bg-bg-elevated p-6",
|
|
196
|
+
children: [
|
|
197
|
+
/* @__PURE__ */ g("div", {
|
|
198
|
+
className: "flex flex-wrap items-center gap-3",
|
|
199
|
+
children: [
|
|
200
|
+
/* @__PURE__ */ h(p, { status: q.status }),
|
|
201
|
+
q.runtime ? /* @__PURE__ */ g(E, {
|
|
202
|
+
variant: "outline",
|
|
203
|
+
children: ["Runtime: ", q.runtime]
|
|
204
|
+
}) : null,
|
|
205
|
+
q.isShared ? /* @__PURE__ */ g(E, {
|
|
206
|
+
variant: "secondary",
|
|
207
|
+
className: "gap-1",
|
|
208
|
+
children: [
|
|
209
|
+
/* @__PURE__ */ h(w, {
|
|
210
|
+
className: "size-3",
|
|
211
|
+
"aria-hidden": "true"
|
|
212
|
+
}),
|
|
213
|
+
"Shared",
|
|
214
|
+
q.shareSlug ? `: ${q.shareSlug}` : ""
|
|
215
|
+
]
|
|
216
|
+
}) : /* @__PURE__ */ h(E, {
|
|
217
|
+
variant: "outline",
|
|
218
|
+
children: "Private"
|
|
219
|
+
})
|
|
220
|
+
]
|
|
221
|
+
}),
|
|
222
|
+
q.description ? /* @__PURE__ */ h("p", {
|
|
223
|
+
className: "mt-4 text-sm text-text-secondary",
|
|
224
|
+
children: q.description
|
|
225
|
+
}) : /* @__PURE__ */ h("p", {
|
|
226
|
+
className: "mt-4 text-sm text-text-secondary",
|
|
227
|
+
children: "No description provided."
|
|
228
|
+
}),
|
|
229
|
+
/* @__PURE__ */ g("dl", {
|
|
230
|
+
className: "mt-6 grid grid-cols-1 gap-4 sm:grid-cols-2 lg:grid-cols-3",
|
|
231
|
+
children: [
|
|
232
|
+
/* @__PURE__ */ g("div", { children: [/* @__PURE__ */ h("dt", {
|
|
233
|
+
className: "text-xs uppercase tracking-wide text-text-secondary",
|
|
234
|
+
children: "Linked datasets"
|
|
235
|
+
}), /* @__PURE__ */ h("dd", {
|
|
236
|
+
className: "mt-1 text-sm tabular-nums text-text-primary",
|
|
237
|
+
children: q.datasetIds.length
|
|
238
|
+
})] }),
|
|
239
|
+
/* @__PURE__ */ g("div", { children: [/* @__PURE__ */ h("dt", {
|
|
240
|
+
className: "text-xs uppercase tracking-wide text-text-secondary",
|
|
241
|
+
children: "Created"
|
|
242
|
+
}), /* @__PURE__ */ h("dd", {
|
|
243
|
+
className: "mt-1 text-sm text-text-primary",
|
|
244
|
+
children: U(q.createdAt)
|
|
245
|
+
})] }),
|
|
246
|
+
/* @__PURE__ */ g("div", { children: [/* @__PURE__ */ h("dt", {
|
|
247
|
+
className: "text-xs uppercase tracking-wide text-text-secondary",
|
|
248
|
+
children: "Updated"
|
|
249
|
+
}), /* @__PURE__ */ h("dd", {
|
|
250
|
+
className: "mt-1 text-sm text-text-primary",
|
|
251
|
+
children: U(q.updatedAt)
|
|
252
|
+
})] }),
|
|
253
|
+
/* @__PURE__ */ g("div", { children: [/* @__PURE__ */ h("dt", {
|
|
254
|
+
className: "text-xs uppercase tracking-wide text-text-secondary",
|
|
255
|
+
children: "Notebook file"
|
|
256
|
+
}), /* @__PURE__ */ h("dd", {
|
|
257
|
+
className: "mt-1 text-sm text-text-primary",
|
|
258
|
+
children: q.file?.id ? /* @__PURE__ */ h(W, {
|
|
259
|
+
fileId: q.file.id,
|
|
260
|
+
label: "Download notebook"
|
|
261
|
+
}) : /* @__PURE__ */ h("span", {
|
|
262
|
+
className: "text-text-secondary",
|
|
263
|
+
children: "No file attached"
|
|
264
|
+
})
|
|
265
|
+
})] })
|
|
266
|
+
]
|
|
267
|
+
}),
|
|
268
|
+
q.tags.length > 0 ? /* @__PURE__ */ g("div", {
|
|
269
|
+
className: "mt-6",
|
|
270
|
+
children: [/* @__PURE__ */ h("p", {
|
|
247
271
|
className: "text-xs uppercase tracking-wide text-text-secondary",
|
|
248
|
-
children: "
|
|
249
|
-
}), /* @__PURE__ */ h("
|
|
250
|
-
className: "mt-
|
|
251
|
-
children:
|
|
252
|
-
|
|
253
|
-
|
|
272
|
+
children: "Tags"
|
|
273
|
+
}), /* @__PURE__ */ h("div", {
|
|
274
|
+
className: "mt-2 flex flex-wrap gap-2",
|
|
275
|
+
children: q.tags.map((e) => /* @__PURE__ */ h(E, {
|
|
276
|
+
variant: "outline",
|
|
277
|
+
children: e
|
|
278
|
+
}, e))
|
|
279
|
+
})]
|
|
280
|
+
}) : null,
|
|
281
|
+
X ? /* @__PURE__ */ g("div", {
|
|
282
|
+
className: "mt-6",
|
|
283
|
+
children: [/* @__PURE__ */ h("p", {
|
|
254
284
|
className: "text-xs uppercase tracking-wide text-text-secondary",
|
|
255
|
-
children: "
|
|
256
|
-
}), /* @__PURE__ */ h("
|
|
257
|
-
className: "mt-
|
|
258
|
-
children:
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
className: "text-
|
|
272
|
-
children: "
|
|
273
|
-
}), /* @__PURE__ */ h("div", {
|
|
274
|
-
className: "mt-2 flex flex-wrap gap-2",
|
|
275
|
-
children: q.tags.map((e) => /* @__PURE__ */ h(E, {
|
|
276
|
-
variant: "outline",
|
|
277
|
-
children: e
|
|
278
|
-
}, e))
|
|
285
|
+
children: "Environment"
|
|
286
|
+
}), /* @__PURE__ */ h("pre", {
|
|
287
|
+
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",
|
|
288
|
+
children: X
|
|
289
|
+
})]
|
|
290
|
+
}) : null
|
|
291
|
+
]
|
|
292
|
+
}),
|
|
293
|
+
/* @__PURE__ */ g("section", {
|
|
294
|
+
className: "space-y-4",
|
|
295
|
+
children: [/* @__PURE__ */ g("div", {
|
|
296
|
+
className: "flex items-center gap-2",
|
|
297
|
+
children: [/* @__PURE__ */ h(x, {
|
|
298
|
+
className: "size-5 text-text-secondary",
|
|
299
|
+
"aria-hidden": "true"
|
|
300
|
+
}), /* @__PURE__ */ h("h2", {
|
|
301
|
+
className: "text-lg font-semibold text-text-primary",
|
|
302
|
+
children: "Discussion"
|
|
279
303
|
})]
|
|
280
|
-
})
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
304
|
+
}), /* @__PURE__ */ h(u, {
|
|
305
|
+
entityType: "cosmicintersection-notebook",
|
|
306
|
+
entityId: q.id,
|
|
307
|
+
title: q.title,
|
|
308
|
+
widgetKey: "notebook-discussion"
|
|
309
|
+
})]
|
|
310
|
+
}),
|
|
311
|
+
/* @__PURE__ */ g("section", {
|
|
312
|
+
className: "space-y-4",
|
|
313
|
+
children: [/* @__PURE__ */ g("div", {
|
|
314
|
+
className: "flex flex-wrap items-center justify-between gap-3",
|
|
315
|
+
children: [/* @__PURE__ */ g("div", { children: [/* @__PURE__ */ h("h2", {
|
|
316
|
+
className: "text-lg font-semibold text-text-primary",
|
|
317
|
+
children: "Analyses"
|
|
318
|
+
}), /* @__PURE__ */ h("p", {
|
|
319
|
+
className: "text-sm text-text-secondary",
|
|
320
|
+
children: "Analysis runs executed against this notebook."
|
|
321
|
+
})] }), /* @__PURE__ */ g(D, {
|
|
322
|
+
type: "button",
|
|
323
|
+
variant: "outline",
|
|
324
|
+
onClick: () => O(!0),
|
|
325
|
+
children: [/* @__PURE__ */ h(C, { className: "size-4" }), "Run analysis"]
|
|
289
326
|
})]
|
|
290
|
-
})
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
327
|
+
}), P ? /* @__PURE__ */ h(l, {
|
|
328
|
+
variant: "rows",
|
|
329
|
+
rows: 3,
|
|
330
|
+
label: "Loading analyses…"
|
|
331
|
+
}) : F ? /* @__PURE__ */ h(c, {
|
|
332
|
+
message: "We could not load analyses for this notebook.",
|
|
333
|
+
onRetry: () => void I()
|
|
334
|
+
}) : J.length === 0 ? /* @__PURE__ */ h(s, {
|
|
335
|
+
icon: v,
|
|
336
|
+
title: "No analyses yet.",
|
|
337
|
+
description: "Run an analysis to generate results and artifacts from this notebook.",
|
|
338
|
+
action: /* @__PURE__ */ g(D, {
|
|
339
|
+
type: "button",
|
|
340
|
+
onClick: () => O(!0),
|
|
341
|
+
children: [/* @__PURE__ */ h(C, { className: "size-4" }), "Run analysis"]
|
|
300
342
|
})
|
|
301
|
-
})
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
343
|
+
}) : /* @__PURE__ */ h("div", {
|
|
344
|
+
className: "rounded-card border border-border-default bg-bg-elevated",
|
|
345
|
+
children: /* @__PURE__ */ g(L, { children: [/* @__PURE__ */ h(V, { children: /* @__PURE__ */ g(H, { children: [
|
|
346
|
+
/* @__PURE__ */ h(B, { children: "Title" }),
|
|
347
|
+
/* @__PURE__ */ h(B, { children: "Method" }),
|
|
348
|
+
/* @__PURE__ */ h(B, { children: "AI" }),
|
|
349
|
+
/* @__PURE__ */ h(B, { children: "Status" }),
|
|
350
|
+
/* @__PURE__ */ h(B, { children: "Started" }),
|
|
351
|
+
/* @__PURE__ */ h(B, { children: "Output" })
|
|
352
|
+
] }) }), /* @__PURE__ */ h(R, { children: J.map((e) => /* @__PURE__ */ g(H, { children: [
|
|
353
|
+
/* @__PURE__ */ h(z, {
|
|
354
|
+
className: "font-medium text-text-primary",
|
|
355
|
+
children: e.title
|
|
356
|
+
}),
|
|
357
|
+
/* @__PURE__ */ h(z, {
|
|
358
|
+
className: "text-text-secondary",
|
|
359
|
+
children: e.method ?? "—"
|
|
360
|
+
}),
|
|
361
|
+
/* @__PURE__ */ h(z, { children: e.aiAssisted ? /* @__PURE__ */ g(E, {
|
|
362
|
+
variant: "secondary",
|
|
363
|
+
className: "gap-1",
|
|
364
|
+
children: [/* @__PURE__ */ h(T, {
|
|
365
|
+
className: "size-3",
|
|
366
|
+
"aria-hidden": "true"
|
|
367
|
+
}), "AI"]
|
|
368
|
+
}) : /* @__PURE__ */ h("span", {
|
|
369
|
+
className: "text-text-secondary",
|
|
370
|
+
children: "—"
|
|
371
|
+
}) }),
|
|
372
|
+
/* @__PURE__ */ h(z, { children: /* @__PURE__ */ h(p, { status: e.status }) }),
|
|
373
|
+
/* @__PURE__ */ h(z, {
|
|
374
|
+
className: "whitespace-nowrap text-text-secondary",
|
|
375
|
+
children: U(e.startedAt)
|
|
376
|
+
}),
|
|
377
|
+
/* @__PURE__ */ h(z, { children: e.outputFile?.id ? /* @__PURE__ */ h(W, {
|
|
378
|
+
fileId: e.outputFile.id,
|
|
379
|
+
label: "Download"
|
|
380
|
+
}) : e.results && Object.keys(e.results).length > 0 ? /* @__PURE__ */ h("span", {
|
|
381
|
+
className: "text-xs text-text-secondary",
|
|
382
|
+
children: "Results recorded"
|
|
383
|
+
}) : /* @__PURE__ */ h("span", {
|
|
384
|
+
className: "text-text-secondary",
|
|
385
|
+
children: "—"
|
|
386
|
+
}) })
|
|
387
|
+
] }, e.id)) })] })
|
|
318
388
|
})]
|
|
319
|
-
})
|
|
320
|
-
|
|
321
|
-
rows: 3,
|
|
322
|
-
label: "Loading analyses…"
|
|
323
|
-
}) : F ? /* @__PURE__ */ h(c, {
|
|
324
|
-
message: "We could not load analyses for this notebook.",
|
|
325
|
-
onRetry: () => void I()
|
|
326
|
-
}) : J.length === 0 ? /* @__PURE__ */ h(s, {
|
|
327
|
-
icon: v,
|
|
328
|
-
title: "No analyses yet.",
|
|
329
|
-
description: "Run an analysis to generate results and artifacts from this notebook.",
|
|
330
|
-
action: /* @__PURE__ */ g(D, {
|
|
331
|
-
type: "button",
|
|
332
|
-
onClick: () => O(!0),
|
|
333
|
-
children: [/* @__PURE__ */ h(C, { className: "size-4" }), "Run analysis"]
|
|
334
|
-
})
|
|
335
|
-
}) : /* @__PURE__ */ h("div", {
|
|
336
|
-
className: "rounded-card border border-border-default bg-bg-elevated",
|
|
337
|
-
children: /* @__PURE__ */ g(L, { children: [/* @__PURE__ */ h(V, { children: /* @__PURE__ */ g(H, { children: [
|
|
338
|
-
/* @__PURE__ */ h(B, { children: "Title" }),
|
|
339
|
-
/* @__PURE__ */ h(B, { children: "Method" }),
|
|
340
|
-
/* @__PURE__ */ h(B, { children: "AI" }),
|
|
341
|
-
/* @__PURE__ */ h(B, { children: "Status" }),
|
|
342
|
-
/* @__PURE__ */ h(B, { children: "Started" }),
|
|
343
|
-
/* @__PURE__ */ h(B, { children: "Output" })
|
|
344
|
-
] }) }), /* @__PURE__ */ h(R, { children: J.map((e) => /* @__PURE__ */ g(H, { children: [
|
|
345
|
-
/* @__PURE__ */ h(z, {
|
|
346
|
-
className: "font-medium text-text-primary",
|
|
347
|
-
children: e.title
|
|
348
|
-
}),
|
|
349
|
-
/* @__PURE__ */ h(z, {
|
|
350
|
-
className: "text-text-secondary",
|
|
351
|
-
children: e.method ?? "—"
|
|
352
|
-
}),
|
|
353
|
-
/* @__PURE__ */ h(z, { children: e.aiAssisted ? /* @__PURE__ */ g(E, {
|
|
354
|
-
variant: "secondary",
|
|
355
|
-
className: "gap-1",
|
|
356
|
-
children: [/* @__PURE__ */ h(T, {
|
|
357
|
-
className: "size-3",
|
|
358
|
-
"aria-hidden": "true"
|
|
359
|
-
}), "AI"]
|
|
360
|
-
}) : /* @__PURE__ */ h("span", {
|
|
361
|
-
className: "text-text-secondary",
|
|
362
|
-
children: "—"
|
|
363
|
-
}) }),
|
|
364
|
-
/* @__PURE__ */ h(z, { children: /* @__PURE__ */ h(p, { status: e.status }) }),
|
|
365
|
-
/* @__PURE__ */ h(z, {
|
|
366
|
-
className: "whitespace-nowrap text-text-secondary",
|
|
367
|
-
children: U(e.startedAt)
|
|
368
|
-
}),
|
|
369
|
-
/* @__PURE__ */ h(z, { children: e.outputFile?.id ? /* @__PURE__ */ h(W, {
|
|
370
|
-
fileId: e.outputFile.id,
|
|
371
|
-
label: "Download"
|
|
372
|
-
}) : e.results && Object.keys(e.results).length > 0 ? /* @__PURE__ */ h("span", {
|
|
373
|
-
className: "text-xs text-text-secondary",
|
|
374
|
-
children: "Results recorded"
|
|
375
|
-
}) : /* @__PURE__ */ h("span", {
|
|
376
|
-
className: "text-text-secondary",
|
|
377
|
-
children: "—"
|
|
378
|
-
}) })
|
|
379
|
-
] }, e.id)) })] })
|
|
380
|
-
})]
|
|
381
|
-
})]
|
|
389
|
+
})
|
|
390
|
+
]
|
|
382
391
|
}), /* @__PURE__ */ h(G, {
|
|
383
392
|
notebookId: q.id,
|
|
384
393
|
open: y,
|
|
@@ -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 EmptyState,\n ErrorState,\n LoadingState,\n PageLayout,\n SafeLink,\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 onEdit={() => navigate(`notebooks/${notebook.id}/edit`)}\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 <div className=\"mt-6 flex flex-wrap items-center gap-2\">\n <SafeLink\n href=\"/conversations\"\n className=\"inline-flex items-center gap-1.5 rounded-button border border-border-default px-3 py-1.5 text-sm text-text-secondary transition-colors hover:bg-bg-sunken hover:text-text-primary\"\n >\n <MessageSquare className=\"size-4\" aria-hidden=\"true\" />\n Discuss in conversations\n </SafeLink>\n </div>\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 { 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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"}
|