@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,460 @@
|
|
|
1
|
+
import { useCosmicIntersection as e } from "../../context/CosmicIntersectionContext.js";
|
|
2
|
+
import { notify as t } from "../../lib/toast.js";
|
|
3
|
+
import { useCosAddSchemaFieldMutation as n, useCosArchiveDatasetMutation as r, useCosDatasetQuery as i, useCosPublishDatasetMutation as ee, useCosUpdateDatasetMutation as te } from "../../api/cosmicApi.js";
|
|
4
|
+
import ne from "../../components/ActionMenu.js";
|
|
5
|
+
import a from "../../components/EmptyState.js";
|
|
6
|
+
import re from "../../components/EntityTagsField.js";
|
|
7
|
+
import ie from "../../components/ErrorState.js";
|
|
8
|
+
import { useFileDownloadUrl as ae } from "../../components/FileUploadField.js";
|
|
9
|
+
import oe from "../../components/LoadingState.js";
|
|
10
|
+
import o from "../../components/PageLayout.js";
|
|
11
|
+
import s from "../../components/SafeLink.js";
|
|
12
|
+
import c, { formatEnumLabel as l } from "../../components/StatusBadge.js";
|
|
13
|
+
import "../../components/index.js";
|
|
14
|
+
import { useState as u } from "react";
|
|
15
|
+
import { jsx as d, jsxs as f } from "react/jsx-runtime";
|
|
16
|
+
import { useParams as se } from "react-router-dom";
|
|
17
|
+
import { Boxes as ce, Columns3 as p, Database as m, Download as le, MessagesSquare as ue, Pencil as de, Plus as fe, Radar as pe } from "lucide-react";
|
|
18
|
+
import { Badge as h, Button as g, Checkbox as me, Dialog as he, DialogContent as ge, DialogDescription as _e, DialogFooter as ve, DialogHeader as ye, DialogTitle as be, Input as _, Label as v, Select as xe, SelectContent as Se, SelectItem as Ce, SelectTrigger as we, SelectValue as Te, Table as Ee, TableBody as De, TableCell as y, TableHead as b, TableHeader as x, TableRow as S, Textarea as C } from "@burdenoff/fe-libs/ui";
|
|
19
|
+
//#region src/cosmicintersection/pages/datasets/DatasetDetailPage.tsx
|
|
20
|
+
var w = [
|
|
21
|
+
"STRING",
|
|
22
|
+
"INTEGER",
|
|
23
|
+
"FLOAT",
|
|
24
|
+
"BOOLEAN",
|
|
25
|
+
"TIMESTAMP",
|
|
26
|
+
"COORDINATE",
|
|
27
|
+
"SPECTRUM",
|
|
28
|
+
"GEOMETRY",
|
|
29
|
+
"IMAGE_REF",
|
|
30
|
+
"JSON"
|
|
31
|
+
];
|
|
32
|
+
function T(e) {
|
|
33
|
+
if (!e) return "—";
|
|
34
|
+
let t = Number(e);
|
|
35
|
+
if (!Number.isFinite(t) || t <= 0) return "—";
|
|
36
|
+
let n = [
|
|
37
|
+
"B",
|
|
38
|
+
"KB",
|
|
39
|
+
"MB",
|
|
40
|
+
"GB",
|
|
41
|
+
"TB",
|
|
42
|
+
"PB"
|
|
43
|
+
], r = t, i = 0;
|
|
44
|
+
for (; r >= 1024 && i < n.length - 1;) r /= 1024, i += 1;
|
|
45
|
+
return `${r >= 10 || i === 0 ? Math.round(r) : r.toFixed(1)} ${n[i]}`;
|
|
46
|
+
}
|
|
47
|
+
function E(e) {
|
|
48
|
+
if (!e) return "—";
|
|
49
|
+
let t = new Date(e);
|
|
50
|
+
return Number.isNaN(t.getTime()) ? "—" : t.toLocaleString();
|
|
51
|
+
}
|
|
52
|
+
function D({ label: e, value: t }) {
|
|
53
|
+
return /* @__PURE__ */ f("div", {
|
|
54
|
+
className: "rounded-card border border-border-default bg-bg-elevated p-4",
|
|
55
|
+
children: [/* @__PURE__ */ d("p", {
|
|
56
|
+
className: "text-xs font-medium uppercase tracking-wide text-text-secondary",
|
|
57
|
+
children: e
|
|
58
|
+
}), /* @__PURE__ */ d("div", {
|
|
59
|
+
className: "mt-1 text-sm text-text-primary",
|
|
60
|
+
children: t
|
|
61
|
+
})]
|
|
62
|
+
});
|
|
63
|
+
}
|
|
64
|
+
function O() {
|
|
65
|
+
let { id: O = "" } = se(), { navigate: k } = e(), { data: Oe, loading: ke, error: Ae, refetch: A } = i(O), j = Oe?.cosDataset ?? null, M = ae(j?.file?.id).data?.getFileDownloadUrl ?? null, [je, { loading: N }] = ee(), [Me] = r(), [Ne, { loading: P }] = te(), [Pe, { loading: F }] = n(), [I, L] = u([]), [Fe, Ie] = u(null), R = j ? `${j.id}:${j.updatedAt}` : null;
|
|
66
|
+
R && R !== Fe && (Ie(R), L(j?.tags ?? []));
|
|
67
|
+
let Le = j != null && (I.length !== j.tags.length || I.some((e, t) => e !== j.tags[t])), [Re, ze] = u(!1), [z, B] = u(""), [V, H] = u("STRING"), [U, W] = u(""), [G, K] = u(""), [q, J] = u(""), [Y, X] = u(!0), Be = () => {
|
|
68
|
+
B(""), H("STRING"), W(""), K(""), J(""), X(!0);
|
|
69
|
+
}, Z = (e) => {
|
|
70
|
+
ze(e), e || Be();
|
|
71
|
+
};
|
|
72
|
+
if (ke) return /* @__PURE__ */ d(o, {
|
|
73
|
+
title: "Dataset",
|
|
74
|
+
backPath: "datasets",
|
|
75
|
+
children: /* @__PURE__ */ d(oe, { label: "Loading dataset…" })
|
|
76
|
+
});
|
|
77
|
+
if (Ae) return /* @__PURE__ */ d(o, {
|
|
78
|
+
title: "Dataset",
|
|
79
|
+
backPath: "datasets",
|
|
80
|
+
children: /* @__PURE__ */ d(ie, {
|
|
81
|
+
message: "We could not load this dataset.",
|
|
82
|
+
onRetry: () => void A()
|
|
83
|
+
})
|
|
84
|
+
});
|
|
85
|
+
if (!j) return /* @__PURE__ */ d(o, {
|
|
86
|
+
title: "Dataset",
|
|
87
|
+
backPath: "datasets",
|
|
88
|
+
children: /* @__PURE__ */ d(a, {
|
|
89
|
+
icon: m,
|
|
90
|
+
title: "Dataset not found.",
|
|
91
|
+
description: "This dataset may have been removed or is outside your current scope.",
|
|
92
|
+
action: /* @__PURE__ */ d(g, {
|
|
93
|
+
type: "button",
|
|
94
|
+
onClick: () => k("datasets"),
|
|
95
|
+
children: "Back to datasets"
|
|
96
|
+
})
|
|
97
|
+
})
|
|
98
|
+
});
|
|
99
|
+
let Q = [...j.schemaFields ?? []].sort((e, t) => e.position - t.position), $ = j.status !== "AVAILABLE" && j.status !== "ARCHIVED", Ve = async () => {
|
|
100
|
+
(await je({ variables: { id: j.id } })).data?.cosPublishDataset && (t.success("Dataset published", `“${j.name}” is now available.`), await A());
|
|
101
|
+
}, He = async () => {
|
|
102
|
+
let e = await Me({ variables: { id: j.id } });
|
|
103
|
+
if (e.error) throw Error(e.error.message);
|
|
104
|
+
if (!e.data?.cosArchiveDataset) throw t.error("Could not archive dataset", "The server did not confirm the change."), Error("Archive not confirmed");
|
|
105
|
+
t.success("Dataset archived"), k("datasets");
|
|
106
|
+
}, Ue = async () => {
|
|
107
|
+
(await Ne({ variables: {
|
|
108
|
+
id: j.id,
|
|
109
|
+
input: { tags: I }
|
|
110
|
+
} })).data?.cosUpdateDataset && (t.success("Tags updated"), await A());
|
|
111
|
+
}, We = async () => {
|
|
112
|
+
if (!z.trim()) {
|
|
113
|
+
t.error("Field name is required");
|
|
114
|
+
return;
|
|
115
|
+
}
|
|
116
|
+
(await Pe({ variables: { input: {
|
|
117
|
+
datasetId: j.id,
|
|
118
|
+
name: z.trim(),
|
|
119
|
+
fieldType: V,
|
|
120
|
+
unit: U.trim() || void 0,
|
|
121
|
+
description: G.trim() || void 0,
|
|
122
|
+
provenance: q.trim() || void 0,
|
|
123
|
+
nullable: Y
|
|
124
|
+
} } })).data?.cosAddSchemaField && (t.success("Schema field added"), Z(!1), await A());
|
|
125
|
+
};
|
|
126
|
+
return /* @__PURE__ */ f(o, {
|
|
127
|
+
title: j.name,
|
|
128
|
+
description: j.description ?? void 0,
|
|
129
|
+
backPath: "datasets",
|
|
130
|
+
actions: /* @__PURE__ */ f("div", {
|
|
131
|
+
className: "flex items-center gap-2",
|
|
132
|
+
children: [
|
|
133
|
+
/* @__PURE__ */ f(g, {
|
|
134
|
+
type: "button",
|
|
135
|
+
variant: "outline",
|
|
136
|
+
onClick: () => k(`datasets/${j.id}/edit`),
|
|
137
|
+
children: [/* @__PURE__ */ d(de, { className: "size-4" }), "Edit"]
|
|
138
|
+
}),
|
|
139
|
+
$ ? /* @__PURE__ */ d(g, {
|
|
140
|
+
type: "button",
|
|
141
|
+
onClick: () => void Ve(),
|
|
142
|
+
disabled: N,
|
|
143
|
+
children: N ? "Publishing…" : "Publish"
|
|
144
|
+
}) : null,
|
|
145
|
+
/* @__PURE__ */ d(ne, {
|
|
146
|
+
ariaLabel: `Actions for ${j.name}`,
|
|
147
|
+
entityName: j.name,
|
|
148
|
+
onDelete: () => He(),
|
|
149
|
+
deleteLabel: "Archive dataset"
|
|
150
|
+
})
|
|
151
|
+
]
|
|
152
|
+
}),
|
|
153
|
+
children: [/* @__PURE__ */ f("div", {
|
|
154
|
+
className: "space-y-6",
|
|
155
|
+
children: [
|
|
156
|
+
/* @__PURE__ */ f("div", {
|
|
157
|
+
className: "flex flex-wrap items-center gap-2",
|
|
158
|
+
children: [
|
|
159
|
+
/* @__PURE__ */ d(c, { status: j.status }),
|
|
160
|
+
/* @__PURE__ */ d(c, {
|
|
161
|
+
status: j.accessLevel,
|
|
162
|
+
label: l(j.accessLevel)
|
|
163
|
+
}),
|
|
164
|
+
j.lineageCaptured ? /* @__PURE__ */ d(h, {
|
|
165
|
+
variant: "secondary",
|
|
166
|
+
children: "Lineage captured"
|
|
167
|
+
}) : null,
|
|
168
|
+
/* @__PURE__ */ f(h, {
|
|
169
|
+
variant: "secondary",
|
|
170
|
+
children: ["v", j.version]
|
|
171
|
+
})
|
|
172
|
+
]
|
|
173
|
+
}),
|
|
174
|
+
/* @__PURE__ */ f("div", {
|
|
175
|
+
className: "grid grid-cols-1 gap-3 sm:grid-cols-2 lg:grid-cols-4",
|
|
176
|
+
children: [
|
|
177
|
+
/* @__PURE__ */ d(D, {
|
|
178
|
+
label: "Source",
|
|
179
|
+
value: j.source ? /* @__PURE__ */ f("button", {
|
|
180
|
+
type: "button",
|
|
181
|
+
onClick: () => k(`sources/${j.source?.id}/edit`),
|
|
182
|
+
className: "inline-flex items-center gap-1.5 text-text-primary underline-offset-2 hover:underline",
|
|
183
|
+
children: [/* @__PURE__ */ d(pe, {
|
|
184
|
+
className: "size-4 text-text-secondary",
|
|
185
|
+
"aria-hidden": "true"
|
|
186
|
+
}), j.source.name]
|
|
187
|
+
}) : /* @__PURE__ */ d("span", {
|
|
188
|
+
className: "text-text-secondary",
|
|
189
|
+
children: "Not linked"
|
|
190
|
+
})
|
|
191
|
+
}),
|
|
192
|
+
/* @__PURE__ */ d(D, {
|
|
193
|
+
label: "Collection",
|
|
194
|
+
value: j.collection ? /* @__PURE__ */ f("button", {
|
|
195
|
+
type: "button",
|
|
196
|
+
onClick: () => k(`collections/${j.collection?.id}`),
|
|
197
|
+
className: "inline-flex items-center gap-1.5 text-text-primary underline-offset-2 hover:underline",
|
|
198
|
+
children: [/* @__PURE__ */ d(ce, {
|
|
199
|
+
className: "size-4 text-text-secondary",
|
|
200
|
+
"aria-hidden": "true"
|
|
201
|
+
}), j.collection.name]
|
|
202
|
+
}) : /* @__PURE__ */ d("span", {
|
|
203
|
+
className: "text-text-secondary",
|
|
204
|
+
children: "Not in a collection"
|
|
205
|
+
})
|
|
206
|
+
}),
|
|
207
|
+
/* @__PURE__ */ d(D, {
|
|
208
|
+
label: "Format",
|
|
209
|
+
value: /* @__PURE__ */ d("span", { children: j.format || "Not specified" })
|
|
210
|
+
}),
|
|
211
|
+
/* @__PURE__ */ d(D, {
|
|
212
|
+
label: "Size",
|
|
213
|
+
value: /* @__PURE__ */ f("span", {
|
|
214
|
+
className: "tabular-nums",
|
|
215
|
+
children: [T(j.sizeBytes), Number(j.rowCount) > 0 ? /* @__PURE__ */ f("span", {
|
|
216
|
+
className: "text-text-secondary",
|
|
217
|
+
children: [
|
|
218
|
+
" ",
|
|
219
|
+
"· ",
|
|
220
|
+
Number(j.rowCount).toLocaleString(),
|
|
221
|
+
" rows"
|
|
222
|
+
]
|
|
223
|
+
}) : null]
|
|
224
|
+
})
|
|
225
|
+
}),
|
|
226
|
+
/* @__PURE__ */ d(D, {
|
|
227
|
+
label: "Ingested",
|
|
228
|
+
value: /* @__PURE__ */ d("span", { children: E(j.ingestedAt) })
|
|
229
|
+
}),
|
|
230
|
+
/* @__PURE__ */ d(D, {
|
|
231
|
+
label: "Created",
|
|
232
|
+
value: /* @__PURE__ */ d("span", { children: E(j.createdAt) })
|
|
233
|
+
}),
|
|
234
|
+
/* @__PURE__ */ d(D, {
|
|
235
|
+
label: "Updated",
|
|
236
|
+
value: /* @__PURE__ */ d("span", { children: E(j.updatedAt) })
|
|
237
|
+
}),
|
|
238
|
+
/* @__PURE__ */ d(D, {
|
|
239
|
+
label: "Artifact",
|
|
240
|
+
value: j.file ? M ? /* @__PURE__ */ f("a", {
|
|
241
|
+
href: M,
|
|
242
|
+
target: "_blank",
|
|
243
|
+
rel: "noopener noreferrer",
|
|
244
|
+
className: "inline-flex items-center gap-1.5 text-text-primary underline-offset-2 hover:underline",
|
|
245
|
+
children: [/* @__PURE__ */ d(le, {
|
|
246
|
+
className: "size-4",
|
|
247
|
+
"aria-hidden": "true"
|
|
248
|
+
}), "Download file"]
|
|
249
|
+
}) : /* @__PURE__ */ d("span", {
|
|
250
|
+
className: "text-text-secondary",
|
|
251
|
+
children: "Resolving link…"
|
|
252
|
+
}) : /* @__PURE__ */ d("span", {
|
|
253
|
+
className: "text-text-secondary",
|
|
254
|
+
children: "No file attached"
|
|
255
|
+
})
|
|
256
|
+
})
|
|
257
|
+
]
|
|
258
|
+
}),
|
|
259
|
+
/* @__PURE__ */ f("section", {
|
|
260
|
+
className: "space-y-3",
|
|
261
|
+
children: [/* @__PURE__ */ f("div", {
|
|
262
|
+
className: "flex items-center justify-between gap-3",
|
|
263
|
+
children: [/* @__PURE__ */ f("div", {
|
|
264
|
+
className: "flex items-center gap-2",
|
|
265
|
+
children: [/* @__PURE__ */ d(p, {
|
|
266
|
+
className: "size-5 text-text-secondary",
|
|
267
|
+
"aria-hidden": "true"
|
|
268
|
+
}), /* @__PURE__ */ d("h2", {
|
|
269
|
+
className: "text-lg font-semibold text-text-primary",
|
|
270
|
+
children: "Schema fields"
|
|
271
|
+
})]
|
|
272
|
+
}), /* @__PURE__ */ f(g, {
|
|
273
|
+
type: "button",
|
|
274
|
+
variant: "outline",
|
|
275
|
+
size: "sm",
|
|
276
|
+
onClick: () => Z(!0),
|
|
277
|
+
children: [/* @__PURE__ */ d(fe, { className: "size-4" }), "Add field"]
|
|
278
|
+
})]
|
|
279
|
+
}), Q.length === 0 ? /* @__PURE__ */ d(a, {
|
|
280
|
+
icon: p,
|
|
281
|
+
title: "No schema fields yet.",
|
|
282
|
+
description: "Describe the columns in this dataset so consumers know what each field means."
|
|
283
|
+
}) : /* @__PURE__ */ d("div", {
|
|
284
|
+
className: "rounded-card border border-border-default bg-bg-elevated",
|
|
285
|
+
children: /* @__PURE__ */ f(Ee, { children: [/* @__PURE__ */ d(x, { children: /* @__PURE__ */ f(S, { children: [
|
|
286
|
+
/* @__PURE__ */ d(b, { children: "Name" }),
|
|
287
|
+
/* @__PURE__ */ d(b, { children: "Type" }),
|
|
288
|
+
/* @__PURE__ */ d(b, { children: "Unit" }),
|
|
289
|
+
/* @__PURE__ */ d(b, { children: "Nullable" }),
|
|
290
|
+
/* @__PURE__ */ d(b, { children: "Provenance" })
|
|
291
|
+
] }) }), /* @__PURE__ */ d(De, { children: Q.map((e) => /* @__PURE__ */ f(S, { children: [
|
|
292
|
+
/* @__PURE__ */ f(y, { children: [/* @__PURE__ */ d("span", {
|
|
293
|
+
className: "font-medium text-text-primary",
|
|
294
|
+
children: e.name
|
|
295
|
+
}), e.description ? /* @__PURE__ */ d("p", {
|
|
296
|
+
className: "mt-0.5 line-clamp-1 max-w-xs text-xs text-text-secondary",
|
|
297
|
+
children: e.description
|
|
298
|
+
}) : null] }),
|
|
299
|
+
/* @__PURE__ */ d(y, { children: /* @__PURE__ */ d(h, {
|
|
300
|
+
variant: "secondary",
|
|
301
|
+
children: l(e.fieldType)
|
|
302
|
+
}) }),
|
|
303
|
+
/* @__PURE__ */ d(y, {
|
|
304
|
+
className: "text-sm text-text-secondary",
|
|
305
|
+
children: e.unit || "—"
|
|
306
|
+
}),
|
|
307
|
+
/* @__PURE__ */ d(y, {
|
|
308
|
+
className: "text-sm text-text-secondary",
|
|
309
|
+
children: e.nullable ? "Yes" : "No"
|
|
310
|
+
}),
|
|
311
|
+
/* @__PURE__ */ d(y, {
|
|
312
|
+
className: "text-sm text-text-secondary",
|
|
313
|
+
children: e.provenance || "—"
|
|
314
|
+
})
|
|
315
|
+
] }, e.id)) })] })
|
|
316
|
+
})]
|
|
317
|
+
}),
|
|
318
|
+
/* @__PURE__ */ f("section", {
|
|
319
|
+
className: "space-y-3 rounded-card border border-border-default bg-bg-elevated p-5",
|
|
320
|
+
children: [/* @__PURE__ */ d(re, {
|
|
321
|
+
value: I,
|
|
322
|
+
onChange: L,
|
|
323
|
+
label: "Dataset tags"
|
|
324
|
+
}), Le ? /* @__PURE__ */ d("div", {
|
|
325
|
+
className: "flex justify-end",
|
|
326
|
+
children: /* @__PURE__ */ d(g, {
|
|
327
|
+
type: "button",
|
|
328
|
+
size: "sm",
|
|
329
|
+
onClick: () => void Ue(),
|
|
330
|
+
disabled: P,
|
|
331
|
+
children: P ? "Saving…" : "Save tags"
|
|
332
|
+
})
|
|
333
|
+
}) : null]
|
|
334
|
+
}),
|
|
335
|
+
/* @__PURE__ */ f("div", {
|
|
336
|
+
className: "flex items-center gap-2 text-sm text-text-secondary",
|
|
337
|
+
children: [
|
|
338
|
+
/* @__PURE__ */ d(ue, {
|
|
339
|
+
className: "size-4",
|
|
340
|
+
"aria-hidden": "true"
|
|
341
|
+
}),
|
|
342
|
+
/* @__PURE__ */ d("span", { children: "Questions about this dataset?" }),
|
|
343
|
+
/* @__PURE__ */ d(s, {
|
|
344
|
+
href: "/conversations",
|
|
345
|
+
className: "text-text-primary underline-offset-2 hover:underline",
|
|
346
|
+
children: "Discuss in conversations"
|
|
347
|
+
})
|
|
348
|
+
]
|
|
349
|
+
})
|
|
350
|
+
]
|
|
351
|
+
}), /* @__PURE__ */ d(he, {
|
|
352
|
+
open: Re,
|
|
353
|
+
onOpenChange: Z,
|
|
354
|
+
children: /* @__PURE__ */ f(ge, { children: [
|
|
355
|
+
/* @__PURE__ */ f(ye, { children: [/* @__PURE__ */ d(be, { children: "Add schema field" }), /* @__PURE__ */ f(_e, { children: [
|
|
356
|
+
"Document a column in “",
|
|
357
|
+
j.name,
|
|
358
|
+
"” — its type, unit and provenance."
|
|
359
|
+
] })] }),
|
|
360
|
+
/* @__PURE__ */ f("div", {
|
|
361
|
+
className: "space-y-4",
|
|
362
|
+
children: [
|
|
363
|
+
/* @__PURE__ */ f("div", {
|
|
364
|
+
className: "space-y-1.5",
|
|
365
|
+
children: [/* @__PURE__ */ d(v, {
|
|
366
|
+
htmlFor: "cos-field-name",
|
|
367
|
+
children: "Name"
|
|
368
|
+
}), /* @__PURE__ */ d(_, {
|
|
369
|
+
id: "cos-field-name",
|
|
370
|
+
value: z,
|
|
371
|
+
onChange: (e) => B(e.target.value),
|
|
372
|
+
placeholder: "e.g. right_ascension",
|
|
373
|
+
required: !0
|
|
374
|
+
})]
|
|
375
|
+
}),
|
|
376
|
+
/* @__PURE__ */ f("div", {
|
|
377
|
+
className: "grid grid-cols-1 gap-4 sm:grid-cols-2",
|
|
378
|
+
children: [/* @__PURE__ */ f("div", {
|
|
379
|
+
className: "space-y-1.5",
|
|
380
|
+
children: [/* @__PURE__ */ d(v, {
|
|
381
|
+
htmlFor: "cos-field-type",
|
|
382
|
+
children: "Type"
|
|
383
|
+
}), /* @__PURE__ */ f(xe, {
|
|
384
|
+
value: V,
|
|
385
|
+
onValueChange: (e) => H(e),
|
|
386
|
+
children: [/* @__PURE__ */ d(we, {
|
|
387
|
+
id: "cos-field-type",
|
|
388
|
+
"aria-label": "Field type",
|
|
389
|
+
children: /* @__PURE__ */ d(Te, {})
|
|
390
|
+
}), /* @__PURE__ */ d(Se, { children: w.map((e) => /* @__PURE__ */ d(Ce, {
|
|
391
|
+
value: e,
|
|
392
|
+
children: l(e)
|
|
393
|
+
}, e)) })]
|
|
394
|
+
})]
|
|
395
|
+
}), /* @__PURE__ */ f("div", {
|
|
396
|
+
className: "space-y-1.5",
|
|
397
|
+
children: [/* @__PURE__ */ d(v, {
|
|
398
|
+
htmlFor: "cos-field-unit",
|
|
399
|
+
children: "Unit"
|
|
400
|
+
}), /* @__PURE__ */ d(_, {
|
|
401
|
+
id: "cos-field-unit",
|
|
402
|
+
value: U,
|
|
403
|
+
onChange: (e) => W(e.target.value),
|
|
404
|
+
placeholder: "e.g. deg, mag, Jy"
|
|
405
|
+
})]
|
|
406
|
+
})]
|
|
407
|
+
}),
|
|
408
|
+
/* @__PURE__ */ f("div", {
|
|
409
|
+
className: "space-y-1.5",
|
|
410
|
+
children: [/* @__PURE__ */ d(v, {
|
|
411
|
+
htmlFor: "cos-field-desc",
|
|
412
|
+
children: "Description"
|
|
413
|
+
}), /* @__PURE__ */ d(C, {
|
|
414
|
+
id: "cos-field-desc",
|
|
415
|
+
value: G,
|
|
416
|
+
onChange: (e) => K(e.target.value),
|
|
417
|
+
rows: 2
|
|
418
|
+
})]
|
|
419
|
+
}),
|
|
420
|
+
/* @__PURE__ */ f("div", {
|
|
421
|
+
className: "space-y-1.5",
|
|
422
|
+
children: [/* @__PURE__ */ d(v, {
|
|
423
|
+
htmlFor: "cos-field-prov",
|
|
424
|
+
children: "Provenance"
|
|
425
|
+
}), /* @__PURE__ */ d(_, {
|
|
426
|
+
id: "cos-field-prov",
|
|
427
|
+
value: q,
|
|
428
|
+
onChange: (e) => J(e.target.value),
|
|
429
|
+
placeholder: "Where this field comes from"
|
|
430
|
+
})]
|
|
431
|
+
}),
|
|
432
|
+
/* @__PURE__ */ f("label", {
|
|
433
|
+
className: "flex items-center gap-2 text-sm text-text-primary",
|
|
434
|
+
children: [/* @__PURE__ */ d(me, {
|
|
435
|
+
checked: Y,
|
|
436
|
+
onCheckedChange: (e) => X(e === !0)
|
|
437
|
+
}), "Nullable (may contain empty values)"]
|
|
438
|
+
})
|
|
439
|
+
]
|
|
440
|
+
}),
|
|
441
|
+
/* @__PURE__ */ f(ve, { children: [/* @__PURE__ */ d(g, {
|
|
442
|
+
type: "button",
|
|
443
|
+
variant: "outline",
|
|
444
|
+
onClick: () => Z(!1),
|
|
445
|
+
disabled: F,
|
|
446
|
+
children: "Cancel"
|
|
447
|
+
}), /* @__PURE__ */ d(g, {
|
|
448
|
+
type: "button",
|
|
449
|
+
onClick: () => void We(),
|
|
450
|
+
disabled: F,
|
|
451
|
+
children: F ? "Adding…" : "Add field"
|
|
452
|
+
})] })
|
|
453
|
+
] })
|
|
454
|
+
})]
|
|
455
|
+
});
|
|
456
|
+
}
|
|
457
|
+
//#endregion
|
|
458
|
+
export { O as default };
|
|
459
|
+
|
|
460
|
+
//# sourceMappingURL=DatasetDetailPage.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"DatasetDetailPage.js","names":[],"sources":["../../../../src/cosmicintersection/pages/datasets/DatasetDetailPage.tsx"],"sourcesContent":["import { useState } from 'react';\nimport { useParams } from 'react-router-dom';\nimport {\n Boxes,\n Columns3,\n Database,\n Download,\n MessagesSquare,\n Pencil,\n Plus,\n Radar,\n} from 'lucide-react';\nimport {\n Badge,\n Button,\n Checkbox,\n Dialog,\n DialogContent,\n DialogDescription,\n DialogFooter,\n DialogHeader,\n DialogTitle,\n Input,\n Label,\n Select,\n SelectContent,\n SelectItem,\n SelectTrigger,\n SelectValue,\n Table,\n TableBody,\n TableCell,\n TableHead,\n TableHeader,\n TableRow,\n Textarea,\n} from '@burdenoff/fe-libs/ui';\n\nimport {\n useCosAddSchemaFieldMutation,\n useCosArchiveDatasetMutation,\n useCosDatasetQuery,\n useCosPublishDatasetMutation,\n useCosUpdateDatasetMutation,\n type CosFieldType,\n} from '../../api/cosmicApi';\nimport {\n ActionMenu,\n EmptyState,\n EntityTagsField,\n ErrorState,\n LoadingState,\n PageLayout,\n SafeLink,\n StatusBadge,\n formatEnumLabel,\n useFileDownloadUrl,\n} from '../../components';\nimport { useCosmicIntersection } from '../../context/CosmicIntersectionContext';\nimport { notify } from '../../lib/toast';\n\nconst FIELD_TYPES: CosFieldType[] = [\n 'STRING',\n 'INTEGER',\n 'FLOAT',\n 'BOOLEAN',\n 'TIMESTAMP',\n 'COORDINATE',\n 'SPECTRUM',\n 'GEOMETRY',\n 'IMAGE_REF',\n 'JSON',\n];\n\nfunction formatBytes(raw: string | null | undefined): string {\n if (!raw) {\n return '—';\n }\n const bytes = Number(raw);\n if (!Number.isFinite(bytes) || bytes <= 0) {\n return '—';\n }\n const units = ['B', 'KB', 'MB', 'GB', 'TB', 'PB'];\n let value = bytes;\n let unit = 0;\n while (value >= 1024 && unit < units.length - 1) {\n value /= 1024;\n unit += 1;\n }\n return `${value >= 10 || unit === 0 ? Math.round(value) : value.toFixed(1)} ${units[unit]}`;\n}\n\nfunction formatDateTime(raw: string | null | undefined): string {\n if (!raw) {\n return '—';\n }\n const date = new Date(raw);\n return Number.isNaN(date.getTime()) ? '—' : date.toLocaleString();\n}\n\nfunction MetaTile({ label, value }: { label: string; value: React.ReactNode }) {\n return (\n <div className=\"rounded-card border border-border-default bg-bg-elevated p-4\">\n <p className=\"text-xs font-medium uppercase tracking-wide text-text-secondary\">{label}</p>\n <div className=\"mt-1 text-sm text-text-primary\">{value}</div>\n </div>\n );\n}\n\nexport default function DatasetDetailPage() {\n const { id = '' } = useParams<{ id: string }>();\n const { navigate } = useCosmicIntersection();\n\n const { data, loading, error, refetch } = useCosDatasetQuery(id);\n const dataset = data?.cosDataset ?? null;\n\n const download = useFileDownloadUrl(dataset?.file?.id);\n const downloadUrl = download.data?.getFileDownloadUrl ?? null;\n\n const [publishDataset, { loading: publishing }] = useCosPublishDatasetMutation();\n const [archiveDataset] = useCosArchiveDatasetMutation();\n const [updateDataset, { loading: savingTags }] = useCosUpdateDatasetMutation();\n const [addSchemaField, { loading: addingField }] = useCosAddSchemaFieldMutation();\n\n // Local, dirty-tracked copy of the tags array so we persist explicitly. Re-sync\n // from the server whenever the dataset (or its updatedAt, after a save) changes\n // — the documented derive-state-during-render pattern, no effect needed.\n const [tags, setTags] = useState<string[]>([]);\n const [syncedKey, setSyncedKey] = useState<string | null>(null);\n const datasetKey = dataset ? `${dataset.id}:${dataset.updatedAt}` : null;\n if (datasetKey && datasetKey !== syncedKey) {\n setSyncedKey(datasetKey);\n setTags(dataset?.tags ?? []);\n }\n const tagsDirty =\n dataset != null &&\n (tags.length !== dataset.tags.length || tags.some((tag, i) => tag !== dataset.tags[i]));\n\n // Add-schema-field dialog state.\n const [fieldOpen, setFieldOpen] = useState(false);\n const [fieldName, setFieldName] = useState('');\n const [fieldType, setFieldType] = useState<CosFieldType>('STRING');\n const [fieldUnit, setFieldUnit] = useState('');\n const [fieldDescription, setFieldDescription] = useState('');\n const [fieldProvenance, setFieldProvenance] = useState('');\n const [fieldNullable, setFieldNullable] = useState(true);\n\n const resetFieldForm = () => {\n setFieldName('');\n setFieldType('STRING');\n setFieldUnit('');\n setFieldDescription('');\n setFieldProvenance('');\n setFieldNullable(true);\n };\n\n const setFieldOpenAndReset = (open: boolean) => {\n setFieldOpen(open);\n if (!open) {\n resetFieldForm();\n }\n };\n\n if (loading) {\n return (\n <PageLayout title=\"Dataset\" backPath=\"datasets\">\n <LoadingState label=\"Loading dataset…\" />\n </PageLayout>\n );\n }\n\n if (error) {\n return (\n <PageLayout title=\"Dataset\" backPath=\"datasets\">\n <ErrorState message=\"We could not load this dataset.\" onRetry={() => void refetch()} />\n </PageLayout>\n );\n }\n\n if (!dataset) {\n return (\n <PageLayout title=\"Dataset\" backPath=\"datasets\">\n <EmptyState\n icon={Database}\n title=\"Dataset not found.\"\n description=\"This dataset may have been removed or is outside your current scope.\"\n action={\n <Button type=\"button\" onClick={() => navigate('datasets')}>\n Back to datasets\n </Button>\n }\n />\n </PageLayout>\n );\n }\n\n const schemaFields = [...(dataset.schemaFields ?? [])].sort((a, b) => a.position - b.position);\n const canPublish = dataset.status !== 'AVAILABLE' && dataset.status !== 'ARCHIVED';\n\n const handlePublish = async () => {\n const response = await publishDataset({ variables: { id: dataset.id } });\n if (response.data?.cosPublishDataset) {\n notify.success('Dataset published', `“${dataset.name}” is now available.`);\n await refetch();\n }\n };\n\n const handleArchive = async () => {\n const response = await archiveDataset({ variables: { id: dataset.id } });\n if (response.error) {\n throw new Error(response.error.message);\n }\n if (!response.data?.cosArchiveDataset) {\n notify.error('Could not archive dataset', 'The server did not confirm the change.');\n throw new Error('Archive not confirmed');\n }\n notify.success('Dataset archived');\n navigate('datasets');\n };\n\n const handleSaveTags = async () => {\n const response = await updateDataset({ variables: { id: dataset.id, input: { tags } } });\n if (response.data?.cosUpdateDataset) {\n notify.success('Tags updated');\n await refetch();\n }\n };\n\n const handleAddField = async () => {\n if (!fieldName.trim()) {\n notify.error('Field name is required');\n return;\n }\n const response = await addSchemaField({\n variables: {\n input: {\n datasetId: dataset.id,\n name: fieldName.trim(),\n fieldType,\n unit: fieldUnit.trim() || undefined,\n description: fieldDescription.trim() || undefined,\n provenance: fieldProvenance.trim() || undefined,\n nullable: fieldNullable,\n },\n },\n });\n if (response.data?.cosAddSchemaField) {\n notify.success('Schema field added');\n setFieldOpenAndReset(false);\n await refetch();\n }\n };\n\n return (\n <PageLayout\n title={dataset.name}\n description={dataset.description ?? undefined}\n backPath=\"datasets\"\n actions={\n <div className=\"flex items-center gap-2\">\n <Button\n type=\"button\"\n variant=\"outline\"\n onClick={() => navigate(`datasets/${dataset.id}/edit`)}\n >\n <Pencil className=\"size-4\" />\n Edit\n </Button>\n {canPublish ? (\n <Button type=\"button\" onClick={() => void handlePublish()} disabled={publishing}>\n {publishing ? 'Publishing…' : 'Publish'}\n </Button>\n ) : null}\n <ActionMenu\n ariaLabel={`Actions for ${dataset.name}`}\n entityName={dataset.name}\n onDelete={() => handleArchive()}\n deleteLabel=\"Archive dataset\"\n />\n </div>\n }\n >\n <div className=\"space-y-6\">\n {/* Status + key facts */}\n <div className=\"flex flex-wrap items-center gap-2\">\n <StatusBadge status={dataset.status} />\n <StatusBadge status={dataset.accessLevel} label={formatEnumLabel(dataset.accessLevel)} />\n {dataset.lineageCaptured ? <Badge variant=\"secondary\">Lineage captured</Badge> : null}\n <Badge variant=\"secondary\">v{dataset.version}</Badge>\n </div>\n\n <div className=\"grid grid-cols-1 gap-3 sm:grid-cols-2 lg:grid-cols-4\">\n <MetaTile\n label=\"Source\"\n value={\n dataset.source ? (\n <button\n type=\"button\"\n onClick={() => navigate(`sources/${dataset.source?.id}/edit`)}\n className=\"inline-flex items-center gap-1.5 text-text-primary underline-offset-2 hover:underline\"\n >\n <Radar className=\"size-4 text-text-secondary\" aria-hidden=\"true\" />\n {dataset.source.name}\n </button>\n ) : (\n <span className=\"text-text-secondary\">Not linked</span>\n )\n }\n />\n <MetaTile\n label=\"Collection\"\n value={\n dataset.collection ? (\n <button\n type=\"button\"\n onClick={() => navigate(`collections/${dataset.collection?.id}`)}\n className=\"inline-flex items-center gap-1.5 text-text-primary underline-offset-2 hover:underline\"\n >\n <Boxes className=\"size-4 text-text-secondary\" aria-hidden=\"true\" />\n {dataset.collection.name}\n </button>\n ) : (\n <span className=\"text-text-secondary\">Not in a collection</span>\n )\n }\n />\n <MetaTile label=\"Format\" value={<span>{dataset.format || 'Not specified'}</span>} />\n <MetaTile\n label=\"Size\"\n value={\n <span className=\"tabular-nums\">\n {formatBytes(dataset.sizeBytes)}\n {Number(dataset.rowCount) > 0 ? (\n <span className=\"text-text-secondary\">\n {' '}\n · {Number(dataset.rowCount).toLocaleString()} rows\n </span>\n ) : null}\n </span>\n }\n />\n <MetaTile label=\"Ingested\" value={<span>{formatDateTime(dataset.ingestedAt)}</span>} />\n <MetaTile label=\"Created\" value={<span>{formatDateTime(dataset.createdAt)}</span>} />\n <MetaTile label=\"Updated\" value={<span>{formatDateTime(dataset.updatedAt)}</span>} />\n <MetaTile\n label=\"Artifact\"\n value={\n dataset.file ? (\n downloadUrl ? (\n <a\n href={downloadUrl}\n target=\"_blank\"\n rel=\"noopener noreferrer\"\n className=\"inline-flex items-center gap-1.5 text-text-primary underline-offset-2 hover:underline\"\n >\n <Download className=\"size-4\" aria-hidden=\"true\" />\n Download file\n </a>\n ) : (\n <span className=\"text-text-secondary\">Resolving link…</span>\n )\n ) : (\n <span className=\"text-text-secondary\">No file attached</span>\n )\n }\n />\n </div>\n\n {/* Schema fields */}\n <section className=\"space-y-3\">\n <div className=\"flex items-center justify-between gap-3\">\n <div className=\"flex items-center gap-2\">\n <Columns3 className=\"size-5 text-text-secondary\" aria-hidden=\"true\" />\n <h2 className=\"text-lg font-semibold text-text-primary\">Schema fields</h2>\n </div>\n <Button\n type=\"button\"\n variant=\"outline\"\n size=\"sm\"\n onClick={() => setFieldOpenAndReset(true)}\n >\n <Plus className=\"size-4\" />\n Add field\n </Button>\n </div>\n\n {schemaFields.length === 0 ? (\n <EmptyState\n icon={Columns3}\n title=\"No schema fields yet.\"\n description=\"Describe the columns in this dataset so consumers know what each field means.\"\n />\n ) : (\n <div className=\"rounded-card border border-border-default bg-bg-elevated\">\n <Table>\n <TableHeader>\n <TableRow>\n <TableHead>Name</TableHead>\n <TableHead>Type</TableHead>\n <TableHead>Unit</TableHead>\n <TableHead>Nullable</TableHead>\n <TableHead>Provenance</TableHead>\n </TableRow>\n </TableHeader>\n <TableBody>\n {schemaFields.map((field) => (\n <TableRow key={field.id}>\n <TableCell>\n <span className=\"font-medium text-text-primary\">{field.name}</span>\n {field.description ? (\n <p className=\"mt-0.5 line-clamp-1 max-w-xs text-xs text-text-secondary\">\n {field.description}\n </p>\n ) : null}\n </TableCell>\n <TableCell>\n <Badge variant=\"secondary\">{formatEnumLabel(field.fieldType)}</Badge>\n </TableCell>\n <TableCell className=\"text-sm text-text-secondary\">\n {field.unit || '—'}\n </TableCell>\n <TableCell className=\"text-sm text-text-secondary\">\n {field.nullable ? 'Yes' : 'No'}\n </TableCell>\n <TableCell className=\"text-sm text-text-secondary\">\n {field.provenance || '—'}\n </TableCell>\n </TableRow>\n ))}\n </TableBody>\n </Table>\n </div>\n )}\n </section>\n\n {/* Tags */}\n <section className=\"space-y-3 rounded-card border border-border-default bg-bg-elevated p-5\">\n <EntityTagsField value={tags} onChange={setTags} label=\"Dataset tags\" />\n {tagsDirty ? (\n <div className=\"flex justify-end\">\n <Button\n type=\"button\"\n size=\"sm\"\n onClick={() => void handleSaveTags()}\n disabled={savingTags}\n >\n {savingTags ? 'Saving…' : 'Save tags'}\n </Button>\n </div>\n ) : null}\n </section>\n\n {/* Discuss */}\n <div className=\"flex items-center gap-2 text-sm text-text-secondary\">\n <MessagesSquare className=\"size-4\" aria-hidden=\"true\" />\n <span>Questions about this dataset?</span>\n <SafeLink\n href=\"/conversations\"\n className=\"text-text-primary underline-offset-2 hover:underline\"\n >\n Discuss in conversations\n </SafeLink>\n </div>\n </div>\n\n {/* Add schema field dialog */}\n <Dialog open={fieldOpen} onOpenChange={setFieldOpenAndReset}>\n <DialogContent>\n <DialogHeader>\n <DialogTitle>Add schema field</DialogTitle>\n <DialogDescription>\n Document a column in “{dataset.name}” — its type, unit and provenance.\n </DialogDescription>\n </DialogHeader>\n\n <div className=\"space-y-4\">\n <div className=\"space-y-1.5\">\n <Label htmlFor=\"cos-field-name\">Name</Label>\n <Input\n id=\"cos-field-name\"\n value={fieldName}\n onChange={(event) => setFieldName(event.target.value)}\n placeholder=\"e.g. right_ascension\"\n required\n />\n </div>\n\n <div className=\"grid grid-cols-1 gap-4 sm:grid-cols-2\">\n <div className=\"space-y-1.5\">\n <Label htmlFor=\"cos-field-type\">Type</Label>\n <Select\n value={fieldType}\n onValueChange={(value) => setFieldType(value as CosFieldType)}\n >\n <SelectTrigger id=\"cos-field-type\" aria-label=\"Field type\">\n <SelectValue />\n </SelectTrigger>\n <SelectContent>\n {FIELD_TYPES.map((type) => (\n <SelectItem key={type} value={type}>\n {formatEnumLabel(type)}\n </SelectItem>\n ))}\n </SelectContent>\n </Select>\n </div>\n <div className=\"space-y-1.5\">\n <Label htmlFor=\"cos-field-unit\">Unit</Label>\n <Input\n id=\"cos-field-unit\"\n value={fieldUnit}\n onChange={(event) => setFieldUnit(event.target.value)}\n placeholder=\"e.g. deg, mag, Jy\"\n />\n </div>\n </div>\n\n <div className=\"space-y-1.5\">\n <Label htmlFor=\"cos-field-desc\">Description</Label>\n <Textarea\n id=\"cos-field-desc\"\n value={fieldDescription}\n onChange={(event) => setFieldDescription(event.target.value)}\n rows={2}\n />\n </div>\n\n <div className=\"space-y-1.5\">\n <Label htmlFor=\"cos-field-prov\">Provenance</Label>\n <Input\n id=\"cos-field-prov\"\n value={fieldProvenance}\n onChange={(event) => setFieldProvenance(event.target.value)}\n placeholder=\"Where this field comes from\"\n />\n </div>\n\n <label className=\"flex items-center gap-2 text-sm text-text-primary\">\n <Checkbox\n checked={fieldNullable}\n onCheckedChange={(checked) => setFieldNullable(checked === true)}\n />\n Nullable (may contain empty values)\n </label>\n </div>\n\n <DialogFooter>\n <Button\n type=\"button\"\n variant=\"outline\"\n onClick={() => setFieldOpenAndReset(false)}\n disabled={addingField}\n >\n Cancel\n </Button>\n <Button type=\"button\" onClick={() => void handleAddField()} disabled={addingField}>\n {addingField ? 'Adding…' : 'Add field'}\n </Button>\n </DialogFooter>\n </DialogContent>\n </Dialog>\n </PageLayout>\n );\n}\n"],"mappings":"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"}
|