@pihanga2/shadcn 0.2.21 → 0.2.23
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +25 -1
- package/cards/attachment/attachment.component.d.ts +4 -0
- package/cards/attachment/attachment.component.js +46 -0
- package/cards/attachment/attachment.component.js.map +1 -0
- package/cards/attachment/attachment.types.d.ts +95 -0
- package/cards/attachment/attachment.types.js +7 -0
- package/cards/attachment/attachment.types.js.map +1 -0
- package/cards/attachment/attachmentGroup.component.d.ts +4 -0
- package/cards/attachment/attachmentGroup.component.js +21 -0
- package/cards/attachment/attachmentGroup.component.js.map +1 -0
- package/cards/attachment/index.d.ts +1 -0
- package/cards/attachment/index.js +16 -0
- package/cards/attachment/index.js.map +1 -0
- package/cards/bubble/bubble.component.d.ts +4 -0
- package/cards/bubble/bubble.component.js +67 -0
- package/cards/bubble/bubble.component.js.map +1 -0
- package/cards/bubble/bubble.types.d.ts +106 -0
- package/cards/bubble/bubble.types.js +7 -0
- package/cards/bubble/bubble.types.js.map +1 -0
- package/cards/bubble/bubbleGroup.component.d.ts +4 -0
- package/cards/bubble/bubbleGroup.component.js +21 -0
- package/cards/bubble/bubbleGroup.component.js.map +1 -0
- package/cards/bubble/index.d.ts +1 -0
- package/cards/bubble/index.js +16 -0
- package/cards/bubble/index.js.map +1 -0
- package/cards/dataTable/dataTable.component.js +191 -124
- package/cards/dataTable/dataTable.component.js.map +1 -1
- package/cards/dataTable/dataTable.types.d.ts +50 -0
- package/cards/dataTable/dataTable.types.js +6 -3
- package/cards/dataTable/dataTable.types.js.map +1 -1
- package/cards/dataTable/index.js +6 -6
- package/cards/dropDownMenu/dropdown-menu.ui.js +41 -41
- package/cards/input/input.component.js +4 -4
- package/cards/jsonViewer/jsonViewer.component.js +1 -2
- package/cards/jsonViewer/jsonViewer.component.js.map +1 -1
- package/cards/message/index.d.ts +1 -0
- package/cards/message/index.js +15 -0
- package/cards/message/index.js.map +1 -0
- package/cards/message/message.component.d.ts +4 -0
- package/cards/message/message.component.js +47 -0
- package/cards/message/message.component.js.map +1 -0
- package/cards/message/message.types.d.ts +56 -0
- package/cards/message/message.types.js +7 -0
- package/cards/message/message.types.js.map +1 -0
- package/cards/message/messageGroup.component.d.ts +4 -0
- package/cards/message/messageGroup.component.js +21 -0
- package/cards/message/messageGroup.component.js.map +1 -0
- package/cards/swimlane/index.d.ts +2 -0
- package/cards/swimlane/index.js +14 -0
- package/cards/swimlane/index.js.map +1 -0
- package/cards/swimlane/swimlane.component.d.ts +4 -0
- package/cards/swimlane/swimlane.component.js +520 -0
- package/cards/swimlane/swimlane.component.js.map +1 -0
- package/cards/swimlane/swimlane.css +1 -0
- package/cards/swimlane/swimlane.demo.d.ts +12 -0
- package/cards/swimlane/swimlane.model.d.ts +41 -0
- package/cards/swimlane/swimlane.model.js +203 -0
- package/cards/swimlane/swimlane.model.js.map +1 -0
- package/cards/swimlane/swimlane.model.test.d.ts +1 -0
- package/cards/swimlane/swimlane.types.d.ts +271 -0
- package/cards/swimlane/swimlane.types.js +7 -0
- package/cards/swimlane/swimlane.types.js.map +1 -0
- package/cards.schema.json +6874 -0
- package/components/ui/attachment.js +102 -0
- package/components/ui/attachment.js.map +1 -0
- package/components/ui/badge.js +7 -7
- package/components/ui/bubble.js +73 -0
- package/components/ui/bubble.js.map +1 -0
- package/components/ui/button.js +11 -11
- package/components/ui/drawer.js +24 -24
- package/components/ui/empty.js +12 -12
- package/components/ui/field.js +16 -16
- package/components/ui/message.js +51 -0
- package/components/ui/message.js.map +1 -0
- package/components/ui/toggle-group.js +1 -1
- package/components/ui/toggle.js +1 -1
- package/package.json +23 -2
|
@@ -0,0 +1,203 @@
|
|
|
1
|
+
import { onSwimlaneEventsReceived as e, onSwimlaneRowsCleared as t } from "./swimlane.types.js";
|
|
2
|
+
//#region src/cards/swimlane/swimlane.model.ts
|
|
3
|
+
function n(e = {}) {
|
|
4
|
+
return {
|
|
5
|
+
laneOrder: [],
|
|
6
|
+
laneLabels: {},
|
|
7
|
+
current: {},
|
|
8
|
+
rows: [],
|
|
9
|
+
pending: [],
|
|
10
|
+
spans: {},
|
|
11
|
+
seq: 0,
|
|
12
|
+
maxRows: e.maxRows ?? 2e3
|
|
13
|
+
};
|
|
14
|
+
}
|
|
15
|
+
function r(e) {
|
|
16
|
+
let t = {};
|
|
17
|
+
for (let n of Object.keys(e)) t[n] = {
|
|
18
|
+
state: e[n].state,
|
|
19
|
+
acts: [...e[n].acts]
|
|
20
|
+
};
|
|
21
|
+
return t;
|
|
22
|
+
}
|
|
23
|
+
function i(e, t) {
|
|
24
|
+
switch (t.type) {
|
|
25
|
+
case "state": return [t.lane];
|
|
26
|
+
case "call": return t.from === t.to ? [t.from] : [t.from, t.to];
|
|
27
|
+
case "expect": return t.from === t.to ? [t.from] : [t.from, t.to];
|
|
28
|
+
case "reply":
|
|
29
|
+
case "done": {
|
|
30
|
+
let n = e.spans[t.id];
|
|
31
|
+
return n ? [n.to, n.from] : [];
|
|
32
|
+
}
|
|
33
|
+
default: return [];
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
function a(e, t, n = Date.now()) {
|
|
37
|
+
for (let r of t) {
|
|
38
|
+
let t = r.ts ?? n;
|
|
39
|
+
for (let n of i(e, r)) e.current[n] || o(e, {
|
|
40
|
+
type: "lane",
|
|
41
|
+
lane: n
|
|
42
|
+
}, t);
|
|
43
|
+
o(e, r, t);
|
|
44
|
+
}
|
|
45
|
+
s(e);
|
|
46
|
+
}
|
|
47
|
+
function o(e, t, n) {
|
|
48
|
+
let i = e.current;
|
|
49
|
+
if (t.type === "expect") {
|
|
50
|
+
e.pending.push({
|
|
51
|
+
id: t.id,
|
|
52
|
+
type: "expect",
|
|
53
|
+
from: t.from,
|
|
54
|
+
to: t.to,
|
|
55
|
+
label: t.label,
|
|
56
|
+
since: n,
|
|
57
|
+
timeoutMs: t.timeoutMs
|
|
58
|
+
});
|
|
59
|
+
return;
|
|
60
|
+
}
|
|
61
|
+
let a = r(i), o;
|
|
62
|
+
switch (t.type) {
|
|
63
|
+
case "lane":
|
|
64
|
+
if (t.label && (e.laneLabels[t.lane] = t.label), i[t.lane]) return;
|
|
65
|
+
i[t.lane] = {
|
|
66
|
+
state: "created",
|
|
67
|
+
acts: []
|
|
68
|
+
}, e.laneOrder.push(t.lane);
|
|
69
|
+
break;
|
|
70
|
+
case "state":
|
|
71
|
+
i[t.lane].state = t.state;
|
|
72
|
+
break;
|
|
73
|
+
case "call": {
|
|
74
|
+
let r = i[t.from]?.acts ?? [], a = t.parentId ?? r[r.length - 1];
|
|
75
|
+
e.spans[t.id] = {
|
|
76
|
+
id: t.id,
|
|
77
|
+
kind: t.kind,
|
|
78
|
+
from: t.from,
|
|
79
|
+
to: t.to,
|
|
80
|
+
label: t.label,
|
|
81
|
+
start: n,
|
|
82
|
+
end: t.kind === "event" ? n : void 0,
|
|
83
|
+
status: t.kind === "event" ? "done" : "open"
|
|
84
|
+
}, a && a !== t.id && (e.spans[t.id].parent = a), t.kind !== "event" && i[t.to].acts.push(t.id);
|
|
85
|
+
break;
|
|
86
|
+
}
|
|
87
|
+
case "reply":
|
|
88
|
+
case "done": {
|
|
89
|
+
let r = e.spans[t.id];
|
|
90
|
+
if (!r) return;
|
|
91
|
+
r.end = n, r.status = t.type === "done" ? "done" : t.ok ? "ok" : "error", t.type === "reply" && (r.result = t.label);
|
|
92
|
+
let a = i[r.to];
|
|
93
|
+
if (a) {
|
|
94
|
+
let e = a.acts.indexOf(t.id);
|
|
95
|
+
e >= 0 && a.acts.splice(e, 1);
|
|
96
|
+
}
|
|
97
|
+
o = {
|
|
98
|
+
from: r.from,
|
|
99
|
+
to: r.to,
|
|
100
|
+
label: r.label
|
|
101
|
+
};
|
|
102
|
+
break;
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
let s, c = t.type === "reply" ? t.id : t.fulfils;
|
|
106
|
+
if (c) {
|
|
107
|
+
let t = e.pending.findIndex((e) => e.id === c);
|
|
108
|
+
t >= 0 && (e.pending.splice(t, 1), s = c);
|
|
109
|
+
}
|
|
110
|
+
t.type === "call" && t.kind === "sync" && e.pending.push({
|
|
111
|
+
id: t.id,
|
|
112
|
+
type: "reply",
|
|
113
|
+
from: t.to,
|
|
114
|
+
to: t.from,
|
|
115
|
+
label: `reply: ${t.label}`,
|
|
116
|
+
since: n,
|
|
117
|
+
timeoutMs: t.timeoutMs
|
|
118
|
+
});
|
|
119
|
+
let l = {
|
|
120
|
+
id: ++e.seq,
|
|
121
|
+
event: {
|
|
122
|
+
...t,
|
|
123
|
+
ts: n
|
|
124
|
+
},
|
|
125
|
+
pre: a,
|
|
126
|
+
post: r(i)
|
|
127
|
+
};
|
|
128
|
+
s && (l.fulfilled = s), o && (l.route = o), e.rows.push(l);
|
|
129
|
+
}
|
|
130
|
+
function s(e) {
|
|
131
|
+
let t = Math.max(50, Math.floor(e.maxRows / 10));
|
|
132
|
+
if (e.rows.length <= e.maxRows + t) return;
|
|
133
|
+
e.rows.splice(0, e.rows.length - e.maxRows);
|
|
134
|
+
let n = /* @__PURE__ */ new Set();
|
|
135
|
+
for (let t of e.rows) "id" in t.event && n.add(t.event.id);
|
|
136
|
+
for (let t of Object.values(e.current)) t.acts.forEach((e) => n.add(e));
|
|
137
|
+
e.pending.forEach((e) => n.add(e.id));
|
|
138
|
+
for (let t of Object.keys(e.spans)) n.has(t) || delete e.spans[t];
|
|
139
|
+
}
|
|
140
|
+
function c(e) {
|
|
141
|
+
e.rows.splice(0, e.rows.length);
|
|
142
|
+
}
|
|
143
|
+
function l(e, t) {
|
|
144
|
+
let n = e, r = [];
|
|
145
|
+
for (let e = t.length - 1; e >= 0; e--) {
|
|
146
|
+
let i = t[e], a = n, o = n[i.from];
|
|
147
|
+
i.type === "reply" && o?.acts.includes(i.id) && (n = {
|
|
148
|
+
...n,
|
|
149
|
+
[i.from]: {
|
|
150
|
+
...o,
|
|
151
|
+
acts: o.acts.filter((e) => e !== i.id)
|
|
152
|
+
}
|
|
153
|
+
}), r.push({
|
|
154
|
+
id: `g-${i.id}`,
|
|
155
|
+
pending: i,
|
|
156
|
+
pre: a,
|
|
157
|
+
post: n
|
|
158
|
+
});
|
|
159
|
+
}
|
|
160
|
+
return r;
|
|
161
|
+
}
|
|
162
|
+
function u(e, t) {
|
|
163
|
+
let n = [];
|
|
164
|
+
for (let r of Object.values(e.spans)) r.parent === t && n.push(r.id);
|
|
165
|
+
return n.sort((t, n) => e.spans[t].start - e.spans[n].start);
|
|
166
|
+
}
|
|
167
|
+
function d(e, t, n) {
|
|
168
|
+
if (t === n) return !0;
|
|
169
|
+
for (let t of Object.values(e.pre)) if (t.acts.includes(n)) return !0;
|
|
170
|
+
for (let t of Object.values(e.post)) if (t.acts.includes(n)) return !0;
|
|
171
|
+
return !1;
|
|
172
|
+
}
|
|
173
|
+
function f(e) {
|
|
174
|
+
let t = new Date(e), n = (e, t = 2) => String(e).padStart(t, "0");
|
|
175
|
+
return `${n(t.getHours())}:${n(t.getMinutes())}:${n(t.getSeconds())}.${n(t.getMilliseconds(), 3)}`;
|
|
176
|
+
}
|
|
177
|
+
function p(e, t, n = Date.now()) {
|
|
178
|
+
if (t.kind === "state") {
|
|
179
|
+
let n = e.rows.find((e) => e.id === t.rowId);
|
|
180
|
+
return !n || n.event.type !== "state" ? t.id : `${t.lane} → ${n.event.state} at ${f(n.event.ts)}`;
|
|
181
|
+
}
|
|
182
|
+
if (t.kind === "pending") {
|
|
183
|
+
let r = e.pending.find((e) => e.id === t.id);
|
|
184
|
+
if (!r) return "already fulfilled";
|
|
185
|
+
let i = n - r.since, a = r.type === "reply" ? "reply" : "message", o = r.timeoutMs ? ` / timeout ${r.timeoutMs} ms${i > r.timeoutMs ? " · OVERDUE" : ""}` : "";
|
|
186
|
+
return `expected ${a} ${r.from} → ${r.to}: "${r.label}" · waiting ${i} ms${o}`;
|
|
187
|
+
}
|
|
188
|
+
let r = e.spans[t.id];
|
|
189
|
+
if (!r) return t.id;
|
|
190
|
+
let i = r.end == null ? `running ${n - r.start} ms` : `${r.end - r.start} ms`, a = r.result ? ` (${r.result})` : "";
|
|
191
|
+
return t.kind === "activity" ? `${r.to} handling "${r.label}" from ${r.from} · started ${f(r.start)} · ${i}${a}` : `${r.kind.toUpperCase()} ${r.from} → ${r.to}: "${r.label}" · ${r.status}${a} · ${i}`;
|
|
192
|
+
}
|
|
193
|
+
function m(n, r, i) {
|
|
194
|
+
e(n, (e, t) => {
|
|
195
|
+
t.modelId === r && a(i(e), t.events);
|
|
196
|
+
}), t(n, (e, t) => {
|
|
197
|
+
t.modelId === r && c(i(e));
|
|
198
|
+
});
|
|
199
|
+
}
|
|
200
|
+
//#endregion
|
|
201
|
+
export { c as clearSwimlaneRows, n as createSwimlaneModel, p as describeSwimlaneTarget, f as formatTs, a as ingestSwimlaneEvents, l as projectPending, m as registerSwimlaneModel, u as relatedCallIds, d as rowTouches };
|
|
202
|
+
|
|
203
|
+
//# sourceMappingURL=swimlane.model.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"swimlane.model.js","names":[],"sources":["../../../src/cards/swimlane/swimlane.model.ts"],"sourcesContent":["/**\n * Swimlane model helpers — pure TypeScript, no React.\n *\n * The model is plain JSON that lives in the app's Redux state.\n * `ingestSwimlaneEvents` MUTATES the model it is given, which is exactly what\n * a Pihanga (Immer) reducer wants:\n *\n * onSwimlaneEventsReceived<AppState>(r, (state, {events}) => {\n * ingestSwimlaneEvents(state.swimlane, events);\n * });\n *\n * or simply `registerSwimlaneModel(r, \"main\", (s) => s.swimlane)`.\n *\n * Every row stores its own plain copies of the lane snapshots, so no object is\n * ever referenced from two places in the state tree (Immer-safe, serialisable).\n */\nimport type {PiRegister, ReduxState} from \"@pihanga2/core\";\n\nimport {\n DEF_MAX_ROWS,\n onSwimlaneEventsReceived,\n onSwimlaneRowsCleared,\n type SwimlaneEvent,\n type SwimlaneGhostRow,\n type SwimlaneLanesSnapshot,\n type SwimlaneModel,\n type SwimlanePending,\n type SwimlaneRow,\n type SwimlaneRowEvent,\n type SwimlaneTarget,\n} from \"./swimlane.types\";\n\nexport function createSwimlaneModel(\n opts: {maxRows?: number} = {},\n): SwimlaneModel {\n return {\n laneOrder: [],\n laneLabels: {},\n current: {},\n rows: [],\n pending: [],\n spans: {},\n seq: 0,\n maxRows: opts.maxRows ?? DEF_MAX_ROWS,\n };\n}\n\nfunction copySnapshot(s: SwimlaneLanesSnapshot): SwimlaneLanesSnapshot {\n const out: SwimlaneLanesSnapshot = {};\n for (const k of Object.keys(s)) {\n out[k] = {state: s[k].state, acts: [...s[k].acts]};\n }\n return out;\n}\n\n/** Lanes an event refers to (used to add lanes implicitly). */\nfunction referencedLanes(m: SwimlaneModel, ev: SwimlaneEvent): string[] {\n switch (ev.type) {\n case \"state\":\n return [ev.lane];\n case \"call\":\n return ev.from === ev.to ? [ev.from] : [ev.from, ev.to];\n case \"expect\":\n return ev.from === ev.to ? [ev.from] : [ev.from, ev.to];\n case \"reply\":\n case \"done\": {\n const s = m.spans[ev.id];\n return s ? [s.to, s.from] : [];\n }\n default:\n return [];\n }\n}\n\n/**\n * Apply a batch of stream events to the model (mutating it).\n * Safe to call on an Immer draft or on a plain object.\n */\nexport function ingestSwimlaneEvents(\n m: SwimlaneModel,\n events: SwimlaneEvent[],\n now: number = Date.now(),\n): void {\n for (const raw of events) {\n const ts = raw.ts ?? now;\n // lanes referenced before they were announced get an implicit lane row\n for (const lane of referencedLanes(m, raw)) {\n if (!m.current[lane]) applyOne(m, {type: \"lane\", lane}, ts);\n }\n applyOne(m, raw, ts);\n }\n trim(m);\n}\n\nfunction applyOne(m: SwimlaneModel, ev: SwimlaneEvent, ts: number): void {\n const cur = m.current;\n\n if (ev.type === \"expect\") {\n m.pending.push({\n id: ev.id,\n type: \"expect\",\n from: ev.from,\n to: ev.to,\n label: ev.label,\n since: ts,\n timeoutMs: ev.timeoutMs,\n });\n return;\n }\n\n const pre = copySnapshot(cur);\n let route: SwimlaneRow[\"route\"];\n\n switch (ev.type) {\n case \"lane\":\n if (ev.label) m.laneLabels[ev.lane] = ev.label;\n if (cur[ev.lane]) return; // already known → only a label update\n cur[ev.lane] = {state: \"created\", acts: []};\n m.laneOrder.push(ev.lane);\n break;\n case \"state\":\n cur[ev.lane].state = ev.state;\n break;\n case \"call\": {\n // causality: explicit parentId, else the innermost open activity of the caller\n const callerActs = cur[ev.from]?.acts ?? [];\n const parent = ev.parentId ?? callerActs[callerActs.length - 1];\n m.spans[ev.id] = {\n id: ev.id,\n kind: ev.kind,\n from: ev.from,\n to: ev.to,\n label: ev.label,\n start: ts,\n end: ev.kind === \"event\" ? ts : undefined,\n status: ev.kind === \"event\" ? \"done\" : \"open\",\n };\n if (parent && parent !== ev.id) m.spans[ev.id].parent = parent;\n if (ev.kind !== \"event\") cur[ev.to].acts.push(ev.id);\n break;\n }\n case \"reply\":\n case \"done\": {\n const s = m.spans[ev.id];\n if (!s) return; // unknown call → nothing sensible to draw\n s.end = ts;\n s.status = ev.type === \"done\" ? \"done\" : ev.ok ? \"ok\" : \"error\";\n if (ev.type === \"reply\") s.result = ev.label;\n const lane = cur[s.to];\n if (lane) {\n const i = lane.acts.indexOf(ev.id);\n if (i >= 0) lane.acts.splice(i, 1);\n }\n route = {from: s.from, to: s.to, label: s.label};\n break;\n }\n }\n\n // does this real event replace an outstanding one?\n let fulfilled: string | undefined;\n const pid = ev.type === \"reply\" ? ev.id : ev.fulfils;\n if (pid) {\n const i = m.pending.findIndex((p) => p.id === pid);\n if (i >= 0) {\n m.pending.splice(i, 1);\n fulfilled = pid;\n }\n }\n // a sync call means we KNOW a reply will come back\n if (ev.type === \"call\" && ev.kind === \"sync\") {\n m.pending.push({\n id: ev.id,\n type: \"reply\",\n from: ev.to,\n to: ev.from,\n label: `reply: ${ev.label}`,\n since: ts,\n timeoutMs: ev.timeoutMs,\n });\n }\n\n const row: SwimlaneRow = {\n id: ++m.seq,\n event: {...ev, ts} as SwimlaneRowEvent,\n pre,\n post: copySnapshot(cur),\n };\n if (fulfilled) row.fulfilled = fulfilled;\n if (route) row.route = route;\n m.rows.push(row);\n}\n\n/** Ring buffer with amortised span garbage collection. */\nfunction trim(m: SwimlaneModel): void {\n const slack = Math.max(50, Math.floor(m.maxRows / 10));\n if (m.rows.length <= m.maxRows + slack) return;\n m.rows.splice(0, m.rows.length - m.maxRows);\n const keep = new Set<string>();\n for (const r of m.rows) {\n if (\"id\" in r.event) keep.add(r.event.id);\n }\n for (const l of Object.values(m.current)) l.acts.forEach((a) => keep.add(a));\n m.pending.forEach((p) => keep.add(p.id));\n for (const id of Object.keys(m.spans)) {\n if (!keep.has(id)) delete m.spans[id];\n }\n}\n\n/** Remove all rows but keep lanes, open activities and outstanding messages. */\nexport function clearSwimlaneRows(m: SwimlaneModel): void {\n m.rows.splice(0, m.rows.length);\n}\n\n/**\n * Project outstanding messages below the \"now\" line (pure).\n * Expected replies are replayed onto the current snapshot so that open\n * activities visibly run down to the ghost reply that will close them.\n * Newest first ≈ innermost call replies first.\n */\nexport function projectPending(\n current: SwimlaneLanesSnapshot,\n pending: SwimlanePending[],\n): SwimlaneGhostRow[] {\n let snap = current;\n const out: SwimlaneGhostRow[] = [];\n for (let i = pending.length - 1; i >= 0; i--) {\n const p = pending[i];\n const pre = snap;\n const lane = snap[p.from];\n if (p.type === \"reply\" && lane?.acts.includes(p.id)) {\n snap = {...snap, [p.from]: {...lane, acts: lane.acts.filter((a) => a !== p.id)}};\n }\n out.push({id: `g-${p.id}`, pending: p, pre, post: snap});\n }\n return out;\n}\n\n/**\n * Direct children of call `id`: calls made while it was being handled.\n * Their call/reply transitions (and outstanding replies) are the transitions\n * the process \"creates and receives\".\n */\nexport function relatedCallIds(m: Pick<SwimlaneModel, \"spans\">, id: string): string[] {\n const out: string[] = [];\n for (const s of Object.values(m.spans)) if (s.parent === id) out.push(s.id);\n return out.sort((a, b) => m.spans[a].start - m.spans[b].start);\n}\n\n/** Does a row (or ghost row) involve the call chain `id`? */\nexport function rowTouches(\n r: {pre: SwimlaneLanesSnapshot; post: SwimlaneLanesSnapshot},\n eventId: string | undefined,\n id: string,\n): boolean {\n if (eventId === id) return true;\n for (const l of Object.values(r.pre)) if (l.acts.includes(id)) return true;\n for (const l of Object.values(r.post)) if (l.acts.includes(id)) return true;\n return false;\n}\n\nexport function formatTs(t: number): string {\n const d = new Date(t);\n const p = (n: number, w = 2) => String(n).padStart(w, \"0\");\n return `${p(d.getHours())}:${p(d.getMinutes())}:${p(d.getSeconds())}.${p(d.getMilliseconds(), 3)}`;\n}\n\n/** Human-readable description of a hover target (used by the tooltip). */\nexport function describeSwimlaneTarget(\n m: SwimlaneModel,\n t: SwimlaneTarget,\n now: number = Date.now(),\n): string {\n if (t.kind === \"state\") {\n const r = m.rows.find((x) => x.id === t.rowId);\n if (!r || r.event.type !== \"state\") return t.id;\n return `${t.lane} → ${r.event.state} at ${formatTs(r.event.ts)}`;\n }\n if (t.kind === \"pending\") {\n const p = m.pending.find((x) => x.id === t.id);\n if (!p) return \"already fulfilled\";\n const w = now - p.since;\n const what = p.type === \"reply\" ? \"reply\" : \"message\";\n const to = p.timeoutMs\n ? ` / timeout ${p.timeoutMs} ms${w > p.timeoutMs ? \" · OVERDUE\" : \"\"}`\n : \"\";\n return `expected ${what} ${p.from} → ${p.to}: \"${p.label}\" · waiting ${w} ms${to}`;\n }\n const s = m.spans[t.id];\n if (!s) return t.id;\n const dur = s.end != null ? `${s.end - s.start} ms` : `running ${now - s.start} ms`;\n const res = s.result ? ` (${s.result})` : \"\";\n if (t.kind === \"activity\") {\n return `${s.to} handling \"${s.label}\" from ${s.from} · started ${formatTs(s.start)} · ${dur}${res}`;\n }\n return `${s.kind.toUpperCase()} ${s.from} → ${s.to}: \"${s.label}\" · ${s.status}${res} · ${dur}`;\n}\n\n/**\n * Wire the data actions for one model:\n *\n * register((r) => registerSwimlaneModel<AppState>(r, \"main\", (s) => s.swimlane));\n * // …later, from a stream adapter:\n * dispatchSwimlaneEvents(dispatch, {modelId: \"main\", events});\n */\nexport function registerSwimlaneModel<S extends ReduxState>(\n r: PiRegister,\n modelId: string,\n select: (state: S) => SwimlaneModel,\n): void {\n onSwimlaneEventsReceived<S>(r, (state, a) => {\n if (a.modelId === modelId) ingestSwimlaneEvents(select(state), a.events);\n });\n onSwimlaneRowsCleared<S>(r, (state, a) => {\n if (a.modelId === modelId) clearSwimlaneRows(select(state));\n });\n}\n"],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,271 @@
|
|
|
1
|
+
export declare const SWIMLANE_CARD = "shad/swimlane";
|
|
2
|
+
export declare const Swimlane: <S extends import('@pihanga2/core').ReduxState>(p: import('@pihanga2/core').PiMapProps<SwimlaneProps, S, SwimlaneEvents>) => import('@pihanga2/core').PiCardDef;
|
|
3
|
+
export declare const SWIMLANE_ACTION: {
|
|
4
|
+
ITEM_CLICKED: string;
|
|
5
|
+
HOVER_CHANGED: string;
|
|
6
|
+
};
|
|
7
|
+
export declare const onSwimlaneHoverChanged: <S extends import('@pihanga2/core').ReduxState>(register: import('@pihanga2/core/types').PiRegisterMinimal, f: import('@pihanga2/core').ReduceF<S, import('@pihanga2/core').ReduxAction & {
|
|
8
|
+
cardID: string;
|
|
9
|
+
} & SwimlaneHoverChangedEvent>) => void;
|
|
10
|
+
export declare const onSwimlaneItemClicked: <S extends import('@pihanga2/core').ReduxState>(register: import('@pihanga2/core/types').PiRegisterMinimal, f: import('@pihanga2/core').ReduceF<S, import('@pihanga2/core').ReduxAction & {
|
|
11
|
+
cardID: string;
|
|
12
|
+
} & SwimlaneItemClickedEvent>) => void;
|
|
13
|
+
export declare const SWIMLANE_DATA_ACTION: {
|
|
14
|
+
EVENTS_RECEIVED: string;
|
|
15
|
+
ROWS_CLEARED: string;
|
|
16
|
+
};
|
|
17
|
+
export declare const dispatchSwimlaneEvents: (d: import('@pihanga2/core').DispatchF, ev: SwimlaneEventsReceivedEvent) => void;
|
|
18
|
+
export declare const dispatchSwimlaneRowsCleared: (d: import('@pihanga2/core').DispatchF, ev: SwimlaneRowsClearedEvent) => void;
|
|
19
|
+
export declare const onSwimlaneEventsReceived: <S extends import('@pihanga2/core').ReduxState>(register: import('@pihanga2/core/types').PiRegisterMinimal, f: import('@pihanga2/core').ReduceF<S, import('@pihanga2/core').ReduxAction & {
|
|
20
|
+
cardID: string;
|
|
21
|
+
} & SwimlaneEventsReceivedEvent>) => void;
|
|
22
|
+
export declare const onSwimlaneRowsCleared: <S extends import('@pihanga2/core').ReduxState>(register: import('@pihanga2/core/types').PiRegisterMinimal, f: import('@pihanga2/core').ReduceF<S, import('@pihanga2/core').ReduxAction & {
|
|
23
|
+
cardID: string;
|
|
24
|
+
} & SwimlaneRowsClearedEvent>) => void;
|
|
25
|
+
/** Run state of a service, drawn on its lifeline. */
|
|
26
|
+
export type SwimlaneRunState = "created" | "starting" | "running" | "degraded" | "stopped";
|
|
27
|
+
/**
|
|
28
|
+
* How a message travels between lanes.
|
|
29
|
+
* - `sync` – request that expects a reply; opens an activity on the target
|
|
30
|
+
* and automatically creates an *outstanding reply*.
|
|
31
|
+
* - `async` – message that opens an activity on the target, closed by `done`.
|
|
32
|
+
* - `event` – fire-and-forget; no activity.
|
|
33
|
+
*/
|
|
34
|
+
export type SwimlaneCallKind = "sync" | "async" | "event";
|
|
35
|
+
type SwimlaneEventBase = {
|
|
36
|
+
/** Epoch ms. Defaults to `Date.now()` at ingest time. */
|
|
37
|
+
ts?: number;
|
|
38
|
+
/** Id of an `expect` event that this real event resolves. */
|
|
39
|
+
fulfils?: string;
|
|
40
|
+
};
|
|
41
|
+
/** A service became known. Lanes referenced by calls are also added implicitly. */
|
|
42
|
+
export type SwimlaneLaneEvent = SwimlaneEventBase & {
|
|
43
|
+
type: "lane";
|
|
44
|
+
lane: string;
|
|
45
|
+
/** Display name (defaults to `lane`). */
|
|
46
|
+
label?: string;
|
|
47
|
+
};
|
|
48
|
+
/** A service changed its run state. */
|
|
49
|
+
export type SwimlaneStateEvent = SwimlaneEventBase & {
|
|
50
|
+
type: "state";
|
|
51
|
+
lane: string;
|
|
52
|
+
state: SwimlaneRunState;
|
|
53
|
+
};
|
|
54
|
+
/** A message between two lanes (or a lane and itself). */
|
|
55
|
+
export type SwimlaneCallEvent = SwimlaneEventBase & {
|
|
56
|
+
type: "call";
|
|
57
|
+
/** Unique id; replies / `done` refer to it. */
|
|
58
|
+
id: string;
|
|
59
|
+
kind: SwimlaneCallKind;
|
|
60
|
+
from: string;
|
|
61
|
+
to: string;
|
|
62
|
+
label: string;
|
|
63
|
+
/** For `sync`: when the expected reply becomes overdue (ms after `ts`). */
|
|
64
|
+
timeoutMs?: number;
|
|
65
|
+
/**
|
|
66
|
+
* Id of the call whose processing caused this call (like a trace's parent
|
|
67
|
+
* span id). When omitted it is inferred at ingest time as the innermost
|
|
68
|
+
* activity open on the `from` lane — exact for sequential processing, a
|
|
69
|
+
* best guess when one service handles several requests concurrently.
|
|
70
|
+
*/
|
|
71
|
+
parentId?: string;
|
|
72
|
+
};
|
|
73
|
+
/** Reply to an earlier `sync` call (drawn from callee back to caller). */
|
|
74
|
+
export type SwimlaneReplyEvent = SwimlaneEventBase & {
|
|
75
|
+
type: "reply";
|
|
76
|
+
/** Id of the originating call. */
|
|
77
|
+
id: string;
|
|
78
|
+
ok: boolean;
|
|
79
|
+
label: string;
|
|
80
|
+
};
|
|
81
|
+
/** Processing of an earlier `async` call finished (closes the activity). */
|
|
82
|
+
export type SwimlaneDoneEvent = SwimlaneEventBase & {
|
|
83
|
+
type: "done";
|
|
84
|
+
id: string;
|
|
85
|
+
};
|
|
86
|
+
/**
|
|
87
|
+
* Announces a message that is KNOWN to arrive later (from → to).
|
|
88
|
+
* Shown as an outstanding ghost row until a real event with `fulfils: id`
|
|
89
|
+
* arrives. Does not create a row itself.
|
|
90
|
+
*/
|
|
91
|
+
export type SwimlaneExpectEvent = SwimlaneEventBase & {
|
|
92
|
+
type: "expect";
|
|
93
|
+
id: string;
|
|
94
|
+
from: string;
|
|
95
|
+
to: string;
|
|
96
|
+
label: string;
|
|
97
|
+
timeoutMs?: number;
|
|
98
|
+
};
|
|
99
|
+
export type SwimlaneEvent = SwimlaneLaneEvent | SwimlaneStateEvent | SwimlaneCallEvent | SwimlaneReplyEvent | SwimlaneDoneEvent | SwimlaneExpectEvent;
|
|
100
|
+
export type SwimlaneLaneSnapshot = {
|
|
101
|
+
state: SwimlaneRunState;
|
|
102
|
+
/** Ids of calls currently being handled by this lane (stack order). */
|
|
103
|
+
acts: string[];
|
|
104
|
+
};
|
|
105
|
+
/** Lane id → snapshot. A lane missing from the record does not exist (yet). */
|
|
106
|
+
export type SwimlaneLanesSnapshot = Record<string, SwimlaneLaneSnapshot>;
|
|
107
|
+
/** A row event is any stream event except `expect` (which never makes a row). */
|
|
108
|
+
export type SwimlaneRowEvent = Exclude<SwimlaneEvent, SwimlaneExpectEvent> & {
|
|
109
|
+
ts: number;
|
|
110
|
+
};
|
|
111
|
+
/**
|
|
112
|
+
* One rendered transition. `pre` / `post` are the lane snapshots before and
|
|
113
|
+
* after the event: the top half of the row is drawn from `pre`, the bottom
|
|
114
|
+
* half from `post`.
|
|
115
|
+
*/
|
|
116
|
+
export type SwimlaneRow = {
|
|
117
|
+
id: number;
|
|
118
|
+
event: SwimlaneRowEvent;
|
|
119
|
+
pre: SwimlaneLanesSnapshot;
|
|
120
|
+
post: SwimlaneLanesSnapshot;
|
|
121
|
+
/** Set when this event replaced an outstanding (expected) message. */
|
|
122
|
+
fulfilled?: string;
|
|
123
|
+
/**
|
|
124
|
+
* For `reply` / `done` rows: the originating call, resolved at ingest time
|
|
125
|
+
* so the row stays drawable after its span has been garbage-collected.
|
|
126
|
+
*/
|
|
127
|
+
route?: {
|
|
128
|
+
from: string;
|
|
129
|
+
to: string;
|
|
130
|
+
label: string;
|
|
131
|
+
};
|
|
132
|
+
};
|
|
133
|
+
/** An outstanding message projected below the "now" line. */
|
|
134
|
+
export type SwimlaneGhostRow = {
|
|
135
|
+
id: string;
|
|
136
|
+
pending: SwimlanePending;
|
|
137
|
+
pre: SwimlaneLanesSnapshot;
|
|
138
|
+
post: SwimlaneLanesSnapshot;
|
|
139
|
+
};
|
|
140
|
+
/** A message that is known to be coming. */
|
|
141
|
+
export type SwimlanePending = {
|
|
142
|
+
id: string;
|
|
143
|
+
/** `reply` = implied by a sync call; `expect` = announced explicitly. */
|
|
144
|
+
type: "reply" | "expect";
|
|
145
|
+
from: string;
|
|
146
|
+
to: string;
|
|
147
|
+
label: string;
|
|
148
|
+
since: number;
|
|
149
|
+
timeoutMs?: number;
|
|
150
|
+
};
|
|
151
|
+
/** Lifecycle of a call, used for tooltips and hover payloads. */
|
|
152
|
+
export type SwimlaneSpan = {
|
|
153
|
+
id: string;
|
|
154
|
+
kind: SwimlaneCallKind;
|
|
155
|
+
from: string;
|
|
156
|
+
to: string;
|
|
157
|
+
label: string;
|
|
158
|
+
start: number;
|
|
159
|
+
end?: number;
|
|
160
|
+
status: "open" | "ok" | "error" | "done";
|
|
161
|
+
result?: string;
|
|
162
|
+
/** Call whose processing caused this one (explicit `parentId` or inferred). */
|
|
163
|
+
parent?: string;
|
|
164
|
+
};
|
|
165
|
+
export type SwimlaneModel = {
|
|
166
|
+
/** Lane ids in display (arrival) order. */
|
|
167
|
+
laneOrder: string[];
|
|
168
|
+
/** Optional display names. */
|
|
169
|
+
laneLabels: Record<string, string>;
|
|
170
|
+
/** Current snapshot (== `post` of the last row). */
|
|
171
|
+
current: SwimlaneLanesSnapshot;
|
|
172
|
+
rows: SwimlaneRow[];
|
|
173
|
+
pending: SwimlanePending[];
|
|
174
|
+
spans: Record<string, SwimlaneSpan>;
|
|
175
|
+
/** Last assigned row id. */
|
|
176
|
+
seq: number;
|
|
177
|
+
/** Ring-buffer size for `rows`. */
|
|
178
|
+
maxRows: number;
|
|
179
|
+
};
|
|
180
|
+
export type SwimlaneProps = {
|
|
181
|
+
/** The model to render — usually a state selector `(s) => s.swimlane`. */
|
|
182
|
+
model: SwimlaneModel;
|
|
183
|
+
/** Show outstanding messages below the "now" line. Default `true`. */
|
|
184
|
+
showPending?: boolean;
|
|
185
|
+
/**
|
|
186
|
+
* Keep the newest row in view while the user is at the bottom of the
|
|
187
|
+
* scroll container. Scrolling up pauses following. Default `true`.
|
|
188
|
+
*/
|
|
189
|
+
autoFollow?: boolean;
|
|
190
|
+
/** Show the built-in hover tooltip. Default `true`. */
|
|
191
|
+
showTooltip?: boolean;
|
|
192
|
+
/**
|
|
193
|
+
* Highlight a call chain (call, activity, reply, outstanding reply) by id,
|
|
194
|
+
* in addition to whatever the pointer is hovering.
|
|
195
|
+
*/
|
|
196
|
+
highlightId?: string;
|
|
197
|
+
/** Horizontal distance between lifelines in px. Default 104. */
|
|
198
|
+
laneWidth?: number;
|
|
199
|
+
/** Height of each transition row in px. Default 30. */
|
|
200
|
+
rowHeight?: number;
|
|
201
|
+
/** Height of the header holding the vertical lane names. Default 130. */
|
|
202
|
+
headerHeight?: number;
|
|
203
|
+
/** Width of the left timestamp column in px. Default 92. */
|
|
204
|
+
gutterWidth?: number;
|
|
205
|
+
/** `top` offset for the sticky header (e.g. height of a navbar). Default 0. */
|
|
206
|
+
stickyTop?: number;
|
|
207
|
+
/**
|
|
208
|
+
* Clock (epoch ms) used for "waiting …" timers and overdue detection of
|
|
209
|
+
* outstanding messages. When omitted the card ticks its own wall clock
|
|
210
|
+
* (4×/s, only while something is outstanding). Pass it to drive the card
|
|
211
|
+
* entirely from props — e.g. for replaying a recorded trace or for tests.
|
|
212
|
+
*/
|
|
213
|
+
now?: number;
|
|
214
|
+
className?: string;
|
|
215
|
+
};
|
|
216
|
+
/** What the pointer is over. */
|
|
217
|
+
export type SwimlaneTargetKind = "transition" | "activity" | "state" | "pending";
|
|
218
|
+
export type SwimlaneTarget = {
|
|
219
|
+
kind: SwimlaneTargetKind;
|
|
220
|
+
/** Call id (transition/activity/pending) or `state-<rowId>` (state). */
|
|
221
|
+
id: string;
|
|
222
|
+
lane?: string;
|
|
223
|
+
rowId?: number;
|
|
224
|
+
};
|
|
225
|
+
export type SwimlaneHoverChangedEvent = {
|
|
226
|
+
/** New hover target, or `null` when the pointer left all targets. */
|
|
227
|
+
target: SwimlaneTarget | null;
|
|
228
|
+
/** Target that was hovered before, if any. */
|
|
229
|
+
previous: SwimlaneTarget | null;
|
|
230
|
+
/** Span details for the new target (when it refers to a call). */
|
|
231
|
+
span?: SwimlaneSpan;
|
|
232
|
+
/** Outstanding message details when `target.kind === "pending"`. */
|
|
233
|
+
pending?: SwimlanePending;
|
|
234
|
+
/**
|
|
235
|
+
* Calls made while handling the hovered call (its direct children). Their
|
|
236
|
+
* call and reply transitions are highlighted as well.
|
|
237
|
+
*/
|
|
238
|
+
related?: string[];
|
|
239
|
+
/**
|
|
240
|
+
* For a hovered transition: call id of the caller-side process (activity)
|
|
241
|
+
* that sent the call and receives its reply. That activity is highlighted.
|
|
242
|
+
*/
|
|
243
|
+
process?: string;
|
|
244
|
+
clientX?: number;
|
|
245
|
+
clientY?: number;
|
|
246
|
+
};
|
|
247
|
+
export type SwimlaneItemClickedEvent = {
|
|
248
|
+
target: SwimlaneTarget;
|
|
249
|
+
span?: SwimlaneSpan;
|
|
250
|
+
pending?: SwimlanePending;
|
|
251
|
+
related?: string[];
|
|
252
|
+
process?: string;
|
|
253
|
+
};
|
|
254
|
+
export type SwimlaneEvents = {
|
|
255
|
+
onHoverChanged: SwimlaneHoverChangedEvent;
|
|
256
|
+
onItemClicked: SwimlaneItemClickedEvent;
|
|
257
|
+
};
|
|
258
|
+
export type SwimlaneEventsReceivedEvent = {
|
|
259
|
+
/** Which model to update (apps may show several swimlanes). */
|
|
260
|
+
modelId: string;
|
|
261
|
+
events: SwimlaneEvent[];
|
|
262
|
+
};
|
|
263
|
+
export type SwimlaneRowsClearedEvent = {
|
|
264
|
+
modelId: string;
|
|
265
|
+
};
|
|
266
|
+
export declare const DEF_LANE_WIDTH = 104;
|
|
267
|
+
export declare const DEF_ROW_HEIGHT = 30;
|
|
268
|
+
export declare const DEF_HEADER_HEIGHT = 130;
|
|
269
|
+
export declare const DEF_GUTTER_WIDTH = 92;
|
|
270
|
+
export declare const DEF_MAX_ROWS = 2000;
|
|
271
|
+
export {};
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import { createCardDeclaration as e, createOnAction as t, createOnDispatch as n, registerActions as r } from "@pihanga2/core";
|
|
2
|
+
//#region src/cards/swimlane/swimlane.types.ts
|
|
3
|
+
var i = "shad/swimlane", a = e(i), o = r(i, ["hover_changed", "item_clicked"]), s = t(o.HOVER_CHANGED), c = t(o.ITEM_CLICKED), l = r(`${i}/data`, ["events_received", "rows_cleared"]), u = n(l.EVENTS_RECEIVED), d = n(l.ROWS_CLEARED), f = t(l.EVENTS_RECEIVED), p = t(l.ROWS_CLEARED), m = 104, h = 30, g = 130, _ = 92, v = 2e3;
|
|
4
|
+
//#endregion
|
|
5
|
+
export { _ as DEF_GUTTER_WIDTH, g as DEF_HEADER_HEIGHT, m as DEF_LANE_WIDTH, v as DEF_MAX_ROWS, h as DEF_ROW_HEIGHT, o as SWIMLANE_ACTION, i as SWIMLANE_CARD, l as SWIMLANE_DATA_ACTION, a as Swimlane, u as dispatchSwimlaneEvents, d as dispatchSwimlaneRowsCleared, f as onSwimlaneEventsReceived, s as onSwimlaneHoverChanged, c as onSwimlaneItemClicked, p as onSwimlaneRowsCleared };
|
|
6
|
+
|
|
7
|
+
//# sourceMappingURL=swimlane.types.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"swimlane.types.js","names":[],"sources":["../../../src/cards/swimlane/swimlane.types.ts"],"sourcesContent":["import {\n createCardDeclaration,\n createOnAction,\n createOnDispatch,\n registerActions,\n} from \"@pihanga2/core\";\n\n// ─────────────────────────────────────────────────────────────────────────────\n// Card identity\n// ─────────────────────────────────────────────────────────────────────────────\n\nexport const SWIMLANE_CARD = \"shad/swimlane\";\n\nexport const Swimlane = createCardDeclaration<SwimlaneProps, SwimlaneEvents>(\n SWIMLANE_CARD,\n);\n\n// ─────────────────────────────────────────────────────────────────────────────\n// Actions EMITTED by the card (user interaction)\n// ─────────────────────────────────────────────────────────────────────────────\n\nexport const SWIMLANE_ACTION = registerActions(SWIMLANE_CARD, [\n \"hover_changed\",\n \"item_clicked\",\n]);\n\nexport const onSwimlaneHoverChanged = createOnAction<SwimlaneHoverChangedEvent>(\n SWIMLANE_ACTION.HOVER_CHANGED,\n);\n\nexport const onSwimlaneItemClicked = createOnAction<SwimlaneItemClickedEvent>(\n SWIMLANE_ACTION.ITEM_CLICKED,\n);\n\n// ─────────────────────────────────────────────────────────────────────────────\n// Actions CONSUMED by the app (feeding the model).\n//\n// These are not emitted by the card. They are a convenience so that stream\n// adapters (WebSocket, SSE, polling …) can push events with a typed dispatcher\n// and apps can wire the model with a single `registerSwimlaneModel()` call\n// (see swimlane.model.ts).\n// ─────────────────────────────────────────────────────────────────────────────\n\nexport const SWIMLANE_DATA_ACTION = registerActions(`${SWIMLANE_CARD}/data`, [\n \"events_received\",\n \"rows_cleared\",\n]);\n\nexport const dispatchSwimlaneEvents =\n createOnDispatch<SwimlaneEventsReceivedEvent>(\n SWIMLANE_DATA_ACTION.EVENTS_RECEIVED,\n );\nexport const dispatchSwimlaneRowsCleared =\n createOnDispatch<SwimlaneRowsClearedEvent>(SWIMLANE_DATA_ACTION.ROWS_CLEARED);\n\nexport const onSwimlaneEventsReceived =\n createOnAction<SwimlaneEventsReceivedEvent>(\n SWIMLANE_DATA_ACTION.EVENTS_RECEIVED,\n );\nexport const onSwimlaneRowsCleared = createOnAction<SwimlaneRowsClearedEvent>(\n SWIMLANE_DATA_ACTION.ROWS_CLEARED,\n);\n\n// ─────────────────────────────────────────────────────────────────────────────\n// Incoming stream events (what a monitored deployment reports)\n// All timestamps are epoch milliseconds; `ts` is filled in on ingest if absent.\n// ─────────────────────────────────────────────────────────────────────────────\n\n/** Run state of a service, drawn on its lifeline. */\nexport type SwimlaneRunState =\n | \"created\"\n | \"starting\"\n | \"running\"\n | \"degraded\"\n | \"stopped\";\n\n/**\n * How a message travels between lanes.\n * - `sync` – request that expects a reply; opens an activity on the target\n * and automatically creates an *outstanding reply*.\n * - `async` – message that opens an activity on the target, closed by `done`.\n * - `event` – fire-and-forget; no activity.\n */\nexport type SwimlaneCallKind = \"sync\" | \"async\" | \"event\";\n\ntype SwimlaneEventBase = {\n /** Epoch ms. Defaults to `Date.now()` at ingest time. */\n ts?: number;\n /** Id of an `expect` event that this real event resolves. */\n fulfils?: string;\n};\n\n/** A service became known. Lanes referenced by calls are also added implicitly. */\nexport type SwimlaneLaneEvent = SwimlaneEventBase & {\n type: \"lane\";\n lane: string;\n /** Display name (defaults to `lane`). */\n label?: string;\n};\n\n/** A service changed its run state. */\nexport type SwimlaneStateEvent = SwimlaneEventBase & {\n type: \"state\";\n lane: string;\n state: SwimlaneRunState;\n};\n\n/** A message between two lanes (or a lane and itself). */\nexport type SwimlaneCallEvent = SwimlaneEventBase & {\n type: \"call\";\n /** Unique id; replies / `done` refer to it. */\n id: string;\n kind: SwimlaneCallKind;\n from: string;\n to: string;\n label: string;\n /** For `sync`: when the expected reply becomes overdue (ms after `ts`). */\n timeoutMs?: number;\n /**\n * Id of the call whose processing caused this call (like a trace's parent\n * span id). When omitted it is inferred at ingest time as the innermost\n * activity open on the `from` lane — exact for sequential processing, a\n * best guess when one service handles several requests concurrently.\n */\n parentId?: string;\n};\n\n/** Reply to an earlier `sync` call (drawn from callee back to caller). */\nexport type SwimlaneReplyEvent = SwimlaneEventBase & {\n type: \"reply\";\n /** Id of the originating call. */\n id: string;\n ok: boolean;\n label: string;\n};\n\n/** Processing of an earlier `async` call finished (closes the activity). */\nexport type SwimlaneDoneEvent = SwimlaneEventBase & {\n type: \"done\";\n id: string;\n};\n\n/**\n * Announces a message that is KNOWN to arrive later (from → to).\n * Shown as an outstanding ghost row until a real event with `fulfils: id`\n * arrives. Does not create a row itself.\n */\nexport type SwimlaneExpectEvent = SwimlaneEventBase & {\n type: \"expect\";\n id: string;\n from: string;\n to: string;\n label: string;\n timeoutMs?: number;\n};\n\nexport type SwimlaneEvent =\n | SwimlaneLaneEvent\n | SwimlaneStateEvent\n | SwimlaneCallEvent\n | SwimlaneReplyEvent\n | SwimlaneDoneEvent\n | SwimlaneExpectEvent;\n\n// ─────────────────────────────────────────────────────────────────────────────\n// Model (lives in the app's Redux state; plain JSON)\n// ─────────────────────────────────────────────────────────────────────────────\n\nexport type SwimlaneLaneSnapshot = {\n state: SwimlaneRunState;\n /** Ids of calls currently being handled by this lane (stack order). */\n acts: string[];\n};\n\n/** Lane id → snapshot. A lane missing from the record does not exist (yet). */\nexport type SwimlaneLanesSnapshot = Record<string, SwimlaneLaneSnapshot>;\n\n/** A row event is any stream event except `expect` (which never makes a row). */\nexport type SwimlaneRowEvent = Exclude<SwimlaneEvent, SwimlaneExpectEvent> & {\n ts: number;\n};\n\n/**\n * One rendered transition. `pre` / `post` are the lane snapshots before and\n * after the event: the top half of the row is drawn from `pre`, the bottom\n * half from `post`.\n */\nexport type SwimlaneRow = {\n id: number;\n event: SwimlaneRowEvent;\n pre: SwimlaneLanesSnapshot;\n post: SwimlaneLanesSnapshot;\n /** Set when this event replaced an outstanding (expected) message. */\n fulfilled?: string;\n /**\n * For `reply` / `done` rows: the originating call, resolved at ingest time\n * so the row stays drawable after its span has been garbage-collected.\n */\n route?: {from: string; to: string; label: string};\n};\n\n/** An outstanding message projected below the \"now\" line. */\nexport type SwimlaneGhostRow = {\n id: string;\n pending: SwimlanePending;\n pre: SwimlaneLanesSnapshot;\n post: SwimlaneLanesSnapshot;\n};\n\n/** A message that is known to be coming. */\nexport type SwimlanePending = {\n id: string;\n /** `reply` = implied by a sync call; `expect` = announced explicitly. */\n type: \"reply\" | \"expect\";\n from: string;\n to: string;\n label: string;\n since: number;\n timeoutMs?: number;\n};\n\n/** Lifecycle of a call, used for tooltips and hover payloads. */\nexport type SwimlaneSpan = {\n id: string;\n kind: SwimlaneCallKind;\n from: string;\n to: string;\n label: string;\n start: number;\n end?: number;\n status: \"open\" | \"ok\" | \"error\" | \"done\";\n result?: string;\n /** Call whose processing caused this one (explicit `parentId` or inferred). */\n parent?: string;\n};\n\nexport type SwimlaneModel = {\n /** Lane ids in display (arrival) order. */\n laneOrder: string[];\n /** Optional display names. */\n laneLabels: Record<string, string>;\n /** Current snapshot (== `post` of the last row). */\n current: SwimlaneLanesSnapshot;\n rows: SwimlaneRow[];\n pending: SwimlanePending[];\n spans: Record<string, SwimlaneSpan>;\n /** Last assigned row id. */\n seq: number;\n /** Ring-buffer size for `rows`. */\n maxRows: number;\n};\n\n// ─────────────────────────────────────────────────────────────────────────────\n// Card props & events\n// ─────────────────────────────────────────────────────────────────────────────\n\nexport type SwimlaneProps = {\n /** The model to render — usually a state selector `(s) => s.swimlane`. */\n model: SwimlaneModel;\n\n /** Show outstanding messages below the \"now\" line. Default `true`. */\n showPending?: boolean;\n\n /**\n * Keep the newest row in view while the user is at the bottom of the\n * scroll container. Scrolling up pauses following. Default `true`.\n */\n autoFollow?: boolean;\n\n /** Show the built-in hover tooltip. Default `true`. */\n showTooltip?: boolean;\n\n /**\n * Highlight a call chain (call, activity, reply, outstanding reply) by id,\n * in addition to whatever the pointer is hovering.\n */\n highlightId?: string;\n\n /** Horizontal distance between lifelines in px. Default 104. */\n laneWidth?: number;\n /** Height of each transition row in px. Default 30. */\n rowHeight?: number;\n /** Height of the header holding the vertical lane names. Default 130. */\n headerHeight?: number;\n /** Width of the left timestamp column in px. Default 92. */\n gutterWidth?: number;\n /** `top` offset for the sticky header (e.g. height of a navbar). Default 0. */\n stickyTop?: number;\n\n /**\n * Clock (epoch ms) used for \"waiting …\" timers and overdue detection of\n * outstanding messages. When omitted the card ticks its own wall clock\n * (4×/s, only while something is outstanding). Pass it to drive the card\n * entirely from props — e.g. for replaying a recorded trace or for tests.\n */\n now?: number;\n\n className?: string;\n};\n\n/** What the pointer is over. */\nexport type SwimlaneTargetKind = \"transition\" | \"activity\" | \"state\" | \"pending\";\n\nexport type SwimlaneTarget = {\n kind: SwimlaneTargetKind;\n /** Call id (transition/activity/pending) or `state-<rowId>` (state). */\n id: string;\n lane?: string;\n rowId?: number;\n};\n\nexport type SwimlaneHoverChangedEvent = {\n /** New hover target, or `null` when the pointer left all targets. */\n target: SwimlaneTarget | null;\n /** Target that was hovered before, if any. */\n previous: SwimlaneTarget | null;\n /** Span details for the new target (when it refers to a call). */\n span?: SwimlaneSpan;\n /** Outstanding message details when `target.kind === \"pending\"`. */\n pending?: SwimlanePending;\n /**\n * Calls made while handling the hovered call (its direct children). Their\n * call and reply transitions are highlighted as well.\n */\n related?: string[];\n /**\n * For a hovered transition: call id of the caller-side process (activity)\n * that sent the call and receives its reply. That activity is highlighted.\n */\n process?: string;\n clientX?: number;\n clientY?: number;\n};\n\nexport type SwimlaneItemClickedEvent = {\n target: SwimlaneTarget;\n span?: SwimlaneSpan;\n pending?: SwimlanePending;\n related?: string[];\n process?: string;\n};\n\nexport type SwimlaneEvents = {\n onHoverChanged: SwimlaneHoverChangedEvent;\n onItemClicked: SwimlaneItemClickedEvent;\n};\n\n// ─────────────────────────────────────────────────────────────────────────────\n// Data-action payloads\n// ─────────────────────────────────────────────────────────────────────────────\n\nexport type SwimlaneEventsReceivedEvent = {\n /** Which model to update (apps may show several swimlanes). */\n modelId: string;\n events: SwimlaneEvent[];\n};\n\nexport type SwimlaneRowsClearedEvent = {\n modelId: string;\n};\n\nexport const DEF_LANE_WIDTH = 104;\nexport const DEF_ROW_HEIGHT = 30;\nexport const DEF_HEADER_HEIGHT = 130;\nexport const DEF_GUTTER_WIDTH = 92;\nexport const DEF_MAX_ROWS = 2000;\n"],"mappings":";;AAWA,IAAa,IAAgB,iBAEhB,IAAW,EACtB,CACF,GAMa,IAAkB,EAAgB,GAAe,CAC5D,iBACA,cACF,CAAC,GAEY,IAAyB,EACpC,EAAgB,aAClB,GAEa,IAAwB,EACnC,EAAgB,YAClB,GAWa,IAAuB,EAAgB,GAAG,EAAc,QAAQ,CAC3E,mBACA,cACF,CAAC,GAEY,IACX,EACE,EAAqB,eACvB,GACW,IACX,EAA2C,EAAqB,YAAY,GAEjE,IACX,EACE,EAAqB,eACvB,GACW,IAAwB,EACnC,EAAqB,YACvB,GA4Sa,IAAiB,KACjB,IAAiB,IACjB,IAAoB,KACpB,IAAmB,IACnB,IAAe"}
|