@memberjunction/ng-task-graph-editor 6.1.0-edge.1 → 6.1.0-edge.2
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/lib/task-graph-canvas-adapter.d.ts +102 -5
- package/dist/lib/task-graph-canvas-adapter.d.ts.map +1 -1
- package/dist/lib/task-graph-canvas-adapter.js +154 -18
- package/dist/lib/task-graph-canvas-adapter.js.map +1 -1
- package/dist/lib/task-graph-editor.component.d.ts +106 -4
- package/dist/lib/task-graph-editor.component.d.ts.map +1 -1
- package/dist/lib/task-graph-editor.component.js +246 -24
- package/dist/lib/task-graph-editor.component.js.map +1 -1
- package/dist/lib/task-graph-editor.module.d.ts +6 -5
- package/dist/lib/task-graph-editor.module.d.ts.map +1 -1
- package/dist/lib/task-graph-editor.module.js +4 -3
- 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-view.component.d.ts +113 -0
- package/dist/lib/task-graph-run-view.component.d.ts.map +1 -0
- package/dist/lib/task-graph-run-view.component.js +289 -0
- package/dist/lib/task-graph-run-view.component.js.map +1 -0
- package/dist/public-api.d.ts +1 -0
- package/dist/public-api.d.ts.map +1 -1
- package/dist/public-api.js +1 -0
- package/dist/public-api.js.map +1 -1
- package/package.json +9 -8
|
@@ -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,113 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fileoverview Watching a graph that is running, on the canvas its author drew on.
|
|
3
|
+
*
|
|
4
|
+
* **Why this is a component and not three.** A run needs rendering in at least three places — inside
|
|
5
|
+
* an Agent Run, inside the test harness, and on a standalone workflow-runs screen — and every one of
|
|
6
|
+
* them wants the identical thing: the graph, with live status, laid out legibly, with a node you can
|
|
7
|
+
* click. Three implementations would be three chances to render the same run differently, and the
|
|
8
|
+
* one that matters most (is that branch grey because it was *not taken*, or because it *broke*?) is
|
|
9
|
+
* exactly the distinction a second implementation gets wrong.
|
|
10
|
+
*
|
|
11
|
+
* **What it owns and what it doesn't.** It owns data acquisition — reading `MJ: Tasks` and
|
|
12
|
+
* `MJ: Task Dependencies` through the host's provider — and geometry. It does not navigate: a
|
|
13
|
+
* widgets-layer component cannot know whether it sits inside Explorer, so selecting a node emits an
|
|
14
|
+
* event and the host decides what "open the agent run" means. That boundary is the whole reason
|
|
15
|
+
* this can live beside the editor rather than in Explorer.
|
|
16
|
+
*
|
|
17
|
+
* @module @memberjunction/ng-task-graph-editor
|
|
18
|
+
*/
|
|
19
|
+
import { ChangeDetectorRef, EventEmitter, OnDestroy } from '@angular/core';
|
|
20
|
+
import { BaseAngularComponent } from '@memberjunction/ng-base-types';
|
|
21
|
+
import { MJTaskEntity } from '@memberjunction/core-entities';
|
|
22
|
+
import { type GraphNodePosition, type TaskGraphSpec } from '@memberjunction/ai-core-plus';
|
|
23
|
+
import type { TaskGraphRuntimeStatus } from './task-graph-canvas-adapter';
|
|
24
|
+
import type { TaskGraphSelectionChangedEventArgs } from './task-graph-editor-events';
|
|
25
|
+
import * as i0 from "@angular/core";
|
|
26
|
+
/** What the host learns when someone clicks a step. */
|
|
27
|
+
export type TaskGraphRunNodeSelectedEvent = {
|
|
28
|
+
/** The `MJ: Tasks` row id. */
|
|
29
|
+
TaskID: string;
|
|
30
|
+
Task: MJTaskEntity | null;
|
|
31
|
+
};
|
|
32
|
+
export declare class TaskGraphRunViewComponent extends BaseAngularComponent implements OnDestroy {
|
|
33
|
+
private cdr;
|
|
34
|
+
/**
|
|
35
|
+
* The graph to watch — the parent `MJ: Tasks` row that represents it.
|
|
36
|
+
*
|
|
37
|
+
* Setter-based rather than `ngOnChanges`, matching the editor beside it: the reaction is
|
|
38
|
+
* explicit and costs nothing on unrelated change-detection passes.
|
|
39
|
+
*/
|
|
40
|
+
set ParentTaskID(value: string | null);
|
|
41
|
+
get ParentTaskID(): string | null;
|
|
42
|
+
/** Name shown on the compiled graph. Purely cosmetic; the rows carry the truth. */
|
|
43
|
+
WorkflowName: string;
|
|
44
|
+
/**
|
|
45
|
+
* Keep re-reading while the graph is still moving.
|
|
46
|
+
*
|
|
47
|
+
* Off by default: most hosts show a finished run, and a component that polls by default would
|
|
48
|
+
* have every historical run quietly issuing queries forever.
|
|
49
|
+
*/
|
|
50
|
+
LiveUpdates: boolean;
|
|
51
|
+
/** How often to re-read while live. Seconds, not milliseconds — this is a human-scale view. */
|
|
52
|
+
PollIntervalSeconds: number;
|
|
53
|
+
/** Height of the canvas. Hosts embed this in very different amounts of space. */
|
|
54
|
+
Height: string;
|
|
55
|
+
NodeSelected: EventEmitter<TaskGraphRunNodeSelectedEvent>;
|
|
56
|
+
/** Emitted once, when every step has reached a terminal status. */
|
|
57
|
+
Settled: EventEmitter<void>;
|
|
58
|
+
Spec: TaskGraphSpec | null;
|
|
59
|
+
RuntimeStatus: TaskGraphRuntimeStatus | null;
|
|
60
|
+
Positions: Map<string, GraphNodePosition>;
|
|
61
|
+
IsLoading: boolean;
|
|
62
|
+
ErrorMessage: string | null;
|
|
63
|
+
/** Rows by id, so a selection event can hand the host the whole task rather than an id. */
|
|
64
|
+
private taskByID;
|
|
65
|
+
private parentTaskID;
|
|
66
|
+
private pollTimer;
|
|
67
|
+
private destroyed;
|
|
68
|
+
constructor(cdr: ChangeDetectorRef);
|
|
69
|
+
ngOnDestroy(): void;
|
|
70
|
+
/** Steps in a terminal state, for the host's summary line. */
|
|
71
|
+
get CompletedCount(): number;
|
|
72
|
+
get TotalCount(): number;
|
|
73
|
+
get SkippedCount(): number;
|
|
74
|
+
/**
|
|
75
|
+
* A node was selected on the canvas.
|
|
76
|
+
*
|
|
77
|
+
* The projected `tempId` IS the task id, so the row lookup is exact — and handing the host the
|
|
78
|
+
* whole task rather than an id spares every host from re-reading a row this component already
|
|
79
|
+
* holds.
|
|
80
|
+
*/
|
|
81
|
+
OnSelectionChanged(args: TaskGraphSelectionChangedEventArgs): void;
|
|
82
|
+
/**
|
|
83
|
+
* Reads the graph and projects it onto the canvas.
|
|
84
|
+
*
|
|
85
|
+
* `BypassCache` throughout: a run view exists to show what is true *now*, and the whole point of
|
|
86
|
+
* the poll is to see a status that changed a second ago. A cached read would render a stale graph
|
|
87
|
+
* that looks authoritative.
|
|
88
|
+
*/
|
|
89
|
+
private load;
|
|
90
|
+
/** Rows → spec + runtime + geometry. */
|
|
91
|
+
private project;
|
|
92
|
+
/**
|
|
93
|
+
* The author's arrangement where there is one, a computed layout everywhere else.
|
|
94
|
+
*
|
|
95
|
+
* Mixing the two per-node rather than choosing one for the whole graph: a workflow whose author
|
|
96
|
+
* positioned some steps and left others where they fell should keep the positions they chose.
|
|
97
|
+
* A wholly unpositioned graph — the normal case for anything an agent emitted — is laid out
|
|
98
|
+
* entirely by the algorithm.
|
|
99
|
+
*/
|
|
100
|
+
private resolvePositions;
|
|
101
|
+
private isSettled;
|
|
102
|
+
private schedulePoll;
|
|
103
|
+
private stopPolling;
|
|
104
|
+
private fail;
|
|
105
|
+
/** Canvas extent, so a host can size its container to the graph rather than guessing. */
|
|
106
|
+
get GraphBounds(): {
|
|
107
|
+
Width: number;
|
|
108
|
+
Height: number;
|
|
109
|
+
};
|
|
110
|
+
static ɵfac: i0.ɵɵFactoryDeclaration<TaskGraphRunViewComponent, never>;
|
|
111
|
+
static ɵcmp: i0.ɵɵComponentDeclaration<TaskGraphRunViewComponent, "mj-task-graph-run-view", 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; }; }, { "NodeSelected": "NodeSelected"; "Settled": "Settled"; }, never, never, false, never>;
|
|
112
|
+
}
|
|
113
|
+
//# sourceMappingURL=task-graph-run-view.component.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"task-graph-run-view.component.d.ts","sourceRoot":"","sources":["../../src/lib/task-graph-run-view.component.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;GAiBG;AACH,OAAO,EAEH,iBAAiB,EAEjB,YAAY,EAEZ,SAAS,EAEZ,MAAM,eAAe,CAAC;AACvB,OAAO,EAAE,oBAAoB,EAAE,MAAM,+BAA+B,CAAC;AAErE,OAAO,EAAE,YAAY,EAA0B,MAAM,+BAA+B,CAAC;AACrF,OAAO,EAKH,KAAK,iBAAiB,EACtB,KAAK,aAAa,EACrB,MAAM,8BAA8B,CAAC;AAEtC,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,6BAA6B,CAAC;AAC1E,OAAO,KAAK,EAAE,kCAAkC,EAAE,MAAM,4BAA4B,CAAC;;AAErF,uDAAuD;AACvD,MAAM,MAAM,6BAA6B,GAAG;IACxC,8BAA8B;IAC9B,MAAM,EAAE,MAAM,CAAC;IACf,IAAI,EAAE,YAAY,GAAG,IAAI,CAAC;CAC7B,CAAC;AAKF,qBAOa,yBAA0B,SAAQ,oBAAqB,YAAW,SAAS;IAkDxE,OAAO,CAAC,GAAG;IAjDvB;;;;;OAKG;IACH,IACW,YAAY,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI,EAI3C;IACD,IAAW,YAAY,IAAI,MAAM,GAAG,IAAI,CAEvC;IAED,mFAAmF;IACnE,YAAY,EAAE,MAAM,CAAc;IAElD;;;;;OAKG;IACa,WAAW,EAAE,OAAO,CAAS;IAE7C,+FAA+F;IAC/E,mBAAmB,EAAE,MAAM,CAAK;IAEhD,iFAAiF;IACjE,MAAM,EAAE,MAAM,CAAW;IAExB,YAAY,8CAAqD;IAClF,mEAAmE;IAClD,OAAO,qBAA4B;IAE7C,IAAI,EAAE,aAAa,GAAG,IAAI,CAAQ;IAClC,aAAa,EAAE,sBAAsB,GAAG,IAAI,CAAQ;IACpD,SAAS,EAAE,GAAG,CAAC,MAAM,EAAE,iBAAiB,CAAC,CAAa;IACtD,SAAS,UAAS;IAClB,YAAY,EAAE,MAAM,GAAG,IAAI,CAAQ;IAE1C,2FAA2F;IAC3F,OAAO,CAAC,QAAQ,CAAmC;IACnD,OAAO,CAAC,YAAY,CAAuB;IAC3C,OAAO,CAAC,SAAS,CAA8C;IAC/D,OAAO,CAAC,SAAS,CAAS;gBAEN,GAAG,EAAE,iBAAiB;IAInC,WAAW,IAAI,IAAI;IAK1B,8DAA8D;IAC9D,IAAW,cAAc,IAAI,MAAM,CAElC;IAED,IAAW,UAAU,IAAI,MAAM,CAE9B;IAED,IAAW,YAAY,IAAI,MAAM,CAEhC;IAED;;;;;;OAMG;IACI,kBAAkB,CAAC,IAAI,EAAE,kCAAkC,GAAG,IAAI;IAMzE;;;;;;OAMG;YACW,IAAI;IA0DlB,wCAAwC;IACxC,OAAO,CAAC,OAAO;IAef;;;;;;;OAOG;IACH,OAAO,CAAC,gBAAgB;IAgBxB,OAAO,CAAC,SAAS;IAIjB,OAAO,CAAC,YAAY;IAIpB,OAAO,CAAC,WAAW;IAOnB,OAAO,CAAC,IAAI;IAMZ,yFAAyF;IACzF,IAAW,WAAW,IAAI;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAA;KAAE,CAG1D;yCAvNQ,yBAAyB;2CAAzB,yBAAyB;CAwNrC"}
|