@dataclouder/ngx-core 0.1.44 → 0.1.46

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.
@@ -1,5 +1,5 @@
1
1
  import * as i0 from '@angular/core';
2
- import { input, Component, inject, ChangeDetectionStrategy, output, Input, HostListener, ChangeDetectorRef, Injectable, Pipe, signal, effect, ViewChild, Directive, InjectionToken, computed, Optional, Inject } from '@angular/core';
2
+ import { input, Component, Injectable, inject, ChangeDetectionStrategy, output, Input, HostListener, ChangeDetectorRef, Pipe, signal, effect, ViewChild, Directive, InjectionToken, computed, Optional, Inject } from '@angular/core';
3
3
  import * as i1 from '@angular/forms';
4
4
  import { FormBuilder, FormsModule, ReactiveFormsModule, FormControl, ControlContainer, FormGroup, FormArray } from '@angular/forms';
5
5
  import * as i2 from 'primeng/button';
@@ -8,15 +8,15 @@ import * as i3$1 from 'primeng/dialog';
8
8
  import { DialogModule } from 'primeng/dialog';
9
9
  import * as i4$1 from 'primeng/inputtext';
10
10
  import { InputTextModule } from 'primeng/inputtext';
11
- import * as i5$1 from 'primeng/inputgroup';
11
+ import * as i5 from 'primeng/inputgroup';
12
12
  import { InputGroupModule } from 'primeng/inputgroup';
13
13
  import { InputGroupAddonModule } from 'primeng/inputgroupaddon';
14
14
  import { DynamicDialogRef, DynamicDialogConfig, DialogService } from 'primeng/dynamicdialog';
15
15
  import * as i3 from 'primeng/select';
16
16
  import { SelectModule } from 'primeng/select';
17
- import * as i4 from 'primeng/multiselect';
17
+ import * as i8 from 'primeng/multiselect';
18
18
  import { MultiSelectModule } from 'primeng/multiselect';
19
- import * as i5 from 'primeng/datepicker';
19
+ import * as i4 from 'primeng/datepicker';
20
20
  import { DatePickerModule } from 'primeng/datepicker';
21
21
  import * as i2$1 from 'primeng/message';
22
22
  import { MessageModule } from 'primeng/message';
@@ -89,6 +89,7 @@ const sortOptions = [
89
89
  { label: 'Más antiguo', value: OptionValue.Oldest },
90
90
  { label: 'A-Z', value: OptionValue.Alphabetical },
91
91
  { label: 'Z-A', value: OptionValue.ReverseAlphabetical },
92
+ { label: 'Última actualización', value: 'lastUpdated' },
92
93
  ];
93
94
  const sortTypes = [
94
95
  { name: 'Recientes', code: 'newest', sort: { createdDate: -1 } },
@@ -96,63 +97,208 @@ const sortTypes = [
96
97
  { name: 'Populares', code: 'popular', sort: { takenCount: -1 } },
97
98
  ];
98
99
 
100
+ class FilterService {
101
+ constructor() {
102
+ this.STORAGE_PREFIX = 'dc_filter_state_';
103
+ }
104
+ /**
105
+ * Saves the UI state of the filters to localStorage.
106
+ * @param key Unique key for the component/list
107
+ * @param state The UI state object (form values)
108
+ */
109
+ saveState(key, state) {
110
+ try {
111
+ localStorage.setItem(`${this.STORAGE_PREFIX}${key}`, JSON.stringify(state));
112
+ }
113
+ catch (e) {
114
+ console.error('Error saving filter state', e);
115
+ }
116
+ }
117
+ /**
118
+ * Loads the UI state of the filters from localStorage.
119
+ * @param key Unique key for the component/list
120
+ * @returns The UI state object or null if not found
121
+ */
122
+ loadState(key) {
123
+ try {
124
+ const item = localStorage.getItem(`${this.STORAGE_PREFIX}${key}`);
125
+ return item ? JSON.parse(item) : null;
126
+ }
127
+ catch (e) {
128
+ console.error('Error loading filter state', e);
129
+ return null;
130
+ }
131
+ }
132
+ /**
133
+ * Builds a MongoDB-compatible query object from the UI filter values and definitions.
134
+ * @param uiFilters The raw values from the form
135
+ * @param customFilters The definitions of the filters
136
+ * @returns A MongoDB query object
137
+ */
138
+ buildQuery(uiFilters, customFilters) {
139
+ const query = {};
140
+ for (const filterDef of customFilters) {
141
+ const value = uiFilters[filterDef.field];
142
+ // Skip empty values
143
+ if (value === null || value === undefined || value === '' || (Array.isArray(value) && value.length === 0)) {
144
+ continue;
145
+ }
146
+ // Use defined operator or infer from type
147
+ const operator = filterDef.operator || this.inferOperator(filterDef.type);
148
+ switch (operator) {
149
+ case '$eq':
150
+ query[filterDef.field] = value;
151
+ break;
152
+ case '$ne':
153
+ query[filterDef.field] = { $ne: value };
154
+ break;
155
+ case '$regex':
156
+ query[filterDef.field] = { $regex: value, $options: 'i' };
157
+ break;
158
+ case '$in':
159
+ query[filterDef.field] = { $in: Array.isArray(value) ? value : [value] };
160
+ break;
161
+ case '$nin':
162
+ query[filterDef.field] = { $nin: Array.isArray(value) ? value : [value] };
163
+ break;
164
+ case '$gt':
165
+ query[filterDef.field] = { $gt: value };
166
+ break;
167
+ case '$gte':
168
+ query[filterDef.field] = { $gte: value };
169
+ break;
170
+ case '$lt':
171
+ query[filterDef.field] = { $lt: value };
172
+ break;
173
+ case '$lte':
174
+ query[filterDef.field] = { $lte: value };
175
+ break;
176
+ case 'range':
177
+ if (Array.isArray(value) && value.length === 2 && value[0] && value[1]) {
178
+ query[filterDef.field] = { $gte: value[0], $lte: value[1] };
179
+ }
180
+ break;
181
+ default:
182
+ // Default fallback
183
+ query[filterDef.field] = value;
184
+ }
185
+ }
186
+ return query;
187
+ }
188
+ inferOperator(type) {
189
+ switch (type) {
190
+ case 'string':
191
+ return '$regex';
192
+ case 'select':
193
+ case 'boolean':
194
+ case 'number':
195
+ return '$eq';
196
+ case 'multi-select':
197
+ return '$in';
198
+ case 'date':
199
+ return 'range'; // Assuming date picker returns a range usually, or exact match if single
200
+ default:
201
+ return '$eq';
202
+ }
203
+ }
204
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.1.6", ngImport: i0, type: FilterService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
205
+ static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.1.6", ngImport: i0, type: FilterService, providedIn: 'root' }); }
206
+ }
207
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.1.6", ngImport: i0, type: FilterService, decorators: [{
208
+ type: Injectable,
209
+ args: [{
210
+ providedIn: 'root',
211
+ }]
212
+ }] });
213
+
99
214
  class DcListFilterDialogComponent {
100
215
  constructor() {
101
216
  this.fb = inject(FormBuilder);
217
+ this.filterService = inject(FilterService);
102
218
  this.ref = inject(DynamicDialogRef);
103
219
  this.config = inject(DynamicDialogConfig);
104
220
  this.customFilters = this.config.data.customFilters || [];
221
+ this.initialUiState = this.config.data.uiState || {};
105
222
  this.availibleFilters = availibleFilters;
106
223
  this.sortOptions = sortOptions;
107
224
  this.selectedFilters = [];
108
225
  this.selectedSort = null;
109
226
  this.dateRange = [];
110
227
  this.buildCustomFiltersForm();
228
+ this.restoreState();
111
229
  }
112
230
  buildCustomFiltersForm() {
231
+ debugger;
113
232
  const formControls = {};
114
233
  for (const filter of this.customFilters) {
115
234
  formControls[filter.field] = [filter.defaultValue || null];
116
235
  }
117
236
  this.customFiltersForm = this.fb.group(formControls);
118
237
  }
238
+ restoreState() {
239
+ if (this.initialUiState) {
240
+ if (this.initialUiState.customFilters) {
241
+ this.customFiltersForm.patchValue(this.initialUiState.customFilters);
242
+ }
243
+ if (this.initialUiState.sort) {
244
+ this.selectedSort = this.initialUiState.sort;
245
+ }
246
+ if (this.initialUiState.dateRange) {
247
+ // Ensure dates are Date objects
248
+ this.dateRange = this.initialUiState.dateRange.map((d) => new Date(d));
249
+ }
250
+ if (this.initialUiState.quickFilters) {
251
+ this.selectedFilters = this.initialUiState.quickFilters;
252
+ }
253
+ }
254
+ }
119
255
  clearFilters() {
120
256
  this.ref.close({ action: 'clear' });
121
257
  }
122
258
  applyFilters() {
123
259
  const customFilterValues = this.customFiltersForm.value;
124
- const activeFilters = Object.entries(customFilterValues).reduce((acc, [key, value]) => {
125
- if (value !== null && value !== undefined && value !== '') {
126
- acc[key] = value;
127
- }
128
- return acc;
129
- }, {});
260
+ // Build MongoDB Query
261
+ const mongoQuery = this.filterService.buildQuery(customFilterValues, this.customFilters);
262
+ // Add Date Range to Query
263
+ if (this.dateRange && this.dateRange.length === 2 && this.dateRange[0] && this.dateRange[1]) {
264
+ mongoQuery['createdAt'] = { $gte: this.dateRange[0], $lte: this.dateRange[1] };
265
+ }
266
+ // Capture UI State for persistence
267
+ const uiState = {
268
+ customFilters: customFilterValues,
269
+ sort: this.selectedSort,
270
+ dateRange: this.dateRange,
271
+ quickFilters: this.selectedFilters,
272
+ };
130
273
  this.ref.close({
131
274
  action: 'apply',
132
- filters: activeFilters,
275
+ filters: mongoQuery, // The actual query for the backend
276
+ uiState: uiState, // The state to save for the UI
133
277
  sort: this.selectedSort,
134
278
  dateRange: this.dateRange,
135
279
  quickFilters: this.selectedFilters,
136
280
  });
137
281
  }
138
282
  static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.1.6", ngImport: i0, type: DcListFilterDialogComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
139
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.1.6", type: DcListFilterDialogComponent, isStandalone: true, selector: "dc-list-filter-dialog", ngImport: i0, template: "<div class=\"filter-dialog-content flex flex-col justify-between h-full\">\n <!-- Filters Content -->\n <div>\n <!-- Sort Options -->\n <div class=\"field\">\n <label class=\"font-semibold block mb-2\">Ordenar por</label>\n <p-select [options]=\"sortOptions\" [(ngModel)]=\"selectedSort\" optionLabel=\"label\" [style]=\"{ width: '100%' }\" placeholder=\"Seleccionar orden\"> </p-select>\n </div>\n\n <p-multiselect [options]=\"availibleFilters\" [(ngModel)]=\"selectedFilters\" optionLabel=\"name\" placeholder=\"Filtros R\u00E1pidos\" [maxSelectedLabels]=\"3\" />\n\n <!-- Date Filter -->\n <div class=\"field\">\n <label class=\"font-semibold block mb-2\">Rango de fechas</label>\n <p-datepicker\n [(ngModel)]=\"dateRange\"\n selectionMode=\"range\"\n [showButtonBar]=\"true\"\n [style]=\"{ width: '100%' }\"\n placeholder=\"Seleccionar fechas\"\n dateFormat=\"dd/mm/yy\">\n </p-datepicker>\n </div>\n\n @if (customFilters?.length > 0) {\n <form [formGroup]=\"customFiltersForm\">\n <h4>Filtros Personalizados</h4>\n @for (customFilter of customFilters; track customFilter.field) {\n <div class=\"field\">\n <label class=\"font-semibold block mb-2\">{{ customFilter.name }}</label>\n @switch (customFilter.type) { @case ('select') {\n <p-select\n [options]=\"customFilter.options\"\n [formControlName]=\"customFilter.field\"\n optionLabel=\"label\"\n optionValue=\"value\"\n [style]=\"{ width: '100%' }\"\n placeholder=\"Seleccionar {{ customFilter.name }}\" />\n } @case ('string') {\n <input type=\"text\" pInputText [formControlName]=\"customFilter.field\" class=\"w-full\" />\n } @case ('date') {\n <p-datepicker [formControlName]=\"customFilter.field\" [style]=\"{ width: '100%' }\" dateFormat=\"dd/mm/yy\"></p-datepicker>\n } }\n </div>\n }\n </form>\n }\n </div>\n\n <!-- Action Buttons -->\n <div>\n <div class=\"flex justify-end gap-2\">\n <p-button label=\"Limpiar\" icon=\"pi pi-trash\" (click)=\"clearFilters()\" styleClass=\"p-button-text\"> </p-button>\n <p-button label=\"Aplicar\" icon=\"pi pi-check\" (click)=\"applyFilters()\" severity=\"primary\"> </p-button>\n </div>\n </div>\n</div>\n", styles: [":host ::ng-deep .filter-dialog-content{display:flex;flex-direction:column;gap:1.5rem;padding:1.5rem}\n"], dependencies: [{ kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i1.ɵNgNoValidate, selector: "form:not([ngNoForm]):not([ngNativeValidate])" }, { kind: "directive", type: i1.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { kind: "directive", type: i1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]" }, { kind: "directive", type: i1.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "ngmodule", type: ReactiveFormsModule }, { kind: "directive", type: i1.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { kind: "directive", type: i1.FormControlName, selector: "[formControlName]", inputs: ["formControlName", "disabled", "ngModel"], outputs: ["ngModelChange"] }, { kind: "ngmodule", type: ButtonModule }, { kind: "component", type: i2.Button, selector: "p-button", inputs: ["type", "iconPos", "icon", "badge", "label", "disabled", "loading", "loadingIcon", "raised", "rounded", "text", "plain", "severity", "outlined", "link", "tabindex", "size", "variant", "style", "styleClass", "badgeClass", "badgeSeverity", "ariaLabel", "buttonProps", "autofocus", "fluid"], outputs: ["onClick", "onFocus", "onBlur"] }, { kind: "ngmodule", type: DialogModule }, { kind: "ngmodule", type: SelectModule }, { kind: "component", type: i3.Select, selector: "p-select", inputs: ["id", "scrollHeight", "filter", "panelStyle", "styleClass", "panelStyleClass", "readonly", "editable", "tabindex", "placeholder", "loadingIcon", "filterPlaceholder", "filterLocale", "inputId", "dataKey", "filterBy", "filterFields", "autofocus", "resetFilterOnHide", "checkmark", "dropdownIcon", "loading", "optionLabel", "optionValue", "optionDisabled", "optionGroupLabel", "optionGroupChildren", "group", "showClear", "emptyFilterMessage", "emptyMessage", "lazy", "virtualScroll", "virtualScrollItemSize", "virtualScrollOptions", "overlayOptions", "ariaFilterLabel", "ariaLabel", "ariaLabelledBy", "filterMatchMode", "tooltip", "tooltipPosition", "tooltipPositionStyle", "tooltipStyleClass", "focusOnHover", "selectOnFocus", "autoOptionFocus", "autofocusFilter", "filterValue", "options", "appendTo"], outputs: ["onChange", "onFilter", "onFocus", "onBlur", "onClick", "onShow", "onHide", "onClear", "onLazyLoad"] }, { kind: "ngmodule", type: MultiSelectModule }, { kind: "component", type: i4.MultiSelect, selector: "p-multiSelect, p-multiselect, p-multi-select", inputs: ["id", "ariaLabel", "styleClass", "panelStyle", "panelStyleClass", "inputId", "readonly", "group", "filter", "filterPlaceHolder", "filterLocale", "overlayVisible", "tabindex", "dataKey", "ariaLabelledBy", "displaySelectedLabel", "maxSelectedLabels", "selectionLimit", "selectedItemsLabel", "showToggleAll", "emptyFilterMessage", "emptyMessage", "resetFilterOnHide", "dropdownIcon", "chipIcon", "optionLabel", "optionValue", "optionDisabled", "optionGroupLabel", "optionGroupChildren", "showHeader", "filterBy", "scrollHeight", "lazy", "virtualScroll", "loading", "virtualScrollItemSize", "loadingIcon", "virtualScrollOptions", "overlayOptions", "ariaFilterLabel", "filterMatchMode", "tooltip", "tooltipPosition", "tooltipPositionStyle", "tooltipStyleClass", "autofocusFilter", "display", "autocomplete", "showClear", "autofocus", "placeholder", "options", "filterValue", "selectAll", "focusOnHover", "filterFields", "selectOnFocus", "autoOptionFocus", "highlightOnSelect", "size", "variant", "fluid", "appendTo"], outputs: ["onChange", "onFilter", "onFocus", "onBlur", "onClick", "onClear", "onPanelShow", "onPanelHide", "onLazyLoad", "onRemove", "onSelectAllChange"] }, { kind: "ngmodule", type: DatePickerModule }, { kind: "component", type: i5.DatePicker, selector: "p-datePicker, p-datepicker, p-date-picker", inputs: ["iconDisplay", "styleClass", "inputStyle", "inputId", "inputStyleClass", "placeholder", "ariaLabelledBy", "ariaLabel", "iconAriaLabel", "dateFormat", "multipleSeparator", "rangeSeparator", "inline", "showOtherMonths", "selectOtherMonths", "showIcon", "icon", "readonlyInput", "shortYearCutoff", "hourFormat", "timeOnly", "stepHour", "stepMinute", "stepSecond", "showSeconds", "showOnFocus", "showWeek", "startWeekFromFirstDayOfYear", "showClear", "dataType", "selectionMode", "maxDateCount", "showButtonBar", "todayButtonStyleClass", "clearButtonStyleClass", "autofocus", "autoZIndex", "baseZIndex", "panelStyleClass", "panelStyle", "keepInvalid", "hideOnDateTimeSelect", "touchUI", "timeSeparator", "focusTrap", "showTransitionOptions", "hideTransitionOptions", "tabindex", "minDate", "maxDate", "disabledDates", "disabledDays", "showTime", "responsiveOptions", "numberOfMonths", "firstDayOfWeek", "view", "defaultDate", "appendTo"], outputs: ["onFocus", "onBlur", "onClose", "onSelect", "onClear", "onInput", "onTodayClick", "onClearClick", "onMonthChange", "onYearChange", "onClickOutside", "onShow"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
283
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.1.6", type: DcListFilterDialogComponent, isStandalone: true, selector: "dc-list-filter-dialog", ngImport: i0, template: "<div class=\"filter-dialog-content flex flex-col justify-between h-full\">\n <!-- Filters Content -->\n <div>\n <!-- Sort Options -->\n <div class=\"field\">\n <label class=\"font-semibold block mb-2\">Ordenar por</label>\n <p-select [options]=\"sortOptions\" [(ngModel)]=\"selectedSort\" optionLabel=\"label\" [style]=\"{ width: '100%' }\" placeholder=\"Seleccionar orden\"> </p-select>\n </div>\n\n <!-- <p-multiselect [options]=\"availibleFilters\" [(ngModel)]=\"selectedFilters\" optionLabel=\"name\" placeholder=\"Filtros R\u00E1pidos\" [maxSelectedLabels]=\"3\" /> -->\n\n <!-- Date Filter -->\n <div class=\"field\">\n <label class=\"font-semibold block mb-2\">Rango de fechas</label>\n <p-datepicker\n [(ngModel)]=\"dateRange\"\n selectionMode=\"range\"\n [showButtonBar]=\"true\"\n [style]=\"{ width: '100%' }\"\n placeholder=\"Seleccionar fechas\"\n dateFormat=\"dd/mm/yy\">\n </p-datepicker>\n </div>\n\n @if (customFilters?.length > 0) {\n <form [formGroup]=\"customFiltersForm\">\n <h4>Filtros Personalizados</h4>\n @for (customFilter of customFilters; track customFilter.field) {\n <div class=\"field\">\n <label class=\"font-semibold block mb-2\">{{ customFilter.name }}</label>\n @switch (customFilter.type) { @case ('select') {\n <p-select\n [options]=\"customFilter.options\"\n [formControlName]=\"customFilter.field\"\n optionLabel=\"label\"\n optionValue=\"value\"\n [style]=\"{ width: '100%' }\"\n placeholder=\"Seleccionar {{ customFilter.name }}\" />\n } @case ('string') {\n <input type=\"text\" pInputText [formControlName]=\"customFilter.field\" class=\"w-full\" />\n } @case ('date') {\n <p-datepicker [formControlName]=\"customFilter.field\" [style]=\"{ width: '100%' }\" dateFormat=\"dd/mm/yy\"></p-datepicker>\n } }\n </div>\n }\n </form>\n }\n </div>\n\n <!-- Action Buttons -->\n <div>\n <div class=\"flex justify-end gap-2\">\n <p-button label=\"Limpiar\" icon=\"pi pi-trash\" (click)=\"clearFilters()\" styleClass=\"p-button-text\"> </p-button>\n <p-button label=\"Aplicar\" icon=\"pi pi-check\" (click)=\"applyFilters()\" severity=\"primary\"> </p-button>\n </div>\n </div>\n</div>\n", styles: [":host ::ng-deep .filter-dialog-content{display:flex;flex-direction:column;gap:1.5rem;padding:1.5rem}\n"], dependencies: [{ kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i1.ɵNgNoValidate, selector: "form:not([ngNoForm]):not([ngNativeValidate])" }, { kind: "directive", type: i1.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { kind: "directive", type: i1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]" }, { kind: "directive", type: i1.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "ngmodule", type: ReactiveFormsModule }, { kind: "directive", type: i1.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { kind: "directive", type: i1.FormControlName, selector: "[formControlName]", inputs: ["formControlName", "disabled", "ngModel"], outputs: ["ngModelChange"] }, { kind: "ngmodule", type: ButtonModule }, { kind: "component", type: i2.Button, selector: "p-button", inputs: ["type", "iconPos", "icon", "badge", "label", "disabled", "loading", "loadingIcon", "raised", "rounded", "text", "plain", "severity", "outlined", "link", "tabindex", "size", "variant", "style", "styleClass", "badgeClass", "badgeSeverity", "ariaLabel", "buttonProps", "autofocus", "fluid"], outputs: ["onClick", "onFocus", "onBlur"] }, { kind: "ngmodule", type: DialogModule }, { kind: "ngmodule", type: SelectModule }, { kind: "component", type: i3.Select, selector: "p-select", inputs: ["id", "scrollHeight", "filter", "panelStyle", "styleClass", "panelStyleClass", "readonly", "editable", "tabindex", "placeholder", "loadingIcon", "filterPlaceholder", "filterLocale", "inputId", "dataKey", "filterBy", "filterFields", "autofocus", "resetFilterOnHide", "checkmark", "dropdownIcon", "loading", "optionLabel", "optionValue", "optionDisabled", "optionGroupLabel", "optionGroupChildren", "group", "showClear", "emptyFilterMessage", "emptyMessage", "lazy", "virtualScroll", "virtualScrollItemSize", "virtualScrollOptions", "overlayOptions", "ariaFilterLabel", "ariaLabel", "ariaLabelledBy", "filterMatchMode", "tooltip", "tooltipPosition", "tooltipPositionStyle", "tooltipStyleClass", "focusOnHover", "selectOnFocus", "autoOptionFocus", "autofocusFilter", "filterValue", "options", "appendTo"], outputs: ["onChange", "onFilter", "onFocus", "onBlur", "onClick", "onShow", "onHide", "onClear", "onLazyLoad"] }, { kind: "ngmodule", type: MultiSelectModule }, { kind: "ngmodule", type: DatePickerModule }, { kind: "component", type: i4.DatePicker, selector: "p-datePicker, p-datepicker, p-date-picker", inputs: ["iconDisplay", "styleClass", "inputStyle", "inputId", "inputStyleClass", "placeholder", "ariaLabelledBy", "ariaLabel", "iconAriaLabel", "dateFormat", "multipleSeparator", "rangeSeparator", "inline", "showOtherMonths", "selectOtherMonths", "showIcon", "icon", "readonlyInput", "shortYearCutoff", "hourFormat", "timeOnly", "stepHour", "stepMinute", "stepSecond", "showSeconds", "showOnFocus", "showWeek", "startWeekFromFirstDayOfYear", "showClear", "dataType", "selectionMode", "maxDateCount", "showButtonBar", "todayButtonStyleClass", "clearButtonStyleClass", "autofocus", "autoZIndex", "baseZIndex", "panelStyleClass", "panelStyle", "keepInvalid", "hideOnDateTimeSelect", "touchUI", "timeSeparator", "focusTrap", "showTransitionOptions", "hideTransitionOptions", "tabindex", "minDate", "maxDate", "disabledDates", "disabledDays", "showTime", "responsiveOptions", "numberOfMonths", "firstDayOfWeek", "view", "defaultDate", "appendTo"], outputs: ["onFocus", "onBlur", "onClose", "onSelect", "onClear", "onInput", "onTodayClick", "onClearClick", "onMonthChange", "onYearChange", "onClickOutside", "onShow"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
140
284
  }
141
285
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.1.6", ngImport: i0, type: DcListFilterDialogComponent, decorators: [{
142
286
  type: Component,
143
- args: [{ selector: 'dc-list-filter-dialog', standalone: true, imports: [FormsModule, ReactiveFormsModule, ButtonModule, DialogModule, SelectModule, MultiSelectModule, DatePickerModule], changeDetection: ChangeDetectionStrategy.OnPush, template: "<div class=\"filter-dialog-content flex flex-col justify-between h-full\">\n <!-- Filters Content -->\n <div>\n <!-- Sort Options -->\n <div class=\"field\">\n <label class=\"font-semibold block mb-2\">Ordenar por</label>\n <p-select [options]=\"sortOptions\" [(ngModel)]=\"selectedSort\" optionLabel=\"label\" [style]=\"{ width: '100%' }\" placeholder=\"Seleccionar orden\"> </p-select>\n </div>\n\n <p-multiselect [options]=\"availibleFilters\" [(ngModel)]=\"selectedFilters\" optionLabel=\"name\" placeholder=\"Filtros R\u00E1pidos\" [maxSelectedLabels]=\"3\" />\n\n <!-- Date Filter -->\n <div class=\"field\">\n <label class=\"font-semibold block mb-2\">Rango de fechas</label>\n <p-datepicker\n [(ngModel)]=\"dateRange\"\n selectionMode=\"range\"\n [showButtonBar]=\"true\"\n [style]=\"{ width: '100%' }\"\n placeholder=\"Seleccionar fechas\"\n dateFormat=\"dd/mm/yy\">\n </p-datepicker>\n </div>\n\n @if (customFilters?.length > 0) {\n <form [formGroup]=\"customFiltersForm\">\n <h4>Filtros Personalizados</h4>\n @for (customFilter of customFilters; track customFilter.field) {\n <div class=\"field\">\n <label class=\"font-semibold block mb-2\">{{ customFilter.name }}</label>\n @switch (customFilter.type) { @case ('select') {\n <p-select\n [options]=\"customFilter.options\"\n [formControlName]=\"customFilter.field\"\n optionLabel=\"label\"\n optionValue=\"value\"\n [style]=\"{ width: '100%' }\"\n placeholder=\"Seleccionar {{ customFilter.name }}\" />\n } @case ('string') {\n <input type=\"text\" pInputText [formControlName]=\"customFilter.field\" class=\"w-full\" />\n } @case ('date') {\n <p-datepicker [formControlName]=\"customFilter.field\" [style]=\"{ width: '100%' }\" dateFormat=\"dd/mm/yy\"></p-datepicker>\n } }\n </div>\n }\n </form>\n }\n </div>\n\n <!-- Action Buttons -->\n <div>\n <div class=\"flex justify-end gap-2\">\n <p-button label=\"Limpiar\" icon=\"pi pi-trash\" (click)=\"clearFilters()\" styleClass=\"p-button-text\"> </p-button>\n <p-button label=\"Aplicar\" icon=\"pi pi-check\" (click)=\"applyFilters()\" severity=\"primary\"> </p-button>\n </div>\n </div>\n</div>\n", styles: [":host ::ng-deep .filter-dialog-content{display:flex;flex-direction:column;gap:1.5rem;padding:1.5rem}\n"] }]
287
+ args: [{ selector: 'dc-list-filter-dialog', standalone: true, imports: [FormsModule, ReactiveFormsModule, ButtonModule, DialogModule, SelectModule, MultiSelectModule, DatePickerModule], changeDetection: ChangeDetectionStrategy.OnPush, template: "<div class=\"filter-dialog-content flex flex-col justify-between h-full\">\n <!-- Filters Content -->\n <div>\n <!-- Sort Options -->\n <div class=\"field\">\n <label class=\"font-semibold block mb-2\">Ordenar por</label>\n <p-select [options]=\"sortOptions\" [(ngModel)]=\"selectedSort\" optionLabel=\"label\" [style]=\"{ width: '100%' }\" placeholder=\"Seleccionar orden\"> </p-select>\n </div>\n\n <!-- <p-multiselect [options]=\"availibleFilters\" [(ngModel)]=\"selectedFilters\" optionLabel=\"name\" placeholder=\"Filtros R\u00E1pidos\" [maxSelectedLabels]=\"3\" /> -->\n\n <!-- Date Filter -->\n <div class=\"field\">\n <label class=\"font-semibold block mb-2\">Rango de fechas</label>\n <p-datepicker\n [(ngModel)]=\"dateRange\"\n selectionMode=\"range\"\n [showButtonBar]=\"true\"\n [style]=\"{ width: '100%' }\"\n placeholder=\"Seleccionar fechas\"\n dateFormat=\"dd/mm/yy\">\n </p-datepicker>\n </div>\n\n @if (customFilters?.length > 0) {\n <form [formGroup]=\"customFiltersForm\">\n <h4>Filtros Personalizados</h4>\n @for (customFilter of customFilters; track customFilter.field) {\n <div class=\"field\">\n <label class=\"font-semibold block mb-2\">{{ customFilter.name }}</label>\n @switch (customFilter.type) { @case ('select') {\n <p-select\n [options]=\"customFilter.options\"\n [formControlName]=\"customFilter.field\"\n optionLabel=\"label\"\n optionValue=\"value\"\n [style]=\"{ width: '100%' }\"\n placeholder=\"Seleccionar {{ customFilter.name }}\" />\n } @case ('string') {\n <input type=\"text\" pInputText [formControlName]=\"customFilter.field\" class=\"w-full\" />\n } @case ('date') {\n <p-datepicker [formControlName]=\"customFilter.field\" [style]=\"{ width: '100%' }\" dateFormat=\"dd/mm/yy\"></p-datepicker>\n } }\n </div>\n }\n </form>\n }\n </div>\n\n <!-- Action Buttons -->\n <div>\n <div class=\"flex justify-end gap-2\">\n <p-button label=\"Limpiar\" icon=\"pi pi-trash\" (click)=\"clearFilters()\" styleClass=\"p-button-text\"> </p-button>\n <p-button label=\"Aplicar\" icon=\"pi pi-check\" (click)=\"applyFilters()\" severity=\"primary\"> </p-button>\n </div>\n </div>\n</div>\n", styles: [":host ::ng-deep .filter-dialog-content{display:flex;flex-direction:column;gap:1.5rem;padding:1.5rem}\n"] }]
144
288
  }], ctorParameters: () => [] });
145
289
 
146
290
  const DEFAULT_FILTERS = { filters: {}, page: 0, rowsPerPage: 10, sort: { _id: -1 } };
147
291
  class DCFilterBarComponent {
148
292
  constructor() {
149
293
  this.dialogService = inject(DialogService);
294
+ this.filterService = inject(FilterService);
150
295
  // Signal Inputs
151
296
  this.items = input([], ...(ngDevMode ? [{ debugName: "items" }] : []));
152
297
  this.options = input({ showCreateButton: true }, ...(ngDevMode ? [{ debugName: "options" }] : []));
153
298
  // Inputs
154
299
  this.customFilters = [];
155
300
  this.isAdmin = false;
301
+ this.persistenceKey = ''; // Key for saving/loading filters
156
302
  // Outputs
157
303
  this.onFilterAction = output();
158
304
  this.onNew = output();
@@ -160,6 +306,29 @@ class DCFilterBarComponent {
160
306
  this.isSearchVisible = false;
161
307
  this.placeholder = '';
162
308
  this.filter = { ...DEFAULT_FILTERS };
309
+ this.uiState = null; // Store UI state separately
310
+ }
311
+ ngOnInit() {
312
+ // debugger;
313
+ if (this.persistenceKey) {
314
+ this.loadSavedFilters();
315
+ }
316
+ }
317
+ loadSavedFilters() {
318
+ const savedState = this.filterService.loadState(this.persistenceKey);
319
+ if (savedState) {
320
+ this.uiState = savedState;
321
+ // Re-construct the query from the saved UI state
322
+ if (savedState.customFilters) {
323
+ const mongoQuery = this.filterService.buildQuery(savedState.customFilters, this.customFilters);
324
+ this.filter = { ...this.filter, filters: mongoQuery };
325
+ // Emit initial filter change so the list loads with these filters
326
+ // We use setTimeout to ensure the parent component is ready
327
+ setTimeout(() => {
328
+ this.doItemAction({ action: 'filterChange', item: this.filter });
329
+ });
330
+ }
331
+ }
163
332
  }
164
333
  createNew() {
165
334
  this.onNew.emit('new');
@@ -180,7 +349,10 @@ class DCFilterBarComponent {
180
349
  width: '70vw',
181
350
  height: '70vh',
182
351
  contentStyle: { 'max-height': '90vh', overflow: 'auto', 'min-height': '500px', height: '100%' },
183
- data: { customFilters: this.customFilters },
352
+ data: {
353
+ customFilters: this.customFilters,
354
+ uiState: this.uiState, // Pass current UI state to dialog
355
+ },
184
356
  closable: true,
185
357
  modal: true,
186
358
  maximizable: true,
@@ -197,20 +369,51 @@ class DCFilterBarComponent {
197
369
  });
198
370
  }
199
371
  applyFilters(result) {
372
+ // result.filters is now the Mongo Query
200
373
  const newFilters = { ...this.filter.filters, ...result.filters };
201
- this.filter = { ...this.filter, filters: newFilters };
374
+ let newSort = this.filter.sort;
375
+ if (result.sort) {
376
+ switch (result.sort.value) {
377
+ case 'newest':
378
+ newSort = { createdAt: -1 };
379
+ break;
380
+ case 'oldest':
381
+ newSort = { createdAt: 1 };
382
+ break;
383
+ case 'alphabetical':
384
+ newSort = { name: 1 };
385
+ break;
386
+ case 'reverseAlphabetical':
387
+ newSort = { name: -1 };
388
+ break;
389
+ case 'lastUpdated':
390
+ newSort = { updatedAt: -1 };
391
+ break;
392
+ }
393
+ }
394
+ this.filter = { ...this.filter, filters: newFilters, sort: newSort };
395
+ // Update UI state
396
+ this.uiState = result.uiState;
397
+ // Save to persistence
398
+ if (this.persistenceKey && this.uiState) {
399
+ this.filterService.saveState(this.persistenceKey, this.uiState);
400
+ }
202
401
  // Handle other filter types from result if necessary (sort, dateRange, etc.)
203
402
  this.doItemAction({ action: 'filterChange', item: this.filter });
204
403
  }
205
404
  clearFilters() {
206
405
  this.filter = { ...DEFAULT_FILTERS };
406
+ this.uiState = null;
407
+ if (this.persistenceKey) {
408
+ this.filterService.saveState(this.persistenceKey, null);
409
+ }
207
410
  this.doItemAction({ action: 'filterChange', item: this.filter });
208
411
  }
209
412
  doItemAction(filterEvent) {
210
413
  this.onFilterAction.emit(filterEvent);
211
414
  }
212
415
  static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.1.6", ngImport: i0, type: DCFilterBarComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
213
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.1.6", type: DCFilterBarComponent, isStandalone: true, selector: "dc-filter-bar", inputs: { items: { classPropertyName: "items", publicName: "items", isSignal: true, isRequired: false, transformFunction: null }, options: { classPropertyName: "options", publicName: "options", isSignal: true, isRequired: false, transformFunction: null }, customFilters: { classPropertyName: "customFilters", publicName: "customFilters", isSignal: false, isRequired: false, transformFunction: null }, isAdmin: { classPropertyName: "isAdmin", publicName: "isAdmin", isSignal: false, isRequired: false, transformFunction: null } }, outputs: { onFilterAction: "onFilterAction", onNew: "onNew" }, providers: [DialogService], ngImport: i0, template: "<div class=\"background-bar\">\n <div class=\"button-flex\">\n <p-button icon=\"pi pi-search\" label=\"buscar\" severity=\"secondary\" (click)=\"isSearchVisible = true\" />\n\n @if (isAdmin) {\n <span class=\"admin\">\n <i style=\"position: absolute; right: -5px; top: -5px; z-index: 2; color: grey\" class=\"pi pi-key\"></i>\n <p-button icon=\"pi pi-plus\" label=\"Crear Nueva\" severity=\"secondary\" (click)=\"createNew()\" />\n </span>\n }\n </div>\n\n @if (isAdmin) {\n <p-button icon=\"pi pi-objects-column\" variant=\"text\" (click)=\"doItemAction({ action: 'changeView', item: null })\" severity=\"secondary\"></p-button>\n } @if(options()?.showActions){ @for(item of items(); track $index) {\n <p-button [icon]=\"item.icon\" variant=\"text\" (click)=\"doItemAction({ action: item.title, item: item })\" severity=\"secondary\"></p-button>\n } @if(isAdmin) {\n <div class=\"button-flex\">\n <p-button icon=\"pi pi-filter\" label=\"Filtrar\" severity=\"secondary\" (click)=\"openFilterDialog()\" />\n </div>\n } }\n</div>\n\n@if (placeholder) {\n<span class=\"search-flex\" (click)=\"search(null)\"> <i class=\"pi pi-times\"></i>{{ placeholder }} </span>\n}\n\n<p-dialog [(visible)]=\"isSearchVisible\" [dismissableMask]=\"true\" [modal]=\"true\" [showHeader]=\"false\" (onHide)=\"isSearchVisible = false\">\n <h4>Qu\u00E9 vamos a buscar? (Enter)</h4>\n <div>\n <p-inputgroup>\n <input (keydown.enter)=\"search(placeholder)\" type=\"text\" pInputText [(ngModel)]=\"placeholder\" />\n\n <p-button label=\"Buscar\" icon=\"pi pi-search\" (click)=\"search(placeholder)\" />\n </p-inputgroup>\n </div>\n</p-dialog>\n", styles: [":host{display:block}.admin{margin-left:10px;position:relative}.background-bar{background-color:var(--p-primary-color);display:flex;border-radius:10px;justify-content:space-between;padding:10px}.button-flex{display:flex;margin-right:10px}.white{color:#fff}.search-flex{margin-left:10px}.search-dialog{width:750px;-webkit-backdrop-filter:blur(70px);backdrop-filter:blur(70px)}.border-none{border:none}.bg-black-alpha-50{background-color:var(--p-primary-color)}\n"], dependencies: [{ kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i1.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { kind: "directive", type: i1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "ngmodule", type: ButtonModule }, { kind: "component", type: i2.Button, selector: "p-button", inputs: ["type", "iconPos", "icon", "badge", "label", "disabled", "loading", "loadingIcon", "raised", "rounded", "text", "plain", "severity", "outlined", "link", "tabindex", "size", "variant", "style", "styleClass", "badgeClass", "badgeSeverity", "ariaLabel", "buttonProps", "autofocus", "fluid"], outputs: ["onClick", "onFocus", "onBlur"] }, { kind: "ngmodule", type: DialogModule }, { kind: "component", type: i3$1.Dialog, selector: "p-dialog", inputs: ["header", "draggable", "resizable", "contentStyle", "contentStyleClass", "modal", "closeOnEscape", "dismissableMask", "rtl", "closable", "breakpoints", "styleClass", "maskStyleClass", "maskStyle", "showHeader", "blockScroll", "autoZIndex", "baseZIndex", "minX", "minY", "focusOnShow", "maximizable", "keepInViewport", "focusTrap", "transitionOptions", "closeIcon", "closeAriaLabel", "closeTabindex", "minimizeIcon", "maximizeIcon", "closeButtonProps", "maximizeButtonProps", "visible", "style", "position", "role", "appendTo", "content", "contentTemplate", "footerTemplate", "closeIconTemplate", "maximizeIconTemplate", "minimizeIconTemplate", "headlessTemplate"], outputs: ["onShow", "onHide", "visibleChange", "onResizeInit", "onResizeEnd", "onDragEnd", "onMaximize"] }, { kind: "ngmodule", type: InputTextModule }, { kind: "directive", type: i4$1.InputText, selector: "[pInputText]", inputs: ["pSize", "variant", "fluid", "invalid"] }, { kind: "ngmodule", type: InputGroupModule }, { kind: "component", type: i5$1.InputGroup, selector: "p-inputgroup, p-inputGroup, p-input-group", inputs: ["styleClass"] }, { kind: "ngmodule", type: InputGroupAddonModule }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
416
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.1.6", type: DCFilterBarComponent, isStandalone: true, selector: "dc-filter-bar", inputs: { items: { classPropertyName: "items", publicName: "items", isSignal: true, isRequired: false, transformFunction: null }, options: { classPropertyName: "options", publicName: "options", isSignal: true, isRequired: false, transformFunction: null }, customFilters: { classPropertyName: "customFilters", publicName: "customFilters", isSignal: false, isRequired: false, transformFunction: null }, isAdmin: { classPropertyName: "isAdmin", publicName: "isAdmin", isSignal: false, isRequired: false, transformFunction: null }, persistenceKey: { classPropertyName: "persistenceKey", publicName: "persistenceKey", isSignal: false, isRequired: false, transformFunction: null } }, outputs: { onFilterAction: "onFilterAction", onNew: "onNew" }, providers: [DialogService], ngImport: i0, template: "<div class=\"background-bar\">\n <div class=\"button-flex\">\n <p-button icon=\"pi pi-search\" label=\"buscar\" severity=\"secondary\" (click)=\"isSearchVisible = true\" />\n\n @if (isAdmin) {\n <span class=\"admin\">\n <i style=\"position: absolute; right: -5px; top: -5px; z-index: 2; color: grey\" class=\"pi pi-key\"></i>\n <p-button icon=\"pi pi-plus\" label=\"Crear Nueva\" severity=\"secondary\" (click)=\"createNew()\" />\n </span>\n }\n </div>\n\n @if (isAdmin) {\n <p-button icon=\"pi pi-objects-column\" variant=\"text\" (click)=\"doItemAction({ action: 'changeView', item: null })\" severity=\"secondary\"></p-button>\n } @if(options()?.showActions){ @for(item of items(); track $index) {\n <p-button [icon]=\"item.icon\" variant=\"text\" (click)=\"doItemAction({ action: item.title, item: item })\" severity=\"secondary\"></p-button>\n } @if(isAdmin) {\n <div class=\"button-flex\">\n <p-button icon=\"pi pi-filter\" label=\"Filtrar\" severity=\"secondary\" (click)=\"openFilterDialog()\" />\n </div>\n } }\n</div>\n\n@if (placeholder) {\n<span class=\"search-flex\" (click)=\"search(null)\"> <i class=\"pi pi-times\"></i>{{ placeholder }} </span>\n}\n\n<p-dialog [(visible)]=\"isSearchVisible\" [dismissableMask]=\"true\" [modal]=\"true\" [showHeader]=\"false\" (onHide)=\"isSearchVisible = false\">\n <h4>Qu\u00E9 vamos a buscar? (Enter)</h4>\n <div>\n <p-inputgroup>\n <input (keydown.enter)=\"search(placeholder)\" type=\"text\" pInputText [(ngModel)]=\"placeholder\" />\n\n <p-button label=\"Buscar\" icon=\"pi pi-search\" (click)=\"search(placeholder)\" />\n </p-inputgroup>\n </div>\n</p-dialog>\n", styles: [":host{display:block}.admin{margin-left:10px;position:relative}.background-bar{background-color:var(--p-primary-color);display:flex;border-radius:10px;justify-content:space-between;padding:10px}.button-flex{display:flex;margin-right:10px}.white{color:#fff}.search-flex{margin-left:10px}.search-dialog{width:750px;-webkit-backdrop-filter:blur(70px);backdrop-filter:blur(70px)}.border-none{border:none}.bg-black-alpha-50{background-color:var(--p-primary-color)}\n"], dependencies: [{ kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i1.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { kind: "directive", type: i1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "ngmodule", type: ButtonModule }, { kind: "component", type: i2.Button, selector: "p-button", inputs: ["type", "iconPos", "icon", "badge", "label", "disabled", "loading", "loadingIcon", "raised", "rounded", "text", "plain", "severity", "outlined", "link", "tabindex", "size", "variant", "style", "styleClass", "badgeClass", "badgeSeverity", "ariaLabel", "buttonProps", "autofocus", "fluid"], outputs: ["onClick", "onFocus", "onBlur"] }, { kind: "ngmodule", type: DialogModule }, { kind: "component", type: i3$1.Dialog, selector: "p-dialog", inputs: ["header", "draggable", "resizable", "contentStyle", "contentStyleClass", "modal", "closeOnEscape", "dismissableMask", "rtl", "closable", "breakpoints", "styleClass", "maskStyleClass", "maskStyle", "showHeader", "blockScroll", "autoZIndex", "baseZIndex", "minX", "minY", "focusOnShow", "maximizable", "keepInViewport", "focusTrap", "transitionOptions", "closeIcon", "closeAriaLabel", "closeTabindex", "minimizeIcon", "maximizeIcon", "closeButtonProps", "maximizeButtonProps", "visible", "style", "position", "role", "appendTo", "content", "contentTemplate", "footerTemplate", "closeIconTemplate", "maximizeIconTemplate", "minimizeIconTemplate", "headlessTemplate"], outputs: ["onShow", "onHide", "visibleChange", "onResizeInit", "onResizeEnd", "onDragEnd", "onMaximize"] }, { kind: "ngmodule", type: InputTextModule }, { kind: "directive", type: i4$1.InputText, selector: "[pInputText]", inputs: ["pSize", "variant", "fluid", "invalid"] }, { kind: "ngmodule", type: InputGroupModule }, { kind: "component", type: i5.InputGroup, selector: "p-inputgroup, p-inputGroup, p-input-group", inputs: ["styleClass"] }, { kind: "ngmodule", type: InputGroupAddonModule }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
214
417
  }
215
418
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.1.6", ngImport: i0, type: DCFilterBarComponent, decorators: [{
216
419
  type: Component,
@@ -219,6 +422,8 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.1.6", ngImpor
219
422
  type: Input
220
423
  }], isAdmin: [{
221
424
  type: Input
425
+ }], persistenceKey: [{
426
+ type: Input
222
427
  }] } });
223
428
 
224
429
  class ConfirmComponent {
@@ -696,7 +901,7 @@ class QuickTableComponent {
696
901
  }
697
902
  }
698
903
  static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.1.6", ngImport: i0, type: QuickTableComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
699
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.1.6", type: QuickTableComponent, isStandalone: true, selector: "app-quick-table", inputs: { columns: { classPropertyName: "columns", publicName: "columns", isSignal: true, isRequired: false, transformFunction: null }, tableData: { classPropertyName: "tableData", publicName: "tableData", isSignal: true, isRequired: false, transformFunction: null }, actions: { classPropertyName: "actions", publicName: "actions", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { onAction: "onAction" }, viewQueries: [{ propertyName: "tableRef", first: true, predicate: ["tableRef"], descendants: true }], ngImport: i0, template: "<p-table\n [tableStyle]=\"{ 'min-width': '20rem' }\"\n #tableRef\n [value]=\"_tableData()\"\n [columns]=\"_columns()\"\n [globalFilterFields]=\"globalFilterFields()\"\n [filters]=\"filters()\"\n (onFilter)=\"onFilterLocal($event)\">\n <ng-template pTemplate=\"caption\">\n <div class=\"flex justify-content-between align-items-center\">\n <h5 class=\"m-0\">Table Data</h5>\n <span class=\"p-input-icon-left\">\n <i class=\"pi pi-search\"></i>\n <input pInputText type=\"text\" (input)=\"onGlobalFilter($event)\" placeholder=\"Search keyword\" />\n </span>\n </div>\n </ng-template>\n <ng-template pTemplate=\"header\" let-columns>\n <tr>\n @for (column of columns; track column) {\n <th [pSortableColumn]=\"column.field\">{{ column.header }} <p-sortIcon [field]=\"column.field\"></p-sortIcon></th>\n }\n </tr>\n <tr>\n @for (column of columns; track column) { @if(column.type === 'tags') {\n <th>\n <p-multiselect\n [options]=\"filters()?.[column.field]?.['options']\"\n placeholder=\"Selecciona\"\n (onChange)=\"filterOutsideTable('tags', column.field, $event.value)\"\n [style]=\"{ minWidth: '14rem' }\"\n [panelStyle]=\"{ minWidth: '16rem' }\">\n <ng-template let-option #item>\n <div class=\"flex items-center gap-2\">\n <span>{{ option }}</span>\n </div>\n </ng-template>\n </p-multiselect>\n </th>\n\n } @else if(column.type === 'select') {\n <th>\n <p-select\n [options]=\"filters()?.[column.field]?.['options']\"\n placeholder=\"Selecciona\"\n (onChange)=\"filterOutsideTable('select', column.field, $event.value)\"\n [style]=\"{ minWidth: '14rem' }\"\n [showClear]=\"true\"></p-select>\n </th>\n } @else if(column.type === 'boolean') {\n <th>\n <p-columnFilter [type]=\"'boolean'\" [field]=\"column.field\"></p-columnFilter>\n </th>\n } @else if(column.type === 'numeric') {\n <th>\n <!-- <p-columnFilter [type]=\"'numeric'\" [field]=\"column.field\"></p-columnFilter> -->\n </th>\n } @else {\n <th>\n <p-columnFilter [type]=\"getFilterType(column)\" [field]=\"column.field\" placeholder=\"Search\" [showMenu]=\"false\"></p-columnFilter>\n </th>\n } }\n </tr>\n </ng-template>\n <!-- @if(tableData()){ -->\n <ng-template pTemplate=\"body\" let-item let-columns=\"columns\">\n <tr>\n @for (column of columns; track column) {\n <td>\n @if(column.type === 'image'){\n <div class=\"image-container\">\n <img [src]=\"item | getPath: column\" alt=\"Image\" class=\"image\" />\n </div>\n } @else if(column.type === 'tags') {\n <div class=\"tags-container\">\n @for (tag of item[column.field]; track tag) {\n <p-tag [rounded]=\"true\" [value]=\"tag\"></p-tag>\n }\n </div>\n } @else if(column.type === 'actions') {\n <div style=\"display: flex; gap: 2px\">\n @for (actionBtn of _actions(); track actionBtn) {\n <p-button (click)=\"selectItem(item, actionBtn)\" [icon]=\"actionBtn.icon\" [severity]=\"actionBtn['severity']\" />\n }\n </div>\n } @else if(column.type === 'boolean') {\n <i\n class=\"pi\"\n [ngClass]=\"{\n 'text-green-500 pi-check-circle': column.reverse ? !(item | getPath: column) : (item | getPath: column),\n 'text-red-500 pi-times-circle': column.reverse ? (item | getPath: column) : !(item | getPath: column)\n }\"></i>\n } @else {\n <span>{{ item | getPath: column}} </span>\n }\n </td>\n }\n </tr>\n </ng-template>\n <!-- } -->\n</p-table>\n", styles: [":host{display:block;height:100%;overflow:auto}.generic-list-container{display:flex;flex-direction:column;height:100%}.generic-list-content{margin-top:10px;flex:1;overflow-y:auto;padding-bottom:10px}.card-source{margin-bottom:10px;position:relative}.paginator-container{margin-top:auto;padding-top:10px}.image-container{width:50px;height:50px;border-radius:50%;overflow:hidden;display:flex;justify-content:center;align-items:center}.image-container img{width:100%;height:100%;object-fit:cover}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1$1.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "ngmodule", type: CardModule }, { kind: "directive", type: i2$3.PrimeTemplate, selector: "[pTemplate]", inputs: ["type", "pTemplate"] }, { kind: "ngmodule", type: ButtonModule }, { kind: "component", type: i2.Button, selector: "p-button", inputs: ["type", "iconPos", "icon", "badge", "label", "disabled", "loading", "loadingIcon", "raised", "rounded", "text", "plain", "severity", "outlined", "link", "tabindex", "size", "variant", "style", "styleClass", "badgeClass", "badgeSeverity", "ariaLabel", "buttonProps", "autofocus", "fluid"], outputs: ["onClick", "onFocus", "onBlur"] }, { kind: "ngmodule", type: SpeedDialModule }, { kind: "ngmodule", type: PaginatorModule }, { kind: "ngmodule", type: TableModule }, { kind: "component", type: i4$2.Table, selector: "p-table", inputs: ["frozenColumns", "frozenValue", "styleClass", "tableStyle", "tableStyleClass", "paginator", "pageLinks", "rowsPerPageOptions", "alwaysShowPaginator", "paginatorPosition", "paginatorStyleClass", "paginatorDropdownAppendTo", "paginatorDropdownScrollHeight", "currentPageReportTemplate", "showCurrentPageReport", "showJumpToPageDropdown", "showJumpToPageInput", "showFirstLastIcon", "showPageLinks", "defaultSortOrder", "sortMode", "resetPageOnSort", "selectionMode", "selectionPageOnly", "contextMenuSelection", "contextMenuSelectionMode", "dataKey", "metaKeySelection", "rowSelectable", "rowTrackBy", "lazy", "lazyLoadOnInit", "compareSelectionBy", "csvSeparator", "exportFilename", "filters", "globalFilterFields", "filterDelay", "filterLocale", "expandedRowKeys", "editingRowKeys", "rowExpandMode", "scrollable", "rowGroupMode", "scrollHeight", "virtualScroll", "virtualScrollItemSize", "virtualScrollOptions", "virtualScrollDelay", "frozenWidth", "contextMenu", "resizableColumns", "columnResizeMode", "reorderableColumns", "loading", "loadingIcon", "showLoader", "rowHover", "customSort", "showInitialSortBadge", "exportFunction", "exportHeader", "stateKey", "stateStorage", "editMode", "groupRowsBy", "size", "showGridlines", "stripedRows", "groupRowsByOrder", "responsiveLayout", "breakpoint", "paginatorLocale", "value", "columns", "first", "rows", "totalRecords", "sortField", "sortOrder", "multiSortMeta", "selection", "selectAll"], outputs: ["contextMenuSelectionChange", "selectAllChange", "selectionChange", "onRowSelect", "onRowUnselect", "onPage", "onSort", "onFilter", "onLazyLoad", "onRowExpand", "onRowCollapse", "onContextMenuSelect", "onColResize", "onColReorder", "onRowReorder", "onEditInit", "onEditComplete", "onEditCancel", "onHeaderCheckboxToggle", "sortFunction", "firstChange", "rowsChange", "onStateSave", "onStateRestore"] }, { kind: "directive", type: i4$2.SortableColumn, selector: "[pSortableColumn]", inputs: ["pSortableColumn", "pSortableColumnDisabled"] }, { kind: "component", type: i4$2.SortIcon, selector: "p-sortIcon", inputs: ["field"] }, { kind: "component", type: i4$2.ColumnFilter, selector: "p-columnFilter, p-column-filter, p-columnfilter", inputs: ["field", "type", "display", "showMenu", "matchMode", "operator", "showOperator", "showClearButton", "showApplyButton", "showMatchModes", "showAddButton", "hideOnClear", "placeholder", "matchModeOptions", "maxConstraints", "minFractionDigits", "maxFractionDigits", "prefix", "suffix", "locale", "localeMatcher", "currency", "currencyDisplay", "filterOn", "useGrouping", "showButtons", "ariaLabel", "filterButtonProps"], outputs: ["onShow", "onHide"] }, { kind: "ngmodule", type: RouterModule }, { kind: "ngmodule", type: InputTextModule }, { kind: "directive", type: i4$1.InputText, selector: "[pInputText]", inputs: ["pSize", "variant", "fluid", "invalid"] }, { kind: "ngmodule", type: TagModule }, { kind: "component", type: i6.Tag, selector: "p-tag", inputs: ["styleClass", "severity", "value", "icon", "rounded"] }, { kind: "ngmodule", type: SelectModule }, { kind: "component", type: i3.Select, selector: "p-select", inputs: ["id", "scrollHeight", "filter", "panelStyle", "styleClass", "panelStyleClass", "readonly", "editable", "tabindex", "placeholder", "loadingIcon", "filterPlaceholder", "filterLocale", "inputId", "dataKey", "filterBy", "filterFields", "autofocus", "resetFilterOnHide", "checkmark", "dropdownIcon", "loading", "optionLabel", "optionValue", "optionDisabled", "optionGroupLabel", "optionGroupChildren", "group", "showClear", "emptyFilterMessage", "emptyMessage", "lazy", "virtualScroll", "virtualScrollItemSize", "virtualScrollOptions", "overlayOptions", "ariaFilterLabel", "ariaLabel", "ariaLabelledBy", "filterMatchMode", "tooltip", "tooltipPosition", "tooltipPositionStyle", "tooltipStyleClass", "focusOnHover", "selectOnFocus", "autoOptionFocus", "autofocusFilter", "filterValue", "options", "appendTo"], outputs: ["onChange", "onFilter", "onFocus", "onBlur", "onClick", "onShow", "onHide", "onClear", "onLazyLoad"] }, { kind: "ngmodule", type: MultiSelectModule }, { kind: "component", type: i4.MultiSelect, selector: "p-multiSelect, p-multiselect, p-multi-select", inputs: ["id", "ariaLabel", "styleClass", "panelStyle", "panelStyleClass", "inputId", "readonly", "group", "filter", "filterPlaceHolder", "filterLocale", "overlayVisible", "tabindex", "dataKey", "ariaLabelledBy", "displaySelectedLabel", "maxSelectedLabels", "selectionLimit", "selectedItemsLabel", "showToggleAll", "emptyFilterMessage", "emptyMessage", "resetFilterOnHide", "dropdownIcon", "chipIcon", "optionLabel", "optionValue", "optionDisabled", "optionGroupLabel", "optionGroupChildren", "showHeader", "filterBy", "scrollHeight", "lazy", "virtualScroll", "loading", "virtualScrollItemSize", "loadingIcon", "virtualScrollOptions", "overlayOptions", "ariaFilterLabel", "filterMatchMode", "tooltip", "tooltipPosition", "tooltipPositionStyle", "tooltipStyleClass", "autofocusFilter", "display", "autocomplete", "showClear", "autofocus", "placeholder", "options", "filterValue", "selectAll", "focusOnHover", "filterFields", "selectOnFocus", "autoOptionFocus", "highlightOnSelect", "size", "variant", "fluid", "appendTo"], outputs: ["onChange", "onFilter", "onFocus", "onBlur", "onClick", "onClear", "onPanelShow", "onPanelHide", "onLazyLoad", "onRemove", "onSelectAllChange"] }, { kind: "pipe", type: GetPathPipe, name: "getPath" }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
904
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.1.6", type: QuickTableComponent, isStandalone: true, selector: "app-quick-table", inputs: { columns: { classPropertyName: "columns", publicName: "columns", isSignal: true, isRequired: false, transformFunction: null }, tableData: { classPropertyName: "tableData", publicName: "tableData", isSignal: true, isRequired: false, transformFunction: null }, actions: { classPropertyName: "actions", publicName: "actions", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { onAction: "onAction" }, viewQueries: [{ propertyName: "tableRef", first: true, predicate: ["tableRef"], descendants: true }], ngImport: i0, template: "<p-table\n [tableStyle]=\"{ 'min-width': '20rem' }\"\n #tableRef\n [value]=\"_tableData()\"\n [columns]=\"_columns()\"\n [globalFilterFields]=\"globalFilterFields()\"\n [filters]=\"filters()\"\n (onFilter)=\"onFilterLocal($event)\">\n <ng-template pTemplate=\"caption\">\n <div class=\"flex justify-content-between align-items-center\">\n <h5 class=\"m-0\">Table Data</h5>\n <span class=\"p-input-icon-left\">\n <i class=\"pi pi-search\"></i>\n <input pInputText type=\"text\" (input)=\"onGlobalFilter($event)\" placeholder=\"Search keyword\" />\n </span>\n </div>\n </ng-template>\n <ng-template pTemplate=\"header\" let-columns>\n <tr>\n @for (column of columns; track column) {\n <th [pSortableColumn]=\"column.field\">{{ column.header }} <p-sortIcon [field]=\"column.field\"></p-sortIcon></th>\n }\n </tr>\n <tr>\n @for (column of columns; track column) { @if(column.type === 'tags') {\n <th>\n <p-multiselect\n [options]=\"filters()?.[column.field]?.['options']\"\n placeholder=\"Selecciona\"\n (onChange)=\"filterOutsideTable('tags', column.field, $event.value)\"\n [style]=\"{ minWidth: '14rem' }\"\n [panelStyle]=\"{ minWidth: '16rem' }\">\n <ng-template let-option #item>\n <div class=\"flex items-center gap-2\">\n <span>{{ option }}</span>\n </div>\n </ng-template>\n </p-multiselect>\n </th>\n\n } @else if(column.type === 'select') {\n <th>\n <p-select\n [options]=\"filters()?.[column.field]?.['options']\"\n placeholder=\"Selecciona\"\n (onChange)=\"filterOutsideTable('select', column.field, $event.value)\"\n [style]=\"{ minWidth: '14rem' }\"\n [showClear]=\"true\"></p-select>\n </th>\n } @else if(column.type === 'boolean') {\n <th>\n <p-columnFilter [type]=\"'boolean'\" [field]=\"column.field\"></p-columnFilter>\n </th>\n } @else if(column.type === 'numeric') {\n <th>\n <!-- <p-columnFilter [type]=\"'numeric'\" [field]=\"column.field\"></p-columnFilter> -->\n </th>\n } @else {\n <th>\n <p-columnFilter [type]=\"getFilterType(column)\" [field]=\"column.field\" placeholder=\"Search\" [showMenu]=\"false\"></p-columnFilter>\n </th>\n } }\n </tr>\n </ng-template>\n <!-- @if(tableData()){ -->\n <ng-template pTemplate=\"body\" let-item let-columns=\"columns\">\n <tr>\n @for (column of columns; track column) {\n <td>\n @if(column.type === 'image'){\n <div class=\"image-container\">\n <img [src]=\"item | getPath: column\" alt=\"Image\" class=\"image\" />\n </div>\n } @else if(column.type === 'tags') {\n <div class=\"tags-container\">\n @for (tag of item[column.field]; track tag) {\n <p-tag [rounded]=\"true\" [value]=\"tag\"></p-tag>\n }\n </div>\n } @else if(column.type === 'actions') {\n <div style=\"display: flex; gap: 2px\">\n @for (actionBtn of _actions(); track actionBtn) {\n <p-button (click)=\"selectItem(item, actionBtn)\" [icon]=\"actionBtn.icon\" [severity]=\"actionBtn['severity']\" />\n }\n </div>\n } @else if(column.type === 'boolean') {\n <i\n class=\"pi\"\n [ngClass]=\"{\n 'text-green-500 pi-check-circle': column.reverse ? !(item | getPath: column) : (item | getPath: column),\n 'text-red-500 pi-times-circle': column.reverse ? (item | getPath: column) : !(item | getPath: column)\n }\"></i>\n } @else {\n <span>{{ item | getPath: column}} </span>\n }\n </td>\n }\n </tr>\n </ng-template>\n <!-- } -->\n</p-table>\n", styles: [":host{display:block;height:100%;overflow:auto}.generic-list-container{display:flex;flex-direction:column;height:100%}.generic-list-content{margin-top:10px;flex:1;overflow-y:auto;padding-bottom:10px}.card-source{margin-bottom:10px;position:relative}.paginator-container{margin-top:auto;padding-top:10px}.image-container{width:50px;height:50px;border-radius:50%;overflow:hidden;display:flex;justify-content:center;align-items:center}.image-container img{width:100%;height:100%;object-fit:cover}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1$1.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "ngmodule", type: CardModule }, { kind: "directive", type: i2$3.PrimeTemplate, selector: "[pTemplate]", inputs: ["type", "pTemplate"] }, { kind: "ngmodule", type: ButtonModule }, { kind: "component", type: i2.Button, selector: "p-button", inputs: ["type", "iconPos", "icon", "badge", "label", "disabled", "loading", "loadingIcon", "raised", "rounded", "text", "plain", "severity", "outlined", "link", "tabindex", "size", "variant", "style", "styleClass", "badgeClass", "badgeSeverity", "ariaLabel", "buttonProps", "autofocus", "fluid"], outputs: ["onClick", "onFocus", "onBlur"] }, { kind: "ngmodule", type: SpeedDialModule }, { kind: "ngmodule", type: PaginatorModule }, { kind: "ngmodule", type: TableModule }, { kind: "component", type: i4$2.Table, selector: "p-table", inputs: ["frozenColumns", "frozenValue", "styleClass", "tableStyle", "tableStyleClass", "paginator", "pageLinks", "rowsPerPageOptions", "alwaysShowPaginator", "paginatorPosition", "paginatorStyleClass", "paginatorDropdownAppendTo", "paginatorDropdownScrollHeight", "currentPageReportTemplate", "showCurrentPageReport", "showJumpToPageDropdown", "showJumpToPageInput", "showFirstLastIcon", "showPageLinks", "defaultSortOrder", "sortMode", "resetPageOnSort", "selectionMode", "selectionPageOnly", "contextMenuSelection", "contextMenuSelectionMode", "dataKey", "metaKeySelection", "rowSelectable", "rowTrackBy", "lazy", "lazyLoadOnInit", "compareSelectionBy", "csvSeparator", "exportFilename", "filters", "globalFilterFields", "filterDelay", "filterLocale", "expandedRowKeys", "editingRowKeys", "rowExpandMode", "scrollable", "rowGroupMode", "scrollHeight", "virtualScroll", "virtualScrollItemSize", "virtualScrollOptions", "virtualScrollDelay", "frozenWidth", "contextMenu", "resizableColumns", "columnResizeMode", "reorderableColumns", "loading", "loadingIcon", "showLoader", "rowHover", "customSort", "showInitialSortBadge", "exportFunction", "exportHeader", "stateKey", "stateStorage", "editMode", "groupRowsBy", "size", "showGridlines", "stripedRows", "groupRowsByOrder", "responsiveLayout", "breakpoint", "paginatorLocale", "value", "columns", "first", "rows", "totalRecords", "sortField", "sortOrder", "multiSortMeta", "selection", "selectAll"], outputs: ["contextMenuSelectionChange", "selectAllChange", "selectionChange", "onRowSelect", "onRowUnselect", "onPage", "onSort", "onFilter", "onLazyLoad", "onRowExpand", "onRowCollapse", "onContextMenuSelect", "onColResize", "onColReorder", "onRowReorder", "onEditInit", "onEditComplete", "onEditCancel", "onHeaderCheckboxToggle", "sortFunction", "firstChange", "rowsChange", "onStateSave", "onStateRestore"] }, { kind: "directive", type: i4$2.SortableColumn, selector: "[pSortableColumn]", inputs: ["pSortableColumn", "pSortableColumnDisabled"] }, { kind: "component", type: i4$2.SortIcon, selector: "p-sortIcon", inputs: ["field"] }, { kind: "component", type: i4$2.ColumnFilter, selector: "p-columnFilter, p-column-filter, p-columnfilter", inputs: ["field", "type", "display", "showMenu", "matchMode", "operator", "showOperator", "showClearButton", "showApplyButton", "showMatchModes", "showAddButton", "hideOnClear", "placeholder", "matchModeOptions", "maxConstraints", "minFractionDigits", "maxFractionDigits", "prefix", "suffix", "locale", "localeMatcher", "currency", "currencyDisplay", "filterOn", "useGrouping", "showButtons", "ariaLabel", "filterButtonProps"], outputs: ["onShow", "onHide"] }, { kind: "ngmodule", type: RouterModule }, { kind: "ngmodule", type: InputTextModule }, { kind: "directive", type: i4$1.InputText, selector: "[pInputText]", inputs: ["pSize", "variant", "fluid", "invalid"] }, { kind: "ngmodule", type: TagModule }, { kind: "component", type: i6.Tag, selector: "p-tag", inputs: ["styleClass", "severity", "value", "icon", "rounded"] }, { kind: "ngmodule", type: SelectModule }, { kind: "component", type: i3.Select, selector: "p-select", inputs: ["id", "scrollHeight", "filter", "panelStyle", "styleClass", "panelStyleClass", "readonly", "editable", "tabindex", "placeholder", "loadingIcon", "filterPlaceholder", "filterLocale", "inputId", "dataKey", "filterBy", "filterFields", "autofocus", "resetFilterOnHide", "checkmark", "dropdownIcon", "loading", "optionLabel", "optionValue", "optionDisabled", "optionGroupLabel", "optionGroupChildren", "group", "showClear", "emptyFilterMessage", "emptyMessage", "lazy", "virtualScroll", "virtualScrollItemSize", "virtualScrollOptions", "overlayOptions", "ariaFilterLabel", "ariaLabel", "ariaLabelledBy", "filterMatchMode", "tooltip", "tooltipPosition", "tooltipPositionStyle", "tooltipStyleClass", "focusOnHover", "selectOnFocus", "autoOptionFocus", "autofocusFilter", "filterValue", "options", "appendTo"], outputs: ["onChange", "onFilter", "onFocus", "onBlur", "onClick", "onShow", "onHide", "onClear", "onLazyLoad"] }, { kind: "ngmodule", type: MultiSelectModule }, { kind: "component", type: i8.MultiSelect, selector: "p-multiSelect, p-multiselect, p-multi-select", inputs: ["id", "ariaLabel", "styleClass", "panelStyle", "panelStyleClass", "inputId", "readonly", "group", "filter", "filterPlaceHolder", "filterLocale", "overlayVisible", "tabindex", "dataKey", "ariaLabelledBy", "displaySelectedLabel", "maxSelectedLabels", "selectionLimit", "selectedItemsLabel", "showToggleAll", "emptyFilterMessage", "emptyMessage", "resetFilterOnHide", "dropdownIcon", "chipIcon", "optionLabel", "optionValue", "optionDisabled", "optionGroupLabel", "optionGroupChildren", "showHeader", "filterBy", "scrollHeight", "lazy", "virtualScroll", "loading", "virtualScrollItemSize", "loadingIcon", "virtualScrollOptions", "overlayOptions", "ariaFilterLabel", "filterMatchMode", "tooltip", "tooltipPosition", "tooltipPositionStyle", "tooltipStyleClass", "autofocusFilter", "display", "autocomplete", "showClear", "autofocus", "placeholder", "options", "filterValue", "selectAll", "focusOnHover", "filterFields", "selectOnFocus", "autoOptionFocus", "highlightOnSelect", "size", "variant", "fluid", "appendTo"], outputs: ["onChange", "onFilter", "onFocus", "onBlur", "onClick", "onClear", "onPanelShow", "onPanelHide", "onLazyLoad", "onRemove", "onSelectAllChange"] }, { kind: "pipe", type: GetPathPipe, name: "getPath" }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
700
905
  }
701
906
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.1.6", ngImport: i0, type: QuickTableComponent, decorators: [{
702
907
  type: Component,
@@ -915,15 +1120,12 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.1.6", ngImpor
915
1120
  }] });
916
1121
 
917
1122
  class DcTagsFormComponent {
918
- constructor(parentContainer) {
919
- this.parentContainer = parentContainer;
1123
+ constructor() {
1124
+ this.form = input.required(...(ngDevMode ? [{ debugName: "form" }] : []));
920
1125
  this.newTagControl = new FormControl('');
921
1126
  }
922
- ngOnInit() {
923
- this.form = this.parentContainer.control;
924
- }
925
1127
  get arrayForm() {
926
- return this.form.get('tags');
1128
+ return this.form().get('tags');
927
1129
  }
928
1130
  addTag() {
929
1131
  const newTag = this.newTagControl.value?.trim();
@@ -935,8 +1137,8 @@ class DcTagsFormComponent {
935
1137
  removeTag(index) {
936
1138
  this.arrayForm.removeAt(index);
937
1139
  }
938
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.1.6", ngImport: i0, type: DcTagsFormComponent, deps: [{ token: i1.ControlContainer }], target: i0.ɵɵFactoryTarget.Component }); }
939
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.1.6", type: DcTagsFormComponent, isStandalone: true, selector: "dc-tags-form", ngImport: i0, template: "<div [formGroup]=\"form\">\n <div formArrayName=\"tags\">\n <div class=\"flex flex-wrap gap-2\">\n @for (tagControl of arrayForm.controls; track tagControl; let i = $index) {\n <p-chip [label]=\"tagControl.value\" [removable]=\"true\" (onRemove)=\"removeTag(i)\"></p-chip>\n }\n </div>\n </div>\n</div>\n\n<div class=\"flex mt-2\">\n <input pInputText type=\"text\" [formControl]=\"newTagControl\" placeholder=\"New tag\" (keydown.enter)=\"addTag(); $event.preventDefault()\" />\n <p-button label=\"Add Tag\" icon=\"pi pi-plus\" (click)=\"addTag()\" [disabled]=\"!newTagControl.value\"></p-button>\n</div>\n", styles: [".tag-field{display:flex;align-items:center;margin-bottom:.5rem}.tag-field input{margin-right:.5rem}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "ngmodule", type: ReactiveFormsModule }, { kind: "directive", type: i1.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { kind: "directive", type: i1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]" }, { kind: "directive", type: i1.FormControlDirective, selector: "[formControl]", inputs: ["formControl", "disabled", "ngModel"], outputs: ["ngModelChange"], exportAs: ["ngForm"] }, { kind: "directive", type: i1.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { kind: "directive", type: i1.FormArrayName, selector: "[formArrayName]", inputs: ["formArrayName"] }, { kind: "ngmodule", type: ButtonModule }, { kind: "component", type: i2.Button, selector: "p-button", inputs: ["type", "iconPos", "icon", "badge", "label", "disabled", "loading", "loadingIcon", "raised", "rounded", "text", "plain", "severity", "outlined", "link", "tabindex", "size", "variant", "style", "styleClass", "badgeClass", "badgeSeverity", "ariaLabel", "buttonProps", "autofocus", "fluid"], outputs: ["onClick", "onFocus", "onBlur"] }, { kind: "ngmodule", type: InputTextModule }, { kind: "directive", type: i4$1.InputText, selector: "[pInputText]", inputs: ["pSize", "variant", "fluid", "invalid"] }, { kind: "ngmodule", type: ChipModule }, { kind: "component", type: i3$3.Chip, selector: "p-chip", inputs: ["label", "icon", "image", "alt", "styleClass", "disabled", "removable", "removeIcon", "chipProps"], outputs: ["onRemove", "onImageError"] }], viewProviders: [
1140
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.1.6", ngImport: i0, type: DcTagsFormComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
1141
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.1.6", type: DcTagsFormComponent, isStandalone: true, selector: "dc-tags-form", inputs: { form: { classPropertyName: "form", publicName: "form", isSignal: true, isRequired: true, transformFunction: null } }, ngImport: i0, template: "<div [formGroup]=\"form()\">\n <div formArrayName=\"tags\">\n <div class=\"flex flex-wrap gap-2\">\n @for (tagControl of arrayForm.controls; track tagControl; let i = $index) {\n <p-chip [label]=\"tagControl.value\" [removable]=\"true\" (onRemove)=\"removeTag(i)\"></p-chip>\n }\n </div>\n </div>\n</div>\n\n<div class=\"flex mt-2\">\n <input pInputText type=\"text\" [formControl]=\"newTagControl\" placeholder=\"New tag\" (keydown.enter)=\"addTag(); $event.preventDefault()\" />\n <p-button label=\"Add Tag\" icon=\"pi pi-plus\" (click)=\"addTag()\" [disabled]=\"!newTagControl.value\"></p-button>\n</div>\n", styles: [".tag-field{display:flex;align-items:center;margin-bottom:.5rem}.tag-field input{margin-right:.5rem}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "ngmodule", type: ReactiveFormsModule }, { kind: "directive", type: i1.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { kind: "directive", type: i1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]" }, { kind: "directive", type: i1.FormControlDirective, selector: "[formControl]", inputs: ["formControl", "disabled", "ngModel"], outputs: ["ngModelChange"], exportAs: ["ngForm"] }, { kind: "directive", type: i1.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { kind: "directive", type: i1.FormArrayName, selector: "[formArrayName]", inputs: ["formArrayName"] }, { kind: "ngmodule", type: ButtonModule }, { kind: "component", type: i2.Button, selector: "p-button", inputs: ["type", "iconPos", "icon", "badge", "label", "disabled", "loading", "loadingIcon", "raised", "rounded", "text", "plain", "severity", "outlined", "link", "tabindex", "size", "variant", "style", "styleClass", "badgeClass", "badgeSeverity", "ariaLabel", "buttonProps", "autofocus", "fluid"], outputs: ["onClick", "onFocus", "onBlur"] }, { kind: "ngmodule", type: InputTextModule }, { kind: "directive", type: i4$1.InputText, selector: "[pInputText]", inputs: ["pSize", "variant", "fluid", "invalid"] }, { kind: "ngmodule", type: ChipModule }, { kind: "component", type: i3$3.Chip, selector: "p-chip", inputs: ["label", "icon", "image", "alt", "styleClass", "disabled", "removable", "removeIcon", "chipProps"], outputs: ["onRemove", "onImageError"] }], viewProviders: [
940
1142
  {
941
1143
  provide: ControlContainer,
942
1144
  useFactory: () => inject(ControlContainer, { skipSelf: true }),
@@ -950,19 +1152,19 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.1.6", ngImpor
950
1152
  provide: ControlContainer,
951
1153
  useFactory: () => inject(ControlContainer, { skipSelf: true }),
952
1154
  },
953
- ], template: "<div [formGroup]=\"form\">\n <div formArrayName=\"tags\">\n <div class=\"flex flex-wrap gap-2\">\n @for (tagControl of arrayForm.controls; track tagControl; let i = $index) {\n <p-chip [label]=\"tagControl.value\" [removable]=\"true\" (onRemove)=\"removeTag(i)\"></p-chip>\n }\n </div>\n </div>\n</div>\n\n<div class=\"flex mt-2\">\n <input pInputText type=\"text\" [formControl]=\"newTagControl\" placeholder=\"New tag\" (keydown.enter)=\"addTag(); $event.preventDefault()\" />\n <p-button label=\"Add Tag\" icon=\"pi pi-plus\" (click)=\"addTag()\" [disabled]=\"!newTagControl.value\"></p-button>\n</div>\n", styles: [".tag-field{display:flex;align-items:center;margin-bottom:.5rem}.tag-field input{margin-right:.5rem}\n"] }]
954
- }], ctorParameters: () => [{ type: i1.ControlContainer }] });
1155
+ ], template: "<div [formGroup]=\"form()\">\n <div formArrayName=\"tags\">\n <div class=\"flex flex-wrap gap-2\">\n @for (tagControl of arrayForm.controls; track tagControl; let i = $index) {\n <p-chip [label]=\"tagControl.value\" [removable]=\"true\" (onRemove)=\"removeTag(i)\"></p-chip>\n }\n </div>\n </div>\n</div>\n\n<div class=\"flex mt-2\">\n <input pInputText type=\"text\" [formControl]=\"newTagControl\" placeholder=\"New tag\" (keydown.enter)=\"addTag(); $event.preventDefault()\" />\n <p-button label=\"Add Tag\" icon=\"pi pi-plus\" (click)=\"addTag()\" [disabled]=\"!newTagControl.value\"></p-button>\n</div>\n", styles: [".tag-field{display:flex;align-items:center;margin-bottom:.5rem}.tag-field input{margin-right:.5rem}\n"] }]
1156
+ }] });
955
1157
 
956
1158
  class DcLearnableFormComponent {
957
1159
  constructor() {
958
1160
  this.form = input.required(...(ngDevMode ? [{ debugName: "form" }] : []));
959
1161
  }
960
1162
  static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.1.6", ngImport: i0, type: DcLearnableFormComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
961
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.0", version: "20.1.6", type: DcLearnableFormComponent, isStandalone: true, selector: "dc-learnable-form", inputs: { form: { classPropertyName: "form", publicName: "form", isSignal: true, isRequired: true, transformFunction: null } }, ngImport: i0, template: "<div [formGroup]=\"form()\">\n <div class=\"form-grid\">\n <div class=\"row\">\n <div class=\"form-field\">\n <label for=\"level\">Level <span pTooltip=\"Difficulty level\">\u2139\uFE0F</span></label>\n <p-inputNumber id=\"level\" formControlName=\"level\" [min]=\"0\" [max]=\"10\"></p-inputNumber>\n </div>\n <div class=\"form-field\">\n <label for=\"takenCount\">Taken Count <span pTooltip=\"How many times this has been taken\">\u2139\uFE0F</span></label>\n <p-inputNumber id=\"takenCount\" formControlName=\"takenCount\" [min]=\"0\"></p-inputNumber>\n </div>\n </div>\n <div class=\"form-field\">\n <label for=\"tags\">Tags <span pTooltip=\"Relevant tags for this content\">\u2139\uFE0F</span></label>\n <dc-tags-form />\n </div>\n </div>\n</div>\n", styles: [".form-grid{display:grid;gap:1rem}.row{display:grid;grid-template-columns:repeat(2,1fr);gap:1rem}.form-field{display:flex;flex-direction:column}\n"], dependencies: [{ kind: "ngmodule", type: ReactiveFormsModule }, { kind: "directive", type: i1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]" }, { kind: "directive", type: i1.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { kind: "directive", type: i1.FormControlName, selector: "[formControlName]", inputs: ["formControlName", "disabled", "ngModel"], outputs: ["ngModelChange"] }, { kind: "ngmodule", type: CardModule }, { kind: "ngmodule", type: InputNumberModule }, { kind: "component", type: i2$5.InputNumber, selector: "p-inputNumber, p-inputnumber, p-input-number", inputs: ["showButtons", "format", "buttonLayout", "inputId", "styleClass", "placeholder", "tabindex", "title", "ariaLabelledBy", "ariaDescribedBy", "ariaLabel", "ariaRequired", "autocomplete", "incrementButtonClass", "decrementButtonClass", "incrementButtonIcon", "decrementButtonIcon", "readonly", "allowEmpty", "locale", "localeMatcher", "mode", "currency", "currencyDisplay", "useGrouping", "minFractionDigits", "maxFractionDigits", "prefix", "suffix", "inputStyle", "inputStyleClass", "showClear", "autofocus"], outputs: ["onInput", "onFocus", "onBlur", "onKeyDown", "onClear"] }, { kind: "ngmodule", type: TooltipModule }, { kind: "directive", type: i4$3.Tooltip, selector: "[pTooltip]", inputs: ["tooltipPosition", "tooltipEvent", "positionStyle", "tooltipStyleClass", "tooltipZIndex", "escape", "showDelay", "hideDelay", "life", "positionTop", "positionLeft", "autoHide", "fitContent", "hideOnEscape", "pTooltip", "tooltipDisabled", "tooltipOptions", "appendTo"] }, { kind: "component", type: DcTagsFormComponent, selector: "dc-tags-form" }] }); }
1163
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.0", version: "20.1.6", type: DcLearnableFormComponent, isStandalone: true, selector: "dc-learnable-form", inputs: { form: { classPropertyName: "form", publicName: "form", isSignal: true, isRequired: true, transformFunction: null } }, ngImport: i0, template: "<div [formGroup]=\"form()\">\n <div class=\"form-grid\">\n <div class=\"row\">\n <div class=\"form-field\">\n <label for=\"level\">Level <span pTooltip=\"Difficulty level\">\u2139\uFE0F</span></label>\n <p-inputNumber id=\"level\" formControlName=\"level\" [min]=\"0\" [max]=\"10\"></p-inputNumber>\n </div>\n <div class=\"form-field\">\n <label for=\"takenCount\">Taken Count <span pTooltip=\"How many times this has been taken\">\u2139\uFE0F</span></label>\n <p-inputNumber id=\"takenCount\" formControlName=\"takenCount\" [min]=\"0\"></p-inputNumber>\n </div>\n </div>\n <div class=\"form-field\">\n <label for=\"tags\">Tags <span pTooltip=\"Relevant tags for this content\">\u2139\uFE0F</span></label>\n <dc-tags-form [form]=\"form()\" />\n </div>\n </div>\n</div>\n", styles: [".form-grid{display:grid;gap:1rem}.row{display:grid;grid-template-columns:repeat(2,1fr);gap:1rem}.form-field{display:flex;flex-direction:column}\n"], dependencies: [{ kind: "ngmodule", type: ReactiveFormsModule }, { kind: "directive", type: i1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]" }, { kind: "directive", type: i1.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { kind: "directive", type: i1.FormControlName, selector: "[formControlName]", inputs: ["formControlName", "disabled", "ngModel"], outputs: ["ngModelChange"] }, { kind: "ngmodule", type: CardModule }, { kind: "ngmodule", type: InputNumberModule }, { kind: "component", type: i2$5.InputNumber, selector: "p-inputNumber, p-inputnumber, p-input-number", inputs: ["showButtons", "format", "buttonLayout", "inputId", "styleClass", "placeholder", "tabindex", "title", "ariaLabelledBy", "ariaDescribedBy", "ariaLabel", "ariaRequired", "autocomplete", "incrementButtonClass", "decrementButtonClass", "incrementButtonIcon", "decrementButtonIcon", "readonly", "allowEmpty", "locale", "localeMatcher", "mode", "currency", "currencyDisplay", "useGrouping", "minFractionDigits", "maxFractionDigits", "prefix", "suffix", "inputStyle", "inputStyleClass", "showClear", "autofocus"], outputs: ["onInput", "onFocus", "onBlur", "onKeyDown", "onClear"] }, { kind: "ngmodule", type: TooltipModule }, { kind: "directive", type: i4$3.Tooltip, selector: "[pTooltip]", inputs: ["tooltipPosition", "tooltipEvent", "positionStyle", "tooltipStyleClass", "tooltipZIndex", "escape", "showDelay", "hideDelay", "life", "positionTop", "positionLeft", "autoHide", "fitContent", "hideOnEscape", "pTooltip", "tooltipDisabled", "tooltipOptions", "appendTo"] }, { kind: "component", type: DcTagsFormComponent, selector: "dc-tags-form", inputs: ["form"] }] }); }
962
1164
  }
963
1165
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.1.6", ngImport: i0, type: DcLearnableFormComponent, decorators: [{
964
1166
  type: Component,
965
- args: [{ selector: 'dc-learnable-form', standalone: true, imports: [ReactiveFormsModule, CardModule, InputNumberModule, TooltipModule, DcTagsFormComponent], template: "<div [formGroup]=\"form()\">\n <div class=\"form-grid\">\n <div class=\"row\">\n <div class=\"form-field\">\n <label for=\"level\">Level <span pTooltip=\"Difficulty level\">\u2139\uFE0F</span></label>\n <p-inputNumber id=\"level\" formControlName=\"level\" [min]=\"0\" [max]=\"10\"></p-inputNumber>\n </div>\n <div class=\"form-field\">\n <label for=\"takenCount\">Taken Count <span pTooltip=\"How many times this has been taken\">\u2139\uFE0F</span></label>\n <p-inputNumber id=\"takenCount\" formControlName=\"takenCount\" [min]=\"0\"></p-inputNumber>\n </div>\n </div>\n <div class=\"form-field\">\n <label for=\"tags\">Tags <span pTooltip=\"Relevant tags for this content\">\u2139\uFE0F</span></label>\n <dc-tags-form />\n </div>\n </div>\n</div>\n", styles: [".form-grid{display:grid;gap:1rem}.row{display:grid;grid-template-columns:repeat(2,1fr);gap:1rem}.form-field{display:flex;flex-direction:column}\n"] }]
1167
+ args: [{ selector: 'dc-learnable-form', standalone: true, imports: [ReactiveFormsModule, CardModule, InputNumberModule, TooltipModule, DcTagsFormComponent], template: "<div [formGroup]=\"form()\">\n <div class=\"form-grid\">\n <div class=\"row\">\n <div class=\"form-field\">\n <label for=\"level\">Level <span pTooltip=\"Difficulty level\">\u2139\uFE0F</span></label>\n <p-inputNumber id=\"level\" formControlName=\"level\" [min]=\"0\" [max]=\"10\"></p-inputNumber>\n </div>\n <div class=\"form-field\">\n <label for=\"takenCount\">Taken Count <span pTooltip=\"How many times this has been taken\">\u2139\uFE0F</span></label>\n <p-inputNumber id=\"takenCount\" formControlName=\"takenCount\" [min]=\"0\"></p-inputNumber>\n </div>\n </div>\n <div class=\"form-field\">\n <label for=\"tags\">Tags <span pTooltip=\"Relevant tags for this content\">\u2139\uFE0F</span></label>\n <dc-tags-form [form]=\"form()\" />\n </div>\n </div>\n</div>\n", styles: [".form-grid{display:grid;gap:1rem}.row{display:grid;grid-template-columns:repeat(2,1fr);gap:1rem}.form-field{display:flex;flex-direction:column}\n"] }]
966
1168
  }] });
967
1169
 
968
1170
  /**
@@ -1140,6 +1342,11 @@ class EntityBaseListComponent extends PaginationBase {
1140
1342
  await this.entityCommunicationService.clone(id);
1141
1343
  await this.loadData(); // Refresh list
1142
1344
  break;
1345
+ case 'search':
1346
+ debugger;
1347
+ this.filterConfig.text = item;
1348
+ this.loadData();
1349
+ break;
1143
1350
  default:
1144
1351
  // this.handleCustomAction(actionEvent);
1145
1352
  }
@@ -1151,6 +1358,187 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.1.6", ngImpor
1151
1358
  type: Directive
1152
1359
  }], ctorParameters: () => [] });
1153
1360
 
1361
+ class EntityBaseListV2Component extends PaginationBase {
1362
+ constructor() {
1363
+ super();
1364
+ // Services
1365
+ this.router = inject(Router);
1366
+ this.route = inject(ActivatedRoute);
1367
+ // Inputs & Outputs
1368
+ this.initialViewType = input('card', ...(ngDevMode ? [{ debugName: "initialViewType" }] : []));
1369
+ this.onlyView = input(false, ...(ngDevMode ? [{ debugName: "onlyView" }] : []));
1370
+ // Outputs
1371
+ this.onSelect = output();
1372
+ // Writable Signals for component state
1373
+ this.items = signal([], ...(ngDevMode ? [{ debugName: "items" }] : []));
1374
+ this.totalRecordsSignal = signal(0, ...(ngDevMode ? [{ debugName: "totalRecordsSignal" }] : []));
1375
+ // Public properties for configuration
1376
+ this.filterBarOptions = { showActions: true, showCreateButton: true, showViewButton: true };
1377
+ this.columns = [];
1378
+ // New State Management
1379
+ this.mongoState = {
1380
+ query: {},
1381
+ projection: {},
1382
+ options: {
1383
+ sort: { _id: -1 },
1384
+ limit: 10,
1385
+ skip: 0,
1386
+ },
1387
+ payload: {},
1388
+ };
1389
+ this.viewType = signal(this.initialViewType(), ...(ngDevMode ? [{ debugName: "viewType" }] : []));
1390
+ effect(() => {
1391
+ // Keep the parent's totalRecords in sync with our signal
1392
+ this.totalRecords = this.totalRecordsSignal();
1393
+ });
1394
+ }
1395
+ async ngOnInit() {
1396
+ // Initialize mongoState from PaginationBase defaults if needed
1397
+ this.mongoState.options.limit = this.rows;
1398
+ this.mongoState.options.skip = this.first;
1399
+ await this.loadData();
1400
+ }
1401
+ async loadData() {
1402
+ try {
1403
+ this.isLoading = true;
1404
+ // Sync PaginationBase state to MongoState
1405
+ this.mongoState.options.limit = this.rows;
1406
+ this.mongoState.options.skip = this.first;
1407
+ // If sort is updated in filterConfig (from PaginationBase), sync it?
1408
+ // PaginationBase updates filterConfig.sort.
1409
+ // We might need to override onPageChange to update mongoState directly or sync here.
1410
+ // Actually, let's use the new operation method
1411
+ const response = await this.entityCommunicationService.operation({
1412
+ action: 'find',
1413
+ query: this.mongoState.query,
1414
+ projection: this.mongoState.projection,
1415
+ options: this.mongoState.options,
1416
+ payload: this.mongoState.payload,
1417
+ });
1418
+ // Assuming response structure matches what we need.
1419
+ // If 'find' returns just array, we might need 'count' separately or use an aggregation that returns both.
1420
+ // The user said: "Allows executing a variety of database operations through a single endpoint."
1421
+ // Usually 'find' returns an array. Pagination requires count.
1422
+ // Maybe we should use 'aggregate' to get both or make two calls.
1423
+ // Or maybe the backend 'find' operation returns { rows, count }?
1424
+ // The user example for 'updateOne' shows standard mongo stuff.
1425
+ // Let's assume for now we might need to fetch count separately or the backend handles pagination metadata if requested.
1426
+ // But typically 'find' returns a cursor/array.
1427
+ // Let's check if we can get count.
1428
+ // The user mentioned: "Bakcend single endpoint to handle everything in mongo."
1429
+ // If I use 'find', I get items.
1430
+ this.items.set(response); // If response is T[]
1431
+ // We need total records for pagination.
1432
+ // Use aggregate to count since 'count' action might not be explicitly supported or to be safe
1433
+ const countResult = await this.entityCommunicationService.operation({
1434
+ action: 'aggregate',
1435
+ payload: [{ $match: this.mongoState.query }, { $count: 'total' }],
1436
+ });
1437
+ const count = countResult && countResult.length > 0 ? countResult[0].total : 0;
1438
+ this.totalRecordsSignal.set(count);
1439
+ }
1440
+ catch (error) {
1441
+ console.error('Error loading data', error);
1442
+ }
1443
+ finally {
1444
+ this.isLoading = false;
1445
+ }
1446
+ }
1447
+ // Override onPageChange to update mongoState
1448
+ async onPageChange(pageEvent) {
1449
+ this.rows = pageEvent.rows;
1450
+ this.first = pageEvent.page * this.rows;
1451
+ this.mongoState.options.limit = this.rows;
1452
+ this.mongoState.options.skip = this.first;
1453
+ await this.loadData();
1454
+ // We can still update URL param if we want, calling super or copying logic
1455
+ // super.updatePageParam(pageEvent.page + 1); // private in super
1456
+ // We'll leave URL update for now or implement if needed.
1457
+ }
1458
+ onNew() {
1459
+ this.router.navigate(['./edit'], { relativeTo: this.route });
1460
+ }
1461
+ toggleView() {
1462
+ this.viewType.update((v) => (v === 'card' ? 'table' : 'card'));
1463
+ }
1464
+ async doAction(actionEvent) {
1465
+ const { item, action } = actionEvent;
1466
+ if (!item) {
1467
+ return;
1468
+ }
1469
+ const id = item?._id || item?.id;
1470
+ switch (action) {
1471
+ case 'view':
1472
+ this.router.navigate(['./details', id], { relativeTo: this.route });
1473
+ break;
1474
+ case 'edit':
1475
+ this.router.navigate(['./edit', id], { relativeTo: this.route });
1476
+ break;
1477
+ case 'delete':
1478
+ const confirmed = confirm(`Are you sure you want to delete this item?`);
1479
+ if (confirmed) {
1480
+ try {
1481
+ await this.entityCommunicationService.operation({
1482
+ action: 'deleteOne',
1483
+ query: { _id: id },
1484
+ });
1485
+ }
1486
+ catch (error) {
1487
+ console.error('Error deleting item', error);
1488
+ }
1489
+ finally {
1490
+ await this.loadData(); // Refresh list
1491
+ }
1492
+ }
1493
+ break;
1494
+ case 'clone':
1495
+ // Clone usually requires specific logic, maybe 'create' with modified data
1496
+ // Or if backend supports 'clone' action via operation?
1497
+ // The user listed: 'findOne', 'find', 'create', 'updateOne', 'updateMany', 'deleteOne', 'deleteMany', 'aggregate'.
1498
+ // No 'clone'. So we might need to fetch, remove _id, and create.
1499
+ const original = await this.entityCommunicationService.operation({ action: 'findOne', query: { _id: id } });
1500
+ if (original) {
1501
+ const { _id, ...rest } = original;
1502
+ // Maybe add 'Copy' to name?
1503
+ await this.entityCommunicationService.operation({ action: 'create', payload: { ...rest, name: rest.name + ' (Copy)' } }); // Assumption on 'name'
1504
+ await this.loadData();
1505
+ }
1506
+ break;
1507
+ case 'search':
1508
+ // Search usually updates query
1509
+ // This depends on how the filter bar sends events.
1510
+ // If it sends a text, we might want to regex search on some fields.
1511
+ // This logic might be better in the child component or configurable.
1512
+ break;
1513
+ default:
1514
+ // this.handleCustomAction(actionEvent);
1515
+ }
1516
+ }
1517
+ // Helper to update query from filter bar
1518
+ updateQueryFromFilter(filterConfig) {
1519
+ // Map filterConfig.filters to mongoState.query
1520
+ // The filter bar returns { filters: { ... }, sort: ... }
1521
+ if (filterConfig.filters) {
1522
+ this.mongoState.query = { ...this.mongoState.query, ...filterConfig.filters };
1523
+ }
1524
+ if (filterConfig.sort) {
1525
+ this.mongoState.options.sort = filterConfig.sort;
1526
+ }
1527
+ if (filterConfig.text) {
1528
+ // Handle text search if needed, or let child handle it
1529
+ }
1530
+ // Reset pagination on filter change
1531
+ this.first = 0;
1532
+ this.mongoState.options.skip = 0;
1533
+ this.loadData();
1534
+ }
1535
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.1.6", ngImport: i0, type: EntityBaseListV2Component, deps: [], target: i0.ɵɵFactoryTarget.Directive }); }
1536
+ static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "17.1.0", version: "20.1.6", type: EntityBaseListV2Component, isStandalone: true, inputs: { initialViewType: { classPropertyName: "initialViewType", publicName: "initialViewType", isSignal: true, isRequired: false, transformFunction: null }, onlyView: { classPropertyName: "onlyView", publicName: "onlyView", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { onSelect: "onSelect" }, usesInheritance: true, ngImport: i0 }); }
1537
+ }
1538
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.1.6", ngImport: i0, type: EntityBaseListV2Component, decorators: [{
1539
+ type: Directive
1540
+ }], ctorParameters: () => [] });
1541
+
1154
1542
  const TOAST_ALERTS_TOKEN = new InjectionToken('Toast alerts Service');
1155
1543
  class ToastAlertsAbstractService {
1156
1544
  }
@@ -1234,6 +1622,12 @@ class EntityBaseFormComponent {
1234
1622
  this.patchForm(result);
1235
1623
  return result;
1236
1624
  }
1625
+ reload() {
1626
+ const id = this.entityId();
1627
+ if (id) {
1628
+ this.loadEntityById(id);
1629
+ }
1630
+ }
1237
1631
  getDirtyValues(form) {
1238
1632
  const dirtyValues = {};
1239
1633
  Object.keys(form.controls).forEach((key) => {
@@ -3243,6 +3637,10 @@ class EntityCommunicationService {
3243
3637
  clone(id, overrides = {}) {
3244
3638
  return this.httpService.postHttp({ service: `api/${this.serviceName}/${id}/clone`, data: overrides });
3245
3639
  }
3640
+ operation(params) {
3641
+ debugger;
3642
+ return this.httpService.postHttp({ service: `api/${this.serviceName}/operation`, data: params, host: this.customHost });
3643
+ }
3246
3644
  static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.1.6", ngImport: i0, type: EntityCommunicationService, deps: "invalid", target: i0.ɵɵFactoryTarget.Injectable }); }
3247
3645
  static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.1.6", ngImport: i0, type: EntityCommunicationService }); }
3248
3646
  }
@@ -3289,6 +3687,17 @@ class FormUtilsService {
3289
3687
  tags: this.fb.array([]),
3290
3688
  });
3291
3689
  }
3690
+ patchLearnableFormGroup(form, data) {
3691
+ if (data.tags) {
3692
+ this.patchFormArray(form.controls.tags, data.tags);
3693
+ }
3694
+ }
3695
+ patchFormArray(formArray, values) {
3696
+ formArray.clear();
3697
+ values.forEach((value) => {
3698
+ formArray.push(this.fb.control(value));
3699
+ });
3700
+ }
3292
3701
  static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.1.6", ngImport: i0, type: FormUtilsService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
3293
3702
  static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.1.6", ngImport: i0, type: FormUtilsService, providedIn: 'root' }); }
3294
3703
  }
@@ -3504,5 +3913,5 @@ const CharacterEventActions = [
3504
3913
  * Generated bundle index. Do not edit.
3505
3914
  */
3506
3915
 
3507
- export { APP_CONFIG, AppConfigService, AudioNotificationService, AudioSpeed, AudioSpeedReverse, CharacterEventActions, ChatUserSettings, ConfirmComponent, ConfirmService, DCFilterBarComponent, DCProgressToastComponent, DcAuditableViewerComponent, DcExtensionsViewerComponent, DcLearnableFormComponent, DcLearnableViewerComponent, DcManageableFormComponent, DcManageableViewerComponent, DcReactionsViewerComponent, EModelQuality, EmptyStateComponent, EntityBaseFormComponent, EntityBaseListComponent, EntityCommunicationService, FlagPipe, FormUtilsService, GetPathPipe, HTTP_CORE_CONFIG, HttpCoreService, IAIModel, LANGUAGES, LangDescTranslation, LoadingBarComponent, LoadingBarService, MobileService, ModelQualityOptions, MoodState, MoodStateOptions, OptionValue, PaginationBase, PromptService, QuickTableComponent, SUPPORTED_LANGUAGES, TOAST_ALERTS_TOKEN, ToastAlertsAbstractService, UiStateService, availibleFilters, extractJsonFromString, formatCamelCaseString, getLangDesc, getSupportedLanguageOptions, provideToastAlert, sortOptions, sortTypes };
3916
+ export { APP_CONFIG, AppConfigService, AudioNotificationService, AudioSpeed, AudioSpeedReverse, CharacterEventActions, ChatUserSettings, ConfirmComponent, ConfirmService, DCFilterBarComponent, DCProgressToastComponent, DcAuditableViewerComponent, DcExtensionsViewerComponent, DcLearnableFormComponent, DcLearnableViewerComponent, DcManageableFormComponent, DcManageableViewerComponent, DcReactionsViewerComponent, DcTagsFormComponent, EModelQuality, EmptyStateComponent, EntityBaseFormComponent, EntityBaseListComponent, EntityBaseListV2Component, EntityCommunicationService, FlagPipe, FormUtilsService, GetPathPipe, HTTP_CORE_CONFIG, HttpCoreService, IAIModel, LANGUAGES, LangDescTranslation, LoadingBarComponent, LoadingBarService, MobileService, ModelQualityOptions, MoodState, MoodStateOptions, OptionValue, PaginationBase, PromptService, QuickTableComponent, SUPPORTED_LANGUAGES, TOAST_ALERTS_TOKEN, ToastAlertsAbstractService, UiStateService, availibleFilters, extractJsonFromString, formatCamelCaseString, getLangDesc, getSupportedLanguageOptions, provideToastAlert, sortOptions, sortTypes };
3508
3917
  //# sourceMappingURL=dataclouder-ngx-core.mjs.map