@bpmnkit/operate 0.0.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (72) hide show
  1. package/README.md +131 -0
  2. package/dist/components/badge.d.ts +2 -0
  3. package/dist/components/badge.js +2 -0
  4. package/dist/components/card.d.ts +2 -0
  5. package/dist/components/card.js +2 -0
  6. package/dist/components/chart.d.ts +6 -0
  7. package/dist/components/chart.js +161 -0
  8. package/dist/components/filter-table.d.ts +20 -0
  9. package/dist/components/filter-table.js +215 -0
  10. package/dist/components/table.d.ts +2 -0
  11. package/dist/components/table.js +2 -0
  12. package/dist/css.d.ts +2 -0
  13. package/dist/css.js +1071 -0
  14. package/dist/index.d.ts +3 -0
  15. package/dist/index.js +2 -0
  16. package/dist/mock-data.d.ts +18 -0
  17. package/dist/mock-data.js +509 -0
  18. package/dist/operate.d.ts +3 -0
  19. package/dist/operate.js +308 -0
  20. package/dist/router.d.ts +9 -0
  21. package/dist/router.js +49 -0
  22. package/dist/stores/base.d.ts +20 -0
  23. package/dist/stores/base.js +32 -0
  24. package/dist/stores/dashboard.d.ts +6 -0
  25. package/dist/stores/dashboard.js +19 -0
  26. package/dist/stores/decisions.d.ts +9 -0
  27. package/dist/stores/decisions.js +19 -0
  28. package/dist/stores/definitions.d.ts +9 -0
  29. package/dist/stores/definitions.js +19 -0
  30. package/dist/stores/incidents.d.ts +10 -0
  31. package/dist/stores/incidents.js +27 -0
  32. package/dist/stores/instances.d.ts +15 -0
  33. package/dist/stores/instances.js +33 -0
  34. package/dist/stores/jobs.d.ts +10 -0
  35. package/dist/stores/jobs.js +19 -0
  36. package/dist/stores/tasks.d.ts +10 -0
  37. package/dist/stores/tasks.js +19 -0
  38. package/dist/stream.d.ts +12 -0
  39. package/dist/stream.js +42 -0
  40. package/dist/types.d.ts +48 -0
  41. package/dist/types.js +2 -0
  42. package/dist/views/dashboard.d.ts +6 -0
  43. package/dist/views/dashboard.js +98 -0
  44. package/dist/views/decision-detail.d.ts +15 -0
  45. package/dist/views/decision-detail.js +167 -0
  46. package/dist/views/decisions.d.ts +7 -0
  47. package/dist/views/decisions.js +78 -0
  48. package/dist/views/definition-detail.d.ts +15 -0
  49. package/dist/views/definition-detail.js +339 -0
  50. package/dist/views/definitions.d.ts +7 -0
  51. package/dist/views/definitions.js +70 -0
  52. package/dist/views/header.d.ts +9 -0
  53. package/dist/views/header.js +49 -0
  54. package/dist/views/incident-detail.d.ts +14 -0
  55. package/dist/views/incident-detail.js +540 -0
  56. package/dist/views/incidents.d.ts +7 -0
  57. package/dist/views/incidents.js +108 -0
  58. package/dist/views/instance-detail.d.ts +16 -0
  59. package/dist/views/instance-detail.js +728 -0
  60. package/dist/views/instances.d.ts +7 -0
  61. package/dist/views/instances.js +249 -0
  62. package/dist/views/jobs.d.ts +6 -0
  63. package/dist/views/jobs.js +60 -0
  64. package/dist/views/messages.d.ts +11 -0
  65. package/dist/views/messages.js +431 -0
  66. package/dist/views/nav.d.ts +10 -0
  67. package/dist/views/nav.js +60 -0
  68. package/dist/views/task-detail.d.ts +13 -0
  69. package/dist/views/task-detail.js +187 -0
  70. package/dist/views/tasks.d.ts +7 -0
  71. package/dist/views/tasks.js +72 -0
  72. package/package.json +46 -0
@@ -0,0 +1,12 @@
1
+ type Unsub = () => void;
2
+ /**
3
+ * Polls the proxy's /operate/stream endpoint via plain fetch (one-shot JSON).
4
+ * Using fetch instead of EventSource releases the HTTP connection after each
5
+ * response, preventing connection-pool exhaustion when multiple stores poll
6
+ * the same origin concurrently.
7
+ */
8
+ export declare function createStream<T>(url: string, onData: (payload: T) => void, onError: (msg: string) => void): Unsub;
9
+ /** Simulates an SSE stream using mock data. Calls onData immediately and then on interval. */
10
+ export declare function createMockStream<T>(getData: () => T, onData: (payload: T) => void, interval: number): Unsub;
11
+ export {};
12
+ //# sourceMappingURL=stream.d.ts.map
package/dist/stream.js ADDED
@@ -0,0 +1,42 @@
1
+ /**
2
+ * Polls the proxy's /operate/stream endpoint via plain fetch (one-shot JSON).
3
+ * Using fetch instead of EventSource releases the HTTP connection after each
4
+ * response, preventing connection-pool exhaustion when multiple stores poll
5
+ * the same origin concurrently.
6
+ */
7
+ export function createStream(url, onData, onError) {
8
+ const interval = Math.max(5_000, Number(new URL(url).searchParams.get("interval") ?? "30000"));
9
+ let aborted = false;
10
+ async function poll() {
11
+ if (aborted)
12
+ return;
13
+ try {
14
+ const r = await fetch(url);
15
+ if (aborted)
16
+ return;
17
+ if (!r.ok)
18
+ throw new Error(`HTTP ${r.status}`);
19
+ const data = (await r.json());
20
+ onData(data);
21
+ }
22
+ catch {
23
+ if (!aborted)
24
+ onError("Connection error. Retrying…");
25
+ }
26
+ }
27
+ void poll();
28
+ const id = setInterval(() => void poll(), interval);
29
+ return () => {
30
+ aborted = true;
31
+ clearInterval(id);
32
+ };
33
+ }
34
+ /** Simulates an SSE stream using mock data. Calls onData immediately and then on interval. */
35
+ export function createMockStream(getData, onData, interval) {
36
+ onData(getData());
37
+ if (interval <= 0)
38
+ return () => { };
39
+ const id = setInterval(() => onData(getData()), interval);
40
+ return () => clearInterval(id);
41
+ }
42
+ //# sourceMappingURL=stream.js.map
@@ -0,0 +1,48 @@
1
+ import type { DecisionDefinitionResult, IncidentResult, JobSearchResult, MessageSubscriptionResult, ProcessDefinitionResult, ProcessInstanceResult, UserTaskResult, VariableResult } from "@bpmnkit/api";
2
+ import type { Theme } from "@bpmnkit/ui";
3
+ export type { Theme };
4
+ export interface OperateOptions {
5
+ container: HTMLElement;
6
+ /** Proxy server base URL. Default: http://localhost:3033 */
7
+ proxyUrl?: string;
8
+ /** Active profile name. Sent as x-profile header. */
9
+ profile?: string;
10
+ theme?: Theme;
11
+ /** Polling interval in ms. Default: 30000. Set to 0 to disable auto-refresh. */
12
+ pollInterval?: number;
13
+ /** Use mock/demo data instead of connecting to proxy. */
14
+ mock?: boolean;
15
+ }
16
+ export interface OperateApi {
17
+ readonly el: HTMLElement;
18
+ setProfile(name: string | null): void;
19
+ setTheme(theme: Theme): void;
20
+ navigate(path: string): void;
21
+ destroy(): void;
22
+ }
23
+ export interface StreamEvent<T> {
24
+ type: "data" | "error" | "keepalive";
25
+ topic?: string;
26
+ payload?: T;
27
+ message?: string;
28
+ }
29
+ export interface ProfileInfo {
30
+ name: string;
31
+ active: boolean;
32
+ apiType: string;
33
+ baseUrl: string | null;
34
+ authType: string;
35
+ }
36
+ export interface DashboardData {
37
+ activeInstances: number;
38
+ openIncidents: number;
39
+ activeJobs: number;
40
+ pendingTasks: number;
41
+ definitions: number;
42
+ /** Usage metrics — aggregate totals (may be absent if endpoint unavailable) */
43
+ usageTotalProcessInstances?: number;
44
+ usageDecisionInstances?: number;
45
+ usageAssignees?: number;
46
+ }
47
+ export type { DecisionDefinitionResult, IncidentResult, JobSearchResult, MessageSubscriptionResult, ProcessDefinitionResult, ProcessInstanceResult, UserTaskResult, VariableResult, };
48
+ //# sourceMappingURL=types.d.ts.map
package/dist/types.js ADDED
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1,6 @@
1
+ import type { DashboardStore } from "../stores/dashboard.js";
2
+ export declare function createDashboardView(store: DashboardStore, onNavigate: (path: string) => void): {
3
+ el: HTMLElement;
4
+ destroy(): void;
5
+ };
6
+ //# sourceMappingURL=dashboard.d.ts.map
@@ -0,0 +1,98 @@
1
+ import { IC_UI } from "@bpmnkit/ui";
2
+ import { createBarChart } from "../components/chart.js";
3
+ // ── Dashboard card ────────────────────────────────────────────────────────────
4
+ function createDashboardCard(label, value, icon, accent, onClick) {
5
+ const card = document.createElement("div");
6
+ card.className = "op-dash-card";
7
+ card.style.setProperty("--accent", accent);
8
+ const top = document.createElement("div");
9
+ top.className = "op-dash-card-top";
10
+ const lbl = document.createElement("div");
11
+ lbl.className = "op-dash-card-label";
12
+ lbl.textContent = label;
13
+ const iconWrap = document.createElement("div");
14
+ iconWrap.className = "op-dash-card-icon";
15
+ iconWrap.innerHTML = icon;
16
+ top.appendChild(lbl);
17
+ top.appendChild(iconWrap);
18
+ card.appendChild(top);
19
+ const val = document.createElement("div");
20
+ val.className = "op-dash-card-value";
21
+ val.textContent = String(value);
22
+ card.appendChild(val);
23
+ card.addEventListener("click", onClick);
24
+ return card;
25
+ }
26
+ function createUsageCard(label, value) {
27
+ const card = document.createElement("div");
28
+ card.className = "op-usage-card";
29
+ const lbl = document.createElement("div");
30
+ lbl.className = "op-usage-card-label";
31
+ lbl.textContent = label;
32
+ const val = document.createElement("div");
33
+ val.className = "op-usage-card-value";
34
+ val.textContent = value !== undefined ? value.toLocaleString() : "—";
35
+ card.appendChild(val);
36
+ card.appendChild(lbl);
37
+ return card;
38
+ }
39
+ // ── View ──────────────────────────────────────────────────────────────────────
40
+ export function createDashboardView(store, onNavigate) {
41
+ const el = document.createElement("div");
42
+ el.className = "op-view op-dashboard";
43
+ const grid = document.createElement("div");
44
+ grid.className = "op-card-grid";
45
+ el.appendChild(grid);
46
+ // Usage metrics section (only shown if data available)
47
+ const usageSection = document.createElement("div");
48
+ usageSection.className = "op-usage-section";
49
+ usageSection.style.display = "none";
50
+ el.appendChild(usageSection);
51
+ const usageHeading = document.createElement("div");
52
+ usageHeading.className = "op-chart-heading";
53
+ usageHeading.textContent = "Lifetime usage";
54
+ usageSection.appendChild(usageHeading);
55
+ const usageGrid = document.createElement("div");
56
+ usageGrid.className = "op-usage-grid";
57
+ usageSection.appendChild(usageGrid);
58
+ const chartWrap = document.createElement("div");
59
+ chartWrap.className = "op-chart-section";
60
+ const chartHeading = document.createElement("div");
61
+ chartHeading.className = "op-chart-heading";
62
+ chartHeading.textContent = "Activity over time";
63
+ chartWrap.appendChild(chartHeading);
64
+ el.appendChild(chartWrap);
65
+ const chart = createBarChart(chartWrap);
66
+ function render() {
67
+ grid.innerHTML = "";
68
+ const d = store.state.data;
69
+ grid.appendChild(createDashboardCard("Active Instances", d?.activeInstances ?? "—", IC_UI.instances, "var(--bpmnkit-accent)", () => onNavigate("/instances")));
70
+ const incAccent = d?.openIncidents ? "var(--op-c-amber)" : "var(--bpmnkit-accent)";
71
+ grid.appendChild(createDashboardCard("Open Incidents", d?.openIncidents ?? "—", IC_UI.incidents, incAccent, () => onNavigate("/incidents")));
72
+ grid.appendChild(createDashboardCard("Active Jobs", d?.activeJobs ?? "—", IC_UI.jobs, "var(--op-c-green)", () => onNavigate("/jobs")));
73
+ grid.appendChild(createDashboardCard("Pending Tasks", d?.pendingTasks ?? "—", IC_UI.tasks, "var(--op-c-purple)", () => onNavigate("/tasks")));
74
+ grid.appendChild(createDashboardCard("Deployed Processes", d?.definitions ?? "—", IC_UI.processes, "var(--bpmnkit-fg-muted)", () => onNavigate("/definitions")));
75
+ // Usage metrics cards (only if data arrived)
76
+ const hasUsage = d?.usageTotalProcessInstances !== undefined ||
77
+ d?.usageDecisionInstances !== undefined ||
78
+ d?.usageAssignees !== undefined;
79
+ if (hasUsage) {
80
+ usageSection.style.display = "";
81
+ usageGrid.innerHTML = "";
82
+ usageGrid.appendChild(createUsageCard("Process Instances", d?.usageTotalProcessInstances));
83
+ usageGrid.appendChild(createUsageCard("Decision Evaluations", d?.usageDecisionInstances));
84
+ usageGrid.appendChild(createUsageCard("Active Assignees", d?.usageAssignees));
85
+ }
86
+ chart.update(store.state.data ?? null);
87
+ }
88
+ const unsub = store.subscribe(render);
89
+ render();
90
+ return {
91
+ el,
92
+ destroy() {
93
+ unsub();
94
+ chart.destroy();
95
+ },
96
+ };
97
+ }
98
+ //# sourceMappingURL=dashboard.js.map
@@ -0,0 +1,15 @@
1
+ import type { DecisionsStore } from "../stores/decisions.js";
2
+ interface Config {
3
+ proxyUrl: string;
4
+ profile: string | null;
5
+ mock: boolean;
6
+ theme: "light" | "dark";
7
+ navigate?: (path: string) => void;
8
+ }
9
+ export declare function createDecisionDetailView(definitionKey: string, store: DecisionsStore, cfg: Config, onBack: () => void): {
10
+ el: HTMLElement;
11
+ setTheme(t: "light" | "dark"): void;
12
+ destroy(): void;
13
+ };
14
+ export {};
15
+ //# sourceMappingURL=decision-detail.d.ts.map
@@ -0,0 +1,167 @@
1
+ import { DmnEditor } from "@bpmnkit/plugins/dmn-editor";
2
+ const MOCK_DMN_XML = `<?xml version="1.0" encoding="UTF-8"?>
3
+ <definitions xmlns="https://www.omg.org/spec/DMN/20191111/MODEL/" xmlns:dmndi="https://www.omg.org/spec/DMN/20191111/DMNDI/" xmlns:dc="http://www.omg.org/spec/DMN/20180521/DC/" id="Definitions_1" name="DRD" namespace="http://camunda.org/schema/1.0/dmn">
4
+ <decision id="approve-order" name="Approve Order">
5
+ <decisionTable id="decisionTable_1">
6
+ <input id="input_1" label="Order Amount">
7
+ <inputExpression id="inputExpression_1" typeRef="double">
8
+ <text>amount</text>
9
+ </inputExpression>
10
+ </input>
11
+ <output id="output_1" label="Approved" name="approved" typeRef="boolean"/>
12
+ <rule id="rule_1">
13
+ <inputEntry id="inputEntry_1"><text>&lt; 1000</text></inputEntry>
14
+ <outputEntry id="outputEntry_1"><text>true</text></outputEntry>
15
+ </rule>
16
+ <rule id="rule_2">
17
+ <inputEntry id="inputEntry_2"><text>&gt;= 1000</text></inputEntry>
18
+ <outputEntry id="outputEntry_2"><text>false</text></outputEntry>
19
+ </rule>
20
+ </decisionTable>
21
+ </decision>
22
+ </definitions>`;
23
+ export function createDecisionDetailView(definitionKey, store, cfg, onBack) {
24
+ const el = document.createElement("div");
25
+ el.className = "op-view op-def-detail";
26
+ // Breadcrumb
27
+ const breadcrumb = document.createElement("div");
28
+ breadcrumb.className = "op-breadcrumb";
29
+ const backBtn = document.createElement("button");
30
+ backBtn.className = "op-back-btn";
31
+ backBtn.textContent = "← Decisions";
32
+ backBtn.addEventListener("click", onBack);
33
+ breadcrumb.appendChild(backBtn);
34
+ el.appendChild(breadcrumb);
35
+ // Metadata row
36
+ const meta = document.createElement("div");
37
+ meta.className = "op-def-meta";
38
+ el.appendChild(meta);
39
+ // Editor pane
40
+ const editorWrap = document.createElement("div");
41
+ editorWrap.className = "op-def-canvas";
42
+ el.appendChild(editorWrap);
43
+ let editor = null;
44
+ function getDef() {
45
+ return store.state.data?.items.find((d) => d.decisionDefinitionKey === definitionKey) ?? null;
46
+ }
47
+ function getVersions() {
48
+ const def = getDef();
49
+ if (!def)
50
+ return [];
51
+ const id = def.decisionDefinitionId;
52
+ return (store.state.data?.items ?? [])
53
+ .filter((d) => d.decisionDefinitionId === id)
54
+ .sort((a, b) => (b.version ?? 0) - (a.version ?? 0));
55
+ }
56
+ function renderMeta(def) {
57
+ meta.innerHTML = "";
58
+ if (!def)
59
+ return;
60
+ const name = document.createElement("span");
61
+ name.className = "op-def-meta-name";
62
+ name.textContent = def.name ?? def.decisionDefinitionId;
63
+ meta.appendChild(name);
64
+ const versions = getVersions();
65
+ if (versions.length > 1 && cfg.navigate) {
66
+ const select = document.createElement("select");
67
+ select.className = "op-version-select";
68
+ for (const v of versions) {
69
+ const opt = document.createElement("option");
70
+ opt.value = v.decisionDefinitionKey;
71
+ opt.textContent = `v${v.version ?? "?"}`;
72
+ opt.selected = v.decisionDefinitionKey === definitionKey;
73
+ select.appendChild(opt);
74
+ }
75
+ select.addEventListener("change", () => {
76
+ cfg.navigate?.(`/decisions/${select.value}`);
77
+ });
78
+ meta.appendChild(select);
79
+ }
80
+ else {
81
+ const ver = document.createElement("span");
82
+ ver.className = "op-def-meta-version";
83
+ ver.textContent = `v${def.version ?? "?"}`;
84
+ meta.appendChild(ver);
85
+ }
86
+ if (def.decisionRequirementsName) {
87
+ const drg = document.createElement("span");
88
+ drg.className = "op-def-meta-version";
89
+ drg.textContent = `DRG: ${def.decisionRequirementsName}`;
90
+ meta.appendChild(drg);
91
+ }
92
+ if (def.tenantId) {
93
+ const tenant = document.createElement("span");
94
+ tenant.className = "op-def-meta-version";
95
+ tenant.textContent = `tenant: ${def.tenantId}`;
96
+ meta.appendChild(tenant);
97
+ }
98
+ const key = document.createElement("span");
99
+ key.className = "op-instance-key";
100
+ key.textContent = def.decisionDefinitionKey;
101
+ meta.appendChild(key);
102
+ }
103
+ function loadEditor(xml) {
104
+ editor?.destroy();
105
+ editorWrap.innerHTML = "";
106
+ editor = new DmnEditor({ container: editorWrap, theme: cfg.theme });
107
+ editor.loadXML(xml).catch(() => { });
108
+ }
109
+ let xmlStarted = false;
110
+ function startXmlFetch(def) {
111
+ if (xmlStarted)
112
+ return;
113
+ xmlStarted = true;
114
+ renderMeta(def);
115
+ if (cfg.mock) {
116
+ loadEditor(MOCK_DMN_XML);
117
+ return;
118
+ }
119
+ const headers = {};
120
+ if (cfg.profile)
121
+ headers["x-profile"] = cfg.profile;
122
+ fetch(`${cfg.proxyUrl}/api/decision-definitions/${def.decisionDefinitionKey}/xml`, { headers })
123
+ .then((r) => (r.ok ? r.text() : null))
124
+ .then((xml) => {
125
+ if (xml)
126
+ loadEditor(xml);
127
+ })
128
+ .catch(() => { });
129
+ }
130
+ // Try to resolve from store immediately
131
+ const def = getDef();
132
+ if (def) {
133
+ startXmlFetch(def);
134
+ }
135
+ else if (!cfg.mock) {
136
+ // Deep-link: fetch directly
137
+ const headers = {};
138
+ if (cfg.profile)
139
+ headers["x-profile"] = cfg.profile;
140
+ fetch(`${cfg.proxyUrl}/api/decision-definitions/${definitionKey}`, { headers })
141
+ .then((r) => (r.ok ? r.json() : null))
142
+ .then((inst) => {
143
+ if (inst && !xmlStarted)
144
+ startXmlFetch(inst);
145
+ })
146
+ .catch(() => { });
147
+ }
148
+ // Re-check when store updates (in case we navigated before store loaded)
149
+ const unsub = store.subscribe(() => {
150
+ if (xmlStarted)
151
+ return;
152
+ const found = getDef();
153
+ if (found)
154
+ startXmlFetch(found);
155
+ });
156
+ return {
157
+ el,
158
+ setTheme(t) {
159
+ editor?.setTheme(t);
160
+ },
161
+ destroy() {
162
+ unsub();
163
+ editor?.destroy();
164
+ },
165
+ };
166
+ }
167
+ //# sourceMappingURL=decision-detail.js.map
@@ -0,0 +1,7 @@
1
+ import type { DecisionsStore } from "../stores/decisions.js";
2
+ import type { DecisionDefinitionResult } from "../types.js";
3
+ export declare function createDecisionsView(store: DecisionsStore, onSelect: (def: DecisionDefinitionResult) => void): {
4
+ el: HTMLElement;
5
+ destroy(): void;
6
+ };
7
+ //# sourceMappingURL=decisions.d.ts.map
@@ -0,0 +1,78 @@
1
+ import { createFilterTable } from "../components/filter-table.js";
2
+ export function createDecisionsView(store, onSelect) {
3
+ const el = document.createElement("div");
4
+ el.className = "op-view op-def-view";
5
+ const { el: tableEl, setRows } = createFilterTable({
6
+ columns: [
7
+ {
8
+ label: "Name",
9
+ render: (row) => row.latest.name ?? row.latest.decisionDefinitionId,
10
+ sortValue: (row) => row.latest.name ?? row.latest.decisionDefinitionId,
11
+ },
12
+ {
13
+ label: "ID",
14
+ width: "200px",
15
+ render: (row) => {
16
+ const span = document.createElement("span");
17
+ span.className = "op-mono-cell";
18
+ span.textContent = row.latest.decisionDefinitionId;
19
+ return span;
20
+ },
21
+ sortValue: (row) => row.latest.decisionDefinitionId,
22
+ },
23
+ {
24
+ label: "DRG",
25
+ width: "180px",
26
+ render: (row) => row.latest.decisionRequirementsName ?? "—",
27
+ sortValue: (row) => row.latest.decisionRequirementsName ?? "",
28
+ },
29
+ {
30
+ label: "Versions",
31
+ width: "80px",
32
+ render: (row) => String(row.versionCount),
33
+ sortValue: (row) => row.versionCount,
34
+ },
35
+ {
36
+ label: "Latest",
37
+ width: "80px",
38
+ render: (row) => `v${row.latest.version ?? "?"}`,
39
+ sortValue: (row) => row.latest.version ?? 0,
40
+ },
41
+ ],
42
+ searchFn: (row) => [
43
+ row.latest.name,
44
+ row.latest.decisionDefinitionId,
45
+ row.latest.decisionRequirementsName,
46
+ row.latest.decisionDefinitionKey,
47
+ ]
48
+ .filter(Boolean)
49
+ .join(" "),
50
+ onRowClick: (row) => onSelect(row.latest),
51
+ emptyText: "No decision definitions deployed",
52
+ });
53
+ el.appendChild(tableEl);
54
+ function buildRows(items) {
55
+ const map = new Map();
56
+ for (const item of items) {
57
+ const id = item.decisionDefinitionId;
58
+ const existing = map.get(id);
59
+ if (!existing) {
60
+ map.set(id, { latest: item, versionCount: 1 });
61
+ }
62
+ else {
63
+ existing.versionCount++;
64
+ if ((item.version ?? 0) > (existing.latest.version ?? 0)) {
65
+ existing.latest = item;
66
+ }
67
+ }
68
+ }
69
+ return Array.from(map.values());
70
+ }
71
+ function render() {
72
+ setRows(buildRows(store.state.data?.items ?? []));
73
+ }
74
+ const unsub = store.subscribe(render);
75
+ render();
76
+ return { el, destroy: unsub };
77
+ }
78
+ //# sourceMappingURL=decisions.js.map
@@ -0,0 +1,15 @@
1
+ import type { DefinitionsStore } from "../stores/definitions.js";
2
+ interface Config {
3
+ proxyUrl: string;
4
+ profile: string | null;
5
+ mock: boolean;
6
+ theme: "light" | "dark";
7
+ navigate?: (path: string) => void;
8
+ }
9
+ export declare function createDefinitionDetailView(definitionKey: string, store: DefinitionsStore, cfg: Config, onBack: () => void): {
10
+ el: HTMLElement;
11
+ setTheme(t: "light" | "dark"): void;
12
+ destroy(): void;
13
+ };
14
+ export {};
15
+ //# sourceMappingURL=definition-detail.d.ts.map