@dataclouder/ngx-core 0.1.47 → 0.1.49
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.
|
@@ -218,9 +218,10 @@ class DcListFilterDialogComponent {
|
|
|
218
218
|
this.ref = inject(DynamicDialogRef);
|
|
219
219
|
this.config = inject(DynamicDialogConfig);
|
|
220
220
|
this.customFilters = this.config.data.customFilters || [];
|
|
221
|
+
this.customSortOptions = this.config.data.customSortOptions || [];
|
|
221
222
|
this.initialUiState = this.config.data.uiState || {};
|
|
222
223
|
this.availibleFilters = availibleFilters;
|
|
223
|
-
this.sortOptions = sortOptions;
|
|
224
|
+
this.sortOptions = [...sortOptions, ...this.customSortOptions];
|
|
224
225
|
this.selectedFilters = [];
|
|
225
226
|
this.selectedSort = null;
|
|
226
227
|
this.dateRange = [];
|
|
@@ -228,7 +229,6 @@ class DcListFilterDialogComponent {
|
|
|
228
229
|
this.restoreState();
|
|
229
230
|
}
|
|
230
231
|
buildCustomFiltersForm() {
|
|
231
|
-
debugger;
|
|
232
232
|
const formControls = {};
|
|
233
233
|
for (const filter of this.customFilters) {
|
|
234
234
|
formControls[filter.field] = [filter.defaultValue || null];
|
|
@@ -280,11 +280,11 @@ class DcListFilterDialogComponent {
|
|
|
280
280
|
});
|
|
281
281
|
}
|
|
282
282
|
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.1.6", ngImport: i0, type: DcListFilterDialogComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
|
|
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 }); }
|
|
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 [showClear]=\"true\"\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 }); }
|
|
284
284
|
}
|
|
285
285
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.1.6", ngImport: i0, type: DcListFilterDialogComponent, decorators: [{
|
|
286
286
|
type: Component,
|
|
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"] }]
|
|
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 [showClear]=\"true\"\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"] }]
|
|
288
288
|
}], ctorParameters: () => [] });
|
|
289
289
|
|
|
290
290
|
const DEFAULT_FILTERS = { filters: {}, page: 0, rowsPerPage: 10, sort: { _id: -1 } };
|
|
@@ -297,6 +297,7 @@ class DCFilterBarComponent {
|
|
|
297
297
|
this.options = input({ showCreateButton: true }, ...(ngDevMode ? [{ debugName: "options" }] : []));
|
|
298
298
|
// Inputs
|
|
299
299
|
this.customFilters = [];
|
|
300
|
+
this.customSortOptions = [];
|
|
300
301
|
this.isAdmin = false;
|
|
301
302
|
this.persistenceKey = ''; // Key for saving/loading filters
|
|
302
303
|
// Outputs
|
|
@@ -309,7 +310,7 @@ class DCFilterBarComponent {
|
|
|
309
310
|
this.uiState = null; // Store UI state separately
|
|
310
311
|
}
|
|
311
312
|
ngOnInit() {
|
|
312
|
-
//
|
|
313
|
+
//
|
|
313
314
|
if (this.persistenceKey) {
|
|
314
315
|
this.loadSavedFilters();
|
|
315
316
|
}
|
|
@@ -351,6 +352,7 @@ class DCFilterBarComponent {
|
|
|
351
352
|
contentStyle: { 'max-height': '90vh', overflow: 'auto', 'min-height': '500px', height: '100%' },
|
|
352
353
|
data: {
|
|
353
354
|
customFilters: this.customFilters,
|
|
355
|
+
customSortOptions: this.customSortOptions,
|
|
354
356
|
uiState: this.uiState, // Pass current UI state to dialog
|
|
355
357
|
},
|
|
356
358
|
closable: true,
|
|
@@ -370,25 +372,32 @@ class DCFilterBarComponent {
|
|
|
370
372
|
}
|
|
371
373
|
applyFilters(result) {
|
|
372
374
|
// result.filters is now the Mongo Query
|
|
373
|
-
|
|
375
|
+
// We replace the filters entirely with the result from the dialog,
|
|
376
|
+
// instead of merging, to ensure removed filters are cleared.
|
|
377
|
+
const newFilters = { ...result.filters };
|
|
374
378
|
let newSort = this.filter.sort;
|
|
375
379
|
if (result.sort) {
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
380
|
+
if (result.sort.mongoSort) {
|
|
381
|
+
newSort = result.sort.mongoSort;
|
|
382
|
+
}
|
|
383
|
+
else {
|
|
384
|
+
switch (result.sort.value) {
|
|
385
|
+
case 'newest':
|
|
386
|
+
newSort = { createdAt: -1 };
|
|
387
|
+
break;
|
|
388
|
+
case 'oldest':
|
|
389
|
+
newSort = { createdAt: 1 };
|
|
390
|
+
break;
|
|
391
|
+
case 'alphabetical':
|
|
392
|
+
newSort = { name: 1 };
|
|
393
|
+
break;
|
|
394
|
+
case 'reverseAlphabetical':
|
|
395
|
+
newSort = { name: -1 };
|
|
396
|
+
break;
|
|
397
|
+
case 'lastUpdated':
|
|
398
|
+
newSort = { updatedAt: -1 };
|
|
399
|
+
break;
|
|
400
|
+
}
|
|
392
401
|
}
|
|
393
402
|
}
|
|
394
403
|
this.filter = { ...this.filter, filters: newFilters, sort: newSort };
|
|
@@ -413,13 +422,15 @@ class DCFilterBarComponent {
|
|
|
413
422
|
this.onFilterAction.emit(filterEvent);
|
|
414
423
|
}
|
|
415
424
|
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.1.6", ngImport: i0, type: DCFilterBarComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
|
|
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 }
|
|
425
|
+
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 }, customSortOptions: { classPropertyName: "customSortOptions", publicName: "customSortOptions", 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 }\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 }); }
|
|
417
426
|
}
|
|
418
427
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.1.6", ngImport: i0, type: DCFilterBarComponent, decorators: [{
|
|
419
428
|
type: Component,
|
|
420
|
-
args: [{ selector: 'dc-filter-bar', standalone: true, imports: [FormsModule, ButtonModule, DialogModule, InputTextModule, InputGroupModule, InputGroupAddonModule], changeDetection: ChangeDetectionStrategy.OnPush, providers: [DialogService], 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 }
|
|
429
|
+
args: [{ selector: 'dc-filter-bar', standalone: true, imports: [FormsModule, ButtonModule, DialogModule, InputTextModule, InputGroupModule, InputGroupAddonModule], changeDetection: ChangeDetectionStrategy.OnPush, providers: [DialogService], 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 }\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"] }]
|
|
421
430
|
}], propDecorators: { customFilters: [{
|
|
422
431
|
type: Input
|
|
432
|
+
}], customSortOptions: [{
|
|
433
|
+
type: Input
|
|
423
434
|
}], isAdmin: [{
|
|
424
435
|
type: Input
|
|
425
436
|
}], persistenceKey: [{
|
|
@@ -1343,7 +1354,6 @@ class EntityBaseListComponent extends PaginationBase {
|
|
|
1343
1354
|
await this.loadData(); // Refresh list
|
|
1344
1355
|
break;
|
|
1345
1356
|
case 'search':
|
|
1346
|
-
debugger;
|
|
1347
1357
|
this.filterConfig.text = item;
|
|
1348
1358
|
this.loadData();
|
|
1349
1359
|
break;
|
|
@@ -1375,6 +1385,7 @@ class EntityBaseListV2Component extends PaginationBase {
|
|
|
1375
1385
|
// Public properties for configuration
|
|
1376
1386
|
this.filterBarOptions = { showActions: true, showCreateButton: true, showViewButton: true };
|
|
1377
1387
|
this.columns = [];
|
|
1388
|
+
this.fixedQuery = {};
|
|
1378
1389
|
// New State Management
|
|
1379
1390
|
this.mongoState = {
|
|
1380
1391
|
query: {},
|
|
@@ -1401,38 +1412,22 @@ class EntityBaseListV2Component extends PaginationBase {
|
|
|
1401
1412
|
async loadData() {
|
|
1402
1413
|
try {
|
|
1403
1414
|
this.isLoading = true;
|
|
1404
|
-
// Sync PaginationBase state to MongoState
|
|
1405
1415
|
this.mongoState.options.limit = this.rows;
|
|
1406
1416
|
this.mongoState.options.skip = this.first;
|
|
1407
|
-
|
|
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
|
|
1417
|
+
const effectiveQuery = { ...this.mongoState.query, ...this.fixedQuery };
|
|
1411
1418
|
const response = await this.entityCommunicationService.operation({
|
|
1412
1419
|
action: 'find',
|
|
1413
|
-
query:
|
|
1420
|
+
query: effectiveQuery,
|
|
1414
1421
|
projection: this.mongoState.projection,
|
|
1415
1422
|
options: this.mongoState.options,
|
|
1416
1423
|
payload: this.mongoState.payload,
|
|
1417
1424
|
});
|
|
1418
|
-
|
|
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[]
|
|
1425
|
+
this.items.set(response);
|
|
1431
1426
|
// We need total records for pagination.
|
|
1432
1427
|
// Use aggregate to count since 'count' action might not be explicitly supported or to be safe
|
|
1433
1428
|
const countResult = await this.entityCommunicationService.operation({
|
|
1434
1429
|
action: 'aggregate',
|
|
1435
|
-
payload: [{ $match:
|
|
1430
|
+
payload: [{ $match: effectiveQuery }, { $count: 'total' }],
|
|
1436
1431
|
});
|
|
1437
1432
|
const count = countResult && countResult.length > 0 ? countResult[0].total : 0;
|
|
1438
1433
|
this.totalRecordsSignal.set(count);
|
|
@@ -1534,7 +1529,9 @@ class EntityBaseListV2Component extends PaginationBase {
|
|
|
1534
1529
|
// Map filterConfig.filters to mongoState.query
|
|
1535
1530
|
// The filter bar returns { filters: { ... }, sort: ... }
|
|
1536
1531
|
if (filterConfig.filters) {
|
|
1537
|
-
|
|
1532
|
+
// Preserve $text search if it exists, as it is managed separately via 'search' action
|
|
1533
|
+
const textQuery = this.mongoState.query.$text ? { $text: this.mongoState.query.$text } : {};
|
|
1534
|
+
this.mongoState.query = { ...textQuery, ...filterConfig.filters };
|
|
1538
1535
|
}
|
|
1539
1536
|
if (filterConfig.sort) {
|
|
1540
1537
|
this.mongoState.options.sort = filterConfig.sort;
|
|
@@ -2876,8 +2873,31 @@ const LANGUAGES = {
|
|
|
2876
2873
|
},
|
|
2877
2874
|
};
|
|
2878
2875
|
function getLangDesc(langCode, lang = 'en') {
|
|
2879
|
-
|
|
2876
|
+
const languageData = LANGUAGES[langCode];
|
|
2877
|
+
if (languageData && languageData.translations) {
|
|
2878
|
+
return languageData.translations[lang] || languageData.nativeName;
|
|
2879
|
+
}
|
|
2880
|
+
return langCode;
|
|
2880
2881
|
}
|
|
2882
|
+
/**
|
|
2883
|
+
* How to use this pipe
|
|
2884
|
+
* @example
|
|
2885
|
+
* // In your component ts file assuming you have a variable with the lang code
|
|
2886
|
+
*
|
|
2887
|
+
* \@Component({
|
|
2888
|
+
* selector: 'app-example',
|
|
2889
|
+
* template: `
|
|
2890
|
+
* <span>{{'en' | langDesc: 'es'}}</span>
|
|
2891
|
+
* `,
|
|
2892
|
+
* standalone: true,
|
|
2893
|
+
* imports: [LangDescTranslation]
|
|
2894
|
+
* })
|
|
2895
|
+
*
|
|
2896
|
+
*
|
|
2897
|
+
* class ExampleComponent {
|
|
2898
|
+
* }
|
|
2899
|
+
*
|
|
2900
|
+
*/
|
|
2881
2901
|
function getSupportedLanguageOptions(lang = 'es') {
|
|
2882
2902
|
return SUPPORTED_LANGUAGES.map((langCode) => ({
|
|
2883
2903
|
value: langCode,
|
|
@@ -2887,7 +2907,8 @@ function getSupportedLanguageOptions(lang = 'es') {
|
|
|
2887
2907
|
|
|
2888
2908
|
class LangDescTranslation {
|
|
2889
2909
|
transform(value, lang) {
|
|
2890
|
-
|
|
2910
|
+
const validLang = lang === 'es' ? 'es' : 'en';
|
|
2911
|
+
return getLangDesc(value, validLang);
|
|
2891
2912
|
}
|
|
2892
2913
|
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.1.6", ngImport: i0, type: LangDescTranslation, deps: [], target: i0.ɵɵFactoryTarget.Pipe }); }
|
|
2893
2914
|
static { this.ɵpipe = i0.ɵɵngDeclarePipe({ minVersion: "14.0.0", version: "20.1.6", ngImport: i0, type: LangDescTranslation, isStandalone: true, name: "langDesc" }); }
|
|
@@ -3652,8 +3673,10 @@ class EntityCommunicationService {
|
|
|
3652
3673
|
clone(id, overrides = {}) {
|
|
3653
3674
|
return this.httpService.postHttp({ service: `api/${this.serviceName}/${id}/clone`, data: overrides });
|
|
3654
3675
|
}
|
|
3676
|
+
getFixedQuery() {
|
|
3677
|
+
return {};
|
|
3678
|
+
}
|
|
3655
3679
|
operation(params) {
|
|
3656
|
-
debugger;
|
|
3657
3680
|
return this.httpService.postHttp({ service: `api/${this.serviceName}/operation`, data: params, host: this.customHost });
|
|
3658
3681
|
}
|
|
3659
3682
|
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.1.6", ngImport: i0, type: EntityCommunicationService, deps: "invalid", target: i0.ɵɵFactoryTarget.Injectable }); }
|
|
@@ -3703,7 +3726,7 @@ class FormUtilsService {
|
|
|
3703
3726
|
});
|
|
3704
3727
|
}
|
|
3705
3728
|
patchLearnableFormGroup(form, data) {
|
|
3706
|
-
if (data
|
|
3729
|
+
if (data && data?.tags) {
|
|
3707
3730
|
this.patchFormArray(form.controls.tags, data.tags);
|
|
3708
3731
|
}
|
|
3709
3732
|
}
|