@xenosystem/blocks 0.13.11 → 0.13.13
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/dist/chunk-6XVFYPVH.js +511 -0
- package/dist/data/index.js +2 -4
- package/dist/edit/index.js +5 -7
- package/dist/icons/index.js +2 -4
- package/dist/ops/index.d.ts +231 -19
- package/dist/ops/index.js +590 -372
- package/dist/time/index.js +1 -2
- package/package.json +3 -3
- package/dist/chunk-K7YLLV2W.js +0 -132
- package/dist/chunk-W4PTX2Y4.js +0 -414
package/dist/ops/index.js
CHANGED
|
@@ -7,11 +7,8 @@ import {
|
|
|
7
7
|
terminalThemeVar
|
|
8
8
|
} from "../chunk-WE6A2DTY.js";
|
|
9
9
|
import {
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
CopyGlyph,
|
|
13
|
-
RetryGlyph
|
|
14
|
-
} from "../chunk-K7YLLV2W.js";
|
|
10
|
+
ICONS
|
|
11
|
+
} from "../chunk-6XVFYPVH.js";
|
|
15
12
|
import "../chunk-2KG3PWR4.js";
|
|
16
13
|
|
|
17
14
|
// src/ops/console/panel.ts
|
|
@@ -63,10 +60,10 @@ function spliceRedactedAppend(existing, addition, redact, carry = REDACTION_CARR
|
|
|
63
60
|
const tail = existing.slice(cut);
|
|
64
61
|
return head + redact(tail + addition);
|
|
65
62
|
}
|
|
66
|
-
function truncateLogMessage(
|
|
67
|
-
if (max <= 0 ||
|
|
68
|
-
if (max <= MESSAGE_ELISION.length) return
|
|
69
|
-
return MESSAGE_ELISION +
|
|
63
|
+
function truncateLogMessage(text3, max) {
|
|
64
|
+
if (max <= 0 || text3.length <= max) return text3;
|
|
65
|
+
if (max <= MESSAGE_ELISION.length) return text3.slice(text3.length - max);
|
|
66
|
+
return MESSAGE_ELISION + text3.slice(text3.length - (max - MESSAGE_ELISION.length));
|
|
70
67
|
}
|
|
71
68
|
function formatRecord(record) {
|
|
72
69
|
const time = new Date(record.ts).toISOString();
|
|
@@ -243,7 +240,7 @@ var ConsoleController = class {
|
|
|
243
240
|
*/
|
|
244
241
|
merge(existing, patch) {
|
|
245
242
|
const secrets = [...this.host.getSecrets?.() ?? []];
|
|
246
|
-
const redact = (
|
|
243
|
+
const redact = (text3) => redactForLog(text3, secrets);
|
|
247
244
|
let message = existing.message;
|
|
248
245
|
if (typeof patch.message === "string") message = redact(patch.message);
|
|
249
246
|
if (typeof patch.appendMessage === "string" && patch.appendMessage.length > 0) {
|
|
@@ -388,6 +385,29 @@ var ConsoleController = class {
|
|
|
388
385
|
}
|
|
389
386
|
/* ── Interaction ───────────────────────────────────────────────────────── */
|
|
390
387
|
/** Follow the tail. Auto-disabled by the view when the user scrolls up. */
|
|
388
|
+
/* ── View state the declaration cannot hold ────────────────────────────── */
|
|
389
|
+
expandedId = null;
|
|
390
|
+
viewport = { height: 0, scrollTop: 0 };
|
|
391
|
+
/** Which record's data is expanded under its row, if any. */
|
|
392
|
+
getExpanded() {
|
|
393
|
+
return this.expandedId;
|
|
394
|
+
}
|
|
395
|
+
/** Toggle a record's expanded detail (only records carrying `data` expand). */
|
|
396
|
+
toggleExpanded(recordId) {
|
|
397
|
+
const record = this.records.find((r) => r.id === recordId);
|
|
398
|
+
if (!record || record.data === void 0) return;
|
|
399
|
+
this.expandedId = this.expandedId === recordId ? null : recordId;
|
|
400
|
+
this.notify();
|
|
401
|
+
}
|
|
402
|
+
/** The scroller reports its viewport; the view state windows the rows from it. */
|
|
403
|
+
setViewport(height, scrollTop) {
|
|
404
|
+
if (this.viewport.height === height && this.viewport.scrollTop === scrollTop) return;
|
|
405
|
+
this.viewport = { height, scrollTop };
|
|
406
|
+
this.notify();
|
|
407
|
+
}
|
|
408
|
+
getViewport() {
|
|
409
|
+
return this.viewport;
|
|
410
|
+
}
|
|
391
411
|
setFollow(follow) {
|
|
392
412
|
if (this.follow === follow) return;
|
|
393
413
|
this.follow = follow;
|
|
@@ -607,203 +627,289 @@ var consoleManifest = {
|
|
|
607
627
|
};
|
|
608
628
|
|
|
609
629
|
// src/ops/console/react/ConsolePanelView.tsx
|
|
610
|
-
import {
|
|
630
|
+
import { useEffect, useRef, useSyncExternalStore } from "react";
|
|
611
631
|
import {
|
|
612
632
|
Badge,
|
|
633
|
+
Code,
|
|
634
|
+
Column,
|
|
613
635
|
EmptyState,
|
|
636
|
+
FilterChip,
|
|
614
637
|
IconButton,
|
|
615
638
|
Row,
|
|
616
639
|
RowList,
|
|
617
640
|
ScrollArea,
|
|
618
641
|
SearchField,
|
|
619
642
|
SegmentedControl,
|
|
643
|
+
Stack,
|
|
620
644
|
StatusBar,
|
|
645
|
+
Text,
|
|
621
646
|
Toolbar,
|
|
622
|
-
ToolbarGroup
|
|
647
|
+
ToolbarGroup,
|
|
648
|
+
VirtualWindow
|
|
623
649
|
} from "@xenosystem/components/chrome";
|
|
650
|
+
|
|
651
|
+
// src/ops/console/declaration.ts
|
|
624
652
|
import { computeWindow } from "@xenosystem/tree-core";
|
|
625
|
-
|
|
626
|
-
|
|
627
|
-
|
|
628
|
-
|
|
629
|
-
|
|
630
|
-
|
|
631
|
-
|
|
653
|
+
var TONE = { trace: "neutral", debug: "neutral", info: "info", warn: "warning", error: "error" };
|
|
654
|
+
function consoleViewState(c, options = {}) {
|
|
655
|
+
const s = c.getState();
|
|
656
|
+
const rowHeight = options.rowHeight ?? 20;
|
|
657
|
+
const showTimestamps = options.showTimestamps ?? true;
|
|
658
|
+
const viewport = c.getViewport();
|
|
659
|
+
const window_ = computeWindow({ scrollTop: viewport.scrollTop, viewportHeight: viewport.height || rowHeight * 20, rowHeight, rowCount: s.rows.length });
|
|
660
|
+
const expanded = c.getExpanded();
|
|
661
|
+
return {
|
|
662
|
+
search: s.filter.search ?? "",
|
|
663
|
+
levels: LEVEL_ORDER.map((l) => ({ value: l, label: l.slice(0, 1).toUpperCase() })),
|
|
664
|
+
level: s.filter.minLevel ?? "trace",
|
|
665
|
+
errors: s.counts.error > 0 ? String(s.counts.error) : void 0,
|
|
666
|
+
warns: s.counts.warn > 0 ? String(s.counts.warn) : void 0,
|
|
667
|
+
multiSource: s.sources.length > 1,
|
|
668
|
+
sources: s.sources.map((src) => ({ id: src.id, label: src.label ?? src.id, on: src.enabled, title: `${src.count} records` })),
|
|
669
|
+
empty: s.rows.length === 0,
|
|
670
|
+
emptyTitle: s.total > 0 ? "No matches" : "No output",
|
|
671
|
+
emptyHint: s.total > 0 ? "Nothing matches the current filter." : options.emptyHint ?? "Run something to see its output here.",
|
|
672
|
+
listed: s.rows.length > 0,
|
|
673
|
+
rowHeight,
|
|
674
|
+
totalHeight: window_.totalHeight,
|
|
675
|
+
offsetTop: window_.offsetTop,
|
|
676
|
+
rows: s.rows.slice(window_.startIndex, window_.endIndex).map((record) => ({
|
|
677
|
+
id: record.id,
|
|
678
|
+
time: showTimestamps ? new Date(record.ts).toISOString().slice(11, 23) : void 0,
|
|
679
|
+
level: record.level,
|
|
680
|
+
tone: TONE[record.level],
|
|
681
|
+
source: record.source,
|
|
682
|
+
message: record.message,
|
|
683
|
+
repeat: (record.count ?? 1) > 1 ? `x${record.count}` : void 0,
|
|
684
|
+
expanded: expanded === record.id && record.data !== void 0,
|
|
685
|
+
// Already redacted — the buffer never held the raw value.
|
|
686
|
+
detail: expanded === record.id && record.data !== void 0 ? safeJson(record.data) : void 0
|
|
687
|
+
})),
|
|
688
|
+
countLabel: `${s.rows.length} of ${s.total}` + (s.dropped > 0 ? ` \xB7 ${s.dropped} dropped` : "") + (s.droppedPatches > 0 ? ` \xB7 ${s.droppedPatches} unmatched` : ""),
|
|
689
|
+
followLabel: s.follow ? "following" : void 0
|
|
690
|
+
};
|
|
691
|
+
}
|
|
692
|
+
function applyConsoleUi(c, intent) {
|
|
693
|
+
switch (intent.kind) {
|
|
694
|
+
case "search":
|
|
695
|
+
c.setSearch(intent.value);
|
|
696
|
+
break;
|
|
697
|
+
case "level":
|
|
698
|
+
c.setLevel(intent.level === "trace" ? void 0 : intent.level);
|
|
699
|
+
break;
|
|
700
|
+
case "copyVisible":
|
|
701
|
+
void globalThis.navigator?.clipboard?.writeText(c.copyVisible());
|
|
702
|
+
break;
|
|
703
|
+
case "clear":
|
|
704
|
+
c.clear();
|
|
705
|
+
break;
|
|
706
|
+
case "source":
|
|
707
|
+
c.toggleSource(intent.id, intent.on);
|
|
708
|
+
break;
|
|
709
|
+
case "row":
|
|
710
|
+
c.toggleExpanded(intent.id);
|
|
711
|
+
c.activate(intent.id);
|
|
712
|
+
break;
|
|
713
|
+
case "contextMenu":
|
|
714
|
+
c.requestContextMenu(intent.id, intent.x, intent.y);
|
|
715
|
+
break;
|
|
716
|
+
}
|
|
717
|
+
}
|
|
718
|
+
var consoleViewManifest = {
|
|
719
|
+
id: consoleManifest.id,
|
|
720
|
+
version: "1.0.0",
|
|
721
|
+
title: "Console",
|
|
722
|
+
category: "ops",
|
|
723
|
+
layout: { slot: "bottom" },
|
|
724
|
+
inputs: [{ id: "view", type: "object", label: "View state", description: "The ConsoleViewModel the runtime derives from the controller on every draw." }],
|
|
725
|
+
outputs: [{ id: "ui", type: "object", label: "UI intent", description: "{ kind, \u2026 } \u2014 applied by the runtime to the controller." }],
|
|
726
|
+
commands: []
|
|
632
727
|
};
|
|
633
|
-
|
|
634
|
-
|
|
635
|
-
|
|
636
|
-
|
|
637
|
-
|
|
638
|
-
|
|
728
|
+
var EMPTY = { search: "", levels: [], level: "trace", multiSource: false, sources: [], empty: true, emptyTitle: "No output", emptyHint: "Run something to see its output here.", listed: false, rowHeight: 20, totalHeight: 0, offsetTop: 0, rows: [], countLabel: "0 of 0" };
|
|
729
|
+
var BEHAVIOURS = {
|
|
730
|
+
"ops/consolePanelView": (inputs) => inputs.view ?? EMPTY
|
|
731
|
+
};
|
|
732
|
+
var CONSOLE_RUNTIME_UNITS = ["console/Scroller"];
|
|
733
|
+
var text = (b) => ({ component: "text", props: { text: b } });
|
|
734
|
+
var ui = (kind, fields = {}) => ({ emit: "ui", value: { object: { kind: { value: kind }, ...fields } } });
|
|
735
|
+
var CONSOLE_DECLARATION = {
|
|
736
|
+
format: "xeno.block@1",
|
|
737
|
+
manifest: consoleViewManifest,
|
|
738
|
+
behaviour: "ops/consolePanelView",
|
|
739
|
+
composition: {
|
|
740
|
+
component: "chrome/Column",
|
|
741
|
+
children: [
|
|
742
|
+
{
|
|
743
|
+
component: "chrome/Toolbar",
|
|
744
|
+
props: {
|
|
745
|
+
left: {
|
|
746
|
+
node: {
|
|
747
|
+
component: "fragment",
|
|
748
|
+
children: [
|
|
749
|
+
{ component: "chrome/SearchField", props: { value: { input: "view.search" }, placeholder: { value: "Filter\u2026" } }, on: { onChange: ui("search", { value: { arg: "" } }) } },
|
|
750
|
+
{ component: "chrome/SegmentedControl", props: { size: { value: "sm" }, label: { value: "Minimum level" }, options: { input: "view.levels" }, value: { input: "view.level" } }, on: { onChange: ui("level", { level: { arg: "" } }) } }
|
|
751
|
+
]
|
|
752
|
+
}
|
|
753
|
+
},
|
|
754
|
+
right: {
|
|
755
|
+
node: {
|
|
756
|
+
component: "chrome/ToolbarGroup",
|
|
757
|
+
props: { end: { value: true } },
|
|
758
|
+
children: [
|
|
759
|
+
{ component: "chrome/Badge", when: { input: "view.errors" }, props: { tone: { value: "error" } }, children: [text({ input: "view.errors" })] },
|
|
760
|
+
{ component: "chrome/Badge", when: { input: "view.warns" }, props: { tone: { value: "warning" } }, children: [text({ input: "view.warns" })] },
|
|
761
|
+
{ component: "chrome/IconButton", props: { icon: { node: { component: "icons/Copy" } }, label: { value: "Copy visible" } }, on: { onClick: ui("copyVisible") } },
|
|
762
|
+
{ component: "chrome/IconButton", props: { icon: { node: { component: "icons/Clear" } }, label: { value: "Clear" } }, on: { onClick: ui("clear") } }
|
|
763
|
+
]
|
|
764
|
+
}
|
|
765
|
+
}
|
|
766
|
+
}
|
|
767
|
+
},
|
|
768
|
+
{
|
|
769
|
+
component: "chrome/Stack",
|
|
770
|
+
when: { input: "view.multiSource" },
|
|
771
|
+
props: { direction: { value: "row" }, gap: { value: 4 }, pad: { value: "inset" } },
|
|
772
|
+
children: [
|
|
773
|
+
{ component: "chrome/FilterChip", each: { input: "view.sources", key: "id" }, props: { on: { item: "on" }, title: { item: "title" } }, on: { onChange: ui("source", { id: { item: "id" }, on: { arg: "" } }) }, children: [text({ item: "label" })] }
|
|
774
|
+
]
|
|
775
|
+
},
|
|
776
|
+
{ component: "chrome/EmptyState", when: { input: "view.empty" }, props: { title: { input: "view.emptyTitle" }, hint: { input: "view.emptyHint" } } },
|
|
777
|
+
{
|
|
778
|
+
component: "console/Scroller",
|
|
779
|
+
when: { input: "view.listed" },
|
|
780
|
+
children: [
|
|
781
|
+
{
|
|
782
|
+
component: "chrome/VirtualWindow",
|
|
783
|
+
props: { totalHeight: { input: "view.totalHeight" }, offsetTop: { input: "view.offsetTop" } },
|
|
784
|
+
children: [
|
|
785
|
+
{
|
|
786
|
+
component: "chrome/RowList",
|
|
787
|
+
props: { role: { value: "log" } },
|
|
788
|
+
children: [
|
|
789
|
+
{
|
|
790
|
+
component: "fragment",
|
|
791
|
+
each: { input: "view.rows", key: "id" },
|
|
792
|
+
children: [
|
|
793
|
+
{
|
|
794
|
+
component: "chrome/Row",
|
|
795
|
+
props: {
|
|
796
|
+
height: { input: "view.rowHeight" },
|
|
797
|
+
noIcon: { value: true },
|
|
798
|
+
label: {
|
|
799
|
+
node: {
|
|
800
|
+
component: "chrome/Stack",
|
|
801
|
+
props: { direction: { value: "row" }, pad: { value: "none" } },
|
|
802
|
+
children: [
|
|
803
|
+
{ component: "chrome/Text", when: { item: "time" }, props: { role: { value: "number" } }, children: [text({ item: "time" })] },
|
|
804
|
+
{ component: "chrome/Badge", props: { tone: { item: "tone" } }, children: [text({ item: "level" })] },
|
|
805
|
+
{ component: "chrome/Text", when: { item: "source" }, props: { role: { value: "meta" } }, children: [text({ item: "source" })] },
|
|
806
|
+
{ component: "chrome/Text", children: [text({ item: "message" })] }
|
|
807
|
+
]
|
|
808
|
+
}
|
|
809
|
+
},
|
|
810
|
+
trailing: { node: { component: "chrome/Badge", when: { item: "repeat" }, props: { title: { value: "Repeated consecutively" } }, children: [text({ item: "repeat" })] } }
|
|
811
|
+
},
|
|
812
|
+
on: { onClick: ui("row", { id: { item: "id" } }), onContextMenuAt: ui("contextMenu", { id: { item: "id" }, x: { arg: "", index: 0 }, y: { arg: "", index: 1 } }) }
|
|
813
|
+
},
|
|
814
|
+
{ component: "chrome/Code", when: { item: "expanded" }, children: [text({ item: "detail" })] }
|
|
815
|
+
]
|
|
816
|
+
}
|
|
817
|
+
]
|
|
818
|
+
}
|
|
819
|
+
]
|
|
820
|
+
}
|
|
821
|
+
]
|
|
822
|
+
},
|
|
823
|
+
{ component: "chrome/StatusBar", props: { left: { input: "view.countLabel" }, right: { input: "view.followLabel" } } }
|
|
824
|
+
]
|
|
825
|
+
}
|
|
826
|
+
};
|
|
827
|
+
|
|
828
|
+
// src/ops/console/react/ConsolePanelView.tsx
|
|
829
|
+
import { Fragment, jsx, jsxs } from "react/jsx-runtime";
|
|
830
|
+
var CopyGlyph = ICONS["icons/Copy"];
|
|
831
|
+
var ClearGlyph = ICONS["icons/Clear"];
|
|
832
|
+
function ConsoleScroller({ controller, rowHeight = 20, children }) {
|
|
639
833
|
const state = useSyncExternalStore(controller.subscribe, controller.getState, controller.getState);
|
|
640
|
-
const
|
|
641
|
-
const [viewport, setViewport] = useState({ height: 0, scrollTop: 0 });
|
|
642
|
-
const [expanded, setExpanded] = useState(null);
|
|
834
|
+
const ref = useRef(null);
|
|
643
835
|
useEffect(() => {
|
|
644
|
-
const
|
|
645
|
-
if (!
|
|
646
|
-
|
|
647
|
-
|
|
648
|
-
|
|
649
|
-
|
|
650
|
-
|
|
836
|
+
const el = ref.current;
|
|
837
|
+
if (!el) return;
|
|
838
|
+
controller.setViewport(el.clientHeight, el.scrollTop);
|
|
839
|
+
const RO = globalThis.ResizeObserver;
|
|
840
|
+
if (!RO) return;
|
|
841
|
+
const ro = new RO(() => controller.setViewport(el.clientHeight, el.scrollTop));
|
|
842
|
+
ro.observe(el);
|
|
843
|
+
return () => ro.disconnect();
|
|
844
|
+
}, [controller]);
|
|
651
845
|
useEffect(() => {
|
|
652
|
-
const
|
|
653
|
-
if (!
|
|
654
|
-
|
|
846
|
+
const el = ref.current;
|
|
847
|
+
if (!el || !state.follow) return;
|
|
848
|
+
el.scrollTop = el.scrollHeight;
|
|
655
849
|
}, [state.rows.length, state.follow]);
|
|
656
|
-
|
|
657
|
-
|
|
658
|
-
|
|
659
|
-
|
|
660
|
-
|
|
661
|
-
|
|
662
|
-
|
|
663
|
-
|
|
664
|
-
|
|
850
|
+
return /* @__PURE__ */ jsx(
|
|
851
|
+
ScrollArea,
|
|
852
|
+
{
|
|
853
|
+
ref,
|
|
854
|
+
onScroll: (e) => {
|
|
855
|
+
const el = e.currentTarget;
|
|
856
|
+
controller.setViewport(el.clientHeight, el.scrollTop);
|
|
857
|
+
const atBottom = el.scrollHeight - el.scrollTop - el.clientHeight < rowHeight;
|
|
858
|
+
if (state.follow && !atBottom) controller.setFollow(false);
|
|
859
|
+
else if (!state.follow && atBottom) controller.setFollow(true);
|
|
860
|
+
},
|
|
861
|
+
children
|
|
862
|
+
}
|
|
665
863
|
);
|
|
666
|
-
|
|
667
|
-
|
|
668
|
-
|
|
669
|
-
rowHeight,
|
|
670
|
-
|
|
671
|
-
|
|
672
|
-
|
|
673
|
-
|
|
864
|
+
}
|
|
865
|
+
function consoleRuntimeComponents(controller, rowHeight) {
|
|
866
|
+
return {
|
|
867
|
+
"console/Scroller": ({ children }) => /* @__PURE__ */ jsx(ConsoleScroller, { controller, rowHeight, children })
|
|
868
|
+
};
|
|
869
|
+
}
|
|
870
|
+
function ConsolePanelView({ controller, ...options }) {
|
|
871
|
+
useSyncExternalStore(controller.subscribe, controller.getState, controller.getState);
|
|
872
|
+
const view = consoleViewState(controller, options);
|
|
873
|
+
const ui3 = (intent) => applyConsoleUi(controller, intent);
|
|
874
|
+
return /* @__PURE__ */ jsxs(Column, { children: [
|
|
674
875
|
/* @__PURE__ */ jsx(
|
|
675
876
|
Toolbar,
|
|
676
877
|
{
|
|
677
878
|
left: /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
678
|
-
/* @__PURE__ */ jsx(
|
|
679
|
-
|
|
680
|
-
{
|
|
681
|
-
value: state.filter.search ?? "",
|
|
682
|
-
onChange: (term) => controller.setSearch(term),
|
|
683
|
-
placeholder: "Filter\u2026"
|
|
684
|
-
}
|
|
685
|
-
),
|
|
686
|
-
/* @__PURE__ */ jsx(
|
|
687
|
-
SegmentedControl,
|
|
688
|
-
{
|
|
689
|
-
size: "sm",
|
|
690
|
-
label: "Minimum level",
|
|
691
|
-
options: LEVEL_ORDER.map((l) => ({ value: l, label: l.slice(0, 1).toUpperCase() })),
|
|
692
|
-
value: state.filter.minLevel ?? "trace",
|
|
693
|
-
onChange: (level) => controller.setLevel(level === "trace" ? void 0 : level)
|
|
694
|
-
}
|
|
695
|
-
)
|
|
879
|
+
/* @__PURE__ */ jsx(SearchField, { value: view.search, placeholder: "Filter\u2026", onChange: (value) => ui3({ kind: "search", value }) }),
|
|
880
|
+
/* @__PURE__ */ jsx(SegmentedControl, { size: "sm", label: "Minimum level", options: view.levels, value: view.level, onChange: (level) => ui3({ kind: "level", level }) })
|
|
696
881
|
] }),
|
|
697
882
|
right: /* @__PURE__ */ jsxs(ToolbarGroup, { end: true, children: [
|
|
698
|
-
|
|
699
|
-
|
|
700
|
-
/* @__PURE__ */ jsx(
|
|
701
|
-
|
|
702
|
-
{
|
|
703
|
-
icon: /* @__PURE__ */ jsx(CopyGlyph, {}),
|
|
704
|
-
label: "Copy visible",
|
|
705
|
-
onClick: () => {
|
|
706
|
-
void navigator?.clipboard?.writeText(controller.copyVisible());
|
|
707
|
-
}
|
|
708
|
-
}
|
|
709
|
-
),
|
|
710
|
-
/* @__PURE__ */ jsx(IconButton, { icon: /* @__PURE__ */ jsx(ClearGlyph, {}), label: "Clear", onClick: () => controller.clear() })
|
|
883
|
+
view.errors ? /* @__PURE__ */ jsx(Badge, { tone: "error", children: view.errors }) : null,
|
|
884
|
+
view.warns ? /* @__PURE__ */ jsx(Badge, { tone: "warning", children: view.warns }) : null,
|
|
885
|
+
/* @__PURE__ */ jsx(IconButton, { icon: /* @__PURE__ */ jsx(CopyGlyph, {}), label: "Copy visible", onClick: () => ui3({ kind: "copyVisible" }) }),
|
|
886
|
+
/* @__PURE__ */ jsx(IconButton, { icon: /* @__PURE__ */ jsx(ClearGlyph, {}), label: "Clear", onClick: () => ui3({ kind: "clear" }) })
|
|
711
887
|
] })
|
|
712
888
|
}
|
|
713
889
|
),
|
|
714
|
-
|
|
715
|
-
|
|
716
|
-
|
|
717
|
-
|
|
718
|
-
|
|
719
|
-
|
|
720
|
-
|
|
721
|
-
|
|
722
|
-
|
|
723
|
-
|
|
724
|
-
|
|
725
|
-
|
|
726
|
-
|
|
727
|
-
|
|
728
|
-
|
|
729
|
-
|
|
730
|
-
|
|
731
|
-
{
|
|
732
|
-
record,
|
|
733
|
-
controller,
|
|
734
|
-
rowHeight,
|
|
735
|
-
showTimestamps,
|
|
736
|
-
expanded: expanded === record.id,
|
|
737
|
-
onToggle: () => setExpanded(expanded === record.id ? null : record.id)
|
|
738
|
-
},
|
|
739
|
-
record.id
|
|
740
|
-
)) }) }) }) }) }),
|
|
741
|
-
/* @__PURE__ */ jsx(
|
|
742
|
-
StatusBar,
|
|
743
|
-
{
|
|
744
|
-
left: `${state.rows.length} of ${state.total}` + (state.dropped > 0 ? ` \xB7 ${state.dropped} dropped` : "") + // A patch that addressed nothing is the one streaming failure with no visible symptom:
|
|
745
|
-
// the producer sees no line grow, and a mis-keyed wire looks exactly like a dead one.
|
|
746
|
-
(state.droppedPatches > 0 ? ` \xB7 ${state.droppedPatches} unmatched` : ""),
|
|
747
|
-
right: state.follow ? "following" : void 0
|
|
748
|
-
}
|
|
749
|
-
)
|
|
750
|
-
] });
|
|
751
|
-
}
|
|
752
|
-
function LogRow({
|
|
753
|
-
record,
|
|
754
|
-
controller,
|
|
755
|
-
rowHeight,
|
|
756
|
-
showTimestamps,
|
|
757
|
-
expanded,
|
|
758
|
-
onToggle
|
|
759
|
-
}) {
|
|
760
|
-
return /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
761
|
-
/* @__PURE__ */ jsx(
|
|
762
|
-
Row,
|
|
763
|
-
{
|
|
764
|
-
style: { height: rowHeight, alignItems: "flex-start" },
|
|
765
|
-
noIcon: true,
|
|
766
|
-
onClick: () => {
|
|
767
|
-
if (record.data !== void 0) onToggle();
|
|
768
|
-
controller.activate(record.id);
|
|
769
|
-
},
|
|
770
|
-
onContextMenu: (e) => {
|
|
771
|
-
e.preventDefault();
|
|
772
|
-
controller.requestContextMenu(record.id, e.clientX, e.clientY);
|
|
773
|
-
},
|
|
774
|
-
label: /* @__PURE__ */ jsxs("span", { style: { display: "flex", gap: 6, alignItems: "center", minWidth: 0 }, children: [
|
|
775
|
-
showTimestamps ? /* @__PURE__ */ jsx("span", { style: { opacity: 0.45, fontVariantNumeric: "tabular-nums", flex: "0 0 auto" }, children: new Date(record.ts).toISOString().slice(11, 23) }) : null,
|
|
776
|
-
/* @__PURE__ */ jsx(Badge, { tone: TONE[record.level], children: record.level }),
|
|
777
|
-
record.source ? /* @__PURE__ */ jsx("span", { style: { opacity: 0.55 }, children: record.source }) : null,
|
|
778
|
-
/* @__PURE__ */ jsx(
|
|
779
|
-
"span",
|
|
780
|
-
{
|
|
781
|
-
style: { overflow: "hidden", textOverflow: "ellipsis", whiteSpace: "nowrap", minWidth: 0 },
|
|
782
|
-
children: record.message
|
|
783
|
-
}
|
|
784
|
-
)
|
|
785
|
-
] }),
|
|
786
|
-
trailing: (record.count ?? 1) > 1 ? (
|
|
787
|
-
// The best feature in any incumbent: a run of identical lines is one row with a count.
|
|
788
|
-
/* @__PURE__ */ jsx(Badge, { title: "Repeated consecutively", children: `x${record.count}` })
|
|
789
|
-
) : null
|
|
790
|
-
}
|
|
791
|
-
),
|
|
792
|
-
expanded && record.data !== void 0 ? /* @__PURE__ */ jsx(
|
|
793
|
-
"pre",
|
|
794
|
-
{
|
|
795
|
-
style: {
|
|
796
|
-
margin: 0,
|
|
797
|
-
padding: "2px 10px 6px 24px",
|
|
798
|
-
fontSize: 10,
|
|
799
|
-
lineHeight: 1.4,
|
|
800
|
-
whiteSpace: "pre-wrap",
|
|
801
|
-
wordBreak: "break-all",
|
|
802
|
-
opacity: 0.8
|
|
890
|
+
view.multiSource ? /* @__PURE__ */ jsx(Stack, { direction: "row", gap: 4, pad: "inset", children: view.sources.map((source) => /* @__PURE__ */ jsx(FilterChip, { on: source.on, title: source.title, onChange: (on) => ui3({ kind: "source", id: source.id, on }), children: source.label }, source.id)) }) : null,
|
|
891
|
+
view.empty ? /* @__PURE__ */ jsx(EmptyState, { title: view.emptyTitle, hint: view.emptyHint }) : null,
|
|
892
|
+
view.listed ? /* @__PURE__ */ jsx(ConsoleScroller, { controller, rowHeight: view.rowHeight, children: /* @__PURE__ */ jsx(VirtualWindow, { totalHeight: view.totalHeight, offsetTop: view.offsetTop, children: /* @__PURE__ */ jsx(RowList, { role: "log", children: view.rows.map((row) => /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
893
|
+
/* @__PURE__ */ jsx(
|
|
894
|
+
Row,
|
|
895
|
+
{
|
|
896
|
+
height: view.rowHeight,
|
|
897
|
+
noIcon: true,
|
|
898
|
+
label: /* @__PURE__ */ jsxs(Stack, { direction: "row", pad: "none", children: [
|
|
899
|
+
row.time ? /* @__PURE__ */ jsx(Text, { role: "number", children: row.time }) : null,
|
|
900
|
+
/* @__PURE__ */ jsx(Badge, { tone: row.tone, children: row.level }),
|
|
901
|
+
row.source ? /* @__PURE__ */ jsx(Text, { role: "meta", children: row.source }) : null,
|
|
902
|
+
/* @__PURE__ */ jsx(Text, { children: row.message })
|
|
903
|
+
] }),
|
|
904
|
+
trailing: row.repeat ? /* @__PURE__ */ jsx(Badge, { title: "Repeated consecutively", children: row.repeat }) : null,
|
|
905
|
+
onClick: () => ui3({ kind: "row", id: row.id }),
|
|
906
|
+
onContextMenuAt: (x, y) => ui3({ kind: "contextMenu", id: row.id, x, y })
|
|
803
907
|
},
|
|
804
|
-
|
|
805
|
-
|
|
806
|
-
|
|
908
|
+
row.id
|
|
909
|
+
),
|
|
910
|
+
row.expanded ? /* @__PURE__ */ jsx(Code, { children: row.detail }, `${row.id}:detail`) : null
|
|
911
|
+
] })) }) }) }) : null,
|
|
912
|
+
/* @__PURE__ */ jsx(StatusBar, { left: view.countLabel, right: view.followLabel })
|
|
807
913
|
] });
|
|
808
914
|
}
|
|
809
915
|
|
|
@@ -1708,19 +1814,25 @@ var runsManifest = {
|
|
|
1708
1814
|
import { useSyncExternalStore as useSyncExternalStore2 } from "react";
|
|
1709
1815
|
import {
|
|
1710
1816
|
Badge as Badge2,
|
|
1817
|
+
Column as Column2,
|
|
1711
1818
|
EmptyState as EmptyState2,
|
|
1819
|
+
FilterChip as FilterChip2,
|
|
1712
1820
|
IconButton as IconButton2,
|
|
1713
|
-
|
|
1821
|
+
Note,
|
|
1822
|
+
Progress,
|
|
1714
1823
|
Row as Row2,
|
|
1715
1824
|
RowList as RowList2,
|
|
1716
1825
|
ScrollArea as ScrollArea2,
|
|
1717
1826
|
SearchField as SearchField2,
|
|
1827
|
+
Stack as Stack2,
|
|
1718
1828
|
StatusBar as StatusBar2,
|
|
1829
|
+
Text as Text2,
|
|
1719
1830
|
TextButton,
|
|
1720
1831
|
Toolbar as Toolbar2,
|
|
1721
1832
|
ToolbarGroup as ToolbarGroup2
|
|
1722
1833
|
} from "@xenosystem/components/chrome";
|
|
1723
|
-
|
|
1834
|
+
|
|
1835
|
+
// src/ops/runs/declaration.ts
|
|
1724
1836
|
var TONE2 = {
|
|
1725
1837
|
requested: "neutral",
|
|
1726
1838
|
queued: "neutral",
|
|
@@ -1733,205 +1845,296 @@ var TONE2 = {
|
|
|
1733
1845
|
failed: "error",
|
|
1734
1846
|
cancelled: "neutral"
|
|
1735
1847
|
};
|
|
1736
|
-
|
|
1737
|
-
|
|
1738
|
-
}
|
|
1739
|
-
|
|
1740
|
-
|
|
1741
|
-
|
|
1742
|
-
|
|
1743
|
-
|
|
1744
|
-
|
|
1745
|
-
})
|
|
1746
|
-
const
|
|
1747
|
-
|
|
1748
|
-
|
|
1749
|
-
|
|
1750
|
-
|
|
1751
|
-
|
|
1752
|
-
|
|
1753
|
-
|
|
1754
|
-
|
|
1755
|
-
|
|
1756
|
-
|
|
1757
|
-
|
|
1758
|
-
|
|
1759
|
-
|
|
1760
|
-
|
|
1761
|
-
|
|
1762
|
-
|
|
1763
|
-
|
|
1764
|
-
|
|
1765
|
-
|
|
1766
|
-
|
|
1767
|
-
|
|
1768
|
-
|
|
1769
|
-
),
|
|
1770
|
-
|
|
1771
|
-
|
|
1772
|
-
|
|
1773
|
-
|
|
1774
|
-
|
|
1775
|
-
|
|
1776
|
-
|
|
1777
|
-
|
|
1778
|
-
|
|
1779
|
-
|
|
1780
|
-
|
|
1781
|
-
|
|
1782
|
-
|
|
1783
|
-
|
|
1784
|
-
|
|
1785
|
-
|
|
1786
|
-
|
|
1787
|
-
{
|
|
1788
|
-
title: state.total > 0 ? "No matching runs" : "No runs yet",
|
|
1789
|
-
hint: state.total > 0 ? "Nothing matches the current filter." : emptyHint ?? "Run something to see it here."
|
|
1790
|
-
}
|
|
1791
|
-
) : /* @__PURE__ */ jsx2(ScrollArea2, { children: /* @__PURE__ */ jsx2(RowList2, { role: "list", children: state.rows.map(
|
|
1792
|
-
(row) => row.kind === "run" ? /* @__PURE__ */ jsx2(RunRow, { row, controller, showProgress, now }, row.key) : /* @__PURE__ */ jsx2(StepRow, { row, controller, showProgress }, row.key)
|
|
1793
|
-
) }) }),
|
|
1794
|
-
/* @__PURE__ */ jsx2(
|
|
1795
|
-
StatusBar2,
|
|
1796
|
-
{
|
|
1797
|
-
left: `${state.runs.length} of ${state.total}${state.dropped > 0 ? ` \xB7 ${state.dropped} dropped` : ""}`,
|
|
1798
|
-
right: showStats && state.stats.terminal > 0 ? `${Math.round((state.stats.successRate ?? 0) * 100)}% ok${state.stats.meanDurationMs !== null ? ` \xB7 ~${formatDuration(state.stats.meanDurationMs)}` : ""}` : (
|
|
1799
|
-
// `null` success rate is NOT 0% — nothing has finished, which is a different fact.
|
|
1800
|
-
state.stats.active > 0 ? `${state.stats.active} active` : void 0
|
|
1801
|
-
)
|
|
1848
|
+
var toneOf = (status) => TONE2[status] ?? "neutral";
|
|
1849
|
+
var truncationHint = (reason) => reason === "cycle" ? "This step is nested inside itself \u2014 the panel stopped here rather than repeat it." : "Nesting is deeper than this panel will render.";
|
|
1850
|
+
function runsViewState(c, options = {}) {
|
|
1851
|
+
const s = c.getState();
|
|
1852
|
+
const showStats = options.showStats ?? true;
|
|
1853
|
+
const showProgress = options.showProgress ?? true;
|
|
1854
|
+
const now = options.now ?? (() => Date.now());
|
|
1855
|
+
const active = new Set(s.filter.statuses ?? []);
|
|
1856
|
+
const statuses = ALL_STATUSES.filter((st) => s.counts[st] > 0).map((st) => ({ id: st, label: `${st} ${s.counts[st]}`, on: active.size === 0 || active.has(st), tone: toneOf(st) }));
|
|
1857
|
+
const sources = s.sources.length > 1 ? s.sources.map((src) => ({ id: src.id, label: src.label, on: src.enabled, tone: "neutral", title: `${src.count} runs` })) : [];
|
|
1858
|
+
const stats = showStats && s.stats.terminal > 0 ? `${Math.round((s.stats.successRate ?? 0) * 100)}% ok${s.stats.meanDurationMs !== null ? ` \xB7 ~${formatDuration(s.stats.meanDurationMs)}` : ""}` : s.stats.active > 0 ? `${s.stats.active} active` : void 0;
|
|
1859
|
+
return {
|
|
1860
|
+
search: s.filter.search ?? "",
|
|
1861
|
+
statuses,
|
|
1862
|
+
multiSource: s.sources.length > 1,
|
|
1863
|
+
sources,
|
|
1864
|
+
hasChips: statuses.length > 0 || sources.length > 0,
|
|
1865
|
+
empty: s.rows.length === 0,
|
|
1866
|
+
emptyTitle: s.total > 0 ? "No matching runs" : "No runs yet",
|
|
1867
|
+
emptyHint: s.total > 0 ? "Nothing matches the current filter." : options.emptyHint ?? "Run something to see it here.",
|
|
1868
|
+
listed: s.rows.length > 0,
|
|
1869
|
+
rows: s.rows.map((row) => {
|
|
1870
|
+
const run = row.run;
|
|
1871
|
+
if (row.kind === "run") {
|
|
1872
|
+
const duration = durationOf(run, now());
|
|
1873
|
+
const hasProgress2 = showProgress && run.progress !== void 0;
|
|
1874
|
+
return {
|
|
1875
|
+
key: row.key,
|
|
1876
|
+
runId: run.id,
|
|
1877
|
+
stepPath: [],
|
|
1878
|
+
depth: 0,
|
|
1879
|
+
step: false,
|
|
1880
|
+
status: run.status,
|
|
1881
|
+
tone: toneOf(run.status),
|
|
1882
|
+
label: run.label,
|
|
1883
|
+
trigger: run.trigger,
|
|
1884
|
+
retries: (run.retryCount ?? 0) > 0 ? `retry x${run.retryCount}` : void 0,
|
|
1885
|
+
truncated: row.truncated ? row.truncated === "cycle" ? "cycle" : "deeper\u2026" : void 0,
|
|
1886
|
+
truncatedHint: row.truncated ? truncationHint(row.truncated) : void 0,
|
|
1887
|
+
hasProgress: hasProgress2,
|
|
1888
|
+
progress: run.progress ?? 0,
|
|
1889
|
+
progressLabel: `${Math.round((run.progress ?? 0) * 100)}%`,
|
|
1890
|
+
duration: !hasProgress2 && duration !== null ? formatDuration(duration) : void 0,
|
|
1891
|
+
canCancel: canCancel(run),
|
|
1892
|
+
cancelLabel: `Cancel ${run.label}`,
|
|
1893
|
+
canRetry: canRetry(run),
|
|
1894
|
+
retryLabel: `Retry ${run.label}`,
|
|
1895
|
+
hasError: !!run.error,
|
|
1896
|
+
errorCode: run.error?.code,
|
|
1897
|
+
errorMessage: run.error?.message
|
|
1898
|
+
};
|
|
1802
1899
|
}
|
|
1803
|
-
|
|
1804
|
-
|
|
1900
|
+
const step = row.step;
|
|
1901
|
+
const elapsed = step.startedAt !== void 0 && step.endedAt !== void 0 ? step.endedAt - step.startedAt : null;
|
|
1902
|
+
const hasProgress = showProgress && step.progress !== void 0;
|
|
1903
|
+
return {
|
|
1904
|
+
key: row.key,
|
|
1905
|
+
runId: row.runId,
|
|
1906
|
+
stepPath: row.stepPath,
|
|
1907
|
+
depth: row.depth,
|
|
1908
|
+
step: true,
|
|
1909
|
+
status: step.status,
|
|
1910
|
+
tone: toneOf(step.status),
|
|
1911
|
+
label: step.label,
|
|
1912
|
+
truncated: row.truncated ? row.truncated === "cycle" ? "cycle" : "deeper\u2026" : void 0,
|
|
1913
|
+
truncatedHint: row.truncated ? truncationHint(row.truncated) : void 0,
|
|
1914
|
+
hasProgress,
|
|
1915
|
+
progress: step.progress ?? 0,
|
|
1916
|
+
progressLabel: `${Math.round((step.progress ?? 0) * 100)}%`,
|
|
1917
|
+
duration: !hasProgress && elapsed !== null ? formatDuration(elapsed) : void 0,
|
|
1918
|
+
canCancel: false,
|
|
1919
|
+
cancelLabel: "",
|
|
1920
|
+
canRetry: false,
|
|
1921
|
+
retryLabel: "",
|
|
1922
|
+
hasError: false
|
|
1923
|
+
};
|
|
1924
|
+
}),
|
|
1925
|
+
countLabel: `${s.runs.length} of ${s.total}${s.dropped > 0 ? ` \xB7 ${s.dropped} dropped` : ""}`,
|
|
1926
|
+
statsLabel: stats
|
|
1927
|
+
};
|
|
1805
1928
|
}
|
|
1806
|
-
function
|
|
1807
|
-
|
|
1808
|
-
|
|
1809
|
-
|
|
1810
|
-
|
|
1811
|
-
|
|
1812
|
-
|
|
1929
|
+
function applyRunsUi(c, intent) {
|
|
1930
|
+
switch (intent.kind) {
|
|
1931
|
+
case "search":
|
|
1932
|
+
c.setSearch(intent.value);
|
|
1933
|
+
break;
|
|
1934
|
+
case "clearTerminal":
|
|
1935
|
+
c.clearTerminal();
|
|
1936
|
+
break;
|
|
1937
|
+
case "status": {
|
|
1938
|
+
const active = new Set(c.getState().filter.statuses ?? []);
|
|
1939
|
+
const st = intent.status;
|
|
1940
|
+
if (active.has(st)) active.delete(st);
|
|
1941
|
+
else active.add(st);
|
|
1942
|
+
c.setStatuses([...active]);
|
|
1943
|
+
break;
|
|
1813
1944
|
}
|
|
1814
|
-
|
|
1815
|
-
|
|
1816
|
-
|
|
1817
|
-
|
|
1818
|
-
|
|
1819
|
-
|
|
1820
|
-
|
|
1821
|
-
|
|
1822
|
-
|
|
1823
|
-
|
|
1824
|
-
|
|
1825
|
-
|
|
1945
|
+
case "source":
|
|
1946
|
+
c.toggleSource(intent.id, intent.on);
|
|
1947
|
+
break;
|
|
1948
|
+
case "row": {
|
|
1949
|
+
const row = c.getState().rows.find((r) => r.runId === intent.runId && r.stepPath.join("/") === intent.stepPath.join("/"));
|
|
1950
|
+
if (row?.hasChildren) c.toggleExpanded(intent.runId, intent.stepPath.length ? intent.stepPath : void 0);
|
|
1951
|
+
c.activate(intent.runId, intent.stepPath.length ? intent.stepPath : void 0);
|
|
1952
|
+
break;
|
|
1953
|
+
}
|
|
1954
|
+
case "contextMenu":
|
|
1955
|
+
c.requestContextMenu(intent.runId, intent.x, intent.y);
|
|
1956
|
+
break;
|
|
1957
|
+
case "cancel":
|
|
1958
|
+
c.cancel(intent.runId);
|
|
1959
|
+
break;
|
|
1960
|
+
case "retry":
|
|
1961
|
+
c.retry(intent.runId);
|
|
1962
|
+
break;
|
|
1963
|
+
}
|
|
1826
1964
|
}
|
|
1827
|
-
|
|
1828
|
-
|
|
1829
|
-
|
|
1830
|
-
|
|
1831
|
-
|
|
1832
|
-
|
|
1833
|
-
|
|
1834
|
-
|
|
1835
|
-
|
|
1836
|
-
|
|
1837
|
-
|
|
1965
|
+
var runsViewManifest = {
|
|
1966
|
+
id: runsManifest.id,
|
|
1967
|
+
version: "1.0.0",
|
|
1968
|
+
title: "Runs",
|
|
1969
|
+
category: "ops",
|
|
1970
|
+
layout: { slot: "side" },
|
|
1971
|
+
inputs: [{ id: "view", type: "object", label: "View state", description: "The RunsViewModel the runtime derives from the controller on every draw." }],
|
|
1972
|
+
outputs: [{ id: "ui", type: "object", label: "UI intent", description: "{ kind, \u2026 } \u2014 applied by the runtime to the controller." }],
|
|
1973
|
+
commands: []
|
|
1974
|
+
};
|
|
1975
|
+
var EMPTY2 = { search: "", statuses: [], multiSource: false, sources: [], hasChips: false, empty: true, emptyTitle: "No runs yet", emptyHint: "Run something to see it here.", listed: false, rows: [], countLabel: "0 of 0" };
|
|
1976
|
+
var BEHAVIOURS2 = {
|
|
1977
|
+
"ops/runsPanelView": (inputs) => inputs.view ?? EMPTY2
|
|
1978
|
+
};
|
|
1979
|
+
var RUNS_RUNTIME_UNITS = [];
|
|
1980
|
+
var text2 = (b) => ({ component: "text", props: { text: b } });
|
|
1981
|
+
var ui2 = (kind, fields = {}) => ({ emit: "ui", value: { object: { kind: { value: kind }, ...fields } } });
|
|
1982
|
+
var chip = (intent) => ({
|
|
1983
|
+
component: "chrome/FilterChip",
|
|
1984
|
+
props: { on: { item: "on" }, title: { item: "title" } },
|
|
1985
|
+
on: { onChange: intent },
|
|
1986
|
+
children: [{ component: "chrome/Badge", props: { tone: { item: "tone" } }, children: [text2({ item: "label" })] }]
|
|
1987
|
+
});
|
|
1988
|
+
var RUNS_DECLARATION = {
|
|
1989
|
+
format: "xeno.block@1",
|
|
1990
|
+
manifest: runsViewManifest,
|
|
1991
|
+
behaviour: "ops/runsPanelView",
|
|
1992
|
+
composition: {
|
|
1993
|
+
component: "chrome/Column",
|
|
1994
|
+
children: [
|
|
1838
1995
|
{
|
|
1839
|
-
|
|
1840
|
-
|
|
1841
|
-
|
|
1842
|
-
|
|
1843
|
-
}
|
|
1844
|
-
|
|
1845
|
-
|
|
1846
|
-
|
|
1847
|
-
},
|
|
1848
|
-
|
|
1849
|
-
|
|
1850
|
-
{
|
|
1851
|
-
|
|
1852
|
-
|
|
1853
|
-
|
|
1854
|
-
|
|
1855
|
-
|
|
1856
|
-
|
|
1857
|
-
|
|
1858
|
-
|
|
1859
|
-
),
|
|
1860
|
-
meta: showProgress && run.progress !== void 0 ? /* @__PURE__ */ jsx2("span", { style: { width: 48, display: "inline-flex" }, children: /* @__PURE__ */ jsx2(
|
|
1861
|
-
ProportionBar,
|
|
1996
|
+
component: "chrome/Toolbar",
|
|
1997
|
+
props: {
|
|
1998
|
+
left: { node: { component: "chrome/SearchField", props: { value: { input: "view.search" }, placeholder: { value: "Filter runs\u2026" } }, on: { onChange: ui2("search", { value: { arg: "" } }) } } },
|
|
1999
|
+
right: { node: { component: "chrome/ToolbarGroup", props: { end: { value: true } }, children: [{ component: "chrome/TextButton", on: { onClick: ui2("clearTerminal") }, children: [text2({ value: "Clear finished" })] }] } }
|
|
2000
|
+
}
|
|
2001
|
+
},
|
|
2002
|
+
{
|
|
2003
|
+
component: "chrome/Stack",
|
|
2004
|
+
when: { input: "view.hasChips" },
|
|
2005
|
+
props: { direction: { value: "row" }, gap: { value: 4 }, pad: { value: "inset" } },
|
|
2006
|
+
children: [
|
|
2007
|
+
{ ...chip(ui2("status", { status: { item: "id" }, on: { arg: "" } })), each: { input: "view.statuses", key: "id" } },
|
|
2008
|
+
{ ...chip(ui2("source", { id: { item: "id" }, on: { arg: "" } })), each: { input: "view.sources", key: "id" } }
|
|
2009
|
+
]
|
|
2010
|
+
},
|
|
2011
|
+
{ component: "chrome/EmptyState", when: { input: "view.empty" }, props: { title: { input: "view.emptyTitle" }, hint: { input: "view.emptyHint" } } },
|
|
2012
|
+
{
|
|
2013
|
+
component: "chrome/ScrollArea",
|
|
2014
|
+
when: { input: "view.listed" },
|
|
2015
|
+
children: [
|
|
1862
2016
|
{
|
|
1863
|
-
|
|
1864
|
-
|
|
1865
|
-
{
|
|
1866
|
-
|
|
2017
|
+
component: "chrome/RowList",
|
|
2018
|
+
children: [
|
|
2019
|
+
{
|
|
2020
|
+
component: "fragment",
|
|
2021
|
+
each: { input: "view.rows", key: "key" },
|
|
2022
|
+
children: [
|
|
2023
|
+
{
|
|
2024
|
+
component: "chrome/Row",
|
|
2025
|
+
props: {
|
|
2026
|
+
noIcon: { value: true },
|
|
2027
|
+
depth: { item: "depth" },
|
|
2028
|
+
dimmed: { item: "step" },
|
|
2029
|
+
label: {
|
|
2030
|
+
node: {
|
|
2031
|
+
component: "chrome/Stack",
|
|
2032
|
+
props: { direction: { value: "row" }, pad: { value: "none" } },
|
|
2033
|
+
children: [
|
|
2034
|
+
{ component: "chrome/Badge", props: { tone: { item: "tone" } }, children: [text2({ item: "status" })] },
|
|
2035
|
+
{ component: "chrome/Text", children: [text2({ item: "label" })] },
|
|
2036
|
+
{ component: "chrome/Text", when: { item: "trigger" }, props: { role: { value: "caption" } }, children: [text2({ item: "trigger" })] },
|
|
2037
|
+
{ component: "chrome/Badge", when: { item: "retries" }, props: { title: { value: "Retries so far" } }, children: [text2({ item: "retries" })] },
|
|
2038
|
+
{ component: "chrome/Badge", when: { item: "truncated" }, props: { tone: { value: "warning" }, title: { item: "truncatedHint" } }, children: [text2({ item: "truncated" })] }
|
|
2039
|
+
]
|
|
2040
|
+
}
|
|
2041
|
+
},
|
|
2042
|
+
meta: {
|
|
2043
|
+
node: {
|
|
2044
|
+
component: "fragment",
|
|
2045
|
+
children: [
|
|
2046
|
+
{ component: "chrome/Progress", when: { item: "hasProgress" }, props: { value: { item: "progress" }, label: { item: "progressLabel" } } },
|
|
2047
|
+
{ component: "chrome/Text", when: { item: "duration" }, props: { role: { value: "number" } }, children: [text2({ item: "duration" })] }
|
|
2048
|
+
]
|
|
2049
|
+
}
|
|
2050
|
+
},
|
|
2051
|
+
trailing: {
|
|
2052
|
+
node: {
|
|
2053
|
+
component: "fragment",
|
|
2054
|
+
children: [
|
|
2055
|
+
{ component: "chrome/IconButton", when: { item: "canCancel" }, props: { size: { value: "sm" }, icon: { node: { component: "icons/Cancel" } }, label: { item: "cancelLabel" } }, on: { onClick: ui2("cancel", { runId: { item: "runId" } }) } },
|
|
2056
|
+
{ component: "chrome/IconButton", when: { item: "canRetry" }, props: { size: { value: "sm" }, icon: { node: { component: "icons/Retry" } }, label: { item: "retryLabel" } }, on: { onClick: ui2("retry", { runId: { item: "runId" } }) } }
|
|
2057
|
+
]
|
|
2058
|
+
}
|
|
2059
|
+
}
|
|
2060
|
+
},
|
|
2061
|
+
on: { onClick: ui2("row", { runId: { item: "runId" }, stepPath: { item: "stepPath" } }), onContextMenuAt: ui2("contextMenu", { runId: { item: "runId" }, x: { arg: "", index: 0 }, y: { arg: "", index: 1 } }) }
|
|
2062
|
+
},
|
|
2063
|
+
{
|
|
2064
|
+
component: "chrome/Note",
|
|
2065
|
+
when: { item: "hasError" },
|
|
2066
|
+
props: { variant: { value: "inset" } },
|
|
2067
|
+
// The host's sentence, verbatim. The panel never composes error prose.
|
|
2068
|
+
children: [{ component: "chrome/Badge", props: { tone: { value: "error" } }, children: [text2({ item: "errorCode" })] }, text2({ value: " " }), text2({ item: "errorMessage" })]
|
|
2069
|
+
}
|
|
2070
|
+
]
|
|
2071
|
+
}
|
|
1867
2072
|
]
|
|
1868
2073
|
}
|
|
1869
|
-
|
|
1870
|
-
|
|
1871
|
-
|
|
1872
|
-
|
|
1873
|
-
|
|
1874
|
-
|
|
1875
|
-
|
|
1876
|
-
|
|
1877
|
-
|
|
1878
|
-
|
|
1879
|
-
|
|
1880
|
-
|
|
1881
|
-
|
|
1882
|
-
|
|
1883
|
-
|
|
1884
|
-
|
|
1885
|
-
|
|
1886
|
-
|
|
1887
|
-
|
|
1888
|
-
|
|
1889
|
-
|
|
2074
|
+
]
|
|
2075
|
+
},
|
|
2076
|
+
{ component: "chrome/StatusBar", props: { left: { input: "view.countLabel" }, right: { input: "view.statsLabel" } } }
|
|
2077
|
+
]
|
|
2078
|
+
}
|
|
2079
|
+
};
|
|
2080
|
+
|
|
2081
|
+
// src/ops/runs/react/RunsPanelView.tsx
|
|
2082
|
+
import { Fragment as Fragment2, jsx as jsx2, jsxs as jsxs2 } from "react/jsx-runtime";
|
|
2083
|
+
var CancelGlyph = ICONS["icons/Cancel"];
|
|
2084
|
+
var RetryGlyph = ICONS["icons/Retry"];
|
|
2085
|
+
function RunsPanelView({ controller, ...options }) {
|
|
2086
|
+
useSyncExternalStore2(controller.subscribe, controller.getState, controller.getState);
|
|
2087
|
+
const view = runsViewState(controller, options);
|
|
2088
|
+
const ui3 = (intent) => applyRunsUi(controller, intent);
|
|
2089
|
+
const chip2 = (c, onChange) => /* @__PURE__ */ jsx2(FilterChip2, { on: c.on, title: c.title, onChange, children: /* @__PURE__ */ jsx2(Badge2, { tone: c.tone, children: c.label }) }, c.id);
|
|
2090
|
+
return /* @__PURE__ */ jsxs2(Column2, { children: [
|
|
2091
|
+
/* @__PURE__ */ jsx2(
|
|
2092
|
+
Toolbar2,
|
|
2093
|
+
{
|
|
2094
|
+
left: /* @__PURE__ */ jsx2(SearchField2, { value: view.search, placeholder: "Filter runs\u2026", onChange: (value) => ui3({ kind: "search", value }) }),
|
|
2095
|
+
right: /* @__PURE__ */ jsx2(ToolbarGroup2, { end: true, children: /* @__PURE__ */ jsx2(TextButton, { onClick: () => ui3({ kind: "clearTerminal" }), children: "Clear finished" }) })
|
|
1890
2096
|
}
|
|
1891
2097
|
),
|
|
1892
|
-
|
|
1893
|
-
|
|
1894
|
-
|
|
1895
|
-
|
|
1896
|
-
|
|
1897
|
-
|
|
1898
|
-
|
|
1899
|
-
|
|
1900
|
-
row,
|
|
1901
|
-
controller,
|
|
1902
|
-
showProgress
|
|
1903
|
-
}) {
|
|
1904
|
-
const step = row.step;
|
|
1905
|
-
const elapsed = step.startedAt !== void 0 && step.endedAt !== void 0 ? step.endedAt - step.startedAt : null;
|
|
1906
|
-
return /* @__PURE__ */ jsx2(
|
|
1907
|
-
Row2,
|
|
1908
|
-
{
|
|
1909
|
-
noIcon: true,
|
|
1910
|
-
style: { paddingLeft: 12 + row.depth * 12, opacity: 0.85 },
|
|
1911
|
-
onClick: () => {
|
|
1912
|
-
if (row.hasChildren) controller.toggleExpanded(row.runId, row.stepPath);
|
|
1913
|
-
controller.activate(row.runId, row.stepPath);
|
|
1914
|
-
},
|
|
1915
|
-
label: /* @__PURE__ */ jsx2(
|
|
1916
|
-
RowLabel,
|
|
2098
|
+
view.hasChips ? /* @__PURE__ */ jsxs2(Stack2, { direction: "row", gap: 4, pad: "inset", children: [
|
|
2099
|
+
view.statuses.map((c) => chip2(c, (on) => ui3({ kind: "status", status: c.id, on }))),
|
|
2100
|
+
view.sources.map((c) => chip2(c, (on) => ui3({ kind: "source", id: c.id, on })))
|
|
2101
|
+
] }) : null,
|
|
2102
|
+
view.empty ? /* @__PURE__ */ jsx2(EmptyState2, { title: view.emptyTitle, hint: view.emptyHint }) : null,
|
|
2103
|
+
view.listed ? /* @__PURE__ */ jsx2(ScrollArea2, { children: /* @__PURE__ */ jsx2(RowList2, { children: view.rows.map((row) => /* @__PURE__ */ jsxs2(Fragment2, { children: [
|
|
2104
|
+
/* @__PURE__ */ jsx2(
|
|
2105
|
+
Row2,
|
|
1917
2106
|
{
|
|
1918
|
-
|
|
1919
|
-
|
|
1920
|
-
|
|
1921
|
-
|
|
2107
|
+
noIcon: true,
|
|
2108
|
+
depth: row.depth,
|
|
2109
|
+
dimmed: row.step,
|
|
2110
|
+
label: /* @__PURE__ */ jsxs2(Stack2, { direction: "row", pad: "none", children: [
|
|
2111
|
+
/* @__PURE__ */ jsx2(Badge2, { tone: row.tone, children: row.status }),
|
|
2112
|
+
/* @__PURE__ */ jsx2(Text2, { children: row.label }),
|
|
2113
|
+
row.trigger ? /* @__PURE__ */ jsx2(Text2, { role: "caption", children: row.trigger }) : null,
|
|
2114
|
+
row.retries ? /* @__PURE__ */ jsx2(Badge2, { title: "Retries so far", children: row.retries }) : null,
|
|
2115
|
+
row.truncated ? /* @__PURE__ */ jsx2(Badge2, { tone: "warning", title: row.truncatedHint, children: row.truncated }) : null
|
|
2116
|
+
] }),
|
|
2117
|
+
meta: /* @__PURE__ */ jsxs2(Fragment2, { children: [
|
|
2118
|
+
row.hasProgress ? /* @__PURE__ */ jsx2(Progress, { value: row.progress, label: row.progressLabel }) : null,
|
|
2119
|
+
row.duration ? /* @__PURE__ */ jsx2(Text2, { role: "number", children: row.duration }) : null
|
|
2120
|
+
] }),
|
|
2121
|
+
trailing: /* @__PURE__ */ jsxs2(Fragment2, { children: [
|
|
2122
|
+
row.canCancel ? /* @__PURE__ */ jsx2(IconButton2, { size: "sm", icon: /* @__PURE__ */ jsx2(CancelGlyph, {}), label: row.cancelLabel, onClick: () => ui3({ kind: "cancel", runId: row.runId }) }) : null,
|
|
2123
|
+
row.canRetry ? /* @__PURE__ */ jsx2(IconButton2, { size: "sm", icon: /* @__PURE__ */ jsx2(RetryGlyph, {}), label: row.retryLabel, onClick: () => ui3({ kind: "retry", runId: row.runId }) }) : null
|
|
2124
|
+
] }),
|
|
2125
|
+
onClick: () => ui3({ kind: "row", runId: row.runId, stepPath: row.stepPath }),
|
|
2126
|
+
onContextMenuAt: (x, y) => ui3({ kind: "contextMenu", runId: row.runId, x, y })
|
|
2127
|
+
},
|
|
2128
|
+
row.key
|
|
1922
2129
|
),
|
|
1923
|
-
|
|
1924
|
-
|
|
1925
|
-
|
|
1926
|
-
|
|
1927
|
-
|
|
1928
|
-
|
|
1929
|
-
|
|
1930
|
-
|
|
1931
|
-
}
|
|
1932
|
-
) }) : elapsed !== null ? /* @__PURE__ */ jsx2("span", { style: { fontVariantNumeric: "tabular-nums", opacity: 0.6 }, children: formatDuration(elapsed) }) : null
|
|
1933
|
-
}
|
|
1934
|
-
);
|
|
2130
|
+
row.hasError ? /* @__PURE__ */ jsxs2(Note, { variant: "inset", children: [
|
|
2131
|
+
/* @__PURE__ */ jsx2(Badge2, { tone: "error", children: row.errorCode }),
|
|
2132
|
+
" ",
|
|
2133
|
+
row.errorMessage
|
|
2134
|
+
] }, `${row.key}:error`) : null
|
|
2135
|
+
] })) }) }) : null,
|
|
2136
|
+
/* @__PURE__ */ jsx2(StatusBar2, { left: view.countLabel, right: view.statsLabel })
|
|
2137
|
+
] });
|
|
1935
2138
|
}
|
|
1936
2139
|
|
|
1937
2140
|
// src/ops/runs/panel.ts
|
|
@@ -2822,11 +3025,11 @@ function omissionLabel(omission) {
|
|
|
2822
3025
|
}
|
|
2823
3026
|
|
|
2824
3027
|
// src/ops/diff/controller.ts
|
|
2825
|
-
var
|
|
3028
|
+
var EMPTY3 = { files: [], status: "idle" };
|
|
2826
3029
|
var DiffController = class {
|
|
2827
3030
|
host;
|
|
2828
3031
|
reviewEnabled;
|
|
2829
|
-
model =
|
|
3032
|
+
model = EMPTY3;
|
|
2830
3033
|
rev = -1;
|
|
2831
3034
|
decisions = /* @__PURE__ */ new Map();
|
|
2832
3035
|
view;
|
|
@@ -3089,7 +3292,7 @@ var DiffController = class {
|
|
|
3089
3292
|
/** Tear down. */
|
|
3090
3293
|
dispose() {
|
|
3091
3294
|
this.listeners.clear();
|
|
3092
|
-
this.model =
|
|
3295
|
+
this.model = EMPTY3;
|
|
3093
3296
|
this.decisions.clear();
|
|
3094
3297
|
}
|
|
3095
3298
|
};
|
|
@@ -3245,8 +3448,8 @@ var MARK = {
|
|
|
3245
3448
|
context: {}
|
|
3246
3449
|
};
|
|
3247
3450
|
var SIGIL = { added: "+", removed: "-", context: " " };
|
|
3248
|
-
function visible(
|
|
3249
|
-
return show ?
|
|
3451
|
+
function visible(text3, show) {
|
|
3452
|
+
return show ? text3.replace(/\t/g, "\u2192 ").replace(/ /g, "\xB7") : text3;
|
|
3250
3453
|
}
|
|
3251
3454
|
function LineText({
|
|
3252
3455
|
line,
|
|
@@ -3629,9 +3832,13 @@ function createDiffPanel(options = {}) {
|
|
|
3629
3832
|
var diffPanel = createDiffPanel();
|
|
3630
3833
|
export {
|
|
3631
3834
|
ALL_STATUSES,
|
|
3835
|
+
BEHAVIOURS as CONSOLE_BEHAVIOURS,
|
|
3836
|
+
CONSOLE_DECLARATION,
|
|
3632
3837
|
CONSOLE_PANEL_ID,
|
|
3838
|
+
CONSOLE_RUNTIME_UNITS,
|
|
3633
3839
|
ConsoleController,
|
|
3634
3840
|
ConsolePanelView,
|
|
3841
|
+
ConsoleScroller,
|
|
3635
3842
|
DEFAULT_MAX_STEP_DEPTH,
|
|
3636
3843
|
DIFF_PANEL_ID,
|
|
3637
3844
|
DiffController,
|
|
@@ -3639,7 +3846,10 @@ export {
|
|
|
3639
3846
|
LEVEL_ORDER,
|
|
3640
3847
|
MESSAGE_ELISION,
|
|
3641
3848
|
REDACTION_CARRY,
|
|
3849
|
+
BEHAVIOURS2 as RUNS_BEHAVIOURS,
|
|
3850
|
+
RUNS_DECLARATION,
|
|
3642
3851
|
RUNS_PANEL_ID,
|
|
3852
|
+
RUNS_RUNTIME_UNITS,
|
|
3643
3853
|
RUN_PATH_SEPARATOR,
|
|
3644
3854
|
RUN_STATUSES,
|
|
3645
3855
|
RunsController,
|
|
@@ -3650,12 +3860,17 @@ export {
|
|
|
3650
3860
|
TerminalPanelView,
|
|
3651
3861
|
XENO_TERMINAL_THEME_KEYS,
|
|
3652
3862
|
appendStepsAtPath,
|
|
3863
|
+
applyConsoleUi,
|
|
3864
|
+
applyRunsUi,
|
|
3653
3865
|
canCancel,
|
|
3654
3866
|
canRetry,
|
|
3655
3867
|
collapseAdjacent,
|
|
3656
3868
|
computeStats,
|
|
3657
3869
|
consoleManifest,
|
|
3658
3870
|
consolePanel,
|
|
3871
|
+
consoleRuntimeComponents,
|
|
3872
|
+
consoleViewManifest,
|
|
3873
|
+
consoleViewState,
|
|
3659
3874
|
countChanges,
|
|
3660
3875
|
createConsolePanel,
|
|
3661
3876
|
createDiffPanel,
|
|
@@ -3688,6 +3903,8 @@ export {
|
|
|
3688
3903
|
resolveStepPath,
|
|
3689
3904
|
runsManifest,
|
|
3690
3905
|
runsPanel,
|
|
3906
|
+
runsViewManifest,
|
|
3907
|
+
runsViewState,
|
|
3691
3908
|
safeJson,
|
|
3692
3909
|
spliceRedactedAppend,
|
|
3693
3910
|
splitRows,
|
|
@@ -3695,5 +3912,6 @@ export {
|
|
|
3695
3912
|
terminalManifest,
|
|
3696
3913
|
terminalPanel,
|
|
3697
3914
|
terminalThemeVar,
|
|
3915
|
+
toneOf,
|
|
3698
3916
|
truncateLogMessage
|
|
3699
3917
|
};
|