@memberjunction/ng-record-process-studio 6.2.0-edge.0 → 6.2.0-edge.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (21) hide show
  1. package/dist/lib/feature-pipeline-builder/feature-pipeline-builder.component.d.ts +211 -11
  2. package/dist/lib/feature-pipeline-builder/feature-pipeline-builder.component.d.ts.map +1 -1
  3. package/dist/lib/feature-pipeline-builder/feature-pipeline-builder.component.js +1639 -400
  4. package/dist/lib/feature-pipeline-builder/feature-pipeline-builder.component.js.map +1 -1
  5. package/dist/lib/record-process-editor/record-process-editor.component.d.ts +10 -0
  6. package/dist/lib/record-process-editor/record-process-editor.component.d.ts.map +1 -1
  7. package/dist/lib/record-process-editor/record-process-editor.component.js +25 -5
  8. package/dist/lib/record-process-editor/record-process-editor.component.js.map +1 -1
  9. package/dist/lib/record-process-history/record-process-history.component.d.ts +10 -0
  10. package/dist/lib/record-process-history/record-process-history.component.d.ts.map +1 -1
  11. package/dist/lib/record-process-history/record-process-history.component.js +30 -10
  12. package/dist/lib/record-process-history/record-process-history.component.js.map +1 -1
  13. package/dist/lib/record-process-studio/record-process-studio.component.d.ts +12 -0
  14. package/dist/lib/record-process-studio/record-process-studio.component.d.ts.map +1 -1
  15. package/dist/lib/record-process-studio/record-process-studio.component.js +31 -7
  16. package/dist/lib/record-process-studio/record-process-studio.component.js.map +1 -1
  17. package/dist/lib/run-detail.d.ts +4 -0
  18. package/dist/lib/run-detail.d.ts.map +1 -1
  19. package/dist/lib/run-detail.js +10 -2
  20. package/dist/lib/run-detail.js.map +1 -1
  21. package/package.json +10 -10
@@ -10,70 +10,103 @@ import { CommonModule } from '@angular/common';
10
10
  import { FormsModule } from '@angular/forms';
11
11
  import { BaseAngularComponent } from '@memberjunction/ng-base-types';
12
12
  import { LogError, RunView } from '@memberjunction/core';
13
- import { renderConstraintBlock, validateSpec, } from '@memberjunction/feature-pipelines';
14
- import { SafeJSONParse, UUIDsEqual } from '@memberjunction/global';
15
- import { MJButtonDirective } from '@memberjunction/ng-ui-components';
13
+ import { KnowledgeHubMetadataEngine, } from '@memberjunction/core-entities';
14
+ import { renderConstraintBlock, validateSpec, GetFeaturePipelineCapabilities, ValidateOutputsAgainstCapabilities, FindEscalationTargetRowProblem, FindEscalationTargetSpecProblem, } from '@memberjunction/feature-pipelines';
15
+ import { EscapeSQLString, SafeJSONParse, UUIDsEqual } from '@memberjunction/global';
16
+ import { MJButtonDirective, MJConfirmDialogComponent } from '@memberjunction/ng-ui-components';
16
17
  import * as i0 from "@angular/core";
17
18
  import * as i1 from "@angular/forms";
18
- const _forTrack0 = ($index, $item) => $item.ID;
19
- const _forTrack1 = ($index, $item) => $item.Name;
20
- function FeaturePipelineBuilderComponent_Conditional_20_For_7_Template(rf, ctx) { if (rf & 1) {
21
- i0.ɵɵelementStart(0, "option", 14);
19
+ const _forTrack0 = ($index, $item) => $item.Name;
20
+ const _forTrack1 = ($index, $item) => $item.ID;
21
+ const _forTrack2 = ($index, $item) => $item.Value;
22
+ function FeaturePipelineBuilderComponent_For_8_Template(rf, ctx) { if (rf & 1) {
23
+ i0.ɵɵelementStart(0, "option", 5);
22
24
  i0.ɵɵtext(1);
23
25
  i0.ɵɵelementEnd();
24
26
  } if (rf & 2) {
25
- const doc_r3 = ctx.$implicit;
26
- i0.ɵɵproperty("value", doc_r3.ID);
27
+ const t_r1 = ctx.$implicit;
28
+ const ctx_r1 = i0.ɵɵnextContext();
29
+ i0.ɵɵproperty("value", t_r1.Name)("selected", ctx_r1.IsCurrentPipelineType(t_r1.Name));
30
+ i0.ɵɵadvance();
31
+ i0.ɵɵtextInterpolate(t_r1.DisplayName || t_r1.Name);
32
+ } }
33
+ function FeaturePipelineBuilderComponent_Conditional_14_Template(rf, ctx) { if (rf & 1) {
34
+ const _r3 = i0.ɵɵgetCurrentView();
35
+ i0.ɵɵelementStart(0, "div", 7)(1, "div", 3)(2, "label");
36
+ i0.ɵɵtext(3, "Capture Reasoning");
37
+ i0.ɵɵelementEnd();
38
+ i0.ɵɵelementStart(4, "select", 36);
39
+ i0.ɵɵlistener("change", function FeaturePipelineBuilderComponent_Conditional_14_Template_select_change_4_listener($event) { i0.ɵɵrestoreView(_r3); const ctx_r1 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r1.UpdateCaptureReasoning($event)); });
40
+ i0.ɵɵelementStart(5, "option", 30);
41
+ i0.ɵɵtext(6, "Yes \u2014 Keep the model's rationale with each Feature Value");
42
+ i0.ɵɵelementEnd();
43
+ i0.ɵɵelementStart(7, "option", 31);
44
+ i0.ɵɵtext(8, "No");
45
+ i0.ɵɵelementEnd()()()();
46
+ } if (rf & 2) {
47
+ const ctx_r1 = i0.ɵɵnextContext();
48
+ i0.ɵɵadvance(4);
49
+ i0.ɵɵproperty("value", ctx_r1.spec.CaptureReasoning ? "true" : "false");
50
+ } }
51
+ function FeaturePipelineBuilderComponent_Conditional_34_For_7_Template(rf, ctx) { if (rf & 1) {
52
+ i0.ɵɵelementStart(0, "option", 5);
53
+ i0.ɵɵtext(1);
54
+ i0.ɵɵelementEnd();
55
+ } if (rf & 2) {
56
+ const doc_r5 = ctx.$implicit;
57
+ const ctx_r1 = i0.ɵɵnextContext(2);
58
+ i0.ɵɵproperty("value", doc_r5.ID)("selected", ctx_r1.IsSavedEntityDoc(doc_r5));
27
59
  i0.ɵɵadvance();
28
- i0.ɵɵtextInterpolate(doc_r3.Name);
60
+ i0.ɵɵtextInterpolate(doc_r5.Name);
29
61
  } }
30
- function FeaturePipelineBuilderComponent_Conditional_20_Template(rf, ctx) { if (rf & 1) {
31
- const _r1 = i0.ɵɵgetCurrentView();
32
- i0.ɵɵelementStart(0, "div", 6)(1, "label");
62
+ function FeaturePipelineBuilderComponent_Conditional_34_Template(rf, ctx) { if (rf & 1) {
63
+ const _r4 = i0.ɵɵgetCurrentView();
64
+ i0.ɵɵelementStart(0, "div", 3)(1, "label");
33
65
  i0.ɵɵtext(2, "Entity Document");
34
66
  i0.ɵɵelementEnd();
35
- i0.ɵɵelementStart(3, "select", 7);
36
- i0.ɵɵlistener("change", function FeaturePipelineBuilderComponent_Conditional_20_Template_select_change_3_listener($event) { i0.ɵɵrestoreView(_r1); const ctx_r1 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r1.onEntityDocChange($event)); });
37
- i0.ɵɵelementStart(4, "option", 13);
67
+ i0.ɵɵelementStart(3, "select", 4);
68
+ i0.ɵɵlistener("change", function FeaturePipelineBuilderComponent_Conditional_34_Template_select_change_3_listener($event) { i0.ɵɵrestoreView(_r4); const ctx_r1 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r1.onEntityDocChange($event)); });
69
+ i0.ɵɵelementStart(4, "option", 18);
38
70
  i0.ɵɵtext(5, "\u2014 Select Entity Document \u2014");
39
71
  i0.ɵɵelementEnd();
40
- i0.ɵɵrepeaterCreate(6, FeaturePipelineBuilderComponent_Conditional_20_For_7_Template, 2, 2, "option", 14, _forTrack0);
72
+ i0.ɵɵrepeaterCreate(6, FeaturePipelineBuilderComponent_Conditional_34_For_7_Template, 2, 3, "option", 5, _forTrack1);
41
73
  i0.ɵɵelementEnd()();
42
74
  } if (rf & 2) {
43
75
  const ctx_r1 = i0.ɵɵnextContext();
44
- i0.ɵɵadvance(3);
45
- i0.ɵɵproperty("value", ctx_r1.spec.Context.EntityDocumentID || "");
46
- i0.ɵɵadvance(3);
76
+ i0.ɵɵadvance(4);
77
+ i0.ɵɵproperty("selected", !ctx_r1.SavedEntityDocListed);
78
+ i0.ɵɵadvance(2);
47
79
  i0.ɵɵrepeater(ctx_r1.availableDocs);
48
80
  } }
49
- function FeaturePipelineBuilderComponent_Conditional_21_Template(rf, ctx) { if (rf & 1) {
50
- const _r4 = i0.ɵɵgetCurrentView();
51
- i0.ɵɵelementStart(0, "div", 6)(1, "label");
81
+ function FeaturePipelineBuilderComponent_Conditional_35_Template(rf, ctx) { if (rf & 1) {
82
+ const _r6 = i0.ɵɵgetCurrentView();
83
+ i0.ɵɵelementStart(0, "div", 3)(1, "label");
52
84
  i0.ɵɵtext(2, "Query ID");
53
85
  i0.ɵɵelementEnd();
54
- i0.ɵɵelementStart(3, "input", 29);
55
- i0.ɵɵlistener("input", function FeaturePipelineBuilderComponent_Conditional_21_Template_input_input_3_listener($event) { i0.ɵɵrestoreView(_r4); const ctx_r1 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r1.onQueryIDChange($event)); });
86
+ i0.ɵɵelementStart(3, "input", 37);
87
+ i0.ɵɵlistener("input", function FeaturePipelineBuilderComponent_Conditional_35_Template_input_input_3_listener($event) { i0.ɵɵrestoreView(_r6); const ctx_r1 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r1.onQueryIDChange($event)); });
56
88
  i0.ɵɵelementEnd()();
57
89
  } if (rf & 2) {
58
90
  const ctx_r1 = i0.ɵɵnextContext();
59
91
  i0.ɵɵadvance(3);
60
92
  i0.ɵɵproperty("value", ctx_r1.spec.Context.QueryID || "");
61
93
  } }
62
- function FeaturePipelineBuilderComponent_For_40_Template(rf, ctx) { if (rf & 1) {
63
- i0.ɵɵelementStart(0, "option", 14);
94
+ function FeaturePipelineBuilderComponent_For_54_Template(rf, ctx) { if (rf & 1) {
95
+ i0.ɵɵelementStart(0, "option", 5);
64
96
  i0.ɵɵtext(1);
65
97
  i0.ɵɵelementEnd();
66
98
  } if (rf & 2) {
67
- const p_r5 = ctx.$implicit;
68
- i0.ɵɵproperty("value", p_r5.ID);
99
+ const p_r7 = ctx.$implicit;
100
+ const ctx_r1 = i0.ɵɵnextContext();
101
+ i0.ɵɵproperty("value", p_r7.ID)("selected", ctx_r1.IsSavedPrompt(p_r7));
69
102
  i0.ɵɵadvance();
70
- i0.ɵɵtextInterpolate(p_r5.Name);
103
+ i0.ɵɵtextInterpolate(p_r7.Name);
71
104
  } }
72
- function FeaturePipelineBuilderComponent_Conditional_41_Template(rf, ctx) { if (rf & 1) {
73
- i0.ɵɵelementStart(0, "div", 6)(1, "label");
105
+ function FeaturePipelineBuilderComponent_Conditional_55_Template(rf, ctx) { if (rf & 1) {
106
+ i0.ɵɵelementStart(0, "div", 3)(1, "label");
74
107
  i0.ɵɵtext(2, "Prompt Description");
75
108
  i0.ɵɵelementEnd();
76
- i0.ɵɵelementStart(3, "div", 30);
109
+ i0.ɵɵelementStart(3, "div", 6);
77
110
  i0.ɵɵtext(4);
78
111
  i0.ɵɵelementEnd()();
79
112
  } if (rf & 2) {
@@ -81,13 +114,13 @@ function FeaturePipelineBuilderComponent_Conditional_41_Template(rf, ctx) { if (
81
114
  i0.ɵɵadvance(4);
82
115
  i0.ɵɵtextInterpolate(ctx_r1.selectedPrompt.Description || "No description provided");
83
116
  } }
84
- function FeaturePipelineBuilderComponent_Conditional_42_Template(rf, ctx) { if (rf & 1) {
85
- i0.ɵɵelementStart(0, "div", 15)(1, "label");
117
+ function FeaturePipelineBuilderComponent_Conditional_56_Template(rf, ctx) { if (rf & 1) {
118
+ i0.ɵɵelementStart(0, "div", 19)(1, "label");
86
119
  i0.ɵɵtext(2, "Injected Constraint Block ");
87
- i0.ɵɵelementStart(3, "span", 31);
120
+ i0.ɵɵelementStart(3, "span", 38);
88
121
  i0.ɵɵtext(4, "\u2014 automatically appended to prompt instructions");
89
122
  i0.ɵɵelementEnd()();
90
- i0.ɵɵelementStart(5, "pre", 32);
123
+ i0.ɵɵelementStart(5, "pre", 39);
91
124
  i0.ɵɵtext(6);
92
125
  i0.ɵɵelementEnd()();
93
126
  } if (rf & 2) {
@@ -95,9 +128,9 @@ function FeaturePipelineBuilderComponent_Conditional_42_Template(rf, ctx) { if (
95
128
  i0.ɵɵadvance(6);
96
129
  i0.ɵɵtextInterpolate(ctx_r1.renderedConstraintPreview);
97
130
  } }
98
- function FeaturePipelineBuilderComponent_Conditional_55_Template(rf, ctx) { if (rf & 1) {
99
- i0.ɵɵelementStart(0, "div", 20);
100
- i0.ɵɵelement(1, "i", 33);
131
+ function FeaturePipelineBuilderComponent_Conditional_69_Template(rf, ctx) { if (rf & 1) {
132
+ i0.ɵɵelementStart(0, "div", 24);
133
+ i0.ɵɵelement(1, "i", 40);
101
134
  i0.ɵɵelementStart(2, "span");
102
135
  i0.ɵɵtext(3, "No outputs defined. Click ");
103
136
  i0.ɵɵelementStart(4, "strong");
@@ -106,243 +139,454 @@ function FeaturePipelineBuilderComponent_Conditional_55_Template(rf, ctx) { if (
106
139
  i0.ɵɵtext(6, " to configure at least one output attribute.");
107
140
  i0.ɵɵelementEnd()();
108
141
  } }
109
- function FeaturePipelineBuilderComponent_Conditional_56_For_2_Conditional_27_For_7_Template(rf, ctx) { if (rf & 1) {
110
- i0.ɵɵelementStart(0, "option", 14);
142
+ function FeaturePipelineBuilderComponent_Conditional_70_For_2_Conditional_20_Template(rf, ctx) { if (rf & 1) {
143
+ i0.ɵɵelementStart(0, "option", 18);
144
+ i0.ɵɵtext(1, "\u2014 Select Target Mode \u2014");
145
+ i0.ɵɵelementEnd();
146
+ } if (rf & 2) {
147
+ i0.ɵɵproperty("selected", true);
148
+ } }
149
+ function FeaturePipelineBuilderComponent_Conditional_70_For_2_For_22_Template(rf, ctx) { if (rf & 1) {
150
+ i0.ɵɵelementStart(0, "option", 5);
111
151
  i0.ɵɵtext(1);
112
152
  i0.ɵɵelementEnd();
113
153
  } if (rf & 2) {
114
- const f_r9 = ctx.$implicit;
115
- i0.ɵɵproperty("value", f_r9.Name);
154
+ const m_r10 = ctx.$implicit;
155
+ const output_r11 = i0.ɵɵnextContext().$implicit;
156
+ i0.ɵɵproperty("value", m_r10.Value)("selected", m_r10.Value === output_r11.Target.Mode);
116
157
  i0.ɵɵadvance();
117
- i0.ɵɵtextInterpolate2("", f_r9.DisplayName || f_r9.Name, " (", f_r9.TSType, ")");
158
+ i0.ɵɵtextInterpolate(m_r10.Label);
118
159
  } }
119
- function FeaturePipelineBuilderComponent_Conditional_56_For_2_Conditional_27_Template(rf, ctx) { if (rf & 1) {
120
- const _r8 = i0.ɵɵgetCurrentView();
121
- i0.ɵɵelementStart(0, "div", 6)(1, "label");
160
+ function FeaturePipelineBuilderComponent_Conditional_70_For_2_Conditional_24_For_7_Template(rf, ctx) { if (rf & 1) {
161
+ i0.ɵɵelementStart(0, "option", 5);
162
+ i0.ɵɵtext(1);
163
+ i0.ɵɵelementEnd();
164
+ } if (rf & 2) {
165
+ const f_r13 = ctx.$implicit;
166
+ const output_r11 = i0.ɵɵnextContext(2).$implicit;
167
+ i0.ɵɵproperty("value", f_r13.Name)("selected", f_r13.Name === output_r11.Target.EntityFieldName);
168
+ i0.ɵɵadvance();
169
+ i0.ɵɵtextInterpolate2("", f_r13.DisplayName || f_r13.Name, " (", f_r13.TSType, ")");
170
+ } }
171
+ function FeaturePipelineBuilderComponent_Conditional_70_For_2_Conditional_24_Template(rf, ctx) { if (rf & 1) {
172
+ const _r12 = i0.ɵɵgetCurrentView();
173
+ i0.ɵɵelementStart(0, "div", 3)(1, "label");
122
174
  i0.ɵɵtext(2, "Target Field");
123
175
  i0.ɵɵelementEnd();
124
- i0.ɵɵelementStart(3, "select", 7);
125
- i0.ɵɵlistener("change", function FeaturePipelineBuilderComponent_Conditional_56_For_2_Conditional_27_Template_select_change_3_listener($event) { i0.ɵɵrestoreView(_r8); const $index_r7 = i0.ɵɵnextContext().$index; const ctx_r1 = i0.ɵɵnextContext(2); return i0.ɵɵresetView(ctx_r1.updateFieldTarget($index_r7, $event)); });
126
- i0.ɵɵelementStart(4, "option", 13);
176
+ i0.ɵɵelementStart(3, "select", 4);
177
+ i0.ɵɵlistener("change", function FeaturePipelineBuilderComponent_Conditional_70_For_2_Conditional_24_Template_select_change_3_listener($event) { i0.ɵɵrestoreView(_r12); const ɵ$index_185_r9 = i0.ɵɵnextContext().$index; const ctx_r1 = i0.ɵɵnextContext(2); return i0.ɵɵresetView(ctx_r1.updateFieldTarget(ɵ$index_185_r9, $event)); });
178
+ i0.ɵɵelementStart(4, "option", 18);
127
179
  i0.ɵɵtext(5, "\u2014 Select Column \u2014");
128
180
  i0.ɵɵelementEnd();
129
- i0.ɵɵrepeaterCreate(6, FeaturePipelineBuilderComponent_Conditional_56_For_2_Conditional_27_For_7_Template, 2, 3, "option", 14, _forTrack1);
181
+ i0.ɵɵrepeaterCreate(6, FeaturePipelineBuilderComponent_Conditional_70_For_2_Conditional_24_For_7_Template, 2, 4, "option", 5, _forTrack0);
130
182
  i0.ɵɵelementEnd()();
131
183
  } if (rf & 2) {
132
- const output_r10 = i0.ɵɵnextContext().$implicit;
184
+ const output_r11 = i0.ɵɵnextContext().$implicit;
133
185
  const ctx_r1 = i0.ɵɵnextContext(2);
134
- i0.ɵɵadvance(3);
135
- i0.ɵɵproperty("value", output_r10.Target.EntityFieldName);
136
- i0.ɵɵadvance(3);
186
+ i0.ɵɵadvance(4);
187
+ i0.ɵɵproperty("selected", !ctx_r1.IsEntityFieldListed(output_r11.Target.EntityFieldName));
188
+ i0.ɵɵadvance(2);
137
189
  i0.ɵɵrepeater(ctx_r1.entityFields);
138
190
  } }
139
- function FeaturePipelineBuilderComponent_Conditional_56_For_2_Conditional_28_For_7_Template(rf, ctx) { if (rf & 1) {
140
- i0.ɵɵelementStart(0, "option", 14);
191
+ function FeaturePipelineBuilderComponent_Conditional_70_For_2_Conditional_25_For_7_Template(rf, ctx) { if (rf & 1) {
192
+ i0.ɵɵelementStart(0, "option", 5);
141
193
  i0.ɵɵtext(1);
142
194
  i0.ɵɵelementEnd();
143
195
  } if (rf & 2) {
144
- const e_r12 = ctx.$implicit;
145
- i0.ɵɵproperty("value", e_r12.Name);
196
+ const e_r15 = ctx.$implicit;
197
+ const output_r11 = i0.ɵɵnextContext(2).$implicit;
198
+ i0.ɵɵproperty("value", e_r15.Name)("selected", e_r15.Name === output_r11.Target.EntityName);
146
199
  i0.ɵɵadvance();
147
- i0.ɵɵtextInterpolate(e_r12.DisplayName || e_r12.Name);
200
+ i0.ɵɵtextInterpolate(e_r15.DisplayName || e_r15.Name);
148
201
  } }
149
- function FeaturePipelineBuilderComponent_Conditional_56_For_2_Conditional_28_Template(rf, ctx) { if (rf & 1) {
150
- const _r11 = i0.ɵɵgetCurrentView();
151
- i0.ɵɵelementStart(0, "div", 6)(1, "label");
202
+ function FeaturePipelineBuilderComponent_Conditional_70_For_2_Conditional_25_Template(rf, ctx) { if (rf & 1) {
203
+ const _r14 = i0.ɵɵgetCurrentView();
204
+ i0.ɵɵelementStart(0, "div", 3)(1, "label");
152
205
  i0.ɵɵtext(2, "Child Entity");
153
206
  i0.ɵɵelementEnd();
154
- i0.ɵɵelementStart(3, "select", 7);
155
- i0.ɵɵlistener("change", function FeaturePipelineBuilderComponent_Conditional_56_For_2_Conditional_28_Template_select_change_3_listener($event) { i0.ɵɵrestoreView(_r11); const $index_r7 = i0.ɵɵnextContext().$index; const ctx_r1 = i0.ɵɵnextContext(2); return i0.ɵɵresetView(ctx_r1.updateChildTargetEntity($index_r7, $event)); });
156
- i0.ɵɵelementStart(4, "option", 13);
207
+ i0.ɵɵelementStart(3, "select", 4);
208
+ i0.ɵɵlistener("change", function FeaturePipelineBuilderComponent_Conditional_70_For_2_Conditional_25_Template_select_change_3_listener($event) { i0.ɵɵrestoreView(_r14); const ɵ$index_185_r9 = i0.ɵɵnextContext().$index; const ctx_r1 = i0.ɵɵnextContext(2); return i0.ɵɵresetView(ctx_r1.updateChildTargetEntity(ɵ$index_185_r9, $event)); });
209
+ i0.ɵɵelementStart(4, "option", 18);
157
210
  i0.ɵɵtext(5, "\u2014 Select Entity \u2014");
158
211
  i0.ɵɵelementEnd();
159
- i0.ɵɵrepeaterCreate(6, FeaturePipelineBuilderComponent_Conditional_56_For_2_Conditional_28_For_7_Template, 2, 2, "option", 14, _forTrack0);
212
+ i0.ɵɵrepeaterCreate(6, FeaturePipelineBuilderComponent_Conditional_70_For_2_Conditional_25_For_7_Template, 2, 3, "option", 5, _forTrack1);
160
213
  i0.ɵɵelementEnd()();
161
214
  } if (rf & 2) {
162
- const output_r10 = i0.ɵɵnextContext().$implicit;
215
+ const output_r11 = i0.ɵɵnextContext().$implicit;
163
216
  const ctx_r1 = i0.ɵɵnextContext(2);
164
- i0.ɵɵadvance(3);
165
- i0.ɵɵproperty("value", output_r10.Target.EntityName);
166
- i0.ɵɵadvance(3);
217
+ i0.ɵɵadvance(4);
218
+ i0.ɵɵproperty("selected", !ctx_r1.IsEntityListed(output_r11.Target.EntityName));
219
+ i0.ɵɵadvance(2);
167
220
  i0.ɵɵrepeater(ctx_r1.availableEntities);
168
221
  } }
169
- function FeaturePipelineBuilderComponent_Conditional_56_For_2_Conditional_43_Template(rf, ctx) { if (rf & 1) {
170
- const _r13 = i0.ɵɵgetCurrentView();
171
- i0.ɵɵelementStart(0, "div", 6)(1, "label");
222
+ function FeaturePipelineBuilderComponent_Conditional_70_For_2_Conditional_30_Template(rf, ctx) { if (rf & 1) {
223
+ i0.ɵɵelementStart(0, "option", 47);
224
+ i0.ɵɵtext(1, "\u2014 Select Constraint \u2014");
225
+ i0.ɵɵelementEnd();
226
+ } if (rf & 2) {
227
+ i0.ɵɵproperty("selected", true);
228
+ } }
229
+ function FeaturePipelineBuilderComponent_Conditional_70_For_2_For_32_Template(rf, ctx) { if (rf & 1) {
230
+ i0.ɵɵelementStart(0, "option", 5);
231
+ i0.ɵɵtext(1);
232
+ i0.ɵɵelementEnd();
233
+ } if (rf & 2) {
234
+ const t_r16 = ctx.$implicit;
235
+ const output_r11 = i0.ɵɵnextContext().$implicit;
236
+ const ctx_r1 = i0.ɵɵnextContext(2);
237
+ i0.ɵɵproperty("value", t_r16.Value)("selected", t_r16.Value === ctx_r1.SavedConstraintType(output_r11));
238
+ i0.ɵɵadvance();
239
+ i0.ɵɵtextInterpolate(t_r16.Label);
240
+ } }
241
+ function FeaturePipelineBuilderComponent_Conditional_70_For_2_Conditional_33_Template(rf, ctx) { if (rf & 1) {
242
+ const _r17 = i0.ɵɵgetCurrentView();
243
+ i0.ɵɵelementStart(0, "div", 3)(1, "label");
172
244
  i0.ɵɵtext(2, "Violation Policy");
173
245
  i0.ɵɵelementEnd();
174
- i0.ɵɵelementStart(3, "select", 7);
175
- i0.ɵɵlistener("change", function FeaturePipelineBuilderComponent_Conditional_56_For_2_Conditional_43_Template_select_change_3_listener($event) { i0.ɵɵrestoreView(_r13); const $index_r7 = i0.ɵɵnextContext().$index; const ctx_r1 = i0.ɵɵnextContext(2); return i0.ɵɵresetView(ctx_r1.updateViolationPolicy($index_r7, $event)); });
176
- i0.ɵɵelementStart(4, "option", 49);
246
+ i0.ɵɵelementStart(3, "select", 13);
247
+ i0.ɵɵlistener("change", function FeaturePipelineBuilderComponent_Conditional_70_For_2_Conditional_33_Template_select_change_3_listener($event) { i0.ɵɵrestoreView(_r17); const ɵ$index_185_r9 = i0.ɵɵnextContext().$index; const ctx_r1 = i0.ɵɵnextContext(2); return i0.ɵɵresetView(ctx_r1.updateViolationPolicy(ɵ$index_185_r9, $event)); });
248
+ i0.ɵɵelementStart(4, "option", 48);
177
249
  i0.ɵɵtext(5, "Fail Row");
178
250
  i0.ɵɵelementEnd();
179
- i0.ɵɵelementStart(6, "option", 50);
251
+ i0.ɵɵelementStart(6, "option", 49);
180
252
  i0.ɵɵtext(7, "Set Output to Null");
181
253
  i0.ɵɵelementEnd();
182
- i0.ɵɵelementStart(8, "option", 51);
254
+ i0.ɵɵelementStart(8, "option", 50);
183
255
  i0.ɵɵtext(9, "Coerce / Fallback");
184
256
  i0.ɵɵelementEnd()()();
185
257
  } if (rf & 2) {
186
- const output_r10 = i0.ɵɵnextContext().$implicit;
258
+ const output_r11 = i0.ɵɵnextContext().$implicit;
187
259
  i0.ɵɵadvance(3);
188
- i0.ɵɵproperty("value", output_r10.Constraint.OnViolation || "fail");
260
+ i0.ɵɵproperty("value", output_r11.Constraint.OnViolation || "fail");
189
261
  } }
190
- function FeaturePipelineBuilderComponent_Conditional_56_For_2_Conditional_44_Template(rf, ctx) { if (rf & 1) {
191
- const _r14 = i0.ɵɵgetCurrentView();
192
- i0.ɵɵelementStart(0, "div", 15)(1, "label");
262
+ function FeaturePipelineBuilderComponent_Conditional_70_For_2_Conditional_34_Conditional_4_For_7_Template(rf, ctx) { if (rf & 1) {
263
+ const _r19 = i0.ɵɵgetCurrentView();
264
+ i0.ɵɵelementStart(0, "div", 53)(1, "span", 54);
265
+ i0.ɵɵtext(2);
266
+ i0.ɵɵelementEnd();
267
+ i0.ɵɵelementStart(3, "input", 55);
268
+ i0.ɵɵlistener("input", function FeaturePipelineBuilderComponent_Conditional_70_For_2_Conditional_34_Conditional_4_For_7_Template_input_input_3_listener($event) { const val_r20 = i0.ɵɵrestoreView(_r19).$implicit; const ɵ$index_185_r9 = i0.ɵɵnextContext(3).$index; const ctx_r1 = i0.ɵɵnextContext(2); return i0.ɵɵresetView(ctx_r1.UpdateEnumValueDescription(ɵ$index_185_r9, val_r20, $event)); });
269
+ i0.ɵɵelementEnd()();
270
+ } if (rf & 2) {
271
+ const val_r20 = ctx.$implicit;
272
+ const output_r11 = i0.ɵɵnextContext(3).$implicit;
273
+ const ctx_r1 = i0.ɵɵnextContext(2);
274
+ i0.ɵɵadvance(2);
275
+ i0.ɵɵtextInterpolate(val_r20);
276
+ i0.ɵɵadvance();
277
+ i0.ɵɵproperty("value", ctx_r1.GetEnumValueDescription(output_r11, val_r20))("placeholder", "Description for " + val_r20);
278
+ } }
279
+ function FeaturePipelineBuilderComponent_Conditional_70_For_2_Conditional_34_Conditional_4_Template(rf, ctx) { if (rf & 1) {
280
+ i0.ɵɵelementStart(0, "div", 19)(1, "label");
281
+ i0.ɵɵtext(2, "Value Descriptions ");
282
+ i0.ɵɵelementStart(3, "span", 38);
283
+ i0.ɵɵtext(4, "\u2014 Decision models require a description for every choice option");
284
+ i0.ɵɵelementEnd()();
285
+ i0.ɵɵelementStart(5, "div", 52);
286
+ i0.ɵɵrepeaterCreate(6, FeaturePipelineBuilderComponent_Conditional_70_For_2_Conditional_34_Conditional_4_For_7_Template, 4, 3, "div", 53, i0.ɵɵrepeaterTrackByIdentity);
287
+ i0.ɵɵelementEnd()();
288
+ } if (rf & 2) {
289
+ const output_r11 = i0.ɵɵnextContext(2).$implicit;
290
+ const ctx_r1 = i0.ɵɵnextContext(2);
291
+ i0.ɵɵadvance(6);
292
+ i0.ɵɵrepeater(ctx_r1.GetEnumValues(output_r11));
293
+ } }
294
+ function FeaturePipelineBuilderComponent_Conditional_70_For_2_Conditional_34_Template(rf, ctx) { if (rf & 1) {
295
+ const _r18 = i0.ɵɵgetCurrentView();
296
+ i0.ɵɵelementStart(0, "div", 19)(1, "label");
193
297
  i0.ɵɵtext(2, "Allowed Values (comma separated)");
194
298
  i0.ɵɵelementEnd();
195
- i0.ɵɵelementStart(3, "input", 52);
196
- i0.ɵɵlistener("input", function FeaturePipelineBuilderComponent_Conditional_56_For_2_Conditional_44_Template_input_input_3_listener($event) { i0.ɵɵrestoreView(_r14); const $index_r7 = i0.ɵɵnextContext().$index; const ctx_r1 = i0.ɵɵnextContext(2); return i0.ɵɵresetView(ctx_r1.updateEnumValues($index_r7, $event)); });
299
+ i0.ɵɵelementStart(3, "input", 51);
300
+ i0.ɵɵlistener("input", function FeaturePipelineBuilderComponent_Conditional_70_For_2_Conditional_34_Template_input_input_3_listener($event) { i0.ɵɵrestoreView(_r18); const ɵ$index_185_r9 = i0.ɵɵnextContext().$index; const ctx_r1 = i0.ɵɵnextContext(2); return i0.ɵɵresetView(ctx_r1.updateEnumValues(ɵ$index_185_r9, $event)); });
197
301
  i0.ɵɵelementEnd()();
302
+ i0.ɵɵconditionalCreate(4, FeaturePipelineBuilderComponent_Conditional_70_For_2_Conditional_34_Conditional_4_Template, 8, 0, "div", 19);
198
303
  } if (rf & 2) {
199
- const output_r10 = i0.ɵɵnextContext().$implicit;
304
+ const output_r11 = i0.ɵɵnextContext().$implicit;
200
305
  const ctx_r1 = i0.ɵɵnextContext(2);
201
306
  i0.ɵɵadvance(3);
202
- i0.ɵɵproperty("value", ctx_r1.getEnumValuesCsv(output_r10.Constraint));
307
+ i0.ɵɵproperty("value", ctx_r1.getEnumValuesCsv(output_r11.Constraint));
308
+ i0.ɵɵadvance();
309
+ i0.ɵɵconditional(ctx_r1.IsDecisionPipeline && ctx_r1.GetEnumValues(output_r11).length > 0 ? 4 : -1);
203
310
  } }
204
- function FeaturePipelineBuilderComponent_Conditional_56_For_2_Conditional_45_Template(rf, ctx) { if (rf & 1) {
205
- const _r15 = i0.ɵɵgetCurrentView();
206
- i0.ɵɵelementStart(0, "div", 48)(1, "div", 6)(2, "label");
311
+ function FeaturePipelineBuilderComponent_Conditional_70_For_2_Conditional_35_Conditional_0_For_11_Template(rf, ctx) { if (rf & 1) {
312
+ const _r22 = i0.ɵɵgetCurrentView();
313
+ i0.ɵɵelementStart(0, "div", 59)(1, "span", 60);
314
+ i0.ɵɵtext(2);
315
+ i0.ɵɵelementEnd();
316
+ i0.ɵɵelementStart(3, "input", 61);
317
+ i0.ɵɵlistener("input", function FeaturePipelineBuilderComponent_Conditional_70_For_2_Conditional_35_Conditional_0_For_11_Template_input_input_3_listener($event) { const ɵ$index_339_r23 = i0.ɵɵrestoreView(_r22).$index; const ɵ$index_185_r9 = i0.ɵɵnextContext(3).$index; const ctx_r1 = i0.ɵɵnextContext(2); return i0.ɵɵresetView(ctx_r1.UpdateNumericLevel(ɵ$index_185_r9, ɵ$index_339_r23, $event)); });
318
+ i0.ɵɵelementEnd();
319
+ i0.ɵɵelementStart(4, "button", 62);
320
+ i0.ɵɵlistener("click", function FeaturePipelineBuilderComponent_Conditional_70_For_2_Conditional_35_Conditional_0_For_11_Template_button_click_4_listener() { const ɵ$index_339_r23 = i0.ɵɵrestoreView(_r22).$index; const ɵ$index_185_r9 = i0.ɵɵnextContext(3).$index; const ctx_r1 = i0.ɵɵnextContext(2); return i0.ɵɵresetView(ctx_r1.MoveNumericLevel(ɵ$index_185_r9, ɵ$index_339_r23, "up")); });
321
+ i0.ɵɵelement(5, "i", 63);
322
+ i0.ɵɵelementEnd();
323
+ i0.ɵɵelementStart(6, "button", 64);
324
+ i0.ɵɵlistener("click", function FeaturePipelineBuilderComponent_Conditional_70_For_2_Conditional_35_Conditional_0_For_11_Template_button_click_6_listener() { const ɵ$index_339_r23 = i0.ɵɵrestoreView(_r22).$index; const ɵ$index_185_r9 = i0.ɵɵnextContext(3).$index; const ctx_r1 = i0.ɵɵnextContext(2); return i0.ɵɵresetView(ctx_r1.MoveNumericLevel(ɵ$index_185_r9, ɵ$index_339_r23, "down")); });
325
+ i0.ɵɵelement(7, "i", 65);
326
+ i0.ɵɵelementEnd();
327
+ i0.ɵɵelementStart(8, "button", 66);
328
+ i0.ɵɵlistener("click", function FeaturePipelineBuilderComponent_Conditional_70_For_2_Conditional_35_Conditional_0_For_11_Template_button_click_8_listener() { const ɵ$index_339_r23 = i0.ɵɵrestoreView(_r22).$index; const ɵ$index_185_r9 = i0.ɵɵnextContext(3).$index; const ctx_r1 = i0.ɵɵnextContext(2); return i0.ɵɵresetView(ctx_r1.RemoveNumericLevel(ɵ$index_185_r9, ɵ$index_339_r23)); });
329
+ i0.ɵɵelement(9, "i", 44);
330
+ i0.ɵɵelementEnd()();
331
+ } if (rf & 2) {
332
+ const lvl_r24 = ctx.$implicit;
333
+ const ɵ$index_339_r23 = ctx.$index;
334
+ const ɵ$count_339_r25 = ctx.$count;
335
+ const output_r11 = i0.ɵɵnextContext(3).$implicit;
336
+ const ctx_r1 = i0.ɵɵnextContext(2);
337
+ i0.ɵɵadvance(2);
338
+ i0.ɵɵtextInterpolate(ɵ$index_339_r23 + 1);
339
+ i0.ɵɵadvance();
340
+ i0.ɵɵproperty("value", lvl_r24);
341
+ i0.ɵɵadvance();
342
+ i0.ɵɵproperty("disabled", ɵ$index_339_r23 === 0);
343
+ i0.ɵɵadvance(2);
344
+ i0.ɵɵproperty("disabled", ɵ$index_339_r23 === ɵ$count_339_r25 - 1);
345
+ i0.ɵɵadvance(2);
346
+ i0.ɵɵproperty("disabled", ctx_r1.GetNumericLevels(output_r11).length <= 2);
347
+ } }
348
+ function FeaturePipelineBuilderComponent_Conditional_70_For_2_Conditional_35_Conditional_0_Template(rf, ctx) { if (rf & 1) {
349
+ const _r21 = i0.ɵɵgetCurrentView();
350
+ i0.ɵɵelementStart(0, "div", 19)(1, "div", 56)(2, "label");
351
+ i0.ɵɵtext(3, "Numeric Levels ");
352
+ i0.ɵɵelementStart(4, "span", 38);
353
+ i0.ɵɵtext(5, "(Ordered: lowest to highest, 2 to 10 levels)");
354
+ i0.ɵɵelementEnd()();
355
+ i0.ɵɵelementStart(6, "button", 57);
356
+ i0.ɵɵlistener("click", function FeaturePipelineBuilderComponent_Conditional_70_For_2_Conditional_35_Conditional_0_Template_button_click_6_listener() { i0.ɵɵrestoreView(_r21); const ɵ$index_185_r9 = i0.ɵɵnextContext(2).$index; const ctx_r1 = i0.ɵɵnextContext(2); return i0.ɵɵresetView(ctx_r1.AddNumericLevel(ɵ$index_185_r9)); });
357
+ i0.ɵɵelement(7, "i", 23);
358
+ i0.ɵɵtext(8, " Add Level ");
359
+ i0.ɵɵelementEnd()();
360
+ i0.ɵɵelementStart(9, "div", 58);
361
+ i0.ɵɵrepeaterCreate(10, FeaturePipelineBuilderComponent_Conditional_70_For_2_Conditional_35_Conditional_0_For_11_Template, 10, 5, "div", 59, i0.ɵɵrepeaterTrackByIndex);
362
+ i0.ɵɵelementEnd()();
363
+ } if (rf & 2) {
364
+ const output_r11 = i0.ɵɵnextContext(2).$implicit;
365
+ const ctx_r1 = i0.ɵɵnextContext(2);
366
+ i0.ɵɵadvance(6);
367
+ i0.ɵɵproperty("disabled", ctx_r1.GetNumericLevels(output_r11).length >= 10);
368
+ i0.ɵɵadvance(4);
369
+ i0.ɵɵrepeater(ctx_r1.GetNumericLevels(output_r11));
370
+ } }
371
+ function FeaturePipelineBuilderComponent_Conditional_70_For_2_Conditional_35_Conditional_1_Template(rf, ctx) { if (rf & 1) {
372
+ const _r26 = i0.ɵɵgetCurrentView();
373
+ i0.ɵɵelementStart(0, "div", 7)(1, "div", 3)(2, "label");
207
374
  i0.ɵɵtext(3, "Min Value");
208
375
  i0.ɵɵelementEnd();
209
- i0.ɵɵelementStart(4, "input", 53);
210
- i0.ɵɵlistener("input", function FeaturePipelineBuilderComponent_Conditional_56_For_2_Conditional_45_Template_input_input_4_listener($event) { i0.ɵɵrestoreView(_r15); const $index_r7 = i0.ɵɵnextContext().$index; const ctx_r1 = i0.ɵɵnextContext(2); return i0.ɵɵresetView(ctx_r1.updateNumericMin($index_r7, $event)); });
376
+ i0.ɵɵelementStart(4, "input", 67);
377
+ i0.ɵɵlistener("input", function FeaturePipelineBuilderComponent_Conditional_70_For_2_Conditional_35_Conditional_1_Template_input_input_4_listener($event) { i0.ɵɵrestoreView(_r26); const ɵ$index_185_r9 = i0.ɵɵnextContext(2).$index; const ctx_r1 = i0.ɵɵnextContext(2); return i0.ɵɵresetView(ctx_r1.updateNumericMin(ɵ$index_185_r9, $event)); });
211
378
  i0.ɵɵelementEnd()();
212
- i0.ɵɵelementStart(5, "div", 6)(6, "label");
379
+ i0.ɵɵelementStart(5, "div", 3)(6, "label");
213
380
  i0.ɵɵtext(7, "Max Value");
214
381
  i0.ɵɵelementEnd();
215
- i0.ɵɵelementStart(8, "input", 53);
216
- i0.ɵɵlistener("input", function FeaturePipelineBuilderComponent_Conditional_56_For_2_Conditional_45_Template_input_input_8_listener($event) { i0.ɵɵrestoreView(_r15); const $index_r7 = i0.ɵɵnextContext().$index; const ctx_r1 = i0.ɵɵnextContext(2); return i0.ɵɵresetView(ctx_r1.updateNumericMax($index_r7, $event)); });
382
+ i0.ɵɵelementStart(8, "input", 67);
383
+ i0.ɵɵlistener("input", function FeaturePipelineBuilderComponent_Conditional_70_For_2_Conditional_35_Conditional_1_Template_input_input_8_listener($event) { i0.ɵɵrestoreView(_r26); const ɵ$index_185_r9 = i0.ɵɵnextContext(2).$index; const ctx_r1 = i0.ɵɵnextContext(2); return i0.ɵɵresetView(ctx_r1.updateNumericMax(ɵ$index_185_r9, $event)); });
217
384
  i0.ɵɵelementEnd()()();
218
385
  } if (rf & 2) {
219
- const output_r10 = i0.ɵɵnextContext().$implicit;
386
+ const output_r11 = i0.ɵɵnextContext(2).$implicit;
220
387
  const ctx_r1 = i0.ɵɵnextContext(2);
221
388
  i0.ɵɵadvance(4);
222
- i0.ɵɵproperty("value", ctx_r1.getNumericMin(output_r10.Constraint));
389
+ i0.ɵɵproperty("value", ctx_r1.getNumericMin(output_r11.Constraint));
223
390
  i0.ɵɵadvance(4);
224
- i0.ɵɵproperty("value", ctx_r1.getNumericMax(output_r10.Constraint));
391
+ i0.ɵɵproperty("value", ctx_r1.getNumericMax(output_r11.Constraint));
225
392
  } }
226
- function FeaturePipelineBuilderComponent_Conditional_56_For_2_Template(rf, ctx) { if (rf & 1) {
227
- const _r6 = i0.ɵɵgetCurrentView();
228
- i0.ɵɵelementStart(0, "div", 34)(1, "div", 35)(2, "h4");
393
+ function FeaturePipelineBuilderComponent_Conditional_70_For_2_Conditional_35_Template(rf, ctx) { if (rf & 1) {
394
+ i0.ɵɵconditionalCreate(0, FeaturePipelineBuilderComponent_Conditional_70_For_2_Conditional_35_Conditional_0_Template, 12, 1, "div", 19)(1, FeaturePipelineBuilderComponent_Conditional_70_For_2_Conditional_35_Conditional_1_Template, 9, 2, "div", 7);
395
+ } if (rf & 2) {
396
+ const ctx_r1 = i0.ɵɵnextContext(3);
397
+ i0.ɵɵconditional(ctx_r1.IsDecisionPipeline ? 0 : 1);
398
+ } }
399
+ function FeaturePipelineBuilderComponent_Conditional_70_For_2_Conditional_36_Template(rf, ctx) { if (rf & 1) {
400
+ const _r27 = i0.ɵɵgetCurrentView();
401
+ i0.ɵɵelementStart(0, "div", 19)(1, "label");
402
+ i0.ɵɵtext(2, "Decision Threshold (0.0 to 1.0) ");
403
+ i0.ɵɵelementStart(3, "span", 38);
404
+ i0.ɵɵtext(4, "\u2014 calibrated probability threshold for true");
405
+ i0.ɵɵelementEnd()();
406
+ i0.ɵɵelementStart(5, "input", 68);
407
+ i0.ɵɵlistener("input", function FeaturePipelineBuilderComponent_Conditional_70_For_2_Conditional_36_Template_input_input_5_listener($event) { i0.ɵɵrestoreView(_r27); const ɵ$index_185_r9 = i0.ɵɵnextContext().$index; const ctx_r1 = i0.ɵɵnextContext(2); return i0.ɵɵresetView(ctx_r1.UpdateBooleanThreshold(ɵ$index_185_r9, $event)); });
408
+ i0.ɵɵelementEnd()();
409
+ } if (rf & 2) {
410
+ const output_r11 = i0.ɵɵnextContext().$implicit;
411
+ const ctx_r1 = i0.ɵɵnextContext(2);
412
+ i0.ɵɵadvance(5);
413
+ i0.ɵɵproperty("value", ctx_r1.GetBooleanThreshold(output_r11) ?? "");
414
+ } }
415
+ function FeaturePipelineBuilderComponent_Conditional_70_For_2_Template(rf, ctx) { if (rf & 1) {
416
+ const _r8 = i0.ɵɵgetCurrentView();
417
+ i0.ɵɵelementStart(0, "div", 41)(1, "div", 42)(2, "h4");
229
418
  i0.ɵɵtext(3);
230
419
  i0.ɵɵelementEnd();
231
- i0.ɵɵelementStart(4, "button", 36);
232
- i0.ɵɵlistener("click", function FeaturePipelineBuilderComponent_Conditional_56_For_2_Template_button_click_4_listener() { const $index_r7 = i0.ɵɵrestoreView(_r6).$index; const ctx_r1 = i0.ɵɵnextContext(2); return i0.ɵɵresetView(ctx_r1.removeOutput($index_r7)); });
233
- i0.ɵɵelement(5, "i", 37);
420
+ i0.ɵɵelementStart(4, "button", 43);
421
+ i0.ɵɵlistener("click", function FeaturePipelineBuilderComponent_Conditional_70_For_2_Template_button_click_4_listener() { const ɵ$index_185_r9 = i0.ɵɵrestoreView(_r8).$index; const ctx_r1 = i0.ɵɵnextContext(2); return i0.ɵɵresetView(ctx_r1.removeOutput(ɵ$index_185_r9)); });
422
+ i0.ɵɵelement(5, "i", 44);
234
423
  i0.ɵɵtext(6, " Remove ");
235
424
  i0.ɵɵelementEnd()();
236
- i0.ɵɵelementStart(7, "div", 5)(8, "div", 6)(9, "label");
425
+ i0.ɵɵelementStart(7, "div", 12)(8, "div", 3)(9, "label");
237
426
  i0.ɵɵtext(10, "Output Name");
238
427
  i0.ɵɵelementEnd();
239
- i0.ɵɵelementStart(11, "input", 38);
240
- i0.ɵɵlistener("input", function FeaturePipelineBuilderComponent_Conditional_56_For_2_Template_input_input_11_listener($event) { const $index_r7 = i0.ɵɵrestoreView(_r6).$index; const ctx_r1 = i0.ɵɵnextContext(2); return i0.ɵɵresetView(ctx_r1.updateOutputProp($index_r7, "Name", $event)); });
428
+ i0.ɵɵelementStart(11, "input", 45);
429
+ i0.ɵɵlistener("input", function FeaturePipelineBuilderComponent_Conditional_70_For_2_Template_input_input_11_listener($event) { const ɵ$index_185_r9 = i0.ɵɵrestoreView(_r8).$index; const ctx_r1 = i0.ɵɵnextContext(2); return i0.ɵɵresetView(ctx_r1.updateOutputProp(ɵ$index_185_r9, "Name", $event)); });
241
430
  i0.ɵɵelementEnd()();
242
- i0.ɵɵelementStart(12, "div", 6)(13, "label");
431
+ i0.ɵɵelementStart(12, "div", 3)(13, "label");
243
432
  i0.ɵɵtext(14, "JSON Path / Ref");
244
433
  i0.ɵɵelementEnd();
245
- i0.ɵɵelementStart(15, "input", 39);
246
- i0.ɵɵlistener("input", function FeaturePipelineBuilderComponent_Conditional_56_For_2_Template_input_input_15_listener($event) { const $index_r7 = i0.ɵɵrestoreView(_r6).$index; const ctx_r1 = i0.ɵɵnextContext(2); return i0.ɵɵresetView(ctx_r1.updateOutputProp($index_r7, "Ref", $event)); });
434
+ i0.ɵɵelementStart(15, "input", 46);
435
+ i0.ɵɵlistener("input", function FeaturePipelineBuilderComponent_Conditional_70_For_2_Template_input_input_15_listener($event) { const ɵ$index_185_r9 = i0.ɵɵrestoreView(_r8).$index; const ctx_r1 = i0.ɵɵnextContext(2); return i0.ɵɵresetView(ctx_r1.updateOutputProp(ɵ$index_185_r9, "Ref", $event)); });
247
436
  i0.ɵɵelementEnd()();
248
- i0.ɵɵelementStart(16, "div", 6)(17, "label");
437
+ i0.ɵɵelementStart(16, "div", 3)(17, "label");
249
438
  i0.ɵɵtext(18, "Target Mode");
250
439
  i0.ɵɵelementEnd();
251
- i0.ɵɵelementStart(19, "select", 7);
252
- i0.ɵɵlistener("change", function FeaturePipelineBuilderComponent_Conditional_56_For_2_Template_select_change_19_listener($event) { const $index_r7 = i0.ɵɵrestoreView(_r6).$index; const ctx_r1 = i0.ɵɵnextContext(2); return i0.ɵɵresetView(ctx_r1.updateTargetMode($index_r7, $event)); });
253
- i0.ɵɵelementStart(20, "option", 40);
254
- i0.ɵɵtext(21, "Entity Column (field)");
255
- i0.ɵɵelementEnd();
256
- i0.ɵɵelementStart(22, "option", 41);
257
- i0.ɵɵtext(23, "Child Rows (child)");
258
- i0.ɵɵelementEnd();
259
- i0.ɵɵelementStart(24, "option", 42);
260
- i0.ɵɵtext(25, "Taxonomy Tags (tags)");
261
- i0.ɵɵelementEnd()()()();
262
- i0.ɵɵelementStart(26, "div", 27);
263
- i0.ɵɵconditionalCreate(27, FeaturePipelineBuilderComponent_Conditional_56_For_2_Conditional_27_Template, 8, 1, "div", 6);
264
- i0.ɵɵconditionalCreate(28, FeaturePipelineBuilderComponent_Conditional_56_For_2_Conditional_28_Template, 8, 1, "div", 6);
265
- i0.ɵɵelementStart(29, "div", 6)(30, "label");
266
- i0.ɵɵtext(31, "Constraint Type");
267
- i0.ɵɵelementEnd();
268
- i0.ɵɵelementStart(32, "select", 7);
269
- i0.ɵɵlistener("change", function FeaturePipelineBuilderComponent_Conditional_56_For_2_Template_select_change_32_listener($event) { const $index_r7 = i0.ɵɵrestoreView(_r6).$index; const ctx_r1 = i0.ɵɵnextContext(2); return i0.ɵɵresetView(ctx_r1.updateConstraintType($index_r7, $event)); });
270
- i0.ɵɵelementStart(33, "option", 43);
271
- i0.ɵɵtext(34, "None / Unconstrained");
272
- i0.ɵɵelementEnd();
273
- i0.ɵɵelementStart(35, "option", 44);
274
- i0.ɵɵtext(36, "Enum (Allowed Values)");
275
- i0.ɵɵelementEnd();
276
- i0.ɵɵelementStart(37, "option", 45);
277
- i0.ɵɵtext(38, "Numeric (Min/Max)");
278
- i0.ɵɵelementEnd();
279
- i0.ɵɵelementStart(39, "option", 46);
280
- i0.ɵɵtext(40, "Boolean");
281
- i0.ɵɵelementEnd();
282
- i0.ɵɵelementStart(41, "option", 47);
283
- i0.ɵɵtext(42, "Free Text");
440
+ i0.ɵɵelementStart(19, "select", 4);
441
+ i0.ɵɵlistener("change", function FeaturePipelineBuilderComponent_Conditional_70_For_2_Template_select_change_19_listener($event) { const ɵ$index_185_r9 = i0.ɵɵrestoreView(_r8).$index; const ctx_r1 = i0.ɵɵnextContext(2); return i0.ɵɵresetView(ctx_r1.updateTargetMode(ɵ$index_185_r9, $event)); });
442
+ i0.ɵɵconditionalCreate(20, FeaturePipelineBuilderComponent_Conditional_70_For_2_Conditional_20_Template, 2, 1, "option", 18);
443
+ i0.ɵɵrepeaterCreate(21, FeaturePipelineBuilderComponent_Conditional_70_For_2_For_22_Template, 2, 3, "option", 5, _forTrack2);
284
444
  i0.ɵɵelementEnd()()();
285
- i0.ɵɵconditionalCreate(43, FeaturePipelineBuilderComponent_Conditional_56_For_2_Conditional_43_Template, 10, 1, "div", 6);
445
+ i0.ɵɵelementStart(23, "div", 32);
446
+ i0.ɵɵconditionalCreate(24, FeaturePipelineBuilderComponent_Conditional_70_For_2_Conditional_24_Template, 8, 1, "div", 3);
447
+ i0.ɵɵconditionalCreate(25, FeaturePipelineBuilderComponent_Conditional_70_For_2_Conditional_25_Template, 8, 1, "div", 3);
448
+ i0.ɵɵelementStart(26, "div", 3)(27, "label");
449
+ i0.ɵɵtext(28, "Constraint Type");
286
450
  i0.ɵɵelementEnd();
287
- i0.ɵɵconditionalCreate(44, FeaturePipelineBuilderComponent_Conditional_56_For_2_Conditional_44_Template, 4, 1, "div", 15);
288
- i0.ɵɵconditionalCreate(45, FeaturePipelineBuilderComponent_Conditional_56_For_2_Conditional_45_Template, 9, 2, "div", 48);
451
+ i0.ɵɵelementStart(29, "select", 4);
452
+ i0.ɵɵlistener("change", function FeaturePipelineBuilderComponent_Conditional_70_For_2_Template_select_change_29_listener($event) { const ɵ$index_185_r9 = i0.ɵɵrestoreView(_r8).$index; const ctx_r1 = i0.ɵɵnextContext(2); return i0.ɵɵresetView(ctx_r1.updateConstraintType(ɵ$index_185_r9, $event)); });
453
+ i0.ɵɵconditionalCreate(30, FeaturePipelineBuilderComponent_Conditional_70_For_2_Conditional_30_Template, 2, 1, "option", 47);
454
+ i0.ɵɵrepeaterCreate(31, FeaturePipelineBuilderComponent_Conditional_70_For_2_For_32_Template, 2, 3, "option", 5, _forTrack2);
455
+ i0.ɵɵelementEnd()();
456
+ i0.ɵɵconditionalCreate(33, FeaturePipelineBuilderComponent_Conditional_70_For_2_Conditional_33_Template, 10, 1, "div", 3);
457
+ i0.ɵɵelementEnd();
458
+ i0.ɵɵconditionalCreate(34, FeaturePipelineBuilderComponent_Conditional_70_For_2_Conditional_34_Template, 5, 2);
459
+ i0.ɵɵconditionalCreate(35, FeaturePipelineBuilderComponent_Conditional_70_For_2_Conditional_35_Template, 2, 1);
460
+ i0.ɵɵconditionalCreate(36, FeaturePipelineBuilderComponent_Conditional_70_For_2_Conditional_36_Template, 6, 1, "div", 19);
289
461
  i0.ɵɵelementEnd();
290
462
  } if (rf & 2) {
291
- const output_r10 = ctx.$implicit;
292
- const $index_r7 = ctx.$index;
463
+ const output_r11 = ctx.$implicit;
464
+ const ɵ$index_185_r9 = ctx.$index;
465
+ const ctx_r1 = i0.ɵɵnextContext(2);
293
466
  i0.ɵɵadvance(3);
294
- i0.ɵɵtextInterpolate2("Output #", $index_r7 + 1, ": ", output_r10.Name || "(unnamed)");
467
+ i0.ɵɵtextInterpolate2("Output #", ɵ$index_185_r9 + 1, ": ", output_r11.Name || "(unnamed)");
295
468
  i0.ɵɵadvance(8);
296
- i0.ɵɵproperty("value", output_r10.Name);
469
+ i0.ɵɵproperty("value", output_r11.Name);
297
470
  i0.ɵɵadvance(4);
298
- i0.ɵɵproperty("value", output_r10.Ref);
299
- i0.ɵɵadvance(4);
300
- i0.ɵɵproperty("value", output_r10.Target.Mode);
301
- i0.ɵɵadvance(8);
302
- i0.ɵɵconditional(output_r10.Target.Mode === "field" ? 27 : -1);
471
+ i0.ɵɵproperty("value", output_r11.Ref);
472
+ i0.ɵɵadvance(5);
473
+ i0.ɵɵconditional(!ctx_r1.IsTargetModeOffered(output_r11) ? 20 : -1);
303
474
  i0.ɵɵadvance();
304
- i0.ɵɵconditional(output_r10.Target.Mode === "child" ? 28 : -1);
305
- i0.ɵɵadvance(4);
306
- i0.ɵɵproperty("value", (output_r10.Constraint == null ? null : output_r10.Constraint.Type) || "none");
307
- i0.ɵɵadvance(11);
308
- i0.ɵɵconditional(output_r10.Constraint ? 43 : -1);
475
+ i0.ɵɵrepeater(ctx_r1.AvailableTargetModes);
476
+ i0.ɵɵadvance(3);
477
+ i0.ɵɵconditional(output_r11.Target.Mode === "field" ? 24 : -1);
309
478
  i0.ɵɵadvance();
310
- i0.ɵɵconditional((output_r10.Constraint == null ? null : output_r10.Constraint.Type) === "enum" ? 44 : -1);
479
+ i0.ɵɵconditional(output_r11.Target.Mode === "child" ? 25 : -1);
480
+ i0.ɵɵadvance(5);
481
+ i0.ɵɵconditional(!ctx_r1.IsConstraintTypeOffered(output_r11) ? 30 : -1);
311
482
  i0.ɵɵadvance();
312
- i0.ɵɵconditional((output_r10.Constraint == null ? null : output_r10.Constraint.Type) === "numeric" ? 45 : -1);
483
+ i0.ɵɵrepeater(ctx_r1.AvailableConstraintTypes);
484
+ i0.ɵɵadvance(2);
485
+ i0.ɵɵconditional(output_r11.Constraint ? 33 : -1);
486
+ i0.ɵɵadvance();
487
+ i0.ɵɵconditional((output_r11.Constraint == null ? null : output_r11.Constraint.Type) === "enum" ? 34 : -1);
488
+ i0.ɵɵadvance();
489
+ i0.ɵɵconditional((output_r11.Constraint == null ? null : output_r11.Constraint.Type) === "numeric" ? 35 : -1);
490
+ i0.ɵɵadvance();
491
+ i0.ɵɵconditional((output_r11.Constraint == null ? null : output_r11.Constraint.Type) === "boolean" && ctx_r1.IsDecisionPipeline ? 36 : -1);
313
492
  } }
314
- function FeaturePipelineBuilderComponent_Conditional_56_Template(rf, ctx) { if (rf & 1) {
315
- i0.ɵɵelementStart(0, "div", 21);
316
- i0.ɵɵrepeaterCreate(1, FeaturePipelineBuilderComponent_Conditional_56_For_2_Template, 46, 11, "div", 34, i0.ɵɵrepeaterTrackByIndex);
493
+ function FeaturePipelineBuilderComponent_Conditional_70_Template(rf, ctx) { if (rf & 1) {
494
+ i0.ɵɵelementStart(0, "div", 25);
495
+ i0.ɵɵrepeaterCreate(1, FeaturePipelineBuilderComponent_Conditional_70_For_2_Template, 37, 12, "div", 41, i0.ɵɵrepeaterTrackByIndex);
317
496
  i0.ɵɵelementEnd();
318
497
  } if (rf & 2) {
319
498
  const ctx_r1 = i0.ɵɵnextContext();
320
499
  i0.ɵɵadvance();
321
500
  i0.ɵɵrepeater(ctx_r1.spec.Outputs);
322
501
  } }
323
- function FeaturePipelineBuilderComponent_Conditional_90_Template(rf, ctx) { if (rf & 1) {
324
- const _r16 = i0.ɵɵgetCurrentView();
325
- i0.ɵɵelementStart(0, "div", 27)(1, "div", 6)(2, "label");
502
+ function FeaturePipelineBuilderComponent_Conditional_71_Conditional_12_For_8_Template(rf, ctx) { if (rf & 1) {
503
+ i0.ɵɵelementStart(0, "option", 73);
504
+ i0.ɵɵtext(1);
505
+ i0.ɵɵelementEnd();
506
+ } if (rf & 2) {
507
+ const target_r30 = ctx.$implicit;
508
+ const ctx_r1 = i0.ɵɵnextContext(3);
509
+ i0.ɵɵproperty("value", target_r30.ID)("disabled", !!ctx_r1.GetTargetProblem(target_r30))("selected", ctx_r1.IsSavedEscalationTarget(target_r30));
510
+ i0.ɵɵadvance();
511
+ i0.ɵɵtextInterpolate2(" ", target_r30.Name, "", ctx_r1.GetTargetProblem(target_r30) ? " (" + ctx_r1.GetTargetProblem(target_r30) + ")" : "", " ");
512
+ } }
513
+ function FeaturePipelineBuilderComponent_Conditional_71_Conditional_12_Template(rf, ctx) { if (rf & 1) {
514
+ const _r29 = i0.ɵɵgetCurrentView();
515
+ i0.ɵɵelementStart(0, "div", 7)(1, "div", 3)(2, "label");
516
+ i0.ɵɵtext(3, "Target LLM Pipeline");
517
+ i0.ɵɵelementEnd();
518
+ i0.ɵɵelementStart(4, "select", 4);
519
+ i0.ɵɵlistener("change", function FeaturePipelineBuilderComponent_Conditional_71_Conditional_12_Template_select_change_4_listener($event) { i0.ɵɵrestoreView(_r29); const ctx_r1 = i0.ɵɵnextContext(2); return i0.ɵɵresetView(ctx_r1.OnEscalationTargetChange($event)); });
520
+ i0.ɵɵelementStart(5, "option", 18);
521
+ i0.ɵɵtext(6);
522
+ i0.ɵɵelementEnd();
523
+ i0.ɵɵrepeaterCreate(7, FeaturePipelineBuilderComponent_Conditional_71_Conditional_12_For_8_Template, 2, 5, "option", 73, _forTrack1);
524
+ i0.ɵɵelementEnd()();
525
+ i0.ɵɵelementStart(9, "div", 3)(10, "label");
526
+ i0.ɵɵtext(11, "Confidence Floor (0.0 to 1.0)");
527
+ i0.ɵɵelementEnd();
528
+ i0.ɵɵelementStart(12, "input", 74);
529
+ i0.ɵɵlistener("input", function FeaturePipelineBuilderComponent_Conditional_71_Conditional_12_Template_input_input_12_listener($event) { i0.ɵɵrestoreView(_r29); const ctx_r1 = i0.ɵɵnextContext(2); return i0.ɵɵresetView(ctx_r1.OnEscalationFloorChange($event)); });
530
+ i0.ɵɵelementEnd()()();
531
+ } if (rf & 2) {
532
+ const ctx_r1 = i0.ɵɵnextContext(2);
533
+ i0.ɵɵadvance(5);
534
+ i0.ɵɵproperty("selected", !ctx_r1.SavedEscalationTargetListed);
535
+ i0.ɵɵadvance();
536
+ i0.ɵɵtextInterpolate(ctx_r1.EscalationTargetsPlaceholder);
537
+ i0.ɵɵadvance();
538
+ i0.ɵɵrepeater(ctx_r1.AvailableEscalationTargets);
539
+ i0.ɵɵadvance(5);
540
+ i0.ɵɵproperty("value", (ctx_r1.spec.Escalation == null ? null : ctx_r1.spec.Escalation.BelowConfidence) ?? "");
541
+ } }
542
+ function FeaturePipelineBuilderComponent_Conditional_71_Template(rf, ctx) { if (rf & 1) {
543
+ const _r28 = i0.ɵɵgetCurrentView();
544
+ i0.ɵɵelementStart(0, "section", 26)(1, "div", 9);
545
+ i0.ɵɵelement(2, "i", 69);
546
+ i0.ɵɵelementStart(3, "h3");
547
+ i0.ɵɵtext(4, "Borderline Escalation");
548
+ i0.ɵɵelementEnd()();
549
+ i0.ɵɵelementStart(5, "p", 11);
550
+ i0.ɵɵtext(6, "Records any output of which the decision model answers below this confidence are re-run through the chosen LLM pipeline. Only those records are re-run.");
551
+ i0.ɵɵelementEnd();
552
+ i0.ɵɵelementStart(7, "div", 70)(8, "label", 71)(9, "input", 72);
553
+ i0.ɵɵlistener("change", function FeaturePipelineBuilderComponent_Conditional_71_Template_input_change_9_listener($event) { i0.ɵɵrestoreView(_r28); const ctx_r1 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r1.OnEscalationToggle($event)); });
554
+ i0.ɵɵelementEnd();
555
+ i0.ɵɵelementStart(10, "span");
556
+ i0.ɵɵtext(11, "Escalate borderline records to an LLM pipeline");
557
+ i0.ɵɵelementEnd()()();
558
+ i0.ɵɵconditionalCreate(12, FeaturePipelineBuilderComponent_Conditional_71_Conditional_12_Template, 13, 3, "div", 7);
559
+ i0.ɵɵelementEnd();
560
+ } if (rf & 2) {
561
+ const ctx_r1 = i0.ɵɵnextContext();
562
+ i0.ɵɵadvance(9);
563
+ i0.ɵɵproperty("checked", ctx_r1.IsEscalationEnabled);
564
+ i0.ɵɵadvance(3);
565
+ i0.ɵɵconditional(ctx_r1.IsEscalationEnabled ? 12 : -1);
566
+ } }
567
+ function FeaturePipelineBuilderComponent_Conditional_105_Template(rf, ctx) { if (rf & 1) {
568
+ const _r31 = i0.ɵɵgetCurrentView();
569
+ i0.ɵɵelementStart(0, "div", 32)(1, "div", 3)(2, "label");
326
570
  i0.ɵɵtext(3, "Cache Key Fields (comma separated)");
327
571
  i0.ɵɵelementEnd();
328
- i0.ɵɵelementStart(4, "input", 54);
329
- i0.ɵɵlistener("input", function FeaturePipelineBuilderComponent_Conditional_90_Template_input_input_4_listener($event) { i0.ɵɵrestoreView(_r16); const ctx_r1 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r1.updateCacheKeyFields($event)); });
572
+ i0.ɵɵelementStart(4, "input", 75);
573
+ i0.ɵɵlistener("input", function FeaturePipelineBuilderComponent_Conditional_105_Template_input_input_4_listener($event) { i0.ɵɵrestoreView(_r31); const ctx_r1 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r1.updateCacheKeyFields($event)); });
330
574
  i0.ɵɵelementEnd()();
331
- i0.ɵɵelementStart(5, "div", 6)(6, "label");
575
+ i0.ɵɵelementStart(5, "div", 3)(6, "label");
332
576
  i0.ɵɵtext(7, "Cache TTL (Seconds)");
333
577
  i0.ɵɵelementEnd();
334
- i0.ɵɵelementStart(8, "input", 53);
335
- i0.ɵɵlistener("input", function FeaturePipelineBuilderComponent_Conditional_90_Template_input_input_8_listener($event) { i0.ɵɵrestoreView(_r16); const ctx_r1 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r1.updateCacheTTL($event)); });
578
+ i0.ɵɵelementStart(8, "input", 67);
579
+ i0.ɵɵlistener("input", function FeaturePipelineBuilderComponent_Conditional_105_Template_input_input_8_listener($event) { i0.ɵɵrestoreView(_r31); const ctx_r1 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r1.updateCacheTTL($event)); });
336
580
  i0.ɵɵelementEnd()();
337
- i0.ɵɵelementStart(9, "div", 6)(10, "label");
581
+ i0.ɵɵelementStart(9, "div", 3)(10, "label");
338
582
  i0.ɵɵtext(11, "Cache Scope");
339
583
  i0.ɵɵelementEnd();
340
- i0.ɵɵelementStart(12, "select", 7);
341
- i0.ɵɵlistener("change", function FeaturePipelineBuilderComponent_Conditional_90_Template_select_change_12_listener($event) { i0.ɵɵrestoreView(_r16); const ctx_r1 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r1.updateCacheScope($event)); });
342
- i0.ɵɵelementStart(13, "option", 55);
584
+ i0.ɵɵelementStart(12, "select", 13);
585
+ i0.ɵɵlistener("change", function FeaturePipelineBuilderComponent_Conditional_105_Template_select_change_12_listener($event) { i0.ɵɵrestoreView(_r31); const ctx_r1 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r1.updateCacheScope($event)); });
586
+ i0.ɵɵelementStart(13, "option", 76);
343
587
  i0.ɵɵtext(14, "Pipeline (Isolated to this process)");
344
588
  i0.ɵɵelementEnd();
345
- i0.ɵɵelementStart(15, "option", 56);
589
+ i0.ɵɵelementStart(15, "option", 77);
346
590
  i0.ɵɵtext(16, "Prompt (Shared across processes with same prompt)");
347
591
  i0.ɵɵelementEnd()()()();
348
592
  } if (rf & 2) {
@@ -354,44 +598,62 @@ function FeaturePipelineBuilderComponent_Conditional_90_Template(rf, ctx) { if (
354
598
  i0.ɵɵadvance(4);
355
599
  i0.ɵɵproperty("value", ctx_r1.spec.Caching.Scope || "pipeline");
356
600
  } }
357
- function FeaturePipelineBuilderComponent_Conditional_91_For_6_Conditional_4_Template(rf, ctx) { if (rf & 1) {
358
- i0.ɵɵelementStart(0, "span", 31);
601
+ function FeaturePipelineBuilderComponent_Conditional_106_For_6_Conditional_4_Template(rf, ctx) { if (rf & 1) {
602
+ i0.ɵɵelementStart(0, "span", 38);
359
603
  i0.ɵɵtext(1);
360
604
  i0.ɵɵelementEnd();
361
605
  } if (rf & 2) {
362
- const issue_r17 = i0.ɵɵnextContext().$implicit;
606
+ const issue_r32 = i0.ɵɵnextContext().$implicit;
363
607
  i0.ɵɵadvance();
364
- i0.ɵɵtextInterpolate1("(Fix: ", issue_r17.FixRecommendation, ")");
608
+ i0.ɵɵtextInterpolate1("(Fix: ", issue_r32.FixRecommendation, ")");
365
609
  } }
366
- function FeaturePipelineBuilderComponent_Conditional_91_For_6_Template(rf, ctx) { if (rf & 1) {
610
+ function FeaturePipelineBuilderComponent_Conditional_106_For_6_Template(rf, ctx) { if (rf & 1) {
367
611
  i0.ɵɵelementStart(0, "li")(1, "strong");
368
612
  i0.ɵɵtext(2);
369
613
  i0.ɵɵelementEnd();
370
614
  i0.ɵɵtext(3);
371
- i0.ɵɵconditionalCreate(4, FeaturePipelineBuilderComponent_Conditional_91_For_6_Conditional_4_Template, 2, 1, "span", 31);
615
+ i0.ɵɵconditionalCreate(4, FeaturePipelineBuilderComponent_Conditional_106_For_6_Conditional_4_Template, 2, 1, "span", 38);
372
616
  i0.ɵɵelementEnd();
373
617
  } if (rf & 2) {
374
- const issue_r17 = ctx.$implicit;
618
+ const issue_r32 = ctx.$implicit;
375
619
  i0.ɵɵadvance(2);
376
- i0.ɵɵtextInterpolate(issue_r17.Field ? issue_r17.Field + ": " : "");
620
+ i0.ɵɵtextInterpolate(issue_r32.Field ? issue_r32.Field + ": " : "");
377
621
  i0.ɵɵadvance();
378
- i0.ɵɵtextInterpolate1("", issue_r17.Message, " ");
622
+ i0.ɵɵtextInterpolate1("", issue_r32.Message, " ");
379
623
  i0.ɵɵadvance();
380
- i0.ɵɵconditional(issue_r17.FixRecommendation ? 4 : -1);
624
+ i0.ɵɵconditional(issue_r32.FixRecommendation ? 4 : -1);
381
625
  } }
382
- function FeaturePipelineBuilderComponent_Conditional_91_Template(rf, ctx) { if (rf & 1) {
383
- i0.ɵɵelementStart(0, "div", 28)(1, "h4");
384
- i0.ɵɵelement(2, "i", 57);
626
+ function FeaturePipelineBuilderComponent_Conditional_106_Template(rf, ctx) { if (rf & 1) {
627
+ i0.ɵɵelementStart(0, "div", 33)(1, "h4");
628
+ i0.ɵɵelement(2, "i", 78);
385
629
  i0.ɵɵtext(3, " Specification Issues");
386
630
  i0.ɵɵelementEnd();
387
631
  i0.ɵɵelementStart(4, "ul");
388
- i0.ɵɵrepeaterCreate(5, FeaturePipelineBuilderComponent_Conditional_91_For_6_Template, 5, 3, "li", null, i0.ɵɵrepeaterTrackByIndex);
632
+ i0.ɵɵrepeaterCreate(5, FeaturePipelineBuilderComponent_Conditional_106_For_6_Template, 5, 3, "li", null, i0.ɵɵrepeaterTrackByIndex);
389
633
  i0.ɵɵelementEnd()();
390
634
  } if (rf & 2) {
391
635
  const ctx_r1 = i0.ɵɵnextContext();
392
636
  i0.ɵɵadvance(5);
393
637
  i0.ɵɵrepeater(ctx_r1.validationErrors);
394
638
  } }
639
+ function FeaturePipelineBuilderComponent_For_110_Template(rf, ctx) { if (rf & 1) {
640
+ i0.ɵɵelementStart(0, "li");
641
+ i0.ɵɵtext(1);
642
+ i0.ɵɵelementEnd();
643
+ } if (rf & 2) {
644
+ const issue_r33 = ctx.$implicit;
645
+ i0.ɵɵadvance();
646
+ i0.ɵɵtextInterpolate(issue_r33);
647
+ } }
648
+ /**
649
+ * The confidence floor typed into the builder, as a number. A blank or non-numeric entry is NaN, so the spec
650
+ * check reports it ("must be a number greater than 0 and less than 1, but is NaN") instead of the builder
651
+ * guessing a value; an out-of-range number is kept as typed, for the same check to report.
652
+ */
653
+ export function ParseConfidenceFloor(raw) {
654
+ const text = raw.trim();
655
+ return text.length === 0 ? Number.NaN : Number(text);
656
+ }
395
657
  export class FeaturePipelineBuilderComponent extends BaseAngularComponent {
396
658
  cdr = inject(ChangeDetectorRef);
397
659
  Record = null;
@@ -406,28 +668,241 @@ export class FeaturePipelineBuilderComponent extends BaseAngularComponent {
406
668
  Outputs: [],
407
669
  Caching: { Cacheable: false },
408
670
  };
409
- availablePrompts = [];
410
- availableDocs = [];
411
- availableEntities = [];
412
- entityFields = [];
413
- selectedPrompt = null;
414
- contextMode = 'fields';
415
- fieldsCsv = '';
416
- cacheKeyFieldsCsv = '';
417
- validationErrors = [];
418
- renderedConstraintPreview = '';
671
+ AvailablePipelineTypes = [
672
+ { Name: 'LLM', Description: null },
673
+ ];
674
+ ShowTypeSwitchConfirm = false;
675
+ PendingPipelineType = null;
676
+ TypeSwitchIssues = [];
677
+ get CurrentPipelineTypeName() {
678
+ return this.spec.PipelineType?.trim() || 'LLM';
679
+ }
680
+ get CurrentCapabilities() {
681
+ return GetFeaturePipelineCapabilities(this.CurrentPipelineTypeName);
682
+ }
683
+ get IsDecisionPipeline() {
684
+ return this.CurrentPipelineTypeName.toLowerCase() === 'decision';
685
+ }
686
+ AvailableEscalationTargets = [];
687
+ /** Whether the escalation targets were loaded. False until a load succeeds, and after one fails. */
688
+ EscalationTargetsLoaded = false;
689
+ /** Why the last load of escalation targets failed, or null when it did not. */
690
+ EscalationTargetsLoadError = null;
691
+ /** Numbers each target load, so a slower earlier load cannot overwrite a later one. */
692
+ escalationTargetsLoadSeq = 0;
693
+ get IsEscalationEnabled() {
694
+ return this.spec.Escalation !== undefined && this.spec.Escalation !== null;
695
+ }
696
+ /** The target picker's empty option: what to pick, or why there is nothing to pick. */
697
+ get EscalationTargetsPlaceholder() {
698
+ if (this.EscalationTargetsLoadError) {
699
+ return '— Pipelines could not be loaded —';
700
+ }
701
+ return this.AvailableEscalationTargets.length > 0 ? '— Select LLM Pipeline —' : '— No other Infer pipelines on this entity —';
702
+ }
703
+ /** Whether `target` is the spec's escalation target. IDs compare through UUIDsEqual, as the target check does. */
704
+ IsSavedEscalationTarget(target) {
705
+ return UUIDsEqual(target.ID, this.spec.Escalation?.PipelineID);
706
+ }
707
+ /** Whether the target picker lists the spec's escalation target. Until the targets load, or when it is not among them, the placeholder shows. */
708
+ get SavedEscalationTargetListed() {
709
+ return this.AvailableEscalationTargets.some((t) => this.IsSavedEscalationTarget(t));
710
+ }
711
+ /**
712
+ * Whether to offer the Capture Reasoning setting: for a type that produces reasoning, and for any spec
713
+ * that already asks for it, so a pipeline switched to a type without reasoning can turn it off.
714
+ */
715
+ get ShowCaptureReasoning() {
716
+ return this.CurrentCapabilities.ProducesReasoning || this.spec.CaptureReasoning === true;
717
+ }
718
+ get SelectedPipelineTypeDescription() {
719
+ const cur = this.CurrentPipelineTypeName.toLowerCase();
720
+ const opt = this.AvailablePipelineTypes.find((t) => t.Name.toLowerCase() === cur);
721
+ return opt?.Description ?? '';
722
+ }
723
+ get AvailableTargetModes() {
724
+ const all = [
725
+ { Value: 'field', Label: 'Entity Column (field)' },
726
+ { Value: 'child', Label: 'Child Rows (child)' },
727
+ { Value: 'tags', Label: 'Taxonomy Tags (tags)' },
728
+ ];
729
+ const supported = this.CurrentCapabilities.TargetModes;
730
+ return all.filter((m) => supported.includes(m.Value));
731
+ }
732
+ get AvailableConstraintTypes() {
733
+ const options = [];
734
+ if (!this.IsDecisionPipeline) {
735
+ options.push({ Value: 'none', Label: 'None / Unconstrained' });
736
+ }
737
+ if (this.CurrentCapabilities.ConstraintTypes.includes('boolean')) {
738
+ options.push({ Value: 'boolean', Label: 'Boolean' });
739
+ }
740
+ if (this.CurrentCapabilities.ConstraintTypes.includes('enum')) {
741
+ options.push({ Value: 'enum', Label: 'Enum (Allowed Values)' });
742
+ }
743
+ if (this.CurrentCapabilities.ConstraintTypes.includes('numeric')) {
744
+ options.push({ Value: 'numeric', Label: this.IsDecisionPipeline ? 'Numeric (Levels)' : 'Numeric (Min/Max)' });
745
+ }
746
+ if (this.CurrentCapabilities.ConstraintTypes.includes('freetext')) {
747
+ options.push({ Value: 'freetext', Label: 'Free Text' });
748
+ }
749
+ return options;
750
+ }
751
+ // The pickers mark the saved option with [selected] on each <option>, not [value] on the <select>. A [value]
752
+ // binding runs before @for creates the options, matches nothing, and does not run again, so the browser shows
753
+ // the first option. When the saved value is not listed, the placeholder is selected. A placeholder inside @if
754
+ // binds [selected] instead of carrying the attribute, because on a live type switch the attribute loses to the
755
+ // option still selected, which is then removed.
756
+ /** Whether `name` is the spec's pipeline type. Names compare case-insensitively, as {@link IsDecisionPipeline} does. */
757
+ IsCurrentPipelineType(name) {
758
+ return name.toLowerCase() === this.CurrentPipelineTypeName.toLowerCase();
759
+ }
760
+ /** The output's saved constraint type as the constraint picker names it: `'none'` when it has none. */
761
+ SavedConstraintType(output) {
762
+ return output.Constraint?.Type || 'none';
763
+ }
764
+ /** Whether the constraint picker lists the output's saved type. A Decision output with no constraint, or one this type cannot produce, is not listed. */
765
+ IsConstraintTypeOffered(output) {
766
+ const saved = this.SavedConstraintType(output);
767
+ return this.AvailableConstraintTypes.some((t) => t.Value === saved);
768
+ }
769
+ /** Whether the target mode picker lists the output's saved mode. */
770
+ IsTargetModeOffered(output) {
771
+ return this.AvailableTargetModes.some((m) => m.Value === output.Target.Mode);
772
+ }
773
+ /** Whether the target field picker lists a field named `name`. */
774
+ IsEntityFieldListed(name) {
775
+ return !!name && this.EntityFields.some((f) => f.Name === name);
776
+ }
777
+ /** Whether the child entity picker lists an entity named `name`. */
778
+ IsEntityListed(name) {
779
+ return !!name && this.AvailableEntities.some((e) => e.Name === name);
780
+ }
781
+ /** Whether `prompt` is the pipeline's saved prompt. */
782
+ IsSavedPrompt(prompt) {
783
+ return UUIDsEqual(prompt.ID, this.Record ? this.Record.PromptID : this.spec.PromptID);
784
+ }
785
+ /** Whether the prompt picker lists the pipeline's saved prompt. */
786
+ get SavedPromptListed() {
787
+ return this.AvailablePrompts.some((p) => this.IsSavedPrompt(p));
788
+ }
789
+ /** Whether `doc` is the spec's saved entity document. */
790
+ IsSavedEntityDoc(doc) {
791
+ return UUIDsEqual(doc.ID, this.spec.Context.EntityDocumentID);
792
+ }
793
+ /** Whether the entity document picker lists the spec's saved document. */
794
+ get SavedEntityDocListed() {
795
+ return this.AvailableDocs.some((d) => this.IsSavedEntityDoc(d));
796
+ }
797
+ AvailablePrompts = [];
798
+ /** @deprecated Use {@link AvailablePrompts}. */
799
+ get availablePrompts() {
800
+ return this.AvailablePrompts;
801
+ }
802
+ /** @deprecated Use {@link AvailablePrompts}. */
803
+ set availablePrompts(value) {
804
+ this.AvailablePrompts = value;
805
+ }
806
+ AvailableDocs = [];
807
+ /** @deprecated Use {@link AvailableDocs}. */
808
+ get availableDocs() {
809
+ return this.AvailableDocs;
810
+ }
811
+ /** @deprecated Use {@link AvailableDocs}. */
812
+ set availableDocs(value) {
813
+ this.AvailableDocs = value;
814
+ }
815
+ AvailableEntities = [];
816
+ /** @deprecated Use {@link AvailableEntities}. */
817
+ get availableEntities() {
818
+ return this.AvailableEntities;
819
+ }
820
+ /** @deprecated Use {@link AvailableEntities}. */
821
+ set availableEntities(value) {
822
+ this.AvailableEntities = value;
823
+ }
824
+ EntityFields = [];
825
+ /** @deprecated Use {@link EntityFields}. */
826
+ get entityFields() {
827
+ return this.EntityFields;
828
+ }
829
+ /** @deprecated Use {@link EntityFields}. */
830
+ set entityFields(value) {
831
+ this.EntityFields = value;
832
+ }
833
+ SelectedPrompt = null;
834
+ /** @deprecated Use {@link SelectedPrompt}. */
835
+ get selectedPrompt() {
836
+ return this.SelectedPrompt;
837
+ }
838
+ /** @deprecated Use {@link SelectedPrompt}. */
839
+ set selectedPrompt(value) {
840
+ this.SelectedPrompt = value;
841
+ }
842
+ ContextMode = 'fields';
843
+ /** @deprecated Use {@link ContextMode}. */
844
+ get contextMode() {
845
+ return this.ContextMode;
846
+ }
847
+ /** @deprecated Use {@link ContextMode}. */
848
+ set contextMode(value) {
849
+ this.ContextMode = value;
850
+ }
851
+ FieldsCsv = '';
852
+ /** @deprecated Use {@link FieldsCsv}. */
853
+ get fieldsCsv() {
854
+ return this.FieldsCsv;
855
+ }
856
+ /** @deprecated Use {@link FieldsCsv}. */
857
+ set fieldsCsv(value) {
858
+ this.FieldsCsv = value;
859
+ }
860
+ CacheKeyFieldsCsv = '';
861
+ /** @deprecated Use {@link CacheKeyFieldsCsv}. */
862
+ get cacheKeyFieldsCsv() {
863
+ return this.CacheKeyFieldsCsv;
864
+ }
865
+ /** @deprecated Use {@link CacheKeyFieldsCsv}. */
866
+ set cacheKeyFieldsCsv(value) {
867
+ this.CacheKeyFieldsCsv = value;
868
+ }
869
+ ValidationErrors = [];
870
+ /** @deprecated Use {@link ValidationErrors}. */
871
+ get validationErrors() {
872
+ return this.ValidationErrors;
873
+ }
874
+ /** @deprecated Use {@link ValidationErrors}. */
875
+ set validationErrors(value) {
876
+ this.ValidationErrors = value;
877
+ }
878
+ RenderedConstraintPreview = '';
879
+ /** @deprecated Use {@link RenderedConstraintPreview}. */
880
+ get renderedConstraintPreview() {
881
+ return this.RenderedConstraintPreview;
882
+ }
883
+ /** @deprecated Use {@link RenderedConstraintPreview}. */
884
+ set renderedConstraintPreview(value) {
885
+ this.RenderedConstraintPreview = value;
886
+ }
419
887
  async ngOnInit() {
420
- this.availableEntities = [...this.ProviderToUse.Entities].sort((a, b) => (a.DisplayName || a.Name).localeCompare(b.DisplayName || b.Name));
888
+ this.AvailableEntities = [...this.ProviderToUse.Entities].sort((a, b) => (a.DisplayName || a.Name).localeCompare(b.DisplayName || b.Name));
889
+ await this.loadPipelineTypes();
421
890
  await this.loadPrompts();
422
891
  await this.loadEntityDocs();
423
- this.syncFromRecord();
892
+ await this.LoadEscalationTargets();
893
+ this.SyncFromRecord();
424
894
  }
425
895
  ngOnChanges(changes) {
426
896
  if (changes['Record'] || changes['EntityID']) {
427
- this.syncFromRecord();
897
+ this.SyncFromRecord();
898
+ // ngOnInit loads the targets for the first binding; reload only when the pipeline or entity changes after it
899
+ const firstBinding = Object.values(changes).every((change) => change.firstChange);
900
+ if (!firstBinding) {
901
+ void this.LoadEscalationTargets();
902
+ }
428
903
  }
429
904
  }
430
- syncFromRecord() {
905
+ SyncFromRecord() {
431
906
  if (this.Record) {
432
907
  this.spec.Name = this.Record.Name || '';
433
908
  this.spec.Description = this.Record.Description || '';
@@ -439,6 +914,16 @@ export class FeaturePipelineBuilderComponent extends BaseAngularComponent {
439
914
  this.spec.Context = parsed.Context ?? {};
440
915
  this.spec.Caching = parsed.Caching ?? { Cacheable: false };
441
916
  this.spec.ProcessorExtensionKey = parsed.ProcessorExtensionKey;
917
+ this.spec.PipelineType = parsed.PipelineType;
918
+ if (parsed.Escalation) {
919
+ this.spec.Escalation = { ...parsed.Escalation };
920
+ }
921
+ else {
922
+ delete this.spec.Escalation;
923
+ }
924
+ // Carried so the capability check sees what the runtime sees, and the next edit keeps them
925
+ this.spec.CaptureReasoning = parsed.CaptureReasoning;
926
+ this.spec.Watermark = parsed.Watermark;
442
927
  }
443
928
  }
444
929
  }
@@ -449,30 +934,100 @@ export class FeaturePipelineBuilderComponent extends BaseAngularComponent {
449
934
  this.spec.Context = {};
450
935
  }
451
936
  if (this.spec.Context.EntityDocumentID) {
452
- this.contextMode = 'document';
937
+ this.ContextMode = 'document';
453
938
  }
454
939
  else if (this.spec.Context.QueryID) {
455
- this.contextMode = 'query';
940
+ this.ContextMode = 'query';
456
941
  }
457
942
  else {
458
- this.contextMode = 'fields';
943
+ this.ContextMode = 'fields';
459
944
  }
460
- this.fieldsCsv = (this.spec.Context.Fields ?? []).join(', ');
461
- this.cacheKeyFieldsCsv = (this.spec.Caching.KeyFields ?? []).join(', ');
945
+ this.FieldsCsv = (this.spec.Context.Fields ?? []).join(', ');
946
+ this.CacheKeyFieldsCsv = (this.spec.Caching.KeyFields ?? []).join(', ');
462
947
  const targetEntityID = this.Record?.EntityID || this.EntityID;
463
948
  if (targetEntityID) {
464
949
  const entity = this.ProviderToUse.EntityByID(targetEntityID);
465
- this.entityFields = entity?.Fields ? [...entity.Fields].sort((a, b) => a.Name.localeCompare(b.Name)) : [];
950
+ this.EntityFields = entity?.Fields ? [...entity.Fields].sort((a, b) => a.Name.localeCompare(b.Name)) : [];
466
951
  }
467
952
  else {
468
- this.entityFields = [];
953
+ this.EntityFields = [];
469
954
  }
470
955
  if (this.Record?.PromptID) {
471
- this.selectedPrompt = this.availablePrompts.find((p) => UUIDsEqual(p.ID, this.Record?.PromptID)) ?? null;
956
+ this.SelectedPrompt = this.AvailablePrompts.find((p) => UUIDsEqual(p.ID, this.Record?.PromptID)) ?? null;
472
957
  }
958
+ this.ensureLoadedTypeIncluded();
473
959
  this.recomputeValidation();
474
960
  this.cdr.detectChanges();
475
961
  }
962
+ /** @deprecated Use {@link SyncFromRecord}. */
963
+ syncFromRecord() {
964
+ return this.SyncFromRecord();
965
+ }
966
+ async loadPipelineTypes() {
967
+ let activeRows = [];
968
+ try {
969
+ await KnowledgeHubMetadataEngine.Instance.Config(false, this.ProviderToUse.CurrentUser, this.ProviderToUse);
970
+ const engineTypes = KnowledgeHubMetadataEngine.Instance.FeaturePipelineTypes;
971
+ if (Array.isArray(engineTypes)) {
972
+ activeRows = engineTypes.filter((t) => t.Status === 'Active');
973
+ }
974
+ }
975
+ catch (error) {
976
+ LogError('Error loading Feature Pipeline Types from KnowledgeHubMetadataEngine', undefined, error);
977
+ }
978
+ if (activeRows.length > 0) {
979
+ this.AvailablePipelineTypes = activeRows.map((t) => ({
980
+ Name: t.Name,
981
+ Description: t.Description || null,
982
+ }));
983
+ if (!this.AvailablePipelineTypes.some((t) => t.Name.toLowerCase() === 'llm')) {
984
+ this.AvailablePipelineTypes.unshift({
985
+ Name: 'LLM',
986
+ Description: null,
987
+ });
988
+ }
989
+ }
990
+ else {
991
+ this.AvailablePipelineTypes = [
992
+ {
993
+ Name: 'LLM',
994
+ Description: null,
995
+ },
996
+ ];
997
+ }
998
+ this.ensureLoadedTypeIncluded();
999
+ }
1000
+ ensureLoadedTypeIncluded() {
1001
+ const typeName = this.spec.PipelineType?.trim();
1002
+ if (!typeName || typeName.toLowerCase() === 'llm') {
1003
+ return;
1004
+ }
1005
+ const exists = this.AvailablePipelineTypes.some((t) => t.Name.toLowerCase() === typeName.toLowerCase());
1006
+ if (exists) {
1007
+ return;
1008
+ }
1009
+ let isInactive = false;
1010
+ let desc = null;
1011
+ try {
1012
+ const engineTypes = KnowledgeHubMetadataEngine.Instance.FeaturePipelineTypes;
1013
+ if (Array.isArray(engineTypes)) {
1014
+ const match = engineTypes.find((t) => t.Name?.trim().toLowerCase() === typeName.toLowerCase());
1015
+ if (match) {
1016
+ isInactive = match.Status !== 'Active';
1017
+ desc = match.Description || null;
1018
+ }
1019
+ }
1020
+ }
1021
+ catch {
1022
+ // Ignore
1023
+ }
1024
+ const label = isInactive ? `${typeName} (inactive)` : `${typeName} (unrecognized)`;
1025
+ this.AvailablePipelineTypes.push({
1026
+ Name: typeName,
1027
+ DisplayName: label,
1028
+ Description: desc,
1029
+ });
1030
+ }
476
1031
  async loadPrompts() {
477
1032
  try {
478
1033
  const rv = RunView.FromMetadataProvider(this.ProviderToUse);
@@ -482,15 +1037,15 @@ export class FeaturePipelineBuilderComponent extends BaseAngularComponent {
482
1037
  ResultType: 'simple',
483
1038
  });
484
1039
  if (res.Success && Array.isArray(res.Results)) {
485
- this.availablePrompts = res.Results;
1040
+ this.AvailablePrompts = res.Results;
486
1041
  }
487
1042
  else {
488
- this.availablePrompts = [];
1043
+ this.AvailablePrompts = [];
489
1044
  LogError(`Failed to load AI Prompts: ${res.ErrorMessage || 'unknown error'}`);
490
1045
  }
491
1046
  }
492
1047
  catch (error) {
493
- this.availablePrompts = [];
1048
+ this.AvailablePrompts = [];
494
1049
  LogError('Error loading AI Prompts', undefined, error);
495
1050
  }
496
1051
  }
@@ -503,49 +1058,161 @@ export class FeaturePipelineBuilderComponent extends BaseAngularComponent {
503
1058
  ResultType: 'simple',
504
1059
  });
505
1060
  if (res.Success && Array.isArray(res.Results)) {
506
- this.availableDocs = res.Results;
1061
+ this.AvailableDocs = res.Results;
507
1062
  }
508
1063
  else {
509
- this.availableDocs = [];
1064
+ this.AvailableDocs = [];
510
1065
  LogError(`Failed to load Entity Documents: ${res.ErrorMessage || 'unknown error'}`);
511
1066
  }
512
1067
  }
513
1068
  catch (error) {
514
- this.availableDocs = [];
1069
+ this.AvailableDocs = [];
515
1070
  LogError('Error loading Entity Documents', undefined, error);
516
1071
  }
517
1072
  }
518
- onContextModeChange(event) {
519
- this.contextMode = event.target.value;
1073
+ /**
1074
+ * Loads the Infer pipelines on this pipeline's entity that it could escalate to. With no entity there is
1075
+ * nothing to offer, so nothing is loaded. A failed load is recorded in {@link EscalationTargetsLoadError},
1076
+ * not taken to mean there are no targets. Only the latest load's result is kept.
1077
+ */
1078
+ async LoadEscalationTargets() {
1079
+ const seq = ++this.escalationTargetsLoadSeq;
1080
+ const targetEntityID = this.Record?.EntityID || this.EntityID;
1081
+ const outcome = targetEntityID
1082
+ ? await this.fetchEscalationTargets(targetEntityID)
1083
+ : { Targets: [], Error: null };
1084
+ if (seq !== this.escalationTargetsLoadSeq) {
1085
+ return; // a later load, for a later Record or entity, has superseded this one
1086
+ }
1087
+ this.AvailableEscalationTargets = outcome.Targets;
1088
+ this.EscalationTargetsLoadError = outcome.Error;
1089
+ this.EscalationTargetsLoaded = outcome.Error === null;
1090
+ this.recomputeValidation();
1091
+ this.cdr.detectChanges();
1092
+ }
1093
+ /** The Infer pipelines on the entity, other than this one, each with its parsed spec; or why they could not be read. */
1094
+ async fetchEscalationTargets(entityID) {
1095
+ try {
1096
+ const rv = RunView.FromMetadataProvider(this.ProviderToUse);
1097
+ const res = await rv.RunView({
1098
+ EntityName: 'MJ: Record Processes',
1099
+ Fields: ['ID', 'Name', 'Description', 'Entity', 'EntityID', 'WorkType', 'Status', 'PromptID', 'Configuration'],
1100
+ ExtraFilter: `WorkType='Infer' AND EntityID='${EscapeSQLString(entityID)}'`,
1101
+ OrderBy: 'Name',
1102
+ ResultType: 'simple',
1103
+ });
1104
+ if (!res.Success) {
1105
+ const reason = res.ErrorMessage || 'unknown error';
1106
+ LogError(`Failed to load Escalation Targets: ${reason}`);
1107
+ return { Targets: [], Error: reason };
1108
+ }
1109
+ const currentID = this.Record?.ID;
1110
+ const targets = (res.Results ?? [])
1111
+ .filter((r) => !currentID || !UUIDsEqual(r.ID, currentID))
1112
+ .map((r) => ({ ...r, ParsedSpec: this.parseTargetSpec(r.Configuration) }));
1113
+ return { Targets: targets, Error: null };
1114
+ }
1115
+ catch (error) {
1116
+ LogError('Error loading Escalation Targets', undefined, error);
1117
+ return { Targets: [], Error: error instanceof Error ? error.message : String(error) };
1118
+ }
1119
+ }
1120
+ /** A target's Configuration as a spec, or undefined when it is empty or not a JSON object. */
1121
+ parseTargetSpec(configuration) {
1122
+ const parsed = configuration ? SafeJSONParse(configuration) : null;
1123
+ return parsed && typeof parsed === 'object' ? parsed : undefined;
1124
+ }
1125
+ /**
1126
+ * Why a pipeline cannot be this pipeline's escalation target, or null when it can. Beyond the shared row and
1127
+ * output checks, its own spec must pass `ValidateSpec`, as the engine requires before it builds the target.
1128
+ */
1129
+ GetTargetProblem(target) {
1130
+ const targetEntityID = this.Record?.EntityID || this.EntityID || '';
1131
+ const rowProblem = FindEscalationTargetRowProblem(target, targetEntityID);
1132
+ if (rowProblem) {
1133
+ return rowProblem;
1134
+ }
1135
+ const specError = target.ParsedSpec ? validateSpec(target.ParsedSpec).find((issue) => issue.Severity === 'error') : undefined;
1136
+ if (specError) {
1137
+ return `has an invalid spec: ${specError.Message}`;
1138
+ }
1139
+ return FindEscalationTargetSpecProblem(target.ParsedSpec, this.spec.Outputs ?? []);
1140
+ }
1141
+ OnEscalationToggle(event) {
1142
+ const checked = event.target.checked;
1143
+ if (checked) {
1144
+ this.spec.Escalation = {
1145
+ PipelineID: this.spec.Escalation?.PipelineID || '',
1146
+ BelowConfidence: this.spec.Escalation?.BelowConfidence ?? 0.7,
1147
+ };
1148
+ }
1149
+ else {
1150
+ delete this.spec.Escalation;
1151
+ }
1152
+ this.emitChanges();
1153
+ }
1154
+ OnEscalationTargetChange(event) {
1155
+ const val = event.target.value;
1156
+ if (!this.spec.Escalation) {
1157
+ this.spec.Escalation = {
1158
+ PipelineID: val,
1159
+ BelowConfidence: 0.7,
1160
+ };
1161
+ }
1162
+ else {
1163
+ this.spec.Escalation.PipelineID = val;
1164
+ }
1165
+ this.emitChanges();
1166
+ }
1167
+ /** Sets the confidence floor from its input, as a number; a blank or invalid entry is NaN, which the spec check reports. */
1168
+ OnEscalationFloorChange(event) {
1169
+ const floor = ParseConfidenceFloor(event.target.value);
1170
+ this.spec.Escalation = { PipelineID: this.spec.Escalation?.PipelineID ?? '', BelowConfidence: floor };
1171
+ this.emitChanges();
1172
+ }
1173
+ OnContextModeChange(event) {
1174
+ this.ContextMode = event.target.value;
520
1175
  if (!this.spec.Context)
521
1176
  this.spec.Context = {};
522
- if (this.contextMode === 'fields') {
1177
+ if (this.ContextMode === 'fields') {
523
1178
  this.spec.Context.EntityDocumentID = undefined;
524
1179
  this.spec.Context.QueryID = undefined;
525
1180
  }
526
- else if (this.contextMode === 'document') {
1181
+ else if (this.ContextMode === 'document') {
527
1182
  this.spec.Context.QueryID = undefined;
528
1183
  }
529
- else if (this.contextMode === 'query') {
1184
+ else if (this.ContextMode === 'query') {
530
1185
  this.spec.Context.EntityDocumentID = undefined;
531
1186
  }
532
1187
  this.emitChanges();
533
1188
  }
534
- onEntityDocChange(event) {
1189
+ /** @deprecated Use {@link OnContextModeChange}. */
1190
+ onContextModeChange(event) {
1191
+ return this.OnContextModeChange(event);
1192
+ }
1193
+ OnEntityDocChange(event) {
535
1194
  if (!this.spec.Context)
536
1195
  this.spec.Context = {};
537
1196
  this.spec.Context.EntityDocumentID = event.target.value;
538
1197
  this.emitChanges();
539
1198
  }
540
- onQueryIDChange(event) {
1199
+ /** @deprecated Use {@link OnEntityDocChange}. */
1200
+ onEntityDocChange(event) {
1201
+ return this.OnEntityDocChange(event);
1202
+ }
1203
+ OnQueryIDChange(event) {
541
1204
  if (!this.spec.Context)
542
1205
  this.spec.Context = {};
543
1206
  this.spec.Context.QueryID = event.target.value;
544
1207
  this.emitChanges();
545
1208
  }
546
- onFieldsCsvChange(event) {
1209
+ /** @deprecated Use {@link OnQueryIDChange}. */
1210
+ onQueryIDChange(event) {
1211
+ return this.OnQueryIDChange(event);
1212
+ }
1213
+ OnFieldsCsvChange(event) {
547
1214
  const val = event.target.value;
548
- this.fieldsCsv = val;
1215
+ this.FieldsCsv = val;
549
1216
  if (!this.spec.Context)
550
1217
  this.spec.Context = {};
551
1218
  this.spec.Context.Fields = val
@@ -554,49 +1221,71 @@ export class FeaturePipelineBuilderComponent extends BaseAngularComponent {
554
1221
  .filter((s) => s.length > 0);
555
1222
  this.emitChanges();
556
1223
  }
557
- onPromptChange(event) {
1224
+ /** @deprecated Use {@link OnFieldsCsvChange}. */
1225
+ onFieldsCsvChange(event) {
1226
+ return this.OnFieldsCsvChange(event);
1227
+ }
1228
+ OnPromptChange(event) {
558
1229
  const promptID = event.target.value;
559
1230
  if (this.Record) {
560
1231
  this.Record.PromptID = promptID;
561
1232
  }
562
1233
  this.spec.PromptID = promptID;
563
- this.selectedPrompt = this.availablePrompts.find((p) => UUIDsEqual(p.ID, promptID)) ?? null;
1234
+ this.SelectedPrompt = this.AvailablePrompts.find((p) => UUIDsEqual(p.ID, promptID)) ?? null;
564
1235
  this.emitChanges();
565
1236
  }
1237
+ /** @deprecated Use {@link OnPromptChange}. */
1238
+ onPromptChange(event) {
1239
+ return this.OnPromptChange(event);
1240
+ }
566
1241
  addOutput() {
567
1242
  const newOutput = {
568
1243
  Name: `Output_${this.spec.Outputs.length + 1}`,
569
1244
  Ref: '$',
570
1245
  Target: {
571
1246
  Mode: 'field',
572
- EntityFieldName: this.entityFields.length > 0 ? this.entityFields[0].Name : '',
1247
+ EntityFieldName: this.EntityFields.length > 0 ? this.EntityFields[0].Name : '',
573
1248
  },
574
1249
  };
1250
+ if (this.IsDecisionPipeline) {
1251
+ newOutput.Constraint = {
1252
+ Type: 'boolean',
1253
+ OnViolation: 'fail',
1254
+ };
1255
+ }
575
1256
  this.spec.Outputs.push(newOutput);
576
1257
  this.emitChanges();
577
1258
  }
578
- removeOutput(index) {
1259
+ RemoveOutput(index) {
579
1260
  this.spec.Outputs.splice(index, 1);
580
1261
  this.emitChanges();
581
1262
  }
582
- updateOutputProp(index, prop, event) {
1263
+ /** @deprecated Use {@link RemoveOutput}. */
1264
+ removeOutput(index) {
1265
+ return this.RemoveOutput(index);
1266
+ }
1267
+ UpdateOutputProp(index, prop, event) {
583
1268
  const val = event.target.value;
584
1269
  this.spec.Outputs[index][prop] = val;
585
1270
  this.emitChanges();
586
1271
  }
587
- updateTargetMode(index, event) {
1272
+ /** @deprecated Use {@link UpdateOutputProp}. */
1273
+ updateOutputProp(index, prop, event) {
1274
+ return this.UpdateOutputProp(index, prop, event);
1275
+ }
1276
+ UpdateTargetMode(index, event) {
588
1277
  const mode = event.target.value;
589
1278
  const current = this.spec.Outputs[index];
590
1279
  if (mode === 'field') {
591
1280
  current.Target = {
592
1281
  Mode: 'field',
593
- EntityFieldName: this.entityFields.length > 0 ? this.entityFields[0].Name : '',
1282
+ EntityFieldName: this.EntityFields.length > 0 ? this.EntityFields[0].Name : '',
594
1283
  };
595
1284
  }
596
1285
  else if (mode === 'child') {
597
1286
  current.Target = {
598
1287
  Mode: 'child',
599
- EntityName: this.availableEntities.length > 0 ? this.availableEntities[0].Name : '',
1288
+ EntityName: this.AvailableEntities.length > 0 ? this.AvailableEntities[0].Name : '',
600
1289
  ParentField: 'ParentID',
601
1290
  Map: {},
602
1291
  };
@@ -609,15 +1298,26 @@ export class FeaturePipelineBuilderComponent extends BaseAngularComponent {
609
1298
  }
610
1299
  this.emitChanges();
611
1300
  }
612
- updateFieldTarget(index, event) {
1301
+ /** @deprecated Use {@link UpdateTargetMode}. */
1302
+ updateTargetMode(index, event) {
1303
+ return this.UpdateTargetMode(index, event);
1304
+ }
1305
+ UpdateFieldTarget(index, event) {
613
1306
  const fieldName = event.target.value;
614
1307
  const target = this.spec.Outputs[index].Target;
615
1308
  if (target.Mode === 'field') {
616
1309
  target.EntityFieldName = fieldName;
1310
+ if (this.spec.Outputs[index].Constraint?.Type === 'enum') {
1311
+ this.prefillEnumValuesFromField(this.spec.Outputs[index]);
1312
+ }
617
1313
  }
618
1314
  this.emitChanges();
619
1315
  }
620
- updateChildTargetEntity(index, event) {
1316
+ /** @deprecated Use {@link UpdateFieldTarget}. */
1317
+ updateFieldTarget(index, event) {
1318
+ return this.UpdateFieldTarget(index, event);
1319
+ }
1320
+ UpdateChildTargetEntity(index, event) {
621
1321
  const entityName = event.target.value;
622
1322
  const target = this.spec.Outputs[index].Target;
623
1323
  if (target.Mode === 'child') {
@@ -625,7 +1325,11 @@ export class FeaturePipelineBuilderComponent extends BaseAngularComponent {
625
1325
  }
626
1326
  this.emitChanges();
627
1327
  }
628
- updateConstraintType(index, event) {
1328
+ /** @deprecated Use {@link UpdateChildTargetEntity}. */
1329
+ updateChildTargetEntity(index, event) {
1330
+ return this.UpdateChildTargetEntity(index, event);
1331
+ }
1332
+ UpdateConstraintType(index, event) {
629
1333
  const type = event.target.value;
630
1334
  const output = this.spec.Outputs[index];
631
1335
  if (type === 'none') {
@@ -633,9 +1337,15 @@ export class FeaturePipelineBuilderComponent extends BaseAngularComponent {
633
1337
  }
634
1338
  else if (type === 'enum') {
635
1339
  output.Constraint = { Type: 'enum', Values: [], OnViolation: 'fail' };
1340
+ this.prefillEnumValuesFromField(output);
636
1341
  }
637
1342
  else if (type === 'numeric') {
638
- output.Constraint = { Type: 'numeric', Min: 0, Max: 100, OnViolation: 'fail' };
1343
+ if (this.IsDecisionPipeline) {
1344
+ output.Constraint = { Type: 'numeric', Levels: ['Low', 'Medium', 'High'], OnViolation: 'fail' };
1345
+ }
1346
+ else {
1347
+ output.Constraint = { Type: 'numeric', Min: 0, Max: 100, OnViolation: 'fail' };
1348
+ }
639
1349
  }
640
1350
  else if (type === 'boolean') {
641
1351
  output.Constraint = { Type: 'boolean', OnViolation: 'fail' };
@@ -645,26 +1355,46 @@ export class FeaturePipelineBuilderComponent extends BaseAngularComponent {
645
1355
  }
646
1356
  this.emitChanges();
647
1357
  }
648
- updateViolationPolicy(index, event) {
1358
+ /** @deprecated Use {@link UpdateConstraintType}. */
1359
+ updateConstraintType(index, event) {
1360
+ return this.UpdateConstraintType(index, event);
1361
+ }
1362
+ UpdateViolationPolicy(index, event) {
649
1363
  const policy = event.target.value;
650
1364
  if (this.spec.Outputs[index].Constraint) {
651
1365
  this.spec.Outputs[index].Constraint.OnViolation = policy;
652
1366
  }
653
1367
  this.emitChanges();
654
1368
  }
655
- getEnumValuesCsv(constraint) {
1369
+ /** @deprecated Use {@link UpdateViolationPolicy}. */
1370
+ updateViolationPolicy(index, event) {
1371
+ return this.UpdateViolationPolicy(index, event);
1372
+ }
1373
+ GetEnumValuesCsv(constraint) {
656
1374
  if (!constraint || constraint.Type !== 'enum' || !Array.isArray(constraint.Values)) {
657
1375
  return '';
658
1376
  }
659
1377
  return constraint.Values.join(', ');
660
1378
  }
661
- getNumericMin(constraint) {
1379
+ /** @deprecated Use {@link GetEnumValuesCsv}. */
1380
+ getEnumValuesCsv(constraint) {
1381
+ return this.GetEnumValuesCsv(constraint);
1382
+ }
1383
+ GetNumericMin(constraint) {
662
1384
  return constraint && constraint.Type === 'numeric' && constraint.Min !== undefined ? constraint.Min : '';
663
1385
  }
664
- getNumericMax(constraint) {
1386
+ /** @deprecated Use {@link GetNumericMin}. */
1387
+ getNumericMin(constraint) {
1388
+ return this.GetNumericMin(constraint);
1389
+ }
1390
+ GetNumericMax(constraint) {
665
1391
  return constraint && constraint.Type === 'numeric' && constraint.Max !== undefined ? constraint.Max : '';
666
1392
  }
667
- updateEnumValues(index, event) {
1393
+ /** @deprecated Use {@link GetNumericMax}. */
1394
+ getNumericMax(constraint) {
1395
+ return this.GetNumericMax(constraint);
1396
+ }
1397
+ UpdateEnumValues(index, event) {
668
1398
  const val = event.target.value;
669
1399
  const output = this.spec.Outputs[index];
670
1400
  if (!output.Constraint || output.Constraint.Type !== 'enum') {
@@ -676,7 +1406,11 @@ export class FeaturePipelineBuilderComponent extends BaseAngularComponent {
676
1406
  .filter((s) => s.length > 0);
677
1407
  this.emitChanges();
678
1408
  }
679
- updateNumericMin(index, event) {
1409
+ /** @deprecated Use {@link UpdateEnumValues}. */
1410
+ updateEnumValues(index, event) {
1411
+ return this.UpdateEnumValues(index, event);
1412
+ }
1413
+ UpdateNumericMin(index, event) {
680
1414
  const val = parseFloat(event.target.value);
681
1415
  const output = this.spec.Outputs[index];
682
1416
  if (output.Constraint && output.Constraint.Type === 'numeric') {
@@ -684,7 +1418,11 @@ export class FeaturePipelineBuilderComponent extends BaseAngularComponent {
684
1418
  }
685
1419
  this.emitChanges();
686
1420
  }
687
- updateNumericMax(index, event) {
1421
+ /** @deprecated Use {@link UpdateNumericMin}. */
1422
+ updateNumericMin(index, event) {
1423
+ return this.UpdateNumericMin(index, event);
1424
+ }
1425
+ UpdateNumericMax(index, event) {
688
1426
  const val = parseFloat(event.target.value);
689
1427
  const output = this.spec.Outputs[index];
690
1428
  if (output.Constraint && output.Constraint.Type === 'numeric') {
@@ -692,25 +1430,41 @@ export class FeaturePipelineBuilderComponent extends BaseAngularComponent {
692
1430
  }
693
1431
  this.emitChanges();
694
1432
  }
695
- updateWatermarkStrategy(event) {
1433
+ /** @deprecated Use {@link UpdateNumericMax}. */
1434
+ updateNumericMax(index, event) {
1435
+ return this.UpdateNumericMax(index, event);
1436
+ }
1437
+ UpdateWatermarkStrategy(event) {
696
1438
  if (this.Record) {
697
1439
  this.Record.WatermarkStrategy = event.target.value;
698
1440
  }
699
1441
  }
700
- updateSkipUnchanged(event) {
1442
+ /** @deprecated Use {@link UpdateWatermarkStrategy}. */
1443
+ updateWatermarkStrategy(event) {
1444
+ return this.UpdateWatermarkStrategy(event);
1445
+ }
1446
+ UpdateSkipUnchanged(event) {
701
1447
  if (this.Record) {
702
1448
  this.Record.SkipUnchanged = event.target.value === 'true';
703
1449
  }
704
1450
  }
705
- updateCacheable(event) {
1451
+ /** @deprecated Use {@link UpdateSkipUnchanged}. */
1452
+ updateSkipUnchanged(event) {
1453
+ return this.UpdateSkipUnchanged(event);
1454
+ }
1455
+ UpdateCacheable(event) {
706
1456
  if (!this.spec.Caching)
707
1457
  this.spec.Caching = { Cacheable: false };
708
1458
  this.spec.Caching.Cacheable = event.target.value === 'true';
709
1459
  this.emitChanges();
710
1460
  }
711
- updateCacheKeyFields(event) {
1461
+ /** @deprecated Use {@link UpdateCacheable}. */
1462
+ updateCacheable(event) {
1463
+ return this.UpdateCacheable(event);
1464
+ }
1465
+ UpdateCacheKeyFields(event) {
712
1466
  const val = event.target.value;
713
- this.cacheKeyFieldsCsv = val;
1467
+ this.CacheKeyFieldsCsv = val;
714
1468
  if (!this.spec.Caching)
715
1469
  this.spec.Caching = { Cacheable: true };
716
1470
  this.spec.Caching.KeyFields = val
@@ -719,21 +1473,239 @@ export class FeaturePipelineBuilderComponent extends BaseAngularComponent {
719
1473
  .filter((s) => s.length > 0);
720
1474
  this.emitChanges();
721
1475
  }
722
- updateCacheTTL(event) {
1476
+ /** @deprecated Use {@link UpdateCacheKeyFields}. */
1477
+ updateCacheKeyFields(event) {
1478
+ return this.UpdateCacheKeyFields(event);
1479
+ }
1480
+ UpdateCacheTTL(event) {
723
1481
  const val = parseInt(event.target.value, 10);
724
1482
  if (!this.spec.Caching)
725
1483
  this.spec.Caching = { Cacheable: true };
726
1484
  this.spec.Caching.TTLSeconds = isNaN(val) ? 86400 : val;
727
1485
  this.emitChanges();
728
1486
  }
729
- updateCacheScope(event) {
1487
+ /** @deprecated Use {@link UpdateCacheTTL}. */
1488
+ updateCacheTTL(event) {
1489
+ return this.UpdateCacheTTL(event);
1490
+ }
1491
+ UpdateCacheScope(event) {
730
1492
  const val = event.target.value;
731
1493
  if (!this.spec.Caching)
732
1494
  this.spec.Caching = { Cacheable: true };
733
1495
  this.spec.Caching.Scope = val;
734
1496
  this.emitChanges();
735
1497
  }
1498
+ /** @deprecated Use {@link UpdateCacheScope}. */
1499
+ updateCacheScope(event) {
1500
+ return this.UpdateCacheScope(event);
1501
+ }
1502
+ /** Turns capture of the model's rationale on or off. Off removes the flag, so a spec that never set it keeps its hash. */
1503
+ UpdateCaptureReasoning(event) {
1504
+ if (event.target.value === 'true') {
1505
+ this.spec.CaptureReasoning = true;
1506
+ }
1507
+ else {
1508
+ delete this.spec.CaptureReasoning;
1509
+ }
1510
+ this.emitChanges();
1511
+ }
1512
+ OnPipelineTypeSelect(event) {
1513
+ const target = event.target;
1514
+ const newType = target.value;
1515
+ const currentType = this.CurrentPipelineTypeName;
1516
+ if (newType.toLowerCase() === currentType.toLowerCase()) {
1517
+ return;
1518
+ }
1519
+ const isNewTypeLLM = newType.trim().toLowerCase() === 'llm';
1520
+ const candidateSpec = {
1521
+ ...this.spec,
1522
+ PipelineType: isNewTypeLLM ? undefined : newType.trim(),
1523
+ };
1524
+ if (newType.trim().toLowerCase() !== 'decision') {
1525
+ delete candidateSpec.Escalation;
1526
+ }
1527
+ const newCapabilities = GetFeaturePipelineCapabilities(newType);
1528
+ const lookup = this.buildFieldValuesLookup();
1529
+ const capIssues = ValidateOutputsAgainstCapabilities(candidateSpec, newCapabilities, lookup);
1530
+ let specIssues = [];
1531
+ const entity = this.Record?.EntityID ? this.ProviderToUse.EntityByID(this.Record.EntityID) : null;
1532
+ if (entity) {
1533
+ const stub = {
1534
+ Name: entity.Name,
1535
+ Fields: (entity.Fields ?? []).map((f) => ({
1536
+ Name: f.Name,
1537
+ TSType: f.TSType,
1538
+ IsVirtual: f.IsVirtual,
1539
+ AllowsNull: f.AllowsNull,
1540
+ RelatedEntity: f.RelatedEntity,
1541
+ RelatedEntityID: f.RelatedEntityID,
1542
+ EntityFieldValues: f.EntityFieldValues ? f.EntityFieldValues.map((v) => ({ Value: v.Value, Code: v.Code })) : undefined,
1543
+ })),
1544
+ };
1545
+ specIssues = validateSpec(candidateSpec, stub).filter((i) => i.Severity === 'error').map((i) => i.Message);
1546
+ }
1547
+ const allIssues = Array.from(new Set([...capIssues, ...specIssues]));
1548
+ if (allIssues.length > 0) {
1549
+ target.value = currentType;
1550
+ this.PendingPipelineType = newType;
1551
+ this.TypeSwitchIssues = allIssues;
1552
+ this.ShowTypeSwitchConfirm = true;
1553
+ this.cdr.detectChanges();
1554
+ }
1555
+ else {
1556
+ this.ApplyPipelineTypeChange(newType);
1557
+ }
1558
+ }
1559
+ OnTypeSwitchConfirmed() {
1560
+ this.ShowTypeSwitchConfirm = false;
1561
+ if (this.PendingPipelineType) {
1562
+ this.ApplyPipelineTypeChange(this.PendingPipelineType);
1563
+ this.PendingPipelineType = null;
1564
+ }
1565
+ this.TypeSwitchIssues = [];
1566
+ this.cdr.detectChanges();
1567
+ }
1568
+ OnTypeSwitchCancelled() {
1569
+ this.ShowTypeSwitchConfirm = false;
1570
+ this.PendingPipelineType = null;
1571
+ this.TypeSwitchIssues = [];
1572
+ this.cdr.detectChanges();
1573
+ }
1574
+ ApplyPipelineTypeChange(newType) {
1575
+ if (newType.trim().toLowerCase() === 'llm') {
1576
+ delete this.spec.PipelineType;
1577
+ }
1578
+ else {
1579
+ this.spec.PipelineType = newType.trim();
1580
+ }
1581
+ if (!this.IsDecisionPipeline) {
1582
+ delete this.spec.Escalation;
1583
+ }
1584
+ this.emitChanges();
1585
+ }
1586
+ GetNumericLevels(output) {
1587
+ if (!output.Constraint || output.Constraint.Type !== 'numeric' || !Array.isArray(output.Constraint.Levels)) {
1588
+ return [];
1589
+ }
1590
+ return output.Constraint.Levels;
1591
+ }
1592
+ AddNumericLevel(index) {
1593
+ const output = this.spec.Outputs[index];
1594
+ if (output?.Constraint?.Type === 'numeric') {
1595
+ if (!Array.isArray(output.Constraint.Levels) || output.Constraint.Levels.length === 0) {
1596
+ output.Constraint.Levels = ['Low', 'Medium', 'High'];
1597
+ this.emitChanges();
1598
+ return;
1599
+ }
1600
+ if (output.Constraint.Levels.length < 10) {
1601
+ output.Constraint.Levels.push(`Level ${output.Constraint.Levels.length + 1}`);
1602
+ this.emitChanges();
1603
+ }
1604
+ }
1605
+ }
1606
+ RemoveNumericLevel(outputIndex, levelIndex) {
1607
+ const output = this.spec.Outputs[outputIndex];
1608
+ if (output?.Constraint?.Type === 'numeric' && Array.isArray(output.Constraint.Levels)) {
1609
+ if (output.Constraint.Levels.length > 2) {
1610
+ output.Constraint.Levels.splice(levelIndex, 1);
1611
+ this.emitChanges();
1612
+ }
1613
+ }
1614
+ }
1615
+ UpdateNumericLevel(outputIndex, levelIndex, event) {
1616
+ const val = event.target.value;
1617
+ const output = this.spec.Outputs[outputIndex];
1618
+ if (output?.Constraint?.Type === 'numeric' && Array.isArray(output.Constraint.Levels)) {
1619
+ output.Constraint.Levels[levelIndex] = val;
1620
+ this.emitChanges();
1621
+ }
1622
+ }
1623
+ MoveNumericLevel(outputIndex, levelIndex, direction) {
1624
+ const output = this.spec.Outputs[outputIndex];
1625
+ if (output?.Constraint?.Type === 'numeric' && Array.isArray(output.Constraint.Levels)) {
1626
+ const targetIndex = direction === 'up' ? levelIndex - 1 : levelIndex + 1;
1627
+ if (targetIndex >= 0 && targetIndex < output.Constraint.Levels.length) {
1628
+ const item = output.Constraint.Levels.splice(levelIndex, 1)[0];
1629
+ output.Constraint.Levels.splice(targetIndex, 0, item);
1630
+ this.emitChanges();
1631
+ }
1632
+ }
1633
+ }
1634
+ GetEnumValues(output) {
1635
+ if (output.Constraint && output.Constraint.Type === 'enum' && Array.isArray(output.Constraint.Values)) {
1636
+ return output.Constraint.Values;
1637
+ }
1638
+ return [];
1639
+ }
1640
+ GetEnumValueDescription(output, val) {
1641
+ if (output.Constraint && output.Constraint.Type === 'enum') {
1642
+ return output.Constraint.ValueDescriptions?.[val] ?? '';
1643
+ }
1644
+ return '';
1645
+ }
1646
+ UpdateEnumValueDescription(outputIndex, val, event) {
1647
+ const desc = event.target.value;
1648
+ const output = this.spec.Outputs[outputIndex];
1649
+ if (output?.Constraint && output.Constraint.Type === 'enum') {
1650
+ if (!output.Constraint.ValueDescriptions) {
1651
+ output.Constraint.ValueDescriptions = {};
1652
+ }
1653
+ output.Constraint.ValueDescriptions[val] = desc;
1654
+ this.emitChanges();
1655
+ }
1656
+ }
1657
+ GetBooleanThreshold(output) {
1658
+ if (output.Constraint && output.Constraint.Type === 'boolean' && output.Constraint.Threshold !== undefined) {
1659
+ return output.Constraint.Threshold;
1660
+ }
1661
+ return null;
1662
+ }
1663
+ UpdateBooleanThreshold(outputIndex, event) {
1664
+ const raw = event.target.value.trim();
1665
+ const output = this.spec.Outputs[outputIndex];
1666
+ if (output?.Constraint && output.Constraint.Type === 'boolean') {
1667
+ if (raw === '') {
1668
+ delete output.Constraint.Threshold;
1669
+ }
1670
+ else {
1671
+ const val = parseFloat(raw);
1672
+ output.Constraint.Threshold = isNaN(val) ? undefined : val;
1673
+ }
1674
+ this.emitChanges();
1675
+ }
1676
+ }
1677
+ prefillEnumValuesFromField(output) {
1678
+ if (output.Target.Mode !== 'field' || output.Constraint?.Type !== 'enum') {
1679
+ return;
1680
+ }
1681
+ const fieldName = output.Target.EntityFieldName;
1682
+ if (!fieldName) {
1683
+ return;
1684
+ }
1685
+ const field = this.EntityFields.find((f) => f.Name === fieldName);
1686
+ if (field && Array.isArray(field.EntityFieldValues) && field.EntityFieldValues.length > 0) {
1687
+ if (!output.Constraint.Values || output.Constraint.Values.length === 0) {
1688
+ output.Constraint.Values = field.EntityFieldValues.map((v) => v.Value);
1689
+ }
1690
+ if (this.IsDecisionPipeline) {
1691
+ if (!output.Constraint.ValueDescriptions) {
1692
+ output.Constraint.ValueDescriptions = {};
1693
+ }
1694
+ for (const v of field.EntityFieldValues) {
1695
+ if (!output.Constraint.ValueDescriptions[v.Value] && v.Description) {
1696
+ output.Constraint.ValueDescriptions[v.Value] = v.Description;
1697
+ }
1698
+ }
1699
+ }
1700
+ }
1701
+ }
736
1702
  emitChanges() {
1703
+ if (this.spec.PipelineType && this.spec.PipelineType.trim().toLowerCase() === 'llm') {
1704
+ delete this.spec.PipelineType;
1705
+ }
1706
+ if (!this.IsDecisionPipeline) {
1707
+ delete this.spec.Escalation;
1708
+ }
737
1709
  if (this.Record) {
738
1710
  this.spec.Name = this.Record.Name || '';
739
1711
  this.spec.Description = this.Record.Description || '';
@@ -760,8 +1732,14 @@ export class FeaturePipelineBuilderComponent extends BaseAngularComponent {
760
1732
  }
761
1733
  this.Record.OutputMapping = JSON.stringify({ fields });
762
1734
  }
1735
+ buildFieldValuesLookup() {
1736
+ return (fieldName) => {
1737
+ const field = this.EntityFields.find((f) => f.Name.toLowerCase() === fieldName.toLowerCase());
1738
+ return field?.EntityFieldValues ? field.EntityFieldValues.map((v) => ({ Value: v.Value, Description: v.Description })) : undefined;
1739
+ };
1740
+ }
763
1741
  recomputeValidation() {
764
- this.renderedConstraintPreview = renderConstraintBlock(this.spec.Outputs);
1742
+ this.RenderedConstraintPreview = renderConstraintBlock(this.spec.Outputs);
765
1743
  const entity = this.Record?.EntityID ? this.ProviderToUse.EntityByID(this.Record.EntityID) : null;
766
1744
  if (entity) {
767
1745
  const stub = {
@@ -776,171 +1754,271 @@ export class FeaturePipelineBuilderComponent extends BaseAngularComponent {
776
1754
  EntityFieldValues: f.EntityFieldValues ? f.EntityFieldValues.map((v) => ({ Value: v.Value, Code: v.Code })) : undefined,
777
1755
  })),
778
1756
  };
779
- this.validationErrors = validateSpec(this.spec, stub);
1757
+ this.ValidationErrors = validateSpec(this.spec, stub);
780
1758
  }
781
1759
  else {
782
- this.validationErrors = this.spec.Outputs.length === 0
783
- ? [{
784
- Path: 'Outputs',
1760
+ this.ValidationErrors = validateSpec(this.spec);
1761
+ }
1762
+ const lookup = this.buildFieldValuesLookup();
1763
+ const capIssues = ValidateOutputsAgainstCapabilities(this.spec, this.CurrentCapabilities, lookup);
1764
+ for (const capIssue of capIssues) {
1765
+ this.ValidationErrors.push({
1766
+ Path: 'Outputs',
1767
+ Severity: 'error',
1768
+ Message: capIssue,
1769
+ FixRecommendation: 'Adjust output configuration to match the selected pipeline capabilities.',
1770
+ });
1771
+ }
1772
+ if (this.IsDecisionPipeline && this.spec.Escalation && this.spec.Escalation.PipelineID && this.EscalationTargetsLoadError) {
1773
+ // The targets are unknown, not absent: say so, and leave the target to be checked at run time
1774
+ this.ValidationErrors.push({
1775
+ Path: 'Escalation.PipelineID',
1776
+ Severity: 'warning',
1777
+ Message: `The escalation target could not be checked: the pipelines on this entity could not be loaded (${this.EscalationTargetsLoadError}).`,
1778
+ FixRecommendation: 'Reopen the pipeline to retry. The target is still checked when the pipeline runs.',
1779
+ });
1780
+ }
1781
+ else if (this.IsDecisionPipeline && this.spec.Escalation) {
1782
+ const targetID = this.spec.Escalation.PipelineID;
1783
+ if (targetID && this.EscalationTargetsLoaded) {
1784
+ const match = this.AvailableEscalationTargets.find((t) => UUIDsEqual(t.ID, targetID));
1785
+ if (!match) {
1786
+ this.ValidationErrors.push({
1787
+ Path: 'Escalation.PipelineID',
785
1788
  Severity: 'error',
786
- Message: 'At least one output attribute must be configured',
787
- FixRecommendation: 'Click Add Output to configure an output attribute',
788
- }]
789
- : [];
1789
+ Message: `Escalation target pipeline '${targetID}' was not found on this entity.`,
1790
+ FixRecommendation: 'Select a valid Active LLM Feature Pipeline on this entity.',
1791
+ });
1792
+ }
1793
+ else {
1794
+ const problem = this.GetTargetProblem(match);
1795
+ if (problem) {
1796
+ this.ValidationErrors.push({
1797
+ Path: 'Escalation.PipelineID',
1798
+ Severity: 'error',
1799
+ Message: `Escalation target pipeline '${match.Name}' ${problem}.`,
1800
+ FixRecommendation: 'Select an Active LLM Feature Pipeline that produces every output of this Decision pipeline.',
1801
+ });
1802
+ }
1803
+ }
1804
+ }
790
1805
  }
791
- const hasErrors = this.validationErrors.some((i) => i.Severity === 'error');
1806
+ const hasErrors = this.ValidationErrors.some((i) => i.Severity === 'error');
792
1807
  this.ValidChange.emit(!hasErrors);
793
1808
  }
794
1809
  static ɵfac = /*@__PURE__*/ (() => { let ɵFeaturePipelineBuilderComponent_BaseFactory; return function FeaturePipelineBuilderComponent_Factory(__ngFactoryType__) { return (ɵFeaturePipelineBuilderComponent_BaseFactory || (ɵFeaturePipelineBuilderComponent_BaseFactory = i0.ɵɵgetInheritedFactory(FeaturePipelineBuilderComponent)))(__ngFactoryType__ || FeaturePipelineBuilderComponent); }; })();
795
- static ɵcmp = /*@__PURE__*/ i0.ɵɵdefineComponent({ type: FeaturePipelineBuilderComponent, selectors: [["mj-feature-pipeline-builder"]], inputs: { Record: "Record", EntityID: "EntityID" }, outputs: { SpecChange: "SpecChange", ValidChange: "ValidChange" }, features: [i0.ɵɵInheritDefinitionFeature, i0.ɵɵNgOnChangesFeature], decls: 92, vars: 13, consts: [[1, "fpb"], [1, "rpe-sec"], [1, "rpe-sec-h"], [1, "num"], [1, "rpe-desc"], [1, "rpe-grid3"], [1, "field"], [1, "mj-input", 3, "change", "value"], ["value", "fields"], ["value", "document"], ["value", "query"], ["placeholder", "e.g. FirstName, LastName, Title", 1, "mj-input", 3, "input", "value"], [1, "rpe-grid2"], ["value", "", "disabled", ""], [3, "value"], [1, "field", "rpe-mt"], [1, "rpe-sec-h", "fpb-split-h"], [1, "fpb-title-group"], ["mjButton", "", "size", "sm", "variant", "secondary", 3, "click"], [1, "fa-solid", "fa-plus"], [1, "fpb-empty-outputs"], [1, "fpb-outputs-list"], ["value", "Checksum"], ["value", "UpdatedAt"], ["value", "None"], ["value", "true"], ["value", "false"], [1, "rpe-grid3", "rpe-mt"], [1, "fpb-issues-card", "fpb-issues-card--error"], ["placeholder", "UUID of approved Query", 1, "mj-input", "mono", 3, "input", "value"], [1, "rpe-static-text"], [1, "muted"], [1, "fpb-code-preview"], [1, "fa-solid", "fa-arrow-turn-up"], [1, "fpb-output-card"], [1, "fpb-output-head"], ["mjButton", "", "size", "sm", "variant", "flat", 3, "click"], [1, "fa-solid", "fa-trash"], ["placeholder", "e.g. SentimentScore", 1, "mj-input", 3, "input", "value"], ["placeholder", "e.g. $.sentiment or $", 1, "mj-input", "mono", 3, "input", "value"], ["value", "field"], ["value", "child"], ["value", "tags"], ["value", "none"], ["value", "enum"], ["value", "numeric"], ["value", "boolean"], ["value", "freetext"], [1, "rpe-grid2", "rpe-mt"], ["value", "fail"], ["value", "null"], ["value", "coerce-to-other"], ["placeholder", "e.g. Positive, Neutral, Negative", 1, "mj-input", 3, "input", "value"], ["type", "number", 1, "mj-input", 3, "input", "value"], ["placeholder", "e.g. CurrentJobTitle", 1, "mj-input", 3, "input", "value"], ["value", "pipeline"], ["value", "prompt"], [1, "fa-solid", "fa-triangle-exclamation"]], template: function FeaturePipelineBuilderComponent_Template(rf, ctx) { if (rf & 1) {
796
- i0.ɵɵelementStart(0, "div", 0)(1, "section", 1)(2, "div", 2)(3, "span", 3);
797
- i0.ɵɵtext(4, "1");
1810
+ static ɵcmp = /*@__PURE__*/ i0.ɵɵdefineComponent({ type: FeaturePipelineBuilderComponent, selectors: [["mj-feature-pipeline-builder"]], inputs: { Record: "Record", EntityID: "EntityID" }, outputs: { SpecChange: "SpecChange", ValidChange: "ValidChange" }, features: [i0.ɵɵInheritDefinitionFeature, i0.ɵɵNgOnChangesFeature], decls: 111, vars: 18, consts: [[1, "fpb"], [1, "rpe-sec", "fpb-type-sec"], [1, "rpe-grid2"], [1, "field"], [1, "mj-input", 3, "change"], [3, "value", "selected"], [1, "rpe-static-text"], [1, "rpe-grid2", "rpe-mt"], [1, "rpe-sec"], [1, "rpe-sec-h"], [1, "num"], [1, "rpe-desc"], [1, "rpe-grid3"], [1, "mj-input", 3, "change", "value"], ["value", "fields"], ["value", "document"], ["value", "query"], ["placeholder", "e.g. FirstName, LastName, Title", 1, "mj-input", 3, "input", "value"], ["value", "", "disabled", "", 3, "selected"], [1, "field", "rpe-mt"], [1, "rpe-sec-h", "fpb-split-h"], [1, "fpb-title-group"], ["mjButton", "", "size", "sm", "variant", "secondary", 3, "click"], [1, "fa-solid", "fa-plus"], [1, "fpb-empty-outputs"], [1, "fpb-outputs-list"], [1, "rpe-sec", "fpb-escalation-sec"], ["value", "Checksum"], ["value", "UpdatedAt"], ["value", "None"], ["value", "true"], ["value", "false"], [1, "rpe-grid3", "rpe-mt"], [1, "fpb-issues-card", "fpb-issues-card--error"], ["Type", "warning", "Title", "Switch Pipeline Type", "ConfirmText", "Switch Anyway", "CancelText", "Cancel", 3, "VisibleChange", "Confirmed", "Cancelled", "Visible", "Message"], [1, "fpb-confirm-issues"], [1, "mj-input", "fpb-reasoning-select", 3, "change", "value"], ["placeholder", "UUID of approved Query", 1, "mj-input", "mono", 3, "input", "value"], [1, "muted"], [1, "fpb-code-preview"], [1, "fa-solid", "fa-arrow-turn-up"], [1, "fpb-output-card"], [1, "fpb-output-head"], ["mjButton", "", "size", "sm", "variant", "flat", 3, "click"], [1, "fa-solid", "fa-trash"], ["placeholder", "e.g. SentimentScore", 1, "mj-input", 3, "input", "value"], ["placeholder", "e.g. $.sentiment or $", 1, "mj-input", "mono", 3, "input", "value"], ["value", "none", "disabled", "", 3, "selected"], ["value", "fail"], ["value", "null"], ["value", "coerce-to-other"], ["placeholder", "e.g. Positive, Neutral, Negative", 1, "mj-input", 3, "input", "value"], [1, "fpb-enum-descriptions"], [1, "fpb-enum-desc-row"], [1, "fpb-enum-val-badge"], [1, "mj-input", 3, "input", "value", "placeholder"], [1, "fpb-levels-header"], ["mjButton", "", "size", "sm", "variant", "secondary", "type", "button", 3, "click", "disabled"], [1, "fpb-levels-list"], [1, "fpb-level-row"], [1, "fpb-level-num"], ["placeholder", "Level label (e.g. Low, Medium, High)", 1, "mj-input", 3, "input", "value"], ["mjButton", "", "size", "sm", "variant", "flat", "type", "button", "title", "Move Up", 3, "click", "disabled"], [1, "fa-solid", "fa-arrow-up"], ["mjButton", "", "size", "sm", "variant", "flat", "type", "button", "title", "Move Down", 3, "click", "disabled"], [1, "fa-solid", "fa-arrow-down"], ["mjButton", "", "size", "sm", "variant", "flat", "type", "button", "title", "Remove Level", 3, "click", "disabled"], ["type", "number", 1, "mj-input", 3, "input", "value"], ["type", "number", "min", "0", "max", "1", "step", "0.05", "placeholder", "0.5", 1, "mj-input", 3, "input", "value"], [1, "fa-solid", "fa-arrow-up-right-from-square"], [1, "fpb-escalation-toggle-row"], [1, "fpb-checkbox-label"], ["type", "checkbox", 3, "change", "checked"], [3, "value", "disabled", "selected"], ["type", "number", "min", "0", "max", "1", "step", "0.05", "placeholder", "0.7", 1, "mj-input", 3, "input", "value"], ["placeholder", "e.g. CurrentJobTitle", 1, "mj-input", 3, "input", "value"], ["value", "pipeline"], ["value", "prompt"], [1, "fa-solid", "fa-triangle-exclamation"]], template: function FeaturePipelineBuilderComponent_Template(rf, ctx) { if (rf & 1) {
1811
+ i0.ɵɵelementStart(0, "div", 0)(1, "section", 1)(2, "div", 2)(3, "div", 3)(4, "label");
1812
+ i0.ɵɵtext(5, "Pipeline Type");
1813
+ i0.ɵɵelementEnd();
1814
+ i0.ɵɵelementStart(6, "select", 4);
1815
+ i0.ɵɵlistener("change", function FeaturePipelineBuilderComponent_Template_select_change_6_listener($event) { return ctx.OnPipelineTypeSelect($event); });
1816
+ i0.ɵɵrepeaterCreate(7, FeaturePipelineBuilderComponent_For_8_Template, 2, 3, "option", 5, _forTrack0);
1817
+ i0.ɵɵelementEnd()();
1818
+ i0.ɵɵelementStart(9, "div", 3)(10, "label");
1819
+ i0.ɵɵtext(11, "Type Description");
1820
+ i0.ɵɵelementEnd();
1821
+ i0.ɵɵelementStart(12, "div", 6);
1822
+ i0.ɵɵtext(13);
1823
+ i0.ɵɵelementEnd()()();
1824
+ i0.ɵɵconditionalCreate(14, FeaturePipelineBuilderComponent_Conditional_14_Template, 9, 1, "div", 7);
1825
+ i0.ɵɵelementEnd();
1826
+ i0.ɵɵelementStart(15, "section", 8)(16, "div", 9)(17, "span", 10);
1827
+ i0.ɵɵtext(18, "1");
798
1828
  i0.ɵɵelementEnd();
799
- i0.ɵɵelementStart(5, "h3");
800
- i0.ɵɵtext(6, "Context Source");
1829
+ i0.ɵɵelementStart(19, "h3");
1830
+ i0.ɵɵtext(20, "Context Source");
801
1831
  i0.ɵɵelementEnd()();
802
- i0.ɵɵelementStart(7, "p", 4);
803
- i0.ɵɵtext(8, "Choose how data from each record is extracted and formatted before being sent to the LLM prompt.");
1832
+ i0.ɵɵelementStart(21, "p", 11);
1833
+ i0.ɵɵtext(22, "Choose how data from each record is extracted and formatted before being sent to the LLM prompt.");
804
1834
  i0.ɵɵelementEnd();
805
- i0.ɵɵelementStart(9, "div", 5)(10, "div", 6)(11, "label");
806
- i0.ɵɵtext(12, "Context Mode");
1835
+ i0.ɵɵelementStart(23, "div", 12)(24, "div", 3)(25, "label");
1836
+ i0.ɵɵtext(26, "Context Mode");
807
1837
  i0.ɵɵelementEnd();
808
- i0.ɵɵelementStart(13, "select", 7);
809
- i0.ɵɵlistener("change", function FeaturePipelineBuilderComponent_Template_select_change_13_listener($event) { return ctx.onContextModeChange($event); });
810
- i0.ɵɵelementStart(14, "option", 8);
811
- i0.ɵɵtext(15, "Record Fields");
1838
+ i0.ɵɵelementStart(27, "select", 13);
1839
+ i0.ɵɵlistener("change", function FeaturePipelineBuilderComponent_Template_select_change_27_listener($event) { return ctx.onContextModeChange($event); });
1840
+ i0.ɵɵelementStart(28, "option", 14);
1841
+ i0.ɵɵtext(29, "Record Fields");
812
1842
  i0.ɵɵelementEnd();
813
- i0.ɵɵelementStart(16, "option", 9);
814
- i0.ɵɵtext(17, "Entity Document (Template)");
1843
+ i0.ɵɵelementStart(30, "option", 15);
1844
+ i0.ɵɵtext(31, "Entity Document (Template)");
815
1845
  i0.ɵɵelementEnd();
816
- i0.ɵɵelementStart(18, "option", 10);
817
- i0.ɵɵtext(19, "Query (Graph Traversal)");
1846
+ i0.ɵɵelementStart(32, "option", 16);
1847
+ i0.ɵɵtext(33, "Query (Graph Traversal)");
818
1848
  i0.ɵɵelementEnd()()();
819
- i0.ɵɵconditionalCreate(20, FeaturePipelineBuilderComponent_Conditional_20_Template, 8, 1, "div", 6);
820
- i0.ɵɵconditionalCreate(21, FeaturePipelineBuilderComponent_Conditional_21_Template, 4, 1, "div", 6);
821
- i0.ɵɵelementStart(22, "div", 6)(23, "label");
822
- i0.ɵɵtext(24, "Field Filter (optional)");
1849
+ i0.ɵɵconditionalCreate(34, FeaturePipelineBuilderComponent_Conditional_34_Template, 8, 1, "div", 3);
1850
+ i0.ɵɵconditionalCreate(35, FeaturePipelineBuilderComponent_Conditional_35_Template, 4, 1, "div", 3);
1851
+ i0.ɵɵelementStart(36, "div", 3)(37, "label");
1852
+ i0.ɵɵtext(38, "Field Filter (optional)");
823
1853
  i0.ɵɵelementEnd();
824
- i0.ɵɵelementStart(25, "input", 11);
825
- i0.ɵɵlistener("input", function FeaturePipelineBuilderComponent_Template_input_input_25_listener($event) { return ctx.onFieldsCsvChange($event); });
1854
+ i0.ɵɵelementStart(39, "input", 17);
1855
+ i0.ɵɵlistener("input", function FeaturePipelineBuilderComponent_Template_input_input_39_listener($event) { return ctx.onFieldsCsvChange($event); });
826
1856
  i0.ɵɵelementEnd()()()();
827
- i0.ɵɵelementStart(26, "section", 1)(27, "div", 2)(28, "span", 3);
828
- i0.ɵɵtext(29, "2");
1857
+ i0.ɵɵelementStart(40, "section", 8)(41, "div", 9)(42, "span", 10);
1858
+ i0.ɵɵtext(43, "2");
829
1859
  i0.ɵɵelementEnd();
830
- i0.ɵɵelementStart(30, "h3");
831
- i0.ɵɵtext(31, "AI Prompt");
1860
+ i0.ɵɵelementStart(44, "h3");
1861
+ i0.ɵɵtext(45, "AI Prompt");
832
1862
  i0.ɵɵelementEnd()();
833
- i0.ɵɵelementStart(32, "div", 12)(33, "div", 6)(34, "label");
834
- i0.ɵɵtext(35, "Prompt");
1863
+ i0.ɵɵelementStart(46, "div", 2)(47, "div", 3)(48, "label");
1864
+ i0.ɵɵtext(49, "Prompt");
835
1865
  i0.ɵɵelementEnd();
836
- i0.ɵɵelementStart(36, "select", 7);
837
- i0.ɵɵlistener("change", function FeaturePipelineBuilderComponent_Template_select_change_36_listener($event) { return ctx.onPromptChange($event); });
838
- i0.ɵɵelementStart(37, "option", 13);
839
- i0.ɵɵtext(38, "\u2014 Select AI Prompt \u2014");
1866
+ i0.ɵɵelementStart(50, "select", 4);
1867
+ i0.ɵɵlistener("change", function FeaturePipelineBuilderComponent_Template_select_change_50_listener($event) { return ctx.onPromptChange($event); });
1868
+ i0.ɵɵelementStart(51, "option", 18);
1869
+ i0.ɵɵtext(52, "\u2014 Select AI Prompt \u2014");
840
1870
  i0.ɵɵelementEnd();
841
- i0.ɵɵrepeaterCreate(39, FeaturePipelineBuilderComponent_For_40_Template, 2, 2, "option", 14, _forTrack0);
1871
+ i0.ɵɵrepeaterCreate(53, FeaturePipelineBuilderComponent_For_54_Template, 2, 3, "option", 5, _forTrack1);
842
1872
  i0.ɵɵelementEnd()();
843
- i0.ɵɵconditionalCreate(41, FeaturePipelineBuilderComponent_Conditional_41_Template, 5, 1, "div", 6);
1873
+ i0.ɵɵconditionalCreate(55, FeaturePipelineBuilderComponent_Conditional_55_Template, 5, 1, "div", 3);
844
1874
  i0.ɵɵelementEnd();
845
- i0.ɵɵconditionalCreate(42, FeaturePipelineBuilderComponent_Conditional_42_Template, 7, 1, "div", 15);
1875
+ i0.ɵɵconditionalCreate(56, FeaturePipelineBuilderComponent_Conditional_56_Template, 7, 1, "div", 19);
846
1876
  i0.ɵɵelementEnd();
847
- i0.ɵɵelementStart(43, "section", 1)(44, "div", 16)(45, "div", 17)(46, "span", 3);
848
- i0.ɵɵtext(47, "3");
1877
+ i0.ɵɵelementStart(57, "section", 8)(58, "div", 20)(59, "div", 21)(60, "span", 10);
1878
+ i0.ɵɵtext(61, "3");
849
1879
  i0.ɵɵelementEnd();
850
- i0.ɵɵelementStart(48, "h3");
851
- i0.ɵɵtext(49, "Outputs & Constraints");
1880
+ i0.ɵɵelementStart(62, "h3");
1881
+ i0.ɵɵtext(63, "Outputs & Constraints");
852
1882
  i0.ɵɵelementEnd()();
853
- i0.ɵɵelementStart(50, "button", 18);
854
- i0.ɵɵlistener("click", function FeaturePipelineBuilderComponent_Template_button_click_50_listener() { return ctx.addOutput(); });
855
- i0.ɵɵelement(51, "i", 19);
856
- i0.ɵɵtext(52, " Add Output ");
1883
+ i0.ɵɵelementStart(64, "button", 22);
1884
+ i0.ɵɵlistener("click", function FeaturePipelineBuilderComponent_Template_button_click_64_listener() { return ctx.addOutput(); });
1885
+ i0.ɵɵelement(65, "i", 23);
1886
+ i0.ɵɵtext(66, " Add Output ");
857
1887
  i0.ɵɵelementEnd()();
858
- i0.ɵɵelementStart(53, "p", 4);
859
- i0.ɵɵtext(54, "Define the structured outputs produced by the LLM, their type constraints, and target write-back destinations.");
1888
+ i0.ɵɵelementStart(67, "p", 11);
1889
+ i0.ɵɵtext(68, "Define the structured outputs produced by the pipeline, their type constraints, and target write-back destinations.");
860
1890
  i0.ɵɵelementEnd();
861
- i0.ɵɵconditionalCreate(55, FeaturePipelineBuilderComponent_Conditional_55_Template, 7, 0, "div", 20)(56, FeaturePipelineBuilderComponent_Conditional_56_Template, 3, 0, "div", 21);
1891
+ i0.ɵɵconditionalCreate(69, FeaturePipelineBuilderComponent_Conditional_69_Template, 7, 0, "div", 24)(70, FeaturePipelineBuilderComponent_Conditional_70_Template, 3, 0, "div", 25);
862
1892
  i0.ɵɵelementEnd();
863
- i0.ɵɵelementStart(57, "section", 1)(58, "div", 2)(59, "span", 3);
864
- i0.ɵɵtext(60, "4");
1893
+ i0.ɵɵconditionalCreate(71, FeaturePipelineBuilderComponent_Conditional_71_Template, 13, 2, "section", 26);
1894
+ i0.ɵɵelementStart(72, "section", 8)(73, "div", 9)(74, "span", 10);
1895
+ i0.ɵɵtext(75, "4");
865
1896
  i0.ɵɵelementEnd();
866
- i0.ɵɵelementStart(61, "h3");
867
- i0.ɵɵtext(62, "Caching & Watermarks");
1897
+ i0.ɵɵelementStart(76, "h3");
1898
+ i0.ɵɵtext(77, "Caching & Watermarks");
868
1899
  i0.ɵɵelementEnd()();
869
- i0.ɵɵelementStart(63, "div", 5)(64, "div", 6)(65, "label");
870
- i0.ɵɵtext(66, "Watermark Strategy");
1900
+ i0.ɵɵelementStart(78, "div", 12)(79, "div", 3)(80, "label");
1901
+ i0.ɵɵtext(81, "Watermark Strategy");
871
1902
  i0.ɵɵelementEnd();
872
- i0.ɵɵelementStart(67, "select", 7);
873
- i0.ɵɵlistener("change", function FeaturePipelineBuilderComponent_Template_select_change_67_listener($event) { return ctx.updateWatermarkStrategy($event); });
874
- i0.ɵɵelementStart(68, "option", 22);
875
- i0.ɵɵtext(69, "Checksum (Content Hash + Prompt Hash)");
1903
+ i0.ɵɵelementStart(82, "select", 13);
1904
+ i0.ɵɵlistener("change", function FeaturePipelineBuilderComponent_Template_select_change_82_listener($event) { return ctx.updateWatermarkStrategy($event); });
1905
+ i0.ɵɵelementStart(83, "option", 27);
1906
+ i0.ɵɵtext(84, "Checksum (Content Hash + Prompt Hash)");
876
1907
  i0.ɵɵelementEnd();
877
- i0.ɵɵelementStart(70, "option", 23);
878
- i0.ɵɵtext(71, "UpdatedAt (Compare modified timestamp)");
1908
+ i0.ɵɵelementStart(85, "option", 28);
1909
+ i0.ɵɵtext(86, "UpdatedAt (Compare modified timestamp)");
879
1910
  i0.ɵɵelementEnd();
880
- i0.ɵɵelementStart(72, "option", 24);
881
- i0.ɵɵtext(73, "None (Always process all records)");
1911
+ i0.ɵɵelementStart(87, "option", 29);
1912
+ i0.ɵɵtext(88, "None (Always process all records)");
882
1913
  i0.ɵɵelementEnd()()();
883
- i0.ɵɵelementStart(74, "div", 6)(75, "label");
884
- i0.ɵɵtext(76, "Skip Unchanged Records");
1914
+ i0.ɵɵelementStart(89, "div", 3)(90, "label");
1915
+ i0.ɵɵtext(91, "Skip Unchanged Records");
885
1916
  i0.ɵɵelementEnd();
886
- i0.ɵɵelementStart(77, "select", 7);
887
- i0.ɵɵlistener("change", function FeaturePipelineBuilderComponent_Template_select_change_77_listener($event) { return ctx.updateSkipUnchanged($event); });
888
- i0.ɵɵelementStart(78, "option", 25);
889
- i0.ɵɵtext(79, "Yes \u2014 Skip unchanged rows");
1917
+ i0.ɵɵelementStart(92, "select", 13);
1918
+ i0.ɵɵlistener("change", function FeaturePipelineBuilderComponent_Template_select_change_92_listener($event) { return ctx.updateSkipUnchanged($event); });
1919
+ i0.ɵɵelementStart(93, "option", 30);
1920
+ i0.ɵɵtext(94, "Yes \u2014 Skip unchanged rows");
890
1921
  i0.ɵɵelementEnd();
891
- i0.ɵɵelementStart(80, "option", 26);
892
- i0.ɵɵtext(81, "No \u2014 Recompute every time");
1922
+ i0.ɵɵelementStart(95, "option", 31);
1923
+ i0.ɵɵtext(96, "No \u2014 Recompute every time");
893
1924
  i0.ɵɵelementEnd()()();
894
- i0.ɵɵelementStart(82, "div", 6)(83, "label");
895
- i0.ɵɵtext(84, "Enable Result Cache");
1925
+ i0.ɵɵelementStart(97, "div", 3)(98, "label");
1926
+ i0.ɵɵtext(99, "Enable Result Cache");
896
1927
  i0.ɵɵelementEnd();
897
- i0.ɵɵelementStart(85, "select", 7);
898
- i0.ɵɵlistener("change", function FeaturePipelineBuilderComponent_Template_select_change_85_listener($event) { return ctx.updateCacheable($event); });
899
- i0.ɵɵelementStart(86, "option", 25);
900
- i0.ɵɵtext(87, "Yes \u2014 Cache outputs by distinct key");
1928
+ i0.ɵɵelementStart(100, "select", 13);
1929
+ i0.ɵɵlistener("change", function FeaturePipelineBuilderComponent_Template_select_change_100_listener($event) { return ctx.updateCacheable($event); });
1930
+ i0.ɵɵelementStart(101, "option", 30);
1931
+ i0.ɵɵtext(102, "Yes \u2014 Cache outputs by distinct key");
901
1932
  i0.ɵɵelementEnd();
902
- i0.ɵɵelementStart(88, "option", 26);
903
- i0.ɵɵtext(89, "No \u2014 Compute per row");
1933
+ i0.ɵɵelementStart(103, "option", 31);
1934
+ i0.ɵɵtext(104, "No \u2014 Compute per row");
904
1935
  i0.ɵɵelementEnd()()()();
905
- i0.ɵɵconditionalCreate(90, FeaturePipelineBuilderComponent_Conditional_90_Template, 17, 3, "div", 27);
906
- i0.ɵɵelementEnd();
907
- i0.ɵɵconditionalCreate(91, FeaturePipelineBuilderComponent_Conditional_91_Template, 7, 0, "div", 28);
1936
+ i0.ɵɵconditionalCreate(105, FeaturePipelineBuilderComponent_Conditional_105_Template, 17, 3, "div", 32);
908
1937
  i0.ɵɵelementEnd();
1938
+ i0.ɵɵconditionalCreate(106, FeaturePipelineBuilderComponent_Conditional_106_Template, 7, 0, "div", 33);
1939
+ i0.ɵɵelementStart(107, "mj-confirm-dialog", 34);
1940
+ i0.ɵɵtwoWayListener("VisibleChange", function FeaturePipelineBuilderComponent_Template_mj_confirm_dialog_VisibleChange_107_listener($event) { i0.ɵɵtwoWayBindingSet(ctx.ShowTypeSwitchConfirm, $event) || (ctx.ShowTypeSwitchConfirm = $event); return $event; });
1941
+ i0.ɵɵlistener("Confirmed", function FeaturePipelineBuilderComponent_Template_mj_confirm_dialog_Confirmed_107_listener() { return ctx.OnTypeSwitchConfirmed(); })("Cancelled", function FeaturePipelineBuilderComponent_Template_mj_confirm_dialog_Cancelled_107_listener() { return ctx.OnTypeSwitchCancelled(); });
1942
+ i0.ɵɵelementStart(108, "ul", 35);
1943
+ i0.ɵɵrepeaterCreate(109, FeaturePipelineBuilderComponent_For_110_Template, 2, 1, "li", null, i0.ɵɵrepeaterTrackByIndex);
1944
+ i0.ɵɵelementEnd()()();
909
1945
  } if (rf & 2) {
1946
+ i0.ɵɵadvance(7);
1947
+ i0.ɵɵrepeater(ctx.AvailablePipelineTypes);
1948
+ i0.ɵɵadvance(6);
1949
+ i0.ɵɵtextInterpolate(ctx.SelectedPipelineTypeDescription || "\u2014");
1950
+ i0.ɵɵadvance();
1951
+ i0.ɵɵconditional(ctx.ShowCaptureReasoning ? 14 : -1);
910
1952
  i0.ɵɵadvance(13);
911
1953
  i0.ɵɵproperty("value", ctx.contextMode);
912
1954
  i0.ɵɵadvance(7);
913
- i0.ɵɵconditional(ctx.contextMode === "document" ? 20 : -1);
1955
+ i0.ɵɵconditional(ctx.contextMode === "document" ? 34 : -1);
914
1956
  i0.ɵɵadvance();
915
- i0.ɵɵconditional(ctx.contextMode === "query" ? 21 : -1);
1957
+ i0.ɵɵconditional(ctx.contextMode === "query" ? 35 : -1);
916
1958
  i0.ɵɵadvance(4);
917
1959
  i0.ɵɵproperty("value", ctx.fieldsCsv);
918
- i0.ɵɵadvance(11);
919
- i0.ɵɵproperty("value", (ctx.Record == null ? null : ctx.Record.PromptID) || "");
920
- i0.ɵɵadvance(3);
1960
+ i0.ɵɵadvance(12);
1961
+ i0.ɵɵproperty("selected", !ctx.SavedPromptListed);
1962
+ i0.ɵɵadvance(2);
921
1963
  i0.ɵɵrepeater(ctx.availablePrompts);
922
1964
  i0.ɵɵadvance(2);
923
- i0.ɵɵconditional(ctx.selectedPrompt ? 41 : -1);
1965
+ i0.ɵɵconditional(ctx.selectedPrompt ? 55 : -1);
924
1966
  i0.ɵɵadvance();
925
- i0.ɵɵconditional(ctx.renderedConstraintPreview ? 42 : -1);
1967
+ i0.ɵɵconditional(ctx.renderedConstraintPreview ? 56 : -1);
926
1968
  i0.ɵɵadvance(13);
927
- i0.ɵɵconditional(!ctx.spec.Outputs || ctx.spec.Outputs.length === 0 ? 55 : 56);
928
- i0.ɵɵadvance(12);
1969
+ i0.ɵɵconditional(!ctx.spec.Outputs || ctx.spec.Outputs.length === 0 ? 69 : 70);
1970
+ i0.ɵɵadvance(2);
1971
+ i0.ɵɵconditional(ctx.IsDecisionPipeline ? 71 : -1);
1972
+ i0.ɵɵadvance(11);
929
1973
  i0.ɵɵproperty("value", (ctx.Record == null ? null : ctx.Record.WatermarkStrategy) || "Checksum");
930
1974
  i0.ɵɵadvance(10);
931
1975
  i0.ɵɵproperty("value", (ctx.Record == null ? null : ctx.Record.SkipUnchanged) ? "true" : "false");
932
1976
  i0.ɵɵadvance(8);
933
1977
  i0.ɵɵproperty("value", ctx.spec.Caching.Cacheable ? "true" : "false");
934
1978
  i0.ɵɵadvance(5);
935
- i0.ɵɵconditional(ctx.spec.Caching.Cacheable ? 90 : -1);
1979
+ i0.ɵɵconditional(ctx.spec.Caching.Cacheable ? 105 : -1);
936
1980
  i0.ɵɵadvance();
937
- i0.ɵɵconditional(ctx.validationErrors.length > 0 ? 91 : -1);
938
- } }, dependencies: [CommonModule, FormsModule, i1.NgSelectOption, i1.ɵNgSelectMultipleOption, MJButtonDirective], styles: [".fpb[_ngcontent-%COMP%] { display: flex; flex-direction: column; gap: 20px; }\n .rpe-desc[_ngcontent-%COMP%] { font-size: 13px; color: var(--mj-text-secondary); margin: -6px 0 16px 0; }\n .rpe-sec[_ngcontent-%COMP%] { background: var(--mj-bg-surface-card); border: 1px solid var(--mj-border-subtle); border-radius: var(--mj-radius-md, 10px); padding: 18px 20px; }\n .rpe-sec-h[_ngcontent-%COMP%] { display: flex; align-items: center; gap: 11px; margin-bottom: 14px; }\n .rpe-sec-h[_ngcontent-%COMP%] h3[_ngcontent-%COMP%] { margin: 0; font-size: 16px; font-weight: 700; color: var(--mj-text-primary); }\n .rpe-sec-h[_ngcontent-%COMP%] .num[_ngcontent-%COMP%] { width: 24px; height: 24px; border-radius: 50%; background: var(--mj-brand-primary); color: #fff; display: grid; place-items: center; font-size: 12px; font-weight: 800; }\n .fpb-split-h[_ngcontent-%COMP%] { justify-content: space-between; }\n .fpb-title-group[_ngcontent-%COMP%] { display: flex; align-items: center; gap: 11px; }\n .rpe-grid2[_ngcontent-%COMP%] { display: grid; grid-template-columns: 1fr 1fr; gap: 16px; }\n .rpe-grid3[_ngcontent-%COMP%] { display: grid; grid-template-columns: 1fr 1fr 1fr; gap: 16px; }\n .field[_ngcontent-%COMP%] { display: flex; flex-direction: column; gap: 6px; }\n .field[_ngcontent-%COMP%] label[_ngcontent-%COMP%] { font-size: 12.5px; font-weight: 600; color: var(--mj-text-secondary); }\n .rpe-mt[_ngcontent-%COMP%] { margin-top: 14px; }\n .mono[_ngcontent-%COMP%] { font-family: monospace; font-size: 12.5px; }\n .muted[_ngcontent-%COMP%] { color: var(--mj-text-muted); font-weight: 400; }\n .rpe-static-text[_ngcontent-%COMP%] { font-size: 13px; color: var(--mj-text-muted); padding: 7px 0; }\n .fpb-code-preview[_ngcontent-%COMP%] { background: var(--mj-bg-surface-sunken, #0f172a); color: var(--mj-text-code, var(--mj-text-primary, #e2e8f0)); border: 1px solid var(--mj-border-subtle, #334155); padding: 12px; border-radius: 6px; font-size: 12px; font-family: var(--mj-font-mono, monospace); white-space: pre-wrap; word-break: break-word; max-height: 160px; overflow-y: auto; margin: 0; }\n .fpb-empty-outputs[_ngcontent-%COMP%] { display: flex; align-items: center; gap: 10px; padding: 20px; border: 1px dashed var(--mj-border-subtle); border-radius: 8px; color: var(--mj-text-muted); font-size: 13px; }\n .fpb-outputs-list[_ngcontent-%COMP%] { display: flex; flex-direction: column; gap: 16px; }\n .fpb-output-card[_ngcontent-%COMP%] { border: 1px solid var(--mj-border-subtle); border-radius: 8px; padding: 14px 16px; background: var(--mj-bg-surface); }\n .fpb-output-head[_ngcontent-%COMP%] { display: flex; justify-content: space-between; align-items: center; margin-bottom: 12px; border-bottom: 1px solid var(--mj-border-subtle); padding-bottom: 8px; }\n .fpb-output-head[_ngcontent-%COMP%] h4[_ngcontent-%COMP%] { margin: 0; font-size: 14px; font-weight: 600; }\n .fpb-issues-card[_ngcontent-%COMP%] { border-radius: 8px; padding: 12px 16px; font-size: 13px; }\n .fpb-issues-card--error[_ngcontent-%COMP%] { background: rgba(239, 68, 68, 0.08); border: 1px solid var(--mj-status-error); color: var(--mj-status-error-text); }\n .fpb-issues-card[_ngcontent-%COMP%] h4[_ngcontent-%COMP%] { margin: 0 0 8px 0; font-size: 14px; display: flex; align-items: center; gap: 8px; }\n .fpb-issues-card[_ngcontent-%COMP%] ul[_ngcontent-%COMP%] { margin: 0; padding-left: 20px; }"], changeDetection: 0 });
1981
+ i0.ɵɵconditional(ctx.validationErrors.length > 0 ? 106 : -1);
1982
+ i0.ɵɵadvance();
1983
+ i0.ɵɵtwoWayProperty("Visible", ctx.ShowTypeSwitchConfirm);
1984
+ i0.ɵɵproperty("Message", "Switching to " + (ctx.PendingPipelineType || "selected type") + " will affect existing outputs:");
1985
+ i0.ɵɵadvance(2);
1986
+ i0.ɵɵrepeater(ctx.TypeSwitchIssues);
1987
+ } }, dependencies: [CommonModule, FormsModule, i1.NgSelectOption, i1.ɵNgSelectMultipleOption, MJButtonDirective, MJConfirmDialogComponent], styles: [".fpb[_ngcontent-%COMP%] { display: flex; flex-direction: column; gap: 20px; }\n .rpe-desc[_ngcontent-%COMP%] { font-size: 13px; color: var(--mj-text-secondary); margin: -6px 0 16px 0; }\n .rpe-sec[_ngcontent-%COMP%] { background: var(--mj-bg-surface-card); border: 1px solid var(--mj-border-subtle); border-radius: var(--mj-radius-md, 10px); padding: 18px 20px; }\n .fpb-type-sec[_ngcontent-%COMP%] { border-left: 3px solid var(--mj-brand-primary); }\n .rpe-sec-h[_ngcontent-%COMP%] { display: flex; align-items: center; gap: 11px; margin-bottom: 14px; }\n .rpe-sec-h[_ngcontent-%COMP%] h3[_ngcontent-%COMP%] { margin: 0; font-size: 16px; font-weight: 700; color: var(--mj-text-primary); }\n .rpe-sec-h[_ngcontent-%COMP%] .num[_ngcontent-%COMP%] { width: 24px; height: 24px; border-radius: 50%; background: var(--mj-brand-primary); color: #fff; display: grid; place-items: center; font-size: 12px; font-weight: 800; }\n .fpb-split-h[_ngcontent-%COMP%] { justify-content: space-between; }\n .fpb-title-group[_ngcontent-%COMP%] { display: flex; align-items: center; gap: 11px; }\n .rpe-grid2[_ngcontent-%COMP%] { display: grid; grid-template-columns: 1fr 1fr; gap: 16px; }\n .rpe-grid3[_ngcontent-%COMP%] { display: grid; grid-template-columns: 1fr 1fr 1fr; gap: 16px; }\n .field[_ngcontent-%COMP%] { display: flex; flex-direction: column; gap: 6px; }\n .field[_ngcontent-%COMP%] label[_ngcontent-%COMP%] { font-size: 12.5px; font-weight: 600; color: var(--mj-text-secondary); }\n .rpe-mt[_ngcontent-%COMP%] { margin-top: 14px; }\n .mono[_ngcontent-%COMP%] { font-family: monospace; font-size: 12.5px; }\n .muted[_ngcontent-%COMP%] { color: var(--mj-text-muted); font-weight: 400; }\n .rpe-static-text[_ngcontent-%COMP%] { font-size: 13px; color: var(--mj-text-muted); padding: 7px 0; }\n .fpb-code-preview[_ngcontent-%COMP%] { background: var(--mj-bg-surface-sunken, #0f172a); color: var(--mj-text-code, var(--mj-text-primary, #e2e8f0)); border: 1px solid var(--mj-border-subtle, #334155); padding: 12px; border-radius: 6px; font-size: 12px; font-family: var(--mj-font-mono, monospace); white-space: pre-wrap; word-break: break-word; max-height: 160px; overflow-y: auto; margin: 0; }\n .fpb-empty-outputs[_ngcontent-%COMP%] { display: flex; align-items: center; gap: 10px; padding: 20px; border: 1px dashed var(--mj-border-subtle); border-radius: 8px; color: var(--mj-text-muted); font-size: 13px; }\n .fpb-outputs-list[_ngcontent-%COMP%] { display: flex; flex-direction: column; gap: 16px; }\n .fpb-output-card[_ngcontent-%COMP%] { border: 1px solid var(--mj-border-subtle); border-radius: 8px; padding: 14px 16px; background: var(--mj-bg-surface); }\n .fpb-output-head[_ngcontent-%COMP%] { display: flex; justify-content: space-between; align-items: center; margin-bottom: 12px; border-bottom: 1px solid var(--mj-border-subtle); padding-bottom: 8px; }\n .fpb-output-head[_ngcontent-%COMP%] h4[_ngcontent-%COMP%] { margin: 0; font-size: 14px; font-weight: 600; }\n .fpb-issues-card[_ngcontent-%COMP%] { border-radius: 8px; padding: 12px 16px; font-size: 13px; }\n .fpb-issues-card--error[_ngcontent-%COMP%] { background: rgba(239, 68, 68, 0.08); border: 1px solid var(--mj-status-error); color: var(--mj-status-error-text); }\n .fpb-issues-card[_ngcontent-%COMP%] h4[_ngcontent-%COMP%] { margin: 0 0 8px 0; font-size: 14px; display: flex; align-items: center; gap: 8px; }\n .fpb-issues-card[_ngcontent-%COMP%] ul[_ngcontent-%COMP%] { margin: 0; padding-left: 20px; }\n .fpb-confirm-issues[_ngcontent-%COMP%] { margin: 10px 0 0 0; padding-left: 20px; color: var(--mj-status-error-text, var(--mj-text-primary)); font-size: 13px; }\n .fpb-confirm-issues[_ngcontent-%COMP%] li[_ngcontent-%COMP%] { margin-bottom: 4px; }\n .fpb-levels-header[_ngcontent-%COMP%] { display: flex; justify-content: space-between; align-items: center; margin-bottom: 8px; }\n .fpb-levels-list[_ngcontent-%COMP%] { display: flex; flex-direction: column; gap: 8px; }\n .fpb-level-row[_ngcontent-%COMP%] { display: flex; align-items: center; gap: 8px; }\n .fpb-level-num[_ngcontent-%COMP%] { width: 22px; height: 22px; display: grid; place-items: center; font-size: 11px; font-weight: 700; border-radius: var(--mj-radius-sm, 4px); background: var(--mj-bg-surface-sunken); color: var(--mj-text-secondary); flex-shrink: 0; }\n .fpb-enum-descriptions[_ngcontent-%COMP%] { display: flex; flex-direction: column; gap: 8px; margin-top: 6px; }\n .fpb-enum-desc-row[_ngcontent-%COMP%] { display: flex; align-items: center; gap: 10px; }\n .fpb-enum-val-badge[_ngcontent-%COMP%] { min-width: 90px; padding: 4px 8px; background: var(--mj-bg-surface-sunken); color: var(--mj-text-primary); border: 1px solid var(--mj-border-subtle); border-radius: var(--mj-radius-sm, 4px); font-size: 12px; font-weight: 600; text-align: center; flex-shrink: 0; }\n .fpb-escalation-toggle-row[_ngcontent-%COMP%] { display: flex; align-items: center; gap: 8px; margin-top: 10px; }\n .fpb-checkbox-label[_ngcontent-%COMP%] { display: inline-flex; align-items: center; gap: 8px; cursor: pointer; font-size: 13px; font-weight: 500; color: var(--mj-text-primary); user-select: none; }\n .fpb-checkbox-label[_ngcontent-%COMP%] input[type=\"checkbox\"][_ngcontent-%COMP%] { width: 16px; height: 16px; cursor: pointer; accent-color: var(--mj-brand-primary); }"], changeDetection: 0 });
939
1988
  }
940
1989
  (() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassMetadata(FeaturePipelineBuilderComponent, [{
941
1990
  type: Component,
942
- args: [{ selector: 'mj-feature-pipeline-builder', standalone: true, changeDetection: ChangeDetectionStrategy.OnPush, imports: [CommonModule, FormsModule, MJButtonDirective], template: `
1991
+ args: [{ selector: 'mj-feature-pipeline-builder', standalone: true, changeDetection: ChangeDetectionStrategy.OnPush, imports: [CommonModule, FormsModule, MJButtonDirective, MJConfirmDialogComponent], template: `
943
1992
  <div class="fpb">
1993
+ <!-- PIPELINE TYPE SELECTOR -->
1994
+ <section class="rpe-sec fpb-type-sec">
1995
+ <div class="rpe-grid2">
1996
+ <div class="field">
1997
+ <label>Pipeline Type</label>
1998
+ <select class="mj-input" (change)="OnPipelineTypeSelect($event)">
1999
+ @for (t of AvailablePipelineTypes; track t.Name) {
2000
+ <option [value]="t.Name" [selected]="IsCurrentPipelineType(t.Name)">{{ t.DisplayName || t.Name }}</option>
2001
+ }
2002
+ </select>
2003
+ </div>
2004
+ <div class="field">
2005
+ <label>Type Description</label>
2006
+ <div class="rpe-static-text">{{ SelectedPipelineTypeDescription || '—' }}</div>
2007
+ </div>
2008
+ </div>
2009
+ @if (ShowCaptureReasoning) {
2010
+ <div class="rpe-grid2 rpe-mt">
2011
+ <div class="field">
2012
+ <label>Capture Reasoning</label>
2013
+ <select class="mj-input fpb-reasoning-select" [value]="spec.CaptureReasoning ? 'true' : 'false'" (change)="UpdateCaptureReasoning($event)">
2014
+ <option value="true">Yes — Keep the model's rationale with each Feature Value</option>
2015
+ <option value="false">No</option>
2016
+ </select>
2017
+ </div>
2018
+ </div>
2019
+ }
2020
+ </section>
2021
+
944
2022
  <!-- STAGE 1: CONTEXT SOURCE -->
945
2023
  <section class="rpe-sec">
946
2024
  <div class="rpe-sec-h">
@@ -962,10 +2040,10 @@ export class FeaturePipelineBuilderComponent extends BaseAngularComponent {
962
2040
  @if (contextMode === 'document') {
963
2041
  <div class="field">
964
2042
  <label>Entity Document</label>
965
- <select class="mj-input" [value]="spec.Context.EntityDocumentID || ''" (change)="onEntityDocChange($event)">
966
- <option value="" disabled>— Select Entity Document —</option>
2043
+ <select class="mj-input" (change)="onEntityDocChange($event)">
2044
+ <option value="" disabled [selected]="!SavedEntityDocListed">— Select Entity Document —</option>
967
2045
  @for (doc of availableDocs; track doc.ID) {
968
- <option [value]="doc.ID">{{ doc.Name }}</option>
2046
+ <option [value]="doc.ID" [selected]="IsSavedEntityDoc(doc)">{{ doc.Name }}</option>
969
2047
  }
970
2048
  </select>
971
2049
  </div>
@@ -994,10 +2072,10 @@ export class FeaturePipelineBuilderComponent extends BaseAngularComponent {
994
2072
  <div class="rpe-grid2">
995
2073
  <div class="field">
996
2074
  <label>Prompt</label>
997
- <select class="mj-input" [value]="Record?.PromptID || ''" (change)="onPromptChange($event)">
998
- <option value="" disabled>— Select AI Prompt —</option>
2075
+ <select class="mj-input" (change)="onPromptChange($event)">
2076
+ <option value="" disabled [selected]="!SavedPromptListed">— Select AI Prompt —</option>
999
2077
  @for (p of availablePrompts; track p.ID) {
1000
- <option [value]="p.ID">{{ p.Name }}</option>
2078
+ <option [value]="p.ID" [selected]="IsSavedPrompt(p)">{{ p.Name }}</option>
1001
2079
  }
1002
2080
  </select>
1003
2081
  </div>
@@ -1028,7 +2106,7 @@ export class FeaturePipelineBuilderComponent extends BaseAngularComponent {
1028
2106
  <i class="fa-solid fa-plus"></i> Add Output
1029
2107
  </button>
1030
2108
  </div>
1031
- <p class="rpe-desc">Define the structured outputs produced by the LLM, their type constraints, and target write-back destinations.</p>
2109
+ <p class="rpe-desc">Define the structured outputs produced by the pipeline, their type constraints, and target write-back destinations.</p>
1032
2110
 
1033
2111
  @if (!spec.Outputs || spec.Outputs.length === 0) {
1034
2112
  <div class="fpb-empty-outputs">
@@ -1037,11 +2115,11 @@ export class FeaturePipelineBuilderComponent extends BaseAngularComponent {
1037
2115
  </div>
1038
2116
  } @else {
1039
2117
  <div class="fpb-outputs-list">
1040
- @for (output of spec.Outputs; track $index) {
2118
+ @for (output of spec.Outputs; track $index; let outputIndex = $index) {
1041
2119
  <div class="fpb-output-card">
1042
2120
  <div class="fpb-output-head">
1043
- <h4>Output #{{ $index + 1 }}: {{ output.Name || '(unnamed)' }}</h4>
1044
- <button mjButton size="sm" variant="flat" (click)="removeOutput($index)">
2121
+ <h4>Output #{{ outputIndex + 1 }}: {{ output.Name || '(unnamed)' }}</h4>
2122
+ <button mjButton size="sm" variant="flat" (click)="removeOutput(outputIndex)">
1045
2123
  <i class="fa-solid fa-trash"></i> Remove
1046
2124
  </button>
1047
2125
  </div>
@@ -1049,18 +2127,21 @@ export class FeaturePipelineBuilderComponent extends BaseAngularComponent {
1049
2127
  <div class="rpe-grid3">
1050
2128
  <div class="field">
1051
2129
  <label>Output Name</label>
1052
- <input class="mj-input" [value]="output.Name" (input)="updateOutputProp($index, 'Name', $event)" placeholder="e.g. SentimentScore">
2130
+ <input class="mj-input" [value]="output.Name" (input)="updateOutputProp(outputIndex, 'Name', $event)" placeholder="e.g. SentimentScore">
1053
2131
  </div>
1054
2132
  <div class="field">
1055
2133
  <label>JSON Path / Ref</label>
1056
- <input class="mj-input mono" [value]="output.Ref" (input)="updateOutputProp($index, 'Ref', $event)" placeholder="e.g. $.sentiment or $">
2134
+ <input class="mj-input mono" [value]="output.Ref" (input)="updateOutputProp(outputIndex, 'Ref', $event)" placeholder="e.g. $.sentiment or $">
1057
2135
  </div>
1058
2136
  <div class="field">
1059
2137
  <label>Target Mode</label>
1060
- <select class="mj-input" [value]="output.Target.Mode" (change)="updateTargetMode($index, $event)">
1061
- <option value="field">Entity Column (field)</option>
1062
- <option value="child">Child Rows (child)</option>
1063
- <option value="tags">Taxonomy Tags (tags)</option>
2138
+ <select class="mj-input" (change)="updateTargetMode(outputIndex, $event)">
2139
+ @if (!IsTargetModeOffered(output)) {
2140
+ <option value="" disabled [selected]="true">— Select Target Mode —</option>
2141
+ }
2142
+ @for (m of AvailableTargetModes; track m.Value) {
2143
+ <option [value]="m.Value" [selected]="m.Value === output.Target.Mode">{{ m.Label }}</option>
2144
+ }
1064
2145
  </select>
1065
2146
  </div>
1066
2147
  </div>
@@ -1070,10 +2151,10 @@ export class FeaturePipelineBuilderComponent extends BaseAngularComponent {
1070
2151
  @if (output.Target.Mode === 'field') {
1071
2152
  <div class="field">
1072
2153
  <label>Target Field</label>
1073
- <select class="mj-input" [value]="output.Target.EntityFieldName" (change)="updateFieldTarget($index, $event)">
1074
- <option value="" disabled>— Select Column —</option>
2154
+ <select class="mj-input" (change)="updateFieldTarget(outputIndex, $event)">
2155
+ <option value="" disabled [selected]="!IsEntityFieldListed(output.Target.EntityFieldName)">— Select Column —</option>
1075
2156
  @for (f of entityFields; track f.Name) {
1076
- <option [value]="f.Name">{{ f.DisplayName || f.Name }} ({{ f.TSType }})</option>
2157
+ <option [value]="f.Name" [selected]="f.Name === output.Target.EntityFieldName">{{ f.DisplayName || f.Name }} ({{ f.TSType }})</option>
1077
2158
  }
1078
2159
  </select>
1079
2160
  </div>
@@ -1082,10 +2163,10 @@ export class FeaturePipelineBuilderComponent extends BaseAngularComponent {
1082
2163
  @if (output.Target.Mode === 'child') {
1083
2164
  <div class="field">
1084
2165
  <label>Child Entity</label>
1085
- <select class="mj-input" [value]="output.Target.EntityName" (change)="updateChildTargetEntity($index, $event)">
1086
- <option value="" disabled>— Select Entity —</option>
2166
+ <select class="mj-input" (change)="updateChildTargetEntity(outputIndex, $event)">
2167
+ <option value="" disabled [selected]="!IsEntityListed(output.Target.EntityName)">— Select Entity —</option>
1087
2168
  @for (e of availableEntities; track e.ID) {
1088
- <option [value]="e.Name">{{ e.DisplayName || e.Name }}</option>
2169
+ <option [value]="e.Name" [selected]="e.Name === output.Target.EntityName">{{ e.DisplayName || e.Name }}</option>
1089
2170
  }
1090
2171
  </select>
1091
2172
  </div>
@@ -1094,19 +2175,20 @@ export class FeaturePipelineBuilderComponent extends BaseAngularComponent {
1094
2175
  <!-- Constraint details -->
1095
2176
  <div class="field">
1096
2177
  <label>Constraint Type</label>
1097
- <select class="mj-input" [value]="output.Constraint?.Type || 'none'" (change)="updateConstraintType($index, $event)">
1098
- <option value="none">None / Unconstrained</option>
1099
- <option value="enum">Enum (Allowed Values)</option>
1100
- <option value="numeric">Numeric (Min/Max)</option>
1101
- <option value="boolean">Boolean</option>
1102
- <option value="freetext">Free Text</option>
2178
+ <select class="mj-input" (change)="updateConstraintType(outputIndex, $event)">
2179
+ @if (!IsConstraintTypeOffered(output)) {
2180
+ <option value="none" disabled [selected]="true">— Select Constraint —</option>
2181
+ }
2182
+ @for (t of AvailableConstraintTypes; track t.Value) {
2183
+ <option [value]="t.Value" [selected]="t.Value === SavedConstraintType(output)">{{ t.Label }}</option>
2184
+ }
1103
2185
  </select>
1104
2186
  </div>
1105
2187
 
1106
2188
  @if (output.Constraint) {
1107
2189
  <div class="field">
1108
2190
  <label>Violation Policy</label>
1109
- <select class="mj-input" [value]="output.Constraint.OnViolation || 'fail'" (change)="updateViolationPolicy($index, $event)">
2191
+ <select class="mj-input" [value]="output.Constraint.OnViolation || 'fail'" (change)="updateViolationPolicy(outputIndex, $event)">
1110
2192
  <option value="fail">Fail Row</option>
1111
2193
  <option value="null">Set Output to Null</option>
1112
2194
  <option value="coerce-to-other">Coerce / Fallback</option>
@@ -1119,19 +2201,109 @@ export class FeaturePipelineBuilderComponent extends BaseAngularComponent {
1119
2201
  @if (output.Constraint?.Type === 'enum') {
1120
2202
  <div class="field rpe-mt">
1121
2203
  <label>Allowed Values (comma separated)</label>
1122
- <input class="mj-input" [value]="getEnumValuesCsv(output.Constraint)" (input)="updateEnumValues($index, $event)" placeholder="e.g. Positive, Neutral, Negative">
2204
+ <input class="mj-input" [value]="getEnumValuesCsv(output.Constraint)" (input)="updateEnumValues(outputIndex, $event)" placeholder="e.g. Positive, Neutral, Negative">
1123
2205
  </div>
2206
+ @if (IsDecisionPipeline && GetEnumValues(output).length > 0) {
2207
+ <div class="field rpe-mt">
2208
+ <label>Value Descriptions <span class="muted">— Decision models require a description for every choice option</span></label>
2209
+ <div class="fpb-enum-descriptions">
2210
+ @for (val of GetEnumValues(output); track val) {
2211
+ <div class="fpb-enum-desc-row">
2212
+ <span class="fpb-enum-val-badge">{{ val }}</span>
2213
+ <input
2214
+ class="mj-input"
2215
+ [value]="GetEnumValueDescription(output, val)"
2216
+ (input)="UpdateEnumValueDescription(outputIndex, val, $event)"
2217
+ [placeholder]="'Description for ' + val">
2218
+ </div>
2219
+ }
2220
+ </div>
2221
+ </div>
2222
+ }
1124
2223
  }
1125
2224
  @if (output.Constraint?.Type === 'numeric') {
1126
- <div class="rpe-grid2 rpe-mt">
1127
- <div class="field">
1128
- <label>Min Value</label>
1129
- <input class="mj-input" type="number" [value]="getNumericMin(output.Constraint)" (input)="updateNumericMin($index, $event)">
2225
+ @if (IsDecisionPipeline) {
2226
+ <div class="field rpe-mt">
2227
+ <div class="fpb-levels-header">
2228
+ <label>Numeric Levels <span class="muted">(Ordered: lowest to highest, 2 to 10 levels)</span></label>
2229
+ <button
2230
+ mjButton
2231
+ size="sm"
2232
+ variant="secondary"
2233
+ type="button"
2234
+ [disabled]="GetNumericLevels(output).length >= 10"
2235
+ (click)="AddNumericLevel(outputIndex)">
2236
+ <i class="fa-solid fa-plus"></i> Add Level
2237
+ </button>
2238
+ </div>
2239
+ <div class="fpb-levels-list">
2240
+ @for (lvl of GetNumericLevels(output); track $index; let lvlIdx = $index; let first = $first; let last = $last) {
2241
+ <div class="fpb-level-row">
2242
+ <span class="fpb-level-num">{{ lvlIdx + 1 }}</span>
2243
+ <input
2244
+ class="mj-input"
2245
+ [value]="lvl"
2246
+ (input)="UpdateNumericLevel(outputIndex, lvlIdx, $event)"
2247
+ placeholder="Level label (e.g. Low, Medium, High)">
2248
+ <button
2249
+ mjButton
2250
+ size="sm"
2251
+ variant="flat"
2252
+ type="button"
2253
+ [disabled]="first"
2254
+ (click)="MoveNumericLevel(outputIndex, lvlIdx, 'up')"
2255
+ title="Move Up">
2256
+ <i class="fa-solid fa-arrow-up"></i>
2257
+ </button>
2258
+ <button
2259
+ mjButton
2260
+ size="sm"
2261
+ variant="flat"
2262
+ type="button"
2263
+ [disabled]="last"
2264
+ (click)="MoveNumericLevel(outputIndex, lvlIdx, 'down')"
2265
+ title="Move Down">
2266
+ <i class="fa-solid fa-arrow-down"></i>
2267
+ </button>
2268
+ <button
2269
+ mjButton
2270
+ size="sm"
2271
+ variant="flat"
2272
+ type="button"
2273
+ [disabled]="GetNumericLevels(output).length <= 2"
2274
+ (click)="RemoveNumericLevel(outputIndex, lvlIdx)"
2275
+ title="Remove Level">
2276
+ <i class="fa-solid fa-trash"></i>
2277
+ </button>
2278
+ </div>
2279
+ }
2280
+ </div>
1130
2281
  </div>
1131
- <div class="field">
1132
- <label>Max Value</label>
1133
- <input class="mj-input" type="number" [value]="getNumericMax(output.Constraint)" (input)="updateNumericMax($index, $event)">
2282
+ } @else {
2283
+ <div class="rpe-grid2 rpe-mt">
2284
+ <div class="field">
2285
+ <label>Min Value</label>
2286
+ <input class="mj-input" type="number" [value]="getNumericMin(output.Constraint)" (input)="updateNumericMin(outputIndex, $event)">
2287
+ </div>
2288
+ <div class="field">
2289
+ <label>Max Value</label>
2290
+ <input class="mj-input" type="number" [value]="getNumericMax(output.Constraint)" (input)="updateNumericMax(outputIndex, $event)">
2291
+ </div>
1134
2292
  </div>
2293
+ }
2294
+ }
2295
+ @if (output.Constraint?.Type === 'boolean' && IsDecisionPipeline) {
2296
+ <div class="field rpe-mt">
2297
+ <label>Decision Threshold (0.0 to 1.0) <span class="muted">— calibrated probability threshold for true</span></label>
2298
+ <input
2299
+ class="mj-input"
2300
+ type="number"
2301
+ min="0"
2302
+ max="1"
2303
+ step="0.05"
2304
+ placeholder="0.5"
2305
+ [value]="GetBooleanThreshold(output) ?? ''"
2306
+ (input)="UpdateBooleanThreshold(outputIndex, $event)">
1135
2307
  </div>
1136
2308
  }
1137
2309
  </div>
@@ -1140,6 +2312,56 @@ export class FeaturePipelineBuilderComponent extends BaseAngularComponent {
1140
2312
  }
1141
2313
  </section>
1142
2314
 
2315
+ <!-- ESCALATION (DECISION PIPELINES ONLY) -->
2316
+ @if (IsDecisionPipeline) {
2317
+ <section class="rpe-sec fpb-escalation-sec">
2318
+ <div class="rpe-sec-h">
2319
+ <i class="fa-solid fa-arrow-up-right-from-square"></i>
2320
+ <h3>Borderline Escalation</h3>
2321
+ </div>
2322
+ <p class="rpe-desc">Records any output of which the decision model answers below this confidence are re-run through the chosen LLM pipeline. Only those records are re-run.</p>
2323
+
2324
+ <div class="fpb-escalation-toggle-row">
2325
+ <label class="fpb-checkbox-label">
2326
+ <input
2327
+ type="checkbox"
2328
+ [checked]="IsEscalationEnabled"
2329
+ (change)="OnEscalationToggle($event)">
2330
+ <span>Escalate borderline records to an LLM pipeline</span>
2331
+ </label>
2332
+ </div>
2333
+
2334
+ @if (IsEscalationEnabled) {
2335
+ <div class="rpe-grid2 rpe-mt">
2336
+ <div class="field">
2337
+ <label>Target LLM Pipeline</label>
2338
+ <select class="mj-input" (change)="OnEscalationTargetChange($event)">
2339
+ <option value="" disabled [selected]="!SavedEscalationTargetListed">{{ EscalationTargetsPlaceholder }}</option>
2340
+ @for (target of AvailableEscalationTargets; track target.ID) {
2341
+ <option [value]="target.ID" [disabled]="!!GetTargetProblem(target)" [selected]="IsSavedEscalationTarget(target)">
2342
+ {{ target.Name }}{{ GetTargetProblem(target) ? ' (' + GetTargetProblem(target) + ')' : '' }}
2343
+ </option>
2344
+ }
2345
+ </select>
2346
+ </div>
2347
+
2348
+ <div class="field">
2349
+ <label>Confidence Floor (0.0 to 1.0)</label>
2350
+ <input
2351
+ class="mj-input"
2352
+ type="number"
2353
+ min="0"
2354
+ max="1"
2355
+ step="0.05"
2356
+ placeholder="0.7"
2357
+ [value]="spec.Escalation?.BelowConfidence ?? ''"
2358
+ (input)="OnEscalationFloorChange($event)">
2359
+ </div>
2360
+ </div>
2361
+ }
2362
+ </section>
2363
+ }
2364
+
1143
2365
  <!-- STAGE 4: MATERIALIZATION & WATERMARK -->
1144
2366
  <section class="rpe-sec">
1145
2367
  <div class="rpe-sec-h">
@@ -1205,8 +2427,25 @@ export class FeaturePipelineBuilderComponent extends BaseAngularComponent {
1205
2427
  </ul>
1206
2428
  </div>
1207
2429
  }
2430
+
2431
+ <!-- TYPE SWITCH CONFIRMATION DIALOG -->
2432
+ <mj-confirm-dialog
2433
+ [(Visible)]="ShowTypeSwitchConfirm"
2434
+ Type="warning"
2435
+ Title="Switch Pipeline Type"
2436
+ [Message]="'Switching to ' + (PendingPipelineType || 'selected type') + ' will affect existing outputs:'"
2437
+ ConfirmText="Switch Anyway"
2438
+ CancelText="Cancel"
2439
+ (Confirmed)="OnTypeSwitchConfirmed()"
2440
+ (Cancelled)="OnTypeSwitchCancelled()">
2441
+ <ul class="fpb-confirm-issues">
2442
+ @for (issue of TypeSwitchIssues; track $index) {
2443
+ <li>{{ issue }}</li>
2444
+ }
2445
+ </ul>
2446
+ </mj-confirm-dialog>
1208
2447
  </div>
1209
- `, styles: ["\n .fpb { display: flex; flex-direction: column; gap: 20px; }\n .rpe-desc { font-size: 13px; color: var(--mj-text-secondary); margin: -6px 0 16px 0; }\n .rpe-sec { background: var(--mj-bg-surface-card); border: 1px solid var(--mj-border-subtle); border-radius: var(--mj-radius-md, 10px); padding: 18px 20px; }\n .rpe-sec-h { display: flex; align-items: center; gap: 11px; margin-bottom: 14px; }\n .rpe-sec-h h3 { margin: 0; font-size: 16px; font-weight: 700; color: var(--mj-text-primary); }\n .rpe-sec-h .num { width: 24px; height: 24px; border-radius: 50%; background: var(--mj-brand-primary); color: #fff; display: grid; place-items: center; font-size: 12px; font-weight: 800; }\n .fpb-split-h { justify-content: space-between; }\n .fpb-title-group { display: flex; align-items: center; gap: 11px; }\n .rpe-grid2 { display: grid; grid-template-columns: 1fr 1fr; gap: 16px; }\n .rpe-grid3 { display: grid; grid-template-columns: 1fr 1fr 1fr; gap: 16px; }\n .field { display: flex; flex-direction: column; gap: 6px; }\n .field label { font-size: 12.5px; font-weight: 600; color: var(--mj-text-secondary); }\n .rpe-mt { margin-top: 14px; }\n .mono { font-family: monospace; font-size: 12.5px; }\n .muted { color: var(--mj-text-muted); font-weight: 400; }\n .rpe-static-text { font-size: 13px; color: var(--mj-text-muted); padding: 7px 0; }\n .fpb-code-preview { background: var(--mj-bg-surface-sunken, #0f172a); color: var(--mj-text-code, var(--mj-text-primary, #e2e8f0)); border: 1px solid var(--mj-border-subtle, #334155); padding: 12px; border-radius: 6px; font-size: 12px; font-family: var(--mj-font-mono, monospace); white-space: pre-wrap; word-break: break-word; max-height: 160px; overflow-y: auto; margin: 0; }\n .fpb-empty-outputs { display: flex; align-items: center; gap: 10px; padding: 20px; border: 1px dashed var(--mj-border-subtle); border-radius: 8px; color: var(--mj-text-muted); font-size: 13px; }\n .fpb-outputs-list { display: flex; flex-direction: column; gap: 16px; }\n .fpb-output-card { border: 1px solid var(--mj-border-subtle); border-radius: 8px; padding: 14px 16px; background: var(--mj-bg-surface); }\n .fpb-output-head { display: flex; justify-content: space-between; align-items: center; margin-bottom: 12px; border-bottom: 1px solid var(--mj-border-subtle); padding-bottom: 8px; }\n .fpb-output-head h4 { margin: 0; font-size: 14px; font-weight: 600; }\n .fpb-issues-card { border-radius: 8px; padding: 12px 16px; font-size: 13px; }\n .fpb-issues-card--error { background: rgba(239, 68, 68, 0.08); border: 1px solid var(--mj-status-error); color: var(--mj-status-error-text); }\n .fpb-issues-card h4 { margin: 0 0 8px 0; font-size: 14px; display: flex; align-items: center; gap: 8px; }\n .fpb-issues-card ul { margin: 0; padding-left: 20px; }\n "] }]
2448
+ `, styles: ["\n .fpb { display: flex; flex-direction: column; gap: 20px; }\n .rpe-desc { font-size: 13px; color: var(--mj-text-secondary); margin: -6px 0 16px 0; }\n .rpe-sec { background: var(--mj-bg-surface-card); border: 1px solid var(--mj-border-subtle); border-radius: var(--mj-radius-md, 10px); padding: 18px 20px; }\n .fpb-type-sec { border-left: 3px solid var(--mj-brand-primary); }\n .rpe-sec-h { display: flex; align-items: center; gap: 11px; margin-bottom: 14px; }\n .rpe-sec-h h3 { margin: 0; font-size: 16px; font-weight: 700; color: var(--mj-text-primary); }\n .rpe-sec-h .num { width: 24px; height: 24px; border-radius: 50%; background: var(--mj-brand-primary); color: #fff; display: grid; place-items: center; font-size: 12px; font-weight: 800; }\n .fpb-split-h { justify-content: space-between; }\n .fpb-title-group { display: flex; align-items: center; gap: 11px; }\n .rpe-grid2 { display: grid; grid-template-columns: 1fr 1fr; gap: 16px; }\n .rpe-grid3 { display: grid; grid-template-columns: 1fr 1fr 1fr; gap: 16px; }\n .field { display: flex; flex-direction: column; gap: 6px; }\n .field label { font-size: 12.5px; font-weight: 600; color: var(--mj-text-secondary); }\n .rpe-mt { margin-top: 14px; }\n .mono { font-family: monospace; font-size: 12.5px; }\n .muted { color: var(--mj-text-muted); font-weight: 400; }\n .rpe-static-text { font-size: 13px; color: var(--mj-text-muted); padding: 7px 0; }\n .fpb-code-preview { background: var(--mj-bg-surface-sunken, #0f172a); color: var(--mj-text-code, var(--mj-text-primary, #e2e8f0)); border: 1px solid var(--mj-border-subtle, #334155); padding: 12px; border-radius: 6px; font-size: 12px; font-family: var(--mj-font-mono, monospace); white-space: pre-wrap; word-break: break-word; max-height: 160px; overflow-y: auto; margin: 0; }\n .fpb-empty-outputs { display: flex; align-items: center; gap: 10px; padding: 20px; border: 1px dashed var(--mj-border-subtle); border-radius: 8px; color: var(--mj-text-muted); font-size: 13px; }\n .fpb-outputs-list { display: flex; flex-direction: column; gap: 16px; }\n .fpb-output-card { border: 1px solid var(--mj-border-subtle); border-radius: 8px; padding: 14px 16px; background: var(--mj-bg-surface); }\n .fpb-output-head { display: flex; justify-content: space-between; align-items: center; margin-bottom: 12px; border-bottom: 1px solid var(--mj-border-subtle); padding-bottom: 8px; }\n .fpb-output-head h4 { margin: 0; font-size: 14px; font-weight: 600; }\n .fpb-issues-card { border-radius: 8px; padding: 12px 16px; font-size: 13px; }\n .fpb-issues-card--error { background: rgba(239, 68, 68, 0.08); border: 1px solid var(--mj-status-error); color: var(--mj-status-error-text); }\n .fpb-issues-card h4 { margin: 0 0 8px 0; font-size: 14px; display: flex; align-items: center; gap: 8px; }\n .fpb-issues-card ul { margin: 0; padding-left: 20px; }\n .fpb-confirm-issues { margin: 10px 0 0 0; padding-left: 20px; color: var(--mj-status-error-text, var(--mj-text-primary)); font-size: 13px; }\n .fpb-confirm-issues li { margin-bottom: 4px; }\n .fpb-levels-header { display: flex; justify-content: space-between; align-items: center; margin-bottom: 8px; }\n .fpb-levels-list { display: flex; flex-direction: column; gap: 8px; }\n .fpb-level-row { display: flex; align-items: center; gap: 8px; }\n .fpb-level-num { width: 22px; height: 22px; display: grid; place-items: center; font-size: 11px; font-weight: 700; border-radius: var(--mj-radius-sm, 4px); background: var(--mj-bg-surface-sunken); color: var(--mj-text-secondary); flex-shrink: 0; }\n .fpb-enum-descriptions { display: flex; flex-direction: column; gap: 8px; margin-top: 6px; }\n .fpb-enum-desc-row { display: flex; align-items: center; gap: 10px; }\n .fpb-enum-val-badge { min-width: 90px; padding: 4px 8px; background: var(--mj-bg-surface-sunken); color: var(--mj-text-primary); border: 1px solid var(--mj-border-subtle); border-radius: var(--mj-radius-sm, 4px); font-size: 12px; font-weight: 600; text-align: center; flex-shrink: 0; }\n .fpb-escalation-toggle-row { display: flex; align-items: center; gap: 8px; margin-top: 10px; }\n .fpb-checkbox-label { display: inline-flex; align-items: center; gap: 8px; cursor: pointer; font-size: 13px; font-weight: 500; color: var(--mj-text-primary); user-select: none; }\n .fpb-checkbox-label input[type=\"checkbox\"] { width: 16px; height: 16px; cursor: pointer; accent-color: var(--mj-brand-primary); }\n "] }]
1210
2449
  }], null, { Record: [{
1211
2450
  type: Input
1212
2451
  }], EntityID: [{
@@ -1216,5 +2455,5 @@ export class FeaturePipelineBuilderComponent extends BaseAngularComponent {
1216
2455
  }], ValidChange: [{
1217
2456
  type: Output
1218
2457
  }] }); })();
1219
- (() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassDebugInfo(FeaturePipelineBuilderComponent, { className: "FeaturePipelineBuilderComponent", filePath: "lib/feature-pipeline-builder/feature-pipeline-builder.component.ts", lineNumber: 346 }); })();
2458
+ (() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassDebugInfo(FeaturePipelineBuilderComponent, { className: "FeaturePipelineBuilderComponent", filePath: "lib/feature-pipeline-builder/feature-pipeline-builder.component.ts", lineNumber: 584 }); })();
1220
2459
  //# sourceMappingURL=feature-pipeline-builder.component.js.map