@memberjunction/ng-task-graph-editor 6.1.0-edge.2 → 6.1.0-edge.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (55) hide show
  1. package/LICENSE +180 -4
  2. package/README.md +197 -0
  3. package/dist/lib/debug-variables.d.ts +27 -0
  4. package/dist/lib/debug-variables.d.ts.map +1 -0
  5. package/dist/lib/debug-variables.js +96 -0
  6. package/dist/lib/debug-variables.js.map +1 -0
  7. package/dist/lib/pane-split.d.ts +11 -0
  8. package/dist/lib/pane-split.d.ts.map +1 -0
  9. package/dist/lib/pane-split.js +36 -0
  10. package/dist/lib/pane-split.js.map +1 -0
  11. package/dist/lib/task-graph-canvas-adapter.d.ts +41 -3
  12. package/dist/lib/task-graph-canvas-adapter.d.ts.map +1 -1
  13. package/dist/lib/task-graph-canvas-adapter.js +175 -36
  14. package/dist/lib/task-graph-canvas-adapter.js.map +1 -1
  15. package/dist/lib/task-graph-debug-toolbar.component.d.ts +27 -0
  16. package/dist/lib/task-graph-debug-toolbar.component.d.ts.map +1 -0
  17. package/dist/lib/task-graph-debug-toolbar.component.js +153 -0
  18. package/dist/lib/task-graph-debug-toolbar.component.js.map +1 -0
  19. package/dist/lib/task-graph-debugger.component.d.ts +96 -0
  20. package/dist/lib/task-graph-debugger.component.d.ts.map +1 -0
  21. package/dist/lib/task-graph-debugger.component.js +371 -0
  22. package/dist/lib/task-graph-debugger.component.js.map +1 -0
  23. package/dist/lib/task-graph-editor.component.d.ts +40 -3
  24. package/dist/lib/task-graph-editor.component.d.ts.map +1 -1
  25. package/dist/lib/task-graph-editor.component.js +83 -10
  26. package/dist/lib/task-graph-editor.component.js.map +1 -1
  27. package/dist/lib/task-graph-editor.module.d.ts +9 -5
  28. package/dist/lib/task-graph-editor.module.d.ts.map +1 -1
  29. package/dist/lib/task-graph-editor.module.js +52 -5
  30. package/dist/lib/task-graph-editor.module.js.map +1 -1
  31. package/dist/lib/task-graph-run-prefs.d.ts +34 -0
  32. package/dist/lib/task-graph-run-prefs.d.ts.map +1 -0
  33. package/dist/lib/task-graph-run-prefs.js +67 -0
  34. package/dist/lib/task-graph-run-prefs.js.map +1 -0
  35. package/dist/lib/task-graph-run-view.component.d.ts +180 -3
  36. package/dist/lib/task-graph-run-view.component.d.ts.map +1 -1
  37. package/dist/lib/task-graph-run-view.component.js +560 -23
  38. package/dist/lib/task-graph-run-view.component.js.map +1 -1
  39. package/dist/lib/task-graph-runtime-source.d.ts +7 -1
  40. package/dist/lib/task-graph-runtime-source.d.ts.map +1 -1
  41. package/dist/lib/task-graph-runtime-source.js +14 -2
  42. package/dist/lib/task-graph-runtime-source.js.map +1 -1
  43. package/dist/lib/task-graph-variables.component.d.ts +23 -0
  44. package/dist/lib/task-graph-variables.component.d.ts.map +1 -0
  45. package/dist/lib/task-graph-variables.component.js +192 -0
  46. package/dist/lib/task-graph-variables.component.js.map +1 -0
  47. package/dist/lib/workflow-debug-host.d.ts +23 -0
  48. package/dist/lib/workflow-debug-host.d.ts.map +1 -0
  49. package/dist/lib/workflow-debug-host.js +101 -0
  50. package/dist/lib/workflow-debug-host.js.map +1 -0
  51. package/dist/public-api.d.ts +7 -0
  52. package/dist/public-api.d.ts.map +1 -1
  53. package/dist/public-api.js +7 -0
  54. package/dist/public-api.js.map +1 -1
  55. package/package.json +11 -10
@@ -0,0 +1,153 @@
1
+ /**
2
+ * VS Code-style debug chrome: Continue / Pause / Step Over / Step Into / Stop.
3
+ *
4
+ * Intent only. The host owns Pause/Resume/Step Remote Operations. This widget never imports
5
+ * a transport, so the same bar can sit in the test harness and on the Explorer run console.
6
+ */
7
+ import { ChangeDetectionStrategy, Component, EventEmitter, HostListener, Input, Output } from '@angular/core';
8
+ import * as i0 from "@angular/core";
9
+ function TaskGraphDebugToolbarComponent_Conditional_1_Template(rf, ctx) { if (rf & 1) {
10
+ i0.ɵɵdomElementStart(0, "span", 1);
11
+ i0.ɵɵdomElement(1, "i", 5);
12
+ i0.ɵɵtext(2, " Finished ");
13
+ i0.ɵɵdomElementEnd();
14
+ } }
15
+ function TaskGraphDebugToolbarComponent_Conditional_2_Template(rf, ctx) { if (rf & 1) {
16
+ const _r1 = i0.ɵɵgetCurrentView();
17
+ i0.ɵɵdomElementStart(0, "span", 6);
18
+ i0.ɵɵdomElement(1, "i", 7);
19
+ i0.ɵɵtext(2, " Paused ");
20
+ i0.ɵɵdomElementEnd();
21
+ i0.ɵɵdomElementStart(3, "button", 8);
22
+ i0.ɵɵdomListener("click", function TaskGraphDebugToolbarComponent_Conditional_2_Template_button_click_3_listener() { i0.ɵɵrestoreView(_r1); const ctx_r1 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r1.Resume.emit()); });
23
+ i0.ɵɵdomElement(4, "i", 9);
24
+ i0.ɵɵdomElementEnd();
25
+ i0.ɵɵdomElementStart(5, "button", 10);
26
+ i0.ɵɵdomListener("click", function TaskGraphDebugToolbarComponent_Conditional_2_Template_button_click_5_listener() { i0.ɵɵrestoreView(_r1); const ctx_r1 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r1.Step.emit()); });
27
+ i0.ɵɵdomElement(6, "i", 11);
28
+ i0.ɵɵdomElementStart(7, "span", 12);
29
+ i0.ɵɵtext(8, "Over");
30
+ i0.ɵɵdomElementEnd()();
31
+ i0.ɵɵdomElementStart(9, "button", 13);
32
+ i0.ɵɵdomListener("click", function TaskGraphDebugToolbarComponent_Conditional_2_Template_button_click_9_listener() { i0.ɵɵrestoreView(_r1); const ctx_r1 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r1.StepWave.emit()); });
33
+ i0.ɵɵdomElement(10, "i", 14);
34
+ i0.ɵɵdomElementStart(11, "span", 12);
35
+ i0.ɵɵtext(12, "Into");
36
+ i0.ɵɵdomElementEnd()();
37
+ } if (rf & 2) {
38
+ const ctx_r1 = i0.ɵɵnextContext();
39
+ i0.ɵɵadvance(3);
40
+ i0.ɵɵdomProperty("disabled", ctx_r1.Busy || !ctx_r1.Enabled);
41
+ i0.ɵɵadvance(2);
42
+ i0.ɵɵdomProperty("disabled", ctx_r1.Busy || !ctx_r1.Enabled);
43
+ i0.ɵɵadvance(4);
44
+ i0.ɵɵdomProperty("disabled", ctx_r1.Busy || !ctx_r1.Enabled);
45
+ } }
46
+ function TaskGraphDebugToolbarComponent_Conditional_3_Template(rf, ctx) { if (rf & 1) {
47
+ const _r3 = i0.ɵɵgetCurrentView();
48
+ i0.ɵɵdomElementStart(0, "span", 15);
49
+ i0.ɵɵdomElement(1, "i", 16);
50
+ i0.ɵɵtext(2, " Running ");
51
+ i0.ɵɵdomElementEnd();
52
+ i0.ɵɵdomElementStart(3, "button", 17);
53
+ i0.ɵɵdomListener("click", function TaskGraphDebugToolbarComponent_Conditional_3_Template_button_click_3_listener() { i0.ɵɵrestoreView(_r3); const ctx_r1 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r1.Pause.emit()); });
54
+ i0.ɵɵdomElement(4, "i", 7);
55
+ i0.ɵɵdomElementEnd();
56
+ } if (rf & 2) {
57
+ const ctx_r1 = i0.ɵɵnextContext();
58
+ i0.ɵɵadvance(3);
59
+ i0.ɵɵdomProperty("disabled", ctx_r1.Busy || !ctx_r1.Enabled);
60
+ } }
61
+ export class TaskGraphDebugToolbarComponent {
62
+ /** Graph is claim-gated. Continue / Step show; Pause hides. */
63
+ Paused = false;
64
+ /** A control is in flight — buttons disable, they do not vanish. */
65
+ Busy = false;
66
+ /** False when the graph has settled or there is nothing to drive. */
67
+ Enabled = true;
68
+ /** Every step is terminal — Play/Step hide; Finished is the state. */
69
+ Settled = false;
70
+ Pause = new EventEmitter();
71
+ Resume = new EventEmitter();
72
+ Step = new EventEmitter();
73
+ StepWave = new EventEmitter();
74
+ Cancel = new EventEmitter();
75
+ OnHotkey(event) {
76
+ if (!this.Enabled || this.Busy || this.Settled)
77
+ return;
78
+ if (isToolbarTypingTarget(event.target))
79
+ return;
80
+ if (event.key === 'F5' && event.shiftKey) {
81
+ event.preventDefault();
82
+ this.Cancel.emit();
83
+ return;
84
+ }
85
+ if (event.key === 'F5') {
86
+ event.preventDefault();
87
+ if (this.Paused)
88
+ this.Resume.emit();
89
+ else
90
+ this.Pause.emit();
91
+ return;
92
+ }
93
+ if (event.key === 'F10') {
94
+ event.preventDefault();
95
+ this.Step.emit();
96
+ return;
97
+ }
98
+ if (event.key === 'F11') {
99
+ event.preventDefault();
100
+ this.StepWave.emit();
101
+ }
102
+ }
103
+ static ɵfac = function TaskGraphDebugToolbarComponent_Factory(__ngFactoryType__) { return new (__ngFactoryType__ || TaskGraphDebugToolbarComponent)(); };
104
+ static ɵcmp = /*@__PURE__*/ i0.ɵɵdefineComponent({ type: TaskGraphDebugToolbarComponent, selectors: [["mj-task-graph-debug-toolbar"]], hostBindings: function TaskGraphDebugToolbarComponent_HostBindings(rf, ctx) { if (rf & 1) {
105
+ i0.ɵɵlistener("keydown", function TaskGraphDebugToolbarComponent_keydown_HostBindingHandler($event) { return ctx.OnHotkey($event); }, i0.ɵɵresolveDocument);
106
+ } }, inputs: { Paused: "Paused", Busy: "Busy", Enabled: "Enabled", Settled: "Settled" }, outputs: { Pause: "Pause", Resume: "Resume", Step: "Step", StepWave: "StepWave", Cancel: "Cancel" }, decls: 7, vars: 2, consts: [["role", "toolbar", "aria-label", "Workflow debugger", 1, "dbg-bar"], ["title", "Every step has finished", 1, "dbg-pill", "dbg-pill-done"], ["aria-hidden", "true", 1, "dbg-sep"], ["type", "button", "title", "Stop (Shift+F5) \u2014 cancel the remaining steps", "aria-label", "Stop", 1, "dbg-btn", "dbg-btn-stop", 3, "click", "disabled"], ["aria-hidden", "true", 1, "fa-solid", "fa-stop"], ["aria-hidden", "true", 1, "fa-solid", "fa-check"], ["title", "Nothing new starts until you continue or step", 1, "dbg-pill"], ["aria-hidden", "true", 1, "fa-solid", "fa-pause"], ["type", "button", "title", "Continue (F5) \u2014 run until the next breakpoint or the end", "aria-label", "Continue", 1, "dbg-btn", "dbg-btn-go", 3, "click", "disabled"], ["aria-hidden", "true", 1, "fa-solid", "fa-play"], ["type", "button", "title", "Step Over (F10) \u2014 run the next ready step, then pause again", "aria-label", "Step over", 1, "dbg-btn", "dbg-btn-labeled", 3, "click", "disabled"], ["aria-hidden", "true", 1, "fa-solid", "fa-share", "dbg-icon-over"], [1, "dbg-btn-text"], ["type", "button", "title", "Step Into (F11) \u2014 run every step that is ready right now, then pause. On a fork, all ready branches run.", "aria-label", "Step into", 1, "dbg-btn", "dbg-btn-labeled", 3, "click", "disabled"], ["aria-hidden", "true", 1, "fa-solid", "fa-turn-down"], ["title", "The dispatcher is claiming and running steps", 1, "dbg-pill", "dbg-pill-run"], ["aria-hidden", "true", 1, "fa-solid", "fa-spinner", "fa-spin"], ["type", "button", "title", "Pause (F5) \u2014 nothing new starts; steps already running will finish", "aria-label", "Pause", 1, "dbg-btn", 3, "click", "disabled"]], template: function TaskGraphDebugToolbarComponent_Template(rf, ctx) { if (rf & 1) {
107
+ i0.ɵɵdomElementStart(0, "div", 0);
108
+ i0.ɵɵconditionalCreate(1, TaskGraphDebugToolbarComponent_Conditional_1_Template, 3, 0, "span", 1)(2, TaskGraphDebugToolbarComponent_Conditional_2_Template, 13, 3)(3, TaskGraphDebugToolbarComponent_Conditional_3_Template, 5, 1);
109
+ i0.ɵɵdomElement(4, "span", 2);
110
+ i0.ɵɵdomElementStart(5, "button", 3);
111
+ i0.ɵɵdomListener("click", function TaskGraphDebugToolbarComponent_Template_button_click_5_listener() { return ctx.Cancel.emit(); });
112
+ i0.ɵɵdomElement(6, "i", 4);
113
+ i0.ɵɵdomElementEnd()();
114
+ } if (rf & 2) {
115
+ i0.ɵɵadvance();
116
+ i0.ɵɵconditional(ctx.Settled ? 1 : ctx.Paused ? 2 : 3);
117
+ i0.ɵɵadvance(4);
118
+ i0.ɵɵdomProperty("disabled", ctx.Busy || ctx.Settled || !ctx.Enabled);
119
+ } }, styles: ["[_nghost-%COMP%] { display: inline-flex; }\n\n.dbg-bar[_ngcontent-%COMP%] {\n display: inline-flex;\n align-items: center;\n gap: 2px;\n padding: 2px;\n border: 1px solid var(--mj-border-default);\n border-radius: var(--mj-radius-md);\n background: var(--mj-bg-surface-elevated);\n}\n\n.dbg-pill[_ngcontent-%COMP%] {\n display: inline-flex;\n align-items: center;\n gap: 6px;\n margin: 0 4px 0 6px;\n font-size: var(--mj-font-size-xs);\n font-weight: 600;\n letter-spacing: 0.04em;\n text-transform: uppercase;\n color: var(--mj-brand-primary);\n}\n.dbg-pill[_ngcontent-%COMP%] i[_ngcontent-%COMP%] { font-size: 10px; }\n.dbg-pill-run[_ngcontent-%COMP%] { color: var(--mj-status-warning); }\n.dbg-pill-done[_ngcontent-%COMP%] { color: var(--mj-status-success); }\n\n.dbg-btn[_ngcontent-%COMP%] {\n min-width: 28px;\n height: 28px;\n padding: 0 6px;\n display: inline-flex;\n align-items: center;\n justify-content: center;\n border: none;\n border-radius: var(--mj-radius-sm);\n background: transparent;\n color: var(--mj-text-secondary);\n cursor: pointer;\n}\n.dbg-btn[_ngcontent-%COMP%]:hover:not(:disabled) {\n background: var(--mj-bg-surface-hover);\n color: var(--mj-text-primary);\n}\n.dbg-btn[_ngcontent-%COMP%]:disabled {\n opacity: 0.45;\n cursor: default;\n}\n.dbg-btn-go[_ngcontent-%COMP%] { color: var(--mj-status-success); }\n.dbg-btn-go[_ngcontent-%COMP%]:hover:not(:disabled) { color: var(--mj-status-success); }\n.dbg-btn-stop[_ngcontent-%COMP%] { color: var(--mj-status-error); }\n.dbg-btn-stop[_ngcontent-%COMP%]:hover:not(:disabled) { color: var(--mj-status-error); }\n\n.dbg-btn-labeled[_ngcontent-%COMP%] { gap: 4px; }\n.dbg-btn-text[_ngcontent-%COMP%] {\n font-size: 10px;\n font-weight: 600;\n letter-spacing: 0.02em;\n}\n\n\n.dbg-icon-over[_ngcontent-%COMP%] { transform: scaleY(-1); }\n\n.dbg-sep[_ngcontent-%COMP%] {\n width: 1px;\n height: 16px;\n margin: 0 2px;\n background: var(--mj-border-default);\n}"], changeDetection: 0 });
120
+ }
121
+ (() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassMetadata(TaskGraphDebugToolbarComponent, [{
122
+ type: Component,
123
+ args: [{ standalone: true, selector: 'mj-task-graph-debug-toolbar', changeDetection: ChangeDetectionStrategy.OnPush, template: "<div class=\"dbg-bar\" role=\"toolbar\" aria-label=\"Workflow debugger\">\n @if (Settled) {\n <span class=\"dbg-pill dbg-pill-done\" title=\"Every step has finished\">\n <i class=\"fa-solid fa-check\" aria-hidden=\"true\"></i>\n Finished\n </span>\n } @else if (Paused) {\n <span class=\"dbg-pill\" title=\"Nothing new starts until you continue or step\">\n <i class=\"fa-solid fa-pause\" aria-hidden=\"true\"></i>\n Paused\n </span>\n <button type=\"button\" class=\"dbg-btn dbg-btn-go\" [disabled]=\"Busy || !Enabled\"\n (click)=\"Resume.emit()\" title=\"Continue (F5) \u2014 run until the next breakpoint or the end\"\n aria-label=\"Continue\">\n <i class=\"fa-solid fa-play\" aria-hidden=\"true\"></i>\n </button>\n <button type=\"button\" class=\"dbg-btn dbg-btn-labeled\" [disabled]=\"Busy || !Enabled\"\n (click)=\"Step.emit()\"\n title=\"Step Over (F10) \u2014 run the next ready step, then pause again\"\n aria-label=\"Step over\">\n <i class=\"fa-solid fa-share dbg-icon-over\" aria-hidden=\"true\"></i>\n <span class=\"dbg-btn-text\">Over</span>\n </button>\n <button type=\"button\" class=\"dbg-btn dbg-btn-labeled\" [disabled]=\"Busy || !Enabled\"\n (click)=\"StepWave.emit()\"\n title=\"Step Into (F11) \u2014 run every step that is ready right now, then pause. On a fork, all ready branches run.\"\n aria-label=\"Step into\">\n <i class=\"fa-solid fa-turn-down\" aria-hidden=\"true\"></i>\n <span class=\"dbg-btn-text\">Into</span>\n </button>\n } @else {\n <span class=\"dbg-pill dbg-pill-run\" title=\"The dispatcher is claiming and running steps\">\n <i class=\"fa-solid fa-spinner fa-spin\" aria-hidden=\"true\"></i>\n Running\n </span>\n <button type=\"button\" class=\"dbg-btn\" [disabled]=\"Busy || !Enabled\"\n (click)=\"Pause.emit()\" title=\"Pause (F5) \u2014 nothing new starts; steps already running will finish\"\n aria-label=\"Pause\">\n <i class=\"fa-solid fa-pause\" aria-hidden=\"true\"></i>\n </button>\n }\n <span class=\"dbg-sep\" aria-hidden=\"true\"></span>\n <button type=\"button\" class=\"dbg-btn dbg-btn-stop\" [disabled]=\"Busy || Settled || !Enabled\"\n (click)=\"Cancel.emit()\" title=\"Stop (Shift+F5) \u2014 cancel the remaining steps\"\n aria-label=\"Stop\">\n <i class=\"fa-solid fa-stop\" aria-hidden=\"true\"></i>\n </button>\n</div>\n", styles: [":host { display: inline-flex; }\n\n.dbg-bar {\n display: inline-flex;\n align-items: center;\n gap: 2px;\n padding: 2px;\n border: 1px solid var(--mj-border-default);\n border-radius: var(--mj-radius-md);\n background: var(--mj-bg-surface-elevated);\n}\n\n.dbg-pill {\n display: inline-flex;\n align-items: center;\n gap: 6px;\n margin: 0 4px 0 6px;\n font-size: var(--mj-font-size-xs);\n font-weight: 600;\n letter-spacing: 0.04em;\n text-transform: uppercase;\n color: var(--mj-brand-primary);\n}\n.dbg-pill i { font-size: 10px; }\n.dbg-pill-run { color: var(--mj-status-warning); }\n.dbg-pill-done { color: var(--mj-status-success); }\n\n.dbg-btn {\n min-width: 28px;\n height: 28px;\n padding: 0 6px;\n display: inline-flex;\n align-items: center;\n justify-content: center;\n border: none;\n border-radius: var(--mj-radius-sm);\n background: transparent;\n color: var(--mj-text-secondary);\n cursor: pointer;\n}\n.dbg-btn:hover:not(:disabled) {\n background: var(--mj-bg-surface-hover);\n color: var(--mj-text-primary);\n}\n.dbg-btn:disabled {\n opacity: 0.45;\n cursor: default;\n}\n.dbg-btn-go { color: var(--mj-status-success); }\n.dbg-btn-go:hover:not(:disabled) { color: var(--mj-status-success); }\n.dbg-btn-stop { color: var(--mj-status-error); }\n.dbg-btn-stop:hover:not(:disabled) { color: var(--mj-status-error); }\n\n.dbg-btn-labeled { gap: 4px; }\n.dbg-btn-text {\n font-size: 10px;\n font-weight: 600;\n letter-spacing: 0.02em;\n}\n/* `fa-share` curves up-right; rotate so it reads as \"step over this one\". */\n.dbg-icon-over { transform: scaleY(-1); }\n\n.dbg-sep {\n width: 1px;\n height: 16px;\n margin: 0 2px;\n background: var(--mj-border-default);\n}\n"] }]
124
+ }], null, { Paused: [{
125
+ type: Input
126
+ }], Busy: [{
127
+ type: Input
128
+ }], Enabled: [{
129
+ type: Input
130
+ }], Settled: [{
131
+ type: Input
132
+ }], Pause: [{
133
+ type: Output
134
+ }], Resume: [{
135
+ type: Output
136
+ }], Step: [{
137
+ type: Output
138
+ }], StepWave: [{
139
+ type: Output
140
+ }], Cancel: [{
141
+ type: Output
142
+ }], OnHotkey: [{
143
+ type: HostListener,
144
+ args: ['document:keydown', ['$event']]
145
+ }] }); })();
146
+ (() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassDebugInfo(TaskGraphDebugToolbarComponent, { className: "TaskGraphDebugToolbarComponent", filePath: "src/lib/task-graph-debug-toolbar.component.ts", lineNumber: 16 }); })();
147
+ function isToolbarTypingTarget(target) {
148
+ if (!(target instanceof HTMLElement))
149
+ return false;
150
+ const tag = target.tagName;
151
+ return tag === 'INPUT' || tag === 'TEXTAREA' || tag === 'SELECT' || target.isContentEditable;
152
+ }
153
+ //# sourceMappingURL=task-graph-debug-toolbar.component.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"task-graph-debug-toolbar.component.js","sourceRoot":"","sources":["../../src/lib/task-graph-debug-toolbar.component.ts","../../src/lib/task-graph-debug-toolbar.component.html"],"names":[],"mappings":"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","sourcesContent":["/**\n * VS Code-style debug chrome: Continue / Pause / Step Over / Step Into / Stop.\n *\n * Intent only. The host owns Pause/Resume/Step Remote Operations. This widget never imports\n * a transport, so the same bar can sit in the test harness and on the Explorer run console.\n */\nimport { ChangeDetectionStrategy, Component, EventEmitter, HostListener, Input, Output } from '@angular/core';\n\n@Component({\n standalone: true,\n selector: 'mj-task-graph-debug-toolbar',\n templateUrl: './task-graph-debug-toolbar.component.html',\n styleUrls: ['./task-graph-debug-toolbar.component.css'],\n changeDetection: ChangeDetectionStrategy.OnPush,\n})\nexport class TaskGraphDebugToolbarComponent {\n /** Graph is claim-gated. Continue / Step show; Pause hides. */\n @Input() public Paused = false;\n /** A control is in flight — buttons disable, they do not vanish. */\n @Input() public Busy = false;\n /** False when the graph has settled or there is nothing to drive. */\n @Input() public Enabled = true;\n /** Every step is terminal — Play/Step hide; Finished is the state. */\n @Input() public Settled = false;\n\n @Output() public Pause = new EventEmitter<void>();\n @Output() public Resume = new EventEmitter<void>();\n @Output() public Step = new EventEmitter<void>();\n @Output() public StepWave = new EventEmitter<void>();\n @Output() public Cancel = new EventEmitter<void>();\n\n @HostListener('document:keydown', ['$event'])\n public OnHotkey(event: KeyboardEvent): void {\n if (!this.Enabled || this.Busy || this.Settled) return;\n if (isToolbarTypingTarget(event.target)) return;\n if (event.key === 'F5' && event.shiftKey) {\n event.preventDefault();\n this.Cancel.emit();\n return;\n }\n if (event.key === 'F5') {\n event.preventDefault();\n if (this.Paused) this.Resume.emit();\n else this.Pause.emit();\n return;\n }\n if (event.key === 'F10') {\n event.preventDefault();\n this.Step.emit();\n return;\n }\n if (event.key === 'F11') {\n event.preventDefault();\n this.StepWave.emit();\n }\n }\n}\n\nfunction isToolbarTypingTarget(target: EventTarget | null): boolean {\n if (!(target instanceof HTMLElement)) return false;\n const tag = target.tagName;\n return tag === 'INPUT' || tag === 'TEXTAREA' || tag === 'SELECT' || target.isContentEditable;\n}\n","<div class=\"dbg-bar\" role=\"toolbar\" aria-label=\"Workflow debugger\">\n @if (Settled) {\n <span class=\"dbg-pill dbg-pill-done\" title=\"Every step has finished\">\n <i class=\"fa-solid fa-check\" aria-hidden=\"true\"></i>\n Finished\n </span>\n } @else if (Paused) {\n <span class=\"dbg-pill\" title=\"Nothing new starts until you continue or step\">\n <i class=\"fa-solid fa-pause\" aria-hidden=\"true\"></i>\n Paused\n </span>\n <button type=\"button\" class=\"dbg-btn dbg-btn-go\" [disabled]=\"Busy || !Enabled\"\n (click)=\"Resume.emit()\" title=\"Continue (F5) — run until the next breakpoint or the end\"\n aria-label=\"Continue\">\n <i class=\"fa-solid fa-play\" aria-hidden=\"true\"></i>\n </button>\n <button type=\"button\" class=\"dbg-btn dbg-btn-labeled\" [disabled]=\"Busy || !Enabled\"\n (click)=\"Step.emit()\"\n title=\"Step Over (F10) — run the next ready step, then pause again\"\n aria-label=\"Step over\">\n <i class=\"fa-solid fa-share dbg-icon-over\" aria-hidden=\"true\"></i>\n <span class=\"dbg-btn-text\">Over</span>\n </button>\n <button type=\"button\" class=\"dbg-btn dbg-btn-labeled\" [disabled]=\"Busy || !Enabled\"\n (click)=\"StepWave.emit()\"\n title=\"Step Into (F11) — run every step that is ready right now, then pause. On a fork, all ready branches run.\"\n aria-label=\"Step into\">\n <i class=\"fa-solid fa-turn-down\" aria-hidden=\"true\"></i>\n <span class=\"dbg-btn-text\">Into</span>\n </button>\n } @else {\n <span class=\"dbg-pill dbg-pill-run\" title=\"The dispatcher is claiming and running steps\">\n <i class=\"fa-solid fa-spinner fa-spin\" aria-hidden=\"true\"></i>\n Running\n </span>\n <button type=\"button\" class=\"dbg-btn\" [disabled]=\"Busy || !Enabled\"\n (click)=\"Pause.emit()\" title=\"Pause (F5) — nothing new starts; steps already running will finish\"\n aria-label=\"Pause\">\n <i class=\"fa-solid fa-pause\" aria-hidden=\"true\"></i>\n </button>\n }\n <span class=\"dbg-sep\" aria-hidden=\"true\"></span>\n <button type=\"button\" class=\"dbg-btn dbg-btn-stop\" [disabled]=\"Busy || Settled || !Enabled\"\n (click)=\"Cancel.emit()\" title=\"Stop (Shift+F5) — cancel the remaining steps\"\n aria-label=\"Stop\">\n <i class=\"fa-solid fa-stop\" aria-hidden=\"true\"></i>\n </button>\n</div>\n"]}
@@ -0,0 +1,96 @@
1
+ /**
2
+ * Drop-in debugger for a live task graph.
3
+ *
4
+ * This is a wrap of the existing run view + VCR toolbar + the session wiring the harness and
5
+ * Runs console already had (RouteOperation, frame subscribe, `$.debug` bag). The picture and
6
+ * the verbs are unchanged; a host now supplies a parent task id and nothing else.
7
+ *
8
+ * @module @memberjunction/ng-task-graph-editor
9
+ */
10
+ import { ChangeDetectorRef, EventEmitter, OnDestroy } from '@angular/core';
11
+ import { BaseAngularComponent } from '@memberjunction/ng-base-types';
12
+ import type { FlowToolbarAlign, FlowToolbarVisibility } from '@memberjunction/ng-flow-editor';
13
+ import { type WorkflowInvocationRoots } from './workflow-debug-host';
14
+ import { TaskGraphRunViewComponent, type TaskGraphRunConnectionSelectedEvent, type TaskGraphRunFrame, type TaskGraphRunNodeSelectedEvent } from './task-graph-run-view.component';
15
+ import * as i0 from "@angular/core";
16
+ export declare class TaskGraphDebuggerComponent extends BaseAngularComponent implements OnDestroy {
17
+ private cdr;
18
+ /**
19
+ * The graph to debug — the parent `MJ: Tasks` row. Everything else is optional.
20
+ */
21
+ set ParentTaskID(value: string | null);
22
+ get ParentTaskID(): string | null;
23
+ WorkflowName: string;
24
+ LiveUpdates: boolean;
25
+ PollIntervalSeconds: number;
26
+ Height: string;
27
+ ShowLegend: boolean;
28
+ ShowCanvasToolbar: boolean;
29
+ ToolbarVisibility: FlowToolbarVisibility;
30
+ ToolbarAlign: FlowToolbarAlign;
31
+ AllowBreakpointEditing: boolean;
32
+ ShowVariables: boolean;
33
+ /** VCR + error line above the canvas. Off if the host already has its own bar. */
34
+ ShowChrome: boolean;
35
+ Enabled: boolean;
36
+ ReplayAt: Date | null;
37
+ /** Claim-gated. Public so a host toolbar can bind the same flag. */
38
+ Paused: boolean;
39
+ IsSettled: boolean;
40
+ Busy: boolean;
41
+ ControlError: string | null;
42
+ Breakpoints: readonly string[];
43
+ PausedAtTaskID: string | null;
44
+ EdgeOverrides: Readonly<Record<string, 'true' | 'false'>>;
45
+ Invocation: WorkflowInvocationRoots | null;
46
+ LatestFrame: TaskGraphRunFrame | null;
47
+ NodeSelected: EventEmitter<TaskGraphRunNodeSelectedEvent>;
48
+ ConnectionSelected: EventEmitter<TaskGraphRunConnectionSelectedEvent>;
49
+ LegendToggled: EventEmitter<boolean>;
50
+ SettledChange: EventEmitter<boolean>;
51
+ PausedChange: EventEmitter<boolean>;
52
+ Frame: EventEmitter<TaskGraphRunFrame>;
53
+ ControlFailed: EventEmitter<string>;
54
+ Settled: EventEmitter<void>;
55
+ RunView: TaskGraphRunViewComponent | undefined;
56
+ private parentTaskID;
57
+ private frameSub;
58
+ constructor(cdr: ChangeDetectorRef);
59
+ ngOnDestroy(): void;
60
+ Pause(): Promise<boolean>;
61
+ Resume(): Promise<boolean>;
62
+ Step(target?: 'one' | 'wave'): Promise<boolean>;
63
+ Cancel(): Promise<boolean>;
64
+ ToggleBreakpoint(taskID: string, enabled: boolean): Promise<boolean>;
65
+ OverrideEdge(edgeID: string, verdict: 'true' | 'false' | null): Promise<boolean>;
66
+ SkipTask(taskID: string): Promise<boolean>;
67
+ RetryTask(taskID: string, inputPayload?: Record<string, unknown> | string): Promise<boolean>;
68
+ UpdateTaskInput(taskID: string, payload: unknown): Promise<boolean>;
69
+ ForceCompleteTask(taskID: string, payload?: unknown): Promise<boolean>;
70
+ HasBreakpoint(taskID: string): boolean;
71
+ GetEdgeOverride(edgeID: string | null): 'true' | 'false' | null;
72
+ /** Re-read `$.debug` from the parent row. Same query the hosts already used. */
73
+ Refresh(): Promise<void>;
74
+ OnRunNodeSelected(event: TaskGraphRunNodeSelectedEvent): void;
75
+ OnRunConnectionSelected(event: TaskGraphRunConnectionSelectedEvent): void;
76
+ OnRunSettled(): void;
77
+ OnRunBreakpointToggled(event: {
78
+ TaskID: string;
79
+ Enabled: boolean;
80
+ }): void;
81
+ OnRunEdgeOverride(event: {
82
+ EdgeID: string;
83
+ Verdict: 'true' | 'false' | null;
84
+ }): void;
85
+ private executeControl;
86
+ private attachFrames;
87
+ private onFrame;
88
+ private detachFrames;
89
+ private markSettled;
90
+ private setPaused;
91
+ private failControl;
92
+ private clearSession;
93
+ static ɵfac: i0.ɵɵFactoryDeclaration<TaskGraphDebuggerComponent, never>;
94
+ static ɵcmp: i0.ɵɵComponentDeclaration<TaskGraphDebuggerComponent, "mj-task-graph-debugger", never, { "ParentTaskID": { "alias": "ParentTaskID"; "required": false; }; "WorkflowName": { "alias": "WorkflowName"; "required": false; }; "LiveUpdates": { "alias": "LiveUpdates"; "required": false; }; "PollIntervalSeconds": { "alias": "PollIntervalSeconds"; "required": false; }; "Height": { "alias": "Height"; "required": false; }; "ShowLegend": { "alias": "ShowLegend"; "required": false; }; "ShowCanvasToolbar": { "alias": "ShowCanvasToolbar"; "required": false; }; "ToolbarVisibility": { "alias": "ToolbarVisibility"; "required": false; }; "ToolbarAlign": { "alias": "ToolbarAlign"; "required": false; }; "AllowBreakpointEditing": { "alias": "AllowBreakpointEditing"; "required": false; }; "ShowVariables": { "alias": "ShowVariables"; "required": false; }; "ShowChrome": { "alias": "ShowChrome"; "required": false; }; "Enabled": { "alias": "Enabled"; "required": false; }; "ReplayAt": { "alias": "ReplayAt"; "required": false; }; }, { "NodeSelected": "NodeSelected"; "ConnectionSelected": "ConnectionSelected"; "LegendToggled": "LegendToggled"; "SettledChange": "SettledChange"; "PausedChange": "PausedChange"; "Frame": "Frame"; "ControlFailed": "ControlFailed"; "Settled": "Settled"; }, never, never, false, never>;
95
+ }
96
+ //# sourceMappingURL=task-graph-debugger.component.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"task-graph-debugger.component.d.ts","sourceRoot":"","sources":["../../src/lib/task-graph-debugger.component.ts"],"names":[],"mappings":"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"}