@memberjunction/ng-dashboard-viewer 5.24.0 → 5.26.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.
@@ -36,18 +36,65 @@ function ViewConfigPanelComponent_Conditional_11_Template(rf, ctx) { if (rf & 1)
36
36
  i0.ɵɵadvance(2);
37
37
  i0.ɵɵtextInterpolate1(" Selected: ", ctx_r1.viewName, " ");
38
38
  } }
39
- function ViewConfigPanelComponent_Conditional_36_Conditional_37_Template(rf, ctx) { if (rf & 1) {
39
+ function ViewConfigPanelComponent_Conditional_36_Conditional_31_Template(rf, ctx) { if (rf & 1) {
40
40
  const _r4 = i0.ɵɵgetCurrentView();
41
- i0.ɵɵelementStart(0, "div", 2)(1, "label", 38);
41
+ i0.ɵɵelementStart(0, "div", 2)(1, "label");
42
+ i0.ɵɵtext(2, "Map Style");
43
+ i0.ɵɵelementEnd();
44
+ i0.ɵɵelementStart(3, "div", 23)(4, "label", 24)(5, "input", 40);
45
+ i0.ɵɵtwoWayListener("ngModelChange", function ViewConfigPanelComponent_Conditional_36_Conditional_31_Template_input_ngModelChange_5_listener($event) { i0.ɵɵrestoreView(_r4); const ctx_r1 = i0.ɵɵnextContext(2); i0.ɵɵtwoWayBindingSet(ctx_r1.mapRenderMode, $event) || (ctx_r1.mapRenderMode = $event); return i0.ɵɵresetView($event); });
46
+ i0.ɵɵlistener("change", function ViewConfigPanelComponent_Conditional_36_Conditional_31_Template_input_change_5_listener() { i0.ɵɵrestoreView(_r4); const ctx_r1 = i0.ɵɵnextContext(2); return i0.ɵɵresetView(ctx_r1.onOptionChange()); });
47
+ i0.ɵɵelementEnd();
48
+ i0.ɵɵelement(6, "span", 26);
49
+ i0.ɵɵelementStart(7, "span", 27);
50
+ i0.ɵɵelement(8, "i", 41);
51
+ i0.ɵɵtext(9, " Points ");
52
+ i0.ɵɵelementEnd()();
53
+ i0.ɵɵelementStart(10, "label", 24)(11, "input", 42);
54
+ i0.ɵɵtwoWayListener("ngModelChange", function ViewConfigPanelComponent_Conditional_36_Conditional_31_Template_input_ngModelChange_11_listener($event) { i0.ɵɵrestoreView(_r4); const ctx_r1 = i0.ɵɵnextContext(2); i0.ɵɵtwoWayBindingSet(ctx_r1.mapRenderMode, $event) || (ctx_r1.mapRenderMode = $event); return i0.ɵɵresetView($event); });
55
+ i0.ɵɵlistener("change", function ViewConfigPanelComponent_Conditional_36_Conditional_31_Template_input_change_11_listener() { i0.ɵɵrestoreView(_r4); const ctx_r1 = i0.ɵɵnextContext(2); return i0.ɵɵresetView(ctx_r1.onOptionChange()); });
56
+ i0.ɵɵelementEnd();
57
+ i0.ɵɵelement(12, "span", 26);
58
+ i0.ɵɵelementStart(13, "span", 27);
59
+ i0.ɵɵelement(14, "i", 43);
60
+ i0.ɵɵtext(15, " Regions ");
61
+ i0.ɵɵelementEnd()();
62
+ i0.ɵɵelementStart(16, "label", 24)(17, "input", 44);
63
+ i0.ɵɵtwoWayListener("ngModelChange", function ViewConfigPanelComponent_Conditional_36_Conditional_31_Template_input_ngModelChange_17_listener($event) { i0.ɵɵrestoreView(_r4); const ctx_r1 = i0.ɵɵnextContext(2); i0.ɵɵtwoWayBindingSet(ctx_r1.mapRenderMode, $event) || (ctx_r1.mapRenderMode = $event); return i0.ɵɵresetView($event); });
64
+ i0.ɵɵlistener("change", function ViewConfigPanelComponent_Conditional_36_Conditional_31_Template_input_change_17_listener() { i0.ɵɵrestoreView(_r4); const ctx_r1 = i0.ɵɵnextContext(2); return i0.ɵɵresetView(ctx_r1.onOptionChange()); });
65
+ i0.ɵɵelementEnd();
66
+ i0.ɵɵelement(18, "span", 26);
67
+ i0.ɵɵelementStart(19, "span", 27);
68
+ i0.ɵɵelement(20, "i", 45);
69
+ i0.ɵɵtext(21, " Heatmap ");
70
+ i0.ɵɵelementEnd()()()();
71
+ } if (rf & 2) {
72
+ const ctx_r1 = i0.ɵɵnextContext(2);
73
+ i0.ɵɵadvance(4);
74
+ i0.ɵɵclassProp("selected", ctx_r1.mapRenderMode === "point");
75
+ i0.ɵɵadvance();
76
+ i0.ɵɵtwoWayProperty("ngModel", ctx_r1.mapRenderMode);
77
+ i0.ɵɵadvance(5);
78
+ i0.ɵɵclassProp("selected", ctx_r1.mapRenderMode === "choropleth");
79
+ i0.ɵɵadvance();
80
+ i0.ɵɵtwoWayProperty("ngModel", ctx_r1.mapRenderMode);
81
+ i0.ɵɵadvance(5);
82
+ i0.ɵɵclassProp("selected", ctx_r1.mapRenderMode === "heatmap");
83
+ i0.ɵɵadvance();
84
+ i0.ɵɵtwoWayProperty("ngModel", ctx_r1.mapRenderMode);
85
+ } }
86
+ function ViewConfigPanelComponent_Conditional_36_Conditional_44_Template(rf, ctx) { if (rf & 1) {
87
+ const _r5 = i0.ɵɵgetCurrentView();
88
+ i0.ɵɵelementStart(0, "div", 2)(1, "label", 46);
42
89
  i0.ɵɵtext(2, "Selection Mode");
43
90
  i0.ɵɵelementEnd();
44
- i0.ɵɵelementStart(3, "select", 39);
45
- i0.ɵɵtwoWayListener("ngModelChange", function ViewConfigPanelComponent_Conditional_36_Conditional_37_Template_select_ngModelChange_3_listener($event) { i0.ɵɵrestoreView(_r4); const ctx_r1 = i0.ɵɵnextContext(2); i0.ɵɵtwoWayBindingSet(ctx_r1.selectionMode, $event) || (ctx_r1.selectionMode = $event); return i0.ɵɵresetView($event); });
46
- i0.ɵɵlistener("change", function ViewConfigPanelComponent_Conditional_36_Conditional_37_Template_select_change_3_listener() { i0.ɵɵrestoreView(_r4); const ctx_r1 = i0.ɵɵnextContext(2); return i0.ɵɵresetView(ctx_r1.onSelectionModeChange()); });
47
- i0.ɵɵelementStart(4, "option", 40);
91
+ i0.ɵɵelementStart(3, "select", 47);
92
+ i0.ɵɵtwoWayListener("ngModelChange", function ViewConfigPanelComponent_Conditional_36_Conditional_44_Template_select_ngModelChange_3_listener($event) { i0.ɵɵrestoreView(_r5); const ctx_r1 = i0.ɵɵnextContext(2); i0.ɵɵtwoWayBindingSet(ctx_r1.selectionMode, $event) || (ctx_r1.selectionMode = $event); return i0.ɵɵresetView($event); });
93
+ i0.ɵɵlistener("change", function ViewConfigPanelComponent_Conditional_36_Conditional_44_Template_select_change_3_listener() { i0.ɵɵrestoreView(_r5); const ctx_r1 = i0.ɵɵnextContext(2); return i0.ɵɵresetView(ctx_r1.onSelectionModeChange()); });
94
+ i0.ɵɵelementStart(4, "option", 48);
48
95
  i0.ɵɵtext(5, "Single Selection");
49
96
  i0.ɵɵelementEnd();
50
- i0.ɵɵelementStart(6, "option", 41);
97
+ i0.ɵɵelementStart(6, "option", 49);
51
98
  i0.ɵɵtext(7, "Multiple Selection");
52
99
  i0.ɵɵelementEnd()()();
53
100
  } if (rf & 2) {
@@ -86,27 +133,37 @@ function ViewConfigPanelComponent_Conditional_36_Template(rf, ctx) { if (rf & 1)
86
133
  i0.ɵɵelementStart(20, "span", 27);
87
134
  i0.ɵɵelement(21, "i", 32);
88
135
  i0.ɵɵtext(22, " Timeline ");
136
+ i0.ɵɵelementEnd()();
137
+ i0.ɵɵelementStart(23, "label", 24)(24, "input", 33);
138
+ i0.ɵɵtwoWayListener("ngModelChange", function ViewConfigPanelComponent_Conditional_36_Template_input_ngModelChange_24_listener($event) { i0.ɵɵrestoreView(_r3); const ctx_r1 = i0.ɵɵnextContext(); i0.ɵɵtwoWayBindingSet(ctx_r1.displayMode, $event) || (ctx_r1.displayMode = $event); return i0.ɵɵresetView($event); });
139
+ i0.ɵɵlistener("change", function ViewConfigPanelComponent_Conditional_36_Template_input_change_24_listener() { i0.ɵɵrestoreView(_r3); const ctx_r1 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r1.onDisplayModeChange()); });
140
+ i0.ɵɵelementEnd();
141
+ i0.ɵɵelement(25, "span", 26);
142
+ i0.ɵɵelementStart(26, "span", 27);
143
+ i0.ɵɵelement(27, "i", 34);
144
+ i0.ɵɵtext(28, " Map ");
89
145
  i0.ɵɵelementEnd()()();
90
- i0.ɵɵelementStart(23, "span", 7);
91
- i0.ɵɵtext(24);
146
+ i0.ɵɵelementStart(29, "span", 7);
147
+ i0.ɵɵtext(30);
92
148
  i0.ɵɵelementEnd()();
93
- i0.ɵɵelementStart(25, "div", 2)(26, "div", 33)(27, "label", 34)(28, "input", 35);
94
- i0.ɵɵtwoWayListener("ngModelChange", function ViewConfigPanelComponent_Conditional_36_Template_input_ngModelChange_28_listener($event) { i0.ɵɵrestoreView(_r3); const ctx_r1 = i0.ɵɵnextContext(); i0.ɵɵtwoWayBindingSet(ctx_r1.allowModeSwitch, $event) || (ctx_r1.allowModeSwitch = $event); return i0.ɵɵresetView($event); });
95
- i0.ɵɵlistener("change", function ViewConfigPanelComponent_Conditional_36_Template_input_change_28_listener() { i0.ɵɵrestoreView(_r3); const ctx_r1 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r1.onOptionChange()); });
149
+ i0.ɵɵconditionalCreate(31, ViewConfigPanelComponent_Conditional_36_Conditional_31_Template, 22, 9, "div", 2);
150
+ i0.ɵɵelementStart(32, "div", 2)(33, "div", 35)(34, "label", 36)(35, "input", 37);
151
+ i0.ɵɵtwoWayListener("ngModelChange", function ViewConfigPanelComponent_Conditional_36_Template_input_ngModelChange_35_listener($event) { i0.ɵɵrestoreView(_r3); const ctx_r1 = i0.ɵɵnextContext(); i0.ɵɵtwoWayBindingSet(ctx_r1.allowModeSwitch, $event) || (ctx_r1.allowModeSwitch = $event); return i0.ɵɵresetView($event); });
152
+ i0.ɵɵlistener("change", function ViewConfigPanelComponent_Conditional_36_Template_input_change_35_listener() { i0.ɵɵrestoreView(_r3); const ctx_r1 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r1.onOptionChange()); });
96
153
  i0.ɵɵelementEnd();
97
- i0.ɵɵelement(29, "span", 36);
98
- i0.ɵɵelementStart(30, "span", 37);
99
- i0.ɵɵtext(31, "Allow Mode Switch");
154
+ i0.ɵɵelement(36, "span", 38);
155
+ i0.ɵɵelementStart(37, "span", 39);
156
+ i0.ɵɵtext(38, "Allow Mode Switch");
100
157
  i0.ɵɵelementEnd()();
101
- i0.ɵɵelementStart(32, "label", 34)(33, "input", 35);
102
- i0.ɵɵtwoWayListener("ngModelChange", function ViewConfigPanelComponent_Conditional_36_Template_input_ngModelChange_33_listener($event) { i0.ɵɵrestoreView(_r3); const ctx_r1 = i0.ɵɵnextContext(); i0.ɵɵtwoWayBindingSet(ctx_r1.enableSelection, $event) || (ctx_r1.enableSelection = $event); return i0.ɵɵresetView($event); });
103
- i0.ɵɵlistener("change", function ViewConfigPanelComponent_Conditional_36_Template_input_change_33_listener() { i0.ɵɵrestoreView(_r3); const ctx_r1 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r1.onOptionChange()); });
158
+ i0.ɵɵelementStart(39, "label", 36)(40, "input", 37);
159
+ i0.ɵɵtwoWayListener("ngModelChange", function ViewConfigPanelComponent_Conditional_36_Template_input_ngModelChange_40_listener($event) { i0.ɵɵrestoreView(_r3); const ctx_r1 = i0.ɵɵnextContext(); i0.ɵɵtwoWayBindingSet(ctx_r1.enableSelection, $event) || (ctx_r1.enableSelection = $event); return i0.ɵɵresetView($event); });
160
+ i0.ɵɵlistener("change", function ViewConfigPanelComponent_Conditional_36_Template_input_change_40_listener() { i0.ɵɵrestoreView(_r3); const ctx_r1 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r1.onOptionChange()); });
104
161
  i0.ɵɵelementEnd();
105
- i0.ɵɵelement(34, "span", 36);
106
- i0.ɵɵelementStart(35, "span", 37);
107
- i0.ɵɵtext(36, "Enable Selection");
162
+ i0.ɵɵelement(41, "span", 38);
163
+ i0.ɵɵelementStart(42, "span", 39);
164
+ i0.ɵɵtext(43, "Enable Selection");
108
165
  i0.ɵɵelementEnd()()()();
109
- i0.ɵɵconditionalCreate(37, ViewConfigPanelComponent_Conditional_36_Conditional_37_Template, 8, 1, "div", 2);
166
+ i0.ɵɵconditionalCreate(44, ViewConfigPanelComponent_Conditional_36_Conditional_44_Template, 8, 1, "div", 2);
110
167
  i0.ɵɵelementEnd();
111
168
  } if (rf & 2) {
112
169
  const ctx_r1 = i0.ɵɵnextContext();
@@ -122,23 +179,29 @@ function ViewConfigPanelComponent_Conditional_36_Template(rf, ctx) { if (rf & 1)
122
179
  i0.ɵɵclassProp("selected", ctx_r1.displayMode === "timeline");
123
180
  i0.ɵɵadvance();
124
181
  i0.ɵɵtwoWayProperty("ngModel", ctx_r1.displayMode);
182
+ i0.ɵɵadvance(5);
183
+ i0.ɵɵclassProp("selected", ctx_r1.displayMode === "map");
184
+ i0.ɵɵadvance();
185
+ i0.ɵɵtwoWayProperty("ngModel", ctx_r1.displayMode);
125
186
  i0.ɵɵadvance(6);
126
187
  i0.ɵɵtextInterpolate(ctx_r1.getDisplayModeDescription());
188
+ i0.ɵɵadvance();
189
+ i0.ɵɵconditional(ctx_r1.displayMode === "map" ? 31 : -1);
127
190
  i0.ɵɵadvance(4);
128
191
  i0.ɵɵtwoWayProperty("ngModel", ctx_r1.allowModeSwitch);
129
192
  i0.ɵɵadvance(5);
130
193
  i0.ɵɵtwoWayProperty("ngModel", ctx_r1.enableSelection);
131
194
  i0.ɵɵadvance(4);
132
- i0.ɵɵconditional(ctx_r1.enableSelection ? 37 : -1);
195
+ i0.ɵɵconditional(ctx_r1.enableSelection ? 44 : -1);
133
196
  } }
134
197
  function ViewConfigPanelComponent_Conditional_43_Template(rf, ctx) { if (rf & 1) {
135
- const _r5 = i0.ɵɵgetCurrentView();
136
- i0.ɵɵelementStart(0, "div", 20)(1, "div", 2)(2, "label", 42);
198
+ const _r6 = i0.ɵɵgetCurrentView();
199
+ i0.ɵɵelementStart(0, "div", 20)(1, "div", 2)(2, "label", 50);
137
200
  i0.ɵɵtext(3, " Extra Filter ");
138
201
  i0.ɵɵelementEnd();
139
- i0.ɵɵelementStart(4, "input", 43);
140
- i0.ɵɵtwoWayListener("ngModelChange", function ViewConfigPanelComponent_Conditional_43_Template_input_ngModelChange_4_listener($event) { i0.ɵɵrestoreView(_r5); const ctx_r1 = i0.ɵɵnextContext(); i0.ɵɵtwoWayBindingSet(ctx_r1.extraFilter, $event) || (ctx_r1.extraFilter = $event); return i0.ɵɵresetView($event); });
141
- i0.ɵɵlistener("input", function ViewConfigPanelComponent_Conditional_43_Template_input_input_4_listener() { i0.ɵɵrestoreView(_r5); const ctx_r1 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r1.onFilterChange()); });
202
+ i0.ɵɵelementStart(4, "input", 51);
203
+ i0.ɵɵtwoWayListener("ngModelChange", function ViewConfigPanelComponent_Conditional_43_Template_input_ngModelChange_4_listener($event) { i0.ɵɵrestoreView(_r6); const ctx_r1 = i0.ɵɵnextContext(); i0.ɵɵtwoWayBindingSet(ctx_r1.extraFilter, $event) || (ctx_r1.extraFilter = $event); return i0.ɵɵresetView($event); });
204
+ i0.ɵɵlistener("input", function ViewConfigPanelComponent_Conditional_43_Template_input_input_4_listener() { i0.ɵɵrestoreView(_r6); const ctx_r1 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r1.onFilterChange()); });
142
205
  i0.ɵɵelementEnd();
143
206
  i0.ɵɵelementStart(5, "span", 7);
144
207
  i0.ɵɵtext(6, " SQL WHERE clause to filter records (applied in addition to view filters) ");
@@ -162,6 +225,7 @@ let ViewConfigPanelComponent = class ViewConfigPanelComponent extends BaseConfig
162
225
  viewName = '';
163
226
  extraFilter = '';
164
227
  displayMode = 'grid';
228
+ mapRenderMode = 'point';
165
229
  allowModeSwitch = true;
166
230
  enableSelection = true;
167
231
  selectionMode = 'single';
@@ -206,6 +270,7 @@ let ViewConfigPanelComponent = class ViewConfigPanelComponent extends BaseConfig
206
270
  this.viewId = config['viewId'] || '';
207
271
  this.extraFilter = config['extraFilter'] || '';
208
272
  this.displayMode = config['displayMode'] || 'grid';
273
+ this.mapRenderMode = config['mapRenderMode'] || 'point';
209
274
  this.allowModeSwitch = config['allowModeSwitch'] ?? true;
210
275
  this.enableSelection = config['enableSelection'] ?? true;
211
276
  this.selectionMode = config['selectionMode'] || 'single';
@@ -233,6 +298,7 @@ let ViewConfigPanelComponent = class ViewConfigPanelComponent extends BaseConfig
233
298
  viewId: this.viewId.trim() || undefined,
234
299
  extraFilter: this.extraFilter.trim() || undefined,
235
300
  displayMode: this.displayMode,
301
+ mapRenderMode: this.displayMode === 'map' ? this.mapRenderMode : undefined,
236
302
  allowModeSwitch: this.allowModeSwitch,
237
303
  enableSelection: this.enableSelection,
238
304
  selectionMode: this.selectionMode
@@ -322,6 +388,8 @@ let ViewConfigPanelComponent = class ViewConfigPanelComponent extends BaseConfig
322
388
  return 'Display records as cards in a responsive grid layout';
323
389
  case 'timeline':
324
390
  return 'Display records chronologically along a timeline';
391
+ case 'map':
392
+ return 'Display geo-coded records on an interactive map';
325
393
  default:
326
394
  return 'Display records in a traditional table/grid format';
327
395
  }
@@ -332,7 +400,7 @@ let ViewConfigPanelComponent = class ViewConfigPanelComponent extends BaseConfig
332
400
  } if (rf & 2) {
333
401
  let _t;
334
402
  i0.ɵɵqueryRefresh(_t = i0.ɵɵloadQuery()) && (ctx.viewDropdown = _t.first);
335
- } }, standalone: false, features: [i0.ɵɵInheritDefinitionFeature], decls: 44, vars: 27, consts: [["viewDropdown", ""], [1, "config-panel", "config-panel--compact"], [1, "form-group"], [1, "fa-solid", "fa-table"], [1, "optional-tag"], [3, "SelectionChange", "BranchConfig", "LeafConfig", "Value", "SelectableTypes", "SelectionMode", "Placeholder", "EnableSearch"], [1, "form-error"], [1, "form-hint"], [1, "form-hint", "form-hint--selected"], ["for", "entityName"], [1, "fa-solid", "fa-database"], ["type", "text", "id", "entityName", "placeholder", "e.g., Accounts, Contacts, Users", 1, "form-input", 3, "ngModelChange", "input", "ngModel"], ["for", "partTitle"], [1, "fa-solid", "fa-heading"], ["type", "text", "id", "partTitle", 1, "form-input", 3, "ngModelChange", "input", "ngModel", "placeholder"], [1, "collapsible-section"], ["type", "button", 1, "collapsible-header", 3, "click"], [1, "collapsible-title"], [1, "fa-solid", "fa-grip"], [1, "collapsible-chevron", "fa-solid"], [1, "collapsible-content"], [1, "fa-solid", "fa-filter"], [1, "fa-solid", "fa-check"], [1, "radio-group", "radio-group--horizontal"], [1, "radio-option", "radio-option--compact"], ["type", "radio", "name", "displayMode", "value", "grid", 3, "ngModelChange", "change", "ngModel"], [1, "radio-mark"], [1, "radio-label"], [1, "fa-solid", "fa-table-cells"], ["type", "radio", "name", "displayMode", "value", "cards", 3, "ngModelChange", "change", "ngModel"], [1, "fa-solid", "fa-id-card"], ["type", "radio", "name", "displayMode", "value", "timeline", 3, "ngModelChange", "change", "ngModel"], [1, "fa-solid", "fa-timeline"], [1, "checkbox-group", "checkbox-group--compact"], [1, "checkbox-option", "checkbox-option--compact"], ["type", "checkbox", 3, "ngModelChange", "change", "ngModel"], [1, "checkbox-mark"], [1, "checkbox-label"], ["for", "selectionMode"], ["id", "selectionMode", 1, "form-select", 3, "ngModelChange", "change", "ngModel"], ["value", "single"], ["value", "multiple"], ["for", "extraFilter"], ["type", "text", "id", "extraFilter", "placeholder", "e.g., Status = 'Active'", 1, "form-input", 3, "ngModelChange", "input", "ngModel"]], template: function ViewConfigPanelComponent_Template(rf, ctx) { if (rf & 1) {
403
+ } }, standalone: false, features: [i0.ɵɵInheritDefinitionFeature], decls: 44, vars: 27, consts: [["viewDropdown", ""], [1, "config-panel", "config-panel--compact"], [1, "form-group"], [1, "fa-solid", "fa-table"], [1, "optional-tag"], [3, "SelectionChange", "BranchConfig", "LeafConfig", "Value", "SelectableTypes", "SelectionMode", "Placeholder", "EnableSearch"], [1, "form-error"], [1, "form-hint"], [1, "form-hint", "form-hint--selected"], ["for", "entityName"], [1, "fa-solid", "fa-database"], ["type", "text", "id", "entityName", "placeholder", "e.g., Accounts, Contacts, Users", 1, "form-input", 3, "ngModelChange", "input", "ngModel"], ["for", "partTitle"], [1, "fa-solid", "fa-heading"], ["type", "text", "id", "partTitle", 1, "form-input", 3, "ngModelChange", "input", "ngModel", "placeholder"], [1, "collapsible-section"], ["type", "button", 1, "collapsible-header", 3, "click"], [1, "collapsible-title"], [1, "fa-solid", "fa-grip"], [1, "collapsible-chevron", "fa-solid"], [1, "collapsible-content"], [1, "fa-solid", "fa-filter"], [1, "fa-solid", "fa-check"], [1, "radio-group", "radio-group--horizontal"], [1, "radio-option", "radio-option--compact"], ["type", "radio", "name", "displayMode", "value", "grid", 3, "ngModelChange", "change", "ngModel"], [1, "radio-mark"], [1, "radio-label"], [1, "fa-solid", "fa-table-cells"], ["type", "radio", "name", "displayMode", "value", "cards", 3, "ngModelChange", "change", "ngModel"], [1, "fa-solid", "fa-id-card"], ["type", "radio", "name", "displayMode", "value", "timeline", 3, "ngModelChange", "change", "ngModel"], [1, "fa-solid", "fa-timeline"], ["type", "radio", "name", "displayMode", "value", "map", 3, "ngModelChange", "change", "ngModel"], [1, "fa-solid", "fa-map-location-dot"], [1, "checkbox-group", "checkbox-group--compact"], [1, "checkbox-option", "checkbox-option--compact"], ["type", "checkbox", 3, "ngModelChange", "change", "ngModel"], [1, "checkbox-mark"], [1, "checkbox-label"], ["type", "radio", "name", "mapRenderMode", "value", "point", 3, "ngModelChange", "change", "ngModel"], [1, "fa-solid", "fa-map-pin"], ["type", "radio", "name", "mapRenderMode", "value", "choropleth", 3, "ngModelChange", "change", "ngModel"], [1, "fa-solid", "fa-earth-americas"], ["type", "radio", "name", "mapRenderMode", "value", "heatmap", 3, "ngModelChange", "change", "ngModel"], [1, "fa-solid", "fa-fire"], ["for", "selectionMode"], ["id", "selectionMode", 1, "form-select", 3, "ngModelChange", "change", "ngModel"], ["value", "single"], ["value", "multiple"], ["for", "extraFilter"], ["type", "text", "id", "extraFilter", "placeholder", "e.g., Status = 'Active'", 1, "form-input", 3, "ngModelChange", "input", "ngModel"]], template: function ViewConfigPanelComponent_Template(rf, ctx) { if (rf & 1) {
336
404
  const _r1 = i0.ɵɵgetCurrentView();
337
405
  i0.ɵɵelementStart(0, "div", 1)(1, "div", 2)(2, "label");
338
406
  i0.ɵɵelement(3, "i", 3);
@@ -381,7 +449,7 @@ let ViewConfigPanelComponent = class ViewConfigPanelComponent extends BaseConfig
381
449
  i0.ɵɵelementEnd();
382
450
  i0.ɵɵelement(35, "i", 19);
383
451
  i0.ɵɵelementEnd();
384
- i0.ɵɵconditionalCreate(36, ViewConfigPanelComponent_Conditional_36_Template, 38, 13, "div", 20);
452
+ i0.ɵɵconditionalCreate(36, ViewConfigPanelComponent_Conditional_36_Template, 45, 17, "div", 20);
385
453
  i0.ɵɵelementEnd();
386
454
  i0.ɵɵelementStart(37, "div", 15)(38, "button", 16);
387
455
  i0.ɵɵlistener("click", function ViewConfigPanelComponent_Template_button_click_38_listener() { i0.ɵɵrestoreView(_r1); return i0.ɵɵresetView(ctx.toggleAdvancedOptions()); });
@@ -420,7 +488,7 @@ let ViewConfigPanelComponent = class ViewConfigPanelComponent extends BaseConfig
420
488
  i0.ɵɵclassProp("fa-chevron-down", !ctx.showAdvancedOptions)("fa-chevron-up", ctx.showAdvancedOptions);
421
489
  i0.ɵɵadvance();
422
490
  i0.ɵɵconditional(ctx.showAdvancedOptions ? 43 : -1);
423
- } }, dependencies: [i1.NgSelectOption, i1.ɵNgSelectMultipleOption, i1.DefaultValueAccessor, i1.CheckboxControlValueAccessor, i1.SelectControlValueAccessor, i1.RadioControlValueAccessor, i1.NgControlStatus, i1.NgModel, i2.TreeDropdownComponent], styles: ["\n\n\n\n\n\n\n\n\n\n.config-panel[_ngcontent-%COMP%] {\n display: flex;\n flex-direction: column;\n gap: 24px;\n padding: 8px 0;\n}\n\n\n\n\n\n\n.form-group[_ngcontent-%COMP%] {\n display: flex;\n flex-direction: column;\n gap: 10px;\n}\n\n.form-group[_ngcontent-%COMP%] > label[_ngcontent-%COMP%] {\n font-size: 14px;\n font-weight: 600;\n color: var(--mj-text-primary);\n display: flex;\n align-items: center;\n gap: 8px;\n}\n\n.form-group[_ngcontent-%COMP%] > label[_ngcontent-%COMP%] i[_ngcontent-%COMP%] {\n color: var(--mj-brand-primary);\n font-size: 14px;\n width: 16px;\n}\n\n.form-group[_ngcontent-%COMP%] > label[_ngcontent-%COMP%] .required[_ngcontent-%COMP%] {\n color: var(--mj-status-error);\n}\n\n\n\n\n\n\n.form-input[_ngcontent-%COMP%] {\n padding: 14px 16px;\n border: 2px solid var(--mj-border-default);\n border-radius: 10px;\n font-size: 15px;\n color: var(--mj-text-primary);\n background: var(--mj-bg-surface);\n transition: all 0.2s ease;\n width: 100%;\n box-sizing: border-box;\n}\n\n.form-input[_ngcontent-%COMP%]:focus {\n outline: none;\n border-color: var(--mj-brand-primary);\n box-shadow: 0 0 0 4px color-mix(in srgb, var(--mj-brand-primary) 12%, transparent);\n}\n\n.form-input[_ngcontent-%COMP%]::placeholder {\n color: var(--mj-text-disabled);\n}\n\n.form-input.error[_ngcontent-%COMP%] {\n border-color: var(--mj-status-error);\n}\n\n.form-input.error[_ngcontent-%COMP%]:focus {\n box-shadow: 0 0 0 4px color-mix(in srgb, var(--mj-status-error) 12%, transparent);\n}\n\n.input-with-action[_ngcontent-%COMP%] {\n display: flex;\n gap: 8px;\n}\n\n.input-with-action[_ngcontent-%COMP%] .form-input[_ngcontent-%COMP%] {\n flex: 1;\n}\n\n.input-action-btn[_ngcontent-%COMP%] {\n width: 48px;\n height: 48px;\n display: flex;\n align-items: center;\n justify-content: center;\n border: 2px solid var(--mj-border-default);\n border-radius: 10px;\n background: var(--mj-bg-surface);\n color: var(--mj-text-secondary);\n cursor: pointer;\n transition: all 0.2s ease;\n flex-shrink: 0;\n}\n\n.input-action-btn[_ngcontent-%COMP%]:hover {\n border-color: var(--mj-brand-primary);\n background: color-mix(in srgb, var(--mj-brand-primary) 10%, var(--mj-bg-surface));\n color: var(--mj-brand-primary);\n}\n\n\n\n\n\n\n.form-hint[_ngcontent-%COMP%] {\n font-size: 13px;\n color: var(--mj-text-muted);\n line-height: 1.4;\n}\n\n.form-error[_ngcontent-%COMP%] {\n font-size: 13px;\n color: var(--mj-status-error);\n display: flex;\n align-items: center;\n gap: 6px;\n}\n\n.form-error[_ngcontent-%COMP%]::before {\n content: '\\f071';\n font-family: 'Font Awesome 6 Free';\n font-weight: 900;\n font-size: 12px;\n}\n\n\n\n\n\n\n.radio-group[_ngcontent-%COMP%] {\n display: flex;\n flex-direction: column;\n gap: 8px;\n}\n\n.radio-option[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n gap: 12px;\n padding: 14px 16px;\n border: 2px solid color-mix(in srgb, var(--mj-brand-primary) 15%, var(--mj-bg-surface));\n border-radius: 10px;\n cursor: pointer;\n transition: all 0.2s ease;\n background: var(--mj-bg-surface);\n}\n\n.radio-option[_ngcontent-%COMP%]:hover {\n border-color: color-mix(in srgb, var(--mj-brand-primary) 30%, var(--mj-bg-surface));\n background: var(--mj-bg-surface-card);\n}\n\n.radio-option.selected[_ngcontent-%COMP%] {\n border-color: var(--mj-brand-primary);\n background: color-mix(in srgb, var(--mj-brand-primary) 10%, var(--mj-bg-surface));\n}\n\n.radio-option[_ngcontent-%COMP%] input[type=\"radio\"][_ngcontent-%COMP%] {\n display: none;\n}\n\n.radio-mark[_ngcontent-%COMP%] {\n width: 20px;\n height: 20px;\n border: 2px solid var(--mj-border-strong);\n border-radius: 50%;\n display: flex;\n align-items: center;\n justify-content: center;\n flex-shrink: 0;\n transition: all 0.2s ease;\n}\n\n.radio-option.selected[_ngcontent-%COMP%] .radio-mark[_ngcontent-%COMP%] {\n border-color: var(--mj-brand-primary);\n}\n\n.radio-option.selected[_ngcontent-%COMP%] .radio-mark[_ngcontent-%COMP%]::after {\n content: '';\n width: 10px;\n height: 10px;\n background: var(--mj-brand-primary);\n border-radius: 50%;\n}\n\n.radio-content[_ngcontent-%COMP%] {\n flex: 1;\n display: flex;\n align-items: center;\n gap: 10px;\n}\n\n.radio-label[_ngcontent-%COMP%] {\n font-size: 14px;\n font-weight: 500;\n color: var(--mj-text-primary);\n}\n\n.radio-badge[_ngcontent-%COMP%] {\n font-size: 11px;\n font-weight: 600;\n padding: 3px 8px;\n border-radius: 4px;\n text-transform: uppercase;\n}\n\n.radio-badge.recommended[_ngcontent-%COMP%] {\n background: color-mix(in srgb, var(--mj-status-success) 10%, var(--mj-bg-surface));\n color: var(--mj-status-success);\n}\n\n.radio-badge.secure[_ngcontent-%COMP%] {\n background: color-mix(in srgb, var(--mj-brand-primary) 10%, var(--mj-bg-surface));\n color: var(--mj-brand-primary);\n}\n\n.radio-badge.warning[_ngcontent-%COMP%] {\n background: color-mix(in srgb, var(--mj-status-warning) 10%, var(--mj-bg-surface));\n color: var(--mj-status-warning);\n}\n\n\n\n\n\n\n.checkbox-group[_ngcontent-%COMP%] {\n display: flex;\n flex-direction: column;\n gap: 8px;\n}\n\n.checkbox-option[_ngcontent-%COMP%] {\n display: flex;\n align-items: flex-start;\n gap: 12px;\n padding: 14px 16px;\n border: 2px solid color-mix(in srgb, var(--mj-brand-primary) 15%, var(--mj-bg-surface));\n border-radius: 10px;\n cursor: pointer;\n transition: all 0.2s ease;\n background: var(--mj-bg-surface);\n}\n\n.checkbox-option[_ngcontent-%COMP%]:hover {\n border-color: color-mix(in srgb, var(--mj-brand-primary) 30%, var(--mj-bg-surface));\n background: var(--mj-bg-surface-card);\n}\n\n.checkbox-option[_ngcontent-%COMP%] input[type=\"checkbox\"][_ngcontent-%COMP%] {\n display: none;\n}\n\n.checkbox-mark[_ngcontent-%COMP%] {\n width: 22px;\n height: 22px;\n border: 2px solid var(--mj-border-strong);\n border-radius: 6px;\n display: flex;\n align-items: center;\n justify-content: center;\n flex-shrink: 0;\n transition: all 0.2s ease;\n margin-top: 2px;\n}\n\n.checkbox-option[_ngcontent-%COMP%] input[_ngcontent-%COMP%]:checked + .checkbox-mark[_ngcontent-%COMP%] {\n background: var(--mj-brand-primary);\n border-color: var(--mj-brand-primary);\n}\n\n.checkbox-option[_ngcontent-%COMP%] input[_ngcontent-%COMP%]:checked + .checkbox-mark[_ngcontent-%COMP%]::after {\n content: '\\f00c';\n font-family: 'Font Awesome 6 Free';\n font-weight: 900;\n font-size: 12px;\n color: var(--mj-text-inverse);\n}\n\n.checkbox-content[_ngcontent-%COMP%] {\n flex: 1;\n display: flex;\n flex-direction: column;\n gap: 2px;\n}\n\n.checkbox-label[_ngcontent-%COMP%] {\n font-size: 14px;\n font-weight: 500;\n color: var(--mj-text-primary);\n}\n\n.checkbox-desc[_ngcontent-%COMP%] {\n font-size: 12px;\n color: var(--mj-text-muted);\n}\n\n\n\n\n\n\n.form-select[_ngcontent-%COMP%] {\n padding: 14px 40px 14px 16px;\n border: 2px solid var(--mj-border-default);\n border-radius: 10px;\n font-size: 15px;\n color: var(--mj-text-primary);\n background: var(--mj-bg-surface);\n transition: all 0.2s ease;\n width: 100%;\n box-sizing: border-box;\n cursor: pointer;\n appearance: none;\n background-image: url(\"data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='12' viewBox='0 0 12 12'%3E%3Cpath fill='%23666' d='M6 8L1 3h10z'/%3E%3C/svg%3E\");\n background-repeat: no-repeat;\n background-position: right 16px center;\n}\n\n.form-select[_ngcontent-%COMP%]:focus {\n outline: none;\n border-color: var(--mj-brand-primary);\n box-shadow: 0 0 0 4px color-mix(in srgb, var(--mj-brand-primary) 12%, transparent);\n}\n\n\n\n\n\n\n.config-panel--compact[_ngcontent-%COMP%] {\n gap: 16px;\n}\n\n.config-panel--compact[_ngcontent-%COMP%] .form-group[_ngcontent-%COMP%] {\n gap: 8px;\n}\n\n.config-panel--compact[_ngcontent-%COMP%] .form-input[_ngcontent-%COMP%] {\n padding: 10px 14px;\n font-size: 14px;\n}\n\n.config-panel--compact[_ngcontent-%COMP%] .form-select[_ngcontent-%COMP%] {\n padding: 10px 36px 10px 14px;\n font-size: 14px;\n}\n\n\n\n\n\n\n.optional-tag[_ngcontent-%COMP%] {\n font-weight: 400;\n font-size: 12px;\n color: var(--mj-text-muted);\n}\n\n\n\n\n\n\n.form-hint--selected[_ngcontent-%COMP%] {\n color: var(--mj-status-success);\n}\n\n.form-hint--selected[_ngcontent-%COMP%] i[_ngcontent-%COMP%] {\n color: var(--mj-status-success);\n}\n\n\n\n\n\n\n.collapsible-section[_ngcontent-%COMP%] {\n border: 1px solid color-mix(in srgb, var(--mj-brand-primary) 15%, var(--mj-bg-surface));\n border-radius: 10px;\n overflow: hidden;\n}\n\n.collapsible-header[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n justify-content: space-between;\n width: 100%;\n padding: 12px 16px;\n border: none;\n background: var(--mj-bg-page);\n cursor: pointer;\n transition: background 0.2s ease;\n}\n\n.collapsible-header[_ngcontent-%COMP%]:hover {\n background: color-mix(in srgb, var(--mj-brand-primary) 10%, var(--mj-bg-surface));\n}\n\n.collapsible-title[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n gap: 8px;\n font-size: 14px;\n font-weight: 600;\n color: var(--mj-text-primary);\n}\n\n.collapsible-title[_ngcontent-%COMP%] i[_ngcontent-%COMP%] {\n color: var(--mj-brand-primary);\n font-size: 14px;\n}\n\n.collapsible-chevron[_ngcontent-%COMP%] {\n color: var(--mj-text-muted);\n font-size: 12px;\n transition: transform 0.2s ease;\n}\n\n.collapsible-content[_ngcontent-%COMP%] {\n padding: 16px;\n border-top: 1px solid color-mix(in srgb, var(--mj-brand-primary) 15%, var(--mj-bg-surface));\n display: flex;\n flex-direction: column;\n gap: 16px;\n}\n\n\n\n\n\n\n.radio-group--horizontal[_ngcontent-%COMP%] {\n flex-direction: row;\n flex-wrap: wrap;\n gap: 8px;\n}\n\n.radio-option--compact[_ngcontent-%COMP%] {\n padding: 10px 14px;\n flex: 1;\n min-width: 100px;\n}\n\n.radio-option--compact[_ngcontent-%COMP%] .radio-label[_ngcontent-%COMP%] {\n font-size: 13px;\n display: flex;\n align-items: center;\n gap: 6px;\n}\n\n.radio-option--compact[_ngcontent-%COMP%] .radio-label[_ngcontent-%COMP%] i[_ngcontent-%COMP%] {\n color: var(--mj-brand-primary);\n font-size: 12px;\n}\n\n.radio-option--compact[_ngcontent-%COMP%] .radio-mark[_ngcontent-%COMP%] {\n width: 16px;\n height: 16px;\n}\n\n.radio-option--compact.selected[_ngcontent-%COMP%] .radio-mark[_ngcontent-%COMP%]::after {\n width: 8px;\n height: 8px;\n}\n\n\n\n\n\n\n.checkbox-group--compact[_ngcontent-%COMP%] {\n gap: 4px;\n}\n\n.checkbox-option--compact[_ngcontent-%COMP%] {\n padding: 10px 14px;\n}\n\n.checkbox-option--compact[_ngcontent-%COMP%] .checkbox-mark[_ngcontent-%COMP%] {\n width: 18px;\n height: 18px;\n margin-top: 0;\n}\n\n.checkbox-option--compact[_ngcontent-%COMP%] .checkbox-label[_ngcontent-%COMP%] {\n font-size: 13px;\n}\n\n\n\n\n\n\nmj-tree-dropdown.error[_ngcontent-%COMP%] {\n --dropdown-border-color: var(--mj-status-error);\n}\n\nmj-tree-dropdown.error[_ngcontent-%COMP%]:focus-within {\n --dropdown-border-focus: var(--mj-status-error);\n}"] });
491
+ } }, dependencies: [i1.NgSelectOption, i1.ɵNgSelectMultipleOption, i1.DefaultValueAccessor, i1.CheckboxControlValueAccessor, i1.SelectControlValueAccessor, i1.RadioControlValueAccessor, i1.NgControlStatus, i1.NgModel, i2.TreeDropdownComponent], styles: ["\n\n\n\n\n\n\n\n\n\n.config-panel[_ngcontent-%COMP%] {\n display: flex;\n flex-direction: column;\n gap: 24px;\n padding: 8px 0;\n}\n\n\n\n\n\n\n.form-group[_ngcontent-%COMP%] {\n display: flex;\n flex-direction: column;\n gap: 10px;\n}\n\n.form-group[_ngcontent-%COMP%] > label[_ngcontent-%COMP%] {\n font-size: 14px;\n font-weight: 600;\n color: var(--mj-text-primary);\n display: flex;\n align-items: center;\n gap: 8px;\n}\n\n.form-group[_ngcontent-%COMP%] > label[_ngcontent-%COMP%] i[_ngcontent-%COMP%] {\n color: var(--mj-brand-primary);\n font-size: 14px;\n width: 16px;\n}\n\n.form-group[_ngcontent-%COMP%] > label[_ngcontent-%COMP%] .required[_ngcontent-%COMP%] {\n color: var(--mj-status-error);\n}\n\n\n\n\n\n\n.form-input[_ngcontent-%COMP%] {\n padding: 14px 16px;\n border: 2px solid var(--mj-border-default);\n border-radius: 10px;\n font-size: 15px;\n color: var(--mj-text-primary);\n background: var(--mj-bg-surface);\n transition: all 0.2s ease;\n width: 100%;\n box-sizing: border-box;\n}\n\n.form-input[_ngcontent-%COMP%]:focus {\n outline: none;\n border-color: var(--mj-brand-primary);\n box-shadow: 0 0 0 4px color-mix(in srgb, var(--mj-brand-primary) 12%, transparent);\n}\n\n.form-input[_ngcontent-%COMP%]::placeholder {\n color: var(--mj-text-disabled);\n}\n\n.form-input.error[_ngcontent-%COMP%] {\n border-color: var(--mj-status-error);\n}\n\n.form-input.error[_ngcontent-%COMP%]:focus {\n box-shadow: 0 0 0 4px color-mix(in srgb, var(--mj-status-error) 12%, transparent);\n}\n\n.input-with-action[_ngcontent-%COMP%] {\n display: flex;\n gap: 8px;\n}\n\n.input-with-action[_ngcontent-%COMP%] .form-input[_ngcontent-%COMP%] {\n flex: 1;\n}\n\n.input-action-btn[_ngcontent-%COMP%] {\n width: 48px;\n height: 48px;\n display: flex;\n align-items: center;\n justify-content: center;\n border: 2px solid var(--mj-border-default);\n border-radius: 10px;\n background: var(--mj-bg-surface);\n color: var(--mj-text-secondary);\n cursor: pointer;\n transition: all 0.2s ease;\n flex-shrink: 0;\n}\n\n.input-action-btn[_ngcontent-%COMP%]:hover {\n border-color: var(--mj-brand-primary);\n background: color-mix(in srgb, var(--mj-brand-primary) 10%, var(--mj-bg-surface));\n color: var(--mj-brand-primary);\n}\n\n\n\n\n\n\n.form-hint[_ngcontent-%COMP%] {\n font-size: 13px;\n color: var(--mj-text-muted);\n line-height: 1.4;\n}\n\n.form-error[_ngcontent-%COMP%] {\n font-size: 13px;\n color: var(--mj-status-error);\n display: flex;\n align-items: center;\n gap: 6px;\n}\n\n.form-error[_ngcontent-%COMP%]::before {\n content: '\\f071';\n font-family: 'Font Awesome 6 Free';\n font-weight: 900;\n font-size: 12px;\n}\n\n\n\n\n\n\n.radio-group[_ngcontent-%COMP%] {\n display: flex;\n flex-direction: column;\n gap: 8px;\n}\n\n.radio-option[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n gap: 12px;\n padding: 14px 16px;\n border: 2px solid color-mix(in srgb, var(--mj-brand-primary) 15%, var(--mj-bg-surface));\n border-radius: 10px;\n cursor: pointer;\n transition: all 0.2s ease;\n background: var(--mj-bg-surface);\n}\n\n.radio-option[_ngcontent-%COMP%]:hover {\n border-color: color-mix(in srgb, var(--mj-brand-primary) 30%, var(--mj-bg-surface));\n background: var(--mj-bg-surface-card);\n}\n\n.radio-option.selected[_ngcontent-%COMP%] {\n border-color: var(--mj-brand-primary);\n background: color-mix(in srgb, var(--mj-brand-primary) 10%, var(--mj-bg-surface));\n}\n\n.radio-option[_ngcontent-%COMP%] input[type=\"radio\"][_ngcontent-%COMP%] {\n display: none;\n}\n\n.radio-mark[_ngcontent-%COMP%] {\n width: 20px;\n height: 20px;\n border: 2px solid var(--mj-border-strong);\n border-radius: 50%;\n display: flex;\n align-items: center;\n justify-content: center;\n flex-shrink: 0;\n transition: all 0.2s ease;\n}\n\n.radio-option.selected[_ngcontent-%COMP%] .radio-mark[_ngcontent-%COMP%] {\n border-color: var(--mj-brand-primary);\n}\n\n.radio-option.selected[_ngcontent-%COMP%] .radio-mark[_ngcontent-%COMP%]::after {\n content: '';\n width: 10px;\n height: 10px;\n background: var(--mj-brand-primary);\n border-radius: 50%;\n}\n\n.radio-content[_ngcontent-%COMP%] {\n flex: 1;\n display: flex;\n align-items: center;\n gap: 10px;\n}\n\n.radio-label[_ngcontent-%COMP%] {\n font-size: 14px;\n font-weight: 500;\n color: var(--mj-text-primary);\n}\n\n.radio-badge[_ngcontent-%COMP%] {\n font-size: 11px;\n font-weight: 600;\n padding: 3px 8px;\n border-radius: 4px;\n text-transform: uppercase;\n}\n\n.radio-badge.recommended[_ngcontent-%COMP%] {\n background: color-mix(in srgb, var(--mj-status-success) 10%, var(--mj-bg-surface));\n color: var(--mj-status-success);\n}\n\n.radio-badge.secure[_ngcontent-%COMP%] {\n background: color-mix(in srgb, var(--mj-brand-primary) 10%, var(--mj-bg-surface));\n color: var(--mj-brand-primary);\n}\n\n.radio-badge.warning[_ngcontent-%COMP%] {\n background: color-mix(in srgb, var(--mj-status-warning) 10%, var(--mj-bg-surface));\n color: var(--mj-status-warning);\n}\n\n\n\n\n\n\n.checkbox-group[_ngcontent-%COMP%] {\n display: flex;\n flex-direction: column;\n gap: 8px;\n}\n\n.checkbox-option[_ngcontent-%COMP%] {\n display: flex;\n align-items: flex-start;\n gap: 12px;\n padding: 14px 16px;\n border: 2px solid color-mix(in srgb, var(--mj-brand-primary) 15%, var(--mj-bg-surface));\n border-radius: 10px;\n cursor: pointer;\n transition: all 0.2s ease;\n background: var(--mj-bg-surface);\n}\n\n.checkbox-option[_ngcontent-%COMP%]:hover {\n border-color: color-mix(in srgb, var(--mj-brand-primary) 30%, var(--mj-bg-surface));\n background: var(--mj-bg-surface-card);\n}\n\n.checkbox-option[_ngcontent-%COMP%] input[type=\"checkbox\"][_ngcontent-%COMP%] {\n display: none;\n}\n\n.checkbox-mark[_ngcontent-%COMP%] {\n width: 22px;\n height: 22px;\n border: 2px solid var(--mj-border-strong);\n border-radius: 6px;\n display: flex;\n align-items: center;\n justify-content: center;\n flex-shrink: 0;\n transition: all 0.2s ease;\n margin-top: 2px;\n}\n\n.checkbox-option[_ngcontent-%COMP%] input[_ngcontent-%COMP%]:checked + .checkbox-mark[_ngcontent-%COMP%] {\n background: var(--mj-brand-primary);\n border-color: var(--mj-brand-primary);\n}\n\n.checkbox-option[_ngcontent-%COMP%] input[_ngcontent-%COMP%]:checked + .checkbox-mark[_ngcontent-%COMP%]::after {\n content: '\\f00c';\n font-family: 'Font Awesome 6 Free';\n font-weight: 900;\n font-size: 12px;\n color: var(--mj-text-inverse);\n}\n\n.checkbox-content[_ngcontent-%COMP%] {\n flex: 1;\n display: flex;\n flex-direction: column;\n gap: 2px;\n}\n\n.checkbox-label[_ngcontent-%COMP%] {\n font-size: 14px;\n font-weight: 500;\n color: var(--mj-text-primary);\n}\n\n.checkbox-desc[_ngcontent-%COMP%] {\n font-size: 12px;\n color: var(--mj-text-muted);\n}\n\n\n\n\n\n\n.form-select[_ngcontent-%COMP%] {\n padding: 14px 40px 14px 16px;\n border: 2px solid var(--mj-border-default);\n border-radius: 10px;\n font-size: 15px;\n color: var(--mj-text-primary);\n background: var(--mj-bg-surface);\n transition: all 0.2s ease;\n width: 100%;\n box-sizing: border-box;\n cursor: pointer;\n appearance: none;\n background-image: url(\"data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='12' viewBox='0 0 12 12'%3E%3Cpath fill='%23666' d='M6 8L1 3h10z'/%3E%3C/svg%3E\");\n background-repeat: no-repeat;\n background-position: right 16px center;\n}\n\n.form-select[_ngcontent-%COMP%]:focus {\n outline: none;\n border-color: var(--mj-brand-primary);\n box-shadow: 0 0 0 4px color-mix(in srgb, var(--mj-brand-primary) 12%, transparent);\n}\n\n\n\n\n\n\n.config-panel--compact[_ngcontent-%COMP%] {\n gap: 16px;\n}\n\n.config-panel--compact[_ngcontent-%COMP%] .form-group[_ngcontent-%COMP%] {\n gap: 8px;\n}\n\n.config-panel--compact[_ngcontent-%COMP%] .form-input[_ngcontent-%COMP%] {\n padding: 10px 14px;\n font-size: 14px;\n}\n\n.config-panel--compact[_ngcontent-%COMP%] .form-select[_ngcontent-%COMP%] {\n padding: 10px 36px 10px 14px;\n font-size: 14px;\n}\n\n\n\n\n\n\n.optional-tag[_ngcontent-%COMP%] {\n font-weight: 400;\n font-size: 12px;\n color: var(--mj-text-muted);\n}\n\n\n\n\n\n\n.form-hint--selected[_ngcontent-%COMP%] {\n color: var(--mj-status-success);\n}\n\n.form-hint--selected[_ngcontent-%COMP%] i[_ngcontent-%COMP%] {\n color: var(--mj-status-success);\n}\n\n\n\n\n\n\n.collapsible-section[_ngcontent-%COMP%] {\n border: 1px solid color-mix(in srgb, var(--mj-brand-primary) 15%, var(--mj-bg-surface));\n border-radius: 10px;\n overflow: hidden;\n}\n\n.collapsible-header[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n justify-content: space-between;\n width: 100%;\n padding: 12px 16px;\n border: none;\n background: var(--mj-bg-page);\n cursor: pointer;\n transition: background 0.2s ease;\n}\n\n.collapsible-header[_ngcontent-%COMP%]:hover {\n background: color-mix(in srgb, var(--mj-brand-primary) 10%, var(--mj-bg-surface));\n}\n\n.collapsible-title[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n gap: 8px;\n font-size: 14px;\n font-weight: 600;\n color: var(--mj-text-primary);\n}\n\n.collapsible-title[_ngcontent-%COMP%] i[_ngcontent-%COMP%] {\n color: var(--mj-brand-primary);\n font-size: 14px;\n}\n\n.collapsible-chevron[_ngcontent-%COMP%] {\n color: var(--mj-text-muted);\n font-size: 12px;\n transition: transform 0.2s ease;\n}\n\n.collapsible-content[_ngcontent-%COMP%] {\n padding: 16px;\n border-top: 1px solid color-mix(in srgb, var(--mj-brand-primary) 15%, var(--mj-bg-surface));\n display: flex;\n flex-direction: column;\n gap: 16px;\n}\n\n\n\n\n\n\n.radio-group--horizontal[_ngcontent-%COMP%] {\n flex-direction: row;\n flex-wrap: wrap;\n gap: 8px;\n}\n\n.radio-option--compact[_ngcontent-%COMP%] {\n padding: 10px 14px;\n flex: 1;\n min-width: 120px;\n}\n\n.radio-option--compact[_ngcontent-%COMP%] .radio-label[_ngcontent-%COMP%] {\n font-size: 13px;\n display: flex;\n align-items: center;\n gap: 6px;\n}\n\n.radio-option--compact[_ngcontent-%COMP%] .radio-label[_ngcontent-%COMP%] i[_ngcontent-%COMP%] {\n color: var(--mj-brand-primary);\n font-size: 12px;\n}\n\n.radio-option--compact[_ngcontent-%COMP%] .radio-mark[_ngcontent-%COMP%] {\n width: 16px;\n height: 16px;\n}\n\n.radio-option--compact.selected[_ngcontent-%COMP%] .radio-mark[_ngcontent-%COMP%]::after {\n width: 8px;\n height: 8px;\n}\n\n\n\n\n\n\n.checkbox-group--compact[_ngcontent-%COMP%] {\n gap: 4px;\n}\n\n.checkbox-option--compact[_ngcontent-%COMP%] {\n padding: 10px 14px;\n}\n\n.checkbox-option--compact[_ngcontent-%COMP%] .checkbox-mark[_ngcontent-%COMP%] {\n width: 18px;\n height: 18px;\n margin-top: 0;\n}\n\n.checkbox-option--compact[_ngcontent-%COMP%] .checkbox-label[_ngcontent-%COMP%] {\n font-size: 13px;\n}\n\n\n\n\n\n\nmj-tree-dropdown.error[_ngcontent-%COMP%] {\n --dropdown-border-color: var(--mj-status-error);\n}\n\nmj-tree-dropdown.error[_ngcontent-%COMP%]:focus-within {\n --dropdown-border-focus: var(--mj-status-error);\n}"] });
424
492
  };
425
493
  ViewConfigPanelComponent = __decorate([
426
494
  RegisterClass(BaseConfigPanel, 'ViewPanelConfigDialog')
@@ -428,7 +496,7 @@ ViewConfigPanelComponent = __decorate([
428
496
  export { ViewConfigPanelComponent };
429
497
  (() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassMetadata(ViewConfigPanelComponent, [{
430
498
  type: Component,
431
- args: [{ standalone: false, selector: 'mj-dashboard-view-config-panel', template: "<!-- View Config Panel - Compact layout with tree dropdown and collapsible sections -->\n<div class=\"config-panel config-panel--compact\">\n <!-- View Selection (Primary) -->\n <div class=\"form-group\">\n <label>\n <i class=\"fa-solid fa-table\"></i>\n Select View\n <span class=\"optional-tag\">(or enter entity below)</span>\n </label>\n <mj-tree-dropdown\n #viewDropdown\n [BranchConfig]=\"ViewCategoryConfig\"\n [LeafConfig]=\"ViewLeafConfig\"\n [Value]=\"ViewIdAsKey\"\n [SelectableTypes]=\"'leaf'\"\n [SelectionMode]=\"'single'\"\n [Placeholder]=\"'Search or browse saved views...'\"\n [EnableSearch]=\"true\"\n (SelectionChange)=\"onViewSelection($event)\"\n [class.error]=\"viewError\">\n </mj-tree-dropdown>\n @if (viewError) {\n <span class=\"form-error\">{{ viewError }}</span>\n }\n @if (!viewError && !viewId && !entityName) {\n <span class=\"form-hint\">\n Select a saved view or enter an entity name below\n </span>\n }\n @if (!viewError && viewId) {\n <span class=\"form-hint form-hint--selected\">\n <i class=\"fa-solid fa-check\"></i>\n Selected: {{ viewName }}\n </span>\n }\n </div>\n\n <!-- Entity Name (Alternative) -->\n <div class=\"form-group\">\n <label for=\"entityName\">\n <i class=\"fa-solid fa-database\"></i>\n Entity Name\n <span class=\"optional-tag\">(alternative to view)</span>\n </label>\n <input\n type=\"text\"\n id=\"entityName\"\n [(ngModel)]=\"entityName\"\n (input)=\"onEntityChange()\"\n placeholder=\"e.g., Accounts, Contacts, Users\"\n class=\"form-input\">\n <span class=\"form-hint\">\n Use this to display all records from an entity without a saved view\n </span>\n </div>\n\n <!-- Title (Optional) -->\n <div class=\"form-group\">\n <label for=\"partTitle\">\n <i class=\"fa-solid fa-heading\"></i>\n Part Title\n <span class=\"optional-tag\">(optional)</span>\n </label>\n <input\n type=\"text\"\n id=\"partTitle\"\n [(ngModel)]=\"title\"\n (input)=\"onTitleChange()\"\n [placeholder]=\"viewName || entityName ? 'Default: ' + (viewName || entityName) : 'Enter a custom title'\"\n class=\"form-input\">\n <span class=\"form-hint\">Leave empty to use view/entity name as title</span>\n </div>\n\n <!-- Display Options (Collapsible) -->\n <div class=\"collapsible-section\">\n <button\n type=\"button\"\n class=\"collapsible-header\"\n (click)=\"toggleDisplayOptions()\"\n [attr.aria-expanded]=\"showDisplayOptions\">\n <span class=\"collapsible-title\">\n <i class=\"fa-solid fa-grip\"></i>\n Display Options\n </span>\n <i class=\"collapsible-chevron fa-solid\"\n [class.fa-chevron-down]=\"!showDisplayOptions\"\n [class.fa-chevron-up]=\"showDisplayOptions\"></i>\n </button>\n\n @if (showDisplayOptions) {\n <div class=\"collapsible-content\">\n <!-- Display Mode -->\n <div class=\"form-group\">\n <label>Display Mode</label>\n <div class=\"radio-group radio-group--horizontal\">\n <label class=\"radio-option radio-option--compact\" [class.selected]=\"displayMode === 'grid'\">\n <input\n type=\"radio\"\n name=\"displayMode\"\n value=\"grid\"\n [(ngModel)]=\"displayMode\"\n (change)=\"onDisplayModeChange()\">\n <span class=\"radio-mark\"></span>\n <span class=\"radio-label\">\n <i class=\"fa-solid fa-table-cells\"></i>\n Grid\n </span>\n </label>\n <label class=\"radio-option radio-option--compact\" [class.selected]=\"displayMode === 'cards'\">\n <input\n type=\"radio\"\n name=\"displayMode\"\n value=\"cards\"\n [(ngModel)]=\"displayMode\"\n (change)=\"onDisplayModeChange()\">\n <span class=\"radio-mark\"></span>\n <span class=\"radio-label\">\n <i class=\"fa-solid fa-id-card\"></i>\n Cards\n </span>\n </label>\n <label class=\"radio-option radio-option--compact\" [class.selected]=\"displayMode === 'timeline'\">\n <input\n type=\"radio\"\n name=\"displayMode\"\n value=\"timeline\"\n [(ngModel)]=\"displayMode\"\n (change)=\"onDisplayModeChange()\">\n <span class=\"radio-mark\"></span>\n <span class=\"radio-label\">\n <i class=\"fa-solid fa-timeline\"></i>\n Timeline\n </span>\n </label>\n </div>\n <span class=\"form-hint\">{{ getDisplayModeDescription() }}</span>\n </div>\n <!-- Selection Options -->\n <div class=\"form-group\">\n <div class=\"checkbox-group checkbox-group--compact\">\n <label class=\"checkbox-option checkbox-option--compact\">\n <input\n type=\"checkbox\"\n [(ngModel)]=\"allowModeSwitch\"\n (change)=\"onOptionChange()\">\n <span class=\"checkbox-mark\"></span>\n <span class=\"checkbox-label\">Allow Mode Switch</span>\n </label>\n <label class=\"checkbox-option checkbox-option--compact\">\n <input\n type=\"checkbox\"\n [(ngModel)]=\"enableSelection\"\n (change)=\"onOptionChange()\">\n <span class=\"checkbox-mark\"></span>\n <span class=\"checkbox-label\">Enable Selection</span>\n </label>\n </div>\n </div>\n <!-- Selection Mode -->\n @if (enableSelection) {\n <div class=\"form-group\">\n <label for=\"selectionMode\">Selection Mode</label>\n <select\n id=\"selectionMode\"\n class=\"form-select\"\n [(ngModel)]=\"selectionMode\"\n (change)=\"onSelectionModeChange()\">\n <option value=\"single\">Single Selection</option>\n <option value=\"multiple\">Multiple Selection</option>\n </select>\n </div>\n }\n </div>\n }\n </div>\n\n <!-- Advanced Options (Collapsible) -->\n <div class=\"collapsible-section\">\n <button\n type=\"button\"\n class=\"collapsible-header\"\n (click)=\"toggleAdvancedOptions()\"\n [attr.aria-expanded]=\"showAdvancedOptions\">\n <span class=\"collapsible-title\">\n <i class=\"fa-solid fa-filter\"></i>\n Advanced Filtering\n </span>\n <i class=\"collapsible-chevron fa-solid\"\n [class.fa-chevron-down]=\"!showAdvancedOptions\"\n [class.fa-chevron-up]=\"showAdvancedOptions\"></i>\n </button>\n\n @if (showAdvancedOptions) {\n <div class=\"collapsible-content\">\n <!-- Extra Filter -->\n <div class=\"form-group\">\n <label for=\"extraFilter\">\n Extra Filter\n </label>\n <input\n type=\"text\"\n id=\"extraFilter\"\n [(ngModel)]=\"extraFilter\"\n (input)=\"onFilterChange()\"\n placeholder=\"e.g., Status = 'Active'\"\n class=\"form-input\">\n <span class=\"form-hint\">\n SQL WHERE clause to filter records (applied in addition to view filters)\n </span>\n </div>\n </div>\n }\n </div>\n</div>\n", styles: ["/**\n * Shared styles for Config Panels (form content only, no dialog chrome)\n */\n\n/* ========================================\n Panel Container\n ======================================== */\n\n.config-panel {\n display: flex;\n flex-direction: column;\n gap: 24px;\n padding: 8px 0;\n}\n\n/* ========================================\n Form Groups\n ======================================== */\n\n.form-group {\n display: flex;\n flex-direction: column;\n gap: 10px;\n}\n\n.form-group > label {\n font-size: 14px;\n font-weight: 600;\n color: var(--mj-text-primary);\n display: flex;\n align-items: center;\n gap: 8px;\n}\n\n.form-group > label i {\n color: var(--mj-brand-primary);\n font-size: 14px;\n width: 16px;\n}\n\n.form-group > label .required {\n color: var(--mj-status-error);\n}\n\n/* ========================================\n Form Inputs\n ======================================== */\n\n.form-input {\n padding: 14px 16px;\n border: 2px solid var(--mj-border-default);\n border-radius: 10px;\n font-size: 15px;\n color: var(--mj-text-primary);\n background: var(--mj-bg-surface);\n transition: all 0.2s ease;\n width: 100%;\n box-sizing: border-box;\n}\n\n.form-input:focus {\n outline: none;\n border-color: var(--mj-brand-primary);\n box-shadow: 0 0 0 4px color-mix(in srgb, var(--mj-brand-primary) 12%, transparent);\n}\n\n.form-input::placeholder {\n color: var(--mj-text-disabled);\n}\n\n.form-input.error {\n border-color: var(--mj-status-error);\n}\n\n.form-input.error:focus {\n box-shadow: 0 0 0 4px color-mix(in srgb, var(--mj-status-error) 12%, transparent);\n}\n\n.input-with-action {\n display: flex;\n gap: 8px;\n}\n\n.input-with-action .form-input {\n flex: 1;\n}\n\n.input-action-btn {\n width: 48px;\n height: 48px;\n display: flex;\n align-items: center;\n justify-content: center;\n border: 2px solid var(--mj-border-default);\n border-radius: 10px;\n background: var(--mj-bg-surface);\n color: var(--mj-text-secondary);\n cursor: pointer;\n transition: all 0.2s ease;\n flex-shrink: 0;\n}\n\n.input-action-btn:hover {\n border-color: var(--mj-brand-primary);\n background: color-mix(in srgb, var(--mj-brand-primary) 10%, var(--mj-bg-surface));\n color: var(--mj-brand-primary);\n}\n\n/* ========================================\n Form Hints & Errors\n ======================================== */\n\n.form-hint {\n font-size: 13px;\n color: var(--mj-text-muted);\n line-height: 1.4;\n}\n\n.form-error {\n font-size: 13px;\n color: var(--mj-status-error);\n display: flex;\n align-items: center;\n gap: 6px;\n}\n\n.form-error::before {\n content: '\\f071';\n font-family: 'Font Awesome 6 Free';\n font-weight: 900;\n font-size: 12px;\n}\n\n/* ========================================\n Radio Group\n ======================================== */\n\n.radio-group {\n display: flex;\n flex-direction: column;\n gap: 8px;\n}\n\n.radio-option {\n display: flex;\n align-items: center;\n gap: 12px;\n padding: 14px 16px;\n border: 2px solid color-mix(in srgb, var(--mj-brand-primary) 15%, var(--mj-bg-surface));\n border-radius: 10px;\n cursor: pointer;\n transition: all 0.2s ease;\n background: var(--mj-bg-surface);\n}\n\n.radio-option:hover {\n border-color: color-mix(in srgb, var(--mj-brand-primary) 30%, var(--mj-bg-surface));\n background: var(--mj-bg-surface-card);\n}\n\n.radio-option.selected {\n border-color: var(--mj-brand-primary);\n background: color-mix(in srgb, var(--mj-brand-primary) 10%, var(--mj-bg-surface));\n}\n\n.radio-option input[type=\"radio\"] {\n display: none;\n}\n\n.radio-mark {\n width: 20px;\n height: 20px;\n border: 2px solid var(--mj-border-strong);\n border-radius: 50%;\n display: flex;\n align-items: center;\n justify-content: center;\n flex-shrink: 0;\n transition: all 0.2s ease;\n}\n\n.radio-option.selected .radio-mark {\n border-color: var(--mj-brand-primary);\n}\n\n.radio-option.selected .radio-mark::after {\n content: '';\n width: 10px;\n height: 10px;\n background: var(--mj-brand-primary);\n border-radius: 50%;\n}\n\n.radio-content {\n flex: 1;\n display: flex;\n align-items: center;\n gap: 10px;\n}\n\n.radio-label {\n font-size: 14px;\n font-weight: 500;\n color: var(--mj-text-primary);\n}\n\n.radio-badge {\n font-size: 11px;\n font-weight: 600;\n padding: 3px 8px;\n border-radius: 4px;\n text-transform: uppercase;\n}\n\n.radio-badge.recommended {\n background: color-mix(in srgb, var(--mj-status-success) 10%, var(--mj-bg-surface));\n color: var(--mj-status-success);\n}\n\n.radio-badge.secure {\n background: color-mix(in srgb, var(--mj-brand-primary) 10%, var(--mj-bg-surface));\n color: var(--mj-brand-primary);\n}\n\n.radio-badge.warning {\n background: color-mix(in srgb, var(--mj-status-warning) 10%, var(--mj-bg-surface));\n color: var(--mj-status-warning);\n}\n\n/* ========================================\n Checkbox Group\n ======================================== */\n\n.checkbox-group {\n display: flex;\n flex-direction: column;\n gap: 8px;\n}\n\n.checkbox-option {\n display: flex;\n align-items: flex-start;\n gap: 12px;\n padding: 14px 16px;\n border: 2px solid color-mix(in srgb, var(--mj-brand-primary) 15%, var(--mj-bg-surface));\n border-radius: 10px;\n cursor: pointer;\n transition: all 0.2s ease;\n background: var(--mj-bg-surface);\n}\n\n.checkbox-option:hover {\n border-color: color-mix(in srgb, var(--mj-brand-primary) 30%, var(--mj-bg-surface));\n background: var(--mj-bg-surface-card);\n}\n\n.checkbox-option input[type=\"checkbox\"] {\n display: none;\n}\n\n.checkbox-mark {\n width: 22px;\n height: 22px;\n border: 2px solid var(--mj-border-strong);\n border-radius: 6px;\n display: flex;\n align-items: center;\n justify-content: center;\n flex-shrink: 0;\n transition: all 0.2s ease;\n margin-top: 2px;\n}\n\n.checkbox-option input:checked + .checkbox-mark {\n background: var(--mj-brand-primary);\n border-color: var(--mj-brand-primary);\n}\n\n.checkbox-option input:checked + .checkbox-mark::after {\n content: '\\f00c';\n font-family: 'Font Awesome 6 Free';\n font-weight: 900;\n font-size: 12px;\n color: var(--mj-text-inverse);\n}\n\n.checkbox-content {\n flex: 1;\n display: flex;\n flex-direction: column;\n gap: 2px;\n}\n\n.checkbox-label {\n font-size: 14px;\n font-weight: 500;\n color: var(--mj-text-primary);\n}\n\n.checkbox-desc {\n font-size: 12px;\n color: var(--mj-text-muted);\n}\n\n/* ========================================\n Select/Dropdown\n ======================================== */\n\n.form-select {\n padding: 14px 40px 14px 16px;\n border: 2px solid var(--mj-border-default);\n border-radius: 10px;\n font-size: 15px;\n color: var(--mj-text-primary);\n background: var(--mj-bg-surface);\n transition: all 0.2s ease;\n width: 100%;\n box-sizing: border-box;\n cursor: pointer;\n appearance: none;\n background-image: url(\"data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='12' viewBox='0 0 12 12'%3E%3Cpath fill='%23666' d='M6 8L1 3h10z'/%3E%3C/svg%3E\");\n background-repeat: no-repeat;\n background-position: right 16px center;\n}\n\n.form-select:focus {\n outline: none;\n border-color: var(--mj-brand-primary);\n box-shadow: 0 0 0 4px color-mix(in srgb, var(--mj-brand-primary) 12%, transparent);\n}\n\n/* ========================================\n Compact Panel Variant\n ======================================== */\n\n.config-panel--compact {\n gap: 16px;\n}\n\n.config-panel--compact .form-group {\n gap: 8px;\n}\n\n.config-panel--compact .form-input {\n padding: 10px 14px;\n font-size: 14px;\n}\n\n.config-panel--compact .form-select {\n padding: 10px 36px 10px 14px;\n font-size: 14px;\n}\n\n/* ========================================\n Optional Tag\n ======================================== */\n\n.optional-tag {\n font-weight: 400;\n font-size: 12px;\n color: var(--mj-text-muted);\n}\n\n/* ========================================\n Selected Hint (Success State)\n ======================================== */\n\n.form-hint--selected {\n color: var(--mj-status-success);\n}\n\n.form-hint--selected i {\n color: var(--mj-status-success);\n}\n\n/* ========================================\n Collapsible Section\n ======================================== */\n\n.collapsible-section {\n border: 1px solid color-mix(in srgb, var(--mj-brand-primary) 15%, var(--mj-bg-surface));\n border-radius: 10px;\n overflow: hidden;\n}\n\n.collapsible-header {\n display: flex;\n align-items: center;\n justify-content: space-between;\n width: 100%;\n padding: 12px 16px;\n border: none;\n background: var(--mj-bg-page);\n cursor: pointer;\n transition: background 0.2s ease;\n}\n\n.collapsible-header:hover {\n background: color-mix(in srgb, var(--mj-brand-primary) 10%, var(--mj-bg-surface));\n}\n\n.collapsible-title {\n display: flex;\n align-items: center;\n gap: 8px;\n font-size: 14px;\n font-weight: 600;\n color: var(--mj-text-primary);\n}\n\n.collapsible-title i {\n color: var(--mj-brand-primary);\n font-size: 14px;\n}\n\n.collapsible-chevron {\n color: var(--mj-text-muted);\n font-size: 12px;\n transition: transform 0.2s ease;\n}\n\n.collapsible-content {\n padding: 16px;\n border-top: 1px solid color-mix(in srgb, var(--mj-brand-primary) 15%, var(--mj-bg-surface));\n display: flex;\n flex-direction: column;\n gap: 16px;\n}\n\n/* ========================================\n Horizontal Radio Group\n ======================================== */\n\n.radio-group--horizontal {\n flex-direction: row;\n flex-wrap: wrap;\n gap: 8px;\n}\n\n.radio-option--compact {\n padding: 10px 14px;\n flex: 1;\n min-width: 100px;\n}\n\n.radio-option--compact .radio-label {\n font-size: 13px;\n display: flex;\n align-items: center;\n gap: 6px;\n}\n\n.radio-option--compact .radio-label i {\n color: var(--mj-brand-primary);\n font-size: 12px;\n}\n\n.radio-option--compact .radio-mark {\n width: 16px;\n height: 16px;\n}\n\n.radio-option--compact.selected .radio-mark::after {\n width: 8px;\n height: 8px;\n}\n\n/* ========================================\n Compact Checkbox Group\n ======================================== */\n\n.checkbox-group--compact {\n gap: 4px;\n}\n\n.checkbox-option--compact {\n padding: 10px 14px;\n}\n\n.checkbox-option--compact .checkbox-mark {\n width: 18px;\n height: 18px;\n margin-top: 0;\n}\n\n.checkbox-option--compact .checkbox-label {\n font-size: 13px;\n}\n\n/* ========================================\n Tree Dropdown Error State\n ======================================== */\n\nmj-tree-dropdown.error {\n --dropdown-border-color: var(--mj-status-error);\n}\n\nmj-tree-dropdown.error:focus-within {\n --dropdown-border-focus: var(--mj-status-error);\n}\n"] }]
499
+ args: [{ standalone: false, selector: 'mj-dashboard-view-config-panel', template: "<!-- View Config Panel - Compact layout with tree dropdown and collapsible sections -->\n<div class=\"config-panel config-panel--compact\">\n <!-- View Selection (Primary) -->\n <div class=\"form-group\">\n <label>\n <i class=\"fa-solid fa-table\"></i>\n Select View\n <span class=\"optional-tag\">(or enter entity below)</span>\n </label>\n <mj-tree-dropdown\n #viewDropdown\n [BranchConfig]=\"ViewCategoryConfig\"\n [LeafConfig]=\"ViewLeafConfig\"\n [Value]=\"ViewIdAsKey\"\n [SelectableTypes]=\"'leaf'\"\n [SelectionMode]=\"'single'\"\n [Placeholder]=\"'Search or browse saved views...'\"\n [EnableSearch]=\"true\"\n (SelectionChange)=\"onViewSelection($event)\"\n [class.error]=\"viewError\">\n </mj-tree-dropdown>\n @if (viewError) {\n <span class=\"form-error\">{{ viewError }}</span>\n }\n @if (!viewError && !viewId && !entityName) {\n <span class=\"form-hint\">\n Select a saved view or enter an entity name below\n </span>\n }\n @if (!viewError && viewId) {\n <span class=\"form-hint form-hint--selected\">\n <i class=\"fa-solid fa-check\"></i>\n Selected: {{ viewName }}\n </span>\n }\n </div>\n\n <!-- Entity Name (Alternative) -->\n <div class=\"form-group\">\n <label for=\"entityName\">\n <i class=\"fa-solid fa-database\"></i>\n Entity Name\n <span class=\"optional-tag\">(alternative to view)</span>\n </label>\n <input\n type=\"text\"\n id=\"entityName\"\n [(ngModel)]=\"entityName\"\n (input)=\"onEntityChange()\"\n placeholder=\"e.g., Accounts, Contacts, Users\"\n class=\"form-input\">\n <span class=\"form-hint\">\n Use this to display all records from an entity without a saved view\n </span>\n </div>\n\n <!-- Title (Optional) -->\n <div class=\"form-group\">\n <label for=\"partTitle\">\n <i class=\"fa-solid fa-heading\"></i>\n Part Title\n <span class=\"optional-tag\">(optional)</span>\n </label>\n <input\n type=\"text\"\n id=\"partTitle\"\n [(ngModel)]=\"title\"\n (input)=\"onTitleChange()\"\n [placeholder]=\"viewName || entityName ? 'Default: ' + (viewName || entityName) : 'Enter a custom title'\"\n class=\"form-input\">\n <span class=\"form-hint\">Leave empty to use view/entity name as title</span>\n </div>\n\n <!-- Display Options (Collapsible) -->\n <div class=\"collapsible-section\">\n <button\n type=\"button\"\n class=\"collapsible-header\"\n (click)=\"toggleDisplayOptions()\"\n [attr.aria-expanded]=\"showDisplayOptions\">\n <span class=\"collapsible-title\">\n <i class=\"fa-solid fa-grip\"></i>\n Display Options\n </span>\n <i class=\"collapsible-chevron fa-solid\"\n [class.fa-chevron-down]=\"!showDisplayOptions\"\n [class.fa-chevron-up]=\"showDisplayOptions\"></i>\n </button>\n\n @if (showDisplayOptions) {\n <div class=\"collapsible-content\">\n <!-- Display Mode -->\n <div class=\"form-group\">\n <label>Display Mode</label>\n <div class=\"radio-group radio-group--horizontal\">\n <label class=\"radio-option radio-option--compact\" [class.selected]=\"displayMode === 'grid'\">\n <input\n type=\"radio\"\n name=\"displayMode\"\n value=\"grid\"\n [(ngModel)]=\"displayMode\"\n (change)=\"onDisplayModeChange()\">\n <span class=\"radio-mark\"></span>\n <span class=\"radio-label\">\n <i class=\"fa-solid fa-table-cells\"></i>\n Grid\n </span>\n </label>\n <label class=\"radio-option radio-option--compact\" [class.selected]=\"displayMode === 'cards'\">\n <input\n type=\"radio\"\n name=\"displayMode\"\n value=\"cards\"\n [(ngModel)]=\"displayMode\"\n (change)=\"onDisplayModeChange()\">\n <span class=\"radio-mark\"></span>\n <span class=\"radio-label\">\n <i class=\"fa-solid fa-id-card\"></i>\n Cards\n </span>\n </label>\n <label class=\"radio-option radio-option--compact\" [class.selected]=\"displayMode === 'timeline'\">\n <input\n type=\"radio\"\n name=\"displayMode\"\n value=\"timeline\"\n [(ngModel)]=\"displayMode\"\n (change)=\"onDisplayModeChange()\">\n <span class=\"radio-mark\"></span>\n <span class=\"radio-label\">\n <i class=\"fa-solid fa-timeline\"></i>\n Timeline\n </span>\n </label>\n <label class=\"radio-option radio-option--compact\" [class.selected]=\"displayMode === 'map'\">\n <input\n type=\"radio\"\n name=\"displayMode\"\n value=\"map\"\n [(ngModel)]=\"displayMode\"\n (change)=\"onDisplayModeChange()\">\n <span class=\"radio-mark\"></span>\n <span class=\"radio-label\">\n <i class=\"fa-solid fa-map-location-dot\"></i>\n Map\n </span>\n </label>\n </div>\n <span class=\"form-hint\">{{ getDisplayModeDescription() }}</span>\n </div>\n <!-- Map Render Mode (only shown when map is selected) -->\n @if (displayMode === 'map') {\n <div class=\"form-group\">\n <label>Map Style</label>\n <div class=\"radio-group radio-group--horizontal\">\n <label class=\"radio-option radio-option--compact\" [class.selected]=\"mapRenderMode === 'point'\">\n <input type=\"radio\" name=\"mapRenderMode\" value=\"point\"\n [(ngModel)]=\"mapRenderMode\" (change)=\"onOptionChange()\">\n <span class=\"radio-mark\"></span>\n <span class=\"radio-label\">\n <i class=\"fa-solid fa-map-pin\"></i>\n Points\n </span>\n </label>\n <label class=\"radio-option radio-option--compact\" [class.selected]=\"mapRenderMode === 'choropleth'\">\n <input type=\"radio\" name=\"mapRenderMode\" value=\"choropleth\"\n [(ngModel)]=\"mapRenderMode\" (change)=\"onOptionChange()\">\n <span class=\"radio-mark\"></span>\n <span class=\"radio-label\">\n <i class=\"fa-solid fa-earth-americas\"></i>\n Regions\n </span>\n </label>\n <label class=\"radio-option radio-option--compact\" [class.selected]=\"mapRenderMode === 'heatmap'\">\n <input type=\"radio\" name=\"mapRenderMode\" value=\"heatmap\"\n [(ngModel)]=\"mapRenderMode\" (change)=\"onOptionChange()\">\n <span class=\"radio-mark\"></span>\n <span class=\"radio-label\">\n <i class=\"fa-solid fa-fire\"></i>\n Heatmap\n </span>\n </label>\n </div>\n </div>\n }\n <!-- Selection Options -->\n <div class=\"form-group\">\n <div class=\"checkbox-group checkbox-group--compact\">\n <label class=\"checkbox-option checkbox-option--compact\">\n <input\n type=\"checkbox\"\n [(ngModel)]=\"allowModeSwitch\"\n (change)=\"onOptionChange()\">\n <span class=\"checkbox-mark\"></span>\n <span class=\"checkbox-label\">Allow Mode Switch</span>\n </label>\n <label class=\"checkbox-option checkbox-option--compact\">\n <input\n type=\"checkbox\"\n [(ngModel)]=\"enableSelection\"\n (change)=\"onOptionChange()\">\n <span class=\"checkbox-mark\"></span>\n <span class=\"checkbox-label\">Enable Selection</span>\n </label>\n </div>\n </div>\n <!-- Selection Mode -->\n @if (enableSelection) {\n <div class=\"form-group\">\n <label for=\"selectionMode\">Selection Mode</label>\n <select\n id=\"selectionMode\"\n class=\"form-select\"\n [(ngModel)]=\"selectionMode\"\n (change)=\"onSelectionModeChange()\">\n <option value=\"single\">Single Selection</option>\n <option value=\"multiple\">Multiple Selection</option>\n </select>\n </div>\n }\n </div>\n }\n </div>\n\n <!-- Advanced Options (Collapsible) -->\n <div class=\"collapsible-section\">\n <button\n type=\"button\"\n class=\"collapsible-header\"\n (click)=\"toggleAdvancedOptions()\"\n [attr.aria-expanded]=\"showAdvancedOptions\">\n <span class=\"collapsible-title\">\n <i class=\"fa-solid fa-filter\"></i>\n Advanced Filtering\n </span>\n <i class=\"collapsible-chevron fa-solid\"\n [class.fa-chevron-down]=\"!showAdvancedOptions\"\n [class.fa-chevron-up]=\"showAdvancedOptions\"></i>\n </button>\n\n @if (showAdvancedOptions) {\n <div class=\"collapsible-content\">\n <!-- Extra Filter -->\n <div class=\"form-group\">\n <label for=\"extraFilter\">\n Extra Filter\n </label>\n <input\n type=\"text\"\n id=\"extraFilter\"\n [(ngModel)]=\"extraFilter\"\n (input)=\"onFilterChange()\"\n placeholder=\"e.g., Status = 'Active'\"\n class=\"form-input\">\n <span class=\"form-hint\">\n SQL WHERE clause to filter records (applied in addition to view filters)\n </span>\n </div>\n </div>\n }\n </div>\n</div>\n", styles: ["/**\n * Shared styles for Config Panels (form content only, no dialog chrome)\n */\n\n/* ========================================\n Panel Container\n ======================================== */\n\n.config-panel {\n display: flex;\n flex-direction: column;\n gap: 24px;\n padding: 8px 0;\n}\n\n/* ========================================\n Form Groups\n ======================================== */\n\n.form-group {\n display: flex;\n flex-direction: column;\n gap: 10px;\n}\n\n.form-group > label {\n font-size: 14px;\n font-weight: 600;\n color: var(--mj-text-primary);\n display: flex;\n align-items: center;\n gap: 8px;\n}\n\n.form-group > label i {\n color: var(--mj-brand-primary);\n font-size: 14px;\n width: 16px;\n}\n\n.form-group > label .required {\n color: var(--mj-status-error);\n}\n\n/* ========================================\n Form Inputs\n ======================================== */\n\n.form-input {\n padding: 14px 16px;\n border: 2px solid var(--mj-border-default);\n border-radius: 10px;\n font-size: 15px;\n color: var(--mj-text-primary);\n background: var(--mj-bg-surface);\n transition: all 0.2s ease;\n width: 100%;\n box-sizing: border-box;\n}\n\n.form-input:focus {\n outline: none;\n border-color: var(--mj-brand-primary);\n box-shadow: 0 0 0 4px color-mix(in srgb, var(--mj-brand-primary) 12%, transparent);\n}\n\n.form-input::placeholder {\n color: var(--mj-text-disabled);\n}\n\n.form-input.error {\n border-color: var(--mj-status-error);\n}\n\n.form-input.error:focus {\n box-shadow: 0 0 0 4px color-mix(in srgb, var(--mj-status-error) 12%, transparent);\n}\n\n.input-with-action {\n display: flex;\n gap: 8px;\n}\n\n.input-with-action .form-input {\n flex: 1;\n}\n\n.input-action-btn {\n width: 48px;\n height: 48px;\n display: flex;\n align-items: center;\n justify-content: center;\n border: 2px solid var(--mj-border-default);\n border-radius: 10px;\n background: var(--mj-bg-surface);\n color: var(--mj-text-secondary);\n cursor: pointer;\n transition: all 0.2s ease;\n flex-shrink: 0;\n}\n\n.input-action-btn:hover {\n border-color: var(--mj-brand-primary);\n background: color-mix(in srgb, var(--mj-brand-primary) 10%, var(--mj-bg-surface));\n color: var(--mj-brand-primary);\n}\n\n/* ========================================\n Form Hints & Errors\n ======================================== */\n\n.form-hint {\n font-size: 13px;\n color: var(--mj-text-muted);\n line-height: 1.4;\n}\n\n.form-error {\n font-size: 13px;\n color: var(--mj-status-error);\n display: flex;\n align-items: center;\n gap: 6px;\n}\n\n.form-error::before {\n content: '\\f071';\n font-family: 'Font Awesome 6 Free';\n font-weight: 900;\n font-size: 12px;\n}\n\n/* ========================================\n Radio Group\n ======================================== */\n\n.radio-group {\n display: flex;\n flex-direction: column;\n gap: 8px;\n}\n\n.radio-option {\n display: flex;\n align-items: center;\n gap: 12px;\n padding: 14px 16px;\n border: 2px solid color-mix(in srgb, var(--mj-brand-primary) 15%, var(--mj-bg-surface));\n border-radius: 10px;\n cursor: pointer;\n transition: all 0.2s ease;\n background: var(--mj-bg-surface);\n}\n\n.radio-option:hover {\n border-color: color-mix(in srgb, var(--mj-brand-primary) 30%, var(--mj-bg-surface));\n background: var(--mj-bg-surface-card);\n}\n\n.radio-option.selected {\n border-color: var(--mj-brand-primary);\n background: color-mix(in srgb, var(--mj-brand-primary) 10%, var(--mj-bg-surface));\n}\n\n.radio-option input[type=\"radio\"] {\n display: none;\n}\n\n.radio-mark {\n width: 20px;\n height: 20px;\n border: 2px solid var(--mj-border-strong);\n border-radius: 50%;\n display: flex;\n align-items: center;\n justify-content: center;\n flex-shrink: 0;\n transition: all 0.2s ease;\n}\n\n.radio-option.selected .radio-mark {\n border-color: var(--mj-brand-primary);\n}\n\n.radio-option.selected .radio-mark::after {\n content: '';\n width: 10px;\n height: 10px;\n background: var(--mj-brand-primary);\n border-radius: 50%;\n}\n\n.radio-content {\n flex: 1;\n display: flex;\n align-items: center;\n gap: 10px;\n}\n\n.radio-label {\n font-size: 14px;\n font-weight: 500;\n color: var(--mj-text-primary);\n}\n\n.radio-badge {\n font-size: 11px;\n font-weight: 600;\n padding: 3px 8px;\n border-radius: 4px;\n text-transform: uppercase;\n}\n\n.radio-badge.recommended {\n background: color-mix(in srgb, var(--mj-status-success) 10%, var(--mj-bg-surface));\n color: var(--mj-status-success);\n}\n\n.radio-badge.secure {\n background: color-mix(in srgb, var(--mj-brand-primary) 10%, var(--mj-bg-surface));\n color: var(--mj-brand-primary);\n}\n\n.radio-badge.warning {\n background: color-mix(in srgb, var(--mj-status-warning) 10%, var(--mj-bg-surface));\n color: var(--mj-status-warning);\n}\n\n/* ========================================\n Checkbox Group\n ======================================== */\n\n.checkbox-group {\n display: flex;\n flex-direction: column;\n gap: 8px;\n}\n\n.checkbox-option {\n display: flex;\n align-items: flex-start;\n gap: 12px;\n padding: 14px 16px;\n border: 2px solid color-mix(in srgb, var(--mj-brand-primary) 15%, var(--mj-bg-surface));\n border-radius: 10px;\n cursor: pointer;\n transition: all 0.2s ease;\n background: var(--mj-bg-surface);\n}\n\n.checkbox-option:hover {\n border-color: color-mix(in srgb, var(--mj-brand-primary) 30%, var(--mj-bg-surface));\n background: var(--mj-bg-surface-card);\n}\n\n.checkbox-option input[type=\"checkbox\"] {\n display: none;\n}\n\n.checkbox-mark {\n width: 22px;\n height: 22px;\n border: 2px solid var(--mj-border-strong);\n border-radius: 6px;\n display: flex;\n align-items: center;\n justify-content: center;\n flex-shrink: 0;\n transition: all 0.2s ease;\n margin-top: 2px;\n}\n\n.checkbox-option input:checked + .checkbox-mark {\n background: var(--mj-brand-primary);\n border-color: var(--mj-brand-primary);\n}\n\n.checkbox-option input:checked + .checkbox-mark::after {\n content: '\\f00c';\n font-family: 'Font Awesome 6 Free';\n font-weight: 900;\n font-size: 12px;\n color: var(--mj-text-inverse);\n}\n\n.checkbox-content {\n flex: 1;\n display: flex;\n flex-direction: column;\n gap: 2px;\n}\n\n.checkbox-label {\n font-size: 14px;\n font-weight: 500;\n color: var(--mj-text-primary);\n}\n\n.checkbox-desc {\n font-size: 12px;\n color: var(--mj-text-muted);\n}\n\n/* ========================================\n Select/Dropdown\n ======================================== */\n\n.form-select {\n padding: 14px 40px 14px 16px;\n border: 2px solid var(--mj-border-default);\n border-radius: 10px;\n font-size: 15px;\n color: var(--mj-text-primary);\n background: var(--mj-bg-surface);\n transition: all 0.2s ease;\n width: 100%;\n box-sizing: border-box;\n cursor: pointer;\n appearance: none;\n background-image: url(\"data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='12' viewBox='0 0 12 12'%3E%3Cpath fill='%23666' d='M6 8L1 3h10z'/%3E%3C/svg%3E\");\n background-repeat: no-repeat;\n background-position: right 16px center;\n}\n\n.form-select:focus {\n outline: none;\n border-color: var(--mj-brand-primary);\n box-shadow: 0 0 0 4px color-mix(in srgb, var(--mj-brand-primary) 12%, transparent);\n}\n\n/* ========================================\n Compact Panel Variant\n ======================================== */\n\n.config-panel--compact {\n gap: 16px;\n}\n\n.config-panel--compact .form-group {\n gap: 8px;\n}\n\n.config-panel--compact .form-input {\n padding: 10px 14px;\n font-size: 14px;\n}\n\n.config-panel--compact .form-select {\n padding: 10px 36px 10px 14px;\n font-size: 14px;\n}\n\n/* ========================================\n Optional Tag\n ======================================== */\n\n.optional-tag {\n font-weight: 400;\n font-size: 12px;\n color: var(--mj-text-muted);\n}\n\n/* ========================================\n Selected Hint (Success State)\n ======================================== */\n\n.form-hint--selected {\n color: var(--mj-status-success);\n}\n\n.form-hint--selected i {\n color: var(--mj-status-success);\n}\n\n/* ========================================\n Collapsible Section\n ======================================== */\n\n.collapsible-section {\n border: 1px solid color-mix(in srgb, var(--mj-brand-primary) 15%, var(--mj-bg-surface));\n border-radius: 10px;\n overflow: hidden;\n}\n\n.collapsible-header {\n display: flex;\n align-items: center;\n justify-content: space-between;\n width: 100%;\n padding: 12px 16px;\n border: none;\n background: var(--mj-bg-page);\n cursor: pointer;\n transition: background 0.2s ease;\n}\n\n.collapsible-header:hover {\n background: color-mix(in srgb, var(--mj-brand-primary) 10%, var(--mj-bg-surface));\n}\n\n.collapsible-title {\n display: flex;\n align-items: center;\n gap: 8px;\n font-size: 14px;\n font-weight: 600;\n color: var(--mj-text-primary);\n}\n\n.collapsible-title i {\n color: var(--mj-brand-primary);\n font-size: 14px;\n}\n\n.collapsible-chevron {\n color: var(--mj-text-muted);\n font-size: 12px;\n transition: transform 0.2s ease;\n}\n\n.collapsible-content {\n padding: 16px;\n border-top: 1px solid color-mix(in srgb, var(--mj-brand-primary) 15%, var(--mj-bg-surface));\n display: flex;\n flex-direction: column;\n gap: 16px;\n}\n\n/* ========================================\n Horizontal Radio Group\n ======================================== */\n\n.radio-group--horizontal {\n flex-direction: row;\n flex-wrap: wrap;\n gap: 8px;\n}\n\n.radio-option--compact {\n padding: 10px 14px;\n flex: 1;\n min-width: 120px;\n}\n\n.radio-option--compact .radio-label {\n font-size: 13px;\n display: flex;\n align-items: center;\n gap: 6px;\n}\n\n.radio-option--compact .radio-label i {\n color: var(--mj-brand-primary);\n font-size: 12px;\n}\n\n.radio-option--compact .radio-mark {\n width: 16px;\n height: 16px;\n}\n\n.radio-option--compact.selected .radio-mark::after {\n width: 8px;\n height: 8px;\n}\n\n/* ========================================\n Compact Checkbox Group\n ======================================== */\n\n.checkbox-group--compact {\n gap: 4px;\n}\n\n.checkbox-option--compact {\n padding: 10px 14px;\n}\n\n.checkbox-option--compact .checkbox-mark {\n width: 18px;\n height: 18px;\n margin-top: 0;\n}\n\n.checkbox-option--compact .checkbox-label {\n font-size: 13px;\n}\n\n/* ========================================\n Tree Dropdown Error State\n ======================================== */\n\nmj-tree-dropdown.error {\n --dropdown-border-color: var(--mj-status-error);\n}\n\nmj-tree-dropdown.error:focus-within {\n --dropdown-border-focus: var(--mj-status-error);\n}\n"] }]
432
500
  }], () => [{ type: i0.ChangeDetectorRef }], { viewDropdown: [{
433
501
  type: ViewChild,
434
502
  args: ['viewDropdown']
@@ -1 +1 @@
1
- {"version":3,"file":"view-config-panel.component.js","sourceRoot":"","sources":["../../../src/lib/config-panels/view-config-panel.component.ts","../../../src/lib/config-panels/view-config-panel.component.html"],"names":[],"mappings":"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","sourcesContent":["import { Component, ChangeDetectorRef, ViewChild } from '@angular/core';\nimport { RegisterClass } from '@memberjunction/global';\nimport { CompositeKey } from '@memberjunction/core';\nimport { BaseConfigPanel } from './base-config-panel';\nimport { PanelConfig } from '../models/dashboard-types';\nimport {\n TreeBranchConfig,\n TreeLeafConfig,\n TreeNode,\n TreeDropdownComponent\n} from '@memberjunction/ng-trees';\n\n/**\n * Configuration panel for View parts.\n * Uses tree dropdown for category-based view selection.\n */\n@RegisterClass(BaseConfigPanel, 'ViewPanelConfigDialog')\n@Component({\n standalone: false,\n selector: 'mj-dashboard-view-config-panel',\n templateUrl: './view-config-panel.component.html',\n styleUrls: ['./config-panel.component.css']\n})\nexport class ViewConfigPanelComponent extends BaseConfigPanel {\n // ViewChild reference\n @ViewChild('viewDropdown') viewDropdown!: TreeDropdownComponent;\n\n // Form fields\n public title = '';\n public entityName = '';\n public viewId = '';\n public viewName = '';\n public extraFilter = '';\n public displayMode: 'grid' | 'cards' | 'timeline' = 'grid';\n public allowModeSwitch = true;\n public enableSelection = true;\n public selectionMode: 'none' | 'single' | 'multiple' = 'single';\n\n // Track previous selection name for smart title updates\n private previousViewName = '';\n\n // Collapsible section states\n public showDisplayOptions = false;\n public showAdvancedOptions = false;\n\n // Validation\n public viewError = '';\n\n // Tree configuration for User View Categories (branches) and User Views (leaves)\n public ViewCategoryConfig: TreeBranchConfig = {\n EntityName: 'MJ: User View Categories',\n DisplayField: 'Name',\n IDField: 'ID',\n ParentIDField: 'ParentID',\n DefaultIcon: 'fa-solid fa-folder',\n DescriptionField: 'Description',\n OrderBy: 'Name ASC'\n };\n\n public ViewLeafConfig: TreeLeafConfig = {\n EntityName: 'MJ: User Views',\n DisplayField: 'Name',\n IDField: 'ID',\n ParentField: 'CategoryID',\n DefaultIcon: 'fa-solid fa-table',\n DescriptionField: 'Description',\n OrderBy: 'Name ASC'\n };\n\n constructor(cdr: ChangeDetectorRef) {\n super(cdr);\n }\n\n /**\n * Get the viewId as a CompositeKey for the tree dropdown\n */\n public get ViewIdAsKey(): CompositeKey | null {\n return this.viewId ? CompositeKey.FromID(this.viewId) : null;\n }\n\n public initFromConfig(config: PanelConfig | null): void {\n if (config && config.type === 'View') {\n this.entityName = (config['entityName'] as string) || '';\n this.viewId = (config['viewId'] as string) || '';\n this.extraFilter = (config['extraFilter'] as string) || '';\n this.displayMode = (config['displayMode'] as 'grid' | 'cards' | 'timeline') || 'grid';\n this.allowModeSwitch = (config['allowModeSwitch'] as boolean) ?? true;\n this.enableSelection = (config['enableSelection'] as boolean) ?? true;\n this.selectionMode = (config['selectionMode'] as 'none' | 'single' | 'multiple') || 'single';\n } else {\n // Defaults for new View panel\n this.entityName = '';\n this.viewId = '';\n this.extraFilter = '';\n this.displayMode = 'grid';\n this.allowModeSwitch = true;\n this.enableSelection = true;\n this.selectionMode = 'single';\n }\n\n this.title = this.panel?.title || '';\n this.viewName = '';\n this.previousViewName = '';\n this.viewError = '';\n this.cdr.detectChanges();\n }\n\n public buildConfig(): PanelConfig {\n return {\n type: 'View',\n entityName: this.entityName.trim() || undefined,\n viewId: this.viewId.trim() || undefined,\n extraFilter: this.extraFilter.trim() || undefined,\n displayMode: this.displayMode,\n allowModeSwitch: this.allowModeSwitch,\n enableSelection: this.enableSelection,\n selectionMode: this.selectionMode\n };\n }\n\n public override validate(): { valid: boolean; errors: string[] } {\n const errors: string[] = [];\n this.viewError = '';\n\n // At least entity name or view ID should be provided\n if (!this.entityName.trim() && !this.viewId.trim()) {\n this.viewError = 'Please select a saved view or enter an entity name';\n errors.push(this.viewError);\n }\n\n this.cdr.detectChanges();\n return { valid: errors.length === 0, errors };\n }\n\n public getDefaultTitle(): string {\n if (this.viewName) {\n return this.viewName;\n }\n if (this.entityName) {\n return this.entityName;\n }\n return 'View';\n }\n\n public getTitle(): string {\n return this.title || this.getDefaultTitle();\n }\n\n // Form event handlers\n public onTitleChange(): void {\n this.emitConfigChanged();\n }\n\n /**\n * Handle view selection from tree dropdown\n */\n public onViewSelection(node: TreeNode | TreeNode[] | null): void {\n // Ignore null/empty selections (these happen during sync, not user interaction)\n if (!node || (Array.isArray(node) && node.length === 0)) {\n return;\n }\n\n this.viewError = '';\n\n if (!Array.isArray(node)) {\n // Only accept leaf nodes (actual views, not categories)\n if (node.Type === 'leaf') {\n const oldViewName = this.viewName;\n this.viewId = node.ID;\n this.viewName = node.Label;\n\n // Extract entity name from the view data if available\n if (node.Data && node.Data['Entity']) {\n this.entityName = String(node.Data['Entity']);\n }\n\n // Smart title update: if title matches old name, update to new name\n if (!this.title || this.title === oldViewName || this.title === this.previousViewName) {\n this.title = node.Label;\n }\n this.previousViewName = node.Label;\n }\n }\n\n this.emitConfigChanged();\n this.cdr.detectChanges();\n }\n\n public onEntityChange(): void {\n this.viewError = '';\n this.emitConfigChanged();\n }\n\n public onDisplayModeChange(): void {\n this.emitConfigChanged();\n }\n\n public onOptionChange(): void {\n this.emitConfigChanged();\n }\n\n public onSelectionModeChange(): void {\n this.emitConfigChanged();\n }\n\n public onFilterChange(): void {\n this.emitConfigChanged();\n }\n\n public toggleDisplayOptions(): void {\n this.showDisplayOptions = !this.showDisplayOptions;\n }\n\n public toggleAdvancedOptions(): void {\n this.showAdvancedOptions = !this.showAdvancedOptions;\n }\n\n public getDisplayModeDescription(): string {\n switch (this.displayMode) {\n case 'cards':\n return 'Display records as cards in a responsive grid layout';\n case 'timeline':\n return 'Display records chronologically along a timeline';\n default:\n return 'Display records in a traditional table/grid format';\n }\n }\n}\n","<!-- View Config Panel - Compact layout with tree dropdown and collapsible sections -->\n<div class=\"config-panel config-panel--compact\">\n <!-- View Selection (Primary) -->\n <div class=\"form-group\">\n <label>\n <i class=\"fa-solid fa-table\"></i>\n Select View\n <span class=\"optional-tag\">(or enter entity below)</span>\n </label>\n <mj-tree-dropdown\n #viewDropdown\n [BranchConfig]=\"ViewCategoryConfig\"\n [LeafConfig]=\"ViewLeafConfig\"\n [Value]=\"ViewIdAsKey\"\n [SelectableTypes]=\"'leaf'\"\n [SelectionMode]=\"'single'\"\n [Placeholder]=\"'Search or browse saved views...'\"\n [EnableSearch]=\"true\"\n (SelectionChange)=\"onViewSelection($event)\"\n [class.error]=\"viewError\">\n </mj-tree-dropdown>\n @if (viewError) {\n <span class=\"form-error\">{{ viewError }}</span>\n }\n @if (!viewError && !viewId && !entityName) {\n <span class=\"form-hint\">\n Select a saved view or enter an entity name below\n </span>\n }\n @if (!viewError && viewId) {\n <span class=\"form-hint form-hint--selected\">\n <i class=\"fa-solid fa-check\"></i>\n Selected: {{ viewName }}\n </span>\n }\n </div>\n\n <!-- Entity Name (Alternative) -->\n <div class=\"form-group\">\n <label for=\"entityName\">\n <i class=\"fa-solid fa-database\"></i>\n Entity Name\n <span class=\"optional-tag\">(alternative to view)</span>\n </label>\n <input\n type=\"text\"\n id=\"entityName\"\n [(ngModel)]=\"entityName\"\n (input)=\"onEntityChange()\"\n placeholder=\"e.g., Accounts, Contacts, Users\"\n class=\"form-input\">\n <span class=\"form-hint\">\n Use this to display all records from an entity without a saved view\n </span>\n </div>\n\n <!-- Title (Optional) -->\n <div class=\"form-group\">\n <label for=\"partTitle\">\n <i class=\"fa-solid fa-heading\"></i>\n Part Title\n <span class=\"optional-tag\">(optional)</span>\n </label>\n <input\n type=\"text\"\n id=\"partTitle\"\n [(ngModel)]=\"title\"\n (input)=\"onTitleChange()\"\n [placeholder]=\"viewName || entityName ? 'Default: ' + (viewName || entityName) : 'Enter a custom title'\"\n class=\"form-input\">\n <span class=\"form-hint\">Leave empty to use view/entity name as title</span>\n </div>\n\n <!-- Display Options (Collapsible) -->\n <div class=\"collapsible-section\">\n <button\n type=\"button\"\n class=\"collapsible-header\"\n (click)=\"toggleDisplayOptions()\"\n [attr.aria-expanded]=\"showDisplayOptions\">\n <span class=\"collapsible-title\">\n <i class=\"fa-solid fa-grip\"></i>\n Display Options\n </span>\n <i class=\"collapsible-chevron fa-solid\"\n [class.fa-chevron-down]=\"!showDisplayOptions\"\n [class.fa-chevron-up]=\"showDisplayOptions\"></i>\n </button>\n\n @if (showDisplayOptions) {\n <div class=\"collapsible-content\">\n <!-- Display Mode -->\n <div class=\"form-group\">\n <label>Display Mode</label>\n <div class=\"radio-group radio-group--horizontal\">\n <label class=\"radio-option radio-option--compact\" [class.selected]=\"displayMode === 'grid'\">\n <input\n type=\"radio\"\n name=\"displayMode\"\n value=\"grid\"\n [(ngModel)]=\"displayMode\"\n (change)=\"onDisplayModeChange()\">\n <span class=\"radio-mark\"></span>\n <span class=\"radio-label\">\n <i class=\"fa-solid fa-table-cells\"></i>\n Grid\n </span>\n </label>\n <label class=\"radio-option radio-option--compact\" [class.selected]=\"displayMode === 'cards'\">\n <input\n type=\"radio\"\n name=\"displayMode\"\n value=\"cards\"\n [(ngModel)]=\"displayMode\"\n (change)=\"onDisplayModeChange()\">\n <span class=\"radio-mark\"></span>\n <span class=\"radio-label\">\n <i class=\"fa-solid fa-id-card\"></i>\n Cards\n </span>\n </label>\n <label class=\"radio-option radio-option--compact\" [class.selected]=\"displayMode === 'timeline'\">\n <input\n type=\"radio\"\n name=\"displayMode\"\n value=\"timeline\"\n [(ngModel)]=\"displayMode\"\n (change)=\"onDisplayModeChange()\">\n <span class=\"radio-mark\"></span>\n <span class=\"radio-label\">\n <i class=\"fa-solid fa-timeline\"></i>\n Timeline\n </span>\n </label>\n </div>\n <span class=\"form-hint\">{{ getDisplayModeDescription() }}</span>\n </div>\n <!-- Selection Options -->\n <div class=\"form-group\">\n <div class=\"checkbox-group checkbox-group--compact\">\n <label class=\"checkbox-option checkbox-option--compact\">\n <input\n type=\"checkbox\"\n [(ngModel)]=\"allowModeSwitch\"\n (change)=\"onOptionChange()\">\n <span class=\"checkbox-mark\"></span>\n <span class=\"checkbox-label\">Allow Mode Switch</span>\n </label>\n <label class=\"checkbox-option checkbox-option--compact\">\n <input\n type=\"checkbox\"\n [(ngModel)]=\"enableSelection\"\n (change)=\"onOptionChange()\">\n <span class=\"checkbox-mark\"></span>\n <span class=\"checkbox-label\">Enable Selection</span>\n </label>\n </div>\n </div>\n <!-- Selection Mode -->\n @if (enableSelection) {\n <div class=\"form-group\">\n <label for=\"selectionMode\">Selection Mode</label>\n <select\n id=\"selectionMode\"\n class=\"form-select\"\n [(ngModel)]=\"selectionMode\"\n (change)=\"onSelectionModeChange()\">\n <option value=\"single\">Single Selection</option>\n <option value=\"multiple\">Multiple Selection</option>\n </select>\n </div>\n }\n </div>\n }\n </div>\n\n <!-- Advanced Options (Collapsible) -->\n <div class=\"collapsible-section\">\n <button\n type=\"button\"\n class=\"collapsible-header\"\n (click)=\"toggleAdvancedOptions()\"\n [attr.aria-expanded]=\"showAdvancedOptions\">\n <span class=\"collapsible-title\">\n <i class=\"fa-solid fa-filter\"></i>\n Advanced Filtering\n </span>\n <i class=\"collapsible-chevron fa-solid\"\n [class.fa-chevron-down]=\"!showAdvancedOptions\"\n [class.fa-chevron-up]=\"showAdvancedOptions\"></i>\n </button>\n\n @if (showAdvancedOptions) {\n <div class=\"collapsible-content\">\n <!-- Extra Filter -->\n <div class=\"form-group\">\n <label for=\"extraFilter\">\n Extra Filter\n </label>\n <input\n type=\"text\"\n id=\"extraFilter\"\n [(ngModel)]=\"extraFilter\"\n (input)=\"onFilterChange()\"\n placeholder=\"e.g., Status = 'Active'\"\n class=\"form-input\">\n <span class=\"form-hint\">\n SQL WHERE clause to filter records (applied in addition to view filters)\n </span>\n </div>\n </div>\n }\n </div>\n</div>\n"]}
1
+ {"version":3,"file":"view-config-panel.component.js","sourceRoot":"","sources":["../../../src/lib/config-panels/view-config-panel.component.ts","../../../src/lib/config-panels/view-config-panel.component.html"],"names":[],"mappings":"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","sourcesContent":["import { Component, ChangeDetectorRef, ViewChild } from '@angular/core';\nimport { RegisterClass } from '@memberjunction/global';\nimport { CompositeKey } from '@memberjunction/core';\nimport { BaseConfigPanel } from './base-config-panel';\nimport { PanelConfig } from '../models/dashboard-types';\nimport {\n TreeBranchConfig,\n TreeLeafConfig,\n TreeNode,\n TreeDropdownComponent\n} from '@memberjunction/ng-trees';\n\n/**\n * Configuration panel for View parts.\n * Uses tree dropdown for category-based view selection.\n */\n@RegisterClass(BaseConfigPanel, 'ViewPanelConfigDialog')\n@Component({\n standalone: false,\n selector: 'mj-dashboard-view-config-panel',\n templateUrl: './view-config-panel.component.html',\n styleUrls: ['./config-panel.component.css']\n})\nexport class ViewConfigPanelComponent extends BaseConfigPanel {\n // ViewChild reference\n @ViewChild('viewDropdown') viewDropdown!: TreeDropdownComponent;\n\n // Form fields\n public title = '';\n public entityName = '';\n public viewId = '';\n public viewName = '';\n public extraFilter = '';\n public displayMode: 'grid' | 'cards' | 'timeline' | 'map' = 'grid';\n public mapRenderMode: 'point' | 'choropleth' | 'heatmap' = 'point';\n public allowModeSwitch = true;\n public enableSelection = true;\n public selectionMode: 'none' | 'single' | 'multiple' = 'single';\n\n // Track previous selection name for smart title updates\n private previousViewName = '';\n\n // Collapsible section states\n public showDisplayOptions = false;\n public showAdvancedOptions = false;\n\n // Validation\n public viewError = '';\n\n // Tree configuration for User View Categories (branches) and User Views (leaves)\n public ViewCategoryConfig: TreeBranchConfig = {\n EntityName: 'MJ: User View Categories',\n DisplayField: 'Name',\n IDField: 'ID',\n ParentIDField: 'ParentID',\n DefaultIcon: 'fa-solid fa-folder',\n DescriptionField: 'Description',\n OrderBy: 'Name ASC'\n };\n\n public ViewLeafConfig: TreeLeafConfig = {\n EntityName: 'MJ: User Views',\n DisplayField: 'Name',\n IDField: 'ID',\n ParentField: 'CategoryID',\n DefaultIcon: 'fa-solid fa-table',\n DescriptionField: 'Description',\n OrderBy: 'Name ASC'\n };\n\n constructor(cdr: ChangeDetectorRef) {\n super(cdr);\n }\n\n /**\n * Get the viewId as a CompositeKey for the tree dropdown\n */\n public get ViewIdAsKey(): CompositeKey | null {\n return this.viewId ? CompositeKey.FromID(this.viewId) : null;\n }\n\n public initFromConfig(config: PanelConfig | null): void {\n if (config && config.type === 'View') {\n this.entityName = (config['entityName'] as string) || '';\n this.viewId = (config['viewId'] as string) || '';\n this.extraFilter = (config['extraFilter'] as string) || '';\n this.displayMode = (config['displayMode'] as 'grid' | 'cards' | 'timeline' | 'map') || 'grid';\n this.mapRenderMode = (config['mapRenderMode'] as 'point' | 'choropleth' | 'heatmap') || 'point';\n this.allowModeSwitch = (config['allowModeSwitch'] as boolean) ?? true;\n this.enableSelection = (config['enableSelection'] as boolean) ?? true;\n this.selectionMode = (config['selectionMode'] as 'none' | 'single' | 'multiple') || 'single';\n } else {\n // Defaults for new View panel\n this.entityName = '';\n this.viewId = '';\n this.extraFilter = '';\n this.displayMode = 'grid';\n this.allowModeSwitch = true;\n this.enableSelection = true;\n this.selectionMode = 'single';\n }\n\n this.title = this.panel?.title || '';\n this.viewName = '';\n this.previousViewName = '';\n this.viewError = '';\n this.cdr.detectChanges();\n }\n\n public buildConfig(): PanelConfig {\n return {\n type: 'View',\n entityName: this.entityName.trim() || undefined,\n viewId: this.viewId.trim() || undefined,\n extraFilter: this.extraFilter.trim() || undefined,\n displayMode: this.displayMode,\n mapRenderMode: this.displayMode === 'map' ? this.mapRenderMode : undefined,\n allowModeSwitch: this.allowModeSwitch,\n enableSelection: this.enableSelection,\n selectionMode: this.selectionMode\n };\n }\n\n public override validate(): { valid: boolean; errors: string[] } {\n const errors: string[] = [];\n this.viewError = '';\n\n // At least entity name or view ID should be provided\n if (!this.entityName.trim() && !this.viewId.trim()) {\n this.viewError = 'Please select a saved view or enter an entity name';\n errors.push(this.viewError);\n }\n\n this.cdr.detectChanges();\n return { valid: errors.length === 0, errors };\n }\n\n public getDefaultTitle(): string {\n if (this.viewName) {\n return this.viewName;\n }\n if (this.entityName) {\n return this.entityName;\n }\n return 'View';\n }\n\n public getTitle(): string {\n return this.title || this.getDefaultTitle();\n }\n\n // Form event handlers\n public onTitleChange(): void {\n this.emitConfigChanged();\n }\n\n /**\n * Handle view selection from tree dropdown\n */\n public onViewSelection(node: TreeNode | TreeNode[] | null): void {\n // Ignore null/empty selections (these happen during sync, not user interaction)\n if (!node || (Array.isArray(node) && node.length === 0)) {\n return;\n }\n\n this.viewError = '';\n\n if (!Array.isArray(node)) {\n // Only accept leaf nodes (actual views, not categories)\n if (node.Type === 'leaf') {\n const oldViewName = this.viewName;\n this.viewId = node.ID;\n this.viewName = node.Label;\n\n // Extract entity name from the view data if available\n if (node.Data && node.Data['Entity']) {\n this.entityName = String(node.Data['Entity']);\n }\n\n // Smart title update: if title matches old name, update to new name\n if (!this.title || this.title === oldViewName || this.title === this.previousViewName) {\n this.title = node.Label;\n }\n this.previousViewName = node.Label;\n }\n }\n\n this.emitConfigChanged();\n this.cdr.detectChanges();\n }\n\n public onEntityChange(): void {\n this.viewError = '';\n this.emitConfigChanged();\n }\n\n public onDisplayModeChange(): void {\n this.emitConfigChanged();\n }\n\n public onOptionChange(): void {\n this.emitConfigChanged();\n }\n\n public onSelectionModeChange(): void {\n this.emitConfigChanged();\n }\n\n public onFilterChange(): void {\n this.emitConfigChanged();\n }\n\n public toggleDisplayOptions(): void {\n this.showDisplayOptions = !this.showDisplayOptions;\n }\n\n public toggleAdvancedOptions(): void {\n this.showAdvancedOptions = !this.showAdvancedOptions;\n }\n\n public getDisplayModeDescription(): string {\n switch (this.displayMode) {\n case 'cards':\n return 'Display records as cards in a responsive grid layout';\n case 'timeline':\n return 'Display records chronologically along a timeline';\n case 'map':\n return 'Display geo-coded records on an interactive map';\n default:\n return 'Display records in a traditional table/grid format';\n }\n }\n}\n","<!-- View Config Panel - Compact layout with tree dropdown and collapsible sections -->\n<div class=\"config-panel config-panel--compact\">\n <!-- View Selection (Primary) -->\n <div class=\"form-group\">\n <label>\n <i class=\"fa-solid fa-table\"></i>\n Select View\n <span class=\"optional-tag\">(or enter entity below)</span>\n </label>\n <mj-tree-dropdown\n #viewDropdown\n [BranchConfig]=\"ViewCategoryConfig\"\n [LeafConfig]=\"ViewLeafConfig\"\n [Value]=\"ViewIdAsKey\"\n [SelectableTypes]=\"'leaf'\"\n [SelectionMode]=\"'single'\"\n [Placeholder]=\"'Search or browse saved views...'\"\n [EnableSearch]=\"true\"\n (SelectionChange)=\"onViewSelection($event)\"\n [class.error]=\"viewError\">\n </mj-tree-dropdown>\n @if (viewError) {\n <span class=\"form-error\">{{ viewError }}</span>\n }\n @if (!viewError && !viewId && !entityName) {\n <span class=\"form-hint\">\n Select a saved view or enter an entity name below\n </span>\n }\n @if (!viewError && viewId) {\n <span class=\"form-hint form-hint--selected\">\n <i class=\"fa-solid fa-check\"></i>\n Selected: {{ viewName }}\n </span>\n }\n </div>\n\n <!-- Entity Name (Alternative) -->\n <div class=\"form-group\">\n <label for=\"entityName\">\n <i class=\"fa-solid fa-database\"></i>\n Entity Name\n <span class=\"optional-tag\">(alternative to view)</span>\n </label>\n <input\n type=\"text\"\n id=\"entityName\"\n [(ngModel)]=\"entityName\"\n (input)=\"onEntityChange()\"\n placeholder=\"e.g., Accounts, Contacts, Users\"\n class=\"form-input\">\n <span class=\"form-hint\">\n Use this to display all records from an entity without a saved view\n </span>\n </div>\n\n <!-- Title (Optional) -->\n <div class=\"form-group\">\n <label for=\"partTitle\">\n <i class=\"fa-solid fa-heading\"></i>\n Part Title\n <span class=\"optional-tag\">(optional)</span>\n </label>\n <input\n type=\"text\"\n id=\"partTitle\"\n [(ngModel)]=\"title\"\n (input)=\"onTitleChange()\"\n [placeholder]=\"viewName || entityName ? 'Default: ' + (viewName || entityName) : 'Enter a custom title'\"\n class=\"form-input\">\n <span class=\"form-hint\">Leave empty to use view/entity name as title</span>\n </div>\n\n <!-- Display Options (Collapsible) -->\n <div class=\"collapsible-section\">\n <button\n type=\"button\"\n class=\"collapsible-header\"\n (click)=\"toggleDisplayOptions()\"\n [attr.aria-expanded]=\"showDisplayOptions\">\n <span class=\"collapsible-title\">\n <i class=\"fa-solid fa-grip\"></i>\n Display Options\n </span>\n <i class=\"collapsible-chevron fa-solid\"\n [class.fa-chevron-down]=\"!showDisplayOptions\"\n [class.fa-chevron-up]=\"showDisplayOptions\"></i>\n </button>\n\n @if (showDisplayOptions) {\n <div class=\"collapsible-content\">\n <!-- Display Mode -->\n <div class=\"form-group\">\n <label>Display Mode</label>\n <div class=\"radio-group radio-group--horizontal\">\n <label class=\"radio-option radio-option--compact\" [class.selected]=\"displayMode === 'grid'\">\n <input\n type=\"radio\"\n name=\"displayMode\"\n value=\"grid\"\n [(ngModel)]=\"displayMode\"\n (change)=\"onDisplayModeChange()\">\n <span class=\"radio-mark\"></span>\n <span class=\"radio-label\">\n <i class=\"fa-solid fa-table-cells\"></i>\n Grid\n </span>\n </label>\n <label class=\"radio-option radio-option--compact\" [class.selected]=\"displayMode === 'cards'\">\n <input\n type=\"radio\"\n name=\"displayMode\"\n value=\"cards\"\n [(ngModel)]=\"displayMode\"\n (change)=\"onDisplayModeChange()\">\n <span class=\"radio-mark\"></span>\n <span class=\"radio-label\">\n <i class=\"fa-solid fa-id-card\"></i>\n Cards\n </span>\n </label>\n <label class=\"radio-option radio-option--compact\" [class.selected]=\"displayMode === 'timeline'\">\n <input\n type=\"radio\"\n name=\"displayMode\"\n value=\"timeline\"\n [(ngModel)]=\"displayMode\"\n (change)=\"onDisplayModeChange()\">\n <span class=\"radio-mark\"></span>\n <span class=\"radio-label\">\n <i class=\"fa-solid fa-timeline\"></i>\n Timeline\n </span>\n </label>\n <label class=\"radio-option radio-option--compact\" [class.selected]=\"displayMode === 'map'\">\n <input\n type=\"radio\"\n name=\"displayMode\"\n value=\"map\"\n [(ngModel)]=\"displayMode\"\n (change)=\"onDisplayModeChange()\">\n <span class=\"radio-mark\"></span>\n <span class=\"radio-label\">\n <i class=\"fa-solid fa-map-location-dot\"></i>\n Map\n </span>\n </label>\n </div>\n <span class=\"form-hint\">{{ getDisplayModeDescription() }}</span>\n </div>\n <!-- Map Render Mode (only shown when map is selected) -->\n @if (displayMode === 'map') {\n <div class=\"form-group\">\n <label>Map Style</label>\n <div class=\"radio-group radio-group--horizontal\">\n <label class=\"radio-option radio-option--compact\" [class.selected]=\"mapRenderMode === 'point'\">\n <input type=\"radio\" name=\"mapRenderMode\" value=\"point\"\n [(ngModel)]=\"mapRenderMode\" (change)=\"onOptionChange()\">\n <span class=\"radio-mark\"></span>\n <span class=\"radio-label\">\n <i class=\"fa-solid fa-map-pin\"></i>\n Points\n </span>\n </label>\n <label class=\"radio-option radio-option--compact\" [class.selected]=\"mapRenderMode === 'choropleth'\">\n <input type=\"radio\" name=\"mapRenderMode\" value=\"choropleth\"\n [(ngModel)]=\"mapRenderMode\" (change)=\"onOptionChange()\">\n <span class=\"radio-mark\"></span>\n <span class=\"radio-label\">\n <i class=\"fa-solid fa-earth-americas\"></i>\n Regions\n </span>\n </label>\n <label class=\"radio-option radio-option--compact\" [class.selected]=\"mapRenderMode === 'heatmap'\">\n <input type=\"radio\" name=\"mapRenderMode\" value=\"heatmap\"\n [(ngModel)]=\"mapRenderMode\" (change)=\"onOptionChange()\">\n <span class=\"radio-mark\"></span>\n <span class=\"radio-label\">\n <i class=\"fa-solid fa-fire\"></i>\n Heatmap\n </span>\n </label>\n </div>\n </div>\n }\n <!-- Selection Options -->\n <div class=\"form-group\">\n <div class=\"checkbox-group checkbox-group--compact\">\n <label class=\"checkbox-option checkbox-option--compact\">\n <input\n type=\"checkbox\"\n [(ngModel)]=\"allowModeSwitch\"\n (change)=\"onOptionChange()\">\n <span class=\"checkbox-mark\"></span>\n <span class=\"checkbox-label\">Allow Mode Switch</span>\n </label>\n <label class=\"checkbox-option checkbox-option--compact\">\n <input\n type=\"checkbox\"\n [(ngModel)]=\"enableSelection\"\n (change)=\"onOptionChange()\">\n <span class=\"checkbox-mark\"></span>\n <span class=\"checkbox-label\">Enable Selection</span>\n </label>\n </div>\n </div>\n <!-- Selection Mode -->\n @if (enableSelection) {\n <div class=\"form-group\">\n <label for=\"selectionMode\">Selection Mode</label>\n <select\n id=\"selectionMode\"\n class=\"form-select\"\n [(ngModel)]=\"selectionMode\"\n (change)=\"onSelectionModeChange()\">\n <option value=\"single\">Single Selection</option>\n <option value=\"multiple\">Multiple Selection</option>\n </select>\n </div>\n }\n </div>\n }\n </div>\n\n <!-- Advanced Options (Collapsible) -->\n <div class=\"collapsible-section\">\n <button\n type=\"button\"\n class=\"collapsible-header\"\n (click)=\"toggleAdvancedOptions()\"\n [attr.aria-expanded]=\"showAdvancedOptions\">\n <span class=\"collapsible-title\">\n <i class=\"fa-solid fa-filter\"></i>\n Advanced Filtering\n </span>\n <i class=\"collapsible-chevron fa-solid\"\n [class.fa-chevron-down]=\"!showAdvancedOptions\"\n [class.fa-chevron-up]=\"showAdvancedOptions\"></i>\n </button>\n\n @if (showAdvancedOptions) {\n <div class=\"collapsible-content\">\n <!-- Extra Filter -->\n <div class=\"form-group\">\n <label for=\"extraFilter\">\n Extra Filter\n </label>\n <input\n type=\"text\"\n id=\"extraFilter\"\n [(ngModel)]=\"extraFilter\"\n (input)=\"onFilterChange()\"\n placeholder=\"e.g., Status = 'Active'\"\n class=\"form-input\">\n <span class=\"form-hint\">\n SQL WHERE clause to filter records (applied in addition to view filters)\n </span>\n </div>\n </div>\n }\n </div>\n</div>\n"]}