@memberjunction/ng-flow-editor 6.1.0-edge.2 → 6.1.0-edge.4
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/dist/lib/components/flow-editor.component.d.ts +27 -4
- package/dist/lib/components/flow-editor.component.d.ts.map +1 -1
- package/dist/lib/components/flow-editor.component.js +281 -157
- package/dist/lib/components/flow-editor.component.js.map +1 -1
- package/dist/lib/components/flow-node.component.d.ts +5 -0
- package/dist/lib/components/flow-node.component.d.ts.map +1 -1
- package/dist/lib/components/flow-node.component.js +79 -44
- package/dist/lib/components/flow-node.component.js.map +1 -1
- package/dist/lib/components/flow-toolbar.component.d.ts +3 -1
- package/dist/lib/components/flow-toolbar.component.d.ts.map +1 -1
- package/dist/lib/components/flow-toolbar.component.js +32 -4
- package/dist/lib/components/flow-toolbar.component.js.map +1 -1
- package/dist/lib/interfaces/flow-types.d.ts +52 -3
- package/dist/lib/interfaces/flow-types.d.ts.map +1 -1
- package/dist/lib/interfaces/flow-types.js +33 -1
- package/dist/lib/interfaces/flow-types.js.map +1 -1
- package/package.json +10 -10
|
@@ -3,7 +3,7 @@ import * as i0 from "@angular/core";
|
|
|
3
3
|
import * as i1 from "@angular/common";
|
|
4
4
|
import * as i2 from "@foblex/flow";
|
|
5
5
|
function FlowNodeComponent_Conditional_0_Template(rf, ctx) { if (rf & 1) {
|
|
6
|
-
i0.ɵɵelement(0, "div",
|
|
6
|
+
i0.ɵɵelement(0, "div", 20);
|
|
7
7
|
} if (rf & 2) {
|
|
8
8
|
const ctx_r0 = i0.ɵɵnextContext();
|
|
9
9
|
i0.ɵɵclassMap("mj-flow-node-port--" + ctx_r0.inputPort.Side);
|
|
@@ -16,7 +16,7 @@ function FlowNodeComponent_Conditional_5_Template(rf, ctx) { if (rf & 1) {
|
|
|
16
16
|
i0.ɵɵproperty("src", ctx_r0.logoURL, i0.ɵɵsanitizeUrl)("alt", ctx_r0.Node.Label);
|
|
17
17
|
} }
|
|
18
18
|
function FlowNodeComponent_Conditional_6_Template(rf, ctx) { if (rf & 1) {
|
|
19
|
-
i0.ɵɵelement(0, "i",
|
|
19
|
+
i0.ɵɵelement(0, "i", 21);
|
|
20
20
|
} if (rf & 2) {
|
|
21
21
|
const ctx_r0 = i0.ɵɵnextContext();
|
|
22
22
|
i0.ɵɵstyleProp("color", ctx_r0.headerColor);
|
|
@@ -28,7 +28,7 @@ function FlowNodeComponent_Conditional_10_Template(rf, ctx) { if (rf & 1) {
|
|
|
28
28
|
i0.ɵɵelementEnd();
|
|
29
29
|
} }
|
|
30
30
|
function FlowNodeComponent_Conditional_11_Template(rf, ctx) { if (rf & 1) {
|
|
31
|
-
i0.ɵɵelement(0, "i",
|
|
31
|
+
i0.ɵɵelement(0, "i", 22);
|
|
32
32
|
} if (rf & 2) {
|
|
33
33
|
const ctx_r0 = i0.ɵɵnextContext();
|
|
34
34
|
i0.ɵɵclassMap("mj-flow-node-status--" + ctx_r0.statusClass);
|
|
@@ -44,7 +44,7 @@ function FlowNodeComponent_Conditional_12_Template(rf, ctx) { if (rf & 1) {
|
|
|
44
44
|
i0.ɵɵtextInterpolate1(" ", ctx_r0.Node.Subtitle, " ");
|
|
45
45
|
} }
|
|
46
46
|
function FlowNodeComponent_Conditional_15_Conditional_1_Conditional_4_Template(rf, ctx) { if (rf & 1) {
|
|
47
|
-
i0.ɵɵelementStart(0, "span",
|
|
47
|
+
i0.ɵɵelementStart(0, "span", 29);
|
|
48
48
|
i0.ɵɵtext(1);
|
|
49
49
|
i0.ɵɵelementEnd();
|
|
50
50
|
} if (rf & 2) {
|
|
@@ -53,12 +53,12 @@ function FlowNodeComponent_Conditional_15_Conditional_1_Conditional_4_Template(r
|
|
|
53
53
|
i0.ɵɵtextInterpolate1("(max ", ctx_r0.loopMaxIterations, ")");
|
|
54
54
|
} }
|
|
55
55
|
function FlowNodeComponent_Conditional_15_Conditional_1_Template(rf, ctx) { if (rf & 1) {
|
|
56
|
-
i0.ɵɵelementStart(0, "div",
|
|
57
|
-
i0.ɵɵelement(1, "i",
|
|
56
|
+
i0.ɵɵelementStart(0, "div", 23);
|
|
57
|
+
i0.ɵɵelement(1, "i", 28);
|
|
58
58
|
i0.ɵɵelementStart(2, "span");
|
|
59
59
|
i0.ɵɵtext(3);
|
|
60
60
|
i0.ɵɵelementEnd();
|
|
61
|
-
i0.ɵɵconditionalCreate(4, FlowNodeComponent_Conditional_15_Conditional_1_Conditional_4_Template, 2, 1, "span",
|
|
61
|
+
i0.ɵɵconditionalCreate(4, FlowNodeComponent_Conditional_15_Conditional_1_Conditional_4_Template, 2, 1, "span", 29);
|
|
62
62
|
i0.ɵɵelementEnd();
|
|
63
63
|
} if (rf & 2) {
|
|
64
64
|
const ctx_r0 = i0.ɵɵnextContext(2);
|
|
@@ -68,7 +68,7 @@ function FlowNodeComponent_Conditional_15_Conditional_1_Template(rf, ctx) { if (
|
|
|
68
68
|
i0.ɵɵconditional(ctx_r0.loopMaxIterations != null ? 4 : -1);
|
|
69
69
|
} }
|
|
70
70
|
function FlowNodeComponent_Conditional_15_Conditional_3_Conditional_5_Template(rf, ctx) { if (rf & 1) {
|
|
71
|
-
i0.ɵɵelementStart(0, "div",
|
|
71
|
+
i0.ɵɵelementStart(0, "div", 33);
|
|
72
72
|
i0.ɵɵtext(1);
|
|
73
73
|
i0.ɵɵelementEnd();
|
|
74
74
|
} if (rf & 2) {
|
|
@@ -78,18 +78,18 @@ function FlowNodeComponent_Conditional_15_Conditional_3_Conditional_5_Template(r
|
|
|
78
78
|
i0.ɵɵtextInterpolate1(" ", ctx_r0.loopBodyName, " ");
|
|
79
79
|
} }
|
|
80
80
|
function FlowNodeComponent_Conditional_15_Conditional_3_Conditional_6_Template(rf, ctx) { if (rf & 1) {
|
|
81
|
-
i0.ɵɵelementStart(0, "div",
|
|
81
|
+
i0.ɵɵelementStart(0, "div", 34);
|
|
82
82
|
i0.ɵɵtext(1, " Not configured ");
|
|
83
83
|
i0.ɵɵelementEnd();
|
|
84
84
|
} }
|
|
85
85
|
function FlowNodeComponent_Conditional_15_Conditional_3_Template(rf, ctx) { if (rf & 1) {
|
|
86
|
-
i0.ɵɵelementStart(0, "div",
|
|
87
|
-
i0.ɵɵelement(2, "i",
|
|
88
|
-
i0.ɵɵelementStart(3, "span",
|
|
86
|
+
i0.ɵɵelementStart(0, "div", 25)(1, "div", 30);
|
|
87
|
+
i0.ɵɵelement(2, "i", 31);
|
|
88
|
+
i0.ɵɵelementStart(3, "span", 32);
|
|
89
89
|
i0.ɵɵtext(4);
|
|
90
90
|
i0.ɵɵelementEnd()();
|
|
91
|
-
i0.ɵɵconditionalCreate(5, FlowNodeComponent_Conditional_15_Conditional_3_Conditional_5_Template, 2, 2, "div",
|
|
92
|
-
i0.ɵɵconditionalCreate(6, FlowNodeComponent_Conditional_15_Conditional_3_Conditional_6_Template, 2, 0, "div",
|
|
91
|
+
i0.ɵɵconditionalCreate(5, FlowNodeComponent_Conditional_15_Conditional_3_Conditional_5_Template, 2, 2, "div", 33);
|
|
92
|
+
i0.ɵɵconditionalCreate(6, FlowNodeComponent_Conditional_15_Conditional_3_Conditional_6_Template, 2, 0, "div", 34);
|
|
93
93
|
i0.ɵɵelementEnd();
|
|
94
94
|
} if (rf & 2) {
|
|
95
95
|
const ctx_r0 = i0.ɵɵnextContext(2);
|
|
@@ -106,15 +106,15 @@ function FlowNodeComponent_Conditional_15_Conditional_3_Template(rf, ctx) { if (
|
|
|
106
106
|
i0.ɵɵconditional(!ctx_r0.loopBodyName ? 6 : -1);
|
|
107
107
|
} }
|
|
108
108
|
function FlowNodeComponent_Conditional_15_Conditional_4_Template(rf, ctx) { if (rf & 1) {
|
|
109
|
-
i0.ɵɵelementStart(0, "div",
|
|
110
|
-
i0.ɵɵelement(1, "i",
|
|
109
|
+
i0.ɵɵelementStart(0, "div", 26);
|
|
110
|
+
i0.ɵɵelement(1, "i", 35);
|
|
111
111
|
i0.ɵɵelementStart(2, "span");
|
|
112
112
|
i0.ɵɵtext(3, "No body type selected");
|
|
113
113
|
i0.ɵɵelementEnd()();
|
|
114
114
|
} }
|
|
115
115
|
function FlowNodeComponent_Conditional_15_Conditional_5_Template(rf, ctx) { if (rf & 1) {
|
|
116
|
-
i0.ɵɵelementStart(0, "div",
|
|
117
|
-
i0.ɵɵelement(1, "i",
|
|
116
|
+
i0.ɵɵelementStart(0, "div", 27);
|
|
117
|
+
i0.ɵɵelement(1, "i", 36);
|
|
118
118
|
i0.ɵɵelementStart(2, "span");
|
|
119
119
|
i0.ɵɵtext(3);
|
|
120
120
|
i0.ɵɵelementEnd()();
|
|
@@ -125,12 +125,12 @@ function FlowNodeComponent_Conditional_15_Conditional_5_Template(rf, ctx) { if (
|
|
|
125
125
|
} }
|
|
126
126
|
function FlowNodeComponent_Conditional_15_Template(rf, ctx) { if (rf & 1) {
|
|
127
127
|
i0.ɵɵelementStart(0, "div", 13);
|
|
128
|
-
i0.ɵɵconditionalCreate(1, FlowNodeComponent_Conditional_15_Conditional_1_Template, 5, 2, "div",
|
|
129
|
-
i0.ɵɵelementStart(2, "div",
|
|
130
|
-
i0.ɵɵconditionalCreate(3, FlowNodeComponent_Conditional_15_Conditional_3_Template, 7, 8, "div",
|
|
131
|
-
i0.ɵɵconditionalCreate(4, FlowNodeComponent_Conditional_15_Conditional_4_Template, 4, 0, "div",
|
|
128
|
+
i0.ɵɵconditionalCreate(1, FlowNodeComponent_Conditional_15_Conditional_1_Template, 5, 2, "div", 23);
|
|
129
|
+
i0.ɵɵelementStart(2, "div", 24);
|
|
130
|
+
i0.ɵɵconditionalCreate(3, FlowNodeComponent_Conditional_15_Conditional_3_Template, 7, 8, "div", 25);
|
|
131
|
+
i0.ɵɵconditionalCreate(4, FlowNodeComponent_Conditional_15_Conditional_4_Template, 4, 0, "div", 26);
|
|
132
132
|
i0.ɵɵelementEnd();
|
|
133
|
-
i0.ɵɵconditionalCreate(5, FlowNodeComponent_Conditional_15_Conditional_5_Template, 4, 1, "div",
|
|
133
|
+
i0.ɵɵconditionalCreate(5, FlowNodeComponent_Conditional_15_Conditional_5_Template, 4, 1, "div", 27);
|
|
134
134
|
i0.ɵɵelementEnd();
|
|
135
135
|
} if (rf & 2) {
|
|
136
136
|
const ctx_r0 = i0.ɵɵnextContext();
|
|
@@ -147,7 +147,28 @@ function FlowNodeComponent_Conditional_15_Template(rf, ctx) { if (rf & 1) {
|
|
|
147
147
|
} }
|
|
148
148
|
function FlowNodeComponent_Conditional_16_Template(rf, ctx) { if (rf & 1) {
|
|
149
149
|
i0.ɵɵelementStart(0, "div", 14);
|
|
150
|
-
i0.ɵɵelement(1, "i",
|
|
150
|
+
i0.ɵɵelement(1, "i", 37);
|
|
151
|
+
i0.ɵɵelementStart(2, "span");
|
|
152
|
+
i0.ɵɵtext(3, "Waiting on you \u2014 Continue or Step");
|
|
153
|
+
i0.ɵɵelementEnd()();
|
|
154
|
+
} }
|
|
155
|
+
function FlowNodeComponent_Conditional_17_Template(rf, ctx) { if (rf & 1) {
|
|
156
|
+
i0.ɵɵelementStart(0, "div", 15);
|
|
157
|
+
i0.ɵɵelement(1, "i", 38);
|
|
158
|
+
i0.ɵɵelementStart(2, "span");
|
|
159
|
+
i0.ɵɵtext(3, "Running");
|
|
160
|
+
i0.ɵɵelementEnd()();
|
|
161
|
+
} }
|
|
162
|
+
function FlowNodeComponent_Conditional_18_Template(rf, ctx) { if (rf & 1) {
|
|
163
|
+
i0.ɵɵelementStart(0, "div", 16);
|
|
164
|
+
i0.ɵɵelement(1, "i", 39);
|
|
165
|
+
i0.ɵɵelementStart(2, "span");
|
|
166
|
+
i0.ɵɵtext(3, "Next \u2014 waiting for the engine");
|
|
167
|
+
i0.ɵɵelementEnd()();
|
|
168
|
+
} }
|
|
169
|
+
function FlowNodeComponent_Conditional_19_Template(rf, ctx) { if (rf & 1) {
|
|
170
|
+
i0.ɵɵelementStart(0, "div", 17);
|
|
171
|
+
i0.ɵɵelement(1, "i", 40);
|
|
151
172
|
i0.ɵɵelementStart(2, "span");
|
|
152
173
|
i0.ɵɵtext(3);
|
|
153
174
|
i0.ɵɵelementEnd()();
|
|
@@ -157,15 +178,15 @@ function FlowNodeComponent_Conditional_16_Template(rf, ctx) { if (rf & 1) {
|
|
|
157
178
|
i0.ɵɵadvance(3);
|
|
158
179
|
i0.ɵɵtextInterpolate(ctx_r0.Node.StatusMessage);
|
|
159
180
|
} }
|
|
160
|
-
function
|
|
161
|
-
i0.ɵɵelement(0, "i",
|
|
181
|
+
function FlowNodeComponent_Conditional_20_For_2_Conditional_1_Template(rf, ctx) { if (rf & 1) {
|
|
182
|
+
i0.ɵɵelement(0, "i", 31);
|
|
162
183
|
} if (rf & 2) {
|
|
163
184
|
const badge_r2 = i0.ɵɵnextContext().$implicit;
|
|
164
185
|
i0.ɵɵproperty("ngClass", badge_r2.Icon);
|
|
165
186
|
} }
|
|
166
|
-
function
|
|
167
|
-
i0.ɵɵelementStart(0, "span",
|
|
168
|
-
i0.ɵɵconditionalCreate(1,
|
|
187
|
+
function FlowNodeComponent_Conditional_20_For_2_Template(rf, ctx) { if (rf & 1) {
|
|
188
|
+
i0.ɵɵelementStart(0, "span", 42);
|
|
189
|
+
i0.ɵɵconditionalCreate(1, FlowNodeComponent_Conditional_20_For_2_Conditional_1_Template, 1, 1, "i", 31);
|
|
169
190
|
i0.ɵɵtext(2);
|
|
170
191
|
i0.ɵɵelementEnd();
|
|
171
192
|
} if (rf & 2) {
|
|
@@ -178,17 +199,17 @@ function FlowNodeComponent_Conditional_17_For_2_Template(rf, ctx) { if (rf & 1)
|
|
|
178
199
|
i0.ɵɵadvance();
|
|
179
200
|
i0.ɵɵtextInterpolate1(" ", badge_r2.Value, " ");
|
|
180
201
|
} }
|
|
181
|
-
function
|
|
182
|
-
i0.ɵɵelementStart(0, "div",
|
|
183
|
-
i0.ɵɵrepeaterCreate(1,
|
|
202
|
+
function FlowNodeComponent_Conditional_20_Template(rf, ctx) { if (rf & 1) {
|
|
203
|
+
i0.ɵɵelementStart(0, "div", 18);
|
|
204
|
+
i0.ɵɵrepeaterCreate(1, FlowNodeComponent_Conditional_20_For_2_Template, 3, 5, "span", 41, i0.ɵɵrepeaterTrackByIdentity);
|
|
184
205
|
i0.ɵɵelementEnd();
|
|
185
206
|
} if (rf & 2) {
|
|
186
207
|
const ctx_r0 = i0.ɵɵnextContext();
|
|
187
208
|
i0.ɵɵadvance();
|
|
188
209
|
i0.ɵɵrepeater(ctx_r0.Node.Badges);
|
|
189
210
|
} }
|
|
190
|
-
function
|
|
191
|
-
i0.ɵɵelement(0, "div",
|
|
211
|
+
function FlowNodeComponent_Conditional_21_Template(rf, ctx) { if (rf & 1) {
|
|
212
|
+
i0.ɵɵelement(0, "div", 43);
|
|
192
213
|
} if (rf & 2) {
|
|
193
214
|
const ctx_r0 = i0.ɵɵnextContext();
|
|
194
215
|
i0.ɵɵclassMap("mj-flow-node-port--" + ctx_r0.outputPort.Side);
|
|
@@ -230,6 +251,17 @@ export class FlowNodeComponent {
|
|
|
230
251
|
get hasStatus() {
|
|
231
252
|
return this.Node?.Status != null && this.Node.Status !== 'default';
|
|
232
253
|
}
|
|
254
|
+
/** Debugger chrome: this step is waiting for Continue / Step, not executing. */
|
|
255
|
+
get isAwaitingUser() {
|
|
256
|
+
return this.Node?.Data?.['AwaitingUser'] === true;
|
|
257
|
+
}
|
|
258
|
+
/** Prerequisites are done; the dispatcher has not claimed it yet. */
|
|
259
|
+
get isQueued() {
|
|
260
|
+
return !this.isAwaitingUser && this.Node?.Data?.['NextToRun'] === true;
|
|
261
|
+
}
|
|
262
|
+
get isExecuting() {
|
|
263
|
+
return !this.isAwaitingUser && this.Node?.Status === 'running';
|
|
264
|
+
}
|
|
233
265
|
get inputPort() {
|
|
234
266
|
const port = this.Node?.Ports?.find(p => p.Direction === 'input');
|
|
235
267
|
if (!port)
|
|
@@ -287,7 +319,7 @@ export class FlowNodeComponent {
|
|
|
287
319
|
return this.Node?.Data?.['LoopItemVariable'] ?? null;
|
|
288
320
|
}
|
|
289
321
|
static ɵfac = function FlowNodeComponent_Factory(__ngFactoryType__) { return new (__ngFactoryType__ || FlowNodeComponent)(); };
|
|
290
|
-
static ɵcmp = /*@__PURE__*/ i0.ɵɵdefineComponent({ type: FlowNodeComponent, selectors: [["mj-flow-node"]], inputs: { Node: "Node", TypeConfig: "TypeConfig", ReadOnly: "ReadOnly", Compact: "Compact" }, standalone: false, decls:
|
|
322
|
+
static ɵcmp = /*@__PURE__*/ i0.ɵɵdefineComponent({ type: FlowNodeComponent, selectors: [["mj-flow-node"]], inputs: { Node: "Node", TypeConfig: "TypeConfig", ReadOnly: "ReadOnly", Compact: "Compact" }, standalone: false, decls: 22, vars: 39, consts: [["fNodeInput", "", 1, "mj-flow-node-port", "mj-flow-node-port--input", 3, "class", "fInputId", "fInputDisabled", "fInputMultiple"], [1, "mj-flow-node-body"], [1, "mj-flow-node-accent"], [1, "mj-flow-node-header"], [1, "mj-flow-node-header-left"], [1, "mj-flow-node-logo", 3, "src", "alt"], [1, "fa-solid", "mj-flow-node-icon", 3, "ngClass", "color"], [1, "mj-flow-node-label"], [1, "mj-flow-node-header-right"], [1, "mj-flow-node-start-badge"], [1, "fa-solid", "mj-flow-node-status", 3, "ngClass", "class", "title"], [1, "mj-flow-node-subtitle"], [1, "mj-flow-node-type-badge"], [1, "mj-flow-loop-section"], [1, "mj-flow-node-awaiting-banner"], [1, "mj-flow-node-running-banner"], [1, "mj-flow-node-queued-banner"], [1, "mj-flow-node-warning-banner", 3, "title"], [1, "mj-flow-node-badges"], ["fNodeOutput", "", 1, "mj-flow-node-port", "mj-flow-node-port--output", 3, "class", "fOutputId", "fOutputDisabled", "fOutputMultiple", "isSelfConnectable"], ["fNodeInput", "", 1, "mj-flow-node-port", "mj-flow-node-port--input", 3, "fInputId", "fInputDisabled", "fInputMultiple"], [1, "fa-solid", "mj-flow-node-icon", 3, "ngClass"], [1, "fa-solid", "mj-flow-node-status", 3, "ngClass", "title"], [1, "mj-flow-loop-iteration"], [1, "mj-flow-loop-body"], [1, "mj-flow-loop-body-inner"], [1, "mj-flow-loop-body-empty"], [1, "mj-flow-loop-variable"], [1, "fa-solid", "fa-repeat", "mj-flow-loop-iteration-icon"], [1, "mj-flow-loop-max"], [1, "mj-flow-loop-body-header"], [1, "fa-solid", 3, "ngClass"], [1, "mj-flow-loop-body-type"], [1, "mj-flow-loop-body-name", 3, "title"], [1, "mj-flow-loop-body-name", "mj-flow-loop-body-name--empty"], [1, "fa-solid", "fa-circle-question"], [1, "fa-solid", "fa-tag"], ["aria-hidden", "true", 1, "fa-solid", "fa-pause"], ["aria-hidden", "true", 1, "fa-solid", "fa-spinner", "fa-spin"], ["aria-hidden", "true", 1, "fa-solid", "fa-hourglass-start"], [1, "fa-solid", "fa-triangle-exclamation"], [1, "mj-flow-node-badge", 3, "borderColor", "title"], [1, "mj-flow-node-badge", 3, "title"], ["fNodeOutput", "", 1, "mj-flow-node-port", "mj-flow-node-port--output", 3, "fOutputId", "fOutputDisabled", "fOutputMultiple", "isSelfConnectable"]], template: function FlowNodeComponent_Template(rf, ctx) { if (rf & 1) {
|
|
291
323
|
i0.ɵɵconditionalCreate(0, FlowNodeComponent_Conditional_0_Template, 1, 5, "div", 0);
|
|
292
324
|
i0.ɵɵelementStart(1, "div", 1);
|
|
293
325
|
i0.ɵɵelement(2, "div", 2);
|
|
@@ -306,14 +338,15 @@ export class FlowNodeComponent {
|
|
|
306
338
|
i0.ɵɵtext(14);
|
|
307
339
|
i0.ɵɵelementEnd();
|
|
308
340
|
i0.ɵɵconditionalCreate(15, FlowNodeComponent_Conditional_15_Template, 6, 6, "div", 13);
|
|
309
|
-
i0.ɵɵconditionalCreate(16, FlowNodeComponent_Conditional_16_Template, 4,
|
|
310
|
-
i0.ɵɵconditionalCreate(
|
|
341
|
+
i0.ɵɵconditionalCreate(16, FlowNodeComponent_Conditional_16_Template, 4, 0, "div", 14)(17, FlowNodeComponent_Conditional_17_Template, 4, 0, "div", 15)(18, FlowNodeComponent_Conditional_18_Template, 4, 0, "div", 16);
|
|
342
|
+
i0.ɵɵconditionalCreate(19, FlowNodeComponent_Conditional_19_Template, 4, 2, "div", 17);
|
|
343
|
+
i0.ɵɵconditionalCreate(20, FlowNodeComponent_Conditional_20_Template, 3, 0, "div", 18);
|
|
311
344
|
i0.ɵɵelementEnd();
|
|
312
|
-
i0.ɵɵconditionalCreate(
|
|
345
|
+
i0.ɵɵconditionalCreate(21, FlowNodeComponent_Conditional_21_Template, 1, 6, "div", 19);
|
|
313
346
|
} if (rf & 2) {
|
|
314
347
|
i0.ɵɵconditional(ctx.inputPort ? 0 : -1);
|
|
315
348
|
i0.ɵɵadvance();
|
|
316
|
-
i0.ɵɵclassProp("mj-flow-node-body--start", ctx.Node.IsStartNode)("mj-flow-node-body--loop", ctx.isLoopNode)("mj-flow-node-body--disabled", ctx.Node.Status === "disabled")("mj-flow-node-body--pending", ctx.Node.Status === "pending")("mj-flow-node-body--
|
|
349
|
+
i0.ɵɵclassProp("mj-flow-node-body--start", ctx.Node.IsStartNode)("mj-flow-node-body--loop", ctx.isLoopNode)("mj-flow-node-body--disabled", ctx.Node.Status === "disabled")("mj-flow-node-body--pending", ctx.Node.Status === "pending")("mj-flow-node-body--skipped", ctx.Node.Status === "skipped")("mj-flow-node-body--running", ctx.isExecuting)("mj-flow-node-body--queued", ctx.isQueued)("mj-flow-node-body--awaiting", ctx.isAwaitingUser)("mj-flow-node-body--warning", ctx.Node.Status === "warning")("mj-flow-node-body--error", ctx.Node.Status === "error")("mj-flow-node-body--success", ctx.Node.Status === "success");
|
|
317
350
|
i0.ɵɵadvance();
|
|
318
351
|
i0.ɵɵstyleProp("background-color", ctx.headerColor);
|
|
319
352
|
i0.ɵɵadvance(3);
|
|
@@ -335,16 +368,18 @@ export class FlowNodeComponent {
|
|
|
335
368
|
i0.ɵɵadvance();
|
|
336
369
|
i0.ɵɵconditional(ctx.isLoopNode ? 15 : -1);
|
|
337
370
|
i0.ɵɵadvance();
|
|
338
|
-
i0.ɵɵconditional(ctx.
|
|
371
|
+
i0.ɵɵconditional(ctx.isAwaitingUser ? 16 : ctx.isExecuting ? 17 : ctx.isQueued ? 18 : -1);
|
|
372
|
+
i0.ɵɵadvance(3);
|
|
373
|
+
i0.ɵɵconditional(ctx.Node.Status === "warning" && ctx.Node.StatusMessage ? 19 : -1);
|
|
339
374
|
i0.ɵɵadvance();
|
|
340
|
-
i0.ɵɵconditional(ctx.Node.Badges && ctx.Node.Badges.length > 0 ?
|
|
375
|
+
i0.ɵɵconditional(ctx.Node.Badges && ctx.Node.Badges.length > 0 ? 20 : -1);
|
|
341
376
|
i0.ɵɵadvance();
|
|
342
|
-
i0.ɵɵconditional(ctx.outputPort ?
|
|
343
|
-
} }, dependencies: [i1.NgClass, i2.FNodeInputDirective, i2.FNodeOutputDirective], styles: ["/* ============================================================\n Flow Node \u2014 Visual design for individual flow graph nodes\n ============================================================ */\n\nmj-flow-node {\n display: block;\n position: relative;\n cursor: default;\n transition: filter 0.15s ease, box-shadow 0.15s ease;\n}\n\n.mj-flow-node-body {\n position: relative;\n min-width: 200px;\n max-width: 280px;\n background: var(--mj-bg-surface);\n border: 1px solid var(--mj-border-default);\n border-radius: var(--mj-radius-lg);\n overflow: hidden;\n box-shadow: var(--mj-shadow-sm);\n transition: border-color 0.15s ease, box-shadow 0.15s ease, opacity 0.15s ease;\n}\n\n.mj-flow-node-body:hover {\n box-shadow: var(--mj-shadow-md);\n border-color: var(--mj-border-strong);\n}\n\n/* Selected state \u2014 applied by Foblex on the host fNode element */\n.f-selected .mj-flow-node-body {\n border-color: var(--mj-brand-primary);\n box-shadow: 0 0 0 2px color-mix(in srgb, var(--mj-brand-primary) 25%, transparent), var(--mj-shadow-md);\n}\n\n/* Status variants */\n.mj-flow-node-body--start {\n border: 2px solid var(--mj-status-success);\n background: color-mix(in srgb, var(--mj-status-success) 5%, var(--mj-bg-surface));\n box-shadow: 0 0 0 3px color-mix(in srgb, var(--mj-status-success) 12%, transparent),\n 0 2px 8px color-mix(in srgb, var(--mj-status-success) 15%, transparent);\n}\n\n.mj-flow-node-body--start:hover {\n box-shadow: 0 0 0 3px color-mix(in srgb, var(--mj-status-success) 18%, transparent),\n 0 4px 16px color-mix(in srgb, var(--mj-status-success) 20%, transparent);\n}\n\n.f-selected .mj-flow-node-body--start {\n border-color: var(--mj-status-success);\n box-shadow: 0 0 0 3px color-mix(in srgb, var(--mj-status-success) 30%, transparent),\n 0 4px 12px color-mix(in srgb, var(--mj-status-success) 15%, transparent);\n}\n\n.mj-flow-node-body--disabled {\n opacity: 0.5;\n filter: grayscale(0.5);\n}\n\n.mj-flow-node-body--pending {\n opacity: 0.7;\n border-style: dashed;\n}\n\n.mj-flow-node-body--running {\n border-color: var(--mj-brand-primary);\n animation: mj-flow-node-pulse 1.5s ease-in-out infinite;\n}\n\n.mj-flow-node-body--warning {\n border: 2px solid var(--mj-status-warning);\n background: color-mix(in srgb, var(--mj-status-warning) 5%, var(--mj-bg-surface));\n box-shadow: 0 0 0 2px color-mix(in srgb, var(--mj-status-warning) 15%, transparent),\n 0 2px 8px color-mix(in srgb, var(--mj-status-warning) 10%, transparent);\n}\n\n.mj-flow-node-body--warning:hover {\n box-shadow: 0 0 0 2px color-mix(in srgb, var(--mj-status-warning) 25%, transparent),\n 0 4px 16px color-mix(in srgb, var(--mj-status-warning) 15%, transparent);\n}\n\n.f-selected .mj-flow-node-body--warning {\n border-color: var(--mj-status-warning);\n box-shadow: 0 0 0 3px color-mix(in srgb, var(--mj-status-warning) 30%, transparent),\n 0 4px 12px color-mix(in srgb, var(--mj-status-warning) 15%, transparent);\n}\n\n.mj-flow-node-body--error {\n border-color: var(--mj-status-error);\n background: var(--mj-status-error-subtle);\n}\n\n.mj-flow-node-body--success {\n border-color: var(--mj-status-success);\n}\n\n/* Color accent bar at top */\n.mj-flow-node-accent {\n height: 3px;\n width: 100%;\n}\n\n/* Header row */\n.mj-flow-node-header {\n display: flex;\n align-items: center;\n justify-content: space-between;\n padding: 8px 12px 4px;\n gap: 8px;\n}\n\n.mj-flow-node-header-left {\n display: flex;\n align-items: center;\n gap: 8px;\n min-width: 0;\n flex: 1;\n}\n\n.mj-flow-node-header-right {\n display: flex;\n align-items: center;\n gap: 6px;\n flex-shrink: 0;\n}\n\n.mj-flow-node-icon {\n font-size: var(--mj-text-sm);\n flex-shrink: 0;\n}\n\n.mj-flow-node-logo {\n width: 18px;\n height: 18px;\n border-radius: var(--mj-radius-sm);\n object-fit: contain;\n flex-shrink: 0;\n}\n\n.mj-flow-node-label {\n font-size: var(--mj-text-sm);\n font-weight: 600;\n color: var(--mj-text-primary);\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n line-height: 1.3;\n}\n\n.mj-flow-node-start-badge {\n font-size: 9px;\n font-weight: 700;\n letter-spacing: 0.5px;\n color: var(--mj-text-inverse);\n background: var(--mj-status-success);\n border: none;\n border-radius: var(--mj-radius-sm);\n padding: 2px 6px;\n line-height: 1.4;\n box-shadow: 0 1px 3px color-mix(in srgb, var(--mj-status-success) 30%, transparent);\n}\n\n/* Status indicator */\n.mj-flow-node-status {\n font-size: var(--mj-text-xs);\n}\n\n.mj-flow-node-status--success { color: var(--mj-status-success); }\n.mj-flow-node-status--error { color: var(--mj-status-error); }\n.mj-flow-node-status--warning { color: var(--mj-status-warning); }\n.mj-flow-node-status--running { color: var(--mj-brand-primary); }\n.mj-flow-node-status--disabled { color: var(--mj-text-disabled); }\n.mj-flow-node-status--pending { color: var(--mj-status-warning); }\n\n/* Subtitle line */\n.mj-flow-node-subtitle {\n padding: 0 12px 2px;\n font-size: var(--mj-text-xs);\n color: var(--mj-text-secondary);\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n line-height: 1.4;\n}\n\n/* Type badge */\n.mj-flow-node-type-badge {\n padding: 2px 12px 6px;\n font-size: 10px;\n font-weight: 500;\n text-transform: uppercase;\n letter-spacing: 0.3px;\n opacity: 0.7;\n}\n\n/* Warning banner \u2014 inline alert on misconfigured nodes */\n.mj-flow-node-warning-banner {\n display: flex;\n align-items: center;\n gap: 5px;\n margin: 2px 8px 6px;\n padding: 4px 8px;\n background: var(--mj-status-warning-bg);\n border: 1px solid var(--mj-status-warning-border);\n border-radius: 5px;\n font-size: 10px;\n font-weight: 600;\n color: var(--mj-status-warning-text);\n line-height: 1.3;\n}\n\n.mj-flow-node-warning-banner i {\n font-size: 10px;\n flex-shrink: 0;\n color: var(--mj-status-warning);\n}\n\n.mj-flow-node-warning-banner span {\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n}\n\n/* Badges row */\n.mj-flow-node-badges {\n display: flex;\n gap: 4px;\n padding: 0 10px 8px;\n flex-wrap: wrap;\n}\n\n.mj-flow-node-badge {\n display: inline-flex;\n align-items: center;\n gap: 3px;\n font-size: 10px;\n color: var(--mj-text-muted);\n background: var(--mj-bg-page);\n border: 1px solid var(--mj-border-default);\n border-radius: var(--mj-radius-sm);\n padding: 1px 6px;\n line-height: 1.4;\n}\n\n.mj-flow-node-badge i {\n font-size: 9px;\n}\n\n/* ============================================================\n Loop Node \u2014 distinctive container for ForEach/While\n ============================================================ */\n\n.mj-flow-node-body--loop {\n min-width: 230px;\n max-width: 300px;\n border-width: 2px;\n border-style: solid;\n border-image: none;\n background: color-mix(in srgb, var(--mj-status-warning) 5%, var(--mj-bg-surface));\n}\n\n.mj-flow-node-body--loop:hover {\n box-shadow: 0 4px 14px color-mix(in srgb, var(--mj-status-warning) 12%, transparent), var(--mj-shadow-sm);\n}\n\n.f-selected .mj-flow-node-body--loop {\n border-color: var(--mj-status-warning);\n box-shadow: 0 0 0 2px color-mix(in srgb, var(--mj-status-warning) 25%, transparent), var(--mj-shadow-md);\n}\n\n/* Loop section container */\n.mj-flow-loop-section {\n padding: 0 10px 8px;\n}\n\n/* Iteration summary (e.g., \"over items\" / \"while condition\") */\n.mj-flow-loop-iteration {\n display: flex;\n align-items: center;\n gap: 5px;\n padding: 3px 0 6px;\n font-size: 10px;\n font-weight: 500;\n color: var(--mj-status-warning-text);\n letter-spacing: 0.2px;\n}\n\n.mj-flow-loop-iteration-icon {\n font-size: 9px;\n color: var(--mj-status-warning);\n}\n\n.mj-flow-loop-max {\n color: var(--mj-status-warning-text);\n opacity: 0.7;\n}\n\n/* Inner body card \u2014 the \"iterated operation\" */\n.mj-flow-loop-body {\n border: 1.5px dashed var(--mj-border-strong);\n border-radius: 7px;\n background: var(--mj-bg-surface);\n transition: border-color 0.15s ease;\n}\n\n.mj-flow-loop-body:not(.mj-flow-loop-body--empty) {\n border-color: var(--mj-border-default);\n background: var(--mj-bg-surface-card);\n}\n\n.mj-flow-loop-body-inner {\n padding: 6px 10px;\n}\n\n.mj-flow-loop-body-header {\n display: flex;\n align-items: center;\n gap: 6px;\n margin-bottom: 2px;\n}\n\n.mj-flow-loop-body-header i {\n font-size: 11px;\n}\n\n.mj-flow-loop-body-type {\n font-size: 10px;\n font-weight: 700;\n text-transform: uppercase;\n letter-spacing: 0.4px;\n}\n\n.mj-flow-loop-body-name {\n font-size: 11px;\n font-weight: 500;\n color: var(--mj-text-primary);\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n padding-left: 17px;\n line-height: 1.4;\n}\n\n.mj-flow-loop-body-name--empty {\n color: var(--mj-text-disabled);\n font-style: italic;\n font-weight: 400;\n}\n\n/* Empty body card \u2014 no body type selected */\n.mj-flow-loop-body--empty {\n border-color: var(--mj-status-warning-border);\n border-style: dashed;\n background: color-mix(in srgb, var(--mj-status-warning) 4%, var(--mj-bg-surface));\n}\n\n.mj-flow-loop-body-empty {\n display: flex;\n align-items: center;\n gap: 6px;\n padding: 8px 10px;\n font-size: 10px;\n font-weight: 500;\n color: var(--mj-status-warning-text);\n}\n\n.mj-flow-loop-body-empty i {\n font-size: 11px;\n color: var(--mj-status-warning);\n}\n\n/* Item variable badge */\n.mj-flow-loop-variable {\n display: inline-flex;\n align-items: center;\n gap: 4px;\n margin-top: 5px;\n font-size: 9px;\n font-weight: 500;\n color: var(--mj-text-muted);\n background: var(--mj-bg-surface-card);\n border: 1px solid var(--mj-border-default);\n border-radius: var(--mj-radius-sm);\n padding: 1px 6px;\n}\n\n.mj-flow-loop-variable i {\n font-size: 8px;\n color: var(--mj-text-disabled);\n}\n\n/* ============================================================\n Ports (Input/Output connectors)\n ============================================================ */\n\n.mj-flow-node-port {\n position: absolute;\n width: 14px;\n height: 14px;\n border-radius: var(--mj-radius-full);\n background: var(--mj-bg-surface);\n border: 2px solid var(--mj-text-disabled);\n z-index: 10;\n transition: border-color 0.15s ease, transform 0.15s ease, background-color 0.15s ease;\n cursor: crosshair;\n}\n\n.mj-flow-node-port:hover {\n border-color: var(--mj-brand-primary);\n transform: scale(1.3);\n background: var(--mj-brand-primary-subtle);\n}\n\n/* Position based on side */\n.mj-flow-node-port--top {\n top: -7px;\n left: 50%;\n transform: translateX(-50%);\n}\n\n.mj-flow-node-port--top:hover {\n transform: translateX(-50%) scale(1.3);\n}\n\n.mj-flow-node-port--bottom {\n bottom: -7px;\n left: 50%;\n transform: translateX(-50%);\n}\n\n.mj-flow-node-port--bottom:hover {\n transform: translateX(-50%) scale(1.3);\n}\n\n.mj-flow-node-port--left {\n left: -7px;\n top: 50%;\n transform: translateY(-50%);\n}\n\n.mj-flow-node-port--left:hover {\n transform: translateY(-50%) scale(1.3);\n}\n\n.mj-flow-node-port--right {\n right: -7px;\n top: 50%;\n transform: translateY(-50%);\n}\n\n.mj-flow-node-port--right:hover {\n transform: translateY(-50%) scale(1.3);\n}\n\n/* Disabled port */\n.mj-flow-node-port.f-node-input-disabled,\n.mj-flow-node-port.f-node-output-disabled {\n opacity: 0;\n pointer-events: none;\n}\n\n/* ============================================================\n Animations\n ============================================================ */\n\n@keyframes mj-flow-node-pulse {\n 0%, 100% {\n box-shadow: 0 0 0 0 color-mix(in srgb, var(--mj-brand-primary) 30%, transparent);\n }\n 50% {\n box-shadow: 0 0 0 6px transparent;\n }\n}\n"], encapsulation: 2, changeDetection: 0 });
|
|
377
|
+
i0.ɵɵconditional(ctx.outputPort ? 21 : -1);
|
|
378
|
+
} }, dependencies: [i1.NgClass, i2.FNodeInputDirective, i2.FNodeOutputDirective], styles: ["/* ============================================================\n Flow Node \u2014 Visual design for individual flow graph nodes\n ============================================================ */\n\nmj-flow-node {\n display: block;\n position: relative;\n cursor: default;\n transition: filter 0.15s ease, box-shadow 0.15s ease;\n}\n\n.mj-flow-node-body {\n position: relative;\n min-width: 200px;\n max-width: 280px;\n background: var(--mj-bg-surface);\n border: 1px solid var(--mj-border-default);\n border-radius: var(--mj-radius-lg);\n overflow: hidden;\n box-shadow: var(--mj-shadow-sm);\n transition: border-color 0.15s ease, box-shadow 0.15s ease, opacity 0.15s ease;\n}\n\n.mj-flow-node-body:hover {\n box-shadow: var(--mj-shadow-md);\n border-color: var(--mj-border-strong);\n}\n\n/* Selected state \u2014 applied by Foblex on the host fNode element */\n.f-selected .mj-flow-node-body {\n border-color: var(--mj-brand-primary);\n box-shadow: 0 0 0 2px color-mix(in srgb, var(--mj-brand-primary) 25%, transparent), var(--mj-shadow-md);\n}\n\n/* Status variants */\n.mj-flow-node-body--start {\n border: 2px solid var(--mj-status-success);\n background: color-mix(in srgb, var(--mj-status-success) 5%, var(--mj-bg-surface));\n box-shadow: 0 0 0 3px color-mix(in srgb, var(--mj-status-success) 12%, transparent),\n 0 2px 8px color-mix(in srgb, var(--mj-status-success) 15%, transparent);\n}\n\n.mj-flow-node-body--start:hover {\n box-shadow: 0 0 0 3px color-mix(in srgb, var(--mj-status-success) 18%, transparent),\n 0 4px 16px color-mix(in srgb, var(--mj-status-success) 20%, transparent);\n}\n\n.f-selected .mj-flow-node-body--start {\n border-color: var(--mj-status-success);\n box-shadow: 0 0 0 3px color-mix(in srgb, var(--mj-status-success) 30%, transparent),\n 0 4px 12px color-mix(in srgb, var(--mj-status-success) 15%, transparent);\n}\n\n.mj-flow-node-body--disabled {\n opacity: 0.5;\n filter: grayscale(0.5);\n}\n\n.mj-flow-node-body--pending {\n opacity: 0.7;\n border-style: dashed;\n}\n\n.mj-flow-node-body--queued {\n opacity: 1;\n border: 2px dashed var(--mj-brand-primary);\n background: color-mix(in srgb, var(--mj-brand-primary) 6%, var(--mj-bg-surface));\n box-shadow: 0 0 0 3px color-mix(in srgb, var(--mj-brand-primary) 16%, transparent);\n animation: mj-flow-node-queued 1.8s ease-in-out infinite;\n}\n\n.mj-flow-node-body--running {\n opacity: 1;\n border: 2px solid var(--mj-brand-primary);\n background: color-mix(in srgb, var(--mj-brand-primary) 8%, var(--mj-bg-surface));\n box-shadow: 0 0 0 4px color-mix(in srgb, var(--mj-brand-primary) 22%, transparent),\n var(--mj-shadow-md);\n animation: mj-flow-node-pulse 1.1s ease-in-out infinite;\n}\n\n/* Debugger: this step is next and nothing starts until the operator continues. */\n.mj-flow-node-body--awaiting {\n opacity: 1;\n border: 2px solid var(--mj-brand-primary);\n background: color-mix(in srgb, var(--mj-brand-primary) 10%, var(--mj-bg-surface));\n box-shadow: 0 0 0 4px color-mix(in srgb, var(--mj-brand-primary) 28%, transparent),\n var(--mj-shadow-md);\n animation: mj-flow-node-awaiting 1.6s ease-in-out infinite;\n}\n.f-selected .mj-flow-node-body--awaiting {\n border-color: var(--mj-brand-primary);\n box-shadow: 0 0 0 5px color-mix(in srgb, var(--mj-brand-primary) 35%, transparent),\n var(--mj-shadow-md);\n}\n\n.mj-flow-node-awaiting-banner {\n display: flex;\n align-items: center;\n gap: 6px;\n margin: 2px 8px 6px;\n padding: 5px 8px;\n background: color-mix(in srgb, var(--mj-brand-primary) 16%, var(--mj-bg-surface));\n border: 1px solid var(--mj-brand-primary);\n border-radius: var(--mj-radius-sm);\n font-size: 11px;\n font-weight: 700;\n color: var(--mj-brand-primary);\n line-height: 1.3;\n}\n.mj-flow-node-awaiting-banner i { font-size: 10px; flex-shrink: 0; }\n\n.mj-flow-node-running-banner,\n.mj-flow-node-queued-banner {\n display: flex;\n align-items: center;\n gap: 6px;\n margin: 2px 8px 6px;\n padding: 5px 8px;\n border-radius: var(--mj-radius-sm);\n font-size: 11px;\n font-weight: 700;\n line-height: 1.3;\n}\n.mj-flow-node-running-banner {\n background: color-mix(in srgb, var(--mj-brand-primary) 16%, var(--mj-bg-surface));\n border: 1px solid var(--mj-brand-primary);\n color: var(--mj-brand-primary);\n}\n.mj-flow-node-queued-banner {\n background: color-mix(in srgb, var(--mj-brand-primary) 8%, var(--mj-bg-surface));\n border: 1px dashed var(--mj-brand-primary);\n color: var(--mj-brand-primary);\n}\n.mj-flow-node-running-banner i,\n.mj-flow-node-queued-banner i { font-size: 10px; flex-shrink: 0; }\n\n.mj-flow-node-body--warning {\n border: 2px solid var(--mj-status-warning);\n background: color-mix(in srgb, var(--mj-status-warning) 5%, var(--mj-bg-surface));\n box-shadow: 0 0 0 2px color-mix(in srgb, var(--mj-status-warning) 15%, transparent),\n 0 2px 8px color-mix(in srgb, var(--mj-status-warning) 10%, transparent);\n}\n\n.mj-flow-node-body--warning:hover {\n box-shadow: 0 0 0 2px color-mix(in srgb, var(--mj-status-warning) 25%, transparent),\n 0 4px 16px color-mix(in srgb, var(--mj-status-warning) 15%, transparent);\n}\n\n.f-selected .mj-flow-node-body--warning {\n border-color: var(--mj-status-warning);\n box-shadow: 0 0 0 3px color-mix(in srgb, var(--mj-status-warning) 30%, transparent),\n 0 4px 12px color-mix(in srgb, var(--mj-status-warning) 15%, transparent);\n}\n\n.mj-flow-node-body--error {\n border-color: var(--mj-status-error);\n background: var(--mj-status-error-subtle);\n}\n\n.mj-flow-node-body--success {\n border-color: var(--mj-status-success);\n}\n\n/* Color accent bar at top */\n.mj-flow-node-accent {\n height: 3px;\n width: 100%;\n}\n\n/* Header row */\n.mj-flow-node-header {\n display: flex;\n align-items: center;\n justify-content: space-between;\n padding: 8px 12px 4px;\n gap: 8px;\n}\n\n.mj-flow-node-header-left {\n display: flex;\n align-items: center;\n gap: 8px;\n min-width: 0;\n flex: 1;\n}\n\n.mj-flow-node-header-right {\n display: flex;\n align-items: center;\n gap: 6px;\n flex-shrink: 0;\n}\n\n.mj-flow-node-icon {\n font-size: var(--mj-text-sm);\n flex-shrink: 0;\n}\n\n.mj-flow-node-logo {\n width: 18px;\n height: 18px;\n border-radius: var(--mj-radius-sm);\n object-fit: contain;\n flex-shrink: 0;\n}\n\n.mj-flow-node-label {\n font-size: var(--mj-text-sm);\n font-weight: 600;\n color: var(--mj-text-primary);\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n line-height: 1.3;\n}\n\n.mj-flow-node-start-badge {\n font-size: 9px;\n font-weight: 700;\n letter-spacing: 0.5px;\n color: var(--mj-text-inverse);\n background: var(--mj-status-success);\n border: none;\n border-radius: var(--mj-radius-sm);\n padding: 2px 6px;\n line-height: 1.4;\n box-shadow: 0 1px 3px color-mix(in srgb, var(--mj-status-success) 30%, transparent);\n}\n\n/* Status indicator */\n.mj-flow-node-status {\n font-size: var(--mj-text-xs);\n}\n\n.mj-flow-node-status--success { color: var(--mj-status-success); }\n.mj-flow-node-status--error { color: var(--mj-status-error); }\n.mj-flow-node-status--warning { color: var(--mj-status-warning); }\n.mj-flow-node-status--running { color: var(--mj-brand-primary); }\n.mj-flow-node-status--disabled { color: var(--mj-text-disabled); }\n.mj-flow-node-status--pending { color: var(--mj-status-warning); }\n\n/* Subtitle line */\n.mj-flow-node-subtitle {\n padding: 0 12px 2px;\n font-size: var(--mj-text-xs);\n color: var(--mj-text-secondary);\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n line-height: 1.4;\n}\n\n/* Type badge */\n.mj-flow-node-type-badge {\n padding: 2px 12px 6px;\n font-size: 10px;\n font-weight: 500;\n text-transform: uppercase;\n letter-spacing: 0.3px;\n opacity: 0.7;\n}\n\n/* Warning banner \u2014 inline alert on misconfigured nodes */\n.mj-flow-node-warning-banner {\n display: flex;\n align-items: center;\n gap: 5px;\n margin: 2px 8px 6px;\n padding: 4px 8px;\n background: var(--mj-status-warning-bg);\n border: 1px solid var(--mj-status-warning-border);\n border-radius: 5px;\n font-size: 10px;\n font-weight: 600;\n color: var(--mj-status-warning-text);\n line-height: 1.3;\n}\n\n.mj-flow-node-warning-banner i {\n font-size: 10px;\n flex-shrink: 0;\n color: var(--mj-status-warning);\n}\n\n.mj-flow-node-warning-banner span {\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n}\n\n/* Badges row */\n.mj-flow-node-badges {\n display: flex;\n gap: 4px;\n padding: 0 10px 8px;\n flex-wrap: wrap;\n}\n\n.mj-flow-node-badge {\n display: inline-flex;\n align-items: center;\n gap: 3px;\n font-size: 10px;\n color: var(--mj-text-muted);\n background: var(--mj-bg-page);\n border: 1px solid var(--mj-border-default);\n border-radius: var(--mj-radius-sm);\n padding: 1px 6px;\n line-height: 1.4;\n}\n\n.mj-flow-node-badge i {\n font-size: 9px;\n}\n\n/* ============================================================\n Loop Node \u2014 distinctive container for ForEach/While\n ============================================================ */\n\n.mj-flow-node-body--loop {\n min-width: 230px;\n max-width: 300px;\n border-width: 2px;\n border-style: solid;\n border-image: none;\n background: color-mix(in srgb, var(--mj-status-warning) 5%, var(--mj-bg-surface));\n}\n\n.mj-flow-node-body--loop.mj-flow-node-body--awaiting {\n border-color: var(--mj-brand-primary);\n background: color-mix(in srgb, var(--mj-brand-primary) 10%, var(--mj-bg-surface));\n}\n\n.mj-flow-node-body--loop:hover {\n box-shadow: 0 4px 14px color-mix(in srgb, var(--mj-status-warning) 12%, transparent), var(--mj-shadow-sm);\n}\n\n.f-selected .mj-flow-node-body--loop {\n border-color: var(--mj-status-warning);\n box-shadow: 0 0 0 2px color-mix(in srgb, var(--mj-status-warning) 25%, transparent), var(--mj-shadow-md);\n}\n\n/* Loop section container */\n.mj-flow-loop-section {\n padding: 0 10px 8px;\n}\n\n/* Iteration summary (e.g., \"over items\" / \"while condition\") */\n.mj-flow-loop-iteration {\n display: flex;\n align-items: center;\n gap: 5px;\n padding: 3px 0 6px;\n font-size: 10px;\n font-weight: 500;\n color: var(--mj-status-warning-text);\n letter-spacing: 0.2px;\n}\n\n.mj-flow-loop-iteration-icon {\n font-size: 9px;\n color: var(--mj-status-warning);\n}\n\n.mj-flow-loop-max {\n color: var(--mj-status-warning-text);\n opacity: 0.7;\n}\n\n/* Inner body card \u2014 the \"iterated operation\" */\n.mj-flow-loop-body {\n border: 1.5px dashed var(--mj-border-strong);\n border-radius: 7px;\n background: var(--mj-bg-surface);\n transition: border-color 0.15s ease;\n}\n\n.mj-flow-loop-body:not(.mj-flow-loop-body--empty) {\n border-color: var(--mj-border-default);\n background: var(--mj-bg-surface-card);\n}\n\n.mj-flow-loop-body-inner {\n padding: 6px 10px;\n}\n\n.mj-flow-loop-body-header {\n display: flex;\n align-items: center;\n gap: 6px;\n margin-bottom: 2px;\n}\n\n.mj-flow-loop-body-header i {\n font-size: 11px;\n}\n\n.mj-flow-loop-body-type {\n font-size: 10px;\n font-weight: 700;\n text-transform: uppercase;\n letter-spacing: 0.4px;\n}\n\n.mj-flow-loop-body-name {\n font-size: 11px;\n font-weight: 500;\n color: var(--mj-text-primary);\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n padding-left: 17px;\n line-height: 1.4;\n}\n\n.mj-flow-loop-body-name--empty {\n color: var(--mj-text-disabled);\n font-style: italic;\n font-weight: 400;\n}\n\n/* Empty body card \u2014 no body type selected */\n.mj-flow-loop-body--empty {\n border-color: var(--mj-status-warning-border);\n border-style: dashed;\n background: color-mix(in srgb, var(--mj-status-warning) 4%, var(--mj-bg-surface));\n}\n\n.mj-flow-loop-body-empty {\n display: flex;\n align-items: center;\n gap: 6px;\n padding: 8px 10px;\n font-size: 10px;\n font-weight: 500;\n color: var(--mj-status-warning-text);\n}\n\n.mj-flow-loop-body-empty i {\n font-size: 11px;\n color: var(--mj-status-warning);\n}\n\n/* Item variable badge */\n.mj-flow-loop-variable {\n display: inline-flex;\n align-items: center;\n gap: 4px;\n margin-top: 5px;\n font-size: 9px;\n font-weight: 500;\n color: var(--mj-text-muted);\n background: var(--mj-bg-surface-card);\n border: 1px solid var(--mj-border-default);\n border-radius: var(--mj-radius-sm);\n padding: 1px 6px;\n}\n\n.mj-flow-loop-variable i {\n font-size: 8px;\n color: var(--mj-text-disabled);\n}\n\n/* ============================================================\n Ports (Input/Output connectors)\n ============================================================ */\n\n.mj-flow-node-port {\n position: absolute;\n width: 14px;\n height: 14px;\n border-radius: var(--mj-radius-full);\n background: var(--mj-bg-surface);\n border: 2px solid var(--mj-text-disabled);\n z-index: 10;\n transition: border-color 0.15s ease, transform 0.15s ease, background-color 0.15s ease;\n cursor: crosshair;\n}\n\n.mj-flow-node-port:hover {\n border-color: var(--mj-brand-primary);\n transform: scale(1.3);\n background: var(--mj-brand-primary-subtle);\n}\n\n/* Position based on side */\n.mj-flow-node-port--top {\n top: -7px;\n left: 50%;\n transform: translateX(-50%);\n}\n\n.mj-flow-node-port--top:hover {\n transform: translateX(-50%) scale(1.3);\n}\n\n.mj-flow-node-port--bottom {\n bottom: -7px;\n left: 50%;\n transform: translateX(-50%);\n}\n\n.mj-flow-node-port--bottom:hover {\n transform: translateX(-50%) scale(1.3);\n}\n\n.mj-flow-node-port--left {\n left: -7px;\n top: 50%;\n transform: translateY(-50%);\n}\n\n.mj-flow-node-port--left:hover {\n transform: translateY(-50%) scale(1.3);\n}\n\n.mj-flow-node-port--right {\n right: -7px;\n top: 50%;\n transform: translateY(-50%);\n}\n\n.mj-flow-node-port--right:hover {\n transform: translateY(-50%) scale(1.3);\n}\n\n/* Disabled port */\n.mj-flow-node-port.f-node-input-disabled,\n.mj-flow-node-port.f-node-output-disabled {\n opacity: 0;\n pointer-events: none;\n}\n\n/* ============================================================\n Animations\n ============================================================ */\n\n@keyframes mj-flow-node-pulse {\n 0%, 100% {\n box-shadow: 0 0 0 4px color-mix(in srgb, var(--mj-brand-primary) 22%, transparent),\n var(--mj-shadow-md);\n }\n 50% {\n box-shadow: 0 0 0 8px color-mix(in srgb, var(--mj-brand-primary) 8%, transparent),\n var(--mj-shadow-md);\n }\n}\n\n@keyframes mj-flow-node-queued {\n 0%, 100% {\n box-shadow: 0 0 0 3px color-mix(in srgb, var(--mj-brand-primary) 16%, transparent);\n }\n 50% {\n box-shadow: 0 0 0 6px color-mix(in srgb, var(--mj-brand-primary) 6%, transparent);\n }\n}\n\n@keyframes mj-flow-node-awaiting {\n 0%, 100% {\n box-shadow: 0 0 0 4px color-mix(in srgb, var(--mj-brand-primary) 28%, transparent),\n var(--mj-shadow-md);\n }\n 50% {\n box-shadow: 0 0 0 8px color-mix(in srgb, var(--mj-brand-primary) 8%, transparent),\n var(--mj-shadow-md);\n }\n}\n\n/* ============================================================\n A step the graph did not take\n ============================================================\n Its own treatment rather than a shade of `disabled`: disabled means \"cannot run\", skipped means\n \"the workflow chose another route\". A reader who cannot tell them apart goes looking for a\n failure that never happened.\n\n Hatching + strike-through, deliberately the same language the run timeline uses for the same\n fact, so a step reads identically whether someone is looking at the list or the diagram. */\n.mj-flow-node-body--skipped {\n opacity: 0.55;\n background-image: repeating-linear-gradient(\n 135deg,\n transparent,\n transparent 5px,\n color-mix(in srgb, var(--mj-text-disabled) 22%, transparent) 5px,\n color-mix(in srgb, var(--mj-text-disabled) 22%, transparent) 10px\n );\n}\n\n.mj-flow-node-body--skipped .mj-flow-node-title {\n text-decoration: line-through;\n text-decoration-color: var(--mj-text-disabled);\n}\n\n.mj-flow-node-status--skipped { color: var(--mj-text-disabled); }\n"], encapsulation: 2, changeDetection: 0 });
|
|
344
379
|
}
|
|
345
380
|
(() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassMetadata(FlowNodeComponent, [{
|
|
346
381
|
type: Component,
|
|
347
|
-
args: [{ standalone: false, selector: 'mj-flow-node', encapsulation: ViewEncapsulation.None, changeDetection: ChangeDetectionStrategy.OnPush, template: "<!-- Input Port -->\n@if (inputPort) {\n <div\n class=\"mj-flow-node-port mj-flow-node-port--input\"\n [class]=\"'mj-flow-node-port--' + inputPort.Side\"\n fNodeInput\n [fInputId]=\"inputPort.ID\"\n [fInputDisabled]=\"inputPort.Disabled\"\n [fInputMultiple]=\"inputPort.Multiple\">\n </div>\n}\n\n<!-- Node Body -->\n<div class=\"mj-flow-node-body\"\n [class.mj-flow-node-body--start]=\"Node.IsStartNode\"\n [class.mj-flow-node-body--loop]=\"isLoopNode\"\n [class.mj-flow-node-body--disabled]=\"Node.Status === 'disabled'\"\n [class.mj-flow-node-body--pending]=\"Node.Status === 'pending'\"\n [class.mj-flow-node-body--running]=\"Node.Status === 'running'\"\n [class.mj-flow-node-body--warning]=\"Node.Status === 'warning'\"\n [class.mj-flow-node-body--error]=\"Node.Status === 'error'\"\n [class.mj-flow-node-body--success]=\"Node.Status === 'success'\">\n\n <!-- Color accent bar -->\n <div class=\"mj-flow-node-accent\" [style.backgroundColor]=\"headerColor\"></div>\n\n <!-- Header -->\n <div class=\"mj-flow-node-header\">\n <div class=\"mj-flow-node-header-left\">\n @if (logoURL) {\n <img class=\"mj-flow-node-logo\" [src]=\"logoURL\" [alt]=\"Node.Label\" />\n }\n @if (!logoURL) {\n <i class=\"fa-solid mj-flow-node-icon\" [ngClass]=\"nodeIcon\" [style.color]=\"headerColor\"></i>\n }\n <span class=\"mj-flow-node-label\">{{ Node.Label }}</span>\n </div>\n <div class=\"mj-flow-node-header-right\">\n @if (Node.IsStartNode) {\n <span class=\"mj-flow-node-start-badge\">START</span>\n }\n @if (hasStatus) {\n <i\n class=\"fa-solid mj-flow-node-status\"\n [ngClass]=\"statusIcon\"\n [class]=\"'mj-flow-node-status--' + statusClass\"\n [title]=\"Node.StatusMessage || ''\"></i>\n }\n </div>\n </div>\n\n <!-- Subtitle / Configured Item (hidden for loop nodes \u2014 they use the body card instead) -->\n @if (Node.Subtitle && !isLoopNode) {\n <div class=\"mj-flow-node-subtitle\">\n {{ Node.Subtitle }}\n </div>\n }\n\n <!-- Type badge -->\n <div class=\"mj-flow-node-type-badge\" [style.color]=\"headerColor\">\n {{ TypeConfig?.Label || Node.Type }}\n </div>\n\n <!-- \u2550\u2550\u2550 Loop Body Card \u2014 shown only for ForEach/While nodes \u2550\u2550\u2550 -->\n @if (isLoopNode) {\n <div class=\"mj-flow-loop-section\">\n <!-- Iteration summary line -->\n @if (loopIterationSummary) {\n <div class=\"mj-flow-loop-iteration\">\n <i class=\"fa-solid fa-repeat mj-flow-loop-iteration-icon\"></i>\n <span>{{ loopIterationSummary }}</span>\n @if (loopMaxIterations != null) {\n <span class=\"mj-flow-loop-max\">(max {{ loopMaxIterations }})</span>\n }\n </div>\n }\n <!-- Body type inner card -->\n <div class=\"mj-flow-loop-body\"\n [class.mj-flow-loop-body--empty]=\"!loopBodyType\">\n @if (loopBodyType) {\n <div class=\"mj-flow-loop-body-inner\">\n <div class=\"mj-flow-loop-body-header\">\n <i class=\"fa-solid\" [ngClass]=\"loopBodyIcon\" [style.color]=\"loopBodyColor\"></i>\n <span class=\"mj-flow-loop-body-type\" [style.color]=\"loopBodyColor\">{{ loopBodyType }}</span>\n </div>\n @if (loopBodyName) {\n <div class=\"mj-flow-loop-body-name\" [title]=\"loopBodyName\">\n {{ loopBodyName }}\n </div>\n }\n @if (!loopBodyName) {\n <div class=\"mj-flow-loop-body-name mj-flow-loop-body-name--empty\">\n Not configured\n </div>\n }\n </div>\n }\n @if (!loopBodyType) {\n <div class=\"mj-flow-loop-body-empty\">\n <i class=\"fa-solid fa-circle-question\"></i>\n <span>No body type selected</span>\n </div>\n }\n </div>\n <!-- Item variable badge -->\n @if (loopItemVariable) {\n <div class=\"mj-flow-loop-variable\">\n <i class=\"fa-solid fa-tag\"></i>\n <span>{{ loopItemVariable }}</span>\n </div>\n }\n </div>\n }\n\n <!-- Warning banner (shown inline when step is misconfigured) -->\n @if (Node.Status === 'warning' && Node.StatusMessage) {\n <div\n class=\"mj-flow-node-warning-banner\"\n [title]=\"Node.StatusMessage\">\n <i class=\"fa-solid fa-triangle-exclamation\"></i>\n <span>{{ Node.StatusMessage }}</span>\n </div>\n }\n\n <!-- Badges row -->\n @if (Node.Badges && Node.Badges.length > 0) {\n <div class=\"mj-flow-node-badges\">\n @for (badge of Node.Badges; track badge) {\n <span\n class=\"mj-flow-node-badge\"\n [style.borderColor]=\"badge.Color || headerColor\"\n [title]=\"badge.Label\">\n @if (badge.Icon) {\n <i class=\"fa-solid\" [ngClass]=\"badge.Icon\"></i>\n }\n {{ badge.Value }}\n </span>\n }\n </div>\n }\n</div>\n\n<!-- Output Port -->\n@if (outputPort) {\n <div\n class=\"mj-flow-node-port mj-flow-node-port--output\"\n [class]=\"'mj-flow-node-port--' + outputPort.Side\"\n fNodeOutput\n [fOutputId]=\"outputPort.ID\"\n [fOutputDisabled]=\"outputPort.Disabled\"\n [fOutputMultiple]=\"outputPort.Multiple\"\n [isSelfConnectable]=\"false\">\n </div>\n}\n", styles: ["/* ============================================================\n Flow Node \u2014 Visual design for individual flow graph nodes\n ============================================================ */\n\nmj-flow-node {\n display: block;\n position: relative;\n cursor: default;\n transition: filter 0.15s ease, box-shadow 0.15s ease;\n}\n\n.mj-flow-node-body {\n position: relative;\n min-width: 200px;\n max-width: 280px;\n background: var(--mj-bg-surface);\n border: 1px solid var(--mj-border-default);\n border-radius: var(--mj-radius-lg);\n overflow: hidden;\n box-shadow: var(--mj-shadow-sm);\n transition: border-color 0.15s ease, box-shadow 0.15s ease, opacity 0.15s ease;\n}\n\n.mj-flow-node-body:hover {\n box-shadow: var(--mj-shadow-md);\n border-color: var(--mj-border-strong);\n}\n\n/* Selected state \u2014 applied by Foblex on the host fNode element */\n.f-selected .mj-flow-node-body {\n border-color: var(--mj-brand-primary);\n box-shadow: 0 0 0 2px color-mix(in srgb, var(--mj-brand-primary) 25%, transparent), var(--mj-shadow-md);\n}\n\n/* Status variants */\n.mj-flow-node-body--start {\n border: 2px solid var(--mj-status-success);\n background: color-mix(in srgb, var(--mj-status-success) 5%, var(--mj-bg-surface));\n box-shadow: 0 0 0 3px color-mix(in srgb, var(--mj-status-success) 12%, transparent),\n 0 2px 8px color-mix(in srgb, var(--mj-status-success) 15%, transparent);\n}\n\n.mj-flow-node-body--start:hover {\n box-shadow: 0 0 0 3px color-mix(in srgb, var(--mj-status-success) 18%, transparent),\n 0 4px 16px color-mix(in srgb, var(--mj-status-success) 20%, transparent);\n}\n\n.f-selected .mj-flow-node-body--start {\n border-color: var(--mj-status-success);\n box-shadow: 0 0 0 3px color-mix(in srgb, var(--mj-status-success) 30%, transparent),\n 0 4px 12px color-mix(in srgb, var(--mj-status-success) 15%, transparent);\n}\n\n.mj-flow-node-body--disabled {\n opacity: 0.5;\n filter: grayscale(0.5);\n}\n\n.mj-flow-node-body--pending {\n opacity: 0.7;\n border-style: dashed;\n}\n\n.mj-flow-node-body--running {\n border-color: var(--mj-brand-primary);\n animation: mj-flow-node-pulse 1.5s ease-in-out infinite;\n}\n\n.mj-flow-node-body--warning {\n border: 2px solid var(--mj-status-warning);\n background: color-mix(in srgb, var(--mj-status-warning) 5%, var(--mj-bg-surface));\n box-shadow: 0 0 0 2px color-mix(in srgb, var(--mj-status-warning) 15%, transparent),\n 0 2px 8px color-mix(in srgb, var(--mj-status-warning) 10%, transparent);\n}\n\n.mj-flow-node-body--warning:hover {\n box-shadow: 0 0 0 2px color-mix(in srgb, var(--mj-status-warning) 25%, transparent),\n 0 4px 16px color-mix(in srgb, var(--mj-status-warning) 15%, transparent);\n}\n\n.f-selected .mj-flow-node-body--warning {\n border-color: var(--mj-status-warning);\n box-shadow: 0 0 0 3px color-mix(in srgb, var(--mj-status-warning) 30%, transparent),\n 0 4px 12px color-mix(in srgb, var(--mj-status-warning) 15%, transparent);\n}\n\n.mj-flow-node-body--error {\n border-color: var(--mj-status-error);\n background: var(--mj-status-error-subtle);\n}\n\n.mj-flow-node-body--success {\n border-color: var(--mj-status-success);\n}\n\n/* Color accent bar at top */\n.mj-flow-node-accent {\n height: 3px;\n width: 100%;\n}\n\n/* Header row */\n.mj-flow-node-header {\n display: flex;\n align-items: center;\n justify-content: space-between;\n padding: 8px 12px 4px;\n gap: 8px;\n}\n\n.mj-flow-node-header-left {\n display: flex;\n align-items: center;\n gap: 8px;\n min-width: 0;\n flex: 1;\n}\n\n.mj-flow-node-header-right {\n display: flex;\n align-items: center;\n gap: 6px;\n flex-shrink: 0;\n}\n\n.mj-flow-node-icon {\n font-size: var(--mj-text-sm);\n flex-shrink: 0;\n}\n\n.mj-flow-node-logo {\n width: 18px;\n height: 18px;\n border-radius: var(--mj-radius-sm);\n object-fit: contain;\n flex-shrink: 0;\n}\n\n.mj-flow-node-label {\n font-size: var(--mj-text-sm);\n font-weight: 600;\n color: var(--mj-text-primary);\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n line-height: 1.3;\n}\n\n.mj-flow-node-start-badge {\n font-size: 9px;\n font-weight: 700;\n letter-spacing: 0.5px;\n color: var(--mj-text-inverse);\n background: var(--mj-status-success);\n border: none;\n border-radius: var(--mj-radius-sm);\n padding: 2px 6px;\n line-height: 1.4;\n box-shadow: 0 1px 3px color-mix(in srgb, var(--mj-status-success) 30%, transparent);\n}\n\n/* Status indicator */\n.mj-flow-node-status {\n font-size: var(--mj-text-xs);\n}\n\n.mj-flow-node-status--success { color: var(--mj-status-success); }\n.mj-flow-node-status--error { color: var(--mj-status-error); }\n.mj-flow-node-status--warning { color: var(--mj-status-warning); }\n.mj-flow-node-status--running { color: var(--mj-brand-primary); }\n.mj-flow-node-status--disabled { color: var(--mj-text-disabled); }\n.mj-flow-node-status--pending { color: var(--mj-status-warning); }\n\n/* Subtitle line */\n.mj-flow-node-subtitle {\n padding: 0 12px 2px;\n font-size: var(--mj-text-xs);\n color: var(--mj-text-secondary);\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n line-height: 1.4;\n}\n\n/* Type badge */\n.mj-flow-node-type-badge {\n padding: 2px 12px 6px;\n font-size: 10px;\n font-weight: 500;\n text-transform: uppercase;\n letter-spacing: 0.3px;\n opacity: 0.7;\n}\n\n/* Warning banner \u2014 inline alert on misconfigured nodes */\n.mj-flow-node-warning-banner {\n display: flex;\n align-items: center;\n gap: 5px;\n margin: 2px 8px 6px;\n padding: 4px 8px;\n background: var(--mj-status-warning-bg);\n border: 1px solid var(--mj-status-warning-border);\n border-radius: 5px;\n font-size: 10px;\n font-weight: 600;\n color: var(--mj-status-warning-text);\n line-height: 1.3;\n}\n\n.mj-flow-node-warning-banner i {\n font-size: 10px;\n flex-shrink: 0;\n color: var(--mj-status-warning);\n}\n\n.mj-flow-node-warning-banner span {\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n}\n\n/* Badges row */\n.mj-flow-node-badges {\n display: flex;\n gap: 4px;\n padding: 0 10px 8px;\n flex-wrap: wrap;\n}\n\n.mj-flow-node-badge {\n display: inline-flex;\n align-items: center;\n gap: 3px;\n font-size: 10px;\n color: var(--mj-text-muted);\n background: var(--mj-bg-page);\n border: 1px solid var(--mj-border-default);\n border-radius: var(--mj-radius-sm);\n padding: 1px 6px;\n line-height: 1.4;\n}\n\n.mj-flow-node-badge i {\n font-size: 9px;\n}\n\n/* ============================================================\n Loop Node \u2014 distinctive container for ForEach/While\n ============================================================ */\n\n.mj-flow-node-body--loop {\n min-width: 230px;\n max-width: 300px;\n border-width: 2px;\n border-style: solid;\n border-image: none;\n background: color-mix(in srgb, var(--mj-status-warning) 5%, var(--mj-bg-surface));\n}\n\n.mj-flow-node-body--loop:hover {\n box-shadow: 0 4px 14px color-mix(in srgb, var(--mj-status-warning) 12%, transparent), var(--mj-shadow-sm);\n}\n\n.f-selected .mj-flow-node-body--loop {\n border-color: var(--mj-status-warning);\n box-shadow: 0 0 0 2px color-mix(in srgb, var(--mj-status-warning) 25%, transparent), var(--mj-shadow-md);\n}\n\n/* Loop section container */\n.mj-flow-loop-section {\n padding: 0 10px 8px;\n}\n\n/* Iteration summary (e.g., \"over items\" / \"while condition\") */\n.mj-flow-loop-iteration {\n display: flex;\n align-items: center;\n gap: 5px;\n padding: 3px 0 6px;\n font-size: 10px;\n font-weight: 500;\n color: var(--mj-status-warning-text);\n letter-spacing: 0.2px;\n}\n\n.mj-flow-loop-iteration-icon {\n font-size: 9px;\n color: var(--mj-status-warning);\n}\n\n.mj-flow-loop-max {\n color: var(--mj-status-warning-text);\n opacity: 0.7;\n}\n\n/* Inner body card \u2014 the \"iterated operation\" */\n.mj-flow-loop-body {\n border: 1.5px dashed var(--mj-border-strong);\n border-radius: 7px;\n background: var(--mj-bg-surface);\n transition: border-color 0.15s ease;\n}\n\n.mj-flow-loop-body:not(.mj-flow-loop-body--empty) {\n border-color: var(--mj-border-default);\n background: var(--mj-bg-surface-card);\n}\n\n.mj-flow-loop-body-inner {\n padding: 6px 10px;\n}\n\n.mj-flow-loop-body-header {\n display: flex;\n align-items: center;\n gap: 6px;\n margin-bottom: 2px;\n}\n\n.mj-flow-loop-body-header i {\n font-size: 11px;\n}\n\n.mj-flow-loop-body-type {\n font-size: 10px;\n font-weight: 700;\n text-transform: uppercase;\n letter-spacing: 0.4px;\n}\n\n.mj-flow-loop-body-name {\n font-size: 11px;\n font-weight: 500;\n color: var(--mj-text-primary);\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n padding-left: 17px;\n line-height: 1.4;\n}\n\n.mj-flow-loop-body-name--empty {\n color: var(--mj-text-disabled);\n font-style: italic;\n font-weight: 400;\n}\n\n/* Empty body card \u2014 no body type selected */\n.mj-flow-loop-body--empty {\n border-color: var(--mj-status-warning-border);\n border-style: dashed;\n background: color-mix(in srgb, var(--mj-status-warning) 4%, var(--mj-bg-surface));\n}\n\n.mj-flow-loop-body-empty {\n display: flex;\n align-items: center;\n gap: 6px;\n padding: 8px 10px;\n font-size: 10px;\n font-weight: 500;\n color: var(--mj-status-warning-text);\n}\n\n.mj-flow-loop-body-empty i {\n font-size: 11px;\n color: var(--mj-status-warning);\n}\n\n/* Item variable badge */\n.mj-flow-loop-variable {\n display: inline-flex;\n align-items: center;\n gap: 4px;\n margin-top: 5px;\n font-size: 9px;\n font-weight: 500;\n color: var(--mj-text-muted);\n background: var(--mj-bg-surface-card);\n border: 1px solid var(--mj-border-default);\n border-radius: var(--mj-radius-sm);\n padding: 1px 6px;\n}\n\n.mj-flow-loop-variable i {\n font-size: 8px;\n color: var(--mj-text-disabled);\n}\n\n/* ============================================================\n Ports (Input/Output connectors)\n ============================================================ */\n\n.mj-flow-node-port {\n position: absolute;\n width: 14px;\n height: 14px;\n border-radius: var(--mj-radius-full);\n background: var(--mj-bg-surface);\n border: 2px solid var(--mj-text-disabled);\n z-index: 10;\n transition: border-color 0.15s ease, transform 0.15s ease, background-color 0.15s ease;\n cursor: crosshair;\n}\n\n.mj-flow-node-port:hover {\n border-color: var(--mj-brand-primary);\n transform: scale(1.3);\n background: var(--mj-brand-primary-subtle);\n}\n\n/* Position based on side */\n.mj-flow-node-port--top {\n top: -7px;\n left: 50%;\n transform: translateX(-50%);\n}\n\n.mj-flow-node-port--top:hover {\n transform: translateX(-50%) scale(1.3);\n}\n\n.mj-flow-node-port--bottom {\n bottom: -7px;\n left: 50%;\n transform: translateX(-50%);\n}\n\n.mj-flow-node-port--bottom:hover {\n transform: translateX(-50%) scale(1.3);\n}\n\n.mj-flow-node-port--left {\n left: -7px;\n top: 50%;\n transform: translateY(-50%);\n}\n\n.mj-flow-node-port--left:hover {\n transform: translateY(-50%) scale(1.3);\n}\n\n.mj-flow-node-port--right {\n right: -7px;\n top: 50%;\n transform: translateY(-50%);\n}\n\n.mj-flow-node-port--right:hover {\n transform: translateY(-50%) scale(1.3);\n}\n\n/* Disabled port */\n.mj-flow-node-port.f-node-input-disabled,\n.mj-flow-node-port.f-node-output-disabled {\n opacity: 0;\n pointer-events: none;\n}\n\n/* ============================================================\n Animations\n ============================================================ */\n\n@keyframes mj-flow-node-pulse {\n 0%, 100% {\n box-shadow: 0 0 0 0 color-mix(in srgb, var(--mj-brand-primary) 30%, transparent);\n }\n 50% {\n box-shadow: 0 0 0 6px transparent;\n }\n}\n"] }]
|
|
382
|
+
args: [{ standalone: false, selector: 'mj-flow-node', encapsulation: ViewEncapsulation.None, changeDetection: ChangeDetectionStrategy.OnPush, template: "<!-- Input Port -->\n@if (inputPort) {\n <div\n class=\"mj-flow-node-port mj-flow-node-port--input\"\n [class]=\"'mj-flow-node-port--' + inputPort.Side\"\n fNodeInput\n [fInputId]=\"inputPort.ID\"\n [fInputDisabled]=\"inputPort.Disabled\"\n [fInputMultiple]=\"inputPort.Multiple\">\n </div>\n}\n\n<!-- Node Body -->\n<div class=\"mj-flow-node-body\"\n [class.mj-flow-node-body--start]=\"Node.IsStartNode\"\n [class.mj-flow-node-body--loop]=\"isLoopNode\"\n [class.mj-flow-node-body--disabled]=\"Node.Status === 'disabled'\"\n [class.mj-flow-node-body--pending]=\"Node.Status === 'pending'\"\n [class.mj-flow-node-body--skipped]=\"Node.Status === 'skipped'\"\n [class.mj-flow-node-body--running]=\"isExecuting\"\n [class.mj-flow-node-body--queued]=\"isQueued\"\n [class.mj-flow-node-body--awaiting]=\"isAwaitingUser\"\n [class.mj-flow-node-body--warning]=\"Node.Status === 'warning'\"\n [class.mj-flow-node-body--error]=\"Node.Status === 'error'\"\n [class.mj-flow-node-body--success]=\"Node.Status === 'success'\">\n\n <!-- Color accent bar -->\n <div class=\"mj-flow-node-accent\" [style.backgroundColor]=\"headerColor\"></div>\n\n <!-- Header -->\n <div class=\"mj-flow-node-header\">\n <div class=\"mj-flow-node-header-left\">\n @if (logoURL) {\n <img class=\"mj-flow-node-logo\" [src]=\"logoURL\" [alt]=\"Node.Label\" />\n }\n @if (!logoURL) {\n <i class=\"fa-solid mj-flow-node-icon\" [ngClass]=\"nodeIcon\" [style.color]=\"headerColor\"></i>\n }\n <span class=\"mj-flow-node-label\">{{ Node.Label }}</span>\n </div>\n <div class=\"mj-flow-node-header-right\">\n @if (Node.IsStartNode) {\n <span class=\"mj-flow-node-start-badge\">START</span>\n }\n @if (hasStatus) {\n <i\n class=\"fa-solid mj-flow-node-status\"\n [ngClass]=\"statusIcon\"\n [class]=\"'mj-flow-node-status--' + statusClass\"\n [title]=\"Node.StatusMessage || ''\"></i>\n }\n </div>\n </div>\n\n <!-- Subtitle / Configured Item (hidden for loop nodes \u2014 they use the body card instead) -->\n @if (Node.Subtitle && !isLoopNode) {\n <div class=\"mj-flow-node-subtitle\">\n {{ Node.Subtitle }}\n </div>\n }\n\n <!-- Type badge -->\n <div class=\"mj-flow-node-type-badge\" [style.color]=\"headerColor\">\n {{ TypeConfig?.Label || Node.Type }}\n </div>\n\n <!-- \u2550\u2550\u2550 Loop Body Card \u2014 shown only for ForEach/While nodes \u2550\u2550\u2550 -->\n @if (isLoopNode) {\n <div class=\"mj-flow-loop-section\">\n <!-- Iteration summary line -->\n @if (loopIterationSummary) {\n <div class=\"mj-flow-loop-iteration\">\n <i class=\"fa-solid fa-repeat mj-flow-loop-iteration-icon\"></i>\n <span>{{ loopIterationSummary }}</span>\n @if (loopMaxIterations != null) {\n <span class=\"mj-flow-loop-max\">(max {{ loopMaxIterations }})</span>\n }\n </div>\n }\n <!-- Body type inner card -->\n <div class=\"mj-flow-loop-body\"\n [class.mj-flow-loop-body--empty]=\"!loopBodyType\">\n @if (loopBodyType) {\n <div class=\"mj-flow-loop-body-inner\">\n <div class=\"mj-flow-loop-body-header\">\n <i class=\"fa-solid\" [ngClass]=\"loopBodyIcon\" [style.color]=\"loopBodyColor\"></i>\n <span class=\"mj-flow-loop-body-type\" [style.color]=\"loopBodyColor\">{{ loopBodyType }}</span>\n </div>\n @if (loopBodyName) {\n <div class=\"mj-flow-loop-body-name\" [title]=\"loopBodyName\">\n {{ loopBodyName }}\n </div>\n }\n @if (!loopBodyName) {\n <div class=\"mj-flow-loop-body-name mj-flow-loop-body-name--empty\">\n Not configured\n </div>\n }\n </div>\n }\n @if (!loopBodyType) {\n <div class=\"mj-flow-loop-body-empty\">\n <i class=\"fa-solid fa-circle-question\"></i>\n <span>No body type selected</span>\n </div>\n }\n </div>\n <!-- Item variable badge -->\n @if (loopItemVariable) {\n <div class=\"mj-flow-loop-variable\">\n <i class=\"fa-solid fa-tag\"></i>\n <span>{{ loopItemVariable }}</span>\n </div>\n }\n </div>\n }\n\n @if (isAwaitingUser) {\n <div class=\"mj-flow-node-awaiting-banner\">\n <i class=\"fa-solid fa-pause\" aria-hidden=\"true\"></i>\n <span>Waiting on you \u2014 Continue or Step</span>\n </div>\n } @else if (isExecuting) {\n <div class=\"mj-flow-node-running-banner\">\n <i class=\"fa-solid fa-spinner fa-spin\" aria-hidden=\"true\"></i>\n <span>Running</span>\n </div>\n } @else if (isQueued) {\n <div class=\"mj-flow-node-queued-banner\">\n <i class=\"fa-solid fa-hourglass-start\" aria-hidden=\"true\"></i>\n <span>Next \u2014 waiting for the engine</span>\n </div>\n }\n\n <!-- Warning banner (shown inline when step is misconfigured) -->\n @if (Node.Status === 'warning' && Node.StatusMessage) {\n <div\n class=\"mj-flow-node-warning-banner\"\n [title]=\"Node.StatusMessage\">\n <i class=\"fa-solid fa-triangle-exclamation\"></i>\n <span>{{ Node.StatusMessage }}</span>\n </div>\n }\n\n <!-- Badges row -->\n @if (Node.Badges && Node.Badges.length > 0) {\n <div class=\"mj-flow-node-badges\">\n @for (badge of Node.Badges; track badge) {\n <span\n class=\"mj-flow-node-badge\"\n [style.borderColor]=\"badge.Color || headerColor\"\n [title]=\"badge.Label\">\n @if (badge.Icon) {\n <i class=\"fa-solid\" [ngClass]=\"badge.Icon\"></i>\n }\n {{ badge.Value }}\n </span>\n }\n </div>\n }\n</div>\n\n<!-- Output Port -->\n@if (outputPort) {\n <div\n class=\"mj-flow-node-port mj-flow-node-port--output\"\n [class]=\"'mj-flow-node-port--' + outputPort.Side\"\n fNodeOutput\n [fOutputId]=\"outputPort.ID\"\n [fOutputDisabled]=\"outputPort.Disabled\"\n [fOutputMultiple]=\"outputPort.Multiple\"\n [isSelfConnectable]=\"false\">\n </div>\n}\n", styles: ["/* ============================================================\n Flow Node \u2014 Visual design for individual flow graph nodes\n ============================================================ */\n\nmj-flow-node {\n display: block;\n position: relative;\n cursor: default;\n transition: filter 0.15s ease, box-shadow 0.15s ease;\n}\n\n.mj-flow-node-body {\n position: relative;\n min-width: 200px;\n max-width: 280px;\n background: var(--mj-bg-surface);\n border: 1px solid var(--mj-border-default);\n border-radius: var(--mj-radius-lg);\n overflow: hidden;\n box-shadow: var(--mj-shadow-sm);\n transition: border-color 0.15s ease, box-shadow 0.15s ease, opacity 0.15s ease;\n}\n\n.mj-flow-node-body:hover {\n box-shadow: var(--mj-shadow-md);\n border-color: var(--mj-border-strong);\n}\n\n/* Selected state \u2014 applied by Foblex on the host fNode element */\n.f-selected .mj-flow-node-body {\n border-color: var(--mj-brand-primary);\n box-shadow: 0 0 0 2px color-mix(in srgb, var(--mj-brand-primary) 25%, transparent), var(--mj-shadow-md);\n}\n\n/* Status variants */\n.mj-flow-node-body--start {\n border: 2px solid var(--mj-status-success);\n background: color-mix(in srgb, var(--mj-status-success) 5%, var(--mj-bg-surface));\n box-shadow: 0 0 0 3px color-mix(in srgb, var(--mj-status-success) 12%, transparent),\n 0 2px 8px color-mix(in srgb, var(--mj-status-success) 15%, transparent);\n}\n\n.mj-flow-node-body--start:hover {\n box-shadow: 0 0 0 3px color-mix(in srgb, var(--mj-status-success) 18%, transparent),\n 0 4px 16px color-mix(in srgb, var(--mj-status-success) 20%, transparent);\n}\n\n.f-selected .mj-flow-node-body--start {\n border-color: var(--mj-status-success);\n box-shadow: 0 0 0 3px color-mix(in srgb, var(--mj-status-success) 30%, transparent),\n 0 4px 12px color-mix(in srgb, var(--mj-status-success) 15%, transparent);\n}\n\n.mj-flow-node-body--disabled {\n opacity: 0.5;\n filter: grayscale(0.5);\n}\n\n.mj-flow-node-body--pending {\n opacity: 0.7;\n border-style: dashed;\n}\n\n.mj-flow-node-body--queued {\n opacity: 1;\n border: 2px dashed var(--mj-brand-primary);\n background: color-mix(in srgb, var(--mj-brand-primary) 6%, var(--mj-bg-surface));\n box-shadow: 0 0 0 3px color-mix(in srgb, var(--mj-brand-primary) 16%, transparent);\n animation: mj-flow-node-queued 1.8s ease-in-out infinite;\n}\n\n.mj-flow-node-body--running {\n opacity: 1;\n border: 2px solid var(--mj-brand-primary);\n background: color-mix(in srgb, var(--mj-brand-primary) 8%, var(--mj-bg-surface));\n box-shadow: 0 0 0 4px color-mix(in srgb, var(--mj-brand-primary) 22%, transparent),\n var(--mj-shadow-md);\n animation: mj-flow-node-pulse 1.1s ease-in-out infinite;\n}\n\n/* Debugger: this step is next and nothing starts until the operator continues. */\n.mj-flow-node-body--awaiting {\n opacity: 1;\n border: 2px solid var(--mj-brand-primary);\n background: color-mix(in srgb, var(--mj-brand-primary) 10%, var(--mj-bg-surface));\n box-shadow: 0 0 0 4px color-mix(in srgb, var(--mj-brand-primary) 28%, transparent),\n var(--mj-shadow-md);\n animation: mj-flow-node-awaiting 1.6s ease-in-out infinite;\n}\n.f-selected .mj-flow-node-body--awaiting {\n border-color: var(--mj-brand-primary);\n box-shadow: 0 0 0 5px color-mix(in srgb, var(--mj-brand-primary) 35%, transparent),\n var(--mj-shadow-md);\n}\n\n.mj-flow-node-awaiting-banner {\n display: flex;\n align-items: center;\n gap: 6px;\n margin: 2px 8px 6px;\n padding: 5px 8px;\n background: color-mix(in srgb, var(--mj-brand-primary) 16%, var(--mj-bg-surface));\n border: 1px solid var(--mj-brand-primary);\n border-radius: var(--mj-radius-sm);\n font-size: 11px;\n font-weight: 700;\n color: var(--mj-brand-primary);\n line-height: 1.3;\n}\n.mj-flow-node-awaiting-banner i { font-size: 10px; flex-shrink: 0; }\n\n.mj-flow-node-running-banner,\n.mj-flow-node-queued-banner {\n display: flex;\n align-items: center;\n gap: 6px;\n margin: 2px 8px 6px;\n padding: 5px 8px;\n border-radius: var(--mj-radius-sm);\n font-size: 11px;\n font-weight: 700;\n line-height: 1.3;\n}\n.mj-flow-node-running-banner {\n background: color-mix(in srgb, var(--mj-brand-primary) 16%, var(--mj-bg-surface));\n border: 1px solid var(--mj-brand-primary);\n color: var(--mj-brand-primary);\n}\n.mj-flow-node-queued-banner {\n background: color-mix(in srgb, var(--mj-brand-primary) 8%, var(--mj-bg-surface));\n border: 1px dashed var(--mj-brand-primary);\n color: var(--mj-brand-primary);\n}\n.mj-flow-node-running-banner i,\n.mj-flow-node-queued-banner i { font-size: 10px; flex-shrink: 0; }\n\n.mj-flow-node-body--warning {\n border: 2px solid var(--mj-status-warning);\n background: color-mix(in srgb, var(--mj-status-warning) 5%, var(--mj-bg-surface));\n box-shadow: 0 0 0 2px color-mix(in srgb, var(--mj-status-warning) 15%, transparent),\n 0 2px 8px color-mix(in srgb, var(--mj-status-warning) 10%, transparent);\n}\n\n.mj-flow-node-body--warning:hover {\n box-shadow: 0 0 0 2px color-mix(in srgb, var(--mj-status-warning) 25%, transparent),\n 0 4px 16px color-mix(in srgb, var(--mj-status-warning) 15%, transparent);\n}\n\n.f-selected .mj-flow-node-body--warning {\n border-color: var(--mj-status-warning);\n box-shadow: 0 0 0 3px color-mix(in srgb, var(--mj-status-warning) 30%, transparent),\n 0 4px 12px color-mix(in srgb, var(--mj-status-warning) 15%, transparent);\n}\n\n.mj-flow-node-body--error {\n border-color: var(--mj-status-error);\n background: var(--mj-status-error-subtle);\n}\n\n.mj-flow-node-body--success {\n border-color: var(--mj-status-success);\n}\n\n/* Color accent bar at top */\n.mj-flow-node-accent {\n height: 3px;\n width: 100%;\n}\n\n/* Header row */\n.mj-flow-node-header {\n display: flex;\n align-items: center;\n justify-content: space-between;\n padding: 8px 12px 4px;\n gap: 8px;\n}\n\n.mj-flow-node-header-left {\n display: flex;\n align-items: center;\n gap: 8px;\n min-width: 0;\n flex: 1;\n}\n\n.mj-flow-node-header-right {\n display: flex;\n align-items: center;\n gap: 6px;\n flex-shrink: 0;\n}\n\n.mj-flow-node-icon {\n font-size: var(--mj-text-sm);\n flex-shrink: 0;\n}\n\n.mj-flow-node-logo {\n width: 18px;\n height: 18px;\n border-radius: var(--mj-radius-sm);\n object-fit: contain;\n flex-shrink: 0;\n}\n\n.mj-flow-node-label {\n font-size: var(--mj-text-sm);\n font-weight: 600;\n color: var(--mj-text-primary);\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n line-height: 1.3;\n}\n\n.mj-flow-node-start-badge {\n font-size: 9px;\n font-weight: 700;\n letter-spacing: 0.5px;\n color: var(--mj-text-inverse);\n background: var(--mj-status-success);\n border: none;\n border-radius: var(--mj-radius-sm);\n padding: 2px 6px;\n line-height: 1.4;\n box-shadow: 0 1px 3px color-mix(in srgb, var(--mj-status-success) 30%, transparent);\n}\n\n/* Status indicator */\n.mj-flow-node-status {\n font-size: var(--mj-text-xs);\n}\n\n.mj-flow-node-status--success { color: var(--mj-status-success); }\n.mj-flow-node-status--error { color: var(--mj-status-error); }\n.mj-flow-node-status--warning { color: var(--mj-status-warning); }\n.mj-flow-node-status--running { color: var(--mj-brand-primary); }\n.mj-flow-node-status--disabled { color: var(--mj-text-disabled); }\n.mj-flow-node-status--pending { color: var(--mj-status-warning); }\n\n/* Subtitle line */\n.mj-flow-node-subtitle {\n padding: 0 12px 2px;\n font-size: var(--mj-text-xs);\n color: var(--mj-text-secondary);\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n line-height: 1.4;\n}\n\n/* Type badge */\n.mj-flow-node-type-badge {\n padding: 2px 12px 6px;\n font-size: 10px;\n font-weight: 500;\n text-transform: uppercase;\n letter-spacing: 0.3px;\n opacity: 0.7;\n}\n\n/* Warning banner \u2014 inline alert on misconfigured nodes */\n.mj-flow-node-warning-banner {\n display: flex;\n align-items: center;\n gap: 5px;\n margin: 2px 8px 6px;\n padding: 4px 8px;\n background: var(--mj-status-warning-bg);\n border: 1px solid var(--mj-status-warning-border);\n border-radius: 5px;\n font-size: 10px;\n font-weight: 600;\n color: var(--mj-status-warning-text);\n line-height: 1.3;\n}\n\n.mj-flow-node-warning-banner i {\n font-size: 10px;\n flex-shrink: 0;\n color: var(--mj-status-warning);\n}\n\n.mj-flow-node-warning-banner span {\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n}\n\n/* Badges row */\n.mj-flow-node-badges {\n display: flex;\n gap: 4px;\n padding: 0 10px 8px;\n flex-wrap: wrap;\n}\n\n.mj-flow-node-badge {\n display: inline-flex;\n align-items: center;\n gap: 3px;\n font-size: 10px;\n color: var(--mj-text-muted);\n background: var(--mj-bg-page);\n border: 1px solid var(--mj-border-default);\n border-radius: var(--mj-radius-sm);\n padding: 1px 6px;\n line-height: 1.4;\n}\n\n.mj-flow-node-badge i {\n font-size: 9px;\n}\n\n/* ============================================================\n Loop Node \u2014 distinctive container for ForEach/While\n ============================================================ */\n\n.mj-flow-node-body--loop {\n min-width: 230px;\n max-width: 300px;\n border-width: 2px;\n border-style: solid;\n border-image: none;\n background: color-mix(in srgb, var(--mj-status-warning) 5%, var(--mj-bg-surface));\n}\n\n.mj-flow-node-body--loop.mj-flow-node-body--awaiting {\n border-color: var(--mj-brand-primary);\n background: color-mix(in srgb, var(--mj-brand-primary) 10%, var(--mj-bg-surface));\n}\n\n.mj-flow-node-body--loop:hover {\n box-shadow: 0 4px 14px color-mix(in srgb, var(--mj-status-warning) 12%, transparent), var(--mj-shadow-sm);\n}\n\n.f-selected .mj-flow-node-body--loop {\n border-color: var(--mj-status-warning);\n box-shadow: 0 0 0 2px color-mix(in srgb, var(--mj-status-warning) 25%, transparent), var(--mj-shadow-md);\n}\n\n/* Loop section container */\n.mj-flow-loop-section {\n padding: 0 10px 8px;\n}\n\n/* Iteration summary (e.g., \"over items\" / \"while condition\") */\n.mj-flow-loop-iteration {\n display: flex;\n align-items: center;\n gap: 5px;\n padding: 3px 0 6px;\n font-size: 10px;\n font-weight: 500;\n color: var(--mj-status-warning-text);\n letter-spacing: 0.2px;\n}\n\n.mj-flow-loop-iteration-icon {\n font-size: 9px;\n color: var(--mj-status-warning);\n}\n\n.mj-flow-loop-max {\n color: var(--mj-status-warning-text);\n opacity: 0.7;\n}\n\n/* Inner body card \u2014 the \"iterated operation\" */\n.mj-flow-loop-body {\n border: 1.5px dashed var(--mj-border-strong);\n border-radius: 7px;\n background: var(--mj-bg-surface);\n transition: border-color 0.15s ease;\n}\n\n.mj-flow-loop-body:not(.mj-flow-loop-body--empty) {\n border-color: var(--mj-border-default);\n background: var(--mj-bg-surface-card);\n}\n\n.mj-flow-loop-body-inner {\n padding: 6px 10px;\n}\n\n.mj-flow-loop-body-header {\n display: flex;\n align-items: center;\n gap: 6px;\n margin-bottom: 2px;\n}\n\n.mj-flow-loop-body-header i {\n font-size: 11px;\n}\n\n.mj-flow-loop-body-type {\n font-size: 10px;\n font-weight: 700;\n text-transform: uppercase;\n letter-spacing: 0.4px;\n}\n\n.mj-flow-loop-body-name {\n font-size: 11px;\n font-weight: 500;\n color: var(--mj-text-primary);\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n padding-left: 17px;\n line-height: 1.4;\n}\n\n.mj-flow-loop-body-name--empty {\n color: var(--mj-text-disabled);\n font-style: italic;\n font-weight: 400;\n}\n\n/* Empty body card \u2014 no body type selected */\n.mj-flow-loop-body--empty {\n border-color: var(--mj-status-warning-border);\n border-style: dashed;\n background: color-mix(in srgb, var(--mj-status-warning) 4%, var(--mj-bg-surface));\n}\n\n.mj-flow-loop-body-empty {\n display: flex;\n align-items: center;\n gap: 6px;\n padding: 8px 10px;\n font-size: 10px;\n font-weight: 500;\n color: var(--mj-status-warning-text);\n}\n\n.mj-flow-loop-body-empty i {\n font-size: 11px;\n color: var(--mj-status-warning);\n}\n\n/* Item variable badge */\n.mj-flow-loop-variable {\n display: inline-flex;\n align-items: center;\n gap: 4px;\n margin-top: 5px;\n font-size: 9px;\n font-weight: 500;\n color: var(--mj-text-muted);\n background: var(--mj-bg-surface-card);\n border: 1px solid var(--mj-border-default);\n border-radius: var(--mj-radius-sm);\n padding: 1px 6px;\n}\n\n.mj-flow-loop-variable i {\n font-size: 8px;\n color: var(--mj-text-disabled);\n}\n\n/* ============================================================\n Ports (Input/Output connectors)\n ============================================================ */\n\n.mj-flow-node-port {\n position: absolute;\n width: 14px;\n height: 14px;\n border-radius: var(--mj-radius-full);\n background: var(--mj-bg-surface);\n border: 2px solid var(--mj-text-disabled);\n z-index: 10;\n transition: border-color 0.15s ease, transform 0.15s ease, background-color 0.15s ease;\n cursor: crosshair;\n}\n\n.mj-flow-node-port:hover {\n border-color: var(--mj-brand-primary);\n transform: scale(1.3);\n background: var(--mj-brand-primary-subtle);\n}\n\n/* Position based on side */\n.mj-flow-node-port--top {\n top: -7px;\n left: 50%;\n transform: translateX(-50%);\n}\n\n.mj-flow-node-port--top:hover {\n transform: translateX(-50%) scale(1.3);\n}\n\n.mj-flow-node-port--bottom {\n bottom: -7px;\n left: 50%;\n transform: translateX(-50%);\n}\n\n.mj-flow-node-port--bottom:hover {\n transform: translateX(-50%) scale(1.3);\n}\n\n.mj-flow-node-port--left {\n left: -7px;\n top: 50%;\n transform: translateY(-50%);\n}\n\n.mj-flow-node-port--left:hover {\n transform: translateY(-50%) scale(1.3);\n}\n\n.mj-flow-node-port--right {\n right: -7px;\n top: 50%;\n transform: translateY(-50%);\n}\n\n.mj-flow-node-port--right:hover {\n transform: translateY(-50%) scale(1.3);\n}\n\n/* Disabled port */\n.mj-flow-node-port.f-node-input-disabled,\n.mj-flow-node-port.f-node-output-disabled {\n opacity: 0;\n pointer-events: none;\n}\n\n/* ============================================================\n Animations\n ============================================================ */\n\n@keyframes mj-flow-node-pulse {\n 0%, 100% {\n box-shadow: 0 0 0 4px color-mix(in srgb, var(--mj-brand-primary) 22%, transparent),\n var(--mj-shadow-md);\n }\n 50% {\n box-shadow: 0 0 0 8px color-mix(in srgb, var(--mj-brand-primary) 8%, transparent),\n var(--mj-shadow-md);\n }\n}\n\n@keyframes mj-flow-node-queued {\n 0%, 100% {\n box-shadow: 0 0 0 3px color-mix(in srgb, var(--mj-brand-primary) 16%, transparent);\n }\n 50% {\n box-shadow: 0 0 0 6px color-mix(in srgb, var(--mj-brand-primary) 6%, transparent);\n }\n}\n\n@keyframes mj-flow-node-awaiting {\n 0%, 100% {\n box-shadow: 0 0 0 4px color-mix(in srgb, var(--mj-brand-primary) 28%, transparent),\n var(--mj-shadow-md);\n }\n 50% {\n box-shadow: 0 0 0 8px color-mix(in srgb, var(--mj-brand-primary) 8%, transparent),\n var(--mj-shadow-md);\n }\n}\n\n/* ============================================================\n A step the graph did not take\n ============================================================\n Its own treatment rather than a shade of `disabled`: disabled means \"cannot run\", skipped means\n \"the workflow chose another route\". A reader who cannot tell them apart goes looking for a\n failure that never happened.\n\n Hatching + strike-through, deliberately the same language the run timeline uses for the same\n fact, so a step reads identically whether someone is looking at the list or the diagram. */\n.mj-flow-node-body--skipped {\n opacity: 0.55;\n background-image: repeating-linear-gradient(\n 135deg,\n transparent,\n transparent 5px,\n color-mix(in srgb, var(--mj-text-disabled) 22%, transparent) 5px,\n color-mix(in srgb, var(--mj-text-disabled) 22%, transparent) 10px\n );\n}\n\n.mj-flow-node-body--skipped .mj-flow-node-title {\n text-decoration: line-through;\n text-decoration-color: var(--mj-text-disabled);\n}\n\n.mj-flow-node-status--skipped { color: var(--mj-text-disabled); }\n"] }]
|
|
348
383
|
}], null, { Node: [{
|
|
349
384
|
type: Input
|
|
350
385
|
}], TypeConfig: [{
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"flow-node.component.js","sourceRoot":"","sources":["../../../src/lib/components/flow-node.component.ts","../../../src/lib/components/flow-node.component.html"],"names":[],"mappings":"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","sourcesContent":["import { Component, Input, ViewEncapsulation, ChangeDetectionStrategy } from '@angular/core';\nimport { FlowNode, FlowNodeTypeConfig } from '../interfaces/flow-types';\n\n/**\n * Renders a single node in the flow canvas.\n * Applied with Foblex's fNode directive in the parent FlowEditorComponent template.\n * Contains input/output ports via Foblex's fNodeInput/fNodeOutput directives.\n */\n@Component({\n standalone: false,\n selector: 'mj-flow-node',\n templateUrl: './flow-node.component.html',\n styleUrls: ['./flow-node.component.css'],\n encapsulation: ViewEncapsulation.None,\n changeDetection: ChangeDetectionStrategy.OnPush\n})\nexport class FlowNodeComponent {\n @Input() Node!: FlowNode;\n @Input() TypeConfig: FlowNodeTypeConfig | null = null;\n @Input() ReadOnly = false;\n @Input() Compact = false;\n\n get headerColor(): string {\n return this.TypeConfig?.Color ?? '#6B7280';\n }\n\n get nodeIcon(): string {\n return this.Node?.Icon ?? this.TypeConfig?.Icon ?? 'fa-circle-nodes';\n }\n\n get logoURL(): string | null {\n return (this.Node?.Data?.['LogoURL'] as string) ?? null;\n }\n\n get statusClass(): string {\n return this.Node?.Status ?? 'default';\n }\n\n get statusIcon(): string {\n switch (this.Node?.Status) {\n case 'success': return 'fa-check-circle';\n case 'error': return 'fa-times-circle';\n case 'warning': return 'fa-exclamation-triangle';\n case 'running': return 'fa-spinner fa-spin';\n case 'disabled': return 'fa-ban';\n case 'pending': return 'fa-clock';\n default: return '';\n }\n }\n\n get hasStatus(): boolean {\n return this.Node?.Status != null && this.Node.Status !== 'default';\n }\n\n get inputPort(): { ID: string; Side: string; Multiple: boolean; Disabled: boolean } | null {\n const port = this.Node?.Ports?.find(p => p.Direction === 'input');\n if (!port) return null;\n return {\n ID: port.ID,\n Side: port.Side ?? 'top',\n Multiple: port.Multiple !== false,\n Disabled: port.Disabled === true\n };\n }\n\n get outputPort(): { ID: string; Side: string; Multiple: boolean; Disabled: boolean } | null {\n const port = this.Node?.Ports?.find(p => p.Direction === 'output');\n if (!port) return null;\n return {\n ID: port.ID,\n Side: port.Side ?? 'bottom',\n Multiple: port.Multiple !== false,\n Disabled: port.Disabled === true\n };\n }\n\n // ── Loop Node Properties ───────────────────────────────────\n\n /** Whether this node represents a loop (ForEach or While) */\n get isLoopNode(): boolean {\n return this.Node?.Type === 'ForEach' || this.Node?.Type === 'While';\n }\n\n /** Loop body type label (e.g., 'Action', 'Prompt', 'Sub-Agent') */\n get loopBodyType(): string | null {\n return (this.Node?.Data?.['LoopBodyType'] as string) ?? null;\n }\n\n /** Resolved name of the loop body operation */\n get loopBodyName(): string | null {\n return (this.Node?.Data?.['LoopBodyName'] as string) ?? null;\n }\n\n /** Icon for the loop body type */\n get loopBodyIcon(): string {\n return (this.Node?.Data?.['LoopBodyIcon'] as string) ?? 'fa-circle-nodes';\n }\n\n /** Color for the loop body type */\n get loopBodyColor(): string {\n return (this.Node?.Data?.['LoopBodyColor'] as string) ?? '#6B7280';\n }\n\n /** Short iteration summary (e.g., \"over items\" or \"while condition\") */\n get loopIterationSummary(): string {\n return (this.Node?.Data?.['LoopIterationSummary'] as string) ?? '';\n }\n\n /** Max iterations limit, if configured */\n get loopMaxIterations(): number | null {\n const val = this.Node?.Data?.['MaxIterations'];\n return typeof val === 'number' ? val : null;\n }\n\n /** Loop item variable name */\n get loopItemVariable(): string | null {\n return (this.Node?.Data?.['LoopItemVariable'] as string) ?? null;\n }\n}\n","<!-- Input Port -->\n@if (inputPort) {\n <div\n class=\"mj-flow-node-port mj-flow-node-port--input\"\n [class]=\"'mj-flow-node-port--' + inputPort.Side\"\n fNodeInput\n [fInputId]=\"inputPort.ID\"\n [fInputDisabled]=\"inputPort.Disabled\"\n [fInputMultiple]=\"inputPort.Multiple\">\n </div>\n}\n\n<!-- Node Body -->\n<div class=\"mj-flow-node-body\"\n [class.mj-flow-node-body--start]=\"Node.IsStartNode\"\n [class.mj-flow-node-body--loop]=\"isLoopNode\"\n [class.mj-flow-node-body--disabled]=\"Node.Status === 'disabled'\"\n [class.mj-flow-node-body--pending]=\"Node.Status === 'pending'\"\n [class.mj-flow-node-body--running]=\"Node.Status === 'running'\"\n [class.mj-flow-node-body--warning]=\"Node.Status === 'warning'\"\n [class.mj-flow-node-body--error]=\"Node.Status === 'error'\"\n [class.mj-flow-node-body--success]=\"Node.Status === 'success'\">\n\n <!-- Color accent bar -->\n <div class=\"mj-flow-node-accent\" [style.backgroundColor]=\"headerColor\"></div>\n\n <!-- Header -->\n <div class=\"mj-flow-node-header\">\n <div class=\"mj-flow-node-header-left\">\n @if (logoURL) {\n <img class=\"mj-flow-node-logo\" [src]=\"logoURL\" [alt]=\"Node.Label\" />\n }\n @if (!logoURL) {\n <i class=\"fa-solid mj-flow-node-icon\" [ngClass]=\"nodeIcon\" [style.color]=\"headerColor\"></i>\n }\n <span class=\"mj-flow-node-label\">{{ Node.Label }}</span>\n </div>\n <div class=\"mj-flow-node-header-right\">\n @if (Node.IsStartNode) {\n <span class=\"mj-flow-node-start-badge\">START</span>\n }\n @if (hasStatus) {\n <i\n class=\"fa-solid mj-flow-node-status\"\n [ngClass]=\"statusIcon\"\n [class]=\"'mj-flow-node-status--' + statusClass\"\n [title]=\"Node.StatusMessage || ''\"></i>\n }\n </div>\n </div>\n\n <!-- Subtitle / Configured Item (hidden for loop nodes — they use the body card instead) -->\n @if (Node.Subtitle && !isLoopNode) {\n <div class=\"mj-flow-node-subtitle\">\n {{ Node.Subtitle }}\n </div>\n }\n\n <!-- Type badge -->\n <div class=\"mj-flow-node-type-badge\" [style.color]=\"headerColor\">\n {{ TypeConfig?.Label || Node.Type }}\n </div>\n\n <!-- ═══ Loop Body Card — shown only for ForEach/While nodes ═══ -->\n @if (isLoopNode) {\n <div class=\"mj-flow-loop-section\">\n <!-- Iteration summary line -->\n @if (loopIterationSummary) {\n <div class=\"mj-flow-loop-iteration\">\n <i class=\"fa-solid fa-repeat mj-flow-loop-iteration-icon\"></i>\n <span>{{ loopIterationSummary }}</span>\n @if (loopMaxIterations != null) {\n <span class=\"mj-flow-loop-max\">(max {{ loopMaxIterations }})</span>\n }\n </div>\n }\n <!-- Body type inner card -->\n <div class=\"mj-flow-loop-body\"\n [class.mj-flow-loop-body--empty]=\"!loopBodyType\">\n @if (loopBodyType) {\n <div class=\"mj-flow-loop-body-inner\">\n <div class=\"mj-flow-loop-body-header\">\n <i class=\"fa-solid\" [ngClass]=\"loopBodyIcon\" [style.color]=\"loopBodyColor\"></i>\n <span class=\"mj-flow-loop-body-type\" [style.color]=\"loopBodyColor\">{{ loopBodyType }}</span>\n </div>\n @if (loopBodyName) {\n <div class=\"mj-flow-loop-body-name\" [title]=\"loopBodyName\">\n {{ loopBodyName }}\n </div>\n }\n @if (!loopBodyName) {\n <div class=\"mj-flow-loop-body-name mj-flow-loop-body-name--empty\">\n Not configured\n </div>\n }\n </div>\n }\n @if (!loopBodyType) {\n <div class=\"mj-flow-loop-body-empty\">\n <i class=\"fa-solid fa-circle-question\"></i>\n <span>No body type selected</span>\n </div>\n }\n </div>\n <!-- Item variable badge -->\n @if (loopItemVariable) {\n <div class=\"mj-flow-loop-variable\">\n <i class=\"fa-solid fa-tag\"></i>\n <span>{{ loopItemVariable }}</span>\n </div>\n }\n </div>\n }\n\n <!-- Warning banner (shown inline when step is misconfigured) -->\n @if (Node.Status === 'warning' && Node.StatusMessage) {\n <div\n class=\"mj-flow-node-warning-banner\"\n [title]=\"Node.StatusMessage\">\n <i class=\"fa-solid fa-triangle-exclamation\"></i>\n <span>{{ Node.StatusMessage }}</span>\n </div>\n }\n\n <!-- Badges row -->\n @if (Node.Badges && Node.Badges.length > 0) {\n <div class=\"mj-flow-node-badges\">\n @for (badge of Node.Badges; track badge) {\n <span\n class=\"mj-flow-node-badge\"\n [style.borderColor]=\"badge.Color || headerColor\"\n [title]=\"badge.Label\">\n @if (badge.Icon) {\n <i class=\"fa-solid\" [ngClass]=\"badge.Icon\"></i>\n }\n {{ badge.Value }}\n </span>\n }\n </div>\n }\n</div>\n\n<!-- Output Port -->\n@if (outputPort) {\n <div\n class=\"mj-flow-node-port mj-flow-node-port--output\"\n [class]=\"'mj-flow-node-port--' + outputPort.Side\"\n fNodeOutput\n [fOutputId]=\"outputPort.ID\"\n [fOutputDisabled]=\"outputPort.Disabled\"\n [fOutputMultiple]=\"outputPort.Multiple\"\n [isSelfConnectable]=\"false\">\n </div>\n}\n"]}
|
|
1
|
+
{"version":3,"file":"flow-node.component.js","sourceRoot":"","sources":["../../../src/lib/components/flow-node.component.ts","../../../src/lib/components/flow-node.component.html"],"names":[],"mappings":"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","sourcesContent":["import { Component, Input, ViewEncapsulation, ChangeDetectionStrategy } from '@angular/core';\nimport { FlowNode, FlowNodeTypeConfig } from '../interfaces/flow-types';\n\n/**\n * Renders a single node in the flow canvas.\n * Applied with Foblex's fNode directive in the parent FlowEditorComponent template.\n * Contains input/output ports via Foblex's fNodeInput/fNodeOutput directives.\n */\n@Component({\n standalone: false,\n selector: 'mj-flow-node',\n templateUrl: './flow-node.component.html',\n styleUrls: ['./flow-node.component.css'],\n encapsulation: ViewEncapsulation.None,\n changeDetection: ChangeDetectionStrategy.OnPush\n})\nexport class FlowNodeComponent {\n @Input() Node!: FlowNode;\n @Input() TypeConfig: FlowNodeTypeConfig | null = null;\n @Input() ReadOnly = false;\n @Input() Compact = false;\n\n get headerColor(): string {\n return this.TypeConfig?.Color ?? '#6B7280';\n }\n\n get nodeIcon(): string {\n return this.Node?.Icon ?? this.TypeConfig?.Icon ?? 'fa-circle-nodes';\n }\n\n get logoURL(): string | null {\n return (this.Node?.Data?.['LogoURL'] as string) ?? null;\n }\n\n get statusClass(): string {\n return this.Node?.Status ?? 'default';\n }\n\n get statusIcon(): string {\n switch (this.Node?.Status) {\n case 'success': return 'fa-check-circle';\n case 'error': return 'fa-times-circle';\n case 'warning': return 'fa-exclamation-triangle';\n case 'running': return 'fa-spinner fa-spin';\n case 'disabled': return 'fa-ban';\n case 'pending': return 'fa-clock';\n default: return '';\n }\n }\n\n get hasStatus(): boolean {\n return this.Node?.Status != null && this.Node.Status !== 'default';\n }\n\n /** Debugger chrome: this step is waiting for Continue / Step, not executing. */\n get isAwaitingUser(): boolean {\n return this.Node?.Data?.['AwaitingUser'] === true;\n }\n\n /** Prerequisites are done; the dispatcher has not claimed it yet. */\n get isQueued(): boolean {\n return !this.isAwaitingUser && this.Node?.Data?.['NextToRun'] === true;\n }\n\n get isExecuting(): boolean {\n return !this.isAwaitingUser && this.Node?.Status === 'running';\n }\n\n get inputPort(): { ID: string; Side: string; Multiple: boolean; Disabled: boolean } | null {\n const port = this.Node?.Ports?.find(p => p.Direction === 'input');\n if (!port) return null;\n return {\n ID: port.ID,\n Side: port.Side ?? 'top',\n Multiple: port.Multiple !== false,\n Disabled: port.Disabled === true\n };\n }\n\n get outputPort(): { ID: string; Side: string; Multiple: boolean; Disabled: boolean } | null {\n const port = this.Node?.Ports?.find(p => p.Direction === 'output');\n if (!port) return null;\n return {\n ID: port.ID,\n Side: port.Side ?? 'bottom',\n Multiple: port.Multiple !== false,\n Disabled: port.Disabled === true\n };\n }\n\n // ── Loop Node Properties ───────────────────────────────────\n\n /** Whether this node represents a loop (ForEach or While) */\n get isLoopNode(): boolean {\n return this.Node?.Type === 'ForEach' || this.Node?.Type === 'While';\n }\n\n /** Loop body type label (e.g., 'Action', 'Prompt', 'Sub-Agent') */\n get loopBodyType(): string | null {\n return (this.Node?.Data?.['LoopBodyType'] as string) ?? null;\n }\n\n /** Resolved name of the loop body operation */\n get loopBodyName(): string | null {\n return (this.Node?.Data?.['LoopBodyName'] as string) ?? null;\n }\n\n /** Icon for the loop body type */\n get loopBodyIcon(): string {\n return (this.Node?.Data?.['LoopBodyIcon'] as string) ?? 'fa-circle-nodes';\n }\n\n /** Color for the loop body type */\n get loopBodyColor(): string {\n return (this.Node?.Data?.['LoopBodyColor'] as string) ?? '#6B7280';\n }\n\n /** Short iteration summary (e.g., \"over items\" or \"while condition\") */\n get loopIterationSummary(): string {\n return (this.Node?.Data?.['LoopIterationSummary'] as string) ?? '';\n }\n\n /** Max iterations limit, if configured */\n get loopMaxIterations(): number | null {\n const val = this.Node?.Data?.['MaxIterations'];\n return typeof val === 'number' ? val : null;\n }\n\n /** Loop item variable name */\n get loopItemVariable(): string | null {\n return (this.Node?.Data?.['LoopItemVariable'] as string) ?? null;\n }\n}\n","<!-- Input Port -->\n@if (inputPort) {\n <div\n class=\"mj-flow-node-port mj-flow-node-port--input\"\n [class]=\"'mj-flow-node-port--' + inputPort.Side\"\n fNodeInput\n [fInputId]=\"inputPort.ID\"\n [fInputDisabled]=\"inputPort.Disabled\"\n [fInputMultiple]=\"inputPort.Multiple\">\n </div>\n}\n\n<!-- Node Body -->\n<div class=\"mj-flow-node-body\"\n [class.mj-flow-node-body--start]=\"Node.IsStartNode\"\n [class.mj-flow-node-body--loop]=\"isLoopNode\"\n [class.mj-flow-node-body--disabled]=\"Node.Status === 'disabled'\"\n [class.mj-flow-node-body--pending]=\"Node.Status === 'pending'\"\n [class.mj-flow-node-body--skipped]=\"Node.Status === 'skipped'\"\n [class.mj-flow-node-body--running]=\"isExecuting\"\n [class.mj-flow-node-body--queued]=\"isQueued\"\n [class.mj-flow-node-body--awaiting]=\"isAwaitingUser\"\n [class.mj-flow-node-body--warning]=\"Node.Status === 'warning'\"\n [class.mj-flow-node-body--error]=\"Node.Status === 'error'\"\n [class.mj-flow-node-body--success]=\"Node.Status === 'success'\">\n\n <!-- Color accent bar -->\n <div class=\"mj-flow-node-accent\" [style.backgroundColor]=\"headerColor\"></div>\n\n <!-- Header -->\n <div class=\"mj-flow-node-header\">\n <div class=\"mj-flow-node-header-left\">\n @if (logoURL) {\n <img class=\"mj-flow-node-logo\" [src]=\"logoURL\" [alt]=\"Node.Label\" />\n }\n @if (!logoURL) {\n <i class=\"fa-solid mj-flow-node-icon\" [ngClass]=\"nodeIcon\" [style.color]=\"headerColor\"></i>\n }\n <span class=\"mj-flow-node-label\">{{ Node.Label }}</span>\n </div>\n <div class=\"mj-flow-node-header-right\">\n @if (Node.IsStartNode) {\n <span class=\"mj-flow-node-start-badge\">START</span>\n }\n @if (hasStatus) {\n <i\n class=\"fa-solid mj-flow-node-status\"\n [ngClass]=\"statusIcon\"\n [class]=\"'mj-flow-node-status--' + statusClass\"\n [title]=\"Node.StatusMessage || ''\"></i>\n }\n </div>\n </div>\n\n <!-- Subtitle / Configured Item (hidden for loop nodes — they use the body card instead) -->\n @if (Node.Subtitle && !isLoopNode) {\n <div class=\"mj-flow-node-subtitle\">\n {{ Node.Subtitle }}\n </div>\n }\n\n <!-- Type badge -->\n <div class=\"mj-flow-node-type-badge\" [style.color]=\"headerColor\">\n {{ TypeConfig?.Label || Node.Type }}\n </div>\n\n <!-- ═══ Loop Body Card — shown only for ForEach/While nodes ═══ -->\n @if (isLoopNode) {\n <div class=\"mj-flow-loop-section\">\n <!-- Iteration summary line -->\n @if (loopIterationSummary) {\n <div class=\"mj-flow-loop-iteration\">\n <i class=\"fa-solid fa-repeat mj-flow-loop-iteration-icon\"></i>\n <span>{{ loopIterationSummary }}</span>\n @if (loopMaxIterations != null) {\n <span class=\"mj-flow-loop-max\">(max {{ loopMaxIterations }})</span>\n }\n </div>\n }\n <!-- Body type inner card -->\n <div class=\"mj-flow-loop-body\"\n [class.mj-flow-loop-body--empty]=\"!loopBodyType\">\n @if (loopBodyType) {\n <div class=\"mj-flow-loop-body-inner\">\n <div class=\"mj-flow-loop-body-header\">\n <i class=\"fa-solid\" [ngClass]=\"loopBodyIcon\" [style.color]=\"loopBodyColor\"></i>\n <span class=\"mj-flow-loop-body-type\" [style.color]=\"loopBodyColor\">{{ loopBodyType }}</span>\n </div>\n @if (loopBodyName) {\n <div class=\"mj-flow-loop-body-name\" [title]=\"loopBodyName\">\n {{ loopBodyName }}\n </div>\n }\n @if (!loopBodyName) {\n <div class=\"mj-flow-loop-body-name mj-flow-loop-body-name--empty\">\n Not configured\n </div>\n }\n </div>\n }\n @if (!loopBodyType) {\n <div class=\"mj-flow-loop-body-empty\">\n <i class=\"fa-solid fa-circle-question\"></i>\n <span>No body type selected</span>\n </div>\n }\n </div>\n <!-- Item variable badge -->\n @if (loopItemVariable) {\n <div class=\"mj-flow-loop-variable\">\n <i class=\"fa-solid fa-tag\"></i>\n <span>{{ loopItemVariable }}</span>\n </div>\n }\n </div>\n }\n\n @if (isAwaitingUser) {\n <div class=\"mj-flow-node-awaiting-banner\">\n <i class=\"fa-solid fa-pause\" aria-hidden=\"true\"></i>\n <span>Waiting on you — Continue or Step</span>\n </div>\n } @else if (isExecuting) {\n <div class=\"mj-flow-node-running-banner\">\n <i class=\"fa-solid fa-spinner fa-spin\" aria-hidden=\"true\"></i>\n <span>Running</span>\n </div>\n } @else if (isQueued) {\n <div class=\"mj-flow-node-queued-banner\">\n <i class=\"fa-solid fa-hourglass-start\" aria-hidden=\"true\"></i>\n <span>Next — waiting for the engine</span>\n </div>\n }\n\n <!-- Warning banner (shown inline when step is misconfigured) -->\n @if (Node.Status === 'warning' && Node.StatusMessage) {\n <div\n class=\"mj-flow-node-warning-banner\"\n [title]=\"Node.StatusMessage\">\n <i class=\"fa-solid fa-triangle-exclamation\"></i>\n <span>{{ Node.StatusMessage }}</span>\n </div>\n }\n\n <!-- Badges row -->\n @if (Node.Badges && Node.Badges.length > 0) {\n <div class=\"mj-flow-node-badges\">\n @for (badge of Node.Badges; track badge) {\n <span\n class=\"mj-flow-node-badge\"\n [style.borderColor]=\"badge.Color || headerColor\"\n [title]=\"badge.Label\">\n @if (badge.Icon) {\n <i class=\"fa-solid\" [ngClass]=\"badge.Icon\"></i>\n }\n {{ badge.Value }}\n </span>\n }\n </div>\n }\n</div>\n\n<!-- Output Port -->\n@if (outputPort) {\n <div\n class=\"mj-flow-node-port mj-flow-node-port--output\"\n [class]=\"'mj-flow-node-port--' + outputPort.Side\"\n fNodeOutput\n [fOutputId]=\"outputPort.ID\"\n [fOutputDisabled]=\"outputPort.Disabled\"\n [fOutputMultiple]=\"outputPort.Multiple\"\n [isSelfConnectable]=\"false\">\n </div>\n}\n"]}
|
|
@@ -19,7 +19,9 @@ export declare class FlowToolbarComponent {
|
|
|
19
19
|
MinimapToggled: EventEmitter<boolean>;
|
|
20
20
|
LegendToggled: EventEmitter<boolean>;
|
|
21
21
|
PanModeToggled: EventEmitter<boolean>;
|
|
22
|
+
MinimizeClicked: EventEmitter<void>;
|
|
23
|
+
HideClicked: EventEmitter<void>;
|
|
22
24
|
static ɵfac: i0.ɵɵFactoryDeclaration<FlowToolbarComponent, never>;
|
|
23
|
-
static ɵcmp: i0.ɵɵComponentDeclaration<FlowToolbarComponent, "mj-flow-toolbar", never, { "ZoomLevel": { "alias": "ZoomLevel"; "required": false; }; "ShowGrid": { "alias": "ShowGrid"; "required": false; }; "ShowMinimap": { "alias": "ShowMinimap"; "required": false; }; "ShowLegend": { "alias": "ShowLegend"; "required": false; }; "ReadOnly": { "alias": "ReadOnly"; "required": false; }; "PanMode": { "alias": "PanMode"; "required": false; }; }, { "ZoomInClicked": "ZoomInClicked"; "ZoomOutClicked": "ZoomOutClicked"; "FitToScreenClicked": "FitToScreenClicked"; "AutoLayoutClicked": "AutoLayoutClicked"; "GridToggled": "GridToggled"; "MinimapToggled": "MinimapToggled"; "LegendToggled": "LegendToggled"; "PanModeToggled": "PanModeToggled"; }, never, never, false, never>;
|
|
25
|
+
static ɵcmp: i0.ɵɵComponentDeclaration<FlowToolbarComponent, "mj-flow-toolbar", never, { "ZoomLevel": { "alias": "ZoomLevel"; "required": false; }; "ShowGrid": { "alias": "ShowGrid"; "required": false; }; "ShowMinimap": { "alias": "ShowMinimap"; "required": false; }; "ShowLegend": { "alias": "ShowLegend"; "required": false; }; "ReadOnly": { "alias": "ReadOnly"; "required": false; }; "PanMode": { "alias": "PanMode"; "required": false; }; }, { "ZoomInClicked": "ZoomInClicked"; "ZoomOutClicked": "ZoomOutClicked"; "FitToScreenClicked": "FitToScreenClicked"; "AutoLayoutClicked": "AutoLayoutClicked"; "GridToggled": "GridToggled"; "MinimapToggled": "MinimapToggled"; "LegendToggled": "LegendToggled"; "PanModeToggled": "PanModeToggled"; "MinimizeClicked": "MinimizeClicked"; "HideClicked": "HideClicked"; }, never, never, false, never>;
|
|
24
26
|
}
|
|
25
27
|
//# sourceMappingURL=flow-toolbar.component.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"flow-toolbar.component.d.ts","sourceRoot":"","sources":["../../../src/lib/components/flow-toolbar.component.ts"],"names":[],"mappings":"AAAA,OAAO,EAA4B,YAAY,EAA8C,MAAM,eAAe,CAAC;;AAEnH;;;GAGG;AACH,
|
|
1
|
+
{"version":3,"file":"flow-toolbar.component.d.ts","sourceRoot":"","sources":["../../../src/lib/components/flow-toolbar.component.ts"],"names":[],"mappings":"AAAA,OAAO,EAA4B,YAAY,EAA8C,MAAM,eAAe,CAAC;;AAEnH;;;GAGG;AACH,qBAuJa,oBAAoB;IACtB,SAAS,SAAO;IAChB,QAAQ,UAAQ;IAChB,WAAW,UAAQ;IACnB,UAAU,UAAQ;IAClB,QAAQ,UAAS;IACjB,OAAO,UAAS;IAEf,aAAa,qBAA4B;IACzC,cAAc,qBAA4B;IAC1C,kBAAkB,qBAA4B;IAC9C,iBAAiB,qBAA4B;IAC7C,WAAW,wBAA+B;IAC1C,cAAc,wBAA+B;IAC7C,aAAa,wBAA+B;IAC5C,cAAc,wBAA+B;IAC7C,eAAe,qBAA4B;IAC3C,WAAW,qBAA4B;yCAjBtC,oBAAoB;2CAApB,oBAAoB;CAkBhC"}
|