@party-stack/ontology-devtools 0.6.0 → 0.6.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.
@@ -1,710 +1,1324 @@
1
- import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
1
+ import './styles.css';
2
+ /* empty css */
2
3
  import { Dialog } from "@base-ui/react/dialog";
3
4
  import { Menu } from "@base-ui/react/menu";
4
5
  import { Tabs } from "@base-ui/react/tabs";
5
6
  import { Tooltip } from "@base-ui/react/tooltip";
6
- import { Graph, layout as layoutGraph, } from "@dagrejs/dagre";
7
+ import { Graph, layout } from "@dagrejs/dagre";
7
8
  import NumberFlow from "@number-flow/react";
8
9
  import { LucideIcon } from "@party-stack/icons-lucide/react";
9
10
  import { createReactPlugin } from "@tanstack/devtools-utils/react";
10
11
  import { useLiveInfiniteQuery, useLiveQuery } from "@tanstack/react-db";
11
- import { createColumnHelper, flexRender, getCoreRowModel, useReactTable, } from "@tanstack/react-table";
12
- import { RefreshCw as ArrowPathIcon, GripVertical as Bars2Icon, CalendarDays as CalendarDaysIcon, Check as CheckIcon, CircleCheck as CheckCircleIcon, ChevronDown as ChevronDownIcon, ChevronUp as ChevronUpIcon, ChevronsUpDown as ChevronUpDownIcon, Database as CircleStackIcon, Clock as ClockIcon, SquareCode as CodeBracketSquareIcon, Hash as HashtagIcon, Inbox as InboxStackIcon, Link as LinkIcon, List as ListBulletIcon, Map as MapIcon, MapPin as MapPinIcon, Paperclip as PaperClipIcon, CircleQuestionMark as QuestionMarkCircleIcon, Share2 as ShareIcon, Grid2X2 as Squares2X2Icon, Trash2 as TrashIcon, Columns3 as ViewColumnsIcon, } from "lucide-react";
13
- import { useEffect, useId, useMemo, useState, } from "react";
14
- import "./styles.css";
15
- export function OntologyIcon({ className, color, name, }) {
16
- return (_jsx(LucideIcon, { "aria-hidden": "true", className: className, name: name, style: color ? { color } : undefined }));
12
+ import { columnOrderingFeature, columnResizingFeature, columnSizingFeature, columnVisibilityFeature, createColumnHelper, flexRender, rowSortingFeature, tableFeatures, useTable } from "@tanstack/react-table";
13
+ import { CalendarDays, Check, ChevronDown, ChevronUp, ChevronsUpDown, CircleCheck, CircleQuestionMark, Clock, Columns3, Database, Grid2X2, GripVertical, Hash, Inbox, Link, List, Map as Map$1, MapPin, Paperclip, RefreshCw, Share2, SquareCode, Trash2 } from "lucide-react";
14
+ import { useEffect, useId, useMemo, useState } from "react";
15
+ import { Fragment, jsx, jsxs } from "react/jsx-runtime";
16
+ //#region src/OntologyDevtools.tsx
17
+ function OntologyIcon({ className, color, name }) {
18
+ return /* @__PURE__ */ jsx(LucideIcon, {
19
+ "aria-hidden": "true",
20
+ className,
21
+ name,
22
+ style: color ? { color } : void 0
23
+ });
17
24
  }
18
- function ObjectTypeIcon({ className, objectType, }) {
19
- return (_jsx(OntologyIcon, { className: className, color: objectType.color, name: objectType.icon?.name ?? "database" }));
25
+ function ObjectTypeIcon({ className, objectType }) {
26
+ return /* @__PURE__ */ jsx(OntologyIcon, {
27
+ className,
28
+ color: objectType.color,
29
+ name: objectType.icon?.name ?? "database"
30
+ });
20
31
  }
21
32
  function PartyStackLogo({ theme }) {
22
- const id = useId().replaceAll(":", "");
23
- const gradientId = `ps-ball-${id}`;
24
- const shadowId = `ps-shadow-${id}`;
25
- return (_jsxs("svg", { "aria-hidden": "true", style: {
26
- display: "block",
27
- height: "100%",
28
- width: "100%",
29
- }, viewBox: "0 0 1200 300", children: [_jsxs("defs", { children: [_jsxs("radialGradient", { cx: "69%", cy: "24%", id: gradientId, r: "82%", children: [_jsx("stop", { offset: "0", stopColor: "#fff" }), _jsx("stop", { offset: ".38", stopColor: "#fff" }), _jsx("stop", { offset: ".62", stopColor: "#f8f7f3" }), _jsx("stop", { offset: ".82", stopColor: "#e1dfda" }), _jsx("stop", { offset: "1", stopColor: "#b7b3ad" })] }), _jsx("filter", { height: "170%", id: shadowId, width: "160%", x: "-30%", y: "-30%", children: _jsx("feDropShadow", { dx: "3", dy: "6", floodColor: "#681611", floodOpacity: ".28", stdDeviation: "5" }) })] }), _jsxs("g", { transform: "translate(22 22) scale(.5)", children: [_jsx("path", { d: "M96 64h184c81 0 136 55 136 136s-55 136-136 136h-56v112H96V64Z", fill: "#e83b32" }), _jsxs("g", { filter: `url(#${shadowId})`, children: [_jsx("circle", { cx: "258", cy: "200", fill: `url(#${gradientId})`, r: "60" }), _jsx("ellipse", { cx: "279", cy: "177", fill: "#fff", opacity: ".92", rx: "8.5", ry: "10.5" })] })] }), _jsx("text", { fill: theme === "dark" ? "#f7f5f0" : "#171717", fontFamily: "Avenir Next, Avenir, Helvetica Neue, Arial, sans-serif", fontSize: "124", fontWeight: "700", letterSpacing: "-3", x: "310", y: "196", children: "Party Stack" })] }));
33
+ const id = useId().replaceAll(":", "");
34
+ const gradientId = `ps-ball-${id}`;
35
+ const shadowId = `ps-shadow-${id}`;
36
+ return /* @__PURE__ */ jsxs("svg", {
37
+ "aria-hidden": "true",
38
+ style: {
39
+ display: "block",
40
+ height: "100%",
41
+ width: "100%"
42
+ },
43
+ viewBox: "0 0 1200 300",
44
+ children: [
45
+ /* @__PURE__ */ jsxs("defs", { children: [/* @__PURE__ */ jsxs("radialGradient", {
46
+ cx: "69%",
47
+ cy: "24%",
48
+ id: gradientId,
49
+ r: "82%",
50
+ children: [
51
+ /* @__PURE__ */ jsx("stop", {
52
+ offset: "0",
53
+ stopColor: "#fff"
54
+ }),
55
+ /* @__PURE__ */ jsx("stop", {
56
+ offset: ".38",
57
+ stopColor: "#fff"
58
+ }),
59
+ /* @__PURE__ */ jsx("stop", {
60
+ offset: ".62",
61
+ stopColor: "#f8f7f3"
62
+ }),
63
+ /* @__PURE__ */ jsx("stop", {
64
+ offset: ".82",
65
+ stopColor: "#e1dfda"
66
+ }),
67
+ /* @__PURE__ */ jsx("stop", {
68
+ offset: "1",
69
+ stopColor: "#b7b3ad"
70
+ })
71
+ ]
72
+ }), /* @__PURE__ */ jsx("filter", {
73
+ height: "170%",
74
+ id: shadowId,
75
+ width: "160%",
76
+ x: "-30%",
77
+ y: "-30%",
78
+ children: /* @__PURE__ */ jsx("feDropShadow", {
79
+ dx: "3",
80
+ dy: "6",
81
+ floodColor: "#681611",
82
+ floodOpacity: ".28",
83
+ stdDeviation: "5"
84
+ })
85
+ })] }),
86
+ /* @__PURE__ */ jsxs("g", {
87
+ transform: "translate(22 22) scale(.5)",
88
+ children: [/* @__PURE__ */ jsx("path", {
89
+ d: "M96 64h184c81 0 136 55 136 136s-55 136-136 136h-56v112H96V64Z",
90
+ fill: "#e83b32"
91
+ }), /* @__PURE__ */ jsxs("g", {
92
+ filter: `url(#${shadowId})`,
93
+ children: [/* @__PURE__ */ jsx("circle", {
94
+ cx: "258",
95
+ cy: "200",
96
+ fill: `url(#${gradientId})`,
97
+ r: "60"
98
+ }), /* @__PURE__ */ jsx("ellipse", {
99
+ cx: "279",
100
+ cy: "177",
101
+ fill: "#fff",
102
+ opacity: ".92",
103
+ rx: "8.5",
104
+ ry: "10.5"
105
+ })]
106
+ })]
107
+ }),
108
+ /* @__PURE__ */ jsx("text", {
109
+ fill: theme === "dark" ? "#f7f5f0" : "#171717",
110
+ fontFamily: "Avenir Next, Avenir, Helvetica Neue, Arial, sans-serif",
111
+ fontSize: "124",
112
+ fontWeight: "700",
113
+ letterSpacing: "-3",
114
+ x: "310",
115
+ y: "196",
116
+ children: "Party Stack"
117
+ })
118
+ ]
119
+ });
30
120
  }
31
121
  function PartyStackLogomark() {
32
- const id = useId().replaceAll(":", "");
33
- const gradientId = `ps-mark-ball-${id}`;
34
- const shadowId = `ps-mark-shadow-${id}`;
35
- return (_jsxs("svg", { "aria-hidden": "true", style: {
36
- display: "block",
37
- height: "100%",
38
- width: "100%",
39
- }, viewBox: "0 0 512 512", children: [_jsxs("defs", { children: [_jsxs("radialGradient", { cx: "69%", cy: "24%", id: gradientId, r: "82%", children: [_jsx("stop", { offset: "0", stopColor: "#fff" }), _jsx("stop", { offset: ".38", stopColor: "#fff" }), _jsx("stop", { offset: ".62", stopColor: "#f8f7f3" }), _jsx("stop", { offset: ".82", stopColor: "#e1dfda" }), _jsx("stop", { offset: "1", stopColor: "#b7b3ad" })] }), _jsx("filter", { height: "170%", id: shadowId, width: "160%", x: "-30%", y: "-30%", children: _jsx("feDropShadow", { dx: "3", dy: "6", floodColor: "#681611", floodOpacity: ".28", stdDeviation: "5" }) })] }), _jsx("path", { d: "M96 64h184c81 0 136 55 136 136s-55 136-136 136h-56v112H96V64Z", fill: "#e83b32" }), _jsxs("g", { filter: `url(#${shadowId})`, children: [_jsx("circle", { cx: "258", cy: "200", fill: `url(#${gradientId})`, r: "60" }), _jsx("ellipse", { cx: "279", cy: "177", fill: "#fff", opacity: ".92", rx: "8.5", ry: "10.5" })] })] }));
40
- }
41
- export function OntologyDevtoolsPluginName({ theme }) {
42
- return (_jsx("div", { style: { height: 30, width: 120 }, children: _jsx(PartyStackLogo, { theme: theme }) }));
43
- }
44
- export function OntologyDevtoolsTrigger({ theme }) {
45
- const dark = theme === "dark";
46
- return (_jsx("div", { "aria-label": "Open Ontology devtools", role: "button", style: {
47
- alignItems: "center",
48
- background: dark
49
- ? "linear-gradient(145deg, #2d2d31, #171719)"
50
- : "linear-gradient(145deg, #fff, #f5f5f4)",
51
- border: dark ? "1px solid rgba(255,255,255,.16)" : "1px solid rgba(23,23,23,.14)",
52
- borderRadius: "999px",
53
- boxSizing: "border-box",
54
- boxShadow: dark
55
- ? "0 10px 30px rgba(0,0,0,.34), 0 0 0 4px rgba(232,59,50,.11)"
56
- : "0 10px 28px rgba(28,25,23,.16), 0 0 0 4px rgba(232,59,50,.09)",
57
- cursor: "pointer",
58
- display: "flex",
59
- height: 48,
60
- justifyContent: "center",
61
- padding: 8,
62
- width: 48,
63
- }, title: "Open Ontology devtools", children: _jsx(PartyStackLogomark, {}) }));
64
- }
65
- export function ontologyDevtoolsTrigger(_element, { theme }) {
66
- return _jsx(OntologyDevtoolsTrigger, { theme: theme });
122
+ const id = useId().replaceAll(":", "");
123
+ const gradientId = `ps-mark-ball-${id}`;
124
+ const shadowId = `ps-mark-shadow-${id}`;
125
+ return /* @__PURE__ */ jsxs("svg", {
126
+ "aria-hidden": "true",
127
+ style: {
128
+ display: "block",
129
+ height: "100%",
130
+ width: "100%"
131
+ },
132
+ viewBox: "0 0 512 512",
133
+ children: [
134
+ /* @__PURE__ */ jsxs("defs", { children: [/* @__PURE__ */ jsxs("radialGradient", {
135
+ cx: "69%",
136
+ cy: "24%",
137
+ id: gradientId,
138
+ r: "82%",
139
+ children: [
140
+ /* @__PURE__ */ jsx("stop", {
141
+ offset: "0",
142
+ stopColor: "#fff"
143
+ }),
144
+ /* @__PURE__ */ jsx("stop", {
145
+ offset: ".38",
146
+ stopColor: "#fff"
147
+ }),
148
+ /* @__PURE__ */ jsx("stop", {
149
+ offset: ".62",
150
+ stopColor: "#f8f7f3"
151
+ }),
152
+ /* @__PURE__ */ jsx("stop", {
153
+ offset: ".82",
154
+ stopColor: "#e1dfda"
155
+ }),
156
+ /* @__PURE__ */ jsx("stop", {
157
+ offset: "1",
158
+ stopColor: "#b7b3ad"
159
+ })
160
+ ]
161
+ }), /* @__PURE__ */ jsx("filter", {
162
+ height: "170%",
163
+ id: shadowId,
164
+ width: "160%",
165
+ x: "-30%",
166
+ y: "-30%",
167
+ children: /* @__PURE__ */ jsx("feDropShadow", {
168
+ dx: "3",
169
+ dy: "6",
170
+ floodColor: "#681611",
171
+ floodOpacity: ".28",
172
+ stdDeviation: "5"
173
+ })
174
+ })] }),
175
+ /* @__PURE__ */ jsx("path", {
176
+ d: "M96 64h184c81 0 136 55 136 136s-55 136-136 136h-56v112H96V64Z",
177
+ fill: "#e83b32"
178
+ }),
179
+ /* @__PURE__ */ jsxs("g", {
180
+ filter: `url(#${shadowId})`,
181
+ children: [/* @__PURE__ */ jsx("circle", {
182
+ cx: "258",
183
+ cy: "200",
184
+ fill: `url(#${gradientId})`,
185
+ r: "60"
186
+ }), /* @__PURE__ */ jsx("ellipse", {
187
+ cx: "279",
188
+ cy: "177",
189
+ fill: "#fff",
190
+ opacity: ".92",
191
+ rx: "8.5",
192
+ ry: "10.5"
193
+ })]
194
+ })
195
+ ]
196
+ });
197
+ }
198
+ function OntologyDevtoolsPluginName({ theme }) {
199
+ return /* @__PURE__ */ jsx("div", {
200
+ style: {
201
+ height: 30,
202
+ width: 120
203
+ },
204
+ children: /* @__PURE__ */ jsx(PartyStackLogo, { theme })
205
+ });
206
+ }
207
+ function OntologyDevtoolsTrigger({ theme }) {
208
+ const dark = theme === "dark";
209
+ return /* @__PURE__ */ jsx("div", {
210
+ "aria-label": "Open Ontology devtools",
211
+ style: {
212
+ alignItems: "center",
213
+ background: dark ? "linear-gradient(145deg, #2d2d31, #171719)" : "linear-gradient(145deg, #fff, #f5f5f4)",
214
+ border: dark ? "1px solid rgba(255,255,255,.16)" : "1px solid rgba(23,23,23,.14)",
215
+ borderRadius: "999px",
216
+ boxSizing: "border-box",
217
+ boxShadow: dark ? "0 10px 30px rgba(0,0,0,.34), 0 0 0 4px rgba(232,59,50,.11)" : "0 10px 28px rgba(28,25,23,.16), 0 0 0 4px rgba(232,59,50,.09)",
218
+ cursor: "pointer",
219
+ display: "flex",
220
+ height: 48,
221
+ justifyContent: "center",
222
+ padding: 8,
223
+ width: 48
224
+ },
225
+ title: "Open Ontology devtools",
226
+ children: /* @__PURE__ */ jsx(PartyStackLogomark, {})
227
+ });
228
+ }
229
+ function ontologyDevtoolsTrigger(_element, { theme }) {
230
+ return /* @__PURE__ */ jsx(OntologyDevtoolsTrigger, { theme });
67
231
  }
68
232
  function OutboxPanel({ children, theme }) {
69
- return (_jsx("div", { className: `ps-outbox-root ps-theme-${theme}`, children: _jsx("div", { className: "ps-outbox", children: children }) }));
233
+ return /* @__PURE__ */ jsx("div", {
234
+ className: `ps-outbox-root ps-theme-${theme}`,
235
+ children: /* @__PURE__ */ jsx("div", {
236
+ className: "ps-outbox",
237
+ children
238
+ })
239
+ });
70
240
  }
71
241
  function statusClass(entry) {
72
- return `ps-outbox-status ps-status-${entry.status}`;
242
+ return `ps-outbox-status ps-status-${entry.status}`;
73
243
  }
74
244
  function statusLabel(entry) {
75
- switch (entry.status) {
76
- case "queued":
77
- return "Waiting";
78
- case "executing":
79
- return "Running";
80
- case "failed":
81
- return "Failed";
82
- }
83
- }
84
- const relativeTime = new Intl.RelativeTimeFormat(undefined, { numeric: "auto" });
245
+ switch (entry.status) {
246
+ case "queued": return "Waiting";
247
+ case "executing": return "Running";
248
+ case "failed": return "Failed";
249
+ }
250
+ }
251
+ const relativeTime = new Intl.RelativeTimeFormat(void 0, { numeric: "auto" });
85
252
  function formatRelativeTime(timestamp, now) {
86
- const elapsedMs = Math.max(0, now - timestamp);
87
- if (elapsedMs < 60_000) {
88
- return "a few seconds ago";
89
- }
90
- const minutes = -Math.round(elapsedMs / 60_000);
91
- if (Math.abs(minutes) < 60) {
92
- return relativeTime.format(minutes, "minute");
93
- }
94
- const hours = Math.round(minutes / 60);
95
- if (Math.abs(hours) < 24) {
96
- return relativeTime.format(hours, "hour");
97
- }
98
- return relativeTime.format(Math.round(hours / 24), "day");
253
+ const elapsedMs = Math.max(0, now - timestamp);
254
+ if (elapsedMs < 6e4) return "a few seconds ago";
255
+ const minutes = -Math.round(elapsedMs / 6e4);
256
+ if (Math.abs(minutes) < 60) return relativeTime.format(minutes, "minute");
257
+ const hours = Math.round(minutes / 60);
258
+ if (Math.abs(hours) < 24) return relativeTime.format(hours, "hour");
259
+ return relativeTime.format(Math.round(hours / 24), "day");
99
260
  }
100
261
  function useRelativeTimeNow() {
101
- const [now, setNow] = useState(() => Date.now());
102
- useEffect(() => {
103
- const interval = setInterval(() => {
104
- setNow(Date.now());
105
- }, 60_000);
106
- return () => {
107
- clearInterval(interval);
108
- };
109
- }, []);
110
- return now;
262
+ const [now, setNow] = useState(() => Date.now());
263
+ useEffect(() => {
264
+ const interval = setInterval(() => {
265
+ setNow(Date.now());
266
+ }, 6e4);
267
+ return () => {
268
+ clearInterval(interval);
269
+ };
270
+ }, []);
271
+ return now;
111
272
  }
112
273
  function cardClass(entry) {
113
- return `ps-outbox-card ps-card-${entry.status}`;
114
- }
115
- function OutboxEntryCard({ entry, outbox, now, }) {
116
- const [pending, setPending] = useState();
117
- const [actionError, setActionError] = useState();
118
- const run = async (action) => {
119
- setPending(action);
120
- setActionError(undefined);
121
- try {
122
- if (action === "retry") {
123
- await outbox.retry(entry.id);
124
- }
125
- else {
126
- await outbox.remove(entry.id);
127
- }
128
- }
129
- catch (error) {
130
- setActionError(error instanceof Error ? error.message : String(error));
131
- }
132
- finally {
133
- setPending(undefined);
134
- }
135
- };
136
- return (_jsxs("article", { className: cardClass(entry), children: [_jsxs("div", { className: "ps-outbox-card-header", children: [_jsx("div", { className: "ps-outbox-name", children: entry.request.actionTypeName }), _jsxs("span", { className: statusClass(entry), children: [_jsx("span", { className: "ps-status-dot" }), statusLabel(entry)] })] }), _jsxs("div", { className: "ps-outbox-meta", children: [_jsxs("span", { children: [_jsx("strong", { children: entry.attempts }), " ", entry.attempts === 1 ? "attempt" : "attempts"] }), _jsx("span", { "aria-hidden": "true", className: "ps-outbox-meta-divider" }), _jsxs("span", { className: "ps-outbox-time", title: new Date(entry.createdAt).toLocaleString(), children: ["Queued ", formatRelativeTime(entry.createdAt, now)] }), !entry.retryable ? _jsx("span", { className: "ps-outbox-permanent", children: "Won't retry" }) : null] }), entry.lastError ? _jsx("div", { className: "ps-outbox-error", children: entry.lastError.message }) : null, _jsxs("details", { className: "ps-outbox-details", children: [_jsx("summary", { children: "Parameters" }), _jsx("pre", { children: JSON.stringify(entry.request.parameters, null, 2) })] }), _jsxs("div", { className: "ps-outbox-actions", children: [_jsxs("button", { className: "ps-button ps-button-primary", type: "button", disabled: !entry.retryable || entry.status === "executing" || pending !== undefined, onClick: () => {
137
- void run("retry");
138
- }, children: [_jsx(ArrowPathIcon, { "aria-hidden": "true" }), pending === "retry" ? "Retrying…" : "Retry"] }), _jsxs("button", { className: "ps-button ps-button-danger", type: "button", disabled: entry.status === "executing" || pending !== undefined, onClick: () => {
139
- void run("remove");
140
- }, children: [_jsx(TrashIcon, { "aria-hidden": "true" }), pending === "remove" ? "Removing…" : "Remove"] })] }), actionError ? _jsx("div", { className: "ps-outbox-action-error", children: actionError }) : null] }));
274
+ return `ps-outbox-card ps-card-${entry.status}`;
275
+ }
276
+ function OutboxEntryCard({ entry, outbox, now }) {
277
+ const [pending, setPending] = useState();
278
+ const [actionError, setActionError] = useState();
279
+ const run = async (action) => {
280
+ setPending(action);
281
+ setActionError(void 0);
282
+ try {
283
+ if (action === "retry") await outbox.retry(entry.id);
284
+ else await outbox.remove(entry.id);
285
+ } catch (error) {
286
+ setActionError(error instanceof Error ? error.message : String(error));
287
+ } finally {
288
+ setPending(void 0);
289
+ }
290
+ };
291
+ return /* @__PURE__ */ jsxs("article", {
292
+ className: cardClass(entry),
293
+ children: [
294
+ /* @__PURE__ */ jsxs("div", {
295
+ className: "ps-outbox-card-header",
296
+ children: [/* @__PURE__ */ jsx("div", {
297
+ className: "ps-outbox-name",
298
+ children: entry.request.actionTypeName
299
+ }), /* @__PURE__ */ jsxs("span", {
300
+ className: statusClass(entry),
301
+ children: [/* @__PURE__ */ jsx("span", { className: "ps-status-dot" }), statusLabel(entry)]
302
+ })]
303
+ }),
304
+ /* @__PURE__ */ jsxs("div", {
305
+ className: "ps-outbox-meta",
306
+ children: [
307
+ /* @__PURE__ */ jsxs("span", { children: [
308
+ /* @__PURE__ */ jsx("strong", { children: entry.attempts }),
309
+ " ",
310
+ entry.attempts === 1 ? "attempt" : "attempts"
311
+ ] }),
312
+ /* @__PURE__ */ jsx("span", {
313
+ "aria-hidden": "true",
314
+ className: "ps-outbox-meta-divider"
315
+ }),
316
+ /* @__PURE__ */ jsxs("span", {
317
+ className: "ps-outbox-time",
318
+ title: new Date(entry.createdAt).toLocaleString(),
319
+ children: ["Queued ", formatRelativeTime(entry.createdAt, now)]
320
+ }),
321
+ !entry.retryable ? /* @__PURE__ */ jsx("span", {
322
+ className: "ps-outbox-permanent",
323
+ children: "Won't retry"
324
+ }) : null
325
+ ]
326
+ }),
327
+ entry.lastError ? /* @__PURE__ */ jsx("div", {
328
+ className: "ps-outbox-error",
329
+ children: entry.lastError.message
330
+ }) : null,
331
+ /* @__PURE__ */ jsxs("details", {
332
+ className: "ps-outbox-details",
333
+ children: [/* @__PURE__ */ jsx("summary", { children: "Parameters" }), /* @__PURE__ */ jsx("pre", { children: JSON.stringify(entry.request.parameters, null, 2) })]
334
+ }),
335
+ /* @__PURE__ */ jsxs("div", {
336
+ className: "ps-outbox-actions",
337
+ children: [/* @__PURE__ */ jsxs("button", {
338
+ className: "ps-button ps-button-primary",
339
+ type: "button",
340
+ disabled: !entry.retryable || entry.status === "executing" || pending !== void 0,
341
+ onClick: () => {
342
+ run("retry");
343
+ },
344
+ children: [/* @__PURE__ */ jsx(RefreshCw, { "aria-hidden": "true" }), pending === "retry" ? "Retrying…" : "Retry"]
345
+ }), /* @__PURE__ */ jsxs("button", {
346
+ className: "ps-button ps-button-danger",
347
+ type: "button",
348
+ disabled: entry.status === "executing" || pending !== void 0,
349
+ onClick: () => {
350
+ run("remove");
351
+ },
352
+ children: [/* @__PURE__ */ jsx(Trash2, { "aria-hidden": "true" }), pending === "remove" ? "Removing…" : "Remove"]
353
+ })]
354
+ }),
355
+ actionError ? /* @__PURE__ */ jsx("div", {
356
+ className: "ps-outbox-action-error",
357
+ children: actionError
358
+ }) : null
359
+ ]
360
+ });
141
361
  }
142
362
  function OutboxRows({ outbox, theme }) {
143
- const now = useRelativeTimeNow();
144
- const { data } = useLiveQuery((query) => query.from({ entry: outbox.collection }).orderBy(({ entry }) => entry.sequence, "asc"), [outbox]);
145
- return (_jsx(OutboxPanel, { theme: theme, children: data.length === 0 ? (_jsx("div", { className: "ps-outbox-empty", children: _jsxs("div", { children: [_jsx("span", { className: "ps-outbox-empty-mark", children: _jsx(CheckIcon, { "aria-hidden": "true" }) }), _jsx("strong", { children: "Queue is clear" }), "Actions will appear here while they wait to sync."] }) })) : (_jsx("div", { className: "ps-outbox-track", children: data.map((entry, index) => (_jsxs("div", { className: "ps-outbox-step", children: [index > 0 ? _jsx("span", { "aria-hidden": "true", className: "ps-outbox-connector" }) : null, _jsx("div", { className: "ps-outbox-node", children: _jsx(OutboxEntryCard, { entry: entry, now: now, outbox: outbox }) })] }, entry.id))) })) }));
146
- }
147
- export function getOutboxActivity(entries) {
148
- if (entries.length === 0)
149
- return "idle";
150
- const head = entries.reduce((first, entry) => (entry.sequence < first.sequence ? entry : first));
151
- if (head.status === "failed")
152
- return "paused";
153
- return "draining";
363
+ const now = useRelativeTimeNow();
364
+ const { data } = useLiveQuery({ query: (query) => query.from({ entry: outbox.collection }).orderBy(({ entry }) => entry.sequence, "asc") });
365
+ return /* @__PURE__ */ jsx(OutboxPanel, {
366
+ theme,
367
+ children: data.length === 0 ? /* @__PURE__ */ jsx("div", {
368
+ className: "ps-outbox-empty",
369
+ children: /* @__PURE__ */ jsxs("div", { children: [
370
+ /* @__PURE__ */ jsx("span", {
371
+ className: "ps-outbox-empty-mark",
372
+ children: /* @__PURE__ */ jsx(Check, { "aria-hidden": "true" })
373
+ }),
374
+ /* @__PURE__ */ jsx("strong", { children: "Queue is clear" }),
375
+ "Actions will appear here while they wait to sync."
376
+ ] })
377
+ }) : /* @__PURE__ */ jsx("div", {
378
+ className: "ps-outbox-track",
379
+ children: data.map((entry, index) => /* @__PURE__ */ jsxs("div", {
380
+ className: "ps-outbox-step",
381
+ children: [index > 0 ? /* @__PURE__ */ jsx("span", {
382
+ "aria-hidden": "true",
383
+ className: "ps-outbox-connector"
384
+ }) : null, /* @__PURE__ */ jsx("div", {
385
+ className: "ps-outbox-node",
386
+ children: /* @__PURE__ */ jsx(OutboxEntryCard, {
387
+ entry,
388
+ now,
389
+ outbox
390
+ })
391
+ })]
392
+ }, entry.id))
393
+ })
394
+ });
395
+ }
396
+ function getOutboxActivity(entries) {
397
+ if (entries.length === 0) return "idle";
398
+ if (entries.reduce((first, entry) => entry.sequence < first.sequence ? entry : first).status === "failed") return "paused";
399
+ return "draining";
154
400
  }
155
401
  function outboxActivityLabel(activity) {
156
- switch (activity) {
157
- case "idle":
158
- return "Idle";
159
- case "draining":
160
- return "Draining";
161
- case "paused":
162
- return "Paused by failure";
163
- }
402
+ switch (activity) {
403
+ case "idle": return "Idle";
404
+ case "draining": return "Draining";
405
+ case "paused": return "Paused by failure";
406
+ }
164
407
  }
165
408
  function outboxBadgeClass(activity) {
166
- switch (activity) {
167
- case "idle":
168
- return "ps:bg-zinc-500/15 ps:text-zinc-400";
169
- case "draining":
170
- return "ps:bg-sky-500/20 ps:text-sky-300";
171
- case "paused":
172
- return "ps:bg-red-500/20 ps:text-red-300";
173
- }
409
+ switch (activity) {
410
+ case "idle": return "ps:bg-zinc-500/15 ps:text-zinc-400";
411
+ case "draining": return "ps:bg-sky-500/20 ps:text-sky-300";
412
+ case "paused": return "ps:bg-red-500/20 ps:text-red-300";
413
+ }
174
414
  }
175
415
  const ontologyViews = [
176
- { id: "outbox", label: "Outbox", icon: InboxStackIcon },
177
- { id: "schema", label: "Schema", icon: ShareIcon },
178
- { id: "objects", label: "Objects", icon: CircleStackIcon },
416
+ {
417
+ id: "outbox",
418
+ label: "Outbox",
419
+ icon: Inbox
420
+ },
421
+ {
422
+ id: "schema",
423
+ label: "Schema",
424
+ icon: Share2
425
+ },
426
+ {
427
+ id: "objects",
428
+ label: "Objects",
429
+ icon: Database
430
+ }
179
431
  ];
180
432
  function formatObjectValue(value) {
181
- if (value === undefined || value === null)
182
- return "—";
183
- if (typeof value === "string")
184
- return value;
185
- if (typeof value === "number" || typeof value === "boolean" || typeof value === "bigint") {
186
- return String(value);
187
- }
188
- try {
189
- return JSON.stringify(value);
190
- }
191
- catch {
192
- return "[Unserializable value]";
193
- }
433
+ if (value === void 0 || value === null) return "—";
434
+ if (typeof value === "string") return value;
435
+ if (typeof value === "number" || typeof value === "boolean" || typeof value === "bigint") return String(value);
436
+ try {
437
+ return JSON.stringify(value);
438
+ } catch {
439
+ return "[Unserializable value]";
440
+ }
194
441
  }
195
442
  const CONTINENTS = [
196
- "15,25 45,20 75,22 110,30 120,35 105,52 100,62 85,68 75,72 60,65 50,42 30,35",
197
- "100,82 118,80 138,90 140,100 130,118 118,132 108,138 100,122 95,100",
198
- "175,38 185,30 198,28 208,32 205,42 198,48 188,48 178,44",
199
- "170,58 185,52 205,56 218,68 215,88 208,108 198,125 185,128 172,112 168,88 165,70",
200
- "212,42 228,32 255,22 282,18 310,22 325,30 330,42 318,55 300,58 282,65 265,78 248,72 232,58 218,50",
201
- "292,112 312,108 332,114 330,126 318,134 298,128 292,118",
443
+ "15,25 45,20 75,22 110,30 120,35 105,52 100,62 85,68 75,72 60,65 50,42 30,35",
444
+ "100,82 118,80 138,90 140,100 130,118 118,132 108,138 100,122 95,100",
445
+ "175,38 185,30 198,28 208,32 205,42 198,48 188,48 178,44",
446
+ "170,58 185,52 205,56 218,68 215,88 208,108 198,125 185,128 172,112 168,88 165,70",
447
+ "212,42 228,32 255,22 282,18 310,22 325,30 330,42 318,55 300,58 282,65 265,78 248,72 232,58 218,50",
448
+ "292,112 312,108 332,114 330,126 318,134 298,128 292,118"
202
449
  ];
203
450
  function resolvedType(ir, type) {
204
- if (type.kind !== "ref")
205
- return type;
206
- const referenced = ir.types.find((candidate) => candidate.name === type.value.name)?.type;
207
- return referenced ? resolvedType(ir, referenced) : type;
208
- }
209
- export function typeDisplayName(ir, type) {
210
- switch (type.kind) {
211
- case "ref":
212
- return type.value.name;
213
- case "optional":
214
- return `${typeDisplayName(ir, type.value.type)} (optional)`;
215
- case "list":
216
- return `List of ${typeDisplayName(ir, type.value.elementType)}`;
217
- case "map":
218
- return `Map of ${typeDisplayName(ir, type.value.valueType)}`;
219
- case "objectReference":
220
- return `${type.value.objectType} reference`;
221
- case "string":
222
- return "String";
223
- case "boolean":
224
- return "Boolean";
225
- case "integer":
226
- return "Integer";
227
- case "float":
228
- return "Float";
229
- case "double":
230
- return "Double";
231
- case "date":
232
- return "Date";
233
- case "timestamp":
234
- return "Timestamp";
235
- case "geopoint":
236
- return "Geopoint";
237
- case "struct":
238
- return "Struct";
239
- case "union":
240
- return "Union";
241
- case "result":
242
- return "Result";
243
- case "attachment":
244
- return "Attachment";
245
- case "unknown":
246
- return "Unknown";
247
- }
451
+ if (type.kind !== "ref") return type;
452
+ const referenced = ir.types.find((candidate) => candidate.name === type.value.name)?.type;
453
+ return referenced ? resolvedType(ir, referenced) : type;
454
+ }
455
+ function typeDisplayName(type) {
456
+ switch (type.kind) {
457
+ case "ref": return type.value.name;
458
+ case "optional": return `${typeDisplayName(type.value.type)} (optional)`;
459
+ case "list": return `List of ${typeDisplayName(type.value.elementType)}`;
460
+ case "map": return `Map of ${typeDisplayName(type.value.valueType)}`;
461
+ case "objectReference": return `${type.value.objectType} reference`;
462
+ case "string": return "String";
463
+ case "boolean": return "Boolean";
464
+ case "integer": return "Integer";
465
+ case "float": return "Float";
466
+ case "double": return "Double";
467
+ case "date": return "Date";
468
+ case "timestamp": return "Timestamp";
469
+ case "geopoint": return "Geopoint";
470
+ case "struct": return "Struct";
471
+ case "union": return "Union";
472
+ case "result": return "Result";
473
+ case "attachment": return "Attachment";
474
+ case "unknown": return "Unknown";
475
+ }
248
476
  }
249
477
  function typeIcon(type) {
250
- switch (type.kind) {
251
- case "ref":
252
- return LinkIcon;
253
- case "optional":
254
- return typeIcon(type.value.type);
255
- case "list":
256
- return ListBulletIcon;
257
- case "map":
258
- return Squares2X2Icon;
259
- case "objectReference":
260
- return LinkIcon;
261
- case "string":
262
- return CodeBracketSquareIcon;
263
- case "boolean":
264
- return CheckCircleIcon;
265
- case "integer":
266
- case "float":
267
- case "double":
268
- return HashtagIcon;
269
- case "date":
270
- return CalendarDaysIcon;
271
- case "timestamp":
272
- return ClockIcon;
273
- case "geopoint":
274
- return MapPinIcon;
275
- case "attachment":
276
- return PaperClipIcon;
277
- case "struct":
278
- case "union":
279
- case "result":
280
- return MapIcon;
281
- case "unknown":
282
- return QuestionMarkCircleIcon;
283
- }
478
+ switch (type.kind) {
479
+ case "ref": return Link;
480
+ case "optional": return typeIcon(type.value.type);
481
+ case "list": return List;
482
+ case "map": return Grid2X2;
483
+ case "objectReference": return Link;
484
+ case "string": return SquareCode;
485
+ case "boolean": return CircleCheck;
486
+ case "integer":
487
+ case "float":
488
+ case "double": return Hash;
489
+ case "date": return CalendarDays;
490
+ case "timestamp": return Clock;
491
+ case "geopoint": return MapPin;
492
+ case "attachment": return Paperclip;
493
+ case "struct":
494
+ case "union":
495
+ case "result": return Map$1;
496
+ case "unknown": return CircleQuestionMark;
497
+ }
284
498
  }
285
499
  function DevtoolsTooltip({ children, label }) {
286
- return (_jsxs(Tooltip.Root, { children: [_jsx(Tooltip.Trigger, { render: _jsx("span", { className: "ps:inline-flex ps:items-center" }), children: children }), _jsx(Tooltip.Portal, { children: _jsx(Tooltip.Positioner, { className: "ps:z-[100001]", sideOffset: 6, children: _jsx(Tooltip.Popup, { className: "ps:max-w-64 ps:rounded-md ps:border ps:border-zinc-700 ps:bg-zinc-900 ps:px-2.5 ps:py-1.5 ps:text-[11px] ps:text-zinc-200 ps:shadow-xl", children: label }) }) })] }));
500
+ return /* @__PURE__ */ jsxs(Tooltip.Root, { children: [/* @__PURE__ */ jsx(Tooltip.Trigger, {
501
+ render: /* @__PURE__ */ jsx("span", { className: "ps:inline-flex ps:items-center" }),
502
+ children
503
+ }), /* @__PURE__ */ jsx(Tooltip.Portal, { children: /* @__PURE__ */ jsx(Tooltip.Positioner, {
504
+ className: "ps:z-[100001]",
505
+ sideOffset: 6,
506
+ children: /* @__PURE__ */ jsx(Tooltip.Popup, {
507
+ className: "ps:max-w-64 ps:rounded-md ps:border ps:border-zinc-700 ps:bg-zinc-900 ps:px-2.5 ps:py-1.5 ps:text-[11px] ps:text-zinc-200 ps:shadow-xl",
508
+ children: label
509
+ })
510
+ }) })] });
287
511
  }
288
- function TypeIndicator({ ir, type }) {
289
- const Icon = typeIcon(type);
290
- return (_jsx(DevtoolsTooltip, { label: typeDisplayName(ir, type), children: _jsx(Icon, { "aria-hidden": true, className: "ps:size-3.5 ps:text-zinc-500" }) }));
512
+ function TypeIndicator({ type }) {
513
+ const Icon = typeIcon(type);
514
+ return /* @__PURE__ */ jsx(DevtoolsTooltip, {
515
+ label: typeDisplayName(type),
516
+ children: /* @__PURE__ */ jsx(Icon, {
517
+ "aria-hidden": true,
518
+ className: "ps:size-3.5 ps:text-zinc-500"
519
+ })
520
+ });
291
521
  }
292
522
  function isGeopoint(value) {
293
- return (typeof value === "object" &&
294
- value !== null &&
295
- "lat" in value &&
296
- typeof value.lat === "number" &&
297
- "lon" in value &&
298
- typeof value.lon === "number");
523
+ return typeof value === "object" && value !== null && "lat" in value && typeof value.lat === "number" && "lon" in value && typeof value.lon === "number";
299
524
  }
300
525
  function GeopointPreview({ value }) {
301
- const cx = value.lon + 180;
302
- const cy = 90 - value.lat;
303
- const label = `${value.lat.toFixed(4)}, ${value.lon.toFixed(4)}`;
304
- return (_jsx(DevtoolsTooltip, { label: _jsxs("svg", { "aria-label": `Map preview for ${label}`, className: "ps:block ps:rounded ps:border ps:border-zinc-700", height: "72", role: "img", viewBox: "0 0 360 180", width: "144", children: [_jsx("rect", { className: "ps:fill-sky-950", height: "180", width: "360" }), CONTINENTS.map((points) => (_jsx("polygon", { className: "ps:fill-zinc-700 ps:stroke-zinc-600", points: points, strokeWidth: "0.5" }, points))), _jsx("circle", { className: "ps:fill-rose-400", cx: cx, cy: cy, r: "5" })] }), children: _jsx("a", { className: "ps:text-sky-400 ps:underline ps:decoration-dotted ps:underline-offset-4", href: `https://www.google.com/maps?q=${value.lat},${value.lon}`, rel: "noopener noreferrer", target: "_blank", children: label }) }));
305
- }
306
- export function timestampPreview(value) {
307
- if (value === undefined || value === null)
308
- return undefined;
309
- const exact = formatObjectValue(value);
310
- let epochMilliseconds;
311
- if (value instanceof Date) {
312
- epochMilliseconds = value.getTime();
313
- }
314
- else if (typeof value === "object" &&
315
- "epochMilliseconds" in value &&
316
- (typeof value.epochMilliseconds === "number" || typeof value.epochMilliseconds === "bigint")) {
317
- epochMilliseconds = Number(value.epochMilliseconds);
318
- }
319
- else if (typeof value === "string") {
320
- const parsed = Date.parse(value);
321
- if (!Number.isNaN(parsed))
322
- epochMilliseconds = parsed;
323
- }
324
- if (epochMilliseconds === undefined || !Number.isFinite(epochMilliseconds)) {
325
- return { display: exact, exact };
326
- }
327
- return {
328
- display: new Intl.DateTimeFormat(undefined, {
329
- dateStyle: "medium",
330
- timeStyle: "medium",
331
- }).format(new Date(epochMilliseconds)),
332
- exact,
333
- };
526
+ const cx = value.lon + 180;
527
+ const cy = 90 - value.lat;
528
+ const label = `${value.lat.toFixed(4)}, ${value.lon.toFixed(4)}`;
529
+ return /* @__PURE__ */ jsx(DevtoolsTooltip, {
530
+ label: /* @__PURE__ */ jsxs("svg", {
531
+ "aria-label": `Map preview for ${label}`,
532
+ className: "ps:block ps:rounded ps:border ps:border-zinc-700",
533
+ height: "72",
534
+ role: "img",
535
+ viewBox: "0 0 360 180",
536
+ width: "144",
537
+ children: [
538
+ /* @__PURE__ */ jsx("rect", {
539
+ className: "ps:fill-sky-950",
540
+ height: "180",
541
+ width: "360"
542
+ }),
543
+ CONTINENTS.map((points) => /* @__PURE__ */ jsx("polygon", {
544
+ className: "ps:fill-zinc-700 ps:stroke-zinc-600",
545
+ points,
546
+ strokeWidth: "0.5"
547
+ }, points)),
548
+ /* @__PURE__ */ jsx("circle", {
549
+ className: "ps:fill-rose-400",
550
+ cx,
551
+ cy,
552
+ r: "5"
553
+ })
554
+ ]
555
+ }),
556
+ children: /* @__PURE__ */ jsx("a", {
557
+ className: "ps:text-sky-400 ps:underline ps:decoration-dotted ps:underline-offset-4",
558
+ href: `https://www.google.com/maps?q=${value.lat},${value.lon}`,
559
+ rel: "noopener noreferrer",
560
+ target: "_blank",
561
+ children: label
562
+ })
563
+ });
564
+ }
565
+ function timestampPreview(value) {
566
+ if (value === void 0 || value === null) return void 0;
567
+ const exact = formatObjectValue(value);
568
+ let epochMilliseconds;
569
+ if (value instanceof Date) epochMilliseconds = value.getTime();
570
+ else if (typeof value === "object" && "epochMilliseconds" in value && (typeof value.epochMilliseconds === "number" || typeof value.epochMilliseconds === "bigint")) epochMilliseconds = Number(value.epochMilliseconds);
571
+ else if (typeof value === "string") {
572
+ const parsed = Date.parse(value);
573
+ if (!Number.isNaN(parsed)) epochMilliseconds = parsed;
574
+ }
575
+ if (epochMilliseconds === void 0 || !Number.isFinite(epochMilliseconds)) return {
576
+ display: exact,
577
+ exact
578
+ };
579
+ return {
580
+ display: new Intl.DateTimeFormat(void 0, {
581
+ dateStyle: "medium",
582
+ timeStyle: "medium"
583
+ }).format(new Date(epochMilliseconds)),
584
+ exact
585
+ };
334
586
  }
335
587
  function isAttachment(value) {
336
- return typeof value === "object" && value !== null && "id" in value && typeof value.id === "string";
588
+ return typeof value === "object" && value !== null && "id" in value && typeof value.id === "string";
337
589
  }
338
590
  function AttachmentPreview({ attachment, ontology }) {
339
- const [preview, setPreview] = useState();
340
- useEffect(() => {
341
- let cancelled = false;
342
- let objectUrl;
343
- void ontology.attachments
344
- .metadata(attachment)
345
- .then(async (metadata) => {
346
- if (metadata.type.startsWith("image/")) {
347
- objectUrl = URL.createObjectURL(await ontology.attachments.blob(attachment));
348
- }
349
- if (!cancelled)
350
- setPreview({ metadata, src: objectUrl });
351
- })
352
- .catch(() => {
353
- if (!cancelled)
354
- setPreview(undefined);
355
- });
356
- return () => {
357
- cancelled = true;
358
- if (objectUrl)
359
- URL.revokeObjectURL(objectUrl);
360
- };
361
- }, [attachment, ontology]);
362
- const label = preview?.metadata.name ?? attachment.id;
363
- if (!preview?.src) {
364
- return (_jsx(DevtoolsTooltip, { label: label, children: _jsxs("span", { className: "ps:inline-flex ps:max-w-40 ps:items-center ps:gap-1.5 ps:truncate", children: [_jsx(PaperClipIcon, { "aria-hidden": true, className: "ps:size-3.5 ps:flex-none ps:text-zinc-500" }), _jsx("span", { className: "ps:truncate", children: label })] }) }));
365
- }
366
- return (_jsxs(Dialog.Root, { children: [_jsx(Dialog.Trigger, { "aria-label": `Open ${label}`, className: "ps:block ps:overflow-hidden ps:rounded-md ps:border ps:border-zinc-700 ps:bg-transparent ps:p-0 ps:hover:border-rose-400", children: _jsx("img", { alt: label, className: "ps:size-10 ps:object-cover", src: preview.src }) }), _jsxs(Dialog.Portal, { children: [_jsx(Dialog.Backdrop, { className: "ps:fixed ps:inset-0 ps:z-[100002] ps:bg-black/75 ps:backdrop-blur-sm" }), _jsx(Dialog.Viewport, { className: "ps:fixed ps:inset-0 ps:z-[100003] ps:grid ps:place-items-center ps:p-8", children: _jsxs(Dialog.Popup, { className: "ps:relative ps:max-h-full ps:max-w-4xl ps:rounded-xl ps:border ps:border-zinc-700 ps:bg-zinc-950 ps:p-3 ps:shadow-2xl", children: [_jsx(Dialog.Title, { className: "ps:sr-only", children: label }), _jsx("img", { alt: label, className: "ps:max-h-[80vh] ps:max-w-[80vw] ps:rounded-lg ps:object-contain", src: preview.src }), _jsx(Dialog.Close, { className: "ps:absolute ps:top-4 ps:right-4 ps:rounded-md ps:border ps:border-zinc-600 ps:bg-zinc-950/90 ps:px-2.5 ps:py-1.5 ps:text-xs ps:text-white", children: "Close" })] }) })] })] }));
367
- }
368
- function PropertyValuePreview({ ir, ontology, type, value, }) {
369
- const resolved = resolvedType(ir, type);
370
- if (resolved.kind === "optional") {
371
- return _jsx(PropertyValuePreview, { ir: ir, ontology: ontology, type: resolved.value.type, value: value });
372
- }
373
- if (resolved.kind === "geopoint" && isGeopoint(value)) {
374
- return _jsx(GeopointPreview, { value: value });
375
- }
376
- if (resolved.kind === "timestamp") {
377
- const preview = timestampPreview(value);
378
- if (preview) {
379
- return (_jsx(DevtoolsTooltip, { label: preview.exact, children: _jsx("span", { children: preview.display }) }));
380
- }
381
- }
382
- if (resolved.kind === "attachment" && isAttachment(value)) {
383
- return _jsx(AttachmentPreview, { attachment: value, ontology: ontology });
384
- }
385
- if (resolved.kind === "list" &&
386
- resolvedType(ir, resolved.value.elementType).kind === "attachment" &&
387
- Array.isArray(value)) {
388
- const attachments = value.filter(isAttachment);
389
- if (attachments.length > 0) {
390
- return (_jsxs("div", { className: "ps:flex ps:items-center ps:gap-1.5", children: [attachments.slice(0, 3).map((attachment) => (_jsx(AttachmentPreview, { attachment: attachment, ontology: ontology }, attachment.id))), attachments.length > 3 ? (_jsxs("span", { className: "ps:text-zinc-500", children: ["+", attachments.length - 3] })) : null] }));
391
- }
392
- }
393
- const formatted = formatObjectValue(value);
394
- return (_jsx("span", { className: "ps:block ps:max-w-72 ps:truncate", title: formatted, children: formatted }));
591
+ const [preview, setPreview] = useState();
592
+ useEffect(() => {
593
+ let cancelled = false;
594
+ let objectUrl;
595
+ ontology.attachments.metadata(attachment).then(async (metadata) => {
596
+ if (metadata.type.startsWith("image/")) objectUrl = URL.createObjectURL(await ontology.attachments.blob(attachment));
597
+ if (!cancelled) setPreview({
598
+ metadata,
599
+ src: objectUrl
600
+ });
601
+ }).catch(() => {
602
+ if (!cancelled) setPreview(void 0);
603
+ });
604
+ return () => {
605
+ cancelled = true;
606
+ if (objectUrl) URL.revokeObjectURL(objectUrl);
607
+ };
608
+ }, [attachment, ontology]);
609
+ const label = preview?.metadata.name ?? attachment.id;
610
+ if (!preview?.src) return /* @__PURE__ */ jsx(DevtoolsTooltip, {
611
+ label,
612
+ children: /* @__PURE__ */ jsxs("span", {
613
+ className: "ps:inline-flex ps:max-w-40 ps:items-center ps:gap-1.5 ps:truncate",
614
+ children: [/* @__PURE__ */ jsx(Paperclip, {
615
+ "aria-hidden": true,
616
+ className: "ps:size-3.5 ps:flex-none ps:text-zinc-500"
617
+ }), /* @__PURE__ */ jsx("span", {
618
+ className: "ps:truncate",
619
+ children: label
620
+ })]
621
+ })
622
+ });
623
+ return /* @__PURE__ */ jsxs(Dialog.Root, { children: [/* @__PURE__ */ jsx(Dialog.Trigger, {
624
+ "aria-label": `Open ${label}`,
625
+ className: "ps:block ps:overflow-hidden ps:rounded-md ps:border ps:border-zinc-700 ps:bg-transparent ps:p-0 ps:hover:border-rose-400",
626
+ children: /* @__PURE__ */ jsx("img", {
627
+ alt: label,
628
+ className: "ps:size-10 ps:object-cover",
629
+ src: preview.src
630
+ })
631
+ }), /* @__PURE__ */ jsxs(Dialog.Portal, { children: [/* @__PURE__ */ jsx(Dialog.Backdrop, { className: "ps:fixed ps:inset-0 ps:z-[100002] ps:bg-black/75 ps:backdrop-blur-sm" }), /* @__PURE__ */ jsx(Dialog.Viewport, {
632
+ className: "ps:fixed ps:inset-0 ps:z-[100003] ps:grid ps:place-items-center ps:p-8",
633
+ children: /* @__PURE__ */ jsxs(Dialog.Popup, {
634
+ className: "ps:relative ps:max-h-full ps:max-w-4xl ps:rounded-xl ps:border ps:border-zinc-700 ps:bg-zinc-950 ps:p-3 ps:shadow-2xl",
635
+ children: [
636
+ /* @__PURE__ */ jsx(Dialog.Title, {
637
+ className: "ps:sr-only",
638
+ children: label
639
+ }),
640
+ /* @__PURE__ */ jsx("img", {
641
+ alt: label,
642
+ className: "ps:max-h-[80vh] ps:max-w-[80vw] ps:rounded-lg ps:object-contain",
643
+ src: preview.src
644
+ }),
645
+ /* @__PURE__ */ jsx(Dialog.Close, {
646
+ className: "ps:absolute ps:top-4 ps:right-4 ps:rounded-md ps:border ps:border-zinc-600 ps:bg-zinc-950/90 ps:px-2.5 ps:py-1.5 ps:text-xs ps:text-white",
647
+ children: "Close"
648
+ })
649
+ ]
650
+ })
651
+ })] })] });
652
+ }
653
+ function PropertyValuePreview({ ir, ontology, type, value }) {
654
+ const resolved = resolvedType(ir, type);
655
+ if (resolved.kind === "optional") return /* @__PURE__ */ jsx(PropertyValuePreview, {
656
+ ir,
657
+ ontology,
658
+ type: resolved.value.type,
659
+ value
660
+ });
661
+ if (resolved.kind === "geopoint" && isGeopoint(value)) return /* @__PURE__ */ jsx(GeopointPreview, { value });
662
+ if (resolved.kind === "timestamp") {
663
+ const preview = timestampPreview(value);
664
+ if (preview) return /* @__PURE__ */ jsx(DevtoolsTooltip, {
665
+ label: preview.exact,
666
+ children: /* @__PURE__ */ jsx("span", { children: preview.display })
667
+ });
668
+ }
669
+ if (resolved.kind === "attachment" && isAttachment(value)) return /* @__PURE__ */ jsx(AttachmentPreview, {
670
+ attachment: value,
671
+ ontology
672
+ });
673
+ if (resolved.kind === "list" && resolvedType(ir, resolved.value.elementType).kind === "attachment" && Array.isArray(value)) {
674
+ const attachments = value.filter(isAttachment);
675
+ if (attachments.length > 0) return /* @__PURE__ */ jsxs("div", {
676
+ className: "ps:flex ps:items-center ps:gap-1.5",
677
+ children: [attachments.slice(0, 3).map((attachment) => /* @__PURE__ */ jsx(AttachmentPreview, {
678
+ attachment,
679
+ ontology
680
+ }, attachment.id)), attachments.length > 3 ? /* @__PURE__ */ jsxs("span", {
681
+ className: "ps:text-zinc-500",
682
+ children: ["+", attachments.length - 3]
683
+ }) : null]
684
+ });
685
+ }
686
+ const formatted = formatObjectValue(value);
687
+ return /* @__PURE__ */ jsx("span", {
688
+ className: "ps:block ps:max-w-72 ps:truncate",
689
+ title: formatted,
690
+ children: formatted
691
+ });
395
692
  }
396
693
  function defaultColumnSize(ir, type) {
397
- switch (resolvedType(ir, type).kind) {
398
- case "boolean":
399
- return 110;
400
- case "integer":
401
- case "float":
402
- case "double":
403
- return 130;
404
- case "date":
405
- case "timestamp":
406
- return 190;
407
- case "geopoint":
408
- return 175;
409
- case "attachment":
410
- case "list":
411
- return 150;
412
- case "objectReference":
413
- return 200;
414
- case "string":
415
- return 220;
416
- default:
417
- return 180;
418
- }
419
- }
420
- export function moveColumn(columnOrder, sourceId, targetId) {
421
- const sourceIndex = columnOrder.indexOf(sourceId);
422
- const targetIndex = columnOrder.indexOf(targetId);
423
- if (sourceIndex === -1 || targetIndex === -1 || sourceIndex === targetIndex) {
424
- return columnOrder;
425
- }
426
- const next = [...columnOrder];
427
- next.splice(sourceIndex, 1);
428
- next.splice(targetIndex, 0, sourceId);
429
- return next;
694
+ switch (resolvedType(ir, type).kind) {
695
+ case "boolean": return 110;
696
+ case "integer":
697
+ case "float":
698
+ case "double": return 130;
699
+ case "date":
700
+ case "timestamp": return 190;
701
+ case "geopoint": return 175;
702
+ case "attachment":
703
+ case "list": return 150;
704
+ case "objectReference": return 200;
705
+ case "string": return 220;
706
+ default: return 180;
707
+ }
708
+ }
709
+ function moveColumn(columnOrder, sourceId, targetId) {
710
+ const sourceIndex = columnOrder.indexOf(sourceId);
711
+ const targetIndex = columnOrder.indexOf(targetId);
712
+ if (sourceIndex === -1 || targetIndex === -1 || sourceIndex === targetIndex) return columnOrder;
713
+ const next = [...columnOrder];
714
+ next.splice(sourceIndex, 1);
715
+ next.splice(targetIndex, 0, sourceId);
716
+ return next;
430
717
  }
718
+ const objectTableFeatures = tableFeatures({
719
+ rowSortingFeature,
720
+ columnOrderingFeature,
721
+ columnSizingFeature,
722
+ columnResizingFeature,
723
+ columnVisibilityFeature
724
+ });
431
725
  const objectColumnHelper = createColumnHelper();
432
- function ObjectTable({ collection, objectType, ontology, pageSize, }) {
433
- const [sorting, setSorting] = useState([]);
434
- const [columnSizing, setColumnSizing] = useState({});
435
- const [columnVisibility, setColumnVisibility] = useState({});
436
- const [columnOrder, setColumnOrder] = useState(() => objectType.properties.map((property) => property.name));
437
- const [draggedColumnId, setDraggedColumnId] = useState();
438
- const [dragOverColumnId, setDragOverColumnId] = useState();
439
- const selectedSort = sorting[0];
440
- const { data, fetchNextPage, hasNextPage, isFetchingNextPage } = useLiveInfiniteQuery((query) => {
441
- const from = query.from({ row: collection });
442
- const primaryKey = objectType.primaryKey;
443
- if (selectedSort && selectedSort.id !== primaryKey) {
444
- return from
445
- .orderBy(({ row }) => row[selectedSort.id], selectedSort.desc ? "desc" : "asc")
446
- .orderBy(({ row }) => row[primaryKey], "asc")
447
- .select(({ row }) => row);
448
- }
449
- return from
450
- .orderBy(({ row }) => row[primaryKey], selectedSort?.desc ? "desc" : "asc")
451
- .select(({ row }) => row);
452
- }, { pageSize }, [collection.id, objectType.primaryKey, pageSize, selectedSort?.id, selectedSort?.desc]);
453
- const rows = data;
454
- const columns = useMemo(() => objectType.properties.map((property) => objectColumnHelper.accessor((row) => row[property.name], {
455
- id: property.name,
456
- maxSize: 520,
457
- minSize: 90,
458
- size: property.name === objectType.primaryKey
459
- ? 220
460
- : defaultColumnSize(ontology.ir, property.type),
461
- header: () => (_jsxs("span", { className: "ps:inline-flex ps:items-center ps:gap-1.5", children: [_jsx(TypeIndicator, { ir: ontology.ir, type: property.type }), _jsx("span", { children: property.displayName }), property.name === objectType.primaryKey ? (_jsx("span", { className: "ps:ml-1.5 ps:text-[9px] ps:font-bold ps:tracking-wide ps:text-rose-400", children: "PK" })) : null] })),
462
- cell: (info) => (_jsx(PropertyValuePreview, { ir: ontology.ir, ontology: ontology, type: property.type, value: info.getValue() })),
463
- })), [objectType, ontology]);
464
- const table = useReactTable({
465
- columnResizeMode: "onEnd",
466
- columns,
467
- data: rows,
468
- enableColumnResizing: true,
469
- getCoreRowModel: getCoreRowModel(),
470
- getRowId: (row, index) => `${formatObjectValue(row[objectType.primaryKey])}-${index}`,
471
- manualSorting: true,
472
- onColumnOrderChange: setColumnOrder,
473
- onColumnSizingChange: setColumnSizing,
474
- onColumnVisibilityChange: setColumnVisibility,
475
- onSortingChange: setSorting,
476
- state: { columnOrder, columnSizing, columnVisibility, sorting },
477
- });
478
- const resizingColumnId = table.getState().columnSizingInfo.isResizingColumn;
479
- const resizingColumn = typeof resizingColumnId === "string" ? table.getColumn(resizingColumnId) : undefined;
480
- const allColumns = table.getAllLeafColumns();
481
- return (_jsxs("div", { className: "ps:flex ps:min-h-0 ps:min-w-0 ps:flex-1 ps:flex-col ps:overflow-hidden", children: [_jsxs("div", { className: "ps:flex ps:flex-none ps:items-center ps:border-b ps:border-zinc-500/20 ps:px-4 ps:py-2", children: [_jsxs("h2", { className: "ps:m-0 ps:flex ps:items-center ps:gap-2 ps:text-lg ps:font-semibold", children: [_jsx(ObjectTypeIcon, { className: "ps:size-5 ps:flex-none ps:text-rose-400", objectType: objectType }), objectType.pluralDisplayName] }), _jsxs("div", { className: "ps:ml-auto ps:flex ps:items-center ps:gap-1.5", children: [_jsxs("button", { className: "ps:inline-flex ps:items-center ps:gap-1.5 ps:rounded-md ps:border-0 ps:bg-transparent ps:px-2 ps:py-1.5 ps:text-xs ps:text-zinc-400 ps:hover:bg-zinc-500/10 ps:hover:text-current ps:disabled:opacity-40", disabled: Object.keys(columnSizing).length === 0, title: "Reset column widths", type: "button", onClick: () => {
482
- table.resetColumnSizing();
483
- }, children: [_jsx(ArrowPathIcon, { "aria-hidden": true, className: "ps:size-3.5" }), "Reset widths"] }), _jsxs(Menu.Root, { children: [_jsxs(Menu.Trigger, { className: "ps:inline-flex ps:items-center ps:gap-1.5 ps:rounded-md ps:border ps:border-zinc-500/30 ps:bg-zinc-500/10 ps:px-2.5 ps:py-1.5 ps:text-xs ps:text-inherit ps:hover:border-zinc-500/60", children: [_jsx(ViewColumnsIcon, { "aria-hidden": true, className: "ps:size-3.5" }), "Columns"] }), _jsx(Menu.Portal, { children: _jsx(Menu.Positioner, { align: "end", className: "ps:z-[100001]", sideOffset: 6, children: _jsx(Menu.Popup, { className: "ps:min-w-48 ps:rounded-lg ps:border ps:border-zinc-700 ps:bg-zinc-900 ps:p-1.5 ps:text-xs ps:text-zinc-200 ps:shadow-2xl", children: _jsxs(Menu.Group, { children: [_jsx(Menu.GroupLabel, { className: "ps:px-2 ps:py-1.5 ps:text-[10px] ps:font-bold ps:tracking-wider ps:text-zinc-500 ps:uppercase", children: "Columns" }), allColumns.map((column, columnIndex) => (_jsxs(Menu.CheckboxItem, { "aria-label": objectType.properties.find((property) => property.name === column.id)?.displayName ?? column.id, checked: column.getIsVisible(), className: dragOverColumnId === column.id &&
484
- draggedColumnId !== column.id
485
- ? "ps:flex ps:cursor-default ps:items-center ps:gap-2 ps:rounded-md ps:bg-rose-500/15 ps:px-2 ps:py-1.5 ps:outline-none"
486
- : "ps:flex ps:cursor-default ps:items-center ps:gap-2 ps:rounded-md ps:px-2 ps:py-1.5 ps:outline-none ps:data-[highlighted]:bg-zinc-700/70", draggable: true, label: objectType.properties.find((property) => property.name === column.id)?.displayName ?? column.id, onCheckedChange: (checked) => {
487
- column.toggleVisibility(checked);
488
- }, onDragEnd: () => {
489
- setDraggedColumnId(undefined);
490
- setDragOverColumnId(undefined);
491
- }, onDragOver: (event) => {
492
- event.preventDefault();
493
- event.dataTransfer.dropEffect = "move";
494
- setDragOverColumnId(column.id);
495
- }, onDragStart: (event) => {
496
- event.dataTransfer.effectAllowed = "move";
497
- event.dataTransfer.setData("text/plain", column.id);
498
- setDraggedColumnId(column.id);
499
- }, onDrop: (event) => {
500
- event.preventDefault();
501
- if (draggedColumnId && draggedColumnId !== column.id) {
502
- setColumnOrder((current) => moveColumn(current, draggedColumnId, column.id));
503
- }
504
- setDraggedColumnId(undefined);
505
- setDragOverColumnId(undefined);
506
- }, onKeyDown: (event) => {
507
- if (!event.altKey ||
508
- (event.key !== "ArrowUp" && event.key !== "ArrowDown")) {
509
- return;
510
- }
511
- event.preventDefault();
512
- const targetIndex = event.key === "ArrowUp"
513
- ? columnIndex - 1
514
- : columnIndex + 1;
515
- const target = allColumns[targetIndex];
516
- if (target) {
517
- setColumnOrder((current) => moveColumn(current, column.id, target.id));
518
- }
519
- }, children: [_jsx("span", { className: "ps:cursor-grab ps:text-zinc-500 ps:active:cursor-grabbing", title: "Drag to reorder", onClick: (event) => {
520
- event.stopPropagation();
521
- }, children: _jsx(Bars2Icon, { "aria-hidden": true, className: "ps:size-3.5" }) }), _jsx("span", { className: "ps:grid ps:size-4 ps:place-items-center ps:rounded ps:border ps:border-zinc-600", children: column.getIsVisible() ? (_jsx(CheckIcon, { "aria-hidden": true, className: "ps:size-3 ps:text-rose-400" })) : null }), _jsx("span", { className: "ps:truncate", children: objectType.properties.find((property) => property.name === column.id)?.displayName ?? column.id })] }, column.id))), _jsx("p", { className: "ps:m-0 ps:px-2 ps:pt-2 ps:pb-1 ps:text-[10px] ps:text-zinc-500", children: "Drag to reorder \u00B7 Alt+\u2191/\u2193 with keyboard" })] }) }) }) })] })] })] }), rows.length === 0 ? (_jsx("div", { className: "ps:m-4 ps:grid ps:min-h-40 ps:place-items-center ps:rounded-xl ps:border ps:border-dashed ps:border-zinc-500/40 ps:text-sm ps:text-zinc-500", children: "No objects loaded" })) : (_jsx("div", { className: "ps-object-table-scroll ps:min-h-0 ps:flex-1 ps:overflow-auto", children: _jsxs("div", { className: "ps:relative ps:min-h-full", style: { minWidth: "100%", width: table.getTotalSize() }, children: [_jsxs("table", { className: "ps:w-full ps:table-fixed ps:border-separate ps:border-spacing-0 ps:text-left ps:text-xs", children: [_jsx("colgroup", { children: table.getVisibleLeafColumns().map((column) => (_jsx("col", { style: { width: column.getSize() } }, column.id))) }), _jsx("thead", { className: "ps-object-table-header", children: table.getHeaderGroups().map((headerGroup) => (_jsx("tr", { children: headerGroup.headers.map((header) => {
522
- const direction = header.column.getIsSorted();
523
- return (_jsxs("th", { className: "ps:relative ps:border-b ps:border-zinc-500/30 ps:bg-zinc-950/95 ps:px-4 ps:py-3 ps:font-semibold ps:whitespace-nowrap ps:backdrop-blur ps:in-[.ps-theme-light]:bg-stone-50/95", children: [header.isPlaceholder ? null : (_jsxs("button", { className: "ps:flex ps:w-full ps:items-center ps:gap-2 ps:border-0 ps:bg-transparent ps:p-0 ps:text-left ps:text-inherit ps:font-inherit ps:hover:text-rose-400", title: `Sort by ${header.column.id}`, type: "button", onClick: header.column.getToggleSortingHandler(), children: [flexRender(header.column.columnDef.header, header.getContext()), direction === "asc" ? (_jsx(ChevronUpIcon, { "aria-hidden": true, className: "ps:size-3.5 ps:flex-none ps:text-rose-400" })) : direction === "desc" ? (_jsx(ChevronDownIcon, { "aria-hidden": true, className: "ps:size-3.5 ps:flex-none ps:text-rose-400" })) : (_jsx(ChevronUpDownIcon, { "aria-hidden": true, className: "ps:size-3.5 ps:flex-none ps:text-zinc-600" })), _jsx("span", { className: "ps:sr-only", children: direction === "asc"
524
- ? "Sorted ascending"
525
- : direction === "desc"
526
- ? "Sorted descending"
527
- : "Not sorted" })] })), header.column.getCanResize() ? (_jsx("button", { "aria-label": `Resize ${header.column.id} column`, "aria-orientation": "vertical", "aria-valuemax": header.column.columnDef.maxSize, "aria-valuemin": header.column.columnDef.minSize, "aria-valuenow": header.column.getSize(), className: header.column.getIsResizing()
528
- ? "ps:absolute ps:top-0 ps:right-0 ps:z-20 ps:h-full ps:w-1 ps:cursor-col-resize ps:touch-none ps:border-0 ps:bg-transparent ps:p-0"
529
- : resizingColumn
530
- ? "ps:pointer-events-none ps:invisible ps:absolute ps:top-0 ps:right-0 ps:h-full ps:w-1 ps:border-0 ps:bg-transparent ps:p-0"
531
- : "ps:absolute ps:top-0 ps:right-0 ps:h-full ps:w-1 ps:cursor-col-resize ps:touch-none ps:border-0 ps:bg-transparent ps:p-0 ps:hover:bg-rose-400/70 ps:focus-visible:bg-rose-400/70 ps:focus:outline-none", disabled: resizingColumn !== undefined &&
532
- !header.column.getIsResizing(), role: "separator", tabIndex: 0, type: "button", onDoubleClick: () => {
533
- header.column.resetSize();
534
- }, onKeyDown: (event) => {
535
- if (event.key !== "ArrowLeft" &&
536
- event.key !== "ArrowRight") {
537
- return;
538
- }
539
- event.preventDefault();
540
- const delta = event.key === "ArrowRight" ? 10 : -10;
541
- const min = header.column.columnDef.minSize ?? 20;
542
- const max = header.column.columnDef.maxSize ??
543
- Number.MAX_SAFE_INTEGER;
544
- setColumnSizing((current) => ({
545
- ...current,
546
- [header.column.id]: Math.min(max, Math.max(min, header.column.getSize() + delta)),
547
- }));
548
- }, onMouseDown: header.getResizeHandler(), onTouchStart: header.getResizeHandler() })) : null] }, header.id));
549
- }) }, headerGroup.id))) }), _jsx("tbody", { children: table.getRowModel().rows.map((row) => (_jsx("tr", { className: "ps:hover:bg-zinc-500/8", children: row.getVisibleCells().map((cell) => (_jsx("td", { className: "ps:max-w-80 ps:border-b ps:border-zinc-500/15 ps:px-4 ps:py-3 ps:text-[11px] ps:whitespace-nowrap", children: flexRender(cell.column.columnDef.cell, cell.getContext()) }, cell.id))) }, row.id))) })] }), hasNextPage ? (_jsx("div", { className: "ps:sticky ps:left-0 ps:flex ps:w-full ps:justify-center ps:border-t ps:border-zinc-500/20 ps:bg-zinc-950/95 ps:p-3 ps:in-[.ps-theme-light]:bg-stone-50/95", children: _jsx("button", { className: "ps:rounded-md ps:border ps:border-zinc-600 ps:bg-zinc-900 ps:px-3 ps:py-1.5 ps:text-xs ps:text-zinc-200 ps:hover:border-rose-400 ps:hover:text-rose-300 ps:disabled:opacity-50", disabled: isFetchingNextPage, type: "button", onClick: () => void fetchNextPage(), children: isFetchingNextPage
550
- ? "Loading…"
551
- : `Load ${pageSize} more` }) })) : null, resizingColumn ? (_jsx("div", { className: "ps:pointer-events-none ps:absolute ps:inset-y-0 ps:z-50 ps:w-0.5 ps:bg-rose-400 ps:shadow-[0_0_0_1px_rgba(251,113,133,0.18)] ps:will-change-transform", style: {
552
- left: resizingColumn.getStart() + resizingColumn.getSize(),
553
- transform: `translateX(${table.getState().columnSizingInfo.deltaOffset ?? 0}px)`,
554
- } })) : null] }) }))] }));
555
- }
556
- function ObjectsView({ ontology, pageSize = 50, }) {
557
- const objectTypes = ontology.ir.objectTypes;
558
- const [selectedName, setSelectedName] = useState(() => objectTypes[0]?.name);
559
- const selected = objectTypes.find((objectType) => objectType.name === selectedName) ?? objectTypes[0];
560
- const collection = selected ? ontology.objects[selected.name] : undefined;
561
- if (!selected || !collection) {
562
- return (_jsx("div", { className: "ps:grid ps:h-full ps:place-items-center ps:text-sm ps:text-zinc-500", children: "This ontology has no object types." }));
563
- }
564
- return (_jsxs("div", { className: "ps:flex ps:h-full ps:min-h-0 ps:w-full ps:min-w-0 ps:overflow-hidden", children: [_jsxs("aside", { className: "ps:w-44 ps:flex-none ps:overflow-y-auto ps:border-r ps:border-zinc-500/20 ps:p-3", children: [_jsx("p", { className: "ps:mt-0 ps:mb-2 ps:px-2 ps:text-[10px] ps:font-bold ps:tracking-[0.14em] ps:text-zinc-500 ps:uppercase", children: "Object types" }), _jsx("div", { className: "ps:flex ps:flex-col ps:gap-1", children: objectTypes.map((objectType) => (_jsxs("button", { className: objectType.name === selected.name
565
- ? "ps:flex ps:items-center ps:gap-2 ps:rounded-lg ps:border-0 ps:bg-rose-500/15 ps:px-2.5 ps:py-2 ps:text-left ps:text-xs ps:font-semibold ps:text-rose-400"
566
- : "ps:flex ps:items-center ps:gap-2 ps:rounded-lg ps:border-0 ps:bg-transparent ps:px-2.5 ps:py-2 ps:text-left ps:text-xs ps:text-inherit ps:hover:bg-zinc-500/10", type: "button", onClick: () => {
567
- setSelectedName(objectType.name);
568
- }, children: [_jsx(ObjectTypeIcon, { className: "ps:size-4 ps:flex-none", objectType: objectType }), _jsx("span", { className: "ps:truncate", children: objectType.pluralDisplayName })] }, objectType.name))) })] }), _jsx(ObjectTable, { collection: collection, objectType: selected, ontology: ontology, pageSize: pageSize }, selected.name)] }));
726
+ function ObjectTable({ collection, objectType, ontology, pageSize }) {
727
+ const [sorting, setSorting] = useState([]);
728
+ const [columnSizing, setColumnSizing] = useState({});
729
+ const [columnVisibility, setColumnVisibility] = useState({});
730
+ const [columnOrder, setColumnOrder] = useState(() => objectType.properties.map((property) => property.name));
731
+ const [draggedColumnId, setDraggedColumnId] = useState();
732
+ const [dragOverColumnId, setDragOverColumnId] = useState();
733
+ const selectedSort = sorting[0];
734
+ const { data, fetchNextPage, hasNextPage, isFetchingNextPage } = useLiveInfiniteQuery((query) => {
735
+ const from = query.from({ row: collection });
736
+ const primaryKey = objectType.primaryKey;
737
+ if (selectedSort && selectedSort.id !== primaryKey) return from.orderBy(({ row }) => row[selectedSort.id], selectedSort.desc ? "desc" : "asc").orderBy(({ row }) => row[primaryKey], "asc").select(({ row }) => row);
738
+ return from.orderBy(({ row }) => row[primaryKey], selectedSort?.desc ? "desc" : "asc").select(({ row }) => row);
739
+ }, { pageSize }, [
740
+ collection.id,
741
+ objectType.primaryKey,
742
+ pageSize,
743
+ selectedSort?.id,
744
+ selectedSort?.desc
745
+ ]);
746
+ const rows = data;
747
+ const columns = useMemo(() => objectType.properties.map((property) => objectColumnHelper.accessor((row) => row[property.name], {
748
+ id: property.name,
749
+ maxSize: 520,
750
+ minSize: 90,
751
+ size: property.name === objectType.primaryKey ? 220 : defaultColumnSize(ontology.ir, property.type),
752
+ header: () => /* @__PURE__ */ jsxs("span", {
753
+ className: "ps:inline-flex ps:items-center ps:gap-1.5",
754
+ children: [
755
+ /* @__PURE__ */ jsx(TypeIndicator, { type: property.type }),
756
+ /* @__PURE__ */ jsx("span", { children: property.displayName }),
757
+ property.name === objectType.primaryKey ? /* @__PURE__ */ jsx("span", {
758
+ className: "ps:ml-1.5 ps:text-[9px] ps:font-bold ps:tracking-wide ps:text-rose-400",
759
+ children: "PK"
760
+ }) : null
761
+ ]
762
+ }),
763
+ cell: (info) => /* @__PURE__ */ jsx(PropertyValuePreview, {
764
+ ir: ontology.ir,
765
+ ontology,
766
+ type: property.type,
767
+ value: info.getValue()
768
+ })
769
+ })), [objectType, ontology]);
770
+ const table = useTable({
771
+ features: objectTableFeatures,
772
+ columnResizeMode: "onEnd",
773
+ columns,
774
+ data: rows,
775
+ enableColumnResizing: true,
776
+ getRowId: (row, index) => `${formatObjectValue(row[objectType.primaryKey])}-${index}`,
777
+ manualSorting: true,
778
+ onColumnOrderChange: setColumnOrder,
779
+ onColumnSizingChange: setColumnSizing,
780
+ onColumnVisibilityChange: setColumnVisibility,
781
+ onSortingChange: setSorting,
782
+ state: {
783
+ columnOrder,
784
+ columnSizing,
785
+ columnVisibility,
786
+ sorting
787
+ }
788
+ });
789
+ const resizingColumnId = table.state.columnResizing.isResizingColumn;
790
+ const resizingColumn = typeof resizingColumnId === "string" ? table.getColumn(resizingColumnId) : void 0;
791
+ const allColumns = table.getAllLeafColumns();
792
+ return /* @__PURE__ */ jsxs("div", {
793
+ className: "ps:flex ps:min-h-0 ps:min-w-0 ps:flex-1 ps:flex-col ps:overflow-hidden",
794
+ children: [/* @__PURE__ */ jsxs("div", {
795
+ className: "ps:flex ps:flex-none ps:items-center ps:border-b ps:border-zinc-500/20 ps:px-4 ps:py-2",
796
+ children: [/* @__PURE__ */ jsxs("h2", {
797
+ className: "ps:m-0 ps:flex ps:items-center ps:gap-2 ps:text-lg ps:font-semibold",
798
+ children: [/* @__PURE__ */ jsx(ObjectTypeIcon, {
799
+ className: "ps:size-5 ps:flex-none ps:text-rose-400",
800
+ objectType
801
+ }), objectType.pluralDisplayName]
802
+ }), /* @__PURE__ */ jsxs("div", {
803
+ className: "ps:ml-auto ps:flex ps:items-center ps:gap-1.5",
804
+ children: [/* @__PURE__ */ jsxs("button", {
805
+ className: "ps:inline-flex ps:items-center ps:gap-1.5 ps:rounded-md ps:border-0 ps:bg-transparent ps:px-2 ps:py-1.5 ps:text-xs ps:text-zinc-400 ps:hover:bg-zinc-500/10 ps:hover:text-current ps:disabled:opacity-40",
806
+ disabled: Object.keys(columnSizing).length === 0,
807
+ title: "Reset column widths",
808
+ type: "button",
809
+ onClick: () => {
810
+ table.resetColumnSizing();
811
+ },
812
+ children: [/* @__PURE__ */ jsx(RefreshCw, {
813
+ "aria-hidden": true,
814
+ className: "ps:size-3.5"
815
+ }), "Reset widths"]
816
+ }), /* @__PURE__ */ jsxs(Menu.Root, { children: [/* @__PURE__ */ jsxs(Menu.Trigger, {
817
+ className: "ps:inline-flex ps:items-center ps:gap-1.5 ps:rounded-md ps:border ps:border-zinc-500/30 ps:bg-zinc-500/10 ps:px-2.5 ps:py-1.5 ps:text-xs ps:text-inherit ps:hover:border-zinc-500/60",
818
+ children: [/* @__PURE__ */ jsx(Columns3, {
819
+ "aria-hidden": true,
820
+ className: "ps:size-3.5"
821
+ }), "Columns"]
822
+ }), /* @__PURE__ */ jsx(Menu.Portal, { children: /* @__PURE__ */ jsx(Menu.Positioner, {
823
+ align: "end",
824
+ className: "ps:z-[100001]",
825
+ sideOffset: 6,
826
+ children: /* @__PURE__ */ jsx(Menu.Popup, {
827
+ className: "ps:min-w-48 ps:rounded-lg ps:border ps:border-zinc-700 ps:bg-zinc-900 ps:p-1.5 ps:text-xs ps:text-zinc-200 ps:shadow-2xl",
828
+ children: /* @__PURE__ */ jsxs(Menu.Group, { children: [
829
+ /* @__PURE__ */ jsx(Menu.GroupLabel, {
830
+ className: "ps:px-2 ps:py-1.5 ps:text-[10px] ps:font-bold ps:tracking-wider ps:text-zinc-500 ps:uppercase",
831
+ children: "Columns"
832
+ }),
833
+ allColumns.map((column, columnIndex) => /* @__PURE__ */ jsxs(Menu.CheckboxItem, {
834
+ "aria-label": objectType.properties.find((property) => property.name === column.id)?.displayName ?? column.id,
835
+ checked: column.getIsVisible(),
836
+ className: dragOverColumnId === column.id && draggedColumnId !== column.id ? "ps:flex ps:cursor-default ps:items-center ps:gap-2 ps:rounded-md ps:bg-rose-500/15 ps:px-2 ps:py-1.5 ps:outline-none" : "ps:flex ps:cursor-default ps:items-center ps:gap-2 ps:rounded-md ps:px-2 ps:py-1.5 ps:outline-none ps:data-[highlighted]:bg-zinc-700/70",
837
+ draggable: true,
838
+ label: objectType.properties.find((property) => property.name === column.id)?.displayName ?? column.id,
839
+ onCheckedChange: (checked) => {
840
+ column.toggleVisibility(checked);
841
+ },
842
+ onDragEnd: () => {
843
+ setDraggedColumnId(void 0);
844
+ setDragOverColumnId(void 0);
845
+ },
846
+ onDragOver: (event) => {
847
+ event.preventDefault();
848
+ event.dataTransfer.dropEffect = "move";
849
+ setDragOverColumnId(column.id);
850
+ },
851
+ onDragStart: (event) => {
852
+ event.dataTransfer.effectAllowed = "move";
853
+ event.dataTransfer.setData("text/plain", column.id);
854
+ setDraggedColumnId(column.id);
855
+ },
856
+ onDrop: (event) => {
857
+ event.preventDefault();
858
+ if (draggedColumnId && draggedColumnId !== column.id) setColumnOrder((current) => moveColumn(current, draggedColumnId, column.id));
859
+ setDraggedColumnId(void 0);
860
+ setDragOverColumnId(void 0);
861
+ },
862
+ onKeyDown: (event) => {
863
+ if (!event.altKey || event.key !== "ArrowUp" && event.key !== "ArrowDown") return;
864
+ event.preventDefault();
865
+ const targetIndex = event.key === "ArrowUp" ? columnIndex - 1 : columnIndex + 1;
866
+ const target = allColumns[targetIndex];
867
+ if (target) setColumnOrder((current) => moveColumn(current, column.id, target.id));
868
+ },
869
+ children: [
870
+ /* @__PURE__ */ jsx("span", {
871
+ "aria-hidden": "true",
872
+ className: "ps:cursor-grab ps:text-zinc-500 ps:active:cursor-grabbing",
873
+ title: "Drag to reorder",
874
+ onClick: (event) => {
875
+ event.stopPropagation();
876
+ },
877
+ children: /* @__PURE__ */ jsx(GripVertical, {
878
+ "aria-hidden": true,
879
+ className: "ps:size-3.5"
880
+ })
881
+ }),
882
+ /* @__PURE__ */ jsx("span", {
883
+ className: "ps:grid ps:size-4 ps:place-items-center ps:rounded ps:border ps:border-zinc-600",
884
+ children: column.getIsVisible() ? /* @__PURE__ */ jsx(Check, {
885
+ "aria-hidden": true,
886
+ className: "ps:size-3 ps:text-rose-400"
887
+ }) : null
888
+ }),
889
+ /* @__PURE__ */ jsx("span", {
890
+ className: "ps:truncate",
891
+ children: objectType.properties.find((property) => property.name === column.id)?.displayName ?? column.id
892
+ })
893
+ ]
894
+ }, column.id)),
895
+ /* @__PURE__ */ jsx("p", {
896
+ className: "ps:m-0 ps:px-2 ps:pt-2 ps:pb-1 ps:text-[10px] ps:text-zinc-500",
897
+ children: "Drag to reorder · Alt+↑/↓ with keyboard"
898
+ })
899
+ ] })
900
+ })
901
+ }) })] })]
902
+ })]
903
+ }), rows.length === 0 ? /* @__PURE__ */ jsx("div", {
904
+ className: "ps:m-4 ps:grid ps:min-h-40 ps:place-items-center ps:rounded-xl ps:border ps:border-dashed ps:border-zinc-500/40 ps:text-sm ps:text-zinc-500",
905
+ children: "No objects loaded"
906
+ }) : /* @__PURE__ */ jsx("div", {
907
+ className: "ps-object-table-scroll ps:min-h-0 ps:flex-1 ps:overflow-auto",
908
+ children: /* @__PURE__ */ jsxs("div", {
909
+ className: "ps:relative ps:min-h-full",
910
+ style: {
911
+ minWidth: "100%",
912
+ width: table.getTotalSize()
913
+ },
914
+ children: [
915
+ /* @__PURE__ */ jsxs("table", {
916
+ className: "ps:w-full ps:table-fixed ps:border-separate ps:border-spacing-0 ps:text-left ps:text-xs",
917
+ children: [
918
+ /* @__PURE__ */ jsx("colgroup", { children: table.getVisibleLeafColumns().map((column) => /* @__PURE__ */ jsx("col", { style: { width: column.getSize() } }, column.id)) }),
919
+ /* @__PURE__ */ jsx("thead", {
920
+ className: "ps-object-table-header",
921
+ children: table.getHeaderGroups().map((headerGroup) => /* @__PURE__ */ jsx("tr", { children: headerGroup.headers.map((header) => {
922
+ const direction = header.column.getIsSorted();
923
+ return /* @__PURE__ */ jsxs("th", {
924
+ className: "ps:relative ps:border-b ps:border-zinc-500/30 ps:bg-zinc-950/95 ps:px-4 ps:py-3 ps:font-semibold ps:whitespace-nowrap ps:backdrop-blur ps:in-[.ps-theme-light]:bg-stone-50/95",
925
+ children: [header.isPlaceholder ? null : /* @__PURE__ */ jsxs("button", {
926
+ className: "ps:flex ps:w-full ps:items-center ps:gap-2 ps:border-0 ps:bg-transparent ps:p-0 ps:text-left ps:text-inherit ps:font-inherit ps:hover:text-rose-400",
927
+ title: `Sort by ${header.column.id}`,
928
+ type: "button",
929
+ onClick: header.column.getToggleSortingHandler(),
930
+ children: [
931
+ flexRender(header.column.columnDef.header, header.getContext()),
932
+ direction === "asc" ? /* @__PURE__ */ jsx(ChevronUp, {
933
+ "aria-hidden": true,
934
+ className: "ps:size-3.5 ps:flex-none ps:text-rose-400"
935
+ }) : direction === "desc" ? /* @__PURE__ */ jsx(ChevronDown, {
936
+ "aria-hidden": true,
937
+ className: "ps:size-3.5 ps:flex-none ps:text-rose-400"
938
+ }) : /* @__PURE__ */ jsx(ChevronsUpDown, {
939
+ "aria-hidden": true,
940
+ className: "ps:size-3.5 ps:flex-none ps:text-zinc-600"
941
+ }),
942
+ /* @__PURE__ */ jsx("span", {
943
+ className: "ps:sr-only",
944
+ children: direction === "asc" ? "Sorted ascending" : direction === "desc" ? "Sorted descending" : "Not sorted"
945
+ })
946
+ ]
947
+ }), header.column.getCanResize() ? /* @__PURE__ */ jsx("button", {
948
+ "aria-label": `Resize ${header.column.id} column`,
949
+ "aria-orientation": "vertical",
950
+ "aria-valuemax": header.column.columnDef.maxSize,
951
+ "aria-valuemin": header.column.columnDef.minSize,
952
+ "aria-valuenow": header.column.getSize(),
953
+ className: header.column.getIsResizing() ? "ps:absolute ps:top-0 ps:right-0 ps:z-20 ps:h-full ps:w-1 ps:cursor-col-resize ps:touch-none ps:border-0 ps:bg-transparent ps:p-0" : resizingColumn ? "ps:pointer-events-none ps:invisible ps:absolute ps:top-0 ps:right-0 ps:h-full ps:w-1 ps:border-0 ps:bg-transparent ps:p-0" : "ps:absolute ps:top-0 ps:right-0 ps:h-full ps:w-1 ps:cursor-col-resize ps:touch-none ps:border-0 ps:bg-transparent ps:p-0 ps:hover:bg-rose-400/70 ps:focus-visible:bg-rose-400/70 ps:focus:outline-none",
954
+ disabled: resizingColumn !== void 0 && !header.column.getIsResizing(),
955
+ role: "separator",
956
+ tabIndex: 0,
957
+ type: "button",
958
+ onDoubleClick: () => {
959
+ header.column.resetSize();
960
+ },
961
+ onKeyDown: (event) => {
962
+ if (event.key !== "ArrowLeft" && event.key !== "ArrowRight") return;
963
+ event.preventDefault();
964
+ const delta = event.key === "ArrowRight" ? 10 : -10;
965
+ const min = header.column.columnDef.minSize ?? 20;
966
+ const max = header.column.columnDef.maxSize ?? Number.MAX_SAFE_INTEGER;
967
+ setColumnSizing((current) => ({
968
+ ...current,
969
+ [header.column.id]: Math.min(max, Math.max(min, header.column.getSize() + delta))
970
+ }));
971
+ },
972
+ onMouseDown: header.getResizeHandler(),
973
+ onTouchStart: header.getResizeHandler()
974
+ }) : null]
975
+ }, header.id);
976
+ }) }, headerGroup.id))
977
+ }),
978
+ /* @__PURE__ */ jsx("tbody", { children: table.getRowModel().rows.map((row) => /* @__PURE__ */ jsx("tr", {
979
+ className: "ps:hover:bg-zinc-500/8",
980
+ children: row.getVisibleCells().map((cell) => /* @__PURE__ */ jsx("td", {
981
+ className: "ps:max-w-80 ps:border-b ps:border-zinc-500/15 ps:px-4 ps:py-3 ps:text-[11px] ps:whitespace-nowrap",
982
+ children: flexRender(cell.column.columnDef.cell, cell.getContext())
983
+ }, cell.id))
984
+ }, row.id)) })
985
+ ]
986
+ }),
987
+ hasNextPage ? /* @__PURE__ */ jsx("div", {
988
+ className: "ps:sticky ps:left-0 ps:flex ps:w-full ps:justify-center ps:border-t ps:border-zinc-500/20 ps:bg-zinc-950/95 ps:p-3 ps:in-[.ps-theme-light]:bg-stone-50/95",
989
+ children: /* @__PURE__ */ jsx("button", {
990
+ className: "ps:rounded-md ps:border ps:border-zinc-600 ps:bg-zinc-900 ps:px-3 ps:py-1.5 ps:text-xs ps:text-zinc-200 ps:hover:border-rose-400 ps:hover:text-rose-300 ps:disabled:opacity-50",
991
+ disabled: isFetchingNextPage,
992
+ type: "button",
993
+ onClick: () => void fetchNextPage(),
994
+ children: isFetchingNextPage ? "Loading…" : `Load ${pageSize} more`
995
+ })
996
+ }) : null,
997
+ resizingColumn ? /* @__PURE__ */ jsx("div", {
998
+ className: "ps:pointer-events-none ps:absolute ps:inset-y-0 ps:z-50 ps:w-0.5 ps:bg-rose-400 ps:shadow-[0_0_0_1px_rgba(251,113,133,0.18)] ps:will-change-transform",
999
+ style: {
1000
+ left: resizingColumn.getStart() + resizingColumn.getSize(),
1001
+ transform: `translateX(${table.state.columnResizing.deltaOffset ?? 0}px)`
1002
+ }
1003
+ }) : null
1004
+ ]
1005
+ })
1006
+ })]
1007
+ });
1008
+ }
1009
+ function ObjectsView({ ontology, pageSize = 50 }) {
1010
+ const objectTypes = ontology.ir.objectTypes;
1011
+ const [selectedName, setSelectedName] = useState(() => objectTypes[0]?.name);
1012
+ const selected = objectTypes.find((objectType) => objectType.name === selectedName) ?? objectTypes[0];
1013
+ const collection = selected ? ontology.objects[selected.name] : void 0;
1014
+ if (!selected || !collection) return /* @__PURE__ */ jsx("div", {
1015
+ className: "ps:grid ps:h-full ps:place-items-center ps:text-sm ps:text-zinc-500",
1016
+ children: "This ontology has no object types."
1017
+ });
1018
+ return /* @__PURE__ */ jsxs("div", {
1019
+ className: "ps:flex ps:h-full ps:min-h-0 ps:w-full ps:min-w-0 ps:overflow-hidden",
1020
+ children: [/* @__PURE__ */ jsxs("aside", {
1021
+ className: "ps:w-44 ps:flex-none ps:overflow-y-auto ps:border-r ps:border-zinc-500/20 ps:p-3",
1022
+ children: [/* @__PURE__ */ jsx("p", {
1023
+ className: "ps:mt-0 ps:mb-2 ps:px-2 ps:text-[10px] ps:font-bold ps:tracking-[0.14em] ps:text-zinc-500 ps:uppercase",
1024
+ children: "Object types"
1025
+ }), /* @__PURE__ */ jsx("div", {
1026
+ className: "ps:flex ps:flex-col ps:gap-1",
1027
+ children: objectTypes.map((objectType) => /* @__PURE__ */ jsxs("button", {
1028
+ className: objectType.name === selected.name ? "ps:flex ps:items-center ps:gap-2 ps:rounded-lg ps:border-0 ps:bg-rose-500/15 ps:px-2.5 ps:py-2 ps:text-left ps:text-xs ps:font-semibold ps:text-rose-400" : "ps:flex ps:items-center ps:gap-2 ps:rounded-lg ps:border-0 ps:bg-transparent ps:px-2.5 ps:py-2 ps:text-left ps:text-xs ps:text-inherit ps:hover:bg-zinc-500/10",
1029
+ type: "button",
1030
+ onClick: () => {
1031
+ setSelectedName(objectType.name);
1032
+ },
1033
+ children: [/* @__PURE__ */ jsx(ObjectTypeIcon, {
1034
+ className: "ps:size-4 ps:flex-none",
1035
+ objectType
1036
+ }), /* @__PURE__ */ jsx("span", {
1037
+ className: "ps:truncate",
1038
+ children: objectType.pluralDisplayName
1039
+ })]
1040
+ }, objectType.name))
1041
+ })]
1042
+ }), /* @__PURE__ */ jsx(ObjectTable, {
1043
+ collection,
1044
+ objectType: selected,
1045
+ ontology,
1046
+ pageSize
1047
+ }, selected.name)]
1048
+ });
569
1049
  }
570
1050
  const SCHEMA_CARD_WIDTH = 230;
571
1051
  const SCHEMA_CARD_HEIGHT = 176;
572
1052
  function schemaEdgeLabel(link) {
573
- const label = `${link.source.displayName} · ${link.cardinality}`;
574
- return {
575
- label,
576
- width: Math.min(180, Math.max(72, label.length * 6 + 16)),
577
- };
578
- }
579
- export function layoutSchema(ir) {
580
- const graph = new Graph({ multigraph: true })
581
- .setGraph({
582
- marginx: 40,
583
- marginy: 40,
584
- nodesep: 72,
585
- rankdir: "LR",
586
- ranksep: 120,
587
- })
588
- .setDefaultEdgeLabel(() => ({ label: "" }));
589
- for (const objectType of ir.objectTypes) {
590
- graph.setNode(objectType.name, {
591
- height: SCHEMA_CARD_HEIGHT,
592
- width: SCHEMA_CARD_WIDTH,
593
- });
594
- }
595
- for (const link of ir.linkTypes) {
596
- const edgeLabel = schemaEdgeLabel(link);
597
- graph.setEdge(link.source.objectType, link.target.objectType, {
598
- height: 24,
599
- label: edgeLabel.label,
600
- width: edgeLabel.width,
601
- }, link.id);
602
- }
603
- layoutGraph(graph);
604
- const objectTypeByName = new Map(ir.objectTypes.map((objectType) => [objectType.name, objectType]));
605
- const nodes = graph
606
- .nodes()
607
- .map((name) => {
608
- const objectType = objectTypeByName.get(name);
609
- const node = graph.node(name);
610
- if (!objectType || !node)
611
- return undefined;
612
- return {
613
- objectType,
614
- x: (node.x ?? 0) - SCHEMA_CARD_WIDTH / 2,
615
- y: (node.y ?? 0) - SCHEMA_CARD_HEIGHT / 2,
616
- };
617
- })
618
- .filter((node) => node !== undefined);
619
- const edges = graph.edges().map((edge) => {
620
- const value = graph.edge(edge);
621
- return {
622
- id: edge.name ?? `${edge.v}-${edge.w}`,
623
- label: value.label ?? "",
624
- labelWidth: value.width ?? 72,
625
- labelX: value.x ?? (value.points?.[0]?.x ?? 0),
626
- labelY: value.y ?? (value.points?.[0]?.y ?? 0),
627
- points: value.points ?? [],
628
- };
629
- });
630
- const graphSize = graph.graph();
631
- return {
632
- nodes,
633
- edges,
634
- width: Math.max(310, graphSize.width ?? 0),
635
- height: Math.max(256, graphSize.height ?? 0),
636
- };
637
- }
638
- export function schemaEdgePath(points, cornerRadius = 12) {
639
- if (points.length === 0)
640
- return "";
641
- const first = points[0];
642
- if (points.length === 1)
643
- return `M ${first.x} ${first.y}`;
644
- const path = [`M ${first.x} ${first.y}`];
645
- for (let index = 1; index < points.length - 1; index += 1) {
646
- const previous = points[index - 1];
647
- const current = points[index];
648
- const next = points[index + 1];
649
- const incoming = Math.hypot(current.x - previous.x, current.y - previous.y);
650
- const outgoing = Math.hypot(next.x - current.x, next.y - current.y);
651
- if (incoming === 0 || outgoing === 0) {
652
- path.push(`L ${current.x} ${current.y}`);
653
- continue;
654
- }
655
- const radius = Math.min(cornerRadius, incoming / 2, outgoing / 2);
656
- const before = {
657
- x: current.x + ((previous.x - current.x) / incoming) * radius,
658
- y: current.y + ((previous.y - current.y) / incoming) * radius,
659
- };
660
- const after = {
661
- x: current.x + ((next.x - current.x) / outgoing) * radius,
662
- y: current.y + ((next.y - current.y) / outgoing) * radius,
663
- };
664
- path.push(`L ${before.x} ${before.y}`, `Q ${current.x} ${current.y} ${after.x} ${after.y}`);
665
- }
666
- const end = points.at(-1);
667
- if (end)
668
- path.push(`L ${end.x} ${end.y}`);
669
- return path.join(" ");
1053
+ const label = `${link.source.displayName} · ${link.cardinality}`;
1054
+ return {
1055
+ label,
1056
+ width: Math.min(180, Math.max(72, label.length * 6 + 16))
1057
+ };
1058
+ }
1059
+ function layoutSchema(ir) {
1060
+ const graph = new Graph({ multigraph: true }).setGraph({
1061
+ marginx: 40,
1062
+ marginy: 40,
1063
+ nodesep: 72,
1064
+ rankdir: "LR",
1065
+ ranksep: 120
1066
+ }).setDefaultEdgeLabel(() => ({ label: "" }));
1067
+ for (const objectType of ir.objectTypes) graph.setNode(objectType.name, {
1068
+ height: SCHEMA_CARD_HEIGHT,
1069
+ width: SCHEMA_CARD_WIDTH
1070
+ });
1071
+ for (const link of ir.linkTypes) {
1072
+ const edgeLabel = schemaEdgeLabel(link);
1073
+ graph.setEdge(link.source.objectType, link.target.objectType, {
1074
+ height: 24,
1075
+ label: edgeLabel.label,
1076
+ width: edgeLabel.width
1077
+ }, link.id);
1078
+ }
1079
+ layout(graph);
1080
+ const objectTypeByName = new Map(ir.objectTypes.map((objectType) => [objectType.name, objectType]));
1081
+ const nodes = graph.nodes().map((name) => {
1082
+ const objectType = objectTypeByName.get(name);
1083
+ const node = graph.node(name);
1084
+ if (!objectType || !node) return void 0;
1085
+ return {
1086
+ objectType,
1087
+ x: (node.x ?? 0) - SCHEMA_CARD_WIDTH / 2,
1088
+ y: (node.y ?? 0) - SCHEMA_CARD_HEIGHT / 2
1089
+ };
1090
+ }).filter((node) => node !== void 0);
1091
+ const edges = graph.edges().map((edge) => {
1092
+ const value = graph.edge(edge);
1093
+ return {
1094
+ id: edge.name ?? `${edge.v}-${edge.w}`,
1095
+ label: value.label ?? "",
1096
+ labelWidth: value.width ?? 72,
1097
+ labelX: value.x ?? value.points?.[0]?.x ?? 0,
1098
+ labelY: value.y ?? value.points?.[0]?.y ?? 0,
1099
+ points: value.points ?? []
1100
+ };
1101
+ });
1102
+ const graphSize = graph.graph();
1103
+ return {
1104
+ nodes,
1105
+ edges,
1106
+ width: Math.max(310, graphSize.width ?? 0),
1107
+ height: Math.max(256, graphSize.height ?? 0)
1108
+ };
1109
+ }
1110
+ function schemaEdgePath(points, cornerRadius = 12) {
1111
+ if (points.length === 0) return "";
1112
+ const first = points[0];
1113
+ if (points.length === 1) return `M ${first.x} ${first.y}`;
1114
+ const path = [`M ${first.x} ${first.y}`];
1115
+ for (let index = 1; index < points.length - 1; index += 1) {
1116
+ const previous = points[index - 1];
1117
+ const current = points[index];
1118
+ const next = points[index + 1];
1119
+ const incoming = Math.hypot(current.x - previous.x, current.y - previous.y);
1120
+ const outgoing = Math.hypot(next.x - current.x, next.y - current.y);
1121
+ if (incoming === 0 || outgoing === 0) {
1122
+ path.push(`L ${current.x} ${current.y}`);
1123
+ continue;
1124
+ }
1125
+ const radius = Math.min(cornerRadius, incoming / 2, outgoing / 2);
1126
+ const before = {
1127
+ x: current.x + (previous.x - current.x) / incoming * radius,
1128
+ y: current.y + (previous.y - current.y) / incoming * radius
1129
+ };
1130
+ const after = {
1131
+ x: current.x + (next.x - current.x) / outgoing * radius,
1132
+ y: current.y + (next.y - current.y) / outgoing * radius
1133
+ };
1134
+ path.push(`L ${before.x} ${before.y}`, `Q ${current.x} ${current.y} ${after.x} ${after.y}`);
1135
+ }
1136
+ const end = points.at(-1);
1137
+ if (end) path.push(`L ${end.x} ${end.y}`);
1138
+ return path.join(" ");
670
1139
  }
671
1140
  function SchemaView({ ir }) {
672
- const schemaLayout = useMemo(() => layoutSchema(ir), [ir]);
673
- const markerId = `ps-schema-arrow-${useId().replaceAll(":", "")}`;
674
- if (ir.objectTypes.length === 0) {
675
- return (_jsx("div", { className: "ps:grid ps:h-full ps:place-items-center ps:text-sm ps:text-zinc-500", children: "This ontology has no schema." }));
676
- }
677
- return (_jsx("div", { className: "ps:h-full ps:overflow-auto ps:p-5", children: _jsxs("div", { className: "ps:relative ps:rounded-2xl ps:border ps:border-zinc-500/20 ps:bg-zinc-950/25 ps:in-[.ps-theme-light]:bg-white/45", style: { height: schemaLayout.height, width: schemaLayout.width }, children: [_jsxs("svg", { "aria-label": "Ontology relations", className: "ps:absolute ps:inset-0 ps:size-full ps:overflow-visible", role: "img", viewBox: `0 0 ${schemaLayout.width} ${schemaLayout.height}`, children: [_jsx("defs", { children: _jsx("marker", { id: markerId, markerHeight: "8", markerWidth: "8", orient: "auto", refX: "7", refY: "4", children: _jsx("path", { className: "ps:fill-rose-400", d: "M0,0 L8,4 L0,8 Z" }) }) }), schemaLayout.edges.map((edge) => (_jsxs("g", { children: [_jsx("path", { className: "ps:fill-none ps:stroke-rose-400/80", d: schemaEdgePath(edge.points), markerEnd: `url(#${markerId})`, strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: "2" }), _jsx("rect", { className: "ps:fill-zinc-900 ps:stroke-zinc-700 ps:in-[.ps-theme-light]:fill-white ps:in-[.ps-theme-light]:stroke-stone-300", height: "22", rx: "7", width: edge.labelWidth, x: edge.labelX - edge.labelWidth / 2, y: edge.labelY - 11 }), _jsx("text", { className: "ps:fill-zinc-300 ps:text-[10px] ps:font-medium ps:in-[.ps-theme-light]:fill-stone-600", dominantBaseline: "middle", textAnchor: "middle", x: edge.labelX, y: edge.labelY, children: edge.label })] }, edge.id)))] }), schemaLayout.nodes.map(({ objectType, x, y }) => (_jsxs("article", { className: "ps:absolute ps:h-44 ps:w-[230px] ps:overflow-hidden ps:rounded-xl ps:border ps:border-zinc-500/30 ps:bg-zinc-900/95 ps:shadow-xl ps:in-[.ps-theme-light]:bg-white/95", style: { left: x, top: y }, children: [_jsxs("header", { className: "ps:border-b ps:border-zinc-500/20 ps:px-3.5 ps:py-3", children: [_jsxs("h3", { className: "ps:m-0 ps:flex ps:items-center ps:gap-2 ps:text-sm ps:font-semibold", children: [_jsx(ObjectTypeIcon, { className: "ps:size-4 ps:flex-none ps:text-rose-400", objectType: objectType }), objectType.displayName] }), _jsx("p", { className: "ps:mt-0.5 ps:mb-0 ps:font-mono ps:text-[10px] ps:text-zinc-500", children: objectType.name })] }), _jsx("div", { className: "ps:max-h-28 ps:overflow-y-auto ps:px-3.5 ps:py-2", children: objectType.properties.map((property) => (_jsxs("div", { className: "ps:flex ps:items-center ps:justify-between ps:gap-3 ps:py-1 ps:text-[11px]", children: [_jsx("span", { className: "ps:truncate", children: property.displayName }), property.name === objectType.primaryKey ? (_jsx("span", { className: "ps:flex-none ps:text-[9px] ps:font-bold ps:text-rose-400", children: "PK" })) : null] }, property.name))) })] }, objectType.name)))] }) }));
678
- }
679
- export function OntologyDevtoolsPanel({ metaOntology, ontology, theme = "dark", }) {
680
- const { data: outboxEntries } = useLiveQuery((query) => query.from({ entry: ontology.outbox.collection }), [ontology.outbox]);
681
- const outboxActivity = getOutboxActivity(outboxEntries);
682
- return (_jsx(Tooltip.Provider, { children: _jsxs(Tabs.Root, { className: `ps-devtools ps-theme-${theme} ps:flex ps:h-full ps:min-h-0 ps:w-full ps:min-w-0 ps:flex-col ps:overflow-hidden ps:font-sans ps:text-[13px] ${theme === "dark" ? "ps:bg-zinc-950 ps:text-stone-200" : "ps:bg-stone-50 ps:text-stone-800"}`, defaultValue: "outbox", style: { contain: "inline-size" }, children: [_jsx(Tabs.List, { "aria-label": "Ontology devtools views", className: "ps:flex ps:flex-none ps:items-center ps:gap-1 ps:border-b ps:border-zinc-500/20 ps:px-4", style: { height: 40 }, children: [
683
- ...ontologyViews,
684
- ...(metaOntology
685
- ? [
686
- {
687
- id: "meta",
688
- label: "Meta",
689
- icon: CodeBracketSquareIcon,
690
- },
691
- ]
692
- : []),
693
- ].map((view) => {
694
- const Icon = view.icon;
695
- return (_jsxs(Tabs.Tab, { className: "ps:group ps:flex ps:h-full ps:items-center ps:gap-1.5 ps:border-x-0 ps:border-t-0 ps:border-b-2 ps:border-transparent ps:bg-transparent ps:px-3 ps:text-xs ps:font-medium ps:text-zinc-500 ps:hover:text-current ps:data-[active]:border-rose-400 ps:data-[active]:font-semibold ps:data-[active]:text-rose-400", value: view.id, children: [_jsx(Icon, { "aria-hidden": true, className: "ps:flex-none", style: { height: 16, width: 16 } }), _jsx("span", { children: view.label }), view.id === "outbox" ? (_jsx(_Fragment, { children: _jsx("span", { className: `ps:inline-flex ps:min-w-5 ps:items-center ps:justify-center ps:rounded-full ps:px-1.5 ps:py-0.5 ps:text-center ps:text-[10px] ps:leading-none ps:transition-colors ${outboxBadgeClass(outboxActivity)}`, title: `${outboxEntries.length} outbox entries · ${outboxActivityLabel(outboxActivity)}`, children: _jsx(NumberFlow, { className: "ps:tabular-nums", isolate: true, value: outboxEntries.length }) }) })) : null] }, view.id));
696
- }) }), _jsx(Tabs.Panel, { className: "ps:min-h-0 ps:min-w-0 ps:flex-1 ps:overflow-hidden", value: "outbox", children: _jsx(OutboxRows, { outbox: ontology.outbox, theme: theme }) }), _jsx(Tabs.Panel, { className: "ps:min-h-0 ps:min-w-0 ps:flex-1 ps:overflow-hidden", value: "schema", children: _jsx(SchemaView, { ir: ontology.ir }) }), _jsx(Tabs.Panel, { className: "ps:min-h-0 ps:min-w-0 ps:flex-1 ps:overflow-hidden", value: "objects", children: _jsx(ObjectsView, { ontology: ontology }) }), metaOntology ? (_jsx(Tabs.Panel, { className: "ps:min-h-0 ps:min-w-0 ps:flex-1 ps:overflow-hidden", value: "meta", children: _jsx(ObjectsView, { ontology: metaOntology, pageSize: 25 }) })) : null] }) }));
697
- }
698
- export function createOntologyDevtoolsPlugin({ ontology, id = "party-stack-ontology", metaOntology, name, defaultOpen, }) {
699
- const [createPlugin] = createReactPlugin({
700
- id,
701
- name: "Ontology",
702
- defaultOpen,
703
- Component: ({ theme }) => (_jsx(OntologyDevtoolsPanel, { metaOntology: metaOntology, ontology: ontology, theme: theme })),
704
- });
705
- return {
706
- ...createPlugin(),
707
- name: name ?? ((_element, { theme }) => _jsx(OntologyDevtoolsPluginName, { theme: theme })),
708
- };
1141
+ const schemaLayout = useMemo(() => layoutSchema(ir), [ir]);
1142
+ const markerId = `ps-schema-arrow-${useId().replaceAll(":", "")}`;
1143
+ if (ir.objectTypes.length === 0) return /* @__PURE__ */ jsx("div", {
1144
+ className: "ps:grid ps:h-full ps:place-items-center ps:text-sm ps:text-zinc-500",
1145
+ children: "This ontology has no schema."
1146
+ });
1147
+ return /* @__PURE__ */ jsx("div", {
1148
+ className: "ps:h-full ps:overflow-auto ps:p-5",
1149
+ children: /* @__PURE__ */ jsxs("div", {
1150
+ className: "ps:relative ps:rounded-2xl ps:border ps:border-zinc-500/20 ps:bg-zinc-950/25 ps:in-[.ps-theme-light]:bg-white/45",
1151
+ style: {
1152
+ height: schemaLayout.height,
1153
+ width: schemaLayout.width
1154
+ },
1155
+ children: [/* @__PURE__ */ jsxs("svg", {
1156
+ "aria-label": "Ontology relations",
1157
+ className: "ps:absolute ps:inset-0 ps:size-full ps:overflow-visible",
1158
+ role: "img",
1159
+ viewBox: `0 0 ${schemaLayout.width} ${schemaLayout.height}`,
1160
+ children: [/* @__PURE__ */ jsx("defs", { children: /* @__PURE__ */ jsx("marker", {
1161
+ id: markerId,
1162
+ markerHeight: "8",
1163
+ markerWidth: "8",
1164
+ orient: "auto",
1165
+ refX: "7",
1166
+ refY: "4",
1167
+ children: /* @__PURE__ */ jsx("path", {
1168
+ className: "ps:fill-rose-400",
1169
+ d: "M0,0 L8,4 L0,8 Z"
1170
+ })
1171
+ }) }), schemaLayout.edges.map((edge) => /* @__PURE__ */ jsxs("g", { children: [
1172
+ /* @__PURE__ */ jsx("path", {
1173
+ className: "ps:fill-none ps:stroke-rose-400/80",
1174
+ d: schemaEdgePath(edge.points),
1175
+ markerEnd: `url(#${markerId})`,
1176
+ strokeLinecap: "round",
1177
+ strokeLinejoin: "round",
1178
+ strokeWidth: "2"
1179
+ }),
1180
+ /* @__PURE__ */ jsx("rect", {
1181
+ className: "ps:fill-zinc-900 ps:stroke-zinc-700 ps:in-[.ps-theme-light]:fill-white ps:in-[.ps-theme-light]:stroke-stone-300",
1182
+ height: "22",
1183
+ rx: "7",
1184
+ width: edge.labelWidth,
1185
+ x: edge.labelX - edge.labelWidth / 2,
1186
+ y: edge.labelY - 11
1187
+ }),
1188
+ /* @__PURE__ */ jsx("text", {
1189
+ className: "ps:fill-zinc-300 ps:text-[10px] ps:font-medium ps:in-[.ps-theme-light]:fill-stone-600",
1190
+ dominantBaseline: "middle",
1191
+ textAnchor: "middle",
1192
+ x: edge.labelX,
1193
+ y: edge.labelY,
1194
+ children: edge.label
1195
+ })
1196
+ ] }, edge.id))]
1197
+ }), schemaLayout.nodes.map(({ objectType, x, y }) => /* @__PURE__ */ jsxs("article", {
1198
+ className: "ps:absolute ps:h-44 ps:w-[230px] ps:overflow-hidden ps:rounded-xl ps:border ps:border-zinc-500/30 ps:bg-zinc-900/95 ps:shadow-xl ps:in-[.ps-theme-light]:bg-white/95",
1199
+ style: {
1200
+ left: x,
1201
+ top: y
1202
+ },
1203
+ children: [/* @__PURE__ */ jsxs("header", {
1204
+ className: "ps:border-b ps:border-zinc-500/20 ps:px-3.5 ps:py-3",
1205
+ children: [/* @__PURE__ */ jsxs("h3", {
1206
+ className: "ps:m-0 ps:flex ps:items-center ps:gap-2 ps:text-sm ps:font-semibold",
1207
+ children: [/* @__PURE__ */ jsx(ObjectTypeIcon, {
1208
+ className: "ps:size-4 ps:flex-none ps:text-rose-400",
1209
+ objectType
1210
+ }), objectType.displayName]
1211
+ }), /* @__PURE__ */ jsx("p", {
1212
+ className: "ps:mt-0.5 ps:mb-0 ps:font-mono ps:text-[10px] ps:text-zinc-500",
1213
+ children: objectType.name
1214
+ })]
1215
+ }), /* @__PURE__ */ jsx("div", {
1216
+ className: "ps:max-h-28 ps:overflow-y-auto ps:px-3.5 ps:py-2",
1217
+ children: objectType.properties.map((property) => /* @__PURE__ */ jsxs("div", {
1218
+ className: "ps:flex ps:items-center ps:justify-between ps:gap-3 ps:py-1 ps:text-[11px]",
1219
+ children: [/* @__PURE__ */ jsx("span", {
1220
+ className: "ps:truncate",
1221
+ children: property.displayName
1222
+ }), property.name === objectType.primaryKey ? /* @__PURE__ */ jsx("span", {
1223
+ className: "ps:flex-none ps:text-[9px] ps:font-bold ps:text-rose-400",
1224
+ children: "PK"
1225
+ }) : null]
1226
+ }, property.name))
1227
+ })]
1228
+ }, objectType.name))]
1229
+ })
1230
+ });
1231
+ }
1232
+ function OntologyDevtoolsPanel({ metaOntology, ontology, theme = "dark" }) {
1233
+ const { data: outboxEntries } = useLiveQuery({ query: (query) => query.from({ entry: ontology.outbox.collection }) });
1234
+ const outboxActivity = getOutboxActivity(outboxEntries);
1235
+ return /* @__PURE__ */ jsx(Tooltip.Provider, { children: /* @__PURE__ */ jsxs(Tabs.Root, {
1236
+ className: `ps-devtools ps-theme-${theme} ps:flex ps:h-full ps:min-h-0 ps:w-full ps:min-w-0 ps:flex-col ps:overflow-hidden ps:font-sans ps:text-[13px] ${theme === "dark" ? "ps:bg-zinc-950 ps:text-stone-200" : "ps:bg-stone-50 ps:text-stone-800"}`,
1237
+ defaultValue: "outbox",
1238
+ style: { contain: "inline-size" },
1239
+ children: [
1240
+ /* @__PURE__ */ jsx(Tabs.List, {
1241
+ "aria-label": "Ontology devtools views",
1242
+ className: "ps:flex ps:flex-none ps:items-center ps:gap-1 ps:border-b ps:border-zinc-500/20 ps:px-4",
1243
+ style: { height: 40 },
1244
+ children: [...ontologyViews, ...metaOntology ? [{
1245
+ id: "meta",
1246
+ label: "Meta",
1247
+ icon: SquareCode
1248
+ }] : []].map((view) => {
1249
+ const Icon = view.icon;
1250
+ return /* @__PURE__ */ jsxs(Tabs.Tab, {
1251
+ className: "ps:group ps:flex ps:h-full ps:items-center ps:gap-1.5 ps:border-x-0 ps:border-t-0 ps:border-b-2 ps:border-transparent ps:bg-transparent ps:px-3 ps:text-xs ps:font-medium ps:text-zinc-500 ps:hover:text-current ps:data-[active]:border-rose-400 ps:data-[active]:font-semibold ps:data-[active]:text-rose-400",
1252
+ value: view.id,
1253
+ children: [
1254
+ /* @__PURE__ */ jsx(Icon, {
1255
+ "aria-hidden": true,
1256
+ className: "ps:flex-none",
1257
+ style: {
1258
+ height: 16,
1259
+ width: 16
1260
+ }
1261
+ }),
1262
+ /* @__PURE__ */ jsx("span", { children: view.label }),
1263
+ view.id === "outbox" ? /* @__PURE__ */ jsx(Fragment, { children: /* @__PURE__ */ jsx("span", {
1264
+ className: `ps:inline-flex ps:min-w-5 ps:items-center ps:justify-center ps:rounded-full ps:px-1.5 ps:py-0.5 ps:text-center ps:text-[10px] ps:leading-none ps:transition-colors ${outboxBadgeClass(outboxActivity)}`,
1265
+ title: `${outboxEntries.length} outbox entries · ${outboxActivityLabel(outboxActivity)}`,
1266
+ children: /* @__PURE__ */ jsx(NumberFlow, {
1267
+ className: "ps:tabular-nums",
1268
+ isolate: true,
1269
+ value: outboxEntries.length
1270
+ })
1271
+ }) }) : null
1272
+ ]
1273
+ }, view.id);
1274
+ })
1275
+ }),
1276
+ /* @__PURE__ */ jsx(Tabs.Panel, {
1277
+ className: "ps:min-h-0 ps:min-w-0 ps:flex-1 ps:overflow-hidden",
1278
+ value: "outbox",
1279
+ children: /* @__PURE__ */ jsx(OutboxRows, {
1280
+ outbox: ontology.outbox,
1281
+ theme
1282
+ })
1283
+ }),
1284
+ /* @__PURE__ */ jsx(Tabs.Panel, {
1285
+ className: "ps:min-h-0 ps:min-w-0 ps:flex-1 ps:overflow-hidden",
1286
+ value: "schema",
1287
+ children: /* @__PURE__ */ jsx(SchemaView, { ir: ontology.ir })
1288
+ }),
1289
+ /* @__PURE__ */ jsx(Tabs.Panel, {
1290
+ className: "ps:min-h-0 ps:min-w-0 ps:flex-1 ps:overflow-hidden",
1291
+ value: "objects",
1292
+ children: /* @__PURE__ */ jsx(ObjectsView, { ontology })
1293
+ }),
1294
+ metaOntology ? /* @__PURE__ */ jsx(Tabs.Panel, {
1295
+ className: "ps:min-h-0 ps:min-w-0 ps:flex-1 ps:overflow-hidden",
1296
+ value: "meta",
1297
+ children: /* @__PURE__ */ jsx(ObjectsView, {
1298
+ ontology: metaOntology,
1299
+ pageSize: 25
1300
+ })
1301
+ }) : null
1302
+ ]
1303
+ }) });
1304
+ }
1305
+ function createOntologyDevtoolsPlugin({ ontology, id = "party-stack-ontology", metaOntology, name, defaultOpen }) {
1306
+ const [createPlugin] = createReactPlugin({
1307
+ id,
1308
+ name: "Ontology",
1309
+ defaultOpen,
1310
+ Component: ({ theme }) => /* @__PURE__ */ jsx(OntologyDevtoolsPanel, {
1311
+ metaOntology,
1312
+ ontology,
1313
+ theme
1314
+ })
1315
+ });
1316
+ return {
1317
+ ...createPlugin(),
1318
+ name: name ?? ((_element, { theme }) => /* @__PURE__ */ jsx(OntologyDevtoolsPluginName, { theme }))
1319
+ };
709
1320
  }
1321
+ //#endregion
1322
+ export { OntologyDevtoolsPanel, OntologyDevtoolsPluginName, OntologyDevtoolsTrigger, OntologyIcon, createOntologyDevtoolsPlugin, getOutboxActivity, layoutSchema, moveColumn, ontologyDevtoolsTrigger, schemaEdgePath, timestampPreview, typeDisplayName };
1323
+
710
1324
  //# sourceMappingURL=OntologyDevtools.js.map