@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.
Files changed (36) hide show
  1. package/dist/cosmicintersection/CosmicIntersectionRoutes.js +31 -23
  2. package/dist/cosmicintersection/CosmicIntersectionRoutes.js.map +1 -1
  3. package/dist/cosmicintersection/api/cosmicApi.js +131 -66
  4. package/dist/cosmicintersection/api/cosmicApi.js.map +1 -1
  5. package/dist/cosmicintersection/components/ActivityFeedPanel.js +68 -0
  6. package/dist/cosmicintersection/components/ActivityFeedPanel.js.map +1 -0
  7. package/dist/cosmicintersection/components/DiscussionPanel.js +57 -0
  8. package/dist/cosmicintersection/components/DiscussionPanel.js.map +1 -0
  9. package/dist/cosmicintersection/components/index.js +5 -3
  10. package/dist/cosmicintersection/pages/access/AccessPage.js +24 -17
  11. package/dist/cosmicintersection/pages/access/AccessPage.js.map +1 -1
  12. package/dist/cosmicintersection/pages/analyses/AnalysesPage.js +12 -12
  13. package/dist/cosmicintersection/pages/collections/CollectionDetailPage.js +109 -96
  14. package/dist/cosmicintersection/pages/collections/CollectionDetailPage.js.map +1 -1
  15. package/dist/cosmicintersection/pages/collections/CollectionFormPage.js +87 -61
  16. package/dist/cosmicintersection/pages/collections/CollectionFormPage.js.map +1 -1
  17. package/dist/cosmicintersection/pages/collections/CollectionsPage.js +51 -42
  18. package/dist/cosmicintersection/pages/collections/CollectionsPage.js.map +1 -1
  19. package/dist/cosmicintersection/pages/dashboard/DashboardPage.js +5 -3
  20. package/dist/cosmicintersection/pages/dashboard/DashboardPage.js.map +1 -1
  21. package/dist/cosmicintersection/pages/datasets/DatasetDetailPage.js +172 -152
  22. package/dist/cosmicintersection/pages/datasets/DatasetDetailPage.js.map +1 -1
  23. package/dist/cosmicintersection/pages/datasets/DatasetFormPage.js +7 -7
  24. package/dist/cosmicintersection/pages/notebooks/NotebookDetailPage.js +205 -196
  25. package/dist/cosmicintersection/pages/notebooks/NotebookDetailPage.js.map +1 -1
  26. package/dist/cosmicintersection/pages/releases/ReleasesPage.js +211 -161
  27. package/dist/cosmicintersection/pages/releases/ReleasesPage.js.map +1 -1
  28. package/dist/cosmicintersection/pages/runs/RunDetailPage.js +113 -108
  29. package/dist/cosmicintersection/pages/runs/RunDetailPage.js.map +1 -1
  30. package/dist/cosmicintersection/pages/runs/RunsPage.js +86 -101
  31. package/dist/cosmicintersection/pages/runs/RunsPage.js.map +1 -1
  32. package/dist/cosmicintersection/pages/sources/SourceDetailPage.js +205 -0
  33. package/dist/cosmicintersection/pages/sources/SourceDetailPage.js.map +1 -0
  34. package/dist/cosmicintersection/pages/sources/SourcesPage.js +110 -104
  35. package/dist/cosmicintersection/pages/sources/SourcesPage.js.map +1 -1
  36. package/package.json +1 -1
@@ -0,0 +1,205 @@
1
+ import { useCosmicIntersection as e } from "../../context/CosmicIntersectionContext.js";
2
+ import { notify as t } from "../../lib/toast.js";
3
+ import { useCosArchiveSourceMutation as n, useCosMarkSourceSyncedMutation as r, useCosSourceQuery as i } from "../../api/cosmicApi.js";
4
+ import a from "../../components/ActionMenu.js";
5
+ import o from "../../components/EmptyState.js";
6
+ import s from "../../components/ErrorState.js";
7
+ import c from "../../components/LoadingState.js";
8
+ import l from "../../components/SafeLink.js";
9
+ import u from "../../components/PageLayout.js";
10
+ import d, { formatEnumLabel as f } from "../../components/StatusBadge.js";
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";
16
+ //#region src/cosmicintersection/pages/sources/SourceDetailPage.tsx
17
+ function k(e) {
18
+ if (!e) return "—";
19
+ let t = new Date(e);
20
+ return Number.isNaN(t.getTime()) ? "—" : t.toLocaleString();
21
+ }
22
+ function A(e) {
23
+ if (!e) return "—";
24
+ let t = new Date(e);
25
+ return Number.isNaN(t.getTime()) ? "—" : t.toLocaleDateString(void 0, {
26
+ year: "numeric",
27
+ month: "short",
28
+ day: "numeric"
29
+ });
30
+ }
31
+ function j({ label: e, value: t }) {
32
+ return /* @__PURE__ */ m("div", {
33
+ className: "rounded-card border border-border-default bg-bg-elevated p-4",
34
+ children: [/* @__PURE__ */ p("p", {
35
+ className: "text-xs font-medium uppercase tracking-wide text-text-secondary",
36
+ children: e
37
+ }), /* @__PURE__ */ p("div", {
38
+ className: "mt-1 text-sm text-text-primary",
39
+ children: t
40
+ })]
41
+ });
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 } });
49
+ if (e.error) throw Error(e.error.message);
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");
52
+ };
53
+ if (F) return /* @__PURE__ */ p(u, {
54
+ title: "Source",
55
+ backPath: "sources",
56
+ children: /* @__PURE__ */ p(c, { label: "Loading source…" })
57
+ });
58
+ if (I) return /* @__PURE__ */ p(u, {
59
+ title: "Source",
60
+ backPath: "sources",
61
+ children: /* @__PURE__ */ p(s, {
62
+ message: "We could not load this source.",
63
+ onRetry: () => void L()
64
+ })
65
+ });
66
+ if (!R) return /* @__PURE__ */ p(u, {
67
+ title: "Source",
68
+ backPath: "sources",
69
+ children: /* @__PURE__ */ p(o, {
70
+ icon: y,
71
+ title: "Source not found.",
72
+ description: "This source may have been removed or is outside your current scope.",
73
+ action: /* @__PURE__ */ p(S, {
74
+ type: "button",
75
+ onClick: () => N("sources"),
76
+ children: "Back to sources"
77
+ })
78
+ })
79
+ });
80
+ let W = R.datasets ?? [];
81
+ return /* @__PURE__ */ p(u, {
82
+ title: R.name,
83
+ description: R.description ?? void 0,
84
+ backPath: "sources",
85
+ actions: /* @__PURE__ */ m("div", {
86
+ className: "flex items-center gap-2",
87
+ children: [/* @__PURE__ */ m(S, {
88
+ type: "button",
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(),
96
+ deleteLabel: "Archive source",
97
+ extraItems: [{
98
+ key: "mark-synced",
99
+ label: B ? "Marking synced…" : "Mark synced",
100
+ icon: b,
101
+ disabled: B,
102
+ onSelect: () => void H()
103
+ }]
104
+ })]
105
+ }),
106
+ children: /* @__PURE__ */ m("div", {
107
+ className: "space-y-6",
108
+ children: [
109
+ /* @__PURE__ */ m("div", {
110
+ className: "flex flex-wrap items-center gap-2",
111
+ children: [/* @__PURE__ */ p(d, { status: R.status }), /* @__PURE__ */ p(x, {
112
+ variant: "secondary",
113
+ children: f(R.type)
114
+ })]
115
+ }),
116
+ /* @__PURE__ */ m("div", {
117
+ className: "grid grid-cols-1 gap-3 sm:grid-cols-2 lg:grid-cols-4",
118
+ children: [
119
+ /* @__PURE__ */ p(j, {
120
+ label: "Endpoint",
121
+ value: R.endpoint ? /* @__PURE__ */ m(l, {
122
+ href: R.endpoint,
123
+ className: "inline-flex items-center gap-1.5 truncate text-text-primary underline-offset-2 hover:underline",
124
+ fallbackClassName: "truncate text-text-secondary",
125
+ children: [/* @__PURE__ */ p(_, {
126
+ className: "size-4 shrink-0 text-text-secondary",
127
+ "aria-hidden": "true"
128
+ }), /* @__PURE__ */ p("span", {
129
+ className: "truncate",
130
+ children: R.endpoint
131
+ })]
132
+ }) : /* @__PURE__ */ p("span", {
133
+ className: "text-text-secondary",
134
+ children: "Not set"
135
+ })
136
+ }),
137
+ /* @__PURE__ */ p(j, {
138
+ label: "Last synced",
139
+ value: /* @__PURE__ */ p("span", { children: k(R.lastSyncedAt) })
140
+ }),
141
+ /* @__PURE__ */ p(j, {
142
+ label: "Created",
143
+ value: /* @__PURE__ */ p("span", { children: k(R.createdAt) })
144
+ }),
145
+ /* @__PURE__ */ p(j, {
146
+ label: "Updated",
147
+ value: /* @__PURE__ */ p("span", { children: k(R.updatedAt) })
148
+ })
149
+ ]
150
+ }),
151
+ R.tags.length > 0 ? /* @__PURE__ */ p("div", {
152
+ className: "flex flex-wrap gap-1",
153
+ children: R.tags.map((e) => /* @__PURE__ */ p(x, {
154
+ variant: "outline",
155
+ className: "text-xs",
156
+ children: e
157
+ }, e))
158
+ }) : null,
159
+ /* @__PURE__ */ m("section", {
160
+ className: "space-y-3",
161
+ children: [/* @__PURE__ */ p("h2", {
162
+ className: "text-lg font-semibold text-text-primary",
163
+ children: "Datasets from this source"
164
+ }), W.length === 0 ? /* @__PURE__ */ p(o, {
165
+ icon: g,
166
+ title: "No datasets from this source yet",
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, {
177
+ className: "cursor-pointer",
178
+ onClick: () => N(`datasets/${e.id}`),
179
+ children: [
180
+ /* @__PURE__ */ p(T, {
181
+ className: "font-medium text-text-primary",
182
+ children: e.name
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, {
187
+ className: "tabular-nums text-sm text-text-secondary",
188
+ children: Number(e.rowCount) > 0 ? Number(e.rowCount).toLocaleString() : "—"
189
+ }),
190
+ /* @__PURE__ */ p(T, {
191
+ className: "whitespace-nowrap text-sm text-text-secondary",
192
+ children: A(e.updatedAt)
193
+ })
194
+ ]
195
+ }, e.id)) })] })
196
+ })]
197
+ })
198
+ ]
199
+ })
200
+ });
201
+ }
202
+ //#endregion
203
+ export { M as default };
204
+
205
+ //# sourceMappingURL=SourceDetailPage.js.map
@@ -0,0 +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,18 +1,18 @@
1
1
  import { useCosmicIntersection as e } from "../../context/CosmicIntersectionContext.js";
2
2
  import { notify as t } from "../../lib/toast.js";
3
3
  import { useCosArchiveSourceMutation as n, useCosMarkSourceSyncedMutation as r, useCosSourcesQuery as i } from "../../api/cosmicApi.js";
4
- import ee from "../../components/ActionMenu.js";
5
- import a from "../../components/EmptyState.js";
6
- import o from "../../components/ErrorState.js";
7
- import s from "../../components/LoadingState.js";
8
- import c from "../../components/PageLayout.js";
9
- import l, { usePagination as u } from "../../components/Pagination.js";
10
- import d from "../../components/SafeLink.js";
11
- import f, { formatEnumLabel as p } from "../../components/StatusBadge.js";
4
+ import a from "../../components/ActionMenu.js";
5
+ import o from "../../components/EmptyState.js";
6
+ import s from "../../components/ErrorState.js";
7
+ import c from "../../components/LoadingState.js";
8
+ import l from "../../components/SafeLink.js";
9
+ import u from "../../components/PageLayout.js";
10
+ import d, { usePagination as f } from "../../components/Pagination.js";
11
+ import p, { formatEnumLabel as m } from "../../components/StatusBadge.js";
12
12
  import "../../components/index.js";
13
- import { useMemo as m, useState as h } from "react";
14
- import { Fragment as g, jsx as _, jsxs as v } from "react/jsx-runtime";
15
- import { Plus as y, Radio as b, RefreshCw as x } from "lucide-react";
13
+ import { useMemo as h, useState as g } from "react";
14
+ import { Fragment as _, jsx as v, jsxs as y } from "react/jsx-runtime";
15
+ import { Plus as ee, Radio as b, RefreshCw as x } from "lucide-react";
16
16
  import { Badge as S, Button as C, Select as w, SelectContent as T, SelectItem as E, SelectTrigger as D, SelectValue as O, Table as k, TableBody as A, TableCell as j, TableHead as M, TableHeader as N, TableRow as P } from "@burdenoff/fe-libs/ui";
17
17
  //#region src/cosmicintersection/pages/sources/SourcesPage.tsx
18
18
  var F = "ALL", I = [
@@ -42,7 +42,7 @@ function R(e) {
42
42
  });
43
43
  }
44
44
  function z() {
45
- let { navigate: z } = e(), [B, V] = h(F), [H, U] = h(F), W = u({
45
+ let { navigate: z } = e(), [B, V] = g(F), [H, U] = g(F), W = f({
46
46
  pageSize: 20,
47
47
  resetKey: `${B}|${H}`
48
48
  }), { data: G, loading: K, error: q, refetch: J } = i({
@@ -52,152 +52,158 @@ function z() {
52
52
  limit: W.limit,
53
53
  offset: W.offset
54
54
  }
55
- }), [Y] = r(), [X] = n(), Z = m(() => G?.cosListSources.items ?? [], [G]), Q = G?.cosListSources.pageInfo, te = async (e) => {
55
+ }), [Y] = r(), [X] = n(), Z = h(() => G?.cosListSources.items ?? [], [G]), Q = G?.cosListSources.pageInfo, te = async (e) => {
56
56
  (await Y({ variables: { id: e.id } })).data?.cosMarkSourceSynced && (t.success("Source marked synced", `“${e.name}” is now up to date.`), await J());
57
57
  }, ne = async (e) => {
58
58
  let n = await X({ variables: { id: e.id } });
59
59
  if (n.error) throw Error(n.error.message);
60
60
  if (!n.data?.cosArchiveSource) throw t.error("Could not archive source", "The server did not confirm the change."), Error("Archive not confirmed");
61
61
  t.success("Source archived"), await J();
62
- }, $ = /* @__PURE__ */ v(C, {
62
+ }, $ = /* @__PURE__ */ y(C, {
63
63
  type: "button",
64
64
  onClick: () => z("sources/create"),
65
- children: [/* @__PURE__ */ _(y, { className: "size-4" }), "New source"]
65
+ children: [/* @__PURE__ */ v(ee, { className: "size-4" }), "New source"]
66
66
  });
67
- return /* @__PURE__ */ _(c, {
67
+ return /* @__PURE__ */ v(u, {
68
68
  title: "Data sources",
69
69
  description: "Instruments, archives and feeds that supply raw data into your federation.",
70
70
  actions: $,
71
- children: /* @__PURE__ */ v("div", {
71
+ children: /* @__PURE__ */ y("div", {
72
72
  className: "space-y-4",
73
- children: [/* @__PURE__ */ v("div", {
73
+ children: [/* @__PURE__ */ y("div", {
74
74
  className: "flex flex-wrap items-center gap-3",
75
- children: [/* @__PURE__ */ _("div", {
75
+ children: [/* @__PURE__ */ v("div", {
76
76
  className: "w-full max-w-[14rem]",
77
- children: /* @__PURE__ */ v(w, {
77
+ children: /* @__PURE__ */ y(w, {
78
78
  value: B,
79
79
  onValueChange: V,
80
- children: [/* @__PURE__ */ _(D, {
80
+ children: [/* @__PURE__ */ v(D, {
81
81
  "aria-label": "Filter by type",
82
- children: /* @__PURE__ */ _(O, { placeholder: "All types" })
83
- }), /* @__PURE__ */ v(T, { children: [/* @__PURE__ */ _(E, {
82
+ children: /* @__PURE__ */ v(O, { placeholder: "All types" })
83
+ }), /* @__PURE__ */ y(T, { children: [/* @__PURE__ */ v(E, {
84
84
  value: F,
85
85
  children: "All types"
86
- }), I.map((e) => /* @__PURE__ */ _(E, {
86
+ }), I.map((e) => /* @__PURE__ */ v(E, {
87
87
  value: e,
88
- children: p(e)
88
+ children: m(e)
89
89
  }, e))] })]
90
90
  })
91
- }), /* @__PURE__ */ _("div", {
91
+ }), /* @__PURE__ */ v("div", {
92
92
  className: "w-full max-w-[14rem]",
93
- children: /* @__PURE__ */ v(w, {
93
+ children: /* @__PURE__ */ y(w, {
94
94
  value: H,
95
95
  onValueChange: U,
96
- children: [/* @__PURE__ */ _(D, {
96
+ children: [/* @__PURE__ */ v(D, {
97
97
  "aria-label": "Filter by status",
98
- children: /* @__PURE__ */ _(O, { placeholder: "All statuses" })
99
- }), /* @__PURE__ */ v(T, { children: [/* @__PURE__ */ _(E, {
98
+ children: /* @__PURE__ */ v(O, { placeholder: "All statuses" })
99
+ }), /* @__PURE__ */ y(T, { children: [/* @__PURE__ */ v(E, {
100
100
  value: F,
101
101
  children: "All statuses"
102
- }), L.map((e) => /* @__PURE__ */ _(E, {
102
+ }), L.map((e) => /* @__PURE__ */ v(E, {
103
103
  value: e,
104
- children: p(e)
104
+ children: m(e)
105
105
  }, e))] })]
106
106
  })
107
107
  })]
108
108
  }), (() => {
109
- if (K) return /* @__PURE__ */ _(s, {
109
+ if (K) return /* @__PURE__ */ v(c, {
110
110
  variant: "rows",
111
111
  rows: 6,
112
112
  label: "Loading sources…"
113
113
  });
114
- if (q) return /* @__PURE__ */ _(o, {
114
+ if (q) return /* @__PURE__ */ v(s, {
115
115
  message: q.message,
116
116
  onRetry: () => void J()
117
117
  });
118
118
  if (Z.length === 0) {
119
119
  let e = B !== F || H !== F;
120
- return /* @__PURE__ */ _(a, {
120
+ return /* @__PURE__ */ v(o, {
121
121
  icon: b,
122
122
  title: e ? "No sources match these filters" : "No data sources yet",
123
123
  description: e ? "Try clearing the type or status filter to see more sources." : "Connect a telescope, satellite feed, archive or API to start ingesting scientific data.",
124
124
  action: e ? void 0 : $
125
125
  });
126
126
  }
127
- return /* @__PURE__ */ v(g, { children: [/* @__PURE__ */ _("div", {
127
+ return /* @__PURE__ */ y(_, { children: [/* @__PURE__ */ v("div", {
128
128
  className: "overflow-hidden rounded-card border border-border-default bg-bg-elevated",
129
- children: /* @__PURE__ */ v(k, { children: [/* @__PURE__ */ _(N, { children: /* @__PURE__ */ v(P, { children: [
130
- /* @__PURE__ */ _(M, { children: "Name" }),
131
- /* @__PURE__ */ _(M, { children: "Type" }),
132
- /* @__PURE__ */ _(M, { children: "Status" }),
133
- /* @__PURE__ */ _(M, { children: "Endpoint" }),
134
- /* @__PURE__ */ _(M, { children: "Last synced" }),
135
- /* @__PURE__ */ _(M, { children: "Tags" }),
136
- /* @__PURE__ */ _(M, {
129
+ children: /* @__PURE__ */ y(k, { children: [/* @__PURE__ */ v(N, { children: /* @__PURE__ */ y(P, { children: [
130
+ /* @__PURE__ */ v(M, { children: "Name" }),
131
+ /* @__PURE__ */ v(M, { children: "Type" }),
132
+ /* @__PURE__ */ v(M, { children: "Status" }),
133
+ /* @__PURE__ */ v(M, { children: "Endpoint" }),
134
+ /* @__PURE__ */ v(M, { children: "Last synced" }),
135
+ /* @__PURE__ */ v(M, { children: "Tags" }),
136
+ /* @__PURE__ */ v(M, {
137
137
  className: "text-right",
138
138
  children: "Actions"
139
139
  })
140
- ] }) }), /* @__PURE__ */ _(A, { children: Z.map((e) => /* @__PURE__ */ v(P, { children: [
141
- /* @__PURE__ */ v(j, { children: [/* @__PURE__ */ _("div", {
142
- className: "font-medium text-text-primary",
143
- children: e.name
144
- }), e.description ? /* @__PURE__ */ _("div", {
145
- className: "mt-0.5 line-clamp-1 max-w-xs text-xs text-text-secondary",
146
- children: e.description
147
- }) : null] }),
148
- /* @__PURE__ */ _(j, { children: /* @__PURE__ */ _(S, {
149
- variant: "secondary",
150
- children: p(e.type)
151
- }) }),
152
- /* @__PURE__ */ _(j, { children: /* @__PURE__ */ _(f, { status: e.status }) }),
153
- /* @__PURE__ */ _(j, {
154
- className: "max-w-[16rem]",
155
- children: e.endpoint ? /* @__PURE__ */ _(d, {
156
- href: e.endpoint,
157
- className: "block truncate text-sm text-text-primary underline-offset-2 hover:underline",
158
- fallbackClassName: "block truncate text-sm text-text-secondary",
159
- children: e.endpoint
160
- }) : /* @__PURE__ */ _("span", {
161
- className: "text-sm text-text-secondary",
162
- children: "—"
140
+ ] }) }), /* @__PURE__ */ v(A, { children: Z.map((e) => /* @__PURE__ */ y(P, {
141
+ className: "cursor-pointer",
142
+ onClick: () => z(`sources/${e.id}`),
143
+ children: [
144
+ /* @__PURE__ */ y(j, { children: [/* @__PURE__ */ v("div", {
145
+ className: "font-medium text-text-primary",
146
+ children: e.name
147
+ }), e.description ? /* @__PURE__ */ v("div", {
148
+ className: "mt-0.5 line-clamp-1 max-w-xs text-xs text-text-secondary",
149
+ children: e.description
150
+ }) : null] }),
151
+ /* @__PURE__ */ v(j, { children: /* @__PURE__ */ v(S, {
152
+ variant: "secondary",
153
+ children: m(e.type)
154
+ }) }),
155
+ /* @__PURE__ */ v(j, { children: /* @__PURE__ */ v(p, { status: e.status }) }),
156
+ /* @__PURE__ */ v(j, {
157
+ className: "max-w-[16rem]",
158
+ onClick: (e) => e.stopPropagation(),
159
+ children: e.endpoint ? /* @__PURE__ */ v(l, {
160
+ href: e.endpoint,
161
+ className: "block truncate text-sm text-text-primary underline-offset-2 hover:underline",
162
+ fallbackClassName: "block truncate text-sm text-text-secondary",
163
+ children: e.endpoint
164
+ }) : /* @__PURE__ */ v("span", {
165
+ className: "text-sm text-text-secondary",
166
+ children: "—"
167
+ })
168
+ }),
169
+ /* @__PURE__ */ v(j, {
170
+ className: "whitespace-nowrap text-sm text-text-secondary",
171
+ children: R(e.lastSyncedAt)
172
+ }),
173
+ /* @__PURE__ */ v(j, { children: /* @__PURE__ */ y("div", {
174
+ className: "flex max-w-[12rem] flex-wrap gap-1",
175
+ children: [e.tags.length === 0 ? /* @__PURE__ */ v("span", {
176
+ className: "text-xs text-text-secondary",
177
+ children: "—"
178
+ }) : e.tags.slice(0, 3).map((e) => /* @__PURE__ */ v(S, {
179
+ variant: "outline",
180
+ className: "text-xs",
181
+ children: e
182
+ }, e)), e.tags.length > 3 ? /* @__PURE__ */ y("span", {
183
+ className: "text-xs text-text-secondary",
184
+ children: ["+", e.tags.length - 3]
185
+ }) : null]
186
+ }) }),
187
+ /* @__PURE__ */ v(j, {
188
+ className: "text-right",
189
+ children: /* @__PURE__ */ v(a, {
190
+ ariaLabel: `Actions for ${e.name}`,
191
+ entityName: e.name,
192
+ onView: () => z(`sources/${e.id}`),
193
+ onEdit: () => z(`sources/${e.id}/edit`),
194
+ onDelete: () => ne(e),
195
+ deleteLabel: "Archive source",
196
+ extraItems: [{
197
+ key: "mark-synced",
198
+ label: "Mark synced",
199
+ icon: x,
200
+ onSelect: () => void te(e)
201
+ }]
202
+ })
163
203
  })
164
- }),
165
- /* @__PURE__ */ _(j, {
166
- className: "whitespace-nowrap text-sm text-text-secondary",
167
- children: R(e.lastSyncedAt)
168
- }),
169
- /* @__PURE__ */ _(j, { children: /* @__PURE__ */ v("div", {
170
- className: "flex max-w-[12rem] flex-wrap gap-1",
171
- children: [e.tags.length === 0 ? /* @__PURE__ */ _("span", {
172
- className: "text-xs text-text-secondary",
173
- children: "—"
174
- }) : e.tags.slice(0, 3).map((e) => /* @__PURE__ */ _(S, {
175
- variant: "outline",
176
- className: "text-xs",
177
- children: e
178
- }, e)), e.tags.length > 3 ? /* @__PURE__ */ v("span", {
179
- className: "text-xs text-text-secondary",
180
- children: ["+", e.tags.length - 3]
181
- }) : null]
182
- }) }),
183
- /* @__PURE__ */ _(j, {
184
- className: "text-right",
185
- children: /* @__PURE__ */ _(ee, {
186
- ariaLabel: `Actions for ${e.name}`,
187
- entityName: e.name,
188
- onEdit: () => z(`sources/${e.id}/edit`),
189
- onDelete: () => ne(e),
190
- deleteLabel: "Archive source",
191
- extraItems: [{
192
- key: "mark-synced",
193
- label: "Mark synced",
194
- icon: x,
195
- onSelect: () => void te(e)
196
- }]
197
- })
198
- })
199
- ] }, e.id)) })] })
200
- }), /* @__PURE__ */ _(l, {
204
+ ]
205
+ }, e.id)) })] })
206
+ }), /* @__PURE__ */ v(d, {
201
207
  offset: W.offset,
202
208
  limit: W.limit,
203
209
  loadedCount: Z.length,
@@ -1 +1 @@
1
- {"version":3,"file":"SourcesPage.js","names":[],"sources":["../../../../src/cosmicintersection/pages/sources/SourcesPage.tsx"],"sourcesContent":["import { useMemo, useState } from 'react';\nimport { Plus, RefreshCw, Radio } from 'lucide-react';\nimport {\n Badge,\n Button,\n Select,\n SelectContent,\n SelectItem,\n SelectTrigger,\n SelectValue,\n Table,\n TableBody,\n TableCell,\n TableHead,\n TableHeader,\n TableRow,\n} from '@burdenoff/fe-libs/ui';\n\nimport {\n useCosArchiveSourceMutation,\n useCosMarkSourceSyncedMutation,\n useCosSourcesQuery,\n type CosSource,\n type CosSourceStatus,\n type CosSourceType,\n} from '../../api/cosmicApi';\nimport {\n ActionMenu,\n EmptyState,\n ErrorState,\n LoadingState,\n PageLayout,\n Pagination,\n SafeLink,\n StatusBadge,\n formatEnumLabel,\n usePagination,\n} from '../../components';\nimport { useCosmicIntersection } from '../../context/CosmicIntersectionContext';\nimport { notify } from '../../lib/toast';\n\nconst ALL = 'ALL';\n\nconst SOURCE_TYPES: CosSourceType[] = [\n 'TELESCOPE',\n 'SATELLITE',\n 'GROUND_SENSOR',\n 'ARCHIVE',\n 'API',\n 'STREAM',\n 'FILE_DROP',\n 'SIMULATION',\n];\n\nconst SOURCE_STATUSES: CosSourceStatus[] = [\n 'CONFIGURING',\n 'CONNECTED',\n 'SYNCING',\n 'DEGRADED',\n 'ERROR',\n 'DISABLED',\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\nexport default function SourcesPage() {\n const { navigate } = useCosmicIntersection();\n const [typeFilter, setTypeFilter] = useState<string>(ALL);\n const [statusFilter, setStatusFilter] = useState<string>(ALL);\n const pagination = usePagination({ pageSize: 20, resetKey: `${typeFilter}|${statusFilter}` });\n\n const { data, loading, error, refetch } = useCosSourcesQuery({\n type: typeFilter === ALL ? undefined : (typeFilter as CosSourceType),\n status: statusFilter === ALL ? undefined : (statusFilter as CosSourceStatus),\n pagination: { limit: pagination.limit, offset: pagination.offset },\n });\n\n const [markSynced] = useCosMarkSourceSyncedMutation();\n const [archiveSource] = useCosArchiveSourceMutation();\n\n const sources = useMemo(() => data?.cosListSources.items ?? [], [data]);\n const pageInfo = data?.cosListSources.pageInfo;\n\n const handleMarkSynced = async (source: CosSource) => {\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 (source: CosSource) => {\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 await refetch();\n };\n\n const newButton = (\n <Button type=\"button\" onClick={() => navigate('sources/create')}>\n <Plus className=\"size-4\" />\n New source\n </Button>\n );\n\n const renderBody = () => {\n if (loading) {\n return <LoadingState variant=\"rows\" rows={6} label=\"Loading sources…\" />;\n }\n if (error) {\n return <ErrorState message={error.message} onRetry={() => void refetch()} />;\n }\n if (sources.length === 0) {\n const filtered = typeFilter !== ALL || statusFilter !== ALL;\n return (\n <EmptyState\n icon={Radio}\n title={filtered ? 'No sources match these filters' : 'No data sources yet'}\n description={\n filtered\n ? 'Try clearing the type or status filter to see more sources.'\n : 'Connect a telescope, satellite feed, archive or API to start ingesting scientific data.'\n }\n action={filtered ? undefined : newButton}\n />\n );\n }\n\n return (\n <>\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>Type</TableHead>\n <TableHead>Status</TableHead>\n <TableHead>Endpoint</TableHead>\n <TableHead>Last synced</TableHead>\n <TableHead>Tags</TableHead>\n <TableHead className=\"text-right\">Actions</TableHead>\n </TableRow>\n </TableHeader>\n <TableBody>\n {sources.map((source) => (\n <TableRow key={source.id}>\n <TableCell>\n <div className=\"font-medium text-text-primary\">{source.name}</div>\n {source.description ? (\n <div className=\"mt-0.5 line-clamp-1 max-w-xs text-xs text-text-secondary\">\n {source.description}\n </div>\n ) : null}\n </TableCell>\n <TableCell>\n <Badge variant=\"secondary\">{formatEnumLabel(source.type)}</Badge>\n </TableCell>\n <TableCell>\n <StatusBadge status={source.status} />\n </TableCell>\n <TableCell className=\"max-w-[16rem]\">\n {source.endpoint ? (\n <SafeLink\n href={source.endpoint}\n className=\"block truncate text-sm text-text-primary underline-offset-2 hover:underline\"\n fallbackClassName=\"block truncate text-sm text-text-secondary\"\n >\n {source.endpoint}\n </SafeLink>\n ) : (\n <span className=\"text-sm text-text-secondary\">—</span>\n )}\n </TableCell>\n <TableCell className=\"whitespace-nowrap text-sm text-text-secondary\">\n {formatDate(source.lastSyncedAt)}\n </TableCell>\n <TableCell>\n <div className=\"flex max-w-[12rem] flex-wrap gap-1\">\n {source.tags.length === 0 ? (\n <span className=\"text-xs text-text-secondary\">—</span>\n ) : (\n source.tags.slice(0, 3).map((tag) => (\n <Badge key={tag} variant=\"outline\" className=\"text-xs\">\n {tag}\n </Badge>\n ))\n )}\n {source.tags.length > 3 ? (\n <span className=\"text-xs text-text-secondary\">\n +{source.tags.length - 3}\n </span>\n ) : null}\n </div>\n </TableCell>\n <TableCell className=\"text-right\">\n <ActionMenu\n ariaLabel={`Actions for ${source.name}`}\n entityName={source.name}\n onEdit={() => navigate(`sources/${source.id}/edit`)}\n onDelete={() => handleArchive(source)}\n deleteLabel=\"Archive source\"\n extraItems={[\n {\n key: 'mark-synced',\n label: 'Mark synced',\n icon: RefreshCw,\n onSelect: () => void handleMarkSynced(source),\n },\n ]}\n />\n </TableCell>\n </TableRow>\n ))}\n </TableBody>\n </Table>\n </div>\n\n <Pagination\n offset={pagination.offset}\n limit={pagination.limit}\n loadedCount={sources.length}\n hasMore={pageInfo?.hasMore ?? false}\n onPrev={pagination.prevPage}\n onNext={pagination.nextPage}\n itemLabel=\"sources\"\n loading={loading}\n />\n </>\n );\n };\n\n return (\n <PageLayout\n title=\"Data sources\"\n description=\"Instruments, archives and feeds that supply raw data into your federation.\"\n actions={newButton}\n >\n <div className=\"space-y-4\">\n <div className=\"flex flex-wrap items-center gap-3\">\n <div className=\"w-full max-w-[14rem]\">\n <Select value={typeFilter} onValueChange={setTypeFilter}>\n <SelectTrigger aria-label=\"Filter by type\">\n <SelectValue placeholder=\"All types\" />\n </SelectTrigger>\n <SelectContent>\n <SelectItem value={ALL}>All types</SelectItem>\n {SOURCE_TYPES.map((type) => (\n <SelectItem key={type} value={type}>\n {formatEnumLabel(type)}\n </SelectItem>\n ))}\n </SelectContent>\n </Select>\n </div>\n <div className=\"w-full max-w-[14rem]\">\n <Select value={statusFilter} onValueChange={setStatusFilter}>\n <SelectTrigger aria-label=\"Filter by status\">\n <SelectValue placeholder=\"All statuses\" />\n </SelectTrigger>\n <SelectContent>\n <SelectItem value={ALL}>All statuses</SelectItem>\n {SOURCE_STATUSES.map((status) => (\n <SelectItem key={status} value={status}>\n {formatEnumLabel(status)}\n </SelectItem>\n ))}\n </SelectContent>\n </Select>\n </div>\n </div>\n\n {renderBody()}\n </div>\n </PageLayout>\n );\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"SourcesPage.js","names":[],"sources":["../../../../src/cosmicintersection/pages/sources/SourcesPage.tsx"],"sourcesContent":["import { useMemo, useState } from 'react';\nimport { Plus, RefreshCw, Radio } from 'lucide-react';\nimport {\n Badge,\n Button,\n Select,\n SelectContent,\n SelectItem,\n SelectTrigger,\n SelectValue,\n Table,\n TableBody,\n TableCell,\n TableHead,\n TableHeader,\n TableRow,\n} from '@burdenoff/fe-libs/ui';\n\nimport {\n useCosArchiveSourceMutation,\n useCosMarkSourceSyncedMutation,\n useCosSourcesQuery,\n type CosSource,\n type CosSourceStatus,\n type CosSourceType,\n} from '../../api/cosmicApi';\nimport {\n ActionMenu,\n EmptyState,\n ErrorState,\n LoadingState,\n PageLayout,\n Pagination,\n SafeLink,\n StatusBadge,\n formatEnumLabel,\n usePagination,\n} from '../../components';\nimport { useCosmicIntersection } from '../../context/CosmicIntersectionContext';\nimport { notify } from '../../lib/toast';\n\nconst ALL = 'ALL';\n\nconst SOURCE_TYPES: CosSourceType[] = [\n 'TELESCOPE',\n 'SATELLITE',\n 'GROUND_SENSOR',\n 'ARCHIVE',\n 'API',\n 'STREAM',\n 'FILE_DROP',\n 'SIMULATION',\n];\n\nconst SOURCE_STATUSES: CosSourceStatus[] = [\n 'CONFIGURING',\n 'CONNECTED',\n 'SYNCING',\n 'DEGRADED',\n 'ERROR',\n 'DISABLED',\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\nexport default function SourcesPage() {\n const { navigate } = useCosmicIntersection();\n const [typeFilter, setTypeFilter] = useState<string>(ALL);\n const [statusFilter, setStatusFilter] = useState<string>(ALL);\n const pagination = usePagination({ pageSize: 20, resetKey: `${typeFilter}|${statusFilter}` });\n\n const { data, loading, error, refetch } = useCosSourcesQuery({\n type: typeFilter === ALL ? undefined : (typeFilter as CosSourceType),\n status: statusFilter === ALL ? undefined : (statusFilter as CosSourceStatus),\n pagination: { limit: pagination.limit, offset: pagination.offset },\n });\n\n const [markSynced] = useCosMarkSourceSyncedMutation();\n const [archiveSource] = useCosArchiveSourceMutation();\n\n const sources = useMemo(() => data?.cosListSources.items ?? [], [data]);\n const pageInfo = data?.cosListSources.pageInfo;\n\n const handleMarkSynced = async (source: CosSource) => {\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 (source: CosSource) => {\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 await refetch();\n };\n\n const newButton = (\n <Button type=\"button\" onClick={() => navigate('sources/create')}>\n <Plus className=\"size-4\" />\n New source\n </Button>\n );\n\n const renderBody = () => {\n if (loading) {\n return <LoadingState variant=\"rows\" rows={6} label=\"Loading sources…\" />;\n }\n if (error) {\n return <ErrorState message={error.message} onRetry={() => void refetch()} />;\n }\n if (sources.length === 0) {\n const filtered = typeFilter !== ALL || statusFilter !== ALL;\n return (\n <EmptyState\n icon={Radio}\n title={filtered ? 'No sources match these filters' : 'No data sources yet'}\n description={\n filtered\n ? 'Try clearing the type or status filter to see more sources.'\n : 'Connect a telescope, satellite feed, archive or API to start ingesting scientific data.'\n }\n action={filtered ? undefined : newButton}\n />\n );\n }\n\n return (\n <>\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>Type</TableHead>\n <TableHead>Status</TableHead>\n <TableHead>Endpoint</TableHead>\n <TableHead>Last synced</TableHead>\n <TableHead>Tags</TableHead>\n <TableHead className=\"text-right\">Actions</TableHead>\n </TableRow>\n </TableHeader>\n <TableBody>\n {sources.map((source) => (\n <TableRow\n key={source.id}\n className=\"cursor-pointer\"\n onClick={() => navigate(`sources/${source.id}`)}\n >\n <TableCell>\n <div className=\"font-medium text-text-primary\">{source.name}</div>\n {source.description ? (\n <div className=\"mt-0.5 line-clamp-1 max-w-xs text-xs text-text-secondary\">\n {source.description}\n </div>\n ) : null}\n </TableCell>\n <TableCell>\n <Badge variant=\"secondary\">{formatEnumLabel(source.type)}</Badge>\n </TableCell>\n <TableCell>\n <StatusBadge status={source.status} />\n </TableCell>\n <TableCell\n className=\"max-w-[16rem]\"\n onClick={(event) => event.stopPropagation()}\n >\n {source.endpoint ? (\n <SafeLink\n href={source.endpoint}\n className=\"block truncate text-sm text-text-primary underline-offset-2 hover:underline\"\n fallbackClassName=\"block truncate text-sm text-text-secondary\"\n >\n {source.endpoint}\n </SafeLink>\n ) : (\n <span className=\"text-sm text-text-secondary\">—</span>\n )}\n </TableCell>\n <TableCell className=\"whitespace-nowrap text-sm text-text-secondary\">\n {formatDate(source.lastSyncedAt)}\n </TableCell>\n <TableCell>\n <div className=\"flex max-w-[12rem] flex-wrap gap-1\">\n {source.tags.length === 0 ? (\n <span className=\"text-xs text-text-secondary\">—</span>\n ) : (\n source.tags.slice(0, 3).map((tag) => (\n <Badge key={tag} variant=\"outline\" className=\"text-xs\">\n {tag}\n </Badge>\n ))\n )}\n {source.tags.length > 3 ? (\n <span className=\"text-xs text-text-secondary\">\n +{source.tags.length - 3}\n </span>\n ) : null}\n </div>\n </TableCell>\n <TableCell className=\"text-right\">\n <ActionMenu\n ariaLabel={`Actions for ${source.name}`}\n entityName={source.name}\n onView={() => navigate(`sources/${source.id}`)}\n onEdit={() => navigate(`sources/${source.id}/edit`)}\n onDelete={() => handleArchive(source)}\n deleteLabel=\"Archive source\"\n extraItems={[\n {\n key: 'mark-synced',\n label: 'Mark synced',\n icon: RefreshCw,\n onSelect: () => void handleMarkSynced(source),\n },\n ]}\n />\n </TableCell>\n </TableRow>\n ))}\n </TableBody>\n </Table>\n </div>\n\n <Pagination\n offset={pagination.offset}\n limit={pagination.limit}\n loadedCount={sources.length}\n hasMore={pageInfo?.hasMore ?? false}\n onPrev={pagination.prevPage}\n onNext={pagination.nextPage}\n itemLabel=\"sources\"\n loading={loading}\n />\n </>\n );\n };\n\n return (\n <PageLayout\n title=\"Data sources\"\n description=\"Instruments, archives and feeds that supply raw data into your federation.\"\n actions={newButton}\n >\n <div className=\"space-y-4\">\n <div className=\"flex flex-wrap items-center gap-3\">\n <div className=\"w-full max-w-[14rem]\">\n <Select value={typeFilter} onValueChange={setTypeFilter}>\n <SelectTrigger aria-label=\"Filter by type\">\n <SelectValue placeholder=\"All types\" />\n </SelectTrigger>\n <SelectContent>\n <SelectItem value={ALL}>All types</SelectItem>\n {SOURCE_TYPES.map((type) => (\n <SelectItem key={type} value={type}>\n {formatEnumLabel(type)}\n </SelectItem>\n ))}\n </SelectContent>\n </Select>\n </div>\n <div className=\"w-full max-w-[14rem]\">\n <Select value={statusFilter} onValueChange={setStatusFilter}>\n <SelectTrigger aria-label=\"Filter by status\">\n <SelectValue placeholder=\"All statuses\" />\n </SelectTrigger>\n <SelectContent>\n <SelectItem value={ALL}>All statuses</SelectItem>\n {SOURCE_STATUSES.map((status) => (\n <SelectItem key={status} value={status}>\n {formatEnumLabel(status)}\n </SelectItem>\n ))}\n </SelectContent>\n </Select>\n </div>\n </div>\n\n {renderBody()}\n </div>\n </PageLayout>\n );\n}\n"],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@burdenoff/microfe-cosmicintersection",
3
- "version": "2026.704.1",
3
+ "version": "2026.704.2",
4
4
  "description": "Burdenoff CosmicIntersection Microfrontend",
5
5
  "type": "module",
6
6
  "files": [