@sdcorejs/angular 19.0.9 → 19.0.11
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.
- package/README.md +270 -140
- package/assets/STYLE-GUIDE.md +2 -2
- package/assets/scss/core/_inline-edit.scss +1 -1
- package/assets/scss/core/form.scss +1 -1
- package/assets/scss/core/utilities/_grid.scss +25 -19
- package/assets/scss/themes/default.scss +2 -2
- package/components/anchor/src/models/sd-anchor.model.d.ts +1 -1
- package/components/badge/src/badge.component.d.ts +3 -14
- package/components/button/src/button.component.d.ts +5 -3
- package/components/document-builder/src/document-builder.component.d.ts +2 -2
- package/components/document-builder/src/plugins/paste-handler/filters/parse.d.ts +1 -1
- package/components/editor/src/plugins/image-upload/utils/batch.utils.d.ts +3 -3
- package/components/form-generic/src/components/form-builder/components/attribute-expression/attribute-expression.component.d.ts +10 -6
- package/components/form-generic/src/components/form-builder/components/attribute-expression/form-expression-query-adapter.d.ts +6 -0
- package/components/form-generic/src/components/form-builder/components/attribute-parameter/attribute-parameter.component.d.ts +2 -2
- package/components/form-generic/src/components/form-builder/components/attribute-selection/attribute-selection.component.d.ts +2 -2
- package/components/form-generic/src/components/form-builder/components/attribute-selection/components/build-queries/build-queries.component.d.ts +2 -2
- package/components/form-generic/src/components/form-builder/components/attribute-selection/components/build-variables/build-variables.component.d.ts +2 -2
- package/components/form-generic/src/components/form-builder/components/attribute-table/attribute-table.component.d.ts +2 -4
- package/components/form-generic/src/components/form-builder/components/attribute-template/attribute-template.component.d.ts +2 -4
- package/components/form-generic/src/components/form-builder/components/checkbox/attribute/checkbox-attribute.component.d.ts +2 -2
- package/components/form-generic/src/components/form-builder/components/chip-calendar/attribute/chip-calendar-attribute.component.d.ts +2 -2
- package/components/form-generic/src/components/form-builder/components/chip-calendar/control/chip-calendar-control.component.d.ts +2 -2
- package/components/form-generic/src/components/form-builder/components/chip-string/attribute/chip-string-attribute.component.d.ts +2 -2
- package/components/form-generic/src/components/form-builder/components/chip-string/control/chip-string-control.component.d.ts +2 -2
- package/components/form-generic/src/components/form-builder/components/configure-validation/configure-validation.component.d.ts +6 -7
- package/components/form-generic/src/components/form-builder/components/datetime/attribute/datetime-attribute.component.d.ts +2 -2
- package/components/form-generic/src/components/form-builder/components/datetime/control/datetime-control.component.d.ts +2 -2
- package/components/form-generic/src/components/form-builder/components/expression-builder/expression-builder.component.d.ts +2 -2
- package/components/form-generic/src/components/form-builder/components/html/attribute/components/build-queries/build-queries.component.d.ts +2 -2
- package/components/form-generic/src/components/form-builder/components/html/control/html-control.component.d.ts +2 -2
- package/components/form-generic/src/components/form-builder/components/number/attribute/number-attribute.component.d.ts +2 -2
- package/components/form-generic/src/components/form-builder/components/number/control/number-control.component.d.ts +2 -2
- package/components/form-generic/src/components/form-builder/components/radio/attribute/radio-attribute.component.d.ts +2 -2
- package/components/form-generic/src/components/form-builder/components/radio/control/radio-control.component.d.ts +2 -2
- package/components/form-generic/src/components/form-builder/components/select/attribute/select-attribute.component.d.ts +2 -2
- package/components/form-generic/src/components/form-builder/components/select/control/select-control.component.d.ts +2 -2
- package/components/form-generic/src/components/form-builder/components/table/attribute/table-attribute.component.d.ts +2 -2
- package/components/form-generic/src/components/form-builder/components/table/control/table-control.component.d.ts +2 -2
- package/components/form-generic/src/components/form-builder/components/textarea/attribute/textarea-attribute.component.d.ts +2 -2
- package/components/form-generic/src/components/form-builder/components/textarea/control/textarea-control.component.d.ts +2 -2
- package/components/form-generic/src/components/form-builder/components/textfield/attribute/textfield-attribute.component.d.ts +2 -2
- package/components/form-generic/src/components/form-builder/components/textfield/control/textfield-control.component.d.ts +2 -2
- package/components/form-generic/src/components/form-builder/components/upload/attribute/upload-attribute.component.d.ts +2 -2
- package/components/form-generic/src/components/form-builder/components/upload/control/upload-control.component.d.ts +2 -2
- package/components/form-generic/src/components/form-builder/form-builder-layout.d.ts +22 -0
- package/components/form-generic/src/components/form-builder/form-builder.component.d.ts +24 -5
- package/components/form-generic/src/components/form-render/components/item/components/chip-calendar/chip-calendar.component.d.ts +2 -2
- package/components/form-generic/src/components/form-render/components/item/components/chip-string/chip-string.component.d.ts +2 -2
- package/components/form-generic/src/components/form-render/components/item/components/datetime/datetime.component.d.ts +2 -2
- package/components/form-generic/src/components/form-render/components/item/components/html/html.component.d.ts +2 -2
- package/components/form-generic/src/components/form-render/components/item/components/number/number.component.d.ts +2 -2
- package/components/form-generic/src/components/form-render/components/item/components/radio/radio.component.d.ts +2 -2
- package/components/form-generic/src/components/form-render/components/item/components/select/select.component.d.ts +2 -2
- package/components/form-generic/src/components/form-render/components/item/components/table/table.component.d.ts +2 -2
- package/components/form-generic/src/components/form-render/components/item/components/textarea/textarea.component.d.ts +2 -2
- package/components/form-generic/src/components/form-render/components/item/components/textfield/textfield.component.d.ts +2 -2
- package/components/form-generic/src/components/form-render/components/item/components/upload/upload.component.d.ts +2 -2
- package/components/form-generic/src/components/form-render/components/variable/variable.component.d.ts +2 -2
- package/components/form-generic/src/components/form-render/form-render.component.d.ts +4 -6
- package/components/form-generic/src/components/sd-feel-expression/sd-feel-expression.component.d.ts +2 -2
- package/components/form-generic/src/configurations/form.configuration.d.ts +1 -1
- package/components/form-generic/src/models/form-generic-component.model.d.ts +2 -2
- package/components/form-generic/src/services/form-generic.service.d.ts +1 -3
- package/components/import-excel/src/import-excel.model.d.ts +2 -2
- package/components/inform/src/inform.component.d.ts +2 -8
- package/components/mini-editor/src/mini-editor.component.d.ts +4 -4
- package/components/modal/src/modal.component.d.ts +1 -1
- package/components/query-builder/src/query-builder.component.d.ts +3 -3
- package/components/query-builder/src/query-builder.model.d.ts +4 -4
- package/components/splitter/src/splitter-state.service.d.ts +1 -1
- package/components/tab-router/src/models/tab-router.model.d.ts +2 -1
- package/components/tab-router/src/services/tab-router.service.d.ts +0 -1
- package/components/table/src/components/command/desktop-command.component.d.ts +7 -7
- package/components/table/src/components/command/pipes/command.pipe.d.ts +1 -12
- package/components/table/src/components/command/pipes/filter.pipe.d.ts +1 -8
- package/components/table/src/components/filter/column-filter/column-filter.component.d.ts +1 -0
- package/components/table/src/models/table-column.model.d.ts +3 -2
- package/components/table/src/models/table-command.model.d.ts +3 -3
- package/components/table/src/models/table-option-selector.model.d.ts +5 -5
- package/components/table/src/pipes/selection-disabled.pipe.d.ts +1 -1
- package/components/table/src/services/config.service.d.ts +4 -5
- package/components/tree/src/tree.model.d.ts +3 -2
- package/components/view/src/view.component.d.ts +1 -1
- package/configurations/src/sd-core.configuration.d.ts +2 -2
- package/fesm2022/sdcorejs-angular-components-anchor.mjs +20 -24
- package/fesm2022/sdcorejs-angular-components-anchor.mjs.map +1 -1
- package/fesm2022/sdcorejs-angular-components-autoid-inspector.mjs +4 -5
- package/fesm2022/sdcorejs-angular-components-autoid-inspector.mjs.map +1 -1
- package/fesm2022/sdcorejs-angular-components-avatar.mjs.map +1 -1
- package/fesm2022/sdcorejs-angular-components-badge.mjs +14 -13
- package/fesm2022/sdcorejs-angular-components-badge.mjs.map +1 -1
- package/fesm2022/sdcorejs-angular-components-button.mjs +15 -17
- package/fesm2022/sdcorejs-angular-components-button.mjs.map +1 -1
- package/fesm2022/sdcorejs-angular-components-chart.mjs.map +1 -1
- package/fesm2022/sdcorejs-angular-components-ckeditor-styles.mjs.map +1 -1
- package/fesm2022/sdcorejs-angular-components-code-editor.mjs +5 -6
- package/fesm2022/sdcorejs-angular-components-code-editor.mjs.map +1 -1
- package/fesm2022/sdcorejs-angular-components-document-builder.mjs +17 -26
- package/fesm2022/sdcorejs-angular-components-document-builder.mjs.map +1 -1
- package/fesm2022/sdcorejs-angular-components-editor.mjs +11 -7
- package/fesm2022/sdcorejs-angular-components-editor.mjs.map +1 -1
- package/fesm2022/sdcorejs-angular-components-form-generic.mjs +715 -436
- package/fesm2022/sdcorejs-angular-components-form-generic.mjs.map +1 -1
- package/fesm2022/sdcorejs-angular-components-history.mjs +2 -2
- package/fesm2022/sdcorejs-angular-components-history.mjs.map +1 -1
- package/fesm2022/sdcorejs-angular-components-import-excel.mjs +38 -23
- package/fesm2022/sdcorejs-angular-components-import-excel.mjs.map +1 -1
- package/fesm2022/sdcorejs-angular-components-inform.mjs +5 -16
- package/fesm2022/sdcorejs-angular-components-inform.mjs.map +1 -1
- package/fesm2022/sdcorejs-angular-components-mini-editor.mjs.map +1 -1
- package/fesm2022/sdcorejs-angular-components-modal-resizable.mjs +5 -6
- package/fesm2022/sdcorejs-angular-components-modal-resizable.mjs.map +1 -1
- package/fesm2022/sdcorejs-angular-components-modal.mjs +28 -18
- package/fesm2022/sdcorejs-angular-components-modal.mjs.map +1 -1
- package/fesm2022/sdcorejs-angular-components-operator.mjs +1 -1
- package/fesm2022/sdcorejs-angular-components-operator.mjs.map +1 -1
- package/fesm2022/sdcorejs-angular-components-org-chart.mjs +4 -5
- package/fesm2022/sdcorejs-angular-components-org-chart.mjs.map +1 -1
- package/fesm2022/sdcorejs-angular-components-preview.mjs +40 -37
- package/fesm2022/sdcorejs-angular-components-preview.mjs.map +1 -1
- package/fesm2022/sdcorejs-angular-components-query-bar.mjs +38 -55
- package/fesm2022/sdcorejs-angular-components-query-bar.mjs.map +1 -1
- package/fesm2022/sdcorejs-angular-components-query-builder.mjs +5 -7
- package/fesm2022/sdcorejs-angular-components-query-builder.mjs.map +1 -1
- package/fesm2022/sdcorejs-angular-components-quick-action.mjs.map +1 -1
- package/fesm2022/sdcorejs-angular-components-section.mjs +3 -5
- package/fesm2022/sdcorejs-angular-components-section.mjs.map +1 -1
- package/fesm2022/sdcorejs-angular-components-side-drawer.mjs +6 -7
- package/fesm2022/sdcorejs-angular-components-side-drawer.mjs.map +1 -1
- package/fesm2022/sdcorejs-angular-components-splitter.mjs +4 -4
- package/fesm2022/sdcorejs-angular-components-splitter.mjs.map +1 -1
- package/fesm2022/sdcorejs-angular-components-stepper.mjs +3 -4
- package/fesm2022/sdcorejs-angular-components-stepper.mjs.map +1 -1
- package/fesm2022/sdcorejs-angular-components-tab-router.mjs +36 -37
- package/fesm2022/sdcorejs-angular-components-tab-router.mjs.map +1 -1
- package/fesm2022/sdcorejs-angular-components-tab.mjs +3 -4
- package/fesm2022/sdcorejs-angular-components-tab.mjs.map +1 -1
- package/fesm2022/sdcorejs-angular-components-table.mjs +79 -101
- package/fesm2022/sdcorejs-angular-components-table.mjs.map +1 -1
- package/fesm2022/sdcorejs-angular-components-tree.mjs +6 -8
- package/fesm2022/sdcorejs-angular-components-tree.mjs.map +1 -1
- package/fesm2022/sdcorejs-angular-components-upload-file.mjs +14 -15
- package/fesm2022/sdcorejs-angular-components-upload-file.mjs.map +1 -1
- package/fesm2022/sdcorejs-angular-components-view.mjs +3 -9
- package/fesm2022/sdcorejs-angular-components-view.mjs.map +1 -1
- package/fesm2022/sdcorejs-angular-configurations.mjs.map +1 -1
- package/fesm2022/sdcorejs-angular-directives.mjs +2 -7
- package/fesm2022/sdcorejs-angular-directives.mjs.map +1 -1
- package/fesm2022/sdcorejs-angular-forms-autocomplete.mjs +5 -10
- package/fesm2022/sdcorejs-angular-forms-autocomplete.mjs.map +1 -1
- package/fesm2022/sdcorejs-angular-forms-checkbox.mjs.map +1 -1
- package/fesm2022/sdcorejs-angular-forms-chip-calendar.mjs +9 -11
- package/fesm2022/sdcorejs-angular-forms-chip-calendar.mjs.map +1 -1
- package/fesm2022/sdcorejs-angular-forms-chip.mjs +7 -9
- package/fesm2022/sdcorejs-angular-forms-chip.mjs.map +1 -1
- package/fesm2022/sdcorejs-angular-forms-date-range.mjs +8 -12
- package/fesm2022/sdcorejs-angular-forms-date-range.mjs.map +1 -1
- package/fesm2022/sdcorejs-angular-forms-date.mjs +8 -12
- package/fesm2022/sdcorejs-angular-forms-date.mjs.map +1 -1
- package/fesm2022/sdcorejs-angular-forms-datetime.mjs +7 -13
- package/fesm2022/sdcorejs-angular-forms-datetime.mjs.map +1 -1
- package/fesm2022/sdcorejs-angular-forms-inline-text.mjs +4 -5
- package/fesm2022/sdcorejs-angular-forms-inline-text.mjs.map +1 -1
- package/fesm2022/sdcorejs-angular-forms-input-color.mjs +3 -3
- package/fesm2022/sdcorejs-angular-forms-input-color.mjs.map +1 -1
- package/fesm2022/sdcorejs-angular-forms-input-number.mjs +6 -8
- package/fesm2022/sdcorejs-angular-forms-input-number.mjs.map +1 -1
- package/fesm2022/sdcorejs-angular-forms-input.mjs +5 -7
- package/fesm2022/sdcorejs-angular-forms-input.mjs.map +1 -1
- package/fesm2022/sdcorejs-angular-forms-label.mjs +4 -6
- package/fesm2022/sdcorejs-angular-forms-label.mjs.map +1 -1
- package/fesm2022/sdcorejs-angular-forms-models.mjs.map +1 -1
- package/fesm2022/sdcorejs-angular-forms-radio.mjs +12 -4
- package/fesm2022/sdcorejs-angular-forms-radio.mjs.map +1 -1
- package/fesm2022/sdcorejs-angular-forms-select.mjs +51 -22
- package/fesm2022/sdcorejs-angular-forms-select.mjs.map +1 -1
- package/fesm2022/sdcorejs-angular-forms-switch.mjs.map +1 -1
- package/fesm2022/sdcorejs-angular-forms-textarea.mjs +7 -9
- package/fesm2022/sdcorejs-angular-forms-textarea.mjs.map +1 -1
- package/fesm2022/sdcorejs-angular-handlers.mjs +3 -6
- package/fesm2022/sdcorejs-angular-handlers.mjs.map +1 -1
- package/fesm2022/sdcorejs-angular-i18n.mjs +11 -7
- package/fesm2022/sdcorejs-angular-i18n.mjs.map +1 -1
- package/fesm2022/sdcorejs-angular-interceptors.mjs +0 -2
- package/fesm2022/sdcorejs-angular-interceptors.mjs.map +1 -1
- package/fesm2022/sdcorejs-angular-modules-auth.mjs +14 -38
- package/fesm2022/sdcorejs-angular-modules-auth.mjs.map +1 -1
- package/fesm2022/sdcorejs-angular-modules-authom.mjs +14 -14
- package/fesm2022/sdcorejs-angular-modules-authom.mjs.map +1 -1
- package/fesm2022/sdcorejs-angular-modules-icon.mjs +523 -0
- package/fesm2022/sdcorejs-angular-modules-icon.mjs.map +1 -0
- package/fesm2022/sdcorejs-angular-modules-keycloak.mjs +22 -11
- package/fesm2022/sdcorejs-angular-modules-keycloak.mjs.map +1 -1
- package/fesm2022/sdcorejs-angular-modules-layout.mjs +53 -52
- package/fesm2022/sdcorejs-angular-modules-layout.mjs.map +1 -1
- package/fesm2022/sdcorejs-angular-modules-permission.mjs +5 -12
- package/fesm2022/sdcorejs-angular-modules-permission.mjs.map +1 -1
- package/fesm2022/sdcorejs-angular-modules.mjs +1 -0
- package/fesm2022/sdcorejs-angular-modules.mjs.map +1 -1
- package/fesm2022/sdcorejs-angular-pipes.mjs +71 -17
- package/fesm2022/sdcorejs-angular-pipes.mjs.map +1 -1
- package/fesm2022/sdcorejs-angular-services-api.mjs +0 -2
- package/fesm2022/sdcorejs-angular-services-api.mjs.map +1 -1
- package/fesm2022/sdcorejs-angular-services-cache.mjs +5 -11
- package/fesm2022/sdcorejs-angular-services-cache.mjs.map +1 -1
- package/fesm2022/sdcorejs-angular-services-confirm.mjs +19 -25
- package/fesm2022/sdcorejs-angular-services-confirm.mjs.map +1 -1
- package/fesm2022/sdcorejs-angular-services-docx.mjs +2 -8
- package/fesm2022/sdcorejs-angular-services-docx.mjs.map +1 -1
- package/fesm2022/sdcorejs-angular-services-excel.mjs +24 -16
- package/fesm2022/sdcorejs-angular-services-excel.mjs.map +1 -1
- package/fesm2022/sdcorejs-angular-services-license.mjs +5 -12
- package/fesm2022/sdcorejs-angular-services-license.mjs.map +1 -1
- package/fesm2022/sdcorejs-angular-services-notify.mjs +70 -87
- package/fesm2022/sdcorejs-angular-services-notify.mjs.map +1 -1
- package/fesm2022/sdcorejs-angular-services-storage.mjs +6 -15
- package/fesm2022/sdcorejs-angular-services-storage.mjs.map +1 -1
- package/fesm2022/sdcorejs-angular-utilities-data-state.mjs.map +1 -1
- package/fesm2022/sdcorejs-angular-utilities-extensions.mjs +47 -5
- package/fesm2022/sdcorejs-angular-utilities-extensions.mjs.map +1 -1
- package/fesm2022/sdcorejs-angular-utilities-models.mjs +21 -5
- package/fesm2022/sdcorejs-angular-utilities-models.mjs.map +1 -1
- package/fesm2022/sdcorejs-angular.mjs.map +1 -1
- package/forms/chip/src/chip.component.d.ts +2 -2
- package/forms/chip-calendar/src/chip-calendar.component.d.ts +2 -2
- package/forms/input-color/src/input-color.component.d.ts +2 -1
- package/forms/select/src/select-footer-action.directive.d.ts +5 -1
- package/forms/select/src/select.component.d.ts +4 -0
- package/modules/auth/guards/auth.guard.d.ts +2 -4
- package/modules/auth/guards/portal.guard.d.ts +2 -4
- package/modules/auth/services/auth.service.d.ts +3 -4
- package/modules/icon/index.d.ts +1 -0
- package/modules/icon/src/icon.component.d.ts +101 -0
- package/modules/icon/src/icon.model.d.ts +59 -0
- package/modules/icon/src/icon.provider.d.ts +33 -0
- package/modules/icon/src/index.d.ts +3 -0
- package/modules/index.d.ts +1 -0
- package/modules/layout/modules/home/guards/home-redirect.guard.d.ts +3 -5
- package/modules/permission/src/configurations/permission.configuration.d.ts +3 -3
- package/modules/permission/src/guards/permission.guard.d.ts +2 -5
- package/package.json +11 -6
- package/pipes/index.d.ts +3 -0
- package/pipes/src/format-date.pipe.d.ts +8 -0
- package/pipes/src/format-datetime.pipe.d.ts +8 -0
- package/pipes/src/format-number.pipe.d.ts +1 -3
- package/pipes/src/view.pipe.d.ts +7 -0
- package/services/confirm/src/lib/components/dialog-confirm/dialog-confirm.component.d.ts +3 -3
- package/services/excel/src/lib/spreadsheet-formula-injection.util.d.ts +5 -0
- package/services/license/src/license.service.d.ts +2 -3
- package/services/notify/src/components/toast/toast.component.d.ts +9 -13
- package/services/notify/src/notify.service.d.ts +4 -5
- package/services/storage/src/storage.service.d.ts +3 -4
- package/utilities/extensions/index.d.ts +1 -0
- package/utilities/extensions/src/object.extension.d.ts +8 -0
- package/utilities/models/src/icon.model.d.ts +4 -2
- package/components/document-builder/src/plugins/paste-handler/filters/replacetabswithinprewithspaces.d.ts +0 -24
|
@@ -1,39 +1,37 @@
|
|
|
1
1
|
import * as i0 from '@angular/core';
|
|
2
|
-
import { input, inject, TemplateRef, Directive, booleanAttribute, computed, ChangeDetectionStrategy, Component, model, output, isSignal, effect, Pipe, ChangeDetectorRef, signal, untracked, viewChild, InjectionToken,
|
|
2
|
+
import { input, inject, TemplateRef, Directive, booleanAttribute, computed, ChangeDetectionStrategy, Component, model, output, isSignal, effect, Pipe, ChangeDetectorRef, signal, untracked, viewChild, InjectionToken, Injectable, EventEmitter, Input, Output, ViewChild, ElementRef, DestroyRef, afterNextRender, Renderer2, NgZone, contentChild, contentChildren } from '@angular/core';
|
|
3
3
|
import { trigger, state, style, transition, animate } from '@angular/animations';
|
|
4
|
-
import * as i4$
|
|
4
|
+
import * as i4$2 from '@angular/material/paginator';
|
|
5
5
|
import { MatPaginatorIntl, MatPaginator, MatPaginatorModule } from '@angular/material/paginator';
|
|
6
|
-
import * as
|
|
6
|
+
import * as i6 from '@angular/material/sort';
|
|
7
7
|
import { MatSort, MatSortModule } from '@angular/material/sort';
|
|
8
|
-
import * as
|
|
8
|
+
import * as i5 from '@angular/material/table';
|
|
9
9
|
import { MatTable, MatTableModule } from '@angular/material/table';
|
|
10
10
|
import * as i1$1 from '@sdcorejs/angular/services';
|
|
11
|
-
import { SdExcelService, SdNotifyService } from '@sdcorejs/angular/services';
|
|
11
|
+
import { SdStorageService, SdExcelService, SdNotifyService } from '@sdcorejs/angular/services';
|
|
12
12
|
import { Subject, fromEvent, Subscription, isObservable, firstValueFrom } from 'rxjs';
|
|
13
13
|
import { debounceTime, startWith, map, switchMap } from 'rxjs/operators';
|
|
14
14
|
import { DateUtilities, StringUtilities } from '@sdcorejs/angular/utilities';
|
|
15
15
|
import { CdkTableModule, CdkColumnDef } from '@angular/cdk/table';
|
|
16
|
-
import * as
|
|
16
|
+
import * as i10 from '@angular/cdk/drag-drop';
|
|
17
17
|
import { moveItemInArray, DragDropModule } from '@angular/cdk/drag-drop';
|
|
18
18
|
import * as i1 from '@angular/common';
|
|
19
19
|
import { NgTemplateOutlet, CommonModule, DatePipe, DecimalPipe } from '@angular/common';
|
|
20
|
-
import * as i2$
|
|
20
|
+
import * as i2$1 from '@angular/forms';
|
|
21
21
|
import { FormGroup, FormsModule } from '@angular/forms';
|
|
22
|
-
import * as
|
|
22
|
+
import * as i8 from '@angular/material/checkbox';
|
|
23
23
|
import { MatCheckboxModule } from '@angular/material/checkbox';
|
|
24
|
-
import * as
|
|
24
|
+
import * as i9 from '@angular/material/radio';
|
|
25
25
|
import { MatRadioModule } from '@angular/material/radio';
|
|
26
|
-
import * as
|
|
27
|
-
import { MatIconModule } from '@angular/material/icon';
|
|
28
|
-
import * as i2 from '@angular/material/menu';
|
|
26
|
+
import * as i3 from '@angular/material/menu';
|
|
29
27
|
import { MatMenuModule } from '@angular/material/menu';
|
|
30
|
-
import * as
|
|
28
|
+
import * as i7 from '@angular/material/progress-spinner';
|
|
31
29
|
import { MatProgressSpinnerModule } from '@angular/material/progress-spinner';
|
|
32
30
|
import { SdButton } from '@sdcorejs/angular/components/button';
|
|
33
31
|
import { SdQuickAction } from '@sdcorejs/angular/components/quick-action';
|
|
34
32
|
import { SdTooltipDirective, SdScrollDirective, SdDesktopDirective, SdMobileDirective, SdHoverCopyDirective } from '@sdcorejs/angular/directives';
|
|
35
|
-
import { SdSafeHtmlPipe, SdFormatNumberPipe } from '@sdcorejs/angular/pipes';
|
|
36
|
-
import {
|
|
33
|
+
import { SdSafeHtmlPipe, SdFormatDatePipe, SdFormatDatetimePipe, SdFormatNumberPipe } from '@sdcorejs/angular/pipes';
|
|
34
|
+
import { Utilities, BrowserUtilities } from '@sdcorejs/utils/fns';
|
|
37
35
|
import { DateUtilities as DateUtilities$1, ArrayUtilities, NumberUtilities } from '@sdcorejs/angular/utilities/extensions';
|
|
38
36
|
import { SdBadge } from '@sdcorejs/angular/components/badge';
|
|
39
37
|
import { SdOperator } from '@sdcorejs/angular/components/operator';
|
|
@@ -44,14 +42,15 @@ import { takeUntilDestroyed } from '@angular/core/rxjs-interop';
|
|
|
44
42
|
import { SdSection } from '@sdcorejs/angular/components/section';
|
|
45
43
|
import { TranslatePipe, I18nService } from '@sdcorejs/angular/i18n';
|
|
46
44
|
import { SdSideDrawer } from '@sdcorejs/angular/components/side-drawer';
|
|
45
|
+
import { SdIcon } from '@sdcorejs/angular/modules/icon';
|
|
47
46
|
import { MatSlideToggleModule } from '@angular/material/slide-toggle';
|
|
48
47
|
import { SdModal } from '@sdcorejs/angular/components/modal';
|
|
49
48
|
import { SdConfirmService } from '@sdcorejs/angular/services/confirm';
|
|
50
49
|
import * as i4 from '@angular/material/button';
|
|
51
50
|
import { MatButtonModule } from '@angular/material/button';
|
|
52
|
-
import * as i2
|
|
51
|
+
import * as i2 from '@angular/material/tooltip';
|
|
53
52
|
import { MatTooltipModule } from '@angular/material/tooltip';
|
|
54
|
-
import * as
|
|
53
|
+
import * as i4$1 from '@angular/material/chips';
|
|
55
54
|
import { MatChipsModule } from '@angular/material/chips';
|
|
56
55
|
|
|
57
56
|
class SdTableCellDefDirective {
|
|
@@ -398,7 +397,6 @@ const SdConvertToPagingReq = (filterRequest, args) => {
|
|
|
398
397
|
return req;
|
|
399
398
|
};
|
|
400
399
|
|
|
401
|
-
/* eslint-disable @typescript-eslint/no-explicit-any */
|
|
402
400
|
class ColumnTitleComponent {
|
|
403
401
|
column = input.required();
|
|
404
402
|
titleDef = input(undefined);
|
|
@@ -417,8 +415,8 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.21", ngImpo
|
|
|
417
415
|
args: [{ selector: 'column-title', changeDetection: ChangeDetectionStrategy.OnPush, standalone: true, imports: [NgTemplateOutlet], template: "@let _column = column();\n@let _templateRef = templateRef();\n\n@if (_templateRef) {\n <ng-container *ngTemplateOutlet=\"_templateRef\"></ng-container>\n} @else {\n {{ _column.title }}\n}\n" }]
|
|
418
416
|
}] });
|
|
419
417
|
|
|
420
|
-
/* eslint-disable @typescript-eslint/no-explicit-any */
|
|
421
418
|
class ColumnFilterComponent {
|
|
419
|
+
#lastOnChangeValueHash;
|
|
422
420
|
// ==========================================
|
|
423
421
|
// 1. SIGNAL INPUTS
|
|
424
422
|
// ==========================================
|
|
@@ -503,14 +501,34 @@ class ColumnFilterComponent {
|
|
|
503
501
|
if (col.type === 'number' && col.filter?.type === 'split-number') {
|
|
504
502
|
filter[col.field] = filter[col.field] || { from: null, to: null };
|
|
505
503
|
}
|
|
504
|
+
this.#lastOnChangeValueHash = this.#filterValueHash(filter[col.field]);
|
|
506
505
|
});
|
|
507
506
|
}
|
|
508
507
|
// ==========================================
|
|
509
508
|
// 4. HANDLERS
|
|
510
509
|
// ==========================================
|
|
511
|
-
onFilterChange = () =>
|
|
510
|
+
onFilterChange = () => {
|
|
511
|
+
this.#emitFilterOnChange();
|
|
512
|
+
this.filterChange.emit();
|
|
513
|
+
};
|
|
512
514
|
// Blur input: commit giá trị KHÔNG trigger reload.
|
|
513
|
-
onFilterCommit = () =>
|
|
515
|
+
onFilterCommit = () => {
|
|
516
|
+
this.#emitFilterOnChange();
|
|
517
|
+
this.filterCommit.emit();
|
|
518
|
+
};
|
|
519
|
+
#emitFilterOnChange = () => {
|
|
520
|
+
const col = this.column();
|
|
521
|
+
const filter = this.columnFilter();
|
|
522
|
+
if (!col?.filter?.onChange || !filter)
|
|
523
|
+
return;
|
|
524
|
+
const value = filter[col.field];
|
|
525
|
+
const hash = this.#filterValueHash(value);
|
|
526
|
+
if (hash === this.#lastOnChangeValueHash)
|
|
527
|
+
return;
|
|
528
|
+
this.#lastOnChangeValueHash = hash;
|
|
529
|
+
col.filter.onChange(value, col, filter);
|
|
530
|
+
};
|
|
531
|
+
#filterValueHash = (value) => Utilities.hash({ value });
|
|
514
532
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.21", ngImport: i0, type: ColumnFilterComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
515
533
|
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "19.2.21", type: ColumnFilterComponent, isStandalone: true, selector: "column-filter", inputs: { autoIdInput: { classPropertyName: "autoIdInput", publicName: "autoId", isSignal: true, isRequired: false, transformFunction: null }, column: { classPropertyName: "column", publicName: "column", isSignal: true, isRequired: true, transformFunction: null }, columnFilter: { classPropertyName: "columnFilter", publicName: "columnFilter", isSignal: true, isRequired: false, transformFunction: null }, cacheValues: { classPropertyName: "cacheValues", publicName: "cacheValues", isSignal: true, isRequired: false, transformFunction: null }, value: { classPropertyName: "value", publicName: "value", isSignal: true, isRequired: false, transformFunction: null }, operator: { classPropertyName: "operator", publicName: "operator", isSignal: true, isRequired: false, transformFunction: null }, isMobile: { classPropertyName: "isMobile", publicName: "isMobile", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { operator: "operatorChange", filterChange: "filterChange", filterCommit: "filterCommit" }, ngImport: i0, template: "@let _column = column();\n@let _columnFilter = columnFilter();\n@let _autoId = autoId();\n@let _templateRef = templateRef();\n@let _operators = operators();\n@let _items = items();\n@let _label = label();\n@let _context = { columnFilter: _columnFilter, autoId: _autoId };\n\n<div class=\"d-flex c-inline-column align-items-center\" style=\"width: 100%; max-width: 100%\">\n @if (\n _column.type === 'string' ||\n _column.type === 'number' ||\n _column.type === 'boolean' ||\n _column.type === 'values' ||\n _column.type === 'lazy-values' ||\n _column.type === 'date' ||\n _column.type === 'datetime' ||\n _column.type === 'time'\n ) {\n <!-- Operator filter -->\n @if (_operators.length) {\n <sd-operator class=\"mr-4\" [(model)]=\"operator\" [operators]=\"operatorValues()\" />\n }\n\n <!-- N\u1EBFu filter nh\u1EADn v\u00E0o template -->\n @if (_templateRef) {\n <ng-container *ngTemplateOutlet=\"_templateRef; context: _context\"></ng-container>\n }\n <!-- M\u1EB7c \u0111\u1ECBnh theo type v\u00E0 gi\u00E1 tr\u1ECB values defined c\u1EE7a column -->\n @else {\n @if (_column.type === 'string') {\n <sd-input\n [autoId]=\"_autoId\"\n style=\"flex: 1 1 0%; min-width: 0\"\n size=\"sm\"\n type=\"text\"\n [label]=\"_label\"\n [(model)]=\"_columnFilter[_column.field]\"\n (keyupEnter)=\"onFilterChange()\"\n (sdBlur)=\"onFilterCommit()\"\n (cleared)=\"onFilterChange()\"\n [disabled]=\"_column.filter?.disabled\"\n hideInlineError>\n </sd-input>\n } @else if (_column.type === 'number') {\n @if (!_column.filter?.type) {\n <sd-input-number\n [autoId]=\"_autoId\"\n style=\"flex: 1 1 0%; min-width: 0\"\n size=\"sm\"\n [label]=\"_label\"\n [(model)]=\"_columnFilter[_column.field]\"\n (keyupEnter)=\"onFilterChange()\"\n (sdBlur)=\"onFilterCommit()\"\n (cleared)=\"onFilterChange()\"\n [disabled]=\"_column.filter?.disabled\"\n hideInlineError>\n </sd-input-number>\n } @else if (_column.filter?.type === 'split-number') {\n <ng-container *ngTemplateOutlet=\"splitNumberTpl; context: { field: _column.field, disabled: _column.filter?.disabled }\">\n </ng-container>\n }\n } @else if (_column.type === 'boolean') {\n <sd-select\n minWidthPanel=\"200px\"\n [autoId]=\"_autoId\"\n style=\"flex: 1 1 0%; min-width: 0\"\n [style.width]=\"'100%'\"\n size=\"sm\"\n [label]=\"_label\"\n [items]=\"[\n { value: '1', display: _column.option?.displayOnTrue || 'True' },\n { value: '0', display: _column.option?.displayOnFalse || 'False' },\n ]\"\n valueField=\"value\"\n displayField=\"display\"\n [(model)]=\"_columnFilter[_column.field]\"\n (sdChange)=\"onFilterChange()\"\n [disabled]=\"_column.filter?.disabled\"\n hideInlineError>\n <ng-template sdItemDef let-item=\"item\">\n @if (item.value === '1') {\n <sd-badge color=\"success\" [title]=\"_column.option?.displayOnTrue || 'True'\"> </sd-badge>\n } @else {\n <sd-badge color=\"error\" [title]=\"_column.option?.displayOnFalse || 'False'\"> </sd-badge>\n }\n </ng-template>\n </sd-select>\n } @else if (_column.type === 'values') {\n <sd-select\n minWidthPanel=\"200px\"\n [autoId]=\"_autoId\"\n style=\"flex: 1 1 0%; min-width: 0\"\n [style.width]=\"'100%'\"\n size=\"sm\"\n [label]=\"_label\"\n [items]=\"_items\"\n [valueField]=\"_column.option.valueField\"\n [displayField]=\"_column.option.displayField\"\n [(model)]=\"_columnFilter[_column.field]\"\n (sdChange)=\"onFilterChange()\"\n [disabled]=\"_column.filter?.disabled\"\n [multiple]=\"_column.option.selection === 'MULTIPLE'\"\n hideInlineError>\n </sd-select>\n } @else if (_column.type === 'lazy-values') {\n <sd-select\n minWidthPanel=\"200px\"\n [autoId]=\"_autoId\"\n style=\"flex: 1 1 0%; min-width: 0\"\n [style.width]=\"'100%'\"\n size=\"sm\"\n [label]=\"_label\"\n [items]=\"_items\"\n [valueField]=\"_column.option.valueField\"\n [displayField]=\"_column.option.displayField\"\n [(model)]=\"_columnFilter[_column.field]\"\n (sdChange)=\"onFilterChange()\"\n [disabled]=\"_column.filter?.disabled\"\n [multiple]=\"_column.option.selection === 'MULTIPLE'\"\n hideInlineError>\n </sd-select>\n } @else if (_column.type === 'date' || _column.type === 'datetime' || _column.type === 'time') {\n @if (!_column.filter?.type || _column.filter?.type === 'daterange') {\n <sd-date-range\n style=\"flex: 1 1 0%; min-width: 0\"\n size=\"sm\"\n [label]=\"_label\"\n [(model)]=\"_columnFilter[_column.field]\"\n (sdChange)=\"onFilterChange()\"\n [disabled]=\"_column.filter?.disabled\"\n hideInlineError>\n </sd-date-range>\n } @else if (_column.filter?.type === 'date') {\n <sd-date\n [autoId]=\"_autoId\"\n style=\"flex: 1 1 0%; min-width: 0\"\n type=\"date\"\n size=\"sm\"\n [label]=\"_label\"\n [(model)]=\"_columnFilter[_column.field]\"\n (sdChange)=\"onFilterChange()\"\n [disabled]=\"_column.filter?.disabled\"\n hideInlineError>\n </sd-date>\n } @else if (_column.filter?.type === 'split-date') {\n <ng-container *ngTemplateOutlet=\"splitDateTpl; context: { field: _column.field, disabled: _column.filter?.disabled }\">\n </ng-container>\n }\n }\n }\n } @else {\n <sd-input [autoId]=\"_autoId\" style=\"flex: 1 1 0%; min-width: 0\" type=\"text\" size=\"sm\" disabled></sd-input>\n }\n</div>\n\n<!-- ================================================ -->\n<!-- Split from/to templates (\u0111\u01B0a xu\u1ED1ng cu\u1ED1i file) -->\n<!-- ================================================ -->\n<ng-template #splitNumberTpl let-field=\"field\" let-disabled=\"disabled\">\n <div class=\"d-flex align-items-center\" style=\"flex: 1 1 0%; min-width: 0\">\n <sd-input-number\n [autoId]=\"_autoId + '-from'\"\n style=\"flex: 1 1 0%; min-width: 0\"\n size=\"sm\"\n [label]=\"_label\"\n [(model)]=\"_columnFilter[field].from\"\n (sdChange)=\"onFilterChange()\"\n (sdBlur)=\"onFilterCommit()\"\n (cleared)=\"onFilterChange()\"\n [disabled]=\"disabled\"\n hideInlineError>\n </sd-input-number>\n <div class=\"mx-4\">-</div>\n <sd-input-number\n [autoId]=\"_autoId + '-to'\"\n style=\"flex: 1 1 0%; min-width: 0\"\n size=\"sm\"\n [(model)]=\"_columnFilter[field].to\"\n (sdChange)=\"onFilterChange()\"\n (sdBlur)=\"onFilterCommit()\"\n (cleared)=\"onFilterChange()\"\n [disabled]=\"disabled\"\n hideInlineError>\n </sd-input-number>\n </div>\n</ng-template>\n\n<ng-template #splitDateTpl let-field=\"field\" let-disabled=\"disabled\">\n <div class=\"d-flex align-items-center\" style=\"flex: 1 1 0%; min-width: 0\">\n <sd-date\n [autoId]=\"_autoId + '-from'\"\n style=\"flex: 1 1 0%; min-width: 0\"\n type=\"date\"\n size=\"sm\"\n [label]=\"_label\"\n [(model)]=\"_columnFilter[field].from\"\n (sdChange)=\"onFilterChange()\"\n [disabled]=\"disabled\"\n hideInlineError>\n </sd-date>\n <div class=\"mx-4\">-</div>\n <sd-date\n [autoId]=\"_autoId + '-to'\"\n style=\"flex: 1 1 0%; min-width: 0\"\n type=\"date\"\n size=\"sm\"\n [(model)]=\"_columnFilter[field].to\"\n (sdChange)=\"onFilterChange()\"\n [disabled]=\"disabled\"\n hideInlineError>\n </sd-date>\n </div>\n</ng-template>\n", styles: [":host ::ng-deep .c-inline-column .mat-mdc-text-field-wrapper{background-color:#fff}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1.NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "component", type: SdOperator, selector: "sd-operator", inputs: ["model", "operators", "disabled", "autoId"], outputs: ["modelChange"] }, { kind: "component", type: SdInput, selector: "sd-input", inputs: ["autoId", "name", "appearance", "floatLabel", "size", "form", "label", "helperText", "placeholder", "type", "hideInlineError", "blurOnEnter", "required", "readonly", "disabled", "viewed", "minlength", "maxlength", "pattern", "patternErrorMessage", "validator", "inlineError", "hyperlink", "model"], outputs: ["modelChange", "sdChange", "sdFocus", "sdBlur", "keyupEnter", "cleared", "sdFocusForceBlur"] }, { kind: "component", type: SdInputNumber, selector: "sd-input-number", inputs: ["autoId", "name", "size", "form", "label", "helperText", "placeholder", "hideInlineError", "blurOnEnter", "required", "readonly", "disabled", "viewed", "type", "precision", "format", "min", "max", "validator", "inlineError", "hyperlink", "appearance", "floatLabel", "model"], outputs: ["modelChange", "sdChange", "sdFocus", "sdBlur", "keyupEnter", "cleared", "sdFocusForceBlur"] }, { kind: "component", type: SdSelect, selector: "sd-select", inputs: ["autoId", "name", "size", "form", "label", "helperText", "placeholder", "valueField", "displayField", "disabledField", "cacheChecksum", "limit", "hyperlink", "minWidthPanel", "hideInlineError", "required", "disabled", "viewed", "multiple", "clearable", "validator", "inlineError", "appearance", "floatLabel", "items", "model"], outputs: ["modelChange", "sdChange", "sdSelection"] }, { kind: "component", type: SdDate, selector: "sd-date", inputs: ["autoId", "name", "size", "form", "label", "helperText", "placeholder", "hideInlineError", "required", "disabled", "viewed", "clearable", "inlineError", "hyperlink", "appearance", "floatLabel", "min", "minDate", "max", "maxDate", "model"], outputs: ["modelChange", "sdChange", "sdFocus"] }, { kind: "component", type: SdDateRange, selector: "sd-date-range", inputs: ["autoId", "name", "size", "form", "label", "helperText", "hideInlineError", "required", "disabled", "viewed", "clearable", "appearance", "floatLabel", "min", "max", "model"], outputs: ["modelChange", "sdChange"] }, { kind: "component", type: SdBadge, selector: "sd-badge", inputs: ["type", "color", "primary", "secondary", "success", "info", "warning", "error", "fontSet", "title", "description", "tooltip", "icon", "size"], outputs: ["click"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
516
534
|
}
|
|
@@ -766,8 +784,6 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.21", ngImpo
|
|
|
766
784
|
args: [{ name: 'sdTree' }]
|
|
767
785
|
}] });
|
|
768
786
|
|
|
769
|
-
/* eslint-disable @typescript-eslint/no-explicit-any */
|
|
770
|
-
// eslint-disable-next-line @angular-eslint/component-class-suffix
|
|
771
787
|
class ExternalFilterComponent {
|
|
772
788
|
// ==========================================
|
|
773
789
|
// 1. SIGNAL INPUTS
|
|
@@ -893,7 +909,7 @@ class ExternalFilterComponent {
|
|
|
893
909
|
});
|
|
894
910
|
};
|
|
895
911
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.21", ngImport: i0, type: ExternalFilterComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
896
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "19.2.21", type: ExternalFilterComponent, isStandalone: true, selector: "external-filter", inputs: { autoIdInput: { classPropertyName: "autoIdInput", publicName: "autoId", isSignal: true, isRequired: false, transformFunction: null }, filter: { classPropertyName: "filter", publicName: "filter", isSignal: true, isRequired: false, transformFunction: null }, externalFilters: { classPropertyName: "externalFilters", publicName: "externalFilters", isSignal: true, isRequired: false, transformFunction: null }, filterRegister: { classPropertyName: "filterRegister", publicName: "filterRegister", isSignal: true, isRequired: false, transformFunction: null } }, ngImport: i0, template: "@let _filter = filter();\n@let _autoId = autoId();\n@let _filterItems = filterItems();\n@let _externalFilter = externalFilter();\n@let _inlineExternal = inlineExternal();\n@let _filtered = filtered();\n@let _col = col();\n\n@if (!_filter?.disabled) {\n @if (!isMobileOrTablet && _filterItems.length) {\n <sd-section\n [hideHeader]=\"_filter?.hideExternalFilterToolbar\"\n icon=\"filter_alt\"\n iconColor=\"secondary\"\n [title]=\"'core.component.table.filter' | translate\"\n [collapsible]=\"_filter?.collapsible ?? _filter?.collapsable ?? true\">\n <div class=\"d-flex mr-4\" sdHeaderRight>\n <sd-button\n [autoId]=\"_autoId + 'clear'\"\n [disabled]=\"!_filtered\"\n type=\"link\"\n prefixIcon=\"cleaning_services\"\n [tooltip]=\"'core.component.table.clear-selection' | translate\"\n (click)=\"$event.stopPropagation(); clearFilter($event)\"></sd-button>\n <sd-button\n [autoId]=\"_autoId + 'setting'\"\n type=\"link\"\n prefixIcon=\"settings\"\n [tooltip]=\"'core.component.table.customize' | translate\"\n [matMenuTriggerFor]=\"menu\"\n (click)=\"$event.stopPropagation()\"></sd-button>\n <mat-menu #menu=\"matMenu\" class=\"sd-custom-panel-filter-configuration\" [attr.data-autoid]=\"_autoId + 'setting-menu'\">\n @for (externalFilter of _filterItems; track externalFilter.field) {\n <button\n [attr.data-autoid]=\"_autoId + 'setting-' + externalFilter.field\"\n mat-menu-item\n (click)=\"onCheckboxChange($event, externalFilter)\"\n [disabled]=\"externalFilter.required\">\n <sd-checkbox\n [autoId]=\"_autoId + 'setting-' + externalFilter.field + '-checkbox'\"\n [label]=\"externalFilter.title\"\n [model]=\"_inlineExternal[externalFilter.field]\"\n [disabled]=\"externalFilter.required\" />\n </button>\n }\n </mat-menu>\n </div>\n <div class=\"row mx-0\" style=\"row-gap: 16px\">\n @for (item of _filterItems; track item.field) {\n @if (_inlineExternal[item.field]) {\n <div class=\"col-md-3 col-sm-6 px-8\" [class.col-lg-2]=\"_col === 2\" [class.col-lg-3]=\"_col === 3\">\n @if (item.type === 'string') {\n <sd-input\n [autoId]=\"_autoId + item.field\"\n [label]=\"item.title\"\n type=\"text\"\n [(model)]=\"_externalFilter[item.field]\"\n (keyupEnter)=\"onKeyupEnter()\"\n appearance=\"outline\"\n [form]=\"form\"\n [required]=\"item.required\"\n hideInlineError>\n </sd-input>\n } @else if (item.type === 'number') {\n <sd-input-number\n [autoId]=\"_autoId + item.field\"\n [label]=\"item.title\"\n [(model)]=\"_externalFilter[item.field]\"\n (keyupEnter)=\"onKeyupEnter()\"\n appearance=\"outline\"\n [form]=\"form\"\n [required]=\"item.required\"\n hideInlineError>\n </sd-input-number>\n } @else if (item.type === 'boolean') {\n <sd-select\n [autoId]=\"_autoId + item.field\"\n [label]=\"item.title\"\n [items]=\"[\n { value: true, display: item.option?.displayOnTrue || 'True' },\n { value: false, display: item.option?.displayOnFalse || 'False' },\n ]\"\n valueField=\"value\"\n displayField=\"display\"\n [(model)]=\"_externalFilter[item.field]\"\n (sdChange)=\"onFilter(item)\"\n appearance=\"outline\"\n [form]=\"form\"\n [required]=\"item.required\"\n hideInlineError>\n </sd-select>\n } @else if (item.type === 'date') {\n <sd-date\n [autoId]=\"_autoId + item.field\"\n [label]=\"item.title\"\n [(model)]=\"_externalFilter[item.field]\"\n (sdChange)=\"onFilter(item)\"\n appearance=\"outline\"\n [form]=\"form\"\n [required]=\"item.required\"\n [min]=\"item.minDate\"\n [max]=\"item.maxDate\"\n hideInlineError>\n </sd-date>\n } @else if (item.type === 'datetime') {\n <sd-datetime\n [autoId]=\"_autoId + item.field\"\n [label]=\"item.title\"\n [(model)]=\"_externalFilter[item.field]\"\n (sdChange)=\"onFilter(item)\"\n appearance=\"outline\"\n [form]=\"form\"\n [required]=\"item.required\"\n [min]=\"item.minDate\"\n [max]=\"item.maxDate\"\n hideInlineError>\n </sd-datetime>\n } @else if (item.type === 'daterange') {\n <sd-date-range\n [autoId]=\"_autoId + item.field\"\n [label]=\"item.title\"\n [(model)]=\"_externalFilter[item.field]\"\n (sdChange)=\"onFilter(item)\"\n [form]=\"form\"\n [required]=\"item.required\"\n [min]=\"item.minDate\"\n [max]=\"item.maxDate\"\n appearance=\"outline\"\n hideInlineError>\n </sd-date-range>\n } @else if (item.type === 'values') {\n @if (item.option.selection === 'MULTIPLE') {\n <sd-select\n [autoId]=\"_autoId + item.field\"\n [label]=\"item.title\"\n [items]=\"item.option.items | filterValues | async\"\n [valueField]=\"item.option.valueField\"\n [displayField]=\"item.option.displayField\"\n [(model)]=\"_externalFilter[item.field]\"\n (sdChange)=\"onFilter(item)\"\n appearance=\"outline\"\n multiple\n [form]=\"form\"\n [required]=\"item.required\"\n hideInlineError>\n </sd-select>\n } @else if (item.option.selection === 'AUTOCOMPLETE') {\n <sd-select\n [autoId]=\"_autoId + item.field\"\n [label]=\"item.title\"\n [items]=\"item.option.items | filterValues | async\"\n [valueField]=\"item.option.valueField\"\n [displayField]=\"item.option.displayField\"\n [(model)]=\"_externalFilter[item.field]\"\n (sdChange)=\"onFilter(item)\"\n appearance=\"outline\"\n [form]=\"form\"\n [required]=\"item.required\"\n hideInlineError>\n </sd-select>\n } @else if (item.option.selection === 'MULTIPLEAUTOCOMPLETE') {\n <sd-select\n [autoId]=\"_autoId + item.field\"\n [label]=\"item.title\"\n [items]=\"item.option.items | filterValues | async\"\n [valueField]=\"item.option.valueField\"\n [displayField]=\"item.option.displayField\"\n [(model)]=\"_externalFilter[item.field]\"\n (sdChange)=\"onFilter(item)\"\n appearance=\"outline\"\n multiple\n [form]=\"form\"\n [required]=\"item.required\"\n hideInlineError>\n </sd-select>\n } @else {\n <sd-select\n [autoId]=\"_autoId + item.field\"\n [label]=\"item.title\"\n [items]=\"item.option.items | filterValues | async\"\n [valueField]=\"item.option.valueField\"\n [displayField]=\"item.option.displayField\"\n [(model)]=\"_externalFilter[item.field]\"\n (sdChange)=\"onFilter(item)\"\n appearance=\"outline\"\n [form]=\"form\"\n [required]=\"item.required\"\n hideInlineError>\n </sd-select>\n }\n } @else if (item.type === 'lazy-values') {\n @if (item.option.selection === 'MULTIPLE') {\n <sd-select\n [autoId]=\"_autoId + item.field\"\n [label]=\"item.title\"\n [items]=\"item.option.items\"\n [valueField]=\"item.option.valueField\"\n [displayField]=\"item.option.displayField\"\n [(model)]=\"_externalFilter[item.field]\"\n (sdChange)=\"onFilter(item)\"\n appearance=\"outline\"\n multiple\n [form]=\"form\"\n [required]=\"item.required\"\n hideInlineError>\n </sd-select>\n } @else {\n <sd-select\n [autoId]=\"_autoId + item.field\"\n [label]=\"item.title\"\n [items]=\"item.option.items\"\n [valueField]=\"item.option.valueField\"\n [displayField]=\"item.option.displayField\"\n [(model)]=\"_externalFilter[item.field]\"\n (sdChange)=\"onFilter(item)\"\n appearance=\"outline\"\n [form]=\"form\"\n [required]=\"item.required\"\n hideInlineError>\n </sd-select>\n }\n } @else if (item.type === 'custom' && item.filterDef) {\n <ng-container\n *ngTemplateOutlet=\"\n item.filterDef;\n context: { form: form, externalFilter: _externalFilter, autoId: _autoId + item.field }\n \">\n </ng-container>\n }\n </div>\n }\n }\n </div>\n @if (_filter?.manualFilter) {\n <div class=\"d-flex justify-content-end mt-16 px-8\">\n <sd-button\n [autoId]=\"_autoId + 'submit'\"\n [disabled]=\"form.invalid\"\n type=\"fill\"\n color=\"primary\"\n [title]=\"'core.component.table.search' | translate\"\n prefixIcon=\"filter_alt\"\n (click)=\"onSubmit()\">\n </sd-button>\n </div>\n }\n </sd-section>\n }\n}\n", styles: [":host{display:block;padding-left:0;padding-right:0}::ng-deep .sd-custom-panel-filter-configuration{width:240px;max-height:550px;overflow-y:auto}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1.NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "pipe", type: i1.AsyncPipe, name: "async" }, { kind: "ngmodule", type: MatMenuModule }, { kind: "component", type: i2.MatMenu, selector: "mat-menu", inputs: ["backdropClass", "aria-label", "aria-labelledby", "aria-describedby", "xPosition", "yPosition", "overlapTrigger", "hasBackdrop", "class", "classList"], outputs: ["closed", "close"], exportAs: ["matMenu"] }, { kind: "component", type: i2.MatMenuItem, selector: "[mat-menu-item]", inputs: ["role", "disabled", "disableRipple"], exportAs: ["matMenuItem"] }, { kind: "directive", type: i2.MatMenuTrigger, selector: "[mat-menu-trigger-for], [matMenuTriggerFor]", inputs: ["mat-menu-trigger-for", "matMenuTriggerFor", "matMenuTriggerData", "matMenuTriggerRestoreFocus"], outputs: ["menuOpened", "onMenuOpen", "menuClosed", "onMenuClose"], exportAs: ["matMenuTrigger"] }, { kind: "ngmodule", type: MatCheckboxModule }, { kind: "component", type: SdSection, selector: "sd-section", inputs: ["title", "subTitle", "icon", "iconColor", "collapsed", "collapsible", "collapsable", "hideHeader", "noPaddingBody"], outputs: ["collapsedChange"] }, { kind: "component", type: SdInput, selector: "sd-input", inputs: ["autoId", "name", "appearance", "floatLabel", "size", "form", "label", "helperText", "placeholder", "type", "hideInlineError", "blurOnEnter", "required", "readonly", "disabled", "viewed", "minlength", "maxlength", "pattern", "patternErrorMessage", "validator", "inlineError", "hyperlink", "model"], outputs: ["modelChange", "sdChange", "sdFocus", "sdBlur", "keyupEnter", "cleared", "sdFocusForceBlur"] }, { kind: "component", type: SdInputNumber, selector: "sd-input-number", inputs: ["autoId", "name", "size", "form", "label", "helperText", "placeholder", "hideInlineError", "blurOnEnter", "required", "readonly", "disabled", "viewed", "type", "precision", "format", "min", "max", "validator", "inlineError", "hyperlink", "appearance", "floatLabel", "model"], outputs: ["modelChange", "sdChange", "sdFocus", "sdBlur", "keyupEnter", "cleared", "sdFocusForceBlur"] }, { kind: "component", type: SdSelect, selector: "sd-select", inputs: ["autoId", "name", "size", "form", "label", "helperText", "placeholder", "valueField", "displayField", "disabledField", "cacheChecksum", "limit", "hyperlink", "minWidthPanel", "hideInlineError", "required", "disabled", "viewed", "multiple", "clearable", "validator", "inlineError", "appearance", "floatLabel", "items", "model"], outputs: ["modelChange", "sdChange", "sdSelection"] }, { kind: "component", type: SdDate, selector: "sd-date", inputs: ["autoId", "name", "size", "form", "label", "helperText", "placeholder", "hideInlineError", "required", "disabled", "viewed", "clearable", "inlineError", "hyperlink", "appearance", "floatLabel", "min", "minDate", "max", "maxDate", "model"], outputs: ["modelChange", "sdChange", "sdFocus"] }, { kind: "component", type: SdDatetime, selector: "sd-datetime", inputs: ["autoId", "name", "size", "form", "label", "helperText", "placeholder", "hideInlineError", "required", "disabled", "viewed", "showSeconds", "clearable", "inlineError", "hyperlink", "appearance", "floatLabel", "min", "minDate", "max", "maxDate", "model"], outputs: ["modelChange", "sdChange", "sdFocus"] }, { kind: "component", type: SdDateRange$1, selector: "sd-date-range", inputs: ["autoId", "name", "size", "form", "label", "helperText", "hideInlineError", "required", "disabled", "viewed", "clearable", "appearance", "floatLabel", "min", "max", "model"], outputs: ["modelChange", "sdChange"] }, { kind: "component", type: SdButton, selector: "sd-button", inputs: ["autoId", "type", "color", "size", "fontSet", "title", "width", "tooltip", "prefixIcon", "suffixIcon", "disabled", "loading", "block", "htmlType"], outputs: ["click"] }, { kind: "pipe", type: FilterValuesPipe, name: "filterValues" }, { kind: "component", type: SdCheckbox, selector: "sd-checkbox", inputs: ["autoId", "name", "form", "label", "color", "disabled", "viewed", "inlineError", "model"], outputs: ["modelChange", "sdChange"] }, { kind: "pipe", type: TranslatePipe, name: "translate" }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
912
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "19.2.21", type: ExternalFilterComponent, isStandalone: true, selector: "external-filter", inputs: { autoIdInput: { classPropertyName: "autoIdInput", publicName: "autoId", isSignal: true, isRequired: false, transformFunction: null }, filter: { classPropertyName: "filter", publicName: "filter", isSignal: true, isRequired: false, transformFunction: null }, externalFilters: { classPropertyName: "externalFilters", publicName: "externalFilters", isSignal: true, isRequired: false, transformFunction: null }, filterRegister: { classPropertyName: "filterRegister", publicName: "filterRegister", isSignal: true, isRequired: false, transformFunction: null } }, ngImport: i0, template: "@let _filter = filter();\n@let _autoId = autoId();\n@let _filterItems = filterItems();\n@let _externalFilter = externalFilter();\n@let _inlineExternal = inlineExternal();\n@let _filtered = filtered();\n@let _col = col();\n\n@if (!_filter?.disabled) {\n @if (!isMobileOrTablet && _filterItems.length) {\n <sd-section\n [hideHeader]=\"_filter?.hideExternalFilterToolbar\"\n icon=\"filter_alt\"\n iconColor=\"secondary\"\n [title]=\"'core.component.table.filter' | translate\"\n [collapsible]=\"_filter?.collapsible ?? _filter?.collapsable ?? true\">\n <div class=\"d-flex mr-4\" sdHeaderRight>\n <sd-button\n [autoId]=\"_autoId + 'clear'\"\n [disabled]=\"!_filtered\"\n type=\"link\"\n prefixIcon=\"cleaning_services\"\n [tooltip]=\"'core.component.table.clear-selection' | translate\"\n (click)=\"$event.stopPropagation(); clearFilter($event)\"></sd-button>\n <sd-button\n [autoId]=\"_autoId + 'setting'\"\n type=\"link\"\n prefixIcon=\"settings\"\n [tooltip]=\"'core.component.table.customize' | translate\"\n [matMenuTriggerFor]=\"menu\"\n (click)=\"$event.stopPropagation()\"></sd-button>\n <mat-menu #menu=\"matMenu\" class=\"sd-custom-panel-filter-configuration\" [attr.data-autoid]=\"_autoId + 'setting-menu'\">\n @for (externalFilter of _filterItems; track externalFilter.field) {\n <button\n [attr.data-autoid]=\"_autoId + 'setting-' + externalFilter.field\"\n mat-menu-item\n (click)=\"onCheckboxChange($event, externalFilter)\"\n [disabled]=\"externalFilter.required\">\n <sd-checkbox\n [autoId]=\"_autoId + 'setting-' + externalFilter.field + '-checkbox'\"\n [label]=\"externalFilter.title\"\n [model]=\"_inlineExternal[externalFilter.field]\"\n [disabled]=\"externalFilter.required\" />\n </button>\n }\n </mat-menu>\n </div>\n <div class=\"row mx-0\" style=\"row-gap: 16px\">\n @for (item of _filterItems; track item.field) {\n @if (_inlineExternal[item.field]) {\n <div class=\"col-md-3 col-sm-6 px-8\" [class.col-lg-2]=\"_col === 2\" [class.col-lg-3]=\"_col === 3\">\n @if (item.type === 'string') {\n <sd-input\n [autoId]=\"_autoId + item.field\"\n [label]=\"item.title\"\n type=\"text\"\n [(model)]=\"_externalFilter[item.field]\"\n (keyupEnter)=\"onKeyupEnter()\"\n appearance=\"outline\"\n [form]=\"form\"\n [required]=\"item.required\"\n hideInlineError>\n </sd-input>\n } @else if (item.type === 'number') {\n <sd-input-number\n [autoId]=\"_autoId + item.field\"\n [label]=\"item.title\"\n [(model)]=\"_externalFilter[item.field]\"\n (keyupEnter)=\"onKeyupEnter()\"\n appearance=\"outline\"\n [form]=\"form\"\n [required]=\"item.required\"\n hideInlineError>\n </sd-input-number>\n } @else if (item.type === 'boolean') {\n <sd-select\n [autoId]=\"_autoId + item.field\"\n [label]=\"item.title\"\n [items]=\"[\n { value: true, display: item.option?.displayOnTrue || 'True' },\n { value: false, display: item.option?.displayOnFalse || 'False' },\n ]\"\n valueField=\"value\"\n displayField=\"display\"\n [(model)]=\"_externalFilter[item.field]\"\n (sdChange)=\"onFilter(item)\"\n appearance=\"outline\"\n [form]=\"form\"\n [required]=\"item.required\"\n hideInlineError>\n </sd-select>\n } @else if (item.type === 'date') {\n <sd-date\n [autoId]=\"_autoId + item.field\"\n [label]=\"item.title\"\n [(model)]=\"_externalFilter[item.field]\"\n (sdChange)=\"onFilter(item)\"\n appearance=\"outline\"\n [form]=\"form\"\n [required]=\"item.required\"\n [min]=\"item.minDate\"\n [max]=\"item.maxDate\"\n hideInlineError>\n </sd-date>\n } @else if (item.type === 'datetime') {\n <sd-datetime\n [autoId]=\"_autoId + item.field\"\n [label]=\"item.title\"\n [(model)]=\"_externalFilter[item.field]\"\n (sdChange)=\"onFilter(item)\"\n appearance=\"outline\"\n [form]=\"form\"\n [required]=\"item.required\"\n [min]=\"item.minDate\"\n [max]=\"item.maxDate\"\n hideInlineError>\n </sd-datetime>\n } @else if (item.type === 'daterange') {\n <sd-date-range\n [autoId]=\"_autoId + item.field\"\n [label]=\"item.title\"\n [(model)]=\"_externalFilter[item.field]\"\n (sdChange)=\"onFilter(item)\"\n [form]=\"form\"\n [required]=\"item.required\"\n [min]=\"item.minDate\"\n [max]=\"item.maxDate\"\n appearance=\"outline\"\n hideInlineError>\n </sd-date-range>\n } @else if (item.type === 'values') {\n @if (item.option.selection === 'MULTIPLE') {\n <sd-select\n [autoId]=\"_autoId + item.field\"\n [label]=\"item.title\"\n [items]=\"item.option.items | filterValues | async\"\n [valueField]=\"item.option.valueField\"\n [displayField]=\"item.option.displayField\"\n [(model)]=\"_externalFilter[item.field]\"\n (sdChange)=\"onFilter(item)\"\n appearance=\"outline\"\n multiple\n [form]=\"form\"\n [required]=\"item.required\"\n hideInlineError>\n </sd-select>\n } @else if (item.option.selection === 'AUTOCOMPLETE') {\n <sd-select\n [autoId]=\"_autoId + item.field\"\n [label]=\"item.title\"\n [items]=\"item.option.items | filterValues | async\"\n [valueField]=\"item.option.valueField\"\n [displayField]=\"item.option.displayField\"\n [(model)]=\"_externalFilter[item.field]\"\n (sdChange)=\"onFilter(item)\"\n appearance=\"outline\"\n [form]=\"form\"\n [required]=\"item.required\"\n hideInlineError>\n </sd-select>\n } @else if (item.option.selection === 'MULTIPLEAUTOCOMPLETE') {\n <sd-select\n [autoId]=\"_autoId + item.field\"\n [label]=\"item.title\"\n [items]=\"item.option.items | filterValues | async\"\n [valueField]=\"item.option.valueField\"\n [displayField]=\"item.option.displayField\"\n [(model)]=\"_externalFilter[item.field]\"\n (sdChange)=\"onFilter(item)\"\n appearance=\"outline\"\n multiple\n [form]=\"form\"\n [required]=\"item.required\"\n hideInlineError>\n </sd-select>\n } @else {\n <sd-select\n [autoId]=\"_autoId + item.field\"\n [label]=\"item.title\"\n [items]=\"item.option.items | filterValues | async\"\n [valueField]=\"item.option.valueField\"\n [displayField]=\"item.option.displayField\"\n [(model)]=\"_externalFilter[item.field]\"\n (sdChange)=\"onFilter(item)\"\n appearance=\"outline\"\n [form]=\"form\"\n [required]=\"item.required\"\n hideInlineError>\n </sd-select>\n }\n } @else if (item.type === 'lazy-values') {\n @if (item.option.selection === 'MULTIPLE') {\n <sd-select\n [autoId]=\"_autoId + item.field\"\n [label]=\"item.title\"\n [items]=\"item.option.items\"\n [valueField]=\"item.option.valueField\"\n [displayField]=\"item.option.displayField\"\n [(model)]=\"_externalFilter[item.field]\"\n (sdChange)=\"onFilter(item)\"\n appearance=\"outline\"\n multiple\n [form]=\"form\"\n [required]=\"item.required\"\n hideInlineError>\n </sd-select>\n } @else {\n <sd-select\n [autoId]=\"_autoId + item.field\"\n [label]=\"item.title\"\n [items]=\"item.option.items\"\n [valueField]=\"item.option.valueField\"\n [displayField]=\"item.option.displayField\"\n [(model)]=\"_externalFilter[item.field]\"\n (sdChange)=\"onFilter(item)\"\n appearance=\"outline\"\n [form]=\"form\"\n [required]=\"item.required\"\n hideInlineError>\n </sd-select>\n }\n } @else if (item.type === 'custom' && item.filterDef) {\n <ng-container\n *ngTemplateOutlet=\"\n item.filterDef;\n context: { form: form, externalFilter: _externalFilter, autoId: _autoId + item.field }\n \">\n </ng-container>\n }\n </div>\n }\n }\n </div>\n @if (_filter?.manualFilter) {\n <div class=\"d-flex justify-content-end mt-16 px-8\">\n <sd-button\n [autoId]=\"_autoId + 'submit'\"\n [disabled]=\"form.invalid\"\n type=\"fill\"\n color=\"primary\"\n [title]=\"'core.component.table.search' | translate\"\n prefixIcon=\"filter_alt\"\n (click)=\"onSubmit()\">\n </sd-button>\n </div>\n }\n </sd-section>\n }\n}\n", styles: [":host{display:block;padding-left:0;padding-right:0}::ng-deep .sd-custom-panel-filter-configuration{width:240px;max-height:550px;overflow-y:auto}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1.NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "pipe", type: i1.AsyncPipe, name: "async" }, { kind: "ngmodule", type: MatMenuModule }, { kind: "component", type: i3.MatMenu, selector: "mat-menu", inputs: ["backdropClass", "aria-label", "aria-labelledby", "aria-describedby", "xPosition", "yPosition", "overlapTrigger", "hasBackdrop", "class", "classList"], outputs: ["closed", "close"], exportAs: ["matMenu"] }, { kind: "component", type: i3.MatMenuItem, selector: "[mat-menu-item]", inputs: ["role", "disabled", "disableRipple"], exportAs: ["matMenuItem"] }, { kind: "directive", type: i3.MatMenuTrigger, selector: "[mat-menu-trigger-for], [matMenuTriggerFor]", inputs: ["mat-menu-trigger-for", "matMenuTriggerFor", "matMenuTriggerData", "matMenuTriggerRestoreFocus"], outputs: ["menuOpened", "onMenuOpen", "menuClosed", "onMenuClose"], exportAs: ["matMenuTrigger"] }, { kind: "ngmodule", type: MatCheckboxModule }, { kind: "component", type: SdSection, selector: "sd-section", inputs: ["title", "subTitle", "icon", "iconColor", "collapsed", "collapsible", "collapsable", "hideHeader", "noPaddingBody"], outputs: ["collapsedChange"] }, { kind: "component", type: SdInput, selector: "sd-input", inputs: ["autoId", "name", "appearance", "floatLabel", "size", "form", "label", "helperText", "placeholder", "type", "hideInlineError", "blurOnEnter", "required", "readonly", "disabled", "viewed", "minlength", "maxlength", "pattern", "patternErrorMessage", "validator", "inlineError", "hyperlink", "model"], outputs: ["modelChange", "sdChange", "sdFocus", "sdBlur", "keyupEnter", "cleared", "sdFocusForceBlur"] }, { kind: "component", type: SdInputNumber, selector: "sd-input-number", inputs: ["autoId", "name", "size", "form", "label", "helperText", "placeholder", "hideInlineError", "blurOnEnter", "required", "readonly", "disabled", "viewed", "type", "precision", "format", "min", "max", "validator", "inlineError", "hyperlink", "appearance", "floatLabel", "model"], outputs: ["modelChange", "sdChange", "sdFocus", "sdBlur", "keyupEnter", "cleared", "sdFocusForceBlur"] }, { kind: "component", type: SdSelect, selector: "sd-select", inputs: ["autoId", "name", "size", "form", "label", "helperText", "placeholder", "valueField", "displayField", "disabledField", "cacheChecksum", "limit", "hyperlink", "minWidthPanel", "hideInlineError", "required", "disabled", "viewed", "multiple", "clearable", "validator", "inlineError", "appearance", "floatLabel", "items", "model"], outputs: ["modelChange", "sdChange", "sdSelection"] }, { kind: "component", type: SdDate, selector: "sd-date", inputs: ["autoId", "name", "size", "form", "label", "helperText", "placeholder", "hideInlineError", "required", "disabled", "viewed", "clearable", "inlineError", "hyperlink", "appearance", "floatLabel", "min", "minDate", "max", "maxDate", "model"], outputs: ["modelChange", "sdChange", "sdFocus"] }, { kind: "component", type: SdDatetime, selector: "sd-datetime", inputs: ["autoId", "name", "size", "form", "label", "helperText", "placeholder", "hideInlineError", "required", "disabled", "viewed", "showSeconds", "clearable", "inlineError", "hyperlink", "appearance", "floatLabel", "min", "minDate", "max", "maxDate", "model"], outputs: ["modelChange", "sdChange", "sdFocus"] }, { kind: "component", type: SdDateRange$1, selector: "sd-date-range", inputs: ["autoId", "name", "size", "form", "label", "helperText", "hideInlineError", "required", "disabled", "viewed", "clearable", "appearance", "floatLabel", "min", "max", "model"], outputs: ["modelChange", "sdChange"] }, { kind: "component", type: SdButton, selector: "sd-button", inputs: ["autoId", "type", "color", "size", "fontSet", "title", "width", "tooltip", "prefixIcon", "suffixIcon", "disabled", "loading", "block", "htmlType"], outputs: ["click"] }, { kind: "pipe", type: FilterValuesPipe, name: "filterValues" }, { kind: "component", type: SdCheckbox, selector: "sd-checkbox", inputs: ["autoId", "name", "form", "label", "color", "disabled", "viewed", "inlineError", "model"], outputs: ["modelChange", "sdChange"] }, { kind: "pipe", type: TranslatePipe, name: "translate" }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
897
913
|
}
|
|
898
914
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.21", ngImport: i0, type: ExternalFilterComponent, decorators: [{
|
|
899
915
|
type: Component,
|
|
@@ -915,7 +931,6 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.21", ngImpo
|
|
|
915
931
|
], template: "@let _filter = filter();\n@let _autoId = autoId();\n@let _filterItems = filterItems();\n@let _externalFilter = externalFilter();\n@let _inlineExternal = inlineExternal();\n@let _filtered = filtered();\n@let _col = col();\n\n@if (!_filter?.disabled) {\n @if (!isMobileOrTablet && _filterItems.length) {\n <sd-section\n [hideHeader]=\"_filter?.hideExternalFilterToolbar\"\n icon=\"filter_alt\"\n iconColor=\"secondary\"\n [title]=\"'core.component.table.filter' | translate\"\n [collapsible]=\"_filter?.collapsible ?? _filter?.collapsable ?? true\">\n <div class=\"d-flex mr-4\" sdHeaderRight>\n <sd-button\n [autoId]=\"_autoId + 'clear'\"\n [disabled]=\"!_filtered\"\n type=\"link\"\n prefixIcon=\"cleaning_services\"\n [tooltip]=\"'core.component.table.clear-selection' | translate\"\n (click)=\"$event.stopPropagation(); clearFilter($event)\"></sd-button>\n <sd-button\n [autoId]=\"_autoId + 'setting'\"\n type=\"link\"\n prefixIcon=\"settings\"\n [tooltip]=\"'core.component.table.customize' | translate\"\n [matMenuTriggerFor]=\"menu\"\n (click)=\"$event.stopPropagation()\"></sd-button>\n <mat-menu #menu=\"matMenu\" class=\"sd-custom-panel-filter-configuration\" [attr.data-autoid]=\"_autoId + 'setting-menu'\">\n @for (externalFilter of _filterItems; track externalFilter.field) {\n <button\n [attr.data-autoid]=\"_autoId + 'setting-' + externalFilter.field\"\n mat-menu-item\n (click)=\"onCheckboxChange($event, externalFilter)\"\n [disabled]=\"externalFilter.required\">\n <sd-checkbox\n [autoId]=\"_autoId + 'setting-' + externalFilter.field + '-checkbox'\"\n [label]=\"externalFilter.title\"\n [model]=\"_inlineExternal[externalFilter.field]\"\n [disabled]=\"externalFilter.required\" />\n </button>\n }\n </mat-menu>\n </div>\n <div class=\"row mx-0\" style=\"row-gap: 16px\">\n @for (item of _filterItems; track item.field) {\n @if (_inlineExternal[item.field]) {\n <div class=\"col-md-3 col-sm-6 px-8\" [class.col-lg-2]=\"_col === 2\" [class.col-lg-3]=\"_col === 3\">\n @if (item.type === 'string') {\n <sd-input\n [autoId]=\"_autoId + item.field\"\n [label]=\"item.title\"\n type=\"text\"\n [(model)]=\"_externalFilter[item.field]\"\n (keyupEnter)=\"onKeyupEnter()\"\n appearance=\"outline\"\n [form]=\"form\"\n [required]=\"item.required\"\n hideInlineError>\n </sd-input>\n } @else if (item.type === 'number') {\n <sd-input-number\n [autoId]=\"_autoId + item.field\"\n [label]=\"item.title\"\n [(model)]=\"_externalFilter[item.field]\"\n (keyupEnter)=\"onKeyupEnter()\"\n appearance=\"outline\"\n [form]=\"form\"\n [required]=\"item.required\"\n hideInlineError>\n </sd-input-number>\n } @else if (item.type === 'boolean') {\n <sd-select\n [autoId]=\"_autoId + item.field\"\n [label]=\"item.title\"\n [items]=\"[\n { value: true, display: item.option?.displayOnTrue || 'True' },\n { value: false, display: item.option?.displayOnFalse || 'False' },\n ]\"\n valueField=\"value\"\n displayField=\"display\"\n [(model)]=\"_externalFilter[item.field]\"\n (sdChange)=\"onFilter(item)\"\n appearance=\"outline\"\n [form]=\"form\"\n [required]=\"item.required\"\n hideInlineError>\n </sd-select>\n } @else if (item.type === 'date') {\n <sd-date\n [autoId]=\"_autoId + item.field\"\n [label]=\"item.title\"\n [(model)]=\"_externalFilter[item.field]\"\n (sdChange)=\"onFilter(item)\"\n appearance=\"outline\"\n [form]=\"form\"\n [required]=\"item.required\"\n [min]=\"item.minDate\"\n [max]=\"item.maxDate\"\n hideInlineError>\n </sd-date>\n } @else if (item.type === 'datetime') {\n <sd-datetime\n [autoId]=\"_autoId + item.field\"\n [label]=\"item.title\"\n [(model)]=\"_externalFilter[item.field]\"\n (sdChange)=\"onFilter(item)\"\n appearance=\"outline\"\n [form]=\"form\"\n [required]=\"item.required\"\n [min]=\"item.minDate\"\n [max]=\"item.maxDate\"\n hideInlineError>\n </sd-datetime>\n } @else if (item.type === 'daterange') {\n <sd-date-range\n [autoId]=\"_autoId + item.field\"\n [label]=\"item.title\"\n [(model)]=\"_externalFilter[item.field]\"\n (sdChange)=\"onFilter(item)\"\n [form]=\"form\"\n [required]=\"item.required\"\n [min]=\"item.minDate\"\n [max]=\"item.maxDate\"\n appearance=\"outline\"\n hideInlineError>\n </sd-date-range>\n } @else if (item.type === 'values') {\n @if (item.option.selection === 'MULTIPLE') {\n <sd-select\n [autoId]=\"_autoId + item.field\"\n [label]=\"item.title\"\n [items]=\"item.option.items | filterValues | async\"\n [valueField]=\"item.option.valueField\"\n [displayField]=\"item.option.displayField\"\n [(model)]=\"_externalFilter[item.field]\"\n (sdChange)=\"onFilter(item)\"\n appearance=\"outline\"\n multiple\n [form]=\"form\"\n [required]=\"item.required\"\n hideInlineError>\n </sd-select>\n } @else if (item.option.selection === 'AUTOCOMPLETE') {\n <sd-select\n [autoId]=\"_autoId + item.field\"\n [label]=\"item.title\"\n [items]=\"item.option.items | filterValues | async\"\n [valueField]=\"item.option.valueField\"\n [displayField]=\"item.option.displayField\"\n [(model)]=\"_externalFilter[item.field]\"\n (sdChange)=\"onFilter(item)\"\n appearance=\"outline\"\n [form]=\"form\"\n [required]=\"item.required\"\n hideInlineError>\n </sd-select>\n } @else if (item.option.selection === 'MULTIPLEAUTOCOMPLETE') {\n <sd-select\n [autoId]=\"_autoId + item.field\"\n [label]=\"item.title\"\n [items]=\"item.option.items | filterValues | async\"\n [valueField]=\"item.option.valueField\"\n [displayField]=\"item.option.displayField\"\n [(model)]=\"_externalFilter[item.field]\"\n (sdChange)=\"onFilter(item)\"\n appearance=\"outline\"\n multiple\n [form]=\"form\"\n [required]=\"item.required\"\n hideInlineError>\n </sd-select>\n } @else {\n <sd-select\n [autoId]=\"_autoId + item.field\"\n [label]=\"item.title\"\n [items]=\"item.option.items | filterValues | async\"\n [valueField]=\"item.option.valueField\"\n [displayField]=\"item.option.displayField\"\n [(model)]=\"_externalFilter[item.field]\"\n (sdChange)=\"onFilter(item)\"\n appearance=\"outline\"\n [form]=\"form\"\n [required]=\"item.required\"\n hideInlineError>\n </sd-select>\n }\n } @else if (item.type === 'lazy-values') {\n @if (item.option.selection === 'MULTIPLE') {\n <sd-select\n [autoId]=\"_autoId + item.field\"\n [label]=\"item.title\"\n [items]=\"item.option.items\"\n [valueField]=\"item.option.valueField\"\n [displayField]=\"item.option.displayField\"\n [(model)]=\"_externalFilter[item.field]\"\n (sdChange)=\"onFilter(item)\"\n appearance=\"outline\"\n multiple\n [form]=\"form\"\n [required]=\"item.required\"\n hideInlineError>\n </sd-select>\n } @else {\n <sd-select\n [autoId]=\"_autoId + item.field\"\n [label]=\"item.title\"\n [items]=\"item.option.items\"\n [valueField]=\"item.option.valueField\"\n [displayField]=\"item.option.displayField\"\n [(model)]=\"_externalFilter[item.field]\"\n (sdChange)=\"onFilter(item)\"\n appearance=\"outline\"\n [form]=\"form\"\n [required]=\"item.required\"\n hideInlineError>\n </sd-select>\n }\n } @else if (item.type === 'custom' && item.filterDef) {\n <ng-container\n *ngTemplateOutlet=\"\n item.filterDef;\n context: { form: form, externalFilter: _externalFilter, autoId: _autoId + item.field }\n \">\n </ng-container>\n }\n </div>\n }\n }\n </div>\n @if (_filter?.manualFilter) {\n <div class=\"d-flex justify-content-end mt-16 px-8\">\n <sd-button\n [autoId]=\"_autoId + 'submit'\"\n [disabled]=\"form.invalid\"\n type=\"fill\"\n color=\"primary\"\n [title]=\"'core.component.table.search' | translate\"\n prefixIcon=\"filter_alt\"\n (click)=\"onSubmit()\">\n </sd-button>\n </div>\n }\n </sd-section>\n }\n}\n", styles: [":host{display:block;padding-left:0;padding-right:0}::ng-deep .sd-custom-panel-filter-configuration{width:240px;max-height:550px;overflow-y:auto}\n"] }]
|
|
916
932
|
}], ctorParameters: () => [] });
|
|
917
933
|
|
|
918
|
-
/* eslint-disable @typescript-eslint/no-explicit-any */
|
|
919
934
|
/**
|
|
920
935
|
* Mobile-filter — side-drawer chiếm ~90% width thiết bị. Dùng cho table khi
|
|
921
936
|
* render trên màn hình điện thoại (inline filter bị ẩn).
|
|
@@ -1117,11 +1132,11 @@ class SelectorActionComponent {
|
|
|
1117
1132
|
}
|
|
1118
1133
|
};
|
|
1119
1134
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.21", ngImport: i0, type: SelectorActionComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
1120
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "19.2.21", type: SelectorActionComponent, isStandalone: true, selector: "selector-action", inputs: { autoIdInput: { classPropertyName: "autoIdInput", publicName: "autoId", isSignal: true, isRequired: false, transformFunction: null }, tableOption: { classPropertyName: "tableOption", publicName: "tableOption", isSignal: true, isRequired: false, transformFunction: null }, selectedTableItems: { classPropertyName: "selectedTableItems", publicName: "selectedTableItems", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { clear: "clear" }, ngImport: i0, template: "@let _actions = selectedTableItems() | actionFilter: tableOption()?.selector?.actions;\n@let _selectedTableItems = selectedTableItems();\n@let _autoId = autoId();\n\n<sd-quick-action [opened]=\"opened()\">\n <div class=\"d-flex align-items-center\" sdMessage>\n <div class=\"c-bg-length\">\n <span class=\"c-length\">{{ _selectedTableItems?.length }}</span>\n </div>\n <div class=\"c-message\">\n {{ message() }}\n </div>\n </div>\n\n <div class=\"d-flex align-items-center mr-8\" sdAction>\n @for (action of _actions; track $index) {\n @if (action.variant === 'normal') {\n <sd-button\n [autoId]=\"_autoId ? _autoId + '-action-' + $index : null\"\n class=\"ml-4\"\n [tooltip]=\"action.tooltip\"\n [prefixIcon]=\"action.icon\"\n [color]=\"action.color\"\n [type]=\"action.type || 'light'\"\n [fontSet]=\"action.fontSet\"\n [title]=\"action.title\"\n (click)=\"onClickAction(action)\"></sd-button>\n } @else if (action.variant === 'children') {\n @let _actionIndex = $index;\n <sd-button\n [autoId]=\"_autoId ? _autoId + '-action-' + _actionIndex : null\"\n class=\"ml-4\"\n [tooltip]=\"action.tooltip\"\n [prefixIcon]=\"action.icon || 'more_vert'\"\n [color]=\"action.color || 'secondary'\"\n [type]=\"action.type || 'light'\"\n [fontSet]=\"action.fontSet
|
|
1135
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "19.2.21", type: SelectorActionComponent, isStandalone: true, selector: "selector-action", inputs: { autoIdInput: { classPropertyName: "autoIdInput", publicName: "autoId", isSignal: true, isRequired: false, transformFunction: null }, tableOption: { classPropertyName: "tableOption", publicName: "tableOption", isSignal: true, isRequired: false, transformFunction: null }, selectedTableItems: { classPropertyName: "selectedTableItems", publicName: "selectedTableItems", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { clear: "clear" }, ngImport: i0, template: "@let _actions = selectedTableItems() | actionFilter: tableOption()?.selector?.actions;\n@let _selectedTableItems = selectedTableItems();\n@let _autoId = autoId();\n\n<sd-quick-action [opened]=\"opened()\">\n <div class=\"d-flex align-items-center\" sdMessage>\n <div class=\"c-bg-length\">\n <span class=\"c-length\">{{ _selectedTableItems?.length }}</span>\n </div>\n <div class=\"c-message\">\n {{ message() }}\n </div>\n </div>\n\n <div class=\"d-flex align-items-center mr-8\" sdAction>\n @for (action of _actions; track $index) {\n @if (action.variant === 'normal') {\n <sd-button\n [autoId]=\"_autoId ? _autoId + '-action-' + $index : null\"\n class=\"ml-4\"\n [tooltip]=\"action.tooltip\"\n [prefixIcon]=\"action.icon\"\n [color]=\"action.color\"\n [type]=\"action.type || 'light'\"\n [fontSet]=\"action.fontSet\"\n [title]=\"action.title\"\n (click)=\"onClickAction(action)\"></sd-button>\n } @else if (action.variant === 'children') {\n @let _actionIndex = $index;\n <sd-button\n [autoId]=\"_autoId ? _autoId + '-action-' + _actionIndex : null\"\n class=\"ml-4\"\n [tooltip]=\"action.tooltip\"\n [prefixIcon]=\"action.icon || 'more_vert'\"\n [color]=\"action.color || 'secondary'\"\n [type]=\"action.type || 'light'\"\n [fontSet]=\"action.fontSet\"\n [title]=\"action.title\"\n [matMenuTriggerFor]=\"menu\">\n </sd-button>\n <mat-menu #menu=\"matMenu\">\n <span>\n @for (child of action.children; track $index) {\n <button\n mat-menu-item\n [attr.data-autoid]=\"_autoId ? _autoId + '-action-' + _actionIndex + '-' + $index : null\"\n (click)=\"onClickAction(child)\">\n @if (child.icon) {\n <sd-icon [fontSet]=\"child.fontSet\" class=\"c-icon\" [name]=\"child.icon\"></sd-icon>\n }\n <span> {{ child.title }}</span>\n </button>\n }\n </span>\n </mat-menu>\n }\n }\n <!-- N\u00FAt close lu\u00F4n hi\u1EC7n k\u1EC3 c\u1EA3 kh\u00F4ng c\u00F3 action \u2014 \u0111\u1EA3m b\u1EA3o user c\u00F3 l\u1ED1i tho\u00E1t clear selection -->\n <sd-button [autoId]=\"_autoId ? _autoId + '-clear-selection' : null\" class=\"ml-4\" prefixIcon=\"close\" color=\"secondary\" type=\"outline\" (click)=\"onClear()\" width=\"35px\"></sd-button>\n </div>\n</sd-quick-action>\n", styles: [".c-bg-length{display:flex;flex-direction:column;align-items:flex-start;padding:12px 8px;position:static;width:auto;min-width:48px;height:48px;left:0;top:0;background:var(--sd-primary);border-radius:4px 0 0 4px}.c-bg-length .c-length{position:static;width:auto;min-width:32px;height:24px;left:8px;top:12px;font-family:Roboto;font-style:normal;font-weight:500;font-size:16px;line-height:24px;text-align:center;color:#fff}.c-message{position:static;min-width:200px;height:20px;left:0;top:6px;font-family:Roboto;font-style:normal;font-weight:400;font-size:14px;line-height:20px;color:#000;margin:0 0 0 8px}\n"], dependencies: [{ kind: "component", type: SdIcon, selector: "sd-icon", inputs: ["name", "fontIcon", "color", "set", "fontSet", "size", "strokeWidth", "absoluteStrokeWidth", "ariaLabel"] }, { kind: "ngmodule", type: MatMenuModule }, { kind: "component", type: i3.MatMenu, selector: "mat-menu", inputs: ["backdropClass", "aria-label", "aria-labelledby", "aria-describedby", "xPosition", "yPosition", "overlapTrigger", "hasBackdrop", "class", "classList"], outputs: ["closed", "close"], exportAs: ["matMenu"] }, { kind: "component", type: i3.MatMenuItem, selector: "[mat-menu-item]", inputs: ["role", "disabled", "disableRipple"], exportAs: ["matMenuItem"] }, { kind: "directive", type: i3.MatMenuTrigger, selector: "[mat-menu-trigger-for], [matMenuTriggerFor]", inputs: ["mat-menu-trigger-for", "matMenuTriggerFor", "matMenuTriggerData", "matMenuTriggerRestoreFocus"], outputs: ["menuOpened", "onMenuOpen", "menuClosed", "onMenuClose"], exportAs: ["matMenuTrigger"] }, { kind: "component", type: SdButton, selector: "sd-button", inputs: ["autoId", "type", "color", "size", "fontSet", "title", "width", "tooltip", "prefixIcon", "suffixIcon", "disabled", "loading", "block", "htmlType"], outputs: ["click"] }, { kind: "component", type: SdQuickAction, selector: "sd-quick-action", inputs: ["opened"] }, { kind: "pipe", type: ActionFilterPipe, name: "actionFilter" }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
1121
1136
|
}
|
|
1122
1137
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.21", ngImport: i0, type: SelectorActionComponent, decorators: [{
|
|
1123
1138
|
type: Component,
|
|
1124
|
-
args: [{ selector: 'selector-action', changeDetection: ChangeDetectionStrategy.OnPush, imports: [
|
|
1139
|
+
args: [{ selector: 'selector-action', changeDetection: ChangeDetectionStrategy.OnPush, imports: [SdIcon, MatMenuModule, SdButton, SdQuickAction, ActionFilterPipe], template: "@let _actions = selectedTableItems() | actionFilter: tableOption()?.selector?.actions;\n@let _selectedTableItems = selectedTableItems();\n@let _autoId = autoId();\n\n<sd-quick-action [opened]=\"opened()\">\n <div class=\"d-flex align-items-center\" sdMessage>\n <div class=\"c-bg-length\">\n <span class=\"c-length\">{{ _selectedTableItems?.length }}</span>\n </div>\n <div class=\"c-message\">\n {{ message() }}\n </div>\n </div>\n\n <div class=\"d-flex align-items-center mr-8\" sdAction>\n @for (action of _actions; track $index) {\n @if (action.variant === 'normal') {\n <sd-button\n [autoId]=\"_autoId ? _autoId + '-action-' + $index : null\"\n class=\"ml-4\"\n [tooltip]=\"action.tooltip\"\n [prefixIcon]=\"action.icon\"\n [color]=\"action.color\"\n [type]=\"action.type || 'light'\"\n [fontSet]=\"action.fontSet\"\n [title]=\"action.title\"\n (click)=\"onClickAction(action)\"></sd-button>\n } @else if (action.variant === 'children') {\n @let _actionIndex = $index;\n <sd-button\n [autoId]=\"_autoId ? _autoId + '-action-' + _actionIndex : null\"\n class=\"ml-4\"\n [tooltip]=\"action.tooltip\"\n [prefixIcon]=\"action.icon || 'more_vert'\"\n [color]=\"action.color || 'secondary'\"\n [type]=\"action.type || 'light'\"\n [fontSet]=\"action.fontSet\"\n [title]=\"action.title\"\n [matMenuTriggerFor]=\"menu\">\n </sd-button>\n <mat-menu #menu=\"matMenu\">\n <span>\n @for (child of action.children; track $index) {\n <button\n mat-menu-item\n [attr.data-autoid]=\"_autoId ? _autoId + '-action-' + _actionIndex + '-' + $index : null\"\n (click)=\"onClickAction(child)\">\n @if (child.icon) {\n <sd-icon [fontSet]=\"child.fontSet\" class=\"c-icon\" [name]=\"child.icon\"></sd-icon>\n }\n <span> {{ child.title }}</span>\n </button>\n }\n </span>\n </mat-menu>\n }\n }\n <!-- N\u00FAt close lu\u00F4n hi\u1EC7n k\u1EC3 c\u1EA3 kh\u00F4ng c\u00F3 action \u2014 \u0111\u1EA3m b\u1EA3o user c\u00F3 l\u1ED1i tho\u00E1t clear selection -->\n <sd-button [autoId]=\"_autoId ? _autoId + '-clear-selection' : null\" class=\"ml-4\" prefixIcon=\"close\" color=\"secondary\" type=\"outline\" (click)=\"onClear()\" width=\"35px\"></sd-button>\n </div>\n</sd-quick-action>\n", styles: [".c-bg-length{display:flex;flex-direction:column;align-items:flex-start;padding:12px 8px;position:static;width:auto;min-width:48px;height:48px;left:0;top:0;background:var(--sd-primary);border-radius:4px 0 0 4px}.c-bg-length .c-length{position:static;width:auto;min-width:32px;height:24px;left:8px;top:12px;font-family:Roboto;font-style:normal;font-weight:500;font-size:16px;line-height:24px;text-align:center;color:#fff}.c-message{position:static;min-width:200px;height:20px;left:0;top:6px;font-family:Roboto;font-style:normal;font-weight:400;font-size:14px;line-height:20px;color:#000;margin:0 0 0 8px}\n"] }]
|
|
1125
1140
|
}] });
|
|
1126
1141
|
|
|
1127
1142
|
const DEFAULT_TABLE_CONFIG = {
|
|
@@ -1133,8 +1148,6 @@ const DEFAULT_TABLE_CONFIG = {
|
|
|
1133
1148
|
const SD_TABLE_CONFIGURATION = new InjectionToken('sd-table.configuration');
|
|
1134
1149
|
|
|
1135
1150
|
class ConfigService {
|
|
1136
|
-
storageService;
|
|
1137
|
-
tableConfiguration;
|
|
1138
1151
|
#COLUMNS = {
|
|
1139
1152
|
SUBINFORMATION: 'sdSubInformationAction',
|
|
1140
1153
|
COMMAND: 'sdCommand',
|
|
@@ -1148,10 +1161,8 @@ class ConfigService {
|
|
|
1148
1161
|
#storage;
|
|
1149
1162
|
#widthChange = new Subject();
|
|
1150
1163
|
widthChange$ = this.#widthChange.asObservable();
|
|
1151
|
-
|
|
1152
|
-
|
|
1153
|
-
this.tableConfiguration = tableConfiguration;
|
|
1154
|
-
}
|
|
1164
|
+
storageService = inject(SdStorageService);
|
|
1165
|
+
tableConfiguration = inject(SD_TABLE_CONFIGURATION, { optional: true });
|
|
1155
1166
|
#loadConfiguredTable = (option) => {
|
|
1156
1167
|
// Nếu không có key thì không lấy được setting
|
|
1157
1168
|
if (!option?.key) {
|
|
@@ -1340,20 +1351,13 @@ class ConfigService {
|
|
|
1340
1351
|
columns,
|
|
1341
1352
|
};
|
|
1342
1353
|
};
|
|
1343
|
-
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.21", ngImport: i0, type: ConfigService, deps: [
|
|
1354
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.21", ngImport: i0, type: ConfigService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
|
|
1344
1355
|
static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "19.2.21", ngImport: i0, type: ConfigService });
|
|
1345
1356
|
}
|
|
1346
1357
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.21", ngImport: i0, type: ConfigService, decorators: [{
|
|
1347
1358
|
type: Injectable
|
|
1348
|
-
}]
|
|
1349
|
-
type: Inject,
|
|
1350
|
-
args: [SD_TABLE_CONFIGURATION]
|
|
1351
|
-
}, {
|
|
1352
|
-
type: Optional
|
|
1353
|
-
}] }] });
|
|
1359
|
+
}] });
|
|
1354
1360
|
|
|
1355
|
-
/* eslint-disable @typescript-eslint/no-explicit-any */
|
|
1356
|
-
// eslint-disable-next-line @angular-eslint/component-class-suffix
|
|
1357
1361
|
class ConfigComponent {
|
|
1358
1362
|
// ==========================================
|
|
1359
1363
|
// 1. SIGNAL INPUTS / OUTPUTS
|
|
@@ -1434,7 +1438,7 @@ class ConfigComponent {
|
|
|
1434
1438
|
this.dragDisabled = true;
|
|
1435
1439
|
}
|
|
1436
1440
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.21", ngImport: i0, type: ConfigComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
1437
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "19.2.21", type: ConfigComponent, isStandalone: true, selector: "config", inputs: { autoIdInput: { classPropertyName: "autoIdInput", publicName: "autoId", isSignal: true, isRequired: false, transformFunction: null }, tableOption: { classPropertyName: "tableOption", publicName: "tableOption", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { changes: "changes" }, providers: [ConfigService], viewQueries: [{ propertyName: "modal", first: true, predicate: SdModal, descendants: true, isSignal: true }, { propertyName: "table", first: true, predicate: MatTable, descendants: true, isSignal: true }], ngImport: i0, template: "@let _configuration = configuration();\n@let _autoId = autoId();\n\n<sd-modal width=\"sm\" [title]=\"'core.component.table.setup' | translate\" #modal>\n @if (_configuration) {\n <div class=\"c-container\">\n <div class=\"c-table\" style=\"max-height: 70vh\">\n <table\n mat-table\n [dataSource]=\"_configuration.columns!\"\n cdkDropList\n [cdkDropListData]=\"_configuration.columns\"\n (cdkDropListDropped)=\"dropTable($event)\">\n <ng-container matColumnDef=\"invisible\">\n <th mat-header-cell class=\"c-th text-center px-4\" *matHeaderCellDef style=\"width: 96px\">\n {{ 'core.component.form-builder.display' | translate }}\n </th>\n <td class=\"text-center px-4\" mat-cell *matCellDef=\"let item\">\n <div class=\"d-flex\" style=\"gap: 8px\">\n <div class=\"c-handle\" (mousedown)=\"handleMouseDown()\" (mouseup)=\"handleMouseUp()\">\n <svg xmlns=\"http://www.w3.org/2000/svg\" height=\"24px\" viewBox=\"0 0 24 24\" width=\"24px\" fill=\"#5f6368\">\n <path d=\"M0 0h24v24H0V0z\" fill=\"none\" />\n <path\n d=\"M11 18c0 1.1-.9 2-2 2s-2-.9-2-2 .9-2 2-2 2 .9 2 2zm-2-8c-1.1 0-2 .9-2 2s.9 2 2 2 2-.9 2-2-.9-2-2-2zm0-6c-1.1 0-2 .9-2 2s.9 2 2 2 2-.9 2-2-.9-2-2-2zm6 4c1.1 0 2-.9 2-2s-.9-2-2-2-2 .9-2 2 .9 2 2 2zm0 2c-1.1 0-2 .9-2 2s.9 2 2 2 2-.9 2-2-.9-2-2-2zm0 6c-1.1 0-2 .9-2 2s.9 2 2 2 2-.9 2-2-.9-2-2-2z\" />\n </svg>\n </div>\n <sd-switch [model]=\"!item.invisible\" (modelChange)=\"item.invisible = !item.invisible\" />\n </div>\n </td>\n </ng-container>\n <ng-container matColumnDef=\"title\">\n <th mat-header-cell class=\"c-th px-4\" *matHeaderCellDef>\n {{ 'core.component.table.column-header' | translate }}\n </th>\n <td class=\"px-4\" mat-cell *matCellDef=\"let item\">\n <sd-input class=\"pb-4\" [placeholder]=\"item?.origin?.title\" [(model)]=\"item.title\" hideInlineError></sd-input>\n </td>\n </ng-container>\n <ng-container matColumnDef=\"width\">\n <th mat-header-cell class=\"c-th px-4\" *matHeaderCellDef style=\"width: 80px\">\n {{ 'core.component.table.width' | translate }}\n </th>\n <td class=\"px-4\" mat-cell *matCellDef=\"let item\">\n <sd-input class=\"pb-4\" [placeholder]=\"item?.origin?.width\" [(model)]=\"item.width\" hideInlineError></sd-input>\n </td>\n </ng-container>\n <ng-container matColumnDef=\"fixed\">\n <th mat-header-cell class=\"c-th text-center px-4\" *matHeaderCellDef style=\"width: 80px\">\n {{ 'core.component.table.fixed' | translate }}\n </th>\n <td class=\"text-center px-4\" mat-cell *matCellDef=\"let item\">\n <sd-switch [(model)]=\"item.fixed\" />\n </td>\n </ng-container>\n\n <ng-container matColumnDef=\"truncate\">\n <th mat-header-cell class=\"c-th text-center px-4\" *matHeaderCellDef style=\"width: 100px\">\n {{ 'core.component.table.char-limit' | translate }}\n </th>\n <td class=\"text-center px-4\" mat-cell *matCellDef=\"let item\">\n <sd-switch [(model)]=\"item.truncate\" />\n </td>\n </ng-container>\n\n <tr mat-header-row *matHeaderRowDef=\"['invisible', 'title', 'width', 'fixed', 'truncate']; sticky: true\"></tr>\n <tr\n mat-row\n *matRowDef=\"let row; columns: ['invisible', 'title', 'width', 'fixed', 'truncate']\"\n cdkDrag\n [cdkDragData]=\"row\"\n cdkDragLockAxis=\"y\"\n [cdkDragDisabled]=\"dragDisabled\">\n </tr>\n </table>\n </div>\n </div>\n }\n <ng-container sdFooter>\n <sd-button [autoId]=\"_autoId ? _autoId + '-config-skip' : null\" class=\"mr-8\" (click)=\"close()\" [title]=\"'core.component.table.skip' | translate\" color=\"secondary\"> </sd-button>\n <sd-button [autoId]=\"_autoId ? _autoId + '-config-reset' : null\" class=\"mr-8\" (click)=\"onReset()\" [title]=\"'core.component.form-builder.default' | translate\" color=\"primary\"> </sd-button>\n <sd-button [autoId]=\"_autoId ? _autoId + '-config-apply' : null\" (click)=\"onSave()\" [title]=\"'core.component.table.apply' | translate\" type=\"fill\" color=\"primary\"> </sd-button>\n </ng-container>\n</sd-modal>\n", styles: [".c-table{position:relative;overflow:auto}.c-table table{width:100%}.c-table .c-th{font-weight:500;font-size:14px;line-height:20px;color:#000}.c-container{position:relative;min-height:200px}.c-handle{color:#ccc;cursor:move}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "ngmodule", type: FormsModule }, { kind: "ngmodule", type: MatTableModule }, { kind: "component", type:
|
|
1441
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "19.2.21", type: ConfigComponent, isStandalone: true, selector: "config", inputs: { autoIdInput: { classPropertyName: "autoIdInput", publicName: "autoId", isSignal: true, isRequired: false, transformFunction: null }, tableOption: { classPropertyName: "tableOption", publicName: "tableOption", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { changes: "changes" }, providers: [ConfigService], viewQueries: [{ propertyName: "modal", first: true, predicate: SdModal, descendants: true, isSignal: true }, { propertyName: "table", first: true, predicate: MatTable, descendants: true, isSignal: true }], ngImport: i0, template: "@let _configuration = configuration();\n@let _autoId = autoId();\n\n<sd-modal width=\"sm\" [title]=\"'core.component.table.setup' | translate\" #modal>\n @if (_configuration) {\n <div class=\"c-container\">\n <div class=\"c-table\" style=\"max-height: 70vh\">\n <table\n mat-table\n [dataSource]=\"_configuration.columns!\"\n cdkDropList\n [cdkDropListData]=\"_configuration.columns\"\n (cdkDropListDropped)=\"dropTable($event)\">\n <ng-container matColumnDef=\"invisible\">\n <th mat-header-cell class=\"c-th text-center px-4\" *matHeaderCellDef style=\"width: 96px\">\n {{ 'core.component.form-builder.display' | translate }}\n </th>\n <td class=\"text-center px-4\" mat-cell *matCellDef=\"let item\">\n <div class=\"d-flex\" style=\"gap: 8px\">\n <div class=\"c-handle\" (mousedown)=\"handleMouseDown()\" (mouseup)=\"handleMouseUp()\">\n <svg xmlns=\"http://www.w3.org/2000/svg\" height=\"24px\" viewBox=\"0 0 24 24\" width=\"24px\" fill=\"#5f6368\">\n <path d=\"M0 0h24v24H0V0z\" fill=\"none\" />\n <path\n d=\"M11 18c0 1.1-.9 2-2 2s-2-.9-2-2 .9-2 2-2 2 .9 2 2zm-2-8c-1.1 0-2 .9-2 2s.9 2 2 2 2-.9 2-2-.9-2-2-2zm0-6c-1.1 0-2 .9-2 2s.9 2 2 2 2-.9 2-2-.9-2-2-2zm6 4c1.1 0 2-.9 2-2s-.9-2-2-2-2 .9-2 2 .9 2 2 2zm0 2c-1.1 0-2 .9-2 2s.9 2 2 2 2-.9 2-2-.9-2-2-2zm0 6c-1.1 0-2 .9-2 2s.9 2 2 2 2-.9 2-2-.9-2-2-2z\" />\n </svg>\n </div>\n <sd-switch [model]=\"!item.invisible\" (modelChange)=\"item.invisible = !item.invisible\" />\n </div>\n </td>\n </ng-container>\n <ng-container matColumnDef=\"title\">\n <th mat-header-cell class=\"c-th px-4\" *matHeaderCellDef>\n {{ 'core.component.table.column-header' | translate }}\n </th>\n <td class=\"px-4\" mat-cell *matCellDef=\"let item\">\n <sd-input class=\"pb-4\" [placeholder]=\"item?.origin?.title\" [(model)]=\"item.title\" hideInlineError></sd-input>\n </td>\n </ng-container>\n <ng-container matColumnDef=\"width\">\n <th mat-header-cell class=\"c-th px-4\" *matHeaderCellDef style=\"width: 80px\">\n {{ 'core.component.table.width' | translate }}\n </th>\n <td class=\"px-4\" mat-cell *matCellDef=\"let item\">\n <sd-input class=\"pb-4\" [placeholder]=\"item?.origin?.width\" [(model)]=\"item.width\" hideInlineError></sd-input>\n </td>\n </ng-container>\n <ng-container matColumnDef=\"fixed\">\n <th mat-header-cell class=\"c-th text-center px-4\" *matHeaderCellDef style=\"width: 80px\">\n {{ 'core.component.table.fixed' | translate }}\n </th>\n <td class=\"text-center px-4\" mat-cell *matCellDef=\"let item\">\n <sd-switch [(model)]=\"item.fixed\" />\n </td>\n </ng-container>\n\n <ng-container matColumnDef=\"truncate\">\n <th mat-header-cell class=\"c-th text-center px-4\" *matHeaderCellDef style=\"width: 100px\">\n {{ 'core.component.table.char-limit' | translate }}\n </th>\n <td class=\"text-center px-4\" mat-cell *matCellDef=\"let item\">\n <sd-switch [(model)]=\"item.truncate\" />\n </td>\n </ng-container>\n\n <tr mat-header-row *matHeaderRowDef=\"['invisible', 'title', 'width', 'fixed', 'truncate']; sticky: true\"></tr>\n <tr\n mat-row\n *matRowDef=\"let row; columns: ['invisible', 'title', 'width', 'fixed', 'truncate']\"\n cdkDrag\n [cdkDragData]=\"row\"\n cdkDragLockAxis=\"y\"\n [cdkDragDisabled]=\"dragDisabled\">\n </tr>\n </table>\n </div>\n </div>\n }\n <ng-container sdFooter>\n <sd-button [autoId]=\"_autoId ? _autoId + '-config-skip' : null\" class=\"mr-8\" (click)=\"close()\" [title]=\"'core.component.table.skip' | translate\" color=\"secondary\"> </sd-button>\n <sd-button [autoId]=\"_autoId ? _autoId + '-config-reset' : null\" class=\"mr-8\" (click)=\"onReset()\" [title]=\"'core.component.form-builder.default' | translate\" color=\"primary\"> </sd-button>\n <sd-button [autoId]=\"_autoId ? _autoId + '-config-apply' : null\" (click)=\"onSave()\" [title]=\"'core.component.table.apply' | translate\" type=\"fill\" color=\"primary\"> </sd-button>\n </ng-container>\n</sd-modal>\n", styles: [".c-table{position:relative;overflow:auto}.c-table table{width:100%}.c-table .c-th{font-weight:500;font-size:14px;line-height:20px;color:#000}.c-container{position:relative;min-height:200px}.c-handle{color:#ccc;cursor:move}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "ngmodule", type: FormsModule }, { kind: "ngmodule", type: MatTableModule }, { kind: "component", type: i5.MatTable, selector: "mat-table, table[mat-table]", exportAs: ["matTable"] }, { kind: "directive", type: i5.MatHeaderCellDef, selector: "[matHeaderCellDef]" }, { kind: "directive", type: i5.MatHeaderRowDef, selector: "[matHeaderRowDef]", inputs: ["matHeaderRowDef", "matHeaderRowDefSticky"] }, { kind: "directive", type: i5.MatColumnDef, selector: "[matColumnDef]", inputs: ["matColumnDef"] }, { kind: "directive", type: i5.MatCellDef, selector: "[matCellDef]" }, { kind: "directive", type: i5.MatRowDef, selector: "[matRowDef]", inputs: ["matRowDefColumns", "matRowDefWhen"] }, { kind: "directive", type: i5.MatHeaderCell, selector: "mat-header-cell, th[mat-header-cell]" }, { kind: "directive", type: i5.MatCell, selector: "mat-cell, td[mat-cell]" }, { kind: "component", type: i5.MatHeaderRow, selector: "mat-header-row, tr[mat-header-row]", exportAs: ["matHeaderRow"] }, { kind: "component", type: i5.MatRow, selector: "mat-row, tr[mat-row]", exportAs: ["matRow"] }, { kind: "ngmodule", type: MatSlideToggleModule }, { kind: "ngmodule", type: CdkTableModule }, { kind: "ngmodule", type: DragDropModule }, { kind: "directive", type: i10.CdkDropList, selector: "[cdkDropList], cdk-drop-list", inputs: ["cdkDropListConnectedTo", "cdkDropListData", "cdkDropListOrientation", "id", "cdkDropListLockAxis", "cdkDropListDisabled", "cdkDropListSortingDisabled", "cdkDropListEnterPredicate", "cdkDropListSortPredicate", "cdkDropListAutoScrollDisabled", "cdkDropListAutoScrollStep", "cdkDropListElementContainer"], outputs: ["cdkDropListDropped", "cdkDropListEntered", "cdkDropListExited", "cdkDropListSorted"], exportAs: ["cdkDropList"] }, { kind: "directive", type: i10.CdkDrag, selector: "[cdkDrag]", inputs: ["cdkDragData", "cdkDragLockAxis", "cdkDragRootElement", "cdkDragBoundary", "cdkDragStartDelay", "cdkDragFreeDragPosition", "cdkDragDisabled", "cdkDragConstrainPosition", "cdkDragPreviewClass", "cdkDragPreviewContainer", "cdkDragScale"], outputs: ["cdkDragStarted", "cdkDragReleased", "cdkDragEnded", "cdkDragEntered", "cdkDragExited", "cdkDragDropped", "cdkDragMoved"], exportAs: ["cdkDrag"] }, { kind: "component", type: SdButton, selector: "sd-button", inputs: ["autoId", "type", "color", "size", "fontSet", "title", "width", "tooltip", "prefixIcon", "suffixIcon", "disabled", "loading", "block", "htmlType"], outputs: ["click"] }, { kind: "component", type: SdInput, selector: "sd-input", inputs: ["autoId", "name", "appearance", "floatLabel", "size", "form", "label", "helperText", "placeholder", "type", "hideInlineError", "blurOnEnter", "required", "readonly", "disabled", "viewed", "minlength", "maxlength", "pattern", "patternErrorMessage", "validator", "inlineError", "hyperlink", "model"], outputs: ["modelChange", "sdChange", "sdFocus", "sdBlur", "keyupEnter", "cleared", "sdFocusForceBlur"] }, { kind: "component", type: SdModal, selector: "sd-modal", inputs: ["autoId", "title", "color", "width", "height", "view", "modalClass", "lazyLoadContent", "hideClose", "disableBackdropClose"], outputs: ["sdClosed"] }, { kind: "component", type: SdSwitch, selector: "sd-switch", inputs: ["autoId", "name", "form", "label", "color", "disabled", "viewed", "hideInlineError", "required", "model"], outputs: ["modelChange", "sdChange"] }, { kind: "pipe", type: TranslatePipe, name: "translate" }] });
|
|
1438
1442
|
}
|
|
1439
1443
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.21", ngImport: i0, type: ConfigComponent, decorators: [{
|
|
1440
1444
|
type: Component,
|
|
@@ -1580,18 +1584,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.21", ngImpo
|
|
|
1580
1584
|
}], ctorParameters: () => [] });
|
|
1581
1585
|
|
|
1582
1586
|
/**
|
|
1583
|
-
*
|
|
1584
|
-
* chứa `disabled`, `title`, `icon`, và `htmlTemplate` (khi command là child có
|
|
1585
|
-
* htmlTemplate). Một lần gọi cho cả 4 truy vấn, template dùng `@let` để alias.
|
|
1586
|
-
*
|
|
1587
|
-
* Trước đây tách thành 3 pipe `commandDisable` / `commandTitle` / `commandIcon`.
|
|
1588
|
-
*
|
|
1589
|
-
* @example
|
|
1590
|
-
* @let meta = item | command:cmd;
|
|
1591
|
-
* <button [disabled]="meta.disabled" [matTooltip]="meta.title">
|
|
1592
|
-
* <mat-icon>{{ meta.icon }}</mat-icon>
|
|
1593
|
-
* <div [innerHTML]="meta.htmlTemplate"></div>
|
|
1594
|
-
* </button>
|
|
1587
|
+
* Resolves command metadata for the current row once, then lets the template reuse it with `@let`.
|
|
1595
1588
|
*/
|
|
1596
1589
|
class CommandPipe {
|
|
1597
1590
|
transform(item, command) {
|
|
@@ -1618,8 +1611,7 @@ class CommandPipe {
|
|
|
1618
1611
|
return '';
|
|
1619
1612
|
return typeof command.icon === 'string' ? command.icon : command.icon(item.data);
|
|
1620
1613
|
};
|
|
1621
|
-
//
|
|
1622
|
-
// Parent (SdTableCommandChildren) không khai báo — trả về undefined.
|
|
1614
|
+
// Only child commands can provide htmlTemplate.
|
|
1623
1615
|
#htmlTemplate = (item, command) => {
|
|
1624
1616
|
const tpl = command?.htmlTemplate;
|
|
1625
1617
|
return typeof tpl === 'function' ? tpl(item.data) : undefined;
|
|
@@ -1629,18 +1621,11 @@ class CommandPipe {
|
|
|
1629
1621
|
}
|
|
1630
1622
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.21", ngImport: i0, type: CommandPipe, decorators: [{
|
|
1631
1623
|
type: Pipe,
|
|
1632
|
-
args: [{ name: 'command' }]
|
|
1624
|
+
args: [{ name: 'command', standalone: true }]
|
|
1633
1625
|
}] });
|
|
1634
1626
|
|
|
1635
1627
|
/**
|
|
1636
|
-
*
|
|
1637
|
-
* cho từng row. Output dùng trực tiếp trong template không cần thêm pipe phụ.
|
|
1638
|
-
*
|
|
1639
|
-
* Đã rename từ `commandFilter` → `filter` sau khi gom toàn bộ pipe command vào
|
|
1640
|
-
* `components/command/pipes/`.
|
|
1641
|
-
*
|
|
1642
|
-
* @example
|
|
1643
|
-
* @let filteredCommands = item | filter:commands | async;
|
|
1628
|
+
* Filters visible commands and pre-resolves icon, title, and stable key for the current row.
|
|
1644
1629
|
*/
|
|
1645
1630
|
class CommandFilterPipe {
|
|
1646
1631
|
async transform(item, commands) {
|
|
@@ -1707,7 +1692,7 @@ class CommandFilterPipe {
|
|
|
1707
1692
|
return '';
|
|
1708
1693
|
return typeof command.title === 'string' ? command.title : command.title(item.data);
|
|
1709
1694
|
};
|
|
1710
|
-
//
|
|
1695
|
+
// Stable autoId key generated from resolved icon and title.
|
|
1711
1696
|
#key = (item, command) => {
|
|
1712
1697
|
const icon = this.#icon(item, command);
|
|
1713
1698
|
const title = this.#title(item, command);
|
|
@@ -1718,46 +1703,35 @@ class CommandFilterPipe {
|
|
|
1718
1703
|
}
|
|
1719
1704
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.21", ngImport: i0, type: CommandFilterPipe, decorators: [{
|
|
1720
1705
|
type: Pipe,
|
|
1721
|
-
args: [{ name: 'filter' }]
|
|
1706
|
+
args: [{ name: 'filter', standalone: true }]
|
|
1722
1707
|
}] });
|
|
1723
1708
|
|
|
1724
|
-
// eslint-disable-next-line @angular-eslint/component-class-suffix
|
|
1725
1709
|
class DesktopCommand {
|
|
1726
|
-
// ==========================================
|
|
1727
|
-
// 1. SIGNAL INPUTS
|
|
1728
|
-
// ==========================================
|
|
1729
1710
|
autoIdInput = input(undefined, { alias: 'autoId' });
|
|
1730
1711
|
item = input.required();
|
|
1731
1712
|
itemIndex = input.required();
|
|
1732
1713
|
commands = input([]);
|
|
1733
|
-
//
|
|
1734
|
-
// 2. COMPUTED
|
|
1735
|
-
// ==========================================
|
|
1736
|
-
// Key định danh row dùng để build autoId: ưu tiên id → code → value → fallback itemIndex.
|
|
1714
|
+
// Row key for autoId: prefer id, then code, then value, then itemIndex.
|
|
1737
1715
|
itemKey = computed(() => {
|
|
1738
1716
|
const data = this.item()?.data;
|
|
1739
1717
|
return data?.['id']?.toString() || data?.['code']?.toString() || data?.['value']?.toString() || this.itemIndex().toString();
|
|
1740
1718
|
});
|
|
1741
|
-
// autoId
|
|
1742
|
-
// Template ghép tiếp `-<commandKey>` (và `-<childKey>` nếu child) cho mỗi button.
|
|
1719
|
+
// Host autoId: `<base>-command-<itemKey>`. Template appends command and child keys.
|
|
1743
1720
|
autoId = computed(() => {
|
|
1744
1721
|
const base = this.autoIdInput();
|
|
1745
1722
|
return base ? `${base}-command-${this.itemKey()}` : '';
|
|
1746
1723
|
});
|
|
1747
|
-
// Commands signal (mặc định mảng rỗng).
|
|
1748
1724
|
_commands = computed(() => this.commands() || []);
|
|
1749
1725
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.21", ngImport: i0, type: DesktopCommand, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
1750
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "19.2.21", type: DesktopCommand, isStandalone: true, selector: "desktop-command", inputs: { autoIdInput: { classPropertyName: "autoIdInput", publicName: "autoId", isSignal: true, isRequired: false, transformFunction: null }, item: { classPropertyName: "item", publicName: "item", isSignal: true, isRequired: true, transformFunction: null }, itemIndex: { classPropertyName: "itemIndex", publicName: "itemIndex", isSignal: true, isRequired: true, transformFunction: null }, commands: { classPropertyName: "commands", publicName: "commands", isSignal: true, isRequired: false, transformFunction: null } }, host: { properties: { "attr.data-autoid": "autoId()" } }, ngImport: i0, template: "@let _autoId = autoId();\n@let _item = item();\n@let filteredCommands = _item | filter: _commands() | async;\n\n@if (filteredCommands?.length) {\n @for (command of filteredCommands; track command.key) {\n @let _meta = _item | command: command;\n @if (command.type === 'normal') {\n <button\n [attr.data-autoid]=\"_autoId + '-' + command.key\"\n (click)=\"command.click(_item.data)\"\n [matTooltip]=\"_meta.title\"\n aria-hidden=\"true\"\n [disabled]=\"_meta.disabled\"\n mat-icon-button>\n <
|
|
1726
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "19.2.21", type: DesktopCommand, isStandalone: true, selector: "desktop-command", inputs: { autoIdInput: { classPropertyName: "autoIdInput", publicName: "autoId", isSignal: true, isRequired: false, transformFunction: null }, item: { classPropertyName: "item", publicName: "item", isSignal: true, isRequired: true, transformFunction: null }, itemIndex: { classPropertyName: "itemIndex", publicName: "itemIndex", isSignal: true, isRequired: true, transformFunction: null }, commands: { classPropertyName: "commands", publicName: "commands", isSignal: true, isRequired: false, transformFunction: null } }, host: { properties: { "attr.data-autoid": "autoId()" } }, ngImport: i0, template: "@let _autoId = autoId();\n@let _item = item();\n@let filteredCommands = _item | filter: _commands() | async;\n\n@if (filteredCommands?.length) {\n @for (command of filteredCommands; track command.key) {\n @let _meta = _item | command: command;\n @if (command.type === 'normal') {\n <button\n [attr.data-autoid]=\"_autoId + '-' + command.key\"\n (click)=\"command.click(_item.data)\"\n [matTooltip]=\"_meta.title\"\n aria-hidden=\"true\"\n [disabled]=\"_meta.disabled\"\n mat-icon-button>\n <sd-icon class=\"c-icon\" [color]=\"command.color || 'secondary'\" [fontSet]=\"command.fontSet\" [name]=\"_meta.icon\"></sd-icon>\n </button>\n } @else {\n <button [attr.data-autoid]=\"_autoId + '-' + command.key\" [matMenuTriggerFor]=\"menu\" aria-hidden=\"true\" mat-icon-button>\n @if (_meta.icon) {\n <sd-icon class=\"c-icon\" [fontSet]=\"command.fontSet\" [name]=\"_meta.icon\"></sd-icon>\n } @else {\n <sd-icon class=\"c-icon\" [fontSet]=\"command.fontSet\" name=\"more_vert\"></sd-icon>\n }\n </button>\n <mat-menu #menu=\"matMenu\" [attr.data-autoid]=\"_autoId + '-' + command.key + '-menu'\">\n <span>\n @for (childCommand of command.children; track childCommand.key) {\n @let _childMeta = _item | command: childCommand;\n <button\n [attr.data-autoid]=\"_autoId + '-' + command.key + '-' + childCommand.key\"\n mat-menu-item\n (click)=\"childCommand.click(_item.data)\"\n [disabled]=\"_childMeta.disabled\">\n @if (_childMeta.htmlTemplate) {\n <div [innerHTML]=\"_childMeta.htmlTemplate\"></div>\n } @else {\n <span class=\"sd-command-menu-item__content\">\n <sd-icon class=\"sd-command-menu-item__icon\"\n [color]=\"childCommand.color || 'secondary'\"\n [fontSet]=\"childCommand.fontSet\" [name]=\"_childMeta.icon\"></sd-icon>\n <span class=\"sd-command-menu-item__title\">{{ _childMeta.title }}</span>\n </span>\n }\n </button>\n }\n </span>\n </mat-menu>\n }\n }\n}\n", styles: [".text-primary{color:var(--sd-primary)!important}.bg-primary{background:var(--sd-primary)!important}.border-primary{border-color:var(--sd-primary)!important}.text-primary-light{color:var(--sd-primary-light)!important}.bg-primary-light{background:var(--sd-primary-light)!important}.border-primary-light{border-color:var(--sd-primary-light)!important}.text-primary-dark{color:var(--sd-primary-dark)!important}.bg-primary-dark{background:var(--sd-primary-dark)!important}.border-primary-dark{border-color:var(--sd-primary-dark)!important}.text-info{color:var(--sd-info)!important}.bg-info{background:var(--sd-info)!important}.border-info{border-color:var(--sd-info)!important}.text-info-light{color:var(--sd-info-light)!important}.bg-info-light{background:var(--sd-info-light)!important}.border-info-light{border-color:var(--sd-info-light)!important}.text-info-dark{color:var(--sd-info-dark)!important}.bg-info-dark{background:var(--sd-info-dark)!important}.border-info-dark{border-color:var(--sd-info-dark)!important}.text-success{color:var(--sd-success)!important}.bg-success{background:var(--sd-success)!important}.border-success{border-color:var(--sd-success)!important}.text-success-light{color:var(--sd-success-light)!important}.bg-success-light{background:var(--sd-success-light)!important}.border-success-light{border-color:var(--sd-success-light)!important}.text-success-dark{color:var(--sd-success-dark)!important}.bg-success-dark{background:var(--sd-success-dark)!important}.border-success-dark{border-color:var(--sd-success-dark)!important}.text-warning{color:var(--sd-warning)!important}.bg-warning{background:var(--sd-warning)!important}.border-warning{border-color:var(--sd-warning)!important}.text-warning-light{color:var(--sd-warning-light)!important}.bg-warning-light{background:var(--sd-warning-light)!important}.border-warning-light{border-color:var(--sd-warning-light)!important}.text-warning-dark{color:var(--sd-warning-dark)!important}.bg-warning-dark{background:var(--sd-warning-dark)!important}.border-warning-dark{border-color:var(--sd-warning-dark)!important}.text-error{color:var(--sd-error)!important}.bg-error{background:var(--sd-error)!important}.border-error{border-color:var(--sd-error)!important}.text-error-light{color:var(--sd-error-light)!important}.bg-error-light{background:var(--sd-error-light)!important}.border-error-light{border-color:var(--sd-error-light)!important}.text-error-dark{color:var(--sd-error-dark)!important}.bg-error-dark{background:var(--sd-error-dark)!important}.border-error-dark{border-color:var(--sd-error-dark)!important}.text-secondary{color:var(--sd-secondary)!important}.bg-secondary{background:var(--sd-secondary)!important}.border-secondary{border-color:var(--sd-secondary)!important}.text-secondary-light{color:var(--sd-secondary-light)!important}.bg-secondary-light{background:var(--sd-secondary-light)!important}.border-secondary-light{border-color:var(--sd-secondary-light)!important}.text-secondary-dark{color:var(--sd-secondary-dark)!important}.bg-secondary-dark{background:var(--sd-secondary-dark)!important}.border-secondary-dark{border-color:var(--sd-secondary-dark)!important}.text-light{color:var(--sd-light)!important}.bg-light{background:var(--sd-light)!important}.border-light{border-color:var(--sd-light)!important}.text-dark{color:var(--sd-dark)!important}.bg-dark{background:var(--sd-dark)!important}.border-dark{border-color:var(--sd-dark)!important}.text-black500{color:var(--sd-black500)!important}.bg-black500{background:var(--sd-black500)!important}.border-black500{border-color:var(--sd-black500)!important}.text-black400{color:var(--sd-black400)!important}.bg-black400{background:var(--sd-black400)!important}.border-black400{border-color:var(--sd-black400)!important}.text-black300{color:var(--sd-black300)!important}.bg-black300{background:var(--sd-black300)!important}.border-black300{border-color:var(--sd-black300)!important}.text-black200{color:var(--sd-black200)!important}.bg-black200{background:var(--sd-black200)!important}.border-black200{border-color:var(--sd-black200)!important}.text-black100{color:var(--sd-black100)!important}.bg-black100{background:var(--sd-black100)!important}.border-black100{border-color:var(--sd-black100)!important}.text-white{color:#fff!important}.bg-white{background:#fff!important}.border-white{border-color:#fff!important}.text-black{color:#000!important}.bg-black{background:#000!important}.border-black{border-color:#000!important}:host{display:flex;align-items:center}button[mat-icon-button]{width:24px;height:24px;line-height:24px;padding:0}sd-icon.c-icon{color:var(--sd-black400)!important;width:16px;height:16px;font-size:16px;line-height:16px}.sd-command-menu-item__content{display:inline-flex;align-items:center;gap:8px;min-width:0;width:100%}.sd-command-menu-item__icon{color:var(--sd-black400)!important;width:24px;height:24px;font-size:18px;line-height:24px!important;margin-right:0!important;flex:0 0 24px}.sd-command-menu-item__title{min-width:0;line-height:20px;white-space:nowrap}\n"], dependencies: [{ kind: "component", type: SdIcon, selector: "sd-icon", inputs: ["name", "fontIcon", "color", "set", "fontSet", "size", "strokeWidth", "absoluteStrokeWidth", "ariaLabel"] }, { kind: "ngmodule", type: CommonModule }, { kind: "pipe", type: i1.AsyncPipe, name: "async" }, { kind: "ngmodule", type: MatTooltipModule }, { kind: "directive", type: i2.MatTooltip, selector: "[matTooltip]", inputs: ["matTooltipPosition", "matTooltipPositionAtOrigin", "matTooltipDisabled", "matTooltipShowDelay", "matTooltipHideDelay", "matTooltipTouchGestures", "matTooltip", "matTooltipClass"], exportAs: ["matTooltip"] }, { kind: "ngmodule", type: MatMenuModule }, { kind: "component", type: i3.MatMenu, selector: "mat-menu", inputs: ["backdropClass", "aria-label", "aria-labelledby", "aria-describedby", "xPosition", "yPosition", "overlapTrigger", "hasBackdrop", "class", "classList"], outputs: ["closed", "close"], exportAs: ["matMenu"] }, { kind: "component", type: i3.MatMenuItem, selector: "[mat-menu-item]", inputs: ["role", "disabled", "disableRipple"], exportAs: ["matMenuItem"] }, { kind: "directive", type: i3.MatMenuTrigger, selector: "[mat-menu-trigger-for], [matMenuTriggerFor]", inputs: ["mat-menu-trigger-for", "matMenuTriggerFor", "matMenuTriggerData", "matMenuTriggerRestoreFocus"], outputs: ["menuOpened", "onMenuOpen", "menuClosed", "onMenuClose"], exportAs: ["matMenuTrigger"] }, { kind: "ngmodule", type: MatButtonModule }, { kind: "component", type: i4.MatIconButton, selector: "button[mat-icon-button]", exportAs: ["matButton"] }, { kind: "pipe", type: CommandPipe, name: "command" }, { kind: "pipe", type: CommandFilterPipe, name: "filter" }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
1751
1727
|
}
|
|
1752
1728
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.21", ngImport: i0, type: DesktopCommand, decorators: [{
|
|
1753
1729
|
type: Component,
|
|
1754
1730
|
args: [{ selector: 'desktop-command', changeDetection: ChangeDetectionStrategy.OnPush, standalone: true, host: {
|
|
1755
1731
|
'[attr.data-autoid]': 'autoId()',
|
|
1756
|
-
}, imports: [CommonModule, MatTooltipModule, MatMenuModule, MatButtonModule,
|
|
1732
|
+
}, imports: [SdIcon, CommonModule, MatTooltipModule, MatMenuModule, MatButtonModule, CommandPipe, CommandFilterPipe], template: "@let _autoId = autoId();\n@let _item = item();\n@let filteredCommands = _item | filter: _commands() | async;\n\n@if (filteredCommands?.length) {\n @for (command of filteredCommands; track command.key) {\n @let _meta = _item | command: command;\n @if (command.type === 'normal') {\n <button\n [attr.data-autoid]=\"_autoId + '-' + command.key\"\n (click)=\"command.click(_item.data)\"\n [matTooltip]=\"_meta.title\"\n aria-hidden=\"true\"\n [disabled]=\"_meta.disabled\"\n mat-icon-button>\n <sd-icon class=\"c-icon\" [color]=\"command.color || 'secondary'\" [fontSet]=\"command.fontSet\" [name]=\"_meta.icon\"></sd-icon>\n </button>\n } @else {\n <button [attr.data-autoid]=\"_autoId + '-' + command.key\" [matMenuTriggerFor]=\"menu\" aria-hidden=\"true\" mat-icon-button>\n @if (_meta.icon) {\n <sd-icon class=\"c-icon\" [fontSet]=\"command.fontSet\" [name]=\"_meta.icon\"></sd-icon>\n } @else {\n <sd-icon class=\"c-icon\" [fontSet]=\"command.fontSet\" name=\"more_vert\"></sd-icon>\n }\n </button>\n <mat-menu #menu=\"matMenu\" [attr.data-autoid]=\"_autoId + '-' + command.key + '-menu'\">\n <span>\n @for (childCommand of command.children; track childCommand.key) {\n @let _childMeta = _item | command: childCommand;\n <button\n [attr.data-autoid]=\"_autoId + '-' + command.key + '-' + childCommand.key\"\n mat-menu-item\n (click)=\"childCommand.click(_item.data)\"\n [disabled]=\"_childMeta.disabled\">\n @if (_childMeta.htmlTemplate) {\n <div [innerHTML]=\"_childMeta.htmlTemplate\"></div>\n } @else {\n <span class=\"sd-command-menu-item__content\">\n <sd-icon class=\"sd-command-menu-item__icon\"\n [color]=\"childCommand.color || 'secondary'\"\n [fontSet]=\"childCommand.fontSet\" [name]=\"_childMeta.icon\"></sd-icon>\n <span class=\"sd-command-menu-item__title\">{{ _childMeta.title }}</span>\n </span>\n }\n </button>\n }\n </span>\n </mat-menu>\n }\n }\n}\n", styles: [".text-primary{color:var(--sd-primary)!important}.bg-primary{background:var(--sd-primary)!important}.border-primary{border-color:var(--sd-primary)!important}.text-primary-light{color:var(--sd-primary-light)!important}.bg-primary-light{background:var(--sd-primary-light)!important}.border-primary-light{border-color:var(--sd-primary-light)!important}.text-primary-dark{color:var(--sd-primary-dark)!important}.bg-primary-dark{background:var(--sd-primary-dark)!important}.border-primary-dark{border-color:var(--sd-primary-dark)!important}.text-info{color:var(--sd-info)!important}.bg-info{background:var(--sd-info)!important}.border-info{border-color:var(--sd-info)!important}.text-info-light{color:var(--sd-info-light)!important}.bg-info-light{background:var(--sd-info-light)!important}.border-info-light{border-color:var(--sd-info-light)!important}.text-info-dark{color:var(--sd-info-dark)!important}.bg-info-dark{background:var(--sd-info-dark)!important}.border-info-dark{border-color:var(--sd-info-dark)!important}.text-success{color:var(--sd-success)!important}.bg-success{background:var(--sd-success)!important}.border-success{border-color:var(--sd-success)!important}.text-success-light{color:var(--sd-success-light)!important}.bg-success-light{background:var(--sd-success-light)!important}.border-success-light{border-color:var(--sd-success-light)!important}.text-success-dark{color:var(--sd-success-dark)!important}.bg-success-dark{background:var(--sd-success-dark)!important}.border-success-dark{border-color:var(--sd-success-dark)!important}.text-warning{color:var(--sd-warning)!important}.bg-warning{background:var(--sd-warning)!important}.border-warning{border-color:var(--sd-warning)!important}.text-warning-light{color:var(--sd-warning-light)!important}.bg-warning-light{background:var(--sd-warning-light)!important}.border-warning-light{border-color:var(--sd-warning-light)!important}.text-warning-dark{color:var(--sd-warning-dark)!important}.bg-warning-dark{background:var(--sd-warning-dark)!important}.border-warning-dark{border-color:var(--sd-warning-dark)!important}.text-error{color:var(--sd-error)!important}.bg-error{background:var(--sd-error)!important}.border-error{border-color:var(--sd-error)!important}.text-error-light{color:var(--sd-error-light)!important}.bg-error-light{background:var(--sd-error-light)!important}.border-error-light{border-color:var(--sd-error-light)!important}.text-error-dark{color:var(--sd-error-dark)!important}.bg-error-dark{background:var(--sd-error-dark)!important}.border-error-dark{border-color:var(--sd-error-dark)!important}.text-secondary{color:var(--sd-secondary)!important}.bg-secondary{background:var(--sd-secondary)!important}.border-secondary{border-color:var(--sd-secondary)!important}.text-secondary-light{color:var(--sd-secondary-light)!important}.bg-secondary-light{background:var(--sd-secondary-light)!important}.border-secondary-light{border-color:var(--sd-secondary-light)!important}.text-secondary-dark{color:var(--sd-secondary-dark)!important}.bg-secondary-dark{background:var(--sd-secondary-dark)!important}.border-secondary-dark{border-color:var(--sd-secondary-dark)!important}.text-light{color:var(--sd-light)!important}.bg-light{background:var(--sd-light)!important}.border-light{border-color:var(--sd-light)!important}.text-dark{color:var(--sd-dark)!important}.bg-dark{background:var(--sd-dark)!important}.border-dark{border-color:var(--sd-dark)!important}.text-black500{color:var(--sd-black500)!important}.bg-black500{background:var(--sd-black500)!important}.border-black500{border-color:var(--sd-black500)!important}.text-black400{color:var(--sd-black400)!important}.bg-black400{background:var(--sd-black400)!important}.border-black400{border-color:var(--sd-black400)!important}.text-black300{color:var(--sd-black300)!important}.bg-black300{background:var(--sd-black300)!important}.border-black300{border-color:var(--sd-black300)!important}.text-black200{color:var(--sd-black200)!important}.bg-black200{background:var(--sd-black200)!important}.border-black200{border-color:var(--sd-black200)!important}.text-black100{color:var(--sd-black100)!important}.bg-black100{background:var(--sd-black100)!important}.border-black100{border-color:var(--sd-black100)!important}.text-white{color:#fff!important}.bg-white{background:#fff!important}.border-white{border-color:#fff!important}.text-black{color:#000!important}.bg-black{background:#000!important}.border-black{border-color:#000!important}:host{display:flex;align-items:center}button[mat-icon-button]{width:24px;height:24px;line-height:24px;padding:0}sd-icon.c-icon{color:var(--sd-black400)!important;width:16px;height:16px;font-size:16px;line-height:16px}.sd-command-menu-item__content{display:inline-flex;align-items:center;gap:8px;min-width:0;width:100%}.sd-command-menu-item__icon{color:var(--sd-black400)!important;width:24px;height:24px;font-size:18px;line-height:24px!important;margin-right:0!important;flex:0 0 24px}.sd-command-menu-item__title{min-width:0;line-height:20px;white-space:nowrap}\n"] }]
|
|
1757
1733
|
}] });
|
|
1758
1734
|
|
|
1759
|
-
/* eslint-disable @angular-eslint/no-input-rename */
|
|
1760
|
-
// eslint-disable-next-line @angular-eslint/component-class-suffix
|
|
1761
1735
|
class SdPopupExport {
|
|
1762
1736
|
ref;
|
|
1763
1737
|
loadingService;
|
|
@@ -1936,7 +1910,7 @@ class SdPopupExport {
|
|
|
1936
1910
|
generateAndUploadTemplate = async (fileName) => {
|
|
1937
1911
|
const sheets = [];
|
|
1938
1912
|
if (Array.isArray(this.exportOption?.sheets)) {
|
|
1939
|
-
for (const sheet of this.exportOption
|
|
1913
|
+
for (const sheet of this.exportOption.sheets) {
|
|
1940
1914
|
if (sheet.name && sheet.items && sheet.headers) {
|
|
1941
1915
|
if (Array.isArray(sheet.items)) {
|
|
1942
1916
|
sheets.push({
|
|
@@ -2039,11 +2013,11 @@ class SdPopupExport {
|
|
|
2039
2013
|
return '';
|
|
2040
2014
|
};
|
|
2041
2015
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.21", ngImport: i0, type: SdPopupExport, deps: [{ token: i0.ChangeDetectorRef }, { token: i1$1.SdLoadingService }, { token: i1$1.SdExcelService }, { token: i1$1.SdNotifyService }, { token: i1$1.SdConfirmService }], target: i0.ɵɵFactoryTarget.Component });
|
|
2042
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "19.2.21", type: SdPopupExport, isStandalone: true, selector: "sd-popup-export", inputs: { _tableOption: ["tableOption", "_tableOption"], configuration: "configuration" }, outputs: { export: "export" }, viewQueries: [{ propertyName: "modal", first: true, predicate: ["modal"], descendants: true }, { propertyName: "listGroups", first: true, predicate: ["listGroups"], descendants: true }], ngImport: i0, template: "<sd-modal width=\"907px\" [title]=\"'Exported template'\" #modal>\n <div class=\"row\">\n <div *ngIf=\"!files?.length\" class=\"col-12\">\n <div class=\"c-empty\">\n <img class=\"sd-image-data-empty\" alt=\"empty-image\" />\n <div class=\"T14R\">{{ 'There are no exported templates' }}</div>\n </div>\n </div>\n <ng-container *ngIf=\"files?.length\">\n <div class=\"col-12\">\n <div class=\"c-table\" style=\"max-height: 50vh\">\n <table mat-table [dataSource]=\"files\">\n <ng-container matColumnDef=\"stt\">\n <th mat-header-cell class=\"c-th text-center px-5\" *matHeaderCellDef style=\"width: 50px\">#</th>\n <td class=\"text-center px-5\" mat-cell *matCellDef=\"let item; let idx = index\">\n {{ idx + 1 }}\n </td>\n </ng-container>\n <ng-container matColumnDef=\"fileName\">\n <th mat-header-cell class=\"c-th px-5\" *matHeaderCellDef>\n {{ 'File name' }}\n </th>\n <td class=\"px-5\" mat-cell *matCellDef=\"let item\">\n {{ item.fileName }}\n </td>\n </ng-container>\n <ng-container matColumnDef=\"action\">\n <th mat-header-cell class=\"c-th px-5\" *matHeaderCellDef style=\"width: 80px\"></th>\n <td class=\"px-5\" mat-cell *matCellDef=\"let item\">\n <div class=\"d-flex\">\n <button mat-icon-button aria-label=\"delete\" (click)=\"removeFile(item)\">\n <
|
|
2016
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "19.2.21", type: SdPopupExport, isStandalone: true, selector: "sd-popup-export", inputs: { _tableOption: ["tableOption", "_tableOption"], configuration: "configuration" }, outputs: { export: "export" }, viewQueries: [{ propertyName: "modal", first: true, predicate: ["modal"], descendants: true }, { propertyName: "listGroups", first: true, predicate: ["listGroups"], descendants: true }], ngImport: i0, template: "<sd-modal width=\"907px\" [title]=\"'Exported template'\" #modal>\n <div class=\"row\">\n <div *ngIf=\"!files?.length\" class=\"col-12\">\n <div class=\"c-empty\">\n <img class=\"sd-image-data-empty\" alt=\"empty-image\" />\n <div class=\"T14R\">{{ 'There are no exported templates' }}</div>\n </div>\n </div>\n <ng-container *ngIf=\"files?.length\">\n <div class=\"col-12\">\n <div class=\"c-table\" style=\"max-height: 50vh\">\n <table mat-table [dataSource]=\"files\">\n <ng-container matColumnDef=\"stt\">\n <th mat-header-cell class=\"c-th text-center px-5\" *matHeaderCellDef style=\"width: 50px\">#</th>\n <td class=\"text-center px-5\" mat-cell *matCellDef=\"let item; let idx = index\">\n {{ idx + 1 }}\n </td>\n </ng-container>\n <ng-container matColumnDef=\"fileName\">\n <th mat-header-cell class=\"c-th px-5\" *matHeaderCellDef>\n {{ 'File name' }}\n </th>\n <td class=\"px-5\" mat-cell *matCellDef=\"let item\">\n {{ item.fileName }}\n </td>\n </ng-container>\n <ng-container matColumnDef=\"action\">\n <th mat-header-cell class=\"c-th px-5\" *matHeaderCellDef style=\"width: 80px\"></th>\n <td class=\"px-5\" mat-cell *matCellDef=\"let item\">\n <div class=\"d-flex\">\n <button mat-icon-button aria-label=\"delete\" (click)=\"removeFile(item)\">\n <sd-icon name=\"delete\"></sd-icon>\n </button>\n <button mat-icon-button aria-label=\"download\" (click)=\"onExport(item)\">\n <sd-icon name=\"download\"></sd-icon>\n </button>\n </div>\n </td>\n </ng-container>\n <tr mat-header-row *matHeaderRowDef=\"['stt', 'fileName', 'action']; sticky: true\"></tr>\n <tr mat-row *matRowDef=\"let row; columns: ['stt', 'fileName', 'action']\"></tr>\n </table>\n </div>\n </div>\n <div *ngIf=\"files.length < 5\" class=\"col-12 mt-10\">\n <sd-button class=\"mr-4\" [title]=\"'New template'\" (click)=\"enableCreating = true\" color=\"info\" [disabled]=\"enableCreating\">\n </sd-button>\n <sd-button *ngIf=\"exportOption?.enableUpload\" [title]=\"'Upload template'\" (click)=\"uploadTemplate()\" type=\"outline\">\n </sd-button>\n </div>\n </ng-container>\n <ng-container *ngIf=\"enableCreating || !files?.length\">\n <div class=\"col-12 mt-20\">\n <div class=\"T14R\">{{ 'Select columns for creating template' }}:</div>\n </div>\n <div class=\"col-12\">\n <mat-chip-listbox selectable=\"true\" multiple=\"true\">\n <ng-container *ngFor=\"let column of columns\">\n <mat-chip-option [selected]=\"selected[column.field]\" (click)=\"selected[column.field] = !selected[column.field]\">\n {{ column.title }}\n </mat-chip-option>\n </ng-container>\n </mat-chip-listbox>\n </div>\n <div class=\"col-12 row\">\n <div class=\"col-10\">\n <sd-input [form]=\"form\" [label]=\"'Template name'\" [(model)]=\"templateName\" [validator]=\"templateNameValidator\"></sd-input>\n </div>\n <div class=\"col-2 mt-8\">\n <sd-button width=\"100%\" [title]=\"'Save'\" color=\"info\" (click)=\"createTemplate()\"> </sd-button>\n </div>\n </div>\n </ng-container>\n </div>\n</sd-modal>\n", styles: [".c-radio-group{display:flex;flex-direction:column;margin:15px 0}.c-radio-button{margin:5px}.c-empty{display:flex;flex-direction:column;justify-content:center;align-items:center;position:static;height:116px;background:#f6f6f6;border-radius:4px}.c-table{position:relative;overflow:auto}.c-table table{width:100%}.c-table .c-th{font-weight:500;font-size:14px;line-height:20px;color:#000}\n"], dependencies: [{ kind: "component", type: SdIcon, selector: "sd-icon", inputs: ["name", "fontIcon", "color", "set", "fontSet", "size", "strokeWidth", "absoluteStrokeWidth", "ariaLabel"] }, { kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "directive", type: i1.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "ngmodule", type: MatTableModule }, { kind: "component", type: i5.MatTable, selector: "mat-table, table[mat-table]", exportAs: ["matTable"] }, { kind: "directive", type: i5.MatHeaderCellDef, selector: "[matHeaderCellDef]" }, { kind: "directive", type: i5.MatHeaderRowDef, selector: "[matHeaderRowDef]", inputs: ["matHeaderRowDef", "matHeaderRowDefSticky"] }, { kind: "directive", type: i5.MatColumnDef, selector: "[matColumnDef]", inputs: ["matColumnDef"] }, { kind: "directive", type: i5.MatCellDef, selector: "[matCellDef]" }, { kind: "directive", type: i5.MatRowDef, selector: "[matRowDef]", inputs: ["matRowDefColumns", "matRowDefWhen"] }, { kind: "directive", type: i5.MatHeaderCell, selector: "mat-header-cell, th[mat-header-cell]" }, { kind: "directive", type: i5.MatCell, selector: "mat-cell, td[mat-cell]" }, { kind: "component", type: i5.MatHeaderRow, selector: "mat-header-row, tr[mat-header-row]", exportAs: ["matHeaderRow"] }, { kind: "component", type: i5.MatRow, selector: "mat-row, tr[mat-row]", exportAs: ["matRow"] }, { kind: "ngmodule", type: MatChipsModule }, { kind: "component", type: i4$1.MatChipListbox, selector: "mat-chip-listbox", inputs: ["multiple", "aria-orientation", "selectable", "compareWith", "required", "hideSingleSelectionIndicator", "value"], outputs: ["change"] }, { kind: "component", type: i4$1.MatChipOption, selector: "mat-basic-chip-option, [mat-basic-chip-option], mat-chip-option, [mat-chip-option]", inputs: ["selectable", "selected"], outputs: ["selectionChange"] }, { kind: "component", type: SdButton, selector: "sd-button", inputs: ["autoId", "type", "color", "size", "fontSet", "title", "width", "tooltip", "prefixIcon", "suffixIcon", "disabled", "loading", "block", "htmlType"], outputs: ["click"] }, { kind: "component", type: SdInput, selector: "sd-input", inputs: ["autoId", "name", "appearance", "floatLabel", "size", "form", "label", "helperText", "placeholder", "type", "hideInlineError", "blurOnEnter", "required", "readonly", "disabled", "viewed", "minlength", "maxlength", "pattern", "patternErrorMessage", "validator", "inlineError", "hyperlink", "model"], outputs: ["modelChange", "sdChange", "sdFocus", "sdBlur", "keyupEnter", "cleared", "sdFocusForceBlur"] }, { kind: "component", type: SdModal, selector: "sd-modal", inputs: ["autoId", "title", "color", "width", "height", "view", "modalClass", "lazyLoadContent", "hideClose", "disableBackdropClose"], outputs: ["sdClosed"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
2043
2017
|
}
|
|
2044
2018
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.21", ngImport: i0, type: SdPopupExport, decorators: [{
|
|
2045
2019
|
type: Component,
|
|
2046
|
-
args: [{ selector: 'sd-popup-export', changeDetection: ChangeDetectionStrategy.OnPush, standalone: true, imports: [CommonModule, MatTableModule,
|
|
2020
|
+
args: [{ selector: 'sd-popup-export', changeDetection: ChangeDetectionStrategy.OnPush, standalone: true, imports: [SdIcon, CommonModule, MatTableModule, MatChipsModule, SdButton, SdInput, SdModal], template: "<sd-modal width=\"907px\" [title]=\"'Exported template'\" #modal>\n <div class=\"row\">\n <div *ngIf=\"!files?.length\" class=\"col-12\">\n <div class=\"c-empty\">\n <img class=\"sd-image-data-empty\" alt=\"empty-image\" />\n <div class=\"T14R\">{{ 'There are no exported templates' }}</div>\n </div>\n </div>\n <ng-container *ngIf=\"files?.length\">\n <div class=\"col-12\">\n <div class=\"c-table\" style=\"max-height: 50vh\">\n <table mat-table [dataSource]=\"files\">\n <ng-container matColumnDef=\"stt\">\n <th mat-header-cell class=\"c-th text-center px-5\" *matHeaderCellDef style=\"width: 50px\">#</th>\n <td class=\"text-center px-5\" mat-cell *matCellDef=\"let item; let idx = index\">\n {{ idx + 1 }}\n </td>\n </ng-container>\n <ng-container matColumnDef=\"fileName\">\n <th mat-header-cell class=\"c-th px-5\" *matHeaderCellDef>\n {{ 'File name' }}\n </th>\n <td class=\"px-5\" mat-cell *matCellDef=\"let item\">\n {{ item.fileName }}\n </td>\n </ng-container>\n <ng-container matColumnDef=\"action\">\n <th mat-header-cell class=\"c-th px-5\" *matHeaderCellDef style=\"width: 80px\"></th>\n <td class=\"px-5\" mat-cell *matCellDef=\"let item\">\n <div class=\"d-flex\">\n <button mat-icon-button aria-label=\"delete\" (click)=\"removeFile(item)\">\n <sd-icon name=\"delete\"></sd-icon>\n </button>\n <button mat-icon-button aria-label=\"download\" (click)=\"onExport(item)\">\n <sd-icon name=\"download\"></sd-icon>\n </button>\n </div>\n </td>\n </ng-container>\n <tr mat-header-row *matHeaderRowDef=\"['stt', 'fileName', 'action']; sticky: true\"></tr>\n <tr mat-row *matRowDef=\"let row; columns: ['stt', 'fileName', 'action']\"></tr>\n </table>\n </div>\n </div>\n <div *ngIf=\"files.length < 5\" class=\"col-12 mt-10\">\n <sd-button class=\"mr-4\" [title]=\"'New template'\" (click)=\"enableCreating = true\" color=\"info\" [disabled]=\"enableCreating\">\n </sd-button>\n <sd-button *ngIf=\"exportOption?.enableUpload\" [title]=\"'Upload template'\" (click)=\"uploadTemplate()\" type=\"outline\">\n </sd-button>\n </div>\n </ng-container>\n <ng-container *ngIf=\"enableCreating || !files?.length\">\n <div class=\"col-12 mt-20\">\n <div class=\"T14R\">{{ 'Select columns for creating template' }}:</div>\n </div>\n <div class=\"col-12\">\n <mat-chip-listbox selectable=\"true\" multiple=\"true\">\n <ng-container *ngFor=\"let column of columns\">\n <mat-chip-option [selected]=\"selected[column.field]\" (click)=\"selected[column.field] = !selected[column.field]\">\n {{ column.title }}\n </mat-chip-option>\n </ng-container>\n </mat-chip-listbox>\n </div>\n <div class=\"col-12 row\">\n <div class=\"col-10\">\n <sd-input [form]=\"form\" [label]=\"'Template name'\" [(model)]=\"templateName\" [validator]=\"templateNameValidator\"></sd-input>\n </div>\n <div class=\"col-2 mt-8\">\n <sd-button width=\"100%\" [title]=\"'Save'\" color=\"info\" (click)=\"createTemplate()\"> </sd-button>\n </div>\n </div>\n </ng-container>\n </div>\n</sd-modal>\n", styles: [".c-radio-group{display:flex;flex-direction:column;margin:15px 0}.c-radio-button{margin:5px}.c-empty{display:flex;flex-direction:column;justify-content:center;align-items:center;position:static;height:116px;background:#f6f6f6;border-radius:4px}.c-table{position:relative;overflow:auto}.c-table table{width:100%}.c-table .c-th{font-weight:500;font-size:14px;line-height:20px;color:#000}\n"] }]
|
|
2047
2021
|
}], ctorParameters: () => [{ type: i0.ChangeDetectorRef }, { type: i1$1.SdLoadingService }, { type: i1$1.SdExcelService }, { type: i1$1.SdNotifyService }, { type: i1$1.SdConfirmService }], propDecorators: { modal: [{
|
|
2048
2022
|
type: ViewChild,
|
|
2049
2023
|
args: ['modal']
|
|
@@ -2394,19 +2368,23 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.21", ngImpo
|
|
|
2394
2368
|
class SdSelectionDisabledPipe {
|
|
2395
2369
|
transform = (selectedItems, rowData, selection) => {
|
|
2396
2370
|
const { disabled, actions } = selection;
|
|
2371
|
+
if (rowData.meta.selector.isSelected) {
|
|
2372
|
+
rowData.meta.selector.selectable = true;
|
|
2373
|
+
return false;
|
|
2374
|
+
}
|
|
2397
2375
|
if (!actions?.length) {
|
|
2398
2376
|
if (!disabled) {
|
|
2399
2377
|
rowData.meta.selector.selectable = true;
|
|
2400
2378
|
return false;
|
|
2401
2379
|
}
|
|
2402
|
-
rowData.meta.selector.selectable = !disabled(rowData, selectedItems);
|
|
2380
|
+
rowData.meta.selector.selectable = !disabled(rowData.data, selectedItems.map(e => e.data));
|
|
2403
2381
|
return !rowData.meta.selector.selectable;
|
|
2404
2382
|
}
|
|
2405
2383
|
// Kiểm tra có bị disabled theo function không
|
|
2406
2384
|
// Dữ liệu chưa được check thì kiểm tra hàm disable nếu có
|
|
2407
|
-
if (disabled
|
|
2385
|
+
if (disabled) {
|
|
2408
2386
|
// Nếu disabled và dữ liệu chưa được check
|
|
2409
|
-
if (disabled(rowData, selectedItems)) {
|
|
2387
|
+
if (disabled(rowData.data, selectedItems.map(e => e.data))) {
|
|
2410
2388
|
return true;
|
|
2411
2389
|
}
|
|
2412
2390
|
}
|
|
@@ -2471,7 +2449,7 @@ class SdSelectionVisibleSelectAllPipe {
|
|
|
2471
2449
|
await new Promise(resolve => setTimeout(resolve, 500));
|
|
2472
2450
|
const first = items.find(t => t.meta.selector?.actions?.length);
|
|
2473
2451
|
if (first) {
|
|
2474
|
-
for (const action of first.meta.selector?.actions) {
|
|
2452
|
+
for (const action of first.meta.selector?.actions ?? []) {
|
|
2475
2453
|
if (items.filter(t => t.meta.selector?.actions?.length).every(e => e.meta.selector?.actions?.includes(action))) {
|
|
2476
2454
|
return true;
|
|
2477
2455
|
}
|
|
@@ -2497,7 +2475,7 @@ class SdSelectionVisiblePipe {
|
|
|
2497
2475
|
rowData.meta.selector.selectable = true;
|
|
2498
2476
|
return rowData.meta.selector.selectable;
|
|
2499
2477
|
}
|
|
2500
|
-
for (const action of selection
|
|
2478
|
+
for (const action of selection.actions) {
|
|
2501
2479
|
if ('children' in action) {
|
|
2502
2480
|
let flag = false;
|
|
2503
2481
|
let hasGroup = false;
|
|
@@ -2826,7 +2804,9 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.21", ngImpo
|
|
|
2826
2804
|
}] });
|
|
2827
2805
|
|
|
2828
2806
|
class TableFormatService {
|
|
2829
|
-
//
|
|
2807
|
+
// Keep table display formatting aligned with the public template pipes.
|
|
2808
|
+
#formatDatePipe = inject(SdFormatDatePipe);
|
|
2809
|
+
#formatDatetimePipe = inject(SdFormatDatetimePipe);
|
|
2830
2810
|
#formatNumberPipe = inject(SdFormatNumberPipe);
|
|
2831
2811
|
// ==========================================
|
|
2832
2812
|
// PUBLIC METHODS
|
|
@@ -2987,15 +2967,15 @@ class TableFormatService {
|
|
|
2987
2967
|
// PRIVATE HELPERS
|
|
2988
2968
|
// ==========================================
|
|
2989
2969
|
#formatDateDisplay(value, type) {
|
|
2990
|
-
const date =
|
|
2991
|
-
const time =
|
|
2970
|
+
const date = this.#formatDatePipe.transform(value);
|
|
2971
|
+
const time = this.#formatDatetimePipe.transform(value, 'HH:mm:ss');
|
|
2992
2972
|
if (type === 'datetime') {
|
|
2993
2973
|
return time && date ? `<div class="T14R">${date}<span class="T14R text-black400 ml-4">${time}</span></div>` : '';
|
|
2994
2974
|
}
|
|
2995
2975
|
if (type === 'date')
|
|
2996
|
-
return date
|
|
2976
|
+
return date ?? '';
|
|
2997
2977
|
if (type === 'time')
|
|
2998
|
-
return time
|
|
2978
|
+
return time ?? '';
|
|
2999
2979
|
return '';
|
|
3000
2980
|
}
|
|
3001
2981
|
#processValuesDisplay(value, column, field, cacheObjValues) {
|
|
@@ -3049,7 +3029,6 @@ const buildColumnWidthMap = (column) => {
|
|
|
3049
3029
|
return result;
|
|
3050
3030
|
};
|
|
3051
3031
|
|
|
3052
|
-
/* eslint-disable @typescript-eslint/no-explicit-any */
|
|
3053
3032
|
const isTableItem = (item) => !!item && typeof item === 'object' && 'data' in item && 'meta' in item;
|
|
3054
3033
|
const resolveItemData = (item) => (isTableItem(item) ? item.data : item);
|
|
3055
3034
|
const hasActiveColumnFilter = (rawColumnFilter = {}, columns = []) => columns.some(col => {
|
|
@@ -4539,7 +4518,7 @@ class SdTable {
|
|
|
4539
4518
|
provide: MatPaginatorIntl,
|
|
4540
4519
|
useClass: MatPaginatorIntlCro,
|
|
4541
4520
|
},
|
|
4542
|
-
], queries: [{ propertyName: "sdSubInformation", first: true, predicate: SdTableExpandDefDirective, descendants: true, isSignal: true }, { propertyName: "sdGroupDef", first: true, predicate: SdTableGroupDefDirective, descendants: true, isSignal: true }, { propertyName: "sdCellDefs", predicate: SdTableCellDefDirective, isSignal: true }, { propertyName: "sdFooterDefs", predicate: SdMaterialFooterDefDirective, isSignal: true }, { propertyName: "sdFilterDefs", predicate: SdTableFilterDefDirective, isSignal: true }, { propertyName: "sdTitleDefs", predicate: SdTableTitleDefDirective, isSignal: true }], viewQueries: [{ propertyName: "table", first: true, predicate: MatTable, descendants: true, isSignal: true }, { propertyName: "configComponent", first: true, predicate: ConfigComponent, descendants: true, isSignal: true }, { propertyName: "sdPopupExport", first: true, predicate: SdPopupExport, descendants: true, isSignal: true }, { propertyName: "scroll", first: true, predicate: SdScrollDirective, descendants: true, isSignal: true }, { propertyName: "quickAction", first: true, predicate: SdQuickAction, descendants: true, isSignal: true }, { propertyName: "externalFilter", first: true, predicate: ExternalFilterComponent, descendants: true, isSignal: true }, { propertyName: "mobileFilter", first: true, predicate: MobileFilterComponent, descendants: true, isSignal: true }, { propertyName: "paginator", first: true, predicate: MatPaginator, descendants: true, isSignal: true }, { propertyName: "sort", first: true, predicate: MatSort, descendants: true, isSignal: true }], ngImport: i0, template: "@let _configuration = configuration();\n@let _tableOption = tableOption()!;\n@let _loading = loading();\n@let _items = items();\n@let _total = total();\n@let _isFiltered = isFiltered();\n@let _requireFiltered = requireFiltered();\n@let _export = _tableOption?.export;\n@let _exporting = exporting();\n@let _titleDef = titleDef();\n@let _autoId = autoId();\n@let _exportTitle = exportTitle();\n@let _cellDef = cellDef();\n@let _footerDef = footerDef();\n@let _sdSubInformation = sdSubInformation();\n@let _configComponent = configComponent();\n@let _mobileFilter = mobileFilter();\n@let _selectedTableItems = selectedTableItems();\n<!-- why: tree kh\u00F4ng c\u00F2n c\u1ED9t ri\u00EAng \u2014 khi KH\u00D4NG c\u00F3 c\u1ED9t Index, icon expand nh\u00FAng v\u00E0o\n c\u1ED9t data \u0111\u1EA7u ti\u00EAn. \u0110\u00E2y l\u00E0 field c\u1EE7a c\u1ED9t \u0111\u00F3 (null n\u1EBFu c\u00F3 Index ho\u1EB7c kh\u00F4ng tree). -->\n@let _treeFirstField = _tableOption?.tree && !_tableOption.index?.enabled ? _configuration?.firstColumns?.[0]?.field : null;\n\n@if (_configuration) {\n @if (!_tableOption.filter?.disabled && !!_tableOption.filter?.externalFilters?.length && filterRegister) {\n <external-filter\n class=\"mb-16\"\n [autoId]=\"_autoId\"\n [filterRegister]=\"filterRegister\"\n [filter]=\"_tableOption.filter!\"\n [externalFilters]=\"_tableOption.filter?.externalFilters!\">\n </external-filter>\n }\n @let groupedItems = _items | sdTree: _tableOption.tree : treeRevision() | sdGroup: _tableOption : groupExpandState;\n\n <!-- Tree toggle d\u00F9ng chung: indent (theo c\u1EA5p) + slot chevron/spinner. Nh\u00FAng v\u00E0o\n c\u1ED9t Index ho\u1EB7c c\u1ED9t data \u0111\u1EA7u qua *ngTemplateOutlet (context: { row }). -->\n <ng-template #sdTreeToggle let-row=\"row\">\n @let _tree = row?.meta?.tree;\n @if (_tree) {\n <span class=\"sd-tree-indent\" [style.width.px]=\"(_tree.level ?? 0) * (_tableOption.tree?.indentSize ?? 20)\"></span>\n <span class=\"sd-tree-toggle-slot\">\n @if (_tree.hasChildren) {\n @if (_tree.isExpanding) {\n <span class=\"lds-ring sd-tree-spinner\">\n <div></div>\n <div></div>\n <div></div>\n <div></div>\n </span>\n } @else {\n @let _aid = _autoId;\n <button\n type=\"button\"\n class=\"sd-tree-toggle-btn\"\n [attr.data-autoid]=\"_aid ? _aid + '-tree-toggle-' + row.meta.id : null\"\n (click)=\"onTreeToggle(row); $event.stopPropagation()\">\n <mat-icon>{{ _tree.isExpanded ? 'expand_more' : 'chevron_right' }}</mat-icon>\n </button>\n }\n }\n </span>\n }\n </ng-template>\n\n <ng-content select=\"[sdTableTop]\"></ng-content>\n <div class=\"c-container\">\n @if (_loading) {\n <div class=\"c-loading\">\n <mat-spinner></mat-spinner>\n </div>\n }\n <div\n class=\"c-table\"\n sdScroll\n stickyShadow\n [style.max-height]=\"_tableOption.style?.maxHeight\"\n [style.min-height]=\"_tableOption.style?.minHeight\">\n <table\n mat-table\n [dataSource]=\"groupedItems\"\n [trackBy]=\"trackBy\"\n matSort\n [matSortDisabled]=\"!_tableOption.sort?.enable\"\n multiTemplateDataRows\n cdkDropList\n [cdkDropListData]=\"groupedItems\"\n [cdkDropListDisabled]=\"!_tableOption.rowReorder?.enabled\"\n [cdkDropListSortPredicate]=\"reorderSortPredicate\"\n (cdkDropListDropped)=\"onReorderDrop($event)\">\n @if (_tableOption.rowReorder?.enabled) {\n <ng-container matColumnDef=\"sdReorder\">\n <th mat-header-cell *matHeaderCellDef class=\"sd-reorder-header\" [attr.rowspan]=\"_configuration.multipleHeader ? 2 : 1\"></th>\n <td mat-cell *matCellDef=\"let row\" class=\"sd-reorder-cell\">\n @if (!row.meta?.group?.items?.length) {\n <mat-icon cdkDragHandle [class.sd-reorder-disabled]=\"isReorderDisabled(row)\">\n {{ _tableOption.rowReorder?.icon || 'drag_indicator' }}\n </mat-icon>\n }\n </td>\n <td mat-footer-cell *matFooterCellDef></td>\n </ng-container>\n }\n\n <ng-container matColumnDef=\"sdSubInformation\" sticky>\n <td class=\"p-0\" mat-cell *matCellDef=\"let item\" [attr.colspan]=\"_configuration.displayedColumns.length\">\n @if (_sdSubInformation?.templateRef) {\n @if (_tableOption.expand?.always) {\n <ng-container *ngTemplateOutlet=\"_sdSubInformation?.templateRef!; context: { item: item }\"> </ng-container>\n } @else {\n <div [@detailExpand]=\"item.isExpanded ? 'expanded' : 'collapsed'\">\n @if (item.isExpanded) {\n <ng-container *ngTemplateOutlet=\"_sdSubInformation?.templateRef!; context: { item: item }\"> </ng-container>\n }\n </div>\n }\n }\n </td>\n <td mat-footer-cell *matFooterCellDef></td>\n </ng-container>\n\n <ng-container matColumnDef=\"sdSubInformationAction\" stickyEnd>\n <th class=\"p-0\" mat-header-cell *matHeaderCellDef style=\"width: 1px\" [attr.rowspan]=\"_configuration.multipleHeader ? 2 : 1\"></th>\n <td mat-cell *matCellDef=\"let element\">\n @if (!element.isExpanding && !_tableOption.expand?.always) {\n <sd-button\n [autoId]=\"_autoId ? _autoId + '-expand-' + element.meta.id : null\"\n type=\"link\"\n [prefixIcon]=\"element.isExpanded ? 'expand_less' : 'expand_more'\"\n (click)=\"onExpand(element)\"\n width=\"35px\">\n </sd-button>\n }\n @if (element.isExpanding) {\n <div class=\"lds-ring\">\n <div></div>\n <div></div>\n <div></div>\n <div></div>\n </div>\n }\n </td>\n </ng-container>\n\n <ng-container matColumnDef=\"sdSelection\" sticky>\n <th class=\"sd-selection-cell p-0\" mat-header-cell *matHeaderCellDef [attr.rowspan]=\"_configuration.multipleHeader ? 2 : 1\">\n @let visibleSelectAll = _items | selectionVisibleSelectAll: _tableOption.selector | async;\n @if (visibleSelectAll) {\n <mat-checkbox\n class=\"c-selection px-8\"\n color=\"primary\"\n [ngModel]=\"isSelectAll()\"\n (ngModelChange)=\"isSelectAll.set($event)\"\n (change)=\"onSelectAll()\">\n </mat-checkbox>\n }\n </th>\n\n <td class=\"sd-selection-cell p-0\" mat-cell *matCellDef=\"let item\">\n @let visible = item | selectionVisible: _tableOption.selector;\n @if (visible) {\n @if (_tableOption.selector?.single) {\n <mat-radio-button\n class=\"c-selection px-8\"\n color=\"primary\"\n [checked]=\"item.meta.selector.isSelected\"\n (change)=\"item.meta.selector.isSelected = true; onSelect(item)\"\n [disabled]=\"_selectedTableItems | selectionDisabled: item : _tableOption.selector!\">\n </mat-radio-button>\n } @else {\n <mat-checkbox\n class=\"c-selection px-8\"\n color=\"primary\"\n [(ngModel)]=\"item.meta.selector.isSelected\"\n (change)=\"onSelect(item)\"\n [disabled]=\"_selectedTableItems | selectionDisabled: item : _tableOption.selector!\">\n </mat-checkbox>\n }\n }\n </td>\n <td mat-footer-cell *matFooterCellDef></td>\n </ng-container>\n @if (_tableOption.index?.enabled) {\n @let _pageOffset = pageOffset();\n @let _indexWidth = _tableOption.index?.width || '50px';\n <!-- why: khi tree, c\u1ED9t Index \"\u00F4m\" th\u00EAm chevron + indent. D\u00F9ng width:1px +\n nowrap (.sd-tree-index-cell) \u0111\u1EC3 c\u1ED9t co S\u00C1T n\u1ED9i dung, kh\u00F4ng chi\u1EBFm ch\u1ED7\n th\u1EEBa; header \"#\" canh tr\u00E1i l\u00F9i v\u00E0o (.sd-tree-index-header) cho th\u1EB3ng s\u1ED1. -->\n @let _treeIndex = !!_tableOption.tree;\n <ng-container matColumnDef=\"sdIndex\" sticky>\n <th\n [class.p-0]=\"!_treeIndex\"\n [class.text-center]=\"!_treeIndex\"\n [class.sd-tree-index-cell]=\"_treeIndex\"\n [class.sd-tree-index-header]=\"_treeIndex\"\n mat-header-cell\n *matHeaderCellDef\n [style.width]=\"_treeIndex ? '1px' : _indexWidth\"\n [style.min-width]=\"_treeIndex ? null : _indexWidth\"\n [style.max-width]=\"_treeIndex ? null : _indexWidth\"\n [attr.rowspan]=\"_configuration.multipleHeader ? 2 : 1\">\n {{ _tableOption.index?.title || '#' }}\n </th>\n <td\n [class.px-4]=\"!_treeIndex\"\n [class.text-center]=\"!_treeIndex\"\n [class.sd-tree-index-cell]=\"_treeIndex\"\n mat-cell\n *matCellDef=\"let item; let i = dataIndex\"\n [style.width]=\"_treeIndex ? '1px' : null\"\n [style.min-width]=\"_treeIndex ? null : _indexWidth\"\n [style.max-width]=\"_treeIndex ? null : _indexWidth\">\n @if (!item?.meta?.group?.isGroupHeader) {\n @if (_treeIndex) {\n <!-- why: tree \u2192 chevron + indent + STT ph\u00E2n c\u1EA5p (1, 1.2, 1.2.1). T\u00F4 \u0111\u1EADm root (level 0). -->\n <span class=\"sd-tree-line\">\n <ng-container *ngTemplateOutlet=\"sdTreeToggle; context: { row: item }\"></ng-container>\n @if (item?.meta?.tree?.indexPath?.length) {\n <span class=\"sd-tree-stt\" [class.sd-stt-root]=\"(item.meta.tree.level ?? 0) === 0\">\n {{ item.meta.tree.indexPath.join('.') }}\n </span>\n }\n </span>\n } @else {\n {{ _pageOffset + i + 1 }}\n }\n }\n </td>\n <td mat-footer-cell *matFooterCellDef [style.width]=\"_treeIndex ? '1px' : null\" [style.min-width]=\"_treeIndex ? null : _indexWidth\" [style.max-width]=\"_treeIndex ? null : _indexWidth\"></td>\n </ng-container>\n }\n <ng-container\n matColumnDef=\"sdCommand\"\n [sticky]=\"_tableOption.command?.align !== 'right'\"\n [stickyEnd]=\"_tableOption.command?.align === 'right'\">\n <th class=\"p-0\" mat-header-cell *matHeaderCellDef style=\"width: 50px\" [attr.rowspan]=\"_configuration.multipleHeader ? 2 : 1\"></th>\n <td class=\"px-8\" mat-cell *matCellDef=\"let item\">\n <desktop-command\n [autoId]=\"_autoId\"\n [commands]=\"_tableOption.command?.commands || _tableOption.commands || []\"\n [item]=\"item\"\n [itemIndex]=\"groupedItems.indexOf(item)\"></desktop-command>\n </td>\n <td mat-footer-cell *matFooterCellDef></td>\n </ng-container>\n <!-- why: group header row d\u00F9ng matRowDef RI\u00CANG v\u1EDBi column list ['sdGroupHeader']\n qua predicate when:isGroupHeaderRow. Cell colspan = displayedColumns.length \u0111\u1EC3\n span TO\u00C0N B\u1ED8 width data row. Tr\u00E1nh colspan trick overflow row khi c\u00E1c TD kh\u00E1c render. -->\n <ng-container matColumnDef=\"sdGroupHeader\">\n <td\n class=\"p-0 sd-group-header-cell\"\n mat-cell\n *matCellDef=\"let item\"\n [attr.colspan]=\"sdGroupColspan()\">\n <div class=\"sd-group-row d-flex align-items-center py-8\">\n <!-- why: slot 42px kh\u1EDBp width v\u1EDBi sd-selection-cell data row \u2192 checkbox group c\u0103n TR\u1EE4C d\u1ECDc \u0111\u00FAng v\u1EDBi checkbox data. -->\n @if (_tableOption.selector?.visible && !_tableOption.selector?.single) {\n <div class=\"sd-group-selection-slot d-flex align-items-center justify-content-center\">\n <mat-checkbox\n class=\"c-selection\"\n color=\"primary\"\n [checked]=\"isGroupAllSelected(item)\"\n [indeterminate]=\"isGroupIndeterminate(item)\"\n (change)=\"onSelectGroup(item, $event.checked)\">\n </mat-checkbox>\n </div>\n } @else {\n <div class=\"sd-group-selection-slot\"></div>\n }\n @if (_tableOption.group?.collapsible) {\n <sd-button\n [autoId]=\"_autoId ? _autoId + '-group-toggle-' + (item.meta.group?.key || item.meta.id) : null\"\n type=\"link\"\n [prefixIcon]=\"item.meta.group.isExpanded ? 'expand_more' : 'chevron_right'\"\n width=\"32px\"\n (click)=\"toggleGroupExpand(item)\">\n </sd-button>\n }\n @if (sdGroupDef()?.templateRef; as tpl) {\n <ng-container *ngTemplateOutlet=\"tpl; context: groupContext(item)\"></ng-container>\n } @else {\n <span class=\"T14R\">{{ item.meta.group.values | json }}</span>\n }\n </div>\n </td>\n </ng-container>\n <!-- why: filler column \u1EDF cu\u1ED1i h\u1EA5p th\u1EE5 leftover space khi t\u1ED5ng width c\u00E1c c\u1ED9t data < container \u2014 gi\u1EEF cho selection/STT/command kh\u00F4ng b\u1ECB d\u00E3n. -->\n <ng-container matColumnDef=\"sdFiller\">\n <th class=\"sd-filler-cell p-0\" mat-header-cell *matHeaderCellDef [attr.rowspan]=\"_configuration.multipleHeader ? 2 : 1\"></th>\n <td class=\"sd-filler-cell p-0\" mat-cell *matCellDef=\"let item\"></td>\n <td class=\"sd-filler-cell p-0\" mat-footer-cell *matFooterCellDef></td>\n </ng-container>\n @for (column of _configuration.firstColumns; track column.field) {\n <ng-container [matColumnDef]=\"column.field\" [sticky]=\"_configuration.fixedColumn[column.field]\">\n <th\n mat-header-cell\n *matHeaderCellDef\n class=\"px-8 py-8 c-th\"\n [sdColumnResize]=\"!!_tableOption.config?.resizable && column.type !== 'children'\"\n [minWidth]=\"column.minWidth\"\n [maxWidth]=\"column.maxWidth\"\n (resizeEnd)=\"onColumnResize(column.field, $event)\"\n [style.width]=\"column.width\"\n [style.min-width]=\"column.minWidth || column.width\"\n [style.max-width]=\"column.maxWidth\"\n [attr.rowspan]=\"_configuration.multipleHeader && column.type !== 'children' ? 2 : 1\"\n [attr.colspan]=\"column.type === 'children' ? column.children.length : 1\">\n <div>\n @if (column.type === 'children') {\n <div\n aria-hidden=\"true\"\n class=\"c-header-title\"\n [class.justify-content-end]=\"column.align === 'right'\"\n [class.text-right]=\"column.align === 'right'\">\n <column-title [column]=\"column\" [titleDef]=\"_titleDef[column.field]\"></column-title>\n </div>\n } @else {\n <div\n aria-hidden=\"true\"\n mat-sort-header\n class=\"c-header-title\"\n [class.justify-content-end]=\"column.align === 'right'\"\n [class.text-right]=\"column.align === 'right'\"\n [disabled]=\"!column.sortable\">\n <column-title [column]=\"column\" [titleDef]=\"_titleDef[column.field]\"></column-title>\n </div>\n @let hideInlineFilter =\n _tableOption.filter?.disabled ||\n _tableOption.filter?.hideInlineFilter === true ||\n (_tableOption.filter?.hideInlineFilter === 'auto' && !_isFiltered && _total! <= 10);\n @if (!hideInlineFilter) {\n <ng-container *sdDesktop>\n <column-filter\n [autoId]=\"_autoId\"\n [value]=\"columnFilter?.[column.field!]!\"\n [operator]=\"columnOperator[column.field]\"\n (operatorChange)=\"columnOperator[column.field] = $event!; onOperatorChange(column, $event)\"\n [columnFilter]=\"columnFilter!\"\n [cacheValues]=\"cacheValues\"\n [column]=\"column\"\n (filterChange)=\"onFilterChange()\"\n (filterCommit)=\"onFilterCommit()\">\n </column-filter>\n </ng-container>\n }\n }\n </div>\n </th>\n <td\n class=\"c-td px-0\"\n [class.d-none]=\"column.type === 'children'\"\n mat-cell\n *matCellDef=\"let item\"\n [sdHoverCopy]=\"(item.data && item.data[column.field]) || ''\"\n [sdHoverCopyDisabled]=\"!column.cell?.copiable\">\n @if (column.type !== 'children' && !item?.meta?.group?.isGroupHeader) {\n @if (_treeFirstField && column.field === _treeFirstField) {\n <!-- why: kh\u00F4ng c\u00F3 c\u1ED9t Index \u2192 chevron + indent nh\u00FAng v\u00E0o c\u1ED9t data \u0111\u1EA7u (nh\u01B0 file explorer). -->\n <span class=\"sd-tree-line px-8\">\n <ng-container *ngTemplateOutlet=\"sdTreeToggle; context: { row: item }\"></ng-container>\n <desktop-cell class=\"d-block\" [column]=\"column\" [item]=\"item\" [cellDef]=\"_cellDef\"></desktop-cell>\n </span>\n } @else {\n <desktop-cell class=\"d-block px-8\" [column]=\"column\" [item]=\"item\" [cellDef]=\"_cellDef\"> </desktop-cell>\n }\n }\n </td>\n <td mat-footer-cell *matFooterCellDef>\n <ng-container *ngIf=\"_footerDef[column.field]\">\n <ng-container *ngTemplateOutlet=\"_footerDef[column.field].templateRef; context: { items: _items, column: column }\">\n </ng-container>\n </ng-container>\n </td>\n </ng-container>\n }\n @for (column of _configuration.secondColumns; track column.field) {\n <ng-container [matColumnDef]=\"column.field\">\n <th\n mat-header-cell\n *matHeaderCellDef\n class=\"c-th px-8\"\n [style.width]=\"column.width\"\n [style.min-width]=\"column.minWidth || column.width\"\n [style.max-width]=\"column.maxWidth\">\n <div>\n <div\n aria-hidden=\"true\"\n mat-sort-header\n class=\"c-header-title\"\n [class.justify-content-end]=\"column.align === 'right'\"\n [class.text-right]=\"column.align === 'right'\"\n [disabled]=\"!column.sortable\">\n <column-title [column]=\"column\" [titleDef]=\"_titleDef[column.field]\"></column-title>\n </div>\n @if (!_tableOption.filter?.disabled && !_tableOption.filter?.hideInlineFilter && columnOperator) {\n <ng-container *sdDesktop>\n <column-filter\n [autoId]=\"_autoId\"\n [value]=\"columnFilter?.[column.field!]!\"\n [operator]=\"columnOperator[column.field]\"\n [columnFilter]=\"columnFilter!\"\n [cacheValues]=\"cacheValues\"\n [column]=\"column\"\n (operatorChange)=\"columnOperator[column.field] = $event!; onOperatorChange(column, $event)\"\n (filterChange)=\"onFilterChange()\"\n (filterCommit)=\"onFilterCommit()\">\n </column-filter>\n </ng-container>\n }\n </div>\n </th>\n <td\n class=\"c-td px-0\"\n mat-cell\n *matCellDef=\"let item\"\n [sdHoverCopy]=\"item[column.field]\"\n [sdHoverCopyDisabled]=\"!column.cell?.copiable\">\n @if (column.type !== 'children') {\n <desktop-cell class=\"d-block px-8\" [column]=\"column\" [item]=\"item\" [cellDef]=\"_cellDef\"> </desktop-cell>\n }\n </td>\n <td mat-footer-cell *matFooterCellDef>\n <ng-container *ngIf=\"_footerDef[column.field]\">\n <ng-container *ngTemplateOutlet=\"_footerDef[column.field].templateRef; context: { items: _items, column: column }\">\n </ng-container>\n </ng-container>\n </td>\n </ng-container>\n }\n <tr class=\"c-first-header\" mat-header-row *matHeaderRowDef=\"_configuration.firstHeaders; sticky: true\"></tr>\n @if (!!_configuration.secondHeaders.length) {\n <tr class=\"c-second-header\" mat-header-row *matHeaderRowDef=\"_configuration.secondHeaders; sticky: true\"></tr>\n }\n <!-- Group header row \u2014 ch\u1EC9 1 cell sdGroupHeader colspan to\u00E0n width. -->\n <tr\n mat-row\n *matRowDef=\"let row; columns: ['sdGroupHeader']; when: isGroupHeaderRow\"\n class=\"c-group-row-tr\"></tr>\n\n <!-- Data row \u2014 d\u00F9ng displayedColumns \u0111\u1EA7y \u0111\u1EE7; when isDataRow \u0111\u1EC3 lo\u1EA1i tr\u1EEB group header. -->\n <tr\n mat-row\n cdkDrag\n [cdkDragData]=\"row\"\n [cdkDragDisabled]=\"\n !_tableOption.rowReorder?.enabled ||\n !!row.meta?.group?.items?.length ||\n (row.meta?.tree?.level ?? 0) > 0 ||\n isReorderDisabled(row)\n \"\n *matRowDef=\"let row; columns: _configuration.displayedColumns; when: isDataRow\"\n matRipple\n class=\"c-row\"\n [class.sd-tree-row]=\"!!_tableOption.tree\"\n [ngClass]=\"_tableOption.tree ? 'sd-tree-level-' + (row.meta?.tree?.level ?? 0) : null\"\n [ngStyle]=\"rowStyle(row)\"\n [class.selected]=\"row.meta.selector.isSelected\"></tr>\n\n <!-- Sub-information row \u2014 also gated b\u1EDFi isDataRow \u0111\u1EC3 KH\u00D4NG render empty expand row d\u01B0\u1EDBi group header. -->\n <tr mat-row *matRowDef=\"let row; columns: ['sdSubInformation']; when: isDataRow\" class=\"c-detail-row\"></tr>\n @if (hasFooter() && !!_configuration.displayedFooters.length) {\n <tr mat-footer-row *matFooterRowDef=\"_configuration.displayedFooters; sticky: true\"></tr>\n }\n </table>\n @if (!_loading && !_total) {\n <div class=\"c-no-data-row\">\n @if (_isFiltered) {\n @if (tableConfiguration?.images?.filterEmpty) {\n <img class=\"c-image\" [src]=\"tableConfiguration!.images!.filterEmpty\" alt=\"filter-empty\" />\n } @else {\n <img class=\"c-image sd-image-filter-empty\" alt=\"filter-empty\" />\n }\n <div class=\"T16M\">{{ 'core.component.table.no-results' | translate }}</div>\n <div class=\"T16R text-secondary\">{{ 'core.component.table.no-results-hint' | translate }}</div>\n } @else {\n @if (_requireFiltered) {\n @if (tableConfiguration?.images?.filterRequired) {\n <img class=\"c-image\" [src]=\"tableConfiguration!.images!.filterRequired\" alt=\"filter-required\" />\n } @else {\n <img class=\"c-image sd-image-filter-required\" alt=\"filter-required\" />\n }\n <div class=\"T16R text-secondary\">{{ 'core.component.table.choose-filter-hint' | translate }}</div>\n } @else {\n @if (tableConfiguration?.images?.dataEmpty) {\n <img class=\"c-image\" [src]=\"tableConfiguration!.images!.dataEmpty\" alt=\"data-empty\" />\n } @else {\n <img class=\"c-image sd-image-data-empty\" alt=\"data-empty\" />\n }\n <div class=\"T16R text-secondary\">{{ 'core.component.table.no-data' | translate }}</div>\n }\n }\n </div>\n }\n </div>\n <div class=\"c-paginator\">\n <div class=\"c-action\">\n <ng-container *sdDesktop>\n @if (_tableOption.reload?.visible) {\n <sd-button\n [autoId]=\"_autoId ? _autoId + '-reload' : null\"\n class=\"mr-8\"\n [title]=\"'core.component.table.reload' | translate\"\n prefixIcon=\"refresh\"\n (click)=\"reload()\"\n [disabled]=\"!_items.length\"\n type=\"link\">\n </sd-button>\n }\n </ng-container>\n @if (_export && _items.length) {\n @if (_export.type === 'custom') {\n <sd-button [autoId]=\"_autoId ? _autoId + '-export' : null\" class=\"mr-8\" [title]=\"_exportTitle\" prefixIcon=\"get_app\" (click)=\"exportCustom()\" type=\"link\"> </sd-button>\n } @else {\n @if (_export.visible) {\n @if (_exporting) {\n <sd-button [autoId]=\"_autoId ? _autoId + '-export' : null\" class=\"mr-8\" [loading]=\"_exporting\" [title]=\"_exportTitle\" prefixIcon=\"get_app\" type=\"link\"> </sd-button>\n } @else {\n @if (_export.visible === 'ALL' || !_export.visible) {\n <sd-button [autoId]=\"_autoId ? _autoId + '-export' : null\" class=\"mr-8\" [title]=\"_exportTitle\" prefixIcon=\"get_app\" [matMenuTriggerFor]=\"menu\" type=\"link\"> </sd-button>\n <mat-menu #menu=\"matMenu\">\n <button mat-menu-item [attr.data-autoid]=\"_autoId ? _autoId + '-export-excel' : null\" (click)=\"exportExcel()\" type=\"button\">\n <mat-icon fontSet=\"material-icons-outlined\">file_download</mat-icon>\n <span> {{ 'core.component.table.export-excel' | translate }}</span>\n </button>\n <button mat-menu-item [attr.data-autoid]=\"_autoId ? _autoId + '-export-csv' : null\" (click)=\"exportCSV()\" type=\"button\">\n <mat-icon fontSet=\"material-icons-outlined\">file_download</mat-icon>\n <span> {{ 'core.component.table.export-csv' | translate }}</span>\n </button>\n </mat-menu>\n } @else if (_export.visible === 'EXCEL') {\n <sd-button [autoId]=\"_autoId ? _autoId + '-export-excel' : null\" class=\"mr-8\" [title]=\"_exportTitle\" prefixIcon=\"get_app\" (click)=\"exportExcel()\" type=\"link\"> </sd-button>\n } @else if (_export.visible === 'CSV') {\n <sd-button [autoId]=\"_autoId ? _autoId + '-export-csv' : null\" class=\"mr-8\" [title]=\"_exportTitle\" prefixIcon=\"get_app\" (click)=\"exportCSV()\" type=\"link\"> </sd-button>\n }\n }\n }\n }\n }\n\n <ng-container *sdDesktop>\n @if (_configComponent) {\n <sd-button\n [autoId]=\"_autoId ? _autoId + '-config' : null\"\n class=\"mr-8\"\n [title]=\"'core.component.table.setup-short' | translate\"\n prefixIcon=\"settings\"\n (click)=\"_configComponent.open()\"\n type=\"link\">\n </sd-button>\n }\n </ng-container>\n <!-- Mobile: n\u00FAt Filter m\u1EDF mobile-filter drawer (inline filter \u1EA9n tr\u00EAn mobile) -->\n <ng-container *sdMobile>\n @if (!_tableOption.filter?.disabled && _mobileFilter) {\n <sd-button\n [autoId]=\"_autoId ? _autoId + '-mobile-filter-open' : null\"\n class=\"mr-8\"\n prefixIcon=\"filter_alt\"\n (click)=\"_mobileFilter.open()\"\n type=\"link\">\n </sd-button>\n }\n </ng-container>\n </div>\n @let hidePaginator = !_tableOption.paginate?.pageSize || _total === undefined || _total <= _tableOption.paginate?.pageSize!;\n <!-- Desktop paginator: full config (pageSize dropdown, first/last buttons) -->\n <ng-container *sdDesktop>\n <mat-paginator\n [class.d-none]=\"_tableOption.paginate?.hidden || hidePaginator\"\n [length]=\"_total\"\n [pageSize]=\"_tableOption.paginate?.pageSize\"\n [pageSizeOptions]=\"_tableOption.paginate?.pages!\"\n [showFirstLastButtons]=\"_tableOption.paginate?.showFirstLastButtons\"\n [hidePageSize]=\"_tableOption.paginate?.hidePageSize\"></mat-paginator>\n </ng-container>\n <!-- Mobile paginator: \u1EA9n pageSize dropdown + first/last buttons \u0111\u1EC3 ti\u1EBFt ki\u1EC7m kh\u00F4ng gian -->\n <ng-container *sdMobile>\n <mat-paginator\n [class.d-none]=\"_tableOption.paginate?.hidden || hidePaginator\"\n [length]=\"_total\"\n [pageSize]=\"_tableOption.paginate?.pageSize\"\n [showFirstLastButtons]=\"false\"\n hidePageSize></mat-paginator>\n </ng-container>\n <!-- \"\u0110ang hi\u1EC3n th\u1ECB...\" ch\u1EC9 desktop -->\n <ng-container *sdDesktop>\n @if (!_tableOption.paginate?.hidden && hidePaginator && _total !== undefined && _total > 0) {\n <div class=\"T14R pr-16\">\n {{ 'core.component.table.showing' | translate }} <span class=\"T14M ml-2\">1-{{ _total }}/{{ _total }}</span>\n </div>\n }\n </ng-container>\n </div>\n </div>\n <selector-action [autoId]=\"_autoId\" [tableOption]=\"_tableOption\" [selectedTableItems]=\"_selectedTableItems\" (clear)=\"onClearSelection(groupedItems)\" />\n @if (_tableOption.config?.visible) {\n <config [autoId]=\"_autoId\" [tableOption]=\"_tableOption\" />\n }\n <!-- Mobile filter drawer \u2014 ch\u1EC9 instantiate khi c\u1EA7n render tr\u00EAn mobile -->\n @if (!_tableOption.filter?.disabled && filterRegister) {\n <mobile-filter\n [autoId]=\"_autoId\"\n [filter]=\"_tableOption.filter!\"\n [externalFilters]=\"_tableOption.filter?.externalFilters!\"\n [columns]=\"_configuration.firstColumns\"\n [filterDefs]=\"sdFilterDefs()\"\n [filterRegister]=\"filterRegister\"\n [cacheValues]=\"cacheValues\">\n </mobile-filter>\n }\n}\n", styles: [":host{display:flex;flex-direction:column;overflow:auto;width:100%;height:100%}:host .c-header-title{height:40px;display:flex;align-items:center}:host .c-container{position:relative;min-height:50px;display:flex;flex-direction:column;flex:1}:host .c-container .c-table{position:relative;flex:1;display:flex;flex-direction:column}:host .c-container .c-table table{border-collapse:separate;width:100%}:host .c-container .c-table table tr.c-first-header.mat-mdc-header-row{height:40px}:host .c-container .c-table table tr.c-second-header.mat-mdc-header-row{height:40px}:host .c-container .c-table table tr.c-detail-row{height:0}:host .c-container .c-table table tr.c-row.activated{background-color:#e5ecff}:host .c-container .c-table table tr.c-row.selected{background-color:#eef2ff}:host .c-container .c-table table tr.c-row:not(.selected):not(.activated):hover{background-color:#f5f5f5}:host .c-container .c-table table tr.c-row td{border-bottom-width:0}:host .c-container .c-table table tr.c-row.c-expandable{cursor:pointer}:host .c-container .c-table table tr.c-row.c-expandable:hover{background:#f5f5f5}:host .c-container .c-table table th.mat-mdc-header-cell{background-color:#f2f3f4;border-bottom:0!important}:host .c-container .c-table table td.mat-mdc-cell,:host .c-container .c-table table td.mat-mdc-footer-cell,:host .c-container .c-table table th.mat-mdc-header-cell{border-bottom-color:#f2f2f2!important}:host .c-container .c-table .c-th{vertical-align:middle;font-weight:500;font-size:14px;line-height:20px;color:#212121}:host .c-container .c-table .c-th.sd-col-resize-host{position:relative}:host .c-container .c-table .c-th.sd-resizing{-webkit-user-select:none;user-select:none}:host .c-container .c-table .c-th .sd-col-resize-handle{position:absolute;top:0;right:0;width:6px;height:100%;cursor:col-resize;-webkit-user-select:none;user-select:none;z-index:2}:host .c-container .c-table .c-th .sd-col-resize-handle:hover{background:#00000014}:host .c-container .c-table .c-td:first{padding-left:10px}:host .c-container .c-table .c-no-data-row{flex:1;width:100%;position:sticky;left:0;display:flex;flex-direction:column;align-items:center;justify-content:center}:host .c-container .c-table .c-no-data-row .c-image{margin-bottom:16px;width:96px}:host .c-container .c-loading{position:absolute;inset:0 0 56px;background:#00000026;z-index:2;display:flex;align-items:center;justify-content:center}:host .c-container .c-paginator{display:flex;flex-direction:row;justify-content:space-between;align-items:center;background-color:#fff}:host .c-container .c-paginator .c-action{padding:5px}:host .c-container .c-empty{text-align:center;background-color:#fff;border:none!important}:host .c-container .c-empty mat-icon{font-size:150px;margin-top:30px;margin-bottom:30px;opacity:.2;width:auto;height:auto}:host button.c-btn-add{background-color:#fff;box-shadow:0 2px 4px #2f313629}:host .lds-ring{display:inline-block;position:relative;width:40px;height:40px}:host .lds-ring div{box-sizing:border-box;display:block;position:absolute;width:32px;height:32px;margin:4px;border:4px solid #cef;border-radius:50%;animation:lds-ring 1.2s cubic-bezier(.5,0,.5,1) infinite;border-color:#cef transparent transparent transparent}:host .lds-ring div:nth-child(1){animation-delay:-.45s}:host .lds-ring div:nth-child(2){animation-delay:-.3s}:host .lds-ring div:nth-child(3){animation-delay:-.15s}@keyframes lds-ring{0%{transform:rotate(0)}to{transform:rotate(360deg)}}:host .sd-reorder-header,:host .sd-reorder-cell{width:40px;min-width:40px;padding:0 4px;box-sizing:border-box}:host .sd-reorder-cell mat-icon{cursor:grab;color:#00000061;display:flex;align-items:center}:host .sd-reorder-cell mat-icon:active{cursor:grabbing}:host .sd-reorder-cell mat-icon.sd-reorder-disabled{opacity:.3;cursor:not-allowed;pointer-events:none}:host ::ng-deep .mat-sort-header-content{display:block;text-align:left;width:100%}:host ::ng-deep .mat-select-arrow{color:#a6a6a6}:host ::ng-deep .mat-sort-header-disabled{background-image:none!important;cursor:default!important;padding-right:0!important}:host ::ng-deep .mat-sort-header-container{align-items:start!important}:host ::ng-deep .mat-sort-header-arrow{margin-top:4px!important}:host ::ng-deep .mat-sort-header-arrow{display:none!important}:host ::ng-deep .mat-sort-header{cursor:pointer}:host ::ng-deep .mat-sort-header[aria-sort]{background-repeat:no-repeat;background-position:center right 0;background-size:16px 16px;cursor:pointer;padding-right:24px}:host ::ng-deep .mat-sort-header[aria-sort=none]{background-image:url(\"data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' height='24px' viewBox='0 0 24 24' width='24px' fill='%23000000'%3E%3Cpath d='M0 0h24v24H0V0z' fill='none'/%3E%3Cpath fill='%237A7A7A' d='M12 5.83L15.17 9l1.41-1.41L12 3 7.41 7.59 8.83 9 12 5.83zm0 12.34L8.83 15l-1.41 1.41L12 21l4.59-4.59L15.17 15 12 18.17z'/%3E%3C/svg%3E\")}:host ::ng-deep .mat-sort-header[aria-sort=ascending]{background-image:url(\"data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' height='24px' viewBox='0 0 24 24' width='24px' fill='%23000000'%3E%3Cpath d='M0 0h24v24H0V0z' fill='none'/%3E%3Cpath fill='%237A7A7A' d='M4 12l1.41 1.41L11 7.83V20h2V7.83l5.58 5.59L20 12l-8-8-8 8z'/%3E%3C/svg%3E\")}:host ::ng-deep .mat-sort-header[aria-sort=descending]{background-image:url(\"data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' height='24px' viewBox='0 0 24 24' width='24px' fill='%23000000'%3E%3Cpath d='M0 0h24v24H0V0z' fill='none'/%3E%3Cpath fill='%237A7A7A' d='M20 12l-1.41-1.41L13 16.17V4h-2v12.17l-5.58-5.59L4 12l8 8 8-8z'/%3E%3C/svg%3E\")}:host ::ng-deep .c-paginator .mat-mdc-paginator .mdc-text-field--outlined .mat-mdc-form-field-infix,:host ::ng-deep .c-paginator .mat-mdc-paginator .mdc-text-field--no-label .mat-mdc-form-field-infix{padding-top:2px;padding-bottom:2px;min-height:32px}:host ::ng-deep .c-paginator .mat-mdc-paginator-range-label{margin:0 4px}:host ::ng-deep .c-paginator .mat-mdc-paginator-page-size-select mat-select{margin-top:2px!important}:host ::ng-deep .cdk-drag-preview{box-shadow:0 4px 12px #00000026;background:#fff;display:table;width:100%}:host ::ng-deep .cdk-drag-preview td{padding:0 8px;border-bottom:1px solid rgba(0,0,0,.12)}:host ::ng-deep .cdk-drag-placeholder{opacity:0}:host ::ng-deep .cdk-drop-list-dragging tr.c-row:not(.cdk-drag-placeholder){transition:transform .25s cubic-bezier(0,0,.2,1)}:host ::ng-deep .sd-selection-cell{width:42px;min-width:42px;max-width:42px}:host ::ng-deep .sd-filler-cell{width:auto;min-width:0;padding:0!important;border:0}:host ::ng-deep .sd-group-header-cell{background:#f5f7fc;border-top:1px solid #e6e9f2;border-bottom:1px solid #e6e9f2}:host ::ng-deep .sd-group-row{min-height:36px}:host ::ng-deep .sd-group-selection-slot{width:42px;min-width:42px;max-width:42px}:host ::ng-deep .c-selection{transform:scale(.85);transform-origin:center}:host ::ng-deep .sd-tree-line{display:inline-flex;align-items:center;min-height:32px}:host ::ng-deep .sd-tree-indent{flex:0 0 auto}:host ::ng-deep .sd-tree-toggle-slot{flex:0 0 auto;display:inline-flex;align-items:center;justify-content:center;width:24px;height:24px}:host ::ng-deep .sd-tree-toggle-btn{display:inline-flex;align-items:center;justify-content:center;width:24px;height:24px;padding:0;border:0;background:transparent;border-radius:50%;cursor:pointer;color:var(--sd-text-secondary, #5b6472);transition:background-color .15s ease}:host ::ng-deep .sd-tree-toggle-btn mat-icon{font-size:18px;width:18px;height:18px;line-height:18px}:host ::ng-deep .sd-tree-toggle-btn:hover{background-color:#0f172a14}:host ::ng-deep .sd-tree-spinner{transform:scale(.45)}:host ::ng-deep .sd-tree-stt{margin-left:2px;white-space:nowrap}:host ::ng-deep .sd-tree-index-cell{text-align:left!important;white-space:nowrap;padding-left:8px;padding-right:8px}:host ::ng-deep .sd-tree-index-header{padding-left:32px}:host ::ng-deep tr.c-row.sd-tree-row.sd-tree-level-0{background:#fbfcfe}:host ::ng-deep tr.c-row.sd-tree-row.sd-tree-level-0>td{font-weight:500}:host ::ng-deep tr.c-row.sd-tree-row.sd-tree-level-1{background:#fff}:host ::ng-deep tr.c-row.sd-tree-row.sd-tree-level-2{background:#fafbfd}:host ::ng-deep tr.c-row.sd-tree-row.sd-tree-level-3{background:#f6f8fb}:host ::ng-deep .sd-stt-root{font-weight:700;color:#1f2330}\n", ":host ::ng-deep .sticky-shadow-right{overflow:visible!important}:host ::ng-deep .sticky-shadow-right:after{content:\"\";position:absolute;top:0;right:0;bottom:0;width:8px;transform:translate(100%);background:linear-gradient(to right,rgba(0,0,0,.12),transparent);pointer-events:none}:host ::ng-deep .sticky-shadow-left{overflow:visible!important}:host ::ng-deep .sticky-shadow-left:after{content:\"\";position:absolute;top:0;left:0;bottom:0;width:8px;transform:translate(-100%);background:linear-gradient(to left,rgba(0,0,0,.12),transparent);pointer-events:none}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "directive", type: i1.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "directive", type: i1.NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "directive", type: i1.NgStyle, selector: "[ngStyle]", inputs: ["ngStyle"] }, { kind: "pipe", type: i1.AsyncPipe, name: "async" }, { kind: "pipe", type: i1.JsonPipe, name: "json" }, { kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i2$2.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i2$2.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "ngmodule", type: MatMenuModule }, { kind: "component", type: i2.MatMenu, selector: "mat-menu", inputs: ["backdropClass", "aria-label", "aria-labelledby", "aria-describedby", "xPosition", "yPosition", "overlapTrigger", "hasBackdrop", "class", "classList"], outputs: ["closed", "close"], exportAs: ["matMenu"] }, { kind: "component", type: i2.MatMenuItem, selector: "[mat-menu-item]", inputs: ["role", "disabled", "disableRipple"], exportAs: ["matMenuItem"] }, { kind: "directive", type: i2.MatMenuTrigger, selector: "[mat-menu-trigger-for], [matMenuTriggerFor]", inputs: ["mat-menu-trigger-for", "matMenuTriggerFor", "matMenuTriggerData", "matMenuTriggerRestoreFocus"], outputs: ["menuOpened", "onMenuOpen", "menuClosed", "onMenuClose"], exportAs: ["matMenuTrigger"] }, { kind: "ngmodule", type: MatPaginatorModule }, { kind: "component", type: i4$1.MatPaginator, selector: "mat-paginator", inputs: ["color", "pageIndex", "length", "pageSize", "pageSizeOptions", "hidePageSize", "showFirstLastButtons", "selectConfig", "disabled"], outputs: ["page"], exportAs: ["matPaginator"] }, { kind: "ngmodule", type: MatIconModule }, { kind: "component", type: i5.MatIcon, selector: "mat-icon", inputs: ["color", "inline", "svgIcon", "fontSet", "fontIcon"], exportAs: ["matIcon"] }, { kind: "ngmodule", type: MatTableModule }, { kind: "component", type: i6.MatTable, selector: "mat-table, table[mat-table]", exportAs: ["matTable"] }, { kind: "directive", type: i6.MatHeaderCellDef, selector: "[matHeaderCellDef]" }, { kind: "directive", type: i6.MatHeaderRowDef, selector: "[matHeaderRowDef]", inputs: ["matHeaderRowDef", "matHeaderRowDefSticky"] }, { kind: "directive", type: i6.MatColumnDef, selector: "[matColumnDef]", inputs: ["matColumnDef"] }, { kind: "directive", type: i6.MatCellDef, selector: "[matCellDef]" }, { kind: "directive", type: i6.MatRowDef, selector: "[matRowDef]", inputs: ["matRowDefColumns", "matRowDefWhen"] }, { kind: "directive", type: i6.MatFooterCellDef, selector: "[matFooterCellDef]" }, { kind: "directive", type: i6.MatFooterRowDef, selector: "[matFooterRowDef]", inputs: ["matFooterRowDef", "matFooterRowDefSticky"] }, { kind: "directive", type: i6.MatHeaderCell, selector: "mat-header-cell, th[mat-header-cell]" }, { kind: "directive", type: i6.MatCell, selector: "mat-cell, td[mat-cell]" }, { kind: "directive", type: i6.MatFooterCell, selector: "mat-footer-cell, td[mat-footer-cell]" }, { kind: "component", type: i6.MatHeaderRow, selector: "mat-header-row, tr[mat-header-row]", exportAs: ["matHeaderRow"] }, { kind: "component", type: i6.MatRow, selector: "mat-row, tr[mat-row]", exportAs: ["matRow"] }, { kind: "component", type: i6.MatFooterRow, selector: "mat-footer-row, tr[mat-footer-row]", exportAs: ["matFooterRow"] }, { kind: "ngmodule", type: MatSortModule }, { kind: "directive", type: i7.MatSort, selector: "[matSort]", inputs: ["matSortActive", "matSortStart", "matSortDirection", "matSortDisableClear", "matSortDisabled"], outputs: ["matSortChange"], exportAs: ["matSort"] }, { kind: "component", type: i7.MatSortHeader, selector: "[mat-sort-header]", inputs: ["mat-sort-header", "arrowPosition", "start", "disabled", "sortActionDescription", "disableClear"], exportAs: ["matSortHeader"] }, { kind: "ngmodule", type: MatProgressSpinnerModule }, { kind: "component", type: i8.MatProgressSpinner, selector: "mat-progress-spinner, mat-spinner", inputs: ["color", "mode", "value", "diameter", "strokeWidth"], exportAs: ["matProgressSpinner"] }, { kind: "ngmodule", type: MatCheckboxModule }, { kind: "component", type: i9.MatCheckbox, selector: "mat-checkbox", inputs: ["aria-label", "aria-labelledby", "aria-describedby", "aria-expanded", "aria-controls", "aria-owns", "id", "required", "labelPosition", "name", "value", "disableRipple", "tabIndex", "color", "disabledInteractive", "checked", "disabled", "indeterminate"], outputs: ["change", "indeterminateChange"], exportAs: ["matCheckbox"] }, { kind: "ngmodule", type: MatRadioModule }, { kind: "component", type: i10.MatRadioButton, selector: "mat-radio-button", inputs: ["id", "name", "aria-label", "aria-labelledby", "aria-describedby", "disableRipple", "tabIndex", "checked", "value", "labelPosition", "disabled", "required", "color", "disabledInteractive"], outputs: ["change"], exportAs: ["matRadioButton"] }, { kind: "ngmodule", type: DragDropModule }, { kind: "directive", type: i11.CdkDropList, selector: "[cdkDropList], cdk-drop-list", inputs: ["cdkDropListConnectedTo", "cdkDropListData", "cdkDropListOrientation", "id", "cdkDropListLockAxis", "cdkDropListDisabled", "cdkDropListSortingDisabled", "cdkDropListEnterPredicate", "cdkDropListSortPredicate", "cdkDropListAutoScrollDisabled", "cdkDropListAutoScrollStep", "cdkDropListElementContainer"], outputs: ["cdkDropListDropped", "cdkDropListEntered", "cdkDropListExited", "cdkDropListSorted"], exportAs: ["cdkDropList"] }, { kind: "directive", type: i11.CdkDrag, selector: "[cdkDrag]", inputs: ["cdkDragData", "cdkDragLockAxis", "cdkDragRootElement", "cdkDragBoundary", "cdkDragStartDelay", "cdkDragFreeDragPosition", "cdkDragDisabled", "cdkDragConstrainPosition", "cdkDragPreviewClass", "cdkDragPreviewContainer", "cdkDragScale"], outputs: ["cdkDragStarted", "cdkDragReleased", "cdkDragEnded", "cdkDragEntered", "cdkDragExited", "cdkDragDropped", "cdkDragMoved"], exportAs: ["cdkDrag"] }, { kind: "directive", type: i11.CdkDragHandle, selector: "[cdkDragHandle]", inputs: ["cdkDragHandleDisabled"] }, { kind: "component", type: SdButton, selector: "sd-button", inputs: ["autoId", "type", "color", "size", "fontSet", "title", "width", "tooltip", "prefixIcon", "suffixIcon", "disabled", "loading", "block", "htmlType"], outputs: ["click"] }, { kind: "component", type: DesktopCommand, selector: "desktop-command", inputs: ["autoId", "item", "itemIndex", "commands"] }, { kind: "component", type: DesktopCellComponent, selector: "desktop-cell", inputs: ["column", "item", "cellDef"] }, { kind: "component", type: ColumnTitleComponent, selector: "column-title", inputs: ["column", "titleDef"] }, { kind: "component", type: ExternalFilterComponent, selector: "external-filter", inputs: ["autoId", "filter", "externalFilters", "filterRegister"] }, { kind: "component", type: ConfigComponent, selector: "config", inputs: ["autoId", "tableOption"], outputs: ["changes"] }, { kind: "component", type: ColumnFilterComponent, selector: "column-filter", inputs: ["autoId", "column", "columnFilter", "cacheValues", "value", "operator", "isMobile"], outputs: ["operatorChange", "filterChange", "filterCommit"] }, { kind: "component", type: MobileFilterComponent, selector: "mobile-filter", inputs: ["autoId", "filter", "externalFilters", "columns", "filterDefs", "filterRegister", "cacheValues"] }, { kind: "pipe", type: SdGroupPipe, name: "sdGroup" }, { kind: "pipe", type: SdTreePipe, name: "sdTree" }, { kind: "pipe", type: SdSelectionVisiblePipe, name: "selectionVisible" }, { kind: "pipe", type: SdSelectionVisibleSelectAllPipe, name: "selectionVisibleSelectAll" }, { kind: "pipe", type: SdSelectionDisabledPipe, name: "selectionDisabled" }, { kind: "directive", type: SdScrollDirective, selector: "[sdScroll]" }, { kind: "directive", type: SdDesktopDirective, selector: "[sdDesktop]" }, { kind: "directive", type: SdMobileDirective, selector: "[sdMobile]" }, { kind: "directive", type: SdHoverCopyDirective, selector: "[sdHoverCopy]", inputs: ["sdHoverCopy", "sdHoverCopyDisabled"] }, { kind: "component", type: SelectorActionComponent, selector: "selector-action", inputs: ["autoId", "tableOption", "selectedTableItems"], outputs: ["clear"] }, { kind: "directive", type: StickyShadowDirective, selector: "[stickyShadow]" }, { kind: "directive", type: SdColumnResizeDirective, selector: "[sdColumnResize]", inputs: ["sdColumnResize", "minWidth", "maxWidth"], outputs: ["resizeEnd"] }, { kind: "pipe", type: TranslatePipe, name: "translate" }], animations: [
|
|
4521
|
+
], queries: [{ propertyName: "sdSubInformation", first: true, predicate: SdTableExpandDefDirective, descendants: true, isSignal: true }, { propertyName: "sdGroupDef", first: true, predicate: SdTableGroupDefDirective, descendants: true, isSignal: true }, { propertyName: "sdCellDefs", predicate: SdTableCellDefDirective, isSignal: true }, { propertyName: "sdFooterDefs", predicate: SdMaterialFooterDefDirective, isSignal: true }, { propertyName: "sdFilterDefs", predicate: SdTableFilterDefDirective, isSignal: true }, { propertyName: "sdTitleDefs", predicate: SdTableTitleDefDirective, isSignal: true }], viewQueries: [{ propertyName: "table", first: true, predicate: MatTable, descendants: true, isSignal: true }, { propertyName: "configComponent", first: true, predicate: ConfigComponent, descendants: true, isSignal: true }, { propertyName: "sdPopupExport", first: true, predicate: SdPopupExport, descendants: true, isSignal: true }, { propertyName: "scroll", first: true, predicate: SdScrollDirective, descendants: true, isSignal: true }, { propertyName: "quickAction", first: true, predicate: SdQuickAction, descendants: true, isSignal: true }, { propertyName: "externalFilter", first: true, predicate: ExternalFilterComponent, descendants: true, isSignal: true }, { propertyName: "mobileFilter", first: true, predicate: MobileFilterComponent, descendants: true, isSignal: true }, { propertyName: "paginator", first: true, predicate: MatPaginator, descendants: true, isSignal: true }, { propertyName: "sort", first: true, predicate: MatSort, descendants: true, isSignal: true }], ngImport: i0, template: "@let _configuration = configuration();\n@let _tableOption = tableOption()!;\n@let _loading = loading();\n@let _items = items();\n@let _total = total();\n@let _isFiltered = isFiltered();\n@let _requireFiltered = requireFiltered();\n@let _export = _tableOption?.export;\n@let _exporting = exporting();\n@let _titleDef = titleDef();\n@let _autoId = autoId();\n@let _exportTitle = exportTitle();\n@let _cellDef = cellDef();\n@let _footerDef = footerDef();\n@let _sdSubInformation = sdSubInformation();\n@let _configComponent = configComponent();\n@let _mobileFilter = mobileFilter();\n@let _selectedTableItems = selectedTableItems();\n<!-- why: tree kh\u00F4ng c\u00F2n c\u1ED9t ri\u00EAng \u2014 khi KH\u00D4NG c\u00F3 c\u1ED9t Index, icon expand nh\u00FAng v\u00E0o\n c\u1ED9t data \u0111\u1EA7u ti\u00EAn. \u0110\u00E2y l\u00E0 field c\u1EE7a c\u1ED9t \u0111\u00F3 (null n\u1EBFu c\u00F3 Index ho\u1EB7c kh\u00F4ng tree). -->\n@let _treeFirstField = _tableOption?.tree && !_tableOption.index?.enabled ? _configuration?.firstColumns?.[0]?.field : null;\n\n@if (_configuration) {\n @if (!_tableOption.filter?.disabled && !!_tableOption.filter?.externalFilters?.length && filterRegister) {\n <external-filter\n class=\"mb-16\"\n [autoId]=\"_autoId\"\n [filterRegister]=\"filterRegister\"\n [filter]=\"_tableOption.filter!\"\n [externalFilters]=\"_tableOption.filter?.externalFilters!\">\n </external-filter>\n }\n @let groupedItems = _items | sdTree: _tableOption.tree : treeRevision() | sdGroup: _tableOption : groupExpandState;\n\n <!-- Tree toggle d\u00F9ng chung: indent (theo c\u1EA5p) + slot chevron/spinner. Nh\u00FAng v\u00E0o\n c\u1ED9t Index ho\u1EB7c c\u1ED9t data \u0111\u1EA7u qua *ngTemplateOutlet (context: { row }). -->\n <ng-template #sdTreeToggle let-row=\"row\">\n @let _tree = row?.meta?.tree;\n @if (_tree) {\n <span class=\"sd-tree-indent\" [style.width.px]=\"(_tree.level ?? 0) * (_tableOption.tree?.indentSize ?? 20)\"></span>\n <span class=\"sd-tree-toggle-slot\">\n @if (_tree.hasChildren) {\n @if (_tree.isExpanding) {\n <span class=\"lds-ring sd-tree-spinner\">\n <div></div>\n <div></div>\n <div></div>\n <div></div>\n </span>\n } @else {\n @let _aid = _autoId;\n <button\n type=\"button\"\n class=\"sd-tree-toggle-btn\"\n [attr.data-autoid]=\"_aid ? _aid + '-tree-toggle-' + row.meta.id : null\"\n (click)=\"onTreeToggle(row); $event.stopPropagation()\">\n <sd-icon [name]=\"_tree.isExpanded ? 'expand_more' : 'chevron_right'\"></sd-icon>\n </button>\n }\n }\n </span>\n }\n </ng-template>\n\n <ng-content select=\"[sdTableTop]\"></ng-content>\n <div class=\"c-container\">\n @if (_loading) {\n <div class=\"c-loading\">\n <mat-spinner></mat-spinner>\n </div>\n }\n <div\n class=\"c-table\"\n sdScroll\n stickyShadow\n [style.max-height]=\"_tableOption.style?.maxHeight\"\n [style.min-height]=\"_tableOption.style?.minHeight\">\n <table\n mat-table\n [dataSource]=\"groupedItems\"\n [trackBy]=\"trackBy\"\n matSort\n [matSortDisabled]=\"!_tableOption.sort?.enable\"\n multiTemplateDataRows\n cdkDropList\n [cdkDropListData]=\"groupedItems\"\n [cdkDropListDisabled]=\"!_tableOption.rowReorder?.enabled\"\n [cdkDropListSortPredicate]=\"reorderSortPredicate\"\n (cdkDropListDropped)=\"onReorderDrop($event)\">\n @if (_tableOption.rowReorder?.enabled) {\n <ng-container matColumnDef=\"sdReorder\">\n <th mat-header-cell *matHeaderCellDef class=\"sd-reorder-header\" [attr.rowspan]=\"_configuration.multipleHeader ? 2 : 1\"></th>\n <td mat-cell *matCellDef=\"let row\" class=\"sd-reorder-cell\">\n @if (!row.meta?.group?.items?.length) {\n <sd-icon cdkDragHandle [class.sd-reorder-disabled]=\"isReorderDisabled(row)\" [name]=\"_tableOption.rowReorder?.icon || 'drag_indicator'\"></sd-icon>\n }\n </td>\n <td mat-footer-cell *matFooterCellDef></td>\n </ng-container>\n }\n\n <ng-container matColumnDef=\"sdSubInformation\" sticky>\n <td class=\"p-0\" mat-cell *matCellDef=\"let item\" [attr.colspan]=\"_configuration.displayedColumns.length\">\n @if (_sdSubInformation?.templateRef) {\n @if (_tableOption.expand?.always) {\n <ng-container *ngTemplateOutlet=\"_sdSubInformation?.templateRef!; context: { item: item }\"> </ng-container>\n } @else {\n <div [@detailExpand]=\"item.isExpanded ? 'expanded' : 'collapsed'\">\n @if (item.isExpanded) {\n <ng-container *ngTemplateOutlet=\"_sdSubInformation?.templateRef!; context: { item: item }\"> </ng-container>\n }\n </div>\n }\n }\n </td>\n <td mat-footer-cell *matFooterCellDef></td>\n </ng-container>\n\n <ng-container matColumnDef=\"sdSubInformationAction\" stickyEnd>\n <th class=\"p-0\" mat-header-cell *matHeaderCellDef style=\"width: 1px\" [attr.rowspan]=\"_configuration.multipleHeader ? 2 : 1\"></th>\n <td mat-cell *matCellDef=\"let element\">\n @if (!element.isExpanding && !_tableOption.expand?.always) {\n <sd-button\n [autoId]=\"_autoId ? _autoId + '-expand-' + element.meta.id : null\"\n type=\"link\"\n [prefixIcon]=\"element.isExpanded ? 'expand_less' : 'expand_more'\"\n (click)=\"onExpand(element)\"\n width=\"35px\">\n </sd-button>\n }\n @if (element.isExpanding) {\n <div class=\"lds-ring\">\n <div></div>\n <div></div>\n <div></div>\n <div></div>\n </div>\n }\n </td>\n </ng-container>\n\n <ng-container matColumnDef=\"sdSelection\" sticky>\n <th class=\"sd-selection-cell p-0\" mat-header-cell *matHeaderCellDef [attr.rowspan]=\"_configuration.multipleHeader ? 2 : 1\">\n @let visibleSelectAll = _items | selectionVisibleSelectAll: _tableOption.selector | async;\n @if (visibleSelectAll) {\n <mat-checkbox\n class=\"c-selection px-8\"\n color=\"primary\"\n [ngModel]=\"isSelectAll()\"\n (ngModelChange)=\"isSelectAll.set($event)\"\n (change)=\"onSelectAll()\">\n </mat-checkbox>\n }\n </th>\n\n <td class=\"sd-selection-cell p-0\" mat-cell *matCellDef=\"let item\">\n @let visible = item | selectionVisible: _tableOption.selector;\n @if (visible) {\n @if (_tableOption.selector?.single) {\n <mat-radio-button\n class=\"c-selection px-8\"\n color=\"primary\"\n [checked]=\"item.meta.selector.isSelected\"\n (change)=\"item.meta.selector.isSelected = true; onSelect(item)\"\n [disabled]=\"_selectedTableItems | selectionDisabled: item : _tableOption.selector!\">\n </mat-radio-button>\n } @else {\n <mat-checkbox\n class=\"c-selection px-8\"\n color=\"primary\"\n [(ngModel)]=\"item.meta.selector.isSelected\"\n (change)=\"onSelect(item)\"\n [disabled]=\"_selectedTableItems | selectionDisabled: item : _tableOption.selector!\">\n </mat-checkbox>\n }\n }\n </td>\n <td mat-footer-cell *matFooterCellDef></td>\n </ng-container>\n @if (_tableOption.index?.enabled) {\n @let _pageOffset = pageOffset();\n @let _indexWidth = _tableOption.index?.width || '50px';\n <!-- why: khi tree, c\u1ED9t Index \"\u00F4m\" th\u00EAm chevron + indent. D\u00F9ng width:1px +\n nowrap (.sd-tree-index-cell) \u0111\u1EC3 c\u1ED9t co S\u00C1T n\u1ED9i dung, kh\u00F4ng chi\u1EBFm ch\u1ED7\n th\u1EEBa; header \"#\" canh tr\u00E1i l\u00F9i v\u00E0o (.sd-tree-index-header) cho th\u1EB3ng s\u1ED1. -->\n @let _treeIndex = !!_tableOption.tree;\n <ng-container matColumnDef=\"sdIndex\" sticky>\n <th\n [class.p-0]=\"!_treeIndex\"\n [class.text-center]=\"!_treeIndex\"\n [class.sd-tree-index-cell]=\"_treeIndex\"\n [class.sd-tree-index-header]=\"_treeIndex\"\n mat-header-cell\n *matHeaderCellDef\n [style.width]=\"_treeIndex ? '1px' : _indexWidth\"\n [style.min-width]=\"_treeIndex ? null : _indexWidth\"\n [style.max-width]=\"_treeIndex ? null : _indexWidth\"\n [attr.rowspan]=\"_configuration.multipleHeader ? 2 : 1\">\n {{ _tableOption.index?.title || '#' }}\n </th>\n <td\n [class.px-4]=\"!_treeIndex\"\n [class.text-center]=\"!_treeIndex\"\n [class.sd-tree-index-cell]=\"_treeIndex\"\n mat-cell\n *matCellDef=\"let item; let i = dataIndex\"\n [style.width]=\"_treeIndex ? '1px' : null\"\n [style.min-width]=\"_treeIndex ? null : _indexWidth\"\n [style.max-width]=\"_treeIndex ? null : _indexWidth\">\n @if (!item?.meta?.group?.isGroupHeader) {\n @if (_treeIndex) {\n <!-- why: tree \u2192 chevron + indent + STT ph\u00E2n c\u1EA5p (1, 1.2, 1.2.1). T\u00F4 \u0111\u1EADm root (level 0). -->\n <span class=\"sd-tree-line\">\n <ng-container *ngTemplateOutlet=\"sdTreeToggle; context: { row: item }\"></ng-container>\n @if (item?.meta?.tree?.indexPath?.length) {\n <span class=\"sd-tree-stt\" [class.sd-stt-root]=\"(item.meta.tree.level ?? 0) === 0\">\n {{ item.meta.tree.indexPath.join('.') }}\n </span>\n }\n </span>\n } @else {\n {{ _pageOffset + i + 1 }}\n }\n }\n </td>\n <td mat-footer-cell *matFooterCellDef [style.width]=\"_treeIndex ? '1px' : null\" [style.min-width]=\"_treeIndex ? null : _indexWidth\" [style.max-width]=\"_treeIndex ? null : _indexWidth\"></td>\n </ng-container>\n }\n <ng-container\n matColumnDef=\"sdCommand\"\n [sticky]=\"_tableOption.command?.align !== 'right'\"\n [stickyEnd]=\"_tableOption.command?.align === 'right'\">\n <th class=\"p-0\" mat-header-cell *matHeaderCellDef style=\"width: 50px\" [attr.rowspan]=\"_configuration.multipleHeader ? 2 : 1\"></th>\n <td class=\"px-8\" mat-cell *matCellDef=\"let item\">\n <desktop-command\n [autoId]=\"_autoId\"\n [commands]=\"_tableOption.command?.commands || _tableOption.commands || []\"\n [item]=\"item\"\n [itemIndex]=\"groupedItems.indexOf(item)\"></desktop-command>\n </td>\n <td mat-footer-cell *matFooterCellDef></td>\n </ng-container>\n <!-- why: group header row d\u00F9ng matRowDef RI\u00CANG v\u1EDBi column list ['sdGroupHeader']\n qua predicate when:isGroupHeaderRow. Cell colspan = displayedColumns.length \u0111\u1EC3\n span TO\u00C0N B\u1ED8 width data row. Tr\u00E1nh colspan trick overflow row khi c\u00E1c TD kh\u00E1c render. -->\n <ng-container matColumnDef=\"sdGroupHeader\">\n <td\n class=\"p-0 sd-group-header-cell\"\n mat-cell\n *matCellDef=\"let item\"\n [attr.colspan]=\"sdGroupColspan()\">\n <div class=\"sd-group-row d-flex align-items-center py-8\">\n <!-- why: slot 42px kh\u1EDBp width v\u1EDBi sd-selection-cell data row \u2192 checkbox group c\u0103n TR\u1EE4C d\u1ECDc \u0111\u00FAng v\u1EDBi checkbox data. -->\n @if (_tableOption.selector?.visible && !_tableOption.selector?.single) {\n <div class=\"sd-group-selection-slot d-flex align-items-center justify-content-center\">\n <mat-checkbox\n class=\"c-selection\"\n color=\"primary\"\n [checked]=\"isGroupAllSelected(item)\"\n [indeterminate]=\"isGroupIndeterminate(item)\"\n (change)=\"onSelectGroup(item, $event.checked)\">\n </mat-checkbox>\n </div>\n } @else {\n <div class=\"sd-group-selection-slot\"></div>\n }\n @if (_tableOption.group?.collapsible) {\n <sd-button\n [autoId]=\"_autoId ? _autoId + '-group-toggle-' + (item.meta.group?.key || item.meta.id) : null\"\n type=\"link\"\n [prefixIcon]=\"item.meta.group.isExpanded ? 'expand_more' : 'chevron_right'\"\n width=\"32px\"\n (click)=\"toggleGroupExpand(item)\">\n </sd-button>\n }\n @if (sdGroupDef()?.templateRef; as tpl) {\n <ng-container *ngTemplateOutlet=\"tpl; context: groupContext(item)\"></ng-container>\n } @else {\n <span class=\"T14R\">{{ item.meta.group.values | json }}</span>\n }\n </div>\n </td>\n </ng-container>\n <!-- why: filler column \u1EDF cu\u1ED1i h\u1EA5p th\u1EE5 leftover space khi t\u1ED5ng width c\u00E1c c\u1ED9t data < container \u2014 gi\u1EEF cho selection/STT/command kh\u00F4ng b\u1ECB d\u00E3n. -->\n <ng-container matColumnDef=\"sdFiller\">\n <th class=\"sd-filler-cell p-0\" mat-header-cell *matHeaderCellDef [attr.rowspan]=\"_configuration.multipleHeader ? 2 : 1\"></th>\n <td class=\"sd-filler-cell p-0\" mat-cell *matCellDef=\"let item\"></td>\n <td class=\"sd-filler-cell p-0\" mat-footer-cell *matFooterCellDef></td>\n </ng-container>\n @for (column of _configuration.firstColumns; track column.field) {\n <ng-container [matColumnDef]=\"column.field\" [sticky]=\"_configuration.fixedColumn[column.field]\">\n <th\n mat-header-cell\n *matHeaderCellDef\n class=\"px-8 py-8 c-th\"\n [sdColumnResize]=\"!!_tableOption.config?.resizable && column.type !== 'children'\"\n [minWidth]=\"column.minWidth\"\n [maxWidth]=\"column.maxWidth\"\n (resizeEnd)=\"onColumnResize(column.field, $event)\"\n [style.width]=\"column.width\"\n [style.min-width]=\"column.minWidth || column.width\"\n [style.max-width]=\"column.maxWidth\"\n [attr.rowspan]=\"_configuration.multipleHeader && column.type !== 'children' ? 2 : 1\"\n [attr.colspan]=\"column.type === 'children' ? column.children.length : 1\">\n <div>\n @if (column.type === 'children') {\n <div\n aria-hidden=\"true\"\n class=\"c-header-title\"\n [class.justify-content-end]=\"column.align === 'right'\"\n [class.text-right]=\"column.align === 'right'\">\n <column-title [column]=\"column\" [titleDef]=\"_titleDef[column.field]\"></column-title>\n </div>\n } @else {\n <div\n aria-hidden=\"true\"\n mat-sort-header\n class=\"c-header-title\"\n [class.justify-content-end]=\"column.align === 'right'\"\n [class.text-right]=\"column.align === 'right'\"\n [disabled]=\"!column.sortable\">\n <column-title [column]=\"column\" [titleDef]=\"_titleDef[column.field]\"></column-title>\n </div>\n @let hideInlineFilter =\n _tableOption.filter?.disabled ||\n _tableOption.filter?.hideInlineFilter === true ||\n (_tableOption.filter?.hideInlineFilter === 'auto' && !_isFiltered && _total! <= 10);\n @if (!hideInlineFilter) {\n <ng-container *sdDesktop>\n <column-filter\n [autoId]=\"_autoId\"\n [value]=\"columnFilter?.[column.field!]!\"\n [operator]=\"columnOperator[column.field]\"\n (operatorChange)=\"columnOperator[column.field] = $event!; onOperatorChange(column, $event)\"\n [columnFilter]=\"columnFilter!\"\n [cacheValues]=\"cacheValues\"\n [column]=\"column\"\n (filterChange)=\"onFilterChange()\"\n (filterCommit)=\"onFilterCommit()\">\n </column-filter>\n </ng-container>\n }\n }\n </div>\n </th>\n <td\n class=\"c-td px-0\"\n [class.d-none]=\"column.type === 'children'\"\n mat-cell\n *matCellDef=\"let item\"\n [sdHoverCopy]=\"(item.data && item.data[column.field]) || ''\"\n [sdHoverCopyDisabled]=\"!column.cell?.copiable\">\n @if (column.type !== 'children' && !item?.meta?.group?.isGroupHeader) {\n @if (_treeFirstField && column.field === _treeFirstField) {\n <!-- why: kh\u00F4ng c\u00F3 c\u1ED9t Index \u2192 chevron + indent nh\u00FAng v\u00E0o c\u1ED9t data \u0111\u1EA7u (nh\u01B0 file explorer). -->\n <span class=\"sd-tree-line px-8\">\n <ng-container *ngTemplateOutlet=\"sdTreeToggle; context: { row: item }\"></ng-container>\n <desktop-cell class=\"d-block\" [column]=\"column\" [item]=\"item\" [cellDef]=\"_cellDef\"></desktop-cell>\n </span>\n } @else {\n <desktop-cell class=\"d-block px-8\" [column]=\"column\" [item]=\"item\" [cellDef]=\"_cellDef\"> </desktop-cell>\n }\n }\n </td>\n <td mat-footer-cell *matFooterCellDef>\n <ng-container *ngIf=\"_footerDef[column.field]\">\n <ng-container *ngTemplateOutlet=\"_footerDef[column.field].templateRef; context: { items: _items, column: column }\">\n </ng-container>\n </ng-container>\n </td>\n </ng-container>\n }\n @for (column of _configuration.secondColumns; track column.field) {\n <ng-container [matColumnDef]=\"column.field\">\n <th\n mat-header-cell\n *matHeaderCellDef\n class=\"c-th px-8\"\n [style.width]=\"column.width\"\n [style.min-width]=\"column.minWidth || column.width\"\n [style.max-width]=\"column.maxWidth\">\n <div>\n <div\n aria-hidden=\"true\"\n mat-sort-header\n class=\"c-header-title\"\n [class.justify-content-end]=\"column.align === 'right'\"\n [class.text-right]=\"column.align === 'right'\"\n [disabled]=\"!column.sortable\">\n <column-title [column]=\"column\" [titleDef]=\"_titleDef[column.field]\"></column-title>\n </div>\n @if (!_tableOption.filter?.disabled && !_tableOption.filter?.hideInlineFilter && columnOperator) {\n <ng-container *sdDesktop>\n <column-filter\n [autoId]=\"_autoId\"\n [value]=\"columnFilter?.[column.field!]!\"\n [operator]=\"columnOperator[column.field]\"\n [columnFilter]=\"columnFilter!\"\n [cacheValues]=\"cacheValues\"\n [column]=\"column\"\n (operatorChange)=\"columnOperator[column.field] = $event!; onOperatorChange(column, $event)\"\n (filterChange)=\"onFilterChange()\"\n (filterCommit)=\"onFilterCommit()\">\n </column-filter>\n </ng-container>\n }\n </div>\n </th>\n <td\n class=\"c-td px-0\"\n mat-cell\n *matCellDef=\"let item\"\n [sdHoverCopy]=\"item[column.field]\"\n [sdHoverCopyDisabled]=\"!column.cell?.copiable\">\n @if (column.type !== 'children') {\n <desktop-cell class=\"d-block px-8\" [column]=\"column\" [item]=\"item\" [cellDef]=\"_cellDef\"> </desktop-cell>\n }\n </td>\n <td mat-footer-cell *matFooterCellDef>\n <ng-container *ngIf=\"_footerDef[column.field]\">\n <ng-container *ngTemplateOutlet=\"_footerDef[column.field].templateRef; context: { items: _items, column: column }\">\n </ng-container>\n </ng-container>\n </td>\n </ng-container>\n }\n <tr class=\"c-first-header\" mat-header-row *matHeaderRowDef=\"_configuration.firstHeaders; sticky: true\"></tr>\n @if (!!_configuration.secondHeaders.length) {\n <tr class=\"c-second-header\" mat-header-row *matHeaderRowDef=\"_configuration.secondHeaders; sticky: true\"></tr>\n }\n <!-- Group header row \u2014 ch\u1EC9 1 cell sdGroupHeader colspan to\u00E0n width. -->\n <tr\n mat-row\n *matRowDef=\"let row; columns: ['sdGroupHeader']; when: isGroupHeaderRow\"\n class=\"c-group-row-tr\"></tr>\n\n <!-- Data row \u2014 d\u00F9ng displayedColumns \u0111\u1EA7y \u0111\u1EE7; when isDataRow \u0111\u1EC3 lo\u1EA1i tr\u1EEB group header. -->\n <tr\n mat-row\n cdkDrag\n [cdkDragData]=\"row\"\n [cdkDragDisabled]=\"\n !_tableOption.rowReorder?.enabled ||\n !!row.meta?.group?.items?.length ||\n (row.meta?.tree?.level ?? 0) > 0 ||\n isReorderDisabled(row)\n \"\n *matRowDef=\"let row; columns: _configuration.displayedColumns; when: isDataRow\"\n matRipple\n class=\"c-row\"\n [class.sd-tree-row]=\"!!_tableOption.tree\"\n [ngClass]=\"_tableOption.tree ? 'sd-tree-level-' + (row.meta?.tree?.level ?? 0) : null\"\n [ngStyle]=\"rowStyle(row)\"\n [class.selected]=\"row.meta.selector.isSelected\"></tr>\n\n <!-- Sub-information row \u2014 also gated b\u1EDFi isDataRow \u0111\u1EC3 KH\u00D4NG render empty expand row d\u01B0\u1EDBi group header. -->\n <tr mat-row *matRowDef=\"let row; columns: ['sdSubInformation']; when: isDataRow\" class=\"c-detail-row\"></tr>\n @if (hasFooter() && !!_configuration.displayedFooters.length) {\n <tr mat-footer-row *matFooterRowDef=\"_configuration.displayedFooters; sticky: true\"></tr>\n }\n </table>\n @if (!_loading && !_total) {\n <div class=\"c-no-data-row\">\n @if (_isFiltered) {\n @if (tableConfiguration?.images?.filterEmpty) {\n <img class=\"c-image\" [src]=\"tableConfiguration!.images!.filterEmpty\" alt=\"filter-empty\" />\n } @else {\n <img class=\"c-image sd-image-filter-empty\" alt=\"filter-empty\" />\n }\n <div class=\"T16M\">{{ 'core.component.table.no-results' | translate }}</div>\n <div class=\"T16R text-secondary\">{{ 'core.component.table.no-results-hint' | translate }}</div>\n } @else {\n @if (_requireFiltered) {\n @if (tableConfiguration?.images?.filterRequired) {\n <img class=\"c-image\" [src]=\"tableConfiguration!.images!.filterRequired\" alt=\"filter-required\" />\n } @else {\n <img class=\"c-image sd-image-filter-required\" alt=\"filter-required\" />\n }\n <div class=\"T16R text-secondary\">{{ 'core.component.table.choose-filter-hint' | translate }}</div>\n } @else {\n @if (tableConfiguration?.images?.dataEmpty) {\n <img class=\"c-image\" [src]=\"tableConfiguration!.images!.dataEmpty\" alt=\"data-empty\" />\n } @else {\n <img class=\"c-image sd-image-data-empty\" alt=\"data-empty\" />\n }\n <div class=\"T16R text-secondary\">{{ 'core.component.table.no-data' | translate }}</div>\n }\n }\n </div>\n }\n </div>\n <div class=\"c-paginator\">\n <div class=\"c-action\">\n <ng-container *sdDesktop>\n @if (_tableOption.reload?.visible) {\n <sd-button\n [autoId]=\"_autoId ? _autoId + '-reload' : null\"\n class=\"mr-8\"\n [title]=\"'core.component.table.reload' | translate\"\n prefixIcon=\"refresh\"\n (click)=\"reload()\"\n [disabled]=\"!_items.length\"\n type=\"link\">\n </sd-button>\n }\n </ng-container>\n @if (_export && _items.length) {\n @if (_export.type === 'custom') {\n <sd-button [autoId]=\"_autoId ? _autoId + '-export' : null\" class=\"mr-8\" [title]=\"_exportTitle\" prefixIcon=\"get_app\" (click)=\"exportCustom()\" type=\"link\"> </sd-button>\n } @else {\n @if (_export.visible) {\n @if (_exporting) {\n <sd-button [autoId]=\"_autoId ? _autoId + '-export' : null\" class=\"mr-8\" [loading]=\"_exporting\" [title]=\"_exportTitle\" prefixIcon=\"get_app\" type=\"link\"> </sd-button>\n } @else {\n @if (_export.visible === 'ALL' || !_export.visible) {\n <sd-button [autoId]=\"_autoId ? _autoId + '-export' : null\" class=\"mr-8\" [title]=\"_exportTitle\" prefixIcon=\"get_app\" [matMenuTriggerFor]=\"menu\" type=\"link\"> </sd-button>\n <mat-menu #menu=\"matMenu\">\n <button mat-menu-item [attr.data-autoid]=\"_autoId ? _autoId + '-export-excel' : null\" (click)=\"exportExcel()\" type=\"button\">\n <sd-icon name=\"file_download\"></sd-icon>\n <span> {{ 'core.component.table.export-excel' | translate }}</span>\n </button>\n <button mat-menu-item [attr.data-autoid]=\"_autoId ? _autoId + '-export-csv' : null\" (click)=\"exportCSV()\" type=\"button\">\n <sd-icon name=\"file_download\"></sd-icon>\n <span> {{ 'core.component.table.export-csv' | translate }}</span>\n </button>\n </mat-menu>\n } @else if (_export.visible === 'EXCEL') {\n <sd-button [autoId]=\"_autoId ? _autoId + '-export-excel' : null\" class=\"mr-8\" [title]=\"_exportTitle\" prefixIcon=\"get_app\" (click)=\"exportExcel()\" type=\"link\"> </sd-button>\n } @else if (_export.visible === 'CSV') {\n <sd-button [autoId]=\"_autoId ? _autoId + '-export-csv' : null\" class=\"mr-8\" [title]=\"_exportTitle\" prefixIcon=\"get_app\" (click)=\"exportCSV()\" type=\"link\"> </sd-button>\n }\n }\n }\n }\n }\n\n <ng-container *sdDesktop>\n @if (_configComponent) {\n <sd-button\n [autoId]=\"_autoId ? _autoId + '-config' : null\"\n class=\"mr-8\"\n [title]=\"'core.component.table.setup-short' | translate\"\n prefixIcon=\"settings\"\n (click)=\"_configComponent.open()\"\n type=\"link\">\n </sd-button>\n }\n </ng-container>\n <!-- Mobile: n\u00FAt Filter m\u1EDF mobile-filter drawer (inline filter \u1EA9n tr\u00EAn mobile) -->\n <ng-container *sdMobile>\n @if (!_tableOption.filter?.disabled && _mobileFilter) {\n <sd-button\n [autoId]=\"_autoId ? _autoId + '-mobile-filter-open' : null\"\n class=\"mr-8\"\n prefixIcon=\"filter_alt\"\n (click)=\"_mobileFilter.open()\"\n type=\"link\">\n </sd-button>\n }\n </ng-container>\n </div>\n @let hidePaginator = !_tableOption.paginate?.pageSize || _total === undefined || _total <= _tableOption.paginate?.pageSize!;\n <!-- Desktop paginator: full config (pageSize dropdown, first/last buttons) -->\n <ng-container *sdDesktop>\n <mat-paginator\n [class.d-none]=\"_tableOption.paginate?.hidden || hidePaginator\"\n [length]=\"_total\"\n [pageSize]=\"_tableOption.paginate?.pageSize\"\n [pageSizeOptions]=\"_tableOption.paginate?.pages!\"\n [showFirstLastButtons]=\"_tableOption.paginate?.showFirstLastButtons\"\n [hidePageSize]=\"_tableOption.paginate?.hidePageSize\"></mat-paginator>\n </ng-container>\n <!-- Mobile paginator: \u1EA9n pageSize dropdown + first/last buttons \u0111\u1EC3 ti\u1EBFt ki\u1EC7m kh\u00F4ng gian -->\n <ng-container *sdMobile>\n <mat-paginator\n [class.d-none]=\"_tableOption.paginate?.hidden || hidePaginator\"\n [length]=\"_total\"\n [pageSize]=\"_tableOption.paginate?.pageSize\"\n [showFirstLastButtons]=\"false\"\n hidePageSize></mat-paginator>\n </ng-container>\n <!-- \"\u0110ang hi\u1EC3n th\u1ECB...\" ch\u1EC9 desktop -->\n <ng-container *sdDesktop>\n @if (!_tableOption.paginate?.hidden && hidePaginator && _total !== undefined && _total > 0) {\n <div class=\"T14R pr-16\">\n {{ 'core.component.table.showing' | translate }} <span class=\"T14M ml-2\">1-{{ _total }}/{{ _total }}</span>\n </div>\n }\n </ng-container>\n </div>\n </div>\n <selector-action [autoId]=\"_autoId\" [tableOption]=\"_tableOption\" [selectedTableItems]=\"_selectedTableItems\" (clear)=\"onClearSelection(groupedItems)\" />\n @if (_tableOption.config?.visible) {\n <config [autoId]=\"_autoId\" [tableOption]=\"_tableOption\" />\n }\n <!-- Mobile filter drawer \u2014 ch\u1EC9 instantiate khi c\u1EA7n render tr\u00EAn mobile -->\n @if (!_tableOption.filter?.disabled && filterRegister) {\n <mobile-filter\n [autoId]=\"_autoId\"\n [filter]=\"_tableOption.filter!\"\n [externalFilters]=\"_tableOption.filter?.externalFilters!\"\n [columns]=\"_configuration.firstColumns\"\n [filterDefs]=\"sdFilterDefs()\"\n [filterRegister]=\"filterRegister\"\n [cacheValues]=\"cacheValues\">\n </mobile-filter>\n }\n}\n", styles: [":host{display:flex;flex-direction:column;overflow:auto;width:100%;height:100%}:host .c-header-title{height:40px;display:flex;align-items:center}:host .c-container{position:relative;min-height:50px;display:flex;flex-direction:column;flex:1}:host .c-container .c-table{position:relative;flex:1;display:flex;flex-direction:column}:host .c-container .c-table table{border-collapse:separate;width:100%}:host .c-container .c-table table tr.c-first-header.mat-mdc-header-row{height:40px}:host .c-container .c-table table tr.c-second-header.mat-mdc-header-row{height:40px}:host .c-container .c-table table tr.c-detail-row{height:0}:host .c-container .c-table table tr.c-row.activated{background-color:#e5ecff}:host .c-container .c-table table tr.c-row.selected{background-color:#eef2ff}:host .c-container .c-table table tr.c-row:not(.selected):not(.activated):hover{background-color:#f5f5f5}:host .c-container .c-table table tr.c-row td{border-bottom-width:0}:host .c-container .c-table table tr.c-row.c-expandable{cursor:pointer}:host .c-container .c-table table tr.c-row.c-expandable:hover{background:#f5f5f5}:host .c-container .c-table table th.mat-mdc-header-cell{background-color:#f2f3f4;border-bottom:0!important}:host .c-container .c-table table td.mat-mdc-cell,:host .c-container .c-table table td.mat-mdc-footer-cell,:host .c-container .c-table table th.mat-mdc-header-cell{border-bottom-color:#f2f2f2!important}:host .c-container .c-table .c-th{vertical-align:middle;font-weight:500;font-size:14px;line-height:20px;color:#212121}:host .c-container .c-table .c-th.sd-col-resize-host{position:relative}:host .c-container .c-table .c-th.sd-resizing{-webkit-user-select:none;user-select:none}:host .c-container .c-table .c-th .sd-col-resize-handle{position:absolute;top:0;right:0;width:6px;height:100%;cursor:col-resize;-webkit-user-select:none;user-select:none;z-index:2}:host .c-container .c-table .c-th .sd-col-resize-handle:hover{background:#00000014}:host .c-container .c-table .c-td:first{padding-left:10px}:host .c-container .c-table .c-no-data-row{flex:1;width:100%;position:sticky;left:0;display:flex;flex-direction:column;align-items:center;justify-content:center}:host .c-container .c-table .c-no-data-row .c-image{margin-bottom:16px;width:96px}:host .c-container .c-loading{position:absolute;inset:0 0 56px;background:#00000026;z-index:2;display:flex;align-items:center;justify-content:center}:host .c-container .c-paginator{display:flex;flex-direction:row;justify-content:space-between;align-items:center;background-color:#fff}:host .c-container .c-paginator .c-action{padding:5px}:host .c-container .c-empty{text-align:center;background-color:#fff;border:none!important}:host .c-container .c-empty sd-icon{font-size:150px;margin-top:30px;margin-bottom:30px;opacity:.2;width:auto;height:auto}:host button.c-btn-add{background-color:#fff;box-shadow:0 2px 4px #2f313629}:host .lds-ring{display:inline-block;position:relative;width:40px;height:40px}:host .lds-ring div{box-sizing:border-box;display:block;position:absolute;width:32px;height:32px;margin:4px;border:4px solid #cef;border-radius:50%;animation:lds-ring 1.2s cubic-bezier(.5,0,.5,1) infinite;border-color:#cef transparent transparent transparent}:host .lds-ring div:nth-child(1){animation-delay:-.45s}:host .lds-ring div:nth-child(2){animation-delay:-.3s}:host .lds-ring div:nth-child(3){animation-delay:-.15s}@keyframes lds-ring{0%{transform:rotate(0)}to{transform:rotate(360deg)}}:host .sd-reorder-header,:host .sd-reorder-cell{width:40px;min-width:40px;padding:0 4px;box-sizing:border-box}:host .sd-reorder-cell sd-icon{cursor:grab;color:#00000061;display:flex;align-items:center}:host .sd-reorder-cell sd-icon:active{cursor:grabbing}:host .sd-reorder-cell sd-icon.sd-reorder-disabled{opacity:.3;cursor:not-allowed;pointer-events:none}:host ::ng-deep .mat-sort-header-content{display:block;text-align:left;width:100%}:host ::ng-deep .mat-select-arrow{color:#a6a6a6}:host ::ng-deep .mat-sort-header-disabled{background-image:none!important;cursor:default!important;padding-right:0!important}:host ::ng-deep .mat-sort-header-container{align-items:start!important}:host ::ng-deep .mat-sort-header-arrow{margin-top:4px!important}:host ::ng-deep .mat-sort-header-arrow{display:none!important}:host ::ng-deep .mat-sort-header{cursor:pointer}:host ::ng-deep .mat-sort-header[aria-sort]{background-repeat:no-repeat;background-position:center right 0;background-size:16px 16px;cursor:pointer;padding-right:24px}:host ::ng-deep .mat-sort-header[aria-sort=none]{background-image:url(\"data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' height='24px' viewBox='0 0 24 24' width='24px' fill='%23000000'%3E%3Cpath d='M0 0h24v24H0V0z' fill='none'/%3E%3Cpath fill='%237A7A7A' d='M12 5.83L15.17 9l1.41-1.41L12 3 7.41 7.59 8.83 9 12 5.83zm0 12.34L8.83 15l-1.41 1.41L12 21l4.59-4.59L15.17 15 12 18.17z'/%3E%3C/svg%3E\")}:host ::ng-deep .mat-sort-header[aria-sort=ascending]{background-image:url(\"data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' height='24px' viewBox='0 0 24 24' width='24px' fill='%23000000'%3E%3Cpath d='M0 0h24v24H0V0z' fill='none'/%3E%3Cpath fill='%237A7A7A' d='M4 12l1.41 1.41L11 7.83V20h2V7.83l5.58 5.59L20 12l-8-8-8 8z'/%3E%3C/svg%3E\")}:host ::ng-deep .mat-sort-header[aria-sort=descending]{background-image:url(\"data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' height='24px' viewBox='0 0 24 24' width='24px' fill='%23000000'%3E%3Cpath d='M0 0h24v24H0V0z' fill='none'/%3E%3Cpath fill='%237A7A7A' d='M20 12l-1.41-1.41L13 16.17V4h-2v12.17l-5.58-5.59L4 12l8 8 8-8z'/%3E%3C/svg%3E\")}:host ::ng-deep .c-paginator .mat-mdc-paginator .mdc-text-field--outlined .mat-mdc-form-field-infix,:host ::ng-deep .c-paginator .mat-mdc-paginator .mdc-text-field--no-label .mat-mdc-form-field-infix{padding-top:2px;padding-bottom:2px;min-height:32px}:host ::ng-deep .c-paginator .mat-mdc-paginator-range-label{margin:0 4px}:host ::ng-deep .c-paginator .mat-mdc-paginator-page-size-select mat-select{margin-top:2px!important}:host ::ng-deep .cdk-drag-preview{box-shadow:0 4px 12px #00000026;background:#fff;display:table;width:100%}:host ::ng-deep .cdk-drag-preview td{padding:0 8px;border-bottom:1px solid rgba(0,0,0,.12)}:host ::ng-deep .cdk-drag-placeholder{opacity:0}:host ::ng-deep .cdk-drop-list-dragging tr.c-row:not(.cdk-drag-placeholder){transition:transform .25s cubic-bezier(0,0,.2,1)}:host ::ng-deep .sd-selection-cell{width:42px;min-width:42px;max-width:42px}:host ::ng-deep .sd-filler-cell{width:auto;min-width:0;padding:0!important;border:0}:host ::ng-deep .sd-group-header-cell{background:#f5f7fc;border-top:1px solid #e6e9f2;border-bottom:1px solid #e6e9f2}:host ::ng-deep .sd-group-row{min-height:36px}:host ::ng-deep .sd-group-selection-slot{width:42px;min-width:42px;max-width:42px}:host ::ng-deep .c-selection{transform:scale(.85);transform-origin:center}:host ::ng-deep .sd-tree-line{display:inline-flex;align-items:center;min-height:32px}:host ::ng-deep .sd-tree-indent{flex:0 0 auto}:host ::ng-deep .sd-tree-toggle-slot{flex:0 0 auto;display:inline-flex;align-items:center;justify-content:center;width:24px;height:24px}:host ::ng-deep .sd-tree-toggle-btn{display:inline-flex;align-items:center;justify-content:center;width:24px;height:24px;padding:0;border:0;background:transparent;border-radius:50%;cursor:pointer;color:var(--sd-text-secondary, #5b6472);transition:background-color .15s ease}:host ::ng-deep .sd-tree-toggle-btn sd-icon{font-size:18px;width:18px;height:18px;line-height:18px}:host ::ng-deep .sd-tree-toggle-btn:hover{background-color:#0f172a14}:host ::ng-deep .sd-tree-spinner{transform:scale(.45)}:host ::ng-deep .sd-tree-stt{margin-left:2px;white-space:nowrap}:host ::ng-deep .sd-tree-index-cell{text-align:left!important;white-space:nowrap;padding-left:8px;padding-right:8px}:host ::ng-deep .sd-tree-index-header{padding-left:32px}:host ::ng-deep tr.c-row.sd-tree-row.sd-tree-level-0{background:#fbfcfe}:host ::ng-deep tr.c-row.sd-tree-row.sd-tree-level-0>td{font-weight:500}:host ::ng-deep tr.c-row.sd-tree-row.sd-tree-level-1{background:#fff}:host ::ng-deep tr.c-row.sd-tree-row.sd-tree-level-2{background:#fafbfd}:host ::ng-deep tr.c-row.sd-tree-row.sd-tree-level-3{background:#f6f8fb}:host ::ng-deep .sd-stt-root{font-weight:700;color:#1f2330}\n", ":host ::ng-deep .sticky-shadow-right{overflow:visible!important}:host ::ng-deep .sticky-shadow-right:after{content:\"\";position:absolute;top:0;right:0;bottom:0;width:8px;transform:translate(100%);background:linear-gradient(to right,rgba(0,0,0,.12),transparent);pointer-events:none}:host ::ng-deep .sticky-shadow-left{overflow:visible!important}:host ::ng-deep .sticky-shadow-left:after{content:\"\";position:absolute;top:0;left:0;bottom:0;width:8px;transform:translate(-100%);background:linear-gradient(to left,rgba(0,0,0,.12),transparent);pointer-events:none}\n"], dependencies: [{ kind: "component", type: SdIcon, selector: "sd-icon", inputs: ["name", "fontIcon", "color", "set", "fontSet", "size", "strokeWidth", "absoluteStrokeWidth", "ariaLabel"] }, { kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "directive", type: i1.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "directive", type: i1.NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "directive", type: i1.NgStyle, selector: "[ngStyle]", inputs: ["ngStyle"] }, { kind: "pipe", type: i1.AsyncPipe, name: "async" }, { kind: "pipe", type: i1.JsonPipe, name: "json" }, { kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i2$1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i2$1.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "ngmodule", type: MatMenuModule }, { kind: "component", type: i3.MatMenu, selector: "mat-menu", inputs: ["backdropClass", "aria-label", "aria-labelledby", "aria-describedby", "xPosition", "yPosition", "overlapTrigger", "hasBackdrop", "class", "classList"], outputs: ["closed", "close"], exportAs: ["matMenu"] }, { kind: "component", type: i3.MatMenuItem, selector: "[mat-menu-item]", inputs: ["role", "disabled", "disableRipple"], exportAs: ["matMenuItem"] }, { kind: "directive", type: i3.MatMenuTrigger, selector: "[mat-menu-trigger-for], [matMenuTriggerFor]", inputs: ["mat-menu-trigger-for", "matMenuTriggerFor", "matMenuTriggerData", "matMenuTriggerRestoreFocus"], outputs: ["menuOpened", "onMenuOpen", "menuClosed", "onMenuClose"], exportAs: ["matMenuTrigger"] }, { kind: "ngmodule", type: MatPaginatorModule }, { kind: "component", type: i4$2.MatPaginator, selector: "mat-paginator", inputs: ["color", "pageIndex", "length", "pageSize", "pageSizeOptions", "hidePageSize", "showFirstLastButtons", "selectConfig", "disabled"], outputs: ["page"], exportAs: ["matPaginator"] }, { kind: "ngmodule", type: MatTableModule }, { kind: "component", type: i5.MatTable, selector: "mat-table, table[mat-table]", exportAs: ["matTable"] }, { kind: "directive", type: i5.MatHeaderCellDef, selector: "[matHeaderCellDef]" }, { kind: "directive", type: i5.MatHeaderRowDef, selector: "[matHeaderRowDef]", inputs: ["matHeaderRowDef", "matHeaderRowDefSticky"] }, { kind: "directive", type: i5.MatColumnDef, selector: "[matColumnDef]", inputs: ["matColumnDef"] }, { kind: "directive", type: i5.MatCellDef, selector: "[matCellDef]" }, { kind: "directive", type: i5.MatRowDef, selector: "[matRowDef]", inputs: ["matRowDefColumns", "matRowDefWhen"] }, { kind: "directive", type: i5.MatFooterCellDef, selector: "[matFooterCellDef]" }, { kind: "directive", type: i5.MatFooterRowDef, selector: "[matFooterRowDef]", inputs: ["matFooterRowDef", "matFooterRowDefSticky"] }, { kind: "directive", type: i5.MatHeaderCell, selector: "mat-header-cell, th[mat-header-cell]" }, { kind: "directive", type: i5.MatCell, selector: "mat-cell, td[mat-cell]" }, { kind: "directive", type: i5.MatFooterCell, selector: "mat-footer-cell, td[mat-footer-cell]" }, { kind: "component", type: i5.MatHeaderRow, selector: "mat-header-row, tr[mat-header-row]", exportAs: ["matHeaderRow"] }, { kind: "component", type: i5.MatRow, selector: "mat-row, tr[mat-row]", exportAs: ["matRow"] }, { kind: "component", type: i5.MatFooterRow, selector: "mat-footer-row, tr[mat-footer-row]", exportAs: ["matFooterRow"] }, { kind: "ngmodule", type: MatSortModule }, { kind: "directive", type: i6.MatSort, selector: "[matSort]", inputs: ["matSortActive", "matSortStart", "matSortDirection", "matSortDisableClear", "matSortDisabled"], outputs: ["matSortChange"], exportAs: ["matSort"] }, { kind: "component", type: i6.MatSortHeader, selector: "[mat-sort-header]", inputs: ["mat-sort-header", "arrowPosition", "start", "disabled", "sortActionDescription", "disableClear"], exportAs: ["matSortHeader"] }, { kind: "ngmodule", type: MatProgressSpinnerModule }, { kind: "component", type: i7.MatProgressSpinner, selector: "mat-progress-spinner, mat-spinner", inputs: ["color", "mode", "value", "diameter", "strokeWidth"], exportAs: ["matProgressSpinner"] }, { kind: "ngmodule", type: MatCheckboxModule }, { kind: "component", type: i8.MatCheckbox, selector: "mat-checkbox", inputs: ["aria-label", "aria-labelledby", "aria-describedby", "aria-expanded", "aria-controls", "aria-owns", "id", "required", "labelPosition", "name", "value", "disableRipple", "tabIndex", "color", "disabledInteractive", "checked", "disabled", "indeterminate"], outputs: ["change", "indeterminateChange"], exportAs: ["matCheckbox"] }, { kind: "ngmodule", type: MatRadioModule }, { kind: "component", type: i9.MatRadioButton, selector: "mat-radio-button", inputs: ["id", "name", "aria-label", "aria-labelledby", "aria-describedby", "disableRipple", "tabIndex", "checked", "value", "labelPosition", "disabled", "required", "color", "disabledInteractive"], outputs: ["change"], exportAs: ["matRadioButton"] }, { kind: "ngmodule", type: DragDropModule }, { kind: "directive", type: i10.CdkDropList, selector: "[cdkDropList], cdk-drop-list", inputs: ["cdkDropListConnectedTo", "cdkDropListData", "cdkDropListOrientation", "id", "cdkDropListLockAxis", "cdkDropListDisabled", "cdkDropListSortingDisabled", "cdkDropListEnterPredicate", "cdkDropListSortPredicate", "cdkDropListAutoScrollDisabled", "cdkDropListAutoScrollStep", "cdkDropListElementContainer"], outputs: ["cdkDropListDropped", "cdkDropListEntered", "cdkDropListExited", "cdkDropListSorted"], exportAs: ["cdkDropList"] }, { kind: "directive", type: i10.CdkDrag, selector: "[cdkDrag]", inputs: ["cdkDragData", "cdkDragLockAxis", "cdkDragRootElement", "cdkDragBoundary", "cdkDragStartDelay", "cdkDragFreeDragPosition", "cdkDragDisabled", "cdkDragConstrainPosition", "cdkDragPreviewClass", "cdkDragPreviewContainer", "cdkDragScale"], outputs: ["cdkDragStarted", "cdkDragReleased", "cdkDragEnded", "cdkDragEntered", "cdkDragExited", "cdkDragDropped", "cdkDragMoved"], exportAs: ["cdkDrag"] }, { kind: "directive", type: i10.CdkDragHandle, selector: "[cdkDragHandle]", inputs: ["cdkDragHandleDisabled"] }, { kind: "component", type: SdButton, selector: "sd-button", inputs: ["autoId", "type", "color", "size", "fontSet", "title", "width", "tooltip", "prefixIcon", "suffixIcon", "disabled", "loading", "block", "htmlType"], outputs: ["click"] }, { kind: "component", type: DesktopCommand, selector: "desktop-command", inputs: ["autoId", "item", "itemIndex", "commands"] }, { kind: "component", type: DesktopCellComponent, selector: "desktop-cell", inputs: ["column", "item", "cellDef"] }, { kind: "component", type: ColumnTitleComponent, selector: "column-title", inputs: ["column", "titleDef"] }, { kind: "component", type: ExternalFilterComponent, selector: "external-filter", inputs: ["autoId", "filter", "externalFilters", "filterRegister"] }, { kind: "component", type: ConfigComponent, selector: "config", inputs: ["autoId", "tableOption"], outputs: ["changes"] }, { kind: "component", type: ColumnFilterComponent, selector: "column-filter", inputs: ["autoId", "column", "columnFilter", "cacheValues", "value", "operator", "isMobile"], outputs: ["operatorChange", "filterChange", "filterCommit"] }, { kind: "component", type: MobileFilterComponent, selector: "mobile-filter", inputs: ["autoId", "filter", "externalFilters", "columns", "filterDefs", "filterRegister", "cacheValues"] }, { kind: "pipe", type: SdGroupPipe, name: "sdGroup" }, { kind: "pipe", type: SdTreePipe, name: "sdTree" }, { kind: "pipe", type: SdSelectionVisiblePipe, name: "selectionVisible" }, { kind: "pipe", type: SdSelectionVisibleSelectAllPipe, name: "selectionVisibleSelectAll" }, { kind: "pipe", type: SdSelectionDisabledPipe, name: "selectionDisabled" }, { kind: "directive", type: SdScrollDirective, selector: "[sdScroll]" }, { kind: "directive", type: SdDesktopDirective, selector: "[sdDesktop]" }, { kind: "directive", type: SdMobileDirective, selector: "[sdMobile]" }, { kind: "directive", type: SdHoverCopyDirective, selector: "[sdHoverCopy]", inputs: ["sdHoverCopy", "sdHoverCopyDisabled"] }, { kind: "component", type: SelectorActionComponent, selector: "selector-action", inputs: ["autoId", "tableOption", "selectedTableItems"], outputs: ["clear"] }, { kind: "directive", type: StickyShadowDirective, selector: "[stickyShadow]" }, { kind: "directive", type: SdColumnResizeDirective, selector: "[sdColumnResize]", inputs: ["sdColumnResize", "minWidth", "maxWidth"], outputs: ["resizeEnd"] }, { kind: "pipe", type: TranslatePipe, name: "translate" }], animations: [
|
|
4543
4522
|
trigger('detailExpand', [
|
|
4544
4523
|
state('collapsed', style({ height: '0', minHeight: '0', visibility: 'hidden' })),
|
|
4545
4524
|
state('expanded', style({ height: '*', visibility: 'visible' })),
|
|
@@ -4570,12 +4549,11 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.21", ngImpo
|
|
|
4570
4549
|
provide: MatPaginatorIntl,
|
|
4571
4550
|
useClass: MatPaginatorIntlCro,
|
|
4572
4551
|
},
|
|
4573
|
-
], imports: [
|
|
4552
|
+
], imports: [SdIcon,
|
|
4574
4553
|
CommonModule,
|
|
4575
4554
|
FormsModule,
|
|
4576
4555
|
MatMenuModule,
|
|
4577
4556
|
MatPaginatorModule,
|
|
4578
|
-
MatIconModule,
|
|
4579
4557
|
MatTableModule,
|
|
4580
4558
|
MatSortModule,
|
|
4581
4559
|
MatProgressSpinnerModule,
|
|
@@ -4604,7 +4582,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.21", ngImpo
|
|
|
4604
4582
|
StickyShadowDirective,
|
|
4605
4583
|
SdColumnResizeDirective,
|
|
4606
4584
|
TranslatePipe,
|
|
4607
|
-
], template: "@let _configuration = configuration();\n@let _tableOption = tableOption()!;\n@let _loading = loading();\n@let _items = items();\n@let _total = total();\n@let _isFiltered = isFiltered();\n@let _requireFiltered = requireFiltered();\n@let _export = _tableOption?.export;\n@let _exporting = exporting();\n@let _titleDef = titleDef();\n@let _autoId = autoId();\n@let _exportTitle = exportTitle();\n@let _cellDef = cellDef();\n@let _footerDef = footerDef();\n@let _sdSubInformation = sdSubInformation();\n@let _configComponent = configComponent();\n@let _mobileFilter = mobileFilter();\n@let _selectedTableItems = selectedTableItems();\n<!-- why: tree kh\u00F4ng c\u00F2n c\u1ED9t ri\u00EAng \u2014 khi KH\u00D4NG c\u00F3 c\u1ED9t Index, icon expand nh\u00FAng v\u00E0o\n c\u1ED9t data \u0111\u1EA7u ti\u00EAn. \u0110\u00E2y l\u00E0 field c\u1EE7a c\u1ED9t \u0111\u00F3 (null n\u1EBFu c\u00F3 Index ho\u1EB7c kh\u00F4ng tree). -->\n@let _treeFirstField = _tableOption?.tree && !_tableOption.index?.enabled ? _configuration?.firstColumns?.[0]?.field : null;\n\n@if (_configuration) {\n @if (!_tableOption.filter?.disabled && !!_tableOption.filter?.externalFilters?.length && filterRegister) {\n <external-filter\n class=\"mb-16\"\n [autoId]=\"_autoId\"\n [filterRegister]=\"filterRegister\"\n [filter]=\"_tableOption.filter!\"\n [externalFilters]=\"_tableOption.filter?.externalFilters!\">\n </external-filter>\n }\n @let groupedItems = _items | sdTree: _tableOption.tree : treeRevision() | sdGroup: _tableOption : groupExpandState;\n\n <!-- Tree toggle d\u00F9ng chung: indent (theo c\u1EA5p) + slot chevron/spinner. Nh\u00FAng v\u00E0o\n c\u1ED9t Index ho\u1EB7c c\u1ED9t data \u0111\u1EA7u qua *ngTemplateOutlet (context: { row }). -->\n <ng-template #sdTreeToggle let-row=\"row\">\n @let _tree = row?.meta?.tree;\n @if (_tree) {\n <span class=\"sd-tree-indent\" [style.width.px]=\"(_tree.level ?? 0) * (_tableOption.tree?.indentSize ?? 20)\"></span>\n <span class=\"sd-tree-toggle-slot\">\n @if (_tree.hasChildren) {\n @if (_tree.isExpanding) {\n <span class=\"lds-ring sd-tree-spinner\">\n <div></div>\n <div></div>\n <div></div>\n <div></div>\n </span>\n } @else {\n @let _aid = _autoId;\n <button\n type=\"button\"\n class=\"sd-tree-toggle-btn\"\n [attr.data-autoid]=\"_aid ? _aid + '-tree-toggle-' + row.meta.id : null\"\n (click)=\"onTreeToggle(row); $event.stopPropagation()\">\n <mat-icon>{{ _tree.isExpanded ? 'expand_more' : 'chevron_right' }}</mat-icon>\n </button>\n }\n }\n </span>\n }\n </ng-template>\n\n <ng-content select=\"[sdTableTop]\"></ng-content>\n <div class=\"c-container\">\n @if (_loading) {\n <div class=\"c-loading\">\n <mat-spinner></mat-spinner>\n </div>\n }\n <div\n class=\"c-table\"\n sdScroll\n stickyShadow\n [style.max-height]=\"_tableOption.style?.maxHeight\"\n [style.min-height]=\"_tableOption.style?.minHeight\">\n <table\n mat-table\n [dataSource]=\"groupedItems\"\n [trackBy]=\"trackBy\"\n matSort\n [matSortDisabled]=\"!_tableOption.sort?.enable\"\n multiTemplateDataRows\n cdkDropList\n [cdkDropListData]=\"groupedItems\"\n [cdkDropListDisabled]=\"!_tableOption.rowReorder?.enabled\"\n [cdkDropListSortPredicate]=\"reorderSortPredicate\"\n (cdkDropListDropped)=\"onReorderDrop($event)\">\n @if (_tableOption.rowReorder?.enabled) {\n <ng-container matColumnDef=\"sdReorder\">\n <th mat-header-cell *matHeaderCellDef class=\"sd-reorder-header\" [attr.rowspan]=\"_configuration.multipleHeader ? 2 : 1\"></th>\n <td mat-cell *matCellDef=\"let row\" class=\"sd-reorder-cell\">\n @if (!row.meta?.group?.items?.length) {\n <mat-icon cdkDragHandle [class.sd-reorder-disabled]=\"isReorderDisabled(row)\">\n {{ _tableOption.rowReorder?.icon || 'drag_indicator' }}\n </mat-icon>\n }\n </td>\n <td mat-footer-cell *matFooterCellDef></td>\n </ng-container>\n }\n\n <ng-container matColumnDef=\"sdSubInformation\" sticky>\n <td class=\"p-0\" mat-cell *matCellDef=\"let item\" [attr.colspan]=\"_configuration.displayedColumns.length\">\n @if (_sdSubInformation?.templateRef) {\n @if (_tableOption.expand?.always) {\n <ng-container *ngTemplateOutlet=\"_sdSubInformation?.templateRef!; context: { item: item }\"> </ng-container>\n } @else {\n <div [@detailExpand]=\"item.isExpanded ? 'expanded' : 'collapsed'\">\n @if (item.isExpanded) {\n <ng-container *ngTemplateOutlet=\"_sdSubInformation?.templateRef!; context: { item: item }\"> </ng-container>\n }\n </div>\n }\n }\n </td>\n <td mat-footer-cell *matFooterCellDef></td>\n </ng-container>\n\n <ng-container matColumnDef=\"sdSubInformationAction\" stickyEnd>\n <th class=\"p-0\" mat-header-cell *matHeaderCellDef style=\"width: 1px\" [attr.rowspan]=\"_configuration.multipleHeader ? 2 : 1\"></th>\n <td mat-cell *matCellDef=\"let element\">\n @if (!element.isExpanding && !_tableOption.expand?.always) {\n <sd-button\n [autoId]=\"_autoId ? _autoId + '-expand-' + element.meta.id : null\"\n type=\"link\"\n [prefixIcon]=\"element.isExpanded ? 'expand_less' : 'expand_more'\"\n (click)=\"onExpand(element)\"\n width=\"35px\">\n </sd-button>\n }\n @if (element.isExpanding) {\n <div class=\"lds-ring\">\n <div></div>\n <div></div>\n <div></div>\n <div></div>\n </div>\n }\n </td>\n </ng-container>\n\n <ng-container matColumnDef=\"sdSelection\" sticky>\n <th class=\"sd-selection-cell p-0\" mat-header-cell *matHeaderCellDef [attr.rowspan]=\"_configuration.multipleHeader ? 2 : 1\">\n @let visibleSelectAll = _items | selectionVisibleSelectAll: _tableOption.selector | async;\n @if (visibleSelectAll) {\n <mat-checkbox\n class=\"c-selection px-8\"\n color=\"primary\"\n [ngModel]=\"isSelectAll()\"\n (ngModelChange)=\"isSelectAll.set($event)\"\n (change)=\"onSelectAll()\">\n </mat-checkbox>\n }\n </th>\n\n <td class=\"sd-selection-cell p-0\" mat-cell *matCellDef=\"let item\">\n @let visible = item | selectionVisible: _tableOption.selector;\n @if (visible) {\n @if (_tableOption.selector?.single) {\n <mat-radio-button\n class=\"c-selection px-8\"\n color=\"primary\"\n [checked]=\"item.meta.selector.isSelected\"\n (change)=\"item.meta.selector.isSelected = true; onSelect(item)\"\n [disabled]=\"_selectedTableItems | selectionDisabled: item : _tableOption.selector!\">\n </mat-radio-button>\n } @else {\n <mat-checkbox\n class=\"c-selection px-8\"\n color=\"primary\"\n [(ngModel)]=\"item.meta.selector.isSelected\"\n (change)=\"onSelect(item)\"\n [disabled]=\"_selectedTableItems | selectionDisabled: item : _tableOption.selector!\">\n </mat-checkbox>\n }\n }\n </td>\n <td mat-footer-cell *matFooterCellDef></td>\n </ng-container>\n @if (_tableOption.index?.enabled) {\n @let _pageOffset = pageOffset();\n @let _indexWidth = _tableOption.index?.width || '50px';\n <!-- why: khi tree, c\u1ED9t Index \"\u00F4m\" th\u00EAm chevron + indent. D\u00F9ng width:1px +\n nowrap (.sd-tree-index-cell) \u0111\u1EC3 c\u1ED9t co S\u00C1T n\u1ED9i dung, kh\u00F4ng chi\u1EBFm ch\u1ED7\n th\u1EEBa; header \"#\" canh tr\u00E1i l\u00F9i v\u00E0o (.sd-tree-index-header) cho th\u1EB3ng s\u1ED1. -->\n @let _treeIndex = !!_tableOption.tree;\n <ng-container matColumnDef=\"sdIndex\" sticky>\n <th\n [class.p-0]=\"!_treeIndex\"\n [class.text-center]=\"!_treeIndex\"\n [class.sd-tree-index-cell]=\"_treeIndex\"\n [class.sd-tree-index-header]=\"_treeIndex\"\n mat-header-cell\n *matHeaderCellDef\n [style.width]=\"_treeIndex ? '1px' : _indexWidth\"\n [style.min-width]=\"_treeIndex ? null : _indexWidth\"\n [style.max-width]=\"_treeIndex ? null : _indexWidth\"\n [attr.rowspan]=\"_configuration.multipleHeader ? 2 : 1\">\n {{ _tableOption.index?.title || '#' }}\n </th>\n <td\n [class.px-4]=\"!_treeIndex\"\n [class.text-center]=\"!_treeIndex\"\n [class.sd-tree-index-cell]=\"_treeIndex\"\n mat-cell\n *matCellDef=\"let item; let i = dataIndex\"\n [style.width]=\"_treeIndex ? '1px' : null\"\n [style.min-width]=\"_treeIndex ? null : _indexWidth\"\n [style.max-width]=\"_treeIndex ? null : _indexWidth\">\n @if (!item?.meta?.group?.isGroupHeader) {\n @if (_treeIndex) {\n <!-- why: tree \u2192 chevron + indent + STT ph\u00E2n c\u1EA5p (1, 1.2, 1.2.1). T\u00F4 \u0111\u1EADm root (level 0). -->\n <span class=\"sd-tree-line\">\n <ng-container *ngTemplateOutlet=\"sdTreeToggle; context: { row: item }\"></ng-container>\n @if (item?.meta?.tree?.indexPath?.length) {\n <span class=\"sd-tree-stt\" [class.sd-stt-root]=\"(item.meta.tree.level ?? 0) === 0\">\n {{ item.meta.tree.indexPath.join('.') }}\n </span>\n }\n </span>\n } @else {\n {{ _pageOffset + i + 1 }}\n }\n }\n </td>\n <td mat-footer-cell *matFooterCellDef [style.width]=\"_treeIndex ? '1px' : null\" [style.min-width]=\"_treeIndex ? null : _indexWidth\" [style.max-width]=\"_treeIndex ? null : _indexWidth\"></td>\n </ng-container>\n }\n <ng-container\n matColumnDef=\"sdCommand\"\n [sticky]=\"_tableOption.command?.align !== 'right'\"\n [stickyEnd]=\"_tableOption.command?.align === 'right'\">\n <th class=\"p-0\" mat-header-cell *matHeaderCellDef style=\"width: 50px\" [attr.rowspan]=\"_configuration.multipleHeader ? 2 : 1\"></th>\n <td class=\"px-8\" mat-cell *matCellDef=\"let item\">\n <desktop-command\n [autoId]=\"_autoId\"\n [commands]=\"_tableOption.command?.commands || _tableOption.commands || []\"\n [item]=\"item\"\n [itemIndex]=\"groupedItems.indexOf(item)\"></desktop-command>\n </td>\n <td mat-footer-cell *matFooterCellDef></td>\n </ng-container>\n <!-- why: group header row d\u00F9ng matRowDef RI\u00CANG v\u1EDBi column list ['sdGroupHeader']\n qua predicate when:isGroupHeaderRow. Cell colspan = displayedColumns.length \u0111\u1EC3\n span TO\u00C0N B\u1ED8 width data row. Tr\u00E1nh colspan trick overflow row khi c\u00E1c TD kh\u00E1c render. -->\n <ng-container matColumnDef=\"sdGroupHeader\">\n <td\n class=\"p-0 sd-group-header-cell\"\n mat-cell\n *matCellDef=\"let item\"\n [attr.colspan]=\"sdGroupColspan()\">\n <div class=\"sd-group-row d-flex align-items-center py-8\">\n <!-- why: slot 42px kh\u1EDBp width v\u1EDBi sd-selection-cell data row \u2192 checkbox group c\u0103n TR\u1EE4C d\u1ECDc \u0111\u00FAng v\u1EDBi checkbox data. -->\n @if (_tableOption.selector?.visible && !_tableOption.selector?.single) {\n <div class=\"sd-group-selection-slot d-flex align-items-center justify-content-center\">\n <mat-checkbox\n class=\"c-selection\"\n color=\"primary\"\n [checked]=\"isGroupAllSelected(item)\"\n [indeterminate]=\"isGroupIndeterminate(item)\"\n (change)=\"onSelectGroup(item, $event.checked)\">\n </mat-checkbox>\n </div>\n } @else {\n <div class=\"sd-group-selection-slot\"></div>\n }\n @if (_tableOption.group?.collapsible) {\n <sd-button\n [autoId]=\"_autoId ? _autoId + '-group-toggle-' + (item.meta.group?.key || item.meta.id) : null\"\n type=\"link\"\n [prefixIcon]=\"item.meta.group.isExpanded ? 'expand_more' : 'chevron_right'\"\n width=\"32px\"\n (click)=\"toggleGroupExpand(item)\">\n </sd-button>\n }\n @if (sdGroupDef()?.templateRef; as tpl) {\n <ng-container *ngTemplateOutlet=\"tpl; context: groupContext(item)\"></ng-container>\n } @else {\n <span class=\"T14R\">{{ item.meta.group.values | json }}</span>\n }\n </div>\n </td>\n </ng-container>\n <!-- why: filler column \u1EDF cu\u1ED1i h\u1EA5p th\u1EE5 leftover space khi t\u1ED5ng width c\u00E1c c\u1ED9t data < container \u2014 gi\u1EEF cho selection/STT/command kh\u00F4ng b\u1ECB d\u00E3n. -->\n <ng-container matColumnDef=\"sdFiller\">\n <th class=\"sd-filler-cell p-0\" mat-header-cell *matHeaderCellDef [attr.rowspan]=\"_configuration.multipleHeader ? 2 : 1\"></th>\n <td class=\"sd-filler-cell p-0\" mat-cell *matCellDef=\"let item\"></td>\n <td class=\"sd-filler-cell p-0\" mat-footer-cell *matFooterCellDef></td>\n </ng-container>\n @for (column of _configuration.firstColumns; track column.field) {\n <ng-container [matColumnDef]=\"column.field\" [sticky]=\"_configuration.fixedColumn[column.field]\">\n <th\n mat-header-cell\n *matHeaderCellDef\n class=\"px-8 py-8 c-th\"\n [sdColumnResize]=\"!!_tableOption.config?.resizable && column.type !== 'children'\"\n [minWidth]=\"column.minWidth\"\n [maxWidth]=\"column.maxWidth\"\n (resizeEnd)=\"onColumnResize(column.field, $event)\"\n [style.width]=\"column.width\"\n [style.min-width]=\"column.minWidth || column.width\"\n [style.max-width]=\"column.maxWidth\"\n [attr.rowspan]=\"_configuration.multipleHeader && column.type !== 'children' ? 2 : 1\"\n [attr.colspan]=\"column.type === 'children' ? column.children.length : 1\">\n <div>\n @if (column.type === 'children') {\n <div\n aria-hidden=\"true\"\n class=\"c-header-title\"\n [class.justify-content-end]=\"column.align === 'right'\"\n [class.text-right]=\"column.align === 'right'\">\n <column-title [column]=\"column\" [titleDef]=\"_titleDef[column.field]\"></column-title>\n </div>\n } @else {\n <div\n aria-hidden=\"true\"\n mat-sort-header\n class=\"c-header-title\"\n [class.justify-content-end]=\"column.align === 'right'\"\n [class.text-right]=\"column.align === 'right'\"\n [disabled]=\"!column.sortable\">\n <column-title [column]=\"column\" [titleDef]=\"_titleDef[column.field]\"></column-title>\n </div>\n @let hideInlineFilter =\n _tableOption.filter?.disabled ||\n _tableOption.filter?.hideInlineFilter === true ||\n (_tableOption.filter?.hideInlineFilter === 'auto' && !_isFiltered && _total! <= 10);\n @if (!hideInlineFilter) {\n <ng-container *sdDesktop>\n <column-filter\n [autoId]=\"_autoId\"\n [value]=\"columnFilter?.[column.field!]!\"\n [operator]=\"columnOperator[column.field]\"\n (operatorChange)=\"columnOperator[column.field] = $event!; onOperatorChange(column, $event)\"\n [columnFilter]=\"columnFilter!\"\n [cacheValues]=\"cacheValues\"\n [column]=\"column\"\n (filterChange)=\"onFilterChange()\"\n (filterCommit)=\"onFilterCommit()\">\n </column-filter>\n </ng-container>\n }\n }\n </div>\n </th>\n <td\n class=\"c-td px-0\"\n [class.d-none]=\"column.type === 'children'\"\n mat-cell\n *matCellDef=\"let item\"\n [sdHoverCopy]=\"(item.data && item.data[column.field]) || ''\"\n [sdHoverCopyDisabled]=\"!column.cell?.copiable\">\n @if (column.type !== 'children' && !item?.meta?.group?.isGroupHeader) {\n @if (_treeFirstField && column.field === _treeFirstField) {\n <!-- why: kh\u00F4ng c\u00F3 c\u1ED9t Index \u2192 chevron + indent nh\u00FAng v\u00E0o c\u1ED9t data \u0111\u1EA7u (nh\u01B0 file explorer). -->\n <span class=\"sd-tree-line px-8\">\n <ng-container *ngTemplateOutlet=\"sdTreeToggle; context: { row: item }\"></ng-container>\n <desktop-cell class=\"d-block\" [column]=\"column\" [item]=\"item\" [cellDef]=\"_cellDef\"></desktop-cell>\n </span>\n } @else {\n <desktop-cell class=\"d-block px-8\" [column]=\"column\" [item]=\"item\" [cellDef]=\"_cellDef\"> </desktop-cell>\n }\n }\n </td>\n <td mat-footer-cell *matFooterCellDef>\n <ng-container *ngIf=\"_footerDef[column.field]\">\n <ng-container *ngTemplateOutlet=\"_footerDef[column.field].templateRef; context: { items: _items, column: column }\">\n </ng-container>\n </ng-container>\n </td>\n </ng-container>\n }\n @for (column of _configuration.secondColumns; track column.field) {\n <ng-container [matColumnDef]=\"column.field\">\n <th\n mat-header-cell\n *matHeaderCellDef\n class=\"c-th px-8\"\n [style.width]=\"column.width\"\n [style.min-width]=\"column.minWidth || column.width\"\n [style.max-width]=\"column.maxWidth\">\n <div>\n <div\n aria-hidden=\"true\"\n mat-sort-header\n class=\"c-header-title\"\n [class.justify-content-end]=\"column.align === 'right'\"\n [class.text-right]=\"column.align === 'right'\"\n [disabled]=\"!column.sortable\">\n <column-title [column]=\"column\" [titleDef]=\"_titleDef[column.field]\"></column-title>\n </div>\n @if (!_tableOption.filter?.disabled && !_tableOption.filter?.hideInlineFilter && columnOperator) {\n <ng-container *sdDesktop>\n <column-filter\n [autoId]=\"_autoId\"\n [value]=\"columnFilter?.[column.field!]!\"\n [operator]=\"columnOperator[column.field]\"\n [columnFilter]=\"columnFilter!\"\n [cacheValues]=\"cacheValues\"\n [column]=\"column\"\n (operatorChange)=\"columnOperator[column.field] = $event!; onOperatorChange(column, $event)\"\n (filterChange)=\"onFilterChange()\"\n (filterCommit)=\"onFilterCommit()\">\n </column-filter>\n </ng-container>\n }\n </div>\n </th>\n <td\n class=\"c-td px-0\"\n mat-cell\n *matCellDef=\"let item\"\n [sdHoverCopy]=\"item[column.field]\"\n [sdHoverCopyDisabled]=\"!column.cell?.copiable\">\n @if (column.type !== 'children') {\n <desktop-cell class=\"d-block px-8\" [column]=\"column\" [item]=\"item\" [cellDef]=\"_cellDef\"> </desktop-cell>\n }\n </td>\n <td mat-footer-cell *matFooterCellDef>\n <ng-container *ngIf=\"_footerDef[column.field]\">\n <ng-container *ngTemplateOutlet=\"_footerDef[column.field].templateRef; context: { items: _items, column: column }\">\n </ng-container>\n </ng-container>\n </td>\n </ng-container>\n }\n <tr class=\"c-first-header\" mat-header-row *matHeaderRowDef=\"_configuration.firstHeaders; sticky: true\"></tr>\n @if (!!_configuration.secondHeaders.length) {\n <tr class=\"c-second-header\" mat-header-row *matHeaderRowDef=\"_configuration.secondHeaders; sticky: true\"></tr>\n }\n <!-- Group header row \u2014 ch\u1EC9 1 cell sdGroupHeader colspan to\u00E0n width. -->\n <tr\n mat-row\n *matRowDef=\"let row; columns: ['sdGroupHeader']; when: isGroupHeaderRow\"\n class=\"c-group-row-tr\"></tr>\n\n <!-- Data row \u2014 d\u00F9ng displayedColumns \u0111\u1EA7y \u0111\u1EE7; when isDataRow \u0111\u1EC3 lo\u1EA1i tr\u1EEB group header. -->\n <tr\n mat-row\n cdkDrag\n [cdkDragData]=\"row\"\n [cdkDragDisabled]=\"\n !_tableOption.rowReorder?.enabled ||\n !!row.meta?.group?.items?.length ||\n (row.meta?.tree?.level ?? 0) > 0 ||\n isReorderDisabled(row)\n \"\n *matRowDef=\"let row; columns: _configuration.displayedColumns; when: isDataRow\"\n matRipple\n class=\"c-row\"\n [class.sd-tree-row]=\"!!_tableOption.tree\"\n [ngClass]=\"_tableOption.tree ? 'sd-tree-level-' + (row.meta?.tree?.level ?? 0) : null\"\n [ngStyle]=\"rowStyle(row)\"\n [class.selected]=\"row.meta.selector.isSelected\"></tr>\n\n <!-- Sub-information row \u2014 also gated b\u1EDFi isDataRow \u0111\u1EC3 KH\u00D4NG render empty expand row d\u01B0\u1EDBi group header. -->\n <tr mat-row *matRowDef=\"let row; columns: ['sdSubInformation']; when: isDataRow\" class=\"c-detail-row\"></tr>\n @if (hasFooter() && !!_configuration.displayedFooters.length) {\n <tr mat-footer-row *matFooterRowDef=\"_configuration.displayedFooters; sticky: true\"></tr>\n }\n </table>\n @if (!_loading && !_total) {\n <div class=\"c-no-data-row\">\n @if (_isFiltered) {\n @if (tableConfiguration?.images?.filterEmpty) {\n <img class=\"c-image\" [src]=\"tableConfiguration!.images!.filterEmpty\" alt=\"filter-empty\" />\n } @else {\n <img class=\"c-image sd-image-filter-empty\" alt=\"filter-empty\" />\n }\n <div class=\"T16M\">{{ 'core.component.table.no-results' | translate }}</div>\n <div class=\"T16R text-secondary\">{{ 'core.component.table.no-results-hint' | translate }}</div>\n } @else {\n @if (_requireFiltered) {\n @if (tableConfiguration?.images?.filterRequired) {\n <img class=\"c-image\" [src]=\"tableConfiguration!.images!.filterRequired\" alt=\"filter-required\" />\n } @else {\n <img class=\"c-image sd-image-filter-required\" alt=\"filter-required\" />\n }\n <div class=\"T16R text-secondary\">{{ 'core.component.table.choose-filter-hint' | translate }}</div>\n } @else {\n @if (tableConfiguration?.images?.dataEmpty) {\n <img class=\"c-image\" [src]=\"tableConfiguration!.images!.dataEmpty\" alt=\"data-empty\" />\n } @else {\n <img class=\"c-image sd-image-data-empty\" alt=\"data-empty\" />\n }\n <div class=\"T16R text-secondary\">{{ 'core.component.table.no-data' | translate }}</div>\n }\n }\n </div>\n }\n </div>\n <div class=\"c-paginator\">\n <div class=\"c-action\">\n <ng-container *sdDesktop>\n @if (_tableOption.reload?.visible) {\n <sd-button\n [autoId]=\"_autoId ? _autoId + '-reload' : null\"\n class=\"mr-8\"\n [title]=\"'core.component.table.reload' | translate\"\n prefixIcon=\"refresh\"\n (click)=\"reload()\"\n [disabled]=\"!_items.length\"\n type=\"link\">\n </sd-button>\n }\n </ng-container>\n @if (_export && _items.length) {\n @if (_export.type === 'custom') {\n <sd-button [autoId]=\"_autoId ? _autoId + '-export' : null\" class=\"mr-8\" [title]=\"_exportTitle\" prefixIcon=\"get_app\" (click)=\"exportCustom()\" type=\"link\"> </sd-button>\n } @else {\n @if (_export.visible) {\n @if (_exporting) {\n <sd-button [autoId]=\"_autoId ? _autoId + '-export' : null\" class=\"mr-8\" [loading]=\"_exporting\" [title]=\"_exportTitle\" prefixIcon=\"get_app\" type=\"link\"> </sd-button>\n } @else {\n @if (_export.visible === 'ALL' || !_export.visible) {\n <sd-button [autoId]=\"_autoId ? _autoId + '-export' : null\" class=\"mr-8\" [title]=\"_exportTitle\" prefixIcon=\"get_app\" [matMenuTriggerFor]=\"menu\" type=\"link\"> </sd-button>\n <mat-menu #menu=\"matMenu\">\n <button mat-menu-item [attr.data-autoid]=\"_autoId ? _autoId + '-export-excel' : null\" (click)=\"exportExcel()\" type=\"button\">\n <mat-icon fontSet=\"material-icons-outlined\">file_download</mat-icon>\n <span> {{ 'core.component.table.export-excel' | translate }}</span>\n </button>\n <button mat-menu-item [attr.data-autoid]=\"_autoId ? _autoId + '-export-csv' : null\" (click)=\"exportCSV()\" type=\"button\">\n <mat-icon fontSet=\"material-icons-outlined\">file_download</mat-icon>\n <span> {{ 'core.component.table.export-csv' | translate }}</span>\n </button>\n </mat-menu>\n } @else if (_export.visible === 'EXCEL') {\n <sd-button [autoId]=\"_autoId ? _autoId + '-export-excel' : null\" class=\"mr-8\" [title]=\"_exportTitle\" prefixIcon=\"get_app\" (click)=\"exportExcel()\" type=\"link\"> </sd-button>\n } @else if (_export.visible === 'CSV') {\n <sd-button [autoId]=\"_autoId ? _autoId + '-export-csv' : null\" class=\"mr-8\" [title]=\"_exportTitle\" prefixIcon=\"get_app\" (click)=\"exportCSV()\" type=\"link\"> </sd-button>\n }\n }\n }\n }\n }\n\n <ng-container *sdDesktop>\n @if (_configComponent) {\n <sd-button\n [autoId]=\"_autoId ? _autoId + '-config' : null\"\n class=\"mr-8\"\n [title]=\"'core.component.table.setup-short' | translate\"\n prefixIcon=\"settings\"\n (click)=\"_configComponent.open()\"\n type=\"link\">\n </sd-button>\n }\n </ng-container>\n <!-- Mobile: n\u00FAt Filter m\u1EDF mobile-filter drawer (inline filter \u1EA9n tr\u00EAn mobile) -->\n <ng-container *sdMobile>\n @if (!_tableOption.filter?.disabled && _mobileFilter) {\n <sd-button\n [autoId]=\"_autoId ? _autoId + '-mobile-filter-open' : null\"\n class=\"mr-8\"\n prefixIcon=\"filter_alt\"\n (click)=\"_mobileFilter.open()\"\n type=\"link\">\n </sd-button>\n }\n </ng-container>\n </div>\n @let hidePaginator = !_tableOption.paginate?.pageSize || _total === undefined || _total <= _tableOption.paginate?.pageSize!;\n <!-- Desktop paginator: full config (pageSize dropdown, first/last buttons) -->\n <ng-container *sdDesktop>\n <mat-paginator\n [class.d-none]=\"_tableOption.paginate?.hidden || hidePaginator\"\n [length]=\"_total\"\n [pageSize]=\"_tableOption.paginate?.pageSize\"\n [pageSizeOptions]=\"_tableOption.paginate?.pages!\"\n [showFirstLastButtons]=\"_tableOption.paginate?.showFirstLastButtons\"\n [hidePageSize]=\"_tableOption.paginate?.hidePageSize\"></mat-paginator>\n </ng-container>\n <!-- Mobile paginator: \u1EA9n pageSize dropdown + first/last buttons \u0111\u1EC3 ti\u1EBFt ki\u1EC7m kh\u00F4ng gian -->\n <ng-container *sdMobile>\n <mat-paginator\n [class.d-none]=\"_tableOption.paginate?.hidden || hidePaginator\"\n [length]=\"_total\"\n [pageSize]=\"_tableOption.paginate?.pageSize\"\n [showFirstLastButtons]=\"false\"\n hidePageSize></mat-paginator>\n </ng-container>\n <!-- \"\u0110ang hi\u1EC3n th\u1ECB...\" ch\u1EC9 desktop -->\n <ng-container *sdDesktop>\n @if (!_tableOption.paginate?.hidden && hidePaginator && _total !== undefined && _total > 0) {\n <div class=\"T14R pr-16\">\n {{ 'core.component.table.showing' | translate }} <span class=\"T14M ml-2\">1-{{ _total }}/{{ _total }}</span>\n </div>\n }\n </ng-container>\n </div>\n </div>\n <selector-action [autoId]=\"_autoId\" [tableOption]=\"_tableOption\" [selectedTableItems]=\"_selectedTableItems\" (clear)=\"onClearSelection(groupedItems)\" />\n @if (_tableOption.config?.visible) {\n <config [autoId]=\"_autoId\" [tableOption]=\"_tableOption\" />\n }\n <!-- Mobile filter drawer \u2014 ch\u1EC9 instantiate khi c\u1EA7n render tr\u00EAn mobile -->\n @if (!_tableOption.filter?.disabled && filterRegister) {\n <mobile-filter\n [autoId]=\"_autoId\"\n [filter]=\"_tableOption.filter!\"\n [externalFilters]=\"_tableOption.filter?.externalFilters!\"\n [columns]=\"_configuration.firstColumns\"\n [filterDefs]=\"sdFilterDefs()\"\n [filterRegister]=\"filterRegister\"\n [cacheValues]=\"cacheValues\">\n </mobile-filter>\n }\n}\n", styles: [":host{display:flex;flex-direction:column;overflow:auto;width:100%;height:100%}:host .c-header-title{height:40px;display:flex;align-items:center}:host .c-container{position:relative;min-height:50px;display:flex;flex-direction:column;flex:1}:host .c-container .c-table{position:relative;flex:1;display:flex;flex-direction:column}:host .c-container .c-table table{border-collapse:separate;width:100%}:host .c-container .c-table table tr.c-first-header.mat-mdc-header-row{height:40px}:host .c-container .c-table table tr.c-second-header.mat-mdc-header-row{height:40px}:host .c-container .c-table table tr.c-detail-row{height:0}:host .c-container .c-table table tr.c-row.activated{background-color:#e5ecff}:host .c-container .c-table table tr.c-row.selected{background-color:#eef2ff}:host .c-container .c-table table tr.c-row:not(.selected):not(.activated):hover{background-color:#f5f5f5}:host .c-container .c-table table tr.c-row td{border-bottom-width:0}:host .c-container .c-table table tr.c-row.c-expandable{cursor:pointer}:host .c-container .c-table table tr.c-row.c-expandable:hover{background:#f5f5f5}:host .c-container .c-table table th.mat-mdc-header-cell{background-color:#f2f3f4;border-bottom:0!important}:host .c-container .c-table table td.mat-mdc-cell,:host .c-container .c-table table td.mat-mdc-footer-cell,:host .c-container .c-table table th.mat-mdc-header-cell{border-bottom-color:#f2f2f2!important}:host .c-container .c-table .c-th{vertical-align:middle;font-weight:500;font-size:14px;line-height:20px;color:#212121}:host .c-container .c-table .c-th.sd-col-resize-host{position:relative}:host .c-container .c-table .c-th.sd-resizing{-webkit-user-select:none;user-select:none}:host .c-container .c-table .c-th .sd-col-resize-handle{position:absolute;top:0;right:0;width:6px;height:100%;cursor:col-resize;-webkit-user-select:none;user-select:none;z-index:2}:host .c-container .c-table .c-th .sd-col-resize-handle:hover{background:#00000014}:host .c-container .c-table .c-td:first{padding-left:10px}:host .c-container .c-table .c-no-data-row{flex:1;width:100%;position:sticky;left:0;display:flex;flex-direction:column;align-items:center;justify-content:center}:host .c-container .c-table .c-no-data-row .c-image{margin-bottom:16px;width:96px}:host .c-container .c-loading{position:absolute;inset:0 0 56px;background:#00000026;z-index:2;display:flex;align-items:center;justify-content:center}:host .c-container .c-paginator{display:flex;flex-direction:row;justify-content:space-between;align-items:center;background-color:#fff}:host .c-container .c-paginator .c-action{padding:5px}:host .c-container .c-empty{text-align:center;background-color:#fff;border:none!important}:host .c-container .c-empty mat-icon{font-size:150px;margin-top:30px;margin-bottom:30px;opacity:.2;width:auto;height:auto}:host button.c-btn-add{background-color:#fff;box-shadow:0 2px 4px #2f313629}:host .lds-ring{display:inline-block;position:relative;width:40px;height:40px}:host .lds-ring div{box-sizing:border-box;display:block;position:absolute;width:32px;height:32px;margin:4px;border:4px solid #cef;border-radius:50%;animation:lds-ring 1.2s cubic-bezier(.5,0,.5,1) infinite;border-color:#cef transparent transparent transparent}:host .lds-ring div:nth-child(1){animation-delay:-.45s}:host .lds-ring div:nth-child(2){animation-delay:-.3s}:host .lds-ring div:nth-child(3){animation-delay:-.15s}@keyframes lds-ring{0%{transform:rotate(0)}to{transform:rotate(360deg)}}:host .sd-reorder-header,:host .sd-reorder-cell{width:40px;min-width:40px;padding:0 4px;box-sizing:border-box}:host .sd-reorder-cell mat-icon{cursor:grab;color:#00000061;display:flex;align-items:center}:host .sd-reorder-cell mat-icon:active{cursor:grabbing}:host .sd-reorder-cell mat-icon.sd-reorder-disabled{opacity:.3;cursor:not-allowed;pointer-events:none}:host ::ng-deep .mat-sort-header-content{display:block;text-align:left;width:100%}:host ::ng-deep .mat-select-arrow{color:#a6a6a6}:host ::ng-deep .mat-sort-header-disabled{background-image:none!important;cursor:default!important;padding-right:0!important}:host ::ng-deep .mat-sort-header-container{align-items:start!important}:host ::ng-deep .mat-sort-header-arrow{margin-top:4px!important}:host ::ng-deep .mat-sort-header-arrow{display:none!important}:host ::ng-deep .mat-sort-header{cursor:pointer}:host ::ng-deep .mat-sort-header[aria-sort]{background-repeat:no-repeat;background-position:center right 0;background-size:16px 16px;cursor:pointer;padding-right:24px}:host ::ng-deep .mat-sort-header[aria-sort=none]{background-image:url(\"data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' height='24px' viewBox='0 0 24 24' width='24px' fill='%23000000'%3E%3Cpath d='M0 0h24v24H0V0z' fill='none'/%3E%3Cpath fill='%237A7A7A' d='M12 5.83L15.17 9l1.41-1.41L12 3 7.41 7.59 8.83 9 12 5.83zm0 12.34L8.83 15l-1.41 1.41L12 21l4.59-4.59L15.17 15 12 18.17z'/%3E%3C/svg%3E\")}:host ::ng-deep .mat-sort-header[aria-sort=ascending]{background-image:url(\"data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' height='24px' viewBox='0 0 24 24' width='24px' fill='%23000000'%3E%3Cpath d='M0 0h24v24H0V0z' fill='none'/%3E%3Cpath fill='%237A7A7A' d='M4 12l1.41 1.41L11 7.83V20h2V7.83l5.58 5.59L20 12l-8-8-8 8z'/%3E%3C/svg%3E\")}:host ::ng-deep .mat-sort-header[aria-sort=descending]{background-image:url(\"data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' height='24px' viewBox='0 0 24 24' width='24px' fill='%23000000'%3E%3Cpath d='M0 0h24v24H0V0z' fill='none'/%3E%3Cpath fill='%237A7A7A' d='M20 12l-1.41-1.41L13 16.17V4h-2v12.17l-5.58-5.59L4 12l8 8 8-8z'/%3E%3C/svg%3E\")}:host ::ng-deep .c-paginator .mat-mdc-paginator .mdc-text-field--outlined .mat-mdc-form-field-infix,:host ::ng-deep .c-paginator .mat-mdc-paginator .mdc-text-field--no-label .mat-mdc-form-field-infix{padding-top:2px;padding-bottom:2px;min-height:32px}:host ::ng-deep .c-paginator .mat-mdc-paginator-range-label{margin:0 4px}:host ::ng-deep .c-paginator .mat-mdc-paginator-page-size-select mat-select{margin-top:2px!important}:host ::ng-deep .cdk-drag-preview{box-shadow:0 4px 12px #00000026;background:#fff;display:table;width:100%}:host ::ng-deep .cdk-drag-preview td{padding:0 8px;border-bottom:1px solid rgba(0,0,0,.12)}:host ::ng-deep .cdk-drag-placeholder{opacity:0}:host ::ng-deep .cdk-drop-list-dragging tr.c-row:not(.cdk-drag-placeholder){transition:transform .25s cubic-bezier(0,0,.2,1)}:host ::ng-deep .sd-selection-cell{width:42px;min-width:42px;max-width:42px}:host ::ng-deep .sd-filler-cell{width:auto;min-width:0;padding:0!important;border:0}:host ::ng-deep .sd-group-header-cell{background:#f5f7fc;border-top:1px solid #e6e9f2;border-bottom:1px solid #e6e9f2}:host ::ng-deep .sd-group-row{min-height:36px}:host ::ng-deep .sd-group-selection-slot{width:42px;min-width:42px;max-width:42px}:host ::ng-deep .c-selection{transform:scale(.85);transform-origin:center}:host ::ng-deep .sd-tree-line{display:inline-flex;align-items:center;min-height:32px}:host ::ng-deep .sd-tree-indent{flex:0 0 auto}:host ::ng-deep .sd-tree-toggle-slot{flex:0 0 auto;display:inline-flex;align-items:center;justify-content:center;width:24px;height:24px}:host ::ng-deep .sd-tree-toggle-btn{display:inline-flex;align-items:center;justify-content:center;width:24px;height:24px;padding:0;border:0;background:transparent;border-radius:50%;cursor:pointer;color:var(--sd-text-secondary, #5b6472);transition:background-color .15s ease}:host ::ng-deep .sd-tree-toggle-btn mat-icon{font-size:18px;width:18px;height:18px;line-height:18px}:host ::ng-deep .sd-tree-toggle-btn:hover{background-color:#0f172a14}:host ::ng-deep .sd-tree-spinner{transform:scale(.45)}:host ::ng-deep .sd-tree-stt{margin-left:2px;white-space:nowrap}:host ::ng-deep .sd-tree-index-cell{text-align:left!important;white-space:nowrap;padding-left:8px;padding-right:8px}:host ::ng-deep .sd-tree-index-header{padding-left:32px}:host ::ng-deep tr.c-row.sd-tree-row.sd-tree-level-0{background:#fbfcfe}:host ::ng-deep tr.c-row.sd-tree-row.sd-tree-level-0>td{font-weight:500}:host ::ng-deep tr.c-row.sd-tree-row.sd-tree-level-1{background:#fff}:host ::ng-deep tr.c-row.sd-tree-row.sd-tree-level-2{background:#fafbfd}:host ::ng-deep tr.c-row.sd-tree-row.sd-tree-level-3{background:#f6f8fb}:host ::ng-deep .sd-stt-root{font-weight:700;color:#1f2330}\n", ":host ::ng-deep .sticky-shadow-right{overflow:visible!important}:host ::ng-deep .sticky-shadow-right:after{content:\"\";position:absolute;top:0;right:0;bottom:0;width:8px;transform:translate(100%);background:linear-gradient(to right,rgba(0,0,0,.12),transparent);pointer-events:none}:host ::ng-deep .sticky-shadow-left{overflow:visible!important}:host ::ng-deep .sticky-shadow-left:after{content:\"\";position:absolute;top:0;left:0;bottom:0;width:8px;transform:translate(-100%);background:linear-gradient(to left,rgba(0,0,0,.12),transparent);pointer-events:none}\n"] }]
|
|
4585
|
+
], template: "@let _configuration = configuration();\n@let _tableOption = tableOption()!;\n@let _loading = loading();\n@let _items = items();\n@let _total = total();\n@let _isFiltered = isFiltered();\n@let _requireFiltered = requireFiltered();\n@let _export = _tableOption?.export;\n@let _exporting = exporting();\n@let _titleDef = titleDef();\n@let _autoId = autoId();\n@let _exportTitle = exportTitle();\n@let _cellDef = cellDef();\n@let _footerDef = footerDef();\n@let _sdSubInformation = sdSubInformation();\n@let _configComponent = configComponent();\n@let _mobileFilter = mobileFilter();\n@let _selectedTableItems = selectedTableItems();\n<!-- why: tree kh\u00F4ng c\u00F2n c\u1ED9t ri\u00EAng \u2014 khi KH\u00D4NG c\u00F3 c\u1ED9t Index, icon expand nh\u00FAng v\u00E0o\n c\u1ED9t data \u0111\u1EA7u ti\u00EAn. \u0110\u00E2y l\u00E0 field c\u1EE7a c\u1ED9t \u0111\u00F3 (null n\u1EBFu c\u00F3 Index ho\u1EB7c kh\u00F4ng tree). -->\n@let _treeFirstField = _tableOption?.tree && !_tableOption.index?.enabled ? _configuration?.firstColumns?.[0]?.field : null;\n\n@if (_configuration) {\n @if (!_tableOption.filter?.disabled && !!_tableOption.filter?.externalFilters?.length && filterRegister) {\n <external-filter\n class=\"mb-16\"\n [autoId]=\"_autoId\"\n [filterRegister]=\"filterRegister\"\n [filter]=\"_tableOption.filter!\"\n [externalFilters]=\"_tableOption.filter?.externalFilters!\">\n </external-filter>\n }\n @let groupedItems = _items | sdTree: _tableOption.tree : treeRevision() | sdGroup: _tableOption : groupExpandState;\n\n <!-- Tree toggle d\u00F9ng chung: indent (theo c\u1EA5p) + slot chevron/spinner. Nh\u00FAng v\u00E0o\n c\u1ED9t Index ho\u1EB7c c\u1ED9t data \u0111\u1EA7u qua *ngTemplateOutlet (context: { row }). -->\n <ng-template #sdTreeToggle let-row=\"row\">\n @let _tree = row?.meta?.tree;\n @if (_tree) {\n <span class=\"sd-tree-indent\" [style.width.px]=\"(_tree.level ?? 0) * (_tableOption.tree?.indentSize ?? 20)\"></span>\n <span class=\"sd-tree-toggle-slot\">\n @if (_tree.hasChildren) {\n @if (_tree.isExpanding) {\n <span class=\"lds-ring sd-tree-spinner\">\n <div></div>\n <div></div>\n <div></div>\n <div></div>\n </span>\n } @else {\n @let _aid = _autoId;\n <button\n type=\"button\"\n class=\"sd-tree-toggle-btn\"\n [attr.data-autoid]=\"_aid ? _aid + '-tree-toggle-' + row.meta.id : null\"\n (click)=\"onTreeToggle(row); $event.stopPropagation()\">\n <sd-icon [name]=\"_tree.isExpanded ? 'expand_more' : 'chevron_right'\"></sd-icon>\n </button>\n }\n }\n </span>\n }\n </ng-template>\n\n <ng-content select=\"[sdTableTop]\"></ng-content>\n <div class=\"c-container\">\n @if (_loading) {\n <div class=\"c-loading\">\n <mat-spinner></mat-spinner>\n </div>\n }\n <div\n class=\"c-table\"\n sdScroll\n stickyShadow\n [style.max-height]=\"_tableOption.style?.maxHeight\"\n [style.min-height]=\"_tableOption.style?.minHeight\">\n <table\n mat-table\n [dataSource]=\"groupedItems\"\n [trackBy]=\"trackBy\"\n matSort\n [matSortDisabled]=\"!_tableOption.sort?.enable\"\n multiTemplateDataRows\n cdkDropList\n [cdkDropListData]=\"groupedItems\"\n [cdkDropListDisabled]=\"!_tableOption.rowReorder?.enabled\"\n [cdkDropListSortPredicate]=\"reorderSortPredicate\"\n (cdkDropListDropped)=\"onReorderDrop($event)\">\n @if (_tableOption.rowReorder?.enabled) {\n <ng-container matColumnDef=\"sdReorder\">\n <th mat-header-cell *matHeaderCellDef class=\"sd-reorder-header\" [attr.rowspan]=\"_configuration.multipleHeader ? 2 : 1\"></th>\n <td mat-cell *matCellDef=\"let row\" class=\"sd-reorder-cell\">\n @if (!row.meta?.group?.items?.length) {\n <sd-icon cdkDragHandle [class.sd-reorder-disabled]=\"isReorderDisabled(row)\" [name]=\"_tableOption.rowReorder?.icon || 'drag_indicator'\"></sd-icon>\n }\n </td>\n <td mat-footer-cell *matFooterCellDef></td>\n </ng-container>\n }\n\n <ng-container matColumnDef=\"sdSubInformation\" sticky>\n <td class=\"p-0\" mat-cell *matCellDef=\"let item\" [attr.colspan]=\"_configuration.displayedColumns.length\">\n @if (_sdSubInformation?.templateRef) {\n @if (_tableOption.expand?.always) {\n <ng-container *ngTemplateOutlet=\"_sdSubInformation?.templateRef!; context: { item: item }\"> </ng-container>\n } @else {\n <div [@detailExpand]=\"item.isExpanded ? 'expanded' : 'collapsed'\">\n @if (item.isExpanded) {\n <ng-container *ngTemplateOutlet=\"_sdSubInformation?.templateRef!; context: { item: item }\"> </ng-container>\n }\n </div>\n }\n }\n </td>\n <td mat-footer-cell *matFooterCellDef></td>\n </ng-container>\n\n <ng-container matColumnDef=\"sdSubInformationAction\" stickyEnd>\n <th class=\"p-0\" mat-header-cell *matHeaderCellDef style=\"width: 1px\" [attr.rowspan]=\"_configuration.multipleHeader ? 2 : 1\"></th>\n <td mat-cell *matCellDef=\"let element\">\n @if (!element.isExpanding && !_tableOption.expand?.always) {\n <sd-button\n [autoId]=\"_autoId ? _autoId + '-expand-' + element.meta.id : null\"\n type=\"link\"\n [prefixIcon]=\"element.isExpanded ? 'expand_less' : 'expand_more'\"\n (click)=\"onExpand(element)\"\n width=\"35px\">\n </sd-button>\n }\n @if (element.isExpanding) {\n <div class=\"lds-ring\">\n <div></div>\n <div></div>\n <div></div>\n <div></div>\n </div>\n }\n </td>\n </ng-container>\n\n <ng-container matColumnDef=\"sdSelection\" sticky>\n <th class=\"sd-selection-cell p-0\" mat-header-cell *matHeaderCellDef [attr.rowspan]=\"_configuration.multipleHeader ? 2 : 1\">\n @let visibleSelectAll = _items | selectionVisibleSelectAll: _tableOption.selector | async;\n @if (visibleSelectAll) {\n <mat-checkbox\n class=\"c-selection px-8\"\n color=\"primary\"\n [ngModel]=\"isSelectAll()\"\n (ngModelChange)=\"isSelectAll.set($event)\"\n (change)=\"onSelectAll()\">\n </mat-checkbox>\n }\n </th>\n\n <td class=\"sd-selection-cell p-0\" mat-cell *matCellDef=\"let item\">\n @let visible = item | selectionVisible: _tableOption.selector;\n @if (visible) {\n @if (_tableOption.selector?.single) {\n <mat-radio-button\n class=\"c-selection px-8\"\n color=\"primary\"\n [checked]=\"item.meta.selector.isSelected\"\n (change)=\"item.meta.selector.isSelected = true; onSelect(item)\"\n [disabled]=\"_selectedTableItems | selectionDisabled: item : _tableOption.selector!\">\n </mat-radio-button>\n } @else {\n <mat-checkbox\n class=\"c-selection px-8\"\n color=\"primary\"\n [(ngModel)]=\"item.meta.selector.isSelected\"\n (change)=\"onSelect(item)\"\n [disabled]=\"_selectedTableItems | selectionDisabled: item : _tableOption.selector!\">\n </mat-checkbox>\n }\n }\n </td>\n <td mat-footer-cell *matFooterCellDef></td>\n </ng-container>\n @if (_tableOption.index?.enabled) {\n @let _pageOffset = pageOffset();\n @let _indexWidth = _tableOption.index?.width || '50px';\n <!-- why: khi tree, c\u1ED9t Index \"\u00F4m\" th\u00EAm chevron + indent. D\u00F9ng width:1px +\n nowrap (.sd-tree-index-cell) \u0111\u1EC3 c\u1ED9t co S\u00C1T n\u1ED9i dung, kh\u00F4ng chi\u1EBFm ch\u1ED7\n th\u1EEBa; header \"#\" canh tr\u00E1i l\u00F9i v\u00E0o (.sd-tree-index-header) cho th\u1EB3ng s\u1ED1. -->\n @let _treeIndex = !!_tableOption.tree;\n <ng-container matColumnDef=\"sdIndex\" sticky>\n <th\n [class.p-0]=\"!_treeIndex\"\n [class.text-center]=\"!_treeIndex\"\n [class.sd-tree-index-cell]=\"_treeIndex\"\n [class.sd-tree-index-header]=\"_treeIndex\"\n mat-header-cell\n *matHeaderCellDef\n [style.width]=\"_treeIndex ? '1px' : _indexWidth\"\n [style.min-width]=\"_treeIndex ? null : _indexWidth\"\n [style.max-width]=\"_treeIndex ? null : _indexWidth\"\n [attr.rowspan]=\"_configuration.multipleHeader ? 2 : 1\">\n {{ _tableOption.index?.title || '#' }}\n </th>\n <td\n [class.px-4]=\"!_treeIndex\"\n [class.text-center]=\"!_treeIndex\"\n [class.sd-tree-index-cell]=\"_treeIndex\"\n mat-cell\n *matCellDef=\"let item; let i = dataIndex\"\n [style.width]=\"_treeIndex ? '1px' : null\"\n [style.min-width]=\"_treeIndex ? null : _indexWidth\"\n [style.max-width]=\"_treeIndex ? null : _indexWidth\">\n @if (!item?.meta?.group?.isGroupHeader) {\n @if (_treeIndex) {\n <!-- why: tree \u2192 chevron + indent + STT ph\u00E2n c\u1EA5p (1, 1.2, 1.2.1). T\u00F4 \u0111\u1EADm root (level 0). -->\n <span class=\"sd-tree-line\">\n <ng-container *ngTemplateOutlet=\"sdTreeToggle; context: { row: item }\"></ng-container>\n @if (item?.meta?.tree?.indexPath?.length) {\n <span class=\"sd-tree-stt\" [class.sd-stt-root]=\"(item.meta.tree.level ?? 0) === 0\">\n {{ item.meta.tree.indexPath.join('.') }}\n </span>\n }\n </span>\n } @else {\n {{ _pageOffset + i + 1 }}\n }\n }\n </td>\n <td mat-footer-cell *matFooterCellDef [style.width]=\"_treeIndex ? '1px' : null\" [style.min-width]=\"_treeIndex ? null : _indexWidth\" [style.max-width]=\"_treeIndex ? null : _indexWidth\"></td>\n </ng-container>\n }\n <ng-container\n matColumnDef=\"sdCommand\"\n [sticky]=\"_tableOption.command?.align !== 'right'\"\n [stickyEnd]=\"_tableOption.command?.align === 'right'\">\n <th class=\"p-0\" mat-header-cell *matHeaderCellDef style=\"width: 50px\" [attr.rowspan]=\"_configuration.multipleHeader ? 2 : 1\"></th>\n <td class=\"px-8\" mat-cell *matCellDef=\"let item\">\n <desktop-command\n [autoId]=\"_autoId\"\n [commands]=\"_tableOption.command?.commands || _tableOption.commands || []\"\n [item]=\"item\"\n [itemIndex]=\"groupedItems.indexOf(item)\"></desktop-command>\n </td>\n <td mat-footer-cell *matFooterCellDef></td>\n </ng-container>\n <!-- why: group header row d\u00F9ng matRowDef RI\u00CANG v\u1EDBi column list ['sdGroupHeader']\n qua predicate when:isGroupHeaderRow. Cell colspan = displayedColumns.length \u0111\u1EC3\n span TO\u00C0N B\u1ED8 width data row. Tr\u00E1nh colspan trick overflow row khi c\u00E1c TD kh\u00E1c render. -->\n <ng-container matColumnDef=\"sdGroupHeader\">\n <td\n class=\"p-0 sd-group-header-cell\"\n mat-cell\n *matCellDef=\"let item\"\n [attr.colspan]=\"sdGroupColspan()\">\n <div class=\"sd-group-row d-flex align-items-center py-8\">\n <!-- why: slot 42px kh\u1EDBp width v\u1EDBi sd-selection-cell data row \u2192 checkbox group c\u0103n TR\u1EE4C d\u1ECDc \u0111\u00FAng v\u1EDBi checkbox data. -->\n @if (_tableOption.selector?.visible && !_tableOption.selector?.single) {\n <div class=\"sd-group-selection-slot d-flex align-items-center justify-content-center\">\n <mat-checkbox\n class=\"c-selection\"\n color=\"primary\"\n [checked]=\"isGroupAllSelected(item)\"\n [indeterminate]=\"isGroupIndeterminate(item)\"\n (change)=\"onSelectGroup(item, $event.checked)\">\n </mat-checkbox>\n </div>\n } @else {\n <div class=\"sd-group-selection-slot\"></div>\n }\n @if (_tableOption.group?.collapsible) {\n <sd-button\n [autoId]=\"_autoId ? _autoId + '-group-toggle-' + (item.meta.group?.key || item.meta.id) : null\"\n type=\"link\"\n [prefixIcon]=\"item.meta.group.isExpanded ? 'expand_more' : 'chevron_right'\"\n width=\"32px\"\n (click)=\"toggleGroupExpand(item)\">\n </sd-button>\n }\n @if (sdGroupDef()?.templateRef; as tpl) {\n <ng-container *ngTemplateOutlet=\"tpl; context: groupContext(item)\"></ng-container>\n } @else {\n <span class=\"T14R\">{{ item.meta.group.values | json }}</span>\n }\n </div>\n </td>\n </ng-container>\n <!-- why: filler column \u1EDF cu\u1ED1i h\u1EA5p th\u1EE5 leftover space khi t\u1ED5ng width c\u00E1c c\u1ED9t data < container \u2014 gi\u1EEF cho selection/STT/command kh\u00F4ng b\u1ECB d\u00E3n. -->\n <ng-container matColumnDef=\"sdFiller\">\n <th class=\"sd-filler-cell p-0\" mat-header-cell *matHeaderCellDef [attr.rowspan]=\"_configuration.multipleHeader ? 2 : 1\"></th>\n <td class=\"sd-filler-cell p-0\" mat-cell *matCellDef=\"let item\"></td>\n <td class=\"sd-filler-cell p-0\" mat-footer-cell *matFooterCellDef></td>\n </ng-container>\n @for (column of _configuration.firstColumns; track column.field) {\n <ng-container [matColumnDef]=\"column.field\" [sticky]=\"_configuration.fixedColumn[column.field]\">\n <th\n mat-header-cell\n *matHeaderCellDef\n class=\"px-8 py-8 c-th\"\n [sdColumnResize]=\"!!_tableOption.config?.resizable && column.type !== 'children'\"\n [minWidth]=\"column.minWidth\"\n [maxWidth]=\"column.maxWidth\"\n (resizeEnd)=\"onColumnResize(column.field, $event)\"\n [style.width]=\"column.width\"\n [style.min-width]=\"column.minWidth || column.width\"\n [style.max-width]=\"column.maxWidth\"\n [attr.rowspan]=\"_configuration.multipleHeader && column.type !== 'children' ? 2 : 1\"\n [attr.colspan]=\"column.type === 'children' ? column.children.length : 1\">\n <div>\n @if (column.type === 'children') {\n <div\n aria-hidden=\"true\"\n class=\"c-header-title\"\n [class.justify-content-end]=\"column.align === 'right'\"\n [class.text-right]=\"column.align === 'right'\">\n <column-title [column]=\"column\" [titleDef]=\"_titleDef[column.field]\"></column-title>\n </div>\n } @else {\n <div\n aria-hidden=\"true\"\n mat-sort-header\n class=\"c-header-title\"\n [class.justify-content-end]=\"column.align === 'right'\"\n [class.text-right]=\"column.align === 'right'\"\n [disabled]=\"!column.sortable\">\n <column-title [column]=\"column\" [titleDef]=\"_titleDef[column.field]\"></column-title>\n </div>\n @let hideInlineFilter =\n _tableOption.filter?.disabled ||\n _tableOption.filter?.hideInlineFilter === true ||\n (_tableOption.filter?.hideInlineFilter === 'auto' && !_isFiltered && _total! <= 10);\n @if (!hideInlineFilter) {\n <ng-container *sdDesktop>\n <column-filter\n [autoId]=\"_autoId\"\n [value]=\"columnFilter?.[column.field!]!\"\n [operator]=\"columnOperator[column.field]\"\n (operatorChange)=\"columnOperator[column.field] = $event!; onOperatorChange(column, $event)\"\n [columnFilter]=\"columnFilter!\"\n [cacheValues]=\"cacheValues\"\n [column]=\"column\"\n (filterChange)=\"onFilterChange()\"\n (filterCommit)=\"onFilterCommit()\">\n </column-filter>\n </ng-container>\n }\n }\n </div>\n </th>\n <td\n class=\"c-td px-0\"\n [class.d-none]=\"column.type === 'children'\"\n mat-cell\n *matCellDef=\"let item\"\n [sdHoverCopy]=\"(item.data && item.data[column.field]) || ''\"\n [sdHoverCopyDisabled]=\"!column.cell?.copiable\">\n @if (column.type !== 'children' && !item?.meta?.group?.isGroupHeader) {\n @if (_treeFirstField && column.field === _treeFirstField) {\n <!-- why: kh\u00F4ng c\u00F3 c\u1ED9t Index \u2192 chevron + indent nh\u00FAng v\u00E0o c\u1ED9t data \u0111\u1EA7u (nh\u01B0 file explorer). -->\n <span class=\"sd-tree-line px-8\">\n <ng-container *ngTemplateOutlet=\"sdTreeToggle; context: { row: item }\"></ng-container>\n <desktop-cell class=\"d-block\" [column]=\"column\" [item]=\"item\" [cellDef]=\"_cellDef\"></desktop-cell>\n </span>\n } @else {\n <desktop-cell class=\"d-block px-8\" [column]=\"column\" [item]=\"item\" [cellDef]=\"_cellDef\"> </desktop-cell>\n }\n }\n </td>\n <td mat-footer-cell *matFooterCellDef>\n <ng-container *ngIf=\"_footerDef[column.field]\">\n <ng-container *ngTemplateOutlet=\"_footerDef[column.field].templateRef; context: { items: _items, column: column }\">\n </ng-container>\n </ng-container>\n </td>\n </ng-container>\n }\n @for (column of _configuration.secondColumns; track column.field) {\n <ng-container [matColumnDef]=\"column.field\">\n <th\n mat-header-cell\n *matHeaderCellDef\n class=\"c-th px-8\"\n [style.width]=\"column.width\"\n [style.min-width]=\"column.minWidth || column.width\"\n [style.max-width]=\"column.maxWidth\">\n <div>\n <div\n aria-hidden=\"true\"\n mat-sort-header\n class=\"c-header-title\"\n [class.justify-content-end]=\"column.align === 'right'\"\n [class.text-right]=\"column.align === 'right'\"\n [disabled]=\"!column.sortable\">\n <column-title [column]=\"column\" [titleDef]=\"_titleDef[column.field]\"></column-title>\n </div>\n @if (!_tableOption.filter?.disabled && !_tableOption.filter?.hideInlineFilter && columnOperator) {\n <ng-container *sdDesktop>\n <column-filter\n [autoId]=\"_autoId\"\n [value]=\"columnFilter?.[column.field!]!\"\n [operator]=\"columnOperator[column.field]\"\n [columnFilter]=\"columnFilter!\"\n [cacheValues]=\"cacheValues\"\n [column]=\"column\"\n (operatorChange)=\"columnOperator[column.field] = $event!; onOperatorChange(column, $event)\"\n (filterChange)=\"onFilterChange()\"\n (filterCommit)=\"onFilterCommit()\">\n </column-filter>\n </ng-container>\n }\n </div>\n </th>\n <td\n class=\"c-td px-0\"\n mat-cell\n *matCellDef=\"let item\"\n [sdHoverCopy]=\"item[column.field]\"\n [sdHoverCopyDisabled]=\"!column.cell?.copiable\">\n @if (column.type !== 'children') {\n <desktop-cell class=\"d-block px-8\" [column]=\"column\" [item]=\"item\" [cellDef]=\"_cellDef\"> </desktop-cell>\n }\n </td>\n <td mat-footer-cell *matFooterCellDef>\n <ng-container *ngIf=\"_footerDef[column.field]\">\n <ng-container *ngTemplateOutlet=\"_footerDef[column.field].templateRef; context: { items: _items, column: column }\">\n </ng-container>\n </ng-container>\n </td>\n </ng-container>\n }\n <tr class=\"c-first-header\" mat-header-row *matHeaderRowDef=\"_configuration.firstHeaders; sticky: true\"></tr>\n @if (!!_configuration.secondHeaders.length) {\n <tr class=\"c-second-header\" mat-header-row *matHeaderRowDef=\"_configuration.secondHeaders; sticky: true\"></tr>\n }\n <!-- Group header row \u2014 ch\u1EC9 1 cell sdGroupHeader colspan to\u00E0n width. -->\n <tr\n mat-row\n *matRowDef=\"let row; columns: ['sdGroupHeader']; when: isGroupHeaderRow\"\n class=\"c-group-row-tr\"></tr>\n\n <!-- Data row \u2014 d\u00F9ng displayedColumns \u0111\u1EA7y \u0111\u1EE7; when isDataRow \u0111\u1EC3 lo\u1EA1i tr\u1EEB group header. -->\n <tr\n mat-row\n cdkDrag\n [cdkDragData]=\"row\"\n [cdkDragDisabled]=\"\n !_tableOption.rowReorder?.enabled ||\n !!row.meta?.group?.items?.length ||\n (row.meta?.tree?.level ?? 0) > 0 ||\n isReorderDisabled(row)\n \"\n *matRowDef=\"let row; columns: _configuration.displayedColumns; when: isDataRow\"\n matRipple\n class=\"c-row\"\n [class.sd-tree-row]=\"!!_tableOption.tree\"\n [ngClass]=\"_tableOption.tree ? 'sd-tree-level-' + (row.meta?.tree?.level ?? 0) : null\"\n [ngStyle]=\"rowStyle(row)\"\n [class.selected]=\"row.meta.selector.isSelected\"></tr>\n\n <!-- Sub-information row \u2014 also gated b\u1EDFi isDataRow \u0111\u1EC3 KH\u00D4NG render empty expand row d\u01B0\u1EDBi group header. -->\n <tr mat-row *matRowDef=\"let row; columns: ['sdSubInformation']; when: isDataRow\" class=\"c-detail-row\"></tr>\n @if (hasFooter() && !!_configuration.displayedFooters.length) {\n <tr mat-footer-row *matFooterRowDef=\"_configuration.displayedFooters; sticky: true\"></tr>\n }\n </table>\n @if (!_loading && !_total) {\n <div class=\"c-no-data-row\">\n @if (_isFiltered) {\n @if (tableConfiguration?.images?.filterEmpty) {\n <img class=\"c-image\" [src]=\"tableConfiguration!.images!.filterEmpty\" alt=\"filter-empty\" />\n } @else {\n <img class=\"c-image sd-image-filter-empty\" alt=\"filter-empty\" />\n }\n <div class=\"T16M\">{{ 'core.component.table.no-results' | translate }}</div>\n <div class=\"T16R text-secondary\">{{ 'core.component.table.no-results-hint' | translate }}</div>\n } @else {\n @if (_requireFiltered) {\n @if (tableConfiguration?.images?.filterRequired) {\n <img class=\"c-image\" [src]=\"tableConfiguration!.images!.filterRequired\" alt=\"filter-required\" />\n } @else {\n <img class=\"c-image sd-image-filter-required\" alt=\"filter-required\" />\n }\n <div class=\"T16R text-secondary\">{{ 'core.component.table.choose-filter-hint' | translate }}</div>\n } @else {\n @if (tableConfiguration?.images?.dataEmpty) {\n <img class=\"c-image\" [src]=\"tableConfiguration!.images!.dataEmpty\" alt=\"data-empty\" />\n } @else {\n <img class=\"c-image sd-image-data-empty\" alt=\"data-empty\" />\n }\n <div class=\"T16R text-secondary\">{{ 'core.component.table.no-data' | translate }}</div>\n }\n }\n </div>\n }\n </div>\n <div class=\"c-paginator\">\n <div class=\"c-action\">\n <ng-container *sdDesktop>\n @if (_tableOption.reload?.visible) {\n <sd-button\n [autoId]=\"_autoId ? _autoId + '-reload' : null\"\n class=\"mr-8\"\n [title]=\"'core.component.table.reload' | translate\"\n prefixIcon=\"refresh\"\n (click)=\"reload()\"\n [disabled]=\"!_items.length\"\n type=\"link\">\n </sd-button>\n }\n </ng-container>\n @if (_export && _items.length) {\n @if (_export.type === 'custom') {\n <sd-button [autoId]=\"_autoId ? _autoId + '-export' : null\" class=\"mr-8\" [title]=\"_exportTitle\" prefixIcon=\"get_app\" (click)=\"exportCustom()\" type=\"link\"> </sd-button>\n } @else {\n @if (_export.visible) {\n @if (_exporting) {\n <sd-button [autoId]=\"_autoId ? _autoId + '-export' : null\" class=\"mr-8\" [loading]=\"_exporting\" [title]=\"_exportTitle\" prefixIcon=\"get_app\" type=\"link\"> </sd-button>\n } @else {\n @if (_export.visible === 'ALL' || !_export.visible) {\n <sd-button [autoId]=\"_autoId ? _autoId + '-export' : null\" class=\"mr-8\" [title]=\"_exportTitle\" prefixIcon=\"get_app\" [matMenuTriggerFor]=\"menu\" type=\"link\"> </sd-button>\n <mat-menu #menu=\"matMenu\">\n <button mat-menu-item [attr.data-autoid]=\"_autoId ? _autoId + '-export-excel' : null\" (click)=\"exportExcel()\" type=\"button\">\n <sd-icon name=\"file_download\"></sd-icon>\n <span> {{ 'core.component.table.export-excel' | translate }}</span>\n </button>\n <button mat-menu-item [attr.data-autoid]=\"_autoId ? _autoId + '-export-csv' : null\" (click)=\"exportCSV()\" type=\"button\">\n <sd-icon name=\"file_download\"></sd-icon>\n <span> {{ 'core.component.table.export-csv' | translate }}</span>\n </button>\n </mat-menu>\n } @else if (_export.visible === 'EXCEL') {\n <sd-button [autoId]=\"_autoId ? _autoId + '-export-excel' : null\" class=\"mr-8\" [title]=\"_exportTitle\" prefixIcon=\"get_app\" (click)=\"exportExcel()\" type=\"link\"> </sd-button>\n } @else if (_export.visible === 'CSV') {\n <sd-button [autoId]=\"_autoId ? _autoId + '-export-csv' : null\" class=\"mr-8\" [title]=\"_exportTitle\" prefixIcon=\"get_app\" (click)=\"exportCSV()\" type=\"link\"> </sd-button>\n }\n }\n }\n }\n }\n\n <ng-container *sdDesktop>\n @if (_configComponent) {\n <sd-button\n [autoId]=\"_autoId ? _autoId + '-config' : null\"\n class=\"mr-8\"\n [title]=\"'core.component.table.setup-short' | translate\"\n prefixIcon=\"settings\"\n (click)=\"_configComponent.open()\"\n type=\"link\">\n </sd-button>\n }\n </ng-container>\n <!-- Mobile: n\u00FAt Filter m\u1EDF mobile-filter drawer (inline filter \u1EA9n tr\u00EAn mobile) -->\n <ng-container *sdMobile>\n @if (!_tableOption.filter?.disabled && _mobileFilter) {\n <sd-button\n [autoId]=\"_autoId ? _autoId + '-mobile-filter-open' : null\"\n class=\"mr-8\"\n prefixIcon=\"filter_alt\"\n (click)=\"_mobileFilter.open()\"\n type=\"link\">\n </sd-button>\n }\n </ng-container>\n </div>\n @let hidePaginator = !_tableOption.paginate?.pageSize || _total === undefined || _total <= _tableOption.paginate?.pageSize!;\n <!-- Desktop paginator: full config (pageSize dropdown, first/last buttons) -->\n <ng-container *sdDesktop>\n <mat-paginator\n [class.d-none]=\"_tableOption.paginate?.hidden || hidePaginator\"\n [length]=\"_total\"\n [pageSize]=\"_tableOption.paginate?.pageSize\"\n [pageSizeOptions]=\"_tableOption.paginate?.pages!\"\n [showFirstLastButtons]=\"_tableOption.paginate?.showFirstLastButtons\"\n [hidePageSize]=\"_tableOption.paginate?.hidePageSize\"></mat-paginator>\n </ng-container>\n <!-- Mobile paginator: \u1EA9n pageSize dropdown + first/last buttons \u0111\u1EC3 ti\u1EBFt ki\u1EC7m kh\u00F4ng gian -->\n <ng-container *sdMobile>\n <mat-paginator\n [class.d-none]=\"_tableOption.paginate?.hidden || hidePaginator\"\n [length]=\"_total\"\n [pageSize]=\"_tableOption.paginate?.pageSize\"\n [showFirstLastButtons]=\"false\"\n hidePageSize></mat-paginator>\n </ng-container>\n <!-- \"\u0110ang hi\u1EC3n th\u1ECB...\" ch\u1EC9 desktop -->\n <ng-container *sdDesktop>\n @if (!_tableOption.paginate?.hidden && hidePaginator && _total !== undefined && _total > 0) {\n <div class=\"T14R pr-16\">\n {{ 'core.component.table.showing' | translate }} <span class=\"T14M ml-2\">1-{{ _total }}/{{ _total }}</span>\n </div>\n }\n </ng-container>\n </div>\n </div>\n <selector-action [autoId]=\"_autoId\" [tableOption]=\"_tableOption\" [selectedTableItems]=\"_selectedTableItems\" (clear)=\"onClearSelection(groupedItems)\" />\n @if (_tableOption.config?.visible) {\n <config [autoId]=\"_autoId\" [tableOption]=\"_tableOption\" />\n }\n <!-- Mobile filter drawer \u2014 ch\u1EC9 instantiate khi c\u1EA7n render tr\u00EAn mobile -->\n @if (!_tableOption.filter?.disabled && filterRegister) {\n <mobile-filter\n [autoId]=\"_autoId\"\n [filter]=\"_tableOption.filter!\"\n [externalFilters]=\"_tableOption.filter?.externalFilters!\"\n [columns]=\"_configuration.firstColumns\"\n [filterDefs]=\"sdFilterDefs()\"\n [filterRegister]=\"filterRegister\"\n [cacheValues]=\"cacheValues\">\n </mobile-filter>\n }\n}\n", styles: [":host{display:flex;flex-direction:column;overflow:auto;width:100%;height:100%}:host .c-header-title{height:40px;display:flex;align-items:center}:host .c-container{position:relative;min-height:50px;display:flex;flex-direction:column;flex:1}:host .c-container .c-table{position:relative;flex:1;display:flex;flex-direction:column}:host .c-container .c-table table{border-collapse:separate;width:100%}:host .c-container .c-table table tr.c-first-header.mat-mdc-header-row{height:40px}:host .c-container .c-table table tr.c-second-header.mat-mdc-header-row{height:40px}:host .c-container .c-table table tr.c-detail-row{height:0}:host .c-container .c-table table tr.c-row.activated{background-color:#e5ecff}:host .c-container .c-table table tr.c-row.selected{background-color:#eef2ff}:host .c-container .c-table table tr.c-row:not(.selected):not(.activated):hover{background-color:#f5f5f5}:host .c-container .c-table table tr.c-row td{border-bottom-width:0}:host .c-container .c-table table tr.c-row.c-expandable{cursor:pointer}:host .c-container .c-table table tr.c-row.c-expandable:hover{background:#f5f5f5}:host .c-container .c-table table th.mat-mdc-header-cell{background-color:#f2f3f4;border-bottom:0!important}:host .c-container .c-table table td.mat-mdc-cell,:host .c-container .c-table table td.mat-mdc-footer-cell,:host .c-container .c-table table th.mat-mdc-header-cell{border-bottom-color:#f2f2f2!important}:host .c-container .c-table .c-th{vertical-align:middle;font-weight:500;font-size:14px;line-height:20px;color:#212121}:host .c-container .c-table .c-th.sd-col-resize-host{position:relative}:host .c-container .c-table .c-th.sd-resizing{-webkit-user-select:none;user-select:none}:host .c-container .c-table .c-th .sd-col-resize-handle{position:absolute;top:0;right:0;width:6px;height:100%;cursor:col-resize;-webkit-user-select:none;user-select:none;z-index:2}:host .c-container .c-table .c-th .sd-col-resize-handle:hover{background:#00000014}:host .c-container .c-table .c-td:first{padding-left:10px}:host .c-container .c-table .c-no-data-row{flex:1;width:100%;position:sticky;left:0;display:flex;flex-direction:column;align-items:center;justify-content:center}:host .c-container .c-table .c-no-data-row .c-image{margin-bottom:16px;width:96px}:host .c-container .c-loading{position:absolute;inset:0 0 56px;background:#00000026;z-index:2;display:flex;align-items:center;justify-content:center}:host .c-container .c-paginator{display:flex;flex-direction:row;justify-content:space-between;align-items:center;background-color:#fff}:host .c-container .c-paginator .c-action{padding:5px}:host .c-container .c-empty{text-align:center;background-color:#fff;border:none!important}:host .c-container .c-empty sd-icon{font-size:150px;margin-top:30px;margin-bottom:30px;opacity:.2;width:auto;height:auto}:host button.c-btn-add{background-color:#fff;box-shadow:0 2px 4px #2f313629}:host .lds-ring{display:inline-block;position:relative;width:40px;height:40px}:host .lds-ring div{box-sizing:border-box;display:block;position:absolute;width:32px;height:32px;margin:4px;border:4px solid #cef;border-radius:50%;animation:lds-ring 1.2s cubic-bezier(.5,0,.5,1) infinite;border-color:#cef transparent transparent transparent}:host .lds-ring div:nth-child(1){animation-delay:-.45s}:host .lds-ring div:nth-child(2){animation-delay:-.3s}:host .lds-ring div:nth-child(3){animation-delay:-.15s}@keyframes lds-ring{0%{transform:rotate(0)}to{transform:rotate(360deg)}}:host .sd-reorder-header,:host .sd-reorder-cell{width:40px;min-width:40px;padding:0 4px;box-sizing:border-box}:host .sd-reorder-cell sd-icon{cursor:grab;color:#00000061;display:flex;align-items:center}:host .sd-reorder-cell sd-icon:active{cursor:grabbing}:host .sd-reorder-cell sd-icon.sd-reorder-disabled{opacity:.3;cursor:not-allowed;pointer-events:none}:host ::ng-deep .mat-sort-header-content{display:block;text-align:left;width:100%}:host ::ng-deep .mat-select-arrow{color:#a6a6a6}:host ::ng-deep .mat-sort-header-disabled{background-image:none!important;cursor:default!important;padding-right:0!important}:host ::ng-deep .mat-sort-header-container{align-items:start!important}:host ::ng-deep .mat-sort-header-arrow{margin-top:4px!important}:host ::ng-deep .mat-sort-header-arrow{display:none!important}:host ::ng-deep .mat-sort-header{cursor:pointer}:host ::ng-deep .mat-sort-header[aria-sort]{background-repeat:no-repeat;background-position:center right 0;background-size:16px 16px;cursor:pointer;padding-right:24px}:host ::ng-deep .mat-sort-header[aria-sort=none]{background-image:url(\"data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' height='24px' viewBox='0 0 24 24' width='24px' fill='%23000000'%3E%3Cpath d='M0 0h24v24H0V0z' fill='none'/%3E%3Cpath fill='%237A7A7A' d='M12 5.83L15.17 9l1.41-1.41L12 3 7.41 7.59 8.83 9 12 5.83zm0 12.34L8.83 15l-1.41 1.41L12 21l4.59-4.59L15.17 15 12 18.17z'/%3E%3C/svg%3E\")}:host ::ng-deep .mat-sort-header[aria-sort=ascending]{background-image:url(\"data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' height='24px' viewBox='0 0 24 24' width='24px' fill='%23000000'%3E%3Cpath d='M0 0h24v24H0V0z' fill='none'/%3E%3Cpath fill='%237A7A7A' d='M4 12l1.41 1.41L11 7.83V20h2V7.83l5.58 5.59L20 12l-8-8-8 8z'/%3E%3C/svg%3E\")}:host ::ng-deep .mat-sort-header[aria-sort=descending]{background-image:url(\"data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' height='24px' viewBox='0 0 24 24' width='24px' fill='%23000000'%3E%3Cpath d='M0 0h24v24H0V0z' fill='none'/%3E%3Cpath fill='%237A7A7A' d='M20 12l-1.41-1.41L13 16.17V4h-2v12.17l-5.58-5.59L4 12l8 8 8-8z'/%3E%3C/svg%3E\")}:host ::ng-deep .c-paginator .mat-mdc-paginator .mdc-text-field--outlined .mat-mdc-form-field-infix,:host ::ng-deep .c-paginator .mat-mdc-paginator .mdc-text-field--no-label .mat-mdc-form-field-infix{padding-top:2px;padding-bottom:2px;min-height:32px}:host ::ng-deep .c-paginator .mat-mdc-paginator-range-label{margin:0 4px}:host ::ng-deep .c-paginator .mat-mdc-paginator-page-size-select mat-select{margin-top:2px!important}:host ::ng-deep .cdk-drag-preview{box-shadow:0 4px 12px #00000026;background:#fff;display:table;width:100%}:host ::ng-deep .cdk-drag-preview td{padding:0 8px;border-bottom:1px solid rgba(0,0,0,.12)}:host ::ng-deep .cdk-drag-placeholder{opacity:0}:host ::ng-deep .cdk-drop-list-dragging tr.c-row:not(.cdk-drag-placeholder){transition:transform .25s cubic-bezier(0,0,.2,1)}:host ::ng-deep .sd-selection-cell{width:42px;min-width:42px;max-width:42px}:host ::ng-deep .sd-filler-cell{width:auto;min-width:0;padding:0!important;border:0}:host ::ng-deep .sd-group-header-cell{background:#f5f7fc;border-top:1px solid #e6e9f2;border-bottom:1px solid #e6e9f2}:host ::ng-deep .sd-group-row{min-height:36px}:host ::ng-deep .sd-group-selection-slot{width:42px;min-width:42px;max-width:42px}:host ::ng-deep .c-selection{transform:scale(.85);transform-origin:center}:host ::ng-deep .sd-tree-line{display:inline-flex;align-items:center;min-height:32px}:host ::ng-deep .sd-tree-indent{flex:0 0 auto}:host ::ng-deep .sd-tree-toggle-slot{flex:0 0 auto;display:inline-flex;align-items:center;justify-content:center;width:24px;height:24px}:host ::ng-deep .sd-tree-toggle-btn{display:inline-flex;align-items:center;justify-content:center;width:24px;height:24px;padding:0;border:0;background:transparent;border-radius:50%;cursor:pointer;color:var(--sd-text-secondary, #5b6472);transition:background-color .15s ease}:host ::ng-deep .sd-tree-toggle-btn sd-icon{font-size:18px;width:18px;height:18px;line-height:18px}:host ::ng-deep .sd-tree-toggle-btn:hover{background-color:#0f172a14}:host ::ng-deep .sd-tree-spinner{transform:scale(.45)}:host ::ng-deep .sd-tree-stt{margin-left:2px;white-space:nowrap}:host ::ng-deep .sd-tree-index-cell{text-align:left!important;white-space:nowrap;padding-left:8px;padding-right:8px}:host ::ng-deep .sd-tree-index-header{padding-left:32px}:host ::ng-deep tr.c-row.sd-tree-row.sd-tree-level-0{background:#fbfcfe}:host ::ng-deep tr.c-row.sd-tree-row.sd-tree-level-0>td{font-weight:500}:host ::ng-deep tr.c-row.sd-tree-row.sd-tree-level-1{background:#fff}:host ::ng-deep tr.c-row.sd-tree-row.sd-tree-level-2{background:#fafbfd}:host ::ng-deep tr.c-row.sd-tree-row.sd-tree-level-3{background:#f6f8fb}:host ::ng-deep .sd-stt-root{font-weight:700;color:#1f2330}\n", ":host ::ng-deep .sticky-shadow-right{overflow:visible!important}:host ::ng-deep .sticky-shadow-right:after{content:\"\";position:absolute;top:0;right:0;bottom:0;width:8px;transform:translate(100%);background:linear-gradient(to right,rgba(0,0,0,.12),transparent);pointer-events:none}:host ::ng-deep .sticky-shadow-left{overflow:visible!important}:host ::ng-deep .sticky-shadow-left:after{content:\"\";position:absolute;top:0;left:0;bottom:0;width:8px;transform:translate(-100%);background:linear-gradient(to left,rgba(0,0,0,.12),transparent);pointer-events:none}\n"] }]
|
|
4608
4586
|
}], ctorParameters: () => [] });
|
|
4609
4587
|
|
|
4610
4588
|
/**
|