@burdenoff/microfe-cosmicintersection 2026.704.2 → 2026.704.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (50) hide show
  1. package/dist/cosmicintersection/CosmicIntersectionRoutes.js +39 -27
  2. package/dist/cosmicintersection/CosmicIntersectionRoutes.js.map +1 -1
  3. package/dist/cosmicintersection/api/cosmicApi.js +6 -0
  4. package/dist/cosmicintersection/api/cosmicApi.js.map +1 -1
  5. package/dist/cosmicintersection/components/FacetPanel.js +66 -0
  6. package/dist/cosmicintersection/components/FacetPanel.js.map +1 -0
  7. package/dist/cosmicintersection/components/LineageGraph.js +388 -0
  8. package/dist/cosmicintersection/components/LineageGraph.js.map +1 -0
  9. package/dist/cosmicintersection/components/ResultsChart.js +329 -0
  10. package/dist/cosmicintersection/components/ResultsChart.js.map +1 -0
  11. package/dist/cosmicintersection/components/StepDAG.js +104 -0
  12. package/dist/cosmicintersection/components/StepDAG.js.map +1 -0
  13. package/dist/cosmicintersection/pages/access/AccessPage.js +207 -155
  14. package/dist/cosmicintersection/pages/access/AccessPage.js.map +1 -1
  15. package/dist/cosmicintersection/pages/analyses/AnalysesPage.js +325 -165
  16. package/dist/cosmicintersection/pages/analyses/AnalysesPage.js.map +1 -1
  17. package/dist/cosmicintersection/pages/collections/CollectionDetailPage.js +138 -93
  18. package/dist/cosmicintersection/pages/collections/CollectionDetailPage.js.map +1 -1
  19. package/dist/cosmicintersection/pages/collections/CollectionFormPage.js.map +1 -1
  20. package/dist/cosmicintersection/pages/dashboard/DashboardPage.js +26 -15
  21. package/dist/cosmicintersection/pages/dashboard/DashboardPage.js.map +1 -1
  22. package/dist/cosmicintersection/pages/datasets/DatasetDetailPage.js +345 -219
  23. package/dist/cosmicintersection/pages/datasets/DatasetDetailPage.js.map +1 -1
  24. package/dist/cosmicintersection/pages/datasets/DatasetsPage.js +321 -163
  25. package/dist/cosmicintersection/pages/datasets/DatasetsPage.js.map +1 -1
  26. package/dist/cosmicintersection/pages/discovery/DiscoveryPage.js +358 -0
  27. package/dist/cosmicintersection/pages/discovery/DiscoveryPage.js.map +1 -0
  28. package/dist/cosmicintersection/pages/lineage/LineagePage.js +171 -0
  29. package/dist/cosmicintersection/pages/lineage/LineagePage.js.map +1 -0
  30. package/dist/cosmicintersection/pages/notebooks/NotebookDetailPage.js +232 -162
  31. package/dist/cosmicintersection/pages/notebooks/NotebookDetailPage.js.map +1 -1
  32. package/dist/cosmicintersection/pages/notebooks/NotebooksPage.js +143 -82
  33. package/dist/cosmicintersection/pages/notebooks/NotebooksPage.js.map +1 -1
  34. package/dist/cosmicintersection/pages/pipelines/PipelineDetailPage.js +286 -142
  35. package/dist/cosmicintersection/pages/pipelines/PipelineDetailPage.js.map +1 -1
  36. package/dist/cosmicintersection/pages/pipelines/PipelineFormPage.js +305 -103
  37. package/dist/cosmicintersection/pages/pipelines/PipelineFormPage.js.map +1 -1
  38. package/dist/cosmicintersection/pages/pipelines/PipelinesPage.js +183 -79
  39. package/dist/cosmicintersection/pages/pipelines/PipelinesPage.js.map +1 -1
  40. package/dist/cosmicintersection/pages/releases/ReleasesPage.js +262 -170
  41. package/dist/cosmicintersection/pages/releases/ReleasesPage.js.map +1 -1
  42. package/dist/cosmicintersection/pages/runs/RunDetailPage.js +179 -136
  43. package/dist/cosmicintersection/pages/runs/RunDetailPage.js.map +1 -1
  44. package/dist/cosmicintersection/pages/runs/RunsPage.js +124 -47
  45. package/dist/cosmicintersection/pages/runs/RunsPage.js.map +1 -1
  46. package/dist/cosmicintersection/pages/sources/SourceDetailPage.js +114 -85
  47. package/dist/cosmicintersection/pages/sources/SourceDetailPage.js.map +1 -1
  48. package/dist/cosmicintersection/pages/sources/SourcesPage.js +263 -152
  49. package/dist/cosmicintersection/pages/sources/SourcesPage.js.map +1 -1
  50. package/package.json +1 -1
@@ -9,17 +9,17 @@ import l from "../../components/SafeLink.js";
9
9
  import u from "../../components/PageLayout.js";
10
10
  import d, { formatEnumLabel as f } from "../../components/StatusBadge.js";
11
11
  import "../../components/index.js";
12
- import { jsx as p, jsxs as m } from "react/jsx-runtime";
13
- import { useParams as h } from "react-router-dom";
14
- import { Database as g, Download as _, Pencil as v, Radio as y, RefreshCw as b } from "lucide-react";
15
- import { Badge as x, Button as S, Table as C, TableBody as w, TableCell as T, TableHead as E, TableHeader as D, TableRow as O } from "@burdenoff/fe-libs/ui";
12
+ import { Fragment as p, jsx as m, jsxs as h } from "react/jsx-runtime";
13
+ import { useParams as g } from "react-router-dom";
14
+ import { Database as _, Download as v, Pencil as y, Radio as b, RefreshCw as x } from "lucide-react";
15
+ import { Badge as S, Button as C, Table as w, TableBody as T, TableCell as E, TableHead as D, TableHeader as O, TableRow as k } from "@burdenoff/fe-libs/ui";
16
16
  //#region src/cosmicintersection/pages/sources/SourceDetailPage.tsx
17
- function k(e) {
17
+ function A(e) {
18
18
  if (!e) return "—";
19
19
  let t = new Date(e);
20
20
  return Number.isNaN(t.getTime()) ? "—" : t.toLocaleString();
21
21
  }
22
- function A(e) {
22
+ function j(e) {
23
23
  if (!e) return "—";
24
24
  let t = new Date(e);
25
25
  return Number.isNaN(t.getTime()) ? "—" : t.toLocaleDateString(void 0, {
@@ -28,178 +28,207 @@ function A(e) {
28
28
  day: "numeric"
29
29
  });
30
30
  }
31
- function j({ label: e, value: t }) {
32
- return /* @__PURE__ */ m("div", {
31
+ function M({ label: e, value: t }) {
32
+ return /* @__PURE__ */ h("div", {
33
33
  className: "rounded-card border border-border-default bg-bg-elevated p-4",
34
- children: [/* @__PURE__ */ p("p", {
34
+ children: [/* @__PURE__ */ m("p", {
35
35
  className: "text-xs font-medium uppercase tracking-wide text-text-secondary",
36
36
  children: e
37
- }), /* @__PURE__ */ p("div", {
37
+ }), /* @__PURE__ */ m("div", {
38
38
  className: "mt-1 text-sm text-text-primary",
39
39
  children: t
40
40
  })]
41
41
  });
42
42
  }
43
- function M() {
44
- let { id: M = "" } = h(), { navigate: N } = e(), { data: P, loading: F, error: I, refetch: L } = i(M), R = P?.cosSource ?? null, [z, { loading: B }] = r(), [V] = n(), H = async () => {
45
- R && (await z({ variables: { id: R.id } })).data?.cosMarkSourceSynced && (t.success("Source marked synced", `“${R.name}” is now up to date.`), await L());
46
- }, U = async () => {
47
- if (!R) return;
48
- let e = await V({ variables: { id: R.id } });
43
+ function N() {
44
+ let { id: N = "" } = g(), { navigate: P } = e(), { data: F, loading: I, error: L, refetch: R } = i(N), z = F?.cosSource ?? null, [B, { loading: V }] = r(), [H] = n(), U = async () => {
45
+ z && (await B({ variables: { id: z.id } })).data?.cosMarkSourceSynced && (t.success("Source marked synced", `“${z.name}” is now up to date.`), await R());
46
+ }, W = async () => {
47
+ if (!z) return;
48
+ let e = await H({ variables: { id: z.id } });
49
49
  if (e.error) throw Error(e.error.message);
50
50
  if (!e.data?.cosArchiveSource) throw t.error("Could not archive source", "The server did not confirm the change."), Error("Archive not confirmed");
51
- t.success("Source archived"), N("sources");
51
+ t.success("Source archived"), P("sources");
52
52
  };
53
- if (F) return /* @__PURE__ */ p(u, {
53
+ if (I) return /* @__PURE__ */ m(u, {
54
54
  title: "Source",
55
55
  backPath: "sources",
56
- children: /* @__PURE__ */ p(c, { label: "Loading source…" })
56
+ children: /* @__PURE__ */ m(c, { label: "Loading source…" })
57
57
  });
58
- if (I) return /* @__PURE__ */ p(u, {
58
+ if (L) return /* @__PURE__ */ m(u, {
59
59
  title: "Source",
60
60
  backPath: "sources",
61
- children: /* @__PURE__ */ p(s, {
61
+ children: /* @__PURE__ */ m(s, {
62
62
  message: "We could not load this source.",
63
- onRetry: () => void L()
63
+ onRetry: () => void R()
64
64
  })
65
65
  });
66
- if (!R) return /* @__PURE__ */ p(u, {
66
+ if (!z) return /* @__PURE__ */ m(u, {
67
67
  title: "Source",
68
68
  backPath: "sources",
69
- children: /* @__PURE__ */ p(o, {
70
- icon: y,
69
+ children: /* @__PURE__ */ m(o, {
70
+ icon: b,
71
71
  title: "Source not found.",
72
72
  description: "This source may have been removed or is outside your current scope.",
73
- action: /* @__PURE__ */ p(S, {
73
+ action: /* @__PURE__ */ m(C, {
74
74
  type: "button",
75
- onClick: () => N("sources"),
75
+ onClick: () => P("sources"),
76
76
  children: "Back to sources"
77
77
  })
78
78
  })
79
79
  });
80
- let W = R.datasets ?? [];
81
- return /* @__PURE__ */ p(u, {
82
- title: R.name,
83
- description: R.description ?? void 0,
80
+ let G = z.datasets ?? [];
81
+ return /* @__PURE__ */ m(u, {
82
+ title: z.name,
83
+ description: z.description ?? void 0,
84
84
  backPath: "sources",
85
- actions: /* @__PURE__ */ m("div", {
85
+ actions: /* @__PURE__ */ h("div", {
86
86
  className: "flex items-center gap-2",
87
- children: [/* @__PURE__ */ m(S, {
87
+ children: [/* @__PURE__ */ h(C, {
88
88
  type: "button",
89
89
  variant: "outline",
90
- onClick: () => N(`sources/${R.id}/edit`),
91
- children: [/* @__PURE__ */ p(v, { className: "size-4" }), "Edit"]
92
- }), /* @__PURE__ */ p(a, {
93
- ariaLabel: `Actions for ${R.name}`,
94
- entityName: R.name,
95
- onDelete: () => U(),
90
+ onClick: () => P(`sources/${z.id}/edit`),
91
+ children: [/* @__PURE__ */ m(y, { className: "size-4" }), "Edit"]
92
+ }), /* @__PURE__ */ m(a, {
93
+ ariaLabel: `Actions for ${z.name}`,
94
+ entityName: z.name,
95
+ onDelete: () => W(),
96
96
  deleteLabel: "Archive source",
97
97
  extraItems: [{
98
98
  key: "mark-synced",
99
- label: B ? "Marking synced…" : "Mark synced",
100
- icon: b,
101
- disabled: B,
102
- onSelect: () => void H()
99
+ label: V ? "Marking synced…" : "Mark synced",
100
+ icon: x,
101
+ disabled: V,
102
+ onSelect: () => void U()
103
103
  }]
104
104
  })]
105
105
  }),
106
- children: /* @__PURE__ */ m("div", {
106
+ children: /* @__PURE__ */ h("div", {
107
107
  className: "space-y-6",
108
108
  children: [
109
- /* @__PURE__ */ m("div", {
109
+ /* @__PURE__ */ h("div", {
110
110
  className: "flex flex-wrap items-center gap-2",
111
- children: [/* @__PURE__ */ p(d, { status: R.status }), /* @__PURE__ */ p(x, {
111
+ children: [/* @__PURE__ */ m(d, { status: z.status }), /* @__PURE__ */ m(S, {
112
112
  variant: "secondary",
113
- children: f(R.type)
113
+ children: f(z.type)
114
114
  })]
115
115
  }),
116
- /* @__PURE__ */ m("div", {
116
+ /* @__PURE__ */ h("div", {
117
117
  className: "grid grid-cols-1 gap-3 sm:grid-cols-2 lg:grid-cols-4",
118
118
  children: [
119
- /* @__PURE__ */ p(j, {
119
+ /* @__PURE__ */ m(M, {
120
120
  label: "Endpoint",
121
- value: R.endpoint ? /* @__PURE__ */ m(l, {
122
- href: R.endpoint,
121
+ value: z.endpoint ? /* @__PURE__ */ h(l, {
122
+ href: z.endpoint,
123
123
  className: "inline-flex items-center gap-1.5 truncate text-text-primary underline-offset-2 hover:underline",
124
124
  fallbackClassName: "truncate text-text-secondary",
125
- children: [/* @__PURE__ */ p(_, {
125
+ children: [/* @__PURE__ */ m(v, {
126
126
  className: "size-4 shrink-0 text-text-secondary",
127
127
  "aria-hidden": "true"
128
- }), /* @__PURE__ */ p("span", {
128
+ }), /* @__PURE__ */ m("span", {
129
129
  className: "truncate",
130
- children: R.endpoint
130
+ children: z.endpoint
131
131
  })]
132
- }) : /* @__PURE__ */ p("span", {
132
+ }) : /* @__PURE__ */ m("span", {
133
133
  className: "text-text-secondary",
134
134
  children: "Not set"
135
135
  })
136
136
  }),
137
- /* @__PURE__ */ p(j, {
137
+ /* @__PURE__ */ m(M, {
138
138
  label: "Last synced",
139
- value: /* @__PURE__ */ p("span", { children: k(R.lastSyncedAt) })
139
+ value: /* @__PURE__ */ m("span", { children: A(z.lastSyncedAt) })
140
140
  }),
141
- /* @__PURE__ */ p(j, {
141
+ /* @__PURE__ */ m(M, {
142
142
  label: "Created",
143
- value: /* @__PURE__ */ p("span", { children: k(R.createdAt) })
143
+ value: /* @__PURE__ */ m("span", { children: A(z.createdAt) })
144
144
  }),
145
- /* @__PURE__ */ p(j, {
145
+ /* @__PURE__ */ m(M, {
146
146
  label: "Updated",
147
- value: /* @__PURE__ */ p("span", { children: k(R.updatedAt) })
147
+ value: /* @__PURE__ */ m("span", { children: A(z.updatedAt) })
148
148
  })
149
149
  ]
150
150
  }),
151
- R.tags.length > 0 ? /* @__PURE__ */ p("div", {
151
+ z.tags.length > 0 ? /* @__PURE__ */ m("div", {
152
152
  className: "flex flex-wrap gap-1",
153
- children: R.tags.map((e) => /* @__PURE__ */ p(x, {
153
+ children: z.tags.map((e) => /* @__PURE__ */ m(S, {
154
154
  variant: "outline",
155
155
  className: "text-xs",
156
156
  children: e
157
157
  }, e))
158
158
  }) : null,
159
- /* @__PURE__ */ m("section", {
159
+ /* @__PURE__ */ h("section", {
160
160
  className: "space-y-3",
161
- children: [/* @__PURE__ */ p("h2", {
161
+ children: [/* @__PURE__ */ m("h2", {
162
162
  className: "text-lg font-semibold text-text-primary",
163
163
  children: "Datasets from this source"
164
- }), W.length === 0 ? /* @__PURE__ */ p(o, {
165
- icon: g,
164
+ }), G.length === 0 ? /* @__PURE__ */ m(o, {
165
+ icon: _,
166
166
  title: "No datasets from this source yet",
167
167
  description: "Datasets that ingest from this source will be listed here."
168
- }) : /* @__PURE__ */ p("div", {
169
- className: "overflow-hidden rounded-card border border-border-default bg-bg-elevated",
170
- children: /* @__PURE__ */ m(C, { children: [/* @__PURE__ */ p(D, { children: /* @__PURE__ */ m(O, { children: [
171
- /* @__PURE__ */ p(E, { children: "Name" }),
172
- /* @__PURE__ */ p(E, { children: "Status" }),
173
- /* @__PURE__ */ p(E, { children: "Access" }),
174
- /* @__PURE__ */ p(E, { children: "Rows" }),
175
- /* @__PURE__ */ p(E, { children: "Updated" })
176
- ] }) }), /* @__PURE__ */ p(w, { children: W.map((e) => /* @__PURE__ */ m(O, {
168
+ }) : /* @__PURE__ */ h(p, { children: [/* @__PURE__ */ m("div", {
169
+ className: "hidden overflow-hidden rounded-card border border-border-default bg-bg-elevated md:block",
170
+ children: /* @__PURE__ */ h(w, { children: [/* @__PURE__ */ m(O, { children: /* @__PURE__ */ h(k, { children: [
171
+ /* @__PURE__ */ m(D, { children: "Name" }),
172
+ /* @__PURE__ */ m(D, { children: "Status" }),
173
+ /* @__PURE__ */ m(D, { children: "Access" }),
174
+ /* @__PURE__ */ m(D, { children: "Rows" }),
175
+ /* @__PURE__ */ m(D, { children: "Updated" })
176
+ ] }) }), /* @__PURE__ */ m(T, { children: G.map((e) => /* @__PURE__ */ h(k, {
177
177
  className: "cursor-pointer",
178
- onClick: () => N(`datasets/${e.id}`),
178
+ onClick: () => P(`datasets/${e.id}`),
179
179
  children: [
180
- /* @__PURE__ */ p(T, {
180
+ /* @__PURE__ */ m(E, {
181
181
  className: "font-medium text-text-primary",
182
182
  children: e.name
183
183
  }),
184
- /* @__PURE__ */ p(T, { children: /* @__PURE__ */ p(d, { status: e.status }) }),
185
- /* @__PURE__ */ p(T, { children: /* @__PURE__ */ p(d, { status: e.accessLevel }) }),
186
- /* @__PURE__ */ p(T, {
184
+ /* @__PURE__ */ m(E, { children: /* @__PURE__ */ m(d, { status: e.status }) }),
185
+ /* @__PURE__ */ m(E, { children: /* @__PURE__ */ m(d, { status: e.accessLevel }) }),
186
+ /* @__PURE__ */ m(E, {
187
187
  className: "tabular-nums text-sm text-text-secondary",
188
188
  children: Number(e.rowCount) > 0 ? Number(e.rowCount).toLocaleString() : "—"
189
189
  }),
190
- /* @__PURE__ */ p(T, {
190
+ /* @__PURE__ */ m(E, {
191
191
  className: "whitespace-nowrap text-sm text-text-secondary",
192
- children: A(e.updatedAt)
192
+ children: j(e.updatedAt)
193
193
  })
194
194
  ]
195
195
  }, e.id)) })] })
196
- })]
196
+ }), /* @__PURE__ */ m("ul", {
197
+ className: "space-y-3 md:hidden",
198
+ children: G.map((e) => /* @__PURE__ */ m("li", { children: /* @__PURE__ */ h("div", {
199
+ role: "button",
200
+ tabIndex: 0,
201
+ "aria-label": `Open ${e.name}`,
202
+ onClick: () => P(`datasets/${e.id}`),
203
+ onKeyDown: (t) => {
204
+ (t.key === "Enter" || t.key === " ") && (t.preventDefault(), P(`datasets/${e.id}`));
205
+ },
206
+ className: "flex flex-col gap-2 rounded-card border border-border-default bg-bg-elevated p-4 outline-none transition-colors hover:bg-bg-sunken focus-visible:ring-2 focus-visible:ring-border-focus",
207
+ children: [
208
+ /* @__PURE__ */ m("p", {
209
+ className: "font-medium text-text-primary",
210
+ children: e.name
211
+ }),
212
+ /* @__PURE__ */ h("div", {
213
+ className: "flex flex-wrap items-center gap-1.5",
214
+ children: [/* @__PURE__ */ m(d, { status: e.status }), /* @__PURE__ */ m(d, { status: e.accessLevel })]
215
+ }),
216
+ /* @__PURE__ */ h("div", {
217
+ className: "flex items-center justify-between gap-2 text-xs text-text-secondary",
218
+ children: [/* @__PURE__ */ m("span", {
219
+ className: "tabular-nums",
220
+ children: Number(e.rowCount) > 0 ? `${Number(e.rowCount).toLocaleString()} rows` : "No rows"
221
+ }), /* @__PURE__ */ m("span", { children: j(e.updatedAt) })]
222
+ })
223
+ ]
224
+ }) }, e.id))
225
+ })] })]
197
226
  })
198
227
  ]
199
228
  })
200
229
  });
201
230
  }
202
231
  //#endregion
203
- export { M as default };
232
+ export { N as default };
204
233
 
205
234
  //# sourceMappingURL=SourceDetailPage.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"SourceDetailPage.js","names":[],"sources":["../../../../src/cosmicintersection/pages/sources/SourceDetailPage.tsx"],"sourcesContent":["/**\n * SourceDetailPage — full record for one data source.\n *\n * Mirrors CollectionDetailPage: a header with the source's metadata (type/status\n * badges, endpoint, last-synced, tags) over a table of the datasets ingested from\n * this source. Header actions edit the source, mark it synced\n * (`cosMarkSourceSynced`) or archive it (`cosArchiveSource`). Everything is read\n * from the backend — no fabricated data.\n */\nimport { Database, Download, Pencil, Radio, RefreshCw } from 'lucide-react';\nimport {\n Badge,\n Button,\n Table,\n TableBody,\n TableCell,\n TableHead,\n TableHeader,\n TableRow,\n} from '@burdenoff/fe-libs/ui';\nimport { useParams } from 'react-router-dom';\n\nimport {\n useCosArchiveSourceMutation,\n useCosMarkSourceSyncedMutation,\n useCosSourceQuery,\n} from '../../api/cosmicApi';\nimport {\n ActionMenu,\n EmptyState,\n ErrorState,\n LoadingState,\n PageLayout,\n SafeLink,\n StatusBadge,\n formatEnumLabel,\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 return Number.isNaN(date.getTime()) ? '—' : date.toLocaleString();\n}\n\nfunction formatDate(value?: string | null): string {\n if (!value) {\n return '—';\n }\n const parsed = new Date(value);\n if (Number.isNaN(parsed.getTime())) {\n return '—';\n }\n return parsed.toLocaleDateString(undefined, { year: 'numeric', month: 'short', day: 'numeric' });\n}\n\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 SourceDetailPage() {\n const { id = '' } = useParams<{ id: string }>();\n const { navigate } = useCosmicIntersection();\n\n const { data, loading, error, refetch } = useCosSourceQuery(id);\n const source = data?.cosSource ?? null;\n\n const [markSynced, { loading: syncing }] = useCosMarkSourceSyncedMutation();\n const [archiveSource] = useCosArchiveSourceMutation();\n\n const handleMarkSynced = async () => {\n if (!source) {\n return;\n }\n const response = await markSynced({ variables: { id: source.id } });\n if (response.data?.cosMarkSourceSynced) {\n notify.success('Source marked synced', `“${source.name}” is now up to date.`);\n await refetch();\n }\n };\n\n const handleArchive = async () => {\n if (!source) {\n return;\n }\n const response = await archiveSource({ variables: { id: source.id } });\n if (response.error) {\n throw new Error(response.error.message);\n }\n if (!response.data?.cosArchiveSource) {\n notify.error('Could not archive source', 'The server did not confirm the change.');\n throw new Error('Archive not confirmed');\n }\n notify.success('Source archived');\n navigate('sources');\n };\n\n if (loading) {\n return (\n <PageLayout title=\"Source\" backPath=\"sources\">\n <LoadingState label=\"Loading source…\" />\n </PageLayout>\n );\n }\n\n if (error) {\n return (\n <PageLayout title=\"Source\" backPath=\"sources\">\n <ErrorState message=\"We could not load this source.\" onRetry={() => void refetch()} />\n </PageLayout>\n );\n }\n\n if (!source) {\n return (\n <PageLayout title=\"Source\" backPath=\"sources\">\n <EmptyState\n icon={Radio}\n title=\"Source not found.\"\n description=\"This source may have been removed or is outside your current scope.\"\n action={\n <Button type=\"button\" onClick={() => navigate('sources')}>\n Back to sources\n </Button>\n }\n />\n </PageLayout>\n );\n }\n\n const datasets = source.datasets ?? [];\n\n const renderDatasets = () => {\n if (datasets.length === 0) {\n return (\n <EmptyState\n icon={Database}\n title=\"No datasets from this source yet\"\n description=\"Datasets that ingest from this source will be listed here.\"\n />\n );\n }\n return (\n <div className=\"overflow-hidden rounded-card border border-border-default bg-bg-elevated\">\n <Table>\n <TableHeader>\n <TableRow>\n <TableHead>Name</TableHead>\n <TableHead>Status</TableHead>\n <TableHead>Access</TableHead>\n <TableHead>Rows</TableHead>\n <TableHead>Updated</TableHead>\n </TableRow>\n </TableHeader>\n <TableBody>\n {datasets.map((dataset) => (\n <TableRow\n key={dataset.id}\n className=\"cursor-pointer\"\n onClick={() => navigate(`datasets/${dataset.id}`)}\n >\n <TableCell className=\"font-medium text-text-primary\">{dataset.name}</TableCell>\n <TableCell>\n <StatusBadge status={dataset.status} />\n </TableCell>\n <TableCell>\n <StatusBadge status={dataset.accessLevel} />\n </TableCell>\n <TableCell className=\"tabular-nums text-sm text-text-secondary\">\n {Number(dataset.rowCount) > 0\n ? Number(dataset.rowCount).toLocaleString()\n : '—'}\n </TableCell>\n <TableCell className=\"whitespace-nowrap text-sm text-text-secondary\">\n {formatDate(dataset.updatedAt)}\n </TableCell>\n </TableRow>\n ))}\n </TableBody>\n </Table>\n </div>\n );\n };\n\n return (\n <PageLayout\n title={source.name}\n description={source.description ?? undefined}\n backPath=\"sources\"\n actions={\n <div className=\"flex items-center gap-2\">\n <Button\n type=\"button\"\n variant=\"outline\"\n onClick={() => navigate(`sources/${source.id}/edit`)}\n >\n <Pencil className=\"size-4\" />\n Edit\n </Button>\n <ActionMenu\n ariaLabel={`Actions for ${source.name}`}\n entityName={source.name}\n onDelete={() => handleArchive()}\n deleteLabel=\"Archive source\"\n extraItems={[\n {\n key: 'mark-synced',\n label: syncing ? 'Marking synced…' : 'Mark synced',\n icon: RefreshCw,\n disabled: syncing,\n onSelect: () => void handleMarkSynced(),\n },\n ]}\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={source.status} />\n <Badge variant=\"secondary\">{formatEnumLabel(source.type)}</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=\"Endpoint\"\n value={\n source.endpoint ? (\n <SafeLink\n href={source.endpoint}\n className=\"inline-flex items-center gap-1.5 truncate text-text-primary underline-offset-2 hover:underline\"\n fallbackClassName=\"truncate text-text-secondary\"\n >\n <Download className=\"size-4 shrink-0 text-text-secondary\" aria-hidden=\"true\" />\n <span className=\"truncate\">{source.endpoint}</span>\n </SafeLink>\n ) : (\n <span className=\"text-text-secondary\">Not set</span>\n )\n }\n />\n <MetaTile label=\"Last synced\" value={<span>{formatDateTime(source.lastSyncedAt)}</span>} />\n <MetaTile label=\"Created\" value={<span>{formatDateTime(source.createdAt)}</span>} />\n <MetaTile label=\"Updated\" value={<span>{formatDateTime(source.updatedAt)}</span>} />\n </div>\n\n {source.tags.length > 0 ? (\n <div className=\"flex flex-wrap gap-1\">\n {source.tags.map((tag) => (\n <Badge key={tag} variant=\"outline\" className=\"text-xs\">\n {tag}\n </Badge>\n ))}\n </div>\n ) : null}\n\n {/* Datasets */}\n <section className=\"space-y-3\">\n <h2 className=\"text-lg font-semibold text-text-primary\">Datasets from this source</h2>\n {renderDatasets()}\n </section>\n </div>\n </PageLayout>\n );\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"SourceDetailPage.js","names":[],"sources":["../../../../src/cosmicintersection/pages/sources/SourceDetailPage.tsx"],"sourcesContent":["/**\n * SourceDetailPage — full record for one data source.\n *\n * Mirrors CollectionDetailPage: a header with the source's metadata (type/status\n * badges, endpoint, last-synced, tags) over a table of the datasets ingested from\n * this source. Header actions edit the source, mark it synced\n * (`cosMarkSourceSynced`) or archive it (`cosArchiveSource`). Everything is read\n * from the backend — no fabricated data.\n */\nimport { Database, Download, Pencil, Radio, RefreshCw } from 'lucide-react';\nimport {\n Badge,\n Button,\n Table,\n TableBody,\n TableCell,\n TableHead,\n TableHeader,\n TableRow,\n} from '@burdenoff/fe-libs/ui';\nimport { useParams } from 'react-router-dom';\n\nimport {\n useCosArchiveSourceMutation,\n useCosMarkSourceSyncedMutation,\n useCosSourceQuery,\n} from '../../api/cosmicApi';\nimport {\n ActionMenu,\n EmptyState,\n ErrorState,\n LoadingState,\n PageLayout,\n SafeLink,\n StatusBadge,\n formatEnumLabel,\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 return Number.isNaN(date.getTime()) ? '—' : date.toLocaleString();\n}\n\nfunction formatDate(value?: string | null): string {\n if (!value) {\n return '—';\n }\n const parsed = new Date(value);\n if (Number.isNaN(parsed.getTime())) {\n return '—';\n }\n return parsed.toLocaleDateString(undefined, { year: 'numeric', month: 'short', day: 'numeric' });\n}\n\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 SourceDetailPage() {\n const { id = '' } = useParams<{ id: string }>();\n const { navigate } = useCosmicIntersection();\n\n const { data, loading, error, refetch } = useCosSourceQuery(id);\n const source = data?.cosSource ?? null;\n\n const [markSynced, { loading: syncing }] = useCosMarkSourceSyncedMutation();\n const [archiveSource] = useCosArchiveSourceMutation();\n\n const handleMarkSynced = async () => {\n if (!source) {\n return;\n }\n const response = await markSynced({ variables: { id: source.id } });\n if (response.data?.cosMarkSourceSynced) {\n notify.success('Source marked synced', `“${source.name}” is now up to date.`);\n await refetch();\n }\n };\n\n const handleArchive = async () => {\n if (!source) {\n return;\n }\n const response = await archiveSource({ variables: { id: source.id } });\n if (response.error) {\n throw new Error(response.error.message);\n }\n if (!response.data?.cosArchiveSource) {\n notify.error('Could not archive source', 'The server did not confirm the change.');\n throw new Error('Archive not confirmed');\n }\n notify.success('Source archived');\n navigate('sources');\n };\n\n if (loading) {\n return (\n <PageLayout title=\"Source\" backPath=\"sources\">\n <LoadingState label=\"Loading source…\" />\n </PageLayout>\n );\n }\n\n if (error) {\n return (\n <PageLayout title=\"Source\" backPath=\"sources\">\n <ErrorState message=\"We could not load this source.\" onRetry={() => void refetch()} />\n </PageLayout>\n );\n }\n\n if (!source) {\n return (\n <PageLayout title=\"Source\" backPath=\"sources\">\n <EmptyState\n icon={Radio}\n title=\"Source not found.\"\n description=\"This source may have been removed or is outside your current scope.\"\n action={\n <Button type=\"button\" onClick={() => navigate('sources')}>\n Back to sources\n </Button>\n }\n />\n </PageLayout>\n );\n }\n\n const datasets = source.datasets ?? [];\n\n const renderDatasets = () => {\n if (datasets.length === 0) {\n return (\n <EmptyState\n icon={Database}\n title=\"No datasets from this source yet\"\n description=\"Datasets that ingest from this source will be listed here.\"\n />\n );\n }\n return (\n <>\n {/* Desktop / tablet: table */}\n <div className=\"hidden overflow-hidden rounded-card border border-border-default bg-bg-elevated md:block\">\n <Table>\n <TableHeader>\n <TableRow>\n <TableHead>Name</TableHead>\n <TableHead>Status</TableHead>\n <TableHead>Access</TableHead>\n <TableHead>Rows</TableHead>\n <TableHead>Updated</TableHead>\n </TableRow>\n </TableHeader>\n <TableBody>\n {datasets.map((dataset) => (\n <TableRow\n key={dataset.id}\n className=\"cursor-pointer\"\n onClick={() => navigate(`datasets/${dataset.id}`)}\n >\n <TableCell className=\"font-medium text-text-primary\">{dataset.name}</TableCell>\n <TableCell>\n <StatusBadge status={dataset.status} />\n </TableCell>\n <TableCell>\n <StatusBadge status={dataset.accessLevel} />\n </TableCell>\n <TableCell className=\"tabular-nums text-sm text-text-secondary\">\n {Number(dataset.rowCount) > 0 ? Number(dataset.rowCount).toLocaleString() : '—'}\n </TableCell>\n <TableCell className=\"whitespace-nowrap text-sm text-text-secondary\">\n {formatDate(dataset.updatedAt)}\n </TableCell>\n </TableRow>\n ))}\n </TableBody>\n </Table>\n </div>\n\n {/* Mobile: stacked cards */}\n <ul className=\"space-y-3 md:hidden\">\n {datasets.map((dataset) => (\n <li key={dataset.id}>\n <div\n role=\"button\"\n tabIndex={0}\n aria-label={`Open ${dataset.name}`}\n onClick={() => navigate(`datasets/${dataset.id}`)}\n onKeyDown={(event) => {\n if (event.key === 'Enter' || event.key === ' ') {\n event.preventDefault();\n navigate(`datasets/${dataset.id}`);\n }\n }}\n className=\"flex flex-col gap-2 rounded-card border border-border-default bg-bg-elevated p-4 outline-none transition-colors hover:bg-bg-sunken focus-visible:ring-2 focus-visible:ring-border-focus\"\n >\n <p className=\"font-medium text-text-primary\">{dataset.name}</p>\n <div className=\"flex flex-wrap items-center gap-1.5\">\n <StatusBadge status={dataset.status} />\n <StatusBadge status={dataset.accessLevel} />\n </div>\n <div className=\"flex items-center justify-between gap-2 text-xs text-text-secondary\">\n <span className=\"tabular-nums\">\n {Number(dataset.rowCount) > 0\n ? `${Number(dataset.rowCount).toLocaleString()} rows`\n : 'No rows'}\n </span>\n <span>{formatDate(dataset.updatedAt)}</span>\n </div>\n </div>\n </li>\n ))}\n </ul>\n </>\n );\n };\n\n return (\n <PageLayout\n title={source.name}\n description={source.description ?? undefined}\n backPath=\"sources\"\n actions={\n <div className=\"flex items-center gap-2\">\n <Button\n type=\"button\"\n variant=\"outline\"\n onClick={() => navigate(`sources/${source.id}/edit`)}\n >\n <Pencil className=\"size-4\" />\n Edit\n </Button>\n <ActionMenu\n ariaLabel={`Actions for ${source.name}`}\n entityName={source.name}\n onDelete={() => handleArchive()}\n deleteLabel=\"Archive source\"\n extraItems={[\n {\n key: 'mark-synced',\n label: syncing ? 'Marking synced…' : 'Mark synced',\n icon: RefreshCw,\n disabled: syncing,\n onSelect: () => void handleMarkSynced(),\n },\n ]}\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={source.status} />\n <Badge variant=\"secondary\">{formatEnumLabel(source.type)}</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=\"Endpoint\"\n value={\n source.endpoint ? (\n <SafeLink\n href={source.endpoint}\n className=\"inline-flex items-center gap-1.5 truncate text-text-primary underline-offset-2 hover:underline\"\n fallbackClassName=\"truncate text-text-secondary\"\n >\n <Download className=\"size-4 shrink-0 text-text-secondary\" aria-hidden=\"true\" />\n <span className=\"truncate\">{source.endpoint}</span>\n </SafeLink>\n ) : (\n <span className=\"text-text-secondary\">Not set</span>\n )\n }\n />\n <MetaTile\n label=\"Last synced\"\n value={<span>{formatDateTime(source.lastSyncedAt)}</span>}\n />\n <MetaTile label=\"Created\" value={<span>{formatDateTime(source.createdAt)}</span>} />\n <MetaTile label=\"Updated\" value={<span>{formatDateTime(source.updatedAt)}</span>} />\n </div>\n\n {source.tags.length > 0 ? (\n <div className=\"flex flex-wrap gap-1\">\n {source.tags.map((tag) => (\n <Badge key={tag} variant=\"outline\" className=\"text-xs\">\n {tag}\n </Badge>\n ))}\n </div>\n ) : null}\n\n {/* Datasets */}\n <section className=\"space-y-3\">\n <h2 className=\"text-lg font-semibold text-text-primary\">Datasets from this source</h2>\n {renderDatasets()}\n </section>\n </div>\n </PageLayout>\n );\n}\n"],"mappings":"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"}