@memberjunction/ng-dashboards 2.49.0 → 2.51.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (65) hide show
  1. package/dist/AI/ai-dashboard.component.d.ts +4 -0
  2. package/dist/AI/ai-dashboard.component.d.ts.map +1 -1
  3. package/dist/AI/ai-dashboard.component.js +71 -23
  4. package/dist/AI/ai-dashboard.component.js.map +1 -1
  5. package/dist/AI/components/agents/agent-configuration.component.d.ts +18 -8
  6. package/dist/AI/components/agents/agent-configuration.component.d.ts.map +1 -1
  7. package/dist/AI/components/agents/agent-configuration.component.js +338 -130
  8. package/dist/AI/components/agents/agent-configuration.component.js.map +1 -1
  9. package/dist/AI/components/agents/agent-editor.component.d.ts.map +1 -1
  10. package/dist/AI/components/agents/agent-editor.component.js +0 -5
  11. package/dist/AI/components/agents/agent-editor.component.js.map +1 -1
  12. package/dist/AI/components/agents/agent-filter-panel.component.d.ts +16 -1
  13. package/dist/AI/components/agents/agent-filter-panel.component.d.ts.map +1 -1
  14. package/dist/AI/components/agents/agent-filter-panel.component.js +124 -14
  15. package/dist/AI/components/agents/agent-filter-panel.component.js.map +1 -1
  16. package/dist/AI/components/charts/time-series-chart.component.d.ts +2 -0
  17. package/dist/AI/components/charts/time-series-chart.component.d.ts.map +1 -1
  18. package/dist/AI/components/charts/time-series-chart.component.js +56 -2
  19. package/dist/AI/components/charts/time-series-chart.component.js.map +1 -1
  20. package/dist/AI/components/execution-monitoring.component.d.ts +4 -7
  21. package/dist/AI/components/execution-monitoring.component.d.ts.map +1 -1
  22. package/dist/AI/components/execution-monitoring.component.js +339 -368
  23. package/dist/AI/components/execution-monitoring.component.js.map +1 -1
  24. package/dist/AI/components/models/model-management-v2.component.d.ts +92 -0
  25. package/dist/AI/components/models/model-management-v2.component.d.ts.map +1 -0
  26. package/dist/AI/components/models/model-management-v2.component.js +1004 -0
  27. package/dist/AI/components/models/model-management-v2.component.js.map +1 -0
  28. package/dist/AI/components/prompts/prompt-management-v2.component.d.ts +66 -0
  29. package/dist/AI/components/prompts/prompt-management-v2.component.d.ts.map +1 -0
  30. package/dist/AI/components/prompts/prompt-management-v2.component.js +719 -0
  31. package/dist/AI/components/prompts/prompt-management-v2.component.js.map +1 -0
  32. package/dist/AI/services/ai-instrumentation.service.d.ts +7 -6
  33. package/dist/AI/services/ai-instrumentation.service.d.ts.map +1 -1
  34. package/dist/AI/services/ai-instrumentation.service.js +141 -147
  35. package/dist/AI/services/ai-instrumentation.service.js.map +1 -1
  36. package/dist/Actions/actions-management-dashboard.component.js +8 -8
  37. package/dist/Actions/actions-management-dashboard.component.js.map +1 -1
  38. package/dist/Actions/components/actions-list-view.component.d.ts +0 -2
  39. package/dist/Actions/components/actions-list-view.component.d.ts.map +1 -1
  40. package/dist/Actions/components/actions-list-view.component.js +37 -37
  41. package/dist/Actions/components/actions-list-view.component.js.map +1 -1
  42. package/dist/Actions/components/actions-overview.component.d.ts +7 -4
  43. package/dist/Actions/components/actions-overview.component.d.ts.map +1 -1
  44. package/dist/Actions/components/actions-overview.component.js +147 -90
  45. package/dist/Actions/components/actions-overview.component.js.map +1 -1
  46. package/dist/Actions/components/categories-list-view.component.d.ts +23 -2
  47. package/dist/Actions/components/categories-list-view.component.d.ts.map +1 -1
  48. package/dist/Actions/components/categories-list-view.component.js +283 -17
  49. package/dist/Actions/components/categories-list-view.component.js.map +1 -1
  50. package/dist/Actions/components/execution-monitoring.component.d.ts +0 -2
  51. package/dist/Actions/components/execution-monitoring.component.d.ts.map +1 -1
  52. package/dist/Actions/components/execution-monitoring.component.js +25 -37
  53. package/dist/Actions/components/execution-monitoring.component.js.map +1 -1
  54. package/dist/module.d.ts +3 -3
  55. package/dist/module.js +6 -6
  56. package/dist/module.js.map +1 -1
  57. package/package.json +7 -6
  58. package/dist/AI/components/models/model-management.component.d.ts +0 -73
  59. package/dist/AI/components/models/model-management.component.d.ts.map +0 -1
  60. package/dist/AI/components/models/model-management.component.js +0 -643
  61. package/dist/AI/components/models/model-management.component.js.map +0 -1
  62. package/dist/AI/components/prompts/prompt-management.component.d.ts +0 -118
  63. package/dist/AI/components/prompts/prompt-management.component.d.ts.map +0 -1
  64. package/dist/AI/components/prompts/prompt-management.component.js +0 -1351
  65. package/dist/AI/components/prompts/prompt-management.component.js.map +0 -1
@@ -0,0 +1,1004 @@
1
+ import { Component, Output, EventEmitter, Input } from '@angular/core';
2
+ import { Subject, BehaviorSubject } from 'rxjs';
3
+ import { takeUntil, debounceTime, distinctUntilChanged } from 'rxjs/operators';
4
+ import { Metadata, RunView } from '@memberjunction/core';
5
+ import * as i0 from "@angular/core";
6
+ import * as i1 from "@memberjunction/ng-shared";
7
+ import * as i2 from "@angular/forms";
8
+ import * as i3 from "@progress/kendo-angular-layout";
9
+ import * as i4 from "@memberjunction/ng-container-directives";
10
+ const _forTrack0 = ($index, $item) => $item.value;
11
+ const _forTrack1 = ($index, $item) => $item.ID;
12
+ function ModelManagementV2Component_Conditional_1_Template(rf, ctx) { if (rf & 1) {
13
+ i0.ɵɵelementStart(0, "div", 1)(1, "div", 2)(2, "div", 3);
14
+ i0.ɵɵelement(3, "div", 4)(4, "div", 4)(5, "div", 4);
15
+ i0.ɵɵelementEnd();
16
+ i0.ɵɵelementStart(6, "div", 5);
17
+ i0.ɵɵtext(7);
18
+ i0.ɵɵelementEnd()()();
19
+ } if (rf & 2) {
20
+ const ctx_r0 = i0.ɵɵnextContext();
21
+ i0.ɵɵadvance(7);
22
+ i0.ɵɵtextInterpolate(ctx_r0.currentLoadingMessage);
23
+ } }
24
+ function ModelManagementV2Component_Conditional_2_Conditional_7_Template(rf, ctx) { if (rf & 1) {
25
+ i0.ɵɵtext(0, " Hide Filters ");
26
+ } }
27
+ function ModelManagementV2Component_Conditional_2_Conditional_8_Template(rf, ctx) { if (rf & 1) {
28
+ i0.ɵɵtext(0, " Show Filters ");
29
+ } }
30
+ function ModelManagementV2Component_Conditional_2_Conditional_21_For_24_Template(rf, ctx) { if (rf & 1) {
31
+ i0.ɵɵelementStart(0, "option", 39);
32
+ i0.ɵɵtext(1);
33
+ i0.ɵɵelementEnd();
34
+ } if (rf & 2) {
35
+ const option_r4 = ctx.$implicit;
36
+ i0.ɵɵproperty("value", option_r4.value);
37
+ i0.ɵɵadvance();
38
+ i0.ɵɵtextInterpolate(option_r4.label);
39
+ } }
40
+ function ModelManagementV2Component_Conditional_2_Conditional_21_For_33_Template(rf, ctx) { if (rf & 1) {
41
+ i0.ɵɵelementStart(0, "option", 39);
42
+ i0.ɵɵtext(1);
43
+ i0.ɵɵelementEnd();
44
+ } if (rf & 2) {
45
+ const vendor_r5 = ctx.$implicit;
46
+ i0.ɵɵproperty("value", vendor_r5.ID);
47
+ i0.ɵɵadvance();
48
+ i0.ɵɵtextInterpolate(vendor_r5.Name);
49
+ } }
50
+ function ModelManagementV2Component_Conditional_2_Conditional_21_For_42_Template(rf, ctx) { if (rf & 1) {
51
+ i0.ɵɵelementStart(0, "option", 39);
52
+ i0.ɵɵtext(1);
53
+ i0.ɵɵelementEnd();
54
+ } if (rf & 2) {
55
+ const type_r6 = ctx.$implicit;
56
+ i0.ɵɵproperty("value", type_r6.ID);
57
+ i0.ɵɵadvance();
58
+ i0.ɵɵtextInterpolate(type_r6.Name);
59
+ } }
60
+ function ModelManagementV2Component_Conditional_2_Conditional_21_Template(rf, ctx) { if (rf & 1) {
61
+ const _r3 = i0.ɵɵgetCurrentView();
62
+ i0.ɵɵelementStart(0, "kendo-splitter-pane", 22)(1, "div", 25)(2, "div", 26)(3, "h3");
63
+ i0.ɵɵtext(4, "Model Filters");
64
+ i0.ɵɵelementEnd();
65
+ i0.ɵɵelementStart(5, "div", 27)(6, "span", 28);
66
+ i0.ɵɵtext(7);
67
+ i0.ɵɵelementEnd();
68
+ i0.ɵɵelementStart(8, "span", 29);
69
+ i0.ɵɵtext(9);
70
+ i0.ɵɵelementEnd()();
71
+ i0.ɵɵelementStart(10, "button", 30);
72
+ i0.ɵɵlistener("click", function ModelManagementV2Component_Conditional_2_Conditional_21_Template_button_click_10_listener() { i0.ɵɵrestoreView(_r3); const ctx_r0 = i0.ɵɵnextContext(2); return i0.ɵɵresetView(ctx_r0.toggleFilterPanel()); });
73
+ i0.ɵɵelement(11, "span", 31);
74
+ i0.ɵɵelementEnd()();
75
+ i0.ɵɵelementStart(12, "div", 32)(13, "div", 33)(14, "label", 34);
76
+ i0.ɵɵelement(15, "span", 35);
77
+ i0.ɵɵtext(16, " Name ");
78
+ i0.ɵɵelementEnd();
79
+ i0.ɵɵelementStart(17, "input", 36);
80
+ i0.ɵɵlistener("input", function ModelManagementV2Component_Conditional_2_Conditional_21_Template_input_input_17_listener($event) { i0.ɵɵrestoreView(_r3); const ctx_r0 = i0.ɵɵnextContext(2); return i0.ɵɵresetView(ctx_r0.onSearchChange($event.target.value)); });
81
+ i0.ɵɵelementEnd()();
82
+ i0.ɵɵelementStart(18, "div", 33)(19, "label", 34);
83
+ i0.ɵɵelement(20, "span", 37);
84
+ i0.ɵɵtext(21, " Sort By ");
85
+ i0.ɵɵelementEnd();
86
+ i0.ɵɵelementStart(22, "select", 38);
87
+ i0.ɵɵlistener("change", function ModelManagementV2Component_Conditional_2_Conditional_21_Template_select_change_22_listener($event) { i0.ɵɵrestoreView(_r3); const ctx_r0 = i0.ɵɵnextContext(2); return i0.ɵɵresetView(ctx_r0.onSortChange($event.target.value)); });
88
+ i0.ɵɵrepeaterCreate(23, ModelManagementV2Component_Conditional_2_Conditional_21_For_24_Template, 2, 2, "option", 39, _forTrack0);
89
+ i0.ɵɵelementEnd()();
90
+ i0.ɵɵelementStart(25, "div", 33)(26, "label", 34);
91
+ i0.ɵɵelement(27, "span", 40);
92
+ i0.ɵɵtext(28, " Vendor ");
93
+ i0.ɵɵelementEnd();
94
+ i0.ɵɵelementStart(29, "select", 38);
95
+ i0.ɵɵlistener("change", function ModelManagementV2Component_Conditional_2_Conditional_21_Template_select_change_29_listener($event) { i0.ɵɵrestoreView(_r3); const ctx_r0 = i0.ɵɵnextContext(2); return i0.ɵɵresetView(ctx_r0.onVendorChange($event.target.value)); });
96
+ i0.ɵɵelementStart(30, "option", 41);
97
+ i0.ɵɵtext(31, "All Vendors");
98
+ i0.ɵɵelementEnd();
99
+ i0.ɵɵrepeaterCreate(32, ModelManagementV2Component_Conditional_2_Conditional_21_For_33_Template, 2, 2, "option", 39, _forTrack1);
100
+ i0.ɵɵelementEnd()();
101
+ i0.ɵɵelementStart(34, "div", 33)(35, "label", 34);
102
+ i0.ɵɵelement(36, "span", 9);
103
+ i0.ɵɵtext(37, " Type ");
104
+ i0.ɵɵelementEnd();
105
+ i0.ɵɵelementStart(38, "select", 38);
106
+ i0.ɵɵlistener("change", function ModelManagementV2Component_Conditional_2_Conditional_21_Template_select_change_38_listener($event) { i0.ɵɵrestoreView(_r3); const ctx_r0 = i0.ɵɵnextContext(2); return i0.ɵɵresetView(ctx_r0.onTypeChange($event.target.value)); });
107
+ i0.ɵɵelementStart(39, "option", 41);
108
+ i0.ɵɵtext(40, "All Types");
109
+ i0.ɵɵelementEnd();
110
+ i0.ɵɵrepeaterCreate(41, ModelManagementV2Component_Conditional_2_Conditional_21_For_42_Template, 2, 2, "option", 39, _forTrack1);
111
+ i0.ɵɵelementEnd()();
112
+ i0.ɵɵelementStart(43, "div", 33)(44, "label", 34);
113
+ i0.ɵɵelement(45, "span", 42);
114
+ i0.ɵɵtext(46, " Status ");
115
+ i0.ɵɵelementEnd();
116
+ i0.ɵɵelementStart(47, "select", 38);
117
+ i0.ɵɵlistener("change", function ModelManagementV2Component_Conditional_2_Conditional_21_Template_select_change_47_listener($event) { i0.ɵɵrestoreView(_r3); const ctx_r0 = i0.ɵɵnextContext(2); return i0.ɵɵresetView(ctx_r0.onStatusChange($event.target.value)); });
118
+ i0.ɵɵelementStart(48, "option", 41);
119
+ i0.ɵɵtext(49, "All Statuses");
120
+ i0.ɵɵelementEnd();
121
+ i0.ɵɵelementStart(50, "option", 43);
122
+ i0.ɵɵtext(51, "Active");
123
+ i0.ɵɵelementEnd();
124
+ i0.ɵɵelementStart(52, "option", 44);
125
+ i0.ɵɵtext(53, "Inactive");
126
+ i0.ɵɵelementEnd()()();
127
+ i0.ɵɵelementStart(54, "div", 33)(55, "label", 34);
128
+ i0.ɵɵelement(56, "span", 45);
129
+ i0.ɵɵtext(57, " Power Rank ");
130
+ i0.ɵɵelementEnd();
131
+ i0.ɵɵelementStart(58, "div", 46)(59, "input", 47);
132
+ i0.ɵɵtwoWayListener("ngModelChange", function ModelManagementV2Component_Conditional_2_Conditional_21_Template_input_ngModelChange_59_listener($event) { i0.ɵɵrestoreView(_r3); const ctx_r0 = i0.ɵɵnextContext(2); i0.ɵɵtwoWayBindingSet(ctx_r0.powerRankRange.min, $event) || (ctx_r0.powerRankRange.min = $event); return i0.ɵɵresetView($event); });
133
+ i0.ɵɵlistener("change", function ModelManagementV2Component_Conditional_2_Conditional_21_Template_input_change_59_listener() { i0.ɵɵrestoreView(_r3); const ctx_r0 = i0.ɵɵnextContext(2); return i0.ɵɵresetView(ctx_r0.validateAndApplyRankFilters("power")); });
134
+ i0.ɵɵelementEnd();
135
+ i0.ɵɵelementStart(60, "span", 48);
136
+ i0.ɵɵtext(61, "-");
137
+ i0.ɵɵelementEnd();
138
+ i0.ɵɵelementStart(62, "input", 49);
139
+ i0.ɵɵtwoWayListener("ngModelChange", function ModelManagementV2Component_Conditional_2_Conditional_21_Template_input_ngModelChange_62_listener($event) { i0.ɵɵrestoreView(_r3); const ctx_r0 = i0.ɵɵnextContext(2); i0.ɵɵtwoWayBindingSet(ctx_r0.powerRankRange.max, $event) || (ctx_r0.powerRankRange.max = $event); return i0.ɵɵresetView($event); });
140
+ i0.ɵɵlistener("change", function ModelManagementV2Component_Conditional_2_Conditional_21_Template_input_change_62_listener() { i0.ɵɵrestoreView(_r3); const ctx_r0 = i0.ɵɵnextContext(2); return i0.ɵɵresetView(ctx_r0.validateAndApplyRankFilters("power")); });
141
+ i0.ɵɵelementEnd()()();
142
+ i0.ɵɵelementStart(63, "div", 50)(64, "button", 51);
143
+ i0.ɵɵlistener("click", function ModelManagementV2Component_Conditional_2_Conditional_21_Template_button_click_64_listener() { i0.ɵɵrestoreView(_r3); const ctx_r0 = i0.ɵɵnextContext(2); return i0.ɵɵresetView(ctx_r0.clearFilters()); });
144
+ i0.ɵɵelement(65, "span", 52);
145
+ i0.ɵɵtext(66, " Reset Filters ");
146
+ i0.ɵɵelementEnd()()()()();
147
+ } if (rf & 2) {
148
+ const ctx_r0 = i0.ɵɵnextContext(2);
149
+ i0.ɵɵadvance(7);
150
+ i0.ɵɵtextInterpolate(ctx_r0.filteredModels.length);
151
+ i0.ɵɵadvance(2);
152
+ i0.ɵɵtextInterpolate1("of ", ctx_r0.models.length, "");
153
+ i0.ɵɵadvance(8);
154
+ i0.ɵɵproperty("value", ctx_r0.searchTerm);
155
+ i0.ɵɵadvance(5);
156
+ i0.ɵɵproperty("value", ctx_r0.sortBy);
157
+ i0.ɵɵadvance();
158
+ i0.ɵɵrepeater(ctx_r0.sortOptions);
159
+ i0.ɵɵadvance(6);
160
+ i0.ɵɵproperty("value", ctx_r0.selectedVendor);
161
+ i0.ɵɵadvance(3);
162
+ i0.ɵɵrepeater(ctx_r0.vendors);
163
+ i0.ɵɵadvance(6);
164
+ i0.ɵɵproperty("value", ctx_r0.selectedType);
165
+ i0.ɵɵadvance(3);
166
+ i0.ɵɵrepeater(ctx_r0.modelTypes);
167
+ i0.ɵɵadvance(6);
168
+ i0.ɵɵproperty("value", ctx_r0.selectedStatus);
169
+ i0.ɵɵadvance(12);
170
+ i0.ɵɵproperty("max", ctx_r0.maxPowerRank);
171
+ i0.ɵɵtwoWayProperty("ngModel", ctx_r0.powerRankRange.min);
172
+ i0.ɵɵadvance(3);
173
+ i0.ɵɵproperty("max", ctx_r0.maxPowerRank);
174
+ i0.ɵɵtwoWayProperty("ngModel", ctx_r0.powerRankRange.max);
175
+ } }
176
+ function ModelManagementV2Component_Conditional_2_Conditional_24_Conditional_6_Template(rf, ctx) { if (rf & 1) {
177
+ const _r7 = i0.ɵɵgetCurrentView();
178
+ i0.ɵɵelementStart(0, "button", 55);
179
+ i0.ɵɵlistener("click", function ModelManagementV2Component_Conditional_2_Conditional_24_Conditional_6_Template_button_click_0_listener() { i0.ɵɵrestoreView(_r7); const ctx_r0 = i0.ɵɵnextContext(3); return i0.ɵɵresetView(ctx_r0.createNewModel()); });
180
+ i0.ɵɵelement(1, "i", 20);
181
+ i0.ɵɵtext(2, " Create First Model ");
182
+ i0.ɵɵelementEnd();
183
+ } }
184
+ function ModelManagementV2Component_Conditional_2_Conditional_24_Template(rf, ctx) { if (rf & 1) {
185
+ i0.ɵɵelementStart(0, "div", 24);
186
+ i0.ɵɵelement(1, "i", 53);
187
+ i0.ɵɵelementStart(2, "h3");
188
+ i0.ɵɵtext(3, "No models found");
189
+ i0.ɵɵelementEnd();
190
+ i0.ɵɵelementStart(4, "p");
191
+ i0.ɵɵtext(5);
192
+ i0.ɵɵelementEnd();
193
+ i0.ɵɵtemplate(6, ModelManagementV2Component_Conditional_2_Conditional_24_Conditional_6_Template, 3, 0, "button", 54);
194
+ i0.ɵɵelementEnd();
195
+ } if (rf & 2) {
196
+ const ctx_r0 = i0.ɵɵnextContext(2);
197
+ i0.ɵɵadvance(5);
198
+ i0.ɵɵtextInterpolate(ctx_r0.hasActiveFilters ? "Try adjusting your filters" : "Create your first AI model to get started");
199
+ i0.ɵɵadvance();
200
+ i0.ɵɵconditional(!ctx_r0.hasActiveFilters ? 6 : -1);
201
+ } }
202
+ function ModelManagementV2Component_Conditional_2_Conditional_25_Case_0_For_2_Conditional_8_Template(rf, ctx) { if (rf & 1) {
203
+ i0.ɵɵelementStart(0, "span", 64);
204
+ i0.ɵɵtext(1);
205
+ i0.ɵɵelementEnd();
206
+ } if (rf & 2) {
207
+ const model_r9 = i0.ɵɵnextContext().$implicit;
208
+ i0.ɵɵadvance();
209
+ i0.ɵɵtextInterpolate(model_r9.Vendor);
210
+ } }
211
+ function ModelManagementV2Component_Conditional_2_Conditional_25_Case_0_For_2_Conditional_11_Template(rf, ctx) { if (rf & 1) {
212
+ i0.ɵɵelementStart(0, "span", 66);
213
+ i0.ɵɵtext(1, "Active");
214
+ i0.ɵɵelementEnd();
215
+ } }
216
+ function ModelManagementV2Component_Conditional_2_Conditional_25_Case_0_For_2_Conditional_12_Template(rf, ctx) { if (rf & 1) {
217
+ i0.ɵɵelementStart(0, "span", 67);
218
+ i0.ɵɵtext(1, "Inactive");
219
+ i0.ɵɵelementEnd();
220
+ } }
221
+ function ModelManagementV2Component_Conditional_2_Conditional_25_Case_0_For_2_Conditional_23_Template(rf, ctx) { if (rf & 1) {
222
+ i0.ɵɵelementStart(0, "span", 74);
223
+ i0.ɵɵelement(1, "i", 77);
224
+ i0.ɵɵtext(2);
225
+ i0.ɵɵelementEnd();
226
+ } if (rf & 2) {
227
+ const model_r9 = i0.ɵɵnextContext().$implicit;
228
+ const ctx_r0 = i0.ɵɵnextContext(4);
229
+ i0.ɵɵadvance(2);
230
+ i0.ɵɵtextInterpolate1(" ", ctx_r0.formatTokenLimit(model_r9.InputTokenLimit), " ");
231
+ } }
232
+ function ModelManagementV2Component_Conditional_2_Conditional_25_Case_0_For_2_Conditional_25_Conditional_1_Template(rf, ctx) { if (rf & 1) {
233
+ i0.ɵɵelementStart(0, "div", 78)(1, "h5");
234
+ i0.ɵɵtext(2, "Description");
235
+ i0.ɵɵelementEnd();
236
+ i0.ɵɵelementStart(3, "p");
237
+ i0.ɵɵtext(4);
238
+ i0.ɵɵelementEnd()();
239
+ } if (rf & 2) {
240
+ const model_r9 = i0.ɵɵnextContext(2).$implicit;
241
+ i0.ɵɵadvance(4);
242
+ i0.ɵɵtextInterpolate(model_r9.Description);
243
+ } }
244
+ function ModelManagementV2Component_Conditional_2_Conditional_25_Case_0_For_2_Conditional_25_Template(rf, ctx) { if (rf & 1) {
245
+ const _r10 = i0.ɵɵgetCurrentView();
246
+ i0.ɵɵelementStart(0, "div", 76);
247
+ i0.ɵɵtemplate(1, ModelManagementV2Component_Conditional_2_Conditional_25_Case_0_For_2_Conditional_25_Conditional_1_Template, 5, 1, "div", 78);
248
+ i0.ɵɵelementStart(2, "div", 79)(3, "h5");
249
+ i0.ɵɵtext(4, "Performance Rankings");
250
+ i0.ɵɵelementEnd();
251
+ i0.ɵɵelementStart(5, "div", 80)(6, "div", 81)(7, "span", 82);
252
+ i0.ɵɵelement(8, "i", 45);
253
+ i0.ɵɵtext(9, " Power ");
254
+ i0.ɵɵelementEnd();
255
+ i0.ɵɵelementStart(10, "span", 83);
256
+ i0.ɵɵtext(11);
257
+ i0.ɵɵelementEnd()();
258
+ i0.ɵɵelementStart(12, "div", 81)(13, "span", 82);
259
+ i0.ɵɵelement(14, "i", 71);
260
+ i0.ɵɵtext(15, " Speed ");
261
+ i0.ɵɵelementEnd();
262
+ i0.ɵɵelementStart(16, "span", 83);
263
+ i0.ɵɵtext(17);
264
+ i0.ɵɵelementEnd()();
265
+ i0.ɵɵelementStart(18, "div", 81)(19, "span", 82);
266
+ i0.ɵɵelement(20, "i", 73);
267
+ i0.ɵɵtext(21, " Cost ");
268
+ i0.ɵɵelementEnd();
269
+ i0.ɵɵelementStart(22, "span", 83);
270
+ i0.ɵɵtext(23);
271
+ i0.ɵɵelementEnd()()()();
272
+ i0.ɵɵelementStart(24, "div", 84)(25, "div", 85)(26, "span", 86);
273
+ i0.ɵɵtext(27, "Status");
274
+ i0.ɵɵelementEnd();
275
+ i0.ɵɵelementStart(28, "span", 87);
276
+ i0.ɵɵtext(29);
277
+ i0.ɵɵelementEnd()();
278
+ i0.ɵɵelementStart(30, "div", 85)(31, "span", 86);
279
+ i0.ɵɵtext(32, "API Name");
280
+ i0.ɵɵelementEnd();
281
+ i0.ɵɵelementStart(33, "span", 87);
282
+ i0.ɵɵtext(34);
283
+ i0.ɵɵelementEnd()();
284
+ i0.ɵɵelementStart(35, "div", 85)(36, "span", 86);
285
+ i0.ɵɵtext(37, "Driver");
286
+ i0.ɵɵelementEnd();
287
+ i0.ɵɵelementStart(38, "span", 87);
288
+ i0.ɵɵtext(39);
289
+ i0.ɵɵelementEnd()()();
290
+ i0.ɵɵelementStart(40, "div", 88)(41, "button", 89);
291
+ i0.ɵɵlistener("click", function ModelManagementV2Component_Conditional_2_Conditional_25_Case_0_For_2_Conditional_25_Template_button_click_41_listener($event) { i0.ɵɵrestoreView(_r10); const model_r9 = i0.ɵɵnextContext().$implicit; const ctx_r0 = i0.ɵɵnextContext(4); ctx_r0.openModel(model_r9.ID); return i0.ɵɵresetView($event.stopPropagation()); });
292
+ i0.ɵɵelement(42, "i", 90);
293
+ i0.ɵɵtext(43, " Edit ");
294
+ i0.ɵɵelementEnd()()();
295
+ } if (rf & 2) {
296
+ const model_r9 = i0.ɵɵnextContext().$implicit;
297
+ const ctx_r0 = i0.ɵɵnextContext(4);
298
+ i0.ɵɵadvance();
299
+ i0.ɵɵconditional(model_r9.Description ? 1 : -1);
300
+ i0.ɵɵadvance(9);
301
+ i0.ɵɵclassMap(ctx_r0.getRankClass(model_r9.PowerRank, "power"));
302
+ i0.ɵɵadvance();
303
+ i0.ɵɵtextInterpolate1(" ", ctx_r0.formatRank(model_r9.PowerRank, "power"), " ");
304
+ i0.ɵɵadvance(5);
305
+ i0.ɵɵclassMap(ctx_r0.getRankClass(model_r9.SpeedRank, "speed"));
306
+ i0.ɵɵadvance();
307
+ i0.ɵɵtextInterpolate1(" ", ctx_r0.formatRank(model_r9.SpeedRank, "speed"), " ");
308
+ i0.ɵɵadvance(5);
309
+ i0.ɵɵclassMap(ctx_r0.getRankClass(model_r9.CostRank, "cost"));
310
+ i0.ɵɵadvance();
311
+ i0.ɵɵtextInterpolate1(" ", ctx_r0.formatRank(model_r9.CostRank, "cost"), " ");
312
+ i0.ɵɵadvance(6);
313
+ i0.ɵɵtextInterpolate(model_r9.IsActive ? "Active" : "Inactive");
314
+ i0.ɵɵadvance(5);
315
+ i0.ɵɵtextInterpolate(model_r9.APIName || "N/A");
316
+ i0.ɵɵadvance(5);
317
+ i0.ɵɵtextInterpolate(model_r9.DriverClass || "N/A");
318
+ } }
319
+ function ModelManagementV2Component_Conditional_2_Conditional_25_Case_0_For_2_Template(rf, ctx) { if (rf & 1) {
320
+ const _r8 = i0.ɵɵgetCurrentView();
321
+ i0.ɵɵelementStart(0, "div", 59)(1, "div", 60);
322
+ i0.ɵɵlistener("click", function ModelManagementV2Component_Conditional_2_Conditional_25_Case_0_For_2_Template_div_click_1_listener() { const model_r9 = i0.ɵɵrestoreView(_r8).$implicit; const ctx_r0 = i0.ɵɵnextContext(4); return i0.ɵɵresetView(ctx_r0.toggleModelExpansion(model_r9.ID)); });
323
+ i0.ɵɵelementStart(2, "div", 61);
324
+ i0.ɵɵelement(3, "i");
325
+ i0.ɵɵelementEnd();
326
+ i0.ɵɵelementStart(4, "div", 62)(5, "h4");
327
+ i0.ɵɵtext(6);
328
+ i0.ɵɵelementEnd();
329
+ i0.ɵɵelementStart(7, "div", 63);
330
+ i0.ɵɵtemplate(8, ModelManagementV2Component_Conditional_2_Conditional_25_Case_0_For_2_Conditional_8_Template, 2, 1, "span", 64);
331
+ i0.ɵɵelementStart(9, "span", 65);
332
+ i0.ɵɵtext(10);
333
+ i0.ɵɵelementEnd();
334
+ i0.ɵɵtemplate(11, ModelManagementV2Component_Conditional_2_Conditional_25_Case_0_For_2_Conditional_11_Template, 2, 0, "span", 66)(12, ModelManagementV2Component_Conditional_2_Conditional_25_Case_0_For_2_Conditional_12_Template, 2, 0, "span", 67);
335
+ i0.ɵɵelementEnd();
336
+ i0.ɵɵelementStart(13, "div", 68)(14, "span", 69);
337
+ i0.ɵɵelement(15, "i", 45);
338
+ i0.ɵɵtext(16);
339
+ i0.ɵɵelementEnd();
340
+ i0.ɵɵelementStart(17, "span", 70);
341
+ i0.ɵɵelement(18, "i", 71);
342
+ i0.ɵɵtext(19);
343
+ i0.ɵɵelementEnd();
344
+ i0.ɵɵelementStart(20, "span", 72);
345
+ i0.ɵɵelement(21, "i", 73);
346
+ i0.ɵɵtext(22);
347
+ i0.ɵɵelementEnd();
348
+ i0.ɵɵtemplate(23, ModelManagementV2Component_Conditional_2_Conditional_25_Case_0_For_2_Conditional_23_Template, 3, 1, "span", 74);
349
+ i0.ɵɵelementEnd()();
350
+ i0.ɵɵelement(24, "i", 75);
351
+ i0.ɵɵelementEnd();
352
+ i0.ɵɵtemplate(25, ModelManagementV2Component_Conditional_2_Conditional_25_Case_0_For_2_Conditional_25_Template, 44, 13, "div", 76);
353
+ i0.ɵɵelementEnd();
354
+ } if (rf & 2) {
355
+ const model_r9 = ctx.$implicit;
356
+ const ctx_r0 = i0.ɵɵnextContext(4);
357
+ i0.ɵɵclassProp("expanded", ctx_r0.expandedModelId === model_r9.ID);
358
+ i0.ɵɵadvance(3);
359
+ i0.ɵɵclassMap(ctx_r0.getModelIcon(model_r9));
360
+ i0.ɵɵadvance(3);
361
+ i0.ɵɵtextInterpolate(model_r9.Name || "Unnamed Model");
362
+ i0.ɵɵadvance(2);
363
+ i0.ɵɵconditional(model_r9.Vendor ? 8 : -1);
364
+ i0.ɵɵadvance(2);
365
+ i0.ɵɵtextInterpolate(model_r9.AIModelType);
366
+ i0.ɵɵadvance();
367
+ i0.ɵɵconditional(model_r9.IsActive ? 11 : 12);
368
+ i0.ɵɵadvance(5);
369
+ i0.ɵɵtextInterpolate1(" ", ctx_r0.formatRank(model_r9.PowerRank, "power"), " ");
370
+ i0.ɵɵadvance(3);
371
+ i0.ɵɵtextInterpolate1(" ", ctx_r0.formatRank(model_r9.SpeedRank, "speed"), " ");
372
+ i0.ɵɵadvance(3);
373
+ i0.ɵɵtextInterpolate1(" ", ctx_r0.formatRank(model_r9.CostRank, "cost"), " ");
374
+ i0.ɵɵadvance();
375
+ i0.ɵɵconditional(model_r9.InputTokenLimit ? 23 : -1);
376
+ i0.ɵɵadvance();
377
+ i0.ɵɵclassProp("rotated", ctx_r0.expandedModelId === model_r9.ID);
378
+ i0.ɵɵadvance();
379
+ i0.ɵɵconditional(ctx_r0.expandedModelId === model_r9.ID ? 25 : -1);
380
+ } }
381
+ function ModelManagementV2Component_Conditional_2_Conditional_25_Case_0_Template(rf, ctx) { if (rf & 1) {
382
+ i0.ɵɵelementStart(0, "div", 56);
383
+ i0.ɵɵrepeaterCreate(1, ModelManagementV2Component_Conditional_2_Conditional_25_Case_0_For_2_Template, 26, 15, "div", 58, _forTrack1);
384
+ i0.ɵɵelementEnd();
385
+ } if (rf & 2) {
386
+ const ctx_r0 = i0.ɵɵnextContext(3);
387
+ i0.ɵɵadvance();
388
+ i0.ɵɵrepeater(ctx_r0.filteredModels);
389
+ } }
390
+ function ModelManagementV2Component_Conditional_2_Conditional_25_Case_1_For_22_Template(rf, ctx) { if (rf & 1) {
391
+ const _r11 = i0.ɵɵgetCurrentView();
392
+ i0.ɵɵelementStart(0, "tr")(1, "td")(2, "div", 92);
393
+ i0.ɵɵelement(3, "i");
394
+ i0.ɵɵtext(4);
395
+ i0.ɵɵelementEnd()();
396
+ i0.ɵɵelementStart(5, "td");
397
+ i0.ɵɵtext(6);
398
+ i0.ɵɵelementEnd();
399
+ i0.ɵɵelementStart(7, "td");
400
+ i0.ɵɵtext(8);
401
+ i0.ɵɵelementEnd();
402
+ i0.ɵɵelementStart(9, "td")(10, "span", 93);
403
+ i0.ɵɵtext(11);
404
+ i0.ɵɵelementEnd()();
405
+ i0.ɵɵelementStart(12, "td")(13, "span", 93);
406
+ i0.ɵɵtext(14);
407
+ i0.ɵɵelementEnd()();
408
+ i0.ɵɵelementStart(15, "td")(16, "span", 93);
409
+ i0.ɵɵtext(17);
410
+ i0.ɵɵelementEnd()();
411
+ i0.ɵɵelementStart(18, "td")(19, "span", 94);
412
+ i0.ɵɵtext(20);
413
+ i0.ɵɵelementEnd()();
414
+ i0.ɵɵelementStart(21, "td")(22, "button", 95);
415
+ i0.ɵɵlistener("click", function ModelManagementV2Component_Conditional_2_Conditional_25_Case_1_For_22_Template_button_click_22_listener() { const model_r12 = i0.ɵɵrestoreView(_r11).$implicit; const ctx_r0 = i0.ɵɵnextContext(4); return i0.ɵɵresetView(ctx_r0.openModel(model_r12.ID)); });
416
+ i0.ɵɵelement(23, "i", 90);
417
+ i0.ɵɵelementEnd()()();
418
+ } if (rf & 2) {
419
+ const model_r12 = ctx.$implicit;
420
+ const ctx_r0 = i0.ɵɵnextContext(4);
421
+ i0.ɵɵadvance(3);
422
+ i0.ɵɵclassMap(ctx_r0.getModelIcon(model_r12));
423
+ i0.ɵɵadvance();
424
+ i0.ɵɵtextInterpolate1(" ", model_r12.Name || "Unnamed Model", " ");
425
+ i0.ɵɵadvance(2);
426
+ i0.ɵɵtextInterpolate(model_r12.Vendor || "-");
427
+ i0.ɵɵadvance(2);
428
+ i0.ɵɵtextInterpolate(model_r12.AIModelType);
429
+ i0.ɵɵadvance(2);
430
+ i0.ɵɵclassMap(ctx_r0.getRankClass(model_r12.PowerRank, "power"));
431
+ i0.ɵɵadvance();
432
+ i0.ɵɵtextInterpolate1(" ", ctx_r0.formatRank(model_r12.PowerRank, "power"), " ");
433
+ i0.ɵɵadvance(2);
434
+ i0.ɵɵclassMap(ctx_r0.getRankClass(model_r12.SpeedRank, "speed"));
435
+ i0.ɵɵadvance();
436
+ i0.ɵɵtextInterpolate1(" ", ctx_r0.formatRank(model_r12.SpeedRank, "speed"), " ");
437
+ i0.ɵɵadvance(2);
438
+ i0.ɵɵclassMap(ctx_r0.getRankClass(model_r12.CostRank, "cost"));
439
+ i0.ɵɵadvance();
440
+ i0.ɵɵtextInterpolate1(" ", ctx_r0.formatRank(model_r12.CostRank, "cost"), " ");
441
+ i0.ɵɵadvance(2);
442
+ i0.ɵɵclassProp("active", model_r12.IsActive)("inactive", !model_r12.IsActive);
443
+ i0.ɵɵadvance();
444
+ i0.ɵɵtextInterpolate1(" ", model_r12.IsActive ? "Active" : "Inactive", " ");
445
+ } }
446
+ function ModelManagementV2Component_Conditional_2_Conditional_25_Case_1_Template(rf, ctx) { if (rf & 1) {
447
+ i0.ɵɵelementStart(0, "div", 57)(1, "table", 91)(2, "thead")(3, "tr")(4, "th");
448
+ i0.ɵɵtext(5, "Name");
449
+ i0.ɵɵelementEnd();
450
+ i0.ɵɵelementStart(6, "th");
451
+ i0.ɵɵtext(7, "Vendor");
452
+ i0.ɵɵelementEnd();
453
+ i0.ɵɵelementStart(8, "th");
454
+ i0.ɵɵtext(9, "Type");
455
+ i0.ɵɵelementEnd();
456
+ i0.ɵɵelementStart(10, "th");
457
+ i0.ɵɵtext(11, "Power");
458
+ i0.ɵɵelementEnd();
459
+ i0.ɵɵelementStart(12, "th");
460
+ i0.ɵɵtext(13, "Speed");
461
+ i0.ɵɵelementEnd();
462
+ i0.ɵɵelementStart(14, "th");
463
+ i0.ɵɵtext(15, "Cost");
464
+ i0.ɵɵelementEnd();
465
+ i0.ɵɵelementStart(16, "th");
466
+ i0.ɵɵtext(17, "Status");
467
+ i0.ɵɵelementEnd();
468
+ i0.ɵɵelementStart(18, "th");
469
+ i0.ɵɵtext(19, "Actions");
470
+ i0.ɵɵelementEnd()()();
471
+ i0.ɵɵelementStart(20, "tbody");
472
+ i0.ɵɵrepeaterCreate(21, ModelManagementV2Component_Conditional_2_Conditional_25_Case_1_For_22_Template, 24, 19, "tr", null, _forTrack1);
473
+ i0.ɵɵelementEnd()()();
474
+ } if (rf & 2) {
475
+ const ctx_r0 = i0.ɵɵnextContext(3);
476
+ i0.ɵɵadvance(21);
477
+ i0.ɵɵrepeater(ctx_r0.filteredModels);
478
+ } }
479
+ function ModelManagementV2Component_Conditional_2_Conditional_25_Template(rf, ctx) { if (rf & 1) {
480
+ i0.ɵɵtemplate(0, ModelManagementV2Component_Conditional_2_Conditional_25_Case_0_Template, 3, 0, "div", 56)(1, ModelManagementV2Component_Conditional_2_Conditional_25_Case_1_Template, 23, 0, "div", 57);
481
+ } if (rf & 2) {
482
+ let tmp_2_0;
483
+ const ctx_r0 = i0.ɵɵnextContext(2);
484
+ i0.ɵɵconditional((tmp_2_0 = ctx_r0.viewMode) === "grid" ? 0 : tmp_2_0 === "list" ? 1 : -1);
485
+ } }
486
+ function ModelManagementV2Component_Conditional_2_Template(rf, ctx) { if (rf & 1) {
487
+ const _r2 = i0.ɵɵgetCurrentView();
488
+ i0.ɵɵelementStart(0, "div", 6)(1, "div", 7)(2, "h2", 8);
489
+ i0.ɵɵelement(3, "i", 9);
490
+ i0.ɵɵtext(4, " AI Models ");
491
+ i0.ɵɵelementEnd();
492
+ i0.ɵɵelementStart(5, "button", 10);
493
+ i0.ɵɵlistener("click", function ModelManagementV2Component_Conditional_2_Template_button_click_5_listener() { i0.ɵɵrestoreView(_r2); const ctx_r0 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r0.toggleFilters()); });
494
+ i0.ɵɵelement(6, "i", 11);
495
+ i0.ɵɵtemplate(7, ModelManagementV2Component_Conditional_2_Conditional_7_Template, 1, 0)(8, ModelManagementV2Component_Conditional_2_Conditional_8_Template, 1, 0);
496
+ i0.ɵɵelementEnd();
497
+ i0.ɵɵelementStart(9, "span", 12);
498
+ i0.ɵɵtext(10);
499
+ i0.ɵɵelementEnd()();
500
+ i0.ɵɵelementStart(11, "div", 13)(12, "div", 14)(13, "button", 15);
501
+ i0.ɵɵlistener("click", function ModelManagementV2Component_Conditional_2_Template_button_click_13_listener() { i0.ɵɵrestoreView(_r2); const ctx_r0 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r0.setViewMode("grid")); });
502
+ i0.ɵɵelement(14, "i", 16);
503
+ i0.ɵɵelementEnd();
504
+ i0.ɵɵelementStart(15, "button", 17);
505
+ i0.ɵɵlistener("click", function ModelManagementV2Component_Conditional_2_Template_button_click_15_listener() { i0.ɵɵrestoreView(_r2); const ctx_r0 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r0.setViewMode("list")); });
506
+ i0.ɵɵelement(16, "i", 18);
507
+ i0.ɵɵelementEnd()();
508
+ i0.ɵɵelementStart(17, "button", 19);
509
+ i0.ɵɵlistener("click", function ModelManagementV2Component_Conditional_2_Template_button_click_17_listener() { i0.ɵɵrestoreView(_r2); const ctx_r0 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r0.createNewModel()); });
510
+ i0.ɵɵelement(18, "i", 20);
511
+ i0.ɵɵtext(19, " New Model ");
512
+ i0.ɵɵelementEnd()()();
513
+ i0.ɵɵelementStart(20, "kendo-splitter", 21);
514
+ i0.ɵɵtemplate(21, ModelManagementV2Component_Conditional_2_Conditional_21_Template, 67, 11, "kendo-splitter-pane", 22);
515
+ i0.ɵɵelementStart(22, "kendo-splitter-pane")(23, "div", 23);
516
+ i0.ɵɵtemplate(24, ModelManagementV2Component_Conditional_2_Conditional_24_Template, 7, 2, "div", 24)(25, ModelManagementV2Component_Conditional_2_Conditional_25_Template, 2, 1);
517
+ i0.ɵɵelementEnd()()();
518
+ } if (rf & 2) {
519
+ const ctx_r0 = i0.ɵɵnextContext();
520
+ i0.ɵɵadvance(7);
521
+ i0.ɵɵconditional(ctx_r0.showFilters ? 7 : 8);
522
+ i0.ɵɵadvance(3);
523
+ i0.ɵɵtextInterpolate1("", ctx_r0.filteredModels.length, " models");
524
+ i0.ɵɵadvance(3);
525
+ i0.ɵɵclassProp("active", ctx_r0.viewMode === "grid");
526
+ i0.ɵɵadvance(2);
527
+ i0.ɵɵclassProp("active", ctx_r0.viewMode === "list");
528
+ i0.ɵɵadvance(6);
529
+ i0.ɵɵconditional(ctx_r0.showFilters ? 21 : -1);
530
+ i0.ɵɵadvance(3);
531
+ i0.ɵɵconditional(ctx_r0.filteredModels.length === 0 ? 24 : 25);
532
+ } }
533
+ export class ModelManagementV2Component {
534
+ sharedService;
535
+ openEntityRecord = new EventEmitter();
536
+ stateChange = new EventEmitter();
537
+ initialState = null;
538
+ // View state
539
+ viewMode = 'grid';
540
+ isLoading = true;
541
+ showFilters = true;
542
+ expandedModelId = null;
543
+ // Data - Keep as AIModelEntity to preserve getters
544
+ models = [];
545
+ filteredModels = [];
546
+ vendors = [];
547
+ modelTypes = [];
548
+ // Filtering
549
+ searchTerm = '';
550
+ searchSubject = new BehaviorSubject('');
551
+ selectedVendor = 'all';
552
+ selectedType = 'all';
553
+ selectedStatus = 'all';
554
+ powerRankRange = { min: 0, max: 10 };
555
+ speedRankRange = { min: 0, max: 10 };
556
+ costRankRange = { min: 0, max: 10 };
557
+ // Sorting
558
+ sortBy = 'name';
559
+ sortOptions = [
560
+ { value: 'name', label: 'Name' },
561
+ { value: 'vendor', label: 'Vendor' },
562
+ { value: 'type', label: 'Type' },
563
+ { value: 'powerRank', label: 'Power Rank' },
564
+ { value: 'speedRank', label: 'Speed Rank' },
565
+ { value: 'costRank', label: 'Cost Rank' },
566
+ { value: 'created', label: 'Created Date' },
567
+ { value: 'updated', label: 'Updated Date' }
568
+ ];
569
+ // Max rank values calculated from all models
570
+ maxPowerRank = 10;
571
+ maxSpeedRank = 10;
572
+ maxCostRank = 10;
573
+ // Loading messages
574
+ loadingMessages = [
575
+ 'Loading AI models...',
576
+ 'Fetching vendor information...',
577
+ 'Calculating rankings...',
578
+ 'Almost ready...'
579
+ ];
580
+ currentLoadingMessage = this.loadingMessages[0];
581
+ loadingMessageIndex = 0;
582
+ loadingMessageInterval;
583
+ destroy$ = new Subject();
584
+ constructor(sharedService) {
585
+ this.sharedService = sharedService;
586
+ }
587
+ ngOnInit() {
588
+ this.setupSearchListener();
589
+ this.startLoadingMessages();
590
+ this.loadInitialData();
591
+ if (this.initialState) {
592
+ this.applyInitialState(this.initialState);
593
+ }
594
+ }
595
+ ngOnDestroy() {
596
+ this.destroy$.next();
597
+ this.destroy$.complete();
598
+ if (this.loadingMessageInterval) {
599
+ clearInterval(this.loadingMessageInterval);
600
+ }
601
+ }
602
+ setupSearchListener() {
603
+ this.searchSubject.pipe(debounceTime(300), distinctUntilChanged(), takeUntil(this.destroy$)).subscribe(searchTerm => {
604
+ this.searchTerm = searchTerm;
605
+ this.applyFilters();
606
+ });
607
+ }
608
+ startLoadingMessages() {
609
+ this.loadingMessageInterval = setInterval(() => {
610
+ this.loadingMessageIndex = (this.loadingMessageIndex + 1) % this.loadingMessages.length;
611
+ this.currentLoadingMessage = this.loadingMessages[this.loadingMessageIndex];
612
+ }, 2000);
613
+ }
614
+ async loadInitialData() {
615
+ try {
616
+ const rv = new RunView();
617
+ // Load models with proper generic typing
618
+ const modelResults = await rv.RunView({
619
+ EntityName: 'AI Models',
620
+ OrderBy: 'Name',
621
+ MaxRows: 1000,
622
+ ResultType: 'entity_object'
623
+ });
624
+ // Load vendors and types in parallel
625
+ const [vendorResults, typeResults] = await Promise.all([
626
+ rv.RunView({
627
+ EntityName: 'MJ: AI Vendors',
628
+ OrderBy: 'Name',
629
+ MaxRows: 1000,
630
+ ResultType: 'entity_object'
631
+ }),
632
+ rv.RunView({
633
+ EntityName: 'AI Model Types',
634
+ OrderBy: 'Name',
635
+ MaxRows: 1000,
636
+ ResultType: 'entity_object'
637
+ })
638
+ ]);
639
+ // Results are now properly typed, no casting needed
640
+ this.vendors = vendorResults.Results;
641
+ this.modelTypes = typeResults.Results;
642
+ // Log summary data
643
+ // Create lookup maps
644
+ const vendorMap = new Map(this.vendors.map(v => [v.ID, v.Name]));
645
+ const typeMap = new Map(this.modelTypes.map(t => [t.ID, t.Name]));
646
+ // Transform models to display format - Results already typed as AIModelEntity[]
647
+ this.models = modelResults.Results.map((model, index) => {
648
+ // Find vendor ID by matching vendor name
649
+ let vendorId;
650
+ if (model.Vendor) {
651
+ const vendor = this.vendors.find(v => v.Name === model.Vendor);
652
+ vendorId = vendor?.ID;
653
+ }
654
+ // Don't spread the model - it loses getter properties!
655
+ // Instead, augment the model with display properties
656
+ const modelWithDisplay = model;
657
+ modelWithDisplay.VendorID = vendorId;
658
+ modelWithDisplay.VendorName = model.Vendor || 'No Vendor';
659
+ modelWithDisplay.ModelTypeName = model.AIModelTypeID ? typeMap.get(model.AIModelTypeID) || 'Unknown' : 'No Type';
660
+ return model;
661
+ });
662
+ // Calculate max values for each rank type from ALL models
663
+ this.maxPowerRank = Math.max(...this.models.map(m => m.PowerRank || 0), 10);
664
+ this.maxSpeedRank = Math.max(...this.models.map(m => m.SpeedRank || 0), 10);
665
+ this.maxCostRank = Math.max(...this.models.map(m => m.CostRank || 0), 10);
666
+ // Update filter ranges based on actual max values
667
+ this.powerRankRange = { min: 0, max: this.maxPowerRank };
668
+ this.speedRankRange = { min: 0, max: this.maxSpeedRank };
669
+ this.costRankRange = { min: 0, max: this.maxCostRank };
670
+ this.filteredModels = [...this.models];
671
+ this.sortModels();
672
+ this.applyFilters();
673
+ this.emitStateChange();
674
+ }
675
+ catch (error) {
676
+ console.error('Error loading model data:', error);
677
+ this.sharedService.CreateSimpleNotification('Error loading models', 'error', 3000);
678
+ }
679
+ finally {
680
+ this.isLoading = false;
681
+ if (this.loadingMessageInterval) {
682
+ clearInterval(this.loadingMessageInterval);
683
+ }
684
+ }
685
+ }
686
+ formatRank(rank, rankType) {
687
+ if (rank === null)
688
+ return 'N/A';
689
+ // Determine which max value to use
690
+ let maxValue = 10;
691
+ if (rankType === 'power') {
692
+ maxValue = this.maxPowerRank;
693
+ }
694
+ else if (rankType === 'speed') {
695
+ maxValue = this.maxSpeedRank;
696
+ }
697
+ else if (rankType === 'cost') {
698
+ maxValue = this.maxCostRank;
699
+ }
700
+ return `${rank}/${maxValue}`;
701
+ }
702
+ applyInitialState(state) {
703
+ if (state.viewMode)
704
+ this.viewMode = state.viewMode;
705
+ if (state.showFilters !== undefined)
706
+ this.showFilters = state.showFilters;
707
+ if (state.searchTerm)
708
+ this.searchTerm = state.searchTerm;
709
+ if (state.selectedVendor)
710
+ this.selectedVendor = state.selectedVendor;
711
+ if (state.selectedType)
712
+ this.selectedType = state.selectedType;
713
+ if (state.selectedStatus)
714
+ this.selectedStatus = state.selectedStatus;
715
+ if (state.sortBy)
716
+ this.sortBy = state.sortBy;
717
+ if (state.powerRankRange)
718
+ this.powerRankRange = state.powerRankRange;
719
+ if (state.speedRankRange)
720
+ this.speedRankRange = state.speedRankRange;
721
+ if (state.costRankRange)
722
+ this.costRankRange = state.costRankRange;
723
+ }
724
+ onSearchChange(value) {
725
+ this.searchSubject.next(value);
726
+ }
727
+ toggleFilters() {
728
+ this.showFilters = !this.showFilters;
729
+ this.emitStateChange();
730
+ }
731
+ toggleFilterPanel() {
732
+ this.showFilters = !this.showFilters;
733
+ this.emitStateChange();
734
+ }
735
+ setViewMode(mode) {
736
+ this.viewMode = mode;
737
+ this.expandedModelId = null;
738
+ this.emitStateChange();
739
+ }
740
+ toggleModelExpansion(modelId) {
741
+ this.expandedModelId = this.expandedModelId === modelId ? null : modelId;
742
+ }
743
+ applyFilters() {
744
+ this.filteredModels = this.models.filter(m => {
745
+ const model = m;
746
+ // Search filter
747
+ if (this.searchTerm) {
748
+ const searchLower = this.searchTerm.toLowerCase();
749
+ const matchesSearch = model.Name?.toLowerCase().includes(searchLower) ||
750
+ model.Description?.toLowerCase().includes(searchLower) ||
751
+ model.VendorName?.toLowerCase().includes(searchLower) ||
752
+ model.ModelTypeName?.toLowerCase().includes(searchLower);
753
+ if (!matchesSearch)
754
+ return false;
755
+ }
756
+ // Vendor filter
757
+ if (this.selectedVendor !== 'all' && model.VendorID !== this.selectedVendor) {
758
+ return false;
759
+ }
760
+ // Type filter
761
+ if (this.selectedType !== 'all' && model.AIModelTypeID !== this.selectedType) {
762
+ return false;
763
+ }
764
+ // Status filter
765
+ if (this.selectedStatus !== 'all') {
766
+ const isActive = model.IsActive === true;
767
+ if (this.selectedStatus === 'active' && !isActive)
768
+ return false;
769
+ if (this.selectedStatus === 'inactive' && isActive)
770
+ return false;
771
+ }
772
+ // Rank filters
773
+ if (model.PowerRank !== null && (model.PowerRank < this.powerRankRange.min || model.PowerRank > this.powerRankRange.max)) {
774
+ return false;
775
+ }
776
+ if (model.SpeedRank !== null && (model.SpeedRank < this.speedRankRange.min || model.SpeedRank > this.speedRankRange.max)) {
777
+ return false;
778
+ }
779
+ if (model.CostRank !== null && (model.CostRank < this.costRankRange.min || model.CostRank > this.costRankRange.max)) {
780
+ return false;
781
+ }
782
+ return true;
783
+ });
784
+ this.sortModels();
785
+ this.emitStateChange();
786
+ }
787
+ sortModels() {
788
+ this.filteredModels.sort((a, b) => {
789
+ const modelA = a;
790
+ const modelB = b;
791
+ switch (this.sortBy) {
792
+ case 'name':
793
+ return (modelA.Name || '').localeCompare(modelB.Name || '');
794
+ case 'vendor':
795
+ return (modelA.VendorName || '').localeCompare(modelB.VendorName || '');
796
+ case 'type':
797
+ return (modelA.ModelTypeName || '').localeCompare(modelB.ModelTypeName || '');
798
+ case 'powerRank':
799
+ return (modelB.PowerRank || 0) - (modelA.PowerRank || 0);
800
+ case 'speedRank':
801
+ return (modelB.SpeedRank || 0) - (modelA.SpeedRank || 0);
802
+ case 'costRank':
803
+ return (modelA.CostRank || 0) - (modelB.CostRank || 0);
804
+ case 'created':
805
+ return new Date(modelB.__mj_CreatedAt).getTime() - new Date(modelA.__mj_CreatedAt).getTime();
806
+ case 'updated':
807
+ return new Date(modelB.__mj_UpdatedAt).getTime() - new Date(modelA.__mj_UpdatedAt).getTime();
808
+ default:
809
+ return 0;
810
+ }
811
+ });
812
+ }
813
+ onVendorChange(vendorId) {
814
+ this.selectedVendor = vendorId;
815
+ this.applyFilters();
816
+ }
817
+ onTypeChange(typeId) {
818
+ this.selectedType = typeId;
819
+ this.applyFilters();
820
+ }
821
+ onStatusChange(status) {
822
+ this.selectedStatus = status;
823
+ this.applyFilters();
824
+ }
825
+ onSortChange(sortBy) {
826
+ this.sortBy = sortBy;
827
+ this.sortModels();
828
+ this.emitStateChange();
829
+ }
830
+ async toggleModelStatus(model, event) {
831
+ event.stopPropagation();
832
+ try {
833
+ model.IsActive = !model.IsActive;
834
+ if (await model.Save()) {
835
+ this.sharedService.CreateSimpleNotification(`Model ${model.IsActive ? 'activated' : 'deactivated'} successfully`, 'success', 3000);
836
+ }
837
+ else {
838
+ // Revert on failure
839
+ model.IsActive = !model.IsActive;
840
+ throw new Error('Failed to save model status');
841
+ }
842
+ }
843
+ catch (error) {
844
+ console.error('Error toggling model status:', error);
845
+ this.sharedService.CreateSimpleNotification('Error updating model status', 'error', 3000);
846
+ }
847
+ }
848
+ openModel(modelId) {
849
+ this.openEntityRecord.emit({
850
+ entityName: 'AI Models',
851
+ recordId: modelId
852
+ });
853
+ }
854
+ async createNewModel() {
855
+ try {
856
+ const md = new Metadata();
857
+ const newModel = await md.GetEntityObject('AI Models');
858
+ if (newModel) {
859
+ newModel.Name = 'New AI Model';
860
+ newModel.IsActive = true;
861
+ if (await newModel.Save()) {
862
+ this.openEntityRecord.emit({
863
+ entityName: 'AI Models',
864
+ recordId: newModel.ID
865
+ });
866
+ // Reload the data
867
+ await this.loadInitialData();
868
+ }
869
+ }
870
+ }
871
+ catch (error) {
872
+ console.error('Error creating new model:', error);
873
+ this.sharedService.CreateSimpleNotification('Error creating model', 'error', 3000);
874
+ }
875
+ }
876
+ getModelIcon(model) {
877
+ const typeName = model.ModelTypeName?.toLowerCase();
878
+ if (typeName?.includes('chat') || typeName?.includes('conversation')) {
879
+ return 'fa-solid fa-comments';
880
+ }
881
+ else if (typeName?.includes('image') || typeName?.includes('vision')) {
882
+ return 'fa-solid fa-image';
883
+ }
884
+ else if (typeName?.includes('audio') || typeName?.includes('speech')) {
885
+ return 'fa-solid fa-microphone';
886
+ }
887
+ else if (typeName?.includes('embed')) {
888
+ return 'fa-solid fa-vector-square';
889
+ }
890
+ return 'fa-solid fa-microchip';
891
+ }
892
+ getRankClass(rank, rankType) {
893
+ if (rank === null || rank === 0)
894
+ return 'rank-none';
895
+ // Determine which max value to use
896
+ let maxValue = 10;
897
+ if (rankType === 'power') {
898
+ maxValue = this.maxPowerRank;
899
+ }
900
+ else if (rankType === 'speed') {
901
+ maxValue = this.maxSpeedRank;
902
+ }
903
+ else if (rankType === 'cost') {
904
+ maxValue = this.maxCostRank;
905
+ }
906
+ // Calculate percentage of max
907
+ const percentage = (rank / maxValue) * 100;
908
+ if (percentage >= 70)
909
+ return 'rank-high';
910
+ if (percentage >= 40)
911
+ return 'rank-medium';
912
+ return 'rank-low';
913
+ }
914
+ emitStateChange() {
915
+ this.stateChange.emit({
916
+ viewMode: this.viewMode,
917
+ showFilters: this.showFilters,
918
+ searchTerm: this.searchTerm,
919
+ selectedVendor: this.selectedVendor,
920
+ selectedType: this.selectedType,
921
+ selectedStatus: this.selectedStatus,
922
+ sortBy: this.sortBy,
923
+ powerRankRange: this.powerRankRange,
924
+ speedRankRange: this.speedRankRange,
925
+ costRankRange: this.costRankRange,
926
+ modelCount: this.filteredModels.length
927
+ });
928
+ }
929
+ get hasActiveFilters() {
930
+ return this.searchTerm !== '' ||
931
+ this.selectedVendor !== 'all' ||
932
+ this.selectedType !== 'all' ||
933
+ this.selectedStatus !== 'all' ||
934
+ this.powerRankRange.min > 0 ||
935
+ this.powerRankRange.max < this.maxPowerRank ||
936
+ this.speedRankRange.min > 0 ||
937
+ this.speedRankRange.max < this.maxSpeedRank ||
938
+ this.costRankRange.min > 0 ||
939
+ this.costRankRange.max < this.maxCostRank;
940
+ }
941
+ clearFilters() {
942
+ this.searchTerm = '';
943
+ this.selectedVendor = 'all';
944
+ this.selectedType = 'all';
945
+ this.selectedStatus = 'all';
946
+ this.powerRankRange = { min: 0, max: this.maxPowerRank };
947
+ this.speedRankRange = { min: 0, max: this.maxSpeedRank };
948
+ this.costRankRange = { min: 0, max: this.maxCostRank };
949
+ this.searchSubject.next('');
950
+ this.applyFilters();
951
+ }
952
+ formatTokenLimit(limit) {
953
+ if (limit >= 1000000) {
954
+ return Math.floor(limit / 1000000) + 'M';
955
+ }
956
+ else if (limit >= 1000) {
957
+ return Math.floor(limit / 1000) + 'K';
958
+ }
959
+ return limit.toString();
960
+ }
961
+ validateAndApplyRankFilters(rankType) {
962
+ // Get the appropriate range and max value based on type
963
+ let range = rankType === 'power' ? this.powerRankRange :
964
+ rankType === 'speed' ? this.speedRankRange :
965
+ this.costRankRange;
966
+ let maxValue = rankType === 'power' ? this.maxPowerRank :
967
+ rankType === 'speed' ? this.maxSpeedRank :
968
+ this.maxCostRank;
969
+ // Ensure min is not greater than max
970
+ if (range.min > range.max) {
971
+ // Swap the values
972
+ const temp = range.min;
973
+ range.min = range.max;
974
+ range.max = temp;
975
+ }
976
+ // Ensure values are within bounds
977
+ range.min = Math.max(0, Math.min(maxValue, range.min));
978
+ range.max = Math.max(0, Math.min(maxValue, range.max));
979
+ // Apply the filters
980
+ this.applyFilters();
981
+ }
982
+ static ɵfac = function ModelManagementV2Component_Factory(t) { return new (t || ModelManagementV2Component)(i0.ɵɵdirectiveInject(i1.SharedService)); };
983
+ static ɵcmp = /*@__PURE__*/ i0.ɵɵdefineComponent({ type: ModelManagementV2Component, selectors: [["app-model-management-v2"]], inputs: { initialState: "initialState" }, outputs: { openEntityRecord: "openEntityRecord", stateChange: "stateChange" }, decls: 3, vars: 3, consts: [["mjFillContainer", "", 1, "model-management-v2", 3, "rightMargin", "bottomMargin"], [1, "loading-container"], [1, "loading-content"], [1, "loading-spinner"], [1, "spinner-ring"], [1, "loading-text"], [1, "dashboard-header", 2, "display", "flex !important", "justify-content", "space-between !important", "align-items", "center !important", "padding", "16px 24px !important", "background", "white !important"], [1, "header-info", 2, "display", "flex !important", "align-items", "center !important", "gap", "16px !important", "flex", "1 !important"], [1, "dashboard-title", 2, "margin", "0 !important", "display", "flex !important", "align-items", "center !important", "gap", "8px !important"], [1, "fa-solid", "fa-microchip"], ["type", "button", "title", "Toggle Filters", 1, "filter-toggle-btn", 3, "click"], [1, "fa-solid", "fa-filter"], [1, "item-count"], [1, "header-controls", 2, "display", "flex !important", "align-items", "center !important", "gap", "16px !important"], [1, "view-toggle"], ["type", "button", "title", "Grid View", 1, "view-btn", 3, "click"], [1, "fa-solid", "fa-grip"], ["type", "button", "title", "List View", 1, "view-btn", 3, "click"], [1, "fa-solid", "fa-list"], ["type", "button", "title", "Create New Model", 1, "control-btn", "primary", 3, "click"], [1, "fa-solid", "fa-plus"], ["mjFillContainer", "", "orientation", "horizontal"], ["size", "320", "min", "250", "max", "400"], [1, "content-area"], [1, "empty-state"], [1, "filter-panel"], [1, "filter-panel-header"], [1, "filter-summary-inline"], [1, "summary-value"], [1, "summary-label"], [1, "close-btn", 3, "click"], [1, "fa-solid", "fa-times"], [1, "filter-content"], [1, "filter-group"], [1, "filter-label"], [1, "fa-solid", "fa-search"], ["type", "text", "placeholder", "Search models...", 1, "filter-input", 3, "input", "value"], [1, "fa-solid", "fa-sort"], [1, "filter-select", 3, "change", "value"], [3, "value"], [1, "fa-solid", "fa-building"], ["value", "all"], [1, "fa-solid", "fa-toggle-on"], ["value", "active"], ["value", "inactive"], [1, "fa-solid", "fa-bolt"], [1, "rank-filter-inputs"], ["type", "number", "min", "0", "placeholder", "Min", 1, "rank-input", 3, "ngModelChange", "change", "max", "ngModel"], [1, "rank-separator"], ["type", "number", "min", "0", "placeholder", "Max", 1, "rank-input", 3, "ngModelChange", "change", "max", "ngModel"], [1, "filter-actions"], ["title", "Reset all filters", 1, "reset-btn", 3, "click"], [1, "fa-solid", "fa-undo"], [1, "fa-solid", "fa-microchip", "fa-4x"], [1, "primary-action"], [1, "primary-action", 3, "click"], [1, "model-grid"], [1, "model-list"], [1, "model-card", 3, "expanded"], [1, "model-card"], [1, "card-header", 3, "click"], [1, "card-icon"], [1, "card-info"], [1, "card-meta"], [1, "vendor"], [1, "type"], [1, "status", "active"], [1, "status", "inactive"], [1, "card-stats"], ["title", "Power Rank", 1, "stat-item"], ["title", "Speed Rank", 1, "stat-item"], [1, "fa-solid", "fa-gauge-high"], ["title", "Cost Rank", 1, "stat-item"], [1, "fa-solid", "fa-dollar-sign"], ["title", "Token Limit", 1, "stat-item"], [1, "fa-solid", "fa-chevron-down", "expand-icon"], [1, "card-content"], [1, "fa-solid", "fa-coins"], [1, "description-section"], [1, "ranks-section"], [1, "ranks-grid"], [1, "rank-item"], [1, "rank-label"], [1, "rank-value"], [1, "stats-grid"], [1, "stat"], [1, "stat-label"], [1, "stat-value"], [1, "card-footer"], [1, "action-button", 3, "click"], [1, "fa-solid", "fa-edit"], [1, "data-table"], [1, "name-cell"], [1, "rank-badge"], [1, "status-badge"], [1, "action-button", "small", 3, "click"]], template: function ModelManagementV2Component_Template(rf, ctx) { if (rf & 1) {
984
+ i0.ɵɵelementStart(0, "div", 0);
985
+ i0.ɵɵtemplate(1, ModelManagementV2Component_Conditional_1_Template, 8, 1, "div", 1)(2, ModelManagementV2Component_Conditional_2_Template, 26, 8);
986
+ i0.ɵɵelementEnd();
987
+ } if (rf & 2) {
988
+ i0.ɵɵproperty("rightMargin", 8)("bottomMargin", 8);
989
+ i0.ɵɵadvance();
990
+ i0.ɵɵconditional(ctx.isLoading ? 1 : 2);
991
+ } }, dependencies: [i2.NgSelectOption, i2.ɵNgSelectMultipleOption, i2.DefaultValueAccessor, i2.NumberValueAccessor, i2.NgControlStatus, i2.MinValidator, i2.MaxValidator, i2.NgModel, i3.SplitterComponent, i3.SplitterPaneComponent, i4.FillContainer], styles: [".model-management-v2[_ngcontent-%COMP%] {\n height: 100%;\n display: flex;\n flex-direction: column;\n background-color: #f5f7fa;\n}\n\n//[_ngcontent-%COMP%] Loading[_ngcontent-%COMP%] state\n.loading-container[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n justify-content: center;\n height: 100%;\n background-color: #f5f7fa;\n}\n\n.loading-content[_ngcontent-%COMP%] {\n text-align: center;\n}\n\n.loading-spinner[_ngcontent-%COMP%] {\n position: relative;\n width: 80px;\n height: 80px;\n margin: 0 auto 20px;\n}\n\n.spinner-ring[_ngcontent-%COMP%] {\n position: absolute;\n width: 100%;\n height: 100%;\n border: 3px solid transparent;\n border-top-color: #17a2b8;\n border-radius: 50%;\n animation: _ngcontent-%COMP%_spin 1.5s cubic-bezier(0.68, -0.55, 0.265, 1.55) infinite;\n \n &:nth-child(2) {\n animation-delay: 0.15s;\n width: 70%;\n height: 70%;\n top: 15%;\n left: 15%;\n border-top-color: #28a745;\n }\n \n &:nth-child(3) {\n animation-delay: 0.3s;\n width: 40%;\n height: 40%;\n top: 30%;\n left: 30%;\n border-top-color: #ffc107;\n }\n}\n\n@keyframes _ngcontent-%COMP%_spin {\n 0% { transform: rotate(0deg); }\n 100% { transform: rotate(360deg); }\n}\n\n.loading-text[_ngcontent-%COMP%] {\n color: #6c757d;\n font-size: 16px;\n animation: _ngcontent-%COMP%_pulse 2s ease-in-out infinite;\n}\n\n@keyframes _ngcontent-%COMP%_pulse {\n 0%, 100% { opacity: 0.6; }\n 50% { opacity: 1; }\n}\n\n//[_ngcontent-%COMP%] Dashboard[_ngcontent-%COMP%] Header\n.dashboard-header[_ngcontent-%COMP%] {\n background: white;\n padding: 16px 24px;\n border-bottom: 1px solid #e0e6ed;\n display: flex;\n justify-content: space-between;\n align-items: center;\n box-shadow: 0 2px 4px rgba(0,0,0,0.04);\n}\n\n.header-info[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n gap: 16px;\n}\n\n.dashboard-title[_ngcontent-%COMP%] {\n margin: 0;\n font-size: 20px;\n font-weight: 600;\n color: #2c3e50;\n display: flex;\n align-items: center;\n gap: 8px;\n}\n\n.dashboard-title[_ngcontent-%COMP%] i[_ngcontent-%COMP%] {\n color: #17a2b8;\n}\n\n.filter-toggle-btn[_ngcontent-%COMP%] {\n background: #f8f9fa;\n border: 1px solid #dee2e6;\n padding: 8px 16px;\n border-radius: 6px;\n font-size: 14px;\n color: #495057;\n cursor: pointer;\n transition: all 0.2s ease;\n display: flex;\n align-items: center;\n gap: 8px;\n}\n\n.filter-toggle-btn[_ngcontent-%COMP%]:hover {\n background: #e9ecef;\n border-color: #ced4da;\n}\n\n.item-count[_ngcontent-%COMP%] {\n color: #6c757d;\n font-size: 14px;\n font-weight: 500;\n}\n\n.header-controls[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n gap: 16px;\n}\n\n//[_ngcontent-%COMP%] View[_ngcontent-%COMP%] Toggle\n.view-toggle[_ngcontent-%COMP%] {\n display: flex;\n background: #f8f9fa;\n border-radius: 6px;\n padding: 2px;\n border: 1px solid #dee2e6;\n}\n\n.view-btn[_ngcontent-%COMP%] {\n background: transparent;\n border: none;\n padding: 6px 12px;\n border-radius: 4px;\n color: #6c757d;\n cursor: pointer;\n transition: all 0.2s ease;\n font-size: 16px;\n}\n\n.view-btn[_ngcontent-%COMP%]:hover {\n color: #495057;\n}\n\n.view-btn.active[_ngcontent-%COMP%] {\n background: white;\n color: #17a2b8;\n box-shadow: 0 1px 2px rgba(0,0,0,0.08);\n}\n\n//[_ngcontent-%COMP%] Control[_ngcontent-%COMP%] Buttons\n.control-btn[_ngcontent-%COMP%] {\n background: #f8f9fa;\n border: 1px solid #dee2e6;\n padding: 10px 20px;\n border-radius: 6px;\n font-size: 14px;\n font-weight: 500;\n color: #495057;\n cursor: pointer;\n transition: all 0.2s ease;\n display: flex;\n align-items: center;\n gap: 8px;\n}\n\n.control-btn[_ngcontent-%COMP%]:hover {\n background: #e9ecef;\n border-color: #ced4da;\n}\n\n.control-btn.primary[_ngcontent-%COMP%] {\n background: #17a2b8;\n border-color: #17a2b8;\n color: white;\n}\n\n.control-btn.primary[_ngcontent-%COMP%]:hover {\n background: #138496;\n border-color: #117a8b;\n transform: translateY(-1px);\n box-shadow: 0 2px 8px rgba(23, 162, 184, 0.3);\n}\n\n//[_ngcontent-%COMP%] Splitter[_ngcontent-%COMP%] content\nkendo-splitter[_ngcontent-%COMP%] {\n flex: 1;\n background-color: #f5f7fa;\n margin-top: 8px;\n}\n\n//[_ngcontent-%COMP%] Filter[_ngcontent-%COMP%] panel\n.filter-panel[_ngcontent-%COMP%] {\n height: 100%;\n background: white;\n border-right: 1px solid #e0e0e0;\n display: flex;\n flex-direction: column;\n overflow: hidden;\n}\n\n.filter-panel-header[_ngcontent-%COMP%] {\n padding: 16px;\n border-bottom: 1px solid #f0f0f0;\n display: flex;\n align-items: center;\n justify-content: space-between;\n flex-shrink: 0;\n \n h3 {\n margin: 0;\n font-size: 16px;\n font-weight: 500;\n color: #333;\n flex: 1;\n }\n \n .filter-summary-inline {\n display: flex;\n align-items: baseline;\n gap: 4px;\n margin-right: 12px;\n font-size: 12px;\n \n .summary-value {\n font-weight: 600;\n color: #2196f3;\n }\n \n .summary-label {\n color: #666;\n }\n }\n \n .close-btn {\n background: none;\n border: none;\n padding: 4px;\n cursor: pointer;\n color: #666;\n border-radius: 3px;\n transition: all 0.2s;\n \n &:hover {\n background: #f0f0f0;\n color: #333;\n }\n \n .fa-solid {\n font-size: 12px;\n }\n }\n}\n\n.filter-content[_ngcontent-%COMP%] {\n flex: 1;\n overflow-y: auto;\n overflow-x: hidden;\n padding: 12px;\n}\n\n.filter-group[_ngcontent-%COMP%] {\n margin-bottom: 20px;\n \n .filter-label {\n display: flex;\n align-items: center;\n gap: 8px;\n margin-bottom: 6px;\n font-size: 12px;\n font-weight: 500;\n color: #555;\n \n .fa-solid {\n font-size: 11px;\n color: #2196f3;\n width: 12px;\n }\n }\n}\n\n.filter-input[_ngcontent-%COMP%], .filter-select[_ngcontent-%COMP%] {\n width: calc(100% - 4px);\n max-width: 100%;\n padding: 8px 10px;\n border: 1px solid #ddd;\n border-radius: 4px;\n font-size: 12px;\n background: white;\n transition: border-color 0.2s;\n box-sizing: border-box;\n \n &:focus {\n outline: none;\n border-color: #2196f3;\n }\n \n &::placeholder {\n color: #999;\n }\n}\n\n.filter-select[_ngcontent-%COMP%] {\n cursor: pointer;\n}\n\n.rank-filter-inputs[_ngcontent-%COMP%] {\n display: flex;\n gap: 8px;\n align-items: center;\n margin-top: 6px;\n}\n\n.rank-input[_ngcontent-%COMP%] {\n width: 60px;\n padding: 6px 8px;\n border: 1px solid #ddd;\n border-radius: 4px;\n font-size: 12px;\n text-align: center;\n background: white;\n transition: border-color 0.2s;\n box-sizing: border-box;\n \n &:focus {\n outline: none;\n border-color: #2196f3;\n }\n \n &::placeholder {\n color: #999;\n font-size: 11px;\n }\n \n // Hide spinner buttons for cleaner look\n &::-webkit-inner-spin-button,\n &::-webkit-outer-spin-button {\n -webkit-appearance: none;\n margin: 0;\n }\n \n -moz-appearance: textfield;\n}\n\n.rank-separator[_ngcontent-%COMP%] {\n color: #999;\n font-size: 12px;\n font-weight: 500;\n}\n\n.filter-actions[_ngcontent-%COMP%] {\n margin-top: 24px;\n padding-top: 16px;\n border-top: 1px solid #f0f0f0;\n \n .reset-btn {\n width: calc(100% - 4px);\n max-width: 100%;\n padding: 8px 12px;\n background: #f8f9fa;\n border: 1px solid #e0e0e0;\n border-radius: 4px;\n color: #666;\n font-size: 12px;\n cursor: pointer;\n display: flex;\n align-items: center;\n justify-content: center;\n gap: 6px;\n transition: all 0.2s;\n box-sizing: border-box;\n \n &:hover {\n background: #e9ecef;\n border-color: #ccc;\n color: #333;\n }\n \n .fa-solid {\n font-size: 11px;\n }\n }\n}\n\n//[_ngcontent-%COMP%] Content[_ngcontent-%COMP%] area\n.content-area[_ngcontent-%COMP%] {\n height: 100%;\n padding: 24px;\n overflow-y: auto;\n background: #f5f7fa;\n}\n\n//[_ngcontent-%COMP%] Empty[_ngcontent-%COMP%] state\n.empty-state[_ngcontent-%COMP%] {\n display: flex;\n flex-direction: column;\n align-items: center;\n justify-content: center;\n height: 100%;\n text-align: center;\n color: #6c757d;\n \n i {\n margin-bottom: 24px;\n opacity: 0.3;\n }\n \n h3 {\n margin: 0 0 8px 0;\n font-size: 20px;\n font-weight: 600;\n color: #495057;\n }\n \n p {\n margin: 0 0 24px 0;\n font-size: 16px;\n }\n}\n\n//[_ngcontent-%COMP%] Grid[_ngcontent-%COMP%] view\n.model-grid[_ngcontent-%COMP%] {\n display: grid;\n grid-template-columns: repeat(auto-fill, minmax(380px, 1fr));\n}\n\n.model-card[_ngcontent-%COMP%] {\n margin: 20px; // instead of gap in grid, for some reason that didn't work\n background: white;\n border-radius: 12px;\n box-shadow: 0 2px 8px rgba(0, 0, 0, 0.04);\n border: 1px solid #e0e6ed;\n transition: all 0.3s ease;\n overflow: hidden;\n \n &:hover {\n transform: translateY(-2px);\n box-shadow: 0 4px 16px rgba(0, 0, 0, 0.08);\n }\n \n &.expanded {\n box-shadow: 0 4px 20px rgba(0, 0, 0, 0.12);\n .expand-icon {\n transform: rotate(180deg);\n }\n }\n}\n\n.card-header[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n padding: 20px;\n cursor: pointer;\n transition: background-color 0.2s ease;\n \n &:hover {\n background-color: #f8f9fa;\n }\n}\n\n.card-icon[_ngcontent-%COMP%] {\n width: 48px;\n height: 48px;\n background-color: #e3f2fd;\n border-radius: 10px;\n display: flex;\n align-items: center;\n justify-content: center;\n margin-right: 16px;\n flex-shrink: 0;\n \n i {\n font-size: 24px;\n color: #17a2b8;\n }\n}\n\n.card-info[_ngcontent-%COMP%] {\n flex: 1;\n min-width: 0;\n \n h4 {\n margin: 0 0 4px 0;\n font-size: 16px;\n font-weight: 600;\n color: #2c3e50;\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n }\n}\n\n.card-meta[_ngcontent-%COMP%] {\n display: flex;\n gap: 12px;\n font-size: 13px;\n color: #6c757d;\n margin-bottom: 8px;\n \n .vendor, .type, .status {\n display: flex;\n align-items: center;\n gap: 4px;\n \n &::before {\n content: '\u2022';\n color: #dee2e6;\n }\n \n &:first-child::before {\n display: none;\n }\n }\n \n .status {\n font-weight: 500;\n \n &.active {\n color: #28a745;\n }\n \n &.inactive {\n color: #dc3545;\n }\n }\n}\n\n.card-stats[_ngcontent-%COMP%] {\n display: flex;\n gap: 16px;\n font-size: 12px;\n color: #495057;\n \n .stat-item {\n display: flex;\n align-items: center;\n gap: 4px;\n \n i {\n font-size: 11px;\n color: #6c757d;\n }\n }\n}\n\n.expand-icon[_ngcontent-%COMP%] {\n color: #adb5bd;\n transition: transform 0.3s ease;\n margin-left: 12px;\n}\n\n.card-content[_ngcontent-%COMP%] {\n padding: 0 20px 20px;\n animation: slideDown 0.3s ease;\n}\n\n@keyframes _ngcontent-%COMP%_slideDown {\n from {\n opacity: 0;\n transform: translateY(-10px);\n }\n to {\n opacity: 1;\n transform: translateY(0);\n }\n}\n\n.description-section[_ngcontent-%COMP%] {\n margin-bottom: 16px;\n \n h5 {\n margin: 0 0 8px 0;\n font-size: 13px;\n font-weight: 600;\n color: #6c757d;\n text-transform: uppercase;\n letter-spacing: 0.5px;\n }\n \n p {\n margin: 0;\n font-size: 14px;\n color: #495057;\n line-height: 1.6;\n }\n}\n\n.ranks-section[_ngcontent-%COMP%] {\n margin-bottom: 16px;\n \n h5 {\n margin: 0 0 12px 0;\n font-size: 13px;\n font-weight: 600;\n color: #6c757d;\n text-transform: uppercase;\n letter-spacing: 0.5px;\n }\n}\n\n.ranks-grid[_ngcontent-%COMP%] {\n display: grid;\n grid-template-columns: repeat(3, 1fr);\n gap: 12px;\n margin-bottom: 16px;\n}\n\n.rank-item[_ngcontent-%COMP%] {\n background-color: #f8f9fa;\n border-radius: 8px;\n padding: 12px;\n text-align: center;\n \n .rank-label {\n display: block;\n font-size: 12px;\n color: #6c757d;\n margin-bottom: 4px;\n \n i {\n margin-right: 4px;\n }\n }\n \n .rank-value {\n display: block;\n font-size: 18px;\n font-weight: 600;\n \n &.rank-high {\n color: #28a745;\n }\n \n &.rank-medium {\n color: #ffc107;\n }\n \n &.rank-low {\n color: #dc3545;\n }\n \n &.rank-none {\n color: #6c757d;\n }\n }\n}\n\n.stats-grid[_ngcontent-%COMP%] {\n display: grid;\n grid-template-columns: repeat(3, 1fr);\n gap: 16px;\n margin-bottom: 16px;\n}\n\n.stat[_ngcontent-%COMP%] {\n text-align: center;\n display: flex;\n flex-direction: column;\n align-items: center;\n \n .stat-label {\n display: block;\n font-size: 12px;\n color: #6c757d;\n margin-bottom: 4px;\n }\n \n .stat-value {\n font-size: 14px;\n font-weight: 500;\n color: #2c3e50;\n display: flex;\n align-items: center;\n justify-content: center;\n \n // Special case for toggle switches - ensure they don't expand\n .toggle-switch {\n display: inline-block !important;\n vertical-align: middle;\n }\n }\n}\n\n//[_ngcontent-%COMP%] Toggle[_ngcontent-%COMP%] switch\n.toggle-switch[_ngcontent-%COMP%] {\n position: relative;\n display: inline-block !important;\n width: 44px !important;\n height: 24px !important;\n flex-shrink: 0;\n \n &.small {\n width: 36px !important;\n height: 20px !important;\n }\n \n input {\n opacity: 0;\n width: 0;\n height: 0;\n \n &:checked + .toggle-slider {\n background-color: #28a745;\n \n &::before {\n transform: translateX(20px);\n }\n }\n }\n}\n\n.toggle-slider[_ngcontent-%COMP%] {\n position: absolute;\n cursor: pointer;\n top: 0;\n left: 0;\n right: 0;\n bottom: 0;\n background-color: #ccc;\n transition: .3s;\n border-radius: 24px;\n \n &::before {\n position: absolute;\n content: \"\";\n height: 18px;\n width: 18px;\n left: 3px;\n bottom: 3px;\n background-color: white;\n transition: .3s;\n border-radius: 50%;\n }\n \n .small & {\n &::before {\n height: 14px;\n width: 14px;\n }\n }\n}\n\n.card-footer[_ngcontent-%COMP%] {\n padding-top: 16px;\n border-top: 1px solid #e9ecef;\n display: flex;\n gap: 8px;\n}\n\n.action-button[_ngcontent-%COMP%] {\n padding: 6px 12px;\n background-color: #f8f9fa;\n border: 1px solid #dee2e6;\n border-radius: 4px;\n color: #495057;\n font-size: 13px;\n cursor: pointer;\n transition: all 0.2s ease;\n \n &:hover {\n background-color: #e9ecef;\n border-color: #adb5bd;\n color: #212529;\n }\n \n &.small {\n padding: 4px 8px;\n font-size: 12px;\n }\n \n i {\n margin-right: 4px;\n }\n}\n\n//[_ngcontent-%COMP%] List[_ngcontent-%COMP%] view\n.model-list[_ngcontent-%COMP%] {\n background: white;\n border-radius: 12px;\n box-shadow: 0 2px 8px rgba(0, 0, 0, 0.04);\n border: 1px solid #e0e6ed;\n overflow: hidden;\n}\n\n.data-table[_ngcontent-%COMP%] {\n width: 100%;\n border-collapse: collapse;\n \n thead {\n background-color: #f8f9fa;\n \n tr {\n border-bottom: 2px solid #dee2e6;\n }\n \n th {\n padding: 12px 16px;\n text-align: left;\n font-size: 13px;\n font-weight: 600;\n color: #495057;\n text-transform: uppercase;\n letter-spacing: 0.5px;\n }\n }\n \n tbody {\n tr {\n border-bottom: 1px solid #e9ecef;\n transition: background-color 0.2s ease;\n \n &:hover {\n background-color: #f8f9fa;\n }\n \n &:last-child {\n border-bottom: none;\n }\n }\n \n td {\n padding: 16px;\n font-size: 14px;\n color: #495057;\n }\n }\n}\n\n.name-cell[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n gap: 8px;\n font-weight: 500;\n color: #2c3e50;\n \n i {\n color: #17a2b8;\n }\n}\n\n.rank-badge[_ngcontent-%COMP%] {\n display: inline-block;\n padding: 4px 8px;\n border-radius: 4px;\n font-size: 12px;\n font-weight: 500;\n background-color: #f8f9fa;\n \n &.rank-high {\n background-color: #d4edda;\n color: #155724;\n }\n \n &.rank-medium {\n background-color: #fff3cd;\n color: #856404;\n }\n \n &.rank-low {\n background-color: #f8d7da;\n color: #721c24;\n }\n \n &.rank-none {\n background-color: #e9ecef;\n color: #6c757d;\n }\n}\n\n.status-badge[_ngcontent-%COMP%] {\n display: inline-block;\n padding: 4px 8px;\n border-radius: 4px;\n font-size: 12px;\n font-weight: 500;\n \n &.active {\n background-color: #d4edda;\n color: #155724;\n }\n \n &.inactive {\n background-color: #f8d7da;\n color: #721c24;\n }\n}\n\n//[_ngcontent-%COMP%] Responsive\n@media[_ngcontent-%COMP%] (max-width[_ngcontent-%COMP%]: 768px)[_ngcontent-%COMP%] {\n .model-header {\n flex-wrap: wrap;\n gap: 16px;\n }\n \n .header-right {\n width: 100%;\n justify-content: space-between;\n }\n \n .model-grid {\n grid-template-columns: 1fr;\n }\n \n .stats-grid,\n .ranks-grid {\n grid-template-columns: 1fr;\n }\n}"] });
992
+ }
993
+ (() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassMetadata(ModelManagementV2Component, [{
994
+ type: Component,
995
+ args: [{ selector: 'app-model-management-v2', template: "<div class=\"model-management-v2\" mjFillContainer [rightMargin]=\"8\" [bottomMargin]=\"8\">\n @if (isLoading) {\n <div class=\"loading-container\">\n <div class=\"loading-content\">\n <div class=\"loading-spinner\">\n <div class=\"spinner-ring\"></div>\n <div class=\"spinner-ring\"></div>\n <div class=\"spinner-ring\"></div>\n </div>\n <div class=\"loading-text\">{{ currentLoadingMessage }}</div>\n </div>\n </div>\n } @else {\n <div class=\"dashboard-header\" style=\"display: flex !important; justify-content: space-between !important; align-items: center !important; padding: 16px 24px !important; background: white !important;\">\n <div class=\"header-info\" style=\"display: flex !important; align-items: center !important; gap: 16px !important; flex: 1 !important;\">\n <h2 class=\"dashboard-title\" style=\"margin: 0 !important; display: flex !important; align-items: center !important; gap: 8px !important;\">\n <i class=\"fa-solid fa-microchip\"></i>\n AI Models\n </h2>\n <button \n type=\"button\" \n class=\"filter-toggle-btn\"\n (click)=\"toggleFilters()\"\n title=\"Toggle Filters\">\n <i class=\"fa-solid fa-filter\"></i>\n @if (showFilters) {\n Hide Filters\n } @else {\n Show Filters\n }\n </button>\n <span class=\"item-count\">{{ filteredModels.length }} models</span>\n </div>\n \n <div class=\"header-controls\" style=\"display: flex !important; align-items: center !important; gap: 16px !important;\">\n <div class=\"view-toggle\">\n <button \n type=\"button\" \n class=\"view-btn\"\n [class.active]=\"viewMode === 'grid'\"\n (click)=\"setViewMode('grid')\"\n title=\"Grid View\">\n <i class=\"fa-solid fa-grip\"></i>\n </button>\n <button \n type=\"button\" \n class=\"view-btn\"\n [class.active]=\"viewMode === 'list'\"\n (click)=\"setViewMode('list')\"\n title=\"List View\">\n <i class=\"fa-solid fa-list\"></i>\n </button>\n </div>\n \n <button \n type=\"button\" \n class=\"control-btn primary\"\n (click)=\"createNewModel()\"\n title=\"Create New Model\">\n <i class=\"fa-solid fa-plus\"></i>\n New Model\n </button>\n </div>\n </div>\n\n <kendo-splitter mjFillContainer orientation=\"horizontal\">\n @if (showFilters) {\n <kendo-splitter-pane size=\"320\" min=\"250\" max=\"400\">\n <div class=\"filter-panel\">\n <div class=\"filter-panel-header\">\n <h3>Model Filters</h3>\n <div class=\"filter-summary-inline\">\n <span class=\"summary-value\">{{ filteredModels.length }}</span>\n <span class=\"summary-label\">of {{ models.length }}</span>\n </div>\n <button class=\"close-btn\" (click)=\"toggleFilterPanel()\">\n <span class=\"fa-solid fa-times\"></span>\n </button>\n </div>\n \n <div class=\"filter-content\">\n <!-- Search Filter -->\n <div class=\"filter-group\">\n <label class=\"filter-label\">\n <span class=\"fa-solid fa-search\"></span>\n Name\n </label>\n <input \n type=\"text\"\n class=\"filter-input\"\n placeholder=\"Search models...\"\n [value]=\"searchTerm\"\n (input)=\"onSearchChange($any($event.target).value)\"\n />\n </div>\n\n <!-- Sort By Filter -->\n <div class=\"filter-group\">\n <label class=\"filter-label\">\n <span class=\"fa-solid fa-sort\"></span>\n Sort By\n </label>\n <select class=\"filter-select\" [value]=\"sortBy\" (change)=\"onSortChange($any($event.target).value)\">\n @for (option of sortOptions; track option.value) {\n <option [value]=\"option.value\">{{ option.label }}</option>\n }\n </select>\n </div>\n\n <!-- Vendor Filter -->\n <div class=\"filter-group\">\n <label class=\"filter-label\">\n <span class=\"fa-solid fa-building\"></span>\n Vendor\n </label>\n <select class=\"filter-select\" [value]=\"selectedVendor\" (change)=\"onVendorChange($any($event.target).value)\">\n <option value=\"all\">All Vendors</option>\n @for (vendor of vendors; track vendor.ID) {\n <option [value]=\"vendor.ID\">{{ vendor.Name }}</option>\n }\n </select>\n </div>\n\n <!-- Type Filter -->\n <div class=\"filter-group\">\n <label class=\"filter-label\">\n <span class=\"fa-solid fa-microchip\"></span>\n Type\n </label>\n <select class=\"filter-select\" [value]=\"selectedType\" (change)=\"onTypeChange($any($event.target).value)\">\n <option value=\"all\">All Types</option>\n @for (type of modelTypes; track type.ID) {\n <option [value]=\"type.ID\">{{ type.Name }}</option>\n }\n </select>\n </div>\n\n <!-- Status Filter -->\n <div class=\"filter-group\">\n <label class=\"filter-label\">\n <span class=\"fa-solid fa-toggle-on\"></span>\n Status\n </label>\n <select class=\"filter-select\" [value]=\"selectedStatus\" (change)=\"onStatusChange($any($event.target).value)\">\n <option value=\"all\">All Statuses</option>\n <option value=\"active\">Active</option>\n <option value=\"inactive\">Inactive</option>\n </select>\n </div>\n\n <!-- Power Rank Filter -->\n <div class=\"filter-group\">\n <label class=\"filter-label\">\n <span class=\"fa-solid fa-bolt\"></span>\n Power Rank\n </label>\n <div class=\"rank-filter-inputs\">\n <input \n type=\"number\" \n min=\"0\" \n [max]=\"maxPowerRank\" \n [(ngModel)]=\"powerRankRange.min\"\n (change)=\"validateAndApplyRankFilters('power')\"\n class=\"rank-input\"\n placeholder=\"Min\"\n />\n <span class=\"rank-separator\">-</span>\n <input \n type=\"number\" \n min=\"0\" \n [max]=\"maxPowerRank\" \n [(ngModel)]=\"powerRankRange.max\"\n (change)=\"validateAndApplyRankFilters('power')\"\n class=\"rank-input\"\n placeholder=\"Max\"\n />\n </div>\n </div>\n\n <!-- Reset Button -->\n <div class=\"filter-actions\">\n <button class=\"reset-btn\" (click)=\"clearFilters()\" title=\"Reset all filters\">\n <span class=\"fa-solid fa-undo\"></span>\n Reset Filters\n </button>\n </div>\n </div>\n </div>\n </kendo-splitter-pane>\n }\n\n <kendo-splitter-pane>\n <div class=\"content-area\">\n @if (filteredModels.length === 0) {\n <div class=\"empty-state\">\n <i class=\"fa-solid fa-microchip fa-4x\"></i>\n <h3>No models found</h3>\n <p>{{ hasActiveFilters ? 'Try adjusting your filters' : 'Create your first AI model to get started' }}</p>\n @if (!hasActiveFilters) {\n <button class=\"primary-action\" (click)=\"createNewModel()\">\n <i class=\"fa-solid fa-plus\"></i>\n Create First Model\n </button>\n }\n </div>\n } @else {\n @switch (viewMode) {\n @case ('grid') {\n <div class=\"model-grid\">\n @for (model of filteredModels; track model.ID) {\n <div class=\"model-card\" [class.expanded]=\"expandedModelId === model.ID\">\n <div class=\"card-header\" (click)=\"toggleModelExpansion(model.ID)\">\n <div class=\"card-icon\">\n <i [class]=\"getModelIcon(model)\"></i>\n </div>\n <div class=\"card-info\">\n <h4>{{ model.Name || 'Unnamed Model' }}</h4>\n <div class=\"card-meta\">\n @if (model.Vendor) {\n <span class=\"vendor\">{{ model.Vendor }}</span>\n }\n <span class=\"type\">{{ model.AIModelType }}</span>\n @if (model.IsActive) {\n <span class=\"status active\">Active</span>\n } @else {\n <span class=\"status inactive\">Inactive</span>\n }\n </div>\n <div class=\"card-stats\">\n <span class=\"stat-item\" title=\"Power Rank\">\n <i class=\"fa-solid fa-bolt\"></i> {{ formatRank(model.PowerRank, 'power') }}\n </span>\n <span class=\"stat-item\" title=\"Speed Rank\">\n <i class=\"fa-solid fa-gauge-high\"></i> {{ formatRank(model.SpeedRank, 'speed') }}\n </span>\n <span class=\"stat-item\" title=\"Cost Rank\">\n <i class=\"fa-solid fa-dollar-sign\"></i> {{ formatRank(model.CostRank, 'cost') }}\n </span>\n @if (model.InputTokenLimit) {\n <span class=\"stat-item\" title=\"Token Limit\">\n <i class=\"fa-solid fa-coins\"></i> {{ formatTokenLimit(model.InputTokenLimit) }}\n </span>\n }\n </div>\n </div>\n <i class=\"fa-solid fa-chevron-down expand-icon\" [class.rotated]=\"expandedModelId === model.ID\"></i>\n </div>\n\n @if (expandedModelId === model.ID) {\n <div class=\"card-content\">\n @if (model.Description) {\n <div class=\"description-section\">\n <h5>Description</h5>\n <p>{{ model.Description }}</p>\n </div>\n }\n\n <div class=\"ranks-section\">\n <h5>Performance Rankings</h5>\n <div class=\"ranks-grid\">\n <div class=\"rank-item\">\n <span class=\"rank-label\">\n <i class=\"fa-solid fa-bolt\"></i> Power\n </span>\n <span class=\"rank-value\" [class]=\"getRankClass(model.PowerRank, 'power')\">\n {{ formatRank(model.PowerRank, 'power') }}\n </span>\n </div>\n <div class=\"rank-item\">\n <span class=\"rank-label\">\n <i class=\"fa-solid fa-gauge-high\"></i> Speed\n </span>\n <span class=\"rank-value\" [class]=\"getRankClass(model.SpeedRank, 'speed')\">\n {{ formatRank(model.SpeedRank, 'speed') }}\n </span>\n </div>\n <div class=\"rank-item\">\n <span class=\"rank-label\">\n <i class=\"fa-solid fa-dollar-sign\"></i> Cost\n </span>\n <span class=\"rank-value\" [class]=\"getRankClass(model.CostRank, 'cost')\">\n {{ formatRank(model.CostRank, 'cost') }}\n </span>\n </div>\n </div>\n </div>\n\n <div class=\"stats-grid\">\n <div class=\"stat\">\n <span class=\"stat-label\">Status</span>\n <span class=\"stat-value\">{{ model.IsActive ? 'Active' : 'Inactive' }}</span>\n </div>\n <div class=\"stat\">\n <span class=\"stat-label\">API Name</span>\n <span class=\"stat-value\">{{ model.APIName || 'N/A' }}</span>\n </div>\n <div class=\"stat\">\n <span class=\"stat-label\">Driver</span>\n <span class=\"stat-value\">{{ model.DriverClass || 'N/A' }}</span>\n </div>\n </div>\n\n <div class=\"card-footer\">\n <button class=\"action-button\" (click)=\"openModel(model.ID); $event.stopPropagation()\">\n <i class=\"fa-solid fa-edit\"></i>\n Edit\n </button>\n </div>\n </div>\n }\n </div>\n }\n </div>\n }\n \n @case ('list') {\n <div class=\"model-list\">\n <table class=\"data-table\">\n <thead>\n <tr>\n <th>Name</th>\n <th>Vendor</th>\n <th>Type</th>\n <th>Power</th>\n <th>Speed</th>\n <th>Cost</th>\n <th>Status</th>\n <th>Actions</th>\n </tr>\n </thead>\n <tbody>\n @for (model of filteredModels; track model.ID) {\n <tr>\n <td>\n <div class=\"name-cell\">\n <i [class]=\"getModelIcon(model)\"></i>\n {{ model.Name || 'Unnamed Model' }}\n </div>\n </td>\n <td>{{ model.Vendor || '-' }}</td>\n <td>{{ model.AIModelType }}</td>\n <td>\n <span class=\"rank-badge\" [class]=\"getRankClass(model.PowerRank, 'power')\">\n {{ formatRank(model.PowerRank, 'power') }}\n </span>\n </td>\n <td>\n <span class=\"rank-badge\" [class]=\"getRankClass(model.SpeedRank, 'speed')\">\n {{ formatRank(model.SpeedRank, 'speed') }}\n </span>\n </td>\n <td>\n <span class=\"rank-badge\" [class]=\"getRankClass(model.CostRank, 'cost')\">\n {{ formatRank(model.CostRank, 'cost') }}\n </span>\n </td>\n <td>\n <span class=\"status-badge\" [class.active]=\"model.IsActive\" [class.inactive]=\"!model.IsActive\">\n {{ model.IsActive ? 'Active' : 'Inactive' }}\n </span>\n </td>\n <td>\n <button class=\"action-button small\" (click)=\"openModel(model.ID)\">\n <i class=\"fa-solid fa-edit\"></i>\n </button>\n </td>\n </tr>\n }\n </tbody>\n </table>\n </div>\n }\n }\n }\n </div>\n </kendo-splitter-pane>\n </kendo-splitter>\n }\n</div>", styles: [".model-management-v2 {\n height: 100%;\n display: flex;\n flex-direction: column;\n background-color: #f5f7fa;\n}\n\n// Loading state\n.loading-container {\n display: flex;\n align-items: center;\n justify-content: center;\n height: 100%;\n background-color: #f5f7fa;\n}\n\n.loading-content {\n text-align: center;\n}\n\n.loading-spinner {\n position: relative;\n width: 80px;\n height: 80px;\n margin: 0 auto 20px;\n}\n\n.spinner-ring {\n position: absolute;\n width: 100%;\n height: 100%;\n border: 3px solid transparent;\n border-top-color: #17a2b8;\n border-radius: 50%;\n animation: spin 1.5s cubic-bezier(0.68, -0.55, 0.265, 1.55) infinite;\n \n &:nth-child(2) {\n animation-delay: 0.15s;\n width: 70%;\n height: 70%;\n top: 15%;\n left: 15%;\n border-top-color: #28a745;\n }\n \n &:nth-child(3) {\n animation-delay: 0.3s;\n width: 40%;\n height: 40%;\n top: 30%;\n left: 30%;\n border-top-color: #ffc107;\n }\n}\n\n@keyframes spin {\n 0% { transform: rotate(0deg); }\n 100% { transform: rotate(360deg); }\n}\n\n.loading-text {\n color: #6c757d;\n font-size: 16px;\n animation: pulse 2s ease-in-out infinite;\n}\n\n@keyframes pulse {\n 0%, 100% { opacity: 0.6; }\n 50% { opacity: 1; }\n}\n\n// Dashboard Header\n.dashboard-header {\n background: white;\n padding: 16px 24px;\n border-bottom: 1px solid #e0e6ed;\n display: flex;\n justify-content: space-between;\n align-items: center;\n box-shadow: 0 2px 4px rgba(0,0,0,0.04);\n}\n\n.header-info {\n display: flex;\n align-items: center;\n gap: 16px;\n}\n\n.dashboard-title {\n margin: 0;\n font-size: 20px;\n font-weight: 600;\n color: #2c3e50;\n display: flex;\n align-items: center;\n gap: 8px;\n}\n\n.dashboard-title i {\n color: #17a2b8;\n}\n\n.filter-toggle-btn {\n background: #f8f9fa;\n border: 1px solid #dee2e6;\n padding: 8px 16px;\n border-radius: 6px;\n font-size: 14px;\n color: #495057;\n cursor: pointer;\n transition: all 0.2s ease;\n display: flex;\n align-items: center;\n gap: 8px;\n}\n\n.filter-toggle-btn:hover {\n background: #e9ecef;\n border-color: #ced4da;\n}\n\n.item-count {\n color: #6c757d;\n font-size: 14px;\n font-weight: 500;\n}\n\n.header-controls {\n display: flex;\n align-items: center;\n gap: 16px;\n}\n\n// View Toggle\n.view-toggle {\n display: flex;\n background: #f8f9fa;\n border-radius: 6px;\n padding: 2px;\n border: 1px solid #dee2e6;\n}\n\n.view-btn {\n background: transparent;\n border: none;\n padding: 6px 12px;\n border-radius: 4px;\n color: #6c757d;\n cursor: pointer;\n transition: all 0.2s ease;\n font-size: 16px;\n}\n\n.view-btn:hover {\n color: #495057;\n}\n\n.view-btn.active {\n background: white;\n color: #17a2b8;\n box-shadow: 0 1px 2px rgba(0,0,0,0.08);\n}\n\n// Control Buttons\n.control-btn {\n background: #f8f9fa;\n border: 1px solid #dee2e6;\n padding: 10px 20px;\n border-radius: 6px;\n font-size: 14px;\n font-weight: 500;\n color: #495057;\n cursor: pointer;\n transition: all 0.2s ease;\n display: flex;\n align-items: center;\n gap: 8px;\n}\n\n.control-btn:hover {\n background: #e9ecef;\n border-color: #ced4da;\n}\n\n.control-btn.primary {\n background: #17a2b8;\n border-color: #17a2b8;\n color: white;\n}\n\n.control-btn.primary:hover {\n background: #138496;\n border-color: #117a8b;\n transform: translateY(-1px);\n box-shadow: 0 2px 8px rgba(23, 162, 184, 0.3);\n}\n\n// Splitter content\nkendo-splitter {\n flex: 1;\n background-color: #f5f7fa;\n margin-top: 8px;\n}\n\n// Filter panel\n.filter-panel {\n height: 100%;\n background: white;\n border-right: 1px solid #e0e0e0;\n display: flex;\n flex-direction: column;\n overflow: hidden;\n}\n\n.filter-panel-header {\n padding: 16px;\n border-bottom: 1px solid #f0f0f0;\n display: flex;\n align-items: center;\n justify-content: space-between;\n flex-shrink: 0;\n \n h3 {\n margin: 0;\n font-size: 16px;\n font-weight: 500;\n color: #333;\n flex: 1;\n }\n \n .filter-summary-inline {\n display: flex;\n align-items: baseline;\n gap: 4px;\n margin-right: 12px;\n font-size: 12px;\n \n .summary-value {\n font-weight: 600;\n color: #2196f3;\n }\n \n .summary-label {\n color: #666;\n }\n }\n \n .close-btn {\n background: none;\n border: none;\n padding: 4px;\n cursor: pointer;\n color: #666;\n border-radius: 3px;\n transition: all 0.2s;\n \n &:hover {\n background: #f0f0f0;\n color: #333;\n }\n \n .fa-solid {\n font-size: 12px;\n }\n }\n}\n\n.filter-content {\n flex: 1;\n overflow-y: auto;\n overflow-x: hidden;\n padding: 12px;\n}\n\n.filter-group {\n margin-bottom: 20px;\n \n .filter-label {\n display: flex;\n align-items: center;\n gap: 8px;\n margin-bottom: 6px;\n font-size: 12px;\n font-weight: 500;\n color: #555;\n \n .fa-solid {\n font-size: 11px;\n color: #2196f3;\n width: 12px;\n }\n }\n}\n\n.filter-input, .filter-select {\n width: calc(100% - 4px);\n max-width: 100%;\n padding: 8px 10px;\n border: 1px solid #ddd;\n border-radius: 4px;\n font-size: 12px;\n background: white;\n transition: border-color 0.2s;\n box-sizing: border-box;\n \n &:focus {\n outline: none;\n border-color: #2196f3;\n }\n \n &::placeholder {\n color: #999;\n }\n}\n\n.filter-select {\n cursor: pointer;\n}\n\n.rank-filter-inputs {\n display: flex;\n gap: 8px;\n align-items: center;\n margin-top: 6px;\n}\n\n.rank-input {\n width: 60px;\n padding: 6px 8px;\n border: 1px solid #ddd;\n border-radius: 4px;\n font-size: 12px;\n text-align: center;\n background: white;\n transition: border-color 0.2s;\n box-sizing: border-box;\n \n &:focus {\n outline: none;\n border-color: #2196f3;\n }\n \n &::placeholder {\n color: #999;\n font-size: 11px;\n }\n \n // Hide spinner buttons for cleaner look\n &::-webkit-inner-spin-button,\n &::-webkit-outer-spin-button {\n -webkit-appearance: none;\n margin: 0;\n }\n \n -moz-appearance: textfield;\n}\n\n.rank-separator {\n color: #999;\n font-size: 12px;\n font-weight: 500;\n}\n\n.filter-actions {\n margin-top: 24px;\n padding-top: 16px;\n border-top: 1px solid #f0f0f0;\n \n .reset-btn {\n width: calc(100% - 4px);\n max-width: 100%;\n padding: 8px 12px;\n background: #f8f9fa;\n border: 1px solid #e0e0e0;\n border-radius: 4px;\n color: #666;\n font-size: 12px;\n cursor: pointer;\n display: flex;\n align-items: center;\n justify-content: center;\n gap: 6px;\n transition: all 0.2s;\n box-sizing: border-box;\n \n &:hover {\n background: #e9ecef;\n border-color: #ccc;\n color: #333;\n }\n \n .fa-solid {\n font-size: 11px;\n }\n }\n}\n\n// Content area\n.content-area {\n height: 100%;\n padding: 24px;\n overflow-y: auto;\n background: #f5f7fa;\n}\n\n// Empty state\n.empty-state {\n display: flex;\n flex-direction: column;\n align-items: center;\n justify-content: center;\n height: 100%;\n text-align: center;\n color: #6c757d;\n \n i {\n margin-bottom: 24px;\n opacity: 0.3;\n }\n \n h3 {\n margin: 0 0 8px 0;\n font-size: 20px;\n font-weight: 600;\n color: #495057;\n }\n \n p {\n margin: 0 0 24px 0;\n font-size: 16px;\n }\n}\n\n// Grid view\n.model-grid {\n display: grid;\n grid-template-columns: repeat(auto-fill, minmax(380px, 1fr));\n}\n\n.model-card {\n margin: 20px; // instead of gap in grid, for some reason that didn't work\n background: white;\n border-radius: 12px;\n box-shadow: 0 2px 8px rgba(0, 0, 0, 0.04);\n border: 1px solid #e0e6ed;\n transition: all 0.3s ease;\n overflow: hidden;\n \n &:hover {\n transform: translateY(-2px);\n box-shadow: 0 4px 16px rgba(0, 0, 0, 0.08);\n }\n \n &.expanded {\n box-shadow: 0 4px 20px rgba(0, 0, 0, 0.12);\n .expand-icon {\n transform: rotate(180deg);\n }\n }\n}\n\n.card-header {\n display: flex;\n align-items: center;\n padding: 20px;\n cursor: pointer;\n transition: background-color 0.2s ease;\n \n &:hover {\n background-color: #f8f9fa;\n }\n}\n\n.card-icon {\n width: 48px;\n height: 48px;\n background-color: #e3f2fd;\n border-radius: 10px;\n display: flex;\n align-items: center;\n justify-content: center;\n margin-right: 16px;\n flex-shrink: 0;\n \n i {\n font-size: 24px;\n color: #17a2b8;\n }\n}\n\n.card-info {\n flex: 1;\n min-width: 0;\n \n h4 {\n margin: 0 0 4px 0;\n font-size: 16px;\n font-weight: 600;\n color: #2c3e50;\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n }\n}\n\n.card-meta {\n display: flex;\n gap: 12px;\n font-size: 13px;\n color: #6c757d;\n margin-bottom: 8px;\n \n .vendor, .type, .status {\n display: flex;\n align-items: center;\n gap: 4px;\n \n &::before {\n content: '\u2022';\n color: #dee2e6;\n }\n \n &:first-child::before {\n display: none;\n }\n }\n \n .status {\n font-weight: 500;\n \n &.active {\n color: #28a745;\n }\n \n &.inactive {\n color: #dc3545;\n }\n }\n}\n\n.card-stats {\n display: flex;\n gap: 16px;\n font-size: 12px;\n color: #495057;\n \n .stat-item {\n display: flex;\n align-items: center;\n gap: 4px;\n \n i {\n font-size: 11px;\n color: #6c757d;\n }\n }\n}\n\n.expand-icon {\n color: #adb5bd;\n transition: transform 0.3s ease;\n margin-left: 12px;\n}\n\n.card-content {\n padding: 0 20px 20px;\n animation: slideDown 0.3s ease;\n}\n\n@keyframes slideDown {\n from {\n opacity: 0;\n transform: translateY(-10px);\n }\n to {\n opacity: 1;\n transform: translateY(0);\n }\n}\n\n.description-section {\n margin-bottom: 16px;\n \n h5 {\n margin: 0 0 8px 0;\n font-size: 13px;\n font-weight: 600;\n color: #6c757d;\n text-transform: uppercase;\n letter-spacing: 0.5px;\n }\n \n p {\n margin: 0;\n font-size: 14px;\n color: #495057;\n line-height: 1.6;\n }\n}\n\n.ranks-section {\n margin-bottom: 16px;\n \n h5 {\n margin: 0 0 12px 0;\n font-size: 13px;\n font-weight: 600;\n color: #6c757d;\n text-transform: uppercase;\n letter-spacing: 0.5px;\n }\n}\n\n.ranks-grid {\n display: grid;\n grid-template-columns: repeat(3, 1fr);\n gap: 12px;\n margin-bottom: 16px;\n}\n\n.rank-item {\n background-color: #f8f9fa;\n border-radius: 8px;\n padding: 12px;\n text-align: center;\n \n .rank-label {\n display: block;\n font-size: 12px;\n color: #6c757d;\n margin-bottom: 4px;\n \n i {\n margin-right: 4px;\n }\n }\n \n .rank-value {\n display: block;\n font-size: 18px;\n font-weight: 600;\n \n &.rank-high {\n color: #28a745;\n }\n \n &.rank-medium {\n color: #ffc107;\n }\n \n &.rank-low {\n color: #dc3545;\n }\n \n &.rank-none {\n color: #6c757d;\n }\n }\n}\n\n.stats-grid {\n display: grid;\n grid-template-columns: repeat(3, 1fr);\n gap: 16px;\n margin-bottom: 16px;\n}\n\n.stat {\n text-align: center;\n display: flex;\n flex-direction: column;\n align-items: center;\n \n .stat-label {\n display: block;\n font-size: 12px;\n color: #6c757d;\n margin-bottom: 4px;\n }\n \n .stat-value {\n font-size: 14px;\n font-weight: 500;\n color: #2c3e50;\n display: flex;\n align-items: center;\n justify-content: center;\n \n // Special case for toggle switches - ensure they don't expand\n .toggle-switch {\n display: inline-block !important;\n vertical-align: middle;\n }\n }\n}\n\n// Toggle switch\n.toggle-switch {\n position: relative;\n display: inline-block !important;\n width: 44px !important;\n height: 24px !important;\n flex-shrink: 0;\n \n &.small {\n width: 36px !important;\n height: 20px !important;\n }\n \n input {\n opacity: 0;\n width: 0;\n height: 0;\n \n &:checked + .toggle-slider {\n background-color: #28a745;\n \n &::before {\n transform: translateX(20px);\n }\n }\n }\n}\n\n.toggle-slider {\n position: absolute;\n cursor: pointer;\n top: 0;\n left: 0;\n right: 0;\n bottom: 0;\n background-color: #ccc;\n transition: .3s;\n border-radius: 24px;\n \n &::before {\n position: absolute;\n content: \"\";\n height: 18px;\n width: 18px;\n left: 3px;\n bottom: 3px;\n background-color: white;\n transition: .3s;\n border-radius: 50%;\n }\n \n .small & {\n &::before {\n height: 14px;\n width: 14px;\n }\n }\n}\n\n.card-footer {\n padding-top: 16px;\n border-top: 1px solid #e9ecef;\n display: flex;\n gap: 8px;\n}\n\n.action-button {\n padding: 6px 12px;\n background-color: #f8f9fa;\n border: 1px solid #dee2e6;\n border-radius: 4px;\n color: #495057;\n font-size: 13px;\n cursor: pointer;\n transition: all 0.2s ease;\n \n &:hover {\n background-color: #e9ecef;\n border-color: #adb5bd;\n color: #212529;\n }\n \n &.small {\n padding: 4px 8px;\n font-size: 12px;\n }\n \n i {\n margin-right: 4px;\n }\n}\n\n// List view\n.model-list {\n background: white;\n border-radius: 12px;\n box-shadow: 0 2px 8px rgba(0, 0, 0, 0.04);\n border: 1px solid #e0e6ed;\n overflow: hidden;\n}\n\n.data-table {\n width: 100%;\n border-collapse: collapse;\n \n thead {\n background-color: #f8f9fa;\n \n tr {\n border-bottom: 2px solid #dee2e6;\n }\n \n th {\n padding: 12px 16px;\n text-align: left;\n font-size: 13px;\n font-weight: 600;\n color: #495057;\n text-transform: uppercase;\n letter-spacing: 0.5px;\n }\n }\n \n tbody {\n tr {\n border-bottom: 1px solid #e9ecef;\n transition: background-color 0.2s ease;\n \n &:hover {\n background-color: #f8f9fa;\n }\n \n &:last-child {\n border-bottom: none;\n }\n }\n \n td {\n padding: 16px;\n font-size: 14px;\n color: #495057;\n }\n }\n}\n\n.name-cell {\n display: flex;\n align-items: center;\n gap: 8px;\n font-weight: 500;\n color: #2c3e50;\n \n i {\n color: #17a2b8;\n }\n}\n\n.rank-badge {\n display: inline-block;\n padding: 4px 8px;\n border-radius: 4px;\n font-size: 12px;\n font-weight: 500;\n background-color: #f8f9fa;\n \n &.rank-high {\n background-color: #d4edda;\n color: #155724;\n }\n \n &.rank-medium {\n background-color: #fff3cd;\n color: #856404;\n }\n \n &.rank-low {\n background-color: #f8d7da;\n color: #721c24;\n }\n \n &.rank-none {\n background-color: #e9ecef;\n color: #6c757d;\n }\n}\n\n.status-badge {\n display: inline-block;\n padding: 4px 8px;\n border-radius: 4px;\n font-size: 12px;\n font-weight: 500;\n \n &.active {\n background-color: #d4edda;\n color: #155724;\n }\n \n &.inactive {\n background-color: #f8d7da;\n color: #721c24;\n }\n}\n\n// Responsive\n@media (max-width: 768px) {\n .model-header {\n flex-wrap: wrap;\n gap: 16px;\n }\n \n .header-right {\n width: 100%;\n justify-content: space-between;\n }\n \n .model-grid {\n grid-template-columns: 1fr;\n }\n \n .stats-grid,\n .ranks-grid {\n grid-template-columns: 1fr;\n }\n}"] }]
996
+ }], () => [{ type: i1.SharedService }], { openEntityRecord: [{
997
+ type: Output
998
+ }], stateChange: [{
999
+ type: Output
1000
+ }], initialState: [{
1001
+ type: Input
1002
+ }] }); })();
1003
+ (() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassDebugInfo(ModelManagementV2Component, { className: "ModelManagementV2Component", filePath: "src/AI/components/models/model-management-v2.component.ts", lineNumber: 22 }); })();
1004
+ //# sourceMappingURL=model-management-v2.component.js.map