@memberjunction/ng-dashboards 2.47.0 → 2.49.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.
- package/README.md +105 -2
- package/dist/AI/ai-dashboard.component.d.ts +2 -0
- package/dist/AI/ai-dashboard.component.d.ts.map +1 -1
- package/dist/AI/ai-dashboard.component.js +66 -43
- package/dist/AI/ai-dashboard.component.js.map +1 -1
- package/dist/AI/components/agents/agent-configuration.component.js +45 -58
- package/dist/AI/components/agents/agent-configuration.component.js.map +1 -1
- package/dist/AI/components/agents/agent-editor.component.d.ts +6 -1
- package/dist/AI/components/agents/agent-editor.component.d.ts.map +1 -1
- package/dist/AI/components/agents/agent-editor.component.js +368 -366
- package/dist/AI/components/agents/agent-editor.component.js.map +1 -1
- package/dist/AI/components/agents/agent-filter-panel.component.js +83 -85
- package/dist/AI/components/agents/agent-filter-panel.component.js.map +1 -1
- package/dist/AI/components/charts/performance-heatmap.component.d.ts +66 -0
- package/dist/AI/components/charts/performance-heatmap.component.d.ts.map +1 -0
- package/dist/AI/components/charts/performance-heatmap.component.js +428 -0
- package/dist/AI/components/charts/performance-heatmap.component.js.map +1 -0
- package/dist/AI/components/charts/time-series-chart.component.d.ts +66 -0
- package/dist/AI/components/charts/time-series-chart.component.d.ts.map +1 -0
- package/dist/AI/components/charts/time-series-chart.component.js +547 -0
- package/dist/AI/components/charts/time-series-chart.component.js.map +1 -0
- package/dist/AI/components/execution-monitoring.component.d.ts +157 -5
- package/dist/AI/components/execution-monitoring.component.d.ts.map +1 -1
- package/dist/AI/components/execution-monitoring.component.js +2032 -20
- package/dist/AI/components/execution-monitoring.component.js.map +1 -1
- package/dist/AI/components/models/model-management.component.js +211 -237
- package/dist/AI/components/models/model-management.component.js.map +1 -1
- package/dist/AI/components/prompts/model-prompt-priority-matrix.component.js +208 -226
- package/dist/AI/components/prompts/model-prompt-priority-matrix.component.js.map +1 -1
- package/dist/AI/components/prompts/prompt-filter-panel.component.js +97 -99
- package/dist/AI/components/prompts/prompt-filter-panel.component.js.map +1 -1
- package/dist/AI/components/prompts/prompt-management.component.js +381 -424
- package/dist/AI/components/prompts/prompt-management.component.js.map +1 -1
- package/dist/AI/components/prompts/prompt-version-control.component.js +173 -191
- package/dist/AI/components/prompts/prompt-version-control.component.js.map +1 -1
- package/dist/AI/components/system/system-config-filter-panel.component.js +85 -87
- package/dist/AI/components/system/system-config-filter-panel.component.js.map +1 -1
- package/dist/AI/components/system/system-configuration.component.js +86 -99
- package/dist/AI/components/system/system-configuration.component.js.map +1 -1
- package/dist/AI/components/widgets/kpi-card.component.d.ts +25 -0
- package/dist/AI/components/widgets/kpi-card.component.d.ts.map +1 -0
- package/dist/AI/components/widgets/kpi-card.component.js +163 -0
- package/dist/AI/components/widgets/kpi-card.component.js.map +1 -0
- package/dist/AI/components/widgets/live-execution-widget.component.d.ts +25 -0
- package/dist/AI/components/widgets/live-execution-widget.component.d.ts.map +1 -0
- package/dist/AI/components/widgets/live-execution-widget.component.js +298 -0
- package/dist/AI/components/widgets/live-execution-widget.component.js.map +1 -0
- package/dist/AI/index.d.ts +7 -0
- package/dist/AI/index.d.ts.map +1 -0
- package/dist/AI/index.js +9 -0
- package/dist/AI/index.js.map +1 -0
- package/dist/AI/services/ai-instrumentation.service.d.ts +109 -0
- package/dist/AI/services/ai-instrumentation.service.d.ts.map +1 -0
- package/dist/AI/services/ai-instrumentation.service.js +490 -0
- package/dist/AI/services/ai-instrumentation.service.js.map +1 -0
- package/dist/Actions/actions-management-dashboard.component.js +40 -41
- package/dist/Actions/actions-management-dashboard.component.js.map +1 -1
- package/dist/Actions/components/actions-list-view.component.js +117 -134
- package/dist/Actions/components/actions-list-view.component.js.map +1 -1
- package/dist/Actions/components/actions-overview.component.js +274 -296
- package/dist/Actions/components/actions-overview.component.js.map +1 -1
- package/dist/Actions/components/categories-list-view.component.js +12 -14
- package/dist/Actions/components/categories-list-view.component.js.map +1 -1
- package/dist/Actions/components/code-management.component.js +12 -14
- package/dist/Actions/components/code-management.component.js.map +1 -1
- package/dist/Actions/components/entity-integration.component.js +12 -14
- package/dist/Actions/components/entity-integration.component.js.map +1 -1
- package/dist/Actions/components/execution-monitoring.component.js +238 -256
- package/dist/Actions/components/execution-monitoring.component.js.map +1 -1
- package/dist/Actions/components/executions-list-view.component.js +12 -14
- package/dist/Actions/components/executions-list-view.component.js.map +1 -1
- package/dist/Actions/components/scheduled-actions.component.js +12 -14
- package/dist/Actions/components/scheduled-actions.component.js.map +1 -1
- package/dist/Actions/components/security-permissions.component.js +12 -14
- package/dist/Actions/components/security-permissions.component.js.map +1 -1
- package/dist/EntityAdmin/components/entity-details.component.js +105 -107
- package/dist/EntityAdmin/components/entity-details.component.js.map +1 -1
- package/dist/EntityAdmin/components/entity-filter-panel.component.js +100 -102
- package/dist/EntityAdmin/components/entity-filter-panel.component.js.map +1 -1
- package/dist/EntityAdmin/components/erd-composite.component.js +84 -100
- package/dist/EntityAdmin/components/erd-composite.component.js.map +1 -1
- package/dist/EntityAdmin/components/erd-diagram.component.js +50 -50
- package/dist/EntityAdmin/components/erd-diagram.component.js.map +1 -1
- package/dist/EntityAdmin/entity-admin-dashboard.component.js +45 -49
- package/dist/EntityAdmin/entity-admin-dashboard.component.js.map +1 -1
- package/dist/generic/base-dashboard.js +28 -40
- package/dist/generic/base-dashboard.js.map +1 -1
- package/dist/module.d.ts +16 -12
- package/dist/module.d.ts.map +1 -1
- package/dist/module.js +36 -15
- package/dist/module.js.map +1 -1
- package/package.json +6 -6
|
@@ -1,30 +1,2042 @@
|
|
|
1
|
-
import { Component, Output, EventEmitter } from '@angular/core';
|
|
1
|
+
import { Component, Output, EventEmitter, Input } from '@angular/core';
|
|
2
|
+
import { Subject } from 'rxjs';
|
|
3
|
+
import { map, takeUntil, debounceTime } from 'rxjs/operators';
|
|
4
|
+
import { RunView } from '@memberjunction/core';
|
|
2
5
|
import * as i0 from "@angular/core";
|
|
6
|
+
import * as i1 from "../services/ai-instrumentation.service";
|
|
7
|
+
import * as i2 from "@angular/forms";
|
|
8
|
+
import * as i3 from "@progress/kendo-angular-layout";
|
|
9
|
+
import * as i4 from "./widgets/kpi-card.component";
|
|
10
|
+
import * as i5 from "./widgets/live-execution-widget.component";
|
|
11
|
+
import * as i6 from "./charts/time-series-chart.component";
|
|
12
|
+
import * as i7 from "./charts/performance-heatmap.component";
|
|
13
|
+
import * as i8 from "@angular/common";
|
|
14
|
+
const _forTrack0 = ($index, $item) => $item.title;
|
|
15
|
+
const _forTrack1 = ($index, $item) => $item.id;
|
|
16
|
+
const _forTrack2 = ($index, $item) => $item.model;
|
|
17
|
+
const _c0 = () => [];
|
|
18
|
+
function ExecutionMonitoringComponent_For_40_Template(rf, ctx) { if (rf & 1) {
|
|
19
|
+
const _r1 = i0.ɵɵgetCurrentView();
|
|
20
|
+
i0.ɵɵelementStart(0, "app-kpi-card", 52);
|
|
21
|
+
i0.ɵɵlistener("click", function ExecutionMonitoringComponent_For_40_Template_app_kpi_card_click_0_listener() { const kpi_r2 = i0.ɵɵrestoreView(_r1).$implicit; const ctx_r2 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r2.onKpiClick(kpi_r2)); });
|
|
22
|
+
i0.ɵɵelementEnd();
|
|
23
|
+
} if (rf & 2) {
|
|
24
|
+
const kpi_r2 = ctx.$implicit;
|
|
25
|
+
const ctx_r2 = i0.ɵɵnextContext();
|
|
26
|
+
i0.ɵɵclassProp("clickable", ctx_r2.isKpiClickable(kpi_r2));
|
|
27
|
+
i0.ɵɵproperty("data", kpi_r2);
|
|
28
|
+
} }
|
|
29
|
+
function ExecutionMonitoringComponent_Conditional_52_Template(rf, ctx) { if (rf & 1) {
|
|
30
|
+
i0.ɵɵelementStart(0, "div", 28)(1, "div", 53)(2, "div", 54);
|
|
31
|
+
i0.ɵɵelement(3, "i", 55);
|
|
32
|
+
i0.ɵɵelementEnd();
|
|
33
|
+
i0.ɵɵelementStart(4, "div", 56)(5, "div", 57);
|
|
34
|
+
i0.ɵɵtext(6, "Success Rate");
|
|
35
|
+
i0.ɵɵelementEnd();
|
|
36
|
+
i0.ɵɵelementStart(7, "div", 58);
|
|
37
|
+
i0.ɵɵtext(8);
|
|
38
|
+
i0.ɵɵelementEnd();
|
|
39
|
+
i0.ɵɵelementStart(9, "div", 59);
|
|
40
|
+
i0.ɵɵtext(10);
|
|
41
|
+
i0.ɵɵelementEnd()()();
|
|
42
|
+
i0.ɵɵelementStart(11, "div", 53)(12, "div", 60);
|
|
43
|
+
i0.ɵɵelement(13, "i", 61);
|
|
44
|
+
i0.ɵɵelementEnd();
|
|
45
|
+
i0.ɵɵelementStart(14, "div", 56)(15, "div", 57);
|
|
46
|
+
i0.ɵɵtext(16, "Error Rate");
|
|
47
|
+
i0.ɵɵelementEnd();
|
|
48
|
+
i0.ɵɵelementStart(17, "div", 58);
|
|
49
|
+
i0.ɵɵtext(18);
|
|
50
|
+
i0.ɵɵelementEnd();
|
|
51
|
+
i0.ɵɵelementStart(19, "div", 59);
|
|
52
|
+
i0.ɵɵtext(20);
|
|
53
|
+
i0.ɵɵelementEnd()()();
|
|
54
|
+
i0.ɵɵelementStart(21, "div", 53)(22, "div", 62);
|
|
55
|
+
i0.ɵɵelement(23, "i", 63);
|
|
56
|
+
i0.ɵɵelementEnd();
|
|
57
|
+
i0.ɵɵelementStart(24, "div", 56)(25, "div", 57);
|
|
58
|
+
i0.ɵɵtext(26, "Avg Response Time");
|
|
59
|
+
i0.ɵɵelementEnd();
|
|
60
|
+
i0.ɵɵelementStart(27, "div", 58);
|
|
61
|
+
i0.ɵɵtext(28);
|
|
62
|
+
i0.ɵɵelementEnd();
|
|
63
|
+
i0.ɵɵelementStart(29, "div", 59);
|
|
64
|
+
i0.ɵɵtext(30, "Across all models");
|
|
65
|
+
i0.ɵɵelementEnd()()();
|
|
66
|
+
i0.ɵɵelementStart(31, "div", 53)(32, "div", 64);
|
|
67
|
+
i0.ɵɵelement(33, "i", 49);
|
|
68
|
+
i0.ɵɵelementEnd();
|
|
69
|
+
i0.ɵɵelementStart(34, "div", 56)(35, "div", 57);
|
|
70
|
+
i0.ɵɵtext(36, "Active Executions");
|
|
71
|
+
i0.ɵɵelementEnd();
|
|
72
|
+
i0.ɵɵelementStart(37, "div", 58);
|
|
73
|
+
i0.ɵɵtext(38);
|
|
74
|
+
i0.ɵɵelementEnd();
|
|
75
|
+
i0.ɵɵelementStart(39, "div", 59);
|
|
76
|
+
i0.ɵɵtext(40, "Currently running");
|
|
77
|
+
i0.ɵɵelementEnd()()()();
|
|
78
|
+
} if (rf & 2) {
|
|
79
|
+
const kpis_r4 = ctx;
|
|
80
|
+
const ctx_r2 = i0.ɵɵnextContext();
|
|
81
|
+
i0.ɵɵadvance(8);
|
|
82
|
+
i0.ɵɵtextInterpolate1("", (kpis_r4.successRate * 100).toFixed(1), "%");
|
|
83
|
+
i0.ɵɵadvance(2);
|
|
84
|
+
i0.ɵɵtextInterpolate1("Last ", ctx_r2.selectedTimeRange, "");
|
|
85
|
+
i0.ɵɵadvance(8);
|
|
86
|
+
i0.ɵɵtextInterpolate1("", (kpis_r4.errorRate * 100).toFixed(1), "%");
|
|
87
|
+
i0.ɵɵadvance(2);
|
|
88
|
+
i0.ɵɵtextInterpolate1("", kpis_r4.totalExecutions, " total executions");
|
|
89
|
+
i0.ɵɵadvance(8);
|
|
90
|
+
i0.ɵɵtextInterpolate1("", (kpis_r4.avgExecutionTime / 1000).toFixed(2), "s");
|
|
91
|
+
i0.ɵɵadvance(10);
|
|
92
|
+
i0.ɵɵtextInterpolate(kpis_r4.activeExecutions);
|
|
93
|
+
} }
|
|
94
|
+
function ExecutionMonitoringComponent_For_59_Conditional_3_Template(rf, ctx) { if (rf & 1) {
|
|
95
|
+
const _r7 = i0.ɵɵgetCurrentView();
|
|
96
|
+
i0.ɵɵelementStart(0, "button", 68);
|
|
97
|
+
i0.ɵɵlistener("click", function ExecutionMonitoringComponent_For_59_Conditional_3_Template_button_click_0_listener($event) { i0.ɵɵrestoreView(_r7); const tab_r6 = i0.ɵɵnextContext().$implicit; const ctx_r2 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r2.closeTab($event, tab_r6.id)); });
|
|
98
|
+
i0.ɵɵelement(1, "i", 69);
|
|
99
|
+
i0.ɵɵelementEnd();
|
|
100
|
+
} }
|
|
101
|
+
function ExecutionMonitoringComponent_For_59_Template(rf, ctx) { if (rf & 1) {
|
|
102
|
+
const _r5 = i0.ɵɵgetCurrentView();
|
|
103
|
+
i0.ɵɵelementStart(0, "div", 65);
|
|
104
|
+
i0.ɵɵlistener("click", function ExecutionMonitoringComponent_For_59_Template_div_click_0_listener() { const tab_r6 = i0.ɵɵrestoreView(_r5).$implicit; const ctx_r2 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r2.selectTab(tab_r6.id)); });
|
|
105
|
+
i0.ɵɵelementStart(1, "span", 66);
|
|
106
|
+
i0.ɵɵtext(2);
|
|
107
|
+
i0.ɵɵelementEnd();
|
|
108
|
+
i0.ɵɵtemplate(3, ExecutionMonitoringComponent_For_59_Conditional_3_Template, 2, 0, "button", 67);
|
|
109
|
+
i0.ɵɵelementEnd();
|
|
110
|
+
} if (rf & 2) {
|
|
111
|
+
const tab_r6 = ctx.$implicit;
|
|
112
|
+
const ctx_r2 = i0.ɵɵnextContext();
|
|
113
|
+
i0.ɵɵclassProp("active", ctx_r2.activeTabId === tab_r6.id);
|
|
114
|
+
i0.ɵɵadvance(2);
|
|
115
|
+
i0.ɵɵtextInterpolate(tab_r6.title);
|
|
116
|
+
i0.ɵɵadvance();
|
|
117
|
+
i0.ɵɵconditional(tab_r6.closeable ? 3 : -1);
|
|
118
|
+
} }
|
|
119
|
+
function ExecutionMonitoringComponent_Conditional_61_Template(rf, ctx) { if (rf & 1) {
|
|
120
|
+
const _r8 = i0.ɵɵgetCurrentView();
|
|
121
|
+
i0.ɵɵelementStart(0, "div", 35)(1, "app-time-series-chart", 70);
|
|
122
|
+
i0.ɵɵpipe(2, "async");
|
|
123
|
+
i0.ɵɵlistener("dataPointClick", function ExecutionMonitoringComponent_Conditional_61_Template_app_time_series_chart_dataPointClick_1_listener($event) { i0.ɵɵrestoreView(_r8); const ctx_r2 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r2.onDataPointClick($event)); })("timeRangeChange", function ExecutionMonitoringComponent_Conditional_61_Template_app_time_series_chart_timeRangeChange_1_listener($event) { i0.ɵɵrestoreView(_r8); const ctx_r2 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r2.onChartTimeRangeChange($event)); });
|
|
124
|
+
i0.ɵɵelementEnd()();
|
|
125
|
+
} if (rf & 2) {
|
|
126
|
+
let tmp_1_0;
|
|
127
|
+
const ctx_r2 = i0.ɵɵnextContext();
|
|
128
|
+
i0.ɵɵadvance();
|
|
129
|
+
i0.ɵɵproperty("data", (tmp_1_0 = i0.ɵɵpipeBind1(2, 2, ctx_r2.trends$)) !== null && tmp_1_0 !== undefined ? tmp_1_0 : i0.ɵɵpureFunction0(4, _c0))("config", ctx_r2.timeSeriesConfig);
|
|
130
|
+
} }
|
|
131
|
+
function ExecutionMonitoringComponent_Conditional_62_Conditional_6_Template(rf, ctx) { if (rf & 1) {
|
|
132
|
+
i0.ɵɵelementStart(0, "span", 74);
|
|
133
|
+
i0.ɵɵtext(1);
|
|
134
|
+
i0.ɵɵelementEnd();
|
|
135
|
+
} if (rf & 2) {
|
|
136
|
+
const ctx_r2 = i0.ɵɵnextContext(2);
|
|
137
|
+
i0.ɵɵadvance();
|
|
138
|
+
i0.ɵɵtextInterpolate(ctx_r2.getFormattedTimestamp(ctx_r2.activeTab));
|
|
139
|
+
} }
|
|
140
|
+
function ExecutionMonitoringComponent_Conditional_62_Conditional_7_Template(rf, ctx) { if (rf & 1) {
|
|
141
|
+
i0.ɵɵelementStart(0, "span", 75);
|
|
142
|
+
i0.ɵɵtext(1);
|
|
143
|
+
i0.ɵɵelementEnd();
|
|
144
|
+
} if (rf & 2) {
|
|
145
|
+
const ctx_r2 = i0.ɵɵnextContext(2);
|
|
146
|
+
i0.ɵɵadvance();
|
|
147
|
+
i0.ɵɵtextInterpolate(ctx_r2.getFormattedMetricLabel(ctx_r2.activeTab));
|
|
148
|
+
} }
|
|
149
|
+
function ExecutionMonitoringComponent_Conditional_62_Conditional_8_Template(rf, ctx) { if (rf & 1) {
|
|
150
|
+
i0.ɵɵelementStart(0, "div", 76);
|
|
151
|
+
i0.ɵɵelement(1, "i", 79);
|
|
152
|
+
i0.ɵɵtext(2, " Loading execution details... ");
|
|
153
|
+
i0.ɵɵelementEnd();
|
|
154
|
+
} }
|
|
155
|
+
function ExecutionMonitoringComponent_Conditional_62_Conditional_9_For_19_Template(rf, ctx) { if (rf & 1) {
|
|
156
|
+
const _r9 = i0.ɵɵgetCurrentView();
|
|
157
|
+
i0.ɵɵelementStart(0, "div", 83);
|
|
158
|
+
i0.ɵɵlistener("click", function ExecutionMonitoringComponent_Conditional_62_Conditional_9_For_19_Template_div_click_0_listener() { const execution_r10 = i0.ɵɵrestoreView(_r9).$implicit; const ctx_r2 = i0.ɵɵnextContext(3); return i0.ɵɵresetView(ctx_r2.viewExecutionDetail(execution_r10)); });
|
|
159
|
+
i0.ɵɵelementStart(1, "div", 84)(2, "span", 85);
|
|
160
|
+
i0.ɵɵtext(3);
|
|
161
|
+
i0.ɵɵelementEnd()();
|
|
162
|
+
i0.ɵɵelementStart(4, "div", 84);
|
|
163
|
+
i0.ɵɵtext(5);
|
|
164
|
+
i0.ɵɵelementEnd();
|
|
165
|
+
i0.ɵɵelementStart(6, "div", 84);
|
|
166
|
+
i0.ɵɵtext(7);
|
|
167
|
+
i0.ɵɵelementEnd();
|
|
168
|
+
i0.ɵɵelementStart(8, "div", 84)(9, "span", 86);
|
|
169
|
+
i0.ɵɵtext(10);
|
|
170
|
+
i0.ɵɵelementEnd()();
|
|
171
|
+
i0.ɵɵelementStart(11, "div", 84);
|
|
172
|
+
i0.ɵɵtext(12);
|
|
173
|
+
i0.ɵɵelementEnd();
|
|
174
|
+
i0.ɵɵelementStart(13, "div", 84);
|
|
175
|
+
i0.ɵɵtext(14);
|
|
176
|
+
i0.ɵɵelementEnd();
|
|
177
|
+
i0.ɵɵelementStart(15, "div", 84);
|
|
178
|
+
i0.ɵɵtext(16);
|
|
179
|
+
i0.ɵɵelementEnd();
|
|
180
|
+
i0.ɵɵelementStart(17, "div", 84);
|
|
181
|
+
i0.ɵɵtext(18);
|
|
182
|
+
i0.ɵɵelementEnd()();
|
|
183
|
+
} if (rf & 2) {
|
|
184
|
+
const execution_r10 = ctx.$implicit;
|
|
185
|
+
const ctx_r2 = i0.ɵɵnextContext(3);
|
|
186
|
+
i0.ɵɵadvance(2);
|
|
187
|
+
i0.ɵɵclassMap("type-badge--" + execution_r10.type);
|
|
188
|
+
i0.ɵɵadvance();
|
|
189
|
+
i0.ɵɵtextInterpolate1(" ", execution_r10.type, " ");
|
|
190
|
+
i0.ɵɵadvance(2);
|
|
191
|
+
i0.ɵɵtextInterpolate(execution_r10.name);
|
|
192
|
+
i0.ɵɵadvance(2);
|
|
193
|
+
i0.ɵɵtextInterpolate(execution_r10.model || "N/A");
|
|
194
|
+
i0.ɵɵadvance(2);
|
|
195
|
+
i0.ɵɵclassMap("status-badge--" + execution_r10.status);
|
|
196
|
+
i0.ɵɵadvance();
|
|
197
|
+
i0.ɵɵtextInterpolate1(" ", execution_r10.status, " ");
|
|
198
|
+
i0.ɵɵadvance(2);
|
|
199
|
+
i0.ɵɵtextInterpolate(ctx_r2.formatDuration(execution_r10.duration));
|
|
200
|
+
i0.ɵɵadvance(2);
|
|
201
|
+
i0.ɵɵtextInterpolate(ctx_r2.formatCurrency(execution_r10.cost));
|
|
202
|
+
i0.ɵɵadvance(2);
|
|
203
|
+
i0.ɵɵtextInterpolate(execution_r10.tokens.toLocaleString());
|
|
204
|
+
i0.ɵɵadvance(2);
|
|
205
|
+
i0.ɵɵtextInterpolate(ctx_r2.formatTime(execution_r10.startTime));
|
|
206
|
+
} }
|
|
207
|
+
function ExecutionMonitoringComponent_Conditional_62_Conditional_9_Template(rf, ctx) { if (rf & 1) {
|
|
208
|
+
i0.ɵɵelementStart(0, "div", 77)(1, "div", 80)(2, "div", 81);
|
|
209
|
+
i0.ɵɵtext(3, "Type");
|
|
210
|
+
i0.ɵɵelementEnd();
|
|
211
|
+
i0.ɵɵelementStart(4, "div", 81);
|
|
212
|
+
i0.ɵɵtext(5, "Name");
|
|
213
|
+
i0.ɵɵelementEnd();
|
|
214
|
+
i0.ɵɵelementStart(6, "div", 81);
|
|
215
|
+
i0.ɵɵtext(7, "Model");
|
|
216
|
+
i0.ɵɵelementEnd();
|
|
217
|
+
i0.ɵɵelementStart(8, "div", 81);
|
|
218
|
+
i0.ɵɵtext(9, "Status");
|
|
219
|
+
i0.ɵɵelementEnd();
|
|
220
|
+
i0.ɵɵelementStart(10, "div", 81);
|
|
221
|
+
i0.ɵɵtext(11, "Duration");
|
|
222
|
+
i0.ɵɵelementEnd();
|
|
223
|
+
i0.ɵɵelementStart(12, "div", 81);
|
|
224
|
+
i0.ɵɵtext(13, "Cost");
|
|
225
|
+
i0.ɵɵelementEnd();
|
|
226
|
+
i0.ɵɵelementStart(14, "div", 81);
|
|
227
|
+
i0.ɵɵtext(15, "Tokens");
|
|
228
|
+
i0.ɵɵelementEnd();
|
|
229
|
+
i0.ɵɵelementStart(16, "div", 81);
|
|
230
|
+
i0.ɵɵtext(17, "Time");
|
|
231
|
+
i0.ɵɵelementEnd()();
|
|
232
|
+
i0.ɵɵrepeaterCreate(18, ExecutionMonitoringComponent_Conditional_62_Conditional_9_For_19_Template, 19, 12, "div", 82, _forTrack1);
|
|
233
|
+
i0.ɵɵelementEnd();
|
|
234
|
+
} if (rf & 2) {
|
|
235
|
+
const ctx_r2 = i0.ɵɵnextContext(2);
|
|
236
|
+
i0.ɵɵadvance(18);
|
|
237
|
+
i0.ɵɵrepeater(ctx_r2.activeTab == null ? null : ctx_r2.activeTab.data);
|
|
238
|
+
} }
|
|
239
|
+
function ExecutionMonitoringComponent_Conditional_62_Conditional_10_Template(rf, ctx) { if (rf & 1) {
|
|
240
|
+
i0.ɵɵelementStart(0, "div", 78);
|
|
241
|
+
i0.ɵɵelement(1, "i", 87);
|
|
242
|
+
i0.ɵɵelementStart(2, "p");
|
|
243
|
+
i0.ɵɵtext(3, "No executions found for this time period");
|
|
244
|
+
i0.ɵɵelementEnd()();
|
|
245
|
+
} }
|
|
246
|
+
function ExecutionMonitoringComponent_Conditional_62_Template(rf, ctx) { if (rf & 1) {
|
|
247
|
+
i0.ɵɵelementStart(0, "div", 36)(1, "div", 71)(2, "h4");
|
|
248
|
+
i0.ɵɵelement(3, "i", 72);
|
|
249
|
+
i0.ɵɵtext(4);
|
|
250
|
+
i0.ɵɵelementEnd();
|
|
251
|
+
i0.ɵɵelementStart(5, "div", 73);
|
|
252
|
+
i0.ɵɵtemplate(6, ExecutionMonitoringComponent_Conditional_62_Conditional_6_Template, 2, 1, "span", 74)(7, ExecutionMonitoringComponent_Conditional_62_Conditional_7_Template, 2, 1, "span", 75);
|
|
253
|
+
i0.ɵɵelementEnd()();
|
|
254
|
+
i0.ɵɵtemplate(8, ExecutionMonitoringComponent_Conditional_62_Conditional_8_Template, 3, 0, "div", 76)(9, ExecutionMonitoringComponent_Conditional_62_Conditional_9_Template, 20, 0, "div", 77)(10, ExecutionMonitoringComponent_Conditional_62_Conditional_10_Template, 4, 0, "div", 78);
|
|
255
|
+
i0.ɵɵelementEnd();
|
|
256
|
+
} if (rf & 2) {
|
|
257
|
+
const ctx_r2 = i0.ɵɵnextContext();
|
|
258
|
+
i0.ɵɵadvance(4);
|
|
259
|
+
i0.ɵɵtextInterpolate1(" ", ctx_r2.activeTab == null ? null : ctx_r2.activeTab.title, " ");
|
|
260
|
+
i0.ɵɵadvance(2);
|
|
261
|
+
i0.ɵɵconditional((ctx_r2.activeTab == null ? null : ctx_r2.activeTab.timestamp) ? 6 : -1);
|
|
262
|
+
i0.ɵɵadvance();
|
|
263
|
+
i0.ɵɵconditional((ctx_r2.activeTab == null ? null : ctx_r2.activeTab.metric) ? 7 : -1);
|
|
264
|
+
i0.ɵɵadvance();
|
|
265
|
+
i0.ɵɵconditional(ctx_r2.loadingDrillDown ? 8 : (ctx_r2.activeTab == null ? null : ctx_r2.activeTab.data == null ? null : ctx_r2.activeTab.data.length) > 0 ? 9 : 10);
|
|
266
|
+
} }
|
|
267
|
+
function ExecutionMonitoringComponent_Conditional_63_Conditional_5_Template(rf, ctx) { if (rf & 1) {
|
|
268
|
+
i0.ɵɵelementStart(0, "div", 76);
|
|
269
|
+
i0.ɵɵelement(1, "i", 79);
|
|
270
|
+
i0.ɵɵtext(2, " Loading model details... ");
|
|
271
|
+
i0.ɵɵelementEnd();
|
|
272
|
+
} }
|
|
273
|
+
function ExecutionMonitoringComponent_Conditional_63_Conditional_6_Conditional_32_Template(rf, ctx) { if (rf & 1) {
|
|
274
|
+
i0.ɵɵelementStart(0, "div", 93)(1, "h5");
|
|
275
|
+
i0.ɵɵtext(2, "Description");
|
|
276
|
+
i0.ɵɵelementEnd();
|
|
277
|
+
i0.ɵɵelementStart(3, "p");
|
|
278
|
+
i0.ɵɵtext(4);
|
|
279
|
+
i0.ɵɵelementEnd()();
|
|
280
|
+
} if (rf & 2) {
|
|
281
|
+
const ctx_r2 = i0.ɵɵnextContext(3);
|
|
282
|
+
i0.ɵɵadvance(4);
|
|
283
|
+
i0.ɵɵtextInterpolate(ctx_r2.activeTab == null ? null : ctx_r2.activeTab.data == null ? null : ctx_r2.activeTab.data.description);
|
|
284
|
+
} }
|
|
285
|
+
function ExecutionMonitoringComponent_Conditional_63_Conditional_6_Template(rf, ctx) { if (rf & 1) {
|
|
286
|
+
i0.ɵɵelementStart(0, "div", 89)(1, "div", 90)(2, "div", 91)(3, "label");
|
|
287
|
+
i0.ɵɵtext(4, "Model Name:");
|
|
288
|
+
i0.ɵɵelementEnd();
|
|
289
|
+
i0.ɵɵelementStart(5, "span");
|
|
290
|
+
i0.ɵɵtext(6);
|
|
291
|
+
i0.ɵɵelementEnd()();
|
|
292
|
+
i0.ɵɵelementStart(7, "div", 91)(8, "label");
|
|
293
|
+
i0.ɵɵtext(9, "Vendor:");
|
|
294
|
+
i0.ɵɵelementEnd();
|
|
295
|
+
i0.ɵɵelementStart(10, "span");
|
|
296
|
+
i0.ɵɵtext(11);
|
|
297
|
+
i0.ɵɵelementEnd()();
|
|
298
|
+
i0.ɵɵelementStart(12, "div", 91)(13, "label");
|
|
299
|
+
i0.ɵɵtext(14, "API Name:");
|
|
300
|
+
i0.ɵɵelementEnd();
|
|
301
|
+
i0.ɵɵelementStart(15, "span");
|
|
302
|
+
i0.ɵɵtext(16);
|
|
303
|
+
i0.ɵɵelementEnd()();
|
|
304
|
+
i0.ɵɵelementStart(17, "div", 91)(18, "label");
|
|
305
|
+
i0.ɵɵtext(19, "Input Cost:");
|
|
306
|
+
i0.ɵɵelementEnd();
|
|
307
|
+
i0.ɵɵelementStart(20, "span");
|
|
308
|
+
i0.ɵɵtext(21);
|
|
309
|
+
i0.ɵɵelementEnd()();
|
|
310
|
+
i0.ɵɵelementStart(22, "div", 91)(23, "label");
|
|
311
|
+
i0.ɵɵtext(24, "Output Cost:");
|
|
312
|
+
i0.ɵɵelementEnd();
|
|
313
|
+
i0.ɵɵelementStart(25, "span");
|
|
314
|
+
i0.ɵɵtext(26);
|
|
315
|
+
i0.ɵɵelementEnd()();
|
|
316
|
+
i0.ɵɵelementStart(27, "div", 91)(28, "label");
|
|
317
|
+
i0.ɵɵtext(29, "Active:");
|
|
318
|
+
i0.ɵɵelementEnd();
|
|
319
|
+
i0.ɵɵelementStart(30, "span", 92);
|
|
320
|
+
i0.ɵɵtext(31);
|
|
321
|
+
i0.ɵɵelementEnd()()();
|
|
322
|
+
i0.ɵɵtemplate(32, ExecutionMonitoringComponent_Conditional_63_Conditional_6_Conditional_32_Template, 5, 1, "div", 93);
|
|
323
|
+
i0.ɵɵelementEnd();
|
|
324
|
+
} if (rf & 2) {
|
|
325
|
+
const ctx_r2 = i0.ɵɵnextContext(2);
|
|
326
|
+
i0.ɵɵadvance(6);
|
|
327
|
+
i0.ɵɵtextInterpolate(ctx_r2.activeTab == null ? null : ctx_r2.activeTab.data == null ? null : ctx_r2.activeTab.data.name);
|
|
328
|
+
i0.ɵɵadvance(5);
|
|
329
|
+
i0.ɵɵtextInterpolate(ctx_r2.activeTab == null ? null : ctx_r2.activeTab.data == null ? null : ctx_r2.activeTab.data.vendor);
|
|
330
|
+
i0.ɵɵadvance(5);
|
|
331
|
+
i0.ɵɵtextInterpolate(ctx_r2.activeTab == null ? null : ctx_r2.activeTab.data == null ? null : ctx_r2.activeTab.data.apiName);
|
|
332
|
+
i0.ɵɵadvance(5);
|
|
333
|
+
i0.ɵɵtextInterpolate1("$", (ctx_r2.activeTab == null ? null : ctx_r2.activeTab.data == null ? null : ctx_r2.activeTab.data.inputTokenCost == null ? null : ctx_r2.activeTab.data.inputTokenCost.toFixed(6)) || "0", " per token");
|
|
334
|
+
i0.ɵɵadvance(5);
|
|
335
|
+
i0.ɵɵtextInterpolate1("$", (ctx_r2.activeTab == null ? null : ctx_r2.activeTab.data == null ? null : ctx_r2.activeTab.data.outputTokenCost == null ? null : ctx_r2.activeTab.data.outputTokenCost.toFixed(6)) || "0", " per token");
|
|
336
|
+
i0.ɵɵadvance(4);
|
|
337
|
+
i0.ɵɵclassProp("active", ctx_r2.activeTab == null ? null : ctx_r2.activeTab.data == null ? null : ctx_r2.activeTab.data.isActive);
|
|
338
|
+
i0.ɵɵadvance();
|
|
339
|
+
i0.ɵɵtextInterpolate1(" ", (ctx_r2.activeTab == null ? null : ctx_r2.activeTab.data == null ? null : ctx_r2.activeTab.data.isActive) ? "Yes" : "No", " ");
|
|
340
|
+
i0.ɵɵadvance();
|
|
341
|
+
i0.ɵɵconditional((ctx_r2.activeTab == null ? null : ctx_r2.activeTab.data == null ? null : ctx_r2.activeTab.data.description) ? 32 : -1);
|
|
342
|
+
} }
|
|
343
|
+
function ExecutionMonitoringComponent_Conditional_63_Template(rf, ctx) { if (rf & 1) {
|
|
344
|
+
i0.ɵɵelementStart(0, "div", 37)(1, "div", 71)(2, "h4");
|
|
345
|
+
i0.ɵɵelement(3, "i", 88);
|
|
346
|
+
i0.ɵɵtext(4);
|
|
347
|
+
i0.ɵɵelementEnd()();
|
|
348
|
+
i0.ɵɵtemplate(5, ExecutionMonitoringComponent_Conditional_63_Conditional_5_Template, 3, 0, "div", 76)(6, ExecutionMonitoringComponent_Conditional_63_Conditional_6_Template, 33, 9, "div", 89);
|
|
349
|
+
i0.ɵɵelementEnd();
|
|
350
|
+
} if (rf & 2) {
|
|
351
|
+
const ctx_r2 = i0.ɵɵnextContext();
|
|
352
|
+
i0.ɵɵadvance(4);
|
|
353
|
+
i0.ɵɵtextInterpolate1(" Model Details: ", ctx_r2.activeTab == null ? null : ctx_r2.activeTab.data == null ? null : ctx_r2.activeTab.data.name, " ");
|
|
354
|
+
i0.ɵɵadvance();
|
|
355
|
+
i0.ɵɵconditional(ctx_r2.loadingDrillDown ? 5 : (ctx_r2.activeTab == null ? null : ctx_r2.activeTab.data) ? 6 : -1);
|
|
356
|
+
} }
|
|
357
|
+
function ExecutionMonitoringComponent_Conditional_78_Conditional_1_For_2_Template(rf, ctx) { if (rf & 1) {
|
|
358
|
+
i0.ɵɵelementStart(0, "div", 95)(1, "div", 96)(2, "span", 97);
|
|
359
|
+
i0.ɵɵtext(3);
|
|
360
|
+
i0.ɵɵelementEnd();
|
|
361
|
+
i0.ɵɵelementStart(4, "span", 98);
|
|
362
|
+
i0.ɵɵtext(5);
|
|
363
|
+
i0.ɵɵelementEnd()();
|
|
364
|
+
i0.ɵɵelementStart(6, "div", 99);
|
|
365
|
+
i0.ɵɵelement(7, "div", 100);
|
|
366
|
+
i0.ɵɵelementEnd();
|
|
367
|
+
i0.ɵɵelementStart(8, "div", 101);
|
|
368
|
+
i0.ɵɵtext(9);
|
|
369
|
+
i0.ɵɵelementEnd()();
|
|
370
|
+
} if (rf & 2) {
|
|
371
|
+
const item_r11 = ctx.$implicit;
|
|
372
|
+
const costData_r12 = i0.ɵɵnextContext();
|
|
373
|
+
const ctx_r2 = i0.ɵɵnextContext(2);
|
|
374
|
+
i0.ɵɵadvance(3);
|
|
375
|
+
i0.ɵɵtextInterpolate(item_r11.model);
|
|
376
|
+
i0.ɵɵadvance(2);
|
|
377
|
+
i0.ɵɵtextInterpolate(ctx_r2.formatCurrency(item_r11.cost));
|
|
378
|
+
i0.ɵɵadvance(2);
|
|
379
|
+
i0.ɵɵstyleProp("width", ctx_r2.getCostBarWidth(item_r11.cost, ctx_r2.getMaxCost(costData_r12)), "%");
|
|
380
|
+
i0.ɵɵadvance(2);
|
|
381
|
+
i0.ɵɵtextInterpolate1(" ", ctx_r2.formatTokens(item_r11.tokens), " tokens ");
|
|
382
|
+
} }
|
|
383
|
+
function ExecutionMonitoringComponent_Conditional_78_Conditional_1_Template(rf, ctx) { if (rf & 1) {
|
|
384
|
+
i0.ɵɵelementStart(0, "div", 94);
|
|
385
|
+
i0.ɵɵrepeaterCreate(1, ExecutionMonitoringComponent_Conditional_78_Conditional_1_For_2_Template, 10, 5, "div", 95, _forTrack2);
|
|
386
|
+
i0.ɵɵelementEnd();
|
|
387
|
+
} if (rf & 2) {
|
|
388
|
+
i0.ɵɵadvance();
|
|
389
|
+
i0.ɵɵrepeater(ctx.slice(0, 8));
|
|
390
|
+
} }
|
|
391
|
+
function ExecutionMonitoringComponent_Conditional_78_Template(rf, ctx) { if (rf & 1) {
|
|
392
|
+
i0.ɵɵelementStart(0, "div", 47);
|
|
393
|
+
i0.ɵɵtemplate(1, ExecutionMonitoringComponent_Conditional_78_Conditional_1_Template, 3, 0, "div", 94);
|
|
394
|
+
i0.ɵɵpipe(2, "async");
|
|
395
|
+
i0.ɵɵelementEnd();
|
|
396
|
+
} if (rf & 2) {
|
|
397
|
+
let tmp_1_0;
|
|
398
|
+
const ctx_r2 = i0.ɵɵnextContext();
|
|
399
|
+
i0.ɵɵadvance();
|
|
400
|
+
i0.ɵɵconditional((tmp_1_0 = i0.ɵɵpipeBind1(2, 1, ctx_r2.costData$)) ? 1 : -1, tmp_1_0);
|
|
401
|
+
} }
|
|
402
|
+
function ExecutionMonitoringComponent_Conditional_85_Conditional_1_For_2_Template(rf, ctx) { if (rf & 1) {
|
|
403
|
+
i0.ɵɵelementStart(0, "div", 103)(1, "div", 104)(2, "span", 97);
|
|
404
|
+
i0.ɵɵtext(3);
|
|
405
|
+
i0.ɵɵelementEnd();
|
|
406
|
+
i0.ɵɵelementStart(4, "span", 105);
|
|
407
|
+
i0.ɵɵtext(5);
|
|
408
|
+
i0.ɵɵelementEnd()();
|
|
409
|
+
i0.ɵɵelementStart(6, "div", 106)(7, "div", 107);
|
|
410
|
+
i0.ɵɵelement(8, "div", 108)(9, "div", 109);
|
|
411
|
+
i0.ɵɵelementEnd();
|
|
412
|
+
i0.ɵɵelementStart(10, "div", 110)(11, "span", 111);
|
|
413
|
+
i0.ɵɵtext(12);
|
|
414
|
+
i0.ɵɵelementEnd();
|
|
415
|
+
i0.ɵɵelementStart(13, "span", 112);
|
|
416
|
+
i0.ɵɵtext(14);
|
|
417
|
+
i0.ɵɵelementEnd()()();
|
|
418
|
+
i0.ɵɵelementStart(15, "div", 113);
|
|
419
|
+
i0.ɵɵtext(16);
|
|
420
|
+
i0.ɵɵelementEnd()();
|
|
421
|
+
} if (rf & 2) {
|
|
422
|
+
const item_r13 = ctx.$implicit;
|
|
423
|
+
const ctx_r2 = i0.ɵɵnextContext(3);
|
|
424
|
+
i0.ɵɵadvance(3);
|
|
425
|
+
i0.ɵɵtextInterpolate(item_r13.model);
|
|
426
|
+
i0.ɵɵadvance(2);
|
|
427
|
+
i0.ɵɵtextInterpolate1(" ", ctx_r2.getTokenRatio(item_r13.inputTokens, item_r13.outputTokens), " ");
|
|
428
|
+
i0.ɵɵadvance(3);
|
|
429
|
+
i0.ɵɵstyleProp("width", ctx_r2.getTokenPercentage(item_r13.inputTokens, item_r13.inputTokens + item_r13.outputTokens), "%");
|
|
430
|
+
i0.ɵɵadvance();
|
|
431
|
+
i0.ɵɵstyleProp("width", ctx_r2.getTokenPercentage(item_r13.outputTokens, item_r13.inputTokens + item_r13.outputTokens), "%");
|
|
432
|
+
i0.ɵɵadvance(3);
|
|
433
|
+
i0.ɵɵtextInterpolate1("Input: ", ctx_r2.formatTokens(item_r13.inputTokens), "");
|
|
434
|
+
i0.ɵɵadvance(2);
|
|
435
|
+
i0.ɵɵtextInterpolate1("Output: ", ctx_r2.formatTokens(item_r13.outputTokens), "");
|
|
436
|
+
i0.ɵɵadvance(2);
|
|
437
|
+
i0.ɵɵtextInterpolate1(" ", ctx_r2.formatCostPerToken(item_r13.cost, item_r13.inputTokens + item_r13.outputTokens), " ");
|
|
438
|
+
} }
|
|
439
|
+
function ExecutionMonitoringComponent_Conditional_85_Conditional_1_Template(rf, ctx) { if (rf & 1) {
|
|
440
|
+
i0.ɵɵelementStart(0, "div", 102);
|
|
441
|
+
i0.ɵɵrepeaterCreate(1, ExecutionMonitoringComponent_Conditional_85_Conditional_1_For_2_Template, 17, 9, "div", 103, _forTrack2);
|
|
442
|
+
i0.ɵɵelementEnd();
|
|
443
|
+
} if (rf & 2) {
|
|
444
|
+
i0.ɵɵadvance();
|
|
445
|
+
i0.ɵɵrepeater(ctx.slice(0, 6));
|
|
446
|
+
} }
|
|
447
|
+
function ExecutionMonitoringComponent_Conditional_85_Template(rf, ctx) { if (rf & 1) {
|
|
448
|
+
i0.ɵɵelementStart(0, "div", 47);
|
|
449
|
+
i0.ɵɵtemplate(1, ExecutionMonitoringComponent_Conditional_85_Conditional_1_Template, 3, 0, "div", 102);
|
|
450
|
+
i0.ɵɵpipe(2, "async");
|
|
451
|
+
i0.ɵɵelementEnd();
|
|
452
|
+
} if (rf & 2) {
|
|
453
|
+
let tmp_1_0;
|
|
454
|
+
const ctx_r2 = i0.ɵɵnextContext();
|
|
455
|
+
i0.ɵɵadvance();
|
|
456
|
+
i0.ɵɵconditional((tmp_1_0 = i0.ɵɵpipeBind1(2, 1, ctx_r2.tokenEfficiency$)) ? 1 : -1, tmp_1_0);
|
|
457
|
+
} }
|
|
458
|
+
function ExecutionMonitoringComponent_Conditional_92_Template(rf, ctx) { if (rf & 1) {
|
|
459
|
+
const _r14 = i0.ɵɵgetCurrentView();
|
|
460
|
+
i0.ɵɵelementStart(0, "div", 50)(1, "app-live-execution-widget", 114);
|
|
461
|
+
i0.ɵɵpipe(2, "async");
|
|
462
|
+
i0.ɵɵlistener("executionClick", function ExecutionMonitoringComponent_Conditional_92_Template_app_live_execution_widget_executionClick_1_listener($event) { i0.ɵɵrestoreView(_r14); const ctx_r2 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r2.onExecutionClick($event)); });
|
|
463
|
+
i0.ɵɵelementEnd()();
|
|
464
|
+
} if (rf & 2) {
|
|
465
|
+
let tmp_1_0;
|
|
466
|
+
const ctx_r2 = i0.ɵɵnextContext();
|
|
467
|
+
i0.ɵɵadvance();
|
|
468
|
+
i0.ɵɵproperty("executions", (tmp_1_0 = i0.ɵɵpipeBind1(2, 1, ctx_r2.liveExecutions$)) !== null && tmp_1_0 !== undefined ? tmp_1_0 : i0.ɵɵpureFunction0(3, _c0));
|
|
469
|
+
} }
|
|
470
|
+
function ExecutionMonitoringComponent_Conditional_93_Conditional_12_Conditional_28_Template(rf, ctx) { if (rf & 1) {
|
|
471
|
+
i0.ɵɵelementStart(0, "div", 127)(1, "label");
|
|
472
|
+
i0.ɵɵtext(2, "Completed:");
|
|
473
|
+
i0.ɵɵelementEnd();
|
|
474
|
+
i0.ɵɵelementStart(3, "span");
|
|
475
|
+
i0.ɵɵtext(4);
|
|
476
|
+
i0.ɵɵpipe(5, "date");
|
|
477
|
+
i0.ɵɵelementEnd()();
|
|
478
|
+
} if (rf & 2) {
|
|
479
|
+
const ctx_r2 = i0.ɵɵnextContext(3);
|
|
480
|
+
i0.ɵɵadvance(4);
|
|
481
|
+
i0.ɵɵtextInterpolate(i0.ɵɵpipeBind2(5, 1, ctx_r2.executionDetails.endTime, "medium"));
|
|
482
|
+
} }
|
|
483
|
+
function ExecutionMonitoringComponent_Conditional_93_Conditional_12_Conditional_48_Template(rf, ctx) { if (rf & 1) {
|
|
484
|
+
i0.ɵɵelementStart(0, "div", 127)(1, "label");
|
|
485
|
+
i0.ɵɵtext(2, "Model:");
|
|
486
|
+
i0.ɵɵelementEnd();
|
|
487
|
+
i0.ɵɵelementStart(3, "span");
|
|
488
|
+
i0.ɵɵtext(4);
|
|
489
|
+
i0.ɵɵelementEnd()();
|
|
490
|
+
} if (rf & 2) {
|
|
491
|
+
const ctx_r2 = i0.ɵɵnextContext(3);
|
|
492
|
+
i0.ɵɵadvance(4);
|
|
493
|
+
i0.ɵɵtextInterpolate(ctx_r2.executionDetails.model);
|
|
494
|
+
} }
|
|
495
|
+
function ExecutionMonitoringComponent_Conditional_93_Conditional_12_Conditional_49_Template(rf, ctx) { if (rf & 1) {
|
|
496
|
+
i0.ɵɵelementStart(0, "div", 125)(1, "h4");
|
|
497
|
+
i0.ɵɵtext(2, "Error Information");
|
|
498
|
+
i0.ɵɵelementEnd();
|
|
499
|
+
i0.ɵɵelementStart(3, "div", 128);
|
|
500
|
+
i0.ɵɵtext(4);
|
|
501
|
+
i0.ɵɵelementEnd()();
|
|
502
|
+
} if (rf & 2) {
|
|
503
|
+
const ctx_r2 = i0.ɵɵnextContext(3);
|
|
504
|
+
i0.ɵɵadvance(4);
|
|
505
|
+
i0.ɵɵtextInterpolate(ctx_r2.executionDetails.errorMessage);
|
|
506
|
+
} }
|
|
507
|
+
function ExecutionMonitoringComponent_Conditional_93_Conditional_12_Conditional_50_For_5_Template(rf, ctx) { if (rf & 1) {
|
|
508
|
+
i0.ɵɵelementStart(0, "div", 130)(1, "div", 131)(2, "span", 132);
|
|
509
|
+
i0.ɵɵtext(3);
|
|
510
|
+
i0.ɵɵelementEnd();
|
|
511
|
+
i0.ɵɵelementStart(4, "span", 133);
|
|
512
|
+
i0.ɵɵtext(5);
|
|
513
|
+
i0.ɵɵelementEnd();
|
|
514
|
+
i0.ɵɵelementStart(6, "span", 134);
|
|
515
|
+
i0.ɵɵtext(7);
|
|
516
|
+
i0.ɵɵelementEnd()();
|
|
517
|
+
i0.ɵɵelementStart(8, "div", 135)(9, "span");
|
|
518
|
+
i0.ɵɵtext(10);
|
|
519
|
+
i0.ɵɵelementEnd();
|
|
520
|
+
i0.ɵɵelementStart(11, "span");
|
|
521
|
+
i0.ɵɵtext(12);
|
|
522
|
+
i0.ɵɵelementEnd()()();
|
|
523
|
+
} if (rf & 2) {
|
|
524
|
+
const child_r16 = ctx.$implicit;
|
|
525
|
+
const ctx_r2 = i0.ɵɵnextContext(4);
|
|
526
|
+
i0.ɵɵadvance(3);
|
|
527
|
+
i0.ɵɵtextInterpolate(child_r16.name);
|
|
528
|
+
i0.ɵɵadvance(2);
|
|
529
|
+
i0.ɵɵtextInterpolate(child_r16.type);
|
|
530
|
+
i0.ɵɵadvance();
|
|
531
|
+
i0.ɵɵclassMap("status-badge--" + child_r16.status);
|
|
532
|
+
i0.ɵɵadvance();
|
|
533
|
+
i0.ɵɵtextInterpolate1(" ", child_r16.status, " ");
|
|
534
|
+
i0.ɵɵadvance(3);
|
|
535
|
+
i0.ɵɵtextInterpolate(ctx_r2.formatCurrency(child_r16.cost));
|
|
536
|
+
i0.ɵɵadvance(2);
|
|
537
|
+
i0.ɵɵtextInterpolate1("", child_r16.tokens.toLocaleString(), " tokens");
|
|
538
|
+
} }
|
|
539
|
+
function ExecutionMonitoringComponent_Conditional_93_Conditional_12_Conditional_50_Template(rf, ctx) { if (rf & 1) {
|
|
540
|
+
i0.ɵɵelementStart(0, "div", 125)(1, "h4");
|
|
541
|
+
i0.ɵɵtext(2);
|
|
542
|
+
i0.ɵɵelementEnd();
|
|
543
|
+
i0.ɵɵelementStart(3, "div", 129);
|
|
544
|
+
i0.ɵɵrepeaterCreate(4, ExecutionMonitoringComponent_Conditional_93_Conditional_12_Conditional_50_For_5_Template, 13, 7, "div", 130, _forTrack1);
|
|
545
|
+
i0.ɵɵelementEnd()();
|
|
546
|
+
} if (rf & 2) {
|
|
547
|
+
const ctx_r2 = i0.ɵɵnextContext(3);
|
|
548
|
+
i0.ɵɵadvance(2);
|
|
549
|
+
i0.ɵɵtextInterpolate1("Child Executions (", ctx_r2.executionDetails.children.length, ")");
|
|
550
|
+
i0.ɵɵadvance(2);
|
|
551
|
+
i0.ɵɵrepeater(ctx_r2.executionDetails.children);
|
|
552
|
+
} }
|
|
553
|
+
function ExecutionMonitoringComponent_Conditional_93_Conditional_12_Template(rf, ctx) { if (rf & 1) {
|
|
554
|
+
i0.ɵɵelementStart(0, "div", 123)(1, "div", 125)(2, "h4");
|
|
555
|
+
i0.ɵɵtext(3, "Basic Information");
|
|
556
|
+
i0.ɵɵelementEnd();
|
|
557
|
+
i0.ɵɵelementStart(4, "div", 126)(5, "div", 127)(6, "label");
|
|
558
|
+
i0.ɵɵtext(7, "Type:");
|
|
559
|
+
i0.ɵɵelementEnd();
|
|
560
|
+
i0.ɵɵelementStart(8, "span");
|
|
561
|
+
i0.ɵɵtext(9);
|
|
562
|
+
i0.ɵɵpipe(10, "titlecase");
|
|
563
|
+
i0.ɵɵelementEnd()();
|
|
564
|
+
i0.ɵɵelementStart(11, "div", 127)(12, "label");
|
|
565
|
+
i0.ɵɵtext(13, "Name:");
|
|
566
|
+
i0.ɵɵelementEnd();
|
|
567
|
+
i0.ɵɵelementStart(14, "span");
|
|
568
|
+
i0.ɵɵtext(15);
|
|
569
|
+
i0.ɵɵelementEnd()();
|
|
570
|
+
i0.ɵɵelementStart(16, "div", 127)(17, "label");
|
|
571
|
+
i0.ɵɵtext(18, "Status:");
|
|
572
|
+
i0.ɵɵelementEnd();
|
|
573
|
+
i0.ɵɵelementStart(19, "span", 86);
|
|
574
|
+
i0.ɵɵtext(20);
|
|
575
|
+
i0.ɵɵpipe(21, "titlecase");
|
|
576
|
+
i0.ɵɵelementEnd()();
|
|
577
|
+
i0.ɵɵelementStart(22, "div", 127)(23, "label");
|
|
578
|
+
i0.ɵɵtext(24, "Started:");
|
|
579
|
+
i0.ɵɵelementEnd();
|
|
580
|
+
i0.ɵɵelementStart(25, "span");
|
|
581
|
+
i0.ɵɵtext(26);
|
|
582
|
+
i0.ɵɵpipe(27, "date");
|
|
583
|
+
i0.ɵɵelementEnd()();
|
|
584
|
+
i0.ɵɵtemplate(28, ExecutionMonitoringComponent_Conditional_93_Conditional_12_Conditional_28_Template, 6, 4, "div", 127);
|
|
585
|
+
i0.ɵɵelementStart(29, "div", 127)(30, "label");
|
|
586
|
+
i0.ɵɵtext(31, "Duration:");
|
|
587
|
+
i0.ɵɵelementEnd();
|
|
588
|
+
i0.ɵɵelementStart(32, "span");
|
|
589
|
+
i0.ɵɵtext(33);
|
|
590
|
+
i0.ɵɵelementEnd()()()();
|
|
591
|
+
i0.ɵɵelementStart(34, "div", 125)(35, "h4");
|
|
592
|
+
i0.ɵɵtext(36, "Resource Usage");
|
|
593
|
+
i0.ɵɵelementEnd();
|
|
594
|
+
i0.ɵɵelementStart(37, "div", 126)(38, "div", 127)(39, "label");
|
|
595
|
+
i0.ɵɵtext(40, "Cost:");
|
|
596
|
+
i0.ɵɵelementEnd();
|
|
597
|
+
i0.ɵɵelementStart(41, "span");
|
|
598
|
+
i0.ɵɵtext(42);
|
|
599
|
+
i0.ɵɵelementEnd()();
|
|
600
|
+
i0.ɵɵelementStart(43, "div", 127)(44, "label");
|
|
601
|
+
i0.ɵɵtext(45, "Tokens:");
|
|
602
|
+
i0.ɵɵelementEnd();
|
|
603
|
+
i0.ɵɵelementStart(46, "span");
|
|
604
|
+
i0.ɵɵtext(47);
|
|
605
|
+
i0.ɵɵelementEnd()();
|
|
606
|
+
i0.ɵɵtemplate(48, ExecutionMonitoringComponent_Conditional_93_Conditional_12_Conditional_48_Template, 5, 1, "div", 127);
|
|
607
|
+
i0.ɵɵelementEnd()();
|
|
608
|
+
i0.ɵɵtemplate(49, ExecutionMonitoringComponent_Conditional_93_Conditional_12_Conditional_49_Template, 5, 1, "div", 125)(50, ExecutionMonitoringComponent_Conditional_93_Conditional_12_Conditional_50_Template, 6, 1, "div", 125);
|
|
609
|
+
i0.ɵɵelementEnd();
|
|
610
|
+
} if (rf & 2) {
|
|
611
|
+
const ctx_r2 = i0.ɵɵnextContext(2);
|
|
612
|
+
i0.ɵɵadvance(9);
|
|
613
|
+
i0.ɵɵtextInterpolate(i0.ɵɵpipeBind1(10, 13, ctx_r2.executionDetails.type));
|
|
614
|
+
i0.ɵɵadvance(6);
|
|
615
|
+
i0.ɵɵtextInterpolate(ctx_r2.executionDetails.name);
|
|
616
|
+
i0.ɵɵadvance(4);
|
|
617
|
+
i0.ɵɵclassMap("status-badge--" + ctx_r2.executionDetails.status);
|
|
618
|
+
i0.ɵɵadvance();
|
|
619
|
+
i0.ɵɵtextInterpolate1(" ", i0.ɵɵpipeBind1(21, 15, ctx_r2.executionDetails.status), " ");
|
|
620
|
+
i0.ɵɵadvance(6);
|
|
621
|
+
i0.ɵɵtextInterpolate(i0.ɵɵpipeBind2(27, 17, ctx_r2.executionDetails.startTime, "medium"));
|
|
622
|
+
i0.ɵɵadvance(2);
|
|
623
|
+
i0.ɵɵconditional(ctx_r2.executionDetails.endTime ? 28 : -1);
|
|
624
|
+
i0.ɵɵadvance(5);
|
|
625
|
+
i0.ɵɵtextInterpolate(ctx_r2.formatDuration(ctx_r2.getDuration(ctx_r2.executionDetails)));
|
|
626
|
+
i0.ɵɵadvance(9);
|
|
627
|
+
i0.ɵɵtextInterpolate(ctx_r2.formatCurrency(ctx_r2.executionDetails.cost, 6));
|
|
628
|
+
i0.ɵɵadvance(5);
|
|
629
|
+
i0.ɵɵtextInterpolate(ctx_r2.executionDetails.tokens.toLocaleString());
|
|
630
|
+
i0.ɵɵadvance();
|
|
631
|
+
i0.ɵɵconditional(ctx_r2.executionDetails.model ? 48 : -1);
|
|
632
|
+
i0.ɵɵadvance();
|
|
633
|
+
i0.ɵɵconditional(ctx_r2.executionDetails.errorMessage ? 49 : -1);
|
|
634
|
+
i0.ɵɵadvance();
|
|
635
|
+
i0.ɵɵconditional(ctx_r2.executionDetails.children.length > 0 ? 50 : -1);
|
|
636
|
+
} }
|
|
637
|
+
function ExecutionMonitoringComponent_Conditional_93_Conditional_13_Template(rf, ctx) { if (rf & 1) {
|
|
638
|
+
i0.ɵɵelementStart(0, "div", 124);
|
|
639
|
+
i0.ɵɵelement(1, "div", 136);
|
|
640
|
+
i0.ɵɵelementStart(2, "p");
|
|
641
|
+
i0.ɵɵtext(3, "Loading execution details...");
|
|
642
|
+
i0.ɵɵelementEnd()();
|
|
643
|
+
} }
|
|
644
|
+
function ExecutionMonitoringComponent_Conditional_93_Template(rf, ctx) { if (rf & 1) {
|
|
645
|
+
const _r15 = i0.ɵɵgetCurrentView();
|
|
646
|
+
i0.ɵɵelementStart(0, "div", 115);
|
|
647
|
+
i0.ɵɵlistener("click", function ExecutionMonitoringComponent_Conditional_93_Template_div_click_0_listener() { i0.ɵɵrestoreView(_r15); const ctx_r2 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r2.closeExecutionModal()); });
|
|
648
|
+
i0.ɵɵelementStart(1, "div", 116);
|
|
649
|
+
i0.ɵɵlistener("click", function ExecutionMonitoringComponent_Conditional_93_Template_div_click_1_listener($event) { i0.ɵɵrestoreView(_r15); return i0.ɵɵresetView($event.stopPropagation()); });
|
|
650
|
+
i0.ɵɵelementStart(2, "div", 117)(3, "h3");
|
|
651
|
+
i0.ɵɵtext(4, "Execution Details");
|
|
652
|
+
i0.ɵɵelementEnd();
|
|
653
|
+
i0.ɵɵelementStart(5, "div", 118)(6, "button", 119);
|
|
654
|
+
i0.ɵɵlistener("click", function ExecutionMonitoringComponent_Conditional_93_Template_button_click_6_listener() { i0.ɵɵrestoreView(_r15); const ctx_r2 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r2.openFullRecord()); });
|
|
655
|
+
i0.ɵɵelement(7, "i", 120);
|
|
656
|
+
i0.ɵɵtext(8, " Open ");
|
|
657
|
+
i0.ɵɵelementEnd();
|
|
658
|
+
i0.ɵɵelementStart(9, "button", 121);
|
|
659
|
+
i0.ɵɵlistener("click", function ExecutionMonitoringComponent_Conditional_93_Template_button_click_9_listener() { i0.ɵɵrestoreView(_r15); const ctx_r2 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r2.closeExecutionModal()); });
|
|
660
|
+
i0.ɵɵelement(10, "i", 69);
|
|
661
|
+
i0.ɵɵelementEnd()()();
|
|
662
|
+
i0.ɵɵelementStart(11, "div", 122);
|
|
663
|
+
i0.ɵɵtemplate(12, ExecutionMonitoringComponent_Conditional_93_Conditional_12_Template, 51, 20, "div", 123)(13, ExecutionMonitoringComponent_Conditional_93_Conditional_13_Template, 4, 0, "div", 124);
|
|
664
|
+
i0.ɵɵelementEnd()()();
|
|
665
|
+
} if (rf & 2) {
|
|
666
|
+
const ctx_r2 = i0.ɵɵnextContext();
|
|
667
|
+
i0.ɵɵadvance(12);
|
|
668
|
+
i0.ɵɵconditional(ctx_r2.executionDetails ? 12 : -1);
|
|
669
|
+
i0.ɵɵadvance();
|
|
670
|
+
i0.ɵɵconditional(ctx_r2.loadingExecutionDetails ? 13 : -1);
|
|
671
|
+
} }
|
|
3
672
|
export class ExecutionMonitoringComponent {
|
|
4
|
-
|
|
5
|
-
|
|
673
|
+
instrumentationService;
|
|
674
|
+
initialState;
|
|
675
|
+
openEntityRecord = new EventEmitter();
|
|
676
|
+
stateChange = new EventEmitter();
|
|
677
|
+
destroy$ = new Subject();
|
|
678
|
+
stateChangeSubject$ = new Subject();
|
|
679
|
+
// Configuration
|
|
680
|
+
refreshInterval = 30000; // 30 seconds
|
|
681
|
+
selectedTimeRange = '24h';
|
|
682
|
+
isLoading = false;
|
|
683
|
+
// Chart configurations
|
|
684
|
+
timeSeriesConfig = {
|
|
685
|
+
showGrid: true,
|
|
686
|
+
showTooltip: true,
|
|
687
|
+
animationDuration: 500,
|
|
688
|
+
useDualAxis: true
|
|
689
|
+
};
|
|
690
|
+
heatmapConfig = {
|
|
691
|
+
height: 350,
|
|
692
|
+
showTooltip: true,
|
|
693
|
+
animationDuration: 300
|
|
694
|
+
};
|
|
695
|
+
// Data streams
|
|
696
|
+
kpis$;
|
|
697
|
+
trends$;
|
|
698
|
+
liveExecutions$;
|
|
699
|
+
chartData$;
|
|
700
|
+
// Derived data streams
|
|
701
|
+
kpiCards$;
|
|
702
|
+
performanceMatrix$;
|
|
703
|
+
costData$;
|
|
704
|
+
tokenEfficiency$;
|
|
705
|
+
// Modal state
|
|
706
|
+
selectedExecution = null;
|
|
707
|
+
executionDetails = null;
|
|
708
|
+
loadingExecutionDetails = false;
|
|
709
|
+
// Drill-down tab state
|
|
710
|
+
drillDownTabs = [];
|
|
711
|
+
activeTabId = 'main-chart';
|
|
712
|
+
loadingDrillDown = false;
|
|
713
|
+
// Panel state for collapsible sections
|
|
714
|
+
panelStates = {
|
|
715
|
+
cost: true,
|
|
716
|
+
efficiency: true, // Expanded by default
|
|
717
|
+
executions: false
|
|
718
|
+
};
|
|
719
|
+
get activeTab() {
|
|
720
|
+
return this.drillDownTabs.find(tab => tab.id === this.activeTabId);
|
|
6
721
|
}
|
|
7
|
-
|
|
8
|
-
this.
|
|
722
|
+
constructor(instrumentationService) {
|
|
723
|
+
this.instrumentationService = instrumentationService;
|
|
724
|
+
// Initialize data streams
|
|
725
|
+
this.kpis$ = this.instrumentationService.kpis$;
|
|
726
|
+
this.trends$ = this.instrumentationService.trends$;
|
|
727
|
+
this.liveExecutions$ = this.instrumentationService.liveExecutions$;
|
|
728
|
+
this.chartData$ = this.instrumentationService.chartData$;
|
|
729
|
+
// Derived streams
|
|
730
|
+
this.kpiCards$ = this.kpis$.pipe(map(kpis => this.createKPICards(kpis)));
|
|
731
|
+
this.performanceMatrix$ = this.chartData$.pipe(map(data => data.performanceMatrix.map(item => ({
|
|
732
|
+
agent: item.agent,
|
|
733
|
+
model: item.model,
|
|
734
|
+
avgTime: item.avgTime,
|
|
735
|
+
successRate: item.successRate
|
|
736
|
+
}))));
|
|
737
|
+
this.costData$ = this.chartData$.pipe(map(data => data.costByModel));
|
|
738
|
+
this.tokenEfficiency$ = this.chartData$.pipe(map(data => data.tokenEfficiency));
|
|
9
739
|
}
|
|
740
|
+
ngOnInit() {
|
|
741
|
+
// Load initial state if provided
|
|
742
|
+
if (this.initialState) {
|
|
743
|
+
this.loadUserState(this.initialState);
|
|
744
|
+
}
|
|
745
|
+
else {
|
|
746
|
+
// Default initialization
|
|
747
|
+
this.instrumentationService.setRefreshInterval(this.refreshInterval);
|
|
748
|
+
this.setTimeRange(this.selectedTimeRange);
|
|
749
|
+
// Initialize with main chart tab
|
|
750
|
+
this.drillDownTabs = [
|
|
751
|
+
{
|
|
752
|
+
id: 'main-chart',
|
|
753
|
+
title: 'Execution Trends',
|
|
754
|
+
type: 'chart',
|
|
755
|
+
closeable: false
|
|
756
|
+
}
|
|
757
|
+
];
|
|
758
|
+
}
|
|
759
|
+
// Set up debounced state change emission
|
|
760
|
+
this.stateChangeSubject$.pipe(debounceTime(2000), // 2 second debounce
|
|
761
|
+
takeUntil(this.destroy$)).subscribe(state => {
|
|
762
|
+
this.stateChange.emit(state);
|
|
763
|
+
});
|
|
764
|
+
}
|
|
765
|
+
ngOnDestroy() {
|
|
766
|
+
this.destroy$.next();
|
|
767
|
+
this.destroy$.complete();
|
|
768
|
+
this.stateChangeSubject$.complete();
|
|
769
|
+
}
|
|
770
|
+
getCurrentState() {
|
|
771
|
+
return {
|
|
772
|
+
selectedTimeRange: this.selectedTimeRange,
|
|
773
|
+
refreshInterval: this.refreshInterval,
|
|
774
|
+
panelStates: { ...this.panelStates },
|
|
775
|
+
drillDownTabs: this.drillDownTabs.map(tab => ({
|
|
776
|
+
id: tab.id,
|
|
777
|
+
title: tab.title,
|
|
778
|
+
type: tab.type,
|
|
779
|
+
timestamp: tab.timestamp?.toISOString(),
|
|
780
|
+
metric: tab.metric
|
|
781
|
+
})),
|
|
782
|
+
activeTabId: this.activeTabId
|
|
783
|
+
};
|
|
784
|
+
}
|
|
785
|
+
emitStateChange() {
|
|
786
|
+
const currentState = this.getCurrentState();
|
|
787
|
+
this.stateChangeSubject$.next(currentState);
|
|
788
|
+
}
|
|
789
|
+
loadUserState(state) {
|
|
790
|
+
if (state.selectedTimeRange) {
|
|
791
|
+
this.selectedTimeRange = state.selectedTimeRange;
|
|
792
|
+
this.setTimeRange(state.selectedTimeRange);
|
|
793
|
+
}
|
|
794
|
+
if (state.refreshInterval !== undefined) {
|
|
795
|
+
this.refreshInterval = state.refreshInterval;
|
|
796
|
+
this.instrumentationService.setRefreshInterval(this.refreshInterval);
|
|
797
|
+
}
|
|
798
|
+
if (state.panelStates) {
|
|
799
|
+
// Only override if state has explicit panel states, otherwise keep defaults
|
|
800
|
+
this.panelStates = { ...this.panelStates, ...state.panelStates };
|
|
801
|
+
}
|
|
802
|
+
if (state.drillDownTabs && state.drillDownTabs.length > 0) {
|
|
803
|
+
this.drillDownTabs = state.drillDownTabs.map(tab => ({
|
|
804
|
+
...tab,
|
|
805
|
+
type: tab.type,
|
|
806
|
+
timestamp: tab.timestamp ? new Date(tab.timestamp) : undefined,
|
|
807
|
+
closeable: tab.id !== 'main-chart'
|
|
808
|
+
}));
|
|
809
|
+
}
|
|
810
|
+
else {
|
|
811
|
+
// Initialize with default tab if not provided
|
|
812
|
+
this.drillDownTabs = [
|
|
813
|
+
{
|
|
814
|
+
id: 'main-chart',
|
|
815
|
+
title: 'Execution Trends',
|
|
816
|
+
type: 'chart',
|
|
817
|
+
closeable: false
|
|
818
|
+
}
|
|
819
|
+
];
|
|
820
|
+
}
|
|
821
|
+
if (state.activeTabId) {
|
|
822
|
+
this.activeTabId = state.activeTabId;
|
|
823
|
+
}
|
|
824
|
+
}
|
|
825
|
+
createKPICards(kpis) {
|
|
826
|
+
return [
|
|
827
|
+
{
|
|
828
|
+
title: 'Total Executions',
|
|
829
|
+
value: kpis.totalExecutions,
|
|
830
|
+
icon: 'fa-chart-bar',
|
|
831
|
+
color: 'primary',
|
|
832
|
+
subtitle: `${kpis.activeExecutions} active`
|
|
833
|
+
},
|
|
834
|
+
{
|
|
835
|
+
title: 'Total Cost',
|
|
836
|
+
value: `$${kpis.totalCost.toFixed(4)}`,
|
|
837
|
+
icon: 'fa-dollar-sign',
|
|
838
|
+
color: 'warning',
|
|
839
|
+
subtitle: `${kpis.costCurrency} • $${kpis.dailyCostBurn.toFixed(2)}/day`
|
|
840
|
+
},
|
|
841
|
+
{
|
|
842
|
+
title: 'Success Rate',
|
|
843
|
+
value: `${(kpis.successRate * 100).toFixed(1)}%`,
|
|
844
|
+
icon: 'fa-check-circle',
|
|
845
|
+
color: 'success',
|
|
846
|
+
subtitle: `${(kpis.errorRate * 100).toFixed(1)}% errors`
|
|
847
|
+
},
|
|
848
|
+
{
|
|
849
|
+
title: 'Avg Response Time',
|
|
850
|
+
value: `${(kpis.avgExecutionTime / 1000).toFixed(2)}s`,
|
|
851
|
+
icon: 'fa-clock',
|
|
852
|
+
color: 'info',
|
|
853
|
+
subtitle: 'All models average'
|
|
854
|
+
},
|
|
855
|
+
{
|
|
856
|
+
title: 'Token Usage',
|
|
857
|
+
value: this.formatTokens(kpis.totalTokens),
|
|
858
|
+
icon: 'fa-coins',
|
|
859
|
+
color: 'primary',
|
|
860
|
+
subtitle: `$${kpis.costPerToken.toFixed(6)}/token`
|
|
861
|
+
},
|
|
862
|
+
{
|
|
863
|
+
title: 'Top Model',
|
|
864
|
+
value: kpis.topModel,
|
|
865
|
+
icon: 'fa-microchip',
|
|
866
|
+
color: 'info',
|
|
867
|
+
subtitle: 'Most used'
|
|
868
|
+
}
|
|
869
|
+
];
|
|
870
|
+
}
|
|
871
|
+
onRefreshIntervalChange() {
|
|
872
|
+
this.instrumentationService.setRefreshInterval(this.refreshInterval);
|
|
873
|
+
this.emitStateChange();
|
|
874
|
+
}
|
|
875
|
+
onTimeRangeChange() {
|
|
876
|
+
this.setTimeRange(this.selectedTimeRange);
|
|
877
|
+
this.emitStateChange();
|
|
878
|
+
}
|
|
879
|
+
setTimeRange(range) {
|
|
880
|
+
const now = new Date();
|
|
881
|
+
let start;
|
|
882
|
+
switch (range) {
|
|
883
|
+
case '1h':
|
|
884
|
+
start = new Date(now.getTime() - 60 * 60 * 1000);
|
|
885
|
+
break;
|
|
886
|
+
case '6h':
|
|
887
|
+
start = new Date(now.getTime() - 6 * 60 * 60 * 1000);
|
|
888
|
+
break;
|
|
889
|
+
case '24h':
|
|
890
|
+
start = new Date(now.getTime() - 24 * 60 * 60 * 1000);
|
|
891
|
+
break;
|
|
892
|
+
case '7d':
|
|
893
|
+
start = new Date(now.getTime() - 7 * 24 * 60 * 60 * 1000);
|
|
894
|
+
break;
|
|
895
|
+
case '30d':
|
|
896
|
+
start = new Date(now.getTime() - 30 * 24 * 60 * 60 * 1000);
|
|
897
|
+
break;
|
|
898
|
+
default:
|
|
899
|
+
start = new Date(now.getTime() - 24 * 60 * 60 * 1000);
|
|
900
|
+
}
|
|
901
|
+
this.instrumentationService.setDateRange(start, now);
|
|
902
|
+
}
|
|
903
|
+
refreshData() {
|
|
904
|
+
this.isLoading = true;
|
|
905
|
+
// Force refresh by temporarily setting interval to 0 and back
|
|
906
|
+
const currentInterval = this.refreshInterval;
|
|
907
|
+
this.instrumentationService.setRefreshInterval(0);
|
|
908
|
+
setTimeout(() => {
|
|
909
|
+
this.instrumentationService.setRefreshInterval(currentInterval);
|
|
910
|
+
this.isLoading = false;
|
|
911
|
+
}, 100);
|
|
912
|
+
}
|
|
913
|
+
onExecutionClick(execution) {
|
|
914
|
+
this.selectedExecution = execution;
|
|
915
|
+
this.loadExecutionDetails(execution);
|
|
916
|
+
}
|
|
917
|
+
onDataPointClick(event) {
|
|
918
|
+
const timestamp = event.data.timestamp;
|
|
919
|
+
const metric = event.metric;
|
|
920
|
+
// Create new drill-down tab
|
|
921
|
+
const tabId = `drill-down-${timestamp.getTime()}-${metric}`;
|
|
922
|
+
const tabTitle = `${this.getMetricDisplayLabel(metric)} - ${this.formatTimestamp(timestamp)}`;
|
|
923
|
+
const newTab = {
|
|
924
|
+
id: tabId,
|
|
925
|
+
title: tabTitle,
|
|
926
|
+
type: 'executions',
|
|
927
|
+
timestamp: timestamp,
|
|
928
|
+
metric: metric,
|
|
929
|
+
closeable: true
|
|
930
|
+
};
|
|
931
|
+
// Add tab if it doesn't exist
|
|
932
|
+
if (!this.drillDownTabs.find(tab => tab.id === tabId)) {
|
|
933
|
+
this.drillDownTabs.push(newTab);
|
|
934
|
+
this.emitStateChange(); // Emit state when new tab is added
|
|
935
|
+
}
|
|
936
|
+
// Switch to the new tab
|
|
937
|
+
this.selectTab(tabId);
|
|
938
|
+
// Load drill-down data
|
|
939
|
+
this.loadDrillDownData(newTab);
|
|
940
|
+
}
|
|
941
|
+
onChartTimeRangeChange(range) {
|
|
942
|
+
this.selectedTimeRange = range;
|
|
943
|
+
this.setTimeRange(range);
|
|
944
|
+
}
|
|
945
|
+
getMetricValue(data, metric) {
|
|
946
|
+
switch (metric) {
|
|
947
|
+
case 'executions': return data.executions;
|
|
948
|
+
case 'cost': return data.cost;
|
|
949
|
+
case 'tokens': return data.tokens;
|
|
950
|
+
case 'avgTime': return data.avgTime;
|
|
951
|
+
case 'errors': return data.errors;
|
|
952
|
+
default: return 0;
|
|
953
|
+
}
|
|
954
|
+
}
|
|
955
|
+
formatMetricValue(metric, value) {
|
|
956
|
+
switch (metric) {
|
|
957
|
+
case 'executions': return value.toLocaleString();
|
|
958
|
+
case 'cost': return `$${value.toFixed(4)}`;
|
|
959
|
+
case 'tokens': return value.toLocaleString();
|
|
960
|
+
case 'avgTime': return `${(value / 1000).toFixed(1)}s`;
|
|
961
|
+
case 'errors': return value.toString();
|
|
962
|
+
default: return value.toString();
|
|
963
|
+
}
|
|
964
|
+
}
|
|
965
|
+
async loadExecutionDetails(execution) {
|
|
966
|
+
this.loadingExecutionDetails = true;
|
|
967
|
+
this.executionDetails = null;
|
|
968
|
+
try {
|
|
969
|
+
const details = await this.instrumentationService.getExecutionDetails(execution.id, execution.type);
|
|
970
|
+
this.executionDetails = details;
|
|
971
|
+
}
|
|
972
|
+
catch (error) {
|
|
973
|
+
console.error('Error loading execution details:', error);
|
|
974
|
+
}
|
|
975
|
+
finally {
|
|
976
|
+
this.loadingExecutionDetails = false;
|
|
977
|
+
}
|
|
978
|
+
}
|
|
979
|
+
closeExecutionModal() {
|
|
980
|
+
this.selectedExecution = null;
|
|
981
|
+
this.executionDetails = null;
|
|
982
|
+
this.loadingExecutionDetails = false;
|
|
983
|
+
}
|
|
984
|
+
openFullRecord() {
|
|
985
|
+
if (this.selectedExecution) {
|
|
986
|
+
// Determine the entity name based on the execution type
|
|
987
|
+
const entityName = this.selectedExecution.type === 'prompt'
|
|
988
|
+
? 'MJ: AI Prompt Runs'
|
|
989
|
+
: 'MJ: AI Agent Runs';
|
|
990
|
+
// Emit the event to open the full record
|
|
991
|
+
this.openEntityRecord.emit({
|
|
992
|
+
entityName: entityName,
|
|
993
|
+
recordId: this.selectedExecution.id
|
|
994
|
+
});
|
|
995
|
+
// Close the modal
|
|
996
|
+
this.closeExecutionModal();
|
|
997
|
+
}
|
|
998
|
+
}
|
|
999
|
+
// Utility methods for templates
|
|
1000
|
+
trackByKpiTitle(index, kpi) {
|
|
1001
|
+
return kpi.title;
|
|
1002
|
+
}
|
|
1003
|
+
trackByCostModel(index, item) {
|
|
1004
|
+
return item.model;
|
|
1005
|
+
}
|
|
1006
|
+
trackByEfficiencyModel(index, item) {
|
|
1007
|
+
return item.model;
|
|
1008
|
+
}
|
|
1009
|
+
formatTokens(tokens) {
|
|
1010
|
+
if (tokens >= 1000000) {
|
|
1011
|
+
return `${(tokens / 1000000).toFixed(1)}M`;
|
|
1012
|
+
}
|
|
1013
|
+
else if (tokens >= 1000) {
|
|
1014
|
+
return `${(tokens / 1000).toFixed(1)}K`;
|
|
1015
|
+
}
|
|
1016
|
+
return tokens.toString();
|
|
1017
|
+
}
|
|
1018
|
+
formatCurrency(amount, decimals = 4) {
|
|
1019
|
+
return `$${amount.toFixed(decimals)}`;
|
|
1020
|
+
}
|
|
1021
|
+
formatCostPerToken(cost, tokens) {
|
|
1022
|
+
const costPer1K = tokens > 0 ? (cost / tokens) * 1000 : 0;
|
|
1023
|
+
return `$${costPer1K.toFixed(4)}/1K tokens`;
|
|
1024
|
+
}
|
|
1025
|
+
getCostBarWidth(cost, maxCost) {
|
|
1026
|
+
return maxCost > 0 ? (cost / maxCost) * 100 : 0;
|
|
1027
|
+
}
|
|
1028
|
+
getMaxCost(costData) {
|
|
1029
|
+
return Math.max(...costData.map(item => item.cost));
|
|
1030
|
+
}
|
|
1031
|
+
getTokenRatio(input, output) {
|
|
1032
|
+
const total = input + output;
|
|
1033
|
+
if (total === 0)
|
|
1034
|
+
return '0:0';
|
|
1035
|
+
const ratio = output / input;
|
|
1036
|
+
return `1:${ratio.toFixed(1)}`;
|
|
1037
|
+
}
|
|
1038
|
+
getTokenPercentage(tokens, total) {
|
|
1039
|
+
return total > 0 ? (tokens / total) * 100 : 0;
|
|
1040
|
+
}
|
|
1041
|
+
getCostPerToken(cost, tokens) {
|
|
1042
|
+
const costPer1K = tokens > 0 ? (cost / tokens) * 1000 : 0;
|
|
1043
|
+
return costPer1K.toFixed(4);
|
|
1044
|
+
}
|
|
1045
|
+
// Tab management methods
|
|
1046
|
+
selectTab(tabId) {
|
|
1047
|
+
this.activeTabId = tabId;
|
|
1048
|
+
// Trigger chart resize after tab switch to fix chart rendering
|
|
1049
|
+
setTimeout(() => {
|
|
1050
|
+
window.dispatchEvent(new Event('resize'));
|
|
1051
|
+
}, 100);
|
|
1052
|
+
this.emitStateChange();
|
|
1053
|
+
}
|
|
1054
|
+
closeTab(event, tabId) {
|
|
1055
|
+
event.stopPropagation();
|
|
1056
|
+
const tabIndex = this.drillDownTabs.findIndex(tab => tab.id === tabId);
|
|
1057
|
+
if (tabIndex === -1)
|
|
1058
|
+
return;
|
|
1059
|
+
// Remove the tab
|
|
1060
|
+
this.drillDownTabs.splice(tabIndex, 1);
|
|
1061
|
+
// If we closed the active tab, switch to another tab
|
|
1062
|
+
if (this.activeTabId === tabId) {
|
|
1063
|
+
if (this.drillDownTabs.length > 0) {
|
|
1064
|
+
// Switch to the previous tab or first tab
|
|
1065
|
+
const newActiveIndex = Math.max(0, tabIndex - 1);
|
|
1066
|
+
this.activeTabId = this.drillDownTabs[newActiveIndex].id;
|
|
1067
|
+
// Trigger resize after tab switch
|
|
1068
|
+
setTimeout(() => {
|
|
1069
|
+
window.dispatchEvent(new Event('resize'));
|
|
1070
|
+
}, 100);
|
|
1071
|
+
}
|
|
1072
|
+
else {
|
|
1073
|
+
// No tabs left, this shouldn't happen as main chart is not closeable
|
|
1074
|
+
this.activeTabId = 'main-chart';
|
|
1075
|
+
}
|
|
1076
|
+
}
|
|
1077
|
+
this.emitStateChange();
|
|
1078
|
+
}
|
|
1079
|
+
// KPI click handling
|
|
1080
|
+
onKpiClick(kpi) {
|
|
1081
|
+
if (kpi.title === 'Top Model' && kpi.value !== 'N/A') {
|
|
1082
|
+
this.openModelDrillDown(String(kpi.value));
|
|
1083
|
+
}
|
|
1084
|
+
// Add other KPI drill-downs as needed
|
|
1085
|
+
}
|
|
1086
|
+
isKpiClickable(kpi) {
|
|
1087
|
+
return kpi.title === 'Top Model' && kpi.value !== 'N/A';
|
|
1088
|
+
}
|
|
1089
|
+
async openModelDrillDown(modelName) {
|
|
1090
|
+
const tabId = `model-detail-${modelName.replace(/[^a-zA-Z0-9]/g, '-')}`;
|
|
1091
|
+
const tabTitle = `Model: ${modelName}`;
|
|
1092
|
+
// Check if tab already exists
|
|
1093
|
+
if (this.drillDownTabs.find(tab => tab.id === tabId)) {
|
|
1094
|
+
this.selectTab(tabId);
|
|
1095
|
+
return;
|
|
1096
|
+
}
|
|
1097
|
+
// Create new model detail tab
|
|
1098
|
+
const newTab = {
|
|
1099
|
+
id: tabId,
|
|
1100
|
+
title: tabTitle,
|
|
1101
|
+
type: 'model-detail',
|
|
1102
|
+
closeable: true
|
|
1103
|
+
};
|
|
1104
|
+
this.drillDownTabs.push(newTab);
|
|
1105
|
+
this.selectTab(tabId);
|
|
1106
|
+
// Load model details
|
|
1107
|
+
this.loadModelDetails(newTab, modelName);
|
|
1108
|
+
}
|
|
1109
|
+
async loadDrillDownData(tab) {
|
|
1110
|
+
if (!tab.timestamp)
|
|
1111
|
+
return;
|
|
1112
|
+
this.loadingDrillDown = true;
|
|
1113
|
+
try {
|
|
1114
|
+
// Create time window around the clicked point (±30 minutes)
|
|
1115
|
+
const startTime = new Date(tab.timestamp.getTime() - 30 * 60 * 1000);
|
|
1116
|
+
const endTime = new Date(tab.timestamp.getTime() + 30 * 60 * 1000);
|
|
1117
|
+
// Load executions for this time period
|
|
1118
|
+
const [promptResults, agentResults] = await Promise.all([
|
|
1119
|
+
new RunView().RunView({
|
|
1120
|
+
EntityName: 'MJ: AI Prompt Runs',
|
|
1121
|
+
ExtraFilter: `RunAt >= '${startTime.toISOString()}' AND RunAt <= '${endTime.toISOString()}'`,
|
|
1122
|
+
OrderBy: 'RunAt DESC',
|
|
1123
|
+
ResultType: 'entity_object'
|
|
1124
|
+
}),
|
|
1125
|
+
new RunView().RunView({
|
|
1126
|
+
EntityName: 'MJ: AI Agent Runs',
|
|
1127
|
+
ExtraFilter: `StartedAt >= '${startTime.toISOString()}' AND StartedAt <= '${endTime.toISOString()}'`,
|
|
1128
|
+
OrderBy: 'StartedAt DESC',
|
|
1129
|
+
ResultType: 'entity_object'
|
|
1130
|
+
})
|
|
1131
|
+
]);
|
|
1132
|
+
// Convert to ExecutionRecord format
|
|
1133
|
+
const executions = [];
|
|
1134
|
+
// Add prompt executions
|
|
1135
|
+
for (const run of promptResults.Results) {
|
|
1136
|
+
const duration = run.CompletedAt ?
|
|
1137
|
+
new Date(run.CompletedAt).getTime() - new Date(run.RunAt).getTime() :
|
|
1138
|
+
Date.now() - new Date(run.RunAt).getTime();
|
|
1139
|
+
executions.push({
|
|
1140
|
+
id: run.ID,
|
|
1141
|
+
type: 'prompt',
|
|
1142
|
+
name: await this.getPromptName(run.PromptID),
|
|
1143
|
+
model: run.ModelID ? await this.getModelName(run.ModelID) : undefined,
|
|
1144
|
+
status: run.Success ? 'completed' : (run.Success === false ? 'failed' : 'running'),
|
|
1145
|
+
startTime: new Date(run.RunAt),
|
|
1146
|
+
endTime: run.CompletedAt ? new Date(run.CompletedAt) : undefined,
|
|
1147
|
+
duration: duration,
|
|
1148
|
+
cost: run.Cost || 0,
|
|
1149
|
+
tokens: run.TokensUsed || 0,
|
|
1150
|
+
errorMessage: run.ErrorMessage || undefined
|
|
1151
|
+
});
|
|
1152
|
+
}
|
|
1153
|
+
// Add agent executions
|
|
1154
|
+
for (const run of agentResults.Results) {
|
|
1155
|
+
const duration = run.CompletedAt ?
|
|
1156
|
+
new Date(run.CompletedAt).getTime() - new Date(run.StartedAt).getTime() :
|
|
1157
|
+
Date.now() - new Date(run.StartedAt).getTime();
|
|
1158
|
+
executions.push({
|
|
1159
|
+
id: run.ID,
|
|
1160
|
+
type: 'agent',
|
|
1161
|
+
name: await this.getAgentName(run.AgentID),
|
|
1162
|
+
status: run.Status.toLowerCase(),
|
|
1163
|
+
startTime: new Date(run.StartedAt),
|
|
1164
|
+
endTime: run.CompletedAt ? new Date(run.CompletedAt) : undefined,
|
|
1165
|
+
duration: duration,
|
|
1166
|
+
cost: run.TotalCost || 0,
|
|
1167
|
+
tokens: run.TotalTokensUsed || 0,
|
|
1168
|
+
errorMessage: run.ErrorMessage || undefined
|
|
1169
|
+
});
|
|
1170
|
+
}
|
|
1171
|
+
// Sort by start time (most recent first)
|
|
1172
|
+
executions.sort((a, b) => b.startTime.getTime() - a.startTime.getTime());
|
|
1173
|
+
// Update tab data
|
|
1174
|
+
tab.data = executions;
|
|
1175
|
+
}
|
|
1176
|
+
catch (error) {
|
|
1177
|
+
console.error('Error loading drill-down data:', error);
|
|
1178
|
+
tab.data = [];
|
|
1179
|
+
}
|
|
1180
|
+
finally {
|
|
1181
|
+
this.loadingDrillDown = false;
|
|
1182
|
+
}
|
|
1183
|
+
}
|
|
1184
|
+
async loadModelDetails(tab, modelName) {
|
|
1185
|
+
this.loadingDrillDown = true;
|
|
1186
|
+
try {
|
|
1187
|
+
// Find model by name
|
|
1188
|
+
const rv = new RunView();
|
|
1189
|
+
const result = await rv.RunView({
|
|
1190
|
+
EntityName: 'AI Models',
|
|
1191
|
+
ExtraFilter: `Name = '${modelName.replace(/'/g, "''")}'`,
|
|
1192
|
+
ResultType: 'entity_object'
|
|
1193
|
+
});
|
|
1194
|
+
const model = result.Results[0];
|
|
1195
|
+
if (model) {
|
|
1196
|
+
tab.data = {
|
|
1197
|
+
name: model.Name,
|
|
1198
|
+
vendor: model.Vendor,
|
|
1199
|
+
apiName: model.APIName,
|
|
1200
|
+
inputTokenCost: 0, // Not available in current model
|
|
1201
|
+
outputTokenCost: 0, // Not available in current model
|
|
1202
|
+
isActive: model.IsActive,
|
|
1203
|
+
description: model.Description
|
|
1204
|
+
};
|
|
1205
|
+
}
|
|
1206
|
+
else {
|
|
1207
|
+
tab.data = null;
|
|
1208
|
+
}
|
|
1209
|
+
}
|
|
1210
|
+
catch (error) {
|
|
1211
|
+
console.error('Error loading model details:', error);
|
|
1212
|
+
tab.data = null;
|
|
1213
|
+
}
|
|
1214
|
+
finally {
|
|
1215
|
+
this.loadingDrillDown = false;
|
|
1216
|
+
}
|
|
1217
|
+
}
|
|
1218
|
+
// Helper methods for drill-down
|
|
1219
|
+
async getPromptName(promptId) {
|
|
1220
|
+
try {
|
|
1221
|
+
const rv = new RunView();
|
|
1222
|
+
const result = await rv.RunView({
|
|
1223
|
+
EntityName: 'AI Prompts',
|
|
1224
|
+
ExtraFilter: `ID = '${promptId}'`,
|
|
1225
|
+
ResultType: 'entity_object'
|
|
1226
|
+
});
|
|
1227
|
+
return result.Results[0]?.Name || 'Unknown Prompt';
|
|
1228
|
+
}
|
|
1229
|
+
catch {
|
|
1230
|
+
return 'Unknown Prompt';
|
|
1231
|
+
}
|
|
1232
|
+
}
|
|
1233
|
+
async getAgentName(agentId) {
|
|
1234
|
+
try {
|
|
1235
|
+
const rv = new RunView();
|
|
1236
|
+
const result = await rv.RunView({
|
|
1237
|
+
EntityName: 'AI Agents',
|
|
1238
|
+
ExtraFilter: `ID = '${agentId}'`,
|
|
1239
|
+
ResultType: 'entity_object'
|
|
1240
|
+
});
|
|
1241
|
+
return result.Results[0]?.Name || 'Unknown Agent';
|
|
1242
|
+
}
|
|
1243
|
+
catch {
|
|
1244
|
+
return 'Unknown Agent';
|
|
1245
|
+
}
|
|
1246
|
+
}
|
|
1247
|
+
async getModelName(modelId) {
|
|
1248
|
+
try {
|
|
1249
|
+
const rv = new RunView();
|
|
1250
|
+
const result = await rv.RunView({
|
|
1251
|
+
EntityName: 'AI Models',
|
|
1252
|
+
ExtraFilter: `ID = '${modelId}'`,
|
|
1253
|
+
ResultType: 'entity_object'
|
|
1254
|
+
});
|
|
1255
|
+
return result.Results[0]?.Name || 'Unknown Model';
|
|
1256
|
+
}
|
|
1257
|
+
catch {
|
|
1258
|
+
return 'Unknown Model';
|
|
1259
|
+
}
|
|
1260
|
+
}
|
|
1261
|
+
formatTimestamp(timestamp) {
|
|
1262
|
+
return timestamp.toLocaleString();
|
|
1263
|
+
}
|
|
1264
|
+
formatTime(time) {
|
|
1265
|
+
return time.toLocaleTimeString();
|
|
1266
|
+
}
|
|
1267
|
+
getMetricDisplayLabel(metric) {
|
|
1268
|
+
const labels = {
|
|
1269
|
+
executions: 'Executions',
|
|
1270
|
+
cost: 'Cost',
|
|
1271
|
+
tokens: 'Tokens',
|
|
1272
|
+
avgTime: 'Avg Time',
|
|
1273
|
+
errors: 'Errors'
|
|
1274
|
+
};
|
|
1275
|
+
return labels[metric] || metric;
|
|
1276
|
+
}
|
|
1277
|
+
getFormattedTimestamp(tab) {
|
|
1278
|
+
return tab?.timestamp ? this.formatTimestamp(tab.timestamp) : '';
|
|
1279
|
+
}
|
|
1280
|
+
getFormattedMetricLabel(tab) {
|
|
1281
|
+
return tab?.metric ? this.getMetricDisplayLabel(tab.metric) : '';
|
|
1282
|
+
}
|
|
1283
|
+
// Panel management methods
|
|
1284
|
+
togglePanel(panelName) {
|
|
1285
|
+
this.panelStates[panelName] = !this.panelStates[panelName];
|
|
1286
|
+
this.emitStateChange();
|
|
1287
|
+
}
|
|
1288
|
+
viewExecutionDetail(execution) {
|
|
1289
|
+
// Convert ExecutionRecord to LiveExecution format for the modal
|
|
1290
|
+
const liveExecution = {
|
|
1291
|
+
id: execution.id,
|
|
1292
|
+
type: execution.type,
|
|
1293
|
+
name: execution.name,
|
|
1294
|
+
status: execution.status,
|
|
1295
|
+
startTime: execution.startTime,
|
|
1296
|
+
duration: execution.duration,
|
|
1297
|
+
cost: execution.cost,
|
|
1298
|
+
tokens: execution.tokens
|
|
1299
|
+
};
|
|
1300
|
+
this.onExecutionClick(liveExecution);
|
|
1301
|
+
}
|
|
1302
|
+
formatDuration(milliseconds) {
|
|
1303
|
+
const seconds = Math.floor(milliseconds / 1000);
|
|
1304
|
+
const minutes = Math.floor(seconds / 60);
|
|
1305
|
+
const hours = Math.floor(minutes / 60);
|
|
1306
|
+
if (hours > 0) {
|
|
1307
|
+
return `${hours}h ${minutes % 60}m ${seconds % 60}s`;
|
|
1308
|
+
}
|
|
1309
|
+
else if (minutes > 0) {
|
|
1310
|
+
return `${minutes}m ${seconds % 60}s`;
|
|
1311
|
+
}
|
|
1312
|
+
else {
|
|
1313
|
+
return `${seconds}s`;
|
|
1314
|
+
}
|
|
1315
|
+
}
|
|
1316
|
+
getDuration(details) {
|
|
1317
|
+
const start = details.startTime.getTime();
|
|
1318
|
+
const end = details.endTime ? details.endTime.getTime() : Date.now();
|
|
1319
|
+
return end - start;
|
|
1320
|
+
}
|
|
1321
|
+
onSplitterLayoutChange(event) {
|
|
1322
|
+
// Trigger window resize event to force charts to recalculate dimensions
|
|
1323
|
+
setTimeout(() => {
|
|
1324
|
+
window.dispatchEvent(new Event('resize'));
|
|
1325
|
+
}, 100);
|
|
1326
|
+
// Emit state change when splitter changes
|
|
1327
|
+
this.emitStateChange();
|
|
1328
|
+
}
|
|
1329
|
+
static ɵfac = function ExecutionMonitoringComponent_Factory(t) { return new (t || ExecutionMonitoringComponent)(i0.ɵɵdirectiveInject(i1.AIInstrumentationService)); };
|
|
1330
|
+
static ɵcmp = /*@__PURE__*/ i0.ɵɵdefineComponent({ type: ExecutionMonitoringComponent, selectors: [["app-execution-monitoring"]], inputs: { initialState: "initialState" }, outputs: { openEntityRecord: "openEntityRecord", stateChange: "stateChange" }, decls: 94, vars: 52, consts: [[1, "execution-monitoring"], [1, "monitoring-header"], [1, "monitoring-title"], [1, "fa-solid", "fa-chart-line"], [1, "monitoring-controls"], [1, "refresh-control"], [3, "ngModelChange", "change", "ngModel"], [3, "value"], [1, "time-range-control"], ["value", "1h"], ["value", "6h"], ["value", "24h"], ["value", "7d"], ["value", "30d"], [1, "refresh-btn", 3, "click", "disabled"], [1, "fa-solid", "fa-refresh"], [1, "kpi-dashboard"], [1, "kpi-grid"], [3, "data", "clickable"], ["orientation", "vertical", 1, "dashboard-splitter", 3, "layoutChange"], ["size", "45%", 3, "resizable", "collapsible"], ["orientation", "horizontal", 3, "layoutChange"], ["size", "30%", 3, "resizable", "collapsible", "collapsed"], [1, "dashboard-section", "system-status"], [1, "status-container"], [1, "chart-header"], [1, "chart-title"], [1, "fa-solid", "fa-heartbeat"], [1, "status-metrics"], [3, "resizable", "collapsible"], [1, "dashboard-section", "drill-down-container"], [1, "drill-down-tabs"], [1, "tab-header"], [1, "tab-item", 3, "active"], [1, "tab-content"], [1, "tab-pane", "trends-chart"], [1, "tab-pane", "executions-drill-down"], [1, "tab-pane", "model-detail"], ["size", "50%", 3, "resizable", "collapsible"], [1, "dashboard-section", "performance-matrix"], ["title", "Agent vs Model Performance", 3, "data", "config"], [1, "dashboard-section", "analysis-panels"], [1, "analysis-panel"], [1, "panel-header", 3, "click"], [1, "panel-title"], [1, "fa-solid", "fa-dollar-sign"], [1, "fa-solid", "panel-toggle-icon"], [1, "panel-content"], [1, "fa-solid", "fa-chart-pie"], [1, "fa-solid", "fa-bolt"], [1, "panel-content", "live-executions-panel"], [1, "execution-modal"], [3, "click", "data"], [1, "status-metric"], [1, "status-icon", "status-icon--success"], [1, "fa-solid", "fa-check"], [1, "status-info"], [1, "status-label"], [1, "status-value"], [1, "status-subtitle"], [1, "status-icon", "status-icon--warning"], [1, "fa-solid", "fa-exclamation-triangle"], [1, "status-icon", "status-icon--info"], [1, "fa-solid", "fa-clock"], [1, "status-icon", "status-icon--primary"], [1, "tab-item", 3, "click"], [1, "tab-title"], ["title", "Close tab", 1, "tab-close"], ["title", "Close tab", 1, "tab-close", 3, "click"], [1, "fa-solid", "fa-times"], ["title", "Execution Trends", 3, "dataPointClick", "timeRangeChange", "data", "config"], [1, "drill-down-header"], [1, "fa-solid", "fa-list"], [1, "drill-down-meta"], [1, "timestamp"], [1, "metric-badge"], [1, "loading-spinner"], [1, "executions-table"], [1, "no-data"], [1, "fa-solid", "fa-spinner", "fa-spin"], [1, "table-header"], [1, "header-cell"], [1, "table-row"], [1, "table-row", 3, "click"], [1, "table-cell"], [1, "type-badge"], [1, "status-badge"], [1, "fa-solid", "fa-inbox"], [1, "fa-solid", "fa-microchip"], [1, "model-details"], [1, "model-info-grid"], [1, "info-item"], [1, "status-indicator"], [1, "model-description"], [1, "cost-bars"], [1, "cost-bar-item"], [1, "cost-bar-info"], [1, "model-name"], [1, "cost-value"], [1, "cost-bar-container"], [1, "cost-bar"], [1, "token-info"], [1, "efficiency-items"], [1, "efficiency-item"], [1, "efficiency-header"], [1, "efficiency-ratio"], [1, "token-breakdown"], [1, "token-bar"], [1, "token-segment", "token-segment--input"], [1, "token-segment", "token-segment--output"], [1, "token-labels"], [1, "input-label"], [1, "output-label"], [1, "cost-per-token"], [3, "executionClick", "executions"], [1, "execution-modal", 3, "click"], [1, "execution-modal-content", 3, "click"], [1, "execution-modal-header"], [1, "modal-header-actions"], [1, "open-record-btn", 3, "click"], [1, "fa-solid", "fa-external-link-alt"], [1, "close-btn", 3, "click"], [1, "execution-modal-body"], [1, "execution-details"], [1, "loading-details"], [1, "detail-section"], [1, "detail-grid"], [1, "detail-item"], [1, "error-message"], [1, "child-executions"], [1, "child-execution"], [1, "child-info"], [1, "child-name"], [1, "child-type"], [1, "child-status"], [1, "child-metrics"], [1, "spinner"]], template: function ExecutionMonitoringComponent_Template(rf, ctx) { if (rf & 1) {
|
|
1331
|
+
i0.ɵɵelementStart(0, "div", 0)(1, "div", 1)(2, "h2", 2);
|
|
1332
|
+
i0.ɵɵelement(3, "i", 3);
|
|
1333
|
+
i0.ɵɵtext(4, " AI Execution Monitoring ");
|
|
1334
|
+
i0.ɵɵelementEnd();
|
|
1335
|
+
i0.ɵɵelementStart(5, "div", 4)(6, "div", 5)(7, "label");
|
|
1336
|
+
i0.ɵɵtext(8, "Refresh:");
|
|
1337
|
+
i0.ɵɵelementEnd();
|
|
1338
|
+
i0.ɵɵelementStart(9, "select", 6);
|
|
1339
|
+
i0.ɵɵtwoWayListener("ngModelChange", function ExecutionMonitoringComponent_Template_select_ngModelChange_9_listener($event) { i0.ɵɵtwoWayBindingSet(ctx.refreshInterval, $event) || (ctx.refreshInterval = $event); return $event; });
|
|
1340
|
+
i0.ɵɵlistener("change", function ExecutionMonitoringComponent_Template_select_change_9_listener() { return ctx.onRefreshIntervalChange(); });
|
|
1341
|
+
i0.ɵɵelementStart(10, "option", 7);
|
|
1342
|
+
i0.ɵɵtext(11, "Manual");
|
|
1343
|
+
i0.ɵɵelementEnd();
|
|
1344
|
+
i0.ɵɵelementStart(12, "option", 7);
|
|
1345
|
+
i0.ɵɵtext(13, "10s");
|
|
1346
|
+
i0.ɵɵelementEnd();
|
|
1347
|
+
i0.ɵɵelementStart(14, "option", 7);
|
|
1348
|
+
i0.ɵɵtext(15, "30s");
|
|
1349
|
+
i0.ɵɵelementEnd();
|
|
1350
|
+
i0.ɵɵelementStart(16, "option", 7);
|
|
1351
|
+
i0.ɵɵtext(17, "1m");
|
|
1352
|
+
i0.ɵɵelementEnd();
|
|
1353
|
+
i0.ɵɵelementStart(18, "option", 7);
|
|
1354
|
+
i0.ɵɵtext(19, "5m");
|
|
1355
|
+
i0.ɵɵelementEnd()()();
|
|
1356
|
+
i0.ɵɵelementStart(20, "div", 8)(21, "label");
|
|
1357
|
+
i0.ɵɵtext(22, "Time Range:");
|
|
1358
|
+
i0.ɵɵelementEnd();
|
|
1359
|
+
i0.ɵɵelementStart(23, "select", 6);
|
|
1360
|
+
i0.ɵɵtwoWayListener("ngModelChange", function ExecutionMonitoringComponent_Template_select_ngModelChange_23_listener($event) { i0.ɵɵtwoWayBindingSet(ctx.selectedTimeRange, $event) || (ctx.selectedTimeRange = $event); return $event; });
|
|
1361
|
+
i0.ɵɵlistener("change", function ExecutionMonitoringComponent_Template_select_change_23_listener() { return ctx.onTimeRangeChange(); });
|
|
1362
|
+
i0.ɵɵelementStart(24, "option", 9);
|
|
1363
|
+
i0.ɵɵtext(25, "Last Hour");
|
|
1364
|
+
i0.ɵɵelementEnd();
|
|
1365
|
+
i0.ɵɵelementStart(26, "option", 10);
|
|
1366
|
+
i0.ɵɵtext(27, "Last 6 Hours");
|
|
1367
|
+
i0.ɵɵelementEnd();
|
|
1368
|
+
i0.ɵɵelementStart(28, "option", 11);
|
|
1369
|
+
i0.ɵɵtext(29, "Last 24 Hours");
|
|
1370
|
+
i0.ɵɵelementEnd();
|
|
1371
|
+
i0.ɵɵelementStart(30, "option", 12);
|
|
1372
|
+
i0.ɵɵtext(31, "Last 7 Days");
|
|
1373
|
+
i0.ɵɵelementEnd();
|
|
1374
|
+
i0.ɵɵelementStart(32, "option", 13);
|
|
1375
|
+
i0.ɵɵtext(33, "Last 30 Days");
|
|
1376
|
+
i0.ɵɵelementEnd()()();
|
|
1377
|
+
i0.ɵɵelementStart(34, "button", 14);
|
|
1378
|
+
i0.ɵɵlistener("click", function ExecutionMonitoringComponent_Template_button_click_34_listener() { return ctx.refreshData(); });
|
|
1379
|
+
i0.ɵɵelement(35, "i", 15);
|
|
1380
|
+
i0.ɵɵtext(36, " Refresh ");
|
|
1381
|
+
i0.ɵɵelementEnd()()();
|
|
1382
|
+
i0.ɵɵelementStart(37, "div", 16)(38, "div", 17);
|
|
1383
|
+
i0.ɵɵrepeaterCreate(39, ExecutionMonitoringComponent_For_40_Template, 1, 3, "app-kpi-card", 18, _forTrack0);
|
|
1384
|
+
i0.ɵɵpipe(41, "async");
|
|
1385
|
+
i0.ɵɵelementEnd()();
|
|
1386
|
+
i0.ɵɵelementStart(42, "kendo-splitter", 19);
|
|
1387
|
+
i0.ɵɵlistener("layoutChange", function ExecutionMonitoringComponent_Template_kendo_splitter_layoutChange_42_listener($event) { return ctx.onSplitterLayoutChange($event); });
|
|
1388
|
+
i0.ɵɵelementStart(43, "kendo-splitter-pane", 20)(44, "kendo-splitter", 21);
|
|
1389
|
+
i0.ɵɵlistener("layoutChange", function ExecutionMonitoringComponent_Template_kendo_splitter_layoutChange_44_listener($event) { return ctx.onSplitterLayoutChange($event); });
|
|
1390
|
+
i0.ɵɵelementStart(45, "kendo-splitter-pane", 22)(46, "div", 23)(47, "div", 24)(48, "div", 25)(49, "h4", 26);
|
|
1391
|
+
i0.ɵɵelement(50, "i", 27);
|
|
1392
|
+
i0.ɵɵtext(51, " System Health ");
|
|
1393
|
+
i0.ɵɵelementEnd()();
|
|
1394
|
+
i0.ɵɵtemplate(52, ExecutionMonitoringComponent_Conditional_52_Template, 41, 6, "div", 28);
|
|
1395
|
+
i0.ɵɵpipe(53, "async");
|
|
1396
|
+
i0.ɵɵelementEnd()()();
|
|
1397
|
+
i0.ɵɵelementStart(54, "kendo-splitter-pane", 29)(55, "div", 30)(56, "div", 31)(57, "div", 32);
|
|
1398
|
+
i0.ɵɵrepeaterCreate(58, ExecutionMonitoringComponent_For_59_Template, 4, 4, "div", 33, _forTrack1);
|
|
1399
|
+
i0.ɵɵelementEnd();
|
|
1400
|
+
i0.ɵɵelementStart(60, "div", 34);
|
|
1401
|
+
i0.ɵɵtemplate(61, ExecutionMonitoringComponent_Conditional_61_Template, 3, 5, "div", 35)(62, ExecutionMonitoringComponent_Conditional_62_Template, 11, 4, "div", 36)(63, ExecutionMonitoringComponent_Conditional_63_Template, 7, 2, "div", 37);
|
|
1402
|
+
i0.ɵɵelementEnd()()()()()();
|
|
1403
|
+
i0.ɵɵelementStart(64, "kendo-splitter-pane", 29)(65, "kendo-splitter", 21);
|
|
1404
|
+
i0.ɵɵlistener("layoutChange", function ExecutionMonitoringComponent_Template_kendo_splitter_layoutChange_65_listener($event) { return ctx.onSplitterLayoutChange($event); });
|
|
1405
|
+
i0.ɵɵelementStart(66, "kendo-splitter-pane", 38)(67, "div", 39);
|
|
1406
|
+
i0.ɵɵelement(68, "app-performance-heatmap", 40);
|
|
1407
|
+
i0.ɵɵpipe(69, "async");
|
|
1408
|
+
i0.ɵɵelementEnd()();
|
|
1409
|
+
i0.ɵɵelementStart(70, "kendo-splitter-pane", 29)(71, "div", 41)(72, "div", 42)(73, "div", 43);
|
|
1410
|
+
i0.ɵɵlistener("click", function ExecutionMonitoringComponent_Template_div_click_73_listener() { return ctx.togglePanel("cost"); });
|
|
1411
|
+
i0.ɵɵelementStart(74, "span", 44);
|
|
1412
|
+
i0.ɵɵelement(75, "i", 45);
|
|
1413
|
+
i0.ɵɵtext(76, " Cost Analysis ");
|
|
1414
|
+
i0.ɵɵelementEnd();
|
|
1415
|
+
i0.ɵɵelement(77, "i", 46);
|
|
1416
|
+
i0.ɵɵelementEnd();
|
|
1417
|
+
i0.ɵɵtemplate(78, ExecutionMonitoringComponent_Conditional_78_Template, 3, 3, "div", 47);
|
|
1418
|
+
i0.ɵɵelementEnd();
|
|
1419
|
+
i0.ɵɵelementStart(79, "div", 42)(80, "div", 43);
|
|
1420
|
+
i0.ɵɵlistener("click", function ExecutionMonitoringComponent_Template_div_click_80_listener() { return ctx.togglePanel("efficiency"); });
|
|
1421
|
+
i0.ɵɵelementStart(81, "span", 44);
|
|
1422
|
+
i0.ɵɵelement(82, "i", 48);
|
|
1423
|
+
i0.ɵɵtext(83, " Token Efficiency ");
|
|
1424
|
+
i0.ɵɵelementEnd();
|
|
1425
|
+
i0.ɵɵelement(84, "i", 46);
|
|
1426
|
+
i0.ɵɵelementEnd();
|
|
1427
|
+
i0.ɵɵtemplate(85, ExecutionMonitoringComponent_Conditional_85_Template, 3, 3, "div", 47);
|
|
1428
|
+
i0.ɵɵelementEnd();
|
|
1429
|
+
i0.ɵɵelementStart(86, "div", 42)(87, "div", 43);
|
|
1430
|
+
i0.ɵɵlistener("click", function ExecutionMonitoringComponent_Template_div_click_87_listener() { return ctx.togglePanel("executions"); });
|
|
1431
|
+
i0.ɵɵelementStart(88, "span", 44);
|
|
1432
|
+
i0.ɵɵelement(89, "i", 49);
|
|
1433
|
+
i0.ɵɵtext(90, " Live Executions ");
|
|
1434
|
+
i0.ɵɵelementEnd();
|
|
1435
|
+
i0.ɵɵelement(91, "i", 46);
|
|
1436
|
+
i0.ɵɵelementEnd();
|
|
1437
|
+
i0.ɵɵtemplate(92, ExecutionMonitoringComponent_Conditional_92_Template, 3, 4, "div", 50);
|
|
1438
|
+
i0.ɵɵelementEnd()()()()()();
|
|
1439
|
+
i0.ɵɵtemplate(93, ExecutionMonitoringComponent_Conditional_93_Template, 14, 2, "div", 51);
|
|
1440
|
+
i0.ɵɵelementEnd();
|
|
1441
|
+
} if (rf & 2) {
|
|
1442
|
+
let tmp_15_0;
|
|
1443
|
+
let tmp_26_0;
|
|
1444
|
+
i0.ɵɵadvance(9);
|
|
1445
|
+
i0.ɵɵtwoWayProperty("ngModel", ctx.refreshInterval);
|
|
1446
|
+
i0.ɵɵadvance();
|
|
1447
|
+
i0.ɵɵproperty("value", 0);
|
|
1448
|
+
i0.ɵɵadvance(2);
|
|
1449
|
+
i0.ɵɵproperty("value", 10000);
|
|
1450
|
+
i0.ɵɵadvance(2);
|
|
1451
|
+
i0.ɵɵproperty("value", 30000);
|
|
1452
|
+
i0.ɵɵadvance(2);
|
|
1453
|
+
i0.ɵɵproperty("value", 60000);
|
|
1454
|
+
i0.ɵɵadvance(2);
|
|
1455
|
+
i0.ɵɵproperty("value", 300000);
|
|
1456
|
+
i0.ɵɵadvance(5);
|
|
1457
|
+
i0.ɵɵtwoWayProperty("ngModel", ctx.selectedTimeRange);
|
|
1458
|
+
i0.ɵɵadvance(11);
|
|
1459
|
+
i0.ɵɵproperty("disabled", ctx.isLoading);
|
|
1460
|
+
i0.ɵɵadvance();
|
|
1461
|
+
i0.ɵɵclassProp("spinning", ctx.isLoading);
|
|
1462
|
+
i0.ɵɵadvance(4);
|
|
1463
|
+
i0.ɵɵrepeater(i0.ɵɵpipeBind1(41, 45, ctx.kpiCards$));
|
|
1464
|
+
i0.ɵɵadvance(4);
|
|
1465
|
+
i0.ɵɵproperty("resizable", true)("collapsible", false);
|
|
1466
|
+
i0.ɵɵadvance(2);
|
|
1467
|
+
i0.ɵɵproperty("resizable", true)("collapsible", true)("collapsed", false);
|
|
1468
|
+
i0.ɵɵadvance(7);
|
|
1469
|
+
i0.ɵɵconditional((tmp_15_0 = i0.ɵɵpipeBind1(53, 47, ctx.kpis$)) ? 52 : -1, tmp_15_0);
|
|
1470
|
+
i0.ɵɵadvance(2);
|
|
1471
|
+
i0.ɵɵproperty("resizable", true)("collapsible", false);
|
|
1472
|
+
i0.ɵɵadvance(4);
|
|
1473
|
+
i0.ɵɵrepeater(ctx.drillDownTabs);
|
|
1474
|
+
i0.ɵɵadvance(3);
|
|
1475
|
+
i0.ɵɵconditional((ctx.activeTab == null ? null : ctx.activeTab.type) === "chart" ? 61 : -1);
|
|
1476
|
+
i0.ɵɵadvance();
|
|
1477
|
+
i0.ɵɵconditional((ctx.activeTab == null ? null : ctx.activeTab.type) === "executions" ? 62 : -1);
|
|
1478
|
+
i0.ɵɵadvance();
|
|
1479
|
+
i0.ɵɵconditional((ctx.activeTab == null ? null : ctx.activeTab.type) === "model-detail" ? 63 : -1);
|
|
1480
|
+
i0.ɵɵadvance();
|
|
1481
|
+
i0.ɵɵproperty("resizable", true)("collapsible", false);
|
|
1482
|
+
i0.ɵɵadvance(2);
|
|
1483
|
+
i0.ɵɵproperty("resizable", true)("collapsible", false);
|
|
1484
|
+
i0.ɵɵadvance(2);
|
|
1485
|
+
i0.ɵɵproperty("data", (tmp_26_0 = i0.ɵɵpipeBind1(69, 49, ctx.performanceMatrix$)) !== null && tmp_26_0 !== undefined ? tmp_26_0 : i0.ɵɵpureFunction0(51, _c0))("config", ctx.heatmapConfig);
|
|
1486
|
+
i0.ɵɵadvance(2);
|
|
1487
|
+
i0.ɵɵproperty("resizable", true)("collapsible", false);
|
|
1488
|
+
i0.ɵɵadvance(7);
|
|
1489
|
+
i0.ɵɵclassProp("fa-chevron-down", !ctx.panelStates.cost)("fa-chevron-up", ctx.panelStates.cost);
|
|
1490
|
+
i0.ɵɵadvance();
|
|
1491
|
+
i0.ɵɵconditional(ctx.panelStates.cost ? 78 : -1);
|
|
1492
|
+
i0.ɵɵadvance(6);
|
|
1493
|
+
i0.ɵɵclassProp("fa-chevron-down", !ctx.panelStates.efficiency)("fa-chevron-up", ctx.panelStates.efficiency);
|
|
1494
|
+
i0.ɵɵadvance();
|
|
1495
|
+
i0.ɵɵconditional(ctx.panelStates.efficiency ? 85 : -1);
|
|
1496
|
+
i0.ɵɵadvance(6);
|
|
1497
|
+
i0.ɵɵclassProp("fa-chevron-down", !ctx.panelStates.executions)("fa-chevron-up", ctx.panelStates.executions);
|
|
1498
|
+
i0.ɵɵadvance();
|
|
1499
|
+
i0.ɵɵconditional(ctx.panelStates.executions ? 92 : -1);
|
|
1500
|
+
i0.ɵɵadvance();
|
|
1501
|
+
i0.ɵɵconditional(ctx.selectedExecution ? 93 : -1);
|
|
1502
|
+
} }, dependencies: [i2.NgSelectOption, i2.ɵNgSelectMultipleOption, i2.SelectControlValueAccessor, i2.NgControlStatus, i2.NgModel, i3.SplitterComponent, i3.SplitterPaneComponent, i4.KPICardComponent, i5.LiveExecutionWidgetComponent, i6.TimeSeriesChartComponent, i7.PerformanceHeatmapComponent, i8.AsyncPipe, i8.TitleCasePipe, i8.DatePipe], styles: [".execution-monitoring[_ngcontent-%COMP%] {\n padding: 20px;\n background: #f8f9fa;\n min-height: 100vh;\n }\n\n .monitoring-header[_ngcontent-%COMP%] {\n background: white;\n padding: 20px;\n border-radius: 8px;\n box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);\n margin-bottom: 20px;\n display: flex;\n justify-content: space-between;\n align-items: center;\n flex-wrap: wrap;\n gap: 16px;\n }\n\n .monitoring-title[_ngcontent-%COMP%] {\n margin: 0;\n font-size: 20px;\n font-weight: 600;\n color: #333;\n display: flex;\n align-items: center;\n gap: 12px;\n }\n\n .monitoring-title[_ngcontent-%COMP%] i[_ngcontent-%COMP%] {\n color: #2196f3;\n }\n\n .monitoring-controls[_ngcontent-%COMP%] {\n display: flex;\n gap: 16px;\n align-items: center;\n flex-wrap: wrap;\n }\n\n .refresh-control[_ngcontent-%COMP%], .time-range-control[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n gap: 8px;\n font-size: 12px;\n }\n\n .refresh-control[_ngcontent-%COMP%] label[_ngcontent-%COMP%], .time-range-control[_ngcontent-%COMP%] label[_ngcontent-%COMP%] {\n color: #666;\n font-weight: 500;\n }\n\n .refresh-control[_ngcontent-%COMP%] select[_ngcontent-%COMP%], .time-range-control[_ngcontent-%COMP%] select[_ngcontent-%COMP%] {\n padding: 6px 12px;\n border: 1px solid #ddd;\n border-radius: 4px;\n font-size: 12px;\n background: white;\n }\n\n .refresh-btn[_ngcontent-%COMP%] {\n background: #2196f3;\n color: white;\n border: none;\n padding: 8px 16px;\n border-radius: 4px;\n font-size: 12px;\n font-weight: 500;\n cursor: pointer;\n display: flex;\n align-items: center;\n gap: 6px;\n transition: background 0.2s ease;\n }\n\n .refresh-btn[_ngcontent-%COMP%]:hover:not(:disabled) {\n background: #1976d2;\n }\n\n .refresh-btn[_ngcontent-%COMP%]:disabled {\n opacity: 0.6;\n cursor: not-allowed;\n }\n\n .refresh-btn[_ngcontent-%COMP%] i.spinning[_ngcontent-%COMP%] {\n animation: _ngcontent-%COMP%_spin 1s linear infinite;\n }\n\n @keyframes _ngcontent-%COMP%_spin {\n 0% { transform: rotate(0deg); }\n 100% { transform: rotate(360deg); }\n }\n\n .kpi-dashboard[_ngcontent-%COMP%] {\n margin-bottom: 20px;\n }\n\n .kpi-grid[_ngcontent-%COMP%] {\n display: grid;\n grid-template-columns: repeat(auto-fit, minmax(240px, 1fr));\n gap: 16px;\n }\n\n .dashboard-splitter[_ngcontent-%COMP%] {\n height: calc(100vh - 550px); \n\n min-height: 600px;\n margin-bottom: 20px;\n }\n\n .dashboard-section[_ngcontent-%COMP%] {\n background: white;\n border-radius: 8px;\n box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);\n overflow: hidden;\n height: 100%;\n display: flex;\n flex-direction: column;\n }\n\n \n\n [_nghost-%COMP%] .k-splitter-pane {\n overflow: hidden;\n }\n\n [_nghost-%COMP%] .k-splitter .k-splitter-pane {\n padding: 10px;\n }\n\n [_nghost-%COMP%] .k-splitter-horizontal > .k-splitter-pane {\n padding: 10px 5px;\n }\n\n [_nghost-%COMP%] .k-splitter-vertical > .k-splitter-pane {\n padding: 5px 10px;\n }\n\n \n\n .cost-chart-container[_ngcontent-%COMP%], .efficiency-chart-container[_ngcontent-%COMP%], .status-container[_ngcontent-%COMP%] {\n padding: 20px;\n height: 100%;\n display: flex;\n flex-direction: column;\n }\n\n .chart-header[_ngcontent-%COMP%] {\n margin-bottom: 16px;\n }\n\n .chart-title[_ngcontent-%COMP%] {\n margin: 0;\n font-size: 16px;\n font-weight: 600;\n color: #333;\n display: flex;\n align-items: center;\n gap: 8px;\n }\n\n .chart-title[_ngcontent-%COMP%] i[_ngcontent-%COMP%] {\n color: #2196f3;\n }\n\n .cost-bars[_ngcontent-%COMP%], .efficiency-items[_ngcontent-%COMP%] {\n flex: 1;\n display: flex;\n flex-direction: column;\n gap: 12px;\n }\n\n .cost-bar-item[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n gap: 12px;\n padding: 8px 0;\n border-bottom: 1px solid #f0f0f0;\n }\n\n .cost-bar-item[_ngcontent-%COMP%]:last-child {\n border-bottom: none;\n }\n\n .cost-bar-info[_ngcontent-%COMP%] {\n min-width: 120px;\n display: flex;\n flex-direction: column;\n gap: 2px;\n }\n\n .model-name[_ngcontent-%COMP%] {\n font-size: 12px;\n font-weight: 500;\n color: #333;\n }\n\n .cost-value[_ngcontent-%COMP%] {\n font-size: 11px;\n color: #ff9800;\n font-weight: 600;\n }\n\n .cost-bar-container[_ngcontent-%COMP%] {\n flex: 1;\n height: 8px;\n background: #f0f0f0;\n border-radius: 4px;\n overflow: hidden;\n }\n\n .cost-bar[_ngcontent-%COMP%] {\n height: 100%;\n background: linear-gradient(90deg, #ff9800, #f57c00);\n border-radius: 4px;\n transition: width 0.3s ease;\n }\n\n .token-info[_ngcontent-%COMP%] {\n font-size: 10px;\n color: #666;\n min-width: 80px;\n text-align: right;\n }\n\n \n\n .efficiency-item[_ngcontent-%COMP%] {\n padding: 12px 0;\n border-bottom: 1px solid #f0f0f0;\n }\n\n .efficiency-item[_ngcontent-%COMP%]:last-child {\n border-bottom: none;\n }\n\n .efficiency-header[_ngcontent-%COMP%] {\n display: flex;\n justify-content: space-between;\n align-items: center;\n margin-bottom: 8px;\n }\n\n .efficiency-ratio[_ngcontent-%COMP%] {\n font-size: 11px;\n color: #2196f3;\n font-weight: 600;\n }\n\n .token-breakdown[_ngcontent-%COMP%] {\n display: flex;\n flex-direction: column;\n gap: 6px;\n }\n\n .token-bar[_ngcontent-%COMP%] {\n height: 6px;\n background: #f0f0f0;\n border-radius: 3px;\n overflow: hidden;\n display: flex;\n }\n\n .token-segment[_ngcontent-%COMP%] {\n height: 100%;\n }\n\n .token-segment--input[_ngcontent-%COMP%] {\n background: #4caf50;\n }\n\n .token-segment--output[_ngcontent-%COMP%] {\n background: #2196f3;\n }\n\n .token-labels[_ngcontent-%COMP%] {\n display: flex;\n justify-content: space-between;\n font-size: 10px;\n color: #666;\n }\n\n .input-label[_ngcontent-%COMP%] {\n color: #4caf50;\n }\n\n .output-label[_ngcontent-%COMP%] {\n color: #2196f3;\n }\n\n .cost-per-token[_ngcontent-%COMP%] {\n font-size: 10px;\n color: #999;\n margin-top: 4px;\n }\n\n \n\n .status-metrics[_ngcontent-%COMP%] {\n display: flex;\n flex-direction: column;\n gap: 16px;\n flex: 1;\n }\n\n .status-metric[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n gap: 12px;\n padding: 12px;\n background: #f8f9fa;\n border-radius: 6px;\n }\n\n .status-icon[_ngcontent-%COMP%] {\n width: 40px;\n height: 40px;\n border-radius: 50%;\n display: flex;\n align-items: center;\n justify-content: center;\n flex-shrink: 0;\n }\n\n .status-icon--success[_ngcontent-%COMP%] {\n background: rgba(76, 175, 80, 0.1);\n color: #4caf50;\n }\n\n .status-icon--warning[_ngcontent-%COMP%] {\n background: rgba(255, 152, 0, 0.1);\n color: #ff9800;\n }\n\n .status-icon--info[_ngcontent-%COMP%] {\n background: rgba(33, 150, 243, 0.1);\n color: #2196f3;\n }\n\n .status-icon--primary[_ngcontent-%COMP%] {\n background: rgba(156, 39, 176, 0.1);\n color: #9c27b0;\n }\n\n .status-info[_ngcontent-%COMP%] {\n flex: 1;\n }\n\n .status-label[_ngcontent-%COMP%] {\n font-size: 12px;\n color: #666;\n font-weight: 500;\n }\n\n .status-value[_ngcontent-%COMP%] {\n font-size: 18px;\n font-weight: 700;\n color: #333;\n margin: 2px 0;\n }\n\n .status-subtitle[_ngcontent-%COMP%] {\n font-size: 10px;\n color: #999;\n }\n\n \n\n .execution-modal[_ngcontent-%COMP%] {\n position: fixed;\n top: 0;\n left: 0;\n width: 100%;\n height: 100%;\n background: rgba(0, 0, 0, 0.5);\n display: flex;\n align-items: center;\n justify-content: center;\n z-index: 1000;\n padding: 20px;\n }\n\n .execution-modal-content[_ngcontent-%COMP%] {\n background: white;\n border-radius: 8px;\n max-width: 800px;\n width: 100%;\n max-height: 80vh;\n overflow: hidden;\n display: flex;\n flex-direction: column;\n }\n\n .execution-modal-header[_ngcontent-%COMP%] {\n padding: 20px;\n border-bottom: 1px solid #f0f0f0;\n display: flex;\n justify-content: space-between;\n align-items: center;\n }\n\n .execution-modal-header[_ngcontent-%COMP%] h3[_ngcontent-%COMP%] {\n margin: 0;\n font-size: 18px;\n font-weight: 600;\n color: #333;\n }\n\n .modal-header-actions[_ngcontent-%COMP%] {\n display: flex;\n gap: 12px;\n align-items: center;\n }\n\n .open-record-btn[_ngcontent-%COMP%] {\n background: #2196f3;\n color: white;\n border: none;\n padding: 8px 16px;\n border-radius: 4px;\n font-size: 13px;\n font-weight: 500;\n cursor: pointer;\n display: flex;\n align-items: center;\n gap: 6px;\n transition: all 0.2s ease;\n }\n\n .open-record-btn[_ngcontent-%COMP%]:hover {\n background: #1976d2;\n transform: translateY(-1px);\n box-shadow: 0 2px 8px rgba(33, 150, 243, 0.3);\n }\n\n .open-record-btn[_ngcontent-%COMP%] i[_ngcontent-%COMP%] {\n font-size: 12px;\n }\n\n .close-btn[_ngcontent-%COMP%] {\n background: none;\n border: none;\n font-size: 16px;\n color: #999;\n cursor: pointer;\n padding: 4px;\n }\n\n .close-btn[_ngcontent-%COMP%]:hover {\n color: #333;\n }\n\n .execution-modal-body[_ngcontent-%COMP%] {\n padding: 20px;\n overflow-y: auto;\n flex: 1;\n }\n\n .execution-details[_ngcontent-%COMP%] {\n display: flex;\n flex-direction: column;\n gap: 20px;\n }\n\n .detail-section[_ngcontent-%COMP%] h4[_ngcontent-%COMP%] {\n margin: 0 0 12px 0;\n font-size: 14px;\n font-weight: 600;\n color: #333;\n border-bottom: 1px solid #f0f0f0;\n padding-bottom: 6px;\n }\n\n .detail-grid[_ngcontent-%COMP%] {\n display: grid;\n grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));\n gap: 12px;\n }\n\n .detail-item[_ngcontent-%COMP%] {\n display: flex;\n flex-direction: column;\n gap: 4px;\n }\n\n .detail-item[_ngcontent-%COMP%] label[_ngcontent-%COMP%] {\n font-size: 11px;\n color: #666;\n font-weight: 500;\n text-transform: uppercase;\n letter-spacing: 0.5px;\n }\n\n .detail-item[_ngcontent-%COMP%] span[_ngcontent-%COMP%] {\n font-size: 13px;\n color: #333;\n }\n\n .status-badge[_ngcontent-%COMP%] {\n display: inline-block;\n padding: 2px 8px;\n border-radius: 12px;\n font-size: 10px;\n font-weight: 500;\n text-transform: uppercase;\n }\n\n .status-badge--completed[_ngcontent-%COMP%] {\n background: rgba(76, 175, 80, 0.1);\n color: #4caf50;\n }\n\n .status-badge--running[_ngcontent-%COMP%] {\n background: rgba(33, 150, 243, 0.1);\n color: #2196f3;\n }\n\n .status-badge--failed[_ngcontent-%COMP%] {\n background: rgba(244, 67, 54, 0.1);\n color: #f44336;\n }\n\n .error-message[_ngcontent-%COMP%] {\n background: #fff3e0;\n border: 1px solid #ffcc02;\n border-radius: 4px;\n padding: 12px;\n font-size: 12px;\n color: #e65100;\n font-family: monospace;\n }\n\n .child-executions[_ngcontent-%COMP%] {\n display: flex;\n flex-direction: column;\n gap: 8px;\n }\n\n .child-execution[_ngcontent-%COMP%] {\n background: #f8f9fa;\n border-radius: 4px;\n padding: 12px;\n display: flex;\n justify-content: space-between;\n align-items: center;\n }\n\n .child-info[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n gap: 8px;\n }\n\n .child-name[_ngcontent-%COMP%] {\n font-size: 12px;\n font-weight: 500;\n color: #333;\n }\n\n .child-type[_ngcontent-%COMP%] {\n font-size: 10px;\n background: #e0e0e0;\n padding: 2px 6px;\n border-radius: 3px;\n color: #666;\n }\n\n .child-status[_ngcontent-%COMP%] {\n font-size: 10px;\n padding: 2px 6px;\n border-radius: 3px;\n }\n\n .child-metrics[_ngcontent-%COMP%] {\n display: flex;\n gap: 12px;\n font-size: 11px;\n color: #666;\n }\n\n .loading-details[_ngcontent-%COMP%] {\n display: flex;\n flex-direction: column;\n align-items: center;\n justify-content: center;\n padding: 40px;\n gap: 12px;\n }\n\n .spinner[_ngcontent-%COMP%] {\n width: 32px;\n height: 32px;\n border: 3px solid #f3f3f3;\n border-top: 3px solid #2196f3;\n border-radius: 50%;\n animation: _ngcontent-%COMP%_spin 1s linear infinite;\n }\n\n \n\n .drill-down-container[_ngcontent-%COMP%] {\n height: 100%;\n display: flex;\n flex-direction: column;\n }\n\n .drill-down-tabs[_ngcontent-%COMP%] {\n height: 100%;\n display: flex;\n flex-direction: column;\n }\n\n .tab-header[_ngcontent-%COMP%] {\n display: flex;\n border-bottom: 1px solid #e0e0e0;\n background: #f8f9fa;\n min-height: 40px;\n overflow-x: auto;\n }\n\n .tab-item[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n gap: 8px;\n padding: 8px 16px;\n background: #f8f9fa;\n border: none;\n border-bottom: 2px solid transparent;\n cursor: pointer;\n font-size: 12px;\n font-weight: 500;\n color: #666;\n white-space: nowrap;\n transition: all 0.2s ease;\n min-width: 120px;\n justify-content: space-between;\n }\n\n .tab-item[_ngcontent-%COMP%]:hover {\n background: #e9ecef;\n color: #333;\n }\n\n .tab-item.active[_ngcontent-%COMP%] {\n background: white;\n color: #2196f3;\n border-bottom-color: #2196f3;\n }\n\n .tab-title[_ngcontent-%COMP%] {\n flex: 1;\n overflow: hidden;\n text-overflow: ellipsis;\n }\n\n .tab-close[_ngcontent-%COMP%] {\n background: none;\n border: none;\n color: #999;\n cursor: pointer;\n padding: 2px;\n border-radius: 2px;\n font-size: 10px;\n width: 16px;\n height: 16px;\n display: flex;\n align-items: center;\n justify-content: center;\n transition: all 0.2s ease;\n }\n\n .tab-close[_ngcontent-%COMP%]:hover {\n background: rgba(0, 0, 0, 0.1);\n color: #333;\n }\n\n .tab-content[_ngcontent-%COMP%] {\n flex: 1;\n overflow: hidden;\n display: flex;\n flex-direction: column;\n }\n\n .tab-pane[_ngcontent-%COMP%] {\n height: 100%;\n overflow: hidden;\n display: flex;\n flex-direction: column;\n }\n\n .trends-chart[_ngcontent-%COMP%] {\n padding: 0;\n }\n\n .trends-chart[_ngcontent-%COMP%] app-time-series-chart[_ngcontent-%COMP%] {\n height: 100%;\n display: block;\n overflow: hidden;\n }\n\n \n\n .tab-pane.trends-chart[_ngcontent-%COMP%] {\n display: flex;\n flex-direction: column;\n overflow: hidden;\n }\n\n \n\n .executions-drill-down[_ngcontent-%COMP%] {\n padding: 20px;\n overflow-y: auto;\n }\n\n .drill-down-header[_ngcontent-%COMP%] {\n display: flex;\n justify-content: space-between;\n align-items: center;\n margin-bottom: 20px;\n padding-bottom: 12px;\n border-bottom: 1px solid #e0e0e0;\n }\n\n .drill-down-header[_ngcontent-%COMP%] h4[_ngcontent-%COMP%] {\n margin: 0;\n font-size: 16px;\n font-weight: 600;\n color: #333;\n display: flex;\n align-items: center;\n gap: 8px;\n }\n\n .drill-down-meta[_ngcontent-%COMP%] {\n display: flex;\n gap: 12px;\n align-items: center;\n font-size: 12px;\n }\n\n .timestamp[_ngcontent-%COMP%] {\n color: #666;\n background: #f0f0f0;\n padding: 4px 8px;\n border-radius: 4px;\n }\n\n .metric-badge[_ngcontent-%COMP%] {\n background: #2196f3;\n color: white;\n padding: 4px 8px;\n border-radius: 4px;\n font-weight: 500;\n }\n\n .loading-spinner[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n justify-content: center;\n padding: 40px;\n color: #666;\n gap: 12px;\n }\n\n .executions-table[_ngcontent-%COMP%] {\n display: flex;\n flex-direction: column;\n gap: 0;\n border: 1px solid #e0e0e0;\n border-radius: 6px;\n overflow: hidden;\n }\n\n .table-header[_ngcontent-%COMP%] {\n display: grid;\n grid-template-columns: 80px 1fr 120px 100px 100px 80px 100px 120px;\n gap: 12px;\n background: #f8f9fa;\n padding: 12px 16px;\n font-size: 11px;\n font-weight: 600;\n color: #666;\n text-transform: uppercase;\n letter-spacing: 0.5px;\n }\n\n .table-row[_ngcontent-%COMP%] {\n display: grid;\n grid-template-columns: 80px 1fr 120px 100px 100px 80px 100px 120px;\n gap: 12px;\n padding: 12px 16px;\n border-top: 1px solid #f0f0f0;\n cursor: pointer;\n transition: background 0.2s ease;\n align-items: center;\n }\n\n .table-row[_ngcontent-%COMP%]:hover {\n background: #f8f9fa;\n }\n\n .table-cell[_ngcontent-%COMP%] {\n font-size: 12px;\n color: #333;\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n }\n\n .type-badge[_ngcontent-%COMP%] {\n background: #e9ecef;\n color: #666;\n padding: 2px 6px;\n border-radius: 3px;\n font-size: 10px;\n font-weight: 500;\n text-transform: uppercase;\n }\n\n .type-badge--prompt[_ngcontent-%COMP%] {\n background: rgba(33, 150, 243, 0.1);\n color: #2196f3;\n }\n\n .type-badge--agent[_ngcontent-%COMP%] {\n background: rgba(76, 175, 80, 0.1);\n color: #4caf50;\n }\n\n .no-data[_ngcontent-%COMP%] {\n display: flex;\n flex-direction: column;\n align-items: center;\n justify-content: center;\n padding: 60px 20px;\n color: #999;\n gap: 16px;\n }\n\n .no-data[_ngcontent-%COMP%] i[_ngcontent-%COMP%] {\n font-size: 48px;\n color: #ddd;\n }\n\n .no-data[_ngcontent-%COMP%] p[_ngcontent-%COMP%] {\n margin: 0;\n font-size: 14px;\n }\n\n \n\n .model-detail[_ngcontent-%COMP%] {\n padding: 20px;\n overflow-y: auto;\n }\n\n .model-details[_ngcontent-%COMP%] {\n display: flex;\n flex-direction: column;\n gap: 24px;\n }\n\n .model-info-grid[_ngcontent-%COMP%] {\n display: grid;\n grid-template-columns: repeat(auto-fit, minmax(250px, 1fr));\n gap: 16px;\n }\n\n .info-item[_ngcontent-%COMP%] {\n display: flex;\n flex-direction: column;\n gap: 6px;\n padding: 16px;\n background: #f8f9fa;\n border-radius: 6px;\n }\n\n .info-item[_ngcontent-%COMP%] label[_ngcontent-%COMP%] {\n font-size: 11px;\n color: #666;\n font-weight: 600;\n text-transform: uppercase;\n letter-spacing: 0.5px;\n margin: 0;\n }\n\n .info-item[_ngcontent-%COMP%] span[_ngcontent-%COMP%] {\n font-size: 14px;\n color: #333;\n font-weight: 500;\n }\n\n .status-indicator[_ngcontent-%COMP%] {\n display: inline-flex;\n align-items: center;\n gap: 4px;\n font-size: 12px;\n }\n\n .status-indicator.active[_ngcontent-%COMP%] {\n color: #4caf50;\n }\n\n .status-indicator.active[_ngcontent-%COMP%]::before {\n content: '';\n width: 6px;\n height: 6px;\n background: #4caf50;\n border-radius: 50%;\n }\n\n .model-description[_ngcontent-%COMP%] {\n padding: 20px;\n background: #f8f9fa;\n border-radius: 8px;\n }\n\n .model-description[_ngcontent-%COMP%] h5[_ngcontent-%COMP%] {\n margin: 0 0 12px 0;\n font-size: 14px;\n font-weight: 600;\n color: #333;\n }\n\n .model-description[_ngcontent-%COMP%] p[_ngcontent-%COMP%] {\n margin: 0;\n font-size: 13px;\n color: #666;\n line-height: 1.5;\n }\n\n \n\n .clickable[_ngcontent-%COMP%] {\n cursor: pointer;\n transition: transform 0.2s ease, box-shadow 0.2s ease;\n }\n\n .clickable[_ngcontent-%COMP%]:hover {\n transform: translateY(-2px);\n box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15);\n }\n\n \n\n .analysis-panels[_ngcontent-%COMP%] {\n padding: 10px;\n height: 100%;\n overflow-y: auto;\n background: #f8f9fa;\n }\n\n .analysis-panel[_ngcontent-%COMP%] {\n margin-bottom: 12px;\n border-radius: 8px;\n box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);\n background: white;\n overflow: hidden;\n }\n\n .analysis-panel[_ngcontent-%COMP%]:last-child {\n margin-bottom: 0;\n }\n\n .panel-header[_ngcontent-%COMP%] {\n padding: 12px 16px;\n background: #f8f9fa;\n border-bottom: 1px solid #e0e0e0;\n cursor: pointer;\n display: flex;\n justify-content: space-between;\n align-items: center;\n transition: background 0.2s ease;\n }\n\n .panel-header[_ngcontent-%COMP%]:hover {\n background: #e9ecef;\n }\n\n .panel-title[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n gap: 8px;\n font-weight: 600;\n color: #333;\n font-size: 14px;\n }\n\n .panel-title[_ngcontent-%COMP%] i[_ngcontent-%COMP%] {\n color: #2196f3;\n width: 16px;\n }\n\n .panel-toggle-icon[_ngcontent-%COMP%] {\n color: #666;\n font-size: 12px;\n transition: transform 0.2s ease;\n }\n\n .panel-content[_ngcontent-%COMP%] {\n padding: 16px;\n border-top: 1px solid #f0f0f0;\n animation: _ngcontent-%COMP%_slideDown 0.2s ease-out;\n }\n\n @keyframes _ngcontent-%COMP%_slideDown {\n from {\n opacity: 0;\n max-height: 0;\n }\n to {\n opacity: 1;\n max-height: 500px;\n }\n }\n\n .live-executions-panel[_ngcontent-%COMP%] {\n padding: 0;\n }\n\n .live-executions-panel[_ngcontent-%COMP%] app-live-execution-widget[_ngcontent-%COMP%] {\n height: 300px;\n display: block;\n }\n\n \n\n @media (max-width: 1200px) {\n .dashboard-splitter[_ngcontent-%COMP%] {\n height: calc(100vh - 270px); \n\n margin-bottom: 20px;\n }\n \n .table-header[_ngcontent-%COMP%], \n .table-row[_ngcontent-%COMP%] {\n grid-template-columns: 60px 1fr 100px 80px 80px 60px 80px 100px;\n gap: 8px;\n }\n \n .model-info-grid[_ngcontent-%COMP%] {\n grid-template-columns: 1fr;\n }\n \n .analysis-panels[_ngcontent-%COMP%] {\n padding: 8px;\n }\n \n .analysis-panel[_ngcontent-%COMP%] {\n margin-bottom: 8px;\n }\n }\n\n @media (max-width: 768px) {\n .execution-monitoring[_ngcontent-%COMP%] {\n padding: 12px;\n }\n \n .monitoring-header[_ngcontent-%COMP%] {\n flex-direction: column;\n align-items: flex-start;\n }\n \n .monitoring-controls[_ngcontent-%COMP%] {\n width: 100%;\n justify-content: flex-start;\n }\n \n .dashboard-splitter[_ngcontent-%COMP%] {\n height: calc(100vh - 270px); \n\n min-height: 400px;\n margin-bottom: 20px;\n }\n \n .kpi-grid[_ngcontent-%COMP%] {\n grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));\n }\n\n \n\n [_nghost-%COMP%] .k-splitter .k-splitter-pane {\n padding: 5px;\n }\n\n [_nghost-%COMP%] .k-splitter-horizontal > .k-splitter-pane {\n padding: 5px 2px;\n }\n\n [_nghost-%COMP%] .k-splitter-vertical > .k-splitter-pane {\n padding: 2px 5px;\n }\n \n .tab-header[_ngcontent-%COMP%] {\n overflow-x: auto;\n }\n \n .tab-item[_ngcontent-%COMP%] {\n min-width: 100px;\n padding: 6px 12px;\n }\n \n .table-header[_ngcontent-%COMP%], \n .table-row[_ngcontent-%COMP%] {\n grid-template-columns: 1fr;\n gap: 4px;\n text-align: left;\n }\n \n .table-row[_ngcontent-%COMP%] {\n display: block;\n padding: 16px;\n }\n \n .table-cell[_ngcontent-%COMP%] {\n display: block;\n margin-bottom: 8px;\n }\n \n .table-cell[_ngcontent-%COMP%]:before {\n content: attr(data-label) ': ';\n font-weight: 600;\n color: #666;\n font-size: 11px;\n text-transform: uppercase;\n }\n \n .executions-drill-down[_ngcontent-%COMP%], \n .model-detail[_ngcontent-%COMP%] {\n padding: 12px;\n }\n \n .panel-content[_ngcontent-%COMP%] {\n padding: 12px;\n }\n \n .panel-header[_ngcontent-%COMP%] {\n padding: 10px 12px;\n }\n \n .panel-title[_ngcontent-%COMP%] {\n font-size: 13px;\n }\n }"] });
|
|
10
1503
|
}
|
|
11
|
-
ExecutionMonitoringComponent.ɵfac = function ExecutionMonitoringComponent_Factory(t) { return new (t || ExecutionMonitoringComponent)(); };
|
|
12
|
-
ExecutionMonitoringComponent.ɵcmp = /*@__PURE__*/ i0.ɵɵdefineComponent({ type: ExecutionMonitoringComponent, selectors: [["app-execution-monitoring"]], outputs: { openEntityRecord: "openEntityRecord" }, decls: 9, vars: 0, consts: [[1, "execution-monitoring"], [1, "header"], [1, "content"]], template: function ExecutionMonitoringComponent_Template(rf, ctx) { if (rf & 1) {
|
|
13
|
-
i0.ɵɵelementStart(0, "div", 0)(1, "div", 1)(2, "h3");
|
|
14
|
-
i0.ɵɵtext(3, "Execution Monitoring");
|
|
15
|
-
i0.ɵɵelementEnd();
|
|
16
|
-
i0.ɵɵelementStart(4, "p");
|
|
17
|
-
i0.ɵɵtext(5, "Monitor AI agent execution and performance");
|
|
18
|
-
i0.ɵɵelementEnd()();
|
|
19
|
-
i0.ɵɵelementStart(6, "div", 2)(7, "p");
|
|
20
|
-
i0.ɵɵtext(8, "Execution monitoring interface will be implemented here.");
|
|
21
|
-
i0.ɵɵelementEnd()()();
|
|
22
|
-
} }, styles: [".execution-monitoring[_ngcontent-%COMP%] {\n padding: 20px;\n height: 100%;\n display: flex;\n flex-direction: column;\n\n .header {\n margin-bottom: 20px;\n \n h3 {\n margin: 0 0 8px 0;\n color: #2c3e50;\n font-size: 1.4rem;\n font-weight: 600;\n }\n \n p {\n margin: 0;\n color: #7f8c8d;\n font-size: 0.9rem;\n }\n }\n\n .content {\n flex: 1;\n background: #f8f9fa;\n border-radius: 8px;\n padding: 20px;\n border: 1px solid #e9ecef;\n }\n}"] });
|
|
23
1504
|
(() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassMetadata(ExecutionMonitoringComponent, [{
|
|
24
1505
|
type: Component,
|
|
25
|
-
args: [{ selector: 'app-execution-monitoring', template:
|
|
26
|
-
|
|
1506
|
+
args: [{ selector: 'app-execution-monitoring', template: `
|
|
1507
|
+
<div class="execution-monitoring">
|
|
1508
|
+
<!-- Header Controls -->
|
|
1509
|
+
<div class="monitoring-header">
|
|
1510
|
+
<h2 class="monitoring-title">
|
|
1511
|
+
<i class="fa-solid fa-chart-line"></i>
|
|
1512
|
+
AI Execution Monitoring
|
|
1513
|
+
</h2>
|
|
1514
|
+
|
|
1515
|
+
<div class="monitoring-controls">
|
|
1516
|
+
<div class="refresh-control">
|
|
1517
|
+
<label>Refresh:</label>
|
|
1518
|
+
<select [(ngModel)]="refreshInterval" (change)="onRefreshIntervalChange()">
|
|
1519
|
+
<option [value]="0">Manual</option>
|
|
1520
|
+
<option [value]="10000">10s</option>
|
|
1521
|
+
<option [value]="30000">30s</option>
|
|
1522
|
+
<option [value]="60000">1m</option>
|
|
1523
|
+
<option [value]="300000">5m</option>
|
|
1524
|
+
</select>
|
|
1525
|
+
</div>
|
|
1526
|
+
|
|
1527
|
+
<div class="time-range-control">
|
|
1528
|
+
<label>Time Range:</label>
|
|
1529
|
+
<select [(ngModel)]="selectedTimeRange" (change)="onTimeRangeChange()">
|
|
1530
|
+
<option value="1h">Last Hour</option>
|
|
1531
|
+
<option value="6h">Last 6 Hours</option>
|
|
1532
|
+
<option value="24h">Last 24 Hours</option>
|
|
1533
|
+
<option value="7d">Last 7 Days</option>
|
|
1534
|
+
<option value="30d">Last 30 Days</option>
|
|
1535
|
+
</select>
|
|
1536
|
+
</div>
|
|
1537
|
+
|
|
1538
|
+
<button class="refresh-btn" (click)="refreshData()" [disabled]="isLoading">
|
|
1539
|
+
<i class="fa-solid fa-refresh" [class.spinning]="isLoading"></i>
|
|
1540
|
+
Refresh
|
|
1541
|
+
</button>
|
|
1542
|
+
</div>
|
|
1543
|
+
</div>
|
|
1544
|
+
|
|
1545
|
+
<!-- KPI Dashboard -->
|
|
1546
|
+
<div class="kpi-dashboard">
|
|
1547
|
+
<div class="kpi-grid">
|
|
1548
|
+
@for (kpi of kpiCards$ | async; track kpi.title) {
|
|
1549
|
+
<app-kpi-card
|
|
1550
|
+
[data]="kpi"
|
|
1551
|
+
(click)="onKpiClick(kpi)"
|
|
1552
|
+
[class.clickable]="isKpiClickable(kpi)"
|
|
1553
|
+
></app-kpi-card>
|
|
1554
|
+
}
|
|
1555
|
+
</div>
|
|
1556
|
+
</div>
|
|
1557
|
+
|
|
1558
|
+
<!-- Main Dashboard with Kendo Splitter -->
|
|
1559
|
+
<kendo-splitter class="dashboard-splitter" orientation="vertical" (layoutChange)="onSplitterLayoutChange($event)">
|
|
1560
|
+
<!-- Top Row: System Health and Trends Chart -->
|
|
1561
|
+
<kendo-splitter-pane size="45%" [resizable]="true" [collapsible]="false">
|
|
1562
|
+
<kendo-splitter orientation="horizontal" (layoutChange)="onSplitterLayoutChange($event)">
|
|
1563
|
+
<!-- System Health -->
|
|
1564
|
+
<kendo-splitter-pane size="30%" [resizable]="true" [collapsible]="true" [collapsed]="false">
|
|
1565
|
+
<div class="dashboard-section system-status">
|
|
1566
|
+
<div class="status-container">
|
|
1567
|
+
<div class="chart-header">
|
|
1568
|
+
<h4 class="chart-title">
|
|
1569
|
+
<i class="fa-solid fa-heartbeat"></i>
|
|
1570
|
+
System Health
|
|
1571
|
+
</h4>
|
|
1572
|
+
</div>
|
|
1573
|
+
@if (kpis$ | async; as kpis) {
|
|
1574
|
+
<div class="status-metrics">
|
|
1575
|
+
<div class="status-metric">
|
|
1576
|
+
<div class="status-icon status-icon--success">
|
|
1577
|
+
<i class="fa-solid fa-check"></i>
|
|
1578
|
+
</div>
|
|
1579
|
+
<div class="status-info">
|
|
1580
|
+
<div class="status-label">Success Rate</div>
|
|
1581
|
+
<div class="status-value">{{ (kpis.successRate * 100).toFixed(1) }}%</div>
|
|
1582
|
+
<div class="status-subtitle">Last {{ selectedTimeRange }}</div>
|
|
1583
|
+
</div>
|
|
1584
|
+
</div>
|
|
1585
|
+
|
|
1586
|
+
<div class="status-metric">
|
|
1587
|
+
<div class="status-icon status-icon--warning">
|
|
1588
|
+
<i class="fa-solid fa-exclamation-triangle"></i>
|
|
1589
|
+
</div>
|
|
1590
|
+
<div class="status-info">
|
|
1591
|
+
<div class="status-label">Error Rate</div>
|
|
1592
|
+
<div class="status-value">{{ (kpis.errorRate * 100).toFixed(1) }}%</div>
|
|
1593
|
+
<div class="status-subtitle">{{ kpis.totalExecutions }} total executions</div>
|
|
1594
|
+
</div>
|
|
1595
|
+
</div>
|
|
1596
|
+
|
|
1597
|
+
<div class="status-metric">
|
|
1598
|
+
<div class="status-icon status-icon--info">
|
|
1599
|
+
<i class="fa-solid fa-clock"></i>
|
|
1600
|
+
</div>
|
|
1601
|
+
<div class="status-info">
|
|
1602
|
+
<div class="status-label">Avg Response Time</div>
|
|
1603
|
+
<div class="status-value">{{ (kpis.avgExecutionTime / 1000).toFixed(2) }}s</div>
|
|
1604
|
+
<div class="status-subtitle">Across all models</div>
|
|
1605
|
+
</div>
|
|
1606
|
+
</div>
|
|
1607
|
+
|
|
1608
|
+
<div class="status-metric">
|
|
1609
|
+
<div class="status-icon status-icon--primary">
|
|
1610
|
+
<i class="fa-solid fa-bolt"></i>
|
|
1611
|
+
</div>
|
|
1612
|
+
<div class="status-info">
|
|
1613
|
+
<div class="status-label">Active Executions</div>
|
|
1614
|
+
<div class="status-value">{{ kpis.activeExecutions }}</div>
|
|
1615
|
+
<div class="status-subtitle">Currently running</div>
|
|
1616
|
+
</div>
|
|
1617
|
+
</div>
|
|
1618
|
+
</div>
|
|
1619
|
+
}
|
|
1620
|
+
</div>
|
|
1621
|
+
</div>
|
|
1622
|
+
</kendo-splitter-pane>
|
|
1623
|
+
|
|
1624
|
+
<!-- Drill-down Tab Container -->
|
|
1625
|
+
<kendo-splitter-pane [resizable]="true" [collapsible]="false">
|
|
1626
|
+
<div class="dashboard-section drill-down-container">
|
|
1627
|
+
<div class="drill-down-tabs">
|
|
1628
|
+
<div class="tab-header">
|
|
1629
|
+
@for (tab of drillDownTabs; track tab.id) {
|
|
1630
|
+
<div
|
|
1631
|
+
class="tab-item"
|
|
1632
|
+
[class.active]="activeTabId === tab.id"
|
|
1633
|
+
(click)="selectTab(tab.id)"
|
|
1634
|
+
>
|
|
1635
|
+
<span class="tab-title">{{ tab.title }}</span>
|
|
1636
|
+
@if (tab.closeable) {
|
|
1637
|
+
<button
|
|
1638
|
+
class="tab-close"
|
|
1639
|
+
(click)="closeTab($event, tab.id)"
|
|
1640
|
+
title="Close tab"
|
|
1641
|
+
>
|
|
1642
|
+
<i class="fa-solid fa-times"></i>
|
|
1643
|
+
</button>
|
|
1644
|
+
}
|
|
1645
|
+
</div>
|
|
1646
|
+
}
|
|
1647
|
+
</div>
|
|
1648
|
+
|
|
1649
|
+
<div class="tab-content">
|
|
1650
|
+
@if (activeTab?.type === 'chart') {
|
|
1651
|
+
<div class="tab-pane trends-chart">
|
|
1652
|
+
<app-time-series-chart
|
|
1653
|
+
[data]="(trends$ | async) ?? []"
|
|
1654
|
+
title="Execution Trends"
|
|
1655
|
+
[config]="timeSeriesConfig"
|
|
1656
|
+
(dataPointClick)="onDataPointClick($event)"
|
|
1657
|
+
(timeRangeChange)="onChartTimeRangeChange($event)"
|
|
1658
|
+
></app-time-series-chart>
|
|
1659
|
+
</div>
|
|
1660
|
+
}
|
|
1661
|
+
|
|
1662
|
+
@if (activeTab?.type === 'executions') {
|
|
1663
|
+
<div class="tab-pane executions-drill-down">
|
|
1664
|
+
<div class="drill-down-header">
|
|
1665
|
+
<h4>
|
|
1666
|
+
<i class="fa-solid fa-list"></i>
|
|
1667
|
+
{{ activeTab?.title }}
|
|
1668
|
+
</h4>
|
|
1669
|
+
<div class="drill-down-meta">
|
|
1670
|
+
@if (activeTab?.timestamp) {
|
|
1671
|
+
<span class="timestamp">{{ getFormattedTimestamp(activeTab) }}</span>
|
|
1672
|
+
}
|
|
1673
|
+
@if (activeTab?.metric) {
|
|
1674
|
+
<span class="metric-badge">{{ getFormattedMetricLabel(activeTab) }}</span>
|
|
1675
|
+
}
|
|
1676
|
+
</div>
|
|
1677
|
+
</div>
|
|
1678
|
+
|
|
1679
|
+
@if (loadingDrillDown) {
|
|
1680
|
+
<div class="loading-spinner">
|
|
1681
|
+
<i class="fa-solid fa-spinner fa-spin"></i>
|
|
1682
|
+
Loading execution details...
|
|
1683
|
+
</div>
|
|
1684
|
+
} @else if (activeTab?.data?.length > 0) {
|
|
1685
|
+
<div class="executions-table">
|
|
1686
|
+
<div class="table-header">
|
|
1687
|
+
<div class="header-cell">Type</div>
|
|
1688
|
+
<div class="header-cell">Name</div>
|
|
1689
|
+
<div class="header-cell">Model</div>
|
|
1690
|
+
<div class="header-cell">Status</div>
|
|
1691
|
+
<div class="header-cell">Duration</div>
|
|
1692
|
+
<div class="header-cell">Cost</div>
|
|
1693
|
+
<div class="header-cell">Tokens</div>
|
|
1694
|
+
<div class="header-cell">Time</div>
|
|
1695
|
+
</div>
|
|
1696
|
+
@for (execution of activeTab?.data; track execution.id) {
|
|
1697
|
+
<div
|
|
1698
|
+
class="table-row"
|
|
1699
|
+
(click)="viewExecutionDetail(execution)"
|
|
1700
|
+
>
|
|
1701
|
+
<div class="table-cell">
|
|
1702
|
+
<span class="type-badge" [class]="'type-badge--' + execution.type">
|
|
1703
|
+
{{ execution.type }}
|
|
1704
|
+
</span>
|
|
1705
|
+
</div>
|
|
1706
|
+
<div class="table-cell">{{ execution.name }}</div>
|
|
1707
|
+
<div class="table-cell">{{ execution.model || 'N/A' }}</div>
|
|
1708
|
+
<div class="table-cell">
|
|
1709
|
+
<span class="status-badge" [class]="'status-badge--' + execution.status">
|
|
1710
|
+
{{ execution.status }}
|
|
1711
|
+
</span>
|
|
1712
|
+
</div>
|
|
1713
|
+
<div class="table-cell">{{ formatDuration(execution.duration) }}</div>
|
|
1714
|
+
<div class="table-cell">{{ formatCurrency(execution.cost) }}</div>
|
|
1715
|
+
<div class="table-cell">{{ execution.tokens.toLocaleString() }}</div>
|
|
1716
|
+
<div class="table-cell">{{ formatTime(execution.startTime) }}</div>
|
|
1717
|
+
</div>
|
|
1718
|
+
}
|
|
1719
|
+
</div>
|
|
1720
|
+
} @else {
|
|
1721
|
+
<div class="no-data">
|
|
1722
|
+
<i class="fa-solid fa-inbox"></i>
|
|
1723
|
+
<p>No executions found for this time period</p>
|
|
1724
|
+
</div>
|
|
1725
|
+
}
|
|
1726
|
+
</div>
|
|
1727
|
+
}
|
|
1728
|
+
|
|
1729
|
+
@if (activeTab?.type === 'model-detail') {
|
|
1730
|
+
<div class="tab-pane model-detail">
|
|
1731
|
+
<div class="drill-down-header">
|
|
1732
|
+
<h4>
|
|
1733
|
+
<i class="fa-solid fa-microchip"></i>
|
|
1734
|
+
Model Details: {{ activeTab?.data?.name }}
|
|
1735
|
+
</h4>
|
|
1736
|
+
</div>
|
|
1737
|
+
|
|
1738
|
+
@if (loadingDrillDown) {
|
|
1739
|
+
<div class="loading-spinner">
|
|
1740
|
+
<i class="fa-solid fa-spinner fa-spin"></i>
|
|
1741
|
+
Loading model details...
|
|
1742
|
+
</div>
|
|
1743
|
+
} @else if (activeTab?.data) {
|
|
1744
|
+
<div class="model-details">
|
|
1745
|
+
<div class="model-info-grid">
|
|
1746
|
+
<div class="info-item">
|
|
1747
|
+
<label>Model Name:</label>
|
|
1748
|
+
<span>{{ activeTab?.data?.name }}</span>
|
|
1749
|
+
</div>
|
|
1750
|
+
<div class="info-item">
|
|
1751
|
+
<label>Vendor:</label>
|
|
1752
|
+
<span>{{ activeTab?.data?.vendor }}</span>
|
|
1753
|
+
</div>
|
|
1754
|
+
<div class="info-item">
|
|
1755
|
+
<label>API Name:</label>
|
|
1756
|
+
<span>{{ activeTab?.data?.apiName }}</span>
|
|
1757
|
+
</div>
|
|
1758
|
+
<div class="info-item">
|
|
1759
|
+
<label>Input Cost:</label>
|
|
1760
|
+
<span>\${{ activeTab?.data?.inputTokenCost?.toFixed(6) || '0' }} per token</span>
|
|
1761
|
+
</div>
|
|
1762
|
+
<div class="info-item">
|
|
1763
|
+
<label>Output Cost:</label>
|
|
1764
|
+
<span>\${{ activeTab?.data?.outputTokenCost?.toFixed(6) || '0' }} per token</span>
|
|
1765
|
+
</div>
|
|
1766
|
+
<div class="info-item">
|
|
1767
|
+
<label>Active:</label>
|
|
1768
|
+
<span class="status-indicator" [class.active]="activeTab?.data?.isActive">
|
|
1769
|
+
{{ activeTab?.data?.isActive ? 'Yes' : 'No' }}
|
|
1770
|
+
</span>
|
|
1771
|
+
</div>
|
|
1772
|
+
</div>
|
|
1773
|
+
|
|
1774
|
+
@if (activeTab?.data?.description) {
|
|
1775
|
+
<div class="model-description">
|
|
1776
|
+
<h5>Description</h5>
|
|
1777
|
+
<p>{{ activeTab?.data?.description }}</p>
|
|
1778
|
+
</div>
|
|
1779
|
+
}
|
|
1780
|
+
</div>
|
|
1781
|
+
}
|
|
1782
|
+
</div>
|
|
1783
|
+
}
|
|
1784
|
+
</div>
|
|
1785
|
+
</div>
|
|
1786
|
+
</div>
|
|
1787
|
+
</kendo-splitter-pane>
|
|
1788
|
+
</kendo-splitter>
|
|
1789
|
+
</kendo-splitter-pane>
|
|
1790
|
+
|
|
1791
|
+
<!-- Bottom Row: Analysis Panels with Expansion Layout -->
|
|
1792
|
+
<kendo-splitter-pane [resizable]="true" [collapsible]="false">
|
|
1793
|
+
<kendo-splitter orientation="horizontal" (layoutChange)="onSplitterLayoutChange($event)">
|
|
1794
|
+
<!-- Left: Performance Heatmap -->
|
|
1795
|
+
<kendo-splitter-pane size="50%" [resizable]="true" [collapsible]="false">
|
|
1796
|
+
<div class="dashboard-section performance-matrix">
|
|
1797
|
+
<app-performance-heatmap
|
|
1798
|
+
[data]="(performanceMatrix$ | async) ?? []"
|
|
1799
|
+
title="Agent vs Model Performance"
|
|
1800
|
+
[config]="heatmapConfig"
|
|
1801
|
+
></app-performance-heatmap>
|
|
1802
|
+
</div>
|
|
1803
|
+
</kendo-splitter-pane>
|
|
1804
|
+
|
|
1805
|
+
<!-- Right: Analysis Panels with Collapsible Sections -->
|
|
1806
|
+
<kendo-splitter-pane [resizable]="true" [collapsible]="false">
|
|
1807
|
+
<div class="dashboard-section analysis-panels">
|
|
1808
|
+
|
|
1809
|
+
<!-- Cost Analysis Panel -->
|
|
1810
|
+
<div class="analysis-panel">
|
|
1811
|
+
<div class="panel-header" (click)="togglePanel('cost')">
|
|
1812
|
+
<span class="panel-title">
|
|
1813
|
+
<i class="fa-solid fa-dollar-sign"></i>
|
|
1814
|
+
Cost Analysis
|
|
1815
|
+
</span>
|
|
1816
|
+
<i class="fa-solid panel-toggle-icon" [class.fa-chevron-down]="!panelStates.cost" [class.fa-chevron-up]="panelStates.cost"></i>
|
|
1817
|
+
</div>
|
|
1818
|
+
@if (panelStates.cost) {
|
|
1819
|
+
<div class="panel-content">
|
|
1820
|
+
@if (costData$ | async; as costData) {
|
|
1821
|
+
<div class="cost-bars">
|
|
1822
|
+
@for (item of costData.slice(0, 8); track item.model) {
|
|
1823
|
+
<div class="cost-bar-item">
|
|
1824
|
+
<div class="cost-bar-info">
|
|
1825
|
+
<span class="model-name">{{ item.model }}</span>
|
|
1826
|
+
<span class="cost-value">{{ formatCurrency(item.cost) }}</span>
|
|
1827
|
+
</div>
|
|
1828
|
+
<div class="cost-bar-container">
|
|
1829
|
+
<div
|
|
1830
|
+
class="cost-bar"
|
|
1831
|
+
[style.width.%]="getCostBarWidth(item.cost, getMaxCost(costData))"
|
|
1832
|
+
></div>
|
|
1833
|
+
</div>
|
|
1834
|
+
<div class="token-info">
|
|
1835
|
+
{{ formatTokens(item.tokens) }} tokens
|
|
1836
|
+
</div>
|
|
1837
|
+
</div>
|
|
1838
|
+
}
|
|
1839
|
+
</div>
|
|
1840
|
+
}
|
|
1841
|
+
</div>
|
|
1842
|
+
}
|
|
1843
|
+
</div>
|
|
1844
|
+
|
|
1845
|
+
<!-- Token Efficiency Panel -->
|
|
1846
|
+
<div class="analysis-panel">
|
|
1847
|
+
<div class="panel-header" (click)="togglePanel('efficiency')">
|
|
1848
|
+
<span class="panel-title">
|
|
1849
|
+
<i class="fa-solid fa-chart-pie"></i>
|
|
1850
|
+
Token Efficiency
|
|
1851
|
+
</span>
|
|
1852
|
+
<i class="fa-solid panel-toggle-icon" [class.fa-chevron-down]="!panelStates.efficiency" [class.fa-chevron-up]="panelStates.efficiency"></i>
|
|
1853
|
+
</div>
|
|
1854
|
+
@if (panelStates.efficiency) {
|
|
1855
|
+
<div class="panel-content">
|
|
1856
|
+
@if (tokenEfficiency$ | async; as efficiencyData) {
|
|
1857
|
+
<div class="efficiency-items">
|
|
1858
|
+
@for (item of efficiencyData.slice(0, 6); track item.model) {
|
|
1859
|
+
<div class="efficiency-item">
|
|
1860
|
+
<div class="efficiency-header">
|
|
1861
|
+
<span class="model-name">{{ item.model }}</span>
|
|
1862
|
+
<span class="efficiency-ratio">
|
|
1863
|
+
{{ getTokenRatio(item.inputTokens, item.outputTokens) }}
|
|
1864
|
+
</span>
|
|
1865
|
+
</div>
|
|
1866
|
+
<div class="token-breakdown">
|
|
1867
|
+
<div class="token-bar">
|
|
1868
|
+
<div
|
|
1869
|
+
class="token-segment token-segment--input"
|
|
1870
|
+
[style.width.%]="getTokenPercentage(item.inputTokens, item.inputTokens + item.outputTokens)"
|
|
1871
|
+
></div>
|
|
1872
|
+
<div
|
|
1873
|
+
class="token-segment token-segment--output"
|
|
1874
|
+
[style.width.%]="getTokenPercentage(item.outputTokens, item.inputTokens + item.outputTokens)"
|
|
1875
|
+
></div>
|
|
1876
|
+
</div>
|
|
1877
|
+
<div class="token-labels">
|
|
1878
|
+
<span class="input-label">Input: {{ formatTokens(item.inputTokens) }}</span>
|
|
1879
|
+
<span class="output-label">Output: {{ formatTokens(item.outputTokens) }}</span>
|
|
1880
|
+
</div>
|
|
1881
|
+
</div>
|
|
1882
|
+
<div class="cost-per-token">
|
|
1883
|
+
{{ formatCostPerToken(item.cost, item.inputTokens + item.outputTokens) }}
|
|
1884
|
+
</div>
|
|
1885
|
+
</div>
|
|
1886
|
+
}
|
|
1887
|
+
</div>
|
|
1888
|
+
}
|
|
1889
|
+
</div>
|
|
1890
|
+
}
|
|
1891
|
+
</div>
|
|
1892
|
+
|
|
1893
|
+
<!-- Live Executions Panel -->
|
|
1894
|
+
<div class="analysis-panel">
|
|
1895
|
+
<div class="panel-header" (click)="togglePanel('executions')">
|
|
1896
|
+
<span class="panel-title">
|
|
1897
|
+
<i class="fa-solid fa-bolt"></i>
|
|
1898
|
+
Live Executions
|
|
1899
|
+
</span>
|
|
1900
|
+
<i class="fa-solid panel-toggle-icon" [class.fa-chevron-down]="!panelStates.executions" [class.fa-chevron-up]="panelStates.executions"></i>
|
|
1901
|
+
</div>
|
|
1902
|
+
@if (panelStates.executions) {
|
|
1903
|
+
<div class="panel-content live-executions-panel">
|
|
1904
|
+
<app-live-execution-widget
|
|
1905
|
+
[executions]="(liveExecutions$ | async) ?? []"
|
|
1906
|
+
(executionClick)="onExecutionClick($event)"
|
|
1907
|
+
></app-live-execution-widget>
|
|
1908
|
+
</div>
|
|
1909
|
+
}
|
|
1910
|
+
</div>
|
|
1911
|
+
</div>
|
|
1912
|
+
</kendo-splitter-pane>
|
|
1913
|
+
</kendo-splitter>
|
|
1914
|
+
</kendo-splitter-pane>
|
|
1915
|
+
</kendo-splitter>
|
|
1916
|
+
|
|
1917
|
+
<!-- Execution Details Modal -->
|
|
1918
|
+
@if (selectedExecution) {
|
|
1919
|
+
<div class="execution-modal" (click)="closeExecutionModal()">
|
|
1920
|
+
<div class="execution-modal-content" (click)="$event.stopPropagation()">
|
|
1921
|
+
<div class="execution-modal-header">
|
|
1922
|
+
<h3>Execution Details</h3>
|
|
1923
|
+
<div class="modal-header-actions">
|
|
1924
|
+
<button class="open-record-btn" (click)="openFullRecord()">
|
|
1925
|
+
<i class="fa-solid fa-external-link-alt"></i>
|
|
1926
|
+
Open
|
|
1927
|
+
</button>
|
|
1928
|
+
<button class="close-btn" (click)="closeExecutionModal()">
|
|
1929
|
+
<i class="fa-solid fa-times"></i>
|
|
1930
|
+
</button>
|
|
1931
|
+
</div>
|
|
1932
|
+
</div>
|
|
1933
|
+
<div class="execution-modal-body">
|
|
1934
|
+
@if (executionDetails) {
|
|
1935
|
+
<div class="execution-details">
|
|
1936
|
+
<div class="detail-section">
|
|
1937
|
+
<h4>Basic Information</h4>
|
|
1938
|
+
<div class="detail-grid">
|
|
1939
|
+
<div class="detail-item">
|
|
1940
|
+
<label>Type:</label>
|
|
1941
|
+
<span>{{ executionDetails.type | titlecase }}</span>
|
|
1942
|
+
</div>
|
|
1943
|
+
<div class="detail-item">
|
|
1944
|
+
<label>Name:</label>
|
|
1945
|
+
<span>{{ executionDetails.name }}</span>
|
|
1946
|
+
</div>
|
|
1947
|
+
<div class="detail-item">
|
|
1948
|
+
<label>Status:</label>
|
|
1949
|
+
<span class="status-badge" [class]="'status-badge--' + executionDetails.status">
|
|
1950
|
+
{{ executionDetails.status | titlecase }}
|
|
1951
|
+
</span>
|
|
1952
|
+
</div>
|
|
1953
|
+
<div class="detail-item">
|
|
1954
|
+
<label>Started:</label>
|
|
1955
|
+
<span>{{ executionDetails.startTime | date:'medium' }}</span>
|
|
1956
|
+
</div>
|
|
1957
|
+
@if (executionDetails.endTime) {
|
|
1958
|
+
<div class="detail-item">
|
|
1959
|
+
<label>Completed:</label>
|
|
1960
|
+
<span>{{ executionDetails.endTime | date:'medium' }}</span>
|
|
1961
|
+
</div>
|
|
1962
|
+
}
|
|
1963
|
+
<div class="detail-item">
|
|
1964
|
+
<label>Duration:</label>
|
|
1965
|
+
<span>{{ formatDuration(getDuration(executionDetails)) }}</span>
|
|
1966
|
+
</div>
|
|
1967
|
+
</div>
|
|
1968
|
+
</div>
|
|
1969
|
+
|
|
1970
|
+
<div class="detail-section">
|
|
1971
|
+
<h4>Resource Usage</h4>
|
|
1972
|
+
<div class="detail-grid">
|
|
1973
|
+
<div class="detail-item">
|
|
1974
|
+
<label>Cost:</label>
|
|
1975
|
+
<span>{{ formatCurrency(executionDetails.cost, 6) }}</span>
|
|
1976
|
+
</div>
|
|
1977
|
+
<div class="detail-item">
|
|
1978
|
+
<label>Tokens:</label>
|
|
1979
|
+
<span>{{ executionDetails.tokens.toLocaleString() }}</span>
|
|
1980
|
+
</div>
|
|
1981
|
+
@if (executionDetails.model) {
|
|
1982
|
+
<div class="detail-item">
|
|
1983
|
+
<label>Model:</label>
|
|
1984
|
+
<span>{{ executionDetails.model }}</span>
|
|
1985
|
+
</div>
|
|
1986
|
+
}
|
|
1987
|
+
</div>
|
|
1988
|
+
</div>
|
|
1989
|
+
|
|
1990
|
+
@if (executionDetails.errorMessage) {
|
|
1991
|
+
<div class="detail-section">
|
|
1992
|
+
<h4>Error Information</h4>
|
|
1993
|
+
<div class="error-message">{{ executionDetails.errorMessage }}</div>
|
|
1994
|
+
</div>
|
|
1995
|
+
}
|
|
1996
|
+
|
|
1997
|
+
@if (executionDetails.children.length > 0) {
|
|
1998
|
+
<div class="detail-section">
|
|
1999
|
+
<h4>Child Executions ({{ executionDetails.children.length }})</h4>
|
|
2000
|
+
<div class="child-executions">
|
|
2001
|
+
@for (child of executionDetails.children; track child.id) {
|
|
2002
|
+
<div class="child-execution">
|
|
2003
|
+
<div class="child-info">
|
|
2004
|
+
<span class="child-name">{{ child.name }}</span>
|
|
2005
|
+
<span class="child-type">{{ child.type }}</span>
|
|
2006
|
+
<span class="child-status" [class]="'status-badge--' + child.status">
|
|
2007
|
+
{{ child.status }}
|
|
2008
|
+
</span>
|
|
2009
|
+
</div>
|
|
2010
|
+
<div class="child-metrics">
|
|
2011
|
+
<span>{{ formatCurrency(child.cost) }}</span>
|
|
2012
|
+
<span>{{ child.tokens.toLocaleString() }} tokens</span>
|
|
2013
|
+
</div>
|
|
2014
|
+
</div>
|
|
2015
|
+
}
|
|
2016
|
+
</div>
|
|
2017
|
+
</div>
|
|
2018
|
+
}
|
|
2019
|
+
</div>
|
|
2020
|
+
}
|
|
2021
|
+
|
|
2022
|
+
@if (loadingExecutionDetails) {
|
|
2023
|
+
<div class="loading-details">
|
|
2024
|
+
<div class="spinner"></div>
|
|
2025
|
+
<p>Loading execution details...</p>
|
|
2026
|
+
</div>
|
|
2027
|
+
}
|
|
2028
|
+
</div>
|
|
2029
|
+
</div>
|
|
2030
|
+
</div>
|
|
2031
|
+
}
|
|
2032
|
+
</div>
|
|
2033
|
+
`, styles: ["\n .execution-monitoring {\n padding: 20px;\n background: #f8f9fa;\n min-height: 100vh;\n }\n\n .monitoring-header {\n background: white;\n padding: 20px;\n border-radius: 8px;\n box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);\n margin-bottom: 20px;\n display: flex;\n justify-content: space-between;\n align-items: center;\n flex-wrap: wrap;\n gap: 16px;\n }\n\n .monitoring-title {\n margin: 0;\n font-size: 20px;\n font-weight: 600;\n color: #333;\n display: flex;\n align-items: center;\n gap: 12px;\n }\n\n .monitoring-title i {\n color: #2196f3;\n }\n\n .monitoring-controls {\n display: flex;\n gap: 16px;\n align-items: center;\n flex-wrap: wrap;\n }\n\n .refresh-control, .time-range-control {\n display: flex;\n align-items: center;\n gap: 8px;\n font-size: 12px;\n }\n\n .refresh-control label, .time-range-control label {\n color: #666;\n font-weight: 500;\n }\n\n .refresh-control select, .time-range-control select {\n padding: 6px 12px;\n border: 1px solid #ddd;\n border-radius: 4px;\n font-size: 12px;\n background: white;\n }\n\n .refresh-btn {\n background: #2196f3;\n color: white;\n border: none;\n padding: 8px 16px;\n border-radius: 4px;\n font-size: 12px;\n font-weight: 500;\n cursor: pointer;\n display: flex;\n align-items: center;\n gap: 6px;\n transition: background 0.2s ease;\n }\n\n .refresh-btn:hover:not(:disabled) {\n background: #1976d2;\n }\n\n .refresh-btn:disabled {\n opacity: 0.6;\n cursor: not-allowed;\n }\n\n .refresh-btn i.spinning {\n animation: spin 1s linear infinite;\n }\n\n @keyframes spin {\n 0% { transform: rotate(0deg); }\n 100% { transform: rotate(360deg); }\n }\n\n .kpi-dashboard {\n margin-bottom: 20px;\n }\n\n .kpi-grid {\n display: grid;\n grid-template-columns: repeat(auto-fit, minmax(240px, 1fr));\n gap: 16px;\n }\n\n .dashboard-splitter {\n height: calc(100vh - 550px); /* Increased to account for headers and margins */\n min-height: 600px;\n margin-bottom: 20px;\n }\n\n .dashboard-section {\n background: white;\n border-radius: 8px;\n box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);\n overflow: hidden;\n height: 100%;\n display: flex;\n flex-direction: column;\n }\n\n /* Ensure splitter panes take full height */\n :host ::ng-deep .k-splitter-pane {\n overflow: hidden;\n }\n\n :host ::ng-deep .k-splitter .k-splitter-pane {\n padding: 10px;\n }\n\n :host ::ng-deep .k-splitter-horizontal > .k-splitter-pane {\n padding: 10px 5px;\n }\n\n :host ::ng-deep .k-splitter-vertical > .k-splitter-pane {\n padding: 5px 10px;\n }\n\n /* Cost Analysis Styles */\n .cost-chart-container, .efficiency-chart-container, .status-container {\n padding: 20px;\n height: 100%;\n display: flex;\n flex-direction: column;\n }\n\n .chart-header {\n margin-bottom: 16px;\n }\n\n .chart-title {\n margin: 0;\n font-size: 16px;\n font-weight: 600;\n color: #333;\n display: flex;\n align-items: center;\n gap: 8px;\n }\n\n .chart-title i {\n color: #2196f3;\n }\n\n .cost-bars, .efficiency-items {\n flex: 1;\n display: flex;\n flex-direction: column;\n gap: 12px;\n }\n\n .cost-bar-item {\n display: flex;\n align-items: center;\n gap: 12px;\n padding: 8px 0;\n border-bottom: 1px solid #f0f0f0;\n }\n\n .cost-bar-item:last-child {\n border-bottom: none;\n }\n\n .cost-bar-info {\n min-width: 120px;\n display: flex;\n flex-direction: column;\n gap: 2px;\n }\n\n .model-name {\n font-size: 12px;\n font-weight: 500;\n color: #333;\n }\n\n .cost-value {\n font-size: 11px;\n color: #ff9800;\n font-weight: 600;\n }\n\n .cost-bar-container {\n flex: 1;\n height: 8px;\n background: #f0f0f0;\n border-radius: 4px;\n overflow: hidden;\n }\n\n .cost-bar {\n height: 100%;\n background: linear-gradient(90deg, #ff9800, #f57c00);\n border-radius: 4px;\n transition: width 0.3s ease;\n }\n\n .token-info {\n font-size: 10px;\n color: #666;\n min-width: 80px;\n text-align: right;\n }\n\n /* Token Efficiency Styles */\n .efficiency-item {\n padding: 12px 0;\n border-bottom: 1px solid #f0f0f0;\n }\n\n .efficiency-item:last-child {\n border-bottom: none;\n }\n\n .efficiency-header {\n display: flex;\n justify-content: space-between;\n align-items: center;\n margin-bottom: 8px;\n }\n\n .efficiency-ratio {\n font-size: 11px;\n color: #2196f3;\n font-weight: 600;\n }\n\n .token-breakdown {\n display: flex;\n flex-direction: column;\n gap: 6px;\n }\n\n .token-bar {\n height: 6px;\n background: #f0f0f0;\n border-radius: 3px;\n overflow: hidden;\n display: flex;\n }\n\n .token-segment {\n height: 100%;\n }\n\n .token-segment--input {\n background: #4caf50;\n }\n\n .token-segment--output {\n background: #2196f3;\n }\n\n .token-labels {\n display: flex;\n justify-content: space-between;\n font-size: 10px;\n color: #666;\n }\n\n .input-label {\n color: #4caf50;\n }\n\n .output-label {\n color: #2196f3;\n }\n\n .cost-per-token {\n font-size: 10px;\n color: #999;\n margin-top: 4px;\n }\n\n /* System Status Styles */\n .status-metrics {\n display: flex;\n flex-direction: column;\n gap: 16px;\n flex: 1;\n }\n\n .status-metric {\n display: flex;\n align-items: center;\n gap: 12px;\n padding: 12px;\n background: #f8f9fa;\n border-radius: 6px;\n }\n\n .status-icon {\n width: 40px;\n height: 40px;\n border-radius: 50%;\n display: flex;\n align-items: center;\n justify-content: center;\n flex-shrink: 0;\n }\n\n .status-icon--success {\n background: rgba(76, 175, 80, 0.1);\n color: #4caf50;\n }\n\n .status-icon--warning {\n background: rgba(255, 152, 0, 0.1);\n color: #ff9800;\n }\n\n .status-icon--info {\n background: rgba(33, 150, 243, 0.1);\n color: #2196f3;\n }\n\n .status-icon--primary {\n background: rgba(156, 39, 176, 0.1);\n color: #9c27b0;\n }\n\n .status-info {\n flex: 1;\n }\n\n .status-label {\n font-size: 12px;\n color: #666;\n font-weight: 500;\n }\n\n .status-value {\n font-size: 18px;\n font-weight: 700;\n color: #333;\n margin: 2px 0;\n }\n\n .status-subtitle {\n font-size: 10px;\n color: #999;\n }\n\n /* Execution Modal Styles */\n .execution-modal {\n position: fixed;\n top: 0;\n left: 0;\n width: 100%;\n height: 100%;\n background: rgba(0, 0, 0, 0.5);\n display: flex;\n align-items: center;\n justify-content: center;\n z-index: 1000;\n padding: 20px;\n }\n\n .execution-modal-content {\n background: white;\n border-radius: 8px;\n max-width: 800px;\n width: 100%;\n max-height: 80vh;\n overflow: hidden;\n display: flex;\n flex-direction: column;\n }\n\n .execution-modal-header {\n padding: 20px;\n border-bottom: 1px solid #f0f0f0;\n display: flex;\n justify-content: space-between;\n align-items: center;\n }\n\n .execution-modal-header h3 {\n margin: 0;\n font-size: 18px;\n font-weight: 600;\n color: #333;\n }\n\n .modal-header-actions {\n display: flex;\n gap: 12px;\n align-items: center;\n }\n\n .open-record-btn {\n background: #2196f3;\n color: white;\n border: none;\n padding: 8px 16px;\n border-radius: 4px;\n font-size: 13px;\n font-weight: 500;\n cursor: pointer;\n display: flex;\n align-items: center;\n gap: 6px;\n transition: all 0.2s ease;\n }\n\n .open-record-btn:hover {\n background: #1976d2;\n transform: translateY(-1px);\n box-shadow: 0 2px 8px rgba(33, 150, 243, 0.3);\n }\n\n .open-record-btn i {\n font-size: 12px;\n }\n\n .close-btn {\n background: none;\n border: none;\n font-size: 16px;\n color: #999;\n cursor: pointer;\n padding: 4px;\n }\n\n .close-btn:hover {\n color: #333;\n }\n\n .execution-modal-body {\n padding: 20px;\n overflow-y: auto;\n flex: 1;\n }\n\n .execution-details {\n display: flex;\n flex-direction: column;\n gap: 20px;\n }\n\n .detail-section h4 {\n margin: 0 0 12px 0;\n font-size: 14px;\n font-weight: 600;\n color: #333;\n border-bottom: 1px solid #f0f0f0;\n padding-bottom: 6px;\n }\n\n .detail-grid {\n display: grid;\n grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));\n gap: 12px;\n }\n\n .detail-item {\n display: flex;\n flex-direction: column;\n gap: 4px;\n }\n\n .detail-item label {\n font-size: 11px;\n color: #666;\n font-weight: 500;\n text-transform: uppercase;\n letter-spacing: 0.5px;\n }\n\n .detail-item span {\n font-size: 13px;\n color: #333;\n }\n\n .status-badge {\n display: inline-block;\n padding: 2px 8px;\n border-radius: 12px;\n font-size: 10px;\n font-weight: 500;\n text-transform: uppercase;\n }\n\n .status-badge--completed {\n background: rgba(76, 175, 80, 0.1);\n color: #4caf50;\n }\n\n .status-badge--running {\n background: rgba(33, 150, 243, 0.1);\n color: #2196f3;\n }\n\n .status-badge--failed {\n background: rgba(244, 67, 54, 0.1);\n color: #f44336;\n }\n\n .error-message {\n background: #fff3e0;\n border: 1px solid #ffcc02;\n border-radius: 4px;\n padding: 12px;\n font-size: 12px;\n color: #e65100;\n font-family: monospace;\n }\n\n .child-executions {\n display: flex;\n flex-direction: column;\n gap: 8px;\n }\n\n .child-execution {\n background: #f8f9fa;\n border-radius: 4px;\n padding: 12px;\n display: flex;\n justify-content: space-between;\n align-items: center;\n }\n\n .child-info {\n display: flex;\n align-items: center;\n gap: 8px;\n }\n\n .child-name {\n font-size: 12px;\n font-weight: 500;\n color: #333;\n }\n\n .child-type {\n font-size: 10px;\n background: #e0e0e0;\n padding: 2px 6px;\n border-radius: 3px;\n color: #666;\n }\n\n .child-status {\n font-size: 10px;\n padding: 2px 6px;\n border-radius: 3px;\n }\n\n .child-metrics {\n display: flex;\n gap: 12px;\n font-size: 11px;\n color: #666;\n }\n\n .loading-details {\n display: flex;\n flex-direction: column;\n align-items: center;\n justify-content: center;\n padding: 40px;\n gap: 12px;\n }\n\n .spinner {\n width: 32px;\n height: 32px;\n border: 3px solid #f3f3f3;\n border-top: 3px solid #2196f3;\n border-radius: 50%;\n animation: spin 1s linear infinite;\n }\n\n /* Drill-down Tab Styles */\n .drill-down-container {\n height: 100%;\n display: flex;\n flex-direction: column;\n }\n\n .drill-down-tabs {\n height: 100%;\n display: flex;\n flex-direction: column;\n }\n\n .tab-header {\n display: flex;\n border-bottom: 1px solid #e0e0e0;\n background: #f8f9fa;\n min-height: 40px;\n overflow-x: auto;\n }\n\n .tab-item {\n display: flex;\n align-items: center;\n gap: 8px;\n padding: 8px 16px;\n background: #f8f9fa;\n border: none;\n border-bottom: 2px solid transparent;\n cursor: pointer;\n font-size: 12px;\n font-weight: 500;\n color: #666;\n white-space: nowrap;\n transition: all 0.2s ease;\n min-width: 120px;\n justify-content: space-between;\n }\n\n .tab-item:hover {\n background: #e9ecef;\n color: #333;\n }\n\n .tab-item.active {\n background: white;\n color: #2196f3;\n border-bottom-color: #2196f3;\n }\n\n .tab-title {\n flex: 1;\n overflow: hidden;\n text-overflow: ellipsis;\n }\n\n .tab-close {\n background: none;\n border: none;\n color: #999;\n cursor: pointer;\n padding: 2px;\n border-radius: 2px;\n font-size: 10px;\n width: 16px;\n height: 16px;\n display: flex;\n align-items: center;\n justify-content: center;\n transition: all 0.2s ease;\n }\n\n .tab-close:hover {\n background: rgba(0, 0, 0, 0.1);\n color: #333;\n }\n\n .tab-content {\n flex: 1;\n overflow: hidden;\n display: flex;\n flex-direction: column;\n }\n\n .tab-pane {\n height: 100%;\n overflow: hidden;\n display: flex;\n flex-direction: column;\n }\n\n .trends-chart {\n padding: 0;\n }\n\n .trends-chart app-time-series-chart {\n height: 100%;\n display: block;\n overflow: hidden;\n }\n\n /* Ensure chart fits within tab pane */\n .tab-pane.trends-chart {\n display: flex;\n flex-direction: column;\n overflow: hidden;\n }\n\n /* Drill-down specific styles */\n .executions-drill-down {\n padding: 20px;\n overflow-y: auto;\n }\n\n .drill-down-header {\n display: flex;\n justify-content: space-between;\n align-items: center;\n margin-bottom: 20px;\n padding-bottom: 12px;\n border-bottom: 1px solid #e0e0e0;\n }\n\n .drill-down-header h4 {\n margin: 0;\n font-size: 16px;\n font-weight: 600;\n color: #333;\n display: flex;\n align-items: center;\n gap: 8px;\n }\n\n .drill-down-meta {\n display: flex;\n gap: 12px;\n align-items: center;\n font-size: 12px;\n }\n\n .timestamp {\n color: #666;\n background: #f0f0f0;\n padding: 4px 8px;\n border-radius: 4px;\n }\n\n .metric-badge {\n background: #2196f3;\n color: white;\n padding: 4px 8px;\n border-radius: 4px;\n font-weight: 500;\n }\n\n .loading-spinner {\n display: flex;\n align-items: center;\n justify-content: center;\n padding: 40px;\n color: #666;\n gap: 12px;\n }\n\n .executions-table {\n display: flex;\n flex-direction: column;\n gap: 0;\n border: 1px solid #e0e0e0;\n border-radius: 6px;\n overflow: hidden;\n }\n\n .table-header {\n display: grid;\n grid-template-columns: 80px 1fr 120px 100px 100px 80px 100px 120px;\n gap: 12px;\n background: #f8f9fa;\n padding: 12px 16px;\n font-size: 11px;\n font-weight: 600;\n color: #666;\n text-transform: uppercase;\n letter-spacing: 0.5px;\n }\n\n .table-row {\n display: grid;\n grid-template-columns: 80px 1fr 120px 100px 100px 80px 100px 120px;\n gap: 12px;\n padding: 12px 16px;\n border-top: 1px solid #f0f0f0;\n cursor: pointer;\n transition: background 0.2s ease;\n align-items: center;\n }\n\n .table-row:hover {\n background: #f8f9fa;\n }\n\n .table-cell {\n font-size: 12px;\n color: #333;\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n }\n\n .type-badge {\n background: #e9ecef;\n color: #666;\n padding: 2px 6px;\n border-radius: 3px;\n font-size: 10px;\n font-weight: 500;\n text-transform: uppercase;\n }\n\n .type-badge--prompt {\n background: rgba(33, 150, 243, 0.1);\n color: #2196f3;\n }\n\n .type-badge--agent {\n background: rgba(76, 175, 80, 0.1);\n color: #4caf50;\n }\n\n .no-data {\n display: flex;\n flex-direction: column;\n align-items: center;\n justify-content: center;\n padding: 60px 20px;\n color: #999;\n gap: 16px;\n }\n\n .no-data i {\n font-size: 48px;\n color: #ddd;\n }\n\n .no-data p {\n margin: 0;\n font-size: 14px;\n }\n\n /* Model detail styles */\n .model-detail {\n padding: 20px;\n overflow-y: auto;\n }\n\n .model-details {\n display: flex;\n flex-direction: column;\n gap: 24px;\n }\n\n .model-info-grid {\n display: grid;\n grid-template-columns: repeat(auto-fit, minmax(250px, 1fr));\n gap: 16px;\n }\n\n .info-item {\n display: flex;\n flex-direction: column;\n gap: 6px;\n padding: 16px;\n background: #f8f9fa;\n border-radius: 6px;\n }\n\n .info-item label {\n font-size: 11px;\n color: #666;\n font-weight: 600;\n text-transform: uppercase;\n letter-spacing: 0.5px;\n margin: 0;\n }\n\n .info-item span {\n font-size: 14px;\n color: #333;\n font-weight: 500;\n }\n\n .status-indicator {\n display: inline-flex;\n align-items: center;\n gap: 4px;\n font-size: 12px;\n }\n\n .status-indicator.active {\n color: #4caf50;\n }\n\n .status-indicator.active::before {\n content: '';\n width: 6px;\n height: 6px;\n background: #4caf50;\n border-radius: 50%;\n }\n\n .model-description {\n padding: 20px;\n background: #f8f9fa;\n border-radius: 8px;\n }\n\n .model-description h5 {\n margin: 0 0 12px 0;\n font-size: 14px;\n font-weight: 600;\n color: #333;\n }\n\n .model-description p {\n margin: 0;\n font-size: 13px;\n color: #666;\n line-height: 1.5;\n }\n\n /* Clickable KPI cards */\n .clickable {\n cursor: pointer;\n transition: transform 0.2s ease, box-shadow 0.2s ease;\n }\n\n .clickable:hover {\n transform: translateY(-2px);\n box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15);\n }\n\n /* Collapsible Panel Styles */\n .analysis-panels {\n padding: 10px;\n height: 100%;\n overflow-y: auto;\n background: #f8f9fa;\n }\n\n .analysis-panel {\n margin-bottom: 12px;\n border-radius: 8px;\n box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);\n background: white;\n overflow: hidden;\n }\n\n .analysis-panel:last-child {\n margin-bottom: 0;\n }\n\n .panel-header {\n padding: 12px 16px;\n background: #f8f9fa;\n border-bottom: 1px solid #e0e0e0;\n cursor: pointer;\n display: flex;\n justify-content: space-between;\n align-items: center;\n transition: background 0.2s ease;\n }\n\n .panel-header:hover {\n background: #e9ecef;\n }\n\n .panel-title {\n display: flex;\n align-items: center;\n gap: 8px;\n font-weight: 600;\n color: #333;\n font-size: 14px;\n }\n\n .panel-title i {\n color: #2196f3;\n width: 16px;\n }\n\n .panel-toggle-icon {\n color: #666;\n font-size: 12px;\n transition: transform 0.2s ease;\n }\n\n .panel-content {\n padding: 16px;\n border-top: 1px solid #f0f0f0;\n animation: slideDown 0.2s ease-out;\n }\n\n @keyframes slideDown {\n from {\n opacity: 0;\n max-height: 0;\n }\n to {\n opacity: 1;\n max-height: 500px;\n }\n }\n\n .live-executions-panel {\n padding: 0;\n }\n\n .live-executions-panel app-live-execution-widget {\n height: 300px;\n display: block;\n }\n\n /* Responsive Design */\n @media (max-width: 1200px) {\n .dashboard-splitter {\n height: calc(100vh - 270px); /* Consistent with main height */\n margin-bottom: 20px;\n }\n \n .table-header,\n .table-row {\n grid-template-columns: 60px 1fr 100px 80px 80px 60px 80px 100px;\n gap: 8px;\n }\n \n .model-info-grid {\n grid-template-columns: 1fr;\n }\n \n .analysis-panels {\n padding: 8px;\n }\n \n .analysis-panel {\n margin-bottom: 8px;\n }\n }\n\n @media (max-width: 768px) {\n .execution-monitoring {\n padding: 12px;\n }\n \n .monitoring-header {\n flex-direction: column;\n align-items: flex-start;\n }\n \n .monitoring-controls {\n width: 100%;\n justify-content: flex-start;\n }\n \n .dashboard-splitter {\n height: calc(100vh - 270px); /* Consistent with main height */\n min-height: 400px;\n margin-bottom: 20px;\n }\n \n .kpi-grid {\n grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));\n }\n\n /* Reduce padding on smaller screens */\n :host ::ng-deep .k-splitter .k-splitter-pane {\n padding: 5px;\n }\n\n :host ::ng-deep .k-splitter-horizontal > .k-splitter-pane {\n padding: 5px 2px;\n }\n\n :host ::ng-deep .k-splitter-vertical > .k-splitter-pane {\n padding: 2px 5px;\n }\n \n .tab-header {\n overflow-x: auto;\n }\n \n .tab-item {\n min-width: 100px;\n padding: 6px 12px;\n }\n \n .table-header,\n .table-row {\n grid-template-columns: 1fr;\n gap: 4px;\n text-align: left;\n }\n \n .table-row {\n display: block;\n padding: 16px;\n }\n \n .table-cell {\n display: block;\n margin-bottom: 8px;\n }\n \n .table-cell:before {\n content: attr(data-label) ': ';\n font-weight: 600;\n color: #666;\n font-size: 11px;\n text-transform: uppercase;\n }\n \n .executions-drill-down,\n .model-detail {\n padding: 12px;\n }\n \n .panel-content {\n padding: 12px;\n }\n \n .panel-header {\n padding: 10px 12px;\n }\n \n .panel-title {\n font-size: 13px;\n }\n }\n "] }]
|
|
2034
|
+
}], () => [{ type: i1.AIInstrumentationService }], { initialState: [{
|
|
2035
|
+
type: Input
|
|
2036
|
+
}], openEntityRecord: [{
|
|
2037
|
+
type: Output
|
|
2038
|
+
}], stateChange: [{
|
|
27
2039
|
type: Output
|
|
28
2040
|
}] }); })();
|
|
29
|
-
(() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassDebugInfo(ExecutionMonitoringComponent, { className: "ExecutionMonitoringComponent", filePath: "src/AI/components/execution-monitoring.component.ts", lineNumber:
|
|
2041
|
+
(() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassDebugInfo(ExecutionMonitoringComponent, { className: "ExecutionMonitoringComponent", filePath: "src/AI/components/execution-monitoring.component.ts", lineNumber: 1723 }); })();
|
|
30
2042
|
//# sourceMappingURL=execution-monitoring.component.js.map
|