@memberjunction/ng-core-entity-forms 2.75.0 → 2.76.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 (86) hide show
  1. package/README.md +124 -0
  2. package/dist/lib/custom/AIAgents/FlowAgentType/flow-agent-diagram.component.d.ts +109 -0
  3. package/dist/lib/custom/AIAgents/FlowAgentType/flow-agent-diagram.component.d.ts.map +1 -0
  4. package/dist/lib/custom/AIAgents/FlowAgentType/flow-agent-diagram.component.js +2020 -0
  5. package/dist/lib/custom/AIAgents/FlowAgentType/flow-agent-diagram.component.js.map +1 -0
  6. package/dist/lib/custom/AIAgents/FlowAgentType/flow-agent-form-section.component.d.ts +32 -0
  7. package/dist/lib/custom/AIAgents/FlowAgentType/flow-agent-form-section.component.d.ts.map +1 -0
  8. package/dist/lib/custom/AIAgents/FlowAgentType/flow-agent-form-section.component.js +413 -0
  9. package/dist/lib/custom/AIAgents/FlowAgentType/flow-agent-form-section.component.js.map +1 -0
  10. package/dist/lib/custom/AIAgents/FlowAgentType/step-info-control.component.d.ts +9 -0
  11. package/dist/lib/custom/AIAgents/FlowAgentType/step-info-control.component.d.ts.map +1 -0
  12. package/dist/lib/custom/AIAgents/FlowAgentType/step-info-control.component.js +84 -0
  13. package/dist/lib/custom/AIAgents/FlowAgentType/step-info-control.component.js.map +1 -0
  14. package/dist/lib/custom/AIAgents/ai-agent-form.component.d.ts +34 -6
  15. package/dist/lib/custom/AIAgents/ai-agent-form.component.d.ts.map +1 -1
  16. package/dist/lib/custom/AIAgents/ai-agent-form.component.js +656 -520
  17. package/dist/lib/custom/AIAgents/ai-agent-form.component.js.map +1 -1
  18. package/dist/lib/custom/AIPromptRuns/ai-prompt-run-form.component.js +223 -221
  19. package/dist/lib/custom/AIPromptRuns/ai-prompt-run-form.component.js.map +1 -1
  20. package/dist/lib/custom/Actions/action-execution-log-form.component.js +51 -49
  21. package/dist/lib/custom/Actions/action-execution-log-form.component.js.map +1 -1
  22. package/dist/lib/custom/Actions/action-test-harness.component.d.ts.map +1 -1
  23. package/dist/lib/custom/Actions/action-test-harness.component.js +5 -3
  24. package/dist/lib/custom/Actions/action-test-harness.component.js.map +1 -1
  25. package/dist/lib/custom/ai-agent-run/ai-agent-run-analytics.component.js +160 -158
  26. package/dist/lib/custom/ai-agent-run/ai-agent-run-analytics.component.js.map +1 -1
  27. package/dist/lib/custom/ai-agent-run/ai-agent-run-cost.service.js +1 -1
  28. package/dist/lib/custom/ai-agent-run/ai-agent-run-cost.service.js.map +1 -1
  29. package/dist/lib/custom/ai-agent-run/ai-agent-run-data.service.d.ts +49 -0
  30. package/dist/lib/custom/ai-agent-run/ai-agent-run-data.service.d.ts.map +1 -0
  31. package/dist/lib/custom/ai-agent-run/ai-agent-run-data.service.js +211 -0
  32. package/dist/lib/custom/ai-agent-run/ai-agent-run-data.service.js.map +1 -0
  33. package/dist/lib/custom/ai-agent-run/ai-agent-run-step-detail.component.d.ts +33 -0
  34. package/dist/lib/custom/ai-agent-run/ai-agent-run-step-detail.component.d.ts.map +1 -0
  35. package/dist/lib/custom/ai-agent-run/ai-agent-run-step-detail.component.js +265 -0
  36. package/dist/lib/custom/ai-agent-run/ai-agent-run-step-detail.component.js.map +1 -0
  37. package/dist/lib/custom/ai-agent-run/ai-agent-run-timeline.component.d.ts +4 -8
  38. package/dist/lib/custom/ai-agent-run/ai-agent-run-timeline.component.d.ts.map +1 -1
  39. package/dist/lib/custom/ai-agent-run/ai-agent-run-timeline.component.js +47 -163
  40. package/dist/lib/custom/ai-agent-run/ai-agent-run-timeline.component.js.map +1 -1
  41. package/dist/lib/custom/ai-agent-run/ai-agent-run-visualization.component.d.ts +71 -0
  42. package/dist/lib/custom/ai-agent-run/ai-agent-run-visualization.component.d.ts.map +1 -0
  43. package/dist/lib/custom/ai-agent-run/ai-agent-run-visualization.component.js +931 -0
  44. package/dist/lib/custom/ai-agent-run/ai-agent-run-visualization.component.js.map +1 -0
  45. package/dist/lib/custom/ai-agent-run/ai-agent-run.component.d.ts +6 -4
  46. package/dist/lib/custom/ai-agent-run/ai-agent-run.component.d.ts.map +1 -1
  47. package/dist/lib/custom/ai-agent-run/ai-agent-run.component.js +202 -297
  48. package/dist/lib/custom/ai-agent-run/ai-agent-run.component.js.map +1 -1
  49. package/dist/lib/custom/custom-forms.module.d.ts +30 -25
  50. package/dist/lib/custom/custom-forms.module.d.ts.map +1 -1
  51. package/dist/lib/custom/custom-forms.module.js +31 -4
  52. package/dist/lib/custom/custom-forms.module.js.map +1 -1
  53. package/dist/lib/generated/Entities/AIAgent/aiagent.form.component.js +34 -14
  54. package/dist/lib/generated/Entities/AIAgent/aiagent.form.component.js.map +1 -1
  55. package/dist/lib/generated/Entities/AIAgentStep/aiagentstep.form.component.d.ts +10 -0
  56. package/dist/lib/generated/Entities/AIAgentStep/aiagentstep.form.component.d.ts.map +1 -0
  57. package/dist/lib/generated/Entities/AIAgentStep/aiagentstep.form.component.js +80 -0
  58. package/dist/lib/generated/Entities/AIAgentStep/aiagentstep.form.component.js.map +1 -0
  59. package/dist/lib/generated/Entities/AIAgentStep/sections/details.component.d.ts +11 -0
  60. package/dist/lib/generated/Entities/AIAgentStep/sections/details.component.d.ts.map +1 -0
  61. package/dist/lib/generated/Entities/AIAgentStep/sections/details.component.js +277 -0
  62. package/dist/lib/generated/Entities/AIAgentStep/sections/details.component.js.map +1 -0
  63. package/dist/lib/generated/Entities/AIAgentStepPath/aiagentsteppath.form.component.d.ts +10 -0
  64. package/dist/lib/generated/Entities/AIAgentStepPath/aiagentsteppath.form.component.d.ts.map +1 -0
  65. package/dist/lib/generated/Entities/AIAgentStepPath/aiagentsteppath.form.component.js +59 -0
  66. package/dist/lib/generated/Entities/AIAgentStepPath/aiagentsteppath.form.component.js.map +1 -0
  67. package/dist/lib/generated/Entities/AIAgentStepPath/sections/details.component.d.ts +11 -0
  68. package/dist/lib/generated/Entities/AIAgentStepPath/sections/details.component.d.ts.map +1 -0
  69. package/dist/lib/generated/Entities/AIAgentStepPath/sections/details.component.js +147 -0
  70. package/dist/lib/generated/Entities/AIAgentStepPath/sections/details.component.js.map +1 -0
  71. package/dist/lib/generated/Entities/AIAgentType/sections/details.component.d.ts.map +1 -1
  72. package/dist/lib/generated/Entities/AIAgentType/sections/details.component.js +31 -4
  73. package/dist/lib/generated/Entities/AIAgentType/sections/details.component.js.map +1 -1
  74. package/dist/lib/generated/Entities/AIPrompt/aiprompt.form.component.js +16 -6
  75. package/dist/lib/generated/Entities/AIPrompt/aiprompt.form.component.js.map +1 -1
  76. package/dist/lib/generated/Entities/Action/action.form.component.js +19 -9
  77. package/dist/lib/generated/Entities/Action/action.form.component.js.map +1 -1
  78. package/dist/lib/generated/generated-forms.module.d.ts +294 -285
  79. package/dist/lib/generated/generated-forms.module.d.ts.map +1 -1
  80. package/dist/lib/generated/generated-forms.module.js +183 -110
  81. package/dist/lib/generated/generated-forms.module.js.map +1 -1
  82. package/dist/public-api.d.ts +2 -0
  83. package/dist/public-api.d.ts.map +1 -1
  84. package/dist/public-api.js +3 -0
  85. package/dist/public-api.js.map +1 -1
  86. package/package.json +21 -17
@@ -0,0 +1,931 @@
1
+ import { Component, Input, ViewChild } from '@angular/core';
2
+ import { Subject, combineLatest } from 'rxjs';
3
+ import { takeUntil } from 'rxjs/operators';
4
+ import * as i0 from "@angular/core";
5
+ import * as i1 from "./ai-agent-run-data.service";
6
+ import * as i2 from "@progress/kendo-angular-layout";
7
+ import * as i3 from "./ai-agent-run-step-detail.component";
8
+ const _c0 = ["svgContainer"];
9
+ function AIAgentRunVisualizationComponent_Conditional_1_Template(rf, ctx) { if (rf & 1) {
10
+ i0.ɵɵelementStart(0, "div", 2);
11
+ i0.ɵɵelement(1, "i", 4);
12
+ i0.ɵɵelementStart(2, "span");
13
+ i0.ɵɵtext(3);
14
+ i0.ɵɵelementEnd()();
15
+ } if (rf & 2) {
16
+ const ctx_r0 = i0.ɵɵnextContext();
17
+ i0.ɵɵadvance(3);
18
+ i0.ɵɵtextInterpolate(ctx_r0.error);
19
+ } }
20
+ function AIAgentRunVisualizationComponent_Conditional_2_Conditional_17_Template(rf, ctx) { if (rf & 1) {
21
+ i0.ɵɵelementStart(0, "div", 18);
22
+ i0.ɵɵelement(1, "i", 20);
23
+ i0.ɵɵelementStart(2, "span");
24
+ i0.ɵɵtext(3, "Loading visualization...");
25
+ i0.ɵɵelementEnd()();
26
+ } }
27
+ function AIAgentRunVisualizationComponent_Conditional_2_Conditional_18_Template(rf, ctx) { if (rf & 1) {
28
+ const _r3 = i0.ɵɵgetCurrentView();
29
+ i0.ɵɵelementStart(0, "kendo-splitter-pane", 19)(1, "mj-ai-agent-run-step-detail", 21);
30
+ i0.ɵɵlistener("closePanel", function AIAgentRunVisualizationComponent_Conditional_2_Conditional_18_Template_mj_ai_agent_run_step_detail_closePanel_1_listener() { i0.ɵɵrestoreView(_r3); const ctx_r0 = i0.ɵɵnextContext(2); return i0.ɵɵresetView(ctx_r0.closeDetailPane()); })("navigateToActionLog", function AIAgentRunVisualizationComponent_Conditional_2_Conditional_18_Template_mj_ai_agent_run_step_detail_navigateToActionLog_1_listener($event) { i0.ɵɵrestoreView(_r3); const ctx_r0 = i0.ɵɵnextContext(2); return i0.ɵɵresetView(ctx_r0.navigateToActionLog($event)); })("copyToClipboard", function AIAgentRunVisualizationComponent_Conditional_2_Conditional_18_Template_mj_ai_agent_run_step_detail_copyToClipboard_1_listener($event) { i0.ɵɵrestoreView(_r3); const ctx_r0 = i0.ɵɵnextContext(2); return i0.ɵɵresetView(ctx_r0.copyToClipboard($event)); });
31
+ i0.ɵɵelementEnd()();
32
+ } if (rf & 2) {
33
+ const ctx_r0 = i0.ɵɵnextContext(2);
34
+ i0.ɵɵproperty("size", "400px")("min", "300px")("max", "600px")("collapsible", true);
35
+ i0.ɵɵadvance();
36
+ i0.ɵɵproperty("selectedTimelineItem", ctx_r0.selectedItem);
37
+ } }
38
+ function AIAgentRunVisualizationComponent_Conditional_2_Template(rf, ctx) { if (rf & 1) {
39
+ const _r2 = i0.ɵɵgetCurrentView();
40
+ i0.ɵɵelementStart(0, "kendo-splitter", 3)(1, "kendo-splitter-pane", 5)(2, "div", 6, 0)(4, "div", 7)(5, "div", 8);
41
+ i0.ɵɵelement(6, "i", 9);
42
+ i0.ɵɵtext(7, " Agent Execution Flow ");
43
+ i0.ɵɵelementEnd();
44
+ i0.ɵɵelementStart(8, "div", 10)(9, "button", 11);
45
+ i0.ɵɵlistener("click", function AIAgentRunVisualizationComponent_Conditional_2_Template_button_click_9_listener() { i0.ɵɵrestoreView(_r2); const ctx_r0 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r0.zoomIn()); });
46
+ i0.ɵɵelement(10, "i", 12);
47
+ i0.ɵɵelementEnd();
48
+ i0.ɵɵelementStart(11, "button", 13);
49
+ i0.ɵɵlistener("click", function AIAgentRunVisualizationComponent_Conditional_2_Template_button_click_11_listener() { i0.ɵɵrestoreView(_r2); const ctx_r0 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r0.zoomOut()); });
50
+ i0.ɵɵelement(12, "i", 14);
51
+ i0.ɵɵelementEnd();
52
+ i0.ɵɵelementStart(13, "button", 15);
53
+ i0.ɵɵlistener("click", function AIAgentRunVisualizationComponent_Conditional_2_Template_button_click_13_listener() { i0.ɵɵrestoreView(_r2); const ctx_r0 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r0.resetZoom()); });
54
+ i0.ɵɵelement(14, "i", 16);
55
+ i0.ɵɵelementEnd();
56
+ i0.ɵɵelementStart(15, "span", 17);
57
+ i0.ɵɵtext(16);
58
+ i0.ɵɵelementEnd()()();
59
+ i0.ɵɵtemplate(17, AIAgentRunVisualizationComponent_Conditional_2_Conditional_17_Template, 4, 0, "div", 18);
60
+ i0.ɵɵelementEnd()();
61
+ i0.ɵɵtemplate(18, AIAgentRunVisualizationComponent_Conditional_2_Conditional_18_Template, 2, 5, "kendo-splitter-pane", 19);
62
+ i0.ɵɵelementEnd();
63
+ } if (rf & 2) {
64
+ const ctx_r0 = i0.ɵɵnextContext();
65
+ i0.ɵɵadvance();
66
+ i0.ɵɵproperty("collapsible", false);
67
+ i0.ɵɵadvance(15);
68
+ i0.ɵɵtextInterpolate1("", (ctx_r0.panZoom.scale * 100).toFixed(0), "%");
69
+ i0.ɵɵadvance();
70
+ i0.ɵɵconditional(ctx_r0.loading ? 17 : -1);
71
+ i0.ɵɵadvance();
72
+ i0.ɵɵconditional(ctx_r0.selectedItem ? 18 : -1);
73
+ } }
74
+ export class AIAgentRunVisualizationComponent {
75
+ constructor(cdr, dataService) {
76
+ this.cdr = cdr;
77
+ this.dataService = dataService;
78
+ this.destroy$ = new Subject();
79
+ this.viewInitialized = false;
80
+ this.pendingData = null;
81
+ this.loading = false; // Start with false so the container renders
82
+ this.error = null;
83
+ this.dataLoading = true; // Track data loading separately
84
+ this.selectedItem = null;
85
+ // Node management
86
+ this.nodes = new Map();
87
+ this.scopes = new Map();
88
+ this.connections = [];
89
+ // Pan and zoom state
90
+ this.panZoom = {
91
+ scale: 1,
92
+ translateX: 0,
93
+ translateY: 0,
94
+ isPanning: false,
95
+ startX: 0,
96
+ startY: 0
97
+ };
98
+ // Drag state
99
+ this.dragState = {
100
+ isDragging: false,
101
+ element: null,
102
+ nodeId: null,
103
+ startX: 0,
104
+ startY: 0,
105
+ startTransform: { x: 0, y: 0 }
106
+ };
107
+ this.onMouseMove = (event) => {
108
+ if (!this.dragState.isDragging || !this.dragState.element)
109
+ return;
110
+ const svg = this.dragState.element.ownerSVGElement;
111
+ if (!svg)
112
+ return;
113
+ const pt = svg.createSVGPoint();
114
+ pt.x = event.clientX;
115
+ pt.y = event.clientY;
116
+ const svgP = pt.matrixTransform(svg.getScreenCTM()?.inverse());
117
+ const dx = svgP.x - this.dragState.startX;
118
+ const dy = svgP.y - this.dragState.startY;
119
+ const newX = this.dragState.startTransform.x + dx;
120
+ const newY = this.dragState.startTransform.y + dy;
121
+ // Update element position
122
+ this.dragState.element.setAttribute('transform', `translate(${newX}, ${newY})`);
123
+ // Update node data
124
+ const node = this.nodes.get(this.dragState.nodeId);
125
+ if (node) {
126
+ node.x = newX;
127
+ node.y = newY;
128
+ }
129
+ // Update connections
130
+ this.drawConnections();
131
+ };
132
+ this.onMouseUp = (event) => {
133
+ if (!this.dragState.isDragging || !this.dragState.element)
134
+ return;
135
+ this.dragState.element.classList.remove('dragging');
136
+ // Clean up
137
+ this.dragState = {
138
+ isDragging: false,
139
+ element: null,
140
+ nodeId: null,
141
+ startX: 0,
142
+ startY: 0,
143
+ startTransform: { x: 0, y: 0 }
144
+ };
145
+ document.removeEventListener('mousemove', this.onMouseMove);
146
+ document.removeEventListener('mouseup', this.onMouseUp);
147
+ };
148
+ }
149
+ ngOnInit() {
150
+ if (this.aiAgentRunId) {
151
+ // Subscribe to data from service
152
+ combineLatest([
153
+ this.dataService.steps$,
154
+ this.dataService.subRuns$,
155
+ this.dataService.actionLogs$,
156
+ this.dataService.promptRuns$,
157
+ this.dataService.loading$
158
+ ]).pipe(takeUntil(this.destroy$)).subscribe(([steps, subRuns, actionLogs, promptRuns, loading]) => {
159
+ if (!loading && steps && steps.length > 0) {
160
+ console.log('Visualization: Received data from service', {
161
+ steps: steps.length,
162
+ subRuns: subRuns.length,
163
+ viewInitialized: this.viewInitialized
164
+ });
165
+ if (this.viewInitialized && this.svgContainer?.nativeElement) {
166
+ // View is ready, build immediately
167
+ this.buildVisualization(steps, subRuns, actionLogs, promptRuns);
168
+ }
169
+ else {
170
+ // Store data for when view is ready
171
+ console.log('View not ready, storing data for later');
172
+ this.pendingData = { steps, subRuns, actionLogs, promptRuns };
173
+ this.loading = false; // Show the container so it can render
174
+ }
175
+ }
176
+ else if (!loading && (!steps || steps.length === 0)) {
177
+ console.log('Visualization: No steps available');
178
+ this.loading = false;
179
+ this.error = null;
180
+ }
181
+ });
182
+ // Subscribe to error state
183
+ this.dataService.error$.pipe(takeUntil(this.destroy$)).subscribe(error => {
184
+ if (error) {
185
+ this.error = error;
186
+ this.loading = false;
187
+ }
188
+ });
189
+ }
190
+ else {
191
+ console.error('Visualization: No agent run ID provided');
192
+ this.error = 'No agent run ID provided';
193
+ this.loading = false;
194
+ this.dataLoading = false;
195
+ }
196
+ }
197
+ ngAfterViewInit() {
198
+ console.log('Visualization ngAfterViewInit');
199
+ this.viewInitialized = true;
200
+ // Initialize SVG
201
+ if (this.svgContainer && this.svgContainer.nativeElement) {
202
+ this.initializeSVG();
203
+ // If we have pending data, process it now
204
+ if (this.pendingData) {
205
+ console.log('Processing pending data after view init');
206
+ this.buildVisualization(this.pendingData.steps, this.pendingData.subRuns, this.pendingData.actionLogs, this.pendingData.promptRuns);
207
+ this.pendingData = null;
208
+ }
209
+ this.cdr.detectChanges();
210
+ }
211
+ else {
212
+ console.error('SVG container not found in ngAfterViewInit');
213
+ }
214
+ }
215
+ ngOnDestroy() {
216
+ this.destroy$.next();
217
+ this.destroy$.complete();
218
+ // Clean up drag listeners
219
+ if (this.dragState.isDragging) {
220
+ document.removeEventListener('mousemove', this.onMouseMove);
221
+ document.removeEventListener('mouseup', this.onMouseUp);
222
+ }
223
+ }
224
+ initializeSVG() {
225
+ const container = this.svgContainer?.nativeElement;
226
+ if (!container) {
227
+ console.error('SVG container element not found');
228
+ return;
229
+ }
230
+ // Create SVG element if it doesn't exist
231
+ let svg = container.querySelector('svg');
232
+ if (!svg) {
233
+ svg = document.createElementNS('http://www.w3.org/2000/svg', 'svg');
234
+ svg.setAttribute('class', 'visualization-svg');
235
+ svg.setAttribute('width', '100%');
236
+ svg.setAttribute('height', '100%');
237
+ // Add event listeners
238
+ svg.addEventListener('wheel', (e) => this.onWheel(e));
239
+ svg.addEventListener('mousedown', (e) => this.onSvgMouseDown(e));
240
+ svg.addEventListener('mousemove', (e) => this.onSvgMouseMove(e));
241
+ svg.addEventListener('mouseup', (e) => this.onSvgMouseUp(e));
242
+ container.appendChild(svg);
243
+ }
244
+ // Add arrow marker definition
245
+ const defs = document.createElementNS('http://www.w3.org/2000/svg', 'defs');
246
+ const marker = document.createElementNS('http://www.w3.org/2000/svg', 'marker');
247
+ marker.setAttribute('id', 'arrowhead-viz');
248
+ marker.setAttribute('markerWidth', '10');
249
+ marker.setAttribute('markerHeight', '7');
250
+ marker.setAttribute('refX', '9');
251
+ marker.setAttribute('refY', '3.5');
252
+ marker.setAttribute('orient', 'auto');
253
+ const polygon = document.createElementNS('http://www.w3.org/2000/svg', 'polygon');
254
+ polygon.setAttribute('points', '0 0, 10 3.5, 0 7');
255
+ polygon.setAttribute('fill', '#4a90e2');
256
+ marker.appendChild(polygon);
257
+ defs.appendChild(marker);
258
+ svg.appendChild(defs);
259
+ console.log('SVG initialized successfully');
260
+ }
261
+ async buildVisualization(steps, subRuns, actionLogs, promptRuns) {
262
+ console.log('buildVisualization called', {
263
+ steps: steps?.length || 0,
264
+ hasContainer: !!this.svgContainer,
265
+ containerElement: this.svgContainer?.nativeElement
266
+ });
267
+ if (!this.svgContainer || !this.svgContainer.nativeElement) {
268
+ console.error('SVG container not available');
269
+ this.loading = false;
270
+ this.error = 'Visualization container not ready';
271
+ return;
272
+ }
273
+ // If no steps, show empty state
274
+ if (!steps || steps.length === 0) {
275
+ console.log('No steps to visualize');
276
+ this.loading = false;
277
+ this.error = null;
278
+ return;
279
+ }
280
+ this.loading = true;
281
+ this.error = null;
282
+ try {
283
+ // Wait a tick for the view to be fully ready
284
+ await new Promise(resolve => setTimeout(resolve, 0));
285
+ // Clear existing elements
286
+ this.clearVisualization();
287
+ // Build nodes and scopes
288
+ await this.buildNodesAndScopes(steps, subRuns, promptRuns);
289
+ // Arrange layout
290
+ this.arrangeLayout();
291
+ // Draw connections
292
+ this.drawConnections();
293
+ // Fit to view
294
+ this.fitToView();
295
+ this.loading = false;
296
+ console.log('Visualization built successfully');
297
+ }
298
+ catch (error) {
299
+ this.error = 'Failed to build visualization';
300
+ console.error('Visualization error:', error);
301
+ this.loading = false;
302
+ }
303
+ }
304
+ clearVisualization() {
305
+ const svg = this.svgContainer?.nativeElement?.querySelector('svg');
306
+ if (!svg)
307
+ return;
308
+ const mainGroup = svg.querySelector('.main-group');
309
+ if (mainGroup) {
310
+ // Remove all child elements except defs
311
+ while (mainGroup.firstChild) {
312
+ mainGroup.removeChild(mainGroup.firstChild);
313
+ }
314
+ }
315
+ this.nodes.clear();
316
+ this.scopes.clear();
317
+ this.connections = [];
318
+ }
319
+ async buildNodesAndScopes(steps, subRuns, promptRuns) {
320
+ const svg = this.svgContainer?.nativeElement?.querySelector('svg');
321
+ if (!svg)
322
+ return;
323
+ let mainGroup = svg.querySelector('.main-group');
324
+ if (!mainGroup) {
325
+ mainGroup = document.createElementNS('http://www.w3.org/2000/svg', 'g');
326
+ mainGroup.setAttribute('class', 'main-group');
327
+ svg.appendChild(mainGroup);
328
+ }
329
+ // Create nodes for each step
330
+ for (let i = 0; i < steps.length; i++) {
331
+ const step = steps[i];
332
+ if (step.StepType === 'Sub-Agent' && step.TargetLogID) {
333
+ // Create a scope for sub-agent
334
+ const subRun = subRuns.find(sr => sr.ID === step.TargetLogID);
335
+ const scopeElement = await this.createScopeElement(step, subRun);
336
+ mainGroup.appendChild(scopeElement);
337
+ const scope = {
338
+ id: step.ID,
339
+ name: subRun?.Agent || 'Sub-Agent',
340
+ x: 0,
341
+ y: 0,
342
+ width: 300,
343
+ height: 200,
344
+ expanded: false,
345
+ nodes: [],
346
+ element: scopeElement
347
+ };
348
+ this.scopes.set(step.ID, scope);
349
+ }
350
+ else {
351
+ // Create regular node
352
+ const nodeElement = this.createNodeElement(step, promptRuns);
353
+ mainGroup.appendChild(nodeElement);
354
+ const nodeData = {
355
+ step: step,
356
+ x: 0,
357
+ y: 0,
358
+ width: 180,
359
+ height: 80,
360
+ element: nodeElement
361
+ };
362
+ this.nodes.set(step.ID, nodeData);
363
+ }
364
+ // Add connection info
365
+ if (i > 0) {
366
+ this.connections.push({
367
+ from: steps[i - 1].ID,
368
+ to: step.ID
369
+ });
370
+ }
371
+ }
372
+ }
373
+ createNodeElement(step, promptRuns) {
374
+ const g = document.createElementNS('http://www.w3.org/2000/svg', 'g');
375
+ g.setAttribute('class', 'step-node');
376
+ g.setAttribute('data-step-id', step.ID);
377
+ // Add event handlers
378
+ g.addEventListener('click', (e) => this.onNodeClick(e, step));
379
+ g.addEventListener('mousedown', (e) => this.onNodeMouseDown(e, step.ID));
380
+ g.style.cursor = 'pointer';
381
+ const nodeWidth = 180;
382
+ const nodeHeight = 80;
383
+ // Background rectangle
384
+ const rect = document.createElementNS('http://www.w3.org/2000/svg', 'rect');
385
+ rect.setAttribute('width', nodeWidth.toString());
386
+ rect.setAttribute('height', nodeHeight.toString());
387
+ rect.setAttribute('rx', '8');
388
+ rect.setAttribute('fill', 'white');
389
+ rect.setAttribute('stroke', this.getStepColor(step));
390
+ rect.setAttribute('stroke-width', '2');
391
+ g.appendChild(rect);
392
+ // Status indicator
393
+ const statusCircle = document.createElementNS('http://www.w3.org/2000/svg', 'circle');
394
+ statusCircle.setAttribute('cx', '12');
395
+ statusCircle.setAttribute('cy', '12');
396
+ statusCircle.setAttribute('r', '6');
397
+ statusCircle.setAttribute('fill', this.getStatusColor(step.Status));
398
+ g.appendChild(statusCircle);
399
+ // Icon
400
+ const icon = document.createElementNS('http://www.w3.org/2000/svg', 'text');
401
+ icon.setAttribute('x', '35');
402
+ icon.setAttribute('y', '20');
403
+ icon.setAttribute('font-size', '18');
404
+ icon.setAttribute('fill', this.getStepColor(step));
405
+ icon.textContent = this.getStepEmoji(step.StepType);
406
+ g.appendChild(icon);
407
+ // Title
408
+ const title = document.createElementNS('http://www.w3.org/2000/svg', 'text');
409
+ title.setAttribute('x', '60');
410
+ title.setAttribute('y', '20');
411
+ title.setAttribute('font-size', '14');
412
+ title.setAttribute('font-weight', '600');
413
+ title.setAttribute('fill', '#2c3e50');
414
+ title.textContent = this.truncateText(step.StepName || `Step ${step.StepNumber}`, 15);
415
+ g.appendChild(title);
416
+ // Step type
417
+ const type = document.createElementNS('http://www.w3.org/2000/svg', 'text');
418
+ type.setAttribute('x', '12');
419
+ type.setAttribute('y', '40');
420
+ type.setAttribute('font-size', '12');
421
+ type.setAttribute('fill', '#6c757d');
422
+ type.textContent = step.StepType;
423
+ g.appendChild(type);
424
+ // Model info for prompts
425
+ if (step.StepType === 'Prompt' && step.TargetLogID && promptRuns) {
426
+ const promptRun = promptRuns.find(pr => pr.ID === step.TargetLogID);
427
+ if (promptRun) {
428
+ const model = document.createElementNS('http://www.w3.org/2000/svg', 'text');
429
+ model.setAttribute('x', '12');
430
+ model.setAttribute('y', '55');
431
+ model.setAttribute('font-size', '11');
432
+ model.setAttribute('fill', '#868e96');
433
+ model.textContent = `${promptRun.Model || 'Unknown'}`;
434
+ g.appendChild(model);
435
+ }
436
+ }
437
+ // Duration
438
+ if (step.CompletedAt) {
439
+ const duration = this.calculateDuration(step.StartedAt, step.CompletedAt);
440
+ const durationText = document.createElementNS('http://www.w3.org/2000/svg', 'text');
441
+ durationText.setAttribute('x', '12');
442
+ durationText.setAttribute('y', '70');
443
+ durationText.setAttribute('font-size', '11');
444
+ durationText.setAttribute('fill', '#868e96');
445
+ durationText.textContent = `⏱️ ${duration}`;
446
+ g.appendChild(durationText);
447
+ }
448
+ return g;
449
+ }
450
+ async createScopeElement(step, subRun) {
451
+ const g = document.createElementNS('http://www.w3.org/2000/svg', 'g');
452
+ g.setAttribute('class', 'scope-container');
453
+ g.setAttribute('data-scope-id', step.ID);
454
+ const scopeWidth = 300;
455
+ const scopeHeight = 200;
456
+ const headerHeight = 40;
457
+ // Background
458
+ const bg = document.createElementNS('http://www.w3.org/2000/svg', 'rect');
459
+ bg.setAttribute('width', scopeWidth.toString());
460
+ bg.setAttribute('height', scopeHeight.toString());
461
+ bg.setAttribute('rx', '12');
462
+ bg.setAttribute('fill', '#f8f9fa');
463
+ bg.setAttribute('stroke', '#4a90e2');
464
+ bg.setAttribute('stroke-width', '2');
465
+ bg.setAttribute('stroke-dasharray', '5,5');
466
+ g.appendChild(bg);
467
+ // Header background
468
+ const headerBg = document.createElementNS('http://www.w3.org/2000/svg', 'rect');
469
+ headerBg.setAttribute('width', scopeWidth.toString());
470
+ headerBg.setAttribute('height', headerHeight.toString());
471
+ headerBg.setAttribute('rx', '12');
472
+ headerBg.setAttribute('fill', '#e3f2fd');
473
+ g.appendChild(headerBg);
474
+ // Fix bottom corners
475
+ const headerFix = document.createElementNS('http://www.w3.org/2000/svg', 'rect');
476
+ headerFix.setAttribute('y', (headerHeight - 12).toString());
477
+ headerFix.setAttribute('width', scopeWidth.toString());
478
+ headerFix.setAttribute('height', '12');
479
+ headerFix.setAttribute('fill', '#e3f2fd');
480
+ g.appendChild(headerFix);
481
+ // Robot icon
482
+ const icon = document.createElementNS('http://www.w3.org/2000/svg', 'text');
483
+ icon.setAttribute('x', '12');
484
+ icon.setAttribute('y', '26');
485
+ icon.setAttribute('font-size', '20');
486
+ icon.textContent = '🤖';
487
+ g.appendChild(icon);
488
+ // Title
489
+ const title = document.createElementNS('http://www.w3.org/2000/svg', 'text');
490
+ title.setAttribute('x', '40');
491
+ title.setAttribute('y', '26');
492
+ title.setAttribute('font-size', '14');
493
+ title.setAttribute('font-weight', '600');
494
+ title.setAttribute('fill', '#1976d2');
495
+ title.textContent = subRun?.Agent || 'Sub-Agent';
496
+ g.appendChild(title);
497
+ // Expand/collapse button
498
+ const expandBtn = document.createElementNS('http://www.w3.org/2000/svg', 'g');
499
+ expandBtn.setAttribute('class', 'expand-button');
500
+ expandBtn.style.cursor = 'pointer';
501
+ expandBtn.setAttribute('transform', `translate(${scopeWidth - 30}, 10)`);
502
+ const expandBg = document.createElementNS('http://www.w3.org/2000/svg', 'circle');
503
+ expandBg.setAttribute('cx', '10');
504
+ expandBg.setAttribute('cy', '10');
505
+ expandBg.setAttribute('r', '10');
506
+ expandBg.setAttribute('fill', 'white');
507
+ expandBg.setAttribute('stroke', '#4a90e2');
508
+ expandBtn.appendChild(expandBg);
509
+ const expandIcon = document.createElementNS('http://www.w3.org/2000/svg', 'text');
510
+ expandIcon.setAttribute('x', '10');
511
+ expandIcon.setAttribute('y', '15');
512
+ expandIcon.setAttribute('text-anchor', 'middle');
513
+ expandIcon.setAttribute('font-size', '12');
514
+ expandIcon.setAttribute('fill', '#4a90e2');
515
+ expandIcon.textContent = '+';
516
+ expandBtn.appendChild(expandIcon);
517
+ expandBtn.addEventListener('click', (e) => this.onScopeExpandClick(e, step.ID));
518
+ g.appendChild(expandBtn);
519
+ // Click handler for scope
520
+ g.addEventListener('click', (e) => {
521
+ if (!e.target.closest('.expand-button')) {
522
+ this.onNodeClick(e, step);
523
+ }
524
+ });
525
+ return g;
526
+ }
527
+ arrangeLayout() {
528
+ const nodeSpacingX = 250;
529
+ const nodeSpacingY = 120;
530
+ const startX = 50;
531
+ const startY = 50;
532
+ let currentY = startY;
533
+ let index = 0;
534
+ // Arrange nodes and scopes sequentially
535
+ const allItems = [...this.nodes.values(), ...Array.from(this.scopes.values()).map(s => ({
536
+ step: { ID: s.id },
537
+ x: 0,
538
+ y: 0,
539
+ width: s.width,
540
+ height: s.height
541
+ }))];
542
+ // Sort by step number if available
543
+ allItems.sort((a, b) => {
544
+ const aStep = a.step;
545
+ const bStep = b.step;
546
+ return (aStep.StepNumber || 0) - (bStep.StepNumber || 0);
547
+ });
548
+ for (const item of allItems) {
549
+ const nodeData = this.nodes.get(item.step.ID);
550
+ const scopeData = this.scopes.get(item.step.ID);
551
+ if (nodeData) {
552
+ nodeData.x = startX;
553
+ nodeData.y = currentY;
554
+ if (nodeData.element) {
555
+ nodeData.element.setAttribute('transform', `translate(${nodeData.x}, ${nodeData.y})`);
556
+ }
557
+ currentY += nodeSpacingY;
558
+ }
559
+ else if (scopeData) {
560
+ scopeData.x = startX;
561
+ scopeData.y = currentY;
562
+ if (scopeData.element) {
563
+ scopeData.element.setAttribute('transform', `translate(${scopeData.x}, ${scopeData.y})`);
564
+ }
565
+ currentY += scopeData.height + nodeSpacingY;
566
+ }
567
+ }
568
+ }
569
+ drawConnections() {
570
+ const svg = this.svgContainer?.nativeElement?.querySelector('svg');
571
+ if (!svg)
572
+ return;
573
+ const mainGroup = svg.querySelector('.main-group');
574
+ if (!mainGroup)
575
+ return;
576
+ // Create connections group if not exists
577
+ let connectionsGroup = mainGroup.querySelector('.connections-group');
578
+ if (!connectionsGroup) {
579
+ connectionsGroup = document.createElementNS('http://www.w3.org/2000/svg', 'g');
580
+ connectionsGroup.setAttribute('class', 'connections-group');
581
+ mainGroup.insertBefore(connectionsGroup, mainGroup.firstChild);
582
+ }
583
+ // Clear existing connections
584
+ while (connectionsGroup.firstChild) {
585
+ connectionsGroup.removeChild(connectionsGroup.firstChild);
586
+ }
587
+ // Draw each connection
588
+ for (const conn of this.connections) {
589
+ const fromNode = this.nodes.get(conn.from);
590
+ const fromScope = this.scopes.get(conn.from);
591
+ const toNode = this.nodes.get(conn.to);
592
+ const toScope = this.scopes.get(conn.to);
593
+ let fromX = 0, fromY = 0, toX = 0, toY = 0;
594
+ if (fromNode) {
595
+ fromX = fromNode.x + fromNode.width / 2;
596
+ fromY = fromNode.y + fromNode.height;
597
+ }
598
+ else if (fromScope) {
599
+ fromX = fromScope.x + fromScope.width / 2;
600
+ fromY = fromScope.y + fromScope.height;
601
+ }
602
+ if (toNode) {
603
+ toX = toNode.x + toNode.width / 2;
604
+ toY = toNode.y;
605
+ }
606
+ else if (toScope) {
607
+ toX = toScope.x + toScope.width / 2;
608
+ toY = toScope.y;
609
+ }
610
+ if (fromX && fromY && toX && toY) {
611
+ const path = document.createElementNS('http://www.w3.org/2000/svg', 'path');
612
+ const d = `M ${fromX} ${fromY} L ${toX} ${toY}`;
613
+ path.setAttribute('d', d);
614
+ path.setAttribute('fill', 'none');
615
+ path.setAttribute('stroke', '#4a90e2');
616
+ path.setAttribute('stroke-width', '2');
617
+ path.setAttribute('marker-end', 'url(#arrowhead-viz)');
618
+ path.setAttribute('opacity', '0.6');
619
+ connectionsGroup.appendChild(path);
620
+ conn.path = path;
621
+ }
622
+ }
623
+ }
624
+ fitToView() {
625
+ const svg = this.svgContainer?.nativeElement?.querySelector('svg');
626
+ const mainGroup = svg?.querySelector('.main-group');
627
+ if (!svg || !mainGroup)
628
+ return;
629
+ const bbox = mainGroup.getBBox();
630
+ const padding = 50;
631
+ const viewBox = `${bbox.x - padding} ${bbox.y - padding} ${bbox.width + 2 * padding} ${bbox.height + 2 * padding}`;
632
+ svg.setAttribute('viewBox', viewBox);
633
+ }
634
+ getStepColor(step) {
635
+ const colorMap = {
636
+ 'Prompt': '#2196f3',
637
+ 'Actions': '#4caf50',
638
+ 'Sub-Agent': '#ff9800',
639
+ 'Tool': '#9c27b0',
640
+ 'Decision': '#f44336'
641
+ };
642
+ return colorMap[step.StepType] || '#757575';
643
+ }
644
+ getStepEmoji(stepType) {
645
+ const emojiMap = {
646
+ 'Prompt': '💬',
647
+ 'Actions': '⚙️',
648
+ 'Sub-Agent': '🤖',
649
+ 'Tool': '🔧',
650
+ 'Decision': '🔀'
651
+ };
652
+ return emojiMap[stepType] || '⚪';
653
+ }
654
+ getStatusColor(status) {
655
+ const colorMap = {
656
+ 'Running': '#1976d2',
657
+ 'Completed': '#388e3c',
658
+ 'Failed': '#d32f2f',
659
+ 'Cancelled': '#f57c00',
660
+ 'Paused': '#757575'
661
+ };
662
+ return colorMap[status] || '#9e9e9e';
663
+ }
664
+ truncateText(text, maxLength) {
665
+ if (text.length <= maxLength)
666
+ return text;
667
+ return text.substring(0, maxLength - 3) + '...';
668
+ }
669
+ calculateDuration(start, end) {
670
+ if (!end)
671
+ return 'Running...';
672
+ const ms = new Date(end).getTime() - new Date(start).getTime();
673
+ if (ms < 1000)
674
+ return `${ms}ms`;
675
+ if (ms < 60000)
676
+ return `${(ms / 1000).toFixed(1)}s`;
677
+ if (ms < 3600000)
678
+ return `${Math.floor(ms / 60000)}m ${Math.floor((ms % 60000) / 1000)}s`;
679
+ return `${Math.floor(ms / 3600000)}h ${Math.floor((ms % 3600000) / 60000)}m`;
680
+ }
681
+ // Event handlers
682
+ onNodeClick(event, step) {
683
+ event.stopPropagation();
684
+ // Create timeline item from step
685
+ const item = {
686
+ id: step.ID,
687
+ type: 'step',
688
+ title: step.StepName || `Step ${step.StepNumber}`,
689
+ subtitle: `Type: ${step.StepType}`,
690
+ status: step.Status,
691
+ startTime: step.StartedAt,
692
+ endTime: step.CompletedAt || undefined,
693
+ duration: this.calculateDuration(step.StartedAt, step.CompletedAt),
694
+ icon: this.getStepIcon(step.StepType),
695
+ color: this.getStatusColorName(step.Status),
696
+ data: step,
697
+ level: 0
698
+ };
699
+ this.selectedItem = item;
700
+ this.cdr.detectChanges();
701
+ }
702
+ getStepIcon(stepType) {
703
+ const iconMap = {
704
+ 'Prompt': 'fa-microchip',
705
+ 'Tool': 'fa-tools',
706
+ 'Sub-Agent': 'fa-robot',
707
+ 'Decision': 'fa-code-branch',
708
+ 'Actions': 'fa-cog'
709
+ };
710
+ return iconMap[stepType] || 'fa-circle';
711
+ }
712
+ getStatusColorName(status) {
713
+ const colorMap = {
714
+ 'Running': 'info',
715
+ 'Completed': 'success',
716
+ 'Failed': 'error',
717
+ 'Cancelled': 'warning',
718
+ 'Paused': 'secondary'
719
+ };
720
+ return colorMap[status] || 'secondary';
721
+ }
722
+ async onScopeExpandClick(event, scopeId) {
723
+ event.stopPropagation();
724
+ const scope = this.scopes.get(scopeId);
725
+ if (!scope)
726
+ return;
727
+ scope.expanded = !scope.expanded;
728
+ if (scope.expanded) {
729
+ // Load sub-agent steps
730
+ await this.loadScopeContents(scopeId);
731
+ }
732
+ // Update UI
733
+ this.updateScopeVisual(scope);
734
+ this.arrangeLayout();
735
+ this.drawConnections();
736
+ }
737
+ async loadScopeContents(scopeId) {
738
+ const scope = this.scopes.get(scopeId);
739
+ if (!scope)
740
+ return;
741
+ // Find the step
742
+ const step = Array.from(this.nodes.values()).find(n => n.step.ID === scopeId)?.step
743
+ || Array.from(this.scopes.values()).find(s => s.id === scopeId);
744
+ if (!step || !step.TargetLogID)
745
+ return;
746
+ const targetLogId = step.TargetLogID;
747
+ try {
748
+ // Load sub-agent data through service
749
+ const data = await this.dataService.loadSubAgentData(targetLogId);
750
+ if (data.steps && data.steps.length > 0) {
751
+ // Create nodes from data
752
+ this.createScopeNodes(scope, data.steps, data.promptRuns);
753
+ }
754
+ }
755
+ catch (error) {
756
+ console.error('Failed to load scope contents:', error);
757
+ }
758
+ }
759
+ createScopeNodes(scope, steps, promptRuns) {
760
+ const svg = this.svgContainer?.nativeElement?.querySelector('svg');
761
+ if (!svg)
762
+ return;
763
+ const mainGroup = svg.querySelector('.main-group');
764
+ if (!mainGroup || !scope.element)
765
+ return;
766
+ // Create nodes inside scope
767
+ const nodeSpacingY = 60;
768
+ const startX = 20;
769
+ const startY = 60;
770
+ for (let i = 0; i < steps.length; i++) {
771
+ const step = steps[i];
772
+ const nodeElement = this.createNodeElement(step, promptRuns);
773
+ // Add node to scope group
774
+ scope.element.appendChild(nodeElement);
775
+ const nodeData = {
776
+ step: step,
777
+ x: startX,
778
+ y: startY + i * nodeSpacingY,
779
+ width: 160,
780
+ height: 60,
781
+ element: nodeElement
782
+ };
783
+ nodeElement.setAttribute('transform', `translate(${nodeData.x}, ${nodeData.y})`);
784
+ scope.nodes.push(nodeData);
785
+ this.nodes.set(step.ID, nodeData);
786
+ }
787
+ // Update scope height
788
+ scope.height = Math.max(200, startY + steps.length * nodeSpacingY + 20);
789
+ }
790
+ updateScopeVisual(scope) {
791
+ if (!scope.element)
792
+ return;
793
+ // Update background height
794
+ const bg = scope.element.querySelector('rect');
795
+ if (bg) {
796
+ bg.setAttribute('height', scope.height.toString());
797
+ }
798
+ // Update expand button
799
+ const expandIcon = scope.element.querySelector('.expand-button text');
800
+ if (expandIcon) {
801
+ expandIcon.textContent = scope.expanded ? '−' : '+';
802
+ }
803
+ }
804
+ // Drag handling
805
+ onNodeMouseDown(event, nodeId) {
806
+ event.preventDefault();
807
+ event.stopPropagation();
808
+ const node = this.nodes.get(nodeId);
809
+ if (!node || !node.element)
810
+ return;
811
+ // Get current transform
812
+ const transform = node.element.getAttribute('transform');
813
+ const match = transform?.match(/translate\(([-\d.]+),\s*([-\d.]+)\)/);
814
+ if (!match)
815
+ return;
816
+ // Get SVG coordinates
817
+ const svg = node.element.ownerSVGElement;
818
+ if (!svg)
819
+ return;
820
+ const pt = svg.createSVGPoint();
821
+ pt.x = event.clientX;
822
+ pt.y = event.clientY;
823
+ const svgP = pt.matrixTransform(svg.getScreenCTM()?.inverse());
824
+ this.dragState = {
825
+ isDragging: true,
826
+ element: node.element,
827
+ nodeId: nodeId,
828
+ startX: svgP.x,
829
+ startY: svgP.y,
830
+ startTransform: {
831
+ x: parseFloat(match[1]),
832
+ y: parseFloat(match[2])
833
+ }
834
+ };
835
+ node.element.classList.add('dragging');
836
+ // Add document-level event listeners
837
+ document.addEventListener('mousemove', this.onMouseMove);
838
+ document.addEventListener('mouseup', this.onMouseUp);
839
+ }
840
+ // Pan and zoom
841
+ onWheel(event) {
842
+ event.preventDefault();
843
+ const delta = event.deltaY > 0 ? 0.9 : 1.1;
844
+ this.panZoom.scale = Math.max(0.3, Math.min(3, this.panZoom.scale * delta));
845
+ this.updateTransform();
846
+ }
847
+ onSvgMouseDown(event) {
848
+ if (event.button === 0 && event.target === event.currentTarget) {
849
+ this.panZoom.isPanning = true;
850
+ this.panZoom.startX = event.clientX - this.panZoom.translateX;
851
+ this.panZoom.startY = event.clientY - this.panZoom.translateY;
852
+ event.preventDefault();
853
+ }
854
+ }
855
+ onSvgMouseMove(event) {
856
+ if (this.panZoom.isPanning) {
857
+ this.panZoom.translateX = event.clientX - this.panZoom.startX;
858
+ this.panZoom.translateY = event.clientY - this.panZoom.startY;
859
+ this.updateTransform();
860
+ }
861
+ }
862
+ onSvgMouseUp(event) {
863
+ this.panZoom.isPanning = false;
864
+ }
865
+ updateTransform() {
866
+ const svg = this.svgContainer?.nativeElement?.querySelector('svg');
867
+ if (svg) {
868
+ const mainGroup = svg.querySelector('.main-group');
869
+ if (mainGroup) {
870
+ mainGroup.setAttribute('transform', `translate(${this.panZoom.translateX}, ${this.panZoom.translateY}) scale(${this.panZoom.scale})`);
871
+ }
872
+ }
873
+ }
874
+ // Toolbar actions
875
+ zoomIn() {
876
+ this.panZoom.scale = Math.min(this.panZoom.scale * 1.2, 3);
877
+ this.updateTransform();
878
+ }
879
+ zoomOut() {
880
+ this.panZoom.scale = Math.max(this.panZoom.scale / 1.2, 0.3);
881
+ this.updateTransform();
882
+ }
883
+ resetZoom() {
884
+ this.panZoom.scale = 1;
885
+ this.panZoom.translateX = 0;
886
+ this.panZoom.translateY = 0;
887
+ this.updateTransform();
888
+ }
889
+ // Detail pane handlers
890
+ closeDetailPane() {
891
+ this.selectedItem = null;
892
+ this.cdr.detectChanges();
893
+ }
894
+ navigateToActionLog(logId) {
895
+ // Emit event to parent component
896
+ // Parent will handle navigation
897
+ }
898
+ async copyToClipboard(text) {
899
+ try {
900
+ await navigator.clipboard.writeText(text);
901
+ }
902
+ catch (err) {
903
+ console.error('Failed to copy to clipboard:', err);
904
+ }
905
+ }
906
+ static { this.ɵfac = function AIAgentRunVisualizationComponent_Factory(t) { return new (t || AIAgentRunVisualizationComponent)(i0.ɵɵdirectiveInject(i0.ChangeDetectorRef), i0.ɵɵdirectiveInject(i1.AIAgentRunDataService)); }; }
907
+ static { this.ɵcmp = /*@__PURE__*/ i0.ɵɵdefineComponent({ type: AIAgentRunVisualizationComponent, selectors: [["mj-ai-agent-run-visualization"]], viewQuery: function AIAgentRunVisualizationComponent_Query(rf, ctx) { if (rf & 1) {
908
+ i0.ɵɵviewQuery(_c0, 5);
909
+ } if (rf & 2) {
910
+ let _t;
911
+ i0.ɵɵqueryRefresh(_t = i0.ɵɵloadQuery()) && (ctx.svgContainer = _t.first);
912
+ } }, inputs: { aiAgentRunId: "aiAgentRunId" }, decls: 3, vars: 1, consts: [["svgContainer", ""], [1, "visualization-container"], [1, "error-state"], ["orientation", "horizontal", 2, "height", "100%"], [1, "fa-solid", "fa-exclamation-triangle"], [3, "collapsible"], [1, "diagram-container"], [1, "diagram-toolbar"], [1, "toolbar-title"], [1, "fa-solid", "fa-diagram-project"], [1, "zoom-controls"], ["title", "Zoom in", 3, "click"], [1, "fa-solid", "fa-search-plus"], ["title", "Zoom out", 3, "click"], [1, "fa-solid", "fa-search-minus"], ["title", "Reset zoom", 3, "click"], [1, "fa-solid", "fa-compress"], [1, "zoom-level"], [1, "loading-overlay"], [3, "size", "min", "max", "collapsible"], [1, "fa-solid", "fa-spinner", "fa-spin"], [3, "closePanel", "navigateToActionLog", "copyToClipboard", "selectedTimelineItem"]], template: function AIAgentRunVisualizationComponent_Template(rf, ctx) { if (rf & 1) {
913
+ i0.ɵɵelementStart(0, "div", 1);
914
+ i0.ɵɵtemplate(1, AIAgentRunVisualizationComponent_Conditional_1_Template, 4, 1, "div", 2)(2, AIAgentRunVisualizationComponent_Conditional_2_Template, 19, 4, "kendo-splitter", 3);
915
+ i0.ɵɵelementEnd();
916
+ } if (rf & 2) {
917
+ i0.ɵɵadvance();
918
+ i0.ɵɵconditional(ctx.error ? 1 : 2);
919
+ } }, dependencies: [i2.SplitterComponent, i2.SplitterPaneComponent, i3.AIAgentRunStepDetailComponent], styles: [".visualization-container[_ngcontent-%COMP%] {\n width: 100%;\n height: 600px;\n min-height: 400px;\n position: relative;\n background: #f5f5f5;\n border: 1px solid #ddd;\n border-radius: 4px;\n overflow: hidden;\n}\n\n.loading-state[_ngcontent-%COMP%], .error-state[_ngcontent-%COMP%], .empty-state[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n justify-content: center;\n height: 100%;\n gap: 0.5rem;\n color: #666;\n}\n\n.error-state[_ngcontent-%COMP%] {\n color: #c00;\n}\n\n.empty-state[_ngcontent-%COMP%] {\n flex-direction: column;\n gap: 1rem;\n}\n\n.empty-state[_ngcontent-%COMP%] i[_ngcontent-%COMP%] {\n font-size: 2rem;\n opacity: 0.5;\n}\n\n.loading-overlay[_ngcontent-%COMP%] {\n position: absolute;\n top: 50%;\n left: 50%;\n transform: translate(-50%, -50%);\n display: flex;\n align-items: center;\n gap: 0.5rem;\n background: rgba(255, 255, 255, 0.9);\n padding: 1rem 2rem;\n border-radius: 4px;\n box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);\n z-index: 10;\n}\n\n.diagram-container[_ngcontent-%COMP%] {\n width: 100%;\n height: 100%;\n position: relative;\n overflow: hidden;\n background: #fafafa;\n}\n\n.diagram-toolbar[_ngcontent-%COMP%] {\n position: absolute;\n top: 10px;\n right: 10px;\n left: 10px;\n display: flex;\n justify-content: space-between;\n align-items: center;\n background: white;\n padding: 8px 12px;\n border-radius: 4px;\n box-shadow: 0 2px 4px rgba(0,0,0,0.1);\n z-index: 10;\n}\n\n.toolbar-title[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n gap: 8px;\n font-size: 14px;\n font-weight: 600;\n color: #2c3e50;\n}\n\n.zoom-controls[_ngcontent-%COMP%] {\n display: flex;\n gap: 4px;\n align-items: center;\n}\n\n.zoom-controls[_ngcontent-%COMP%] button[_ngcontent-%COMP%] {\n padding: 6px 10px;\n border: 1px solid #ddd;\n background: white;\n border-radius: 3px;\n cursor: pointer;\n font-size: 12px;\n display: flex;\n align-items: center;\n transition: all 0.2s;\n}\n\n.zoom-controls[_ngcontent-%COMP%] button[_ngcontent-%COMP%]:hover {\n background: #f0f0f0;\n border-color: #4a90e2;\n}\n\n.zoom-level[_ngcontent-%COMP%] {\n font-size: 12px;\n color: #666;\n margin-left: 8px;\n font-family: monospace;\n}\n\n.visualization-svg[_ngcontent-%COMP%] {\n width: 100%;\n height: 100%;\n cursor: grab;\n}\n\n.visualization-svg[_ngcontent-%COMP%]:active {\n cursor: grabbing;\n}\n\n\n\n[_nghost-%COMP%] .step-node {\n cursor: pointer;\n transition: transform 0.2s;\n}\n\n[_nghost-%COMP%] .step-node:hover {\n transform: scale(1.02);\n}\n\n[_nghost-%COMP%] .step-node.dragging {\n opacity: 0.8;\n cursor: move;\n}\n\n[_nghost-%COMP%] .step-node rect {\n filter: drop-shadow(0 2px 4px rgba(0,0,0,0.1));\n}\n\n[_nghost-%COMP%] .step-node:hover rect {\n filter: drop-shadow(0 4px 8px rgba(0,0,0,0.15));\n}\n\n[_nghost-%COMP%] .scope-container {\n cursor: pointer;\n}\n\n[_nghost-%COMP%] .scope-container rect {\n filter: drop-shadow(0 2px 4px rgba(0,0,0,0.1));\n}\n\n[_nghost-%COMP%] .expand-button:hover circle {\n fill: #e3f2fd;\n}\n\n[_nghost-%COMP%] .connections-group path {\n transition: stroke-width 0.2s;\n}\n\n[_nghost-%COMP%] .connections-group path:hover {\n stroke-width: 3;\n}\n\n\n\n[_nghost-%COMP%] .k-splitter {\n border: none;\n}\n\n[_nghost-%COMP%] .k-splitter-pane {\n overflow: visible;\n}\n\n[_nghost-%COMP%] .k-splitbar {\n background: #e0e6ed;\n width: 4px;\n}\n\n[_nghost-%COMP%] .k-splitbar:hover {\n background: #c1c9d2;\n}\n\n[_nghost-%COMP%] .k-splitbar-draggable-horizontal {\n cursor: col-resize;\n}\n\n\n\n[_nghost-%COMP%] .step-node[data-type=\"prompt\"] rect {\n fill: #e3f2fd;\n}\n\n[_nghost-%COMP%] .step-node[data-type=\"action\"] rect {\n fill: #e8f5e9;\n}\n\n[_nghost-%COMP%] .step-node[data-type=\"subagent\"] rect {\n fill: #fff3e0;\n}\n\n[_nghost-%COMP%] .step-node[data-type=\"tool\"] rect {\n fill: #f3e5f5;\n}\n\n[_nghost-%COMP%] .step-node[data-type=\"decision\"] rect {\n fill: #ffebee;\n}"] }); }
920
+ }
921
+ (() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassMetadata(AIAgentRunVisualizationComponent, [{
922
+ type: Component,
923
+ args: [{ selector: 'mj-ai-agent-run-visualization', template: "<div class=\"visualization-container\">\n @if (error) {\n <div class=\"error-state\">\n <i class=\"fa-solid fa-exclamation-triangle\"></i>\n <span>{{ error }}</span>\n </div>\n } @else {\n <kendo-splitter orientation=\"horizontal\" style=\"height: 100%;\">\n <!-- Diagram Pane -->\n <kendo-splitter-pane [collapsible]=\"false\">\n <div class=\"diagram-container\" #svgContainer>\n <div class=\"diagram-toolbar\">\n <div class=\"toolbar-title\">\n <i class=\"fa-solid fa-diagram-project\"></i>\n Agent Execution Flow\n </div>\n <div class=\"zoom-controls\">\n <button (click)=\"zoomIn()\" title=\"Zoom in\">\n <i class=\"fa-solid fa-search-plus\"></i>\n </button>\n <button (click)=\"zoomOut()\" title=\"Zoom out\">\n <i class=\"fa-solid fa-search-minus\"></i>\n </button>\n <button (click)=\"resetZoom()\" title=\"Reset zoom\">\n <i class=\"fa-solid fa-compress\"></i>\n </button>\n <span class=\"zoom-level\">{{ (panZoom.scale * 100).toFixed(0) }}%</span>\n </div>\n </div>\n @if (loading) {\n <div class=\"loading-overlay\">\n <i class=\"fa-solid fa-spinner fa-spin\"></i>\n <span>Loading visualization...</span>\n </div>\n }\n </div>\n </kendo-splitter-pane>\n \n <!-- Detail Pane -->\n @if (selectedItem) {\n <kendo-splitter-pane [size]=\"'400px'\" [min]=\"'300px'\" [max]=\"'600px'\" [collapsible]=\"true\">\n <mj-ai-agent-run-step-detail\n [selectedTimelineItem]=\"selectedItem\"\n (closePanel)=\"closeDetailPane()\"\n (navigateToActionLog)=\"navigateToActionLog($event)\"\n (copyToClipboard)=\"copyToClipboard($event)\">\n </mj-ai-agent-run-step-detail>\n </kendo-splitter-pane>\n }\n </kendo-splitter>\n }\n</div>", styles: [".visualization-container {\n width: 100%;\n height: 600px;\n min-height: 400px;\n position: relative;\n background: #f5f5f5;\n border: 1px solid #ddd;\n border-radius: 4px;\n overflow: hidden;\n}\n\n.loading-state, .error-state, .empty-state {\n display: flex;\n align-items: center;\n justify-content: center;\n height: 100%;\n gap: 0.5rem;\n color: #666;\n}\n\n.error-state {\n color: #c00;\n}\n\n.empty-state {\n flex-direction: column;\n gap: 1rem;\n}\n\n.empty-state i {\n font-size: 2rem;\n opacity: 0.5;\n}\n\n.loading-overlay {\n position: absolute;\n top: 50%;\n left: 50%;\n transform: translate(-50%, -50%);\n display: flex;\n align-items: center;\n gap: 0.5rem;\n background: rgba(255, 255, 255, 0.9);\n padding: 1rem 2rem;\n border-radius: 4px;\n box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);\n z-index: 10;\n}\n\n.diagram-container {\n width: 100%;\n height: 100%;\n position: relative;\n overflow: hidden;\n background: #fafafa;\n}\n\n.diagram-toolbar {\n position: absolute;\n top: 10px;\n right: 10px;\n left: 10px;\n display: flex;\n justify-content: space-between;\n align-items: center;\n background: white;\n padding: 8px 12px;\n border-radius: 4px;\n box-shadow: 0 2px 4px rgba(0,0,0,0.1);\n z-index: 10;\n}\n\n.toolbar-title {\n display: flex;\n align-items: center;\n gap: 8px;\n font-size: 14px;\n font-weight: 600;\n color: #2c3e50;\n}\n\n.zoom-controls {\n display: flex;\n gap: 4px;\n align-items: center;\n}\n\n.zoom-controls button {\n padding: 6px 10px;\n border: 1px solid #ddd;\n background: white;\n border-radius: 3px;\n cursor: pointer;\n font-size: 12px;\n display: flex;\n align-items: center;\n transition: all 0.2s;\n}\n\n.zoom-controls button:hover {\n background: #f0f0f0;\n border-color: #4a90e2;\n}\n\n.zoom-level {\n font-size: 12px;\n color: #666;\n margin-left: 8px;\n font-family: monospace;\n}\n\n.visualization-svg {\n width: 100%;\n height: 100%;\n cursor: grab;\n}\n\n.visualization-svg:active {\n cursor: grabbing;\n}\n\n/* SVG Styles */\n:host ::ng-deep .step-node {\n cursor: pointer;\n transition: transform 0.2s;\n}\n\n:host ::ng-deep .step-node:hover {\n transform: scale(1.02);\n}\n\n:host ::ng-deep .step-node.dragging {\n opacity: 0.8;\n cursor: move;\n}\n\n:host ::ng-deep .step-node rect {\n filter: drop-shadow(0 2px 4px rgba(0,0,0,0.1));\n}\n\n:host ::ng-deep .step-node:hover rect {\n filter: drop-shadow(0 4px 8px rgba(0,0,0,0.15));\n}\n\n:host ::ng-deep .scope-container {\n cursor: pointer;\n}\n\n:host ::ng-deep .scope-container rect {\n filter: drop-shadow(0 2px 4px rgba(0,0,0,0.1));\n}\n\n:host ::ng-deep .expand-button:hover circle {\n fill: #e3f2fd;\n}\n\n:host ::ng-deep .connections-group path {\n transition: stroke-width 0.2s;\n}\n\n:host ::ng-deep .connections-group path:hover {\n stroke-width: 3;\n}\n\n/* Splitter customization */\n:host ::ng-deep .k-splitter {\n border: none;\n}\n\n:host ::ng-deep .k-splitter-pane {\n overflow: visible;\n}\n\n:host ::ng-deep .k-splitbar {\n background: #e0e6ed;\n width: 4px;\n}\n\n:host ::ng-deep .k-splitbar:hover {\n background: #c1c9d2;\n}\n\n:host ::ng-deep .k-splitbar-draggable-horizontal {\n cursor: col-resize;\n}\n\n/* Node type colors */\n:host ::ng-deep .step-node[data-type=\"prompt\"] rect {\n fill: #e3f2fd;\n}\n\n:host ::ng-deep .step-node[data-type=\"action\"] rect {\n fill: #e8f5e9;\n}\n\n:host ::ng-deep .step-node[data-type=\"subagent\"] rect {\n fill: #fff3e0;\n}\n\n:host ::ng-deep .step-node[data-type=\"tool\"] rect {\n fill: #f3e5f5;\n}\n\n:host ::ng-deep .step-node[data-type=\"decision\"] rect {\n fill: #ffebee;\n}"] }]
924
+ }], () => [{ type: i0.ChangeDetectorRef }, { type: i1.AIAgentRunDataService }], { svgContainer: [{
925
+ type: ViewChild,
926
+ args: ['svgContainer', { static: false }]
927
+ }], aiAgentRunId: [{
928
+ type: Input
929
+ }] }); })();
930
+ (() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassDebugInfo(AIAgentRunVisualizationComponent, { className: "AIAgentRunVisualizationComponent", filePath: "src/lib/custom/ai-agent-run/ai-agent-run-visualization.component.ts", lineNumber: 34 }); })();
931
+ //# sourceMappingURL=ai-agent-run-visualization.component.js.map