@memberjunction/ng-task-graph-editor 6.1.0-edge.1 → 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.
- package/LICENSE +180 -4
- package/README.md +197 -0
- package/dist/lib/debug-variables.d.ts +27 -0
- package/dist/lib/debug-variables.d.ts.map +1 -0
- package/dist/lib/debug-variables.js +96 -0
- package/dist/lib/debug-variables.js.map +1 -0
- package/dist/lib/pane-split.d.ts +11 -0
- package/dist/lib/pane-split.d.ts.map +1 -0
- package/dist/lib/pane-split.js +36 -0
- package/dist/lib/pane-split.js.map +1 -0
- package/dist/lib/task-graph-canvas-adapter.d.ts +142 -7
- package/dist/lib/task-graph-canvas-adapter.d.ts.map +1 -1
- package/dist/lib/task-graph-canvas-adapter.js +319 -44
- package/dist/lib/task-graph-canvas-adapter.js.map +1 -1
- package/dist/lib/task-graph-debug-toolbar.component.d.ts +27 -0
- package/dist/lib/task-graph-debug-toolbar.component.d.ts.map +1 -0
- package/dist/lib/task-graph-debug-toolbar.component.js +153 -0
- package/dist/lib/task-graph-debug-toolbar.component.js.map +1 -0
- package/dist/lib/task-graph-debugger.component.d.ts +96 -0
- package/dist/lib/task-graph-debugger.component.d.ts.map +1 -0
- package/dist/lib/task-graph-debugger.component.js +371 -0
- package/dist/lib/task-graph-debugger.component.js.map +1 -0
- package/dist/lib/task-graph-editor.component.d.ts +144 -5
- package/dist/lib/task-graph-editor.component.d.ts.map +1 -1
- package/dist/lib/task-graph-editor.component.js +321 -26
- package/dist/lib/task-graph-editor.component.js.map +1 -1
- package/dist/lib/task-graph-editor.module.d.ts +10 -5
- package/dist/lib/task-graph-editor.module.d.ts.map +1 -1
- package/dist/lib/task-graph-editor.module.js +53 -5
- package/dist/lib/task-graph-editor.module.js.map +1 -1
- package/dist/lib/task-graph-properties-panel.component.d.ts +34 -8
- package/dist/lib/task-graph-properties-panel.component.d.ts.map +1 -1
- package/dist/lib/task-graph-properties-panel.component.js +164 -45
- package/dist/lib/task-graph-properties-panel.component.js.map +1 -1
- package/dist/lib/task-graph-run-prefs.d.ts +34 -0
- package/dist/lib/task-graph-run-prefs.d.ts.map +1 -0
- package/dist/lib/task-graph-run-prefs.js +67 -0
- package/dist/lib/task-graph-run-prefs.js.map +1 -0
- package/dist/lib/task-graph-run-view.component.d.ts +290 -0
- package/dist/lib/task-graph-run-view.component.d.ts.map +1 -0
- package/dist/lib/task-graph-run-view.component.js +826 -0
- package/dist/lib/task-graph-run-view.component.js.map +1 -0
- package/dist/lib/task-graph-runtime-source.d.ts +7 -1
- package/dist/lib/task-graph-runtime-source.d.ts.map +1 -1
- package/dist/lib/task-graph-runtime-source.js +14 -2
- package/dist/lib/task-graph-runtime-source.js.map +1 -1
- package/dist/lib/task-graph-variables.component.d.ts +23 -0
- package/dist/lib/task-graph-variables.component.d.ts.map +1 -0
- package/dist/lib/task-graph-variables.component.js +192 -0
- package/dist/lib/task-graph-variables.component.js.map +1 -0
- package/dist/lib/workflow-debug-host.d.ts +23 -0
- package/dist/lib/workflow-debug-host.d.ts.map +1 -0
- package/dist/lib/workflow-debug-host.js +101 -0
- package/dist/lib/workflow-debug-host.js.map +1 -0
- package/dist/public-api.d.ts +8 -0
- package/dist/public-api.d.ts.map +1 -1
- package/dist/public-api.js +8 -0
- package/dist/public-api.js.map +1 -1
- package/package.json +11 -9
|
@@ -14,7 +14,8 @@
|
|
|
14
14
|
* @module @memberjunction/ng-task-graph-editor
|
|
15
15
|
*/
|
|
16
16
|
import { Component, EventEmitter, Input, Output } from '@angular/core';
|
|
17
|
-
import {
|
|
17
|
+
import { ConfigOf, TaskNode } from '@memberjunction/ai-core-plus';
|
|
18
|
+
import { GetDependencies, GetTaskNodeType, IsAuthorableNodeType } from './task-graph-canvas-adapter';
|
|
18
19
|
import * as i0 from "@angular/core";
|
|
19
20
|
import * as i1 from "@angular/forms";
|
|
20
21
|
import * as i2 from "@memberjunction/ng-ui-components";
|
|
@@ -22,8 +23,8 @@ const _forTrack0 = ($index, $item) => $item.FromTempId;
|
|
|
22
23
|
function TaskGraphPropertiesPanelComponent_Conditional_1_Template(rf, ctx) { if (rf & 1) {
|
|
23
24
|
i0.ɵɵelement(0, "mj-empty-state", 1);
|
|
24
25
|
} }
|
|
25
|
-
function
|
|
26
|
-
i0.ɵɵelementStart(0, "option",
|
|
26
|
+
function TaskGraphPropertiesPanelComponent_Conditional_2_Case_18_Conditional_0_For_2_Template(rf, ctx) { if (rf & 1) {
|
|
27
|
+
i0.ɵɵelementStart(0, "option", 16);
|
|
27
28
|
i0.ɵɵtext(1);
|
|
28
29
|
i0.ɵɵelementEnd();
|
|
29
30
|
} if (rf & 2) {
|
|
@@ -32,45 +33,87 @@ function TaskGraphPropertiesPanelComponent_Conditional_2_Conditional_15_For_2_Te
|
|
|
32
33
|
i0.ɵɵadvance();
|
|
33
34
|
i0.ɵɵtextInterpolate(name_r4);
|
|
34
35
|
} }
|
|
35
|
-
function
|
|
36
|
+
function TaskGraphPropertiesPanelComponent_Conditional_2_Case_18_Conditional_0_Template(rf, ctx) { if (rf & 1) {
|
|
36
37
|
const _r3 = i0.ɵɵgetCurrentView();
|
|
37
|
-
i0.ɵɵelementStart(0, "select",
|
|
38
|
-
i0.ɵɵtwoWayListener("ngModelChange", function
|
|
39
|
-
i0.ɵɵlistener("change", function
|
|
40
|
-
i0.ɵɵrepeaterCreate(1,
|
|
38
|
+
i0.ɵɵelementStart(0, "select", 15);
|
|
39
|
+
i0.ɵɵtwoWayListener("ngModelChange", function TaskGraphPropertiesPanelComponent_Conditional_2_Case_18_Conditional_0_Template_select_ngModelChange_0_listener($event) { i0.ɵɵrestoreView(_r3); const ctx_r1 = i0.ɵɵnextContext(3); i0.ɵɵtwoWayBindingSet(ctx_r1.AgentName, $event) || (ctx_r1.AgentName = $event); return i0.ɵɵresetView($event); });
|
|
40
|
+
i0.ɵɵlistener("change", function TaskGraphPropertiesPanelComponent_Conditional_2_Case_18_Conditional_0_Template_select_change_0_listener() { i0.ɵɵrestoreView(_r3); const ctx_r1 = i0.ɵɵnextContext(3); return i0.ɵɵresetView(ctx_r1.Commit()); });
|
|
41
|
+
i0.ɵɵrepeaterCreate(1, TaskGraphPropertiesPanelComponent_Conditional_2_Case_18_Conditional_0_For_2_Template, 2, 2, "option", 16, i0.ɵɵrepeaterTrackByIdentity);
|
|
41
42
|
i0.ɵɵelementEnd();
|
|
42
43
|
} if (rf & 2) {
|
|
43
|
-
const ctx_r1 = i0.ɵɵnextContext(
|
|
44
|
-
i0.ɵɵtwoWayProperty("ngModel", ctx_r1.
|
|
44
|
+
const ctx_r1 = i0.ɵɵnextContext(3);
|
|
45
|
+
i0.ɵɵtwoWayProperty("ngModel", ctx_r1.AgentName);
|
|
45
46
|
i0.ɵɵproperty("disabled", ctx_r1.ReadOnly);
|
|
46
47
|
i0.ɵɵadvance();
|
|
47
48
|
i0.ɵɵrepeater(ctx_r1.AvailableAgentNames);
|
|
48
49
|
} }
|
|
49
|
-
function
|
|
50
|
-
i0.ɵɵelement(0, "mj-alert",
|
|
50
|
+
function TaskGraphPropertiesPanelComponent_Conditional_2_Case_18_Conditional_1_Template(rf, ctx) { if (rf & 1) {
|
|
51
|
+
i0.ɵɵelement(0, "mj-alert", 14);
|
|
52
|
+
} }
|
|
53
|
+
function TaskGraphPropertiesPanelComponent_Conditional_2_Case_18_Template(rf, ctx) { if (rf & 1) {
|
|
54
|
+
i0.ɵɵconditionalCreate(0, TaskGraphPropertiesPanelComponent_Conditional_2_Case_18_Conditional_0_Template, 3, 2, "select", 13)(1, TaskGraphPropertiesPanelComponent_Conditional_2_Case_18_Conditional_1_Template, 1, 0, "mj-alert", 14);
|
|
55
|
+
} if (rf & 2) {
|
|
56
|
+
const ctx_r1 = i0.ɵɵnextContext(2);
|
|
57
|
+
i0.ɵɵconditional(ctx_r1.AvailableAgentNames.length > 0 ? 0 : 1);
|
|
58
|
+
} }
|
|
59
|
+
function TaskGraphPropertiesPanelComponent_Conditional_2_Case_19_Conditional_0_For_2_Template(rf, ctx) { if (rf & 1) {
|
|
60
|
+
i0.ɵɵelementStart(0, "option", 16);
|
|
61
|
+
i0.ɵɵtext(1);
|
|
62
|
+
i0.ɵɵelementEnd();
|
|
63
|
+
} if (rf & 2) {
|
|
64
|
+
const name_r6 = ctx.$implicit;
|
|
65
|
+
i0.ɵɵproperty("value", name_r6);
|
|
66
|
+
i0.ɵɵadvance();
|
|
67
|
+
i0.ɵɵtextInterpolate(name_r6);
|
|
51
68
|
} }
|
|
52
|
-
function
|
|
69
|
+
function TaskGraphPropertiesPanelComponent_Conditional_2_Case_19_Conditional_0_Template(rf, ctx) { if (rf & 1) {
|
|
53
70
|
const _r5 = i0.ɵɵgetCurrentView();
|
|
54
|
-
i0.ɵɵelementStart(0, "
|
|
55
|
-
i0.ɵɵ
|
|
71
|
+
i0.ɵɵelementStart(0, "select", 19);
|
|
72
|
+
i0.ɵɵtwoWayListener("ngModelChange", function TaskGraphPropertiesPanelComponent_Conditional_2_Case_19_Conditional_0_Template_select_ngModelChange_0_listener($event) { i0.ɵɵrestoreView(_r5); const ctx_r1 = i0.ɵɵnextContext(3); i0.ɵɵtwoWayBindingSet(ctx_r1.ActionName, $event) || (ctx_r1.ActionName = $event); return i0.ɵɵresetView($event); });
|
|
73
|
+
i0.ɵɵlistener("change", function TaskGraphPropertiesPanelComponent_Conditional_2_Case_19_Conditional_0_Template_select_change_0_listener() { i0.ɵɵrestoreView(_r5); const ctx_r1 = i0.ɵɵnextContext(3); return i0.ɵɵresetView(ctx_r1.Commit()); });
|
|
74
|
+
i0.ɵɵrepeaterCreate(1, TaskGraphPropertiesPanelComponent_Conditional_2_Case_19_Conditional_0_For_2_Template, 2, 2, "option", 16, i0.ɵɵrepeaterTrackByIdentity);
|
|
75
|
+
i0.ɵɵelementEnd();
|
|
76
|
+
} if (rf & 2) {
|
|
77
|
+
const ctx_r1 = i0.ɵɵnextContext(3);
|
|
78
|
+
i0.ɵɵtwoWayProperty("ngModel", ctx_r1.ActionName);
|
|
79
|
+
i0.ɵɵproperty("disabled", ctx_r1.ReadOnly);
|
|
80
|
+
i0.ɵɵadvance();
|
|
81
|
+
i0.ɵɵrepeater(ctx_r1.AvailableActionNames);
|
|
82
|
+
} }
|
|
83
|
+
function TaskGraphPropertiesPanelComponent_Conditional_2_Case_19_Conditional_1_Template(rf, ctx) { if (rf & 1) {
|
|
84
|
+
i0.ɵɵelement(0, "mj-alert", 18);
|
|
85
|
+
} }
|
|
86
|
+
function TaskGraphPropertiesPanelComponent_Conditional_2_Case_19_Template(rf, ctx) { if (rf & 1) {
|
|
87
|
+
i0.ɵɵconditionalCreate(0, TaskGraphPropertiesPanelComponent_Conditional_2_Case_19_Conditional_0_Template, 3, 2, "select", 17)(1, TaskGraphPropertiesPanelComponent_Conditional_2_Case_19_Conditional_1_Template, 1, 0, "mj-alert", 18);
|
|
88
|
+
} if (rf & 2) {
|
|
89
|
+
const ctx_r1 = i0.ɵɵnextContext(2);
|
|
90
|
+
i0.ɵɵconditional(ctx_r1.AvailableActionNames.length > 0 ? 0 : 1);
|
|
91
|
+
} }
|
|
92
|
+
function TaskGraphPropertiesPanelComponent_Conditional_2_Case_20_Template(rf, ctx) { if (rf & 1) {
|
|
93
|
+
i0.ɵɵelement(0, "mj-alert", 12);
|
|
94
|
+
} }
|
|
95
|
+
function TaskGraphPropertiesPanelComponent_Conditional_2_Conditional_21_For_3_Template(rf, ctx) { if (rf & 1) {
|
|
96
|
+
const _r7 = i0.ɵɵgetCurrentView();
|
|
97
|
+
i0.ɵɵelementStart(0, "div", 20)(1, "span", 21);
|
|
98
|
+
i0.ɵɵelement(2, "i", 22);
|
|
56
99
|
i0.ɵɵtext(3);
|
|
57
100
|
i0.ɵɵelementEnd();
|
|
58
|
-
i0.ɵɵelementStart(4, "input",
|
|
59
|
-
i0.ɵɵlistener("blur", function
|
|
101
|
+
i0.ɵɵelementStart(4, "input", 23);
|
|
102
|
+
i0.ɵɵlistener("blur", function TaskGraphPropertiesPanelComponent_Conditional_2_Conditional_21_For_3_Template_input_blur_4_listener($event) { const edge_r8 = i0.ɵɵrestoreView(_r7).$implicit; const ctx_r1 = i0.ɵɵnextContext(3); return i0.ɵɵresetView(ctx_r1.CommitCondition(edge_r8.FromTempId, $event.target.value)); });
|
|
60
103
|
i0.ɵɵelementEnd()();
|
|
61
104
|
} if (rf & 2) {
|
|
62
|
-
const
|
|
105
|
+
const edge_r8 = ctx.$implicit;
|
|
63
106
|
const ctx_r1 = i0.ɵɵnextContext(3);
|
|
64
107
|
i0.ɵɵadvance(3);
|
|
65
|
-
i0.ɵɵtextInterpolate1(" ",
|
|
108
|
+
i0.ɵɵtextInterpolate1(" ", edge_r8.FromName);
|
|
66
109
|
i0.ɵɵadvance();
|
|
67
|
-
i0.ɵɵproperty("ngModel",
|
|
110
|
+
i0.ɵɵproperty("ngModel", edge_r8.Condition)("disabled", ctx_r1.ReadOnly);
|
|
68
111
|
} }
|
|
69
|
-
function
|
|
112
|
+
function TaskGraphPropertiesPanelComponent_Conditional_2_Conditional_21_Template(rf, ctx) { if (rf & 1) {
|
|
70
113
|
i0.ɵɵelementStart(0, "label", 6);
|
|
71
114
|
i0.ɵɵtext(1, "Runs after");
|
|
72
115
|
i0.ɵɵelementEnd();
|
|
73
|
-
i0.ɵɵrepeaterCreate(2,
|
|
116
|
+
i0.ɵɵrepeaterCreate(2, TaskGraphPropertiesPanelComponent_Conditional_2_Conditional_21_For_3_Template, 5, 3, "div", 20, _forTrack0);
|
|
74
117
|
} if (rf & 2) {
|
|
75
118
|
const ctx_r1 = i0.ɵɵnextContext(2);
|
|
76
119
|
i0.ɵɵadvance(2);
|
|
@@ -96,18 +139,24 @@ function TaskGraphPropertiesPanelComponent_Conditional_2_Template(rf, ctx) { if
|
|
|
96
139
|
i0.ɵɵtext(7, "Who does it");
|
|
97
140
|
i0.ɵɵelementEnd();
|
|
98
141
|
i0.ɵɵelementStart(8, "div", 7)(9, "button", 8);
|
|
99
|
-
i0.ɵɵlistener("click", function TaskGraphPropertiesPanelComponent_Conditional_2_Template_button_click_9_listener() { i0.ɵɵrestoreView(_r1); const ctx_r1 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r1.SetAssignment("
|
|
142
|
+
i0.ɵɵlistener("click", function TaskGraphPropertiesPanelComponent_Conditional_2_Template_button_click_9_listener() { i0.ɵɵrestoreView(_r1); const ctx_r1 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r1.SetAssignment("AgentTask")); });
|
|
100
143
|
i0.ɵɵelement(10, "i", 9);
|
|
101
144
|
i0.ɵɵtext(11, " An agent ");
|
|
102
145
|
i0.ɵɵelementEnd();
|
|
103
146
|
i0.ɵɵelementStart(12, "button", 8);
|
|
104
|
-
i0.ɵɵlistener("click", function TaskGraphPropertiesPanelComponent_Conditional_2_Template_button_click_12_listener() { i0.ɵɵrestoreView(_r1); const ctx_r1 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r1.SetAssignment("
|
|
147
|
+
i0.ɵɵlistener("click", function TaskGraphPropertiesPanelComponent_Conditional_2_Template_button_click_12_listener() { i0.ɵɵrestoreView(_r1); const ctx_r1 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r1.SetAssignment("ActionTask")); });
|
|
105
148
|
i0.ɵɵelement(13, "i", 10);
|
|
106
|
-
i0.ɵɵtext(14, "
|
|
149
|
+
i0.ɵɵtext(14, " An action ");
|
|
150
|
+
i0.ɵɵelementEnd();
|
|
151
|
+
i0.ɵɵelementStart(15, "button", 8);
|
|
152
|
+
i0.ɵɵlistener("click", function TaskGraphPropertiesPanelComponent_Conditional_2_Template_button_click_15_listener() { i0.ɵɵrestoreView(_r1); const ctx_r1 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r1.SetAssignment("HumanTask")); });
|
|
153
|
+
i0.ɵɵelement(16, "i", 11);
|
|
154
|
+
i0.ɵɵtext(17, " A person ");
|
|
107
155
|
i0.ɵɵelementEnd()();
|
|
108
|
-
i0.ɵɵconditionalCreate(
|
|
109
|
-
i0.ɵɵconditionalCreate(
|
|
156
|
+
i0.ɵɵconditionalCreate(18, TaskGraphPropertiesPanelComponent_Conditional_2_Case_18_Template, 2, 1)(19, TaskGraphPropertiesPanelComponent_Conditional_2_Case_19_Template, 2, 1)(20, TaskGraphPropertiesPanelComponent_Conditional_2_Case_20_Template, 1, 0, "mj-alert", 12);
|
|
157
|
+
i0.ɵɵconditionalCreate(21, TaskGraphPropertiesPanelComponent_Conditional_2_Conditional_21_Template, 4, 0);
|
|
110
158
|
} if (rf & 2) {
|
|
159
|
+
let tmp_11_0;
|
|
111
160
|
const ctx_r1 = i0.ɵɵnextContext();
|
|
112
161
|
i0.ɵɵadvance(2);
|
|
113
162
|
i0.ɵɵtwoWayProperty("ngModel", ctx_r1.Draft.name);
|
|
@@ -116,13 +165,15 @@ function TaskGraphPropertiesPanelComponent_Conditional_2_Template(rf, ctx) { if
|
|
|
116
165
|
i0.ɵɵtwoWayProperty("ngModel", ctx_r1.Draft.description);
|
|
117
166
|
i0.ɵɵproperty("disabled", ctx_r1.ReadOnly);
|
|
118
167
|
i0.ɵɵadvance(4);
|
|
119
|
-
i0.ɵɵproperty("variant",
|
|
168
|
+
i0.ɵɵproperty("variant", ctx_r1.Assignment === "AgentTask" ? "primary" : "outline")("disabled", ctx_r1.ReadOnly);
|
|
120
169
|
i0.ɵɵadvance(3);
|
|
121
|
-
i0.ɵɵproperty("variant", ctx_r1.
|
|
170
|
+
i0.ɵɵproperty("variant", ctx_r1.Assignment === "ActionTask" ? "primary" : "outline")("disabled", ctx_r1.ReadOnly);
|
|
122
171
|
i0.ɵɵadvance(3);
|
|
123
|
-
i0.ɵɵ
|
|
124
|
-
i0.ɵɵadvance(
|
|
125
|
-
i0.ɵɵconditional(ctx_r1.
|
|
172
|
+
i0.ɵɵproperty("variant", ctx_r1.Assignment === "HumanTask" ? "primary" : "outline")("disabled", ctx_r1.ReadOnly);
|
|
173
|
+
i0.ɵɵadvance(3);
|
|
174
|
+
i0.ɵɵconditional((tmp_11_0 = ctx_r1.Assignment) === "AgentTask" ? 18 : tmp_11_0 === "ActionTask" ? 19 : 20);
|
|
175
|
+
i0.ɵɵadvance(3);
|
|
176
|
+
i0.ɵɵconditional(ctx_r1.IncomingEdges.length > 0 ? 21 : -1);
|
|
126
177
|
} }
|
|
127
178
|
/** A requested change to one task. The parent applies it; this panel never writes. */
|
|
128
179
|
export class TaskPropertyChangeRequestedEventArgs {
|
|
@@ -161,20 +212,55 @@ export class TaskGraphPropertiesPanelComponent {
|
|
|
161
212
|
Spec = null;
|
|
162
213
|
/** Agent names offered in the assignment dropdown. Supplied by the host, which owns data access. */
|
|
163
214
|
AvailableAgentNames = [];
|
|
215
|
+
/** Action names offered in the assignment dropdown. Same ownership rule as `AvailableAgentNames`. */
|
|
216
|
+
AvailableActionNames = [];
|
|
164
217
|
ReadOnly = false;
|
|
165
218
|
TaskPropertyChangeRequested = new EventEmitter();
|
|
166
219
|
DependencyConditionChangeRequested = new EventEmitter();
|
|
167
220
|
Draft = null;
|
|
168
221
|
currentTask = null;
|
|
169
222
|
/**
|
|
170
|
-
*
|
|
223
|
+
* Which of the three assignment shapes this step currently uses.
|
|
224
|
+
*
|
|
225
|
+
* Derived from the draft rather than stored separately: the node's own `kind` is the single
|
|
226
|
+
* source of truth, and a parallel field could disagree with it.
|
|
227
|
+
*/
|
|
228
|
+
get Assignment() {
|
|
229
|
+
if (!this.Draft)
|
|
230
|
+
return 'AgentTask';
|
|
231
|
+
const type = GetTaskNodeType(this.Draft);
|
|
232
|
+
// This panel edits the three authorable shapes. A display-only kind (a Prompt, a loop, an
|
|
233
|
+
// external step — kinds a run can contain but nobody draws here) has no editor, so it falls
|
|
234
|
+
// back rather than being mis-presented as an agent step with an agent picker.
|
|
235
|
+
return IsAuthorableNodeType(type) ? type : 'AgentTask';
|
|
236
|
+
}
|
|
237
|
+
/**
|
|
238
|
+
* The chosen agent, read and written through the node's configuration.
|
|
171
239
|
*
|
|
172
|
-
*
|
|
173
|
-
*
|
|
174
|
-
*
|
|
240
|
+
* A template cannot narrow a discriminated union, so the two-way binding goes through here
|
|
241
|
+
* rather than at `Draft.configuration.agentName` — which would also be wrong the moment the
|
|
242
|
+
* draft is a different kind.
|
|
175
243
|
*/
|
|
244
|
+
get AgentName() {
|
|
245
|
+
return ConfigOf(this.Draft, 'Agent')?.agentName ?? '';
|
|
246
|
+
}
|
|
247
|
+
set AgentName(value) {
|
|
248
|
+
if (this.Draft?.kind === 'Agent') {
|
|
249
|
+
this.Draft = { ...this.Draft, configuration: { ...ConfigOf(this.Draft, 'Agent'), agentName: value } };
|
|
250
|
+
}
|
|
251
|
+
}
|
|
252
|
+
/** The chosen action. Same reasoning as {@link AgentName}. */
|
|
253
|
+
get ActionName() {
|
|
254
|
+
return ConfigOf(this.Draft, 'Action')?.actionName ?? '';
|
|
255
|
+
}
|
|
256
|
+
set ActionName(value) {
|
|
257
|
+
if (this.Draft?.kind === 'Action') {
|
|
258
|
+
this.Draft = { ...this.Draft, configuration: { ...ConfigOf(this.Draft, 'Action'), actionName: value } };
|
|
259
|
+
}
|
|
260
|
+
}
|
|
261
|
+
/** True when this step waits on a person. */
|
|
176
262
|
get IsHumanTask() {
|
|
177
|
-
return
|
|
263
|
+
return this.Assignment === 'HumanTask';
|
|
178
264
|
}
|
|
179
265
|
/** The edges into this task, so their conditions are editable where the step is. */
|
|
180
266
|
get IncomingEdges() {
|
|
@@ -187,13 +273,44 @@ export class TaskGraphPropertiesPanelComponent {
|
|
|
187
273
|
Condition: d.condition ?? '',
|
|
188
274
|
}));
|
|
189
275
|
}
|
|
190
|
-
/**
|
|
191
|
-
|
|
276
|
+
/**
|
|
277
|
+
* Switches the step between an agent, an action and a person.
|
|
278
|
+
*
|
|
279
|
+
* Replacing `kind` and `configuration` together is the whole operation now. Under the old flat
|
|
280
|
+
* shape this had to clear two sibling fields on every branch, and forgetting one produced an
|
|
281
|
+
* `AssignmentConflict` from a gesture that looked like a simple choice — a bug the union made
|
|
282
|
+
* unrepresentable rather than merely guarded.
|
|
283
|
+
*
|
|
284
|
+
* The previous name is carried over where it still applies, so toggling Agent → Person → Agent
|
|
285
|
+
* does not silently forget what the author had chosen.
|
|
286
|
+
*/
|
|
287
|
+
SetAssignment(kind, name) {
|
|
192
288
|
if (!this.Draft || this.ReadOnly)
|
|
193
289
|
return;
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
:
|
|
290
|
+
const base = {
|
|
291
|
+
tempId: this.Draft.tempId,
|
|
292
|
+
name: this.Draft.name,
|
|
293
|
+
description: this.Draft.description,
|
|
294
|
+
dependsOn: this.Draft.dependsOn,
|
|
295
|
+
policy: this.Draft.policy,
|
|
296
|
+
layout: this.Draft.layout,
|
|
297
|
+
inputPayload: this.Draft.inputPayload,
|
|
298
|
+
};
|
|
299
|
+
switch (kind) {
|
|
300
|
+
case 'HumanTask':
|
|
301
|
+
this.Draft = TaskNode.Human(base, ConfigOf(this.Draft, 'Human') ?? {});
|
|
302
|
+
break;
|
|
303
|
+
case 'ActionTask':
|
|
304
|
+
this.Draft = TaskNode.Action(base, {
|
|
305
|
+
actionName: name ?? ConfigOf(this.Draft, 'Action')?.actionName ?? this.AvailableActionNames[0] ?? '',
|
|
306
|
+
});
|
|
307
|
+
break;
|
|
308
|
+
default:
|
|
309
|
+
this.Draft = TaskNode.Agent(base, {
|
|
310
|
+
agentName: name ?? ConfigOf(this.Draft, 'Agent')?.agentName ?? this.AvailableAgentNames[0] ?? '',
|
|
311
|
+
});
|
|
312
|
+
break;
|
|
313
|
+
}
|
|
197
314
|
this.Commit();
|
|
198
315
|
}
|
|
199
316
|
/** Asks the parent to apply the draft. */
|
|
@@ -209,9 +326,9 @@ export class TaskGraphPropertiesPanelComponent {
|
|
|
209
326
|
this.DependencyConditionChangeRequested.emit(new DependencyConditionChangeRequestedEventArgs(fromTempId, this.Draft.tempId, condition));
|
|
210
327
|
}
|
|
211
328
|
static ɵfac = function TaskGraphPropertiesPanelComponent_Factory(__ngFactoryType__) { return new (__ngFactoryType__ || TaskGraphPropertiesPanelComponent)(); };
|
|
212
|
-
static ɵcmp = /*@__PURE__*/ i0.ɵɵdefineComponent({ type: TaskGraphPropertiesPanelComponent, selectors: [["mj-task-graph-properties"]], inputs: { Task: "Task", Spec: "Spec", AvailableAgentNames: "AvailableAgentNames", ReadOnly: "ReadOnly" }, outputs: { TaskPropertyChangeRequested: "TaskPropertyChangeRequested", DependencyConditionChangeRequested: "DependencyConditionChangeRequested" }, standalone: false, decls: 3, vars: 1, consts: [[1, "mj-tgp"], ["Icon", "fa-hand-pointer", "Title", "No step selected", "Message", "Pick a step on the canvas to edit what it does."], ["for", "tgp-name", 1, "mj-tgp__label"], ["id", "tgp-name", "type", "text", 1, "mj-input", 3, "ngModelChange", "blur", "ngModel", "disabled"], ["for", "tgp-desc", 1, "mj-tgp__label"], ["id", "tgp-desc", "rows", "3", 1, "mj-textarea", 3, "ngModelChange", "blur", "ngModel", "disabled"], [1, "mj-tgp__label"], [1, "mj-tgp__assignment"], ["mjButton", "", "size", "sm", 3, "click", "variant", "disabled"], [1, "fa-solid", "fa-robot"], [1, "fa-solid", "fa-
|
|
329
|
+
static ɵcmp = /*@__PURE__*/ i0.ɵɵdefineComponent({ type: TaskGraphPropertiesPanelComponent, selectors: [["mj-task-graph-properties"]], inputs: { Task: "Task", Spec: "Spec", AvailableAgentNames: "AvailableAgentNames", AvailableActionNames: "AvailableActionNames", ReadOnly: "ReadOnly" }, outputs: { TaskPropertyChangeRequested: "TaskPropertyChangeRequested", DependencyConditionChangeRequested: "DependencyConditionChangeRequested" }, standalone: false, decls: 3, vars: 1, consts: [[1, "mj-tgp"], ["Icon", "fa-hand-pointer", "Title", "No step selected", "Message", "Pick a step on the canvas to edit what it does."], ["for", "tgp-name", 1, "mj-tgp__label"], ["id", "tgp-name", "type", "text", 1, "mj-input", 3, "ngModelChange", "blur", "ngModel", "disabled"], ["for", "tgp-desc", 1, "mj-tgp__label"], ["id", "tgp-desc", "rows", "3", 1, "mj-textarea", 3, "ngModelChange", "blur", "ngModel", "disabled"], [1, "mj-tgp__label"], [1, "mj-tgp__assignment"], ["mjButton", "", "size", "sm", 3, "click", "variant", "disabled"], [1, "fa-solid", "fa-robot"], [1, "fa-solid", "fa-bolt"], [1, "fa-solid", "fa-user-check"], ["Variant", "info", "Size", "sm", "Message", "This step waits for you. Assigning it to someone else isn't available yet."], ["aria-label", "Agent", 1, "mj-input", 3, "ngModel", "disabled"], ["Variant", "warning", "Size", "sm", "Message", "No agents are available to assign. This step will not run until one is chosen."], ["aria-label", "Agent", 1, "mj-input", 3, "ngModelChange", "change", "ngModel", "disabled"], [3, "value"], ["aria-label", "Action", 1, "mj-input", 3, "ngModel", "disabled"], ["Variant", "warning", "Size", "sm", "Message", "No actions are available to assign. This step will not run until one is chosen."], ["aria-label", "Action", 1, "mj-input", 3, "ngModelChange", "change", "ngModel", "disabled"], [1, "mj-tgp__edge"], [1, "mj-tgp__edge-name"], [1, "fa-solid", "fa-arrow-right-long"], ["type", "text", "placeholder", "Always \u2014 or a condition, e.g. output.severity > 3", 1, "mj-input", "mj-tgp__edge-condition", 3, "blur", "ngModel", "disabled"]], template: function TaskGraphPropertiesPanelComponent_Template(rf, ctx) { if (rf & 1) {
|
|
213
330
|
i0.ɵɵelementStart(0, "div", 0);
|
|
214
|
-
i0.ɵɵconditionalCreate(1, TaskGraphPropertiesPanelComponent_Conditional_1_Template, 1, 0, "mj-empty-state", 1)(2, TaskGraphPropertiesPanelComponent_Conditional_2_Template,
|
|
331
|
+
i0.ɵɵconditionalCreate(1, TaskGraphPropertiesPanelComponent_Conditional_1_Template, 1, 0, "mj-empty-state", 1)(2, TaskGraphPropertiesPanelComponent_Conditional_2_Template, 22, 12);
|
|
215
332
|
i0.ɵɵelementEnd();
|
|
216
333
|
} if (rf & 2) {
|
|
217
334
|
i0.ɵɵadvance();
|
|
@@ -220,13 +337,15 @@ export class TaskGraphPropertiesPanelComponent {
|
|
|
220
337
|
}
|
|
221
338
|
(() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassMetadata(TaskGraphPropertiesPanelComponent, [{
|
|
222
339
|
type: Component,
|
|
223
|
-
args: [{ standalone: false, selector: 'mj-task-graph-properties', template: "<div class=\"mj-tgp\">\n @if (!Draft) {\n <mj-empty-state\n Icon=\"fa-hand-pointer\"\n Title=\"No step selected\"\n Message=\"Pick a step on the canvas to edit what it does.\">\n </mj-empty-state>\n } @else {\n <label class=\"mj-tgp__label\" for=\"tgp-name\">Name</label>\n <input id=\"tgp-name\" class=\"mj-input\" type=\"text\"\n [(ngModel)]=\"Draft.name\" [disabled]=\"ReadOnly\" (blur)=\"Commit()\" />\n\n <label class=\"mj-tgp__label\" for=\"tgp-desc\">What this step does</label>\n <textarea id=\"tgp-desc\" class=\"mj-textarea\" rows=\"3\"\n [(ngModel)]=\"Draft.description\" [disabled]=\"ReadOnly\" (blur)=\"Commit()\"></textarea>\n\n <label class=\"mj-tgp__label\">Who does it</label>\n <div class=\"mj-tgp__assignment\">\n <button mjButton [variant]=\"
|
|
340
|
+
args: [{ standalone: false, selector: 'mj-task-graph-properties', template: "<div class=\"mj-tgp\">\n @if (!Draft) {\n <mj-empty-state\n Icon=\"fa-hand-pointer\"\n Title=\"No step selected\"\n Message=\"Pick a step on the canvas to edit what it does.\">\n </mj-empty-state>\n } @else {\n <label class=\"mj-tgp__label\" for=\"tgp-name\">Name</label>\n <input id=\"tgp-name\" class=\"mj-input\" type=\"text\"\n [(ngModel)]=\"Draft.name\" [disabled]=\"ReadOnly\" (blur)=\"Commit()\" />\n\n <label class=\"mj-tgp__label\" for=\"tgp-desc\">What this step does</label>\n <textarea id=\"tgp-desc\" class=\"mj-textarea\" rows=\"3\"\n [(ngModel)]=\"Draft.description\" [disabled]=\"ReadOnly\" (blur)=\"Commit()\"></textarea>\n\n <label class=\"mj-tgp__label\">Who does it</label>\n <!-- Three, because TaskGraphSpecNode has exactly three mutually-exclusive assignment shapes:\n agentName, actionName, assignToUser. -->\n <div class=\"mj-tgp__assignment\">\n <button mjButton [variant]=\"Assignment === 'AgentTask' ? 'primary' : 'outline'\" size=\"sm\"\n [disabled]=\"ReadOnly\" (click)=\"SetAssignment('AgentTask')\">\n <i class=\"fa-solid fa-robot\"></i> An agent\n </button>\n <button mjButton [variant]=\"Assignment === 'ActionTask' ? 'primary' : 'outline'\" size=\"sm\"\n [disabled]=\"ReadOnly\" (click)=\"SetAssignment('ActionTask')\">\n <i class=\"fa-solid fa-bolt\"></i> An action\n </button>\n <button mjButton [variant]=\"Assignment === 'HumanTask' ? 'primary' : 'outline'\" size=\"sm\"\n [disabled]=\"ReadOnly\" (click)=\"SetAssignment('HumanTask')\">\n <i class=\"fa-solid fa-user-check\"></i> A person\n </button>\n </div>\n\n @switch (Assignment) {\n @case ('AgentTask') {\n @if (AvailableAgentNames.length > 0) {\n <select class=\"mj-input\" aria-label=\"Agent\" [(ngModel)]=\"AgentName\" [disabled]=\"ReadOnly\" (change)=\"Commit()\">\n @for (name of AvailableAgentNames; track name) {\n <option [value]=\"name\">{{ name }}</option>\n }\n </select>\n } @else {\n <!-- Says the list is empty rather than rendering an empty dropdown, which reads as a bug. -->\n <mj-alert Variant=\"warning\" Size=\"sm\"\n Message=\"No agents are available to assign. This step will not run until one is chosen.\">\n </mj-alert>\n }\n }\n @case ('ActionTask') {\n @if (AvailableActionNames.length > 0) {\n <select class=\"mj-input\" aria-label=\"Action\" [(ngModel)]=\"ActionName\" [disabled]=\"ReadOnly\" (change)=\"Commit()\">\n @for (name of AvailableActionNames; track name) {\n <option [value]=\"name\">{{ name }}</option>\n }\n </select>\n } @else {\n <mj-alert Variant=\"warning\" Size=\"sm\"\n Message=\"No actions are available to assign. This step will not run until one is chosen.\">\n </mj-alert>\n }\n }\n @default {\n <!-- Cross-user assignment is rejected at submission until the authorization model lands\n (#3524), so the panel states the rule rather than offering a picker that would fail. -->\n <mj-alert Variant=\"info\" Size=\"sm\"\n Message=\"This step waits for you. Assigning it to someone else isn't available yet.\">\n </mj-alert>\n }\n }\n\n @if (IncomingEdges.length > 0) {\n <label class=\"mj-tgp__label\">Runs after</label>\n @for (edge of IncomingEdges; track edge.FromTempId) {\n <div class=\"mj-tgp__edge\">\n <span class=\"mj-tgp__edge-name\"><i class=\"fa-solid fa-arrow-right-long\"></i> {{ edge.FromName }}</span>\n <!-- Leaving this empty makes the edge unconditional, which is how a fallback is written. -->\n <input class=\"mj-input mj-tgp__edge-condition\" type=\"text\"\n placeholder=\"Always \u2014 or a condition, e.g. output.severity > 3\"\n [ngModel]=\"edge.Condition\" [disabled]=\"ReadOnly\"\n (blur)=\"CommitCondition(edge.FromTempId, $any($event.target).value)\" />\n </div>\n }\n }\n }\n</div>\n", styles: ["/* Design tokens only \u2014 no hardcoded colors. */\n.mj-tgp {\n display: flex;\n flex-direction: column;\n gap: var(--mj-space-sm, 0.5rem);\n padding: var(--mj-space-md, 1rem);\n overflow-y: auto;\n background: var(--mj-bg-surface);\n color: var(--mj-text-primary);\n}\n\n.mj-tgp__label {\n font-size: var(--mj-font-size-sm, 0.8125rem);\n font-weight: 600;\n color: var(--mj-text-secondary);\n margin-top: var(--mj-space-xs, 0.25rem);\n}\n\n.mj-tgp__assignment {\n display: flex;\n gap: var(--mj-space-xs, 0.25rem);\n}\n\n.mj-tgp__edge {\n display: flex;\n flex-direction: column;\n gap: var(--mj-space-2xs, 0.125rem);\n padding: var(--mj-space-xs, 0.25rem) 0;\n border-top: 1px solid var(--mj-border-subtle);\n}\n\n.mj-tgp__edge-name {\n font-size: var(--mj-font-size-sm, 0.8125rem);\n color: var(--mj-text-secondary);\n}\n\n.mj-tgp__edge-condition {\n width: 100%;\n}\n"] }]
|
|
224
341
|
}], null, { Task: [{
|
|
225
342
|
type: Input
|
|
226
343
|
}], Spec: [{
|
|
227
344
|
type: Input
|
|
228
345
|
}], AvailableAgentNames: [{
|
|
229
346
|
type: Input
|
|
347
|
+
}], AvailableActionNames: [{
|
|
348
|
+
type: Input
|
|
230
349
|
}], ReadOnly: [{
|
|
231
350
|
type: Input
|
|
232
351
|
}], TaskPropertyChangeRequested: [{
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"task-graph-properties-panel.component.js","sourceRoot":"","sources":["../../src/lib/task-graph-properties-panel.component.ts","../../src/lib/task-graph-properties-panel.component.html"],"names":[],"mappings":"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","sourcesContent":["/**\n * @fileoverview Edits the selected task's properties, plus the graph-level traversal settings.\n *\n * Split out of the canvas component for the reason panels usually are — the canvas is about\n * *structure* (what connects to what) and this is about *content* (what a step actually does). But\n * also for a sharper reason: a host embedding the read-only viewer in a chat card or a run history\n * pane wants the graph without a form beside it, and a panel welded into the canvas cannot be\n * declined.\n *\n * Emits intent rather than mutating: the canvas component owns the spec, so every edit here leaves\n * as a request the parent applies through the same `Before*`/`After*` path a drag or a delete takes.\n * Two write paths into one spec would be two places for the veto contract to be wrong.\n *\n * @module @memberjunction/ng-task-graph-editor\n */\nimport { Component, EventEmitter, Input, Output } from '@angular/core';\nimport type { TaskGraphSpec, TaskGraphSpecNode } from '@memberjunction/ai-core-plus';\nimport { GetDependencies } from './task-graph-canvas-adapter';\n\n/** A requested change to one task. The parent applies it; this panel never writes. */\nexport class TaskPropertyChangeRequestedEventArgs {\n constructor(\n public readonly TempId: string,\n public readonly Next: TaskGraphSpecNode,\n ) {}\n}\n\n/** A requested change to a dependency edge's condition. */\nexport class DependencyConditionChangeRequestedEventArgs {\n constructor(\n public readonly FromTempId: string,\n public readonly ToTempId: string,\n /** Empty string clears the condition, making the edge unconditional again. */\n public readonly Condition: string,\n ) {}\n}\n\n@Component({\n standalone: false,\n selector: 'mj-task-graph-properties',\n templateUrl: './task-graph-properties-panel.component.html',\n styleUrls: ['./task-graph-properties-panel.component.css'],\n})\nexport class TaskGraphPropertiesPanelComponent {\n /** The task being edited. Null shows the empty state rather than a form bound to nothing. */\n @Input()\n public set Task(value: TaskGraphSpecNode | null) {\n this.currentTask = value;\n // A working copy, so a half-typed name never reaches the spec — and so Cancel is possible\n // at all. Editing the live node would make every keystroke an unvetoable mutation.\n this.Draft = value ? { ...value } : null;\n }\n public get Task(): TaskGraphSpecNode | null {\n return this.currentTask;\n }\n\n /** The whole graph, for resolving the selected task's incoming edges. */\n @Input() public Spec: TaskGraphSpec | null = null;\n\n /** Agent names offered in the assignment dropdown. Supplied by the host, which owns data access. */\n @Input() public AvailableAgentNames: readonly string[] = [];\n\n @Input() public ReadOnly: boolean = false;\n\n @Output() public TaskPropertyChangeRequested = new EventEmitter<TaskPropertyChangeRequestedEventArgs>();\n @Output() public DependencyConditionChangeRequested = new EventEmitter<DependencyConditionChangeRequestedEventArgs>();\n\n public Draft: TaskGraphSpecNode | null = null;\n\n private currentTask: TaskGraphSpecNode | null = null;\n\n /**\n * Whether this step waits on a person.\n *\n * Derived from the absence of an agent rather than stored separately, because the spec's own\n * rule is that a task has exactly one assignee. A separate boolean could disagree with\n * `agentName` and the validator would then reject a graph the form said was fine.\n */\n public get IsHumanTask(): boolean {\n return !this.Draft?.agentName;\n }\n\n /** The edges into this task, so their conditions are editable where the step is. */\n public get IncomingEdges(): Array<{ FromTempId: string; FromName: string; Condition: string }> {\n if (!this.Draft || !this.Spec) return [];\n const nameOf = (id: string) => this.Spec!.tasks.find((t) => t.tempId === id)?.name ?? id;\n return GetDependencies(this.Draft).map((d) => ({\n FromTempId: d.tempId,\n FromName: nameOf(d.tempId),\n Condition: d.condition ?? '',\n }));\n }\n\n /** Switches the step between an agent and a person, keeping the spec's xor rule intact. */\n public SetAssignment(kind: 'agent' | 'human', agentName?: string): void {\n if (!this.Draft || this.ReadOnly) return;\n this.Draft = kind === 'human'\n ? { ...this.Draft, agentName: undefined, assignToUser: true }\n : { ...this.Draft, agentName: agentName ?? this.AvailableAgentNames[0], assignToUser: undefined };\n this.Commit();\n }\n\n /** Asks the parent to apply the draft. */\n public Commit(): void {\n if (!this.Draft || !this.currentTask || this.ReadOnly) return;\n this.TaskPropertyChangeRequested.emit(\n new TaskPropertyChangeRequestedEventArgs(this.currentTask.tempId, { ...this.Draft }),\n );\n }\n\n /** Asks the parent to change (or, with an empty string, clear) an edge's condition. */\n public CommitCondition(fromTempId: string, condition: string): void {\n if (!this.Draft || this.ReadOnly) return;\n this.DependencyConditionChangeRequested.emit(\n new DependencyConditionChangeRequestedEventArgs(fromTempId, this.Draft.tempId, condition),\n );\n }\n}\n","<div class=\"mj-tgp\">\n @if (!Draft) {\n <mj-empty-state\n Icon=\"fa-hand-pointer\"\n Title=\"No step selected\"\n Message=\"Pick a step on the canvas to edit what it does.\">\n </mj-empty-state>\n } @else {\n <label class=\"mj-tgp__label\" for=\"tgp-name\">Name</label>\n <input id=\"tgp-name\" class=\"mj-input\" type=\"text\"\n [(ngModel)]=\"Draft.name\" [disabled]=\"ReadOnly\" (blur)=\"Commit()\" />\n\n <label class=\"mj-tgp__label\" for=\"tgp-desc\">What this step does</label>\n <textarea id=\"tgp-desc\" class=\"mj-textarea\" rows=\"3\"\n [(ngModel)]=\"Draft.description\" [disabled]=\"ReadOnly\" (blur)=\"Commit()\"></textarea>\n\n <label class=\"mj-tgp__label\">Who does it</label>\n <div class=\"mj-tgp__assignment\">\n <button mjButton [variant]=\"!IsHumanTask ? 'primary' : 'outline'\" size=\"sm\"\n [disabled]=\"ReadOnly\" (click)=\"SetAssignment('agent')\">\n <i class=\"fa-solid fa-robot\"></i> An agent\n </button>\n <button mjButton [variant]=\"IsHumanTask ? 'primary' : 'outline'\" size=\"sm\"\n [disabled]=\"ReadOnly\" (click)=\"SetAssignment('human')\">\n <i class=\"fa-solid fa-user-check\"></i> A person\n </button>\n </div>\n\n @if (!IsHumanTask) {\n <select class=\"mj-input\" [(ngModel)]=\"Draft.agentName\" [disabled]=\"ReadOnly\" (change)=\"Commit()\">\n @for (name of AvailableAgentNames; track name) {\n <option [value]=\"name\">{{ name }}</option>\n }\n </select>\n } @else {\n <!-- Cross-user assignment is rejected at submission until the authorization model lands\n (#3524), so the panel states the rule rather than offering a picker that would fail. -->\n <mj-alert Variant=\"info\" Size=\"sm\"\n Message=\"This step waits for you. Assigning it to someone else isn't available yet.\">\n </mj-alert>\n }\n\n @if (IncomingEdges.length > 0) {\n <label class=\"mj-tgp__label\">Runs after</label>\n @for (edge of IncomingEdges; track edge.FromTempId) {\n <div class=\"mj-tgp__edge\">\n <span class=\"mj-tgp__edge-name\"><i class=\"fa-solid fa-arrow-right-long\"></i> {{ edge.FromName }}</span>\n <!-- Leaving this empty makes the edge unconditional, which is how a fallback is written. -->\n <input class=\"mj-input mj-tgp__edge-condition\" type=\"text\"\n placeholder=\"Always — or a condition, e.g. output.severity > 3\"\n [ngModel]=\"edge.Condition\" [disabled]=\"ReadOnly\"\n (blur)=\"CommitCondition(edge.FromTempId, $any($event.target).value)\" />\n </div>\n }\n }\n }\n</div>\n"]}
|
|
1
|
+
{"version":3,"file":"task-graph-properties-panel.component.js","sourceRoot":"","sources":["../../src/lib/task-graph-properties-panel.component.ts","../../src/lib/task-graph-properties-panel.component.html"],"names":[],"mappings":"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","sourcesContent":["/**\n * @fileoverview Edits the selected task's properties, plus the graph-level traversal settings.\n *\n * Split out of the canvas component for the reason panels usually are — the canvas is about\n * *structure* (what connects to what) and this is about *content* (what a step actually does). But\n * also for a sharper reason: a host embedding the read-only viewer in a chat card or a run history\n * pane wants the graph without a form beside it, and a panel welded into the canvas cannot be\n * declined.\n *\n * Emits intent rather than mutating: the canvas component owns the spec, so every edit here leaves\n * as a request the parent applies through the same `Before*`/`After*` path a drag or a delete takes.\n * Two write paths into one spec would be two places for the veto contract to be wrong.\n *\n * @module @memberjunction/ng-task-graph-editor\n */\nimport { Component, EventEmitter, Input, Output } from '@angular/core';\nimport { ConfigOf, TaskNode, type TaskGraphSpec, type TaskGraphSpecNode, type TaskNodeBase } from '@memberjunction/ai-core-plus';\nimport { GetDependencies, GetTaskNodeType, IsAuthorableNodeType, type TaskGraphNodeType } from './task-graph-canvas-adapter';\n\n/** A requested change to one task. The parent applies it; this panel never writes. */\nexport class TaskPropertyChangeRequestedEventArgs {\n constructor(\n public readonly TempId: string,\n public readonly Next: TaskGraphSpecNode,\n ) {}\n}\n\n/** A requested change to a dependency edge's condition. */\nexport class DependencyConditionChangeRequestedEventArgs {\n constructor(\n public readonly FromTempId: string,\n public readonly ToTempId: string,\n /** Empty string clears the condition, making the edge unconditional again. */\n public readonly Condition: string,\n ) {}\n}\n\n@Component({\n standalone: false,\n selector: 'mj-task-graph-properties',\n templateUrl: './task-graph-properties-panel.component.html',\n styleUrls: ['./task-graph-properties-panel.component.css'],\n})\nexport class TaskGraphPropertiesPanelComponent {\n /** The task being edited. Null shows the empty state rather than a form bound to nothing. */\n @Input()\n public set Task(value: TaskGraphSpecNode | null) {\n this.currentTask = value;\n // A working copy, so a half-typed name never reaches the spec — and so Cancel is possible\n // at all. Editing the live node would make every keystroke an unvetoable mutation.\n this.Draft = value ? { ...value } : null;\n }\n public get Task(): TaskGraphSpecNode | null {\n return this.currentTask;\n }\n\n /** The whole graph, for resolving the selected task's incoming edges. */\n @Input() public Spec: TaskGraphSpec | null = null;\n\n /** Agent names offered in the assignment dropdown. Supplied by the host, which owns data access. */\n @Input() public AvailableAgentNames: readonly string[] = [];\n\n /** Action names offered in the assignment dropdown. Same ownership rule as `AvailableAgentNames`. */\n @Input() public AvailableActionNames: readonly string[] = [];\n\n @Input() public ReadOnly: boolean = false;\n\n @Output() public TaskPropertyChangeRequested = new EventEmitter<TaskPropertyChangeRequestedEventArgs>();\n @Output() public DependencyConditionChangeRequested = new EventEmitter<DependencyConditionChangeRequestedEventArgs>();\n\n public Draft: TaskGraphSpecNode | null = null;\n\n private currentTask: TaskGraphSpecNode | null = null;\n\n /**\n * Which of the three assignment shapes this step currently uses.\n *\n * Derived from the draft rather than stored separately: the node's own `kind` is the single\n * source of truth, and a parallel field could disagree with it.\n */\n public get Assignment(): TaskGraphNodeType {\n if (!this.Draft) return 'AgentTask';\n const type = GetTaskNodeType(this.Draft);\n // This panel edits the three authorable shapes. A display-only kind (a Prompt, a loop, an\n // external step — kinds a run can contain but nobody draws here) has no editor, so it falls\n // back rather than being mis-presented as an agent step with an agent picker.\n return IsAuthorableNodeType(type) ? type : 'AgentTask';\n }\n\n /**\n * The chosen agent, read and written through the node's configuration.\n *\n * A template cannot narrow a discriminated union, so the two-way binding goes through here\n * rather than at `Draft.configuration.agentName` — which would also be wrong the moment the\n * draft is a different kind.\n */\n public get AgentName(): string {\n return ConfigOf(this.Draft!, 'Agent')?.agentName ?? '';\n }\n public set AgentName(value: string) {\n if (this.Draft?.kind === 'Agent') {\n this.Draft = { ...this.Draft, configuration: { ...ConfigOf(this.Draft, 'Agent')!, agentName: value } };\n }\n }\n\n /** The chosen action. Same reasoning as {@link AgentName}. */\n public get ActionName(): string {\n return ConfigOf(this.Draft!, 'Action')?.actionName ?? '';\n }\n public set ActionName(value: string) {\n if (this.Draft?.kind === 'Action') {\n this.Draft = { ...this.Draft, configuration: { ...ConfigOf(this.Draft, 'Action')!, actionName: value } };\n }\n }\n\n /** True when this step waits on a person. */\n public get IsHumanTask(): boolean {\n return this.Assignment === 'HumanTask';\n }\n\n /** The edges into this task, so their conditions are editable where the step is. */\n public get IncomingEdges(): Array<{ FromTempId: string; FromName: string; Condition: string }> {\n if (!this.Draft || !this.Spec) return [];\n const nameOf = (id: string) => this.Spec!.tasks.find((t) => t.tempId === id)?.name ?? id;\n return GetDependencies(this.Draft).map((d) => ({\n FromTempId: d.tempId,\n FromName: nameOf(d.tempId),\n Condition: d.condition ?? '',\n }));\n }\n\n /**\n * Switches the step between an agent, an action and a person.\n *\n * Replacing `kind` and `configuration` together is the whole operation now. Under the old flat\n * shape this had to clear two sibling fields on every branch, and forgetting one produced an\n * `AssignmentConflict` from a gesture that looked like a simple choice — a bug the union made\n * unrepresentable rather than merely guarded.\n *\n * The previous name is carried over where it still applies, so toggling Agent → Person → Agent\n * does not silently forget what the author had chosen.\n */\n public SetAssignment(kind: TaskGraphNodeType, name?: string): void {\n if (!this.Draft || this.ReadOnly) return;\n const base: TaskNodeBase = {\n tempId: this.Draft.tempId,\n name: this.Draft.name,\n description: this.Draft.description,\n dependsOn: this.Draft.dependsOn,\n policy: this.Draft.policy,\n layout: this.Draft.layout,\n inputPayload: this.Draft.inputPayload,\n };\n switch (kind) {\n case 'HumanTask':\n this.Draft = TaskNode.Human(base, ConfigOf(this.Draft, 'Human') ?? {});\n break;\n case 'ActionTask':\n this.Draft = TaskNode.Action(base, {\n actionName: name ?? ConfigOf(this.Draft, 'Action')?.actionName ?? this.AvailableActionNames[0] ?? '',\n });\n break;\n default:\n this.Draft = TaskNode.Agent(base, {\n agentName: name ?? ConfigOf(this.Draft, 'Agent')?.agentName ?? this.AvailableAgentNames[0] ?? '',\n });\n break;\n }\n this.Commit();\n }\n\n /** Asks the parent to apply the draft. */\n public Commit(): void {\n if (!this.Draft || !this.currentTask || this.ReadOnly) return;\n this.TaskPropertyChangeRequested.emit(\n new TaskPropertyChangeRequestedEventArgs(this.currentTask.tempId, { ...this.Draft }),\n );\n }\n\n /** Asks the parent to change (or, with an empty string, clear) an edge's condition. */\n public CommitCondition(fromTempId: string, condition: string): void {\n if (!this.Draft || this.ReadOnly) return;\n this.DependencyConditionChangeRequested.emit(\n new DependencyConditionChangeRequestedEventArgs(fromTempId, this.Draft.tempId, condition),\n );\n }\n}\n","<div class=\"mj-tgp\">\n @if (!Draft) {\n <mj-empty-state\n Icon=\"fa-hand-pointer\"\n Title=\"No step selected\"\n Message=\"Pick a step on the canvas to edit what it does.\">\n </mj-empty-state>\n } @else {\n <label class=\"mj-tgp__label\" for=\"tgp-name\">Name</label>\n <input id=\"tgp-name\" class=\"mj-input\" type=\"text\"\n [(ngModel)]=\"Draft.name\" [disabled]=\"ReadOnly\" (blur)=\"Commit()\" />\n\n <label class=\"mj-tgp__label\" for=\"tgp-desc\">What this step does</label>\n <textarea id=\"tgp-desc\" class=\"mj-textarea\" rows=\"3\"\n [(ngModel)]=\"Draft.description\" [disabled]=\"ReadOnly\" (blur)=\"Commit()\"></textarea>\n\n <label class=\"mj-tgp__label\">Who does it</label>\n <!-- Three, because TaskGraphSpecNode has exactly three mutually-exclusive assignment shapes:\n agentName, actionName, assignToUser. -->\n <div class=\"mj-tgp__assignment\">\n <button mjButton [variant]=\"Assignment === 'AgentTask' ? 'primary' : 'outline'\" size=\"sm\"\n [disabled]=\"ReadOnly\" (click)=\"SetAssignment('AgentTask')\">\n <i class=\"fa-solid fa-robot\"></i> An agent\n </button>\n <button mjButton [variant]=\"Assignment === 'ActionTask' ? 'primary' : 'outline'\" size=\"sm\"\n [disabled]=\"ReadOnly\" (click)=\"SetAssignment('ActionTask')\">\n <i class=\"fa-solid fa-bolt\"></i> An action\n </button>\n <button mjButton [variant]=\"Assignment === 'HumanTask' ? 'primary' : 'outline'\" size=\"sm\"\n [disabled]=\"ReadOnly\" (click)=\"SetAssignment('HumanTask')\">\n <i class=\"fa-solid fa-user-check\"></i> A person\n </button>\n </div>\n\n @switch (Assignment) {\n @case ('AgentTask') {\n @if (AvailableAgentNames.length > 0) {\n <select class=\"mj-input\" aria-label=\"Agent\" [(ngModel)]=\"AgentName\" [disabled]=\"ReadOnly\" (change)=\"Commit()\">\n @for (name of AvailableAgentNames; track name) {\n <option [value]=\"name\">{{ name }}</option>\n }\n </select>\n } @else {\n <!-- Says the list is empty rather than rendering an empty dropdown, which reads as a bug. -->\n <mj-alert Variant=\"warning\" Size=\"sm\"\n Message=\"No agents are available to assign. This step will not run until one is chosen.\">\n </mj-alert>\n }\n }\n @case ('ActionTask') {\n @if (AvailableActionNames.length > 0) {\n <select class=\"mj-input\" aria-label=\"Action\" [(ngModel)]=\"ActionName\" [disabled]=\"ReadOnly\" (change)=\"Commit()\">\n @for (name of AvailableActionNames; track name) {\n <option [value]=\"name\">{{ name }}</option>\n }\n </select>\n } @else {\n <mj-alert Variant=\"warning\" Size=\"sm\"\n Message=\"No actions are available to assign. This step will not run until one is chosen.\">\n </mj-alert>\n }\n }\n @default {\n <!-- Cross-user assignment is rejected at submission until the authorization model lands\n (#3524), so the panel states the rule rather than offering a picker that would fail. -->\n <mj-alert Variant=\"info\" Size=\"sm\"\n Message=\"This step waits for you. Assigning it to someone else isn't available yet.\">\n </mj-alert>\n }\n }\n\n @if (IncomingEdges.length > 0) {\n <label class=\"mj-tgp__label\">Runs after</label>\n @for (edge of IncomingEdges; track edge.FromTempId) {\n <div class=\"mj-tgp__edge\">\n <span class=\"mj-tgp__edge-name\"><i class=\"fa-solid fa-arrow-right-long\"></i> {{ edge.FromName }}</span>\n <!-- Leaving this empty makes the edge unconditional, which is how a fallback is written. -->\n <input class=\"mj-input mj-tgp__edge-condition\" type=\"text\"\n placeholder=\"Always — or a condition, e.g. output.severity > 3\"\n [ngModel]=\"edge.Condition\" [disabled]=\"ReadOnly\"\n (blur)=\"CommitCondition(edge.FromTempId, $any($event.target).value)\" />\n </div>\n }\n }\n }\n</div>\n"]}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* One persisted bag for the run-view chrome the person can resize.
|
|
3
|
+
*
|
|
4
|
+
* A single `MJ: User Settings` key holds a JSON object so adding a field later is a merge, not a
|
|
5
|
+
* new key — and every field is typed. Size and openness stay separate properties on purpose:
|
|
6
|
+
* minimizing the data pane and opening it again must restore the width they dragged to.
|
|
7
|
+
*/
|
|
8
|
+
import { type PaneSizePair } from './pane-split';
|
|
9
|
+
export declare const TASK_GRAPH_RUN_PREFS_KEY = "mj.taskGraphRun.prefs.v1";
|
|
10
|
+
export interface TaskGraphRunPrefs {
|
|
11
|
+
/** Left invocation / output pane is expanded. Default minimized. */
|
|
12
|
+
InvocationOpen: boolean;
|
|
13
|
+
/** `[invocation, canvas]` percentages while the left pane is open. */
|
|
14
|
+
InvocationSplit: PaneSizePair;
|
|
15
|
+
}
|
|
16
|
+
export declare const DEFAULT_TASK_GRAPH_RUN_PREFS: TaskGraphRunPrefs;
|
|
17
|
+
export type TaskGraphRunPrefsSettingsPort = {
|
|
18
|
+
Get(key: string): string | undefined;
|
|
19
|
+
Set(key: string, value: string): void;
|
|
20
|
+
};
|
|
21
|
+
/** Merge a stored bag onto defaults. Unknown or partial JSON is never fatal. */
|
|
22
|
+
export declare function ParseTaskGraphRunPrefs(raw: string | undefined): TaskGraphRunPrefs;
|
|
23
|
+
export declare function SerializeTaskGraphRunPrefs(prefs: TaskGraphRunPrefs): string;
|
|
24
|
+
/** Restore / write the bag through a settings port so the rules can be unit-tested. */
|
|
25
|
+
export declare class TaskGraphRunPrefsStore {
|
|
26
|
+
private readonly settings;
|
|
27
|
+
Value: TaskGraphRunPrefs;
|
|
28
|
+
constructor(settings: TaskGraphRunPrefsSettingsPort);
|
|
29
|
+
Restore(): void;
|
|
30
|
+
SetInvocationOpen(open: boolean): void;
|
|
31
|
+
SetInvocationSplit(pair: PaneSizePair): void;
|
|
32
|
+
private persist;
|
|
33
|
+
}
|
|
34
|
+
//# sourceMappingURL=task-graph-run-prefs.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"task-graph-run-prefs.d.ts","sourceRoot":"","sources":["../../src/lib/task-graph-run-prefs.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AACH,OAAO,EAAkB,KAAK,YAAY,EAAE,MAAM,cAAc,CAAC;AAEjE,eAAO,MAAM,wBAAwB,6BAA6B,CAAC;AAEnE,MAAM,WAAW,iBAAiB;IAC9B,oEAAoE;IACpE,cAAc,EAAE,OAAO,CAAC;IACxB,sEAAsE;IACtE,eAAe,EAAE,YAAY,CAAC;CACjC;AAED,eAAO,MAAM,4BAA4B,EAAE,iBAG1C,CAAC;AAEF,MAAM,MAAM,6BAA6B,GAAG;IACxC,GAAG,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,CAAC;IACrC,GAAG,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;CACzC,CAAC;AASF,gFAAgF;AAChF,wBAAgB,sBAAsB,CAAC,GAAG,EAAE,MAAM,GAAG,SAAS,GAAG,iBAAiB,CAgBjF;AAED,wBAAgB,0BAA0B,CAAC,KAAK,EAAE,iBAAiB,GAAG,MAAM,CAE3E;AAED,uFAAuF;AACvF,qBAAa,sBAAsB;IAGnB,OAAO,CAAC,QAAQ,CAAC,QAAQ;IAF9B,KAAK,EAAE,iBAAiB,CAAkB;gBAEpB,QAAQ,EAAE,6BAA6B;IAE7D,OAAO,IAAI,IAAI;IAIf,iBAAiB,CAAC,IAAI,EAAE,OAAO,GAAG,IAAI;IAKtC,kBAAkB,CAAC,IAAI,EAAE,YAAY,GAAG,IAAI;IAKnD,OAAO,CAAC,OAAO;CAGlB"}
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* One persisted bag for the run-view chrome the person can resize.
|
|
3
|
+
*
|
|
4
|
+
* A single `MJ: User Settings` key holds a JSON object so adding a field later is a merge, not a
|
|
5
|
+
* new key — and every field is typed. Size and openness stay separate properties on purpose:
|
|
6
|
+
* minimizing the data pane and opening it again must restore the width they dragged to.
|
|
7
|
+
*/
|
|
8
|
+
import { AsPaneSizePair } from './pane-split';
|
|
9
|
+
export const TASK_GRAPH_RUN_PREFS_KEY = 'mj.taskGraphRun.prefs.v1';
|
|
10
|
+
export const DEFAULT_TASK_GRAPH_RUN_PREFS = {
|
|
11
|
+
InvocationOpen: false,
|
|
12
|
+
InvocationSplit: [22, 78],
|
|
13
|
+
};
|
|
14
|
+
function copyDefaults() {
|
|
15
|
+
return {
|
|
16
|
+
InvocationOpen: DEFAULT_TASK_GRAPH_RUN_PREFS.InvocationOpen,
|
|
17
|
+
InvocationSplit: [...DEFAULT_TASK_GRAPH_RUN_PREFS.InvocationSplit],
|
|
18
|
+
};
|
|
19
|
+
}
|
|
20
|
+
/** Merge a stored bag onto defaults. Unknown or partial JSON is never fatal. */
|
|
21
|
+
export function ParseTaskGraphRunPrefs(raw) {
|
|
22
|
+
const next = copyDefaults();
|
|
23
|
+
if (!raw)
|
|
24
|
+
return next;
|
|
25
|
+
try {
|
|
26
|
+
const parsed = JSON.parse(raw);
|
|
27
|
+
if (!parsed || typeof parsed !== 'object' || Array.isArray(parsed))
|
|
28
|
+
return next;
|
|
29
|
+
const obj = parsed;
|
|
30
|
+
if (typeof obj['InvocationOpen'] === 'boolean') {
|
|
31
|
+
next.InvocationOpen = obj['InvocationOpen'];
|
|
32
|
+
}
|
|
33
|
+
const split = AsPaneSizePair(obj['InvocationSplit']);
|
|
34
|
+
if (split)
|
|
35
|
+
next.InvocationSplit = split;
|
|
36
|
+
return next;
|
|
37
|
+
}
|
|
38
|
+
catch {
|
|
39
|
+
return next;
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
export function SerializeTaskGraphRunPrefs(prefs) {
|
|
43
|
+
return JSON.stringify(prefs);
|
|
44
|
+
}
|
|
45
|
+
/** Restore / write the bag through a settings port so the rules can be unit-tested. */
|
|
46
|
+
export class TaskGraphRunPrefsStore {
|
|
47
|
+
settings;
|
|
48
|
+
Value = copyDefaults();
|
|
49
|
+
constructor(settings) {
|
|
50
|
+
this.settings = settings;
|
|
51
|
+
}
|
|
52
|
+
Restore() {
|
|
53
|
+
this.Value = ParseTaskGraphRunPrefs(this.settings.Get(TASK_GRAPH_RUN_PREFS_KEY));
|
|
54
|
+
}
|
|
55
|
+
SetInvocationOpen(open) {
|
|
56
|
+
this.Value = { ...this.Value, InvocationOpen: open };
|
|
57
|
+
this.persist();
|
|
58
|
+
}
|
|
59
|
+
SetInvocationSplit(pair) {
|
|
60
|
+
this.Value = { ...this.Value, InvocationSplit: pair };
|
|
61
|
+
this.persist();
|
|
62
|
+
}
|
|
63
|
+
persist() {
|
|
64
|
+
this.settings.Set(TASK_GRAPH_RUN_PREFS_KEY, SerializeTaskGraphRunPrefs(this.Value));
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
//# sourceMappingURL=task-graph-run-prefs.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"task-graph-run-prefs.js","sourceRoot":"","sources":["../../src/lib/task-graph-run-prefs.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AACH,OAAO,EAAE,cAAc,EAAqB,MAAM,cAAc,CAAC;AAEjE,MAAM,CAAC,MAAM,wBAAwB,GAAG,0BAA0B,CAAC;AASnE,MAAM,CAAC,MAAM,4BAA4B,GAAsB;IAC3D,cAAc,EAAE,KAAK;IACrB,eAAe,EAAE,CAAC,EAAE,EAAE,EAAE,CAAC;CAC5B,CAAC;AAOF,SAAS,YAAY;IACjB,OAAO;QACH,cAAc,EAAE,4BAA4B,CAAC,cAAc;QAC3D,eAAe,EAAE,CAAC,GAAG,4BAA4B,CAAC,eAAe,CAAC;KACrE,CAAC;AACN,CAAC;AAED,gFAAgF;AAChF,MAAM,UAAU,sBAAsB,CAAC,GAAuB;IAC1D,MAAM,IAAI,GAAG,YAAY,EAAE,CAAC;IAC5B,IAAI,CAAC,GAAG;QAAE,OAAO,IAAI,CAAC;IACtB,IAAI,CAAC;QACD,MAAM,MAAM,GAAY,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;QACxC,IAAI,CAAC,MAAM,IAAI,OAAO,MAAM,KAAK,QAAQ,IAAI,KAAK,CAAC,OAAO,CAAC,MAAM,CAAC;YAAE,OAAO,IAAI,CAAC;QAChF,MAAM,GAAG,GAAG,MAAiC,CAAC;QAC9C,IAAI,OAAO,GAAG,CAAC,gBAAgB,CAAC,KAAK,SAAS,EAAE,CAAC;YAC7C,IAAI,CAAC,cAAc,GAAG,GAAG,CAAC,gBAAgB,CAAC,CAAC;QAChD,CAAC;QACD,MAAM,KAAK,GAAG,cAAc,CAAC,GAAG,CAAC,iBAAiB,CAAC,CAAC,CAAC;QACrD,IAAI,KAAK;YAAE,IAAI,CAAC,eAAe,GAAG,KAAK,CAAC;QACxC,OAAO,IAAI,CAAC;IAChB,CAAC;IAAC,MAAM,CAAC;QACL,OAAO,IAAI,CAAC;IAChB,CAAC;AACL,CAAC;AAED,MAAM,UAAU,0BAA0B,CAAC,KAAwB;IAC/D,OAAO,IAAI,CAAC,SAAS,CAAC,KAAK,CAAC,CAAC;AACjC,CAAC;AAED,uFAAuF;AACvF,MAAM,OAAO,sBAAsB;IAGF;IAFtB,KAAK,GAAsB,YAAY,EAAE,CAAC;IAEjD,YAA6B,QAAuC;QAAvC,aAAQ,GAAR,QAAQ,CAA+B;IAAG,CAAC;IAEjE,OAAO;QACV,IAAI,CAAC,KAAK,GAAG,sBAAsB,CAAC,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,wBAAwB,CAAC,CAAC,CAAC;IACrF,CAAC;IAEM,iBAAiB,CAAC,IAAa;QAClC,IAAI,CAAC,KAAK,GAAG,EAAE,GAAG,IAAI,CAAC,KAAK,EAAE,cAAc,EAAE,IAAI,EAAE,CAAC;QACrD,IAAI,CAAC,OAAO,EAAE,CAAC;IACnB,CAAC;IAEM,kBAAkB,CAAC,IAAkB;QACxC,IAAI,CAAC,KAAK,GAAG,EAAE,GAAG,IAAI,CAAC,KAAK,EAAE,eAAe,EAAE,IAAI,EAAE,CAAC;QACtD,IAAI,CAAC,OAAO,EAAE,CAAC;IACnB,CAAC;IAEO,OAAO;QACX,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,wBAAwB,EAAE,0BAA0B,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC;IACxF,CAAC;CACJ","sourcesContent":["/**\n * One persisted bag for the run-view chrome the person can resize.\n *\n * A single `MJ: User Settings` key holds a JSON object so adding a field later is a merge, not a\n * new key — and every field is typed. Size and openness stay separate properties on purpose:\n * minimizing the data pane and opening it again must restore the width they dragged to.\n */\nimport { AsPaneSizePair, type PaneSizePair } from './pane-split';\n\nexport const TASK_GRAPH_RUN_PREFS_KEY = 'mj.taskGraphRun.prefs.v1';\n\nexport interface TaskGraphRunPrefs {\n /** Left invocation / output pane is expanded. Default minimized. */\n InvocationOpen: boolean;\n /** `[invocation, canvas]` percentages while the left pane is open. */\n InvocationSplit: PaneSizePair;\n}\n\nexport const DEFAULT_TASK_GRAPH_RUN_PREFS: TaskGraphRunPrefs = {\n InvocationOpen: false,\n InvocationSplit: [22, 78],\n};\n\nexport type TaskGraphRunPrefsSettingsPort = {\n Get(key: string): string | undefined;\n Set(key: string, value: string): void;\n};\n\nfunction copyDefaults(): TaskGraphRunPrefs {\n return {\n InvocationOpen: DEFAULT_TASK_GRAPH_RUN_PREFS.InvocationOpen,\n InvocationSplit: [...DEFAULT_TASK_GRAPH_RUN_PREFS.InvocationSplit],\n };\n}\n\n/** Merge a stored bag onto defaults. Unknown or partial JSON is never fatal. */\nexport function ParseTaskGraphRunPrefs(raw: string | undefined): TaskGraphRunPrefs {\n const next = copyDefaults();\n if (!raw) return next;\n try {\n const parsed: unknown = JSON.parse(raw);\n if (!parsed || typeof parsed !== 'object' || Array.isArray(parsed)) return next;\n const obj = parsed as Record<string, unknown>;\n if (typeof obj['InvocationOpen'] === 'boolean') {\n next.InvocationOpen = obj['InvocationOpen'];\n }\n const split = AsPaneSizePair(obj['InvocationSplit']);\n if (split) next.InvocationSplit = split;\n return next;\n } catch {\n return next;\n }\n}\n\nexport function SerializeTaskGraphRunPrefs(prefs: TaskGraphRunPrefs): string {\n return JSON.stringify(prefs);\n}\n\n/** Restore / write the bag through a settings port so the rules can be unit-tested. */\nexport class TaskGraphRunPrefsStore {\n public Value: TaskGraphRunPrefs = copyDefaults();\n\n constructor(private readonly settings: TaskGraphRunPrefsSettingsPort) {}\n\n public Restore(): void {\n this.Value = ParseTaskGraphRunPrefs(this.settings.Get(TASK_GRAPH_RUN_PREFS_KEY));\n }\n\n public SetInvocationOpen(open: boolean): void {\n this.Value = { ...this.Value, InvocationOpen: open };\n this.persist();\n }\n\n public SetInvocationSplit(pair: PaneSizePair): void {\n this.Value = { ...this.Value, InvocationSplit: pair };\n this.persist();\n }\n\n private persist(): void {\n this.settings.Set(TASK_GRAPH_RUN_PREFS_KEY, SerializeTaskGraphRunPrefs(this.Value));\n }\n}\n"]}
|