@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.
@@ -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", 17);
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", 18);
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", 19);
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", 26);
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", 20);
57
- i0.ɵɵelement(1, "i", 25);
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", 26);
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", 30);
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", 31);
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", 22)(1, "div", 27);
87
- i0.ɵɵelement(2, "i", 28);
88
- i0.ɵɵelementStart(3, "span", 29);
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", 30);
92
- i0.ɵɵconditionalCreate(6, FlowNodeComponent_Conditional_15_Conditional_3_Conditional_6_Template, 2, 0, "div", 31);
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", 23);
110
- i0.ɵɵelement(1, "i", 32);
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", 24);
117
- i0.ɵɵelement(1, "i", 33);
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", 20);
129
- i0.ɵɵelementStart(2, "div", 21);
130
- i0.ɵɵconditionalCreate(3, FlowNodeComponent_Conditional_15_Conditional_3_Template, 7, 8, "div", 22);
131
- i0.ɵɵconditionalCreate(4, FlowNodeComponent_Conditional_15_Conditional_4_Template, 4, 0, "div", 23);
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", 24);
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", 34);
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 FlowNodeComponent_Conditional_17_For_2_Conditional_1_Template(rf, ctx) { if (rf & 1) {
161
- i0.ɵɵelement(0, "i", 28);
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 FlowNodeComponent_Conditional_17_For_2_Template(rf, ctx) { if (rf & 1) {
167
- i0.ɵɵelementStart(0, "span", 36);
168
- i0.ɵɵconditionalCreate(1, FlowNodeComponent_Conditional_17_For_2_Conditional_1_Template, 1, 1, "i", 28);
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 FlowNodeComponent_Conditional_17_Template(rf, ctx) { if (rf & 1) {
182
- i0.ɵɵelementStart(0, "div", 15);
183
- i0.ɵɵrepeaterCreate(1, FlowNodeComponent_Conditional_17_For_2_Template, 3, 5, "span", 35, i0.ɵɵrepeaterTrackByIdentity);
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 FlowNodeComponent_Conditional_18_Template(rf, ctx) { if (rf & 1) {
191
- i0.ɵɵelement(0, "div", 37);
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: 19, vars: 32, 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-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"], [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) {
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, 2, "div", 14);
310
- i0.ɵɵconditionalCreate(17, FlowNodeComponent_Conditional_17_Template, 3, 0, "div", 15);
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(18, FlowNodeComponent_Conditional_18_Template, 1, 6, "div", 16);
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--running", ctx.Node.Status === "running")("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");
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.Node.Status === "warning" && ctx.Node.StatusMessage ? 16 : -1);
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 ? 17 : -1);
375
+ i0.ɵɵconditional(ctx.Node.Badges && ctx.Node.Badges.length > 0 ? 20 : -1);
341
376
  i0.ɵɵadvance();
342
- i0.ɵɵconditional(ctx.outputPort ? 18 : -1);
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,qBA0Ia,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;yCAf5C,oBAAoB;2CAApB,oBAAoB;CAgBhC"}
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"}