@memberjunction/ng-entity-viewer 5.43.0 → 5.45.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 (75) hide show
  1. package/dist/lib/aggregate-panel/aggregate-panel.component.d.ts +5 -0
  2. package/dist/lib/aggregate-panel/aggregate-panel.component.d.ts.map +1 -1
  3. package/dist/lib/aggregate-panel/aggregate-panel.component.js +45 -47
  4. package/dist/lib/aggregate-panel/aggregate-panel.component.js.map +1 -1
  5. package/dist/lib/entity-cards/entity-cards.component.js +7 -10
  6. package/dist/lib/entity-cards/entity-cards.component.js.map +1 -1
  7. package/dist/lib/entity-data-grid/entity-data-grid.component.d.ts +10 -1
  8. package/dist/lib/entity-data-grid/entity-data-grid.component.d.ts.map +1 -1
  9. package/dist/lib/entity-data-grid/entity-data-grid.component.js +35 -34
  10. package/dist/lib/entity-data-grid/entity-data-grid.component.js.map +1 -1
  11. package/dist/lib/entity-record-detail-panel/entity-record-detail-panel.component.d.ts +0 -4
  12. package/dist/lib/entity-record-detail-panel/entity-record-detail-panel.component.d.ts.map +1 -1
  13. package/dist/lib/entity-record-detail-panel/entity-record-detail-panel.component.js +166 -207
  14. package/dist/lib/entity-record-detail-panel/entity-record-detail-panel.component.js.map +1 -1
  15. package/dist/lib/entity-viewer/entity-viewer.component.d.ts +109 -5
  16. package/dist/lib/entity-viewer/entity-viewer.component.d.ts.map +1 -1
  17. package/dist/lib/entity-viewer/entity-viewer.component.js +287 -42
  18. package/dist/lib/entity-viewer/entity-viewer.component.js.map +1 -1
  19. package/dist/lib/recycle-bin/recycle-bin.component.js +21 -44
  20. package/dist/lib/recycle-bin/recycle-bin.component.js.map +1 -1
  21. package/dist/lib/shared-view-warning-dialog/shared-view-warning-dialog.component.js +19 -20
  22. package/dist/lib/shared-view-warning-dialog/shared-view-warning-dialog.component.js.map +1 -1
  23. package/dist/lib/view-config-panel/view-config-panel.component.js +268 -301
  24. package/dist/lib/view-config-panel/view-config-panel.component.js.map +1 -1
  25. package/dist/lib/view-selector/view-selector.component.d.ts +26 -1
  26. package/dist/lib/view-selector/view-selector.component.d.ts.map +1 -1
  27. package/dist/lib/view-selector/view-selector.component.js +118 -76
  28. package/dist/lib/view-selector/view-selector.component.js.map +1 -1
  29. package/dist/lib/view-types/descriptors/grid-view-type.d.ts +7 -0
  30. package/dist/lib/view-types/descriptors/grid-view-type.d.ts.map +1 -1
  31. package/dist/lib/view-types/descriptors/grid-view-type.js +7 -0
  32. package/dist/lib/view-types/descriptors/grid-view-type.js.map +1 -1
  33. package/dist/lib/view-types/renderers/grid-view-renderer.component.d.ts +18 -1
  34. package/dist/lib/view-types/renderers/grid-view-renderer.component.d.ts.map +1 -1
  35. package/dist/lib/view-types/renderers/grid-view-renderer.component.js +29 -3
  36. package/dist/lib/view-types/renderers/grid-view-renderer.component.js.map +1 -1
  37. package/dist/lib/view-types/renderers/map-view-renderer.component.d.ts.map +1 -1
  38. package/dist/lib/view-types/renderers/map-view-renderer.component.js +11 -14
  39. package/dist/lib/view-types/renderers/map-view-renderer.component.js.map +1 -1
  40. package/dist/lib/view-types/renderers/timeline-view-renderer.component.d.ts.map +1 -1
  41. package/dist/lib/view-types/renderers/timeline-view-renderer.component.js +12 -14
  42. package/dist/lib/view-types/renderers/timeline-view-renderer.component.js.map +1 -1
  43. package/dist/lib/view-types/view-type.contracts.d.ts +44 -0
  44. package/dist/lib/view-types/view-type.contracts.d.ts.map +1 -1
  45. package/dist/lib/view-types/view-type.contracts.js +6 -0
  46. package/dist/lib/view-types/view-type.contracts.js.map +1 -1
  47. package/dist/lib/view-workspace/view-workspace.component.d.ts +32 -1
  48. package/dist/lib/view-workspace/view-workspace.component.d.ts.map +1 -1
  49. package/dist/lib/view-workspace/view-workspace.component.js +68 -7
  50. package/dist/lib/view-workspace/view-workspace.component.js.map +1 -1
  51. package/dist/module.d.ts +1 -1
  52. package/dist/module.d.ts.map +1 -1
  53. package/dist/module.js +10 -1
  54. package/dist/module.js.map +1 -1
  55. package/package.json +18 -17
  56. package/dist/__tests__/entity-cards-selection.test.d.ts +0 -2
  57. package/dist/__tests__/entity-cards-selection.test.d.ts.map +0 -1
  58. package/dist/__tests__/entity-cards-selection.test.js +0 -149
  59. package/dist/__tests__/entity-cards-selection.test.js.map +0 -1
  60. package/dist/__tests__/entity-cards-viewmodel.test.d.ts +0 -2
  61. package/dist/__tests__/entity-cards-viewmodel.test.d.ts.map +0 -1
  62. package/dist/__tests__/entity-cards-viewmodel.test.js +0 -208
  63. package/dist/__tests__/entity-cards-viewmodel.test.js.map +0 -1
  64. package/dist/__tests__/highlight.test.d.ts +0 -2
  65. package/dist/__tests__/highlight.test.d.ts.map +0 -1
  66. package/dist/__tests__/highlight.test.js +0 -67
  67. package/dist/__tests__/highlight.test.js.map +0 -1
  68. package/dist/__tests__/index.test.d.ts +0 -2
  69. package/dist/__tests__/index.test.d.ts.map +0 -1
  70. package/dist/__tests__/index.test.js +0 -7
  71. package/dist/__tests__/index.test.js.map +0 -1
  72. package/dist/__tests__/view-types.test.d.ts +0 -2
  73. package/dist/__tests__/view-types.test.d.ts.map +0 -1
  74. package/dist/__tests__/view-types.test.js +0 -102
  75. package/dist/__tests__/view-types.test.js.map +0 -1
@@ -1,10 +1,12 @@
1
1
  import { Component, Input, Output, EventEmitter, ViewEncapsulation } from '@angular/core';
2
2
  import { UserViewEngine } from '@memberjunction/core-entities';
3
3
  import { Subject } from 'rxjs';
4
+ import { takeUntil } from 'rxjs/operators';
4
5
  import { UUIDsEqual } from '@memberjunction/global';
5
6
  import { BaseAngularComponent } from '@memberjunction/ng-base-types';
6
7
  import * as i0 from "@angular/core";
7
8
  import * as i1 from "@angular/forms";
9
+ import * as i2 from "@memberjunction/ng-ui-components";
8
10
  const _forTrack0 = ($index, $item) => $item.id;
9
11
  function ViewSelectorComponent_Conditional_1_Template(rf, ctx) { if (rf & 1) {
10
12
  const _r1 = i0.ɵɵgetCurrentView();
@@ -30,12 +32,12 @@ function ViewSelectorComponent_Conditional_9_Conditional_18_Template(rf, ctx) {
30
32
  i0.ɵɵelement(0, "i", 32);
31
33
  } }
32
34
  function ViewSelectorComponent_Conditional_9_Conditional_19_For_8_Conditional_6_Template(rf, ctx) { if (rf & 1) {
33
- i0.ɵɵelementStart(0, "span", 44);
35
+ i0.ɵɵelementStart(0, "span", 45);
34
36
  i0.ɵɵtext(1, "Default");
35
37
  i0.ɵɵelementEnd();
36
38
  } }
37
39
  function ViewSelectorComponent_Conditional_9_Conditional_19_For_8_Conditional_7_Template(rf, ctx) { if (rf & 1) {
38
- i0.ɵɵelementStart(0, "div", 45);
40
+ i0.ɵɵelementStart(0, "div", 46);
39
41
  i0.ɵɵtext(1);
40
42
  i0.ɵɵelementEnd();
41
43
  } if (rf & 2) {
@@ -45,7 +47,7 @@ function ViewSelectorComponent_Conditional_9_Conditional_19_For_8_Conditional_7_
45
47
  } }
46
48
  function ViewSelectorComponent_Conditional_9_Conditional_19_For_8_Conditional_8_Conditional_1_Template(rf, ctx) { if (rf & 1) {
47
49
  i0.ɵɵelementStart(0, "span");
48
- i0.ɵɵelement(1, "i", 54);
50
+ i0.ɵɵelement(1, "i", 55);
49
51
  i0.ɵɵtext(2);
50
52
  i0.ɵɵelementEnd();
51
53
  } if (rf & 2) {
@@ -56,7 +58,7 @@ function ViewSelectorComponent_Conditional_9_Conditional_19_For_8_Conditional_8_
56
58
  } }
57
59
  function ViewSelectorComponent_Conditional_9_Conditional_19_For_8_Conditional_8_Conditional_2_Template(rf, ctx) { if (rf & 1) {
58
60
  i0.ɵɵelementStart(0, "span");
59
- i0.ɵɵelement(1, "i", 55);
61
+ i0.ɵɵelement(1, "i", 56);
60
62
  i0.ɵɵtext(2);
61
63
  i0.ɵɵelementEnd();
62
64
  } if (rf & 2) {
@@ -67,7 +69,7 @@ function ViewSelectorComponent_Conditional_9_Conditional_19_For_8_Conditional_8_
67
69
  } }
68
70
  function ViewSelectorComponent_Conditional_9_Conditional_19_For_8_Conditional_8_Conditional_3_Template(rf, ctx) { if (rf & 1) {
69
71
  i0.ɵɵelementStart(0, "span");
70
- i0.ɵɵelement(1, "i", 56);
72
+ i0.ɵɵelement(1, "i", 57);
71
73
  i0.ɵɵtext(2);
72
74
  i0.ɵɵelementEnd();
73
75
  } if (rf & 2) {
@@ -77,7 +79,7 @@ function ViewSelectorComponent_Conditional_9_Conditional_19_For_8_Conditional_8_
77
79
  i0.ɵɵtextInterpolate1(" ", ctx_r1.GetViewSortInfo(view_r5));
78
80
  } }
79
81
  function ViewSelectorComponent_Conditional_9_Conditional_19_For_8_Conditional_8_Template(rf, ctx) { if (rf & 1) {
80
- i0.ɵɵelementStart(0, "div", 46);
82
+ i0.ɵɵelementStart(0, "div", 47);
81
83
  i0.ɵɵconditionalCreate(1, ViewSelectorComponent_Conditional_9_Conditional_19_For_8_Conditional_8_Conditional_1_Template, 3, 2, "span");
82
84
  i0.ɵɵconditionalCreate(2, ViewSelectorComponent_Conditional_9_Conditional_19_For_8_Conditional_8_Conditional_2_Template, 3, 2, "span");
83
85
  i0.ɵɵconditionalCreate(3, ViewSelectorComponent_Conditional_9_Conditional_19_For_8_Conditional_8_Conditional_3_Template, 3, 1, "span");
@@ -100,26 +102,26 @@ function ViewSelectorComponent_Conditional_9_Conditional_19_For_8_Template(rf, c
100
102
  i0.ɵɵelementStart(0, "div", 27);
101
103
  i0.ɵɵlistener("click", function ViewSelectorComponent_Conditional_9_Conditional_19_For_8_Template_div_click_0_listener() { const view_r5 = i0.ɵɵrestoreView(_r4).$implicit; const ctx_r1 = i0.ɵɵnextContext(3); return i0.ɵɵresetView(ctx_r1.SelectView(view_r5)); });
102
104
  i0.ɵɵelementStart(1, "div", 28);
103
- i0.ɵɵelement(2, "i", 43);
105
+ i0.ɵɵelement(2, "i", 44);
104
106
  i0.ɵɵelementEnd();
105
107
  i0.ɵɵelementStart(3, "div", 30)(4, "div", 31);
106
108
  i0.ɵɵtext(5);
107
- i0.ɵɵconditionalCreate(6, ViewSelectorComponent_Conditional_9_Conditional_19_For_8_Conditional_6_Template, 2, 0, "span", 44);
109
+ i0.ɵɵconditionalCreate(6, ViewSelectorComponent_Conditional_9_Conditional_19_For_8_Conditional_6_Template, 2, 0, "span", 45);
108
110
  i0.ɵɵelementEnd();
109
- i0.ɵɵconditionalCreate(7, ViewSelectorComponent_Conditional_9_Conditional_19_For_8_Conditional_7_Template, 2, 1, "div", 45);
110
- i0.ɵɵconditionalCreate(8, ViewSelectorComponent_Conditional_9_Conditional_19_For_8_Conditional_8_Template, 4, 3, "div", 46);
111
+ i0.ɵɵconditionalCreate(7, ViewSelectorComponent_Conditional_9_Conditional_19_For_8_Conditional_7_Template, 2, 1, "div", 46);
112
+ i0.ɵɵconditionalCreate(8, ViewSelectorComponent_Conditional_9_Conditional_19_For_8_Conditional_8_Template, 4, 3, "div", 47);
111
113
  i0.ɵɵelementEnd();
112
- i0.ɵɵelementStart(9, "div", 47)(10, "button", 48);
114
+ i0.ɵɵelementStart(9, "div", 48)(10, "button", 49);
113
115
  i0.ɵɵlistener("click", function ViewSelectorComponent_Conditional_9_Conditional_19_For_8_Template_button_click_10_listener($event) { const view_r5 = i0.ɵɵrestoreView(_r4).$implicit; const ctx_r1 = i0.ɵɵnextContext(3); return i0.ɵɵresetView(ctx_r1.OnDuplicateView(view_r5.id, $event)); });
114
- i0.ɵɵelement(11, "i", 49);
116
+ i0.ɵɵelement(11, "i", 50);
115
117
  i0.ɵɵelementEnd();
116
- i0.ɵɵelementStart(12, "button", 50);
118
+ i0.ɵɵelementStart(12, "button", 51);
117
119
  i0.ɵɵlistener("click", function ViewSelectorComponent_Conditional_9_Conditional_19_For_8_Template_button_click_12_listener($event) { const view_r5 = i0.ɵɵrestoreView(_r4).$implicit; const ctx_r1 = i0.ɵɵnextContext(3); return i0.ɵɵresetView(ctx_r1.OnConfigureViewById(view_r5.id, $event)); });
118
- i0.ɵɵelement(13, "i", 51);
120
+ i0.ɵɵelement(13, "i", 52);
119
121
  i0.ɵɵelementEnd();
120
- i0.ɵɵelementStart(14, "button", 52);
122
+ i0.ɵɵelementStart(14, "button", 53);
121
123
  i0.ɵɵlistener("click", function ViewSelectorComponent_Conditional_9_Conditional_19_For_8_Template_button_click_14_listener($event) { const view_r5 = i0.ɵɵrestoreView(_r4).$implicit; const ctx_r1 = i0.ɵɵnextContext(3); return i0.ɵɵresetView(ctx_r1.OnOpenViewInTab(view_r5.id, $event)); });
122
- i0.ɵɵelement(15, "i", 53);
124
+ i0.ɵɵelement(15, "i", 54);
123
125
  i0.ɵɵelementEnd()();
124
126
  i0.ɵɵconditionalCreate(16, ViewSelectorComponent_Conditional_9_Conditional_19_For_8_Conditional_16_Template, 1, 0, "i", 32);
125
127
  i0.ɵɵelementEnd();
@@ -141,15 +143,15 @@ function ViewSelectorComponent_Conditional_9_Conditional_19_For_8_Template(rf, c
141
143
  i0.ɵɵconditional(ctx_r1.SelectedViewID === view_r5.id ? 16 : -1);
142
144
  } }
143
145
  function ViewSelectorComponent_Conditional_9_Conditional_19_Template(rf, ctx) { if (rf & 1) {
144
- i0.ɵɵelementStart(0, "div", 26)(1, "div", 39);
145
- i0.ɵɵelement(2, "i", 40);
146
+ i0.ɵɵelementStart(0, "div", 26)(1, "div", 40);
147
+ i0.ɵɵelement(2, "i", 41);
146
148
  i0.ɵɵelementStart(3, "span");
147
149
  i0.ɵɵtext(4, "My Views");
148
150
  i0.ɵɵelementEnd();
149
- i0.ɵɵelementStart(5, "span", 41);
151
+ i0.ɵɵelementStart(5, "span", 42);
150
152
  i0.ɵɵtext(6);
151
153
  i0.ɵɵelementEnd()();
152
- i0.ɵɵrepeaterCreate(7, ViewSelectorComponent_Conditional_9_Conditional_19_For_8_Template, 17, 9, "div", 42, _forTrack0);
154
+ i0.ɵɵrepeaterCreate(7, ViewSelectorComponent_Conditional_9_Conditional_19_For_8_Template, 17, 9, "div", 43, _forTrack0);
153
155
  i0.ɵɵelementEnd();
154
156
  } if (rf & 2) {
155
157
  const ctx_r1 = i0.ɵɵnextContext(2);
@@ -159,17 +161,17 @@ function ViewSelectorComponent_Conditional_9_Conditional_19_Template(rf, ctx) {
159
161
  i0.ɵɵrepeater(ctx_r1.FilteredMyViews);
160
162
  } }
161
163
  function ViewSelectorComponent_Conditional_9_Conditional_20_For_8_Conditional_6_Template(rf, ctx) { if (rf & 1) {
162
- i0.ɵɵelementStart(0, "span", 60);
164
+ i0.ɵɵelementStart(0, "span", 61);
163
165
  i0.ɵɵtext(1, "View Only");
164
166
  i0.ɵɵelementEnd();
165
167
  } }
166
168
  function ViewSelectorComponent_Conditional_9_Conditional_20_For_8_Conditional_7_Template(rf, ctx) { if (rf & 1) {
167
- i0.ɵɵelementStart(0, "span", 61);
169
+ i0.ɵɵelementStart(0, "span", 62);
168
170
  i0.ɵɵtext(1, "Can Edit");
169
171
  i0.ɵɵelementEnd();
170
172
  } }
171
173
  function ViewSelectorComponent_Conditional_9_Conditional_20_For_8_Conditional_8_Template(rf, ctx) { if (rf & 1) {
172
- i0.ɵɵelementStart(0, "div", 45);
174
+ i0.ɵɵelementStart(0, "div", 46);
173
175
  i0.ɵɵtext(1);
174
176
  i0.ɵɵelementEnd();
175
177
  } if (rf & 2) {
@@ -179,7 +181,7 @@ function ViewSelectorComponent_Conditional_9_Conditional_20_For_8_Conditional_8_
179
181
  } }
180
182
  function ViewSelectorComponent_Conditional_9_Conditional_20_For_8_Conditional_9_Conditional_1_Template(rf, ctx) { if (rf & 1) {
181
183
  i0.ɵɵelementStart(0, "span");
182
- i0.ɵɵelement(1, "i", 54);
184
+ i0.ɵɵelement(1, "i", 55);
183
185
  i0.ɵɵtext(2);
184
186
  i0.ɵɵelementEnd();
185
187
  } if (rf & 2) {
@@ -190,7 +192,7 @@ function ViewSelectorComponent_Conditional_9_Conditional_20_For_8_Conditional_9_
190
192
  } }
191
193
  function ViewSelectorComponent_Conditional_9_Conditional_20_For_8_Conditional_9_Conditional_2_Template(rf, ctx) { if (rf & 1) {
192
194
  i0.ɵɵelementStart(0, "span");
193
- i0.ɵɵelement(1, "i", 55);
195
+ i0.ɵɵelement(1, "i", 56);
194
196
  i0.ɵɵtext(2);
195
197
  i0.ɵɵelementEnd();
196
198
  } if (rf & 2) {
@@ -200,7 +202,7 @@ function ViewSelectorComponent_Conditional_9_Conditional_20_For_8_Conditional_9_
200
202
  i0.ɵɵtextInterpolate2(" ", ctx_r1.GetViewColumnCount(view_r7), " col", ctx_r1.GetViewColumnCount(view_r7) !== 1 ? "s" : "");
201
203
  } }
202
204
  function ViewSelectorComponent_Conditional_9_Conditional_20_For_8_Conditional_9_Template(rf, ctx) { if (rf & 1) {
203
- i0.ɵɵelementStart(0, "div", 46);
205
+ i0.ɵɵelementStart(0, "div", 47);
204
206
  i0.ɵɵconditionalCreate(1, ViewSelectorComponent_Conditional_9_Conditional_20_For_8_Conditional_9_Conditional_1_Template, 3, 2, "span");
205
207
  i0.ɵɵconditionalCreate(2, ViewSelectorComponent_Conditional_9_Conditional_20_For_8_Conditional_9_Conditional_2_Template, 3, 2, "span");
206
208
  i0.ɵɵelementEnd();
@@ -214,9 +216,9 @@ function ViewSelectorComponent_Conditional_9_Conditional_20_For_8_Conditional_9_
214
216
  } }
215
217
  function ViewSelectorComponent_Conditional_9_Conditional_20_For_8_Conditional_13_Template(rf, ctx) { if (rf & 1) {
216
218
  const _r8 = i0.ɵɵgetCurrentView();
217
- i0.ɵɵelementStart(0, "button", 50);
219
+ i0.ɵɵelementStart(0, "button", 51);
218
220
  i0.ɵɵlistener("click", function ViewSelectorComponent_Conditional_9_Conditional_20_For_8_Conditional_13_Template_button_click_0_listener($event) { i0.ɵɵrestoreView(_r8); const view_r7 = i0.ɵɵnextContext().$implicit; const ctx_r1 = i0.ɵɵnextContext(3); return i0.ɵɵresetView(ctx_r1.OnConfigureViewById(view_r7.id, $event)); });
219
- i0.ɵɵelement(1, "i", 51);
221
+ i0.ɵɵelement(1, "i", 52);
220
222
  i0.ɵɵelementEnd();
221
223
  } }
222
224
  function ViewSelectorComponent_Conditional_9_Conditional_20_For_8_Conditional_14_Template(rf, ctx) { if (rf & 1) {
@@ -226,21 +228,21 @@ function ViewSelectorComponent_Conditional_9_Conditional_20_For_8_Template(rf, c
226
228
  const _r6 = i0.ɵɵgetCurrentView();
227
229
  i0.ɵɵelementStart(0, "div", 27);
228
230
  i0.ɵɵlistener("click", function ViewSelectorComponent_Conditional_9_Conditional_20_For_8_Template_div_click_0_listener() { const view_r7 = i0.ɵɵrestoreView(_r6).$implicit; const ctx_r1 = i0.ɵɵnextContext(3); return i0.ɵɵresetView(ctx_r1.SelectView(view_r7)); });
229
- i0.ɵɵelementStart(1, "div", 58);
230
- i0.ɵɵelement(2, "i", 59);
231
+ i0.ɵɵelementStart(1, "div", 59);
232
+ i0.ɵɵelement(2, "i", 60);
231
233
  i0.ɵɵelementEnd();
232
234
  i0.ɵɵelementStart(3, "div", 30)(4, "div", 31);
233
235
  i0.ɵɵtext(5);
234
- i0.ɵɵconditionalCreate(6, ViewSelectorComponent_Conditional_9_Conditional_20_For_8_Conditional_6_Template, 2, 0, "span", 60)(7, ViewSelectorComponent_Conditional_9_Conditional_20_For_8_Conditional_7_Template, 2, 0, "span", 61);
236
+ i0.ɵɵconditionalCreate(6, ViewSelectorComponent_Conditional_9_Conditional_20_For_8_Conditional_6_Template, 2, 0, "span", 61)(7, ViewSelectorComponent_Conditional_9_Conditional_20_For_8_Conditional_7_Template, 2, 0, "span", 62);
235
237
  i0.ɵɵelementEnd();
236
- i0.ɵɵconditionalCreate(8, ViewSelectorComponent_Conditional_9_Conditional_20_For_8_Conditional_8_Template, 2, 1, "div", 45);
237
- i0.ɵɵconditionalCreate(9, ViewSelectorComponent_Conditional_9_Conditional_20_For_8_Conditional_9_Template, 3, 2, "div", 46);
238
+ i0.ɵɵconditionalCreate(8, ViewSelectorComponent_Conditional_9_Conditional_20_For_8_Conditional_8_Template, 2, 1, "div", 46);
239
+ i0.ɵɵconditionalCreate(9, ViewSelectorComponent_Conditional_9_Conditional_20_For_8_Conditional_9_Template, 3, 2, "div", 47);
238
240
  i0.ɵɵelementEnd();
239
- i0.ɵɵelementStart(10, "div", 47)(11, "button", 62);
241
+ i0.ɵɵelementStart(10, "div", 48)(11, "button", 63);
240
242
  i0.ɵɵlistener("click", function ViewSelectorComponent_Conditional_9_Conditional_20_For_8_Template_button_click_11_listener($event) { const view_r7 = i0.ɵɵrestoreView(_r6).$implicit; const ctx_r1 = i0.ɵɵnextContext(3); return i0.ɵɵresetView(ctx_r1.OnDuplicateView(view_r7.id, $event)); });
241
- i0.ɵɵelement(12, "i", 49);
243
+ i0.ɵɵelement(12, "i", 50);
242
244
  i0.ɵɵelementEnd();
243
- i0.ɵɵconditionalCreate(13, ViewSelectorComponent_Conditional_9_Conditional_20_For_8_Conditional_13_Template, 2, 0, "button", 63);
245
+ i0.ɵɵconditionalCreate(13, ViewSelectorComponent_Conditional_9_Conditional_20_For_8_Conditional_13_Template, 2, 0, "button", 64);
244
246
  i0.ɵɵelementEnd();
245
247
  i0.ɵɵconditionalCreate(14, ViewSelectorComponent_Conditional_9_Conditional_20_For_8_Conditional_14_Template, 1, 0, "i", 32);
246
248
  i0.ɵɵelementEnd();
@@ -262,15 +264,15 @@ function ViewSelectorComponent_Conditional_9_Conditional_20_For_8_Template(rf, c
262
264
  i0.ɵɵconditional(ctx_r1.SelectedViewID === view_r7.id ? 14 : -1);
263
265
  } }
264
266
  function ViewSelectorComponent_Conditional_9_Conditional_20_Template(rf, ctx) { if (rf & 1) {
265
- i0.ɵɵelementStart(0, "div", 26)(1, "div", 39);
266
- i0.ɵɵelement(2, "i", 57);
267
+ i0.ɵɵelementStart(0, "div", 26)(1, "div", 40);
268
+ i0.ɵɵelement(2, "i", 58);
267
269
  i0.ɵɵelementStart(3, "span");
268
270
  i0.ɵɵtext(4, "Shared With Me");
269
271
  i0.ɵɵelementEnd();
270
- i0.ɵɵelementStart(5, "span", 41);
272
+ i0.ɵɵelementStart(5, "span", 42);
271
273
  i0.ɵɵtext(6);
272
274
  i0.ɵɵelementEnd()();
273
- i0.ɵɵrepeaterCreate(7, ViewSelectorComponent_Conditional_9_Conditional_20_For_8_Template, 15, 8, "div", 42, _forTrack0);
275
+ i0.ɵɵrepeaterCreate(7, ViewSelectorComponent_Conditional_9_Conditional_20_For_8_Template, 15, 8, "div", 43, _forTrack0);
274
276
  i0.ɵɵelementEnd();
275
277
  } if (rf & 2) {
276
278
  const ctx_r1 = i0.ɵɵnextContext(2);
@@ -280,29 +282,17 @@ function ViewSelectorComponent_Conditional_9_Conditional_20_Template(rf, ctx) {
280
282
  i0.ɵɵrepeater(ctx_r1.FilteredSharedViews);
281
283
  } }
282
284
  function ViewSelectorComponent_Conditional_9_Conditional_21_Template(rf, ctx) { if (rf & 1) {
283
- i0.ɵɵelementStart(0, "div", 33);
284
- i0.ɵɵelement(1, "i", 64);
285
- i0.ɵɵelementStart(2, "div", 65)(3, "strong");
286
- i0.ɵɵtext(4, "No saved views yet");
287
- i0.ɵɵelementEnd();
288
- i0.ɵɵelementStart(5, "span");
289
- i0.ɵɵtext(6, "Save your current configuration as a view");
290
- i0.ɵɵelementEnd()()();
285
+ i0.ɵɵelement(0, "mj-empty-state", 33);
291
286
  } }
292
287
  function ViewSelectorComponent_Conditional_9_Conditional_22_Template(rf, ctx) { if (rf & 1) {
293
- i0.ɵɵelementStart(0, "div", 33);
294
- i0.ɵɵelement(1, "i", 66);
295
- i0.ɵɵelementStart(2, "span");
296
- i0.ɵɵtext(3);
297
- i0.ɵɵelementEnd()();
288
+ i0.ɵɵelement(0, "mj-empty-state", 34);
298
289
  } if (rf & 2) {
299
290
  const ctx_r1 = i0.ɵɵnextContext(2);
300
- i0.ɵɵadvance(3);
301
- i0.ɵɵtextInterpolate1("No views match \"", ctx_r1.SearchText, "\"");
291
+ i0.ɵɵproperty("Title", ctx_r1.NoViewsMatchMessage);
302
292
  } }
303
293
  function ViewSelectorComponent_Conditional_9_Conditional_23_Template(rf, ctx) { if (rf & 1) {
304
- i0.ɵɵelementStart(0, "div", 34);
305
- i0.ɵɵelement(1, "i", 67);
294
+ i0.ɵɵelementStart(0, "div", 35);
295
+ i0.ɵɵelement(1, "i", 65);
306
296
  i0.ɵɵelementStart(2, "span");
307
297
  i0.ɵɵtext(3, "Loading views...");
308
298
  i0.ɵɵelementEnd()();
@@ -335,19 +325,19 @@ function ViewSelectorComponent_Conditional_9_Template(rf, ctx) { if (rf & 1) {
335
325
  i0.ɵɵelementEnd()();
336
326
  i0.ɵɵconditionalCreate(19, ViewSelectorComponent_Conditional_9_Conditional_19_Template, 9, 1, "div", 26);
337
327
  i0.ɵɵconditionalCreate(20, ViewSelectorComponent_Conditional_9_Conditional_20_Template, 9, 1, "div", 26);
338
- i0.ɵɵconditionalCreate(21, ViewSelectorComponent_Conditional_9_Conditional_21_Template, 7, 0, "div", 33);
339
- i0.ɵɵconditionalCreate(22, ViewSelectorComponent_Conditional_9_Conditional_22_Template, 4, 1, "div", 33);
340
- i0.ɵɵconditionalCreate(23, ViewSelectorComponent_Conditional_9_Conditional_23_Template, 4, 0, "div", 34);
328
+ i0.ɵɵconditionalCreate(21, ViewSelectorComponent_Conditional_9_Conditional_21_Template, 1, 0, "mj-empty-state", 33);
329
+ i0.ɵɵconditionalCreate(22, ViewSelectorComponent_Conditional_9_Conditional_22_Template, 1, 1, "mj-empty-state", 34);
330
+ i0.ɵɵconditionalCreate(23, ViewSelectorComponent_Conditional_9_Conditional_23_Template, 4, 0, "div", 35);
341
331
  i0.ɵɵelementEnd();
342
- i0.ɵɵelementStart(24, "div", 35)(25, "button", 36);
332
+ i0.ɵɵelementStart(24, "div", 36)(25, "button", 37);
343
333
  i0.ɵɵlistener("click", function ViewSelectorComponent_Conditional_9_Template_button_click_25_listener() { i0.ɵɵrestoreView(_r3); const ctx_r1 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r1.OnQuickSave()); });
344
334
  i0.ɵɵelement(26, "i", 13);
345
335
  i0.ɵɵelementStart(27, "span");
346
336
  i0.ɵɵtext(28, "New View");
347
337
  i0.ɵɵelementEnd()();
348
- i0.ɵɵelementStart(29, "button", 37);
338
+ i0.ɵɵelementStart(29, "button", 38);
349
339
  i0.ɵɵlistener("click", function ViewSelectorComponent_Conditional_9_Template_button_click_29_listener() { i0.ɵɵrestoreView(_r3); const ctx_r1 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r1.OnResetToDefault()); });
350
- i0.ɵɵelement(30, "i", 38);
340
+ i0.ɵɵelement(30, "i", 39);
351
341
  i0.ɵɵelementStart(31, "span");
352
342
  i0.ɵɵtext(32, "Reset to Default");
353
343
  i0.ɵɵelementEnd()()()();
@@ -376,9 +366,9 @@ function ViewSelectorComponent_Conditional_9_Template(rf, ctx) { if (rf & 1) {
376
366
  } }
377
367
  function ViewSelectorComponent_Conditional_10_Template(rf, ctx) { if (rf & 1) {
378
368
  const _r9 = i0.ɵɵgetCurrentView();
379
- i0.ɵɵelementStart(0, "button", 68);
369
+ i0.ɵɵelementStart(0, "button", 66);
380
370
  i0.ɵɵlistener("click", function ViewSelectorComponent_Conditional_10_Template_button_click_0_listener() { i0.ɵɵrestoreView(_r9); const ctx_r1 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r1.OnOpenInTab()); });
381
- i0.ɵɵelement(1, "i", 69);
371
+ i0.ɵɵelement(1, "i", 67);
382
372
  i0.ɵɵelementEnd();
383
373
  } }
384
374
  /**
@@ -453,6 +443,8 @@ export class ViewSelectorComponent extends BaseAngularComponent {
453
443
  SelectedView = null;
454
444
  SearchText = '';
455
445
  destroy$ = new Subject();
446
+ /** Guards the one-time reactive subscription to UserViewEngine set up in {@link ensureEngineSubscription}. */
447
+ subscribedToEngine = false;
456
448
  get metadata() { return this.ProviderToUse; }
457
449
  constructor(cdr) {
458
450
  super();
@@ -461,7 +453,7 @@ export class ViewSelectorComponent extends BaseAngularComponent {
461
453
  ngOnChanges(changes) {
462
454
  if (changes['Entity']) {
463
455
  if (this.Entity) {
464
- this.LoadViews();
456
+ void this.LoadViews();
465
457
  }
466
458
  else {
467
459
  this.MyViews = [];
@@ -479,7 +471,14 @@ export class ViewSelectorComponent extends BaseAngularComponent {
479
471
  this.destroy$.complete();
480
472
  }
481
473
  /**
482
- * Load views for the current entity
474
+ * Ensure the {@link UserViewEngine} cache is loaded, establish a one-time reactive
475
+ * subscription to it, and (re)derive the view lists for the current entity.
476
+ *
477
+ * The subscription is what keeps this dropdown correct: BaseEntity `.Save()`/`.Delete()`
478
+ * on a User View auto-invalidates the engine cache (an in-place array mutation), which
479
+ * emits on `ObserveProperty('_views')`. So when the workspace creates, updates, duplicates,
480
+ * or deletes a view, the list here re-derives automatically — no manual reload required,
481
+ * and no stale-cache race between a fire-and-forget reload and the async cache update.
483
482
  */
484
483
  async LoadViews() {
485
484
  if (!this.Entity) {
@@ -488,11 +487,49 @@ export class ViewSelectorComponent extends BaseAngularComponent {
488
487
  this.IsLoading = true;
489
488
  this.cdr.detectChanges();
490
489
  try {
491
- const userId = this.metadata.CurrentUser?.ID;
492
- // Use UserViewEngine cache instead of a direct RunView to avoid redundant DB calls.
493
- // The engine is initialized once and caches all views; GetAccessibleViewsForEntity()
494
- // already filters by owned + shared and checks UserCanView.
490
+ // Load once; subsequent calls are cheap no-ops. We never force a refresh here — the
491
+ // reactive subscription below keeps the lists fresh once data has changed.
495
492
  await UserViewEngine.Instance.Config(false);
493
+ }
494
+ catch (error) {
495
+ console.error('Failed to load views:', error);
496
+ }
497
+ finally {
498
+ this.IsLoading = false;
499
+ }
500
+ this.ensureEngineSubscription();
501
+ this.recomputeViews();
502
+ }
503
+ /**
504
+ * Subscribe (once for the component's lifetime) to the engine's cached `_views` array.
505
+ * The BehaviorSubject replays the current array on subscribe and re-emits on every
506
+ * subsequent create/update/delete/refresh, so {@link recomputeViews} runs whenever the
507
+ * underlying data actually changes.
508
+ */
509
+ ensureEngineSubscription() {
510
+ if (this.subscribedToEngine) {
511
+ return;
512
+ }
513
+ this.subscribedToEngine = true;
514
+ UserViewEngine.Instance
515
+ .ObserveProperty('_views')
516
+ .pipe(takeUntil(this.destroy$))
517
+ .subscribe(() => this.recomputeViews());
518
+ }
519
+ /**
520
+ * Re-derive the owned/shared view lists for the current entity from the engine cache.
521
+ * `GetAccessibleViewsForEntity()` already filters by owned + shared and checks UserCanView.
522
+ */
523
+ recomputeViews() {
524
+ if (!this.Entity) {
525
+ this.MyViews = [];
526
+ this.SharedViews = [];
527
+ this.SelectedView = null;
528
+ this.cdr.detectChanges();
529
+ return;
530
+ }
531
+ try {
532
+ const userId = this.metadata.CurrentUser?.ID;
496
533
  const accessibleViews = UserViewEngine.Instance.GetAccessibleViewsForEntity(this.Entity.ID);
497
534
  // Separate into owned and shared
498
535
  this.MyViews = accessibleViews
@@ -505,10 +542,9 @@ export class ViewSelectorComponent extends BaseAngularComponent {
505
542
  this.updateSelectedViewFromId();
506
543
  }
507
544
  catch (error) {
508
- console.error('Failed to load views:', error);
545
+ console.error('Failed to derive views:', error);
509
546
  }
510
547
  finally {
511
- this.IsLoading = false;
512
548
  this.cdr.detectChanges();
513
549
  }
514
550
  }
@@ -662,6 +698,12 @@ export class ViewSelectorComponent extends BaseAngularComponent {
662
698
  get HasViews() {
663
699
  return this.MyViews.length > 0 || this.SharedViews.length > 0;
664
700
  }
701
+ /**
702
+ * Title for the "no search results" empty state — echoes the current search term.
703
+ */
704
+ get NoViewsMatchMessage() {
705
+ return `No views match "${this.SearchText}"`;
706
+ }
665
707
  /**
666
708
  * Check if the current user can edit the selected view
667
709
  */
@@ -782,7 +824,7 @@ export class ViewSelectorComponent extends BaseAngularComponent {
782
824
  this.SelectDefault();
783
825
  }
784
826
  static ɵfac = function ViewSelectorComponent_Factory(__ngFactoryType__) { return new (__ngFactoryType__ || ViewSelectorComponent)(i0.ɵɵdirectiveInject(i0.ChangeDetectorRef)); };
785
- static ɵcmp = /*@__PURE__*/ i0.ɵɵdefineComponent({ type: ViewSelectorComponent, selectors: [["mj-view-selector"]], inputs: { Entity: "Entity", SelectedViewID: "SelectedViewID", ViewModified: "ViewModified" }, outputs: { ViewSelected: "ViewSelected", SaveViewRequested: "SaveViewRequested", ManageViewsRequested: "ManageViewsRequested", OpenInTabRequested: "OpenInTabRequested", ConfigureViewRequested: "ConfigureViewRequested", CreateNewRecordRequested: "CreateNewRecordRequested", ExportRequested: "ExportRequested", DuplicateViewRequested: "DuplicateViewRequested", QuickSaveRequested: "QuickSaveRequested", RevertRequested: "RevertRequested" }, standalone: false, features: [i0.ɵɵInheritDefinitionFeature, i0.ɵɵNgOnChangesFeature], decls: 17, vars: 12, consts: [[1, "vs-container"], [1, "vs-backdrop"], [1, "vs-wrapper"], ["title", "Select a saved view", 1, "vs-button", 3, "click", "disabled"], [1, "fa-solid", "fa-layer-group", "vs-btn-icon"], [1, "vs-btn-name"], ["title", "View has unsaved changes", 1, "vs-modified-dot"], [1, "fa-solid", "fa-chevron-down", "vs-arrow"], [1, "vs-panel"], ["title", "Open this view in a new tab", 1, "vs-icon-btn"], ["title", "Configure view settings (columns, filters, sorting)", 1, "vs-icon-btn", 3, "click"], [1, "fa-solid", "fa-sliders-h"], ["title", "Create new record", 1, "vs-icon-btn", 3, "click"], [1, "fa-solid", "fa-plus"], ["title", "Export to Excel", 1, "vs-icon-btn", "vs-export-btn", 3, "click"], [1, "fa-solid", "fa-file-excel"], [1, "vs-backdrop", 3, "click"], [1, "vs-panel-header"], [1, "fa-solid", "fa-table-list", "vs-header-icon"], [1, "vs-panel-title"], [1, "vs-Entity-badge"], ["title", "Close", 1, "vs-close-btn", 3, "click"], [1, "fa-solid", "fa-times"], [1, "vs-panel-search"], ["type", "text", "placeholder", "Search views...", 1, "vs-search-input", 3, "ngModelChange", "keydown.escape", "ngModel"], [1, "vs-panel-body"], [1, "vs-section"], [1, "vs-card", 3, "click"], [1, "vs-card-icon"], [1, "fa-solid", "fa-table"], [1, "vs-card-content"], [1, "vs-card-name"], [1, "fa-solid", "fa-check", "vs-card-check"], [1, "vs-empty-message"], [1, "vs-loading"], [1, "vs-panel-footer"], ["title", "Save current view configuration", 1, "vs-panel-btn", "primary", 3, "click"], ["title", "Reset to default view", 1, "vs-panel-btn", 3, "click"], [1, "fa-solid", "fa-arrow-rotate-left"], [1, "vs-section-header"], [1, "fa-solid", "fa-user"], [1, "vs-section-count"], [1, "vs-card", 3, "active"], [1, "fa-solid", "fa-table-list"], [1, "vs-default-badge"], [1, "vs-card-desc"], [1, "vs-card-meta"], [1, "vs-card-actions"], ["title", "Duplicate", 1, "vs-action-btn", 3, "click"], [1, "fa-regular", "fa-copy"], ["title", "Configure", 1, "vs-action-btn", 3, "click"], [1, "fa-solid", "fa-sliders"], ["title", "Open in Tab", 1, "vs-action-btn", 3, "click"], [1, "fa-solid", "fa-up-right-from-square"], [1, "fa-solid", "fa-filter"], [1, "fa-solid", "fa-table-columns"], [1, "fa-solid", "fa-arrow-down-short-wide"], [1, "fa-solid", "fa-share-nodes"], [1, "vs-card-icon", "shared"], [1, "fa-solid", "fa-users"], [1, "vs-shared-badge"], [1, "vs-shared-badge", "editable"], ["title", "Duplicate as My View", 1, "vs-action-btn", 3, "click"], ["title", "Configure", 1, "vs-action-btn"], [1, "fa-solid", "fa-bookmark"], [1, "vs-empty-text"], [1, "fa-solid", "fa-search"], [1, "fa-solid", "fa-spinner", "fa-spin"], ["title", "Open this view in a new tab", 1, "vs-icon-btn", 3, "click"], [1, "fa-solid", "fa-external-link-alt"]], template: function ViewSelectorComponent_Template(rf, ctx) { if (rf & 1) {
827
+ static ɵcmp = /*@__PURE__*/ i0.ɵɵdefineComponent({ type: ViewSelectorComponent, selectors: [["mj-view-selector"]], inputs: { Entity: "Entity", SelectedViewID: "SelectedViewID", ViewModified: "ViewModified" }, outputs: { ViewSelected: "ViewSelected", SaveViewRequested: "SaveViewRequested", ManageViewsRequested: "ManageViewsRequested", OpenInTabRequested: "OpenInTabRequested", ConfigureViewRequested: "ConfigureViewRequested", CreateNewRecordRequested: "CreateNewRecordRequested", ExportRequested: "ExportRequested", DuplicateViewRequested: "DuplicateViewRequested", QuickSaveRequested: "QuickSaveRequested", RevertRequested: "RevertRequested" }, standalone: false, features: [i0.ɵɵInheritDefinitionFeature, i0.ɵɵNgOnChangesFeature], decls: 17, vars: 12, consts: [[1, "vs-container"], [1, "vs-backdrop"], [1, "vs-wrapper"], ["title", "Select a saved view", 1, "vs-button", 3, "click", "disabled"], [1, "fa-solid", "fa-layer-group", "vs-btn-icon"], [1, "vs-btn-name"], ["title", "View has unsaved changes", 1, "vs-modified-dot"], [1, "fa-solid", "fa-chevron-down", "vs-arrow"], [1, "vs-panel"], ["title", "Open this view in a new tab", 1, "vs-icon-btn"], ["title", "Configure view settings (columns, filters, sorting)", 1, "vs-icon-btn", 3, "click"], [1, "fa-solid", "fa-sliders-h"], ["title", "Create new record", 1, "vs-icon-btn", 3, "click"], [1, "fa-solid", "fa-plus"], ["title", "Export to Excel", 1, "vs-icon-btn", "vs-export-btn", 3, "click"], [1, "fa-solid", "fa-file-excel"], [1, "vs-backdrop", 3, "click"], [1, "vs-panel-header"], [1, "fa-solid", "fa-table-list", "vs-header-icon"], [1, "vs-panel-title"], [1, "vs-Entity-badge"], ["title", "Close", 1, "vs-close-btn", 3, "click"], [1, "fa-solid", "fa-times"], [1, "vs-panel-search"], ["type", "text", "placeholder", "Search views...", 1, "vs-search-input", 3, "ngModelChange", "keydown.escape", "ngModel"], [1, "vs-panel-body"], [1, "vs-section"], [1, "vs-card", 3, "click"], [1, "vs-card-icon"], [1, "fa-solid", "fa-table"], [1, "vs-card-content"], [1, "vs-card-name"], [1, "fa-solid", "fa-check", "vs-card-check"], ["Size", "compact", "Icon", "fa-solid fa-bookmark", "Title", "No saved views yet", "Message", "Save your current configuration as a view"], ["Size", "compact", "Variant", "no-results", 3, "Title"], [1, "vs-loading"], [1, "vs-panel-footer"], ["title", "Save current view configuration", 1, "vs-panel-btn", "primary", 3, "click"], ["title", "Reset to default view", 1, "vs-panel-btn", 3, "click"], [1, "fa-solid", "fa-arrow-rotate-left"], [1, "vs-section-header"], [1, "fa-solid", "fa-user"], [1, "vs-section-count"], [1, "vs-card", 3, "active"], [1, "fa-solid", "fa-table-list"], [1, "vs-default-badge"], [1, "vs-card-desc"], [1, "vs-card-meta"], [1, "vs-card-actions"], ["title", "Duplicate", 1, "vs-action-btn", 3, "click"], [1, "fa-regular", "fa-copy"], ["title", "Configure", 1, "vs-action-btn", 3, "click"], [1, "fa-solid", "fa-sliders"], ["title", "Open in Tab", 1, "vs-action-btn", 3, "click"], [1, "fa-solid", "fa-up-right-from-square"], [1, "fa-solid", "fa-filter"], [1, "fa-solid", "fa-table-columns"], [1, "fa-solid", "fa-arrow-down-short-wide"], [1, "fa-solid", "fa-share-nodes"], [1, "vs-card-icon", "shared"], [1, "fa-solid", "fa-users"], [1, "vs-shared-badge"], [1, "vs-shared-badge", "editable"], ["title", "Duplicate as My View", 1, "vs-action-btn", 3, "click"], ["title", "Configure", 1, "vs-action-btn"], [1, "fa-solid", "fa-spinner", "fa-spin"], ["title", "Open this view in a new tab", 1, "vs-icon-btn", 3, "click"], [1, "fa-solid", "fa-external-link-alt"]], template: function ViewSelectorComponent_Template(rf, ctx) { if (rf & 1) {
786
828
  i0.ɵɵelementStart(0, "div", 0);
787
829
  i0.ɵɵconditionalCreate(1, ViewSelectorComponent_Conditional_1_Template, 1, 0, "div", 1);
788
830
  i0.ɵɵelementStart(2, "div", 2)(3, "button", 3);
@@ -825,11 +867,11 @@ export class ViewSelectorComponent extends BaseAngularComponent {
825
867
  i0.ɵɵconditional(ctx.IsDropdownOpen ? 9 : -1);
826
868
  i0.ɵɵadvance();
827
869
  i0.ɵɵconditional(ctx.SelectedViewID ? 10 : -1);
828
- } }, dependencies: [i1.DefaultValueAccessor, i1.NgControlStatus, i1.NgModel], styles: ["/* ========================================\n VIEW SELECTOR - All classes prefixed vs-\n to avoid conflicts (ViewEncapsulation.None)\n ======================================== */\n\n/* Container */\n.vs-container {\n display: flex;\n align-items: center;\n gap: 4px;\n position: relative;\n}\n\n/* Backdrop for closing panel */\n.vs-backdrop {\n position: fixed;\n top: 0;\n left: 0;\n right: 0;\n bottom: 0;\n z-index: 999;\n background: transparent;\n}\n\n.vs-wrapper {\n position: relative;\n}\n\n/* Main Button */\n.vs-button {\n display: flex;\n align-items: center;\n gap: 8px;\n padding: 6px 12px;\n background: var(--mj-bg-surface-card);\n border: 1px solid var(--mj-border-default);\n border-radius: 4px;\n cursor: pointer;\n font-size: 13px;\n font-weight: 500;\n color: var(--mj-text-primary);\n transition: all 0.15s ease;\n min-width: 140px;\n max-width: 280px;\n}\n\n.vs-button:hover {\n border-color: var(--mj-brand-primary);\n background: color-mix(in srgb, var(--mj-brand-primary) 5%, var(--mj-bg-surface));\n}\n\n.vs-button:disabled {\n opacity: 0.6;\n cursor: not-allowed;\n}\n\n.vs-button.open {\n border-color: var(--mj-brand-primary);\n background: color-mix(in srgb, var(--mj-brand-primary) 5%, var(--mj-bg-surface));\n}\n\n.vs-button.modified {\n border-color: var(--mj-status-warning);\n}\n\n.vs-btn-icon {\n color: var(--mj-brand-primary);\n font-size: 12px;\n}\n\n.vs-btn-name {\n flex: 1;\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n text-align: left;\n}\n\n.vs-modified-dot {\n color: var(--mj-status-warning);\n font-weight: bold;\n font-size: 18px;\n line-height: 1;\n}\n\n.vs-arrow {\n color: var(--mj-text-muted);\n font-size: 10px;\n transition: transform 0.2s ease;\n}\n\n.vs-arrow.rotated {\n transform: rotate(180deg);\n}\n\n/* ========================================\n RICH VIEW PANEL\n Styles ported directly from prototype\n ======================================== */\n\n/* Reset inherited styles inside panel */\n.vs-panel,\n.vs-panel * {\n box-sizing: border-box;\n line-height: 1.5;\n text-align: left;\n}\n\n.vs-panel {\n position: absolute;\n top: calc(100% + 4px);\n left: 0;\n width: 400px;\n max-width: calc(100vw - 40px);\n background: var(--mj-bg-surface);\n border: 1px solid var(--mj-border-default);\n border-radius: 12px;\n box-shadow: 0 8px 32px rgba(0, 0, 0, 0.16);\n z-index: 1000;\n overflow: hidden;\n font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;\n font-size: 13px;\n color: var(--mj-text-primary);\n}\n\n/* Panel Header */\n.vs-panel-header {\n padding: 16px 20px;\n display: flex;\n align-items: center;\n gap: 12px;\n border-bottom: 1px solid var(--mj-border-default);\n}\n\n.vs-header-icon {\n color: var(--mj-brand-primary);\n font-size: 14px;\n}\n\n.vs-panel-title {\n font-size: 15px;\n font-weight: 600;\n color: var(--mj-text-primary);\n}\n\n.vs-entity-badge {\n font-size: 11px;\n font-weight: 500;\n background: color-mix(in srgb, var(--mj-brand-primary) 12%, var(--mj-bg-surface));\n color: var(--mj-brand-primary);\n padding: 2px 8px;\n border-radius: 10px;\n}\n\n.vs-close-btn {\n margin-left: auto;\n background: none;\n border: none;\n cursor: pointer;\n color: var(--mj-text-muted);\n font-size: 16px;\n padding: 4px;\n display: flex;\n align-items: center;\n justify-content: center;\n}\n\n.vs-close-btn:hover {\n color: var(--mj-text-primary);\n}\n\n/* Panel Search */\n.vs-panel-search {\n padding: 12px 20px;\n border-bottom: 1px solid var(--mj-border-default);\n}\n\n.vs-search-input {\n width: 100%;\n padding: 6px 12px 6px 32px;\n border: 1px solid var(--mj-border-default);\n border-radius: 4px;\n font-size: 13px;\n background: var(--mj-bg-surface-card) url(\"data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 512 512' fill='%23999'%3E%3Cpath d='M416 208c0 45.9-14.9 88.3-40 122.7L502.6 457.4c12.5 12.5 12.5 32.8 0 45.3s-32.8 12.5-45.3 0L330.7 376c-34.4 25.2-76.8 40-122.7 40C93.1 416 0 322.9 0 208S93.1 0 208 0S416 93.1 416 208z'/%3E%3C/svg%3E\") no-repeat 10px center;\n background-size: 14px;\n box-sizing: border-box;\n font-family: inherit;\n}\n\n.vs-search-input:focus {\n outline: none;\n border-color: var(--mj-brand-primary);\n}\n\n.vs-search-input::placeholder {\n color: var(--mj-text-muted);\n}\n\n/* Panel Body */\n.vs-panel-body {\n max-height: 400px;\n overflow-y: auto;\n}\n\n/* View Section */\n.vs-section {\n padding: 8px 0;\n}\n\n.vs-section-header {\n padding: 6px 20px;\n font-size: 11px;\n font-weight: 700;\n color: var(--mj-text-muted);\n text-transform: uppercase;\n letter-spacing: 0.5px;\n display: flex;\n align-items: center;\n gap: 6px;\n}\n\n.vs-section-header i {\n font-size: 10px;\n}\n\n.vs-section-count {\n background: var(--mj-border-default);\n padding: 0 6px;\n border-radius: 8px;\n font-size: 10px;\n}\n\n/* View Card */\n.vs-card {\n padding: 10px 20px;\n cursor: pointer;\n transition: background 0.1s;\n display: flex;\n align-items: flex-start;\n gap: 12px;\n}\n\n.vs-card:hover {\n background: color-mix(in srgb, var(--mj-brand-primary) 5%, var(--mj-bg-surface));\n}\n\n.vs-card.active {\n background: color-mix(in srgb, var(--mj-brand-primary) 12%, var(--mj-bg-surface));\n border-left: 3px solid var(--mj-brand-primary);\n padding-left: 17px;\n}\n\n/* View Card Icon */\n.vs-card-icon {\n width: 32px;\n height: 32px;\n border-radius: 6px;\n background: var(--mj-bg-surface-card);\n display: flex;\n align-items: center;\n justify-content: center;\n color: var(--mj-text-muted);\n font-size: 14px;\n flex-shrink: 0;\n margin-top: 2px;\n}\n\n.vs-card-icon.active {\n background: var(--mj-brand-primary);\n color: var(--mj-text-inverse);\n}\n\n.vs-card-icon.shared {\n background: var(--mj-bg-surface-card);\n color: var(--mj-text-muted);\n}\n\n/* View Card Content */\n.vs-card-content {\n flex: 1;\n min-width: 0;\n padding-top: 4px;\n}\n\n.vs-card-name {\n font-size: 13px;\n font-weight: 500;\n color: var(--mj-text-primary);\n display: flex;\n align-items: center;\n gap: 6px;\n}\n\n.vs-card.active .vs-card-name {\n color: var(--mj-brand-primary);\n font-weight: 600;\n}\n\n.vs-default-badge {\n font-size: 9px;\n font-weight: 600;\n background: var(--mj-status-success-bg);\n color: var(--mj-status-success-text);\n padding: 1px 5px;\n border-radius: 6px;\n text-transform: uppercase;\n letter-spacing: 0.3px;\n}\n\n.vs-shared-badge {\n font-size: 9px;\n font-weight: 600;\n background: color-mix(in srgb, var(--mj-brand-primary) 12%, var(--mj-bg-surface));\n color: var(--mj-brand-primary);\n padding: 1px 5px;\n border-radius: 6px;\n}\n\n.vs-shared-badge.editable {\n background: var(--mj-status-success-bg);\n color: var(--mj-status-success-text);\n}\n\n.vs-card-desc {\n font-size: 12px;\n color: var(--mj-text-muted);\n margin-top: 2px;\n display: -webkit-box;\n -webkit-line-clamp: 2;\n -webkit-box-orient: vertical;\n overflow: hidden;\n}\n\n.vs-card-meta {\n display: flex;\n gap: 10px;\n margin-top: 4px;\n font-size: 11px;\n color: var(--mj-text-muted);\n}\n\n.vs-card-meta span {\n display: flex;\n align-items: center;\n gap: 3px;\n}\n\n.vs-card-meta i {\n font-size: 10px;\n}\n\n/* View Card Check */\n.vs-card-check {\n color: var(--mj-brand-primary);\n font-size: 12px;\n flex-shrink: 0;\n margin-top: 2px;\n}\n\n/* View Card Actions (hover reveal) */\n.vs-card-actions {\n display: flex;\n gap: 2px;\n opacity: 0;\n transition: opacity 0.15s;\n flex-shrink: 0;\n margin-top: 2px;\n}\n\n.vs-card:hover .vs-card-actions {\n opacity: 1;\n}\n\n.vs-action-btn {\n width: 26px;\n height: 26px;\n border-radius: 4px;\n border: none;\n background: none;\n cursor: pointer;\n color: var(--mj-text-muted);\n font-size: 12px;\n display: flex;\n align-items: center;\n justify-content: center;\n}\n\n.vs-action-btn:hover {\n background: var(--mj-bg-surface-card);\n color: var(--mj-text-primary);\n}\n\n/* Empty State */\n.vs-empty-message {\n display: flex;\n align-items: center;\n gap: 12px;\n padding: 20px;\n color: var(--mj-text-muted);\n font-size: 13px;\n}\n\n.vs-empty-message i {\n font-size: 16px;\n opacity: 0.5;\n}\n\n.vs-empty-text {\n display: flex;\n flex-direction: column;\n gap: 2px;\n}\n\n.vs-empty-text strong {\n color: var(--mj-text-secondary);\n font-size: 13px;\n}\n\n.vs-empty-text span {\n font-size: 12px;\n}\n\n/* Loading */\n.vs-loading {\n display: flex;\n align-items: center;\n justify-content: center;\n gap: 8px;\n padding: 20px;\n color: var(--mj-text-muted);\n font-size: 13px;\n text-align: center;\n}\n\n/* Panel Footer */\n.vs-panel-footer {\n padding: 12px 20px;\n border-top: 1px solid var(--mj-border-default);\n display: flex;\n gap: 8px;\n}\n\n.vs-panel-btn {\n flex: 1;\n padding: 8px 12px;\n border-radius: 4px;\n border: 1px solid var(--mj-border-default);\n background: var(--mj-bg-surface);\n cursor: pointer;\n font-size: 12px;\n font-weight: 500;\n color: var(--mj-text-secondary);\n display: flex;\n align-items: center;\n justify-content: center;\n gap: 6px;\n transition: all 0.15s;\n font-family: inherit;\n text-align: center;\n}\n\n.vs-panel-btn:hover {\n border-color: var(--mj-brand-primary);\n color: var(--mj-brand-primary);\n}\n\n.vs-panel-btn.primary {\n background: var(--mj-brand-primary);\n color: var(--mj-text-inverse);\n border-color: var(--mj-brand-primary);\n}\n\n.vs-panel-btn.primary:hover {\n background: var(--mj-brand-primary-hover);\n}\n\n.vs-panel-btn i {\n font-size: 11px;\n}\n\n/* ========================================\n ICON BUTTONS (outside panel)\n ======================================== */\n\n.vs-icon-btn {\n display: flex;\n align-items: center;\n justify-content: center;\n width: 32px;\n height: 32px;\n background: var(--mj-bg-surface-card);\n border: 1px solid var(--mj-border-default);\n border-radius: 6px;\n cursor: pointer;\n color: var(--mj-text-secondary);\n transition: all 0.15s ease;\n}\n\n.vs-icon-btn:hover {\n background: var(--mj-bg-surface-hover);\n border-color: var(--mj-border-strong);\n color: var(--mj-brand-primary);\n}\n\n.vs-icon-btn i {\n font-size: 12px;\n}\n\n.vs-export-btn:hover {\n color: var(--mj-status-success);\n}\n\n/* Responsive */\n@media (max-width: 768px) {\n .vs-button {\n min-width: 100px;\n max-width: 180px;\n padding: 6px 10px;\n }\n\n .vs-panel {\n width: calc(100vw - 32px);\n max-width: 400px;\n }\n}\n"], encapsulation: 2 });
870
+ } }, dependencies: [i1.DefaultValueAccessor, i1.NgControlStatus, i1.NgModel, i2.MJEmptyStateComponent], styles: ["/* ========================================\n VIEW SELECTOR - All classes prefixed vs-\n to avoid conflicts (ViewEncapsulation.None)\n ======================================== */\n\n/* Container */\n.vs-container {\n display: flex;\n align-items: center;\n gap: 4px;\n position: relative;\n}\n\n/* Backdrop for closing panel */\n.vs-backdrop {\n position: fixed;\n top: 0;\n left: 0;\n right: 0;\n bottom: 0;\n z-index: 999;\n background: transparent;\n}\n\n.vs-wrapper {\n position: relative;\n}\n\n/* Main Button */\n.vs-button {\n display: flex;\n align-items: center;\n gap: 8px;\n padding: 6px 12px;\n background: var(--mj-bg-surface-card);\n border: 1px solid var(--mj-border-default);\n border-radius: 4px;\n cursor: pointer;\n font-size: 13px;\n font-weight: 500;\n color: var(--mj-text-primary);\n transition: all 0.15s ease;\n min-width: 140px;\n max-width: 280px;\n}\n\n.vs-button:hover {\n border-color: var(--mj-brand-primary);\n background: color-mix(in srgb, var(--mj-brand-primary) 5%, var(--mj-bg-surface));\n}\n\n.vs-button:disabled {\n opacity: 0.6;\n cursor: not-allowed;\n}\n\n.vs-button.open {\n border-color: var(--mj-brand-primary);\n background: color-mix(in srgb, var(--mj-brand-primary) 5%, var(--mj-bg-surface));\n}\n\n.vs-button.modified {\n border-color: var(--mj-status-warning);\n}\n\n.vs-btn-icon {\n color: var(--mj-brand-primary);\n font-size: 12px;\n}\n\n.vs-btn-name {\n flex: 1;\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n text-align: left;\n}\n\n.vs-modified-dot {\n color: var(--mj-status-warning);\n font-weight: bold;\n font-size: 18px;\n line-height: 1;\n}\n\n.vs-arrow {\n color: var(--mj-text-muted);\n font-size: 10px;\n transition: transform 0.2s ease;\n}\n\n.vs-arrow.rotated {\n transform: rotate(180deg);\n}\n\n/* ========================================\n RICH VIEW PANEL\n Styles ported directly from prototype\n ======================================== */\n\n/* Reset inherited styles inside panel */\n.vs-panel,\n.vs-panel * {\n box-sizing: border-box;\n line-height: 1.5;\n text-align: left;\n}\n\n.vs-panel {\n position: absolute;\n top: calc(100% + 4px);\n left: 0;\n width: 400px;\n max-width: calc(100vw - 40px);\n background: var(--mj-bg-surface);\n border: 1px solid var(--mj-border-default);\n border-radius: 12px;\n box-shadow: 0 8px 32px rgba(0, 0, 0, 0.16);\n z-index: 1000;\n overflow: hidden;\n font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;\n font-size: 13px;\n color: var(--mj-text-primary);\n}\n\n/* Panel Header */\n.vs-panel-header {\n padding: 16px 20px;\n display: flex;\n align-items: center;\n gap: 12px;\n border-bottom: 1px solid var(--mj-border-default);\n}\n\n.vs-header-icon {\n color: var(--mj-brand-primary);\n font-size: 14px;\n}\n\n.vs-panel-title {\n font-size: 15px;\n font-weight: 600;\n color: var(--mj-text-primary);\n}\n\n.vs-entity-badge {\n font-size: 11px;\n font-weight: 500;\n background: color-mix(in srgb, var(--mj-brand-primary) 12%, var(--mj-bg-surface));\n color: var(--mj-brand-primary);\n padding: 2px 8px;\n border-radius: 10px;\n}\n\n.vs-close-btn {\n margin-left: auto;\n background: none;\n border: none;\n cursor: pointer;\n color: var(--mj-text-muted);\n font-size: 16px;\n padding: 4px;\n display: flex;\n align-items: center;\n justify-content: center;\n}\n\n.vs-close-btn:hover {\n color: var(--mj-text-primary);\n}\n\n/* Panel Search */\n.vs-panel-search {\n padding: 12px 20px;\n border-bottom: 1px solid var(--mj-border-default);\n}\n\n.vs-search-input {\n width: 100%;\n padding: 6px 12px 6px 32px;\n border: 1px solid var(--mj-border-default);\n border-radius: 4px;\n font-size: 13px;\n background: var(--mj-bg-surface-card) url(\"data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 512 512' fill='%23999'%3E%3Cpath d='M416 208c0 45.9-14.9 88.3-40 122.7L502.6 457.4c12.5 12.5 12.5 32.8 0 45.3s-32.8 12.5-45.3 0L330.7 376c-34.4 25.2-76.8 40-122.7 40C93.1 416 0 322.9 0 208S93.1 0 208 0S416 93.1 416 208z'/%3E%3C/svg%3E\") no-repeat 10px center;\n background-size: 14px;\n box-sizing: border-box;\n font-family: inherit;\n}\n\n.vs-search-input:focus {\n outline: none;\n border-color: var(--mj-brand-primary);\n}\n\n.vs-search-input::placeholder {\n color: var(--mj-text-muted);\n}\n\n/* Panel Body */\n.vs-panel-body {\n max-height: 400px;\n overflow-y: auto;\n}\n\n/* View Section */\n.vs-section {\n padding: 8px 0;\n}\n\n.vs-section-header {\n padding: 6px 20px;\n font-size: 11px;\n font-weight: 700;\n color: var(--mj-text-muted);\n text-transform: uppercase;\n letter-spacing: 0.5px;\n display: flex;\n align-items: center;\n gap: 6px;\n}\n\n.vs-section-header i {\n font-size: 10px;\n}\n\n.vs-section-count {\n background: var(--mj-border-default);\n padding: 0 6px;\n border-radius: 8px;\n font-size: 10px;\n}\n\n/* View Card */\n.vs-card {\n padding: 10px 20px;\n cursor: pointer;\n transition: background 0.1s;\n display: flex;\n align-items: flex-start;\n gap: 12px;\n}\n\n.vs-card:hover {\n background: color-mix(in srgb, var(--mj-brand-primary) 5%, var(--mj-bg-surface));\n}\n\n.vs-card.active {\n background: color-mix(in srgb, var(--mj-brand-primary) 12%, var(--mj-bg-surface));\n border-left: 3px solid var(--mj-brand-primary);\n padding-left: 17px;\n}\n\n/* View Card Icon */\n.vs-card-icon {\n width: 32px;\n height: 32px;\n border-radius: 6px;\n background: var(--mj-bg-surface-card);\n display: flex;\n align-items: center;\n justify-content: center;\n color: var(--mj-text-muted);\n font-size: 14px;\n flex-shrink: 0;\n margin-top: 2px;\n}\n\n.vs-card-icon.active {\n background: var(--mj-brand-primary);\n color: var(--mj-text-inverse);\n}\n\n.vs-card-icon.shared {\n background: var(--mj-bg-surface-card);\n color: var(--mj-text-muted);\n}\n\n/* View Card Content */\n.vs-card-content {\n flex: 1;\n min-width: 0;\n padding-top: 4px;\n}\n\n.vs-card-name {\n font-size: 13px;\n font-weight: 500;\n color: var(--mj-text-primary);\n display: flex;\n align-items: center;\n gap: 6px;\n}\n\n.vs-card.active .vs-card-name {\n color: var(--mj-brand-primary);\n font-weight: 600;\n}\n\n.vs-default-badge {\n font-size: 9px;\n font-weight: 600;\n background: var(--mj-status-success-bg);\n color: var(--mj-status-success-text);\n padding: 1px 5px;\n border-radius: 6px;\n text-transform: uppercase;\n letter-spacing: 0.3px;\n}\n\n.vs-shared-badge {\n font-size: 9px;\n font-weight: 600;\n background: color-mix(in srgb, var(--mj-brand-primary) 12%, var(--mj-bg-surface));\n color: var(--mj-brand-primary);\n padding: 1px 5px;\n border-radius: 6px;\n}\n\n.vs-shared-badge.editable {\n background: var(--mj-status-success-bg);\n color: var(--mj-status-success-text);\n}\n\n.vs-card-desc {\n font-size: 12px;\n color: var(--mj-text-muted);\n margin-top: 2px;\n display: -webkit-box;\n -webkit-line-clamp: 2;\n -webkit-box-orient: vertical;\n overflow: hidden;\n}\n\n.vs-card-meta {\n display: flex;\n gap: 10px;\n margin-top: 4px;\n font-size: 11px;\n color: var(--mj-text-muted);\n}\n\n.vs-card-meta span {\n display: flex;\n align-items: center;\n gap: 3px;\n}\n\n.vs-card-meta i {\n font-size: 10px;\n}\n\n/* View Card Check */\n.vs-card-check {\n color: var(--mj-brand-primary);\n font-size: 12px;\n flex-shrink: 0;\n margin-top: 2px;\n}\n\n/* View Card Actions (hover reveal) */\n.vs-card-actions {\n display: flex;\n gap: 2px;\n opacity: 0;\n transition: opacity 0.15s;\n flex-shrink: 0;\n margin-top: 2px;\n}\n\n.vs-card:hover .vs-card-actions {\n opacity: 1;\n}\n\n.vs-action-btn {\n width: 26px;\n height: 26px;\n border-radius: 4px;\n border: none;\n background: none;\n cursor: pointer;\n color: var(--mj-text-muted);\n font-size: 12px;\n display: flex;\n align-items: center;\n justify-content: center;\n}\n\n.vs-action-btn:hover {\n background: var(--mj-bg-surface-card);\n color: var(--mj-text-primary);\n}\n\n/* Loading */\n.vs-loading {\n display: flex;\n align-items: center;\n justify-content: center;\n gap: 8px;\n padding: 20px;\n color: var(--mj-text-muted);\n font-size: 13px;\n text-align: center;\n}\n\n/* Panel Footer */\n.vs-panel-footer {\n padding: 12px 20px;\n border-top: 1px solid var(--mj-border-default);\n display: flex;\n gap: 8px;\n}\n\n.vs-panel-btn {\n flex: 1;\n padding: 8px 12px;\n border-radius: 4px;\n border: 1px solid var(--mj-border-default);\n background: var(--mj-bg-surface);\n cursor: pointer;\n font-size: 12px;\n font-weight: 500;\n color: var(--mj-text-secondary);\n display: flex;\n align-items: center;\n justify-content: center;\n gap: 6px;\n transition: all 0.15s;\n font-family: inherit;\n text-align: center;\n}\n\n.vs-panel-btn:hover {\n border-color: var(--mj-brand-primary);\n color: var(--mj-brand-primary);\n}\n\n.vs-panel-btn.primary {\n background: var(--mj-brand-primary);\n color: var(--mj-text-inverse);\n border-color: var(--mj-brand-primary);\n}\n\n.vs-panel-btn.primary:hover {\n background: var(--mj-brand-primary-hover);\n}\n\n.vs-panel-btn i {\n font-size: 11px;\n}\n\n/* ========================================\n ICON BUTTONS (outside panel)\n ======================================== */\n\n.vs-icon-btn {\n display: flex;\n align-items: center;\n justify-content: center;\n width: 32px;\n height: 32px;\n background: var(--mj-bg-surface-card);\n border: 1px solid var(--mj-border-default);\n border-radius: 6px;\n cursor: pointer;\n color: var(--mj-text-secondary);\n transition: all 0.15s ease;\n}\n\n.vs-icon-btn:hover {\n background: var(--mj-bg-surface-hover);\n border-color: var(--mj-border-strong);\n color: var(--mj-brand-primary);\n}\n\n.vs-icon-btn i {\n font-size: 12px;\n}\n\n.vs-export-btn:hover {\n color: var(--mj-status-success);\n}\n\n/* Responsive */\n@media (max-width: 768px) {\n .vs-button {\n min-width: 100px;\n max-width: 180px;\n padding: 6px 10px;\n }\n\n .vs-panel {\n width: calc(100vw - 32px);\n max-width: 400px;\n }\n}\n"], encapsulation: 2 });
829
871
  }
830
872
  (() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassMetadata(ViewSelectorComponent, [{
831
873
  type: Component,
832
- args: [{ standalone: false, selector: 'mj-view-selector', encapsulation: ViewEncapsulation.None, template: "<div class=\"vs-container\">\n <!-- Backdrop for closing panel -->\n @if (IsDropdownOpen) {\n <div class=\"vs-backdrop\" (click)=\"CloseDropdown()\"></div>\n }\n\n <!-- Main View Selector Button -->\n <div class=\"vs-wrapper\">\n <button\n class=\"vs-button\"\n [class.modified]=\"ViewModified\"\n [class.open]=\"IsDropdownOpen\"\n (click)=\"ToggleDropdown()\"\n [disabled]=\"IsLoading\"\n title=\"Select a saved view\">\n <i class=\"fa-solid fa-layer-group vs-btn-icon\"></i>\n <span class=\"vs-btn-name\">{{ DisplayName }}</span>\n @if (ViewModified) {\n <span class=\"vs-modified-dot\" title=\"View has unsaved changes\">\u2022</span>\n }\n <i class=\"fa-solid fa-chevron-down vs-arrow\" [class.rotated]=\"IsDropdownOpen\"></i>\n </button>\n\n <!-- Rich View Panel -->\n @if (IsDropdownOpen) {\n <div class=\"vs-panel\">\n <!-- Panel Header -->\n <div class=\"vs-panel-header\">\n <i class=\"fa-solid fa-table-list vs-header-icon\"></i>\n <span class=\"vs-panel-title\">Views</span>\n @if (Entity) {\n <span class=\"vs-Entity-badge\">{{ Entity.DisplayNameOrName }}</span>\n }\n <button class=\"vs-close-btn\" (click)=\"CloseDropdown()\" title=\"Close\">\n <i class=\"fa-solid fa-times\"></i>\n </button>\n </div>\n\n <!-- Search -->\n <div class=\"vs-panel-search\">\n <input\n type=\"text\"\n class=\"vs-search-input\"\n placeholder=\"Search views...\"\n [(ngModel)]=\"SearchText\"\n (keydown.escape)=\"SearchText = ''\"\n />\n </div>\n\n <!-- Panel Body -->\n <div class=\"vs-panel-body\">\n <!-- Default Option -->\n <div class=\"vs-section\">\n <div\n class=\"vs-card\"\n [class.active]=\"!SelectedViewID\"\n (click)=\"SelectDefault()\">\n <div class=\"vs-card-icon\" [class.active]=\"!SelectedViewID\">\n <i class=\"fa-solid fa-table\"></i>\n </div>\n <div class=\"vs-card-content\">\n <div class=\"vs-card-name\">(Default)</div>\n </div>\n @if (!SelectedViewID) {\n <i class=\"fa-solid fa-check vs-card-check\"></i>\n }\n </div>\n </div>\n\n <!-- My Views Section -->\n @if (FilteredMyViews.length > 0) {\n <div class=\"vs-section\">\n <div class=\"vs-section-header\">\n <i class=\"fa-solid fa-user\"></i>\n <span>My Views</span>\n <span class=\"vs-section-count\">{{ FilteredMyViews.length }}</span>\n </div>\n @for (view of FilteredMyViews; track view.id) {\n <div\n class=\"vs-card\"\n [class.active]=\"SelectedViewID === view.id\"\n (click)=\"SelectView(view)\">\n <div class=\"vs-card-icon\" [class.active]=\"SelectedViewID === view.id\">\n <i class=\"fa-solid fa-table-list\"></i>\n </div>\n <div class=\"vs-card-content\">\n <div class=\"vs-card-name\">\n {{ view.name }}\n @if (view.isDefault) {\n <span class=\"vs-default-badge\">Default</span>\n }\n </div>\n @if (view.entity.Description) {\n <div class=\"vs-card-desc\">{{ view.entity.Description }}</div>\n }\n @if (GetViewFilterCount(view) > 0 || GetViewColumnCount(view) > 0 || GetViewSortInfo(view)) {\n <div class=\"vs-card-meta\">\n @if (GetViewFilterCount(view) > 0) {\n <span><i class=\"fa-solid fa-filter\"></i> {{ GetViewFilterCount(view) }} filter{{ GetViewFilterCount(view) !== 1 ? 's' : '' }}</span>\n }\n @if (GetViewColumnCount(view) > 0) {\n <span><i class=\"fa-solid fa-table-columns\"></i> {{ GetViewColumnCount(view) }} col{{ GetViewColumnCount(view) !== 1 ? 's' : '' }}</span>\n }\n @if (GetViewSortInfo(view)) {\n <span><i class=\"fa-solid fa-arrow-down-short-wide\"></i> {{ GetViewSortInfo(view) }}</span>\n }\n </div>\n }\n </div>\n <div class=\"vs-card-actions\">\n <button\n class=\"vs-action-btn\"\n (click)=\"OnDuplicateView(view.id, $event)\"\n title=\"Duplicate\">\n <i class=\"fa-regular fa-copy\"></i>\n </button>\n <button\n class=\"vs-action-btn\"\n (click)=\"OnConfigureViewById(view.id, $event)\"\n title=\"Configure\">\n <i class=\"fa-solid fa-sliders\"></i>\n </button>\n <button\n class=\"vs-action-btn\"\n (click)=\"OnOpenViewInTab(view.id, $event)\"\n title=\"Open in Tab\">\n <i class=\"fa-solid fa-up-right-from-square\"></i>\n </button>\n </div>\n @if (SelectedViewID === view.id) {\n <i class=\"fa-solid fa-check vs-card-check\"></i>\n }\n </div>\n }\n </div>\n }\n\n <!-- Shared Views Section -->\n @if (FilteredSharedViews.length > 0) {\n <div class=\"vs-section\">\n <div class=\"vs-section-header\">\n <i class=\"fa-solid fa-share-nodes\"></i>\n <span>Shared With Me</span>\n <span class=\"vs-section-count\">{{ FilteredSharedViews.length }}</span>\n </div>\n @for (view of FilteredSharedViews; track view.id) {\n <div\n class=\"vs-card\"\n [class.active]=\"SelectedViewID === view.id\"\n (click)=\"SelectView(view)\">\n <div class=\"vs-card-icon shared\">\n <i class=\"fa-solid fa-users\"></i>\n </div>\n <div class=\"vs-card-content\">\n <div class=\"vs-card-name\">\n {{ view.name }}\n @if (!view.userCanEdit) {\n <span class=\"vs-shared-badge\">View Only</span>\n } @else {\n <span class=\"vs-shared-badge editable\">Can Edit</span>\n }\n </div>\n @if (view.entity.Description) {\n <div class=\"vs-card-desc\">{{ view.entity.Description }}</div>\n }\n @if (GetViewFilterCount(view) > 0 || GetViewColumnCount(view) > 0) {\n <div class=\"vs-card-meta\">\n @if (GetViewFilterCount(view) > 0) {\n <span><i class=\"fa-solid fa-filter\"></i> {{ GetViewFilterCount(view) }} filter{{ GetViewFilterCount(view) !== 1 ? 's' : '' }}</span>\n }\n @if (GetViewColumnCount(view) > 0) {\n <span><i class=\"fa-solid fa-table-columns\"></i> {{ GetViewColumnCount(view) }} col{{ GetViewColumnCount(view) !== 1 ? 's' : '' }}</span>\n }\n </div>\n }\n </div>\n <div class=\"vs-card-actions\">\n <button\n class=\"vs-action-btn\"\n (click)=\"OnDuplicateView(view.id, $event)\"\n title=\"Duplicate as My View\">\n <i class=\"fa-regular fa-copy\"></i>\n </button>\n @if (view.userCanEdit) {\n <button\n class=\"vs-action-btn\"\n (click)=\"OnConfigureViewById(view.id, $event)\"\n title=\"Configure\">\n <i class=\"fa-solid fa-sliders\"></i>\n </button>\n }\n </div>\n @if (SelectedViewID === view.id) {\n <i class=\"fa-solid fa-check vs-card-check\"></i>\n }\n </div>\n }\n </div>\n }\n\n <!-- No Views Message -->\n @if (!HasViews && !IsLoading) {\n <div class=\"vs-empty-message\">\n <i class=\"fa-solid fa-bookmark\"></i>\n <div class=\"vs-empty-text\">\n <strong>No saved views yet</strong>\n <span>Save your current configuration as a view</span>\n </div>\n </div>\n }\n\n <!-- No Search Results -->\n @if (HasViews && FilteredMyViews.length === 0 && FilteredSharedViews.length === 0 && SearchText) {\n <div class=\"vs-empty-message\">\n <i class=\"fa-solid fa-search\"></i>\n <span>No views match \"{{ SearchText }}\"</span>\n </div>\n }\n\n <!-- Loading Indicator -->\n @if (IsLoading) {\n <div class=\"vs-loading\">\n <i class=\"fa-solid fa-spinner fa-spin\"></i>\n <span>Loading views...</span>\n </div>\n }\n </div>\n\n <!-- Panel Footer -->\n <div class=\"vs-panel-footer\">\n <button\n class=\"vs-panel-btn primary\"\n (click)=\"OnQuickSave()\"\n title=\"Save current view configuration\">\n <i class=\"fa-solid fa-plus\"></i>\n <span>New View</span>\n </button>\n <button\n class=\"vs-panel-btn\"\n (click)=\"OnResetToDefault()\"\n title=\"Reset to default view\">\n <i class=\"fa-solid fa-arrow-rotate-left\"></i>\n <span>Reset to Default</span>\n </button>\n </div>\n </div>\n }\n </div>\n\n <!-- Open in Tab Button (only visible when a view is selected) -->\n @if (SelectedViewID) {\n <button\n class=\"vs-icon-btn\"\n (click)=\"OnOpenInTab()\"\n title=\"Open this view in a new tab\">\n <i class=\"fa-solid fa-external-link-alt\"></i>\n </button>\n }\n\n <!-- Configure View Button -->\n <button\n class=\"vs-icon-btn\"\n (click)=\"OnConfigureView()\"\n title=\"Configure view settings (columns, filters, sorting)\">\n <i class=\"fa-solid fa-sliders-h\"></i>\n </button>\n\n <!-- Create New Record Button -->\n <button\n class=\"vs-icon-btn\"\n (click)=\"OnCreateNewRecord()\"\n title=\"Create new record\">\n <i class=\"fa-solid fa-plus\"></i>\n </button>\n\n <!-- Export Button -->\n <button\n class=\"vs-icon-btn vs-export-btn\"\n (click)=\"OnExport()\"\n title=\"Export to Excel\">\n <i class=\"fa-solid fa-file-excel\"></i>\n </button>\n</div>\n", styles: ["/* ========================================\n VIEW SELECTOR - All classes prefixed vs-\n to avoid conflicts (ViewEncapsulation.None)\n ======================================== */\n\n/* Container */\n.vs-container {\n display: flex;\n align-items: center;\n gap: 4px;\n position: relative;\n}\n\n/* Backdrop for closing panel */\n.vs-backdrop {\n position: fixed;\n top: 0;\n left: 0;\n right: 0;\n bottom: 0;\n z-index: 999;\n background: transparent;\n}\n\n.vs-wrapper {\n position: relative;\n}\n\n/* Main Button */\n.vs-button {\n display: flex;\n align-items: center;\n gap: 8px;\n padding: 6px 12px;\n background: var(--mj-bg-surface-card);\n border: 1px solid var(--mj-border-default);\n border-radius: 4px;\n cursor: pointer;\n font-size: 13px;\n font-weight: 500;\n color: var(--mj-text-primary);\n transition: all 0.15s ease;\n min-width: 140px;\n max-width: 280px;\n}\n\n.vs-button:hover {\n border-color: var(--mj-brand-primary);\n background: color-mix(in srgb, var(--mj-brand-primary) 5%, var(--mj-bg-surface));\n}\n\n.vs-button:disabled {\n opacity: 0.6;\n cursor: not-allowed;\n}\n\n.vs-button.open {\n border-color: var(--mj-brand-primary);\n background: color-mix(in srgb, var(--mj-brand-primary) 5%, var(--mj-bg-surface));\n}\n\n.vs-button.modified {\n border-color: var(--mj-status-warning);\n}\n\n.vs-btn-icon {\n color: var(--mj-brand-primary);\n font-size: 12px;\n}\n\n.vs-btn-name {\n flex: 1;\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n text-align: left;\n}\n\n.vs-modified-dot {\n color: var(--mj-status-warning);\n font-weight: bold;\n font-size: 18px;\n line-height: 1;\n}\n\n.vs-arrow {\n color: var(--mj-text-muted);\n font-size: 10px;\n transition: transform 0.2s ease;\n}\n\n.vs-arrow.rotated {\n transform: rotate(180deg);\n}\n\n/* ========================================\n RICH VIEW PANEL\n Styles ported directly from prototype\n ======================================== */\n\n/* Reset inherited styles inside panel */\n.vs-panel,\n.vs-panel * {\n box-sizing: border-box;\n line-height: 1.5;\n text-align: left;\n}\n\n.vs-panel {\n position: absolute;\n top: calc(100% + 4px);\n left: 0;\n width: 400px;\n max-width: calc(100vw - 40px);\n background: var(--mj-bg-surface);\n border: 1px solid var(--mj-border-default);\n border-radius: 12px;\n box-shadow: 0 8px 32px rgba(0, 0, 0, 0.16);\n z-index: 1000;\n overflow: hidden;\n font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;\n font-size: 13px;\n color: var(--mj-text-primary);\n}\n\n/* Panel Header */\n.vs-panel-header {\n padding: 16px 20px;\n display: flex;\n align-items: center;\n gap: 12px;\n border-bottom: 1px solid var(--mj-border-default);\n}\n\n.vs-header-icon {\n color: var(--mj-brand-primary);\n font-size: 14px;\n}\n\n.vs-panel-title {\n font-size: 15px;\n font-weight: 600;\n color: var(--mj-text-primary);\n}\n\n.vs-entity-badge {\n font-size: 11px;\n font-weight: 500;\n background: color-mix(in srgb, var(--mj-brand-primary) 12%, var(--mj-bg-surface));\n color: var(--mj-brand-primary);\n padding: 2px 8px;\n border-radius: 10px;\n}\n\n.vs-close-btn {\n margin-left: auto;\n background: none;\n border: none;\n cursor: pointer;\n color: var(--mj-text-muted);\n font-size: 16px;\n padding: 4px;\n display: flex;\n align-items: center;\n justify-content: center;\n}\n\n.vs-close-btn:hover {\n color: var(--mj-text-primary);\n}\n\n/* Panel Search */\n.vs-panel-search {\n padding: 12px 20px;\n border-bottom: 1px solid var(--mj-border-default);\n}\n\n.vs-search-input {\n width: 100%;\n padding: 6px 12px 6px 32px;\n border: 1px solid var(--mj-border-default);\n border-radius: 4px;\n font-size: 13px;\n background: var(--mj-bg-surface-card) url(\"data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 512 512' fill='%23999'%3E%3Cpath d='M416 208c0 45.9-14.9 88.3-40 122.7L502.6 457.4c12.5 12.5 12.5 32.8 0 45.3s-32.8 12.5-45.3 0L330.7 376c-34.4 25.2-76.8 40-122.7 40C93.1 416 0 322.9 0 208S93.1 0 208 0S416 93.1 416 208z'/%3E%3C/svg%3E\") no-repeat 10px center;\n background-size: 14px;\n box-sizing: border-box;\n font-family: inherit;\n}\n\n.vs-search-input:focus {\n outline: none;\n border-color: var(--mj-brand-primary);\n}\n\n.vs-search-input::placeholder {\n color: var(--mj-text-muted);\n}\n\n/* Panel Body */\n.vs-panel-body {\n max-height: 400px;\n overflow-y: auto;\n}\n\n/* View Section */\n.vs-section {\n padding: 8px 0;\n}\n\n.vs-section-header {\n padding: 6px 20px;\n font-size: 11px;\n font-weight: 700;\n color: var(--mj-text-muted);\n text-transform: uppercase;\n letter-spacing: 0.5px;\n display: flex;\n align-items: center;\n gap: 6px;\n}\n\n.vs-section-header i {\n font-size: 10px;\n}\n\n.vs-section-count {\n background: var(--mj-border-default);\n padding: 0 6px;\n border-radius: 8px;\n font-size: 10px;\n}\n\n/* View Card */\n.vs-card {\n padding: 10px 20px;\n cursor: pointer;\n transition: background 0.1s;\n display: flex;\n align-items: flex-start;\n gap: 12px;\n}\n\n.vs-card:hover {\n background: color-mix(in srgb, var(--mj-brand-primary) 5%, var(--mj-bg-surface));\n}\n\n.vs-card.active {\n background: color-mix(in srgb, var(--mj-brand-primary) 12%, var(--mj-bg-surface));\n border-left: 3px solid var(--mj-brand-primary);\n padding-left: 17px;\n}\n\n/* View Card Icon */\n.vs-card-icon {\n width: 32px;\n height: 32px;\n border-radius: 6px;\n background: var(--mj-bg-surface-card);\n display: flex;\n align-items: center;\n justify-content: center;\n color: var(--mj-text-muted);\n font-size: 14px;\n flex-shrink: 0;\n margin-top: 2px;\n}\n\n.vs-card-icon.active {\n background: var(--mj-brand-primary);\n color: var(--mj-text-inverse);\n}\n\n.vs-card-icon.shared {\n background: var(--mj-bg-surface-card);\n color: var(--mj-text-muted);\n}\n\n/* View Card Content */\n.vs-card-content {\n flex: 1;\n min-width: 0;\n padding-top: 4px;\n}\n\n.vs-card-name {\n font-size: 13px;\n font-weight: 500;\n color: var(--mj-text-primary);\n display: flex;\n align-items: center;\n gap: 6px;\n}\n\n.vs-card.active .vs-card-name {\n color: var(--mj-brand-primary);\n font-weight: 600;\n}\n\n.vs-default-badge {\n font-size: 9px;\n font-weight: 600;\n background: var(--mj-status-success-bg);\n color: var(--mj-status-success-text);\n padding: 1px 5px;\n border-radius: 6px;\n text-transform: uppercase;\n letter-spacing: 0.3px;\n}\n\n.vs-shared-badge {\n font-size: 9px;\n font-weight: 600;\n background: color-mix(in srgb, var(--mj-brand-primary) 12%, var(--mj-bg-surface));\n color: var(--mj-brand-primary);\n padding: 1px 5px;\n border-radius: 6px;\n}\n\n.vs-shared-badge.editable {\n background: var(--mj-status-success-bg);\n color: var(--mj-status-success-text);\n}\n\n.vs-card-desc {\n font-size: 12px;\n color: var(--mj-text-muted);\n margin-top: 2px;\n display: -webkit-box;\n -webkit-line-clamp: 2;\n -webkit-box-orient: vertical;\n overflow: hidden;\n}\n\n.vs-card-meta {\n display: flex;\n gap: 10px;\n margin-top: 4px;\n font-size: 11px;\n color: var(--mj-text-muted);\n}\n\n.vs-card-meta span {\n display: flex;\n align-items: center;\n gap: 3px;\n}\n\n.vs-card-meta i {\n font-size: 10px;\n}\n\n/* View Card Check */\n.vs-card-check {\n color: var(--mj-brand-primary);\n font-size: 12px;\n flex-shrink: 0;\n margin-top: 2px;\n}\n\n/* View Card Actions (hover reveal) */\n.vs-card-actions {\n display: flex;\n gap: 2px;\n opacity: 0;\n transition: opacity 0.15s;\n flex-shrink: 0;\n margin-top: 2px;\n}\n\n.vs-card:hover .vs-card-actions {\n opacity: 1;\n}\n\n.vs-action-btn {\n width: 26px;\n height: 26px;\n border-radius: 4px;\n border: none;\n background: none;\n cursor: pointer;\n color: var(--mj-text-muted);\n font-size: 12px;\n display: flex;\n align-items: center;\n justify-content: center;\n}\n\n.vs-action-btn:hover {\n background: var(--mj-bg-surface-card);\n color: var(--mj-text-primary);\n}\n\n/* Empty State */\n.vs-empty-message {\n display: flex;\n align-items: center;\n gap: 12px;\n padding: 20px;\n color: var(--mj-text-muted);\n font-size: 13px;\n}\n\n.vs-empty-message i {\n font-size: 16px;\n opacity: 0.5;\n}\n\n.vs-empty-text {\n display: flex;\n flex-direction: column;\n gap: 2px;\n}\n\n.vs-empty-text strong {\n color: var(--mj-text-secondary);\n font-size: 13px;\n}\n\n.vs-empty-text span {\n font-size: 12px;\n}\n\n/* Loading */\n.vs-loading {\n display: flex;\n align-items: center;\n justify-content: center;\n gap: 8px;\n padding: 20px;\n color: var(--mj-text-muted);\n font-size: 13px;\n text-align: center;\n}\n\n/* Panel Footer */\n.vs-panel-footer {\n padding: 12px 20px;\n border-top: 1px solid var(--mj-border-default);\n display: flex;\n gap: 8px;\n}\n\n.vs-panel-btn {\n flex: 1;\n padding: 8px 12px;\n border-radius: 4px;\n border: 1px solid var(--mj-border-default);\n background: var(--mj-bg-surface);\n cursor: pointer;\n font-size: 12px;\n font-weight: 500;\n color: var(--mj-text-secondary);\n display: flex;\n align-items: center;\n justify-content: center;\n gap: 6px;\n transition: all 0.15s;\n font-family: inherit;\n text-align: center;\n}\n\n.vs-panel-btn:hover {\n border-color: var(--mj-brand-primary);\n color: var(--mj-brand-primary);\n}\n\n.vs-panel-btn.primary {\n background: var(--mj-brand-primary);\n color: var(--mj-text-inverse);\n border-color: var(--mj-brand-primary);\n}\n\n.vs-panel-btn.primary:hover {\n background: var(--mj-brand-primary-hover);\n}\n\n.vs-panel-btn i {\n font-size: 11px;\n}\n\n/* ========================================\n ICON BUTTONS (outside panel)\n ======================================== */\n\n.vs-icon-btn {\n display: flex;\n align-items: center;\n justify-content: center;\n width: 32px;\n height: 32px;\n background: var(--mj-bg-surface-card);\n border: 1px solid var(--mj-border-default);\n border-radius: 6px;\n cursor: pointer;\n color: var(--mj-text-secondary);\n transition: all 0.15s ease;\n}\n\n.vs-icon-btn:hover {\n background: var(--mj-bg-surface-hover);\n border-color: var(--mj-border-strong);\n color: var(--mj-brand-primary);\n}\n\n.vs-icon-btn i {\n font-size: 12px;\n}\n\n.vs-export-btn:hover {\n color: var(--mj-status-success);\n}\n\n/* Responsive */\n@media (max-width: 768px) {\n .vs-button {\n min-width: 100px;\n max-width: 180px;\n padding: 6px 10px;\n }\n\n .vs-panel {\n width: calc(100vw - 32px);\n max-width: 400px;\n }\n}\n"] }]
874
+ args: [{ standalone: false, selector: 'mj-view-selector', encapsulation: ViewEncapsulation.None, template: "<div class=\"vs-container\">\n <!-- Backdrop for closing panel -->\n @if (IsDropdownOpen) {\n <div class=\"vs-backdrop\" (click)=\"CloseDropdown()\"></div>\n }\n\n <!-- Main View Selector Button -->\n <div class=\"vs-wrapper\">\n <button\n class=\"vs-button\"\n [class.modified]=\"ViewModified\"\n [class.open]=\"IsDropdownOpen\"\n (click)=\"ToggleDropdown()\"\n [disabled]=\"IsLoading\"\n title=\"Select a saved view\">\n <i class=\"fa-solid fa-layer-group vs-btn-icon\"></i>\n <span class=\"vs-btn-name\">{{ DisplayName }}</span>\n @if (ViewModified) {\n <span class=\"vs-modified-dot\" title=\"View has unsaved changes\">\u2022</span>\n }\n <i class=\"fa-solid fa-chevron-down vs-arrow\" [class.rotated]=\"IsDropdownOpen\"></i>\n </button>\n\n <!-- Rich View Panel -->\n @if (IsDropdownOpen) {\n <div class=\"vs-panel\">\n <!-- Panel Header -->\n <div class=\"vs-panel-header\">\n <i class=\"fa-solid fa-table-list vs-header-icon\"></i>\n <span class=\"vs-panel-title\">Views</span>\n @if (Entity) {\n <span class=\"vs-Entity-badge\">{{ Entity.DisplayNameOrName }}</span>\n }\n <button class=\"vs-close-btn\" (click)=\"CloseDropdown()\" title=\"Close\">\n <i class=\"fa-solid fa-times\"></i>\n </button>\n </div>\n\n <!-- Search -->\n <div class=\"vs-panel-search\">\n <input\n type=\"text\"\n class=\"vs-search-input\"\n placeholder=\"Search views...\"\n [(ngModel)]=\"SearchText\"\n (keydown.escape)=\"SearchText = ''\"\n />\n </div>\n\n <!-- Panel Body -->\n <div class=\"vs-panel-body\">\n <!-- Default Option -->\n <div class=\"vs-section\">\n <div\n class=\"vs-card\"\n [class.active]=\"!SelectedViewID\"\n (click)=\"SelectDefault()\">\n <div class=\"vs-card-icon\" [class.active]=\"!SelectedViewID\">\n <i class=\"fa-solid fa-table\"></i>\n </div>\n <div class=\"vs-card-content\">\n <div class=\"vs-card-name\">(Default)</div>\n </div>\n @if (!SelectedViewID) {\n <i class=\"fa-solid fa-check vs-card-check\"></i>\n }\n </div>\n </div>\n\n <!-- My Views Section -->\n @if (FilteredMyViews.length > 0) {\n <div class=\"vs-section\">\n <div class=\"vs-section-header\">\n <i class=\"fa-solid fa-user\"></i>\n <span>My Views</span>\n <span class=\"vs-section-count\">{{ FilteredMyViews.length }}</span>\n </div>\n @for (view of FilteredMyViews; track view.id) {\n <div\n class=\"vs-card\"\n [class.active]=\"SelectedViewID === view.id\"\n (click)=\"SelectView(view)\">\n <div class=\"vs-card-icon\" [class.active]=\"SelectedViewID === view.id\">\n <i class=\"fa-solid fa-table-list\"></i>\n </div>\n <div class=\"vs-card-content\">\n <div class=\"vs-card-name\">\n {{ view.name }}\n @if (view.isDefault) {\n <span class=\"vs-default-badge\">Default</span>\n }\n </div>\n @if (view.entity.Description) {\n <div class=\"vs-card-desc\">{{ view.entity.Description }}</div>\n }\n @if (GetViewFilterCount(view) > 0 || GetViewColumnCount(view) > 0 || GetViewSortInfo(view)) {\n <div class=\"vs-card-meta\">\n @if (GetViewFilterCount(view) > 0) {\n <span><i class=\"fa-solid fa-filter\"></i> {{ GetViewFilterCount(view) }} filter{{ GetViewFilterCount(view) !== 1 ? 's' : '' }}</span>\n }\n @if (GetViewColumnCount(view) > 0) {\n <span><i class=\"fa-solid fa-table-columns\"></i> {{ GetViewColumnCount(view) }} col{{ GetViewColumnCount(view) !== 1 ? 's' : '' }}</span>\n }\n @if (GetViewSortInfo(view)) {\n <span><i class=\"fa-solid fa-arrow-down-short-wide\"></i> {{ GetViewSortInfo(view) }}</span>\n }\n </div>\n }\n </div>\n <div class=\"vs-card-actions\">\n <button\n class=\"vs-action-btn\"\n (click)=\"OnDuplicateView(view.id, $event)\"\n title=\"Duplicate\">\n <i class=\"fa-regular fa-copy\"></i>\n </button>\n <button\n class=\"vs-action-btn\"\n (click)=\"OnConfigureViewById(view.id, $event)\"\n title=\"Configure\">\n <i class=\"fa-solid fa-sliders\"></i>\n </button>\n <button\n class=\"vs-action-btn\"\n (click)=\"OnOpenViewInTab(view.id, $event)\"\n title=\"Open in Tab\">\n <i class=\"fa-solid fa-up-right-from-square\"></i>\n </button>\n </div>\n @if (SelectedViewID === view.id) {\n <i class=\"fa-solid fa-check vs-card-check\"></i>\n }\n </div>\n }\n </div>\n }\n\n <!-- Shared Views Section -->\n @if (FilteredSharedViews.length > 0) {\n <div class=\"vs-section\">\n <div class=\"vs-section-header\">\n <i class=\"fa-solid fa-share-nodes\"></i>\n <span>Shared With Me</span>\n <span class=\"vs-section-count\">{{ FilteredSharedViews.length }}</span>\n </div>\n @for (view of FilteredSharedViews; track view.id) {\n <div\n class=\"vs-card\"\n [class.active]=\"SelectedViewID === view.id\"\n (click)=\"SelectView(view)\">\n <div class=\"vs-card-icon shared\">\n <i class=\"fa-solid fa-users\"></i>\n </div>\n <div class=\"vs-card-content\">\n <div class=\"vs-card-name\">\n {{ view.name }}\n @if (!view.userCanEdit) {\n <span class=\"vs-shared-badge\">View Only</span>\n } @else {\n <span class=\"vs-shared-badge editable\">Can Edit</span>\n }\n </div>\n @if (view.entity.Description) {\n <div class=\"vs-card-desc\">{{ view.entity.Description }}</div>\n }\n @if (GetViewFilterCount(view) > 0 || GetViewColumnCount(view) > 0) {\n <div class=\"vs-card-meta\">\n @if (GetViewFilterCount(view) > 0) {\n <span><i class=\"fa-solid fa-filter\"></i> {{ GetViewFilterCount(view) }} filter{{ GetViewFilterCount(view) !== 1 ? 's' : '' }}</span>\n }\n @if (GetViewColumnCount(view) > 0) {\n <span><i class=\"fa-solid fa-table-columns\"></i> {{ GetViewColumnCount(view) }} col{{ GetViewColumnCount(view) !== 1 ? 's' : '' }}</span>\n }\n </div>\n }\n </div>\n <div class=\"vs-card-actions\">\n <button\n class=\"vs-action-btn\"\n (click)=\"OnDuplicateView(view.id, $event)\"\n title=\"Duplicate as My View\">\n <i class=\"fa-regular fa-copy\"></i>\n </button>\n @if (view.userCanEdit) {\n <button\n class=\"vs-action-btn\"\n (click)=\"OnConfigureViewById(view.id, $event)\"\n title=\"Configure\">\n <i class=\"fa-solid fa-sliders\"></i>\n </button>\n }\n </div>\n @if (SelectedViewID === view.id) {\n <i class=\"fa-solid fa-check vs-card-check\"></i>\n }\n </div>\n }\n </div>\n }\n\n <!-- No Views Message -->\n @if (!HasViews && !IsLoading) {\n <mj-empty-state\n Size=\"compact\"\n Icon=\"fa-solid fa-bookmark\"\n Title=\"No saved views yet\"\n Message=\"Save your current configuration as a view\" />\n }\n\n <!-- No Search Results -->\n @if (HasViews && FilteredMyViews.length === 0 && FilteredSharedViews.length === 0 && SearchText) {\n <mj-empty-state\n Size=\"compact\"\n Variant=\"no-results\"\n [Title]=\"NoViewsMatchMessage\" />\n }\n\n <!-- Loading Indicator -->\n @if (IsLoading) {\n <div class=\"vs-loading\">\n <i class=\"fa-solid fa-spinner fa-spin\"></i>\n <span>Loading views...</span>\n </div>\n }\n </div>\n\n <!-- Panel Footer -->\n <div class=\"vs-panel-footer\">\n <button\n class=\"vs-panel-btn primary\"\n (click)=\"OnQuickSave()\"\n title=\"Save current view configuration\">\n <i class=\"fa-solid fa-plus\"></i>\n <span>New View</span>\n </button>\n <button\n class=\"vs-panel-btn\"\n (click)=\"OnResetToDefault()\"\n title=\"Reset to default view\">\n <i class=\"fa-solid fa-arrow-rotate-left\"></i>\n <span>Reset to Default</span>\n </button>\n </div>\n </div>\n }\n </div>\n\n <!-- Open in Tab Button (only visible when a view is selected) -->\n @if (SelectedViewID) {\n <button\n class=\"vs-icon-btn\"\n (click)=\"OnOpenInTab()\"\n title=\"Open this view in a new tab\">\n <i class=\"fa-solid fa-external-link-alt\"></i>\n </button>\n }\n\n <!-- Configure View Button -->\n <button\n class=\"vs-icon-btn\"\n (click)=\"OnConfigureView()\"\n title=\"Configure view settings (columns, filters, sorting)\">\n <i class=\"fa-solid fa-sliders-h\"></i>\n </button>\n\n <!-- Create New Record Button -->\n <button\n class=\"vs-icon-btn\"\n (click)=\"OnCreateNewRecord()\"\n title=\"Create new record\">\n <i class=\"fa-solid fa-plus\"></i>\n </button>\n\n <!-- Export Button -->\n <button\n class=\"vs-icon-btn vs-export-btn\"\n (click)=\"OnExport()\"\n title=\"Export to Excel\">\n <i class=\"fa-solid fa-file-excel\"></i>\n </button>\n</div>\n", styles: ["/* ========================================\n VIEW SELECTOR - All classes prefixed vs-\n to avoid conflicts (ViewEncapsulation.None)\n ======================================== */\n\n/* Container */\n.vs-container {\n display: flex;\n align-items: center;\n gap: 4px;\n position: relative;\n}\n\n/* Backdrop for closing panel */\n.vs-backdrop {\n position: fixed;\n top: 0;\n left: 0;\n right: 0;\n bottom: 0;\n z-index: 999;\n background: transparent;\n}\n\n.vs-wrapper {\n position: relative;\n}\n\n/* Main Button */\n.vs-button {\n display: flex;\n align-items: center;\n gap: 8px;\n padding: 6px 12px;\n background: var(--mj-bg-surface-card);\n border: 1px solid var(--mj-border-default);\n border-radius: 4px;\n cursor: pointer;\n font-size: 13px;\n font-weight: 500;\n color: var(--mj-text-primary);\n transition: all 0.15s ease;\n min-width: 140px;\n max-width: 280px;\n}\n\n.vs-button:hover {\n border-color: var(--mj-brand-primary);\n background: color-mix(in srgb, var(--mj-brand-primary) 5%, var(--mj-bg-surface));\n}\n\n.vs-button:disabled {\n opacity: 0.6;\n cursor: not-allowed;\n}\n\n.vs-button.open {\n border-color: var(--mj-brand-primary);\n background: color-mix(in srgb, var(--mj-brand-primary) 5%, var(--mj-bg-surface));\n}\n\n.vs-button.modified {\n border-color: var(--mj-status-warning);\n}\n\n.vs-btn-icon {\n color: var(--mj-brand-primary);\n font-size: 12px;\n}\n\n.vs-btn-name {\n flex: 1;\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n text-align: left;\n}\n\n.vs-modified-dot {\n color: var(--mj-status-warning);\n font-weight: bold;\n font-size: 18px;\n line-height: 1;\n}\n\n.vs-arrow {\n color: var(--mj-text-muted);\n font-size: 10px;\n transition: transform 0.2s ease;\n}\n\n.vs-arrow.rotated {\n transform: rotate(180deg);\n}\n\n/* ========================================\n RICH VIEW PANEL\n Styles ported directly from prototype\n ======================================== */\n\n/* Reset inherited styles inside panel */\n.vs-panel,\n.vs-panel * {\n box-sizing: border-box;\n line-height: 1.5;\n text-align: left;\n}\n\n.vs-panel {\n position: absolute;\n top: calc(100% + 4px);\n left: 0;\n width: 400px;\n max-width: calc(100vw - 40px);\n background: var(--mj-bg-surface);\n border: 1px solid var(--mj-border-default);\n border-radius: 12px;\n box-shadow: 0 8px 32px rgba(0, 0, 0, 0.16);\n z-index: 1000;\n overflow: hidden;\n font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;\n font-size: 13px;\n color: var(--mj-text-primary);\n}\n\n/* Panel Header */\n.vs-panel-header {\n padding: 16px 20px;\n display: flex;\n align-items: center;\n gap: 12px;\n border-bottom: 1px solid var(--mj-border-default);\n}\n\n.vs-header-icon {\n color: var(--mj-brand-primary);\n font-size: 14px;\n}\n\n.vs-panel-title {\n font-size: 15px;\n font-weight: 600;\n color: var(--mj-text-primary);\n}\n\n.vs-entity-badge {\n font-size: 11px;\n font-weight: 500;\n background: color-mix(in srgb, var(--mj-brand-primary) 12%, var(--mj-bg-surface));\n color: var(--mj-brand-primary);\n padding: 2px 8px;\n border-radius: 10px;\n}\n\n.vs-close-btn {\n margin-left: auto;\n background: none;\n border: none;\n cursor: pointer;\n color: var(--mj-text-muted);\n font-size: 16px;\n padding: 4px;\n display: flex;\n align-items: center;\n justify-content: center;\n}\n\n.vs-close-btn:hover {\n color: var(--mj-text-primary);\n}\n\n/* Panel Search */\n.vs-panel-search {\n padding: 12px 20px;\n border-bottom: 1px solid var(--mj-border-default);\n}\n\n.vs-search-input {\n width: 100%;\n padding: 6px 12px 6px 32px;\n border: 1px solid var(--mj-border-default);\n border-radius: 4px;\n font-size: 13px;\n background: var(--mj-bg-surface-card) url(\"data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 512 512' fill='%23999'%3E%3Cpath d='M416 208c0 45.9-14.9 88.3-40 122.7L502.6 457.4c12.5 12.5 12.5 32.8 0 45.3s-32.8 12.5-45.3 0L330.7 376c-34.4 25.2-76.8 40-122.7 40C93.1 416 0 322.9 0 208S93.1 0 208 0S416 93.1 416 208z'/%3E%3C/svg%3E\") no-repeat 10px center;\n background-size: 14px;\n box-sizing: border-box;\n font-family: inherit;\n}\n\n.vs-search-input:focus {\n outline: none;\n border-color: var(--mj-brand-primary);\n}\n\n.vs-search-input::placeholder {\n color: var(--mj-text-muted);\n}\n\n/* Panel Body */\n.vs-panel-body {\n max-height: 400px;\n overflow-y: auto;\n}\n\n/* View Section */\n.vs-section {\n padding: 8px 0;\n}\n\n.vs-section-header {\n padding: 6px 20px;\n font-size: 11px;\n font-weight: 700;\n color: var(--mj-text-muted);\n text-transform: uppercase;\n letter-spacing: 0.5px;\n display: flex;\n align-items: center;\n gap: 6px;\n}\n\n.vs-section-header i {\n font-size: 10px;\n}\n\n.vs-section-count {\n background: var(--mj-border-default);\n padding: 0 6px;\n border-radius: 8px;\n font-size: 10px;\n}\n\n/* View Card */\n.vs-card {\n padding: 10px 20px;\n cursor: pointer;\n transition: background 0.1s;\n display: flex;\n align-items: flex-start;\n gap: 12px;\n}\n\n.vs-card:hover {\n background: color-mix(in srgb, var(--mj-brand-primary) 5%, var(--mj-bg-surface));\n}\n\n.vs-card.active {\n background: color-mix(in srgb, var(--mj-brand-primary) 12%, var(--mj-bg-surface));\n border-left: 3px solid var(--mj-brand-primary);\n padding-left: 17px;\n}\n\n/* View Card Icon */\n.vs-card-icon {\n width: 32px;\n height: 32px;\n border-radius: 6px;\n background: var(--mj-bg-surface-card);\n display: flex;\n align-items: center;\n justify-content: center;\n color: var(--mj-text-muted);\n font-size: 14px;\n flex-shrink: 0;\n margin-top: 2px;\n}\n\n.vs-card-icon.active {\n background: var(--mj-brand-primary);\n color: var(--mj-text-inverse);\n}\n\n.vs-card-icon.shared {\n background: var(--mj-bg-surface-card);\n color: var(--mj-text-muted);\n}\n\n/* View Card Content */\n.vs-card-content {\n flex: 1;\n min-width: 0;\n padding-top: 4px;\n}\n\n.vs-card-name {\n font-size: 13px;\n font-weight: 500;\n color: var(--mj-text-primary);\n display: flex;\n align-items: center;\n gap: 6px;\n}\n\n.vs-card.active .vs-card-name {\n color: var(--mj-brand-primary);\n font-weight: 600;\n}\n\n.vs-default-badge {\n font-size: 9px;\n font-weight: 600;\n background: var(--mj-status-success-bg);\n color: var(--mj-status-success-text);\n padding: 1px 5px;\n border-radius: 6px;\n text-transform: uppercase;\n letter-spacing: 0.3px;\n}\n\n.vs-shared-badge {\n font-size: 9px;\n font-weight: 600;\n background: color-mix(in srgb, var(--mj-brand-primary) 12%, var(--mj-bg-surface));\n color: var(--mj-brand-primary);\n padding: 1px 5px;\n border-radius: 6px;\n}\n\n.vs-shared-badge.editable {\n background: var(--mj-status-success-bg);\n color: var(--mj-status-success-text);\n}\n\n.vs-card-desc {\n font-size: 12px;\n color: var(--mj-text-muted);\n margin-top: 2px;\n display: -webkit-box;\n -webkit-line-clamp: 2;\n -webkit-box-orient: vertical;\n overflow: hidden;\n}\n\n.vs-card-meta {\n display: flex;\n gap: 10px;\n margin-top: 4px;\n font-size: 11px;\n color: var(--mj-text-muted);\n}\n\n.vs-card-meta span {\n display: flex;\n align-items: center;\n gap: 3px;\n}\n\n.vs-card-meta i {\n font-size: 10px;\n}\n\n/* View Card Check */\n.vs-card-check {\n color: var(--mj-brand-primary);\n font-size: 12px;\n flex-shrink: 0;\n margin-top: 2px;\n}\n\n/* View Card Actions (hover reveal) */\n.vs-card-actions {\n display: flex;\n gap: 2px;\n opacity: 0;\n transition: opacity 0.15s;\n flex-shrink: 0;\n margin-top: 2px;\n}\n\n.vs-card:hover .vs-card-actions {\n opacity: 1;\n}\n\n.vs-action-btn {\n width: 26px;\n height: 26px;\n border-radius: 4px;\n border: none;\n background: none;\n cursor: pointer;\n color: var(--mj-text-muted);\n font-size: 12px;\n display: flex;\n align-items: center;\n justify-content: center;\n}\n\n.vs-action-btn:hover {\n background: var(--mj-bg-surface-card);\n color: var(--mj-text-primary);\n}\n\n/* Loading */\n.vs-loading {\n display: flex;\n align-items: center;\n justify-content: center;\n gap: 8px;\n padding: 20px;\n color: var(--mj-text-muted);\n font-size: 13px;\n text-align: center;\n}\n\n/* Panel Footer */\n.vs-panel-footer {\n padding: 12px 20px;\n border-top: 1px solid var(--mj-border-default);\n display: flex;\n gap: 8px;\n}\n\n.vs-panel-btn {\n flex: 1;\n padding: 8px 12px;\n border-radius: 4px;\n border: 1px solid var(--mj-border-default);\n background: var(--mj-bg-surface);\n cursor: pointer;\n font-size: 12px;\n font-weight: 500;\n color: var(--mj-text-secondary);\n display: flex;\n align-items: center;\n justify-content: center;\n gap: 6px;\n transition: all 0.15s;\n font-family: inherit;\n text-align: center;\n}\n\n.vs-panel-btn:hover {\n border-color: var(--mj-brand-primary);\n color: var(--mj-brand-primary);\n}\n\n.vs-panel-btn.primary {\n background: var(--mj-brand-primary);\n color: var(--mj-text-inverse);\n border-color: var(--mj-brand-primary);\n}\n\n.vs-panel-btn.primary:hover {\n background: var(--mj-brand-primary-hover);\n}\n\n.vs-panel-btn i {\n font-size: 11px;\n}\n\n/* ========================================\n ICON BUTTONS (outside panel)\n ======================================== */\n\n.vs-icon-btn {\n display: flex;\n align-items: center;\n justify-content: center;\n width: 32px;\n height: 32px;\n background: var(--mj-bg-surface-card);\n border: 1px solid var(--mj-border-default);\n border-radius: 6px;\n cursor: pointer;\n color: var(--mj-text-secondary);\n transition: all 0.15s ease;\n}\n\n.vs-icon-btn:hover {\n background: var(--mj-bg-surface-hover);\n border-color: var(--mj-border-strong);\n color: var(--mj-brand-primary);\n}\n\n.vs-icon-btn i {\n font-size: 12px;\n}\n\n.vs-export-btn:hover {\n color: var(--mj-status-success);\n}\n\n/* Responsive */\n@media (max-width: 768px) {\n .vs-button {\n min-width: 100px;\n max-width: 180px;\n padding: 6px 10px;\n }\n\n .vs-panel {\n width: calc(100vw - 32px);\n max-width: 400px;\n }\n}\n"] }]
833
875
  }], () => [{ type: i0.ChangeDetectorRef }], { Entity: [{
834
876
  type: Input
835
877
  }], SelectedViewID: [{