@memberjunction/ng-flow-editor 0.0.1 → 4.1.0

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 (58) hide show
  1. package/README.md +151 -43
  2. package/dist/lib/agent-editor/agent-flow-transformer.service.d.ts +83 -0
  3. package/dist/lib/agent-editor/agent-flow-transformer.service.d.ts.map +1 -0
  4. package/dist/lib/agent-editor/agent-flow-transformer.service.js +447 -0
  5. package/dist/lib/agent-editor/agent-flow-transformer.service.js.map +1 -0
  6. package/dist/lib/agent-editor/agent-properties-panel.component.d.ts +92 -0
  7. package/dist/lib/agent-editor/agent-properties-panel.component.d.ts.map +1 -0
  8. package/dist/lib/agent-editor/agent-properties-panel.component.js +1139 -0
  9. package/dist/lib/agent-editor/agent-properties-panel.component.js.map +1 -0
  10. package/dist/lib/agent-editor/agent-step-list.component.d.ts +17 -0
  11. package/dist/lib/agent-editor/agent-step-list.component.d.ts.map +1 -0
  12. package/dist/lib/agent-editor/agent-step-list.component.js +278 -0
  13. package/dist/lib/agent-editor/agent-step-list.component.js.map +1 -0
  14. package/dist/lib/agent-editor/flow-agent-editor.component.d.ts +134 -0
  15. package/dist/lib/agent-editor/flow-agent-editor.component.d.ts.map +1 -0
  16. package/dist/lib/agent-editor/flow-agent-editor.component.js +999 -0
  17. package/dist/lib/agent-editor/flow-agent-editor.component.js.map +1 -0
  18. package/dist/lib/components/flow-editor.component.d.ts +169 -0
  19. package/dist/lib/components/flow-editor.component.d.ts.map +1 -0
  20. package/dist/lib/components/flow-editor.component.js +1090 -0
  21. package/dist/lib/components/flow-editor.component.js.map +1 -0
  22. package/dist/lib/components/flow-node.component.d.ts +50 -0
  23. package/dist/lib/components/flow-node.component.d.ts.map +1 -0
  24. package/dist/lib/components/flow-node.component.js +358 -0
  25. package/dist/lib/components/flow-node.component.js.map +1 -0
  26. package/dist/lib/components/flow-palette.component.d.ts +17 -0
  27. package/dist/lib/components/flow-palette.component.d.ts.map +1 -0
  28. package/dist/lib/components/flow-palette.component.js +110 -0
  29. package/dist/lib/components/flow-palette.component.js.map +1 -0
  30. package/dist/lib/components/flow-status-bar.component.d.ts +13 -0
  31. package/dist/lib/components/flow-status-bar.component.d.ts.map +1 -0
  32. package/dist/lib/components/flow-status-bar.component.js +81 -0
  33. package/dist/lib/components/flow-status-bar.component.js.map +1 -0
  34. package/dist/lib/components/flow-toolbar.component.d.ts +25 -0
  35. package/dist/lib/components/flow-toolbar.component.d.ts.map +1 -0
  36. package/dist/lib/components/flow-toolbar.component.js +192 -0
  37. package/dist/lib/components/flow-toolbar.component.js.map +1 -0
  38. package/dist/lib/flow-editor.module.d.ts +19 -0
  39. package/dist/lib/flow-editor.module.d.ts.map +1 -0
  40. package/dist/lib/flow-editor.module.js +84 -0
  41. package/dist/lib/flow-editor.module.js.map +1 -0
  42. package/dist/lib/interfaces/flow-types.d.ts +153 -0
  43. package/dist/lib/interfaces/flow-types.d.ts.map +1 -0
  44. package/dist/lib/interfaces/flow-types.js +6 -0
  45. package/dist/lib/interfaces/flow-types.js.map +1 -0
  46. package/dist/lib/services/flow-layout.service.d.ts +21 -0
  47. package/dist/lib/services/flow-layout.service.d.ts.map +1 -0
  48. package/dist/lib/services/flow-layout.service.js +76 -0
  49. package/dist/lib/services/flow-layout.service.js.map +1 -0
  50. package/dist/lib/services/flow-state.service.d.ts +37 -0
  51. package/dist/lib/services/flow-state.service.d.ts.map +1 -0
  52. package/dist/lib/services/flow-state.service.js +89 -0
  53. package/dist/lib/services/flow-state.service.js.map +1 -0
  54. package/dist/public-api.d.ts +14 -0
  55. package/dist/public-api.d.ts.map +1 -0
  56. package/dist/public-api.js +22 -0
  57. package/dist/public-api.js.map +1 -0
  58. package/package.json +51 -6
@@ -0,0 +1,999 @@
1
+ import { Component, Input, Output, EventEmitter, ViewChild, ViewEncapsulation, HostListener, HostBinding } from '@angular/core';
2
+ import { Metadata, RunView, CompositeKey } from '@memberjunction/core';
3
+ import { UserInfoEngine } from '@memberjunction/core-entities';
4
+ import { AgentFlowTransformerService, AGENT_STEP_TYPE_CONFIGS } from './agent-flow-transformer.service';
5
+ import * as i0 from "@angular/core";
6
+ import * as i1 from "./agent-flow-transformer.service";
7
+ import * as i2 from "@angular/common";
8
+ import * as i3 from "../components/flow-editor.component";
9
+ import * as i4 from "./agent-properties-panel.component";
10
+ import * as i5 from "./agent-step-list.component";
11
+ const _c0 = ["flowEditor"];
12
+ function FlowAgentEditorComponent_Conditional_3_Template(rf, ctx) { if (rf & 1) {
13
+ const _r1 = i0.ɵɵgetCurrentView();
14
+ i0.ɵɵelementStart(0, "button", 26);
15
+ i0.ɵɵlistener("click", function FlowAgentEditorComponent_Conditional_3_Template_button_click_0_listener() { i0.ɵɵrestoreView(_r1); const ctx_r1 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r1.flowEditor == null ? null : ctx_r1.flowEditor.Undo()); });
16
+ i0.ɵɵelement(1, "i", 27);
17
+ i0.ɵɵelementEnd();
18
+ } if (rf & 2) {
19
+ const ctx_r1 = i0.ɵɵnextContext();
20
+ i0.ɵɵproperty("disabled", !(ctx_r1.flowEditor == null ? null : ctx_r1.flowEditor.CanUndo));
21
+ } }
22
+ function FlowAgentEditorComponent_Conditional_4_Template(rf, ctx) { if (rf & 1) {
23
+ const _r3 = i0.ɵɵgetCurrentView();
24
+ i0.ɵɵelementStart(0, "button", 28);
25
+ i0.ɵɵlistener("click", function FlowAgentEditorComponent_Conditional_4_Template_button_click_0_listener() { i0.ɵɵrestoreView(_r3); const ctx_r1 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r1.flowEditor == null ? null : ctx_r1.flowEditor.Redo()); });
26
+ i0.ɵɵelement(1, "i", 29);
27
+ i0.ɵɵelementEnd();
28
+ } if (rf & 2) {
29
+ const ctx_r1 = i0.ɵɵnextContext();
30
+ i0.ɵɵproperty("disabled", !(ctx_r1.flowEditor == null ? null : ctx_r1.flowEditor.CanRedo));
31
+ } }
32
+ function FlowAgentEditorComponent_Conditional_16_Template(rf, ctx) { if (rf & 1) {
33
+ i0.ɵɵelementStart(0, "span", 12);
34
+ i0.ɵɵelement(1, "i", 30);
35
+ i0.ɵɵtext(2, " Editing ");
36
+ i0.ɵɵelementEnd();
37
+ } }
38
+ function FlowAgentEditorComponent_Conditional_17_Template(rf, ctx) { if (rf & 1) {
39
+ i0.ɵɵelementStart(0, "span", 13);
40
+ i0.ɵɵelement(1, "i", 31);
41
+ i0.ɵɵtext(2, " Read Only ");
42
+ i0.ɵɵelementEnd();
43
+ } }
44
+ function FlowAgentEditorComponent_Conditional_19_Template(rf, ctx) { if (rf & 1) {
45
+ i0.ɵɵelementStart(0, "span", 15);
46
+ i0.ɵɵelement(1, "i", 32);
47
+ i0.ɵɵtext(2, " Unsaved ");
48
+ i0.ɵɵelementEnd();
49
+ } }
50
+ function FlowAgentEditorComponent_Conditional_20_Template(rf, ctx) { if (rf & 1) {
51
+ i0.ɵɵelementStart(0, "span", 16);
52
+ i0.ɵɵtext(1);
53
+ i0.ɵɵpipe(2, "date");
54
+ i0.ɵɵelementEnd();
55
+ } if (rf & 2) {
56
+ const ctx_r1 = i0.ɵɵnextContext();
57
+ i0.ɵɵadvance();
58
+ i0.ɵɵtextInterpolate1(" Saved ", i0.ɵɵpipeBind2(2, 1, ctx_r1.lastSaved, "shortTime"), " ");
59
+ } }
60
+ function FlowAgentEditorComponent_Conditional_21_Template(rf, ctx) { if (rf & 1) {
61
+ const _r4 = i0.ɵɵgetCurrentView();
62
+ i0.ɵɵelementStart(0, "button", 33);
63
+ i0.ɵɵlistener("click", function FlowAgentEditorComponent_Conditional_21_Template_button_click_0_listener() { i0.ɵɵrestoreView(_r4); const ctx_r1 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r1.Save()); });
64
+ i0.ɵɵelement(1, "i", 34);
65
+ i0.ɵɵtext(2);
66
+ i0.ɵɵelementEnd();
67
+ } if (rf & 2) {
68
+ const ctx_r1 = i0.ɵɵnextContext();
69
+ i0.ɵɵproperty("disabled", ctx_r1.isSaving || !ctx_r1.hasUnsavedChanges);
70
+ i0.ɵɵadvance();
71
+ i0.ɵɵproperty("ngClass", ctx_r1.isSaving ? "fa-spinner fa-spin" : "fa-floppy-disk");
72
+ i0.ɵɵadvance();
73
+ i0.ɵɵtextInterpolate1(" ", ctx_r1.isSaving ? "Saving..." : "Save", " ");
74
+ } }
75
+ function FlowAgentEditorComponent_Conditional_22_Template(rf, ctx) { if (rf & 1) {
76
+ const _r5 = i0.ɵɵgetCurrentView();
77
+ i0.ɵɵelementStart(0, "button", 35);
78
+ i0.ɵɵlistener("click", function FlowAgentEditorComponent_Conditional_22_Template_button_click_0_listener() { i0.ɵɵrestoreView(_r5); const ctx_r1 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r1.cancelFullscreenEdit()); });
79
+ i0.ɵɵelement(1, "i", 36);
80
+ i0.ɵɵtext(2, " Cancel ");
81
+ i0.ɵɵelementEnd();
82
+ } }
83
+ function FlowAgentEditorComponent_Conditional_23_Template(rf, ctx) { if (rf & 1) {
84
+ i0.ɵɵelement(0, "div", 19);
85
+ } }
86
+ function FlowAgentEditorComponent_Conditional_24_Template(rf, ctx) { if (rf & 1) {
87
+ const _r6 = i0.ɵɵgetCurrentView();
88
+ i0.ɵɵelementStart(0, "button", 37);
89
+ i0.ɵɵlistener("click", function FlowAgentEditorComponent_Conditional_24_Template_button_click_0_listener() { i0.ɵɵrestoreView(_r6); const ctx_r1 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r1.toggleFullscreenEditMode()); });
90
+ i0.ɵɵelement(1, "i", 38);
91
+ i0.ɵɵtext(2, " Edit ");
92
+ i0.ɵɵelementEnd();
93
+ } }
94
+ function FlowAgentEditorComponent_Conditional_25_Template(rf, ctx) { if (rf & 1) {
95
+ const _r7 = i0.ɵɵgetCurrentView();
96
+ i0.ɵɵelementStart(0, "button", 39);
97
+ i0.ɵɵlistener("click", function FlowAgentEditorComponent_Conditional_25_Template_button_click_0_listener() { i0.ɵɵrestoreView(_r7); const ctx_r1 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r1.toggleFullScreen()); });
98
+ i0.ɵɵelement(1, "i", 40);
99
+ i0.ɵɵtext(2, " Expand ");
100
+ i0.ɵɵelementEnd();
101
+ } }
102
+ function FlowAgentEditorComponent_Conditional_26_Template(rf, ctx) { if (rf & 1) {
103
+ const _r8 = i0.ɵɵgetCurrentView();
104
+ i0.ɵɵelementStart(0, "button", 41);
105
+ i0.ɵɵlistener("click", function FlowAgentEditorComponent_Conditional_26_Template_button_click_0_listener() { i0.ɵɵrestoreView(_r8); const ctx_r1 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r1.toggleFullScreen()); });
106
+ i0.ɵɵelement(1, "i", 36);
107
+ i0.ɵɵtext(2, " Close ");
108
+ i0.ɵɵelementEnd();
109
+ } }
110
+ function FlowAgentEditorComponent_Conditional_27_Template(rf, ctx) { if (rf & 1) {
111
+ i0.ɵɵelementStart(0, "div", 23);
112
+ i0.ɵɵelement(1, "i", 42);
113
+ i0.ɵɵelementStart(2, "span");
114
+ i0.ɵɵtext(3, "Loading flow...");
115
+ i0.ɵɵelementEnd()();
116
+ } }
117
+ function FlowAgentEditorComponent_Conditional_28_Conditional_1_Template(rf, ctx) { if (rf & 1) {
118
+ const _r9 = i0.ɵɵgetCurrentView();
119
+ i0.ɵɵelementStart(0, "div", 43)(1, "mj-flow-editor", 45, 0);
120
+ i0.ɵɵlistener("NodeSelected", function FlowAgentEditorComponent_Conditional_28_Conditional_1_Template_mj_flow_editor_NodeSelected_1_listener($event) { i0.ɵɵrestoreView(_r9); const ctx_r1 = i0.ɵɵnextContext(2); return i0.ɵɵresetView(ctx_r1.onNodeSelected($event)); })("NodeAdded", function FlowAgentEditorComponent_Conditional_28_Conditional_1_Template_mj_flow_editor_NodeAdded_1_listener($event) { i0.ɵɵrestoreView(_r9); const ctx_r1 = i0.ɵɵnextContext(2); return i0.ɵɵresetView(ctx_r1.onNodeAdded($event)); })("NodeRemoved", function FlowAgentEditorComponent_Conditional_28_Conditional_1_Template_mj_flow_editor_NodeRemoved_1_listener($event) { i0.ɵɵrestoreView(_r9); const ctx_r1 = i0.ɵɵnextContext(2); return i0.ɵɵresetView(ctx_r1.onNodeRemoved($event)); })("ConnectionCreated", function FlowAgentEditorComponent_Conditional_28_Conditional_1_Template_mj_flow_editor_ConnectionCreated_1_listener($event) { i0.ɵɵrestoreView(_r9); const ctx_r1 = i0.ɵɵnextContext(2); return i0.ɵɵresetView(ctx_r1.onConnectionCreated($event)); })("ConnectionRemoved", function FlowAgentEditorComponent_Conditional_28_Conditional_1_Template_mj_flow_editor_ConnectionRemoved_1_listener($event) { i0.ɵɵrestoreView(_r9); const ctx_r1 = i0.ɵɵnextContext(2); return i0.ɵɵresetView(ctx_r1.onConnectionRemoved($event)); })("ConnectionReassigned", function FlowAgentEditorComponent_Conditional_28_Conditional_1_Template_mj_flow_editor_ConnectionReassigned_1_listener($event) { i0.ɵɵrestoreView(_r9); const ctx_r1 = i0.ɵɵnextContext(2); return i0.ɵɵresetView(ctx_r1.onConnectionReassigned($event)); })("ConnectionSelected", function FlowAgentEditorComponent_Conditional_28_Conditional_1_Template_mj_flow_editor_ConnectionSelected_1_listener($event) { i0.ɵɵrestoreView(_r9); const ctx_r1 = i0.ɵɵnextContext(2); return i0.ɵɵresetView(ctx_r1.onConnectionSelected($event)); })("NodesChanged", function FlowAgentEditorComponent_Conditional_28_Conditional_1_Template_mj_flow_editor_NodesChanged_1_listener($event) { i0.ɵɵrestoreView(_r9); const ctx_r1 = i0.ɵɵnextContext(2); return i0.ɵɵresetView(ctx_r1.onNodesChanged($event)); })("ConnectionsChanged", function FlowAgentEditorComponent_Conditional_28_Conditional_1_Template_mj_flow_editor_ConnectionsChanged_1_listener($event) { i0.ɵɵrestoreView(_r9); const ctx_r1 = i0.ɵɵnextContext(2); return i0.ɵɵresetView(ctx_r1.onConnectionsChanged($event)); })("GridToggled", function FlowAgentEditorComponent_Conditional_28_Conditional_1_Template_mj_flow_editor_GridToggled_1_listener($event) { i0.ɵɵrestoreView(_r9); const ctx_r1 = i0.ɵɵnextContext(2); return i0.ɵɵresetView(ctx_r1.onGridPrefChanged($event)); })("MinimapToggled", function FlowAgentEditorComponent_Conditional_28_Conditional_1_Template_mj_flow_editor_MinimapToggled_1_listener($event) { i0.ɵɵrestoreView(_r9); const ctx_r1 = i0.ɵɵnextContext(2); return i0.ɵɵresetView(ctx_r1.onMinimapPrefChanged($event)); })("LegendToggled", function FlowAgentEditorComponent_Conditional_28_Conditional_1_Template_mj_flow_editor_LegendToggled_1_listener($event) { i0.ɵɵrestoreView(_r9); const ctx_r1 = i0.ɵɵnextContext(2); return i0.ɵɵresetView(ctx_r1.onLegendPrefChanged($event)); });
121
+ i0.ɵɵelementEnd();
122
+ i0.ɵɵelementStart(3, "div", 46)(4, "mj-agent-properties-panel", 47);
123
+ i0.ɵɵlistener("StepChanged", function FlowAgentEditorComponent_Conditional_28_Conditional_1_Template_mj_agent_properties_panel_StepChanged_4_listener($event) { i0.ɵɵrestoreView(_r9); const ctx_r1 = i0.ɵɵnextContext(2); return i0.ɵɵresetView(ctx_r1.onStepChanged($event)); })("PathChanged", function FlowAgentEditorComponent_Conditional_28_Conditional_1_Template_mj_agent_properties_panel_PathChanged_4_listener($event) { i0.ɵɵrestoreView(_r9); const ctx_r1 = i0.ɵɵnextContext(2); return i0.ɵɵresetView(ctx_r1.onPathChanged($event)); })("DeleteStepRequested", function FlowAgentEditorComponent_Conditional_28_Conditional_1_Template_mj_agent_properties_panel_DeleteStepRequested_4_listener($event) { i0.ɵɵrestoreView(_r9); const ctx_r1 = i0.ɵɵnextContext(2); return i0.ɵɵresetView(ctx_r1.onDeleteStepRequested($event)); })("DeletePathRequested", function FlowAgentEditorComponent_Conditional_28_Conditional_1_Template_mj_agent_properties_panel_DeletePathRequested_4_listener($event) { i0.ɵɵrestoreView(_r9); const ctx_r1 = i0.ɵɵnextContext(2); return i0.ɵɵresetView(ctx_r1.onDeletePathRequested($event)); })("CloseRequested", function FlowAgentEditorComponent_Conditional_28_Conditional_1_Template_mj_agent_properties_panel_CloseRequested_4_listener() { i0.ɵɵrestoreView(_r9); const ctx_r1 = i0.ɵɵnextContext(2); return i0.ɵɵresetView(ctx_r1.onCloseProperties()); });
124
+ i0.ɵɵelementEnd()()();
125
+ } if (rf & 2) {
126
+ const ctx_r1 = i0.ɵɵnextContext(2);
127
+ i0.ɵɵadvance();
128
+ i0.ɵɵproperty("Nodes", ctx_r1.nodes)("Connections", ctx_r1.connections)("NodeTypes", ctx_r1.nodeTypes)("ReadOnly", !ctx_r1.isEditingActive)("ShowMinimap", ctx_r1.prefShowMinimap)("ShowPalette", ctx_r1.isEditingActive)("ShowGrid", ctx_r1.prefShowGrid)("ShowLegend", ctx_r1.prefShowLegend)("ShowStatusBar", true)("ShowToolbar", true)("AutoLayoutDirection", "vertical");
129
+ i0.ɵɵadvance(2);
130
+ i0.ɵɵclassProp("mj-agent-editor-properties--visible", ctx_r1.showPropertiesPanel);
131
+ i0.ɵɵadvance();
132
+ i0.ɵɵproperty("Step", ctx_r1.selectedStep)("SelectedConnection", ctx_r1.selectedConnection)("PathEntity", ctx_r1.selectedPathEntity)("ReadOnly", !ctx_r1.isEditingActive)("Actions", ctx_r1.availableActions)("Prompts", ctx_r1.availablePrompts)("Agents", ctx_r1.availableAgents)("AllSteps", ctx_r1.steps);
133
+ } }
134
+ function FlowAgentEditorComponent_Conditional_28_Conditional_2_Template(rf, ctx) { if (rf & 1) {
135
+ const _r10 = i0.ɵɵgetCurrentView();
136
+ i0.ɵɵelementStart(0, "div", 44)(1, "mj-agent-step-list", 48);
137
+ i0.ɵɵlistener("StepClicked", function FlowAgentEditorComponent_Conditional_28_Conditional_2_Template_mj_agent_step_list_StepClicked_1_listener($event) { i0.ɵɵrestoreView(_r10); const ctx_r1 = i0.ɵɵnextContext(2); return i0.ɵɵresetView(ctx_r1.onStepClickedInList($event)); });
138
+ i0.ɵɵelementEnd();
139
+ i0.ɵɵelementStart(2, "div", 46)(3, "mj-agent-properties-panel", 47);
140
+ i0.ɵɵlistener("StepChanged", function FlowAgentEditorComponent_Conditional_28_Conditional_2_Template_mj_agent_properties_panel_StepChanged_3_listener($event) { i0.ɵɵrestoreView(_r10); const ctx_r1 = i0.ɵɵnextContext(2); return i0.ɵɵresetView(ctx_r1.onStepChanged($event)); })("PathChanged", function FlowAgentEditorComponent_Conditional_28_Conditional_2_Template_mj_agent_properties_panel_PathChanged_3_listener($event) { i0.ɵɵrestoreView(_r10); const ctx_r1 = i0.ɵɵnextContext(2); return i0.ɵɵresetView(ctx_r1.onPathChanged($event)); })("DeleteStepRequested", function FlowAgentEditorComponent_Conditional_28_Conditional_2_Template_mj_agent_properties_panel_DeleteStepRequested_3_listener($event) { i0.ɵɵrestoreView(_r10); const ctx_r1 = i0.ɵɵnextContext(2); return i0.ɵɵresetView(ctx_r1.onDeleteStepRequested($event)); })("DeletePathRequested", function FlowAgentEditorComponent_Conditional_28_Conditional_2_Template_mj_agent_properties_panel_DeletePathRequested_3_listener($event) { i0.ɵɵrestoreView(_r10); const ctx_r1 = i0.ɵɵnextContext(2); return i0.ɵɵresetView(ctx_r1.onDeletePathRequested($event)); })("CloseRequested", function FlowAgentEditorComponent_Conditional_28_Conditional_2_Template_mj_agent_properties_panel_CloseRequested_3_listener() { i0.ɵɵrestoreView(_r10); const ctx_r1 = i0.ɵɵnextContext(2); return i0.ɵɵresetView(ctx_r1.onCloseProperties()); });
141
+ i0.ɵɵelementEnd()()();
142
+ } if (rf & 2) {
143
+ const ctx_r1 = i0.ɵɵnextContext(2);
144
+ i0.ɵɵadvance();
145
+ i0.ɵɵproperty("Steps", ctx_r1.steps)("Paths", ctx_r1.paths)("SelectedStepID", (ctx_r1.selectedStep == null ? null : ctx_r1.selectedStep.ID) || null);
146
+ i0.ɵɵadvance();
147
+ i0.ɵɵclassProp("mj-agent-editor-properties--visible", ctx_r1.showPropertiesPanel);
148
+ i0.ɵɵadvance();
149
+ i0.ɵɵproperty("Step", ctx_r1.selectedStep)("SelectedConnection", ctx_r1.selectedConnection)("PathEntity", ctx_r1.selectedPathEntity)("ReadOnly", !ctx_r1.isEditingActive)("Actions", ctx_r1.availableActions)("Prompts", ctx_r1.availablePrompts)("Agents", ctx_r1.availableAgents)("AllSteps", ctx_r1.steps);
150
+ } }
151
+ function FlowAgentEditorComponent_Conditional_28_Template(rf, ctx) { if (rf & 1) {
152
+ i0.ɵɵelementStart(0, "div", 24);
153
+ i0.ɵɵconditionalCreate(1, FlowAgentEditorComponent_Conditional_28_Conditional_1_Template, 5, 21, "div", 43);
154
+ i0.ɵɵconditionalCreate(2, FlowAgentEditorComponent_Conditional_28_Conditional_2_Template, 4, 13, "div", 44);
155
+ i0.ɵɵelementEnd();
156
+ } if (rf & 2) {
157
+ const ctx_r1 = i0.ɵɵnextContext();
158
+ i0.ɵɵadvance();
159
+ i0.ɵɵconditional(ctx_r1.viewMode === "diagram" ? 1 : -1);
160
+ i0.ɵɵadvance();
161
+ i0.ɵɵconditional(ctx_r1.viewMode === "list" ? 2 : -1);
162
+ } }
163
+ function FlowAgentEditorComponent_Conditional_29_Template(rf, ctx) { if (rf & 1) {
164
+ const _r11 = i0.ɵɵgetCurrentView();
165
+ i0.ɵɵelementStart(0, "div", 25)(1, "div", 49)(2, "div", 50);
166
+ i0.ɵɵelement(3, "i", 51);
167
+ i0.ɵɵelementEnd();
168
+ i0.ɵɵelementStart(4, "h3", 52);
169
+ i0.ɵɵtext(5, "Unsaved Changes");
170
+ i0.ɵɵelementEnd();
171
+ i0.ɵɵelementStart(6, "p", 53);
172
+ i0.ɵɵtext(7, " You have unsaved changes to this flow. What would you like to do? ");
173
+ i0.ɵɵelementEnd();
174
+ i0.ɵɵelementStart(8, "div", 54)(9, "button", 55);
175
+ i0.ɵɵlistener("click", function FlowAgentEditorComponent_Conditional_29_Template_button_click_9_listener() { i0.ɵɵrestoreView(_r11); const ctx_r1 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r1.onUnsavedDialogSave()); });
176
+ i0.ɵɵelement(10, "i", 56);
177
+ i0.ɵɵtext(11, " Save & Close ");
178
+ i0.ɵɵelementEnd();
179
+ i0.ɵɵelementStart(12, "button", 57);
180
+ i0.ɵɵlistener("click", function FlowAgentEditorComponent_Conditional_29_Template_button_click_12_listener() { i0.ɵɵrestoreView(_r11); const ctx_r1 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r1.onUnsavedDialogDiscard()); });
181
+ i0.ɵɵtext(13, " Discard Changes ");
182
+ i0.ɵɵelementEnd();
183
+ i0.ɵɵelementStart(14, "button", 58);
184
+ i0.ɵɵlistener("click", function FlowAgentEditorComponent_Conditional_29_Template_button_click_14_listener() { i0.ɵɵrestoreView(_r11); const ctx_r1 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r1.onUnsavedDialogCancel()); });
185
+ i0.ɵɵtext(15, " Cancel ");
186
+ i0.ɵɵelementEnd()()()();
187
+ } }
188
+ /**
189
+ * Flow Agent Editor — wraps the generic FlowEditorComponent with
190
+ * MJ agent-specific CRUD, properties panel, and data transformation.
191
+ */
192
+ export class FlowAgentEditorComponent {
193
+ cdr;
194
+ transformer;
195
+ elRef;
196
+ renderer;
197
+ // ── Host Bindings ─────────────────────────────────────────────
198
+ get HostFullScreen() { return this.FullScreen; }
199
+ // ── Inputs ──────────────────────────────────────────────────
200
+ AgentID = null;
201
+ EditMode = true;
202
+ FullScreen = false;
203
+ // ── Outputs ─────────────────────────────────────────────────
204
+ FlowSaved = new EventEmitter();
205
+ FlowChanged = new EventEmitter();
206
+ FullScreenToggled = new EventEmitter();
207
+ StepSelected = new EventEmitter();
208
+ // ── View Children ───────────────────────────────────────────
209
+ flowEditor;
210
+ // ── State ───────────────────────────────────────────────────
211
+ nodes = [];
212
+ connections = [];
213
+ nodeTypes = AGENT_STEP_TYPE_CONFIGS;
214
+ viewMode = 'diagram';
215
+ isLoading = true;
216
+ isSaving = false;
217
+ hasUnsavedChanges = false;
218
+ lastSaved = null;
219
+ // Fullscreen self-contained edit mode
220
+ fullscreenEditMode = false;
221
+ showUnsavedDialog = false;
222
+ // Entity data
223
+ steps = [];
224
+ paths = [];
225
+ deletedStepIDs = [];
226
+ deletedPathIDs = [];
227
+ // Selected items
228
+ selectedStep = null;
229
+ selectedConnection = null;
230
+ selectedPathEntity = null;
231
+ showPropertiesPanel = false;
232
+ // Picker data (includes icon fields for node rendering)
233
+ availableActions = [];
234
+ availablePrompts = [];
235
+ availableAgents = [];
236
+ // Permission state — cached once on init
237
+ userCanUpdate = false;
238
+ // User view preferences (persisted via UserInfoEngine)
239
+ prefShowGrid = true;
240
+ prefShowMinimap = true;
241
+ prefShowLegend = true;
242
+ static PREF_KEY = 'flow-editor/view-prefs';
243
+ // Initial zoom state
244
+ needsInitialZoom = false;
245
+ resizeObserver = null;
246
+ // Fullscreen DOM relocation state
247
+ originalParent = null;
248
+ originalNextSibling = null;
249
+ backdropElement = null;
250
+ constructor(cdr, transformer, elRef, renderer) {
251
+ this.cdr = cdr;
252
+ this.transformer = transformer;
253
+ this.elRef = elRef;
254
+ this.renderer = renderer;
255
+ }
256
+ // ── Lifecycle ───────────────────────────────────────────────
257
+ ngOnInit() {
258
+ this.loadViewPreferences();
259
+ this.checkUpdatePermission();
260
+ if (this.AgentID) {
261
+ this.loadAll();
262
+ }
263
+ }
264
+ ngOnChanges(changes) {
265
+ if (changes['AgentID'] && !changes['AgentID'].firstChange && this.AgentID) {
266
+ this.loadAll();
267
+ }
268
+ }
269
+ ngOnDestroy() {
270
+ this.teardownResizeObserver();
271
+ // Restore element to original parent if still in fullscreen
272
+ if (this.FullScreen) {
273
+ this.restoreFromFullscreen();
274
+ }
275
+ }
276
+ // ── Data Loading ────────────────────────────────────────────
277
+ async loadAll() {
278
+ this.isLoading = true;
279
+ this.cdr.detectChanges();
280
+ try {
281
+ await Promise.all([
282
+ this.loadStepsAndPaths(),
283
+ this.loadPickerData()
284
+ ]);
285
+ this.rebuildFlowModel();
286
+ }
287
+ finally {
288
+ this.isLoading = false;
289
+ this.cdr.detectChanges();
290
+ // Flag that we need an initial zoom; it will fire when the host element
291
+ // first becomes visible (e.g. Kendo PanelBar expands)
292
+ this.setupInitialZoomObserver();
293
+ }
294
+ }
295
+ async loadStepsAndPaths() {
296
+ if (!this.AgentID)
297
+ return;
298
+ const rv = new RunView();
299
+ const [stepsResult, pathsResult] = await rv.RunViews([
300
+ {
301
+ EntityName: 'MJ: AI Agent Steps',
302
+ ExtraFilter: `AgentID='${this.AgentID}'`,
303
+ OrderBy: 'Name ASC',
304
+ ResultType: 'entity_object'
305
+ },
306
+ {
307
+ EntityName: 'MJ: AI Agent Step Paths',
308
+ ExtraFilter: `OriginStepID IN (SELECT ID FROM [__mj].[AIAgentStep] WHERE AgentID='${this.AgentID}')`,
309
+ OrderBy: 'Priority DESC',
310
+ ResultType: 'entity_object'
311
+ }
312
+ ]);
313
+ this.steps = stepsResult.Success ? stepsResult.Results : [];
314
+ this.paths = pathsResult.Success ? pathsResult.Results : [];
315
+ this.deletedStepIDs = [];
316
+ this.deletedPathIDs = [];
317
+ }
318
+ async loadPickerData() {
319
+ const rv = new RunView();
320
+ const [actionsResult, promptsResult, agentsResult] = await rv.RunViews([
321
+ {
322
+ EntityName: 'Actions',
323
+ Fields: ['ID', 'Name', 'IconClass'],
324
+ ExtraFilter: `Status='Active'`,
325
+ OrderBy: 'Name ASC',
326
+ ResultType: 'simple'
327
+ },
328
+ {
329
+ EntityName: 'AI Prompts',
330
+ Fields: ['ID', 'Name'],
331
+ ExtraFilter: '',
332
+ OrderBy: 'Name ASC',
333
+ ResultType: 'simple'
334
+ },
335
+ {
336
+ EntityName: 'AI Agents',
337
+ Fields: ['ID', 'Name', 'IconClass', 'LogoURL'],
338
+ ExtraFilter: this.AgentID ? `ID <> '${this.AgentID}'` : '',
339
+ OrderBy: 'Name ASC',
340
+ ResultType: 'simple'
341
+ }
342
+ ]);
343
+ this.availableActions = actionsResult.Success
344
+ ? actionsResult.Results
345
+ : [];
346
+ this.availablePrompts = promptsResult.Success
347
+ ? promptsResult.Results
348
+ : [];
349
+ this.availableAgents = agentsResult.Success
350
+ ? agentsResult.Results
351
+ : [];
352
+ }
353
+ rebuildFlowModel() {
354
+ this.nodes = this.transformer.StepsToNodes(this.steps, this.availableActions, this.availableAgents);
355
+ this.connections = this.transformer.PathsToConnections(this.paths);
356
+ }
357
+ /**
358
+ * Observe the host element's size. When it transitions from zero to non-zero height
359
+ * (i.e. the collapsed Kendo panel expands), trigger the initial auto-arrange or zoom-to-fit.
360
+ */
361
+ setupInitialZoomObserver() {
362
+ if (this.nodes.length === 0)
363
+ return;
364
+ this.needsInitialZoom = true;
365
+ this.teardownResizeObserver();
366
+ this.resizeObserver = new ResizeObserver((entries) => {
367
+ for (const entry of entries) {
368
+ const height = entry.contentRect.height;
369
+ if (height > 0 && this.needsInitialZoom) {
370
+ this.needsInitialZoom = false;
371
+ this.teardownResizeObserver();
372
+ // Short delay for Foblex canvas to finish its own init after becoming visible
373
+ setTimeout(() => this.applyInitialZoom(), 100);
374
+ }
375
+ }
376
+ });
377
+ this.resizeObserver.observe(this.elRef.nativeElement);
378
+ }
379
+ applyInitialZoom() {
380
+ if (!this.flowEditor || this.nodes.length === 0)
381
+ return;
382
+ const allAtOrigin = this.nodes.every(n => n.Position.X === 0 && n.Position.Y === 0);
383
+ if (allAtOrigin) {
384
+ this.flowEditor.AutoArrange();
385
+ }
386
+ else {
387
+ this.flowEditor.ZoomToFit();
388
+ }
389
+ }
390
+ teardownResizeObserver() {
391
+ if (this.resizeObserver) {
392
+ this.resizeObserver.disconnect();
393
+ this.resizeObserver = null;
394
+ }
395
+ }
396
+ // ── Save ────────────────────────────────────────────────────
397
+ async Save() {
398
+ if (this.isSaving || !this.AgentID)
399
+ return;
400
+ this.isSaving = true;
401
+ this.cdr.detectChanges();
402
+ try {
403
+ // Update positions from canvas to entities
404
+ this.syncPositionsFromCanvas();
405
+ // Delete removed items first
406
+ await this.deleteRemovedEntities();
407
+ // Save all steps
408
+ for (const step of this.steps) {
409
+ const result = await step.Save();
410
+ if (!result) {
411
+ console.error(`Failed to save step: ${step.Name}`, step.LatestResult);
412
+ }
413
+ }
414
+ // Save all paths
415
+ for (const path of this.paths) {
416
+ const result = await path.Save();
417
+ if (!result) {
418
+ console.error(`Failed to save path: ${path.ID}`, path.LatestResult);
419
+ }
420
+ }
421
+ this.hasUnsavedChanges = false;
422
+ this.lastSaved = new Date();
423
+ // Exit self-contained fullscreen edit mode after successful save
424
+ if (this.fullscreenEditMode) {
425
+ this.fullscreenEditMode = false;
426
+ }
427
+ this.FlowSaved.emit();
428
+ }
429
+ catch (err) {
430
+ console.error('Error saving flow:', err);
431
+ }
432
+ finally {
433
+ this.isSaving = false;
434
+ this.cdr.detectChanges();
435
+ }
436
+ }
437
+ syncPositionsFromCanvas() {
438
+ this.syncPositionsToEntities();
439
+ }
440
+ /** Write current FlowNode positions back to the underlying step entities.
441
+ * Called on every node move so that rebuildFlowModel() never loses drag changes. */
442
+ syncPositionsToEntities() {
443
+ for (const node of this.nodes) {
444
+ const step = this.steps.find(s => s.ID === node.ID);
445
+ if (step) {
446
+ this.transformer.ApplyNodePosition(step, node);
447
+ }
448
+ }
449
+ }
450
+ async deleteRemovedEntities() {
451
+ const md = new Metadata();
452
+ for (const pathId of this.deletedPathIDs) {
453
+ const pathEntity = await md.GetEntityObject('MJ: AI Agent Step Paths');
454
+ await pathEntity.InnerLoad(CompositeKey.FromID(pathId));
455
+ await pathEntity.Delete();
456
+ }
457
+ for (const stepId of this.deletedStepIDs) {
458
+ const stepEntity = await md.GetEntityObject('MJ: AI Agent Steps');
459
+ await stepEntity.InnerLoad(CompositeKey.FromID(stepId));
460
+ await stepEntity.Delete();
461
+ }
462
+ this.deletedPathIDs = [];
463
+ this.deletedStepIDs = [];
464
+ }
465
+ // ── Flow Editor Event Handlers ──────────────────────────────
466
+ async onNodeAdded(event) {
467
+ if (!this.AgentID)
468
+ return;
469
+ const md = new Metadata();
470
+ const step = await md.GetEntityObject('MJ: AI Agent Steps');
471
+ step.NewRecord(); // This generates a UUID immediately - available before Save()
472
+ step.AgentID = this.AgentID;
473
+ step.Name = event.Node.Label;
474
+ step.StepType = event.Node.Type;
475
+ step.Status = 'Active';
476
+ step.StartingStep = this.steps.length === 0; // First step is starting step
477
+ step.PositionX = Math.round(event.DropPosition.X);
478
+ step.PositionY = Math.round(event.DropPosition.Y);
479
+ step.OnErrorBehavior = 'fail';
480
+ step.RetryCount = 0;
481
+ step.TimeoutSeconds = 600;
482
+ // Add the unsaved step to the array - it already has a UUID from NewRecord()
483
+ // This allows connections to be drawn immediately without waiting for a database save
484
+ this.steps.push(step);
485
+ // Build a FlowNode using the entity's pre-generated ID so Foblex can track it
486
+ const newNode = this.transformer.StepToNode(step, this.availableActions, this.availableAgents);
487
+ this.nodes.push(newNode);
488
+ this.markDirty();
489
+ // Select the new node
490
+ setTimeout(() => {
491
+ this.flowEditor?.SelectNode(step.ID);
492
+ this.onNodeSelected(newNode);
493
+ }, 100);
494
+ this.cdr.detectChanges();
495
+ }
496
+ async onConnectionCreated(event) {
497
+ if (!this.AgentID)
498
+ return;
499
+ // Prevent duplicate
500
+ const exists = this.paths.some(p => p.OriginStepID === event.SourceNodeID && p.DestinationStepID === event.TargetNodeID);
501
+ if (exists)
502
+ return;
503
+ const md = new Metadata();
504
+ const path = await md.GetEntityObject('MJ: AI Agent Step Paths');
505
+ path.NewRecord(); // Generates UUID immediately - available before Save()
506
+ path.OriginStepID = event.SourceNodeID;
507
+ path.DestinationStepID = event.TargetNodeID;
508
+ path.Priority = 0;
509
+ // Add unsaved path to the array - save will happen on main Save() button
510
+ this.paths.push(path);
511
+ this.rebuildFlowModel();
512
+ this.markDirty();
513
+ this.cdr.detectChanges();
514
+ }
515
+ onNodeSelected(node) {
516
+ if (node) {
517
+ this.selectedStep = this.steps.find(s => s.ID === node.ID) ?? null;
518
+ this.selectedConnection = null;
519
+ this.selectedPathEntity = null;
520
+ this.showPropertiesPanel = true;
521
+ this.StepSelected.emit(this.selectedStep);
522
+ }
523
+ else {
524
+ this.selectedStep = null;
525
+ // Only hide the panel if no connection is currently selected.
526
+ // When the user clicks a connection, Foblex fires NodeSelected(null) AND
527
+ // ConnectionSelected(conn) — we must not let the null-node event hide
528
+ // the panel that the connection event just opened.
529
+ if (!this.selectedConnection) {
530
+ this.showPropertiesPanel = false;
531
+ }
532
+ this.StepSelected.emit(null);
533
+ }
534
+ this.cdr.detectChanges();
535
+ }
536
+ onConnectionSelected(conn) {
537
+ if (conn) {
538
+ this.selectedConnection = conn;
539
+ this.selectedPathEntity = this.paths.find(p => p.ID === conn.ID) ?? null;
540
+ this.selectedStep = null;
541
+ this.showPropertiesPanel = true;
542
+ }
543
+ else {
544
+ this.selectedConnection = null;
545
+ this.selectedPathEntity = null;
546
+ }
547
+ this.cdr.detectChanges();
548
+ }
549
+ onNodeRemoved(node) {
550
+ const step = this.steps.find(s => s.ID === node.ID);
551
+ if (step) {
552
+ // Track for deletion on save (only if it was previously saved)
553
+ if (step.IsSaved) {
554
+ this.deletedStepIDs.push(step.ID);
555
+ // Also mark paths connected to this step for deletion
556
+ const connectedPaths = this.paths.filter(p => p.OriginStepID === step.ID || p.DestinationStepID === step.ID);
557
+ for (const path of connectedPaths) {
558
+ if (path.IsSaved) {
559
+ this.deletedPathIDs.push(path.ID);
560
+ }
561
+ }
562
+ }
563
+ this.steps = this.steps.filter(s => s.ID !== node.ID);
564
+ this.paths = this.paths.filter(p => p.OriginStepID !== node.ID && p.DestinationStepID !== node.ID);
565
+ this.markDirty();
566
+ }
567
+ }
568
+ onConnectionRemoved(conn) {
569
+ const path = this.paths.find(p => p.ID === conn.ID);
570
+ if (path) {
571
+ if (path.IsSaved) {
572
+ this.deletedPathIDs.push(path.ID);
573
+ }
574
+ this.paths = this.paths.filter(p => p.ID !== conn.ID);
575
+ this.markDirty();
576
+ }
577
+ }
578
+ onConnectionReassigned(event) {
579
+ const path = this.paths.find(p => p.ID === event.ConnectionID);
580
+ if (!path)
581
+ return;
582
+ // Update the entity's origin/destination to match the new visual endpoints
583
+ path.OriginStepID = event.NewSourceNodeID;
584
+ path.DestinationStepID = event.NewTargetNodeID;
585
+ // Rebuild all connections so sibling-based visual logic recalculates
586
+ // (e.g., Default vs Duplicate Default labels depend on sibling analysis)
587
+ this.rebuildFlowModel();
588
+ this.markDirty();
589
+ this.cdr.detectChanges();
590
+ }
591
+ onNodesChanged(nodes) {
592
+ this.nodes = nodes;
593
+ // Sync canvas positions back to entities immediately so that
594
+ // any subsequent rebuildFlowModel() preserves drag changes.
595
+ this.syncPositionsToEntities();
596
+ this.markDirty();
597
+ }
598
+ onConnectionsChanged(connections) {
599
+ this.connections = connections;
600
+ this.markDirty();
601
+ }
602
+ // ── Properties Panel Events ─────────────────────────────────
603
+ onStepChanged(step) {
604
+ // Update the corresponding flow node in-place and push to generic editor
605
+ const node = this.nodes.find(n => n.ID === step.ID);
606
+ if (node) {
607
+ const newLabel = step.Name;
608
+ const newSubtitle = this.transformer.BuildStepSubtitle(step);
609
+ const baseStatus = this.transformer.MapStepStatus(step.Status);
610
+ const warningMessage = (baseStatus !== 'disabled') ? this.transformer.BuildConfigWarningMessage(step) : null;
611
+ const newStatus = warningMessage ? 'warning' : baseStatus;
612
+ const newIsStart = step.StartingStep === true;
613
+ node.Label = newLabel;
614
+ node.Subtitle = newSubtitle;
615
+ node.Status = newStatus;
616
+ node.StatusMessage = warningMessage ?? undefined;
617
+ node.IsStartNode = newIsStart;
618
+ // Update input port disabled state for starting steps
619
+ const inputPort = node.Ports.find(p => p.Direction === 'input');
620
+ if (inputPort) {
621
+ inputPort.Disabled = newIsStart;
622
+ }
623
+ // Re-resolve icon from picker data (handles action/agent assignment changes)
624
+ const resolved = this.transformer.ResolveStepIcon(step, this.availableActions, this.availableAgents);
625
+ node.Icon = resolved.Icon;
626
+ if (!node.Data)
627
+ node.Data = {};
628
+ node.Data['LogoURL'] = resolved.LogoURL ?? null;
629
+ // For loop nodes, rebuild the loop-specific Data properties so the
630
+ // inner body card updates immediately when the user changes body type / config
631
+ if (step.StepType === 'ForEach' || step.StepType === 'While') {
632
+ this.updateLoopNodeData(step, node);
633
+ }
634
+ // Push visual update to the generic flow editor (creates new object ref for OnPush)
635
+ this.flowEditor?.UpdateNode(step.ID, {
636
+ Label: newLabel,
637
+ Subtitle: newSubtitle,
638
+ Status: newStatus,
639
+ StatusMessage: warningMessage ?? undefined,
640
+ IsStartNode: newIsStart,
641
+ Icon: resolved.Icon,
642
+ Data: node.Data
643
+ });
644
+ }
645
+ this.markDirty();
646
+ this.cdr.detectChanges();
647
+ }
648
+ /** Update loop-specific data fields on a FlowNode from the step entity */
649
+ updateLoopNodeData(step, node) {
650
+ if (!node.Data)
651
+ node.Data = {};
652
+ // Delegate to the transformer's public methods for consistency
653
+ const bodyType = step.LoopBodyType;
654
+ node.Data['LoopBodyType'] = bodyType ?? null;
655
+ node.Data['LoopBodyName'] = this.resolveLoopBodyNameFromStep(step);
656
+ node.Data['LoopBodyIcon'] = this.getBodyTypeIcon(bodyType);
657
+ node.Data['LoopBodyColor'] = this.getBodyTypeColor(bodyType);
658
+ node.Data['LoopIterationSummary'] = this.transformer.BuildLoopIterationSummary(step);
659
+ }
660
+ resolveLoopBodyNameFromStep(step) {
661
+ switch (step.LoopBodyType) {
662
+ case 'Action': return step.Action ?? null;
663
+ case 'Prompt': return step.Prompt ?? null;
664
+ case 'Sub-Agent': return step.SubAgent ?? null;
665
+ default: return null;
666
+ }
667
+ }
668
+ getBodyTypeIcon(bodyType) {
669
+ switch (bodyType) {
670
+ case 'Action': return 'fa-bolt';
671
+ case 'Prompt': return 'fa-comment-dots';
672
+ case 'Sub-Agent': return 'fa-robot';
673
+ default: return 'fa-circle-nodes';
674
+ }
675
+ }
676
+ getBodyTypeColor(bodyType) {
677
+ switch (bodyType) {
678
+ case 'Action': return '#3B82F6';
679
+ case 'Prompt': return '#8B5CF6';
680
+ case 'Sub-Agent': return '#10B981';
681
+ default: return '#6B7280';
682
+ }
683
+ }
684
+ onPathChanged(path) {
685
+ // Rebuild all connections from the same origin since always/conditional logic
686
+ // depends on sibling paths (e.g., "Default" label only appears when siblings exist)
687
+ this.rebuildFlowModel();
688
+ this.markDirty();
689
+ this.cdr.detectChanges();
690
+ }
691
+ onDeleteStepRequested(step) {
692
+ const node = this.nodes.find(n => n.ID === step.ID);
693
+ if (node) {
694
+ this.flowEditor?.SelectNode(step.ID);
695
+ this.flowEditor?.DeleteSelected();
696
+ }
697
+ this.showPropertiesPanel = false;
698
+ this.selectedStep = null;
699
+ this.cdr.detectChanges();
700
+ }
701
+ onDeletePathRequested(path) {
702
+ const conn = this.connections.find(c => c.ID === path.ID);
703
+ if (conn) {
704
+ if (path.IsSaved) {
705
+ this.deletedPathIDs.push(path.ID);
706
+ }
707
+ this.paths = this.paths.filter(p => p.ID !== path.ID);
708
+ this.rebuildFlowModel();
709
+ this.markDirty();
710
+ }
711
+ this.showPropertiesPanel = false;
712
+ this.selectedConnection = null;
713
+ this.selectedPathEntity = null;
714
+ this.cdr.detectChanges();
715
+ }
716
+ onCloseProperties() {
717
+ this.showPropertiesPanel = false;
718
+ this.flowEditor?.ClearSelection();
719
+ }
720
+ // ── View & UI Controls ──────────────────────────────────────
721
+ toggleViewMode() {
722
+ this.viewMode = this.viewMode === 'diagram' ? 'list' : 'diagram';
723
+ this.cdr.detectChanges();
724
+ }
725
+ /** Whether editing is currently allowed — combines parent EditMode + fullscreen self-contained edit */
726
+ get isEditingActive() {
727
+ return this.EditMode || this.fullscreenEditMode;
728
+ }
729
+ toggleFullscreenEditMode() {
730
+ this.fullscreenEditMode = !this.fullscreenEditMode;
731
+ this.cdr.detectChanges();
732
+ }
733
+ cancelFullscreenEdit() {
734
+ if (this.hasUnsavedChanges) {
735
+ // Reload to discard changes
736
+ this.fullscreenEditMode = false;
737
+ this.hasUnsavedChanges = false;
738
+ this.loadAll();
739
+ }
740
+ else {
741
+ this.fullscreenEditMode = false;
742
+ this.cdr.detectChanges();
743
+ }
744
+ }
745
+ toggleFullScreen() {
746
+ if (this.FullScreen && this.hasUnsavedChanges) {
747
+ this.showUnsavedDialog = true;
748
+ this.cdr.detectChanges();
749
+ return;
750
+ }
751
+ this.performFullscreenToggle();
752
+ }
753
+ onUnsavedDialogSave() {
754
+ this.showUnsavedDialog = false;
755
+ this.Save().then(() => this.performFullscreenToggle());
756
+ }
757
+ onUnsavedDialogDiscard() {
758
+ this.showUnsavedDialog = false;
759
+ this.hasUnsavedChanges = false;
760
+ this.fullscreenEditMode = false;
761
+ this.performFullscreenToggle();
762
+ // Reload original data
763
+ this.loadAll();
764
+ }
765
+ onUnsavedDialogCancel() {
766
+ this.showUnsavedDialog = false;
767
+ this.cdr.detectChanges();
768
+ }
769
+ performFullscreenToggle() {
770
+ this.FullScreen = !this.FullScreen;
771
+ if (this.FullScreen) {
772
+ this.moveToBodyForFullscreen();
773
+ }
774
+ else {
775
+ this.fullscreenEditMode = false;
776
+ this.restoreFromFullscreen();
777
+ }
778
+ this.FullScreenToggled.emit(this.FullScreen);
779
+ this.cdr.detectChanges();
780
+ // Re-fit after layout change
781
+ setTimeout(() => this.flowEditor?.ZoomToFit(), 200);
782
+ }
783
+ moveToBodyForFullscreen() {
784
+ const hostEl = this.elRef.nativeElement;
785
+ this.originalParent = hostEl.parentElement;
786
+ this.originalNextSibling = hostEl.nextSibling;
787
+ // Create backdrop as a separate body-level element so it covers everything
788
+ this.backdropElement = this.renderer.createElement('div');
789
+ this.renderer.addClass(this.backdropElement, 'mj-agent-editor-backdrop');
790
+ this.renderer.listen(this.backdropElement, 'click', () => this.toggleFullScreen());
791
+ this.renderer.appendChild(document.body, this.backdropElement);
792
+ // Move the host element to body — @HostBinding applies the fixed-position class
793
+ this.renderer.appendChild(document.body, hostEl);
794
+ }
795
+ restoreFromFullscreen() {
796
+ // Remove backdrop
797
+ if (this.backdropElement) {
798
+ this.renderer.removeChild(document.body, this.backdropElement);
799
+ this.backdropElement = null;
800
+ }
801
+ // Restore host element to original position
802
+ if (!this.originalParent)
803
+ return;
804
+ const hostEl = this.elRef.nativeElement;
805
+ if (this.originalNextSibling) {
806
+ this.renderer.insertBefore(this.originalParent, hostEl, this.originalNextSibling);
807
+ }
808
+ else {
809
+ this.renderer.appendChild(this.originalParent, hostEl);
810
+ }
811
+ this.originalParent = null;
812
+ this.originalNextSibling = null;
813
+ }
814
+ onStepClickedInList(step) {
815
+ this.selectedStep = step;
816
+ this.selectedConnection = null;
817
+ this.selectedPathEntity = null;
818
+ this.showPropertiesPanel = true;
819
+ this.StepSelected.emit(step);
820
+ this.cdr.detectChanges();
821
+ }
822
+ // ── Keyboard Shortcuts ─────────────────────────────────────
823
+ onEscapeKey() {
824
+ if (this.showUnsavedDialog) {
825
+ this.onUnsavedDialogCancel();
826
+ }
827
+ else if (this.FullScreen) {
828
+ this.toggleFullScreen();
829
+ }
830
+ }
831
+ // ── Permission Check ────────────────────────────────────────
832
+ checkUpdatePermission() {
833
+ const md = new Metadata();
834
+ const entity = md.EntityByName('AI Agents');
835
+ if (entity) {
836
+ const perms = entity.GetUserPermisions(md.CurrentUser);
837
+ this.userCanUpdate = perms?.CanUpdate === true;
838
+ }
839
+ }
840
+ // ── View Preference Persistence ─────────────────────────────
841
+ loadViewPreferences() {
842
+ const raw = UserInfoEngine.Instance.GetSetting(FlowAgentEditorComponent.PREF_KEY);
843
+ if (raw) {
844
+ try {
845
+ const prefs = JSON.parse(raw);
846
+ if (prefs.grid != null)
847
+ this.prefShowGrid = prefs.grid;
848
+ if (prefs.minimap != null)
849
+ this.prefShowMinimap = prefs.minimap;
850
+ if (prefs.legend != null)
851
+ this.prefShowLegend = prefs.legend;
852
+ }
853
+ catch {
854
+ // Ignore malformed preference data
855
+ }
856
+ }
857
+ }
858
+ saveViewPreferences() {
859
+ const prefs = JSON.stringify({
860
+ grid: this.prefShowGrid,
861
+ minimap: this.prefShowMinimap,
862
+ legend: this.prefShowLegend
863
+ });
864
+ // Fire-and-forget — preference save errors are non-critical
865
+ UserInfoEngine.Instance.SetSetting(FlowAgentEditorComponent.PREF_KEY, prefs);
866
+ }
867
+ onGridPrefChanged(show) {
868
+ this.prefShowGrid = show;
869
+ this.saveViewPreferences();
870
+ }
871
+ onMinimapPrefChanged(show) {
872
+ this.prefShowMinimap = show;
873
+ this.saveViewPreferences();
874
+ }
875
+ onLegendPrefChanged(show) {
876
+ this.prefShowLegend = show;
877
+ this.saveViewPreferences();
878
+ }
879
+ // ── Helpers ─────────────────────────────────────────────────
880
+ markDirty() {
881
+ if (!this.hasUnsavedChanges) {
882
+ this.hasUnsavedChanges = true;
883
+ this.FlowChanged.emit(true);
884
+ }
885
+ }
886
+ static ɵfac = function FlowAgentEditorComponent_Factory(__ngFactoryType__) { return new (__ngFactoryType__ || FlowAgentEditorComponent)(i0.ɵɵdirectiveInject(i0.ChangeDetectorRef), i0.ɵɵdirectiveInject(i1.AgentFlowTransformerService), i0.ɵɵdirectiveInject(i0.ElementRef), i0.ɵɵdirectiveInject(i0.Renderer2)); };
887
+ static ɵcmp = /*@__PURE__*/ i0.ɵɵdefineComponent({ type: FlowAgentEditorComponent, selectors: [["mj-flow-agent-editor"]], viewQuery: function FlowAgentEditorComponent_Query(rf, ctx) { if (rf & 1) {
888
+ i0.ɵɵviewQuery(_c0, 5);
889
+ } if (rf & 2) {
890
+ let _t;
891
+ i0.ɵɵqueryRefresh(_t = i0.ɵɵloadQuery()) && (ctx.flowEditor = _t.first);
892
+ } }, hostVars: 2, hostBindings: function FlowAgentEditorComponent_HostBindings(rf, ctx) { if (rf & 1) {
893
+ i0.ɵɵlistener("keydown.escape", function FlowAgentEditorComponent_keydown_escape_HostBindingHandler() { return ctx.onEscapeKey(); }, i0.ɵɵresolveDocument);
894
+ } if (rf & 2) {
895
+ i0.ɵɵclassProp("mj-flow-agent-editor--fullscreen", ctx.HostFullScreen);
896
+ } }, inputs: { AgentID: "AgentID", EditMode: "EditMode", FullScreen: "FullScreen" }, outputs: { FlowSaved: "FlowSaved", FlowChanged: "FlowChanged", FullScreenToggled: "FullScreenToggled", StepSelected: "StepSelected" }, standalone: false, features: [i0.ɵɵProvidersFeature([AgentFlowTransformerService]), i0.ɵɵNgOnChangesFeature], decls: 30, vars: 21, consts: [["flowEditor", ""], [1, "mj-agent-editor"], [1, "mj-agent-editor-toolbar"], [1, "mj-agent-editor-toolbar-left"], ["title", "Undo (Ctrl+Z)", 1, "mj-agent-editor-btn", 3, "disabled"], ["title", "Redo (Ctrl+Y)", 1, "mj-agent-editor-btn", 3, "disabled"], [1, "mj-agent-editor-toolbar-center"], [1, "mj-agent-editor-title"], [1, "fa-solid", "fa-diagram-project"], [1, "mj-agent-editor-view-toggle"], [1, "mj-agent-editor-view-btn", 3, "click"], [1, "fa-solid", "fa-list"], [1, "mj-agent-editor-mode-badge", "mj-agent-editor-mode-badge--editing"], [1, "mj-agent-editor-mode-badge", "mj-agent-editor-mode-badge--readonly"], [1, "mj-agent-editor-toolbar-right"], [1, "mj-agent-editor-status", "mj-agent-editor-status--unsaved"], [1, "mj-agent-editor-status"], [1, "mj-agent-editor-btn", "mj-agent-editor-btn--primary", 3, "disabled"], ["title", "Cancel editing", 1, "mj-agent-editor-btn"], [1, "mj-agent-editor-btn-divider"], ["title", "Edit flow", 1, "mj-agent-editor-btn", "mj-agent-editor-btn--edit"], ["title", "Expand to full screen", 1, "mj-agent-editor-btn", "mj-agent-editor-btn--expand"], ["title", "Close full screen (Esc)", 1, "mj-agent-editor-btn", "mj-agent-editor-btn--close"], [1, "mj-agent-editor-loading"], [1, "mj-agent-editor-body"], [1, "mj-agent-editor-dialog-overlay"], ["title", "Undo (Ctrl+Z)", 1, "mj-agent-editor-btn", 3, "click", "disabled"], [1, "fa-solid", "fa-rotate-left"], ["title", "Redo (Ctrl+Y)", 1, "mj-agent-editor-btn", 3, "click", "disabled"], [1, "fa-solid", "fa-rotate-right"], [1, "fa-solid", "fa-pen"], [1, "fa-solid", "fa-lock"], [1, "fa-solid", "fa-circle"], [1, "mj-agent-editor-btn", "mj-agent-editor-btn--primary", 3, "click", "disabled"], [1, "fa-solid", 3, "ngClass"], ["title", "Cancel editing", 1, "mj-agent-editor-btn", 3, "click"], [1, "fa-solid", "fa-xmark"], ["title", "Edit flow", 1, "mj-agent-editor-btn", "mj-agent-editor-btn--edit", 3, "click"], [1, "fa-solid", "fa-pen-to-square"], ["title", "Expand to full screen", 1, "mj-agent-editor-btn", "mj-agent-editor-btn--expand", 3, "click"], [1, "fa-solid", "fa-up-right-and-down-left-from-center"], ["title", "Close full screen (Esc)", 1, "mj-agent-editor-btn", "mj-agent-editor-btn--close", 3, "click"], [1, "fa-solid", "fa-spinner", "fa-spin"], [1, "mj-agent-editor-diagram"], [1, "mj-agent-editor-list"], [3, "NodeSelected", "NodeAdded", "NodeRemoved", "ConnectionCreated", "ConnectionRemoved", "ConnectionReassigned", "ConnectionSelected", "NodesChanged", "ConnectionsChanged", "GridToggled", "MinimapToggled", "LegendToggled", "Nodes", "Connections", "NodeTypes", "ReadOnly", "ShowMinimap", "ShowPalette", "ShowGrid", "ShowLegend", "ShowStatusBar", "ShowToolbar", "AutoLayoutDirection"], [1, "mj-agent-editor-properties"], [3, "StepChanged", "PathChanged", "DeleteStepRequested", "DeletePathRequested", "CloseRequested", "Step", "SelectedConnection", "PathEntity", "ReadOnly", "Actions", "Prompts", "Agents", "AllSteps"], [3, "StepClicked", "Steps", "Paths", "SelectedStepID"], [1, "mj-agent-editor-dialog"], [1, "mj-agent-editor-dialog-icon"], [1, "fa-solid", "fa-triangle-exclamation"], [1, "mj-agent-editor-dialog-title"], [1, "mj-agent-editor-dialog-message"], [1, "mj-agent-editor-dialog-actions"], [1, "mj-agent-editor-btn", "mj-agent-editor-btn--primary", 3, "click"], [1, "fa-solid", "fa-floppy-disk"], [1, "mj-agent-editor-btn", "mj-agent-editor-btn--danger-outline", 3, "click"], [1, "mj-agent-editor-btn", 3, "click"]], template: function FlowAgentEditorComponent_Template(rf, ctx) { if (rf & 1) {
897
+ i0.ɵɵelementStart(0, "div", 1)(1, "div", 2)(2, "div", 3);
898
+ i0.ɵɵconditionalCreate(3, FlowAgentEditorComponent_Conditional_3_Template, 2, 1, "button", 4);
899
+ i0.ɵɵconditionalCreate(4, FlowAgentEditorComponent_Conditional_4_Template, 2, 1, "button", 5);
900
+ i0.ɵɵelementEnd();
901
+ i0.ɵɵelementStart(5, "div", 6)(6, "span", 7);
902
+ i0.ɵɵelement(7, "i", 8);
903
+ i0.ɵɵtext(8, " Flow Configuration ");
904
+ i0.ɵɵelementEnd();
905
+ i0.ɵɵelementStart(9, "div", 9)(10, "button", 10);
906
+ i0.ɵɵlistener("click", function FlowAgentEditorComponent_Template_button_click_10_listener() { return ctx.viewMode = "diagram"; });
907
+ i0.ɵɵelement(11, "i", 8);
908
+ i0.ɵɵtext(12, " Diagram ");
909
+ i0.ɵɵelementEnd();
910
+ i0.ɵɵelementStart(13, "button", 10);
911
+ i0.ɵɵlistener("click", function FlowAgentEditorComponent_Template_button_click_13_listener() { return ctx.viewMode = "list"; });
912
+ i0.ɵɵelement(14, "i", 11);
913
+ i0.ɵɵtext(15, " List ");
914
+ i0.ɵɵelementEnd()();
915
+ i0.ɵɵconditionalCreate(16, FlowAgentEditorComponent_Conditional_16_Template, 3, 0, "span", 12);
916
+ i0.ɵɵconditionalCreate(17, FlowAgentEditorComponent_Conditional_17_Template, 3, 0, "span", 13);
917
+ i0.ɵɵelementEnd();
918
+ i0.ɵɵelementStart(18, "div", 14);
919
+ i0.ɵɵconditionalCreate(19, FlowAgentEditorComponent_Conditional_19_Template, 3, 0, "span", 15);
920
+ i0.ɵɵconditionalCreate(20, FlowAgentEditorComponent_Conditional_20_Template, 3, 4, "span", 16);
921
+ i0.ɵɵconditionalCreate(21, FlowAgentEditorComponent_Conditional_21_Template, 3, 3, "button", 17);
922
+ i0.ɵɵconditionalCreate(22, FlowAgentEditorComponent_Conditional_22_Template, 3, 0, "button", 18);
923
+ i0.ɵɵconditionalCreate(23, FlowAgentEditorComponent_Conditional_23_Template, 1, 0, "div", 19);
924
+ i0.ɵɵconditionalCreate(24, FlowAgentEditorComponent_Conditional_24_Template, 3, 0, "button", 20);
925
+ i0.ɵɵconditionalCreate(25, FlowAgentEditorComponent_Conditional_25_Template, 3, 0, "button", 21);
926
+ i0.ɵɵconditionalCreate(26, FlowAgentEditorComponent_Conditional_26_Template, 3, 0, "button", 22);
927
+ i0.ɵɵelementEnd()();
928
+ i0.ɵɵconditionalCreate(27, FlowAgentEditorComponent_Conditional_27_Template, 4, 0, "div", 23);
929
+ i0.ɵɵconditionalCreate(28, FlowAgentEditorComponent_Conditional_28_Template, 3, 2, "div", 24);
930
+ i0.ɵɵconditionalCreate(29, FlowAgentEditorComponent_Conditional_29_Template, 16, 0, "div", 25);
931
+ i0.ɵɵelementEnd();
932
+ } if (rf & 2) {
933
+ i0.ɵɵadvance();
934
+ i0.ɵɵclassProp("mj-agent-editor-toolbar--editing", ctx.isEditingActive);
935
+ i0.ɵɵadvance(2);
936
+ i0.ɵɵconditional(ctx.isEditingActive ? 3 : -1);
937
+ i0.ɵɵadvance();
938
+ i0.ɵɵconditional(ctx.isEditingActive ? 4 : -1);
939
+ i0.ɵɵadvance(6);
940
+ i0.ɵɵclassProp("mj-agent-editor-view-btn--active", ctx.viewMode === "diagram");
941
+ i0.ɵɵadvance(3);
942
+ i0.ɵɵclassProp("mj-agent-editor-view-btn--active", ctx.viewMode === "list");
943
+ i0.ɵɵadvance(3);
944
+ i0.ɵɵconditional(ctx.isEditingActive ? 16 : -1);
945
+ i0.ɵɵadvance();
946
+ i0.ɵɵconditional(!ctx.isEditingActive ? 17 : -1);
947
+ i0.ɵɵadvance(2);
948
+ i0.ɵɵconditional(ctx.hasUnsavedChanges ? 19 : -1);
949
+ i0.ɵɵadvance();
950
+ i0.ɵɵconditional(ctx.lastSaved ? 20 : -1);
951
+ i0.ɵɵadvance();
952
+ i0.ɵɵconditional(ctx.isEditingActive ? 21 : -1);
953
+ i0.ɵɵadvance();
954
+ i0.ɵɵconditional(ctx.fullscreenEditMode && !ctx.EditMode ? 22 : -1);
955
+ i0.ɵɵadvance();
956
+ i0.ɵɵconditional(ctx.isEditingActive ? 23 : -1);
957
+ i0.ɵɵadvance();
958
+ i0.ɵɵconditional(!ctx.EditMode && !ctx.fullscreenEditMode && ctx.userCanUpdate ? 24 : -1);
959
+ i0.ɵɵadvance();
960
+ i0.ɵɵconditional(!ctx.FullScreen ? 25 : -1);
961
+ i0.ɵɵadvance();
962
+ i0.ɵɵconditional(ctx.FullScreen ? 26 : -1);
963
+ i0.ɵɵadvance();
964
+ i0.ɵɵconditional(ctx.isLoading ? 27 : -1);
965
+ i0.ɵɵadvance();
966
+ i0.ɵɵconditional(!ctx.isLoading ? 28 : -1);
967
+ i0.ɵɵadvance();
968
+ i0.ɵɵconditional(ctx.showUnsavedDialog ? 29 : -1);
969
+ } }, dependencies: [i2.NgClass, i3.FlowEditorComponent, i4.AgentPropertiesPanelComponent, i5.AgentStepListComponent, i2.DatePipe], styles: ["/* ============================================================\n Flow Agent Editor \u2014 MJ-specific flow editor wrapper\n ============================================================ */\n\n/* \u2500\u2500 Host element fullscreen positioning \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */\n\nmj-flow-agent-editor.mj-flow-agent-editor--fullscreen {\n position: fixed;\n top: 12px;\n left: 12px;\n right: 12px;\n padding-right: 25px;\n bottom: 12px;\n z-index: 10000;\n border-radius: 10px;\n height: auto !important;\n min-height: unset !important;\n box-shadow: 0 25px 60px rgba(0, 0, 0, 0.3), 0 0 0 1px rgba(0, 0, 0, 0.08);\n}\n\nmj-flow-agent-editor.mj-flow-agent-editor--fullscreen .mj-agent-editor {\n height: 100%;\n min-height: unset;\n border-radius: 10px;\n}\n\n.mj-agent-editor {\n display: flex;\n flex-direction: column;\n width: 100%;\n height: 100%;\n min-height: 500px;\n background: #f8fafc;\n border-radius: 8px;\n overflow: hidden;\n position: relative;\n}\n\n/* \u2500\u2500 Backdrop overlay \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */\n\n.mj-agent-editor-backdrop {\n position: fixed;\n top: 0;\n left: 0;\n right: 0;\n bottom: 0;\n background: rgba(0, 0, 0, 0.5);\n z-index: 9999;\n}\n\n/* \u2500\u2500 Toolbar \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */\n\n.mj-agent-editor-toolbar {\n display: flex;\n align-items: center;\n justify-content: space-between;\n padding: 8px 12px;\n background: #ffffff;\n border-bottom: 1px solid #e2e8f0;\n gap: 12px;\n flex-shrink: 0;\n transition: background 0.2s ease, border-color 0.2s ease;\n}\n\n.mj-agent-editor-toolbar--editing {\n background: linear-gradient(135deg, #f0fdf4 0%, #ecfdf5 50%, #f0fdf4 100%);\n border-bottom-color: #bbf7d0;\n}\n\n.mj-flow-agent-editor--fullscreen .mj-agent-editor-toolbar {\n padding: 10px 16px;\n border-bottom: 1px solid #e2e8f0;\n background: #ffffff;\n border-radius: 10px 10px 0 0;\n}\n\n.mj-flow-agent-editor--fullscreen .mj-agent-editor-toolbar--editing {\n background: linear-gradient(135deg, #f0fdf4 0%, #ecfdf5 50%, #f0fdf4 100%);\n border-bottom-color: #bbf7d0;\n}\n\n.mj-agent-editor-toolbar-left,\n.mj-agent-editor-toolbar-center,\n.mj-agent-editor-toolbar-right {\n display: flex;\n align-items: center;\n gap: 6px;\n}\n\n.mj-agent-editor-toolbar-right {\n gap: 10px;\n}\n\n.mj-agent-editor-btn {\n display: inline-flex;\n align-items: center;\n gap: 6px;\n padding: 6px 10px;\n border: 1px solid #e2e8f0;\n border-radius: 6px;\n background: #ffffff;\n color: #475569;\n font-size: 13px;\n font-weight: 500;\n cursor: pointer;\n transition: all 0.15s ease;\n white-space: nowrap;\n}\n\n.mj-agent-editor-btn i { font-size: 12px; }\n\n.mj-agent-editor-btn:hover:not(:disabled) { background: #f1f5f9; border-color: #cbd5e1; }\n.mj-agent-editor-btn:disabled { opacity: 0.4; cursor: not-allowed; }\n\n.mj-agent-editor-btn--primary {\n background: #3b82f6;\n border-color: #3b82f6;\n color: #ffffff;\n}\n\n.mj-agent-editor-btn--primary:hover:not(:disabled) { background: #2563eb; border-color: #2563eb; }\n\n.mj-agent-editor-btn--expand {\n background: #f0f9ff;\n border-color: #bae6fd;\n color: #0284c7;\n}\n\n.mj-agent-editor-btn--expand:hover:not(:disabled) { background: #e0f2fe; border-color: #7dd3fc; color: #0369a1; }\n\n.mj-agent-editor-btn--close {\n background: #fef2f2;\n border-color: #fecaca;\n color: #dc2626;\n}\n\n.mj-agent-editor-btn--close:hover:not(:disabled) { background: #fee2e2; border-color: #fca5a5; color: #b91c1c; }\n\n.mj-agent-editor-btn-divider {\n width: 1px;\n height: 22px;\n background: #e2e8f0;\n margin: 0 2px;\n}\n\n/* \u2500\u2500 View Toggle \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */\n\n.mj-agent-editor-view-toggle {\n display: flex;\n border: 1px solid #e2e8f0;\n border-radius: 6px;\n overflow: hidden;\n}\n\n.mj-agent-editor-view-btn {\n display: inline-flex;\n align-items: center;\n gap: 6px;\n padding: 5px 12px;\n border: none;\n background: #ffffff;\n color: #64748b;\n font-size: 12px;\n font-weight: 500;\n cursor: pointer;\n transition: all 0.15s ease;\n}\n\n.mj-agent-editor-view-btn i { font-size: 11px; }\n\n.mj-agent-editor-view-btn:not(:last-child) { border-right: 1px solid #e2e8f0; }\n\n.mj-agent-editor-view-btn--active {\n background: #eff6ff;\n color: #3b82f6;\n}\n\n.mj-agent-editor-view-btn:hover:not(.mj-agent-editor-view-btn--active) { background: #f8fafc; }\n\n/* \u2500\u2500 Fullscreen Title \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */\n\n.mj-agent-editor-title {\n font-size: 14px;\n font-weight: 600;\n color: #1e293b;\n display: inline-flex;\n align-items: center;\n gap: 8px;\n margin-right: 12px;\n}\n\n.mj-agent-editor-title i {\n color: #3b82f6;\n font-size: 14px;\n}\n\n/* \u2500\u2500 Status Indicators \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */\n\n.mj-agent-editor-status {\n font-size: 12px;\n color: #94a3b8;\n display: inline-flex;\n align-items: center;\n gap: 4px;\n}\n\n.mj-agent-editor-status--unsaved {\n color: #f59e0b;\n}\n\n.mj-agent-editor-status--unsaved i { font-size: 6px; }\n\n/* \u2500\u2500 Inline Floating Controls (non-fullscreen) \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */\n\n.mj-agent-editor-inline-controls {\n position: absolute;\n top: 8px;\n right: 8px;\n z-index: 100;\n display: flex;\n align-items: center;\n gap: 6px;\n}\n\n.mj-agent-editor-inline-expand {\n display: flex;\n align-items: center;\n justify-content: center;\n width: 30px;\n height: 30px;\n border: 1px solid rgba(0, 0, 0, 0.12);\n border-radius: 6px;\n background: rgba(255, 255, 255, 0.85);\n color: #475569;\n font-size: 12px;\n cursor: pointer;\n transition: all 0.15s ease;\n box-shadow: 0 1px 4px rgba(0, 0, 0, 0.08);\n backdrop-filter: blur(4px);\n}\n\n.mj-agent-editor-inline-expand:hover {\n background: #ffffff;\n border-color: #94a3b8;\n color: #1e293b;\n box-shadow: 0 2px 8px rgba(0, 0, 0, 0.12);\n transform: scale(1.05);\n}\n\n.mj-agent-editor-inline-dot {\n width: 8px;\n height: 8px;\n border-radius: 50%;\n background: #f59e0b;\n box-shadow: 0 0 0 2px rgba(255, 255, 255, 0.9), 0 0 6px rgba(245, 158, 11, 0.4);\n animation: mj-inline-dot-pulse 2s ease-in-out infinite;\n}\n\n@keyframes mj-inline-dot-pulse {\n 0%, 100% { opacity: 1; }\n 50% { opacity: 0.5; }\n}\n\n/* \u2500\u2500 Loading \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */\n\n.mj-agent-editor-loading {\n display: flex;\n align-items: center;\n justify-content: center;\n gap: 10px;\n flex: 1;\n font-size: 14px;\n color: #64748b;\n}\n\n.mj-agent-editor-loading i { font-size: 16px; }\n\n/* \u2500\u2500 Body \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */\n\n.mj-agent-editor-body {\n flex: 1;\n overflow: hidden;\n display: flex;\n flex-direction: column;\n}\n\n.mj-agent-editor-diagram {\n display: flex;\n flex: 1;\n overflow: hidden;\n position: relative;\n}\n\n.mj-agent-editor-diagram mj-flow-editor {\n flex: 1;\n display: flex;\n}\n\n.mj-agent-editor-list {\n display: flex;\n flex: 1;\n overflow: hidden;\n}\n\n.mj-agent-editor-list mj-agent-step-list {\n flex: 1;\n overflow-y: auto;\n}\n\n/* \u2500\u2500 Properties Panel \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */\n\n.mj-agent-editor-properties {\n width: 320px;\n flex-shrink: 0;\n overflow: hidden;\n transform: translateX(320px);\n margin-right: -320px;\n transition: transform 0.2s ease, margin-right 0.2s ease;\n border-left: 1px solid #e2e8f0;\n}\n\n.mj-agent-editor-properties--visible {\n transform: translateX(0);\n margin-right: 0;\n}\n\n.mj-agent-editor-properties mj-agent-properties-panel {\n display: block;\n width: 320px;\n height: 100%;\n}\n\n/* \u2500\u2500 Mode Indicator Badge \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */\n\n.mj-agent-editor-mode-badge {\n display: inline-flex;\n align-items: center;\n gap: 5px;\n font-size: 11px;\n font-weight: 600;\n padding: 3px 10px;\n border-radius: 12px;\n letter-spacing: 0.2px;\n}\n\n.mj-agent-editor-mode-badge i { font-size: 10px; }\n\n.mj-agent-editor-mode-badge--editing {\n background: #ecfdf5;\n color: #059669;\n}\n\n.mj-agent-editor-mode-badge--readonly {\n background: #f1f5f9;\n color: #64748b;\n}\n\n/* \u2500\u2500 Edit Button \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */\n\n.mj-agent-editor-btn--edit {\n background: #ecfdf5;\n border-color: #a7f3d0;\n color: #059669;\n}\n\n.mj-agent-editor-btn--edit:hover:not(:disabled) {\n background: #d1fae5;\n border-color: #6ee7b7;\n color: #047857;\n}\n\n/* \u2500\u2500 Danger Outline Button \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */\n\n.mj-agent-editor-btn--danger-outline {\n border-color: #fecaca;\n color: #dc2626;\n background: #ffffff;\n}\n\n.mj-agent-editor-btn--danger-outline:hover:not(:disabled) {\n background: #fef2f2;\n border-color: #fca5a5;\n}\n\n/* \u2500\u2500 Unsaved Changes Dialog \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */\n\n.mj-agent-editor-dialog-overlay {\n position: absolute;\n top: 0;\n left: 0;\n right: 0;\n bottom: 0;\n background: rgba(0, 0, 0, 0.4);\n display: flex;\n align-items: center;\n justify-content: center;\n z-index: 10001;\n animation: mj-dialog-fade-in 0.15s ease-out;\n}\n\n@keyframes mj-dialog-fade-in {\n from { opacity: 0; }\n to { opacity: 1; }\n}\n\n.mj-agent-editor-dialog {\n background: #ffffff;\n border-radius: 12px;\n padding: 28px 32px;\n max-width: 400px;\n width: 90%;\n box-shadow: 0 20px 50px rgba(0, 0, 0, 0.2), 0 0 0 1px rgba(0, 0, 0, 0.05);\n text-align: center;\n animation: mj-dialog-scale-in 0.15s ease-out;\n}\n\n@keyframes mj-dialog-scale-in {\n from { transform: scale(0.95); opacity: 0; }\n to { transform: scale(1); opacity: 1; }\n}\n\n.mj-agent-editor-dialog-icon {\n font-size: 28px;\n color: #f59e0b;\n margin-bottom: 12px;\n}\n\n.mj-agent-editor-dialog-title {\n font-size: 16px;\n font-weight: 600;\n color: #1e293b;\n margin: 0 0 8px;\n}\n\n.mj-agent-editor-dialog-message {\n font-size: 13px;\n color: #64748b;\n margin: 0 0 20px;\n line-height: 1.5;\n}\n\n.mj-agent-editor-dialog-actions {\n display: flex;\n gap: 8px;\n justify-content: center;\n flex-wrap: wrap;\n}\n"], encapsulation: 2 });
970
+ }
971
+ (() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassMetadata(FlowAgentEditorComponent, [{
972
+ type: Component,
973
+ args: [{ standalone: false, selector: 'mj-flow-agent-editor', encapsulation: ViewEncapsulation.None, providers: [AgentFlowTransformerService], template: "<div class=\"mj-agent-editor\">\n\n <!-- \u2500\u2500 Toolbar \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 -->\n <div class=\"mj-agent-editor-toolbar\" [class.mj-agent-editor-toolbar--editing]=\"isEditingActive\">\n <div class=\"mj-agent-editor-toolbar-left\">\n <!-- Undo / Redo (edit mode only) -->\n @if (isEditingActive) {\n <button class=\"mj-agent-editor-btn\"\n [disabled]=\"!flowEditor?.CanUndo\" (click)=\"flowEditor?.Undo()\" title=\"Undo (Ctrl+Z)\">\n <i class=\"fa-solid fa-rotate-left\"></i>\n </button>\n }\n @if (isEditingActive) {\n <button class=\"mj-agent-editor-btn\"\n [disabled]=\"!flowEditor?.CanRedo\" (click)=\"flowEditor?.Redo()\" title=\"Redo (Ctrl+Y)\">\n <i class=\"fa-solid fa-rotate-right\"></i>\n </button>\n }\n </div>\n\n <div class=\"mj-agent-editor-toolbar-center\">\n <!-- Fullscreen title -->\n <span class=\"mj-agent-editor-title\">\n <i class=\"fa-solid fa-diagram-project\"></i> Flow Configuration\n </span>\n\n <!-- View Mode Toggle -->\n <div class=\"mj-agent-editor-view-toggle\">\n <button class=\"mj-agent-editor-view-btn\"\n [class.mj-agent-editor-view-btn--active]=\"viewMode === 'diagram'\"\n (click)=\"viewMode = 'diagram'\">\n <i class=\"fa-solid fa-diagram-project\"></i> Diagram\n </button>\n <button class=\"mj-agent-editor-view-btn\"\n [class.mj-agent-editor-view-btn--active]=\"viewMode === 'list'\"\n (click)=\"viewMode = 'list'\">\n <i class=\"fa-solid fa-list\"></i> List\n </button>\n </div>\n\n <!-- Mode indicator badge -->\n @if (isEditingActive) {\n <span class=\"mj-agent-editor-mode-badge mj-agent-editor-mode-badge--editing\">\n <i class=\"fa-solid fa-pen\"></i> Editing\n </span>\n }\n @if (!isEditingActive) {\n <span class=\"mj-agent-editor-mode-badge mj-agent-editor-mode-badge--readonly\">\n <i class=\"fa-solid fa-lock\"></i> Read Only\n </span>\n }\n </div>\n\n <div class=\"mj-agent-editor-toolbar-right\">\n <!-- Status indicators -->\n @if (hasUnsavedChanges) {\n <span class=\"mj-agent-editor-status mj-agent-editor-status--unsaved\">\n <i class=\"fa-solid fa-circle\"></i> Unsaved\n </span>\n }\n @if (lastSaved) {\n <span class=\"mj-agent-editor-status\">\n Saved {{ lastSaved | date:'shortTime' }}\n </span>\n }\n\n <!-- Save + Cancel (when editing) -->\n @if (isEditingActive) {\n <button class=\"mj-agent-editor-btn mj-agent-editor-btn--primary\"\n [disabled]=\"isSaving || !hasUnsavedChanges\" (click)=\"Save()\">\n <i class=\"fa-solid\" [ngClass]=\"isSaving ? 'fa-spinner fa-spin' : 'fa-floppy-disk'\"></i>\n {{ isSaving ? 'Saving...' : 'Save' }}\n </button>\n }\n @if (fullscreenEditMode && !EditMode) {\n <button\n class=\"mj-agent-editor-btn\"\n (click)=\"cancelFullscreenEdit()\" title=\"Cancel editing\">\n <i class=\"fa-solid fa-xmark\"></i> Cancel\n </button>\n }\n\n @if (isEditingActive) {\n <div class=\"mj-agent-editor-btn-divider\"></div>\n }\n\n <!-- Fullscreen edit toggle (only when parent is NOT in edit mode) -->\n @if (!EditMode && !fullscreenEditMode && userCanUpdate) {\n <button\n class=\"mj-agent-editor-btn mj-agent-editor-btn--edit\"\n (click)=\"toggleFullscreenEditMode()\" title=\"Edit flow\">\n <i class=\"fa-solid fa-pen-to-square\"></i> Edit\n </button>\n }\n\n <!-- Expand / Close fullscreen -->\n @if (!FullScreen) {\n <button class=\"mj-agent-editor-btn mj-agent-editor-btn--expand\"\n (click)=\"toggleFullScreen()\" title=\"Expand to full screen\">\n <i class=\"fa-solid fa-up-right-and-down-left-from-center\"></i> Expand\n </button>\n }\n @if (FullScreen) {\n <button class=\"mj-agent-editor-btn mj-agent-editor-btn--close\"\n (click)=\"toggleFullScreen()\" title=\"Close full screen (Esc)\">\n <i class=\"fa-solid fa-xmark\"></i> Close\n </button>\n }\n </div>\n </div>\n\n <!-- \u2500\u2500 Loading State \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 -->\n @if (isLoading) {\n <div class=\"mj-agent-editor-loading\">\n <i class=\"fa-solid fa-spinner fa-spin\"></i>\n <span>Loading flow...</span>\n </div>\n }\n\n <!-- \u2500\u2500 Main Content \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 -->\n @if (!isLoading) {\n <div class=\"mj-agent-editor-body\">\n <!-- Diagram View -->\n @if (viewMode === 'diagram') {\n <div class=\"mj-agent-editor-diagram\">\n <mj-flow-editor #flowEditor\n [Nodes]=\"nodes\"\n [Connections]=\"connections\"\n [NodeTypes]=\"nodeTypes\"\n [ReadOnly]=\"!isEditingActive\"\n [ShowMinimap]=\"prefShowMinimap\"\n [ShowPalette]=\"isEditingActive\"\n [ShowGrid]=\"prefShowGrid\"\n [ShowLegend]=\"prefShowLegend\"\n [ShowStatusBar]=\"true\"\n [ShowToolbar]=\"true\"\n [AutoLayoutDirection]=\"'vertical'\"\n (NodeSelected)=\"onNodeSelected($event)\"\n (NodeAdded)=\"onNodeAdded($event)\"\n (NodeRemoved)=\"onNodeRemoved($event)\"\n (ConnectionCreated)=\"onConnectionCreated($event)\"\n (ConnectionRemoved)=\"onConnectionRemoved($event)\"\n (ConnectionReassigned)=\"onConnectionReassigned($event)\"\n (ConnectionSelected)=\"onConnectionSelected($event)\"\n (NodesChanged)=\"onNodesChanged($event)\"\n (ConnectionsChanged)=\"onConnectionsChanged($event)\"\n (GridToggled)=\"onGridPrefChanged($event)\"\n (MinimapToggled)=\"onMinimapPrefChanged($event)\"\n (LegendToggled)=\"onLegendPrefChanged($event)\">\n </mj-flow-editor>\n <!-- Properties Panel -->\n <div class=\"mj-agent-editor-properties\"\n [class.mj-agent-editor-properties--visible]=\"showPropertiesPanel\">\n <mj-agent-properties-panel\n [Step]=\"selectedStep\"\n [SelectedConnection]=\"selectedConnection\"\n [PathEntity]=\"selectedPathEntity\"\n [ReadOnly]=\"!isEditingActive\"\n [Actions]=\"availableActions\"\n [Prompts]=\"availablePrompts\"\n [Agents]=\"availableAgents\"\n [AllSteps]=\"steps\"\n (StepChanged)=\"onStepChanged($event)\"\n (PathChanged)=\"onPathChanged($event)\"\n (DeleteStepRequested)=\"onDeleteStepRequested($event)\"\n (DeletePathRequested)=\"onDeletePathRequested($event)\"\n (CloseRequested)=\"onCloseProperties()\">\n </mj-agent-properties-panel>\n </div>\n </div>\n }\n <!-- List View -->\n @if (viewMode === 'list') {\n <div class=\"mj-agent-editor-list\">\n <mj-agent-step-list\n [Steps]=\"steps\"\n [Paths]=\"paths\"\n [SelectedStepID]=\"selectedStep?.ID || null\"\n (StepClicked)=\"onStepClickedInList($event)\">\n </mj-agent-step-list>\n <!-- Properties Panel in list mode too -->\n <div class=\"mj-agent-editor-properties\"\n [class.mj-agent-editor-properties--visible]=\"showPropertiesPanel\">\n <mj-agent-properties-panel\n [Step]=\"selectedStep\"\n [SelectedConnection]=\"selectedConnection\"\n [PathEntity]=\"selectedPathEntity\"\n [ReadOnly]=\"!isEditingActive\"\n [Actions]=\"availableActions\"\n [Prompts]=\"availablePrompts\"\n [Agents]=\"availableAgents\"\n [AllSteps]=\"steps\"\n (StepChanged)=\"onStepChanged($event)\"\n (PathChanged)=\"onPathChanged($event)\"\n (DeleteStepRequested)=\"onDeleteStepRequested($event)\"\n (DeletePathRequested)=\"onDeletePathRequested($event)\"\n (CloseRequested)=\"onCloseProperties()\">\n </mj-agent-properties-panel>\n </div>\n </div>\n }\n </div>\n }\n\n <!-- \u2500\u2500 Unsaved Changes Dialog \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 -->\n @if (showUnsavedDialog) {\n <div class=\"mj-agent-editor-dialog-overlay\">\n <div class=\"mj-agent-editor-dialog\">\n <div class=\"mj-agent-editor-dialog-icon\">\n <i class=\"fa-solid fa-triangle-exclamation\"></i>\n </div>\n <h3 class=\"mj-agent-editor-dialog-title\">Unsaved Changes</h3>\n <p class=\"mj-agent-editor-dialog-message\">\n You have unsaved changes to this flow. What would you like to do?\n </p>\n <div class=\"mj-agent-editor-dialog-actions\">\n <button class=\"mj-agent-editor-btn mj-agent-editor-btn--primary\" (click)=\"onUnsavedDialogSave()\">\n <i class=\"fa-solid fa-floppy-disk\"></i> Save & Close\n </button>\n <button class=\"mj-agent-editor-btn mj-agent-editor-btn--danger-outline\" (click)=\"onUnsavedDialogDiscard()\">\n Discard Changes\n </button>\n <button class=\"mj-agent-editor-btn\" (click)=\"onUnsavedDialogCancel()\">\n Cancel\n </button>\n </div>\n </div>\n </div>\n }\n</div>\n", styles: ["/* ============================================================\n Flow Agent Editor \u2014 MJ-specific flow editor wrapper\n ============================================================ */\n\n/* \u2500\u2500 Host element fullscreen positioning \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */\n\nmj-flow-agent-editor.mj-flow-agent-editor--fullscreen {\n position: fixed;\n top: 12px;\n left: 12px;\n right: 12px;\n padding-right: 25px;\n bottom: 12px;\n z-index: 10000;\n border-radius: 10px;\n height: auto !important;\n min-height: unset !important;\n box-shadow: 0 25px 60px rgba(0, 0, 0, 0.3), 0 0 0 1px rgba(0, 0, 0, 0.08);\n}\n\nmj-flow-agent-editor.mj-flow-agent-editor--fullscreen .mj-agent-editor {\n height: 100%;\n min-height: unset;\n border-radius: 10px;\n}\n\n.mj-agent-editor {\n display: flex;\n flex-direction: column;\n width: 100%;\n height: 100%;\n min-height: 500px;\n background: #f8fafc;\n border-radius: 8px;\n overflow: hidden;\n position: relative;\n}\n\n/* \u2500\u2500 Backdrop overlay \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */\n\n.mj-agent-editor-backdrop {\n position: fixed;\n top: 0;\n left: 0;\n right: 0;\n bottom: 0;\n background: rgba(0, 0, 0, 0.5);\n z-index: 9999;\n}\n\n/* \u2500\u2500 Toolbar \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */\n\n.mj-agent-editor-toolbar {\n display: flex;\n align-items: center;\n justify-content: space-between;\n padding: 8px 12px;\n background: #ffffff;\n border-bottom: 1px solid #e2e8f0;\n gap: 12px;\n flex-shrink: 0;\n transition: background 0.2s ease, border-color 0.2s ease;\n}\n\n.mj-agent-editor-toolbar--editing {\n background: linear-gradient(135deg, #f0fdf4 0%, #ecfdf5 50%, #f0fdf4 100%);\n border-bottom-color: #bbf7d0;\n}\n\n.mj-flow-agent-editor--fullscreen .mj-agent-editor-toolbar {\n padding: 10px 16px;\n border-bottom: 1px solid #e2e8f0;\n background: #ffffff;\n border-radius: 10px 10px 0 0;\n}\n\n.mj-flow-agent-editor--fullscreen .mj-agent-editor-toolbar--editing {\n background: linear-gradient(135deg, #f0fdf4 0%, #ecfdf5 50%, #f0fdf4 100%);\n border-bottom-color: #bbf7d0;\n}\n\n.mj-agent-editor-toolbar-left,\n.mj-agent-editor-toolbar-center,\n.mj-agent-editor-toolbar-right {\n display: flex;\n align-items: center;\n gap: 6px;\n}\n\n.mj-agent-editor-toolbar-right {\n gap: 10px;\n}\n\n.mj-agent-editor-btn {\n display: inline-flex;\n align-items: center;\n gap: 6px;\n padding: 6px 10px;\n border: 1px solid #e2e8f0;\n border-radius: 6px;\n background: #ffffff;\n color: #475569;\n font-size: 13px;\n font-weight: 500;\n cursor: pointer;\n transition: all 0.15s ease;\n white-space: nowrap;\n}\n\n.mj-agent-editor-btn i { font-size: 12px; }\n\n.mj-agent-editor-btn:hover:not(:disabled) { background: #f1f5f9; border-color: #cbd5e1; }\n.mj-agent-editor-btn:disabled { opacity: 0.4; cursor: not-allowed; }\n\n.mj-agent-editor-btn--primary {\n background: #3b82f6;\n border-color: #3b82f6;\n color: #ffffff;\n}\n\n.mj-agent-editor-btn--primary:hover:not(:disabled) { background: #2563eb; border-color: #2563eb; }\n\n.mj-agent-editor-btn--expand {\n background: #f0f9ff;\n border-color: #bae6fd;\n color: #0284c7;\n}\n\n.mj-agent-editor-btn--expand:hover:not(:disabled) { background: #e0f2fe; border-color: #7dd3fc; color: #0369a1; }\n\n.mj-agent-editor-btn--close {\n background: #fef2f2;\n border-color: #fecaca;\n color: #dc2626;\n}\n\n.mj-agent-editor-btn--close:hover:not(:disabled) { background: #fee2e2; border-color: #fca5a5; color: #b91c1c; }\n\n.mj-agent-editor-btn-divider {\n width: 1px;\n height: 22px;\n background: #e2e8f0;\n margin: 0 2px;\n}\n\n/* \u2500\u2500 View Toggle \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */\n\n.mj-agent-editor-view-toggle {\n display: flex;\n border: 1px solid #e2e8f0;\n border-radius: 6px;\n overflow: hidden;\n}\n\n.mj-agent-editor-view-btn {\n display: inline-flex;\n align-items: center;\n gap: 6px;\n padding: 5px 12px;\n border: none;\n background: #ffffff;\n color: #64748b;\n font-size: 12px;\n font-weight: 500;\n cursor: pointer;\n transition: all 0.15s ease;\n}\n\n.mj-agent-editor-view-btn i { font-size: 11px; }\n\n.mj-agent-editor-view-btn:not(:last-child) { border-right: 1px solid #e2e8f0; }\n\n.mj-agent-editor-view-btn--active {\n background: #eff6ff;\n color: #3b82f6;\n}\n\n.mj-agent-editor-view-btn:hover:not(.mj-agent-editor-view-btn--active) { background: #f8fafc; }\n\n/* \u2500\u2500 Fullscreen Title \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */\n\n.mj-agent-editor-title {\n font-size: 14px;\n font-weight: 600;\n color: #1e293b;\n display: inline-flex;\n align-items: center;\n gap: 8px;\n margin-right: 12px;\n}\n\n.mj-agent-editor-title i {\n color: #3b82f6;\n font-size: 14px;\n}\n\n/* \u2500\u2500 Status Indicators \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */\n\n.mj-agent-editor-status {\n font-size: 12px;\n color: #94a3b8;\n display: inline-flex;\n align-items: center;\n gap: 4px;\n}\n\n.mj-agent-editor-status--unsaved {\n color: #f59e0b;\n}\n\n.mj-agent-editor-status--unsaved i { font-size: 6px; }\n\n/* \u2500\u2500 Inline Floating Controls (non-fullscreen) \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */\n\n.mj-agent-editor-inline-controls {\n position: absolute;\n top: 8px;\n right: 8px;\n z-index: 100;\n display: flex;\n align-items: center;\n gap: 6px;\n}\n\n.mj-agent-editor-inline-expand {\n display: flex;\n align-items: center;\n justify-content: center;\n width: 30px;\n height: 30px;\n border: 1px solid rgba(0, 0, 0, 0.12);\n border-radius: 6px;\n background: rgba(255, 255, 255, 0.85);\n color: #475569;\n font-size: 12px;\n cursor: pointer;\n transition: all 0.15s ease;\n box-shadow: 0 1px 4px rgba(0, 0, 0, 0.08);\n backdrop-filter: blur(4px);\n}\n\n.mj-agent-editor-inline-expand:hover {\n background: #ffffff;\n border-color: #94a3b8;\n color: #1e293b;\n box-shadow: 0 2px 8px rgba(0, 0, 0, 0.12);\n transform: scale(1.05);\n}\n\n.mj-agent-editor-inline-dot {\n width: 8px;\n height: 8px;\n border-radius: 50%;\n background: #f59e0b;\n box-shadow: 0 0 0 2px rgba(255, 255, 255, 0.9), 0 0 6px rgba(245, 158, 11, 0.4);\n animation: mj-inline-dot-pulse 2s ease-in-out infinite;\n}\n\n@keyframes mj-inline-dot-pulse {\n 0%, 100% { opacity: 1; }\n 50% { opacity: 0.5; }\n}\n\n/* \u2500\u2500 Loading \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */\n\n.mj-agent-editor-loading {\n display: flex;\n align-items: center;\n justify-content: center;\n gap: 10px;\n flex: 1;\n font-size: 14px;\n color: #64748b;\n}\n\n.mj-agent-editor-loading i { font-size: 16px; }\n\n/* \u2500\u2500 Body \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */\n\n.mj-agent-editor-body {\n flex: 1;\n overflow: hidden;\n display: flex;\n flex-direction: column;\n}\n\n.mj-agent-editor-diagram {\n display: flex;\n flex: 1;\n overflow: hidden;\n position: relative;\n}\n\n.mj-agent-editor-diagram mj-flow-editor {\n flex: 1;\n display: flex;\n}\n\n.mj-agent-editor-list {\n display: flex;\n flex: 1;\n overflow: hidden;\n}\n\n.mj-agent-editor-list mj-agent-step-list {\n flex: 1;\n overflow-y: auto;\n}\n\n/* \u2500\u2500 Properties Panel \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */\n\n.mj-agent-editor-properties {\n width: 320px;\n flex-shrink: 0;\n overflow: hidden;\n transform: translateX(320px);\n margin-right: -320px;\n transition: transform 0.2s ease, margin-right 0.2s ease;\n border-left: 1px solid #e2e8f0;\n}\n\n.mj-agent-editor-properties--visible {\n transform: translateX(0);\n margin-right: 0;\n}\n\n.mj-agent-editor-properties mj-agent-properties-panel {\n display: block;\n width: 320px;\n height: 100%;\n}\n\n/* \u2500\u2500 Mode Indicator Badge \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */\n\n.mj-agent-editor-mode-badge {\n display: inline-flex;\n align-items: center;\n gap: 5px;\n font-size: 11px;\n font-weight: 600;\n padding: 3px 10px;\n border-radius: 12px;\n letter-spacing: 0.2px;\n}\n\n.mj-agent-editor-mode-badge i { font-size: 10px; }\n\n.mj-agent-editor-mode-badge--editing {\n background: #ecfdf5;\n color: #059669;\n}\n\n.mj-agent-editor-mode-badge--readonly {\n background: #f1f5f9;\n color: #64748b;\n}\n\n/* \u2500\u2500 Edit Button \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */\n\n.mj-agent-editor-btn--edit {\n background: #ecfdf5;\n border-color: #a7f3d0;\n color: #059669;\n}\n\n.mj-agent-editor-btn--edit:hover:not(:disabled) {\n background: #d1fae5;\n border-color: #6ee7b7;\n color: #047857;\n}\n\n/* \u2500\u2500 Danger Outline Button \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */\n\n.mj-agent-editor-btn--danger-outline {\n border-color: #fecaca;\n color: #dc2626;\n background: #ffffff;\n}\n\n.mj-agent-editor-btn--danger-outline:hover:not(:disabled) {\n background: #fef2f2;\n border-color: #fca5a5;\n}\n\n/* \u2500\u2500 Unsaved Changes Dialog \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */\n\n.mj-agent-editor-dialog-overlay {\n position: absolute;\n top: 0;\n left: 0;\n right: 0;\n bottom: 0;\n background: rgba(0, 0, 0, 0.4);\n display: flex;\n align-items: center;\n justify-content: center;\n z-index: 10001;\n animation: mj-dialog-fade-in 0.15s ease-out;\n}\n\n@keyframes mj-dialog-fade-in {\n from { opacity: 0; }\n to { opacity: 1; }\n}\n\n.mj-agent-editor-dialog {\n background: #ffffff;\n border-radius: 12px;\n padding: 28px 32px;\n max-width: 400px;\n width: 90%;\n box-shadow: 0 20px 50px rgba(0, 0, 0, 0.2), 0 0 0 1px rgba(0, 0, 0, 0.05);\n text-align: center;\n animation: mj-dialog-scale-in 0.15s ease-out;\n}\n\n@keyframes mj-dialog-scale-in {\n from { transform: scale(0.95); opacity: 0; }\n to { transform: scale(1); opacity: 1; }\n}\n\n.mj-agent-editor-dialog-icon {\n font-size: 28px;\n color: #f59e0b;\n margin-bottom: 12px;\n}\n\n.mj-agent-editor-dialog-title {\n font-size: 16px;\n font-weight: 600;\n color: #1e293b;\n margin: 0 0 8px;\n}\n\n.mj-agent-editor-dialog-message {\n font-size: 13px;\n color: #64748b;\n margin: 0 0 20px;\n line-height: 1.5;\n}\n\n.mj-agent-editor-dialog-actions {\n display: flex;\n gap: 8px;\n justify-content: center;\n flex-wrap: wrap;\n}\n"] }]
974
+ }], () => [{ type: i0.ChangeDetectorRef }, { type: i1.AgentFlowTransformerService }, { type: i0.ElementRef }, { type: i0.Renderer2 }], { HostFullScreen: [{
975
+ type: HostBinding,
976
+ args: ['class.mj-flow-agent-editor--fullscreen']
977
+ }], AgentID: [{
978
+ type: Input
979
+ }], EditMode: [{
980
+ type: Input
981
+ }], FullScreen: [{
982
+ type: Input
983
+ }], FlowSaved: [{
984
+ type: Output
985
+ }], FlowChanged: [{
986
+ type: Output
987
+ }], FullScreenToggled: [{
988
+ type: Output
989
+ }], StepSelected: [{
990
+ type: Output
991
+ }], flowEditor: [{
992
+ type: ViewChild,
993
+ args: ['flowEditor']
994
+ }], onEscapeKey: [{
995
+ type: HostListener,
996
+ args: ['document:keydown.escape']
997
+ }] }); })();
998
+ (() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassDebugInfo(FlowAgentEditorComponent, { className: "FlowAgentEditorComponent", filePath: "src/lib/agent-editor/flow-agent-editor.component.ts", lineNumber: 27 }); })();
999
+ //# sourceMappingURL=flow-agent-editor.component.js.map