@memberjunction/ng-dashboards 5.26.0 → 5.27.1
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/dist/AI/components/analytics/agent-runs/agent-run-analysis.component.d.ts +96 -0
- package/dist/AI/components/analytics/agent-runs/agent-run-analysis.component.d.ts.map +1 -0
- package/dist/AI/components/analytics/agent-runs/agent-run-analysis.component.js +710 -0
- package/dist/AI/components/analytics/agent-runs/agent-run-analysis.component.js.map +1 -0
- package/dist/AI/components/analytics/ai-analytics-resource.component.d.ts +52 -0
- package/dist/AI/components/analytics/ai-analytics-resource.component.d.ts.map +1 -0
- package/dist/AI/components/analytics/ai-analytics-resource.component.js +356 -0
- package/dist/AI/components/analytics/ai-analytics-resource.component.js.map +1 -0
- package/dist/AI/components/analytics/analytics-filter-bar.component.d.ts +52 -0
- package/dist/AI/components/analytics/analytics-filter-bar.component.d.ts.map +1 -0
- package/dist/AI/components/analytics/analytics-filter-bar.component.js +306 -0
- package/dist/AI/components/analytics/analytics-filter-bar.component.js.map +1 -0
- package/dist/AI/components/analytics/cost-budget/cost-budget.component.d.ts +81 -0
- package/dist/AI/components/analytics/cost-budget/cost-budget.component.d.ts.map +1 -0
- package/dist/AI/components/analytics/cost-budget/cost-budget.component.js +744 -0
- package/dist/AI/components/analytics/cost-budget/cost-budget.component.js.map +1 -0
- package/dist/AI/components/analytics/error-analysis/error-analysis.component.d.ts +61 -0
- package/dist/AI/components/analytics/error-analysis/error-analysis.component.d.ts.map +1 -0
- package/dist/AI/components/analytics/error-analysis/error-analysis.component.js +490 -0
- package/dist/AI/components/analytics/error-analysis/error-analysis.component.js.map +1 -0
- package/dist/AI/components/analytics/executive-summary/executive-summary.component.d.ts +77 -0
- package/dist/AI/components/analytics/executive-summary/executive-summary.component.d.ts.map +1 -0
- package/dist/AI/components/analytics/executive-summary/executive-summary.component.js +673 -0
- package/dist/AI/components/analytics/executive-summary/executive-summary.component.js.map +1 -0
- package/dist/AI/components/analytics/model-performance/model-performance.component.d.ts +65 -0
- package/dist/AI/components/analytics/model-performance/model-performance.component.d.ts.map +1 -0
- package/dist/AI/components/analytics/model-performance/model-performance.component.js +537 -0
- package/dist/AI/components/analytics/model-performance/model-performance.component.js.map +1 -0
- package/dist/AI/components/analytics/prompt-runs/prompt-run-analysis.component.d.ts +131 -0
- package/dist/AI/components/analytics/prompt-runs/prompt-run-analysis.component.d.ts.map +1 -0
- package/dist/AI/components/analytics/prompt-runs/prompt-run-analysis.component.js +1030 -0
- package/dist/AI/components/analytics/prompt-runs/prompt-run-analysis.component.js.map +1 -0
- package/dist/AI/components/analytics/usage-patterns/usage-patterns.component.d.ts +78 -0
- package/dist/AI/components/analytics/usage-patterns/usage-patterns.component.d.ts.map +1 -0
- package/dist/AI/components/analytics/usage-patterns/usage-patterns.component.js +569 -0
- package/dist/AI/components/analytics/usage-patterns/usage-patterns.component.js.map +1 -0
- package/dist/AI/components/execution-monitoring.component.d.ts.map +1 -1
- package/dist/AI/components/execution-monitoring.component.js +4 -14
- package/dist/AI/components/execution-monitoring.component.js.map +1 -1
- package/dist/AI/components/overview/ai-overview-hub.component.d.ts +58 -0
- package/dist/AI/components/overview/ai-overview-hub.component.d.ts.map +1 -0
- package/dist/AI/components/overview/ai-overview-hub.component.js +315 -0
- package/dist/AI/components/overview/ai-overview-hub.component.js.map +1 -0
- package/dist/AI/components/prompts/prompt-management.component.js +1 -1
- package/dist/AI/components/prompts/prompt-management.component.js.map +1 -1
- package/dist/AI/index.d.ts +11 -0
- package/dist/AI/index.d.ts.map +1 -1
- package/dist/AI/index.js +13 -0
- package/dist/AI/index.js.map +1 -1
- package/dist/AI/interfaces/analytics-preferences.interface.d.ts +50 -0
- package/dist/AI/interfaces/analytics-preferences.interface.d.ts.map +1 -0
- package/dist/AI/interfaces/analytics-preferences.interface.js +9 -0
- package/dist/AI/interfaces/analytics-preferences.interface.js.map +1 -0
- package/dist/ComponentStudio/components/artifact-load-dialog.component.d.ts.map +1 -1
- package/dist/ComponentStudio/components/artifact-load-dialog.component.js +1 -1
- package/dist/ComponentStudio/components/artifact-load-dialog.component.js.map +1 -1
- package/dist/Home/home-dashboard.component.js +2 -2
- package/dist/MCP/index.d.ts +1 -0
- package/dist/MCP/index.d.ts.map +1 -1
- package/dist/MCP/index.js +2 -0
- package/dist/MCP/index.js.map +1 -1
- package/dist/MCP/mcp-dashboard.component.d.ts +1 -0
- package/dist/MCP/mcp-dashboard.component.d.ts.map +1 -1
- package/dist/MCP/mcp-dashboard.component.js +5 -4
- package/dist/MCP/mcp-dashboard.component.js.map +1 -1
- package/dist/MCP/mcp-resource.component.d.ts +6 -5
- package/dist/MCP/mcp-resource.component.d.ts.map +1 -1
- package/dist/MCP/mcp-resource.component.js +7 -8
- package/dist/MCP/mcp-resource.component.js.map +1 -1
- package/dist/ai-dashboards.module.d.ts +27 -17
- package/dist/ai-dashboards.module.d.ts.map +1 -1
- package/dist/ai-dashboards.module.js +66 -3
- package/dist/ai-dashboards.module.js.map +1 -1
- package/dist/public-api.d.ts +1 -1
- package/dist/public-api.d.ts.map +1 -1
- package/dist/public-api.js +1 -1
- package/dist/public-api.js.map +1 -1
- package/package.json +48 -48
- package/dist/__tests__/analytics-resource.test.d.ts +0 -2
- package/dist/__tests__/analytics-resource.test.d.ts.map +0 -1
- package/dist/__tests__/analytics-resource.test.js +0 -181
- package/dist/__tests__/analytics-resource.test.js.map +0 -1
- package/dist/__tests__/dashboards.test.d.ts +0 -2
- package/dist/__tests__/dashboards.test.d.ts.map +0 -1
- package/dist/__tests__/dashboards.test.js +0 -40
- package/dist/__tests__/dashboards.test.js.map +0 -1
- package/dist/__tests__/integration-data-service.test.d.ts +0 -2
- package/dist/__tests__/integration-data-service.test.d.ts.map +0 -1
- package/dist/__tests__/integration-data-service.test.js +0 -132
- package/dist/__tests__/integration-data-service.test.js.map +0 -1
- package/dist/__tests__/mapping-validation.test.d.ts +0 -2
- package/dist/__tests__/mapping-validation.test.d.ts.map +0 -1
- package/dist/__tests__/mapping-validation.test.js +0 -170
- package/dist/__tests__/mapping-validation.test.js.map +0 -1
- package/dist/__tests__/scheduling.test.d.ts +0 -2
- package/dist/__tests__/scheduling.test.d.ts.map +0 -1
- package/dist/__tests__/scheduling.test.js +0 -205
- package/dist/__tests__/scheduling.test.js.map +0 -1
|
@@ -0,0 +1,490 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fileoverview Error Analysis -- Basic.
|
|
3
|
+
*
|
|
4
|
+
* Displays error summary cards, and errors grouped by source (Prompt+Model combination).
|
|
5
|
+
* Each group can be expanded to show individual error details.
|
|
6
|
+
* Data loaded from MJ: AI Prompt Runs where Success=false.
|
|
7
|
+
*/
|
|
8
|
+
import { Component, Input, ChangeDetectorRef, inject } from '@angular/core';
|
|
9
|
+
import { Subject } from 'rxjs';
|
|
10
|
+
import { RunView } from '@memberjunction/core';
|
|
11
|
+
import * as i0 from "@angular/core";
|
|
12
|
+
import * as i1 from "@memberjunction/ng-shared-generic";
|
|
13
|
+
import * as i2 from "../analytics-filter-bar.component";
|
|
14
|
+
import * as i3 from "@angular/common";
|
|
15
|
+
const _forTrack0 = ($index, $item) => $item.Source;
|
|
16
|
+
const _forTrack1 = ($index, $item) => $item.ID;
|
|
17
|
+
function AnalyticsErrorAnalysisComponent_Conditional_1_Template(rf, ctx) { if (rf & 1) {
|
|
18
|
+
i0.ɵɵelementStart(0, "div", 1);
|
|
19
|
+
i0.ɵɵelement(1, "mj-loading", 2);
|
|
20
|
+
i0.ɵɵelementEnd();
|
|
21
|
+
} }
|
|
22
|
+
function AnalyticsErrorAnalysisComponent_Conditional_2_Conditional_27_Template(rf, ctx) { if (rf & 1) {
|
|
23
|
+
i0.ɵɵelementStart(0, "div", 16);
|
|
24
|
+
i0.ɵɵelement(1, "i", 18);
|
|
25
|
+
i0.ɵɵelementStart(2, "div", 19);
|
|
26
|
+
i0.ɵɵtext(3, "No Errors Found");
|
|
27
|
+
i0.ɵɵelementEnd();
|
|
28
|
+
i0.ɵɵelementStart(4, "div", 20);
|
|
29
|
+
i0.ɵɵtext(5, "No errors detected in the selected time range.");
|
|
30
|
+
i0.ɵɵelementEnd()();
|
|
31
|
+
} }
|
|
32
|
+
function AnalyticsErrorAnalysisComponent_Conditional_2_For_29_Conditional_19_Template(rf, ctx) { if (rf & 1) {
|
|
33
|
+
i0.ɵɵelementStart(0, "div", 34)(1, "span", 36);
|
|
34
|
+
i0.ɵɵtext(2, "Last error:");
|
|
35
|
+
i0.ɵɵelementEnd();
|
|
36
|
+
i0.ɵɵtext(3);
|
|
37
|
+
i0.ɵɵelementEnd();
|
|
38
|
+
} if (rf & 2) {
|
|
39
|
+
const group_r2 = i0.ɵɵnextContext().$implicit;
|
|
40
|
+
i0.ɵɵadvance(3);
|
|
41
|
+
i0.ɵɵtextInterpolate1(" ", group_r2.LastErrorMessage, " ");
|
|
42
|
+
} }
|
|
43
|
+
function AnalyticsErrorAnalysisComponent_Conditional_2_For_29_Conditional_20_For_2_Conditional_4_Template(rf, ctx) { if (rf & 1) {
|
|
44
|
+
i0.ɵɵelementStart(0, "span", 40);
|
|
45
|
+
i0.ɵɵtext(1);
|
|
46
|
+
i0.ɵɵelementEnd();
|
|
47
|
+
} if (rf & 2) {
|
|
48
|
+
const err_r4 = i0.ɵɵnextContext().$implicit;
|
|
49
|
+
i0.ɵɵadvance();
|
|
50
|
+
i0.ɵɵtextInterpolate(err_r4.Duration);
|
|
51
|
+
} }
|
|
52
|
+
function AnalyticsErrorAnalysisComponent_Conditional_2_For_29_Conditional_20_For_2_Template(rf, ctx) { if (rf & 1) {
|
|
53
|
+
i0.ɵɵelementStart(0, "div", 37)(1, "div", 38)(2, "span", 39);
|
|
54
|
+
i0.ɵɵtext(3);
|
|
55
|
+
i0.ɵɵelementEnd();
|
|
56
|
+
i0.ɵɵconditionalCreate(4, AnalyticsErrorAnalysisComponent_Conditional_2_For_29_Conditional_20_For_2_Conditional_4_Template, 2, 1, "span", 40);
|
|
57
|
+
i0.ɵɵelementEnd();
|
|
58
|
+
i0.ɵɵelementStart(5, "div", 41);
|
|
59
|
+
i0.ɵɵtext(6);
|
|
60
|
+
i0.ɵɵelementEnd()();
|
|
61
|
+
} if (rf & 2) {
|
|
62
|
+
const err_r4 = ctx.$implicit;
|
|
63
|
+
i0.ɵɵadvance(3);
|
|
64
|
+
i0.ɵɵtextInterpolate(err_r4.Time);
|
|
65
|
+
i0.ɵɵadvance();
|
|
66
|
+
i0.ɵɵconditional(err_r4.Duration ? 4 : -1);
|
|
67
|
+
i0.ɵɵadvance(2);
|
|
68
|
+
i0.ɵɵtextInterpolate(err_r4.ErrorMessage);
|
|
69
|
+
} }
|
|
70
|
+
function AnalyticsErrorAnalysisComponent_Conditional_2_For_29_Conditional_20_Template(rf, ctx) { if (rf & 1) {
|
|
71
|
+
i0.ɵɵelementStart(0, "div", 35);
|
|
72
|
+
i0.ɵɵrepeaterCreate(1, AnalyticsErrorAnalysisComponent_Conditional_2_For_29_Conditional_20_For_2_Template, 7, 3, "div", 37, _forTrack1);
|
|
73
|
+
i0.ɵɵelementEnd();
|
|
74
|
+
} if (rf & 2) {
|
|
75
|
+
const group_r2 = i0.ɵɵnextContext().$implicit;
|
|
76
|
+
i0.ɵɵadvance();
|
|
77
|
+
i0.ɵɵrepeater(group_r2.Errors);
|
|
78
|
+
} }
|
|
79
|
+
function AnalyticsErrorAnalysisComponent_Conditional_2_For_29_Template(rf, ctx) { if (rf & 1) {
|
|
80
|
+
const _r1 = i0.ɵɵgetCurrentView();
|
|
81
|
+
i0.ɵɵelementStart(0, "div", 21)(1, "div", 22);
|
|
82
|
+
i0.ɵɵlistener("click", function AnalyticsErrorAnalysisComponent_Conditional_2_For_29_Template_div_click_1_listener() { const group_r2 = i0.ɵɵrestoreView(_r1).$implicit; const ctx_r2 = i0.ɵɵnextContext(2); return i0.ɵɵresetView(ctx_r2.ToggleGroup(group_r2)); })("keydown.enter", function AnalyticsErrorAnalysisComponent_Conditional_2_For_29_Template_div_keydown_enter_1_listener() { const group_r2 = i0.ɵɵrestoreView(_r1).$implicit; const ctx_r2 = i0.ɵɵnextContext(2); return i0.ɵɵresetView(ctx_r2.ToggleGroup(group_r2)); });
|
|
83
|
+
i0.ɵɵelementStart(2, "div", 23);
|
|
84
|
+
i0.ɵɵelement(3, "i", 24);
|
|
85
|
+
i0.ɵɵelementStart(4, "div", 25)(5, "div", 26);
|
|
86
|
+
i0.ɵɵtext(6);
|
|
87
|
+
i0.ɵɵelementEnd();
|
|
88
|
+
i0.ɵɵelementStart(7, "div", 27)(8, "span", 28);
|
|
89
|
+
i0.ɵɵtext(9);
|
|
90
|
+
i0.ɵɵelementEnd();
|
|
91
|
+
i0.ɵɵelementStart(10, "span", 29);
|
|
92
|
+
i0.ɵɵtext(11, "+");
|
|
93
|
+
i0.ɵɵelementEnd();
|
|
94
|
+
i0.ɵɵelementStart(12, "span", 30);
|
|
95
|
+
i0.ɵɵtext(13);
|
|
96
|
+
i0.ɵɵelementEnd()()()();
|
|
97
|
+
i0.ɵɵelementStart(14, "div", 31)(15, "span", 32);
|
|
98
|
+
i0.ɵɵtext(16);
|
|
99
|
+
i0.ɵɵelementEnd();
|
|
100
|
+
i0.ɵɵelementStart(17, "div", 33);
|
|
101
|
+
i0.ɵɵtext(18);
|
|
102
|
+
i0.ɵɵelementEnd()()();
|
|
103
|
+
i0.ɵɵconditionalCreate(19, AnalyticsErrorAnalysisComponent_Conditional_2_For_29_Conditional_19_Template, 4, 1, "div", 34);
|
|
104
|
+
i0.ɵɵconditionalCreate(20, AnalyticsErrorAnalysisComponent_Conditional_2_For_29_Conditional_20_Template, 3, 0, "div", 35);
|
|
105
|
+
i0.ɵɵelementEnd();
|
|
106
|
+
} if (rf & 2) {
|
|
107
|
+
const group_r2 = ctx.$implicit;
|
|
108
|
+
i0.ɵɵclassProp("error-group--expanded", group_r2.IsExpanded);
|
|
109
|
+
i0.ɵɵadvance(3);
|
|
110
|
+
i0.ɵɵclassMap(group_r2.IsExpanded ? "fa-solid fa-chevron-down" : "fa-solid fa-chevron-right");
|
|
111
|
+
i0.ɵɵadvance(3);
|
|
112
|
+
i0.ɵɵtextInterpolate(group_r2.Source);
|
|
113
|
+
i0.ɵɵadvance(3);
|
|
114
|
+
i0.ɵɵtextInterpolate(group_r2.PromptName);
|
|
115
|
+
i0.ɵɵadvance(4);
|
|
116
|
+
i0.ɵɵtextInterpolate(group_r2.ModelName);
|
|
117
|
+
i0.ɵɵadvance(3);
|
|
118
|
+
i0.ɵɵtextInterpolate(group_r2.Count);
|
|
119
|
+
i0.ɵɵadvance(2);
|
|
120
|
+
i0.ɵɵtextInterpolate(group_r2.LastErrorTime);
|
|
121
|
+
i0.ɵɵadvance();
|
|
122
|
+
i0.ɵɵconditional(!group_r2.IsExpanded ? 19 : -1);
|
|
123
|
+
i0.ɵɵadvance();
|
|
124
|
+
i0.ɵɵconditional(group_r2.IsExpanded ? 20 : -1);
|
|
125
|
+
} }
|
|
126
|
+
function AnalyticsErrorAnalysisComponent_Conditional_2_Template(rf, ctx) { if (rf & 1) {
|
|
127
|
+
i0.ɵɵelementStart(0, "div", 3)(1, "div", 4)(2, "div", 5);
|
|
128
|
+
i0.ɵɵelement(3, "i", 6);
|
|
129
|
+
i0.ɵɵelementEnd();
|
|
130
|
+
i0.ɵɵelementStart(4, "div", 7)(5, "div", 8);
|
|
131
|
+
i0.ɵɵtext(6, "Total Errors");
|
|
132
|
+
i0.ɵɵelementEnd();
|
|
133
|
+
i0.ɵɵelementStart(7, "div", 9);
|
|
134
|
+
i0.ɵɵtext(8);
|
|
135
|
+
i0.ɵɵpipe(9, "number");
|
|
136
|
+
i0.ɵɵelementEnd()()();
|
|
137
|
+
i0.ɵɵelementStart(10, "div", 10)(11, "div", 11);
|
|
138
|
+
i0.ɵɵelement(12, "i", 12);
|
|
139
|
+
i0.ɵɵelementEnd();
|
|
140
|
+
i0.ɵɵelementStart(13, "div", 7)(14, "div", 8);
|
|
141
|
+
i0.ɵɵtext(15, "Error Rate");
|
|
142
|
+
i0.ɵɵelementEnd();
|
|
143
|
+
i0.ɵɵelementStart(16, "div", 9);
|
|
144
|
+
i0.ɵɵtext(17);
|
|
145
|
+
i0.ɵɵpipe(18, "number");
|
|
146
|
+
i0.ɵɵelementEnd()()();
|
|
147
|
+
i0.ɵɵelementStart(19, "div", 10)(20, "div", 13);
|
|
148
|
+
i0.ɵɵelement(21, "i", 14);
|
|
149
|
+
i0.ɵɵelementEnd();
|
|
150
|
+
i0.ɵɵelementStart(22, "div", 7)(23, "div", 8);
|
|
151
|
+
i0.ɵɵtext(24, "Most Common");
|
|
152
|
+
i0.ɵɵelementEnd();
|
|
153
|
+
i0.ɵɵelementStart(25, "div", 15);
|
|
154
|
+
i0.ɵɵtext(26);
|
|
155
|
+
i0.ɵɵelementEnd()()()();
|
|
156
|
+
i0.ɵɵconditionalCreate(27, AnalyticsErrorAnalysisComponent_Conditional_2_Conditional_27_Template, 6, 0, "div", 16);
|
|
157
|
+
i0.ɵɵrepeaterCreate(28, AnalyticsErrorAnalysisComponent_Conditional_2_For_29_Template, 21, 11, "div", 17, _forTrack0);
|
|
158
|
+
} if (rf & 2) {
|
|
159
|
+
const ctx_r2 = i0.ɵɵnextContext();
|
|
160
|
+
i0.ɵɵadvance(8);
|
|
161
|
+
i0.ɵɵtextInterpolate(i0.ɵɵpipeBind1(9, 5, ctx_r2.Summary.TotalErrors));
|
|
162
|
+
i0.ɵɵadvance(9);
|
|
163
|
+
i0.ɵɵtextInterpolate1("", i0.ɵɵpipeBind2(18, 7, ctx_r2.Summary.ErrorRate, "1.1-1"), "%");
|
|
164
|
+
i0.ɵɵadvance(8);
|
|
165
|
+
i0.ɵɵproperty("title", ctx_r2.Summary.MostCommonError);
|
|
166
|
+
i0.ɵɵadvance();
|
|
167
|
+
i0.ɵɵtextInterpolate1(" ", ctx_r2.Summary.MostCommonError || "N/A", " ");
|
|
168
|
+
i0.ɵɵadvance();
|
|
169
|
+
i0.ɵɵconditional(ctx_r2.ErrorGroups.length === 0 ? 27 : -1);
|
|
170
|
+
i0.ɵɵadvance();
|
|
171
|
+
i0.ɵɵrepeater(ctx_r2.ErrorGroups);
|
|
172
|
+
} }
|
|
173
|
+
const FIELDS = [
|
|
174
|
+
'ID', 'RunAt', 'ErrorMessage', 'Model', 'Prompt',
|
|
175
|
+
'Vendor', 'ExecutionTimeMS', 'Status'
|
|
176
|
+
];
|
|
177
|
+
export class AnalyticsErrorAnalysisComponent {
|
|
178
|
+
TimeRange = '7d';
|
|
179
|
+
Filters = { Models: [], Agents: [], Prompts: [], Statuses: [] };
|
|
180
|
+
cdr = inject(ChangeDetectorRef);
|
|
181
|
+
destroy$ = new Subject();
|
|
182
|
+
IsLoading = false;
|
|
183
|
+
Summary = {
|
|
184
|
+
TotalErrors: 0,
|
|
185
|
+
ErrorRate: 0,
|
|
186
|
+
MostCommonError: ''
|
|
187
|
+
};
|
|
188
|
+
ErrorGroups = [];
|
|
189
|
+
failedRuns = [];
|
|
190
|
+
totalRunCount = 0;
|
|
191
|
+
ngOnInit() {
|
|
192
|
+
this.LoadData();
|
|
193
|
+
}
|
|
194
|
+
ngOnDestroy() {
|
|
195
|
+
this.destroy$.next();
|
|
196
|
+
this.destroy$.complete();
|
|
197
|
+
}
|
|
198
|
+
// ── Public Handlers ──
|
|
199
|
+
OnTimeRangeChange(range) {
|
|
200
|
+
this.TimeRange = range;
|
|
201
|
+
this.LoadData();
|
|
202
|
+
}
|
|
203
|
+
OnFiltersChange(filters) {
|
|
204
|
+
this.Filters = filters;
|
|
205
|
+
this.LoadData();
|
|
206
|
+
}
|
|
207
|
+
ToggleGroup(group) {
|
|
208
|
+
group.IsExpanded = !group.IsExpanded;
|
|
209
|
+
this.cdr.detectChanges();
|
|
210
|
+
}
|
|
211
|
+
// ── Data Loading ──
|
|
212
|
+
async LoadData() {
|
|
213
|
+
this.IsLoading = true;
|
|
214
|
+
this.cdr.detectChanges();
|
|
215
|
+
try {
|
|
216
|
+
const rv = new RunView();
|
|
217
|
+
const dateFilter = this.buildDateFilter();
|
|
218
|
+
const extraFilters = this.buildExtraFilters();
|
|
219
|
+
const baseFilter = [dateFilter, ...extraFilters].filter(Boolean).join(' AND ');
|
|
220
|
+
const errorFilter = baseFilter + ' AND Success = 0';
|
|
221
|
+
const [errorResult, totalResult] = await rv.RunViews([
|
|
222
|
+
{
|
|
223
|
+
EntityName: 'MJ: AI Prompt Runs',
|
|
224
|
+
ExtraFilter: errorFilter,
|
|
225
|
+
Fields: FIELDS,
|
|
226
|
+
OrderBy: 'RunAt DESC',
|
|
227
|
+
ResultType: 'simple'
|
|
228
|
+
},
|
|
229
|
+
{
|
|
230
|
+
EntityName: 'MJ: AI Prompt Runs',
|
|
231
|
+
ExtraFilter: baseFilter,
|
|
232
|
+
Fields: ['ID'],
|
|
233
|
+
ResultType: 'simple'
|
|
234
|
+
}
|
|
235
|
+
]);
|
|
236
|
+
this.failedRuns = (errorResult?.Results ?? []);
|
|
237
|
+
this.totalRunCount = totalResult?.Results?.length ?? 0;
|
|
238
|
+
this.computeSummary();
|
|
239
|
+
this.buildErrorGroups();
|
|
240
|
+
}
|
|
241
|
+
catch (e) {
|
|
242
|
+
console.error('Error Analysis load error:', e);
|
|
243
|
+
}
|
|
244
|
+
finally {
|
|
245
|
+
this.IsLoading = false;
|
|
246
|
+
this.cdr.detectChanges();
|
|
247
|
+
}
|
|
248
|
+
}
|
|
249
|
+
// ── Computations ──
|
|
250
|
+
computeSummary() {
|
|
251
|
+
const errorCount = this.failedRuns.length;
|
|
252
|
+
const errorRate = this.totalRunCount > 0 ? (errorCount / this.totalRunCount) * 100 : 0;
|
|
253
|
+
// Find most common error by grouping error messages
|
|
254
|
+
const messageCounts = new Map();
|
|
255
|
+
for (const run of this.failedRuns) {
|
|
256
|
+
const msg = this.normalizeErrorMessage(run.ErrorMessage ?? 'Unknown error');
|
|
257
|
+
messageCounts.set(msg, (messageCounts.get(msg) ?? 0) + 1);
|
|
258
|
+
}
|
|
259
|
+
let mostCommon = '';
|
|
260
|
+
let maxCount = 0;
|
|
261
|
+
for (const [msg, count] of messageCounts) {
|
|
262
|
+
if (count > maxCount) {
|
|
263
|
+
maxCount = count;
|
|
264
|
+
mostCommon = msg;
|
|
265
|
+
}
|
|
266
|
+
}
|
|
267
|
+
this.Summary = {
|
|
268
|
+
TotalErrors: errorCount,
|
|
269
|
+
ErrorRate: errorRate,
|
|
270
|
+
MostCommonError: mostCommon
|
|
271
|
+
};
|
|
272
|
+
}
|
|
273
|
+
buildErrorGroups() {
|
|
274
|
+
const groups = new Map();
|
|
275
|
+
for (const run of this.failedRuns) {
|
|
276
|
+
const prompt = run.Prompt ?? 'Unknown Prompt';
|
|
277
|
+
const model = run.Model ?? 'Unknown Model';
|
|
278
|
+
const key = prompt + ' + ' + model;
|
|
279
|
+
if (!groups.has(key))
|
|
280
|
+
groups.set(key, []);
|
|
281
|
+
groups.get(key).push(run);
|
|
282
|
+
}
|
|
283
|
+
this.ErrorGroups = Array.from(groups.entries())
|
|
284
|
+
.map(([source, runs]) => {
|
|
285
|
+
const sortedRuns = runs.sort((a, b) => new Date(b.RunAt).getTime() - new Date(a.RunAt).getTime());
|
|
286
|
+
return {
|
|
287
|
+
Source: source,
|
|
288
|
+
PromptName: sortedRuns[0].Prompt ?? 'Unknown',
|
|
289
|
+
ModelName: sortedRuns[0].Model ?? 'Unknown',
|
|
290
|
+
Count: sortedRuns.length,
|
|
291
|
+
LastErrorMessage: this.truncateMessage(sortedRuns[0].ErrorMessage ?? 'No message'),
|
|
292
|
+
LastErrorTime: this.formatRelativeTime(sortedRuns[0].RunAt),
|
|
293
|
+
IsExpanded: false,
|
|
294
|
+
Errors: sortedRuns.slice(0, 20).map(r => ({
|
|
295
|
+
ID: r.ID,
|
|
296
|
+
Time: this.formatDateTime(r.RunAt),
|
|
297
|
+
ErrorMessage: r.ErrorMessage ?? 'No error message',
|
|
298
|
+
Duration: r.ExecutionTimeMS != null ? r.ExecutionTimeMS + 'ms' : ''
|
|
299
|
+
}))
|
|
300
|
+
};
|
|
301
|
+
})
|
|
302
|
+
.sort((a, b) => b.Count - a.Count);
|
|
303
|
+
}
|
|
304
|
+
// ── Helpers ──
|
|
305
|
+
buildDateFilter() {
|
|
306
|
+
const now = new Date();
|
|
307
|
+
const msMap = {
|
|
308
|
+
'1h': 3600000, '6h': 21600000, '24h': 86400000,
|
|
309
|
+
'7d': 604800000, '30d': 2592000000
|
|
310
|
+
};
|
|
311
|
+
const ms = msMap[this.TimeRange] ?? 604800000;
|
|
312
|
+
const start = new Date(now.getTime() - ms);
|
|
313
|
+
return `RunAt >= '${start.toISOString()}'`;
|
|
314
|
+
}
|
|
315
|
+
buildExtraFilters() {
|
|
316
|
+
const filters = [];
|
|
317
|
+
if (this.Filters.Models.length > 0) {
|
|
318
|
+
filters.push(`ModelID IN (${this.Filters.Models.map(id => `'${id}'`).join(',')})`);
|
|
319
|
+
}
|
|
320
|
+
if (this.Filters.Prompts.length > 0) {
|
|
321
|
+
filters.push(`PromptID IN (${this.Filters.Prompts.map(id => `'${id}'`).join(',')})`);
|
|
322
|
+
}
|
|
323
|
+
return filters;
|
|
324
|
+
}
|
|
325
|
+
normalizeErrorMessage(msg) {
|
|
326
|
+
// Truncate and normalize for grouping
|
|
327
|
+
return msg.slice(0, 100).trim().toLowerCase();
|
|
328
|
+
}
|
|
329
|
+
truncateMessage(msg) {
|
|
330
|
+
if (msg.length <= 120)
|
|
331
|
+
return msg;
|
|
332
|
+
return msg.slice(0, 120) + '...';
|
|
333
|
+
}
|
|
334
|
+
formatRelativeTime(dateStr) {
|
|
335
|
+
const now = Date.now();
|
|
336
|
+
const then = new Date(dateStr).getTime();
|
|
337
|
+
const diffMin = Math.floor((now - then) / 60000);
|
|
338
|
+
if (diffMin < 1)
|
|
339
|
+
return 'just now';
|
|
340
|
+
if (diffMin < 60)
|
|
341
|
+
return diffMin + 'm ago';
|
|
342
|
+
const diffHr = Math.floor(diffMin / 60);
|
|
343
|
+
if (diffHr < 24)
|
|
344
|
+
return diffHr + 'h ago';
|
|
345
|
+
const diffDay = Math.floor(diffHr / 24);
|
|
346
|
+
return diffDay + 'd ago';
|
|
347
|
+
}
|
|
348
|
+
formatDateTime(dateStr) {
|
|
349
|
+
const d = new Date(dateStr);
|
|
350
|
+
const months = ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'];
|
|
351
|
+
const hh = d.getHours().toString().padStart(2, '0');
|
|
352
|
+
const mm = d.getMinutes().toString().padStart(2, '0');
|
|
353
|
+
return `${months[d.getMonth()]} ${d.getDate()} ${hh}:${mm}`;
|
|
354
|
+
}
|
|
355
|
+
static ɵfac = function AnalyticsErrorAnalysisComponent_Factory(__ngFactoryType__) { return new (__ngFactoryType__ || AnalyticsErrorAnalysisComponent)(); };
|
|
356
|
+
static ɵcmp = /*@__PURE__*/ i0.ɵɵdefineComponent({ type: AnalyticsErrorAnalysisComponent, selectors: [["app-analytics-error-analysis"]], inputs: { TimeRange: "TimeRange", Filters: "Filters" }, standalone: false, decls: 3, vars: 9, consts: [[3, "TimeRangeChange", "FiltersChange", "TimeRange", "Filters", "ShowAgentFilter", "ShowPromptFilter", "ShowModelFilter", "ShowStatusFilter", "ShowCompareToggle", "ShowExportButton"], [1, "loading-container"], ["text", "Loading error data..."], [1, "summary-row"], [1, "summary-card", "summary-card--error"], [1, "summary-icon"], [1, "fa-solid", "fa-circle-exclamation"], [1, "summary-content"], [1, "summary-label"], [1, "summary-value"], [1, "summary-card"], [1, "summary-icon", "summary-icon--warning"], [1, "fa-solid", "fa-percentage"], [1, "summary-icon", "summary-icon--info"], [1, "fa-solid", "fa-bug"], [1, "summary-value", "summary-value--text", 3, "title"], [1, "empty-state"], [1, "error-group", 3, "error-group--expanded"], [1, "fa-solid", "fa-check-circle", "empty-state__icon"], [1, "empty-state__title"], [1, "empty-state__subtitle"], [1, "error-group"], ["role", "button", "tabindex", "0", 1, "error-group__header", 3, "click", "keydown.enter"], [1, "error-group__left"], [1, "expand-icon"], [1, "error-group__source"], [1, "source-name"], [1, "source-details"], [1, "source-prompt"], [1, "source-separator"], [1, "source-model"], [1, "error-group__right"], [1, "error-count-badge"], [1, "last-error-time"], [1, "error-group__preview"], [1, "error-group__body"], [1, "preview-label"], [1, "error-detail"], [1, "error-detail__header"], [1, "error-detail__time"], [1, "error-detail__duration"], [1, "error-detail__message"]], template: function AnalyticsErrorAnalysisComponent_Template(rf, ctx) { if (rf & 1) {
|
|
357
|
+
i0.ɵɵelementStart(0, "app-analytics-filter-bar", 0);
|
|
358
|
+
i0.ɵɵlistener("TimeRangeChange", function AnalyticsErrorAnalysisComponent_Template_app_analytics_filter_bar_TimeRangeChange_0_listener($event) { return ctx.OnTimeRangeChange($event); })("FiltersChange", function AnalyticsErrorAnalysisComponent_Template_app_analytics_filter_bar_FiltersChange_0_listener($event) { return ctx.OnFiltersChange($event); });
|
|
359
|
+
i0.ɵɵelementEnd();
|
|
360
|
+
i0.ɵɵconditionalCreate(1, AnalyticsErrorAnalysisComponent_Conditional_1_Template, 2, 0, "div", 1)(2, AnalyticsErrorAnalysisComponent_Conditional_2_Template, 30, 10);
|
|
361
|
+
} if (rf & 2) {
|
|
362
|
+
i0.ɵɵproperty("TimeRange", ctx.TimeRange)("Filters", ctx.Filters)("ShowAgentFilter", false)("ShowPromptFilter", true)("ShowModelFilter", true)("ShowStatusFilter", false)("ShowCompareToggle", false)("ShowExportButton", false);
|
|
363
|
+
i0.ɵɵadvance();
|
|
364
|
+
i0.ɵɵconditional(ctx.IsLoading ? 1 : 2);
|
|
365
|
+
} }, dependencies: [i1.LoadingComponent, i2.AnalyticsFilterBarComponent, i3.DecimalPipe], styles: ["[_nghost-%COMP%] { display: block; }\n\n .loading-container[_ngcontent-%COMP%] {\n display: flex;\n justify-content: center;\n align-items: center;\n min-height: 300px;\n }\n\n \n\n .summary-row[_ngcontent-%COMP%] {\n display: grid;\n grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));\n gap: 12px;\n margin: 16px 0;\n }\n\n .summary-card[_ngcontent-%COMP%] {\n background: var(--mj-bg-surface);\n border: 1px solid var(--mj-border-default);\n border-radius: 10px;\n padding: 16px;\n display: flex;\n align-items: center;\n gap: 14px;\n }\n\n .summary-card--error[_ngcontent-%COMP%] {\n border-left: 4px solid var(--mj-status-error);\n }\n\n .summary-icon[_ngcontent-%COMP%] {\n width: 40px;\n height: 40px;\n border-radius: 10px;\n display: flex;\n align-items: center;\n justify-content: center;\n background: color-mix(in srgb, var(--mj-status-error) 12%, var(--mj-bg-surface));\n color: var(--mj-status-error);\n font-size: 16px;\n flex-shrink: 0;\n }\n\n .summary-icon--warning[_ngcontent-%COMP%] {\n background: color-mix(in srgb, var(--mj-status-warning) 12%, var(--mj-bg-surface));\n color: var(--mj-status-warning);\n }\n\n .summary-icon--info[_ngcontent-%COMP%] {\n background: color-mix(in srgb, var(--mj-brand-primary) 12%, var(--mj-bg-surface));\n color: var(--mj-brand-primary);\n }\n\n .summary-label[_ngcontent-%COMP%] {\n font-size: 11px;\n font-weight: 600;\n color: var(--mj-text-muted);\n text-transform: uppercase;\n letter-spacing: 0.5px;\n }\n\n .summary-value[_ngcontent-%COMP%] {\n font-size: 22px;\n font-weight: 700;\n color: var(--mj-text-primary);\n letter-spacing: -0.02em;\n }\n\n .summary-value--text[_ngcontent-%COMP%] {\n font-size: 13px;\n font-weight: 500;\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n max-width: 220px;\n }\n\n \n\n .empty-state[_ngcontent-%COMP%] {\n text-align: center;\n padding: 48px 24px;\n color: var(--mj-text-muted);\n }\n\n .empty-state__icon[_ngcontent-%COMP%] {\n font-size: 40px;\n color: var(--mj-status-success);\n margin-bottom: 12px;\n }\n\n .empty-state__title[_ngcontent-%COMP%] {\n font-size: 16px;\n font-weight: 600;\n color: var(--mj-text-primary);\n margin-bottom: 4px;\n }\n\n .empty-state__subtitle[_ngcontent-%COMP%] {\n font-size: 13px;\n color: var(--mj-text-muted);\n }\n\n \n\n .error-group[_ngcontent-%COMP%] {\n background: var(--mj-bg-surface);\n border: 1px solid var(--mj-border-default);\n border-radius: 10px;\n margin-bottom: 8px;\n overflow: hidden;\n transition: border-color 0.2s;\n }\n\n .error-group--expanded[_ngcontent-%COMP%] {\n border-color: var(--mj-status-error);\n }\n\n .error-group__header[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n justify-content: space-between;\n padding: 14px 16px;\n cursor: pointer;\n transition: background 0.15s;\n }\n\n .error-group__header[_ngcontent-%COMP%]:hover {\n background: var(--mj-bg-surface-hover);\n }\n\n .error-group__left[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n gap: 10px;\n min-width: 0;\n }\n\n .expand-icon[_ngcontent-%COMP%] {\n font-size: 11px;\n color: var(--mj-text-muted);\n width: 16px;\n flex-shrink: 0;\n transition: transform 0.2s;\n }\n\n .error-group__source[_ngcontent-%COMP%] {\n min-width: 0;\n }\n\n .source-name[_ngcontent-%COMP%] {\n font-size: 14px;\n font-weight: 600;\n color: var(--mj-text-primary);\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n }\n\n .source-details[_ngcontent-%COMP%] {\n font-size: 12px;\n color: var(--mj-text-muted);\n display: flex;\n align-items: center;\n gap: 4px;\n margin-top: 2px;\n }\n\n .source-separator[_ngcontent-%COMP%] {\n color: var(--mj-text-disabled);\n }\n\n .error-group__right[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n gap: 12px;\n flex-shrink: 0;\n }\n\n .error-count-badge[_ngcontent-%COMP%] {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n min-width: 28px;\n height: 24px;\n padding: 0 8px;\n border-radius: 12px;\n background: color-mix(in srgb, var(--mj-status-error) 12%, var(--mj-bg-surface));\n color: var(--mj-status-error);\n font-size: 12px;\n font-weight: 700;\n }\n\n .last-error-time[_ngcontent-%COMP%] {\n font-size: 12px;\n color: var(--mj-text-disabled);\n white-space: nowrap;\n }\n\n .error-group__preview[_ngcontent-%COMP%] {\n padding: 0 16px 12px 42px;\n font-size: 12px;\n color: var(--mj-text-muted);\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n }\n\n .preview-label[_ngcontent-%COMP%] {\n color: var(--mj-text-disabled);\n margin-right: 4px;\n }\n\n .error-group__body[_ngcontent-%COMP%] {\n border-top: 1px solid var(--mj-border-subtle);\n max-height: 400px;\n overflow-y: auto;\n }\n\n .error-detail[_ngcontent-%COMP%] {\n padding: 12px 16px 12px 42px;\n border-bottom: 1px solid var(--mj-border-subtle);\n }\n\n .error-detail[_ngcontent-%COMP%]:last-child {\n border-bottom: none;\n }\n\n .error-detail__header[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n gap: 10px;\n margin-bottom: 4px;\n }\n\n .error-detail__time[_ngcontent-%COMP%] {\n font-size: 11px;\n font-weight: 600;\n color: var(--mj-text-muted);\n }\n\n .error-detail__duration[_ngcontent-%COMP%] {\n font-size: 11px;\n color: var(--mj-text-disabled);\n font-variant-numeric: tabular-nums;\n }\n\n .error-detail__message[_ngcontent-%COMP%] {\n font-size: 13px;\n color: var(--mj-status-error-text, var(--mj-status-error));\n line-height: 1.5;\n word-break: break-word;\n font-family: monospace;\n background: color-mix(in srgb, var(--mj-status-error) 5%, var(--mj-bg-surface));\n padding: 8px 10px;\n border-radius: 6px;\n border: 1px solid color-mix(in srgb, var(--mj-status-error) 15%, var(--mj-bg-surface));\n }\n\n \n\n @media (max-width: 768px) {\n .summary-row[_ngcontent-%COMP%] {\n grid-template-columns: 1fr;\n }\n\n .summary-value[_ngcontent-%COMP%] {\n font-size: 18px;\n }\n }"] });
|
|
366
|
+
}
|
|
367
|
+
(() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassMetadata(AnalyticsErrorAnalysisComponent, [{
|
|
368
|
+
type: Component,
|
|
369
|
+
args: [{ standalone: false, selector: 'app-analytics-error-analysis', template: `
|
|
370
|
+
<!-- Filter Bar -->
|
|
371
|
+
<app-analytics-filter-bar
|
|
372
|
+
[TimeRange]="TimeRange"
|
|
373
|
+
[Filters]="Filters"
|
|
374
|
+
[ShowAgentFilter]="false"
|
|
375
|
+
[ShowPromptFilter]="true"
|
|
376
|
+
[ShowModelFilter]="true"
|
|
377
|
+
[ShowStatusFilter]="false"
|
|
378
|
+
[ShowCompareToggle]="false"
|
|
379
|
+
[ShowExportButton]="false"
|
|
380
|
+
(TimeRangeChange)="OnTimeRangeChange($event)"
|
|
381
|
+
(FiltersChange)="OnFiltersChange($event)"
|
|
382
|
+
></app-analytics-filter-bar>
|
|
383
|
+
|
|
384
|
+
@if (IsLoading) {
|
|
385
|
+
<div class="loading-container">
|
|
386
|
+
<mj-loading text="Loading error data..."></mj-loading>
|
|
387
|
+
</div>
|
|
388
|
+
} @else {
|
|
389
|
+
<!-- Summary Cards -->
|
|
390
|
+
<div class="summary-row">
|
|
391
|
+
<div class="summary-card summary-card--error">
|
|
392
|
+
<div class="summary-icon">
|
|
393
|
+
<i class="fa-solid fa-circle-exclamation"></i>
|
|
394
|
+
</div>
|
|
395
|
+
<div class="summary-content">
|
|
396
|
+
<div class="summary-label">Total Errors</div>
|
|
397
|
+
<div class="summary-value">{{ Summary.TotalErrors | number }}</div>
|
|
398
|
+
</div>
|
|
399
|
+
</div>
|
|
400
|
+
<div class="summary-card">
|
|
401
|
+
<div class="summary-icon summary-icon--warning">
|
|
402
|
+
<i class="fa-solid fa-percentage"></i>
|
|
403
|
+
</div>
|
|
404
|
+
<div class="summary-content">
|
|
405
|
+
<div class="summary-label">Error Rate</div>
|
|
406
|
+
<div class="summary-value">{{ Summary.ErrorRate | number:'1.1-1' }}%</div>
|
|
407
|
+
</div>
|
|
408
|
+
</div>
|
|
409
|
+
<div class="summary-card">
|
|
410
|
+
<div class="summary-icon summary-icon--info">
|
|
411
|
+
<i class="fa-solid fa-bug"></i>
|
|
412
|
+
</div>
|
|
413
|
+
<div class="summary-content">
|
|
414
|
+
<div class="summary-label">Most Common</div>
|
|
415
|
+
<div class="summary-value summary-value--text" [title]="Summary.MostCommonError">
|
|
416
|
+
{{ Summary.MostCommonError || 'N/A' }}
|
|
417
|
+
</div>
|
|
418
|
+
</div>
|
|
419
|
+
</div>
|
|
420
|
+
</div>
|
|
421
|
+
|
|
422
|
+
<!-- Error Groups -->
|
|
423
|
+
@if (ErrorGroups.length === 0) {
|
|
424
|
+
<div class="empty-state">
|
|
425
|
+
<i class="fa-solid fa-check-circle empty-state__icon"></i>
|
|
426
|
+
<div class="empty-state__title">No Errors Found</div>
|
|
427
|
+
<div class="empty-state__subtitle">No errors detected in the selected time range.</div>
|
|
428
|
+
</div>
|
|
429
|
+
}
|
|
430
|
+
|
|
431
|
+
@for (group of ErrorGroups; track group.Source) {
|
|
432
|
+
<div class="error-group" [class.error-group--expanded]="group.IsExpanded">
|
|
433
|
+
<div
|
|
434
|
+
class="error-group__header"
|
|
435
|
+
(click)="ToggleGroup(group)"
|
|
436
|
+
role="button"
|
|
437
|
+
tabindex="0"
|
|
438
|
+
(keydown.enter)="ToggleGroup(group)">
|
|
439
|
+
<div class="error-group__left">
|
|
440
|
+
<i [class]="group.IsExpanded ? 'fa-solid fa-chevron-down' : 'fa-solid fa-chevron-right'"
|
|
441
|
+
class="expand-icon"></i>
|
|
442
|
+
<div class="error-group__source">
|
|
443
|
+
<div class="source-name">{{ group.Source }}</div>
|
|
444
|
+
<div class="source-details">
|
|
445
|
+
<span class="source-prompt">{{ group.PromptName }}</span>
|
|
446
|
+
<span class="source-separator">+</span>
|
|
447
|
+
<span class="source-model">{{ group.ModelName }}</span>
|
|
448
|
+
</div>
|
|
449
|
+
</div>
|
|
450
|
+
</div>
|
|
451
|
+
<div class="error-group__right">
|
|
452
|
+
<span class="error-count-badge">{{ group.Count }}</span>
|
|
453
|
+
<div class="last-error-time">{{ group.LastErrorTime }}</div>
|
|
454
|
+
</div>
|
|
455
|
+
</div>
|
|
456
|
+
|
|
457
|
+
@if (!group.IsExpanded) {
|
|
458
|
+
<div class="error-group__preview">
|
|
459
|
+
<span class="preview-label">Last error:</span>
|
|
460
|
+
{{ group.LastErrorMessage }}
|
|
461
|
+
</div>
|
|
462
|
+
}
|
|
463
|
+
|
|
464
|
+
@if (group.IsExpanded) {
|
|
465
|
+
<div class="error-group__body">
|
|
466
|
+
@for (err of group.Errors; track err.ID) {
|
|
467
|
+
<div class="error-detail">
|
|
468
|
+
<div class="error-detail__header">
|
|
469
|
+
<span class="error-detail__time">{{ err.Time }}</span>
|
|
470
|
+
@if (err.Duration) {
|
|
471
|
+
<span class="error-detail__duration">{{ err.Duration }}</span>
|
|
472
|
+
}
|
|
473
|
+
</div>
|
|
474
|
+
<div class="error-detail__message">{{ err.ErrorMessage }}</div>
|
|
475
|
+
</div>
|
|
476
|
+
}
|
|
477
|
+
</div>
|
|
478
|
+
}
|
|
479
|
+
</div>
|
|
480
|
+
}
|
|
481
|
+
}
|
|
482
|
+
`, styles: ["\n :host { display: block; }\n\n .loading-container {\n display: flex;\n justify-content: center;\n align-items: center;\n min-height: 300px;\n }\n\n /* \u2500\u2500 Summary Row \u2500\u2500 */\n .summary-row {\n display: grid;\n grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));\n gap: 12px;\n margin: 16px 0;\n }\n\n .summary-card {\n background: var(--mj-bg-surface);\n border: 1px solid var(--mj-border-default);\n border-radius: 10px;\n padding: 16px;\n display: flex;\n align-items: center;\n gap: 14px;\n }\n\n .summary-card--error {\n border-left: 4px solid var(--mj-status-error);\n }\n\n .summary-icon {\n width: 40px;\n height: 40px;\n border-radius: 10px;\n display: flex;\n align-items: center;\n justify-content: center;\n background: color-mix(in srgb, var(--mj-status-error) 12%, var(--mj-bg-surface));\n color: var(--mj-status-error);\n font-size: 16px;\n flex-shrink: 0;\n }\n\n .summary-icon--warning {\n background: color-mix(in srgb, var(--mj-status-warning) 12%, var(--mj-bg-surface));\n color: var(--mj-status-warning);\n }\n\n .summary-icon--info {\n background: color-mix(in srgb, var(--mj-brand-primary) 12%, var(--mj-bg-surface));\n color: var(--mj-brand-primary);\n }\n\n .summary-label {\n font-size: 11px;\n font-weight: 600;\n color: var(--mj-text-muted);\n text-transform: uppercase;\n letter-spacing: 0.5px;\n }\n\n .summary-value {\n font-size: 22px;\n font-weight: 700;\n color: var(--mj-text-primary);\n letter-spacing: -0.02em;\n }\n\n .summary-value--text {\n font-size: 13px;\n font-weight: 500;\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n max-width: 220px;\n }\n\n /* \u2500\u2500 Empty State \u2500\u2500 */\n .empty-state {\n text-align: center;\n padding: 48px 24px;\n color: var(--mj-text-muted);\n }\n\n .empty-state__icon {\n font-size: 40px;\n color: var(--mj-status-success);\n margin-bottom: 12px;\n }\n\n .empty-state__title {\n font-size: 16px;\n font-weight: 600;\n color: var(--mj-text-primary);\n margin-bottom: 4px;\n }\n\n .empty-state__subtitle {\n font-size: 13px;\n color: var(--mj-text-muted);\n }\n\n /* \u2500\u2500 Error Groups \u2500\u2500 */\n .error-group {\n background: var(--mj-bg-surface);\n border: 1px solid var(--mj-border-default);\n border-radius: 10px;\n margin-bottom: 8px;\n overflow: hidden;\n transition: border-color 0.2s;\n }\n\n .error-group--expanded {\n border-color: var(--mj-status-error);\n }\n\n .error-group__header {\n display: flex;\n align-items: center;\n justify-content: space-between;\n padding: 14px 16px;\n cursor: pointer;\n transition: background 0.15s;\n }\n\n .error-group__header:hover {\n background: var(--mj-bg-surface-hover);\n }\n\n .error-group__left {\n display: flex;\n align-items: center;\n gap: 10px;\n min-width: 0;\n }\n\n .expand-icon {\n font-size: 11px;\n color: var(--mj-text-muted);\n width: 16px;\n flex-shrink: 0;\n transition: transform 0.2s;\n }\n\n .error-group__source {\n min-width: 0;\n }\n\n .source-name {\n font-size: 14px;\n font-weight: 600;\n color: var(--mj-text-primary);\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n }\n\n .source-details {\n font-size: 12px;\n color: var(--mj-text-muted);\n display: flex;\n align-items: center;\n gap: 4px;\n margin-top: 2px;\n }\n\n .source-separator {\n color: var(--mj-text-disabled);\n }\n\n .error-group__right {\n display: flex;\n align-items: center;\n gap: 12px;\n flex-shrink: 0;\n }\n\n .error-count-badge {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n min-width: 28px;\n height: 24px;\n padding: 0 8px;\n border-radius: 12px;\n background: color-mix(in srgb, var(--mj-status-error) 12%, var(--mj-bg-surface));\n color: var(--mj-status-error);\n font-size: 12px;\n font-weight: 700;\n }\n\n .last-error-time {\n font-size: 12px;\n color: var(--mj-text-disabled);\n white-space: nowrap;\n }\n\n .error-group__preview {\n padding: 0 16px 12px 42px;\n font-size: 12px;\n color: var(--mj-text-muted);\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n }\n\n .preview-label {\n color: var(--mj-text-disabled);\n margin-right: 4px;\n }\n\n .error-group__body {\n border-top: 1px solid var(--mj-border-subtle);\n max-height: 400px;\n overflow-y: auto;\n }\n\n .error-detail {\n padding: 12px 16px 12px 42px;\n border-bottom: 1px solid var(--mj-border-subtle);\n }\n\n .error-detail:last-child {\n border-bottom: none;\n }\n\n .error-detail__header {\n display: flex;\n align-items: center;\n gap: 10px;\n margin-bottom: 4px;\n }\n\n .error-detail__time {\n font-size: 11px;\n font-weight: 600;\n color: var(--mj-text-muted);\n }\n\n .error-detail__duration {\n font-size: 11px;\n color: var(--mj-text-disabled);\n font-variant-numeric: tabular-nums;\n }\n\n .error-detail__message {\n font-size: 13px;\n color: var(--mj-status-error-text, var(--mj-status-error));\n line-height: 1.5;\n word-break: break-word;\n font-family: monospace;\n background: color-mix(in srgb, var(--mj-status-error) 5%, var(--mj-bg-surface));\n padding: 8px 10px;\n border-radius: 6px;\n border: 1px solid color-mix(in srgb, var(--mj-status-error) 15%, var(--mj-bg-surface));\n }\n\n /* \u2500\u2500 Responsive \u2500\u2500 */\n @media (max-width: 768px) {\n .summary-row {\n grid-template-columns: 1fr;\n }\n\n .summary-value {\n font-size: 18px;\n }\n }\n "] }]
|
|
483
|
+
}], null, { TimeRange: [{
|
|
484
|
+
type: Input
|
|
485
|
+
}], Filters: [{
|
|
486
|
+
type: Input
|
|
487
|
+
}] }); })();
|
|
488
|
+
(() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassDebugInfo(AnalyticsErrorAnalysisComponent, { className: "AnalyticsErrorAnalysisComponent", filePath: "src/AI/components/analytics/error-analysis/error-analysis.component.ts", lineNumber: 447 }); })();
|
|
489
|
+
export function LoadAnalyticsErrorAnalysis() { }
|
|
490
|
+
//# sourceMappingURL=error-analysis.component.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"error-analysis.component.js","sourceRoot":"","sources":["../../../../../src/AI/components/analytics/error-analysis/error-analysis.component.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * @fileoverview Error Analysis -- Basic.\n *\n * Displays error summary cards, and errors grouped by source (Prompt+Model combination).\n * Each group can be expanded to show individual error details.\n * Data loaded from MJ: AI Prompt Runs where Success=false.\n */\n\nimport {\n Component, Input, Output, EventEmitter,\n OnInit, OnDestroy, ChangeDetectorRef, inject\n} from '@angular/core';\nimport { Subject } from 'rxjs';\nimport { RunView } from '@memberjunction/core';\nimport { GlobalFilterState } from '../../../interfaces/analytics-preferences.interface';\n\n// ── Interfaces ──\n\ninterface FailedRunRecord {\n ID: string;\n RunAt: string;\n ErrorMessage: string | null;\n Model: string | null;\n Prompt: string | null;\n Vendor: string | null;\n ExecutionTimeMS: number | null;\n Status: string;\n}\n\ninterface ErrorSummary {\n TotalErrors: number;\n ErrorRate: number;\n MostCommonError: string;\n}\n\ninterface ErrorGroup {\n Source: string;\n PromptName: string;\n ModelName: string;\n Count: number;\n LastErrorMessage: string;\n LastErrorTime: string;\n IsExpanded: boolean;\n Errors: ErrorDetail[];\n}\n\ninterface ErrorDetail {\n ID: string;\n Time: string;\n ErrorMessage: string;\n Duration: string;\n}\n\nconst FIELDS = [\n 'ID', 'RunAt', 'ErrorMessage', 'Model', 'Prompt',\n 'Vendor', 'ExecutionTimeMS', 'Status'\n];\n\n@Component({\n standalone: false,\n selector: 'app-analytics-error-analysis',\n template: `\n <!-- Filter Bar -->\n <app-analytics-filter-bar\n [TimeRange]=\"TimeRange\"\n [Filters]=\"Filters\"\n [ShowAgentFilter]=\"false\"\n [ShowPromptFilter]=\"true\"\n [ShowModelFilter]=\"true\"\n [ShowStatusFilter]=\"false\"\n [ShowCompareToggle]=\"false\"\n [ShowExportButton]=\"false\"\n (TimeRangeChange)=\"OnTimeRangeChange($event)\"\n (FiltersChange)=\"OnFiltersChange($event)\"\n ></app-analytics-filter-bar>\n\n @if (IsLoading) {\n <div class=\"loading-container\">\n <mj-loading text=\"Loading error data...\"></mj-loading>\n </div>\n } @else {\n <!-- Summary Cards -->\n <div class=\"summary-row\">\n <div class=\"summary-card summary-card--error\">\n <div class=\"summary-icon\">\n <i class=\"fa-solid fa-circle-exclamation\"></i>\n </div>\n <div class=\"summary-content\">\n <div class=\"summary-label\">Total Errors</div>\n <div class=\"summary-value\">{{ Summary.TotalErrors | number }}</div>\n </div>\n </div>\n <div class=\"summary-card\">\n <div class=\"summary-icon summary-icon--warning\">\n <i class=\"fa-solid fa-percentage\"></i>\n </div>\n <div class=\"summary-content\">\n <div class=\"summary-label\">Error Rate</div>\n <div class=\"summary-value\">{{ Summary.ErrorRate | number:'1.1-1' }}%</div>\n </div>\n </div>\n <div class=\"summary-card\">\n <div class=\"summary-icon summary-icon--info\">\n <i class=\"fa-solid fa-bug\"></i>\n </div>\n <div class=\"summary-content\">\n <div class=\"summary-label\">Most Common</div>\n <div class=\"summary-value summary-value--text\" [title]=\"Summary.MostCommonError\">\n {{ Summary.MostCommonError || 'N/A' }}\n </div>\n </div>\n </div>\n </div>\n\n <!-- Error Groups -->\n @if (ErrorGroups.length === 0) {\n <div class=\"empty-state\">\n <i class=\"fa-solid fa-check-circle empty-state__icon\"></i>\n <div class=\"empty-state__title\">No Errors Found</div>\n <div class=\"empty-state__subtitle\">No errors detected in the selected time range.</div>\n </div>\n }\n\n @for (group of ErrorGroups; track group.Source) {\n <div class=\"error-group\" [class.error-group--expanded]=\"group.IsExpanded\">\n <div\n class=\"error-group__header\"\n (click)=\"ToggleGroup(group)\"\n role=\"button\"\n tabindex=\"0\"\n (keydown.enter)=\"ToggleGroup(group)\">\n <div class=\"error-group__left\">\n <i [class]=\"group.IsExpanded ? 'fa-solid fa-chevron-down' : 'fa-solid fa-chevron-right'\"\n class=\"expand-icon\"></i>\n <div class=\"error-group__source\">\n <div class=\"source-name\">{{ group.Source }}</div>\n <div class=\"source-details\">\n <span class=\"source-prompt\">{{ group.PromptName }}</span>\n <span class=\"source-separator\">+</span>\n <span class=\"source-model\">{{ group.ModelName }}</span>\n </div>\n </div>\n </div>\n <div class=\"error-group__right\">\n <span class=\"error-count-badge\">{{ group.Count }}</span>\n <div class=\"last-error-time\">{{ group.LastErrorTime }}</div>\n </div>\n </div>\n\n @if (!group.IsExpanded) {\n <div class=\"error-group__preview\">\n <span class=\"preview-label\">Last error:</span>\n {{ group.LastErrorMessage }}\n </div>\n }\n\n @if (group.IsExpanded) {\n <div class=\"error-group__body\">\n @for (err of group.Errors; track err.ID) {\n <div class=\"error-detail\">\n <div class=\"error-detail__header\">\n <span class=\"error-detail__time\">{{ err.Time }}</span>\n @if (err.Duration) {\n <span class=\"error-detail__duration\">{{ err.Duration }}</span>\n }\n </div>\n <div class=\"error-detail__message\">{{ err.ErrorMessage }}</div>\n </div>\n }\n </div>\n }\n </div>\n }\n }\n `,\n styles: [`\n :host { display: block; }\n\n .loading-container {\n display: flex;\n justify-content: center;\n align-items: center;\n min-height: 300px;\n }\n\n /* ── Summary Row ── */\n .summary-row {\n display: grid;\n grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));\n gap: 12px;\n margin: 16px 0;\n }\n\n .summary-card {\n background: var(--mj-bg-surface);\n border: 1px solid var(--mj-border-default);\n border-radius: 10px;\n padding: 16px;\n display: flex;\n align-items: center;\n gap: 14px;\n }\n\n .summary-card--error {\n border-left: 4px solid var(--mj-status-error);\n }\n\n .summary-icon {\n width: 40px;\n height: 40px;\n border-radius: 10px;\n display: flex;\n align-items: center;\n justify-content: center;\n background: color-mix(in srgb, var(--mj-status-error) 12%, var(--mj-bg-surface));\n color: var(--mj-status-error);\n font-size: 16px;\n flex-shrink: 0;\n }\n\n .summary-icon--warning {\n background: color-mix(in srgb, var(--mj-status-warning) 12%, var(--mj-bg-surface));\n color: var(--mj-status-warning);\n }\n\n .summary-icon--info {\n background: color-mix(in srgb, var(--mj-brand-primary) 12%, var(--mj-bg-surface));\n color: var(--mj-brand-primary);\n }\n\n .summary-label {\n font-size: 11px;\n font-weight: 600;\n color: var(--mj-text-muted);\n text-transform: uppercase;\n letter-spacing: 0.5px;\n }\n\n .summary-value {\n font-size: 22px;\n font-weight: 700;\n color: var(--mj-text-primary);\n letter-spacing: -0.02em;\n }\n\n .summary-value--text {\n font-size: 13px;\n font-weight: 500;\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n max-width: 220px;\n }\n\n /* ── Empty State ── */\n .empty-state {\n text-align: center;\n padding: 48px 24px;\n color: var(--mj-text-muted);\n }\n\n .empty-state__icon {\n font-size: 40px;\n color: var(--mj-status-success);\n margin-bottom: 12px;\n }\n\n .empty-state__title {\n font-size: 16px;\n font-weight: 600;\n color: var(--mj-text-primary);\n margin-bottom: 4px;\n }\n\n .empty-state__subtitle {\n font-size: 13px;\n color: var(--mj-text-muted);\n }\n\n /* ── Error Groups ── */\n .error-group {\n background: var(--mj-bg-surface);\n border: 1px solid var(--mj-border-default);\n border-radius: 10px;\n margin-bottom: 8px;\n overflow: hidden;\n transition: border-color 0.2s;\n }\n\n .error-group--expanded {\n border-color: var(--mj-status-error);\n }\n\n .error-group__header {\n display: flex;\n align-items: center;\n justify-content: space-between;\n padding: 14px 16px;\n cursor: pointer;\n transition: background 0.15s;\n }\n\n .error-group__header:hover {\n background: var(--mj-bg-surface-hover);\n }\n\n .error-group__left {\n display: flex;\n align-items: center;\n gap: 10px;\n min-width: 0;\n }\n\n .expand-icon {\n font-size: 11px;\n color: var(--mj-text-muted);\n width: 16px;\n flex-shrink: 0;\n transition: transform 0.2s;\n }\n\n .error-group__source {\n min-width: 0;\n }\n\n .source-name {\n font-size: 14px;\n font-weight: 600;\n color: var(--mj-text-primary);\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n }\n\n .source-details {\n font-size: 12px;\n color: var(--mj-text-muted);\n display: flex;\n align-items: center;\n gap: 4px;\n margin-top: 2px;\n }\n\n .source-separator {\n color: var(--mj-text-disabled);\n }\n\n .error-group__right {\n display: flex;\n align-items: center;\n gap: 12px;\n flex-shrink: 0;\n }\n\n .error-count-badge {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n min-width: 28px;\n height: 24px;\n padding: 0 8px;\n border-radius: 12px;\n background: color-mix(in srgb, var(--mj-status-error) 12%, var(--mj-bg-surface));\n color: var(--mj-status-error);\n font-size: 12px;\n font-weight: 700;\n }\n\n .last-error-time {\n font-size: 12px;\n color: var(--mj-text-disabled);\n white-space: nowrap;\n }\n\n .error-group__preview {\n padding: 0 16px 12px 42px;\n font-size: 12px;\n color: var(--mj-text-muted);\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n }\n\n .preview-label {\n color: var(--mj-text-disabled);\n margin-right: 4px;\n }\n\n .error-group__body {\n border-top: 1px solid var(--mj-border-subtle);\n max-height: 400px;\n overflow-y: auto;\n }\n\n .error-detail {\n padding: 12px 16px 12px 42px;\n border-bottom: 1px solid var(--mj-border-subtle);\n }\n\n .error-detail:last-child {\n border-bottom: none;\n }\n\n .error-detail__header {\n display: flex;\n align-items: center;\n gap: 10px;\n margin-bottom: 4px;\n }\n\n .error-detail__time {\n font-size: 11px;\n font-weight: 600;\n color: var(--mj-text-muted);\n }\n\n .error-detail__duration {\n font-size: 11px;\n color: var(--mj-text-disabled);\n font-variant-numeric: tabular-nums;\n }\n\n .error-detail__message {\n font-size: 13px;\n color: var(--mj-status-error-text, var(--mj-status-error));\n line-height: 1.5;\n word-break: break-word;\n font-family: monospace;\n background: color-mix(in srgb, var(--mj-status-error) 5%, var(--mj-bg-surface));\n padding: 8px 10px;\n border-radius: 6px;\n border: 1px solid color-mix(in srgb, var(--mj-status-error) 15%, var(--mj-bg-surface));\n }\n\n /* ── Responsive ── */\n @media (max-width: 768px) {\n .summary-row {\n grid-template-columns: 1fr;\n }\n\n .summary-value {\n font-size: 18px;\n }\n }\n `]\n})\nexport class AnalyticsErrorAnalysisComponent implements OnInit, OnDestroy {\n @Input() TimeRange = '7d';\n @Input() Filters: GlobalFilterState = { Models: [], Agents: [], Prompts: [], Statuses: [] };\n\n private cdr = inject(ChangeDetectorRef);\n private destroy$ = new Subject<void>();\n\n public IsLoading = false;\n\n public Summary: ErrorSummary = {\n TotalErrors: 0,\n ErrorRate: 0,\n MostCommonError: ''\n };\n\n public ErrorGroups: ErrorGroup[] = [];\n\n private failedRuns: FailedRunRecord[] = [];\n private totalRunCount = 0;\n\n ngOnInit(): void {\n this.LoadData();\n }\n\n ngOnDestroy(): void {\n this.destroy$.next();\n this.destroy$.complete();\n }\n\n // ── Public Handlers ──\n\n public OnTimeRangeChange(range: string): void {\n this.TimeRange = range;\n this.LoadData();\n }\n\n public OnFiltersChange(filters: GlobalFilterState): void {\n this.Filters = filters;\n this.LoadData();\n }\n\n public ToggleGroup(group: ErrorGroup): void {\n group.IsExpanded = !group.IsExpanded;\n this.cdr.detectChanges();\n }\n\n // ── Data Loading ──\n\n private async LoadData(): Promise<void> {\n this.IsLoading = true;\n this.cdr.detectChanges();\n\n try {\n const rv = new RunView();\n const dateFilter = this.buildDateFilter();\n const extraFilters = this.buildExtraFilters();\n const baseFilter = [dateFilter, ...extraFilters].filter(Boolean).join(' AND ');\n const errorFilter = baseFilter + ' AND Success = 0';\n\n const [errorResult, totalResult] = await rv.RunViews([\n {\n EntityName: 'MJ: AI Prompt Runs',\n ExtraFilter: errorFilter,\n Fields: FIELDS,\n OrderBy: 'RunAt DESC',\n ResultType: 'simple'\n },\n {\n EntityName: 'MJ: AI Prompt Runs',\n ExtraFilter: baseFilter,\n Fields: ['ID'],\n ResultType: 'simple'\n }\n ]);\n\n this.failedRuns = (errorResult?.Results ?? []) as FailedRunRecord[];\n this.totalRunCount = totalResult?.Results?.length ?? 0;\n\n this.computeSummary();\n this.buildErrorGroups();\n } catch (e) {\n console.error('Error Analysis load error:', e);\n } finally {\n this.IsLoading = false;\n this.cdr.detectChanges();\n }\n }\n\n // ── Computations ──\n\n private computeSummary(): void {\n const errorCount = this.failedRuns.length;\n const errorRate = this.totalRunCount > 0 ? (errorCount / this.totalRunCount) * 100 : 0;\n\n // Find most common error by grouping error messages\n const messageCounts = new Map<string, number>();\n for (const run of this.failedRuns) {\n const msg = this.normalizeErrorMessage(run.ErrorMessage ?? 'Unknown error');\n messageCounts.set(msg, (messageCounts.get(msg) ?? 0) + 1);\n }\n\n let mostCommon = '';\n let maxCount = 0;\n for (const [msg, count] of messageCounts) {\n if (count > maxCount) {\n maxCount = count;\n mostCommon = msg;\n }\n }\n\n this.Summary = {\n TotalErrors: errorCount,\n ErrorRate: errorRate,\n MostCommonError: mostCommon\n };\n }\n\n private buildErrorGroups(): void {\n const groups = new Map<string, FailedRunRecord[]>();\n\n for (const run of this.failedRuns) {\n const prompt = run.Prompt ?? 'Unknown Prompt';\n const model = run.Model ?? 'Unknown Model';\n const key = prompt + ' + ' + model;\n if (!groups.has(key)) groups.set(key, []);\n groups.get(key)!.push(run);\n }\n\n this.ErrorGroups = Array.from(groups.entries())\n .map(([source, runs]) => {\n const sortedRuns = runs.sort((a, b) =>\n new Date(b.RunAt).getTime() - new Date(a.RunAt).getTime()\n );\n\n return {\n Source: source,\n PromptName: sortedRuns[0].Prompt ?? 'Unknown',\n ModelName: sortedRuns[0].Model ?? 'Unknown',\n Count: sortedRuns.length,\n LastErrorMessage: this.truncateMessage(sortedRuns[0].ErrorMessage ?? 'No message'),\n LastErrorTime: this.formatRelativeTime(sortedRuns[0].RunAt),\n IsExpanded: false,\n Errors: sortedRuns.slice(0, 20).map(r => ({\n ID: r.ID,\n Time: this.formatDateTime(r.RunAt),\n ErrorMessage: r.ErrorMessage ?? 'No error message',\n Duration: r.ExecutionTimeMS != null ? r.ExecutionTimeMS + 'ms' : ''\n }))\n };\n })\n .sort((a, b) => b.Count - a.Count);\n }\n\n // ── Helpers ──\n\n private buildDateFilter(): string {\n const now = new Date();\n const msMap: Record<string, number> = {\n '1h': 3600000, '6h': 21600000, '24h': 86400000,\n '7d': 604800000, '30d': 2592000000\n };\n const ms = msMap[this.TimeRange] ?? 604800000;\n const start = new Date(now.getTime() - ms);\n return `RunAt >= '${start.toISOString()}'`;\n }\n\n private buildExtraFilters(): string[] {\n const filters: string[] = [];\n if (this.Filters.Models.length > 0) {\n filters.push(`ModelID IN (${this.Filters.Models.map(id => `'${id}'`).join(',')})`);\n }\n if (this.Filters.Prompts.length > 0) {\n filters.push(`PromptID IN (${this.Filters.Prompts.map(id => `'${id}'`).join(',')})`);\n }\n return filters;\n }\n\n private normalizeErrorMessage(msg: string): string {\n // Truncate and normalize for grouping\n return msg.slice(0, 100).trim().toLowerCase();\n }\n\n private truncateMessage(msg: string): string {\n if (msg.length <= 120) return msg;\n return msg.slice(0, 120) + '...';\n }\n\n private formatRelativeTime(dateStr: string): string {\n const now = Date.now();\n const then = new Date(dateStr).getTime();\n const diffMin = Math.floor((now - then) / 60000);\n if (diffMin < 1) return 'just now';\n if (diffMin < 60) return diffMin + 'm ago';\n const diffHr = Math.floor(diffMin / 60);\n if (diffHr < 24) return diffHr + 'h ago';\n const diffDay = Math.floor(diffHr / 24);\n return diffDay + 'd ago';\n }\n\n private formatDateTime(dateStr: string): string {\n const d = new Date(dateStr);\n const months = ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'];\n const hh = d.getHours().toString().padStart(2, '0');\n const mm = d.getMinutes().toString().padStart(2, '0');\n return `${months[d.getMonth()]} ${d.getDate()} ${hh}:${mm}`;\n }\n}\n\nexport function LoadAnalyticsErrorAnalysis() { /* tree-shaking prevention */ }\n"]}
|