@sd-angular/core 19.0.0-beta.8 → 19.0.0-beta.81
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 +686 -33
- package/assets/scss/ckeditor5.scss +61 -4
- package/assets/scss/core/bootstrap.scss +17 -0
- package/assets/scss/core/form.scss +32 -6
- package/assets/scss/core/grid.scss +40 -0
- package/assets/scss/sd-core.scss +5 -0
- package/assets/scss/themes/material-theme.scss +82 -40
- package/components/anchor-v2/src/components/anchor-item-v2/anchor-item-v2.component.d.ts +5 -5
- package/components/anchor-v2/src/components/anchor-v2/anchor-v2.component.d.ts +12 -18
- package/components/anchor-v2/src/components/anchor-vertical-v2/anchor-vertical-list-v2.component.d.ts +9 -10
- package/components/anchor-v2/src/models/sd-anchor-v2.model.d.ts +3 -3
- package/components/avatar/index.d.ts +1 -0
- package/components/avatar/src/avatar.component.d.ts +19 -0
- package/components/badge/src/badge.component.d.ts +77 -19
- package/components/button/src/button.component.d.ts +30 -28
- package/components/chart/index.d.ts +4 -0
- package/components/chart/src/bar-chart.component.d.ts +18 -0
- package/components/chart/src/doughnut-chart.component.d.ts +16 -0
- package/components/chart/src/line-chart.component.d.ts +18 -0
- package/components/chart/src/pie-chart.component.d.ts +16 -0
- package/components/code-editor/index.d.ts +1 -0
- package/components/code-editor/src/code-editor.component.d.ts +25 -0
- package/components/document-builder/index.d.ts +1 -0
- package/components/document-builder/src/document-builder.component.d.ts +13 -42
- package/components/document-builder/src/document-builder.model.d.ts +15 -12
- package/components/document-builder/src/plugins/block-space/block-space.plugin.d.ts +9 -0
- package/components/document-builder/src/plugins/ck-comment/ck-comment.plugin.d.ts +44 -0
- package/components/document-builder/src/plugins/ck-comment/ck-comment.plugin.model.d.ts +57 -0
- package/components/document-builder/src/plugins/heading/heading.plugin.d.ts +1 -0
- package/components/document-builder/src/plugins/highlight-range/highlight-range.plugin.d.ts +4 -0
- package/components/document-builder/src/plugins/image-custom/image-custom.plugin.d.ts +31 -0
- package/components/document-builder/src/plugins/index.d.ts +7 -2
- package/components/document-builder/src/plugins/page-orientation/page-orientation.plugin.d.ts +2 -2
- package/components/document-builder/src/plugins/paste-handler/filters/bookmark.d.ts +14 -0
- package/components/document-builder/src/plugins/paste-handler/filters/br.d.ts +15 -0
- package/components/document-builder/src/plugins/paste-handler/filters/image.d.ts +25 -0
- package/components/document-builder/src/plugins/paste-handler/filters/list.d.ts +29 -0
- package/components/document-builder/src/plugins/paste-handler/filters/parse.d.ts +35 -0
- package/components/document-builder/src/plugins/paste-handler/filters/removeboldwrapper.d.ts +15 -0
- package/components/document-builder/src/plugins/paste-handler/filters/removegooglesheetstag.d.ts +15 -0
- package/components/document-builder/src/plugins/paste-handler/filters/removeinvalidtablewidth.d.ts +15 -0
- package/components/document-builder/src/plugins/paste-handler/filters/removemsattributes.d.ts +15 -0
- package/components/document-builder/src/plugins/paste-handler/filters/removestyleblock.d.ts +15 -0
- package/components/document-builder/src/plugins/paste-handler/filters/removexmlns.d.ts +15 -0
- package/components/document-builder/src/plugins/paste-handler/filters/replacemsfootnotes.d.ts +54 -0
- package/components/document-builder/src/plugins/paste-handler/filters/replacetabswithinprewithspaces.d.ts +24 -0
- package/components/document-builder/src/plugins/paste-handler/filters/space.d.ts +27 -0
- package/components/document-builder/src/plugins/paste-handler/filters/table.d.ts +16 -0
- package/components/document-builder/src/plugins/paste-handler/filters/utils.d.ts +25 -0
- package/components/document-builder/src/plugins/paste-handler/index.d.ts +35 -0
- package/components/document-builder/src/plugins/paste-handler/normalizers/googledocsnormalizer.d.ts +31 -0
- package/components/document-builder/src/plugins/paste-handler/normalizers/googlesheetsnormalizer.d.ts +31 -0
- package/components/document-builder/src/plugins/paste-handler/normalizers/mswordnormalizer.d.ts +29 -0
- package/components/document-builder/src/plugins/paste-handler/types.d.ts +30 -0
- package/components/document-builder/src/plugins/table-custom/index.d.ts +34 -0
- package/components/document-builder/src/plugins/variable/variable.plugin.d.ts +39 -0
- package/components/editor/index.d.ts +3 -0
- package/components/editor/src/configurations/editor.configuration.d.ts +12 -0
- package/components/editor/src/configurations/index.d.ts +1 -0
- package/components/editor/src/editor.component.d.ts +42 -0
- package/components/editor/src/models/editor.model.d.ts +8 -0
- package/components/editor/src/models/image-upload.plugin.model.d.ts +20 -0
- package/components/editor/src/models/index.d.ts +2 -0
- package/components/editor/src/plugins/image-upload/image-upload.plugin.d.ts +22 -0
- package/components/editor/src/plugins/image-upload/utils/batch.utils.d.ts +14 -0
- package/components/editor/src/plugins/image-upload/utils/index.d.ts +3 -0
- package/components/editor/src/plugins/image-upload/utils/style.utils.d.ts +2 -0
- package/components/editor/src/plugins/image-upload/utils/validate.utils.d.ts +3 -0
- package/components/index.d.ts +6 -0
- package/components/mini-editor/index.d.ts +2 -0
- package/components/mini-editor/src/mini-editor.component.d.ts +91 -0
- package/components/mini-editor/src/mini-editor.model.d.ts +44 -0
- package/components/modal/index.d.ts +1 -1
- package/components/modal/src/modal.component.d.ts +26 -0
- package/components/section/index.d.ts +1 -0
- package/components/section/src/section-item/section-item.component.d.ts +7 -0
- package/components/section/src/section.component.d.ts +11 -11
- package/components/side-drawer/src/side-drawer.component.d.ts +11 -24
- package/components/tab-router/src/components/tab-router-item/tab-router-item.component.d.ts +4 -1
- package/components/tab-router/src/components/tab-router-outlet/tab-router-outlet.component.d.ts +3 -15
- package/components/table/index.d.ts +2 -0
- package/components/table/src/components/column-filter/column-filter.component.d.ts +3 -3
- package/components/table/src/components/column-title/column-title.component.d.ts +10 -0
- package/components/table/src/components/desktop-cell/desktop-cell.component.d.ts +18 -11
- package/components/table/src/components/desktop-cell/view/view.component.d.ts +24 -0
- package/components/table/src/components/external-filter/external-filter.component.d.ts +1 -1
- package/components/table/src/components/index.d.ts +1 -0
- package/components/table/src/components/selector-action/action-filter.pipe.d.ts +11 -10
- package/components/table/src/components/selector-action/selector-action.component.d.ts +5 -3
- package/components/table/src/directives/index.d.ts +4 -0
- package/components/table/src/directives/sd-table-cell-def.directive.d.ts +2 -3
- package/components/table/src/directives/sd-table-column-filter-def.directive.d.ts +8 -0
- package/components/table/src/directives/sd-table-expand-def.directive.d.ts +0 -1
- package/components/table/src/directives/sd-table-filter-def.directive.d.ts +4 -6
- package/components/table/src/directives/sd-table-footer-def.directive.d.ts +2 -3
- package/components/table/src/directives/sd-table-title-def.directive.d.ts +8 -0
- package/components/table/src/directives/sticky-shadow.directive.d.ts +17 -0
- package/components/table/src/models/table-column.model.d.ts +49 -40
- package/components/table/src/models/table-command.model.d.ts +7 -3
- package/components/table/src/models/table-item.model.d.ts +5 -4
- package/components/table/src/models/table-option-config.model.d.ts +3 -0
- package/components/table/src/models/table-option-export.model.d.ts +3 -2
- package/components/table/src/models/table-option-selector.model.d.ts +17 -10
- package/components/table/src/models/table-option.model.d.ts +15 -8
- package/components/table/src/services/index.d.ts +3 -0
- package/components/table/src/services/table-export/table-export.service.d.ts +26 -0
- package/components/table/src/services/table-filter/table-filter.model.d.ts +6 -5
- package/components/table/src/services/table-format/table-format.service.d.ts +16 -0
- package/components/table/src/table.component.d.ts +46 -53
- package/components/upload-file/src/configurations/upload-file.configuration.d.ts +34 -1
- package/components/upload-file/src/services/upload-file.service.d.ts +0 -1
- package/components/upload-file/src/upload-file.component.d.ts +52 -54
- package/components/view/index.d.ts +1 -0
- package/components/view/src/view.component.d.ts +16 -0
- package/components/workflow/src/models/form-generic-component.model.d.ts +5 -4
- package/components/workflow/src/models/form-generic-expression.model.d.ts +1 -0
- package/components/workflow/src/models/index.d.ts +1 -0
- package/components/workflow/src/pipes/html.pipe.d.ts +4 -4
- package/directives/index.d.ts +2 -0
- package/directives/src/sd-href.directive.d.ts +9 -0
- package/directives/src/sd-tooltip.directive.d.ts +26 -0
- package/fesm2022/sd-angular-core-components-anchor-v2.mjs +79 -154
- package/fesm2022/sd-angular-core-components-anchor-v2.mjs.map +1 -1
- package/fesm2022/sd-angular-core-components-avatar.mjs +103 -0
- package/fesm2022/sd-angular-core-components-avatar.mjs.map +1 -0
- package/fesm2022/sd-angular-core-components-badge.mjs +101 -91
- package/fesm2022/sd-angular-core-components-badge.mjs.map +1 -1
- package/fesm2022/sd-angular-core-components-button.mjs +70 -96
- package/fesm2022/sd-angular-core-components-button.mjs.map +1 -1
- package/fesm2022/sd-angular-core-components-chart.mjs +290 -0
- package/fesm2022/sd-angular-core-components-chart.mjs.map +1 -0
- package/fesm2022/sd-angular-core-components-code-editor.mjs +127 -0
- package/fesm2022/sd-angular-core-components-code-editor.mjs.map +1 -0
- package/fesm2022/sd-angular-core-components-document-builder.mjs +4005 -611
- package/fesm2022/sd-angular-core-components-document-builder.mjs.map +1 -1
- package/fesm2022/sd-angular-core-components-editor.mjs +933 -0
- package/fesm2022/sd-angular-core-components-editor.mjs.map +1 -0
- package/fesm2022/sd-angular-core-components-history.mjs +1 -1
- package/fesm2022/sd-angular-core-components-history.mjs.map +1 -1
- package/fesm2022/sd-angular-core-components-import-excel.mjs +1 -1
- package/fesm2022/sd-angular-core-components-import-excel.mjs.map +1 -1
- package/fesm2022/sd-angular-core-components-mini-editor.mjs +332 -0
- package/fesm2022/sd-angular-core-components-mini-editor.mjs.map +1 -0
- package/fesm2022/sd-angular-core-components-modal.mjs +63 -92
- package/fesm2022/sd-angular-core-components-modal.mjs.map +1 -1
- package/fesm2022/sd-angular-core-components-preview.mjs +1 -1
- package/fesm2022/sd-angular-core-components-preview.mjs.map +1 -1
- package/fesm2022/sd-angular-core-components-quick-action.mjs +2 -2
- package/fesm2022/sd-angular-core-components-quick-action.mjs.map +1 -1
- package/fesm2022/sd-angular-core-components-section.mjs +41 -43
- package/fesm2022/sd-angular-core-components-section.mjs.map +1 -1
- package/fesm2022/sd-angular-core-components-side-drawer.mjs +78 -84
- package/fesm2022/sd-angular-core-components-side-drawer.mjs.map +1 -1
- package/fesm2022/sd-angular-core-components-tab-router.mjs +151 -241
- package/fesm2022/sd-angular-core-components-tab-router.mjs.map +1 -1
- package/fesm2022/sd-angular-core-components-table.mjs +1394 -1254
- package/fesm2022/sd-angular-core-components-table.mjs.map +1 -1
- package/fesm2022/sd-angular-core-components-upload-file.mjs +390 -443
- package/fesm2022/sd-angular-core-components-upload-file.mjs.map +1 -1
- package/fesm2022/sd-angular-core-components-view.mjs +45 -0
- package/fesm2022/sd-angular-core-components-view.mjs.map +1 -0
- package/fesm2022/sd-angular-core-components-workflow.mjs +165 -168
- package/fesm2022/sd-angular-core-components-workflow.mjs.map +1 -1
- package/fesm2022/sd-angular-core-components.mjs +6 -0
- package/fesm2022/sd-angular-core-components.mjs.map +1 -1
- package/fesm2022/sd-angular-core-directives.mjs +286 -27
- package/fesm2022/sd-angular-core-directives.mjs.map +1 -1
- package/fesm2022/sd-angular-core-forms-autocomplete.mjs +289 -363
- package/fesm2022/sd-angular-core-forms-autocomplete.mjs.map +1 -1
- package/fesm2022/sd-angular-core-forms-chip-calendar.mjs +170 -189
- package/fesm2022/sd-angular-core-forms-chip-calendar.mjs.map +1 -1
- package/fesm2022/sd-angular-core-forms-chip.mjs +184 -194
- package/fesm2022/sd-angular-core-forms-chip.mjs.map +1 -1
- package/fesm2022/sd-angular-core-forms-date-range.mjs +180 -242
- package/fesm2022/sd-angular-core-forms-date-range.mjs.map +1 -1
- package/fesm2022/sd-angular-core-forms-date.mjs +178 -270
- package/fesm2022/sd-angular-core-forms-date.mjs.map +1 -1
- package/fesm2022/sd-angular-core-forms-datetime.mjs +177 -285
- package/fesm2022/sd-angular-core-forms-datetime.mjs.map +1 -1
- package/fesm2022/sd-angular-core-forms-input-number.mjs +210 -337
- package/fesm2022/sd-angular-core-forms-input-number.mjs.map +1 -1
- package/fesm2022/sd-angular-core-forms-input.mjs +169 -286
- package/fesm2022/sd-angular-core-forms-input.mjs.map +1 -1
- package/fesm2022/sd-angular-core-forms-radio.mjs +3 -2
- package/fesm2022/sd-angular-core-forms-radio.mjs.map +1 -1
- package/fesm2022/sd-angular-core-forms-select.mjs +390 -447
- package/fesm2022/sd-angular-core-forms-select.mjs.map +1 -1
- package/fesm2022/sd-angular-core-forms-textarea.mjs +167 -226
- package/fesm2022/sd-angular-core-forms-textarea.mjs.map +1 -1
- package/fesm2022/sd-angular-core-modules-authom.mjs +359 -0
- package/fesm2022/sd-angular-core-modules-authom.mjs.map +1 -0
- package/fesm2022/sd-angular-core-modules-keycloak.mjs +126 -0
- package/fesm2022/sd-angular-core-modules-keycloak.mjs.map +1 -0
- package/fesm2022/sd-angular-core-modules-layout.mjs +709 -456
- package/fesm2022/sd-angular-core-modules-layout.mjs.map +1 -1
- package/fesm2022/sd-angular-core-modules-permission.mjs +160 -74
- package/fesm2022/sd-angular-core-modules-permission.mjs.map +1 -1
- package/fesm2022/sd-angular-core-modules.mjs +2 -1
- package/fesm2022/sd-angular-core-modules.mjs.map +1 -1
- package/fesm2022/sd-angular-core-services-api.mjs +5 -10
- package/fesm2022/sd-angular-core-services-api.mjs.map +1 -1
- package/fesm2022/sd-angular-core-services-confirm.mjs +9 -7
- package/fesm2022/sd-angular-core-services-confirm.mjs.map +1 -1
- package/fesm2022/sd-angular-core-services-docx.mjs +173 -0
- package/fesm2022/sd-angular-core-services-docx.mjs.map +1 -0
- package/fesm2022/sd-angular-core-services-notify.mjs +2 -2
- package/fesm2022/sd-angular-core-services-notify.mjs.map +1 -1
- package/fesm2022/sd-angular-core-services.mjs +1 -0
- package/fesm2022/sd-angular-core-services.mjs.map +1 -1
- package/fesm2022/sd-angular-core-utilities-extensions.mjs +58 -80
- package/fesm2022/sd-angular-core-utilities-extensions.mjs.map +1 -1
- package/fesm2022/sd-angular-core-utilities-models.mjs +15 -1
- package/fesm2022/sd-angular-core-utilities-models.mjs.map +1 -1
- package/fesm2022/sd-angular-core.mjs +0 -1
- package/fesm2022/sd-angular-core.mjs.map +1 -1
- package/forms/autocomplete/src/autocomplete.component.d.ts +55 -55
- package/forms/chip/src/chip.component.d.ts +37 -40
- package/forms/chip-calendar/src/chip-calendar.component.d.ts +37 -38
- package/forms/date/src/date.component.d.ts +48 -46
- package/forms/date-range/src/date-range.component.d.ts +35 -34
- package/forms/datetime/src/datetime.component.d.ts +48 -49
- package/forms/input/src/input.component.d.ts +54 -57
- package/forms/input-number/src/input-number.component.d.ts +53 -54
- package/forms/select/src/select.component.d.ts +67 -64
- package/forms/textarea/src/textarea.component.d.ts +40 -43
- package/modules/authom/authom.configuration.d.ts +17 -0
- package/modules/authom/authom.interceptor.d.ts +3 -0
- package/modules/authom/authom.module.d.ts +16 -0
- package/modules/authom/authom.service.d.ts +32 -0
- package/modules/authom/index.d.ts +35 -0
- package/modules/index.d.ts +2 -1
- package/modules/keycloak/index.d.ts +4 -0
- package/modules/keycloak/keycloak.configuration.d.ts +11 -0
- package/modules/keycloak/keycloak.interceptor.d.ts +2 -0
- package/modules/keycloak/keycloak.module.d.ts +18 -0
- package/modules/keycloak/keycloak.service.d.ts +14 -0
- package/modules/layout/components/index.d.ts +2 -0
- package/modules/layout/components/layout-main/layout-main.component.d.ts +8 -12
- package/modules/layout/components/page/page.component.d.ts +5 -7
- package/modules/layout/components/sidebar-mobile-v1/components/sidebar/sidebar.component.d.ts +35 -0
- package/modules/layout/components/sidebar-mobile-v1/components/user/user.component.d.ts +24 -0
- package/modules/layout/components/sidebar-mobile-v1/main.component.d.ts +21 -0
- package/modules/layout/components/sidebar-v1/components/sidebar/sidebar.component.d.ts +22 -29
- package/modules/layout/components/sidebar-v1/components/user/user.component.d.ts +11 -17
- package/modules/layout/components/sidebar-v1/main.component.d.ts +14 -14
- package/modules/layout/configurations/layout.configuration.d.ts +46 -3
- package/modules/layout/modules/forbidden/pages/root/root.component.d.ts +3 -8
- package/modules/layout/modules/home/components/home-page/home-page.component.d.ts +2 -5
- package/modules/layout/modules/not-found/pages/root/root.component.d.ts +3 -8
- package/modules/layout/pipes/high-light-search.pipe.d.ts +1 -1
- package/modules/layout/services/index.d.ts +1 -0
- package/modules/layout/services/layout.service.d.ts +10 -0
- package/modules/layout/services/menu/menu.model.d.ts +4 -1
- package/modules/layout/services/storage/storage.service.d.ts +0 -3
- package/modules/permission/src/configurations/permission.configuration.d.ts +56 -2
- package/modules/permission/src/directives/permission.directive.d.ts +5 -8
- package/modules/permission/src/guards/permission.guard.d.ts +2 -1
- package/modules/permission/src/services/permission.service.d.ts +6 -9
- package/package.json +107 -79
- package/public-api.d.ts +0 -1
- package/sd-angular-core-19.0.0-beta.81.tgz +0 -0
- package/services/api/src/api.model.d.ts +6 -1
- package/services/confirm/src/lib/confirm.service.d.ts +5 -0
- package/services/docx/index.d.ts +1 -0
- package/services/docx/src/lib/docx.model.d.ts +9 -0
- package/services/docx/src/lib/docx.service.d.ts +13 -0
- package/services/docx/src/public-api.d.ts +2 -0
- package/services/index.d.ts +1 -0
- package/services/notify/index.d.ts +1 -0
- package/services/notify/src/notify.model.d.ts +1 -1
- package/services/notify/src/notify.service.d.ts +5 -5
- package/utilities/extensions/src/string.extension.d.ts +3 -0
- package/utilities/extensions/src/utility.extension.d.ts +1 -0
- package/utilities/models/index.d.ts +3 -0
- package/utilities/models/src/filter.model.d.ts +17 -4
- package/utilities/models/src/icon.model.d.ts +2 -0
- package/utilities/models/src/nested-key-of.model.d.ts +5 -0
- package/utilities/models/src/order.model.d.ts +2 -1
- package/utilities/models/src/paging.model.d.ts +2 -1
- package/utilities/models/src/pattern.model.d.ts +1 -1
- package/utilities/models/src/unwrap-signal.model.d.ts +6 -0
- package/components/document-builder/src/plugins/comment/comment.plugin.d.ts +0 -4
- package/components/document-builder/src/plugins/table-fit/table-fit.plugin.d.ts +0 -4
- package/components/modal/src/modal/modal.component.d.ts +0 -31
- package/components/table/src/components/desktop-cell-view/desktop-cell-view.component.d.ts +0 -14
- package/fesm2022/sd-angular-core-guards-permission.mjs +0 -155
- package/fesm2022/sd-angular-core-guards-permission.mjs.map +0 -1
- package/fesm2022/sd-angular-core-guards.mjs +0 -6
- package/fesm2022/sd-angular-core-guards.mjs.map +0 -1
- package/fesm2022/sd-angular-core-modules-oidc.mjs +0 -127
- package/fesm2022/sd-angular-core-modules-oidc.mjs.map +0 -1
- package/guards/index.d.ts +0 -1
- package/guards/permission/index.d.ts +0 -4
- package/guards/permission/src/configurations/index.d.ts +0 -1
- package/guards/permission/src/configurations/permission.configuration.d.ts +0 -8
- package/guards/permission/src/directives/index.d.ts +0 -1
- package/guards/permission/src/directives/permission.directive.d.ts +0 -12
- package/guards/permission/src/guards/index.d.ts +0 -1
- package/guards/permission/src/guards/permission.guard.d.ts +0 -13
- package/guards/permission/src/services/index.d.ts +0 -1
- package/guards/permission/src/services/permission.service.d.ts +0 -15
- package/modules/oidc/dynamic-sts.loader.d.ts +0 -11
- package/modules/oidc/index.d.ts +0 -2
- package/modules/oidc/oidc.configuration.d.ts +0 -11
- package/modules/oidc/oidc.module.d.ts +0 -14
- package/sd-angular-core-19.0.0-beta.8.tgz +0 -0
|
@@ -1,67 +1,144 @@
|
|
|
1
1
|
import * as i0 from '@angular/core';
|
|
2
|
-
import { InjectionToken,
|
|
2
|
+
import { InjectionToken, inject, Injectable, TemplateRef, ViewContainerRef, input, effect, Directive, Inject } from '@angular/core';
|
|
3
|
+
import { SdCacheService } from '@sd-angular/core/services/cache';
|
|
3
4
|
import { ArrayUtilities } from '@sd-angular/core/utilities/extensions';
|
|
4
5
|
import { SdResolveMaybeAsync } from '@sd-angular/core/utilities';
|
|
5
|
-
import * as i1 from '@sd-angular/core/services/cache';
|
|
6
6
|
|
|
7
|
+
/**
|
|
8
|
+
* InjectionToken cho cấu hình permission.
|
|
9
|
+
*
|
|
10
|
+
* Ví dụ provider:
|
|
11
|
+
* {
|
|
12
|
+
* provide: SD_PERMISSION_CONFIGURATION,
|
|
13
|
+
* useValue: {
|
|
14
|
+
* disabled: false,
|
|
15
|
+
* loadPermissions: () => ['SAMPLE_C_EMPLOYEE_VIEW'],
|
|
16
|
+
* onForbiden: () => router.navigateByUrl('/layout/forbidden')
|
|
17
|
+
* }
|
|
18
|
+
* }
|
|
19
|
+
*/
|
|
7
20
|
const SD_PERMISSION_CONFIGURATION = new InjectionToken('sd-permission.configuration');
|
|
8
21
|
|
|
9
22
|
class SdPermissionService {
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
#
|
|
13
|
-
#
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
default: [],
|
|
21
|
-
});
|
|
23
|
+
#permissionMapByKey = {};
|
|
24
|
+
#configuration = inject(SD_PERMISSION_CONFIGURATION);
|
|
25
|
+
#cacheService = inject(SdCacheService);
|
|
26
|
+
#permissionsByKey = this.#cacheService.create('212a51fa-38d5-43b2-bd46-922d85950ba3', {
|
|
27
|
+
type: 'session',
|
|
28
|
+
default: {},
|
|
29
|
+
});
|
|
30
|
+
#loadedKeys = new Set();
|
|
31
|
+
constructor() {
|
|
32
|
+
this.#validateDuplicateConfigKeys();
|
|
22
33
|
}
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
34
|
+
#getConfigurations = () => {
|
|
35
|
+
const config = this.#configuration;
|
|
36
|
+
if (!config) {
|
|
37
|
+
return [];
|
|
38
|
+
}
|
|
39
|
+
return Array.isArray(config) ? config : [config];
|
|
40
|
+
};
|
|
41
|
+
#normalizeKey = (key) => {
|
|
42
|
+
return key === undefined ? '__undefined__' : key;
|
|
43
|
+
};
|
|
44
|
+
#validateDuplicateConfigKeys = () => {
|
|
45
|
+
const seen = new Set();
|
|
46
|
+
for (const config of this.#getConfigurations()) {
|
|
47
|
+
const normalizedKey = this.#normalizeKey(config.key);
|
|
48
|
+
if (seen.has(normalizedKey)) {
|
|
49
|
+
const keyLabel = config.key === undefined ? 'undefined' : config.key;
|
|
50
|
+
throw new Error(`[Permission] Duplicate permission configuration key: ${keyLabel}`);
|
|
40
51
|
}
|
|
52
|
+
seen.add(normalizedKey);
|
|
41
53
|
}
|
|
42
54
|
};
|
|
43
|
-
|
|
55
|
+
#getConfigurationByKey = (key) => {
|
|
56
|
+
return this.#getConfigurations().find(config => config.key === key);
|
|
57
|
+
};
|
|
58
|
+
#getEffectivePermissionKey = (key) => {
|
|
59
|
+
if (this.#getConfigurationByKey(key)) {
|
|
60
|
+
return key;
|
|
61
|
+
}
|
|
62
|
+
// Portal-level config uses key = undefined and acts as default fallback
|
|
63
|
+
if (key !== undefined && this.#getConfigurationByKey(undefined)) {
|
|
64
|
+
return undefined;
|
|
65
|
+
}
|
|
66
|
+
return key;
|
|
67
|
+
};
|
|
68
|
+
#setPermissionsForKey = (normalizedKey, permissions) => {
|
|
69
|
+
const distinctPermissions = ArrayUtilities.distinct(permissions || []);
|
|
70
|
+
const current = this.#permissionsByKey.get() || {};
|
|
71
|
+
this.#permissionsByKey.set({
|
|
72
|
+
...current,
|
|
73
|
+
[normalizedKey]: distinctPermissions,
|
|
74
|
+
});
|
|
75
|
+
const permissionMap = {};
|
|
76
|
+
distinctPermissions.forEach(permission => {
|
|
77
|
+
permissionMap[permission] = true;
|
|
78
|
+
});
|
|
79
|
+
this.#permissionMapByKey[normalizedKey] = permissionMap;
|
|
80
|
+
};
|
|
81
|
+
loadPermissions = async (key) => {
|
|
82
|
+
const effectiveKey = this.#getEffectivePermissionKey(key);
|
|
83
|
+
const normalizedKey = this.#normalizeKey(effectiveKey);
|
|
84
|
+
if (this.#loadedKeys.has(normalizedKey)) {
|
|
85
|
+
return this.#permissionsByKey.get()?.[normalizedKey] || [];
|
|
86
|
+
}
|
|
87
|
+
const configuration = this.#getConfigurationByKey(effectiveKey);
|
|
88
|
+
if (!configuration) {
|
|
89
|
+
this.#setPermissionsForKey(normalizedKey, []);
|
|
90
|
+
this.#loadedKeys.add(normalizedKey);
|
|
91
|
+
return [];
|
|
92
|
+
}
|
|
93
|
+
try {
|
|
94
|
+
const permissions = await SdResolveMaybeAsync(configuration.loadPermissions());
|
|
95
|
+
this.#setPermissionsForKey(normalizedKey, permissions || []);
|
|
96
|
+
}
|
|
97
|
+
catch (err) {
|
|
98
|
+
console.error(err);
|
|
99
|
+
this.#setPermissionsForKey(normalizedKey, []);
|
|
100
|
+
}
|
|
101
|
+
finally {
|
|
102
|
+
this.#loadedKeys.add(normalizedKey);
|
|
103
|
+
}
|
|
104
|
+
return this.#permissionsByKey.get()?.[normalizedKey] || [];
|
|
105
|
+
};
|
|
106
|
+
loadAllPermissions = async () => {
|
|
107
|
+
const configurations = this.#getConfigurations();
|
|
108
|
+
if (!configurations.length) {
|
|
109
|
+
await this.loadPermissions(undefined);
|
|
110
|
+
return;
|
|
111
|
+
}
|
|
112
|
+
await Promise.all(configurations.map(config => this.loadPermissions(config.key)));
|
|
113
|
+
};
|
|
114
|
+
hasPermission = (permission, key) => {
|
|
44
115
|
if (!permission?.toString()) {
|
|
45
116
|
return true;
|
|
46
117
|
}
|
|
47
|
-
|
|
118
|
+
const effectiveKey = this.#getEffectivePermissionKey(key);
|
|
119
|
+
const configuration = this.#getConfigurationByKey(effectiveKey);
|
|
120
|
+
if (configuration?.disabled) {
|
|
48
121
|
return true;
|
|
49
122
|
}
|
|
123
|
+
const normalizedKey = this.#normalizeKey(effectiveKey);
|
|
124
|
+
const permissionMap = this.#permissionMapByKey[normalizedKey] || {};
|
|
50
125
|
const permissions = Array.isArray(permission) ? permission : [permission];
|
|
51
|
-
return permissions.some(
|
|
126
|
+
return permissions.some(val => permissionMap[val]);
|
|
52
127
|
};
|
|
53
|
-
getToken = async () => {
|
|
54
|
-
|
|
128
|
+
getToken = async (key) => {
|
|
129
|
+
const effectiveKey = this.#getEffectivePermissionKey(key);
|
|
130
|
+
const getToken = this.#getConfigurationByKey(effectiveKey)?.getToken;
|
|
131
|
+
if (!getToken) {
|
|
55
132
|
throw new Error('[Permission] Method getToken');
|
|
56
133
|
}
|
|
57
|
-
const token =
|
|
58
|
-
if (token
|
|
59
|
-
return
|
|
134
|
+
const token = await SdResolveMaybeAsync(getToken());
|
|
135
|
+
if (token === '') {
|
|
136
|
+
return undefined;
|
|
60
137
|
}
|
|
61
138
|
return token;
|
|
62
139
|
};
|
|
63
|
-
decodeToken = async () => {
|
|
64
|
-
const token = await this.getToken();
|
|
140
|
+
decodeToken = async (key) => {
|
|
141
|
+
const token = await this.getToken(key);
|
|
65
142
|
if (!token) {
|
|
66
143
|
return null;
|
|
67
144
|
}
|
|
@@ -79,49 +156,46 @@ class SdPermissionService {
|
|
|
79
156
|
return null;
|
|
80
157
|
}
|
|
81
158
|
};
|
|
82
|
-
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.17", ngImport: i0, type: SdPermissionService, deps: [
|
|
159
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.17", ngImport: i0, type: SdPermissionService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
|
|
83
160
|
static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "19.2.17", ngImport: i0, type: SdPermissionService, providedIn: 'root' });
|
|
84
161
|
}
|
|
85
162
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.17", ngImport: i0, type: SdPermissionService, decorators: [{
|
|
86
163
|
type: Injectable,
|
|
87
164
|
args: [{ providedIn: 'root' }]
|
|
88
|
-
}], ctorParameters: () => [
|
|
89
|
-
type: Inject,
|
|
90
|
-
args: [SD_PERMISSION_CONFIGURATION]
|
|
91
|
-
}] }, { type: i1.SdCacheService }] });
|
|
165
|
+
}], ctorParameters: () => [] });
|
|
92
166
|
|
|
93
167
|
class SdPermissionDirective {
|
|
94
|
-
templateRef;
|
|
95
|
-
viewContainerRef;
|
|
96
|
-
permissionService;
|
|
168
|
+
#templateRef = inject(TemplateRef);
|
|
169
|
+
#viewContainerRef = inject(ViewContainerRef);
|
|
170
|
+
#permissionService = inject(SdPermissionService);
|
|
97
171
|
// Nếu là mảng thì chỉ cần có 1 permission trong mảng đó xem như có quyền
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
172
|
+
sdPermission = input(undefined);
|
|
173
|
+
sdPermissionKey = input(undefined);
|
|
174
|
+
constructor() {
|
|
175
|
+
effect(() => {
|
|
176
|
+
const permission = this.sdPermission();
|
|
177
|
+
const permissionKey = this.sdPermissionKey();
|
|
178
|
+
this.#viewContainerRef.clear();
|
|
179
|
+
// Nếu không gắn permission thì render
|
|
180
|
+
if (!permission?.toString()) {
|
|
181
|
+
this.#viewContainerRef.createEmbeddedView(this.#templateRef);
|
|
182
|
+
return;
|
|
183
|
+
}
|
|
184
|
+
// Kiểm tra permission theo key (nếu có)
|
|
185
|
+
if (this.#permissionService.hasPermission(permission, permissionKey)) {
|
|
186
|
+
this.#viewContainerRef.createEmbeddedView(this.#templateRef);
|
|
187
|
+
}
|
|
188
|
+
});
|
|
113
189
|
}
|
|
114
|
-
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.17", ngImport: i0, type: SdPermissionDirective, deps: [
|
|
115
|
-
static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "
|
|
190
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.17", ngImport: i0, type: SdPermissionDirective, deps: [], target: i0.ɵɵFactoryTarget.Directive });
|
|
191
|
+
static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "17.1.0", version: "19.2.17", type: SdPermissionDirective, isStandalone: true, selector: "[sdPermission]", inputs: { sdPermission: { classPropertyName: "sdPermission", publicName: "sdPermission", isSignal: true, isRequired: false, transformFunction: null }, sdPermissionKey: { classPropertyName: "sdPermissionKey", publicName: "sdPermissionKey", isSignal: true, isRequired: false, transformFunction: null } }, ngImport: i0 });
|
|
116
192
|
}
|
|
117
193
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.17", ngImport: i0, type: SdPermissionDirective, decorators: [{
|
|
118
194
|
type: Directive,
|
|
119
195
|
args: [{
|
|
120
196
|
selector: '[sdPermission]',
|
|
121
197
|
}]
|
|
122
|
-
}], ctorParameters: () => [
|
|
123
|
-
type: Input
|
|
124
|
-
}] } });
|
|
198
|
+
}], ctorParameters: () => [] });
|
|
125
199
|
|
|
126
200
|
class SdPermissionGuard {
|
|
127
201
|
configuration;
|
|
@@ -130,18 +204,30 @@ class SdPermissionGuard {
|
|
|
130
204
|
this.configuration = configuration;
|
|
131
205
|
this.permissionService = permissionService;
|
|
132
206
|
}
|
|
207
|
+
#getConfigurations = () => {
|
|
208
|
+
const config = this.configuration;
|
|
209
|
+
if (!config) {
|
|
210
|
+
return [];
|
|
211
|
+
}
|
|
212
|
+
return Array.isArray(config) ? config : [config];
|
|
213
|
+
};
|
|
133
214
|
canActivate = async (next, state) => {
|
|
134
|
-
//
|
|
135
|
-
await this.permissionService.
|
|
215
|
+
// Guard ở layer portal: preload toàn bộ permission theo tất cả key đã cấu hình
|
|
216
|
+
await this.permissionService.loadAllPermissions().catch(console.error);
|
|
136
217
|
return true;
|
|
137
218
|
};
|
|
138
219
|
canActivateChild = async (activatedRoute, state) => {
|
|
139
220
|
const permission = activatedRoute.data['permission'];
|
|
140
|
-
|
|
221
|
+
const permissionKey = activatedRoute.data?.['permissionKey'];
|
|
222
|
+
if (this.permissionService.hasPermission(permission, permissionKey)) {
|
|
141
223
|
return true;
|
|
142
224
|
}
|
|
143
|
-
|
|
144
|
-
|
|
225
|
+
const configurations = this.#getConfigurations();
|
|
226
|
+
const onForbiden = configurations
|
|
227
|
+
.filter(config => config.key === permissionKey || (permissionKey !== undefined && config.key === undefined))
|
|
228
|
+
.map(config => config.onForbiden)
|
|
229
|
+
.find(val => !!val);
|
|
230
|
+
onForbiden?.();
|
|
145
231
|
return false;
|
|
146
232
|
};
|
|
147
233
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.17", ngImport: i0, type: SdPermissionGuard, deps: [{ token: SD_PERMISSION_CONFIGURATION }, { token: SdPermissionService }], target: i0.ɵɵFactoryTarget.Injectable });
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"sd-angular-core-modules-permission.mjs","sources":["../../../projects/sd-angular/modules/permission/src/configurations/permission.configuration.ts","../../../projects/sd-angular/modules/permission/src/services/permission.service.ts","../../../projects/sd-angular/modules/permission/src/directives/permission.directive.ts","../../../projects/sd-angular/modules/permission/src/guards/permission.guard.ts","../../../projects/sd-angular/modules/permission/sd-angular-core-modules-permission.ts"],"sourcesContent":["import { InjectionToken } from '@angular/core';\r\nimport { SdMaybeAsync } from '@sd-angular/core/utilities';\r\n\r\nexport interface ISdPermissionConfiguration {\r\n disabled?: boolean; // Vô hiệu việc kiểm tra permission, mục đích để test chức năng khi chưa có permisison\r\n loadPermissions: () => SdMaybeAsync<string[]>;\r\n onForbiden?: () => void; // Xử lý khi không có quyền truy cập vào URL\r\n getToken?: () => Promise<string | undefined | null> | string | undefined | null; // Lấy thông tin token\r\n}\r\n\r\nexport const SD_PERMISSION_CONFIGURATION = new InjectionToken<ISdPermissionConfiguration>('sd-permission.configuration');\r\n","import { Inject, Injectable } from '@angular/core';\r\nimport { SdCache, SdCacheService } from '@sd-angular/core/services/cache';\r\nimport { ArrayUtilities } from '@sd-angular/core/utilities/extensions';\r\nimport { ISdPermissionConfiguration, SD_PERMISSION_CONFIGURATION } from '../configurations';\r\nimport { SdResolveMaybeAsync } from '@sd-angular/core/utilities';\r\n\r\n@Injectable({ providedIn: 'root' })\r\nexport class SdPermissionService {\r\n #permission: Record<string, boolean> = {};\r\n #permissions: SdCache<string[]>;\r\n #loaded = false;\r\n constructor(\r\n @Inject(SD_PERMISSION_CONFIGURATION) private configuration: ISdPermissionConfiguration,\r\n private cacheService: SdCacheService\r\n ) {\r\n this.#permissions = this.cacheService.create<string[]>('212a51fa-38d5-43b2-bd46-922d85950ba3', {\r\n type: 'session',\r\n default: [],\r\n });\r\n }\r\n\r\n loadPermissions = async () => {\r\n if (!this.#loaded) {\r\n try {\r\n // Trả về Promise<string[]> nhưng chấp nhận mọi kiểu MaybeAsync\r\n const permissions: string[] = await SdResolveMaybeAsync(this.configuration.loadPermissions());\r\n const distinctPermissions = ArrayUtilities.distinct(permissions);\r\n this.#permissions.set(ArrayUtilities.distinct(permissions));\r\n // Chuyển sang dạng map để kiểm tra nhanh hơn\r\n this.#permission = {};\r\n distinctPermissions.forEach(p => (this.#permission[p] = true));\r\n this.#loaded = true;\r\n } catch (err) {\r\n console.error(err);\r\n this.#permissions.set([]);\r\n this.#permission = {};\r\n this.#loaded = true;\r\n }\r\n }\r\n };\r\n\r\n hasPermission = (permission: string | string[]) => {\r\n if (!permission?.toString()) {\r\n return true;\r\n }\r\n if (this.configuration.disabled) {\r\n return true;\r\n }\r\n const permissions = Array.isArray(permission) ? permission : [permission];\r\n return permissions.some(permission => this.#permission[permission]);\r\n };\r\n\r\n getToken = async () => {\r\n if (!this.configuration.getToken) {\r\n throw new Error('[Permission] Method getToken');\r\n }\r\n const token = this.configuration.getToken();\r\n if (token instanceof Promise) {\r\n return await token;\r\n }\r\n return token;\r\n };\r\n\r\n decodeToken = async <T>(): Promise<T | null> => {\r\n const token = await this.getToken();\r\n if (!token) {\r\n return null;\r\n }\r\n try {\r\n const payload = token.split('.')[1];\r\n const base64 = payload.replace(/-/g, '+').replace(/_/g, '/');\r\n const jsonPayload = decodeURIComponent(\r\n atob(base64)\r\n .split('')\r\n .map(c => '%' + ('00' + c.charCodeAt(0).toString(16)).slice(-2))\r\n .join('')\r\n );\r\n return JSON.parse(jsonPayload);\r\n } catch (error) {\r\n console.error('Invalid token', error);\r\n return null;\r\n }\r\n };\r\n}\r\n","import { Directive, Input, TemplateRef, ViewContainerRef } from '@angular/core';\r\nimport { SdPermissionService } from '../services';\r\n\r\n@Directive({\r\n selector: '[sdPermission]',\r\n})\r\nexport class SdPermissionDirective {\r\n // Nếu là mảng thì chỉ cần có 1 permission trong mảng đó xem như có quyền\r\n @Input() set sdPermission(permission: string | string[] | undefined | null) {\r\n // Nếu không gắn permisison thì render\r\n if (!permission?.toString()) {\r\n this.viewContainerRef.createEmbeddedView(this.templateRef);\r\n return;\r\n }\r\n // Kiểm tra permisison\r\n if (this.permissionService.hasPermission(permission)) {\r\n this.viewContainerRef.createEmbeddedView(this.templateRef);\r\n }\r\n }\r\n\r\n constructor(\r\n private templateRef: TemplateRef<any>,\r\n private viewContainerRef: ViewContainerRef,\r\n private permissionService: SdPermissionService\r\n ) {}\r\n}\r\n","import { Inject, Injectable } from '@angular/core';\r\nimport { ActivatedRouteSnapshot, CanActivate, CanActivateChild, RouterStateSnapshot } from '@angular/router';\r\nimport { ISdPermissionConfiguration, SD_PERMISSION_CONFIGURATION } from '../configurations';\r\nimport { SdPermissionService } from '../services';\r\n\r\n@Injectable({ providedIn: 'root' })\r\nexport class SdPermissionGuard implements CanActivate, CanActivateChild {\r\n constructor(\r\n @Inject(SD_PERMISSION_CONFIGURATION)\r\n private configuration: ISdPermissionConfiguration,\r\n private permissionService: SdPermissionService\r\n ) {}\r\n\r\n canActivate = async (next: ActivatedRouteSnapshot, state: RouterStateSnapshot) => {\r\n // Đảm bảo permission đã được loaded\r\n await this.permissionService.loadPermissions().catch(console.error);\r\n return true;\r\n };\r\n\r\n canActivateChild = async (activatedRoute: ActivatedRouteSnapshot, state: RouterStateSnapshot) => {\r\n const permission = activatedRoute.data['permission'];\r\n if (this.permissionService.hasPermission(permission)) {\r\n return true;\r\n }\r\n //\r\n this.configuration?.onForbiden?.();\r\n return false;\r\n };\r\n}\r\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './index';\n"],"names":["i1.SdPermissionService"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"sd-angular-core-modules-permission.mjs","sources":["../../../projects/sd-angular/modules/permission/src/configurations/permission.configuration.ts","../../../projects/sd-angular/modules/permission/src/services/permission.service.ts","../../../projects/sd-angular/modules/permission/src/directives/permission.directive.ts","../../../projects/sd-angular/modules/permission/src/guards/permission.guard.ts","../../../projects/sd-angular/modules/permission/sd-angular-core-modules-permission.ts"],"sourcesContent":["import { InjectionToken } from '@angular/core';\r\nimport { SdMaybeAsync } from '@sd-angular/core/utilities';\r\n\r\n/**\r\n * Cấu hình trung tâm cho module permission.\r\n *\r\n * Luồng hoạt động chính:\r\n * 1. `loadPermissions(key?)` ở service được gọi để lấy danh sách mã quyền theo từng `key` cấu hình.\r\n * 2. Guard/service đối chiếu mã quyền theo route metadata.\r\n * 3. Khi không đủ quyền, callback `onForbiden()` sẽ được gọi (nếu có).\r\n *\r\n * Lưu ý:\r\n * - `SD_PERMISSION_CONFIGURATION` hỗ trợ cả cấu hình đơn và mảng cấu hình (`multi: true`).\r\n * - Nếu cần tạm bỏ qua kiểm tra quyền (POC/UAT cục bộ), đặt `disabled = true`.\r\n */\r\nexport interface ISdPermissionConfiguration {\r\n /**\r\n * Khóa định danh cấu hình.\r\n * Dùng để phân biệt khi hệ thống mở rộng theo nhiều profile permission.\r\n *\r\n * Lưu ý: `undefined` cũng được xem là một key hợp lệ (cấu hình mặc định).\r\n */\r\n key?: string;\r\n\r\n /**\r\n * Bật/tắt kiểm tra permission toàn cục.\r\n * - `true`: bỏ qua kiểm tra quyền.\r\n * - `false | undefined`: kiểm tra quyền theo cấu hình route.\r\n */\r\n disabled?: boolean;\r\n\r\n /**\r\n * Trả về danh sách mã quyền của user hiện tại.\r\n * Có thể đồng bộ hoặc bất đồng bộ.\r\n *\r\n * Ví dụ giá trị trả về:\r\n * - `['PRODUCT_C_EMPLOYEE_VIEW', 'PRODUCT_C_EMPLOYEE_UPDATE']`\r\n */\r\n loadPermissions: () => SdMaybeAsync<string[]>;\r\n\r\n /**\r\n * Callback xử lý khi user không có quyền truy cập URL hiện tại.\r\n * Thường dùng để điều hướng sang trang forbidden hoặc hiển thị thông báo.\r\n *\r\n * Giữ nguyên tên `onForbiden` để tương thích API hiện tại.\r\n */\r\n onForbiden?: () => void;\r\n\r\n /**\r\n * Cung cấp access token hiện tại cho các tác vụ liên quan permission.\r\n * Hỗ trợ trả về đồng bộ, Promise hoặc Observable.\r\n */\r\n getToken?: () => SdMaybeAsync<string | undefined | null>;\r\n}\r\n\r\n/**\r\n * InjectionToken cho cấu hình permission.\r\n *\r\n * Ví dụ provider:\r\n * {\r\n * provide: SD_PERMISSION_CONFIGURATION,\r\n * useValue: {\r\n * disabled: false,\r\n * loadPermissions: () => ['SAMPLE_C_EMPLOYEE_VIEW'],\r\n * onForbiden: () => router.navigateByUrl('/layout/forbidden')\r\n * }\r\n * }\r\n */\r\nexport const SD_PERMISSION_CONFIGURATION =\r\n new InjectionToken<ISdPermissionConfiguration | ISdPermissionConfiguration[]>('sd-permission.configuration');\r\n","import { inject, Injectable } from '@angular/core';\r\nimport { SdCache, SdCacheService } from '@sd-angular/core/services/cache';\r\nimport { ArrayUtilities } from '@sd-angular/core/utilities/extensions';\r\nimport { ISdPermissionConfiguration, SD_PERMISSION_CONFIGURATION } from '../configurations';\r\nimport { SdMaybeAsync, SdResolveMaybeAsync } from '@sd-angular/core/utilities';\r\n\r\n@Injectable({ providedIn: 'root' })\r\nexport class SdPermissionService {\r\n #permissionMapByKey: Record<string, Record<string, boolean>> = {};\r\n readonly #configuration = inject<ISdPermissionConfiguration | ISdPermissionConfiguration[]>(SD_PERMISSION_CONFIGURATION);\r\n readonly #cacheService = inject(SdCacheService);\r\n #permissionsByKey: SdCache<Record<string, string[]>> = this.#cacheService.create<Record<string, string[]>>('212a51fa-38d5-43b2-bd46-922d85950ba3', {\r\n type: 'session',\r\n default: {},\r\n });\r\n readonly #loadedKeys = new Set<string>();\r\n\r\n constructor() {\r\n this.#validateDuplicateConfigKeys();\r\n }\r\n\r\n #getConfigurations = (): ISdPermissionConfiguration[] => {\r\n const config = this.#configuration;\r\n if (!config) {\r\n return [];\r\n }\r\n return Array.isArray(config) ? config : [config];\r\n };\r\n\r\n #normalizeKey = (key?: string): string => {\r\n return key === undefined ? '__undefined__' : key;\r\n };\r\n\r\n #validateDuplicateConfigKeys = (): void => {\r\n const seen = new Set<string>();\r\n for (const config of this.#getConfigurations()) {\r\n const normalizedKey = this.#normalizeKey(config.key);\r\n if (seen.has(normalizedKey)) {\r\n const keyLabel = config.key === undefined ? 'undefined' : config.key;\r\n throw new Error(`[Permission] Duplicate permission configuration key: ${keyLabel}`);\r\n }\r\n seen.add(normalizedKey);\r\n }\r\n };\r\n\r\n #getConfigurationByKey = (key?: string): ISdPermissionConfiguration | undefined => {\r\n return this.#getConfigurations().find(config => config.key === key);\r\n };\r\n\r\n #getEffectivePermissionKey = (key?: string): string | undefined => {\r\n if (this.#getConfigurationByKey(key)) {\r\n return key;\r\n }\r\n\r\n // Portal-level config uses key = undefined and acts as default fallback\r\n if (key !== undefined && this.#getConfigurationByKey(undefined)) {\r\n return undefined;\r\n }\r\n\r\n return key;\r\n };\r\n\r\n #setPermissionsForKey = (normalizedKey: string, permissions: string[]): void => {\r\n const distinctPermissions = ArrayUtilities.distinct(permissions || []);\r\n const current = this.#permissionsByKey.get() || {};\r\n this.#permissionsByKey.set({\r\n ...current,\r\n [normalizedKey]: distinctPermissions,\r\n });\r\n\r\n const permissionMap: Record<string, boolean> = {};\r\n distinctPermissions.forEach(permission => {\r\n permissionMap[permission] = true;\r\n });\r\n this.#permissionMapByKey[normalizedKey] = permissionMap;\r\n };\r\n\r\n loadPermissions = async (key?: string): Promise<string[]> => {\r\n const effectiveKey = this.#getEffectivePermissionKey(key);\r\n const normalizedKey = this.#normalizeKey(effectiveKey);\r\n if (this.#loadedKeys.has(normalizedKey)) {\r\n return this.#permissionsByKey.get()?.[normalizedKey] || [];\r\n }\r\n\r\n const configuration = this.#getConfigurationByKey(effectiveKey);\r\n if (!configuration) {\r\n this.#setPermissionsForKey(normalizedKey, []);\r\n this.#loadedKeys.add(normalizedKey);\r\n return [];\r\n }\r\n\r\n try {\r\n const permissions: string[] = await SdResolveMaybeAsync(configuration.loadPermissions());\r\n this.#setPermissionsForKey(normalizedKey, permissions || []);\r\n } catch (err) {\r\n console.error(err);\r\n this.#setPermissionsForKey(normalizedKey, []);\r\n } finally {\r\n this.#loadedKeys.add(normalizedKey);\r\n }\r\n\r\n return this.#permissionsByKey.get()?.[normalizedKey] || [];\r\n };\r\n\r\n loadAllPermissions = async (): Promise<void> => {\r\n const configurations = this.#getConfigurations();\r\n if (!configurations.length) {\r\n await this.loadPermissions(undefined);\r\n return;\r\n }\r\n\r\n await Promise.all(configurations.map(config => this.loadPermissions(config.key)));\r\n };\r\n\r\n hasPermission = (permission: string | string[], key?: string) => {\r\n if (!permission?.toString()) {\r\n return true;\r\n }\r\n\r\n const effectiveKey = this.#getEffectivePermissionKey(key);\r\n const configuration = this.#getConfigurationByKey(effectiveKey);\r\n if (configuration?.disabled) {\r\n return true;\r\n }\r\n\r\n const normalizedKey = this.#normalizeKey(effectiveKey);\r\n const permissionMap = this.#permissionMapByKey[normalizedKey] || {};\r\n const permissions = Array.isArray(permission) ? permission : [permission];\r\n return permissions.some(val => permissionMap[val]);\r\n };\r\n\r\n getToken = async (key?: string) => {\r\n const effectiveKey = this.#getEffectivePermissionKey(key);\r\n const getToken = this.#getConfigurationByKey(effectiveKey)?.getToken as (() => SdMaybeAsync<string | undefined | null>) | undefined;\r\n if (!getToken) {\r\n throw new Error('[Permission] Method getToken');\r\n }\r\n\r\n const token = await SdResolveMaybeAsync(getToken());\r\n if (token === '') {\r\n return undefined;\r\n }\r\n return token;\r\n };\r\n\r\n decodeToken = async <T>(key?: string): Promise<T | null> => {\r\n const token = await this.getToken(key);\r\n if (!token) {\r\n return null;\r\n }\r\n try {\r\n const payload = token.split('.')[1];\r\n const base64 = payload.replace(/-/g, '+').replace(/_/g, '/');\r\n const jsonPayload = decodeURIComponent(\r\n atob(base64)\r\n .split('')\r\n .map(c => '%' + ('00' + c.charCodeAt(0).toString(16)).slice(-2))\r\n .join('')\r\n );\r\n return JSON.parse(jsonPayload);\r\n } catch (error) {\r\n console.error('Invalid token', error);\r\n return null;\r\n }\r\n };\r\n}\r\n","import { Directive, effect, inject, input, TemplateRef, ViewContainerRef } from '@angular/core';\r\nimport { SdPermissionService } from '../services';\r\n\r\n@Directive({\r\n selector: '[sdPermission]',\r\n})\r\nexport class SdPermissionDirective {\r\n readonly #templateRef = inject<TemplateRef<any>>(TemplateRef);\r\n readonly #viewContainerRef = inject(ViewContainerRef);\r\n readonly #permissionService = inject(SdPermissionService);\r\n\r\n // Nếu là mảng thì chỉ cần có 1 permission trong mảng đó xem như có quyền\r\n readonly sdPermission = input<string | string[] | undefined | null>(undefined);\r\n readonly sdPermissionKey = input<string | undefined>(undefined);\r\n\r\n constructor() {\r\n effect(() => {\r\n const permission = this.sdPermission();\r\n const permissionKey = this.sdPermissionKey();\r\n\r\n this.#viewContainerRef.clear();\r\n\r\n // Nếu không gắn permission thì render\r\n if (!permission?.toString()) {\r\n this.#viewContainerRef.createEmbeddedView(this.#templateRef);\r\n return;\r\n }\r\n\r\n // Kiểm tra permission theo key (nếu có)\r\n if (this.#permissionService.hasPermission(permission, permissionKey)) {\r\n this.#viewContainerRef.createEmbeddedView(this.#templateRef);\r\n }\r\n });\r\n }\r\n}\r\n","import { Inject, Injectable } from '@angular/core';\r\nimport { ActivatedRouteSnapshot, CanActivate, CanActivateChild, RouterStateSnapshot } from '@angular/router';\r\nimport { ISdPermissionConfiguration, SD_PERMISSION_CONFIGURATION } from '../configurations';\r\nimport { SdPermissionService } from '../services';\r\n\r\n@Injectable({ providedIn: 'root' })\r\nexport class SdPermissionGuard implements CanActivate, CanActivateChild {\r\n constructor(\r\n @Inject(SD_PERMISSION_CONFIGURATION)\r\n private configuration: ISdPermissionConfiguration | ISdPermissionConfiguration[],\r\n private permissionService: SdPermissionService\r\n ) {}\r\n\r\n #getConfigurations = (): ISdPermissionConfiguration[] => {\r\n const config = this.configuration;\r\n if (!config) {\r\n return [];\r\n }\r\n return Array.isArray(config) ? config : [config];\r\n };\r\n\r\n canActivate = async (next: ActivatedRouteSnapshot, state: RouterStateSnapshot) => {\r\n // Guard ở layer portal: preload toàn bộ permission theo tất cả key đã cấu hình\r\n await this.permissionService.loadAllPermissions().catch(console.error);\r\n return true;\r\n };\r\n\r\n canActivateChild = async (activatedRoute: ActivatedRouteSnapshot, state: RouterStateSnapshot) => {\r\n const permission = activatedRoute.data['permission'];\r\n const permissionKey = activatedRoute.data?.['permissionKey'] as string | undefined;\r\n if (this.permissionService.hasPermission(permission, permissionKey)) {\r\n return true;\r\n }\r\n\r\n const configurations = this.#getConfigurations();\r\n const onForbiden = configurations\r\n .filter(config => config.key === permissionKey || (permissionKey !== undefined && config.key === undefined))\r\n .map(config => config.onForbiden)\r\n .find(val => !!val);\r\n onForbiden?.();\r\n return false;\r\n };\r\n}\r\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './index';\n"],"names":["i1.SdPermissionService"],"mappings":"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"}
|
|
@@ -1,7 +1,8 @@
|
|
|
1
|
-
export * from '@sd-angular/core/modules/
|
|
1
|
+
export * from '@sd-angular/core/modules/keycloak';
|
|
2
2
|
export * from '@sd-angular/core/modules/permission';
|
|
3
3
|
export * from '@sd-angular/core/modules/auth';
|
|
4
4
|
export * from '@sd-angular/core/modules/layout';
|
|
5
|
+
export * from '@sd-angular/core/modules/authom';
|
|
5
6
|
|
|
6
7
|
/**
|
|
7
8
|
* Generated bundle index. Do not edit.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"sd-angular-core-modules.mjs","sources":["../../../projects/sd-angular/modules/sd-angular-core-modules.ts"],"sourcesContent":["/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './index';\n"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"sd-angular-core-modules.mjs","sources":["../../../projects/sd-angular/modules/sd-angular-core-modules.ts"],"sourcesContent":["/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './index';\n"],"names":[],"mappings":";;;;;;AAAA;;AAEG"}
|
|
@@ -1,19 +1,14 @@
|
|
|
1
1
|
import * as i0 from '@angular/core';
|
|
2
2
|
import { InjectionToken, Inject, Optional, Injectable, NgModule } from '@angular/core';
|
|
3
|
-
import { SdUtilities } from '@sd-angular/core/utilities';
|
|
4
|
-
import { SdUtilities as SdUtilities$1 } from '@sd-angular/core/utilities/extensions';
|
|
3
|
+
import { SdUtilities } from '@sd-angular/core/utilities/extensions';
|
|
5
4
|
import { lastValueFrom, from, throwError } from 'rxjs';
|
|
6
5
|
import { timeout, map, catchError, shareReplay, switchMap } from 'rxjs/operators';
|
|
7
6
|
import { v4 } from 'uuid';
|
|
8
7
|
import * as i1 from '@angular/common/http';
|
|
9
|
-
import { HttpResponse,
|
|
8
|
+
import { HttpResponse, HTTP_INTERCEPTORS, provideHttpClient, withInterceptorsFromDi } from '@angular/common/http';
|
|
10
9
|
import * as i2 from '@sd-angular/core/services/cache';
|
|
11
10
|
|
|
12
11
|
const SD_API_CONFIG = new InjectionToken('sd-api.configuration');
|
|
13
|
-
const TOKEN = SdUtilities.hash({
|
|
14
|
-
origin: location.origin,
|
|
15
|
-
key: 'ed4a2ffc-af43-41fb-9ac9-970f43d99571',
|
|
16
|
-
});
|
|
17
12
|
|
|
18
13
|
class SdApiService {
|
|
19
14
|
httpClient;
|
|
@@ -49,7 +44,7 @@ class SdApiService {
|
|
|
49
44
|
};
|
|
50
45
|
// Upload file logic giữ nguyên nhưng refactor nhẹ
|
|
51
46
|
upload = async (url, option) => {
|
|
52
|
-
const file = await SdUtilities
|
|
47
|
+
const file = await SdUtilities.upload(option);
|
|
53
48
|
if (!Array.isArray(file) && file) {
|
|
54
49
|
return this.uploadFile(url, file);
|
|
55
50
|
}
|
|
@@ -143,7 +138,7 @@ class SdApiService {
|
|
|
143
138
|
if (body instanceof FormData || option?.autoCache === false) {
|
|
144
139
|
return v4();
|
|
145
140
|
}
|
|
146
|
-
return SdUtilities
|
|
141
|
+
return SdUtilities.hash({
|
|
147
142
|
url,
|
|
148
143
|
method,
|
|
149
144
|
params: option?.params,
|
|
@@ -251,5 +246,5 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.17", ngImpo
|
|
|
251
246
|
* Generated bundle index. Do not edit.
|
|
252
247
|
*/
|
|
253
248
|
|
|
254
|
-
export { SD_API_CONFIG, SdApiModule, SdApiService, SdHttpInterceptor
|
|
249
|
+
export { SD_API_CONFIG, SdApiModule, SdApiService, SdHttpInterceptor };
|
|
255
250
|
//# sourceMappingURL=sd-angular-core-services-api.mjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"sd-angular-core-services-api.mjs","sources":["../../../projects/sd-angular/services/api/src/api.model.ts","../../../projects/sd-angular/services/api/src/api.service.ts","../../../projects/sd-angular/services/api/src/interceptors/api.interceptor.ts","../../../projects/sd-angular/services/api/src/api.module.ts","../../../projects/sd-angular/services/api/sd-angular-core-services-api.ts"],"sourcesContent":["/* eslint-disable @typescript-eslint/no-explicit-any */\r\nimport { HttpClient, HttpErrorResponse, HttpRequest, HttpResponse } from '@angular/common/http';\r\nimport { InjectionToken } from '@angular/core';\r\nimport { SdCacheOption } from '@sd-angular/core/services/cache';\r\nimport { SdUtilities } from '@sd-angular/core/utilities';\r\n// import hash from 'object-hash';\r\n\r\nexport interface SdApiOption {\r\n cacheOption?: SdCacheOption;\r\n timeout?: number; // Default: 30000 (30s)\r\n autoCache?: boolean; // Default: true\r\n}\r\ntype HttpGetOption = Parameters<HttpClient['get']>[1];\r\nexport type SdGetOption = HttpGetOption & SdApiOption;\r\n\r\ntype HttpPostOption = Parameters<HttpClient['post']>[2];\r\nexport type SdPostOption = HttpPostOption & SdApiOption;\r\n\r\ntype HttpPutOption = Parameters<HttpClient['put']>[2];\r\nexport type SdPutOption = HttpPutOption & SdApiOption;\r\n\r\ntype HttpDeleteOption = Parameters<HttpClient['delete']>[1];\r\nexport type SdDeleteOption = HttpDeleteOption & SdApiOption;\r\n\r\nexport interface SdApiHandler {\r\n hosts: string[];\r\n // Can thiệp header, token ... theo từng host sử dụng interceptor\r\n intercept?: (request: HttpRequest<any>) => HttpRequest<any>;\r\n beforeRemote?: (request: HttpRequest<any>) => void | Promise<void>;\r\n afterRemote?: (response: HttpResponse<any> | HttpErrorResponse | Error) => void | Promise<void>;\r\n mapResponse?: <Tres = any, Tdata = any>(response: Tres) => Tdata;\r\n timeout?: number; // Default 30s\r\n}\r\n\r\nexport interface ISdApiConfiguration {\r\n handlers: SdApiHandler[];\r\n}\r\n\r\nexport const SD_API_CONFIG = new InjectionToken<ISdApiConfiguration>('sd-api.configuration');\r\n\r\nexport const TOKEN = SdUtilities.hash({\r\n origin: location.origin,\r\n key: 'ed4a2ffc-af43-41fb-9ac9-970f43d99571',\r\n});\r\n","/* eslint-disable @typescript-eslint/no-explicit-any */\r\nimport { HttpClient } from '@angular/common/http';\r\nimport { Inject, Injectable, Optional } from '@angular/core';\r\nimport { SdCacheService } from '@sd-angular/core/services/cache';\r\nimport { SdUtilities } from '@sd-angular/core/utilities/extensions';\r\nimport { lastValueFrom, Observable } from 'rxjs';\r\nimport { catchError, map, shareReplay, timeout } from 'rxjs/operators';\r\nimport { v4 } from 'uuid';\r\nimport { ISdApiConfiguration, SD_API_CONFIG, SdApiHandler, SdDeleteOption, SdGetOption, SdPostOption, SdPutOption } from './api.model';\r\n\r\n// Gom nhóm các Option lại cho gọn\r\ntype SdHttpOptions = SdGetOption & SdPostOption & SdPutOption & SdDeleteOption;\r\ntype HttpMethod = 'GET' | 'POST' | 'PUT' | 'DELETE';\r\n\r\n@Injectable({\r\n providedIn: 'root',\r\n})\r\nexport class SdApiService {\r\n readonly #defaultTimeout = 60000; // 60s\r\n readonly #dedupCacheDuration = 1000; // 1s (Deduplication cache duration)\r\n\r\n // Thay đổi cấu trúc Cache: Lưu Observable thay vì Subject phức tạp\r\n // Key: hash string -> Value: { stream$: Observable, expiry: number }\r\n #inFlightRequests: Map<string, { stream$: Observable<any>; expiry: number }> = new Map();\r\n\r\n constructor(\r\n private httpClient: HttpClient,\r\n @Inject(SD_API_CONFIG) @Optional() private configurations: ISdApiConfiguration[],\r\n private cacheService: SdCacheService\r\n ) {\r\n // Optional: Cơ chế dọn dẹp cache định kỳ (mỗi 1 phút dọn dẹp các key hết hạn)\r\n setInterval(() => this.#cleanupCache(), 60000);\r\n }\r\n\r\n get http() {\r\n return this.httpClient;\r\n }\r\n\r\n // --- PUBLIC METHODS ---\r\n\r\n get = <T = any>(url: string, option?: SdGetOption): Promise<T> => {\r\n return this.#executeWithLayeredCache<T>(url, 'GET', undefined, option);\r\n };\r\n\r\n post = <T = any>(url: string, body?: any, option?: SdPostOption): Promise<T> => {\r\n return this.#executeWithLayeredCache<T>(url, 'POST', body, option);\r\n };\r\n\r\n put = <T = any>(url: string, body?: any, option?: SdPutOption): Promise<T> => {\r\n return this.#executeWithLayeredCache<T>(url, 'PUT', body, option);\r\n };\r\n\r\n delete = <T = any>(url: string, option?: SdDeleteOption): Promise<T> => {\r\n return this.#executeWithLayeredCache<T>(url, 'DELETE', undefined, option);\r\n };\r\n\r\n // Upload file logic giữ nguyên nhưng refactor nhẹ\r\n upload = async (url: string, option?: { extensions?: string[]; maxSizeInMb?: number }): Promise<any> => {\r\n const file = await SdUtilities.upload(option);\r\n if (!Array.isArray(file) && file) {\r\n return this.uploadFile(url, file);\r\n }\r\n };\r\n\r\n uploadFile = async (url: string, file: File): Promise<any> => {\r\n if (!file) return null;\r\n if (file.name.lastIndexOf('.') === -1) throw new Error('Invalid file extension');\r\n\r\n const formData = new FormData();\r\n formData.append('file', file, file.name);\r\n // Upload thường không cần deduplication cache, set autoCache: false\r\n return await this.post(url, formData, { autoCache: false });\r\n };\r\n\r\n // --- PRIVATE CORE LOGIC ---\r\n\r\n /**\r\n * Hàm trung gian xử lý Layer Cache (SdCacheService) trước khi gọi API thực tế\r\n */\r\n #executeWithLayeredCache = async <T>(url: string, method: HttpMethod, body?: any, option?: SdHttpOptions): Promise<T> => {\r\n // Layer 1: Persistent Cache (SdCacheService)\r\n if (option?.cacheOption) {\r\n const key = this.#generateKey(url, method, body, option);\r\n const { get, set, has } = this.cacheService.create(key, option.cacheOption);\r\n\r\n if (has()) {\r\n return get();\r\n }\r\n\r\n const result = await this.#request<T>(url, method, body, option);\r\n set(result);\r\n return result;\r\n }\r\n\r\n // Không có cache dài hạn thì gọi trực tiếp logic deduplication\r\n return this.#request<T>(url, method, body, option);\r\n };\r\n\r\n /**\r\n * Core Request: Xử lý Deduplication, Timeout, Mapping Response\r\n */\r\n #request = <T>(url: string, method: HttpMethod, body: any, option?: SdHttpOptions): Promise<T> => {\r\n const key = this.#generateKey(url, method, body, option);\r\n\r\n // Layer 2: Deduplication Cache (In-Flight Request / Short-term cache)\r\n const now = Date.now();\r\n const cachedItem = this.#inFlightRequests.get(key);\r\n\r\n // Nếu đã có request đang chạy hoặc mới chạy xong trong vòng 1s -> Trả về stream đó luôn\r\n if (cachedItem && cachedItem.expiry > now) {\r\n return lastValueFrom(cachedItem.stream$);\r\n }\r\n\r\n // Setup request mới\r\n const handler = this.#getHandler(url);\r\n const apiTimeout = option?.timeout ?? handler?.timeout ?? this.#defaultTimeout;\r\n\r\n // Tạo Observable call API\r\n const request$ = this.httpClient\r\n .request(method, url, {\r\n body,\r\n headers: option?.headers,\r\n params: option?.params,\r\n observe: 'response', // Lấy full response để check status\r\n responseType: option?.responseType,\r\n })\r\n .pipe(\r\n timeout(apiTimeout),\r\n map(res => {\r\n // Normalize Response Logic\r\n const bodyRes = res.body as any;\r\n // Logic check response cũ của bạn\r\n if (bodyRes && typeof bodyRes === 'object' && 'ok' in bodyRes && !bodyRes.ok) {\r\n throw bodyRes; // Giả sử structure trả về { ok: false, ... } là lỗi\r\n }\r\n\r\n if (handler?.mapResponse) {\r\n return handler.mapResponse(bodyRes);\r\n }\r\n\r\n return bodyRes;\r\n }),\r\n catchError(err => {\r\n // Xóa cache ngay lập tức nếu lỗi để user có thể retry\r\n this.#inFlightRequests.delete(key);\r\n throw err;\r\n }),\r\n // QUAN TRỌNG: shareReplay(1) giúp share kết quả cho các subscriber đến sau (trong 1s)\r\n shareReplay(1)\r\n );\r\n\r\n // Lưu vào Map\r\n this.#inFlightRequests.set(key, {\r\n stream$: request$,\r\n expiry: now + this.#dedupCacheDuration,\r\n });\r\n\r\n // Chuyển đổi sang Promise cho đúng return type của bạn\r\n return lastValueFrom(request$);\r\n };\r\n\r\n // --- HELPERS ---\r\n\r\n #getHandler = (url: string): SdApiHandler | undefined => {\r\n const handlers = this.configurations?.flatMap(b => b?.handlers || []) || [];\r\n return handlers.find(e => e.hosts.some(host => url.startsWith(host)));\r\n };\r\n\r\n #generateKey = (url: string, method: HttpMethod, body: any, option?: SdHttpOptions): string => {\r\n // FormData không hash được nội dung file, luôn generate key mới\r\n if (body instanceof FormData || option?.autoCache === false) {\r\n return v4();\r\n }\r\n return SdUtilities.hash({\r\n url,\r\n method,\r\n params: option?.params,\r\n headers: option?.headers,\r\n body,\r\n });\r\n };\r\n\r\n // Dọn dẹp memory leak\r\n #cleanupCache() {\r\n const now = Date.now();\r\n this.#inFlightRequests.forEach((value, key) => {\r\n if (value.expiry < now) {\r\n this.#inFlightRequests.delete(key);\r\n }\r\n });\r\n }\r\n}\r\n","/* eslint-disable @typescript-eslint/no-explicit-any */\r\nimport { HttpErrorResponse, HttpEvent, HttpHandler, HttpInterceptor, HttpRequest, HttpResponse } from '@angular/common/http';\r\nimport { Inject, Injectable, Optional } from '@angular/core';\r\nimport { from, Observable, throwError } from 'rxjs';\r\nimport { catchError, map, switchMap } from 'rxjs/operators';\r\nimport { SD_API_CONFIG, ISdApiConfiguration, SdApiHandler } from '../api.model';\r\n\r\n@Injectable()\r\nexport class SdHttpInterceptor implements HttpInterceptor {\r\n constructor(\r\n @Inject(SD_API_CONFIG)\r\n @Optional()\r\n private configurations: ISdApiConfiguration[]\r\n ) {}\r\n intercept(request: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {\r\n const url = request.url;\r\n if (!url) {\r\n throw new Error(`Invalid URL`);\r\n }\r\n const handlers = this.configurations?.reduce<SdApiHandler[]>((a, b) => [...a, ...(b?.handlers || [])], []) || [];\r\n const handler = handlers?.find(e => e.hosts.some(host => url.startsWith(host)));\r\n const intercept = handler?.intercept;\r\n if (intercept) {\r\n request = request.clone(intercept(request));\r\n }\r\n if (request.body instanceof FormData) {\r\n request = request.clone({\r\n headers: request.headers.delete('Content-Type'),\r\n });\r\n }\r\n const beforeRemoteHandler = handler?.beforeRemote;\r\n const afterRemoteHandler = handler?.afterRemote;\r\n const beforeRemote = beforeRemoteHandler?.(request);\r\n if (beforeRemote instanceof Promise) {\r\n return from(beforeRemote).pipe(\r\n switchMap(() => next.handle(request)),\r\n map((event: HttpEvent<any>) => {\r\n if (event instanceof HttpResponse) {\r\n afterRemoteHandler?.(event);\r\n }\r\n return event;\r\n }),\r\n catchError((error: HttpErrorResponse) => {\r\n afterRemoteHandler?.(error);\r\n return throwError(() => error);\r\n })\r\n );\r\n }\r\n return next.handle(request).pipe(\r\n map((event: HttpEvent<any>) => {\r\n if (event instanceof HttpResponse) {\r\n afterRemoteHandler?.(event);\r\n }\r\n return event;\r\n }),\r\n catchError((error: HttpErrorResponse) => {\r\n afterRemoteHandler?.(error);\r\n return throwError(() => error);\r\n })\r\n );\r\n }\r\n}\r\n","import { HTTP_INTERCEPTORS, provideHttpClient, withInterceptorsFromDi } from '@angular/common/http';\nimport { NgModule } from '@angular/core';\nimport { SdHttpInterceptor } from './interceptors/api.interceptor';\n\n@NgModule({\n imports: [],\n exports: [],\n providers: [provideHttpClient(withInterceptorsFromDi()), { provide: HTTP_INTERCEPTORS, useClass: SdHttpInterceptor, multi: true }],\n})\nexport class SdApiModule {}\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './index';\n"],"names":["SdUtilities"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"sd-angular-core-services-api.mjs","sources":["../../../projects/sd-angular/services/api/src/api.model.ts","../../../projects/sd-angular/services/api/src/api.service.ts","../../../projects/sd-angular/services/api/src/interceptors/api.interceptor.ts","../../../projects/sd-angular/services/api/src/api.module.ts","../../../projects/sd-angular/services/api/sd-angular-core-services-api.ts"],"sourcesContent":["/* eslint-disable @typescript-eslint/no-explicit-any */\r\nimport { HttpClient, HttpErrorResponse, HttpRequest, HttpResponse } from '@angular/common/http';\r\nimport { InjectionToken } from '@angular/core';\r\nimport { SdCacheOption } from '@sd-angular/core/services/cache';\r\nimport { SdUtilities } from '@sd-angular/core/utilities';\r\n// import hash from 'object-hash';\r\n\r\nexport interface SdApiOption {\r\n cacheOption?: SdCacheOption;\r\n timeout?: number; // Default: 30000 (30s)\r\n autoCache?: boolean; // Default: true\r\n}\r\ntype HttpGetOption = Parameters<HttpClient['get']>[1];\r\nexport type SdGetOption = HttpGetOption & SdApiOption;\r\n\r\ntype HttpPostOption = Parameters<HttpClient['post']>[2];\r\nexport type SdPostOption = HttpPostOption & SdApiOption;\r\n\r\ntype HttpPutOption = Parameters<HttpClient['put']>[2];\r\nexport type SdPutOption = HttpPutOption & SdApiOption;\r\n\r\ntype HttpDeleteOption = Parameters<HttpClient['delete']>[1];\r\nexport type SdDeleteOption = HttpDeleteOption & SdApiOption;\r\n\r\nexport interface SdApiHandler {\r\n /** Danh sách host URL mà handler này sẽ xử lý */\r\n hosts: string[];\r\n /** Can thiệp request: gắn header, token, transform body... */\r\n intercept?: (request: HttpRequest<any>) => HttpRequest<any>;\r\n /** Hook chạy TRƯỚC khi gửi request (dùng để log, tracking...) */\r\n beforeRemote?: (request: HttpRequest<any>) => void | Promise<void>;\r\n /** Hook chạy SAU khi nhận response (xử lý lỗi, notify...) */\r\n afterRemote?: (\r\n response: HttpResponse<any> | HttpErrorResponse | Error\r\n ) => void | Promise<void>;\r\n /** Transform response body thành kiểu dữ liệu mong muốn */\r\n mapResponse?: <Tres = any, Tdata = any>(response: Tres) => Tdata;\r\n /** Timeout tính bằng milliseconds. Mặc định: 30000 (30 giây) */\r\n timeout?: number;\r\n}\r\n\r\nexport interface ISdApiConfiguration {\r\n handlers: SdApiHandler[];\r\n}\r\n\r\nexport const SD_API_CONFIG = new InjectionToken<ISdApiConfiguration>('sd-api.configuration');\r\n","/* eslint-disable @typescript-eslint/no-explicit-any */\r\nimport { HttpClient } from '@angular/common/http';\r\nimport { Inject, Injectable, Optional } from '@angular/core';\r\nimport { SdCacheService } from '@sd-angular/core/services/cache';\r\nimport { SdUtilities } from '@sd-angular/core/utilities/extensions';\r\nimport { lastValueFrom, Observable } from 'rxjs';\r\nimport { catchError, map, shareReplay, timeout } from 'rxjs/operators';\r\nimport { v4 } from 'uuid';\r\nimport { ISdApiConfiguration, SD_API_CONFIG, SdApiHandler, SdDeleteOption, SdGetOption, SdPostOption, SdPutOption } from './api.model';\r\n\r\n// Gom nhóm các Option lại cho gọn\r\ntype SdHttpOptions = SdGetOption & SdPostOption & SdPutOption & SdDeleteOption;\r\ntype HttpMethod = 'GET' | 'POST' | 'PUT' | 'DELETE';\r\n\r\n@Injectable({\r\n providedIn: 'root',\r\n})\r\nexport class SdApiService {\r\n readonly #defaultTimeout = 60000; // 60s\r\n readonly #dedupCacheDuration = 1000; // 1s (Deduplication cache duration)\r\n\r\n // Thay đổi cấu trúc Cache: Lưu Observable thay vì Subject phức tạp\r\n // Key: hash string -> Value: { stream$: Observable, expiry: number }\r\n #inFlightRequests: Map<string, { stream$: Observable<any>; expiry: number }> = new Map();\r\n\r\n constructor(\r\n private httpClient: HttpClient,\r\n @Inject(SD_API_CONFIG) @Optional() private configurations: ISdApiConfiguration[],\r\n private cacheService: SdCacheService\r\n ) {\r\n // Optional: Cơ chế dọn dẹp cache định kỳ (mỗi 1 phút dọn dẹp các key hết hạn)\r\n setInterval(() => this.#cleanupCache(), 60000);\r\n }\r\n\r\n get http() {\r\n return this.httpClient;\r\n }\r\n\r\n // --- PUBLIC METHODS ---\r\n\r\n get = <T = any>(url: string, option?: SdGetOption): Promise<T> => {\r\n return this.#executeWithLayeredCache<T>(url, 'GET', undefined, option);\r\n };\r\n\r\n post = <T = any>(url: string, body?: any, option?: SdPostOption): Promise<T> => {\r\n return this.#executeWithLayeredCache<T>(url, 'POST', body, option);\r\n };\r\n\r\n put = <T = any>(url: string, body?: any, option?: SdPutOption): Promise<T> => {\r\n return this.#executeWithLayeredCache<T>(url, 'PUT', body, option);\r\n };\r\n\r\n delete = <T = any>(url: string, option?: SdDeleteOption): Promise<T> => {\r\n return this.#executeWithLayeredCache<T>(url, 'DELETE', undefined, option);\r\n };\r\n\r\n // Upload file logic giữ nguyên nhưng refactor nhẹ\r\n upload = async (url: string, option?: { extensions?: string[]; maxSizeInMb?: number }): Promise<any> => {\r\n const file = await SdUtilities.upload(option);\r\n if (!Array.isArray(file) && file) {\r\n return this.uploadFile(url, file);\r\n }\r\n };\r\n\r\n uploadFile = async (url: string, file: File): Promise<any> => {\r\n if (!file) return null;\r\n if (file.name.lastIndexOf('.') === -1) throw new Error('Invalid file extension');\r\n\r\n const formData = new FormData();\r\n formData.append('file', file, file.name);\r\n // Upload thường không cần deduplication cache, set autoCache: false\r\n return await this.post(url, formData, { autoCache: false });\r\n };\r\n\r\n // --- PRIVATE CORE LOGIC ---\r\n\r\n /**\r\n * Hàm trung gian xử lý Layer Cache (SdCacheService) trước khi gọi API thực tế\r\n */\r\n #executeWithLayeredCache = async <T>(url: string, method: HttpMethod, body?: any, option?: SdHttpOptions): Promise<T> => {\r\n // Layer 1: Persistent Cache (SdCacheService)\r\n if (option?.cacheOption) {\r\n const key = this.#generateKey(url, method, body, option);\r\n const { get, set, has } = this.cacheService.create(key, option.cacheOption);\r\n\r\n if (has()) {\r\n return get();\r\n }\r\n\r\n const result = await this.#request<T>(url, method, body, option);\r\n set(result);\r\n return result;\r\n }\r\n\r\n // Không có cache dài hạn thì gọi trực tiếp logic deduplication\r\n return this.#request<T>(url, method, body, option);\r\n };\r\n\r\n /**\r\n * Core Request: Xử lý Deduplication, Timeout, Mapping Response\r\n */\r\n #request = <T>(url: string, method: HttpMethod, body: any, option?: SdHttpOptions): Promise<T> => {\r\n const key = this.#generateKey(url, method, body, option);\r\n\r\n // Layer 2: Deduplication Cache (In-Flight Request / Short-term cache)\r\n const now = Date.now();\r\n const cachedItem = this.#inFlightRequests.get(key);\r\n\r\n // Nếu đã có request đang chạy hoặc mới chạy xong trong vòng 1s -> Trả về stream đó luôn\r\n if (cachedItem && cachedItem.expiry > now) {\r\n return lastValueFrom(cachedItem.stream$);\r\n }\r\n\r\n // Setup request mới\r\n const handler = this.#getHandler(url);\r\n const apiTimeout = option?.timeout ?? handler?.timeout ?? this.#defaultTimeout;\r\n\r\n // Tạo Observable call API\r\n const request$ = this.httpClient\r\n .request(method, url, {\r\n body,\r\n headers: option?.headers,\r\n params: option?.params,\r\n observe: 'response', // Lấy full response để check status\r\n responseType: option?.responseType,\r\n })\r\n .pipe(\r\n timeout(apiTimeout),\r\n map(res => {\r\n // Normalize Response Logic\r\n const bodyRes = res.body as any;\r\n // Logic check response cũ của bạn\r\n if (bodyRes && typeof bodyRes === 'object' && 'ok' in bodyRes && !bodyRes.ok) {\r\n throw bodyRes; // Giả sử structure trả về { ok: false, ... } là lỗi\r\n }\r\n\r\n if (handler?.mapResponse) {\r\n return handler.mapResponse(bodyRes);\r\n }\r\n\r\n return bodyRes;\r\n }),\r\n catchError(err => {\r\n // Xóa cache ngay lập tức nếu lỗi để user có thể retry\r\n this.#inFlightRequests.delete(key);\r\n throw err;\r\n }),\r\n // QUAN TRỌNG: shareReplay(1) giúp share kết quả cho các subscriber đến sau (trong 1s)\r\n shareReplay(1)\r\n );\r\n\r\n // Lưu vào Map\r\n this.#inFlightRequests.set(key, {\r\n stream$: request$,\r\n expiry: now + this.#dedupCacheDuration,\r\n });\r\n\r\n // Chuyển đổi sang Promise cho đúng return type của bạn\r\n return lastValueFrom(request$);\r\n };\r\n\r\n // --- HELPERS ---\r\n\r\n #getHandler = (url: string): SdApiHandler | undefined => {\r\n const handlers = this.configurations?.flatMap(b => b?.handlers || []) || [];\r\n return handlers.find(e => e.hosts.some(host => url.startsWith(host)));\r\n };\r\n\r\n #generateKey = (url: string, method: HttpMethod, body: any, option?: SdHttpOptions): string => {\r\n // FormData không hash được nội dung file, luôn generate key mới\r\n if (body instanceof FormData || option?.autoCache === false) {\r\n return v4();\r\n }\r\n return SdUtilities.hash({\r\n url,\r\n method,\r\n params: option?.params,\r\n headers: option?.headers,\r\n body,\r\n });\r\n };\r\n\r\n // Dọn dẹp memory leak\r\n #cleanupCache() {\r\n const now = Date.now();\r\n this.#inFlightRequests.forEach((value, key) => {\r\n if (value.expiry < now) {\r\n this.#inFlightRequests.delete(key);\r\n }\r\n });\r\n }\r\n}\r\n","/* eslint-disable @typescript-eslint/no-explicit-any */\r\nimport { HttpErrorResponse, HttpEvent, HttpHandler, HttpInterceptor, HttpRequest, HttpResponse } from '@angular/common/http';\r\nimport { Inject, Injectable, Optional } from '@angular/core';\r\nimport { from, Observable, throwError } from 'rxjs';\r\nimport { catchError, map, switchMap } from 'rxjs/operators';\r\nimport { SD_API_CONFIG, ISdApiConfiguration, SdApiHandler } from '../api.model';\r\n\r\n@Injectable()\r\nexport class SdHttpInterceptor implements HttpInterceptor {\r\n constructor(\r\n @Inject(SD_API_CONFIG)\r\n @Optional()\r\n private configurations: ISdApiConfiguration[]\r\n ) {}\r\n intercept(request: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {\r\n const url = request.url;\r\n if (!url) {\r\n throw new Error(`Invalid URL`);\r\n }\r\n const handlers = this.configurations?.reduce<SdApiHandler[]>((a, b) => [...a, ...(b?.handlers || [])], []) || [];\r\n const handler = handlers?.find(e => e.hosts.some(host => url.startsWith(host)));\r\n const intercept = handler?.intercept;\r\n if (intercept) {\r\n request = request.clone(intercept(request));\r\n }\r\n if (request.body instanceof FormData) {\r\n request = request.clone({\r\n headers: request.headers.delete('Content-Type'),\r\n });\r\n }\r\n const beforeRemoteHandler = handler?.beforeRemote;\r\n const afterRemoteHandler = handler?.afterRemote;\r\n const beforeRemote = beforeRemoteHandler?.(request);\r\n if (beforeRemote instanceof Promise) {\r\n return from(beforeRemote).pipe(\r\n switchMap(() => next.handle(request)),\r\n map((event: HttpEvent<any>) => {\r\n if (event instanceof HttpResponse) {\r\n afterRemoteHandler?.(event);\r\n }\r\n return event;\r\n }),\r\n catchError((error: HttpErrorResponse) => {\r\n afterRemoteHandler?.(error);\r\n return throwError(() => error);\r\n })\r\n );\r\n }\r\n return next.handle(request).pipe(\r\n map((event: HttpEvent<any>) => {\r\n if (event instanceof HttpResponse) {\r\n afterRemoteHandler?.(event);\r\n }\r\n return event;\r\n }),\r\n catchError((error: HttpErrorResponse) => {\r\n afterRemoteHandler?.(error);\r\n return throwError(() => error);\r\n })\r\n );\r\n }\r\n}\r\n","import { HTTP_INTERCEPTORS, provideHttpClient, withInterceptorsFromDi } from '@angular/common/http';\nimport { NgModule } from '@angular/core';\nimport { SdHttpInterceptor } from './interceptors/api.interceptor';\n\n@NgModule({\n imports: [],\n exports: [],\n providers: [provideHttpClient(withInterceptorsFromDi()), { provide: HTTP_INTERCEPTORS, useClass: SdHttpInterceptor, multi: true }],\n})\nexport class SdApiModule {}\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './index';\n"],"names":[],"mappings":"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"}
|