From 7244e3df27b90729610533f3682b776162055813 Mon Sep 17 00:00:00 2001 From: Cody Griffith Date: Tue, 3 Dec 2024 18:21:55 +0100 Subject: [PATCH] Automated sync from source branch v93 (#211) * Automated sync from source branch v93 --------- Co-authored-by: imx-sync-bot Co-authored-by: PROD\CGriffit --- .commit | 1 + .github/workflows/npm-build.yml | 98 +- imxweb/.eslintignore | 1 + imxweb/.eslintrc.json | 64 + imxweb/.gitignore | 4 +- imxweb/.npmrc | 4 +- imxweb/.prettierignore | 5 + imxweb/.prettierrc.json | 7 + imxweb/.vscode/launch.json | 9 +- imxweb/.vscode/settings.json | 30 +- imxweb/angular.json | 720 +- imxweb/build-docs.js | 40 + imxweb/build/imx-prepare-workspace/Build.proj | 10 +- imxweb/build/nx/Build.proj | 41 + imxweb/changes/changesFrom9.1.1To9.2.0.md | 1575 - .../assets/images/dashboard/1-dashboard.png | Bin 55956 -> 18301 bytes .../assets/images/dashboard/2-dashboard.png | Bin 0 -> 18085 bytes .../dashboard/5-block-identity-button.png | Bin 71872 -> 31801 bytes .../images/data_table/1-overall-structure.png | Bin 47013 -> 18487 bytes .../images/data_table/2-first-version.png | Bin 37323 -> 9203 bytes .../3-table-with-search-enabled.png | Bin 40718 -> 18394 bytes .../data_table/4-table-with-buttons.png | Bin 0 -> 17212 bytes .../images/data_table/4-table-with-search.png | Bin 42788 -> 0 bytes .../assets/images/menu/1-menu-bar.png | Bin 6914 -> 9717 bytes .../assets/images/menu/3-sub-item-menu.png | Bin 13890 -> 12445 bytes imxweb/compodoc/samples/data_table.md | 60 +- imxweb/compodoc/samples/menu.md | 40 +- imxweb/compodoc/samples/tiles.md | 73 +- imxweb/custom-theme/custom-theme.scss | 18 +- imxweb/custom-theme/package.json | 4 +- imxweb/custom-theme/readme.md | 74 +- .../elemental-ui-cadence-icon-3.1.107.tgz | Bin 0 -> 377024 bytes .../imx-modules/elemental-ui-core-18.0.14.tgz | Bin 0 -> 1259482 bytes .../imx-modules/elemental-ui_cadence-icon.tgz | Bin 323247 -> 0 bytes imxweb/imx-modules/elemental-ui_core.tgz | Bin 1322765 -> 0 bytes imxweb/imx-modules/imx-api-APC.tgz-hash | 8 + imxweb/imx-modules/imx-api-APC.tgz-version | 1 + imxweb/imx-modules/imx-api-aad.tgz | Bin 43355 -> 190239 bytes imxweb/imx-modules/imx-api-aad.tgz-hash | 8 + imxweb/imx-modules/imx-api-aad.tgz-version | 1 + imxweb/imx-modules/imx-api-aob.tgz | Bin 57653 -> 205337 bytes imxweb/imx-modules/imx-api-aob.tgz-hash | 8 + imxweb/imx-modules/imx-api-aob.tgz-version | 1 + imxweb/imx-modules/imx-api-apc.tgz | Bin 16821 -> 163777 bytes imxweb/imx-modules/imx-api-att.tgz | Bin 64094 -> 213058 bytes imxweb/imx-modules/imx-api-att.tgz-hash | 8 + imxweb/imx-modules/imx-api-att.tgz-version | 1 + imxweb/imx-modules/imx-api-cpl.tgz | Bin 26565 -> 173960 bytes imxweb/imx-modules/imx-api-cpl.tgz-hash | 8 + imxweb/imx-modules/imx-api-cpl.tgz-version | 1 + imxweb/imx-modules/imx-api-dpr.tgz | Bin 16302 -> 162227 bytes imxweb/imx-modules/imx-api-dpr.tgz-hash | 8 + imxweb/imx-modules/imx-api-dpr.tgz-version | 1 + imxweb/imx-modules/imx-api-hds.tgz | Bin 12160 -> 159380 bytes imxweb/imx-modules/imx-api-hds.tgz-hash | 8 + imxweb/imx-modules/imx-api-hds.tgz-version | 1 + imxweb/imx-modules/imx-api-o3e.tgz | Bin 26180 -> 0 bytes imxweb/imx-modules/imx-api-o3t.tgz | Bin 11090 -> 0 bytes imxweb/imx-modules/imx-api-olg.tgz | Bin 21648 -> 168870 bytes imxweb/imx-modules/imx-api-olg.tgz-hash | 8 + imxweb/imx-modules/imx-api-olg.tgz-version | 1 + imxweb/imx-modules/imx-api-pol.tgz | Bin 17128 -> 163527 bytes imxweb/imx-modules/imx-api-pol.tgz-hash | 8 + imxweb/imx-modules/imx-api-pol.tgz-version | 1 + imxweb/imx-modules/imx-api-qbm.tgz | Bin 70381 -> 229397 bytes imxweb/imx-modules/imx-api-qbm.tgz-hash | 8 + imxweb/imx-modules/imx-api-qbm.tgz-version | 1 + imxweb/imx-modules/imx-api-qer.tgz | Bin 276994 -> 431368 bytes imxweb/imx-modules/imx-api-qer.tgz-hash | 8 + imxweb/imx-modules/imx-api-qer.tgz-version | 1 + imxweb/imx-modules/imx-api-rmb.tgz | Bin 22563 -> 170079 bytes imxweb/imx-modules/imx-api-rmb.tgz-hash | 8 + imxweb/imx-modules/imx-api-rmb.tgz-version | 1 + imxweb/imx-modules/imx-api-rms.tgz | Bin 22920 -> 169072 bytes imxweb/imx-modules/imx-api-rms.tgz-hash | 8 + imxweb/imx-modules/imx-api-rms.tgz-version | 1 + imxweb/imx-modules/imx-api-rps.tgz | Bin 27001 -> 177346 bytes imxweb/imx-modules/imx-api-rps.tgz-hash | 8 + imxweb/imx-modules/imx-api-rps.tgz-version | 1 + imxweb/imx-modules/imx-api-sac.tgz | Bin 23970 -> 171250 bytes imxweb/imx-modules/imx-api-sac.tgz-hash | 8 + imxweb/imx-modules/imx-api-sac.tgz-version | 1 + imxweb/imx-modules/imx-api-tsb.tgz | Bin 66352 -> 214180 bytes imxweb/imx-modules/imx-api-tsb.tgz-hash | 8 + imxweb/imx-modules/imx-api-tsb.tgz-version | 1 + imxweb/imx-modules/imx-api-uci.tgz | Bin 7724 -> 155293 bytes imxweb/imx-modules/imx-api-uci.tgz-hash | 8 + imxweb/imx-modules/imx-api-uci.tgz-version | 1 + imxweb/imx-modules/imx-api.tgz | Bin 3499 -> 0 bytes imxweb/imx-modules/imx-qbm-dbts.tgz | Bin 150441 -> 174610 bytes imxweb/install-local-packages.js | 71 + imxweb/nx.json | 48 + imxweb/package-lock.json | 41311 ++++++---------- imxweb/package.json | 219 +- imxweb/prebuild.js | 48 + imxweb/projects/aad/.compodocrc.json | 2 +- imxweb/projects/aad/.eslintrc.json | 35 + imxweb/projects/aad/imx-plugin-config.json | 14 +- imxweb/projects/aad/karma.conf.js | 13 +- imxweb/projects/aad/ng-package.dynamic.json | 5 +- imxweb/projects/aad/ng-package.json | 2 +- imxweb/projects/aad/package.json | 2 +- imxweb/projects/aad/project.json | 65 + .../projects/aad/src/lib/aad-config.module.ts | 22 +- .../aad-extension/aad-extension.service.ts | 10 +- .../licence-overview-button.component.html | 12 +- .../licence-overview-button.component.scss | 7 - .../licence-overview-button.component.ts | 30 +- .../src/lib/admin/aad-permissions.service.ts | 8 +- .../aad/src/lib/admin/permissions-helper.ts | 6 +- .../projects/aad/src/lib/api.service.spec.ts | 4 +- imxweb/projects/aad/src/lib/api.service.ts | 11 +- .../aad-group-denied-plans.component.html | 30 +- .../aad-group-denied-plans.component.ts | 23 +- .../aad-group-subscriptions.component.html | 31 +- .../aad-group-subscriptions.component.ts | 26 +- .../aad-user-create-dialog.component.html | 21 +- .../aad-user-create-dialog.component.scss | 8 - .../aad-user-create-dialog.component.ts | 15 +- .../aad-user-denied-plans.component.html | 50 +- .../aad-user-denied-plans.component.ts | 34 +- .../aad-user-subscriptions.component.html | 53 +- .../aad-user-subscriptions.component.ts | 37 +- .../aad/src/lib/azure-ad/azure-ad-common.scss | 26 +- .../aad/src/lib/azure-ad/azure-ad.module.ts | 11 +- .../aad/src/lib/azure-ad/azure-ad.service.ts | 53 +- imxweb/projects/aad/src/lib/init.service.ts | 45 +- imxweb/projects/aad/src/public_api.ts | 4 +- imxweb/projects/aad/src/test.ts | 26 +- .../aad/src/test/aad-common-test-mocks.ts | 77 +- imxweb/projects/aad/tsconfig.lib.json | 9 +- imxweb/projects/aad/tsconfig.lib.prod.json | 3 - imxweb/projects/aad/tsconfig.spec.json | 15 +- imxweb/projects/aob/.compodocrc.json | 2 +- imxweb/projects/aob/.eslintrc.json | 35 + imxweb/projects/aob/imx-plugin-config.json | 8 +- imxweb/projects/aob/karma.conf.js | 17 +- imxweb/projects/aob/ng-package.dynamic.json | 5 +- imxweb/projects/aob/ng-package.json | 2 +- imxweb/projects/aob/package.json | 3 +- imxweb/projects/aob/project.json | 64 + .../aob/src/lib/accounts/accounts.module.ts | 12 +- .../aob/src/lib/accounts/accounts.service.ts | 137 +- .../src/lib/accounts/aob-account-container.ts | 24 +- .../aob/src/lib/aob-api-client.service.ts | 11 +- .../projects/aob/src/lib/aob-config.module.ts | 55 +- imxweb/projects/aob/src/lib/aob.service.ts | 36 +- .../application-property.component.html | 4 +- .../application-property.component.scss | 30 - .../application-property.component.ts | 4 +- .../application-property.module.ts | 17 +- .../application-content.interface.ts | 12 +- .../application-create.component.html | 52 +- .../application-create.component.scss | 39 +- .../application-create.component.ts | 55 +- .../application-detail.component.html | 38 +- .../application-detail.component.scss | 86 +- .../application-detail.component.ts | 32 +- .../account-details.interface.ts | 6 +- .../application-details.component.html | 145 +- .../application-details.component.scss | 198 +- .../application-details.component.ts | 137 +- .../application-hyperview.component.html | 3 - .../application-hyperview.component.scss | 23 - .../application-hyperview.component.ts | 65 - .../application-hyperview.module.ts | 44 - .../application-image-select.component.html | 6 +- .../application-image-select.component.scss | 2 +- .../application-image-select.component.ts | 43 +- ...age-selector-dialog-parameter.interface.ts | 4 +- .../image-selector-dialog.component.html | 61 +- .../image-selector-dialog.component.scss | 53 +- .../image-selector-dialog.component.ts | 35 +- .../application-navigation.component.html | 42 +- .../application-navigation.component.scss | 43 +- .../application-navigation.component.ts | 46 +- .../applications-routing.module.ts | 18 +- .../applications/applications.component.html | 2 +- .../applications/applications.component.scss | 12 - .../applications/applications.component.ts | 71 +- .../lib/applications/applications.module.ts | 82 +- .../lib/applications/applications.service.ts | 40 +- .../authentication-root.component.html | 15 +- .../authentication-root.component.scss | 2 +- .../authentication-root.component.ts | 12 +- .../edit-application.component.html | 57 +- .../edit-application.component.scss | 26 - .../edit-application.component.ts | 108 +- .../selection-container.spec.ts | 45 +- .../edit-application/selection-container.ts | 39 +- ...ervice-category-information.component.html | 10 +- ...-service-category-information.component.ts | 18 +- .../service-category-tree-database.ts | 23 +- .../service-category.component.html | 19 +- .../service-category.component.scss | 11 - .../service-category.component.ts | 53 +- .../service-category.service.ts | 12 +- .../identities/identities.component.html | 89 +- .../identities/identities.component.scss | 21 - .../identities/identities.component.ts | 20 +- .../identities/identity-detail-data.ts | 10 +- .../identity-detail.component.html | 39 +- .../identity-detail.component.ts | 58 +- .../identities/identity.service.ts | 23 +- .../column-info/column-info.component.html | 6 +- .../column-info/column-info.component.scss | 6 +- .../lib/column-info/column-info.component.ts | 6 +- .../src/lib/column-info/column-info.module.ts | 8 +- .../entitlements-add.component.html | 138 +- .../entitlements-add.component.scss | 39 +- .../entitlements-add.component.ts | 150 +- .../system-role-config.component.html | 62 +- .../system-role-config.component.scss | 29 +- .../system-role-config.component.ts | 82 +- .../system-role-config.service.ts | 20 +- .../entitlement-detail.component.html | 3 +- .../entitlement-detail.component.scss | 2 +- .../entitlement-detail.component.ts | 54 +- .../entitlement-edit-auto-add.component.html | 39 +- .../entitlement-edit-auto-add.component.scss | 24 - .../entitlement-edit-auto-add.component.ts | 74 +- .../entitlement-edit-auto-add.service.ts | 18 +- ...entitlement-to-add-data-wrapper.service.ts | 32 +- .../entitlement-to-add-typed.ts | 17 +- ...mapped-entitlements-preview.component.html | 93 +- ...mapped-entitlements-preview.component.scss | 34 +- .../mapped-entitlements-preview.component.ts | 48 +- .../entitlement-edit.component.html | 40 +- .../entitlement-edit.component.scss | 12 +- .../entitlement-edit.component.ts | 83 +- .../entitlement-edit.module.ts | 16 +- .../entitlements/entitlement-filter.spec.ts | 18 +- .../lib/entitlements/entitlement-filter.ts | 4 +- .../entitlement-wrapper.interface.ts | 8 +- .../entitlements/entitlements.component.html | 241 +- .../entitlements/entitlements.component.scss | 72 +- .../entitlements/entitlements.component.ts | 250 +- .../lib/entitlements/entitlements.model.ts | 6 +- .../lib/entitlements/entitlements.module.ts | 52 +- .../lib/entitlements/entitlements.service.ts | 118 +- .../entitlements/publish-data.interface.ts | 6 +- .../lock-info-alert-extension.ts | 2 +- .../lock-info-alert.component.html | 9 +- .../lock-info-alert.component.scss | 10 +- .../lock-info-alert.component.spec.ts | 7 +- .../lock-info-alert.component.ts | 10 +- .../lib/global-kpi/global-kpi.component.html | 52 +- .../lib/global-kpi/global-kpi.component.scss | 44 +- .../lib/global-kpi/global-kpi.component.ts | 163 +- .../src/lib/global-kpi/global-kpi.module.ts | 16 +- .../src/lib/global-kpi/global-kpi.service.ts | 12 +- .../src/lib/global-kpi/kpi-data.interface.ts | 18 +- .../kpi-tile/kpi-tile.component.html | 27 +- .../kpi-tile/kpi-tile.component.scss | 9 - .../global-kpi/kpi-tile/kpi-tile.component.ts | 10 +- .../guards/aob-applications-guard.service.ts | 12 +- .../src/lib/guards/aob-kpi-guard.service.ts | 12 +- .../aob/src/lib/images/image.service.ts | 9 +- .../kpi-overview/kpi-overview.component.html | 90 +- .../kpi-overview/kpi-overview.component.scss | 50 +- .../kpi-overview/kpi-overview.component.ts | 66 +- .../kpi/kpi-overview/kpi-overview.service.ts | 12 +- imxweb/projects/aob/src/lib/kpi/kpi.module.ts | 2 +- .../lifecycle-action-parameter.interface.ts | 5 +- .../lifecycle-action.component.html | 142 +- .../lifecycle-action.component.scss | 71 +- .../lifecycle-action.component.spec.ts | 156 +- .../lifecycle-action.component.ts | 112 +- .../lifecycle-action.enum.ts | 4 +- .../lifecycle-actions.module.ts | 17 +- .../lib/permissions/aob-permissions-helper.ts | 6 +- .../permissions/aob-permissions.service.ts | 15 +- .../lib/service-items/service-items.module.ts | 8 +- .../service-items/service-items.service.ts | 27 +- .../aob/src/lib/shops/shops.service.ts | 69 +- .../lib/start-page/start-page.component.html | 32 +- .../lib/start-page/start-page.component.scss | 25 +- .../lib/start-page/start-page.component.ts | 24 +- .../src/lib/start-page/start-page.module.ts | 11 +- .../aob/src/lib/user/user.component.html | 4 +- .../aob/src/lib/user/user.component.scss | 16 +- .../aob/src/lib/user/user.component.ts | 12 +- .../projects/aob/src/lib/user/user.module.ts | 18 +- imxweb/projects/aob/src/public-api.ts | 4 +- imxweb/projects/aob/src/test.ts | 26 +- imxweb/projects/aob/tsconfig.lib.json | 11 +- imxweb/projects/aob/tsconfig.lib.prod.json | 3 - imxweb/projects/aob/tsconfig.spec.json | 15 +- imxweb/projects/aob/tslint.json | 17 - imxweb/projects/apc/.compodocrc.json | 2 +- imxweb/projects/apc/.eslintrc.json | 35 + imxweb/projects/apc/imx-plugin-config.json | 2 +- imxweb/projects/apc/karma.conf.js | 11 +- imxweb/projects/apc/ng-package.dynamic.json | 5 +- imxweb/projects/apc/ng-package.json | 2 +- imxweb/projects/apc/package.json | 2 +- imxweb/projects/apc/project.json | 58 + .../apc/src/lib/apc-api-client.service.ts | 9 +- .../projects/apc/src/lib/apc-config.module.ts | 20 +- imxweb/projects/apc/src/lib/app-info.model.ts | 6 +- imxweb/projects/apc/src/lib/init.service.ts | 11 +- .../software-memberships.component.html | 150 +- .../software-memberships.component.scss | 57 +- .../software-memberships.component.ts | 96 +- .../software-sidesheet.component.html | 43 +- .../software-sidesheet.component.scss | 113 +- .../software-sidesheet.component.ts | 30 +- .../src/lib/software/software.component.html | 53 +- .../src/lib/software/software.component.scss | 51 +- .../src/lib/software/software.component.ts | 65 +- .../apc/src/lib/software/software.module.ts | 31 +- .../apc/src/lib/software/software.service.ts | 64 +- imxweb/projects/apc/src/public_api.ts | 2 +- imxweb/projects/apc/src/test.ts | 26 +- imxweb/projects/apc/tsconfig.lib.json | 9 +- imxweb/projects/apc/tsconfig.lib.prod.json | 3 - imxweb/projects/apc/tsconfig.spec.json | 15 +- imxweb/projects/apc/tslint.json | 17 - imxweb/projects/att/.compodocrc.json | 2 +- imxweb/projects/att/.eslintrc.json | 35 + imxweb/projects/att/imx-plugin-config.json | 26 +- imxweb/projects/att/karma.conf.js | 13 +- .../ng-package.dynamic-pwd.json} | 5 +- imxweb/projects/att/ng-package.dynamic.json | 5 +- imxweb/projects/att/ng-package.json | 2 +- imxweb/projects/att/package.json | 2 +- imxweb/projects/att/project.json | 78 + imxweb/projects/att/src/default-mocks.spec.ts | 4 +- .../att/src/lib/admin/permissions-helper.ts | 14 +- .../att/src/lib/admin/permissions.service.ts | 10 +- imxweb/projects/att/src/lib/api.service.ts | 11 +- .../projects/att/src/lib/att-config.module.ts | 12 +- .../attestation-action.component.html | 10 +- .../attestation-action.component.scss | 21 +- .../attestation-action.component.spec.ts | 6 +- .../attestation-action.component.ts | 24 +- .../attestation-action.service.ts | 183 +- .../attestation-case-action.interface.ts | 10 +- .../attestation-workflow.service.ts | 12 +- .../attestation-display.component.html | 2 +- .../attestation-display.component.scss | 1 - .../attestation-display.component.ts | 11 +- .../attestation-display.module.ts | 17 +- .../attestation-feature-guard.service.spec.ts | 14 +- .../lib/attestation-feature-guard.service.ts | 15 +- ...estation-case-load-parameters.interface.ts | 6 +- .../attestation-history-action.service.ts | 90 +- .../attestation-history-case.ts | 29 +- ...attestation-history-details.component.html | 67 +- ...attestation-history-details.component.scss | 54 +- .../attestation-history-details.component.ts | 62 +- .../attestation-history-filter.component.html | 4 +- .../attestation-history-filter.component.scss | 2 +- .../attestation-history-filter.component.ts | 31 +- ...attestation-history-wrapper.component.html | 52 +- ...attestation-history-wrapper.component.scss | 18 +- .../attestation-history-wrapper.component.ts | 46 +- .../attestation-history.component.html | 119 +- .../attestation-history.component.scss | 90 +- .../attestation-history.component.ts | 227 +- .../attestation-history.module.ts | 35 +- .../attestation-history.service.ts | 46 +- .../my-attestation-cases.component.html | 15 +- .../my-attestation-cases.component.scss | 7 - .../my-attestation-cases.component.ts | 4 +- .../attestation-snapshot.component.html | 14 +- .../attestation-snapshot.component.scss | 17 +- .../attestation-snapshot.component.ts | 28 +- .../attestation-snapshot.module.ts | 41 +- .../claim-device/claim-device.component.html | 58 +- .../claim-device/claim-device.component.scss | 5 - .../claim-device.component.spec.ts | 56 +- .../claim-device/claim-device.component.ts | 72 +- .../lib/claim-device/claim-device.module.ts | 11 +- .../lib/claim-device/claim-device.service.ts | 47 +- .../dashboard-plugin.component.html | 8 +- .../dashboard-plugin.component.ts | 12 +- .../att/src/lib/datamodel/datamodel-helper.ts | 91 - .../src/lib/decision/approvers.interface.ts | 6 +- .../approvers/approvers.component.html | 26 +- .../approvers/approvers.component.scss | 23 +- .../decision/approvers/approvers.component.ts | 4 +- .../decision/attestation-case.component.html | 94 +- .../decision/attestation-case.component.scss | 90 +- .../decision/attestation-case.component.ts | 45 +- .../src/lib/decision/attestation-case.spec.ts | 47 +- .../att/src/lib/decision/attestation-case.ts | 30 +- .../lib/decision/attestation-cases.service.ts | 114 +- .../attestation-decision-load-parameters.ts | 6 +- .../attestation-decision.component.html | 302 +- .../attestation-decision.component.scss | 167 +- .../attestation-decision.component.ts | 393 +- .../decision/attestation-decision.module.ts | 52 +- .../attestation-inquiries.component.html | 100 +- .../attestation-inquiries.component.scss | 29 +- .../attestation-inquiries.component.ts | 154 +- .../attestation-inquiry.model.ts | 6 +- ...cision-compliance-violation.component.html | 162 +- ...cision-compliance-violation.component.scss | 46 +- ...decision-compliance-violation.component.ts | 6 +- .../decision-history-item.component.html | 71 +- .../decision-history-item.component.scss | 41 +- .../decision-history-item.component.ts | 6 +- .../decision-policy-violation.component.html | 136 +- .../decision-policy-violation.component.scss | 46 +- .../decision-policy-violation.component.ts | 15 +- .../loss-preview-dialog.component.html | 4 +- .../loss-preview-dialog.component.scss | 12 +- .../loss-preview-dialog.component.ts | 9 +- .../loss-preview-table.component.html | 37 +- .../loss-preview-table.component.scss | 26 - .../loss-preview-table.component.ts | 10 +- .../lib/decision/loss-preview.interface.ts | 4 +- .../mitigating-controls.component.html | 29 +- .../mitigating-controls.component.scss | 2 +- .../mitigating-controls.component.ts | 15 +- .../entity-property-editor.component.html | 2 +- .../entity-property-editor.component.scss | 2 +- .../entity-property-editor.component.ts | 14 +- .../guards/attestation-admin-guard.service.ts | 12 +- .../attestation-policies-guard.service.ts | 12 +- .../att/src/lib/hardware-guard.service.ts | 13 +- .../src/lib/identity-attestation.service.ts | 34 +- imxweb/projects/att/src/lib/init.service.ts | 61 +- .../new-user/confirm-dialog.component.html | 6 +- .../lib/new-user/confirm-dialog.component.ts | 9 +- .../new-user/new-user-metadata.service.ts} | 24 +- .../src/lib/new-user/new-user.component.html | 34 +- .../src/lib/new-user/new-user.component.scss | 19 - .../src/lib/new-user/new-user.component.ts | 76 +- .../att/src/lib/new-user/new-user.module.ts | 9 +- .../new-user/open-sidesheet.component.scss | 5 - .../lib/new-user/open-sidesheet.component.ts | 31 +- .../new-user/user-activation.component.html | 29 +- .../new-user/user-activation.component.scss | 8 - .../lib/new-user/user-activation.component.ts | 67 +- .../pick-category/pick-category-common.scss | 27 +- .../pick-category-create.component.html | 50 +- .../pick-category-create.component.scss | 91 +- .../pick-category-create.component.spec.ts | 56 +- .../pick-category-create.component.ts | 78 +- ...-category-select-identities.component.html | 55 +- ...-category-select-identities.component.scss | 38 +- ...tegory-select-identities.component.spec.ts | 57 +- ...ck-category-select-identities.component.ts | 67 +- .../pick-category-sidesheet.component.html | 75 +- .../pick-category-sidesheet.component.scss | 31 +- .../pick-category-sidesheet.component.spec.ts | 59 +- .../pick-category-sidesheet.component.ts | 108 +- .../pick-category.component.html | 66 +- .../pick-category.component.scss | 41 +- .../pick-category.component.spec.ts | 66 +- .../pick-category/pick-category.component.ts | 162 +- .../lib/pick-category/pick-category.module.ts | 29 +- .../pick-category.service.spec.ts | 52 +- .../pick-category/pick-category.service.ts | 136 +- ...ion-cases-component-parameter.interface.ts | 18 +- ...attestation-cases-tree-database.service.ts | 122 - .../attestation-cases.component.html | 95 +- .../attestation-cases.component.scss | 149 +- .../attestation-cases.component.ts | 125 +- .../confirm-deactivation.component.html | 26 +- .../confirm-deactivation.component.scss | 15 +- .../confirm-deactivation.component.ts | 5 +- .../edit-master-data.component.html | 133 +- .../edit-master-data.component.scss | 70 +- .../edit-master-data.component.ts | 153 +- .../editors/edit-generic.component.html | 3 +- .../editors/edit-generic.component.ts | 10 +- .../policies/editors/edit-name.component.html | 3 +- .../policies/editors/edit-name.component.ts | 9 +- .../editors/edit-origin.component.html | 21 +- .../editors/edit-origin.component.scss | 6 +- .../editors/edit-origin.component.spec.ts | 141 +- .../policies/editors/edit-origin.component.ts | 32 +- .../editors/edit-threshold.component.html | 40 +- .../editors/edit-threshold.component.scss | 12 +- .../editors/edit-threshold.component.ts | 16 +- .../policies/editors/edit-uint.component.html | 7 +- .../policies/editors/edit-uint.component.ts | 9 +- .../filter-changed-argument.interface.ts | 10 +- .../editors/filter-editor.component.html | 50 +- .../editors/filter-editor.component.scss | 2 +- .../editors/filter-editor.component.ts | 15 +- .../editors/filter-element-column.service.ts | 75 +- .../policies/editors/filter-element-model.ts | 47 +- .../policy-details.component.html | 21 +- .../policy-details.component.scss | 37 +- .../policy-details.component.ts | 24 +- .../policies/policy-editor/filter-model.ts | 79 +- .../policy-editor.component.html | 53 +- .../policy-editor.component.scss | 63 +- .../policy-editor/policy-editor.component.ts | 199 +- .../policy-filter-element.component.html | 92 +- .../policy-filter-element.component.scss | 57 +- .../policy-filter-element.component.ts | 48 +- .../policy-list/attestation-policy.ts | 4 +- .../policy-list/policy-list.component.html | 161 +- .../policy-list/policy-list.component.scss | 81 +- .../policy-list/policy-list.component.ts | 297 +- .../policy-load-parameters.interface.ts | 4 +- .../att/src/lib/policies/policy.interface.ts | 4 +- .../att/src/lib/policies/policy.module.ts | 149 +- .../att/src/lib/policies/policy.service.ts | 27 +- .../selected-objects-info.interface.ts | 10 +- .../selected-objects.component.html | 23 +- .../selected-objects.component.scss | 13 +- .../selected-objects.component.ts | 37 +- ...edit-policy-group-sidesheet.component.html | 18 +- ...edit-policy-group-sidesheet.component.scss | 13 +- .../edit-policy-group-sidesheet.component.ts | 45 +- .../policy-group-list.component.html | 87 +- .../policy-group-list.component.scss | 34 +- .../policy-group-list.component.ts | 185 +- .../policy-group/policy-group.interface.ts | 6 +- .../lib/policy-group/policy-group.module.ts | 44 +- .../lib/policy-group/policy-group.service.ts | 116 +- .../src/lib/runs/attestation-runs.module.ts | 34 +- .../attestation-wrapper.component.html | 3 +- .../attestation-wrapper.component.scss | 6 +- .../attestation-wrapper.component.ts | 28 +- .../attestation/attestation.component.html | 47 +- .../attestation/attestation.component.scss | 82 +- .../runs/attestation/attestation.component.ts | 23 +- .../runs/case-chart/case-chart.component.html | 4 +- .../runs/case-chart/case-chart.component.scss | 6 - .../runs/case-chart/case-chart.component.ts | 12 +- imxweb/projects/att/src/lib/runs/helpers.ts | 2 +- .../lib/runs/pending-approvers.component.html | 72 +- .../lib/runs/pending-approvers.component.scss | 56 +- .../lib/runs/pending-approvers.component.ts | 45 +- .../lib/runs/progress/progress.component.html | 12 +- .../lib/runs/progress/progress.component.scss | 10 - .../lib/runs/progress/progress.component.ts | 7 +- .../runs/run-extend/run-extend.component.html | 35 +- .../runs/run-extend/run-extend.component.scss | 26 +- .../runs/run-extend/run-extend.component.ts | 24 +- .../src/lib/runs/run-sidesheet.component.html | 313 +- .../src/lib/runs/run-sidesheet.component.scss | 94 +- .../src/lib/runs/run-sidesheet.component.ts | 135 +- .../runs/runs-grid/runs-grid.component.html | 166 +- .../runs/runs-grid/runs-grid.component.scss | 23 +- .../lib/runs/runs-grid/runs-grid.component.ts | 247 +- .../runs/runs-load-parameters.interface.ts | 4 +- .../att/src/lib/runs/runs.component.html | 17 +- .../att/src/lib/runs/runs.component.scss | 15 - .../att/src/lib/runs/runs.component.ts | 17 +- .../projects/att/src/lib/runs/runs.service.ts | 31 +- .../runs/send-reminder-mail.component.html | 20 +- .../runs/send-reminder-mail.component.scss | 30 +- .../lib/runs/send-reminder-mail.component.ts | 13 +- imxweb/projects/att/src/public_api.ts | 20 +- imxweb/projects/att/src/test.ts | 29 +- imxweb/projects/att/tsconfig.lib.json | 12 +- imxweb/projects/att/tsconfig.lib.prod.json | 3 - imxweb/projects/att/tsconfig.spec.json | 15 +- imxweb/projects/att/tslint.json | 17 - imxweb/projects/cpl/.compodocrc.json | 2 +- imxweb/projects/cpl/.eslintrc.json | 35 + imxweb/projects/cpl/imx-plugin-config.json | 15 +- imxweb/projects/cpl/karma.conf.js | 13 +- imxweb/projects/cpl/ng-package.dynamic.json | 5 +- imxweb/projects/cpl/ng-package.json | 2 +- imxweb/projects/cpl/package.json | 2 +- imxweb/projects/cpl/project.json | 64 + imxweb/projects/cpl/src/lib/api.service.ts | 11 +- .../projects/cpl/src/lib/cpl-config.module.ts | 28 +- .../dashboard-plugin.component.html | 14 +- .../dashboard-plugin.component.ts | 11 +- .../guards/compliance-rules-guard.service.ts | 12 +- .../guards/rule-violations-guard.service.ts | 12 +- ...olations-mitigation-control.component.html | 14 +- ...olations-mitigation-control.component.scss | 2 +- ...violations-mitigation-control.component.ts | 42 +- .../identity-rule-violations.component.html | 31 +- .../identity-rule-violations.component.scss | 48 +- .../identity-rule-violations.component.ts | 23 +- .../identity-rule-violations.module.ts | 14 +- .../identity-rule-violations.service.ts | 37 +- imxweb/projects/cpl/src/lib/init.service.ts | 32 +- .../cart-item-compliance-check.component.html | 4 +- .../cart-item-compliance-check.component.ts | 12 +- .../item-validator/item-validator.service.ts | 12 +- ...itigating-control-container.component.html | 11 +- .../mitigating-control-container.component.ts | 42 +- .../mitigating-control-container.module.ts | 4 +- .../src/lib/mitigating-controls-common.scss | 155 +- ...ompliance-violation-details.component.html | 39 +- ...ompliance-violation-details.component.scss | 18 +- .../compliance-violation-details.component.ts | 60 +- .../compliance-violation.service.ts | 11 +- .../edit-mitigating-controls.component.scss | 4 +- .../edit-mitigating-controls.component.ts | 10 +- .../extended-deferred-operations-data.ts | 30 +- .../mitigating-control-data.interface.ts | 10 +- ...mitigating-controls-request.component.html | 32 +- ...mitigating-controls-request.component.scss | 2 +- .../mitigating-controls-request.component.ts | 44 +- .../mitigating-controls-request.service.ts | 20 +- .../request-mitigating-control-filter.pipe.ts | 2 +- .../request-mitigating-controls.ts | 13 +- .../lib/request/compliance-violation-model.ts | 4 +- .../request/request-rule-violation-detail.ts | 8 +- .../request/request-rule-violation.spec.ts | 2 +- .../src/lib/request/request-rule-violation.ts | 14 +- .../cpl/src/lib/request/request.module.ts | 8 +- .../workflow-violation-details.component.html | 12 +- .../workflow-violation-details.component.scss | 17 - .../workflow-violation-details.component.ts | 13 +- .../role-compliance-violation-typed-entity.ts | 26 +- .../role-compliance-violations-wrapper.ts | 12 +- .../role-compliance-violations.component.html | 36 +- .../role-compliance-violations.component.scss | 8 +- .../role-compliance-violations.component.ts | 10 +- .../role-compliance-violations.module.ts | 14 +- .../role-compliance-violations.service.ts | 24 +- .../mitigating-controls-person.component.html | 39 +- .../mitigating-controls-person.component.scss | 34 +- .../mitigating-controls-person.component.ts | 22 +- .../mitigating-controls-person.service.ts | 20 +- .../person-mitigating-controls.ts | 22 +- .../resolve/resolve.component.html | 43 +- .../resolve/resolve.component.scss | 15 +- .../resolve/resolve.component.ts | 300 +- ...-violations-action-parameters.interface.ts | 2 +- .../rules-violations-action.component.html | 18 +- .../rules-violations-action.component.scss | 26 +- .../rules-violations-action.component.ts | 9 +- .../rules-violations-action.interface.ts | 2 +- .../rules-violations-action.service.ts | 95 +- ...les-violations-multi-action.component.html | 23 +- ...les-violations-multi-action.component.scss | 40 +- ...rules-violations-multi-action.component.ts | 10 +- ...es-violations-single-action.component.html | 11 +- ...es-violations-single-action.component.scss | 10 - ...ules-violations-single-action.component.ts | 10 +- .../rules-violations-approval.ts | 6 +- .../rules-violations-details.component.html | 35 +- .../rules-violations-details.component.scss | 57 +- .../rules-violations-details.component.ts | 22 +- ...es-violations-load-parameters.interface.ts | 4 +- .../rules-violations.component.html | 180 +- .../rules-violations.component.scss | 66 +- .../rules-violations.component.ts | 168 +- .../rules-violations.module.ts | 94 +- .../rules-violations.service.ts | 35 +- .../rules/admin/cpl-permissions.service.ts | 10 +- .../src/lib/rules/admin/permissions-helper.ts | 7 +- .../mitigating-controls-rules.component.html | 30 +- .../mitigating-controls-rules.component.scss | 28 +- ...itigating-controls-rules.component.spec.ts | 28 +- .../mitigating-controls-rules.component.ts | 11 +- .../mitigating-controls-rules.service.spec.ts | 7 +- .../mitigating-controls-rules.service.ts | 21 +- .../rules-mitigating-controls.ts | 21 +- .../cpl/src/lib/rules/rule-parameter.ts | 6 +- .../rules-sidesheet.component.html | 19 +- .../rules-sidesheet.component.scss | 47 +- .../rules-sidesheet.component.ts | 24 +- .../violations-per-rule.component.html | 8 +- .../violations-per-rule.component.scss | 29 +- .../violations-per-rule.component.ts | 25 +- .../cpl/src/lib/rules/rules.component.html | 127 +- .../cpl/src/lib/rules/rules.component.scss | 33 +- .../cpl/src/lib/rules/rules.component.ts | 97 +- .../cpl/src/lib/rules/rules.module.ts | 30 +- .../cpl/src/lib/rules/rules.service.ts | 52 +- imxweb/projects/cpl/src/public_api.ts | 4 +- imxweb/projects/cpl/src/test.ts | 26 +- imxweb/projects/cpl/tsconfig.lib.json | 11 +- imxweb/projects/cpl/tsconfig.lib.prod.json | 3 - imxweb/projects/cpl/tsconfig.spec.json | 15 +- imxweb/projects/cpl/tslint.json | 17 - imxweb/projects/custom-app/.eslintrc.json | 35 + imxweb/projects/custom-app/karma.conf.js | 13 +- imxweb/projects/custom-app/package.json | 4 +- imxweb/projects/custom-app/project.json | 197 + imxweb/projects/custom-app/readme.md | 2 +- .../custom-app/src/app/app-routing.module.ts | 17 +- .../custom-app/src/app/app.component.html | 17 +- .../custom-app/src/app/app.component.scss | 2 +- .../custom-app/src/app/app.component.ts | 19 +- .../projects/custom-app/src/app/app.module.ts | 143 +- .../custom-app/src/app/app.service.ts | 25 +- .../custom-app/src/app/start.component.html | 6 +- .../custom-app/src/app/start.component.ts | 17 +- .../src/environments/environment.prod.ts | 4 +- .../src/environments/environment.ts | 6 +- imxweb/projects/custom-app/src/index.html | 20 +- imxweb/projects/custom-app/src/main.ts | 7 +- imxweb/projects/custom-app/src/polyfills.ts | 20 +- imxweb/projects/custom-app/src/styles.scss | 9 +- .../projects/{o3t => custom-app}/src/test.ts | 26 +- .../projects/custom-app/tsconfig-es5.app.json | 8 +- imxweb/projects/custom-app/tsconfig.app.json | 13 +- imxweb/projects/custom-app/tsconfig.spec.json | 15 +- imxweb/projects/custom-app/tslint.json | 17 - imxweb/projects/dpr/.compodocrc.json | 2 +- imxweb/projects/dpr/.eslintrc.json | 35 + imxweb/projects/dpr/karma.conf.js | 13 +- imxweb/projects/dpr/ng-package.dynamic.json | 3 +- imxweb/projects/dpr/ng-package.json | 2 +- imxweb/projects/dpr/package.json | 2 +- imxweb/projects/dpr/project.json | 64 + imxweb/projects/dpr/src/lib/api.service.ts | 11 +- .../outstanding/dependencies.component.html | 10 +- .../outstanding/dependencies.component.scss | 13 +- .../lib/outstanding/dependencies.component.ts | 19 +- .../outstanding/outstanding-object-entity.ts | 10 +- .../outstanding/outstanding.component.html | 81 +- .../outstanding/outstanding.component.scss | 55 +- .../lib/outstanding/outstanding.component.ts | 82 +- .../src/lib/outstanding/outstanding.module.ts | 18 +- .../lib/outstanding/outstanding.service.ts | 31 +- .../selected-items.component.html | 25 +- .../selected-items.component.scss | 31 +- .../selected-items.component.ts | 36 +- imxweb/projects/dpr/src/public_api.ts | 4 +- imxweb/projects/dpr/src/test.ts | 26 +- imxweb/projects/dpr/tsconfig.lib.json | 9 +- imxweb/projects/dpr/tsconfig.lib.prod.json | 3 - imxweb/projects/dpr/tsconfig.spec.json | 15 +- imxweb/projects/dpr/tslint.json | 17 - imxweb/projects/hds/.compodocrc.json | 2 +- imxweb/projects/hds/.eslintrc.json | 35 + imxweb/projects/hds/imx-plugin-config.json | 2 +- imxweb/projects/hds/karma.conf.js | 11 +- imxweb/projects/hds/ng-package.dynamic.json | 5 +- imxweb/projects/hds/ng-package.json | 2 +- imxweb/projects/hds/package.json | 2 +- imxweb/projects/hds/project.json | 65 + .../calls-attachment-dialog.component.html | 14 +- .../calls-attachment-dialog.component.scss | 25 - .../calls-attachment-dialog.component.ts | 14 +- .../calls-attachment-service.service.ts | 26 +- .../calls-attachment.component.html | 59 +- .../calls-attachment.component.scss | 89 +- .../calls-attachment.component.ts | 171 +- .../calls-attachment.model.ts | 2 +- .../calls-history-sidesheet.component.html | 23 +- .../calls-history-sidesheet.component.scss | 117 - .../calls-history-sidesheet.component.ts | 20 +- .../calls-history.component.html | 21 +- .../calls-history.component.scss | 12 +- .../calls-history/calls-history.component.ts | 85 +- .../calls-sidesheet.component.html | 56 +- .../calls-sidesheet.component.scss | 81 +- .../calls-sidesheet.component.ts | 73 +- .../hds/src/lib/calls/calls.component.html | 187 +- .../hds/src/lib/calls/calls.component.scss | 26 - .../hds/src/lib/calls/calls.component.ts | 125 +- .../hds/src/lib/calls/calls.module.ts | 27 +- .../hds/src/lib/hds-api-client.service.ts | 12 +- .../projects/hds/src/lib/hds-config.module.ts | 17 +- imxweb/projects/hds/src/lib/init.service.ts | 21 +- imxweb/projects/hds/src/public_api.ts | 2 +- imxweb/projects/hds/src/test.ts | 26 +- imxweb/projects/hds/tsconfig.lib.json | 9 +- imxweb/projects/hds/tsconfig.lib.prod.json | 3 - imxweb/projects/hds/tsconfig.spec.json | 15 +- imxweb/projects/hds/tslint.json | 17 - imxweb/projects/o3t/imx-plugin-config.json | 8 - imxweb/projects/o3t/package.json | 8 - .../team-channel-details.component.html | 38 - .../team-channel-details.component.ts | 83 - .../team-channels.component.html | 34 - .../team-channels/team-channels.component.ts | 123 - .../team-details/team-details.component.html | 60 - .../team-details/team-details.component.ts | 140 - .../o3t/src/lib/teams/teams.component.html | 42 - .../o3t/src/lib/teams/teams.component.ts | 123 - .../o3t/src/lib/teams/teams.service.ts | 75 - .../o3t/src/test/o3t-common-test-mocks.ts | 165 - imxweb/projects/o3t/tslint.json | 17 - imxweb/projects/olg/.compodocrc.json | 2 +- imxweb/projects/olg/.eslintrc.json | 35 + imxweb/projects/olg/imx-plugin-config.json | 2 +- imxweb/projects/olg/karma.conf.js | 11 +- imxweb/projects/olg/ng-package.dynamic.json | 5 +- imxweb/projects/olg/ng-package.json | 2 +- imxweb/projects/olg/package.json | 2 +- imxweb/projects/olg/project.json | 65 + .../projects/olg/src/lib/init.service.spec.ts | 2 +- imxweb/projects/olg/src/lib/init.service.ts | 9 +- .../mfa-form-control.component.html | 20 +- .../mfa-form-control.component.scss | 12 +- .../mfa-form-control.component.ts | 72 +- .../olg/src/lib/mfa/mfa.component.html | 7 +- .../olg/src/lib/mfa/mfa.component.scss | 7 +- .../projects/olg/src/lib/mfa/mfa.component.ts | 18 +- .../projects/olg/src/lib/mfa/mfa.service.ts | 4 +- .../olg/src/lib/mfa/portal-mfa.service.ts | 4 +- .../olg/src/lib/olg-api-client.service.ts | 12 +- .../projects/olg/src/lib/olg-config.module.ts | 25 +- imxweb/projects/olg/src/public_api.ts | 3 +- imxweb/projects/olg/src/test.ts | 26 +- imxweb/projects/olg/tsconfig.lib.json | 9 +- imxweb/projects/olg/tsconfig.lib.prod.json | 3 - imxweb/projects/olg/tsconfig.spec.json | 15 +- imxweb/projects/olg/tslint.json | 17 - imxweb/projects/pol/.compodocrc.json | 2 +- imxweb/projects/pol/.eslintrc.json | 35 + imxweb/projects/pol/imx-plugin-config.json | 14 +- imxweb/projects/pol/karma.conf.js | 13 +- imxweb/projects/pol/ng-package.dynamic.json | 5 +- imxweb/projects/pol/ng-package.json | 2 +- imxweb/projects/pol/package.json | 2 +- imxweb/projects/pol/project.json | 64 + .../pol/src/lib/admin/permissions-helper.ts | 10 +- .../pol/src/lib/admin/permissions.service.ts | 7 +- imxweb/projects/pol/src/lib/api.service.ts | 11 +- .../dashboard-plugin.component.html | 14 +- .../dashboard-plugin.component.ts | 14 +- .../lib/guards/policy-admin-guard.service.ts | 19 +- .../policy-owner-or-admin-guard.service.ts} | 42 +- imxweb/projects/pol/src/lib/init.service.ts | 51 +- .../projects/pol/src/lib/pol-config.module.ts | 43 +- .../mitigating-controls-policy.component.html | 15 +- .../mitigating-controls-policy.component.scss | 31 +- .../mitigating-controls-policy.component.ts | 12 +- .../policies-sidesheet.component.html | 25 +- .../policies-sidesheet.component.scss | 48 - .../policies-sidesheet.component.ts | 18 +- .../src/lib/policies/policies.component.html | 85 +- .../src/lib/policies/policies.component.scss | 29 +- .../src/lib/policies/policies.component.ts | 85 +- .../pol/src/lib/policies/policies.module.ts | 29 +- .../pol/src/lib/policies/policies.service.ts | 18 +- .../pol/src/lib/policies/policy-parameter.ts | 6 +- .../mitigating-controls.component.html | 66 +- .../mitigating-controls.component.scss | 154 +- .../mitigating-controls.component.ts | 34 +- .../policy-violation-extended.ts | 11 +- .../lib/policy-violations/policy-violation.ts | 32 +- ...lations-action-multi-action.component.html | 33 +- ...lations-action-multi-action.component.scss | 18 - ...iolations-action-multi-action.component.ts | 7 +- ...-violations-action-parameters.interface.ts | 10 +- ...ations-action-single-action.component.html | 13 +- ...ations-action-single-action.component.scss | 12 +- ...olations-action-single-action.component.ts | 10 +- .../policy-violations-action.component.html | 13 +- .../policy-violations-action.component.scss | 14 +- .../policy-violations-action.component.ts | 9 +- .../policy-violations-action.interface.ts | 2 +- ...policy-violations-sidesheet.component.html | 48 +- ...policy-violations-sidesheet.component.scss | 74 +- .../policy-violations-sidesheet.component.ts | 69 +- .../policy-violations.component.html | 176 +- .../policy-violations.component.scss | 83 +- .../policy-violations.component.ts | 198 +- .../policy-violations.module.ts | 40 +- .../policy-violations.service.ts | 125 +- imxweb/projects/pol/src/public_api.ts | 3 +- imxweb/projects/pol/src/test.ts | 26 +- imxweb/projects/pol/tsconfig.lib.json | 9 +- imxweb/projects/pol/tsconfig.lib.prod.json | 3 - imxweb/projects/pol/tsconfig.spec.json | 15 +- imxweb/projects/pol/tslint.json | 17 - imxweb/projects/{o3t => qam}/.compodocrc.json | 11 +- imxweb/projects/{o3t => qam}/Build.proj | 11 +- imxweb/projects/qam/imx-plugin-config.json | 8 + imxweb/projects/{o3t => qam}/karma.conf.js | 16 +- .../{uci => qam}/ng-package.dynamic.json | 4 +- imxweb/projects/{o3t => qam}/ng-package.json | 4 +- imxweb/projects/qam/package.json | 8 + imxweb/projects/qam/project.json | 65 + imxweb/projects/qam/src/lib/TypedClient.ts | 5497 ++ .../access-request-data.service.ts | 64 + ...access-request-sidesheet-data.interface.ts | 36 + .../access-request-sidesheet.component.html | 53 + .../access-request-sidesheet.component.scss | 3 + .../access-request-sidesheet.component.ts | 209 + .../access-request-tree-database.ts | 89 + .../access-request/access-request.module.ts} | 33 +- .../access-request/access-request.service.ts | 120 + .../lib/access-request/qam-resourcetree.ts | 124 + .../qam/src/lib/access/access.component.html | 13 + .../qam/src/lib/access/access.component.scss | 21 + .../qam/src/lib/access/access.component.ts | 69 + .../lib/access/trustee-view.component.html | 61 + .../lib/access/trustee-view.component.scss | 73 + .../src/lib/access/trustee-view.component.ts | 97 + .../src/lib/access/user-access.component.html | 1 + .../src/lib/access/user-access.component.ts} | 20 +- .../dug-activities.component.html | 61 + .../dug-activities.component.scss | 3 + .../dug-activities.component.ts | 116 + .../dug-activities/dug-activities.service.ts} | 34 +- .../lib/dug-activities/dug-activity-entity.ts | 91 + .../dug-dashboards.component.html | 12 + .../dug-dashboards.component.scss | 41 + .../dug-dashboards.component.ts | 57 + .../dug-dashboards/dug-dashboards.service.ts} | 21 +- .../dug-overview/dug-overview.component.html | 47 + .../dug-overview/dug-overview.component.scss | 11 + .../dug-overview/dug-overview.component.ts | 128 + .../lib/dug-overview/dug-overview.service.ts | 67 + .../lib/dug/access-comparison.component.html | 13 + .../lib/dug/access-comparison.component.ts | 120 + .../dug/dug-access-analysis.component.html | 17 + .../lib/dug/dug-access-analysis.component.ts | 58 + .../lib/dug/dug-access-analysis.service.ts | 46 + .../lib/dug/dug-access-detail.component.html | 27 + .../lib/dug/dug-access-detail.component.scss | 46 + .../lib/dug/dug-access-detail.component.ts | 151 + .../assigned-permissions.component.html | 30 + .../assigned-permissions.component.scss | 5 + .../assigned-permissions.component.ts | 71 + .../assigned-permissions/trustee-entity.ts | 142 + .../box-icon/box-icon.component.html | 8 + .../box-icon/box-icon.component.scss | 10 + .../dug-access/box-icon/box-icon.component.ts | 37 + .../dug/dug-access/dug-access.component.html | 21 + .../dug/dug-access/dug-access.component.scss | 12 + .../dug/dug-access/dug-access.component.ts | 86 + .../lib/dug/dug-access/dug-access.module.ts} | 62 +- .../effective-permission-tree-database.ts | 52 + .../effective-permission.component.html | 50 + .../effective-permission.component.scss | 153 + .../effective-permission.component.ts | 89 + .../permission-member.component.html | 46 + .../permission-member.component.scss | 85 + .../permission-member.component.ts | 91 + .../trustee-entity-hierarchy.ts | 190 + .../dug-activity/dug-activity.component.html | 14 + .../dug-activity/dug-activity.component.scss | 9 + .../dug-activity/dug-activity.component.ts | 64 + .../dug/dug-activity/dug-activity.module.ts} | 25 +- .../lib/dug/dug-reports/dug-report-entity.ts | 96 + .../dug-reports/dug-reports.component.html | 15 + .../dug-reports/dug-reports.component.scss | 3 + .../dug/dug-reports/dug-reports.component.ts | 73 + .../dug/dug-reports/dug-reports.service.ts | 49 + .../src/lib/dug/dug-sidesheet.component.html | 150 + .../src/lib/dug/dug-sidesheet.component.scss | 30 + .../src/lib/dug/dug-sidesheet.component.ts | 256 + .../src/lib/identity/identity.component.html | 73 + .../src/lib/identity/identity.component.scss | 42 + .../src/lib/identity/identity.component.ts | 156 + imxweb/projects/qam/src/lib/init.service.ts | 118 + .../src/lib/qam-api-client.service.ts} | 39 +- .../projects/qam/src/lib/qam-config.module.ts | 131 + imxweb/projects/qam/src/lib/qam.scss | 50 + .../src/public_api.ts} | 10 +- imxweb/projects/qam/src/test.ts | 40 + .../projects/{o3t => qam}/tsconfig.lib.json | 9 +- .../{o3t => qam}/tsconfig.lib.prod.json | 3 - .../projects/{o3t => qam}/tsconfig.spec.json | 0 imxweb/projects/{aad => qam}/tslint.json | 0 .../qbm-app-landingpage/.compodocrc.json | 2 +- .../qbm-app-landingpage/.eslintrc.json | 35 + imxweb/projects/qbm-app-landingpage/README.md | 1 + .../qbm-app-landingpage/karma.conf.js | 13 +- .../projects/qbm-app-landingpage/package.json | 6 +- .../projects/qbm-app-landingpage/project.json | 209 + .../src/app/app-routing.module.ts | 9 +- .../src/app/app.component.html | 5 +- .../src/app/app.component.scss | 25 +- .../src/app/app.component.ts | 83 +- .../qbm-app-landingpage/src/app/app.module.ts | 46 +- .../src/app/app.service.ts | 40 +- .../src/app/appcontainer.service.spec.ts | 24 +- .../src/app/appcontainer.service.ts | 10 +- .../src/app/start/start.component.html | 6 +- .../src/app/start/start.component.scss | 9 +- .../src/app/start/start.component.ts | 6 +- .../src/environments/environment.prod.ts | 4 +- .../src/environments/environment.ts | 4 +- .../qbm-app-landingpage/src/index.html | 20 +- .../projects/qbm-app-landingpage/src/main.ts | 7 +- .../qbm-app-landingpage/src/polyfills.ts | 22 +- .../qbm-app-landingpage/src/styles.scss | 55 +- .../projects/qbm-app-landingpage/src/test.ts | 13 +- .../qbm-app-landingpage/tsconfig-es5.app.json | 8 +- .../qbm-app-landingpage/tsconfig.app.json | 13 +- .../qbm-app-landingpage/tsconfig.spec.json | 16 +- .../projects/qbm-app-landingpage/tslint.json | 17 - imxweb/projects/qbm/.compodocrc.json | 2 +- imxweb/projects/qbm/.eslintrc.json | 35 + imxweb/projects/qbm/README.md | 16 +- .../qbm/additionalDocumentation/admin.md | 24 +- .../qbm/additionalDocumentation/datasets.md | 66 +- .../qbm/additionalDocumentation/messages.md | 55 +- .../qbm/additionalDocumentation/other.md | 60 +- .../qbm/additionalDocumentation/overview.md | 10 +- .../qbm/additionalDocumentation/properties.md | 21 +- .../qbm/additionalDocumentation/summary.json | 12 +- imxweb/projects/qbm/karma.conf.js | 39 +- imxweb/projects/qbm/ng-package.json | 2 +- imxweb/projects/qbm/package.json | 10 +- imxweb/projects/qbm/project.json | 60 + imxweb/projects/qbm/src/default-mocks.spec.ts | 12 +- .../qbm/src/lib/about/About.component.html | 21 +- .../qbm/src/lib/about/About.component.scss | 122 +- .../qbm/src/lib/about/About.component.ts | 40 +- .../qbm/src/lib/about/About.service.ts | 54 +- .../lib/admin/about/admin-about.service.ts | 56 + .../admin/add-config-sidesheet.component.html | 26 +- .../admin/add-config-sidesheet.component.scss | 9 - .../admin/add-config-sidesheet.component.ts | 32 +- .../lib/admin/admin-component.interface.ts | 6 +- .../qbm/src/lib/admin/admin-routes.ts | 28 +- .../qbm/src/lib/admin/admin.module.ts | 23 +- .../apply-config-sidesheet.component.html | 28 +- .../apply-config-sidesheet.component.scss | 53 +- .../admin/apply-config-sidesheet.component.ts | 26 +- .../qbm/src/lib/admin/cache.component.html | 24 +- .../qbm/src/lib/admin/cache.component.ts | 66 +- .../lib/admin/config-key-path.component.html | 2 +- .../lib/admin/config-key-path.component.scss | 4 +- .../lib/admin/config-key-path.component.ts | 11 +- .../qbm/src/lib/admin/config-section.ts | 17 +- .../qbm/src/lib/admin/config.component.html | 71 +- .../qbm/src/lib/admin/config.component.scss | 51 +- .../qbm/src/lib/admin/config.component.ts | 72 +- .../qbm/src/lib/admin/config.service.ts | 225 +- .../convert-config-sidesheet.component.html | 15 +- .../convert-config-sidesheet.component.scss | 2 +- .../convert-config-sidesheet.component.ts | 21 +- .../src/lib/admin/dashboard.component.scss | 162 - .../qbm/src/lib/admin/dashboard.component.ts | 12 +- .../delete-config-sidesheet.component.html | 10 +- .../delete-config-sidesheet.component.ts | 27 +- .../src/lib/admin/list-setting.component.html | 27 +- .../src/lib/admin/list-setting.component.scss | 23 +- .../src/lib/admin/list-setting.component.ts | 19 +- .../log-details-sidesheet.component.html | 37 +- .../log-details-sidesheet.component.scss | 9 +- .../admin/log-details-sidesheet.component.ts | 17 +- .../qbm/src/lib/admin/logs.component.html | 70 +- .../qbm/src/lib/admin/logs.component.scss | 69 +- .../qbm/src/lib/admin/logs.component.ts | 127 +- .../qbm/src/lib/admin/packages.component.html | 2 +- .../qbm/src/lib/admin/packages.component.scss | 5 +- .../qbm/src/lib/admin/packages.component.ts | 29 +- .../qbm/src/lib/admin/plugins.component.html | 8 +- .../qbm/src/lib/admin/plugins.component.ts | 4 +- .../src/lib/admin/select-value.component.html | 6 +- .../src/lib/admin/select-value.component.ts | 23 +- imxweb/projects/qbm/src/lib/admin/shared.scss | 42 +- .../qbm/src/lib/admin/status.component.html | 28 +- .../qbm/src/lib/admin/status.component.ts | 219 +- .../qbm/src/lib/admin/status.service.ts | 18 +- .../lib/admin/swagger/swagger.component.html | 3 +- .../lib/admin/swagger/swagger.component.scss | 4 +- .../lib/admin/swagger/swagger.component.ts | 6 +- .../api-client/api-client-angular.service.ts | 17 +- .../lib/api-client/api-client-fetch.spec.ts | 102 +- .../src/lib/api-client/api-client-fetch.ts | 240 +- .../src/lib/api-client/api-client.service.ts | 12 +- .../qbm/src/lib/api-client/api-client.spec.ts | 56 +- .../qbm/src/lib/api-client/dynamic-method.ts | 65 +- ...ic-collection-load-parameters.interface.ts | 4 +- .../dynamic-method-type-wrapper.interface.ts | 4 +- .../dynamic-method/dynamic-method.service.ts | 32 +- .../interactive-parameter.interface.ts | 2 +- .../method-descriptor.service.ts | 79 +- .../typed-entity-builder.service.ts | 46 +- .../src/lib/appConfig/appConfig.service.ts | 69 +- .../src/lib/appConfig/appconfig.interface.ts | 2 +- .../lib/appConfig/route-config.interface.ts | 2 +- .../translationConfiguration.interface.ts | 4 +- .../auth-config-provider.interface.ts | 9 +- .../authentication-guard.service.ts | 29 +- .../authentication/authentication.module.ts | 13 +- .../authentication/authentication.service.ts | 75 +- .../custom-auth-flow.interface.ts | 8 +- .../src/lib/authentication/oauth.service.ts | 34 +- .../lib/authentication/redirect.service.ts | 4 +- .../auto-complete.component.html | 19 +- .../auto-complete.component.scss | 17 +- .../auto-complete/auto-complete.component.ts | 9 +- .../lib/auto-complete/auto-complete.module.ts | 16 +- imxweb/projects/qbm/src/lib/base/Guid.ts | 2 +- .../projects/qbm/src/lib/base/busy.service.ts | 22 +- .../elemental-defaults.ts} | 35 +- .../qbm/src/lib/base/error.service.ts | 15 +- .../qbm/src/lib/base/global-error-handler.ts | 31 +- .../qbm/src/lib/base/ie-warning.service.ts | 8 +- .../qbm/src/lib/base/metadata.service.ts | 86 +- .../lib/base/opsupport-db-object.service.ts | 4 +- .../qbm/src/lib/base/paginator.spec.ts | 54 +- imxweb/projects/qbm/src/lib/base/paginator.ts | 63 +- .../qbm/src/lib/base/qbm-sqlwizard.service.ts | 4 +- .../lib/base/query-parameters-handler.spec.ts | 46 +- .../src/lib/base/query-parameters-handler.ts | 20 +- .../qbm/src/lib/base/registry.service.ts | 10 +- .../projects/qbm/src/lib/base/server-error.ts | 16 +- .../src/lib/base/server-exception-error.ts | 30 +- .../sidesheet-helper.ts} | 21 +- .../qbm/src/lib/base/timezone-info.spec.ts | 5 +- .../qbm/src/lib/base/timezone-info.ts | 69 +- .../qbm/src/lib/base/user-action.service.ts | 2 +- .../qbm/src/lib/base/user-agent-helper.ts | 2 +- .../bulk-item/bulk-item-icon.ts | 2 +- .../bulk-item/bulk-item.component.html | 45 +- .../bulk-item/bulk-item.component.scss | 33 +- .../bulk-item/bulk-item.component.ts | 8 +- .../bulk-item/bulk-item.ts | 6 +- .../bulk-property-editor.component.html | 6 +- .../bulk-property-editor.component.scss | 1 - .../bulk-property-editor.component.ts | 12 +- .../bulk-property-editor.module.ts | 8 +- .../busy-indicator.component.html | 2 +- .../busy-indicator.component.scss | 6 +- .../busy-indicator.component.ts | 8 +- .../busy-indicator/busy-indicator.module.ts | 27 +- .../qbm/src/lib/cache/cache.service.ts | 27 +- .../src/lib/captcha/captcha.component.html | 38 +- .../src/lib/captcha/captcha.component.scss | 18 + .../qbm/src/lib/captcha/captcha.component.ts | 65 +- .../qbm/src/lib/captcha/captcha.module.ts | 23 +- .../qbm/src/lib/captcha/captcha.service.ts | 71 +- imxweb/projects/qbm/src/lib/cdr/Readme.md | 45 +- .../src/lib/cdr/base-cdr-editor-provider.ts | 8 +- .../projects/qbm/src/lib/cdr/base-cdr.spec.ts | 23 +- imxweb/projects/qbm/src/lib/cdr/base-cdr.ts | 18 +- .../qbm/src/lib/cdr/base-readonly-cdr.ts | 3 +- .../cdr-editor-provider-registry.interface.ts | 13 +- .../lib/cdr/cdr-editor-provider.interface.ts | 25 +- .../qbm/src/lib/cdr/cdr-editor.interface.ts | 25 +- .../cdr/cdr-editor/cdr-editor.component.html | 2 +- .../cdr/cdr-editor/cdr-editor.component.scss | 4 +- .../cdr/cdr-editor/cdr-editor.component.ts | 38 +- .../qbm/src/lib/cdr/cdr-factory.service.ts | 29 +- .../qbm/src/lib/cdr/cdr-registry.service.ts | 51 +- .../cdr/cdr-sidesheet/cdr-sidesheet-config.ts | 2 +- .../cdr-sidesheet.component.html | 15 +- .../cdr-sidesheet/cdr-sidesheet.component.ts | 15 +- imxweb/projects/qbm/src/lib/cdr/cdr.module.ts | 59 +- .../column-dependent-reference.interface.ts | 57 +- .../cdr/date-range/date-range.component.html | 33 +- .../cdr/date-range/date-range.component.scss | 9 +- .../cdr/date-range/date-range.component.ts | 31 +- .../cdr/default-cdr-editor-provider.spec.ts | 115 +- .../lib/cdr/default-cdr-editor-provider.ts | 29 +- .../edit-binary/edit-binary.component.html | 13 +- .../edit-binary/edit-binary.component.scss | 4 - .../cdr/edit-binary/edit-binary.component.ts | 2 +- .../edit-bitmask/edit-bitmask.component.html | 10 + .../edit-bitmask/edit-bitmask.component.scss | 3 + .../edit-bitmask/edit-bitmask.component.ts | 179 + .../edit-boolean/edit-boolean.component.html | 16 +- .../edit-boolean/edit-boolean.component.scss | 6 - .../edit-boolean/edit-boolean.component.ts | 2 +- .../cdr/edit-date/edit-date.component.html | 4 +- .../cdr/edit-date/edit-date.component.scss | 2 +- .../lib/cdr/edit-date/edit-date.component.ts | 38 +- .../edit-default/edit-default.component.html | 45 +- .../edit-default/edit-default.component.scss | 6 +- .../edit-default/edit-default.component.ts | 4 +- .../cdr/edit-fk/edit-fk-multi.component.html | 30 +- .../cdr/edit-fk/edit-fk-multi.component.scss | 40 +- .../edit-fk/edit-fk-multi.component.spec.ts | 26 +- .../cdr/edit-fk/edit-fk-multi.component.ts | 45 +- .../lib/cdr/edit-fk/edit-fk.component.html | 90 +- .../lib/cdr/edit-fk/edit-fk.component.scss | 59 +- .../lib/cdr/edit-fk/edit-fk.component.spec.ts | 26 +- .../src/lib/cdr/edit-fk/edit-fk.component.ts | 155 +- .../cdr/edit-image/edit-image.component.html | 10 +- .../cdr/edit-image/edit-image.component.scss | 2 +- .../cdr/edit-image/edit-image.component.ts | 30 +- .../edit-limited-value.component.html | 25 +- .../edit-limited-value.component.scss | 20 - .../edit-limited-value.component.ts | 8 +- .../edit-multi-limited-value.component.html | 43 +- .../edit-multi-limited-value.component.scss | 12 +- .../edit-multi-limited-value.component.ts | 88 +- .../edit-multi-value.component.html | 20 +- .../edit-multi-value.component.scss | 6 +- .../edit-multi-value.component.ts | 25 +- .../edit-multiline.component.html | 36 +- .../edit-multiline.component.scss | 19 +- .../edit-multiline.component.ts | 2 +- .../edit-number/edit-number.component.html | 57 +- .../edit-number/edit-number.component.scss | 10 +- .../cdr/edit-number/edit-number.component.ts | 4 +- .../cdr/edit-number/number-error.interface.ts | 2 +- .../edit-number/number-validator.service.ts | 6 +- .../edit-risk-index.component.html | 41 +- .../edit-risk-index.component.scss | 73 +- .../edit-risk-index.component.ts | 17 +- .../lib/cdr/edit-url/edit-url.component.html | 21 +- .../lib/cdr/edit-url/edit-url.component.scss | 4 - .../cdr/edit-url/edit-url.component.spec.ts | 11 +- .../lib/cdr/edit-url/edit-url.component.ts | 6 +- .../edit-url/url-validator.service.spec.ts | 2 +- .../lib/cdr/edit-url/url-validator.service.ts | 6 +- .../projects/qbm/src/lib/cdr/editor-base.ts | 41 +- .../lib/cdr/entity-column-container.spec.ts | 23 +- .../src/lib/cdr/entity-column-container.ts | 30 +- .../entity-column-editor.component.html | 4 +- .../entity-column-editor.component.scss | 2 +- .../entity-column-editor.component.ts | 11 +- .../lib/cdr/fk-cdr-editor-provider.spec.ts | 95 +- .../qbm/src/lib/cdr/fk-cdr-editor-provider.ts | 14 +- .../lib/cdr/limited-values-container.spec.ts | 63 +- .../src/lib/cdr/limited-values-container.ts | 17 +- .../property-viewer.component.ts | 40 +- .../view-property-default.component.html | 3 +- .../view-property-default.component.scss | 2 +- .../view-property-default.component.ts | 4 +- .../view-property.component.html | 2 +- .../view-property/view-property.component.ts | 4 +- .../chart-options/line-chart-options.spec.ts | 10 +- .../lib/chart-options/line-chart-options.ts | 24 +- .../chart-options/series-information.spec.ts | 3 +- .../lib/chart-options/series-information.ts | 7 +- .../chart-options/x-axis-information.spec.ts | 4 +- .../lib/chart-options/x-axis-information.ts | 4 +- .../chart-options/y-axis-information.spec.ts | 3 +- .../lib/chart-options/y-axis-information.ts | 16 +- .../lib/chart-tile/chart-tile.component.html | 22 +- .../lib/chart-tile/chart-tile.component.ts | 7 +- .../src/lib/classlogger/classlogger.module.ts | 13 +- .../lib/classlogger/classlogger.service.ts | 5 +- .../elemental-ui-config.interface.ts | 4 +- .../elemental-ui-config.service.ts | 35 +- .../lib/confirmation/confirmation.module.ts | 8 +- .../lib/confirmation/confirmation.service.ts | 68 +- .../lib/connection/connection.component.html | 33 +- .../lib/connection/connection.component.scss | 44 +- .../lib/connection/connection.component.ts | 94 +- .../qbm/src/lib/connection/connection.ts | 4 +- .../lib/custom-theme/custom-theme.module.ts | 10 +- .../lib/custom-theme/custom-theme.service.ts | 18 +- .../data-export/data-export.component.html | 108 +- .../data-export/data-export.component.scss | 32 +- .../lib/data-export/data-export.component.ts | 118 +- .../src/lib/data-export/data-export.module.ts | 5 +- .../export-columns.service.spec.ts | 2 +- .../lib/data-export/export-columns.service.ts | 78 +- .../additional-infos.component.html | 55 +- .../additional-infos.component.scss | 36 +- .../additional-infos.component.ts | 16 +- .../client-property-for-table-columns.ts | 8 +- .../lib/data-source-toolbar/column-options.ts | 94 +- .../data-model/data-model-helper.spec.ts | 51 +- .../data-model/data-model-helper.ts | 54 +- .../data-model-wrapper.interface.ts | 6 +- .../data-model/filter-tree-parameter.ts | 4 +- .../group-info-load-parameters.interface.ts | 4 +- .../data-source-item-status.interface.ts | 26 +- .../data-source-paginator.component.html | 8 +- .../data-source-paginator.component.scss | 8 - .../data-source-paginator.component.ts | 45 +- .../data-source-toolbar-custom.component.html | 2 +- .../data-source-toolbar-custom.component.ts | 6 +- ...-source-toolbar-export-method.interface.ts | 7 +- .../data-source-toolbar-filters.interface.ts | 8 +- .../data-source-toolbar-groups.interface.ts | 14 +- ...data-source-toolbar-menu-item.interface.ts | 4 +- .../data-source-toolbar-settings.ts | 11 +- .../data-source-toolbar-view-config-helper.ts | 6 +- ...ta-source-toolbar-view-config.interface.ts | 7 +- .../data-source-toolbar.component.html | 284 +- .../data-source-toolbar.component.scss | 239 +- .../data-source-toolbar.component.ts | 599 +- .../data-source-toolbar.module.ts | 98 +- .../data-source-wrapper.spec.ts | 30 +- .../data-source-wrapper.ts | 67 +- .../data-tile-badge.interface.ts | 3 +- .../filter-tree/filter-tree-database.ts | 36 +- .../filter-tree-entity-wrapper.service.ts | 41 +- .../filter-tree-selection-arg.interface.ts | 16 +- .../filter-tree/filter-tree.component.html | 68 +- .../filter-tree/filter-tree.component.scss | 22 +- .../filter-tree/filter-tree.component.ts | 18 +- .../filter-tree-sidesheet.component.html | 36 + .../filter-tree-sidesheet.component.scss | 90 + .../filter-tree-sidesheet.component.ts | 124 + .../filter-tree-sidesheet.model.ts | 109 + .../filter-wizard.component.html | 63 +- .../filter-wizard.component.scss | 21 +- .../filter-wizard/filter-wizard.component.ts | 90 +- .../filter-wizard/filter-wizard.interfaces.ts | 11 +- .../filter-wizard/filter-wizard.module.ts | 33 +- .../filter-wizard/filter-wizard.service.ts | 14 +- .../predefined-filter-tree.component.scss | 1 - .../predefined-filter-tree.component.ts | 9 +- .../predefined-filter.component.html | 113 +- .../predefined-filter.component.scss | 26 +- .../predefined-filter.component.ts | 247 +- .../save-config-dialog.component.html | 27 +- .../save-config-dialog.component.scss | 2 +- .../save-config-dialog.component.ts | 24 +- .../selection-model-wrapper.spec.ts | 23 +- .../selection-model-wrapper.ts | 40 +- .../data-table-additional-info.model.ts | 8 +- .../data-table-cell.component.html | 5 +- .../data-table-cell.component.scss | 2 +- .../data-table-cell.component.ts | 16 +- .../data-table-column.component.html | 2 +- .../data-table-column.component.scss | 44 +- .../data-table/data-table-column.component.ts | 33 +- .../data-table-display-cell.component.html | 15 +- .../data-table-display-cell.component.ts | 7 +- .../data-table-generic-column.component.html | 8 +- .../data-table-generic-column.component.scss | 4 - .../data-table-generic-column.component.ts | 5 +- .../data-table/data-table-groups.interface.ts | 8 +- .../data-table-row-highlight.interface.ts | 4 +- .../lib/data-table/data-table.component.html | 51 +- .../lib/data-table/data-table.component.scss | 171 +- .../lib/data-table/data-table.component.ts | 95 +- .../src/lib/data-table/data-table.module.ts | 26 +- .../lib/data-table/excluded-columns.pipe.ts | 9 +- .../group-paginator.component.html | 8 +- .../group-paginator.component.ts | 14 +- .../table-accessibility.directive.ts | 23 +- .../data-tile-menu-item.interface.ts | 4 +- .../lib/data-tiles/data-tile.component.html | 71 +- .../lib/data-tiles/data-tile.component.scss | 20 +- .../src/lib/data-tiles/data-tile.component.ts | 68 +- .../lib/data-tiles/data-tiles.component.html | 18 +- .../lib/data-tiles/data-tiles.component.scss | 11 +- .../lib/data-tiles/data-tiles.component.ts | 41 +- .../src/lib/data-tiles/data-tiles.module.ts | 13 +- .../data-tree-wrapper.component.html | 4 + .../data-tree-wrapper.component.scss | 2 +- .../data-tree-wrapper.component.ts | 9 +- .../data-tree-wrapper.module.ts | 21 +- .../checkable-tree.component.html | 35 +- .../checkable-tree.component.scss | 8 +- .../checkable-tree.component.ts | 59 +- .../lib/data-tree/data-tree-no-results.scss | 9 +- .../data-tree-search-results.component.html | 60 +- .../data-tree-search-results.component.scss | 49 +- .../data-tree-search-results.component.ts | 60 +- .../search-result-action.interface.ts | 4 +- .../lib/data-tree/data-tree.component.html | 10 +- .../lib/data-tree/data-tree.component.scss | 28 +- .../src/lib/data-tree/data-tree.component.ts | 26 +- .../qbm/src/lib/data-tree/data-tree.module.ts | 13 +- .../src/lib/data-tree/entity-tree-database.ts | 11 +- .../mat-selection-list-multiple-directive.ts | 33 +- .../node-checked-change.interface.ts | 4 +- .../qbm/src/lib/data-tree/tree-database.ts | 34 +- .../src/lib/data-tree/tree-datasource.spec.ts | 142 +- .../qbm/src/lib/data-tree/tree-datasource.ts | 28 +- .../tree-node-result-parameter.interface.ts | 4 +- .../qbm/src/lib/data-tree/tree-node.ts | 28 +- .../tree-selection-list.component.scss | 4 +- .../tree-selection-list.component.ts | 23 +- .../data-view-auto-table.component.html | 182 + .../data-view-auto-table.component.scss | 95 + .../data-view-auto-table.component.ts | 210 + .../data-view-chipbar.component.html | 67 + .../data-view-chipbar.component.scss | 22 + .../data-view-chipbar.component.ts | 187 + .../data-view-filter.component.html | 10 + .../data-view-filter.component.scss | 0 .../data-view-filter.component.ts | 177 + .../data-view-group.component.html | 8 + .../data-view-group.component.ts | 69 + .../data-view-nested-table.component.html | 90 + .../data-view-nested-table.component.ts | 210 + .../data-view-paginator.component.html | 13 + .../data-view-paginator.component.scss | 8 + .../data-view-paginator.component.ts | 73 + .../data-view-search.component.html | 2 + .../data-view-search.component.scss | 3 + .../data-view-search.component.ts | 125 + .../data-view-selection.component.html | 25 + .../data-view-selection.component.scss | 58 + .../data-view-selection.component.ts | 76 + .../data-view-settings.component.html | 85 + .../data-view-settings.component.ts | 262 + .../data-view-source-factory.service.ts | 51 + .../lib/data-view/data-view-source.spec.ts | 138 + .../qbm/src/lib/data-view/data-view-source.ts | 622 + .../data-view-status.component.html | 34 + .../data-view-status.component.scss | 4 + .../data-view-status.component.ts} | 20 +- .../data-view-toolbar.component.html | 19 + .../data-view-toolbar.component.scss | 9 + .../data-view-toolbar.component.ts | 67 + .../src/lib/data-view/data-view.interface.ts | 100 + .../qbm/src/lib/data-view/data-view.module.ts | 109 + .../projects/qbm/src/lib/date/date.module.ts | 30 +- .../date/calendar/calendar.component.html | 12 +- .../date/calendar/calendar.component.scss | 2 +- .../date/date/calendar/calendar.component.ts | 8 +- .../qbm/src/lib/date/date/date-parser.spec.ts | 86 +- .../qbm/src/lib/date/date/date-parser.ts | 65 +- .../qbm/src/lib/date/date/date.component.html | 50 +- .../qbm/src/lib/date/date/date.component.scss | 19 - .../qbm/src/lib/date/date/date.component.ts | 55 +- .../time-picker/time-picker.component.html | 12 +- .../date/time-picker/time-picker.component.ts | 12 +- .../qbm/src/lib/date/localized-date.pipe.ts | 10 +- .../qbm/src/lib/date/short-date.pipe.ts | 10 +- .../disable-control.directive.ts | 10 +- .../disable-control/disable-control.module.ts | 16 +- .../qbm/src/lib/doc/doc-chapter.service.ts | 52 - .../dynamic-tab-data-provider.directive.ts | 6 +- .../lib/dynamic-tabs/dynamic-tabs.model.ts | 2 +- .../lib/dynamic-tabs/dynamic-tabs.module.ts | 18 +- .../entity-select.component.html | 9 +- .../entity-select/entity-select.component.ts | 42 +- .../entity-select/entity-select.interface.ts | 6 +- .../qbm/src/lib/entity/entity.module.ts | 34 +- .../qbm/src/lib/entity/entity.service.ts | 20 +- .../fk-table-select.component.html | 12 +- .../fk-table-select.component.scss | 2 +- .../fk-table-select.component.ts | 16 +- ...candidate-sidesheet-parameter.interface.ts | 6 +- ...-entity-candidate-sidesheet.component.html | 31 +- ...-entity-candidate-sidesheet.component.scss | 26 +- ...ed-entity-candidate-sidesheet.component.ts | 31 +- .../typed-entity-table-filter.interface.ts | 4 +- .../typed-entity-fk-data.interface.ts | 18 +- .../typed-entity-select.component.html | 23 +- .../typed-entity-select.component.scss | 41 +- .../typed-entity-select.component.ts | 44 +- .../typed-entity-selection-data.interface.ts | 12 +- .../typed-entity-selector.component.html | 46 +- .../typed-entity-selector.component.scss | 39 +- .../typed-entity-selector.component.ts | 31 +- .../projects/qbm/src/lib/ext/ext.component.ts | 25 +- .../projects/qbm/src/lib/ext/ext.directive.ts | 4 +- imxweb/projects/qbm/src/lib/ext/ext.module.ts | 4 +- .../projects/qbm/src/lib/ext/ext.service.ts | 21 +- imxweb/projects/qbm/src/lib/ext/extension.ts | 2 +- .../file-selector.service.spec.ts | 12 +- .../file-selector/file-selector.service.ts | 10 +- .../filter-tile/filter-tile.component.html | 2 +- .../filter-tile/filter-tile.component.scss | 28 +- .../lib/filter-tile/filter-tile.component.ts | 6 +- .../fk-advanced-picker/candidate-entity.ts | 31 +- .../fk-advanced-picker/candidate.interface.ts | 6 +- .../fk-advanced-picker.component.html | 33 +- .../fk-advanced-picker.component.scss | 49 +- .../fk-advanced-picker.component.ts | 34 +- .../fk-advanced-picker.module.ts | 2 +- .../fk-candidate-entity-builder.service.ts | 15 +- .../fk-candidates-data.interface.ts | 21 +- .../fk-candidates.component.html | 6 +- .../fk-candidates.component.scss | 9 - .../fk-candidates/fk-candidates.component.ts | 72 +- .../fk-selector.component.html | 17 +- .../fk-selector.component.scss | 39 - .../fk-selector.component.ts | 42 +- .../foreign-key-picker-data.interface.ts | 16 +- .../foreign-key-selection.interface.ts | 8 +- .../src/lib/fk-container/dyn-fk-container.ts | 4 +- .../qbm/src/lib/fk-container/fk-container.ts | 21 +- .../fk-hierarchical-dialog.component.html | 65 +- .../fk-hierarchical-dialog.component.scss | 47 +- .../fk-hierarchical-dialog.component.spec.ts | 11 +- .../fk-hierarchical-dialog.component.ts | 32 +- .../fk-hierarchical-dialog.module.ts | 14 +- .../hierarchical-candidate.ts | 10 +- .../hierarchical-fk-database.ts | 61 +- .../help-contextual-dialog.component.html | 6 +- .../help-contextual-dialog.component.scss | 8 +- .../help-contextual-dialog.component.ts | 12 +- .../help-contextual.component.html | 2 +- .../help-contextual.component.scss | 27 +- .../help-contextual.component.ts | 37 +- .../help-contextual/help-contextual.module.ts | 21 +- .../help-contextual.service.ts | 30 +- .../lib/hyperview/connector-provider.spec.ts | 36 +- .../src/lib/hyperview/connector-provider.ts | 29 +- .../qbm/src/lib/hyperview/connector.spec.ts | 6 +- .../qbm/src/lib/hyperview/connector.ts | 15 +- .../qbm/src/lib/hyperview/connectors.spec.ts | 38 +- .../qbm/src/lib/hyperview/connectors.ts | 14 +- .../hyperview-layout-hierarchical.ts | 65 +- .../hyperview-layout-horizontal.spec.ts | 7 +- .../hyperview/hyperview-layout-horizontal.ts | 12 +- .../hyperview-layout-vertical.spec.ts | 9 +- .../hyperview/hyperview-layout-vertical.ts | 15 +- .../qbm/src/lib/hyperview/hyperview-types.ts | 2 +- .../lib/hyperview/hyperview.component.html | 36 +- .../lib/hyperview/hyperview.component.scss | 21 +- .../src/lib/hyperview/hyperview.component.ts | 53 +- .../qbm/src/lib/hyperview/hyperview.module.ts | 27 +- .../lib/hyperview/listshape.component.scss | 13 +- .../src/lib/hyperview/listshape.component.ts | 7 +- .../hyperview/propertyshape.component.html | 10 +- .../hyperview/propertyshape.component.scss | 21 +- .../lib/hyperview/propertyshape.component.ts | 26 +- .../src/lib/hyperview/shape.component.html | 20 +- .../src/lib/hyperview/shape.component.scss | 20 +- .../qbm/src/lib/hyperview/shape.component.ts | 32 +- .../lib/hyperview/simpleshape.component.html | 4 +- .../lib/hyperview/simpleshape.component.ts | 6 +- .../src/lib/hyperview/zoom-pan.directive.ts | 7 +- .../lib/icon-stack/icon-stack.component.html | 2 +- .../lib/icon-stack/icon-stack.component.scss | 9 +- .../lib/icon-stack/icon-stack.component.ts | 8 +- .../image-select/image-select.component.html | 73 +- .../image-select/image-select.component.scss | 40 - .../image-select/image-select.component.ts | 10 +- .../image-view/image-view.component.html | 8 +- .../image-view/image-view.component.scss | 1 - .../image/image-view/image-view.component.ts | 6 +- .../qbm/src/lib/image/image.module.ts | 18 +- .../lib/images/base64-image.service.spec.ts | 24 +- .../src/lib/images/base64-image.service.ts | 6 +- .../src/lib/indexbar/indexbar.component.html | 11 +- .../src/lib/indexbar/indexbar.component.ts | 149 +- .../info-badge/info-badge.component.html | 7 +- .../info-badge/info-badge.component.scss | 30 - .../info-badge/info-badge.component.ts | 5 +- .../info-button/info-button.component.html | 2 +- .../info-button/info-button.component.scss | 43 +- .../info-button/info-button.component.ts | 32 +- .../info-dialog/info-dialog.component.html | 4 +- .../info-dialog/info-dialog.component.scss | 6 +- .../info-dialog/info-dialog.component.ts | 16 +- .../info-modal-dialog.module.ts | 2 +- .../jobqueue-overview.component.html | 10 +- .../jobqueue-overview.component.scss | 21 +- .../jobqueue-overview.component.ts | 112 +- .../jobqueue-overview.module.ts | 2 +- .../jobqueue-overview.service.spec.ts | 6 +- .../jobqueue-overview.service.ts | 40 +- .../src/lib/lds-replace/lds-replace.module.ts | 16 +- .../src/lib/lds-replace/lds-replace.pipe.ts | 4 +- .../qbm/src/lib/login/login.component.html | 118 +- .../qbm/src/lib/login/login.component.scss | 109 +- .../qbm/src/lib/login/login.component.ts | 260 +- .../mast-head-menu-item.interface.ts | 2 +- .../lib/mast-head/mast-head-menu.interface.ts | 2 +- .../lib/mast-head/mast-head.component.html | 42 +- .../lib/mast-head/mast-head.component.scss | 66 +- .../src/lib/mast-head/mast-head.component.ts | 99 +- .../qbm/src/lib/mast-head/mast-head.module.ts | 26 +- .../src/lib/mast-head/mast-head.service.ts | 21 +- .../master-detail.component.html | 15 - .../master-detail.component.scss | 17 +- .../master-detail/master-detail.component.ts | 139 - .../lib/menu/menu-item/menu-item.interface.ts | 14 +- .../src/lib/menu/menu-item/menu-item.spec.ts | 96 +- ...navigation-commands-menu-item.interface.ts | 2 +- .../related-application-menu-item.ts | 58 +- .../related-application.interface.ts | 12 +- .../qbm/src/lib/menu/menu.component.html | 19 - .../qbm/src/lib/menu/menu.component.scss | 113 - .../qbm/src/lib/menu/menu.component.ts | 106 - .../projects/qbm/src/lib/menu/menu.module.ts | 43 - .../projects/qbm/src/lib/menu/menu.service.ts | 53 +- .../message-dialog-result.enum.ts | 4 +- .../message-dialog.component.html | 61 +- .../message-dialog.component.scss | 7 + .../message-dialog.component.ts | 22 +- .../message-dialog/message-dialog.service.ts} | 15 +- .../message-parameter.interface.ts | 3 +- .../src/lib/model-css/model-css.service.ts | 25 +- .../multi-select-formcontrol.component.html | 60 +- .../multi-select-formcontrol.component.scss | 41 +- .../multi-select-formcontrol.component.ts | 75 +- .../multi-select-formcontrol.module.ts | 8 +- .../src/lib/multi-value/multi-value.module.ts | 12 +- .../lib/multi-value/multi-value.service.ts | 14 +- .../object-history-api.service.ts | 11 +- .../object-history-gridview.component.html | 28 +- .../object-history-gridview.component.scss | 6 +- .../object-history-gridview.component.ts | 46 +- ...ct-history-state-comparison.component.html | 39 +- ...ct-history-state-comparison.component.scss | 16 +- ...ject-history-state-comparison.component.ts | 44 +- ...ject-history-state-overview.component.html | 39 +- ...ject-history-state-overview.component.scss | 17 +- ...object-history-state-overview.component.ts | 44 +- .../object-history.component.html | 101 +- .../object-history.component.scss | 107 +- .../object-history.component.ts | 137 +- .../object-history/object-history.module.ts | 39 +- .../object-history/object-history.service.ts | 27 +- .../ordered-list/ordered-list.component.html | 22 +- .../ordered-list/ordered-list.component.scss | 29 +- .../ordered-list/ordered-list.component.ts | 16 +- .../lib/ordered-list/ordered-list.module.ts | 37 +- .../parameter-replacement.interface.ts | 2 +- .../parameterized-text.component.html | 2 + .../parameterized-text.component.scss | 2 +- .../parameterized-text.component.ts | 7 +- .../parameterized-text.interface.ts | 4 +- .../parameterized-text.module.ts | 16 +- .../parameterized-text.service.ts | 14 +- .../text-token.interface.ts | 2 +- .../src/lib/plugins/plugin-loader.service.ts | 260 - .../processing-queue.interface.ts | 173 + .../processing-queue.service.ts | 136 + .../processing-queue/processing-queue.spec.ts | 132 + .../progressbar/progressbar.component.html | 12 +- .../progressbar/progressbar.component.scss | 22 - .../lib/progressbar/progressbar.component.ts | 11 +- imxweb/projects/qbm/src/lib/qbm.module.ts | 83 +- .../component-can-deactivate.interface.ts | 2 +- .../src/lib/route-guard/route-guard.module.ts | 12 +- .../lib/route-guard/route-guard.service.ts | 58 +- .../qbm/src/lib/search/db-object-info.ts | 8 +- .../qbm/src/lib/search/search.service.ts | 48 +- .../qbm/src/lib/searchbar/iSearchService.ts | 14 +- .../lib/searchbar/searchbar.component.html | 74 +- .../lib/searchbar/searchbar.component.scss | 100 +- .../src/lib/searchbar/searchbar.component.ts | 64 +- .../lib/select/autocomplete.component.html | 64 - .../lib/select/autocomplete.component.scss | 81 - .../src/lib/select/autocomplete.component.ts | 264 - .../data-navigation-parameters.interface.ts | 4 +- .../src/lib/select/fk-selection-container.ts | 38 +- .../qbm/src/lib/select/select-data-source.ts | 63 - .../qbm/src/lib/select/select.component.html | 40 - .../qbm/src/lib/select/select.component.scss | 40 - .../qbm/src/lib/select/select.component.ts | 222 - .../selected-elements-dialog.component.html | 14 +- .../selected-elements-dialog.component.scss | 35 +- .../selected-elements-dialog.component.ts | 44 +- .../selected-elements-dialog.model.ts | 5 +- .../selected-elements.component.html | 16 +- .../selected-elements.component.scss | 7 +- .../selected-elements.component.ts | 52 +- .../selected-elements.module.ts | 3 +- .../src/lib/services/device-state.service.ts | 80 - .../auth-prop-data-provider.interface.ts | 3 +- .../src/lib/session/imx-session.service.ts | 24 +- .../qbm/src/lib/session/session-state.spec.ts | 49 +- .../qbm/src/lib/session/session-state.ts | 104 +- .../qbm/src/lib/settings/settings-service.ts | 11 +- .../side-navigation-view-interfaces.ts | 11 +- .../side-navigation-view.component.html | 25 +- .../side-navigation-view.component.scss | 1 - .../side-navigation-view.component.ts | 59 +- .../side-navigation-view.module.ts | 2 +- .../custom-tree-control.component.html | 111 + .../custom-tree-control.component.scss | 48 + .../custom-tree-control.component.ts | 152 + .../sidenav-tree-dynamic-extension.ts | 68 +- .../sidenav-tree/sidenav-tree.component.html | 106 +- .../sidenav-tree/sidenav-tree.component.scss | 280 +- .../sidenav-tree/sidenav-tree.component.ts | 46 +- .../qbm/src/lib/snackbar/snack-bar.service.ts | 26 +- .../qbm/src/lib/splash/splash.service.ts | 16 +- .../qbm/src/lib/sqlwizard/SqlNodeView.ts | 213 +- .../sqlwizard/column-selection.component.html | 12 +- .../sqlwizard/column-selection.component.ts | 161 +- .../lib/sqlwizard/date-picker.component.html | 14 +- .../lib/sqlwizard/date-picker.component.ts | 29 +- .../simple-expression.component.html | 17 +- .../simple-expression.component.scss | 11 +- .../sqlwizard/simple-expression.component.ts | 82 +- .../single-expression.component.html | 47 +- .../sqlwizard/single-expression.component.ts | 60 +- .../lib/sqlwizard/single-value.component.html | 31 +- .../lib/sqlwizard/single-value.component.ts | 181 +- .../lib/sqlwizard/sqlwizard-api.service.ts | 5 +- .../lib/sqlwizard/sqlwizard.component.html | 15 +- .../src/lib/sqlwizard/sqlwizard.component.ts | 30 +- .../qbm/src/lib/sqlwizard/sqlwizard.module.ts | 34 +- .../qbm/src/lib/sqlwizard/sqlwizard.scss | 50 +- .../src/lib/sqlwizard/sqlwizard.service.ts | 14 +- .../sqlwizard/table-selection.component.html | 3 +- .../sqlwizard/table-selection.component.ts | 31 +- .../where-clause-expression.component.ts | 25 +- .../qbm/src/lib/storage/storage.module.ts | 12 +- .../src/lib/storage/storage.service.spec.ts | 3 +- .../qbm/src/lib/storage/storage.service.ts | 12 +- .../src/lib/styles/data-explorer-common.scss | 158 +- .../styles/data-explorer-details-common.scss | 13 +- .../qbm/src/lib/styles/imx-page-title.scss | 38 +- .../lib/system-info/system-info.service.ts | 13 +- .../lib/table-image/table-image.service.ts | 10 +- .../temp-billboard.component.ts | 139 - .../src/lib/testing/TestHelperModule.spec.ts | 13 +- .../src/lib/testing/base-imx-api-mock.spec.ts | 57 +- .../qbm/src/lib/testing/clear-styles.spec.ts | 8 +- .../qbm/src/lib/testing/dst-mock-help.spec.ts | 6 +- .../lib/testing/entity-column-stub.spec.ts | 27 +- .../lib/testing/entity-schema-stub.spec.ts | 15 +- .../qbm/src/lib/tile/tile-variables.scss | 1 - .../qbm/src/lib/tile/tile.component.html | 113 +- .../qbm/src/lib/tile/tile.component.scss | 63 +- .../qbm/src/lib/tile/tile.component.ts | 26 +- .../projects/qbm/src/lib/tile/tile.module.ts | 24 +- .../src/lib/timeline/timeline.component.html | 30 +- .../src/lib/timeline/timeline.component.scss | 63 +- .../src/lib/timeline/timeline.component.ts | 27 +- .../qbm/src/lib/timeline/timeline.model.ts | 53 + .../projects/qbm/src/lib/timeline/timeline.ts | 4 +- .../translation-editor.component.html | 25 +- .../translation-editor.component.scss | 20 +- .../translation-editor.component.ts | 90 +- .../imx-missing-translation-handler.spec.ts | 52 +- .../imx-missing-translation-handler.ts | 6 +- .../lib/translation/imx-translate-loader.ts | 6 +- .../imx-translation-provider.service.ts | 78 +- .../qbm/src/lib/translation/text-container.ts | 2 +- .../qbm/src/lib/treeTable/MatColumn.html | 35 +- .../qbm/src/lib/treeTable/MatColumn.scss | 2 +- .../qbm/src/lib/treeTable/MatColumn.ts | 41 +- .../qbm/src/lib/treeTable/imx-data-source.ts | 67 +- .../lib/treeTable/tableTestClasses.spec.ts | 13 +- .../lib/treeTable/treeTable.component.html | 48 +- .../src/lib/treeTable/treeTable.component.ts | 45 +- .../two-factor-authentication.component.ts | 28 +- .../two-factor-authentication.service.ts | 8 +- .../src/lib/user-message/message.interface.ts | 2 +- .../user-message/user-message.component.html | 11 +- .../user-message/user-message.component.scss | 6 +- .../user-message/user-message.component.ts | 45 +- .../lib/user-message/user-message.module.ts | 10 +- .../lib/user-message/user-message.service.ts | 4 +- .../src/lib/value-wrapper/value-wrapper.ts | 2 +- imxweb/projects/qbm/src/public_api.ts | 216 +- imxweb/projects/qbm/src/test.ts | 18 +- imxweb/projects/qbm/tsconfig.lib.json | 9 +- imxweb/projects/qbm/tsconfig.spec.json | 15 +- imxweb/projects/qbm/tslint.json | 17 - .../.compodocrc.json | 2 +- .../qer-app-operationssupport/.eslintrc.json | 38 + .../qer-app-operationssupport/README.md | 3 +- .../dpr-api-client.service.ts | 11 +- .../qer-app-operationssupport/karma.conf.js | 15 +- .../qer-app-operationssupport/package.json | 6 +- .../qer-app-operationssupport/prebuild.js | 6 + .../qer-app-operationssupport/project.json | 221 + .../src/app/app-routing.module.ts | 40 +- .../src/app/app.component.html | 5 +- .../src/app/app.component.scss | 25 +- .../src/app/app.component.ts | 85 +- .../src/app/app.module.ts | 68 +- .../src/app/app.service.ts | 101 +- .../app/base/ops-sql-wizard-api.service.ts | 8 +- .../src/app/base/subscription.service.ts | 6 +- .../app/dashboard/dashboard.component.html | 20 +- .../app/dashboard/dashboard.component.scss | 2 +- .../src/app/dashboard/dashboard.component.ts | 10 +- .../src/app/dashboard/dashboard.module.ts | 13 +- .../data-changes-sidesheet.component.html | 12 +- .../data-changes-sidesheet.component.scss | 1 - .../data-changes-sidesheet.component.ts | 28 +- .../data-changes/data-changes.component.html | 173 +- .../data-changes/data-changes.component.scss | 90 +- .../data-changes/data-changes.component.ts | 279 +- .../app/data-changes/data-changes.module.ts | 62 +- .../app/data-changes/data-changes.service.ts | 50 +- .../src/app/db-queue/db-queue.component.html | 23 +- .../src/app/db-queue/db-queue.component.scss | 17 - .../src/app/db-queue/db-queue.component.ts | 21 +- .../src/app/db-queue/db-queue.module.ts | 15 +- .../src/app/db-queue/db-queue.service.ts | 8 +- .../outstanding-manager-guard.service.ts | 12 +- .../system-status-route-guard.service.ts | 17 +- .../app/hyperview/ops-hyperview.service.ts | 10 +- .../src/app/information/issue-tiles.scss | 4 +- .../notifications/notification-issue-item.ts | 4 +- .../notifications.component.html | 18 +- .../notifications.component.scss | 32 +- .../notifications/notifications.component.ts | 7 +- .../notifications/notifications.module.ts | 8 +- .../notifications.service.spec.ts | 82 +- .../notifications/notifications.service.ts | 35 +- .../service-issues/service-issue-item.ts | 9 +- .../service-issue.component.html | 7 +- .../service-issue.component.scss | 12 +- .../service-issues/service-issue.component.ts | 4 +- .../service-issues.component.html | 16 +- .../service-issues.component.scss | 12 +- .../service-issues.component.ts | 10 +- .../service-issues/service-issues.models.ts | 2 +- .../service-issues/service-issues.module.ts | 18 +- .../service-issues.service.spec.ts | 395 +- .../service-issues/service-issues.service.ts | 95 +- .../system-overview.component.html | 29 +- .../system-overview.component.ts | 24 +- .../system-overview/system-overview.module.ts | 15 +- .../system-overview.service.ts | 6 +- .../system-tree/system-tree-database.spec.ts | 36 +- .../system-tree/system-tree-database.ts | 26 +- .../system-tree-datasource.spec.ts | 95 +- .../system-tree/system-tree-datasource.ts | 34 +- .../system-tree/system-tree-node.spec.ts | 22 +- .../system-tree/system-tree-node.ts | 8 +- .../system-status-information.interface.ts | 2 +- .../system-status.component.html | 55 +- .../system-status.component.scss | 17 +- .../system-status/system-status.component.ts | 79 +- .../system-status/system-status.module.ts | 15 +- .../system-status/system-status.service.ts | 15 +- .../src/app/journal/filter-tile-params.ts | 4 +- .../src/app/journal/journal.component.html | 46 +- .../src/app/journal/journal.component.scss | 25 +- .../src/app/journal/journal.component.ts | 25 +- .../src/app/journal/journal.module.ts | 8 +- .../src/app/journal/journal.service.ts | 15 +- .../object-overview.component.html | 108 +- .../object-overview.component.scss | 58 +- .../object-overview.component.ts | 114 +- .../object-overview/object-overview.module.ts | 27 +- .../object-overview.service.ts | 9 +- .../opsupport-history-api.service.ts | 13 +- .../object-overview/person-db-queue-info.ts | 8 +- .../object-overview/person-job-queue-info.ts | 7 +- .../object-search/object-search.component.ts | 19 +- .../app/object-search/object-search.module.ts | 14 +- .../src/app/permissions/permissions-helper.ts | 6 +- .../permissions/permissions.service.spec.ts | 8 +- .../app/permissions/permissions.service.ts | 8 +- .../error-message-sidesheet.component.html | 7 +- .../error-message-sidesheet.component.scss | 15 +- .../error-message-sidesheet.component.ts | 6 +- .../frozen-jobs/frozen-jobs.component.html | 37 +- .../frozen-jobs/frozen-jobs.component.scss | 39 - .../frozen-jobs/frozen-jobs.component.ts | 59 +- .../frozen-jobs/frozen-jobs.service.spec.ts | 10 +- .../frozen-jobs/frozen-jobs.service.ts | 8 +- .../frozen-jobs/queue-tree.service.ts | 113 +- .../single-frozen-job.component.html | 100 +- .../single-frozen-job.component.scss | 34 +- .../single-frozen-job.component.ts | 77 +- .../job-chains/job-chains.component.html | 26 +- .../job-chains/job-chains.component.scss | 15 - .../job-chains/job-chains.component.ts | 22 +- .../job-chains/job-chains.service.spec.ts | 12 +- .../job-chains/job-chains.service.ts | 10 +- .../job-history/job-history.component.html | 25 +- .../job-history/job-history.component.scss | 27 +- .../job-history/job-history.component.ts | 29 +- .../job-history/job-history.service.ts | 10 +- .../job-performance-queues.service.ts | 2 +- .../job-performance.component.html | 28 +- .../job-performance.component.scss | 19 +- .../job-performance.component.ts | 31 +- .../job-performance.service.spec.ts | 10 +- .../job-performance.service.ts | 10 +- .../jobs-gridview.component.html | 26 +- .../jobs-gridview.component.scss | 45 +- .../jobs-gridview/jobs-gridview.component.ts | 48 +- .../app/processes/jobs/jobs.component.html | 21 +- .../app/processes/jobs/jobs.component.scss | 15 +- .../src/app/processes/jobs/jobs.component.ts | 11 +- .../app/processes/jobs/queue-jobs.service.ts | 23 +- .../change-operation-sidesheet.component.html | 24 +- .../change-operation-sidesheet.component.scss | 2 +- .../change-operation-sidesheet.component.ts | 22 +- .../change-operation-table.component.html | 7 +- .../change-operation-table.component.scss | 3 +- .../change-operation-table.component.ts | 62 +- .../objects-by-id/object-by-id.service.ts | 10 +- .../objects-by-id.component.html | 23 +- .../objects-by-id.component.scss | 68 +- .../objects-by-id/objects-by-id.component.ts | 27 +- .../src/app/processes/processes.module.ts | 22 +- .../job-servers-details.component.html | 14 +- .../job-servers-details.component.scss | 11 +- .../job-servers-details.component.spec.ts | 21 +- .../job-servers-details.component.ts | 23 +- .../job-servers-edit.component.html | 20 +- .../job-servers-edit.component.scss | 2 +- .../job-servers-edit.component.spec.ts | 15 +- .../job-servers-edit.component.ts | 8 +- .../job-servers-gridview.component.html | 13 +- .../job-servers-gridview.component.scss | 23 - .../job-servers-gridview.component.ts | 43 +- .../app/service-report/job-servers.service.ts | 15 +- .../service-availability.component.html | 14 +- .../service-availability.component.scss | 4 +- .../service-availability.component.ts | 4 +- .../service-report.component.html | 13 +- .../service-report.component.scss | 22 +- .../service-report.component.ts | 7 +- .../service-report/service-report.module.ts | 10 +- .../services-inactive.component.html | 6 +- .../services-inactive.component.ts | 8 +- .../sync-information.component.html | 32 +- .../sync-information.component.scss | 17 - .../sync-information.component.ts | 22 +- .../sync-journal/sync-journal.component.html | 39 +- .../sync-journal/sync-journal.component.scss | 16 - .../sync-journal/sync-journal.component.ts | 61 +- .../src/app/sync/sync.module.ts | 30 +- .../src/app/sync/sync.service.ts | 13 +- .../app/test-utilities/imx-api-mock.spec.ts | 276 +- .../imx-session.service.spy.spec.ts | 60 +- ...x-translation-provider.service.spy.spec.ts | 10 +- .../app/test-utilities/router-mock.spec.ts | 14 +- .../test-utilities/test-helper.module.spec.ts | 12 +- .../typed-entity-provider.spec.ts | 32 +- .../unresolved-refs.component.html | 18 +- .../unresolved-refs.component.scss | 16 - .../unresolved-refs.component.ts | 16 +- .../unresolved-refs/unresolved-refs.module.ts | 19 +- .../unresolved-refs.service.ts | 8 +- .../web-applications.component.html | 30 +- .../web-applications.component.scss | 26 +- .../web-applications.component.ts | 14 +- .../web-applications.module.ts | 22 +- .../web-applications.service.ts | 8 +- .../src/environments/environment.prod.ts | 4 +- .../src/environments/environment.ts | 4 +- .../qer-app-operationssupport/src/index.html | 20 +- .../qer-app-operationssupport/src/main.ts | 4 +- .../src/polyfills.ts | 21 +- .../qer-app-operationssupport/src/styles.scss | 280 +- .../qer-app-operationssupport/src/test.ts | 30 +- .../tsconfig-es5.app.json | 8 +- .../tsconfig.app.json | 14 +- .../tsconfig.spec.json | 16 +- .../qer-app-operationssupport/tslint.json | 17 - .../projects/qer-app-portal/.compodocrc.json | 2 +- imxweb/projects/qer-app-portal/.eslintrc.json | 35 + imxweb/projects/qer-app-portal/README.md | 49 +- imxweb/projects/qer-app-portal/karma.conf.js | 13 +- imxweb/projects/qer-app-portal/package.json | 5 +- imxweb/projects/qer-app-portal/project.json | 214 + .../src/app/app-routing.module.ts | 28 +- .../qer-app-portal/src/app/app.component.html | 1 - .../qer-app-portal/src/app/app.component.scss | 20 +- .../qer-app-portal/src/app/app.component.ts | 96 +- .../qer-app-portal/src/app/app.module.ts | 41 +- .../qer-app-portal/src/app/app.service.ts | 101 +- .../app/hyperview/portal-hyperview.service.ts | 16 +- .../app/portal-doc-configuration.service.ts | 54 - .../src/app/portal-history.service.ts | 13 +- .../src/environments/environment.prod.ts | 4 +- .../src/environments/environment.ts | 7 +- imxweb/projects/qer-app-portal/src/index.html | 20 +- imxweb/projects/qer-app-portal/src/main.ts | 7 +- .../projects/qer-app-portal/src/polyfills.ts | 22 +- .../projects/qer-app-portal/src/styles.scss | 129 +- imxweb/projects/qer-app-portal/src/test.ts | 23 +- .../qer-app-portal/tsconfig-es5.app.json | 8 +- .../projects/qer-app-portal/tsconfig.app.json | 13 +- .../qer-app-portal/tsconfig.spec.json | 16 +- imxweb/projects/qer-app-portal/tslint.json | 17 - .../qer-app-pwdportal/.compodocrc.json | 2 +- .../projects/qer-app-pwdportal/.eslintrc.json | 35 + .../projects/qer-app-pwdportal/karma.conf.js | 13 +- .../projects/qer-app-pwdportal/package.json | 4 +- .../projects/qer-app-pwdportal/project.json | 211 + .../src/app/app-routing.module.ts | 27 +- .../src/app/app.component.html | 25 +- .../src/app/app.component.scss | 14 +- .../src/app/app.component.ts | 79 +- .../qer-app-pwdportal/src/app/app.module.ts | 25 +- .../qer-app-pwdportal/src/app/app.service.ts | 92 +- .../src/app/pwd-sql-wizard-api.service.ts | 6 +- .../src/environments/environment.prod.ts | 4 +- .../src/environments/environment.ts | 6 +- .../projects/qer-app-pwdportal/src/index.html | 28 +- imxweb/projects/qer-app-pwdportal/src/main.ts | 7 +- .../qer-app-pwdportal/src/polyfills.ts | 20 +- .../qer-app-pwdportal/src/styles.scss | 17 +- imxweb/projects/qer-app-pwdportal/src/test.ts | 27 +- .../qer-app-pwdportal/tsconfig-es5.app.json | 8 +- .../qer-app-pwdportal/tsconfig.app.json | 13 +- .../qer-app-pwdportal/tsconfig.spec.json | 15 +- imxweb/projects/qer-app-pwdportal/tslint.json | 17 - imxweb/projects/qer/.compodocrc.json | 2 +- imxweb/projects/qer/.eslintrc.json | 35 + imxweb/projects/qer/README.md | 2 +- .../qer/additionalDocumentation/identity.md | 39 +- .../qer/additionalDocumentation/it-shop.md | 50 +- .../qer/additionalDocumentation/other.md | 26 +- .../qer/additionalDocumentation/roles.md | 8 +- imxweb/projects/qer/karma.conf.js | 11 +- imxweb/projects/qer/ng-package.json | 2 +- imxweb/projects/qer/package.json | 9 +- imxweb/projects/qer/project.json | 61 + imxweb/projects/qer/src/default-mocks.spec.ts | 4 +- .../qer/src/lib/about/portal-about.service.ts | 55 + .../addressbook-detail.component.html | 1 - .../addressbook-detail.component.scss | 8 - .../addressbook-detail.component.ts | 11 +- .../addressbook-detail.interface.ts | 4 +- .../addressbook/addressbook.component.html | 44 +- .../addressbook/addressbook.component.scss | 11 +- .../lib/addressbook/addressbook.component.ts | 135 +- .../src/lib/addressbook/addressbook.module.ts | 29 +- .../lib/addressbook/addressbook.service.ts | 40 +- .../admin/authentication-factors.interface.ts | 2 +- .../src/lib/admin/feature-config.service.ts | 14 +- .../src/lib/admin/qer-permissions-helper.ts | 37 +- .../src/lib/admin/qer-permissions.service.ts | 48 +- .../approval-level-form.component.html | 34 +- .../approval-level-form.component.scss | 2 +- .../approval-level-form.component.ts | 12 +- .../approval-step-form.component.html | 22 +- .../approval-step-form.component.scss | 3 +- .../approval-step-form.component.ts | 19 +- .../approval-workflow-constants.service.ts | 208 +- .../approval-workflow-data.service.ts | 37 +- ...approval-workflow-edit-info.component.html | 26 - ...approval-workflow-edit-info.component.scss | 61 - .../approval-workflow-edit.component.html | 150 +- .../approval-workflow-edit.component.scss | 59 +- .../approval-workflow-edit.component.ts | 390 +- .../approval-workflow.model.ts | 6 +- .../container-dom.component.scss | 2 +- .../container-dom/container-dom.component.ts | 7 +- .../dom-manager.service.ts | 22 +- .../edge-dom/edge-dom.component.html | 2 +- .../edge-dom/edge-dom.component.scss | 4 +- .../edge-dom/edge-dom.component.ts | 10 +- .../node-dom/node-dom.component.ts | 5 +- .../approval-workflow-form.component.html | 32 +- .../approval-workflow-form.component.scss | 2 +- .../approval-workflow-form.component.ts | 22 +- .../approval-workflow-home.component.html | 37 +- .../approval-workflow-home.component.scss | 31 +- .../approval-workflow-home.component.ts | 59 +- .../approval-workflow-styles.scss | 122 - .../approval-workflow.interface.ts | 18 +- .../approval-workflows.module.ts | 31 +- .../approval-workflows/awm-colors.service.ts | 8 +- .../approval-workflows/form-data.service.ts | 107 +- .../archived-requests.component.html | 20 +- .../archived-requests.component.scss | 34 +- .../archived-requests.component.ts | 15 +- .../archived-requests.module.ts | 84 +- .../archived-requests.service.ts | 34 +- .../businessowner-addon-tile.component.html | 12 +- .../businessowner-addon-tile.component.ts | 5 +- .../businessowner-addon-tile.module.ts | 14 +- ...businessowner-overview-tile.component.html | 2 +- .../businessowner-overview-tile.component.ts | 5 +- .../businessowner-overview-tile.module.ts | 13 +- .../data-explorer-registry.service.ts | 13 +- .../data-explorer-view.component.html | 2 +- .../data-explorer-view.component.scss | 154 - .../data-explorer-view.component.ts | 12 +- .../data-explorer-view.module.ts | 17 +- .../delegation/delegation-guard.service.ts | 56 + .../lib/delegation/delegation.component.html | 130 +- .../lib/delegation/delegation.component.scss | 139 +- .../lib/delegation/delegation.component.ts | 88 +- .../src/lib/delegation/delegation.module.ts | 103 +- .../src/lib/delegation/delegation.service.ts | 88 +- .../dynamic-exclusion-dialog.component.html | 20 +- .../dynamic-exclusion-dialog.component.scss | 3 - .../dynamic-exclusion-dialog.component.ts | 14 +- .../dynamic-exclusion-dialog.module.ts | 28 +- .../filter-sqlwizard.service.ts | 45 + .../lib/guards/application-guard.service.ts | 14 +- .../lib/guards/data-explorer-guard.service.ts | 87 - .../src/lib/guards/feature-guard.service.ts | 12 +- .../guards/itshop-pattern-guard.service.ts | 14 +- .../src/lib/guards/manager-guard.service.ts | 12 +- .../guards/person-admin-guard.service.spec.ts | 3 +- .../lib/guards/person-admin-guard.service.ts | 12 +- .../lib/guards/rule-admin-guard.service.ts | 14 +- .../lib/guards/shop-admin-guard.service.ts | 12 +- .../qer/src/lib/guards/shop-guard.service.ts | 12 +- .../guards/shop-statistics-guard.service.ts | 12 +- .../lib/guards/statistics-guard.service.ts | 12 +- .../lib/guards/struct-admin-guard.service.ts | 12 +- .../helper-alert-content.interface.ts | 4 +- .../create-new-identity.component.html | 97 +- .../create-new-identity.component.scss | 22 +- .../create-new-identity.component.ts | 196 +- .../duplicate-check-parameter.interface.ts | 4 +- .../duplicates-sidesheet.component.html | 28 +- .../duplicates-sidesheet.component.scss | 14 +- .../duplicates-sidesheet.component.ts | 61 +- .../identities/identities-reports.service.ts | 43 +- .../lib/identities/identities.component.html | 181 +- .../lib/identities/identities.component.scss | 15 +- .../lib/identities/identities.component.ts | 225 +- .../src/lib/identities/identities.module.ts | 106 +- .../src/lib/identities/identities.service.ts | 101 +- .../assignments/assignments.component.html | 30 +- .../assignments/assignments.component.scss | 156 +- .../assignments/assignments.component.ts | 94 +- ...ty-role-memberships-parameter.interface.ts | 4 +- .../identity-role-memberships.component.html | 17 +- .../identity-role-memberships.component.scss | 7 +- .../identity-role-memberships.component.ts | 39 +- .../identity-role-memberships.module.ts | 14 +- .../identity-role-memberships.service.ts | 106 +- .../identity-sidesheet.component.html | 181 +- .../identity-sidesheet.component.scss | 170 +- .../identity-sidesheet.component.ts | 154 +- .../identities/test/common-test-mocks.spec.ts | 55 +- .../irequestable-entitlement-type.ts | 9 +- .../member-selector.component.html | 10 +- .../member-selector.component.ts | 10 +- .../reason-sidesheet.component.ts | 13 +- .../request-config-members.component.html | 46 +- .../request-config-members.component.scss | 35 - .../request-config-members.component.ts | 102 +- .../request-config-sidesheet-common.scss | 109 +- .../request-config-sidesheet.component.html | 45 +- .../request-config-sidesheet.component.ts | 27 +- .../itshop-config/request-config.module.ts | 93 +- .../request-shelf-entitlements.component.html | 18 +- .../request-shelf-entitlements.component.ts | 56 +- .../request-shelf-sidesheet.component.html | 28 +- .../request-shelf-sidesheet.component.ts | 20 +- .../request-shelves/request-shelf-token.ts | 6 +- .../request-shelves.component.html | 8 +- .../request-shelves.component.ts | 33 +- .../requestable-entitlement-type.service.ts | 32 +- .../itshop-config/requestable-entl-type.ts | 54 +- .../requests-entity-selector.component.html | 5 +- .../requests-entity-selector.component.ts | 46 +- .../src/lib/itshop-config/requests.service.ts | 78 +- .../requests/requests.component.html | 65 +- .../requests/requests.component.scss | 54 +- .../requests/requests.component.ts | 97 +- .../resource-entitlement-type.ts | 33 +- .../test/requests-configuration-mocks.ts | 29 +- .../duplicate-pattern-item.ts | 5 +- .../duplicate-pattern-items.component.html | 16 +- .../duplicate-pattern-items.component.scss | 11 +- .../duplicate-pattern-items.component.ts | 21 +- ...itshop-pattern-add-products.component.html | 48 +- ...itshop-pattern-add-products.component.scss | 42 +- ...hop-pattern-add-products.component.spec.ts | 6 +- .../itshop-pattern-add-products.component.ts | 132 +- .../itshop-pattern-changed.enum.ts | 6 +- ...op-pattern-create-sidesheet.component.html | 22 +- ...op-pattern-create-sidesheet.component.scss | 44 +- ...shop-pattern-create-sidesheet.component.ts | 49 +- .../itshop-pattern-create.service.ts | 130 +- ...p-pattern-item-edit-parameter.interface.ts | 6 +- .../itshop-pattern-item-edit.component.html | 25 +- .../itshop-pattern-item-edit.component.scss | 29 +- ...itshop-pattern-item-edit.component.spec.ts | 16 +- .../itshop-pattern-item-edit.component.ts | 23 +- .../itshop-pattern-sidesheet.component.html | 164 +- .../itshop-pattern-sidesheet.component.scss | 105 +- ...itshop-pattern-sidesheet.component.spec.ts | 14 +- .../itshop-pattern-sidesheet.component.ts | 145 +- .../itshop-pattern.component.html | 105 +- .../itshop-pattern.component.scss | 52 +- .../itshop-pattern.component.ts | 208 +- .../itshop-pattern/itshop-pattern.module.ts | 85 +- .../itshop-pattern/itshop-pattern.service.ts | 145 +- .../pattern-item-candidate.interface.ts | 7 +- .../lib/itshop/decision-history.service.ts | 17 +- .../qer/src/lib/itshop/image.service.spec.ts | 12 +- .../qer/src/lib/itshop/image.service.ts | 32 +- .../src/lib/itshop/itshop-request.service.ts | 28 +- .../qer/src/lib/itshop/itshop.module.ts | 20 +- .../qer/src/lib/itshop/itshop.service.ts | 49 +- .../non-requestable-items.component.html | 15 +- .../non-requestable-items.component.scss | 2 +- .../non-requestable-items.component.spec.ts | 27 +- .../non-requestable-items.component.ts | 25 +- .../peer-group/peer-group.component.html | 7 +- .../itshop/peer-group/peer-group.component.ts | 8 +- .../request-info/approver-container.spec.ts | 191 +- .../itshop/request-info/approver-container.ts | 122 +- .../decision-history.component.html | 50 +- .../decision-history.component.scss | 43 +- .../decision-history.component.ts | 18 +- .../request-info/itshop-request-data.spec.ts | 24 +- .../request-info/itshop-request-data.ts | 12 +- ...itshop-request-entity-wrapper.interface.ts | 8 +- .../ordered-working-step.interface.ts | 2 +- .../request-info/request-info.component.html | 20 +- .../request-info/request-info.component.scss | 55 +- .../request-info/request-info.component.ts | 47 +- ...request-parameter-data-entity.interface.ts | 8 +- .../product-details.service.ts | 22 +- .../product-entitlements.component.html | 46 +- .../product-entitlements.component.scss | 28 - .../product-entitlements.component.ts | 34 +- .../service-item-detail.component.html | 6 +- .../service-item-detail.component.scss | 6 - .../service-item-detail.component.ts | 20 +- .../workflow-history-item-wrapper.spec.ts | 31 +- .../workflow-history-item-wrapper.ts | 54 +- .../itshop/shelf-selection-sidesheet.model.ts | 15 +- .../lib/itshop/shelf-selection.component.html | 66 +- .../lib/itshop/shelf-selection.component.scss | 15 +- .../lib/itshop/shelf-selection.component.ts | 54 +- .../qer/src/lib/itshop/shelf.service.ts | 66 +- .../lib/itshop/workflow-data-wrapper.spec.ts | 308 +- .../src/lib/itshop/workflow-data-wrapper.ts | 60 +- .../src/lib/itshopapprove/approval.spec.ts | 193 +- .../qer/src/lib/itshopapprove/approval.ts | 16 +- .../itshopapprove/approvals-decision.enum.ts | 4 +- .../approvals-load-parameters.ts | 4 +- .../approvals-sidesheet.component.html | 82 +- .../approvals-sidesheet.component.scss | 39 +- .../approvals-sidesheet.component.ts | 29 +- .../approvals-table.component.html | 273 +- .../approvals-table.component.scss | 127 +- .../approvals-table.component.spec.ts | 25 +- .../approvals-table.component.ts | 267 +- .../itshopapprove/approvals.component.html | 28 +- .../itshopapprove/approvals.component.scss | 56 +- .../itshopapprove/approvals.component.spec.ts | 10 +- .../lib/itshopapprove/approvals.component.ts | 31 +- .../src/lib/itshopapprove/approvals.module.ts | 100 +- .../lib/itshopapprove/approvals.service.ts | 77 +- .../itshopapprove/decision-step.service.ts | 21 +- .../inquiries/inquiries.component.html | 123 +- .../inquiries/inquiries.component.scss | 24 +- .../inquiries/inquiries.component.ts | 170 +- .../recommendation-sidesheet.component.html | 51 +- .../recommendation-sidesheet.component.scss | 26 +- .../recommendation-sidesheet.component.ts | 19 +- .../approval-history.component.html | 34 +- .../approval-history.component.scss | 27 +- .../approval-history.component.ts | 110 +- .../approval-history.service.ts | 28 +- .../history-filter.component.html | 8 +- .../history-filter.component.scss | 2 +- .../history-filter.component.ts | 32 +- .../workflow-action-edit-wrapper.interface.ts | 2 +- .../workflow-action-edit.interface.ts | 26 +- .../workflow-action-parameters.interface.ts | 2 +- .../workflow-action.component.html | 18 +- .../workflow-action.component.scss | 31 +- .../workflow-action.component.ts | 14 +- .../workflow-action.service.ts | 232 +- .../workflow-multi-action.component.html | 5 +- .../workflow-multi-action.component.ts | 38 +- .../workflow-single-action.component.html | 5 +- .../workflow-single-action.component.scss | 12 +- .../workflow-single-action.component.ts | 22 +- .../answer-questions.component.html | 70 +- .../answer-questions.component.ts | 57 +- .../query-person.component.html | 19 +- .../query-person.component.ts | 61 +- .../decision-reason.component.html | 15 +- .../decision-reason.component.scss | 2 +- .../decision-reason.component.ts | 47 +- .../justification/justification-type.enum.ts | 4 +- .../lib/justification/justification.module.ts | 23 +- .../justification/justification.service.ts | 27 +- .../lib/metadata/portal-metadata.service.ts | 51 + .../my-responsibilities-registry.service.ts | 10 +- .../my-responsibilities-view.component.html | 2 +- .../my-responsibilities-view.component.ts | 21 +- .../my-responsibilities-view.module.ts | 8 +- .../src/lib/new-request/constants.ts} | 8 +- .../lib/new-request/current-product-source.ts | 6 +- .../element-visibility.directive.ts | 7 +- .../new-request-add-to-cart.service.ts | 125 +- .../new-request-content.component.html | 37 +- .../new-request-content.component.scss | 51 +- .../new-request-content.component.ts | 131 +- .../lib/new-request/new-request-global.scss | 119 +- .../new-request-header-toolbar.component.html | 35 +- .../new-request-header-toolbar.component.scss | 8 +- .../new-request-header-toolbar.component.ts | 84 +- .../new-request-header.component.html | 8 +- .../new-request-header.component.scss | 30 +- .../new-request-header.component.ts | 5 +- .../new-request-recipients.component.html | 29 +- .../new-request-recipients.component.scss | 6 + .../new-request-recipients.component.ts | 65 +- .../recipients-api.service.ts | 14 +- ...request-reference-user-card.component.html | 13 +- ...request-reference-user-card.component.scss | 2 +- ...w-request-reference-user-card.component.ts | 12 +- .../new-request-orchestration.service.ts | 136 +- .../new-request-peer-group.component.html | 92 +- .../new-request-peer-group.component.scss | 7 +- .../new-request-peer-group.component.ts | 81 +- ...peer-group-discard-selected.component.html | 22 +- ...peer-group-discard-selected.component.scss | 15 - .../peer-group-discard-selected.component.ts | 24 +- .../new-request-product-bundle.component.scss | 4 +- .../new-request-product-bundle.component.ts | 2 +- .../product-bundle-items.component.html | 105 +- .../product-bundle-items.component.scss | 60 +- .../product-bundle-items.component.ts | 94 +- .../product-bundle-list.component.html | 6 +- .../product-bundle-list.component.scss | 136 +- .../product-bundle-list.component.ts | 49 +- .../fk-advanced-picker-response.ts | 16 +- .../new-request-category-api.service.ts | 15 +- .../new-request-product-api.service.ts | 13 +- .../new-request-product.component.html | 94 +- .../new-request-product.component.scss | 79 +- .../new-request-product.component.ts | 113 +- .../product-details-sidesheet.component.html | 39 +- .../product-details-sidesheet.component.scss | 64 +- .../product-details-sidesheet.component.ts | 52 +- .../product-details.service.ts | 43 +- .../product-entitlement-api.service.ts | 24 +- .../product-entitlements.component.html | 47 +- .../product-entitlements.component.scss | 2 +- .../product-entitlements.component.ts | 17 +- .../service-item-parameters.ts | 4 +- .../new-request-reference-user.component.html | 73 +- .../new-request-reference-user.component.scss | 3 +- .../new-request-reference-user.component.ts | 128 +- .../new-request/new-request-routing.module.ts | 15 +- ...w-request-selected-products.component.html | 8 +- ...w-request-selected-products.component.scss | 23 +- ...new-request-selected-products.component.ts | 6 +- ...selected-product-item-col-def.interface.ts | 2 +- .../selected-product-item.interface.ts | 6 +- .../new-request-selection.service.ts | 44 +- .../new-request-tab/new-request-tab-model.ts | 2 +- .../new-request/new-request.component.html | 1 - .../new-request/new-request.component.scss | 1 - .../lib/new-request/new-request.component.ts | 9 +- .../src/lib/new-request/new-request.module.ts | 109 +- .../notification-registry.service.ts | 96 +- .../notification-stream.service.ts | 25 +- ...object-attestation-statistics.interface.ts | 2 +- .../object-hyperview.component.scss | 17 +- .../object-hyperview.component.ts | 31 +- ...rface.ts => object-hyperview.interface.ts} | 2 +- .../object-hyperview.module.ts | 6 +- .../object-hyperview.service.ts | 8 +- .../src/lib/ops/about/ops-about.service.ts | 55 + .../lib/ops/metadata/ops-metadata.service.ts | 51 + .../src/lib/ops/objectOverviewContainer.ts | 4 +- .../ops/objectOverviewPerson.component.html | 2 +- .../lib/ops/objectOverviewPerson.component.ts | 27 +- imxweb/projects/qer/src/lib/ops/ops.module.ts | 58 +- .../src/lib/ops/ops.service.ts} | 23 +- .../qer/src/lib/ops/passcode.service.ts | 37 +- .../src/lib/ops/passcodeViewer.component.html | 25 +- .../src/lib/ops/passcodeViewer.component.scss | 2 +- .../src/lib/ops/passcodeViewer.component.ts | 12 +- .../ops/permissions/ops-permissions-helper.ts | 29 + .../permissions/ops-permissions.service.ts} | 26 +- .../projects/qer/src/lib/ops/user.service.ts | 27 +- .../src/lib/org-chart/identity.component.html | 11 +- .../src/lib/org-chart/identity.component.scss | 8 +- .../src/lib/org-chart/identity.component.ts | 27 +- .../lib/org-chart/org-chart.component.html | 11 +- .../lib/org-chart/org-chart.component.scss | 72 +- .../src/lib/org-chart/org-chart.component.ts | 9 +- .../qer/src/lib/org-chart/org-chart.module.ts | 26 +- .../src/lib/org-chart/org-chart.service.ts | 16 +- .../qer/src/lib/org-chart/variables.scss | 3 - .../owner-control.component.html | 11 +- .../owner-control.component.scss | 13 +- .../owner-control.component.spec.ts | 12 +- .../owner-control/owner-control.component.ts | 12 +- .../lib/owner-control/owner-control.module.ts | 21 +- .../owner-control/owner-control.service.ts | 35 +- .../qer/src/lib/owner-control/owner.model.ts | 4 +- .../extended-collection-data.interface.ts | 7 +- .../extended-entity-wrapper.interface.ts | 2 +- .../parameter-category-column.interface.ts | 4 +- .../parameter-category.interface.ts | 4 +- .../lib/parameter-data/parameter-container.ts | 40 +- .../parameter-data-container.ts | 4 +- .../parameter-data-fk-provider-item.ts | 30 +- ...arameter-data-load-parameters.interface.ts | 4 +- .../parameter-data-wrapper.interface.ts | 6 +- .../parameter-data/parameter-data.service.ts | 254 +- .../confirm-password-matcher.ts | 3 +- .../password-question.service.ts | 23 +- ...assword-questions-sidesheet.component.html | 87 + ...assword-questions-sidesheet.component.scss | 26 + .../password-questions-sidesheet.component.ts | 70 +- .../password-questions-validator.ts | 11 +- .../password-questions.component.html | 99 + .../password-questions.component.scss | 61 + .../password-questions.component.ts | 102 +- .../password-questions.module.ts} | 70 +- .../lib/password/about/pwd-about.service.ts | 55 + .../password/check-passwords.component.html | 120 +- .../password/check-passwords.component.scss | 10 +- .../lib/password/check-passwords.component.ts | 101 +- .../src/lib/password/dashboard.component.html | 64 +- .../src/lib/password/dashboard.component.ts | 17 +- .../qer/src/lib/password/helpers.model.ts | 4 +- .../password/metadata/pwd-metadata.service.ts | 51 + .../passcode-login/passcode-login-flow.ts | 9 +- .../passcode-login.component.html | 60 +- .../passcode-login.component.scss | 55 +- .../passcode-login.component.ts | 184 +- .../passcode-login/passcode-login.module.ts | 22 +- .../qer/src/lib/password/password-helper.ts | 16 +- .../qer/src/lib/password/password-item.ts | 13 +- .../password/password-query.component.html | 85 +- .../lib/password/password-query.component.ts | 46 +- .../password/password-reset.component.html | 108 +- .../password/password-reset.component.scss | 15 +- .../lib/password/password-reset.component.ts | 27 +- .../qer/src/lib/password/password.module.ts | 51 +- .../qer/src/lib/password/password.service.ts | 52 +- .../lib/password/qa-login/qa-login-flow.ts | 9 +- .../password/qa-login/qa-login.component.html | 91 +- .../password/qa-login/qa-login.component.scss | 56 +- .../password/qa-login/qa-login.component.ts | 241 +- .../lib/password/qa-login/qa-login.module.ts | 22 +- .../pattern-item-list-filter-type.enum.ts | 6 +- .../pattern-item-list.component.html | 25 +- .../pattern-item-list.component.scss | 12 - .../pattern-item-list.component.spec.ts | 4 +- .../pattern-item-list.component.ts | 82 +- .../pattern-item-list/pattern-item.service.ts | 61 +- .../pattern-item-list/pattern-items.module.ts | 16 +- .../person-all-load-parameters.interface.ts | 4 +- .../qer/src/lib/person/person.module.ts | 10 +- .../qer/src/lib/person/person.service.ts | 38 +- .../dependency.service.ts | 41 +- .../optional-items-sidesheet.component.html | 42 +- .../optional-items-sidesheet.component.scss | 38 +- .../optional-items-sidesheet.component.ts | 57 +- .../pattern-details-sidesheet.component.html | 101 +- .../pattern-details-sidesheet.component.scss | 48 +- .../pattern-details-sidesheet.component.ts | 47 +- .../product-details-sidesheet.component.html | 2 +- .../product-details-sidesheet.component.scss | 27 +- .../product-details-sidesheet.component.ts | 27 +- .../product-selection.component.html | 55 +- .../product-selection.component.scss | 51 +- .../product-selection.component.ts | 212 +- .../product-selection.module.ts | 179 +- .../product-selection.service.ts | 64 +- .../recipients-wrapper.spec.ts | 4 +- .../product-selection/recipients-wrapper.ts | 8 +- .../role-memberships.component.html | 44 +- .../role-memberships.component.scss | 10 - .../role-memberships.component.ts | 71 +- .../service-item-edit/item-edit.service.ts | 34 +- .../service-item-edit.component.html | 20 +- .../service-item-edit.component.scss | 16 +- .../service-item-edit.component.ts | 10 +- .../service-item-order.interface.ts | 9 +- .../category-tree.component.html | 5 +- .../category-tree.component.scss | 6 +- .../category-tree.component.ts | 18 +- .../servicecategory-list.component.html | 26 +- .../servicecategory-list.component.scss | 8 +- .../servicecategory-list.component.ts | 33 +- .../servicecategory-tree-database.ts | 29 +- .../identity-select.component.html | 10 +- .../identity-select.component.scss | 3 - .../identity-select.component.ts | 14 +- .../lib/profile/mailsubscription.service.ts | 46 +- .../profile/mailsubscriptions.component.html | 38 +- .../profile/mailsubscriptions.component.scss | 49 +- .../profile/mailsubscriptions.component.ts | 72 +- ...assword-questions-sidesheet.component.html | 60 - ...assword-questions-sidesheet.component.scss | 53 - .../password-questions.component.html | 91 - .../password-questions.component.scss | 107 - .../src/lib/profile/profile.component.html | 50 +- .../src/lib/profile/profile.component.scss | 55 +- .../qer/src/lib/profile/profile.component.ts | 138 +- .../qer/src/lib/profile/profile.module.ts | 68 +- .../security-keys-sidesheet.component.html | 35 +- .../security-keys-sidesheet.component.scss | 13 - .../security-keys-sidesheet.component.ts | 42 +- .../security-keys.component.html | 55 +- .../security-keys.component.scss | 14 - .../security-keys/security-keys.component.ts | 64 +- .../security-keys/security-keys.service.ts | 34 +- .../project-configuration.module.ts | 12 +- .../project-configuration.service.ts | 17 +- .../qer/src/lib/qer-api-client.service.ts | 35 +- imxweb/projects/qer/src/lib/qer.module.ts | 48 +- imxweb/projects/qer/src/lib/qer.service.ts | 26 +- .../qpm-integration.component.html | 32 +- .../qpm-integration.component.scss | 2 +- .../qpm-integration.component.ts | 46 +- .../qpm-integration/qpm-integration.module.ts | 22 +- .../queue-sidesheet.component.html | 186 + .../queue-sidesheet.component.scss | 191 + .../queue-sidesheet.component.ts | 104 + .../queue-status/queue-status.component.html | 40 + .../queue-status/queue-status.component.scss | 11 + .../queue-status/queue-status.component.ts | 118 + .../application-details.component.html | 4 +- .../application-details.component.scss | 22 +- .../application-details.component.ts | 21 +- .../application-dialog.component.html | 16 +- .../application-dialog.component.ts | 13 +- ...lated-application-menu-item.component.html | 2 +- ...related-application-menu-item.component.ts | 21 +- ...ated-applications-sidesheet.component.html | 16 +- ...elated-applications-sidesheet.component.ts | 36 +- .../related-applications.component.ts | 21 +- .../related-applications.module.ts | 28 +- .../related-applications.service.ts | 9 +- .../request-history/itshop-request.spec.ts | 109 +- .../src/lib/request-history/itshop-request.ts | 23 +- .../request-action.component.html | 59 +- .../request-action.component.ts | 71 +- .../request-action/request-action.service.ts | 103 +- .../request-detail-parameter.interface.ts | 6 +- .../request-detail.component.html | 129 +- .../request-detail.component.scss | 10 - .../request-detail.component.ts | 17 +- .../default-request-display.component.html | 18 +- .../default-request-display.component.scss | 21 +- .../default-request-display.component.ts | 18 +- .../request-display.component.ts | 32 +- .../request-display.interface.ts | 4 +- .../request-display.service.ts | 4 +- .../request-history-filter.component.html | 17 +- .../request-history-filter.component.scss | 2 +- .../request-history-filter.component.spec.ts | 9 +- .../request-history-filter.component.ts | 51 +- ...quest-history-load-parameters.interface.ts | 5 +- .../request-history.component.html | 15 +- .../request-history.component.scss | 11 - .../request-history.component.ts | 33 +- .../request-history/request-history.module.ts | 83 +- .../request-history.service.ts | 87 +- .../request-table.component.html | 139 +- .../request-table.component.scss | 9 +- .../request-table.component.ts | 298 +- .../requestfilter.component.html | 51 +- .../requestfilter.component.scss | 7 +- .../requestfilter.component.ts | 173 +- .../requests-feature-guard.service.spec.ts | 18 +- .../src/lib/requests-feature-guard.service.ts | 23 +- .../src/lib/resources/resource-info.model.ts | 6 +- .../resource-sidesheet.component.html | 67 +- .../resource-sidesheet.component.scss | 38 - .../resource-sidesheet.component.ts | 52 +- .../lib/resources/resources.component.html | 55 +- .../lib/resources/resources.component.scss | 41 +- .../src/lib/resources/resources.component.ts | 99 +- .../qer/src/lib/resources/resources.module.ts | 28 +- .../src/lib/resources/resources.service.ts | 411 +- .../risk-config-sidesheet.component.html | 16 +- .../risk-config-sidesheet.component.ts | 23 +- .../risk-config/risk-config.component.html | 117 +- .../risk-config/risk-config.component.scss | 44 +- .../lib/risk-config/risk-config.component.ts | 138 +- .../src/lib/risk-config/risk-config.module.ts | 93 +- .../lib/risk-config/risk-config.service.ts | 33 +- .../projects/qer/src/lib/risk/risk.module.ts | 14 +- .../riskanalysis-sidesheet.component.html | 2 +- .../riskanalysis-sidesheet.component.scss | 14 +- .../risk/riskanalysis-sidesheet.component.ts | 15 +- .../src/lib/risk/riskanalysis.component.html | 105 +- .../src/lib/risk/riskanalysis.component.scss | 7 +- .../src/lib/risk/riskanalysis.component.ts | 87 +- .../src/lib/role-management/api-wrapper.ts | 55 + .../compare/compare-item-builder.ts | 6 +- .../compare/compare-item.component.html | 2 +- .../compare/compare-item.component.ts | 11 +- .../role-management/compare/compare-item.ts | 4 +- .../compare/compare.component.html | 53 +- .../compare/compare.component.scss | 36 +- .../compare/compare.component.ts | 67 +- .../compare/compare.service.ts | 15 +- .../data-management.service.spec.ts | 8 +- .../data-management.service.ts | 16 +- .../dynamicrole-sqlwizard.service.ts | 12 +- .../identities.service.spec.ts | 2 +- .../identities.service.ts | 34 +- ...mberships-choose-identities.component.html | 83 +- ...mberships-choose-identities.component.scss | 4 +- ...rships-choose-identities.component.spec.ts | 11 +- ...memberships-choose-identities.component.ts | 96 +- .../not-requestable-memberships-entity.ts | 11 +- ...not-requestable-memberships.component.html | 26 +- ...not-requestable-memberships.component.scss | 19 +- .../not-requestable-memberships.component.ts | 28 +- .../new-role/new-role.component.html | 10 +- .../new-role/new-role.component.ts | 44 +- .../restore/restore-handler.ts | 30 +- .../restore/restore.component.html | 14 +- .../restore/restore.component.scss | 10 - .../restore/restore.component.ts | 33 +- .../role-data-model.interface.ts | 4 +- .../role-detail/role-detail.component.html | 8 +- .../role-detail/role-detail.component.scss | 99 +- .../role-detail/role-detail.component.spec.ts | 11 +- .../role-detail/role-detail.component.ts | 40 +- .../role-entitlements/entitlement-handlers.ts | 81 +- .../entitlement-selector.component.html | 11 +- .../entitlement-selector.component.scss | 40 +- .../entitlement-selector.component.ts | 70 +- .../role-entitlement-action.service.ts | 49 +- .../role-entitlements.component.html | 19 +- .../role-entitlements.component.scss | 48 - .../role-entitlements.component.ts | 126 +- ...role-recommendation-result-item-builder.ts | 10 +- .../role-recommendation-result-item.ts | 4 +- .../role-recommendations.component.html | 46 +- .../role-recommendations.component.scss | 25 +- .../role-recommendations.component.ts | 27 +- .../role-main-data.component.html | 62 +- .../role-main-data.component.scss | 48 +- .../role-main-data.component.spec.ts | 11 +- .../role-main-data.component.ts | 85 +- .../role-manangement.module.ts | 100 +- .../dynamic-role.component.html | 32 +- .../dynamic-role.component.scss | 32 +- .../dynamic-role.component.ts | 68 +- .../excluded-memberships.component.html | 113 +- .../excluded-memberships.component.scss | 24 +- .../excluded-memberships.component.ts | 40 +- .../role-memberships/membership-entity.ts | 4 +- .../role-memberships/membership-handlers.ts | 305 +- .../primary-memberships.component.html | 6 +- .../primary-memberships.component.scss | 10 +- .../primary-memberships.component.spec.ts | 11 +- .../primary-memberships.component.ts | 37 +- .../remove-membership.component.html | 76 +- .../remove-membership.component.scss | 56 +- .../remove-membership.component.ts | 26 +- .../role-memberships.component.html | 14 +- .../role-memberships.component.scss | 58 - .../role-memberships.component.spec.ts | 47 +- .../role-memberships.component.ts | 23 +- .../role-memberships.module.ts | 12 +- .../role-memberships/role-sidesheet-tabs.scss | 39 +- .../secondary-memberships.component.html | 37 +- .../secondary-memberships.component.scss | 55 +- .../secondary-memberships.component.ts | 124 +- .../lib/role-management/role-object-info.ts | 21 +- .../lib/role-management/role.service.spec.ts | 2 +- .../src/lib/role-management/role.service.ts | 778 +- .../roles-overview/role-adaptor.ts | 10 +- .../roles-overview.component.html | 74 +- .../roles-overview.component.scss | 76 +- .../roles-overview.component.spec.ts | 11 +- .../roles-overview.component.ts | 109 +- .../tree-database-adaptor.service.spec.ts | 2 +- .../tree-database-adaptor.service.ts | 46 +- .../rollback/rollback-item-builder.ts | 9 +- .../role-management/rollback/rollback-item.ts | 9 +- .../rollback/rollback.component.html | 47 +- .../rollback/rollback.component.scss | 39 +- .../rollback/rollback.component.ts | 36 +- .../rollback/rollback.service.ts | 21 +- .../src/lib/role-management/sidesheet.scss | 23 - .../split/split.component.html | 24 +- .../split/split.component.scss | 39 +- .../role-management/split/split.component.ts | 88 +- .../role-management/split/split.service.ts | 9 +- .../service-categories.component.html | 21 +- .../service-categories.component.scss | 22 +- .../service-categories.component.ts | 136 +- .../service-categories.module.ts | 74 +- .../service-categories.service.ts | 17 +- .../service-category-changed.enum.ts | 4 +- .../service-category-tree-database.ts | 32 +- .../service-category.component.html | 56 +- .../service-category.component.scss | 32 - .../service-category.component.ts | 69 +- .../service-item-tags.component.html | 24 +- .../service-item-tags.component.scss | 34 - .../service-item-tags.component.ts | 5 +- .../service-item-tags.module.ts | 18 +- .../service-item-tags.service.ts | 40 +- .../service-items-edit-form.component.html | 49 +- .../service-items-edit-form.component.scss | 9 +- .../service-items-edit-form.component.ts | 42 +- .../service-items-edit-form.module.ts | 15 +- ...ervice-items-edit-sidesheet.component.html | 53 +- ...ervice-items-edit-sidesheet.component.scss | 57 +- .../service-items-edit-sidesheet.component.ts | 25 +- .../service-items-edit.component.html | 47 +- .../service-items-edit.component.scss | 67 +- .../service-items-edit.component.ts | 111 +- .../service-items-edit.module.ts | 90 +- .../service-items-edit.service.ts | 53 +- .../service-item-info.component.html | 32 +- .../service-item-info.component.ts | 17 +- .../service-item-select.component.html | 23 +- .../service-item-select.component.scss | 41 +- .../service-item-select.component.ts | 44 +- .../typed-entity-selection-data.interface.ts | 4 +- .../service-items-selector.component.html | 27 +- .../service-items-selector.component.scss | 31 +- .../service-items-selector.component.ts | 11 +- .../lib/service-items/service-items.module.ts | 38 +- .../service-items/service-items.service.ts | 114 +- .../serviceitem-list.component.html | 85 +- .../serviceitem-list.component.scss | 15 +- .../serviceitem-list.component.spec.ts | 22 +- .../serviceitem-list.component.ts | 65 +- .../src/lib/settings/settings.component.html | 16 +- .../src/lib/settings/settings.component.scss | 7 +- .../src/lib/settings/settings.component.ts | 167 +- .../base-viewer/base-viewer.component.ts | 8 +- .../detail-viewer/detail-viewer.component.ts | 10 +- .../details-container.interface.ts | 2 +- .../details-view.interface.ts | 5 +- .../duplicate-check.component.html | 5 +- .../duplicate-check.component.ts | 7 +- .../exclusion-check.component.ts | 7 +- .../exclusion-result.interface.ts | 2 +- .../mandatory-acc-product-result.interface.ts | 2 +- .../product-dependency-check.component.html | 4 +- .../product-dependency-check.component.ts | 7 +- .../shopping-cart-validation-detail.module.ts | 22 +- ...ing-cart-validation-detail.service.spec.ts | 4 +- ...shopping-cart-validation-detail.service.ts | 8 +- .../cart-item-clone-parameters.interface.ts | 4 +- .../cart-item-edit/cart-item-clone.service.ts | 80 +- .../cart-item-edit-parameter.interface.ts | 12 +- .../cart-item-edit.component.html | 60 +- .../cart-item-edit.component.scss | 12 +- .../cart-item-edit.component.ts | 10 +- .../cart-item-edit/cart-item-fk.service.ts | 69 +- .../cart-item-interactive.service.ts | 33 +- .../order-for-additional-users.component.html | 26 +- .../order-for-additional-users.component.ts | 14 +- .../request-parameters.service.ts | 24 +- ...rt-item-validation-overview.component.html | 44 +- ...rt-item-validation-overview.component.scss | 60 +- ...cart-item-validation-overview.component.ts | 27 +- .../cart-item-validation-result.interface.ts | 4 +- .../cart-items-extension.service.ts | 46 + .../src/lib/shopping-cart/cart-items.model.ts | 47 + .../lib/shopping-cart/cart-items.service.ts | 161 +- .../cart-items/cart-item-check-status.enum.ts | 4 +- .../cart-items/cart-item-display.component.ts | 41 +- .../cart-items/cart-item-logic.interface.ts | 6 +- .../cart-items/cart-item-logic.service.ts | 20 +- .../cart-item-validation-status.enum.ts | 23 +- .../cart-items/cart-items.component.html | 150 +- .../cart-items/cart-items.component.scss | 33 +- .../cart-items/cart-items.component.spec.ts | 69 +- .../cart-items/cart-items.component.ts | 403 +- .../default-cart-item-display.component.ts | 34 +- .../confirm-cart-submit.dialog.html | 6 +- .../confirm-cart-submit.dialog.scss | 2 +- .../confirm-cart-submit.dialog.ts | 8 +- .../requestable-product.interface.ts | 9 +- .../shopping-cart-button.component.html | 9 + .../shopping-cart-button.component.scss | 8 + .../shopping-cart-button.component.ts | 68 + .../shopping-cart-empty.component.html | 31 +- .../shopping-cart-empty.component.scss | 27 +- .../shopping-cart-empty.component.ts | 6 +- .../shopping-cart-for-later.component.html | 96 +- .../shopping-cart-for-later.component.scss | 56 +- .../shopping-cart-for-later.component.ts | 39 +- .../shopping-cart-submit-warnings.dialog.html | 19 +- .../shopping-cart-submit-warnings.dialog.ts | 14 +- .../shopping-cart-validator.spec.ts | 109 +- .../shopping-cart/shopping-cart-validator.ts | 40 +- .../shopping-cart.component.html | 276 +- .../shopping-cart.component.scss | 27 +- .../shopping-cart/shopping-cart.component.ts | 175 +- .../lib/shopping-cart/shopping-cart.module.ts | 129 +- .../lib/shopping-cart/shopping-cart.spec.ts | 112 +- .../src/lib/shopping-cart/shopping-cart.ts | 110 +- .../sourcedetective-sidesheet.component.html | 9 +- .../sourcedetective-sidesheet.component.scss | 9 +- .../sourcedetective-sidesheet.component.ts | 17 +- .../sourcedetective-type.enum.ts | 4 +- .../sourcedetective.component.html | 103 +- .../sourcedetective.component.scss | 24 +- .../sourcedetective.component.ts | 75 +- .../sourcedetective/sourcedetective.module.ts | 16 +- .../lib/statistics/charts/chart-data-typed.ts | 54 +- .../chart-table-service.service.ts | 11 +- .../chart-table/chart-table.component.html | 33 +- .../chart-table/chart-table.component.scss | 38 +- .../chart-table/chart-table.component.ts | 18 +- .../charts/chart-tile/chart-details.ts | 4 +- .../chart-tile/chart-tile.component.html | 23 +- .../chart-tile/chart-tile.component.spec.ts | 20 +- .../charts/chart-tile/chart-tile.component.ts | 108 +- .../point-stat-visual/point-stat-typed.ts | 4 +- .../point-stat-visual.component.html | 8 +- .../point-stat-visual.component.scss | 8 +- .../point-stat-visual.component.ts | 4 +- .../point-stat-visual.service.ts | 28 +- .../table-stat-visual.component.html | 13 + .../table-stat-visual.component.scss | 20 + .../table-stat-visual.component.ts | 52 + .../charts-sidesheet.component.html | 117 +- .../charts-sidesheet.component.scss | 93 +- .../charts-sidesheet.component.spec.ts | 26 +- .../charts-sidesheet.component.ts | 49 +- .../statistics-chart-handler.service.ts | 99 +- .../block-detail-sidesheet.component.html | 17 +- .../block-detail-sidesheet.component.scss | 63 +- .../block-detail-sidesheet.component.ts | 50 +- .../heatmaps/block-properties.interface.ts | 68 +- .../discrete-legend.component.html | 10 +- .../discrete-legend.component.ts | 8 +- .../heatmap-chart.component.html | 4 +- .../heatmap-chart.component.scss | 4 - .../heatmap-chart.component.spec.ts | 8 +- .../heatmap-chart/heatmap-chart.component.ts | 10 +- .../heatmaps/heatmap-data-extended.ts | 4 +- .../statistics/heatmaps/heatmap-data-typed.ts | 40 +- .../statistics/heatmaps/heatmap-info-typed.ts | 4 +- .../heatmap-sidesheet.component.html | 115 +- .../heatmap-sidesheet.component.scss | 131 +- .../heatmap-sidesheet.component.spec.ts | 32 +- .../heatmap-sidesheet.component.ts | 84 +- .../heatmap-sidesheet.service.spec.ts | 7 +- .../heatmap-sidesheet.service.ts | 118 +- .../heatmap-tile/heatmap-tile.component.html | 4 +- .../heatmap-tile/heatmap-tile.component.scss | 32 +- .../heatmap-tile.component.spec.ts | 21 +- .../heatmap-tile/heatmap-tile.component.ts | 8 +- .../treemap-chart.component.html | 2 +- .../treemap-chart.component.scss | 4 - .../treemap-chart.component.spec.ts | 14 +- .../treemap-chart/treemap-chart.component.ts | 10 +- .../qer/src/lib/statistics/stat-mixins.scss | 150 +- .../lib/statistics/statistics-api.service.ts | 19 +- .../statistics-for-objects-api.service.ts | 32 +- .../statistics-for-objects.component.html | 26 +- .../statistics-for-objects.component.scss | 5 +- .../statistics-for-objects.component.spec.ts | 14 +- .../statistics-for-objects.component.ts | 82 +- .../statistics-home-page/chart-info-typed.ts | 15 +- .../favorites-tab.component.html | 11 +- .../favorites-tab.component.scss | 4 +- .../favorites-tab.component.spec.ts | 26 +- .../favorites-tab/favorites-tab.component.ts | 65 +- .../heatmap-info-typed.ts | 36 +- .../heatmap-visual.component.html | 4 +- .../heatmap-visual.component.scss | 32 +- .../heatmap-visual.component.ts | 8 +- .../statistics-cards-visuals.component.html | 44 +- .../statistics-cards-visuals.component.scss | 44 +- .../statistics-cards-visuals.component.ts | 65 +- .../statistics-cards.component.html | 112 +- .../statistics-cards.component.scss | 83 +- .../statistics-cards.component.spec.ts | 30 +- .../statistics-cards.component.ts | 33 +- .../statistics-constants.service.ts | 23 +- .../statistics-data.service.ts | 250 +- .../statistics-home-page.component.html | 60 +- .../statistics-home-page.component.scss | 67 +- .../statistics-home-page.component.spec.ts | 36 +- .../statistics-home-page.component.ts | 53 +- ...s-ordering-sidesheet-dialog.component.html | 12 - ...s-ordering-sidesheet-dialog.component.scss | 21 - ...atistics-ordering-sidesheet.component.html | 97 +- ...atistics-ordering-sidesheet.component.scss | 102 +- ...stics-ordering-sidesheet.component.spec.ts | 64 +- ...statistics-ordering-sidesheet.component.ts | 54 +- .../statistics-tree.component.html | 6 +- .../statistics-tree.component.scss | 39 +- .../statistics-tree.component.spec.ts | 26 +- .../statistics-tree.component.ts | 80 +- .../src/lib/statistics/statistics.module.ts | 83 +- .../team-responsibilities.component.html | 155 +- .../team-responsibilities.component.scss | 12 +- .../team-responsibilities.component.ts | 222 +- .../team-responsibilities.module.ts | 95 +- .../team-responsibilities.service.ts | 195 +- ...onsibility-assign-sidesheet.component.html | 48 + ...onsibility-assign-sidesheet.component.scss | 7 + ...sponsibility-assign-sidesheet.component.ts | 125 + .../team-responsibility-dialog.component.html | 22 + .../team-responsibility-dialog.component.scss | 3 + .../team-responsibility-dialog.component.ts | 53 + ...am-responsibility-sidesheet.component.html | 103 +- ...am-responsibility-sidesheet.component.scss | 70 + ...team-responsibility-sidesheet.component.ts | 173 +- ...esponsibility-status-dialog.component.html | 21 + ...esponsibility-status-dialog.component.scss | 3 + ...-responsibility-status-dialog.component.ts | 28 + .../team-responsibility-tile.component.html | 12 +- .../team-responsibility-tile.component.ts | 10 +- .../terms-of-use-accept.component.html | 19 +- .../terms-of-use-accept.component.scss | 11 - .../terms-of-use-accept.component.ts | 70 +- .../src/lib/terms-of-use/terms-of-use-item.ts | 8 +- .../terms-of-use-list.component.html | 20 +- .../terms-of-use-list.component.scss | 2 +- .../terms-of-use-list.component.ts | 49 +- .../terms-of-use-viewer.component.html | 10 +- .../terms-of-use-viewer.component.scss | 12 +- .../terms-of-use-viewer.component.ts | 21 +- .../lib/terms-of-use/terms-of-use.module.ts | 16 +- .../lib/terms-of-use/terms-of-use.service.ts | 46 +- .../badge-tile/badge-tile.component.html | 15 +- .../badge-tile/badge-tile.component.scss | 31 +- .../tiles/badge-tile/badge-tile.component.ts | 10 +- .../tiles/icon-tile/icon-tile.component.html | 28 +- .../tiles/icon-tile/icon-tile.component.scss | 32 +- .../tiles/icon-tile/icon-tile.component.ts | 5 +- .../notification-tile.component.html | 31 +- .../notification-tile.component.scss | 4 - .../notification-tile.component.ts | 27 +- .../qer/src/lib/tiles/tiles.module.ts | 28 +- .../user-process/user-process.component.html | 12 +- .../user-process/user-process.component.scss | 63 +- .../user-process/user-process.component.ts | 26 +- .../lib/user-process/user-process.module.ts | 34 +- .../user-process/user-processes.service.ts | 11 +- .../lib/user/pending-items-type.interface.ts | 4 +- .../qer/src/lib/user/user-model.service.ts | 22 +- .../projects/qer/src/lib/user/user.module.ts | 12 +- .../lib/view-config/view-config.service.ts | 103 +- .../create-new-device.component.html | 12 +- .../create-new-device.component.scss | 7 - .../create-new-device.component.ts | 30 +- .../view-devices.component.html | 95 +- .../view-devices.component.scss | 58 +- .../view-devices.component.ts | 238 +- .../view-devices-sidesheet.component.html | 18 +- .../view-devices-sidesheet.component.scss | 20 - .../view-devices-sidesheet.component.ts | 50 +- .../lib/view-devices/view-devices.module.ts | 67 +- .../lib/view-devices/view-devices.service.ts | 43 +- .../businessowner-chartsummary.component.html | 89 +- .../businessowner-chartsummary.component.scss | 35 +- .../businessowner-chartsummary.component.ts | 72 +- .../src/lib/wport/start/dashboard.service.ts | 10 +- .../src/lib/wport/start/start.component.html | 68 +- .../src/lib/wport/start/start.component.scss | 17 +- .../src/lib/wport/start/start.component.ts | 30 +- imxweb/projects/qer/src/public_api.ts | 72 +- imxweb/projects/qer/src/test.ts | 18 +- imxweb/projects/qer/tsconfig.lib.json | 11 +- imxweb/projects/qer/tsconfig.spec.json | 15 +- imxweb/projects/qer/tslint.json | 17 - imxweb/projects/rmb/.compodocrc.json | 2 +- imxweb/projects/rmb/.eslintrc.json | 35 + imxweb/projects/rmb/imx-plugin-config.json | 2 +- imxweb/projects/rmb/karma.conf.js | 11 +- imxweb/projects/rmb/ng-package.dynamic.json | 5 +- imxweb/projects/rmb/ng-package.json | 2 +- imxweb/projects/rmb/package.json | 2 +- imxweb/projects/rmb/project.json | 64 + imxweb/projects/rmb/src/lib/init.service.ts | 78 +- imxweb/projects/rmb/src/lib/org-data-model.ts | 13 +- imxweb/projects/rmb/src/lib/org-membership.ts | 84 +- .../rmb/src/lib/rmb-api-client.service.ts | 11 +- .../projects/rmb/src/lib/rmb-config.module.ts | 10 +- .../lib/team-role/team-role.component.html | 8 +- .../lib/team-role/team-role.component.scss | 3 - .../src/lib/team-role/team-role.component.ts | 76 +- .../rmb/src/lib/team-role/team-role.module.ts | 26 +- imxweb/projects/rmb/src/public_api.ts | 2 +- imxweb/projects/rmb/src/test.ts | 26 +- imxweb/projects/rmb/tsconfig.lib.json | 9 +- imxweb/projects/rmb/tsconfig.lib.prod.json | 3 - imxweb/projects/rmb/tsconfig.spec.json | 15 +- imxweb/projects/rmb/tslint.json | 17 - imxweb/projects/rms/.compodocrc.json | 2 +- imxweb/projects/rms/.eslintrc.json | 35 + imxweb/projects/rms/imx-plugin-config.json | 2 +- imxweb/projects/rms/karma.conf.js | 11 +- imxweb/projects/rms/ng-package.dynamic.json | 5 +- imxweb/projects/rms/ng-package.json | 2 +- imxweb/projects/rms/package.json | 2 +- imxweb/projects/rms/project.json | 64 + .../projects/rms/src/lib/eset-data-model.ts | 13 +- .../projects/rms/src/lib/eset-entitlements.ts | 65 +- .../projects/rms/src/lib/eset-membership.ts | 70 +- imxweb/projects/rms/src/lib/init.service.ts | 54 +- .../src/lib/requestable-systemrole-type.ts | 60 +- .../rms/src/lib/rms-api-client.service.ts | 13 +- .../projects/rms/src/lib/rms-config.module.ts | 9 +- imxweb/projects/rms/src/public_api.ts | 2 +- imxweb/projects/rms/src/test.ts | 26 +- imxweb/projects/rms/tsconfig.lib.json | 9 +- imxweb/projects/rms/tsconfig.lib.prod.json | 3 - imxweb/projects/rms/tsconfig.spec.json | 15 +- imxweb/projects/rms/tslint.json | 17 - imxweb/projects/rps/.compodocrc.json | 2 +- imxweb/projects/rps/.eslintrc.json | 35 + imxweb/projects/rps/imx-plugin-config.json | 8 +- imxweb/projects/rps/karma.conf.js | 11 +- imxweb/projects/rps/ng-package.dynamic.json | 5 +- imxweb/projects/rps/ng-package.json | 2 +- imxweb/projects/rps/package.json | 2 +- imxweb/projects/rps/project.json | 64 + .../rps/src/lib/admin/permissions-helper.ts | 6 +- .../src/lib/admin/rps-permissions.service.ts | 9 +- imxweb/projects/rps/src/lib/init.service.ts | 16 +- .../list-report-data-provider.interface.ts | 10 +- .../list-report-viewer.component.html | 4 +- .../list-report-viewer.component.scss | 21 +- .../list-report-viewer.component.ts | 46 +- .../list-report-viewer.module.ts | 6 +- .../list-report-viewer.service.ts | 6 +- .../parameter-sidesheet.component.html | 18 +- .../parameter-sidesheet.component.scss | 4 - .../parameter-sidesheet.component.ts | 29 +- .../report-button-mail.component.html | 3 + .../report-button-mail.component.scss | 1 + .../report-button-mail.component.ts | 119 + .../report-button/report-button-parameter.ts | 2 +- .../report-button.component.html | 4 +- .../report-button.component.scss | 2 +- .../report-button/report-button.component.ts | 59 +- .../lib/report-button/report-button.module.ts | 13 +- .../edit-report-sidesheet.component.html | 20 +- .../edit-report-sidesheet.component.scss | 25 - .../edit-report-sidesheet.component.ts | 67 +- .../lib/reports/edit-report.component.html | 62 +- .../lib/reports/edit-report.component.scss | 64 +- .../src/lib/reports/edit-report.component.ts | 113 +- .../rps/src/lib/reports/edit-report.module.ts | 82 +- .../src/lib/reports/edit-report.service.ts | 31 +- .../reports/editreport-sqlwizard.service.ts | 16 +- .../rps/src/lib/rps-api-client.service.ts | 11 +- .../projects/rps/src/lib/rps-config.module.ts | 21 +- .../statistic-report-button.component.html | 6 +- .../statistic-report-button.component.scss | 14 +- .../statistic-report-button.component.ts | 15 +- .../statistic-report-button.module.ts | 5 +- .../statistic-report-button.service.ts | 6 +- ...ist-report-viewer-sidesheet.component.html | 6 +- ...ist-report-viewer-sidesheet.component.scss | 4 +- .../list-report-viewer-sidesheet.component.ts | 12 +- .../report-parameter-wrapper.ts | 42 +- .../report-subscription.service.ts | 88 +- .../report-subscription.ts | 31 +- .../report-view-config.component.html | 10 +- .../report-view-config.component.scss | 32 +- .../report-view-config.component.ts | 55 +- .../subscription-details.component.html | 8 +- .../subscription-details.component.scss | 13 - .../subscription-details.component.ts | 20 +- .../subscription-properties.component.html | 40 +- .../subscription-properties.component.scss | 7 +- .../subscription-properties.component.ts | 12 +- .../report-selector.component.html | 32 +- .../report-selector.component.scss | 18 +- .../report-selector.component.ts | 24 +- .../subscription-overview.component.html | 40 +- .../subscription-overview.component.scss | 6 +- .../subscription-overview.component.ts | 51 +- .../subscription-wizard.component.html | 34 +- .../subscription-wizard.component.scss | 8 +- .../subscription-wizard.component.ts | 41 +- .../subscriptions.component.html | 40 +- .../subscriptions.component.scss | 49 +- .../subscriptions/subscriptions.component.ts | 48 +- .../lib/subscriptions/subscriptions.module.ts | 72 +- .../subscriptions/subscriptions.service.ts | 21 +- imxweb/projects/rps/src/public_api.ts | 6 +- imxweb/projects/rps/src/test.ts | 26 +- imxweb/projects/rps/tsconfig.lib.json | 9 +- imxweb/projects/rps/tsconfig.lib.prod.json | 3 - imxweb/projects/rps/tsconfig.spec.json | 15 +- imxweb/projects/rps/tslint.json | 17 - imxweb/projects/sac/.compodocrc.json | 2 +- imxweb/projects/sac/.eslintrc.json | 35 + imxweb/projects/sac/imx-plugin-config.json | 8 +- imxweb/projects/sac/karma.conf.js | 11 +- imxweb/projects/sac/ng-package.dynamic.json | 5 +- imxweb/projects/sac/ng-package.json | 3 +- imxweb/projects/sac/package.json | 24 +- imxweb/projects/sac/project.json | 49 + imxweb/projects/sac/src/lib/init.service.ts | 18 +- .../sac/src/lib/sac-api-client.service.ts | 11 +- .../projects/sac/src/lib/sac-config.module.ts | 7 +- ...ance-violation-views-by-ability-builder.ts | 6 +- ...iance-violation-views-by-ability-entity.ts | 4 +- ...-violation-views-by-ability.component.html | 29 +- ...-violation-views-by-ability.component.scss | 6 +- ...ce-violation-views-by-ability.component.ts | 51 +- ...nce-violation-views-by-role.component.html | 64 +- ...nce-violation-views-by-role.component.scss | 98 +- ...iance-violation-views-by-role.component.ts | 32 +- .../sap-compliance-violation.component.html | 38 +- .../sap-compliance-violation.component.scss | 45 +- .../sap-compliance-violation.component.ts | 10 +- .../sap-compliance-violation.model.ts | 13 +- imxweb/projects/sac/src/public_api.ts | 2 +- imxweb/projects/sac/src/test.ts | 26 +- imxweb/projects/sac/tsconfig.lib.json | 13 +- imxweb/projects/sac/tsconfig.lib.prod.json | 3 - imxweb/projects/sac/tsconfig.spec.json | 15 +- imxweb/projects/sac/tslint.json | 17 - imxweb/projects/tsb/.compodocrc.json | 2 +- imxweb/projects/tsb/.eslintrc.json | 35 + imxweb/projects/tsb/imx-plugin-config.json | 8 +- imxweb/projects/tsb/karma.conf.js | 11 +- imxweb/projects/tsb/ng-package.dynamic.json | 5 +- imxweb/projects/tsb/ng-package.json | 2 +- imxweb/projects/tsb/package.json | 2 +- imxweb/projects/tsb/project.json | 64 + .../account-ext/account-ext.service.ts | 10 +- .../account-ext/accounts-ext.component.html | 37 +- .../account-ext/accounts-ext.component.scss | 4 +- .../account-ext/accounts-ext.component.ts | 10 +- .../account-sidesheet.component.html | 84 +- .../account-sidesheet.component.scss | 90 +- .../account-sidesheet.component.ts | 47 +- .../src/lib/accounts/account-typed-entity.ts | 4 +- .../lib/accounts/accounts-reports.service.ts | 14 +- .../src/lib/accounts/accounts.component.html | 113 +- .../src/lib/accounts/accounts.component.scss | 21 +- .../src/lib/accounts/accounts.component.ts | 187 +- .../tsb/src/lib/accounts/accounts.models.ts | 8 +- .../tsb/src/lib/accounts/accounts.module.ts | 42 +- .../tsb/src/lib/accounts/accounts.service.ts | 46 +- .../target-system-report.component.html | 25 +- .../target-system-report.component.scss | 6 - .../target-system-report.component.ts | 47 +- .../src/lib/admin/tsb-permissions-helper.ts | 6 +- .../src/lib/admin/tsb-permissions.service.ts | 8 +- .../claim-group/claim-group.component.html | 67 +- .../claim-group/claim-group.component.scss | 19 +- .../lib/claim-group/claim-group.component.ts | 83 +- .../src/lib/claim-group/claim-group.module.ts | 11 +- .../lib/claim-group/claim-group.service.ts | 77 +- .../container-tree-database-wrapper.ts | 19 +- .../data-explorer-filters.component.html | 57 +- .../data-explorer-filters.component.scss | 16 +- .../data-explorer-filters.component.ts | 57 +- .../lib/data-filters/data-filters.module.ts | 17 +- .../projects/tsb/src/lib/de-helper.service.ts | 18 +- .../group-memberships-ext.component.html | 55 +- .../group-memberships-ext.component.scss | 14 +- .../group-memberships-ext.component.ts | 82 +- .../group-memberships-ext.service.ts | 14 +- .../child-system-entitlements.component.html | 14 +- ...hild-system-entitlements.component.spec.ts | 48 +- .../child-system-entitlements.component.ts | 36 +- .../group-members.component.html | 172 +- .../group-members.component.scss | 28 +- .../group-members/group-members.component.ts | 228 +- .../new-membership/new-membership.service.ts | 39 +- .../group-sidesheet.component.html | 173 +- .../group-sidesheet.component.scss | 105 +- .../group-sidesheet.component.ts | 81 +- .../tsb/src/lib/groups/group-typed-entity.ts | 12 +- .../src/lib/groups/groups-reports.service.ts | 12 +- .../tsb/src/lib/groups/groups.component.html | 117 +- .../tsb/src/lib/groups/groups.component.scss | 27 +- .../tsb/src/lib/groups/groups.component.ts | 245 +- .../tsb/src/lib/groups/groups.models.ts | 16 +- .../tsb/src/lib/groups/groups.module.ts | 32 +- .../tsb/src/lib/groups/groups.service.ts | 126 +- .../product-owner-sidesheet.component.html | 22 +- .../product-owner-sidesheet.component.scss | 2 +- .../product-owner-sidesheet.component.ts | 12 +- .../product-owner-sidesheet.service.ts | 14 +- .../tsb-namespace-admin-guard.service.ts | 14 +- imxweb/projects/tsb/src/lib/init.service.ts | 67 +- .../src/lib/no-data/no-data.component.html | 10 +- .../src/lib/no-data/no-data.component.scss | 9 +- .../tsb/src/lib/no-data/no-data.component.ts | 2 +- .../tsb/src/lib/no-data/no-data.module.ts | 19 +- .../report-button-ext.component.html | 2 +- .../report-button-ext.component.scss | 2 +- .../report-button-ext.component.ts | 29 +- .../report-button-ext.module.ts | 13 +- .../db-object-key-wrapper.interface.ts | 6 +- .../target-system/path-parameter-wrapper.ts | 2 +- .../target-system-dynamic-method.service.ts | 47 +- .../target-system/target-system.service.ts | 8 +- .../src/lib/test/common-test-mocks.spec.ts | 55 +- .../tsb/src/lib/tsb-api-client.service.ts | 11 +- .../projects/tsb/src/lib/tsb-config.module.ts | 21 +- imxweb/projects/tsb/src/public_api.ts | 2 +- imxweb/projects/tsb/src/test.ts | 31 +- imxweb/projects/tsb/tsconfig.lib.json | 9 +- imxweb/projects/tsb/tsconfig.lib.prod.json | 3 - imxweb/projects/tsb/tsconfig.spec.json | 15 +- imxweb/projects/tsb/tslint.json | 17 - imxweb/projects/uci/.compodocrc.json | 2 +- imxweb/projects/uci/.eslintrc.json | 35 + imxweb/projects/uci/.vscode/settings.json | 2 +- imxweb/projects/uci/imx-plugin-config.json | 8 +- imxweb/projects/uci/karma.conf.js | 11 +- .../projects/uci/ng-package.dynamic-ops.json | 26 + imxweb/projects/uci/ng-package.json | 2 +- imxweb/projects/uci/package.json | 2 +- imxweb/projects/uci/project.json | 70 + .../change-sidesheet.component.html | 27 +- .../change-sidesheet.component.scss | 16 +- .../changeview/change-sidesheet.component.ts | 46 +- .../lib/changeview/change-view.component.html | 79 +- .../lib/changeview/change-view.component.scss | 17 +- .../lib/changeview/change-view.component.ts | 192 +- .../src/lib/changeview/change-view.service.ts | 27 +- .../src/lib/changeview/changeview.module.ts | 31 +- imxweb/projects/uci/src/lib/init.service.ts | 61 +- .../uci/src/lib/uci-api-client.service.ts | 11 +- .../projects/uci/src/lib/uci-config.module.ts | 17 +- imxweb/projects/uci/src/public_api.ts | 2 +- imxweb/projects/uci/src/test.ts | 26 +- imxweb/projects/uci/tsconfig.lib.json | 9 +- imxweb/projects/uci/tsconfig.lib.prod.json | 3 - imxweb/projects/uci/tsconfig.spec.json | 15 +- imxweb/projects/uci/tslint.json | 17 - imxweb/remove-local-package-locks.js | 47 +- imxweb/shared/assets/variables.scss | 29 - imxweb/shared/scss/base/colors.scss | 46 + imxweb/shared/scss/base/fonts.scss | 6 + imxweb/shared/scss/base/margins-paddings.scss | 59 + imxweb/shared/scss/base/mixins.scss | 237 + imxweb/shared/scss/{ => base}/theme.scss | 11 +- imxweb/shared/scss/base/variables.scss | 54 + imxweb/shared/scss/common-table.scss | 44 - imxweb/shared/scss/common/captcha-login.scss | 68 + .../scss/common/mitigating-controls.scss | 136 + imxweb/shared/scss/common/select.scss | 35 + imxweb/shared/scss/components/alert.scss | 88 + .../shared/scss/components/autocomplete.scss | 20 + imxweb/shared/scss/components/badge.scss | 44 + .../shared/scss/components/button-toggle.scss | 72 + imxweb/shared/scss/components/button.scss | 247 + imxweb/shared/scss/components/card.scss | 160 + imxweb/shared/scss/components/chart.scss | 63 + imxweb/shared/scss/components/checkbox.scss | 67 + imxweb/shared/scss/components/chips.scss | 58 + imxweb/shared/scss/components/clickable.scss | 12 + .../scss/components/data-source-toolbar.scss | 21 + .../shared/scss/components/date-picker.scss | 28 + imxweb/shared/scss/components/dialog.scss | 42 + imxweb/shared/scss/components/divider.scss | 19 + imxweb/shared/scss/components/download.scss | 9 + .../scss/components/expansion-panel.scss | 109 + imxweb/shared/scss/components/form-field.scss | 100 + imxweb/shared/scss/components/icon.scss | 216 + imxweb/shared/scss/components/input.scss | 64 + .../shared/scss/components/layout-grid.scss | 9 + imxweb/shared/scss/components/list.scss | 103 + imxweb/shared/scss/components/logo.scss | 14 + imxweb/shared/scss/components/masthead.scss | 41 + imxweb/shared/scss/components/menu.scss | 29 + imxweb/shared/scss/components/paginator.scss | 26 + .../shared/scss/components/progress-bar.scss | 66 + .../shared/scss/components/radio-button.scss | 61 + imxweb/shared/scss/components/ripple.scss | 13 + imxweb/shared/scss/components/scrollbar.scss | 14 + imxweb/shared/scss/components/search.scss | 19 + imxweb/shared/scss/components/select.scss | 115 + .../scss/components/side-navigation.scss | 438 + imxweb/shared/scss/components/sidesheet.scss | 61 + .../shared/scss/components/slide-toggle.scss | 41 + imxweb/shared/scss/components/slider.scss | 55 + imxweb/shared/scss/components/snackbar.scss | 9 + .../shared/scss/components/sort-header.scss | 9 + imxweb/shared/scss/components/spinner.scss | 31 + imxweb/shared/scss/components/stepper.scss | 34 + imxweb/shared/scss/components/table.scss | 337 + imxweb/shared/scss/components/tabs.scss | 262 + .../scss/components/theme-switcher.scss | 15 + .../shared/scss/components/time-picker.scss | 39 + imxweb/shared/scss/components/toolbar.scss | 63 + imxweb/shared/scss/components/tooltip.scss | 24 + .../scss/components/top-navigation.scss | 25 + imxweb/shared/scss/components/tree.scss | 117 + imxweb/shared/scss/side-navigation.scss | 176 - imxweb/shared/{assets => scss}/styles.scss | 361 +- imxweb/tsconfig.json | 43 +- imxweb/tslint.json | 158 - 3237 files changed, 90075 insertions(+), 85679 deletions(-) create mode 100644 .commit create mode 100644 imxweb/.eslintignore create mode 100644 imxweb/.eslintrc.json create mode 100644 imxweb/.prettierignore create mode 100644 imxweb/.prettierrc.json create mode 100644 imxweb/build-docs.js create mode 100644 imxweb/build/nx/Build.proj delete mode 100644 imxweb/changes/changesFrom9.1.1To9.2.0.md create mode 100644 imxweb/compodoc/assets/images/dashboard/2-dashboard.png create mode 100644 imxweb/compodoc/assets/images/data_table/4-table-with-buttons.png delete mode 100644 imxweb/compodoc/assets/images/data_table/4-table-with-search.png create mode 100644 imxweb/imx-modules/elemental-ui-cadence-icon-3.1.107.tgz create mode 100644 imxweb/imx-modules/elemental-ui-core-18.0.14.tgz delete mode 100644 imxweb/imx-modules/elemental-ui_cadence-icon.tgz delete mode 100644 imxweb/imx-modules/elemental-ui_core.tgz create mode 100644 imxweb/imx-modules/imx-api-APC.tgz-hash create mode 100644 imxweb/imx-modules/imx-api-APC.tgz-version create mode 100644 imxweb/imx-modules/imx-api-aad.tgz-hash create mode 100644 imxweb/imx-modules/imx-api-aad.tgz-version create mode 100644 imxweb/imx-modules/imx-api-aob.tgz-hash create mode 100644 imxweb/imx-modules/imx-api-aob.tgz-version create mode 100644 imxweb/imx-modules/imx-api-att.tgz-hash create mode 100644 imxweb/imx-modules/imx-api-att.tgz-version create mode 100644 imxweb/imx-modules/imx-api-cpl.tgz-hash create mode 100644 imxweb/imx-modules/imx-api-cpl.tgz-version create mode 100644 imxweb/imx-modules/imx-api-dpr.tgz-hash create mode 100644 imxweb/imx-modules/imx-api-dpr.tgz-version create mode 100644 imxweb/imx-modules/imx-api-hds.tgz-hash create mode 100644 imxweb/imx-modules/imx-api-hds.tgz-version delete mode 100644 imxweb/imx-modules/imx-api-o3e.tgz delete mode 100644 imxweb/imx-modules/imx-api-o3t.tgz create mode 100644 imxweb/imx-modules/imx-api-olg.tgz-hash create mode 100644 imxweb/imx-modules/imx-api-olg.tgz-version create mode 100644 imxweb/imx-modules/imx-api-pol.tgz-hash create mode 100644 imxweb/imx-modules/imx-api-pol.tgz-version create mode 100644 imxweb/imx-modules/imx-api-qbm.tgz-hash create mode 100644 imxweb/imx-modules/imx-api-qbm.tgz-version create mode 100644 imxweb/imx-modules/imx-api-qer.tgz-hash create mode 100644 imxweb/imx-modules/imx-api-qer.tgz-version create mode 100644 imxweb/imx-modules/imx-api-rmb.tgz-hash create mode 100644 imxweb/imx-modules/imx-api-rmb.tgz-version create mode 100644 imxweb/imx-modules/imx-api-rms.tgz-hash create mode 100644 imxweb/imx-modules/imx-api-rms.tgz-version create mode 100644 imxweb/imx-modules/imx-api-rps.tgz-hash create mode 100644 imxweb/imx-modules/imx-api-rps.tgz-version create mode 100644 imxweb/imx-modules/imx-api-sac.tgz-hash create mode 100644 imxweb/imx-modules/imx-api-sac.tgz-version create mode 100644 imxweb/imx-modules/imx-api-tsb.tgz-hash create mode 100644 imxweb/imx-modules/imx-api-tsb.tgz-version create mode 100644 imxweb/imx-modules/imx-api-uci.tgz-hash create mode 100644 imxweb/imx-modules/imx-api-uci.tgz-version delete mode 100644 imxweb/imx-modules/imx-api.tgz create mode 100644 imxweb/install-local-packages.js create mode 100644 imxweb/nx.json create mode 100644 imxweb/prebuild.js create mode 100644 imxweb/projects/aad/.eslintrc.json create mode 100644 imxweb/projects/aad/project.json delete mode 100644 imxweb/projects/aad/src/lib/aad-extension/licence-overview-button/licence-overview-button.component.scss delete mode 100644 imxweb/projects/aad/src/lib/azure-ad/aad-user/aad-user-create-dialog.component.scss create mode 100644 imxweb/projects/aob/.eslintrc.json create mode 100644 imxweb/projects/aob/project.json delete mode 100644 imxweb/projects/aob/src/lib/applications/application-hyperview/application-hyperview.component.html delete mode 100644 imxweb/projects/aob/src/lib/applications/application-hyperview/application-hyperview.component.scss delete mode 100644 imxweb/projects/aob/src/lib/applications/application-hyperview/application-hyperview.component.ts delete mode 100644 imxweb/projects/aob/src/lib/applications/application-hyperview/application-hyperview.module.ts delete mode 100644 imxweb/projects/aob/src/lib/applications/edit-application/edit-application.component.scss delete mode 100644 imxweb/projects/aob/src/lib/applications/edit-application/service-category/service-category.component.scss delete mode 100644 imxweb/projects/aob/src/lib/entitlements/entitlement-edit-auto-add/entitlement-edit-auto-add.component.scss delete mode 100644 imxweb/projects/aob/src/lib/global-kpi/kpi-tile/kpi-tile.component.scss delete mode 100644 imxweb/projects/aob/tslint.json create mode 100644 imxweb/projects/apc/.eslintrc.json create mode 100644 imxweb/projects/apc/project.json delete mode 100644 imxweb/projects/apc/tslint.json create mode 100644 imxweb/projects/att/.eslintrc.json rename imxweb/projects/{o3t/ng-package.dynamic.json => att/ng-package.dynamic-pwd.json} (84%) create mode 100644 imxweb/projects/att/project.json delete mode 100644 imxweb/projects/att/src/lib/attestation-display/attestation-display.component.scss delete mode 100644 imxweb/projects/att/src/lib/datamodel/datamodel-helper.ts rename imxweb/projects/{aob/src/lib/applications/application-hyperview/application-hyperview.service.ts => att/src/lib/new-user/new-user-metadata.service.ts} (64%) delete mode 100644 imxweb/projects/att/src/lib/new-user/open-sidesheet.component.scss delete mode 100644 imxweb/projects/att/src/lib/policies/attestation-cases/attestation-cases-tree-database.service.ts delete mode 100644 imxweb/projects/att/src/lib/runs/progress/progress.component.scss delete mode 100644 imxweb/projects/att/tslint.json create mode 100644 imxweb/projects/cpl/.eslintrc.json create mode 100644 imxweb/projects/cpl/project.json delete mode 100644 imxweb/projects/cpl/tslint.json create mode 100644 imxweb/projects/custom-app/.eslintrc.json create mode 100644 imxweb/projects/custom-app/project.json rename imxweb/projects/{o3t => custom-app}/src/test.ts (66%) delete mode 100644 imxweb/projects/custom-app/tslint.json create mode 100644 imxweb/projects/dpr/.eslintrc.json create mode 100644 imxweb/projects/dpr/project.json delete mode 100644 imxweb/projects/dpr/tslint.json create mode 100644 imxweb/projects/hds/.eslintrc.json create mode 100644 imxweb/projects/hds/project.json delete mode 100644 imxweb/projects/hds/tslint.json delete mode 100644 imxweb/projects/o3t/imx-plugin-config.json delete mode 100644 imxweb/projects/o3t/package.json delete mode 100644 imxweb/projects/o3t/src/lib/teams/team-channel-details/team-channel-details.component.html delete mode 100644 imxweb/projects/o3t/src/lib/teams/team-channel-details/team-channel-details.component.ts delete mode 100644 imxweb/projects/o3t/src/lib/teams/team-channels/team-channels.component.html delete mode 100644 imxweb/projects/o3t/src/lib/teams/team-channels/team-channels.component.ts delete mode 100644 imxweb/projects/o3t/src/lib/teams/team-details/team-details.component.html delete mode 100644 imxweb/projects/o3t/src/lib/teams/team-details/team-details.component.ts delete mode 100644 imxweb/projects/o3t/src/lib/teams/teams.component.html delete mode 100644 imxweb/projects/o3t/src/lib/teams/teams.component.ts delete mode 100644 imxweb/projects/o3t/src/lib/teams/teams.service.ts delete mode 100644 imxweb/projects/o3t/src/test/o3t-common-test-mocks.ts delete mode 100644 imxweb/projects/o3t/tslint.json create mode 100644 imxweb/projects/olg/.eslintrc.json create mode 100644 imxweb/projects/olg/project.json delete mode 100644 imxweb/projects/olg/tslint.json create mode 100644 imxweb/projects/pol/.eslintrc.json create mode 100644 imxweb/projects/pol/project.json rename imxweb/projects/{qbm/src/lib/object-sheet/navigation.service.ts => pol/src/lib/guards/policy-owner-or-admin-guard.service.ts} (55%) delete mode 100644 imxweb/projects/pol/src/lib/policies/policies-sidesheet/policies-sidesheet.component.scss delete mode 100644 imxweb/projects/pol/tslint.json rename imxweb/projects/{o3t => qam}/.compodocrc.json (55%) rename imxweb/projects/{o3t => qam}/Build.proj (75%) create mode 100644 imxweb/projects/qam/imx-plugin-config.json rename imxweb/projects/{o3t => qam}/karma.conf.js (78%) rename imxweb/projects/{uci => qam}/ng-package.dynamic.json (87%) rename imxweb/projects/{o3t => qam}/ng-package.json (62%) create mode 100644 imxweb/projects/qam/package.json create mode 100644 imxweb/projects/qam/project.json create mode 100644 imxweb/projects/qam/src/lib/TypedClient.ts create mode 100644 imxweb/projects/qam/src/lib/access-request/access-request-data.service.ts create mode 100644 imxweb/projects/qam/src/lib/access-request/access-request-sidesheet-data.interface.ts create mode 100644 imxweb/projects/qam/src/lib/access-request/access-request-sidesheet.component.html create mode 100644 imxweb/projects/qam/src/lib/access-request/access-request-sidesheet.component.scss create mode 100644 imxweb/projects/qam/src/lib/access-request/access-request-sidesheet.component.ts create mode 100644 imxweb/projects/qam/src/lib/access-request/access-request-tree-database.ts rename imxweb/projects/{qbm/src/lib/sidenav-tree/sidenav-tree.module.ts => qam/src/lib/access-request/access-request.module.ts} (63%) create mode 100644 imxweb/projects/qam/src/lib/access-request/access-request.service.ts create mode 100644 imxweb/projects/qam/src/lib/access-request/qam-resourcetree.ts create mode 100644 imxweb/projects/qam/src/lib/access/access.component.html create mode 100644 imxweb/projects/qam/src/lib/access/access.component.scss create mode 100644 imxweb/projects/qam/src/lib/access/access.component.ts create mode 100644 imxweb/projects/qam/src/lib/access/trustee-view.component.html create mode 100644 imxweb/projects/qam/src/lib/access/trustee-view.component.scss create mode 100644 imxweb/projects/qam/src/lib/access/trustee-view.component.ts create mode 100644 imxweb/projects/qam/src/lib/access/user-access.component.html rename imxweb/projects/{qer/src/lib/approval-workflows/approval-workflow-edit/approval-workflow-edit-info/approval-workflow-edit-info.component.ts => qam/src/lib/access/user-access.component.ts} (66%) create mode 100644 imxweb/projects/qam/src/lib/dug-activities/dug-activities.component.html create mode 100644 imxweb/projects/qam/src/lib/dug-activities/dug-activities.component.scss create mode 100644 imxweb/projects/qam/src/lib/dug-activities/dug-activities.component.ts rename imxweb/projects/{qer/src/lib/statistics/statistics-home-page/statistics-ordering-sidesheet/statistics-ordering-sidesheet-dialog/statistics-ordering-sidesheet-dialog.component.ts => qam/src/lib/dug-activities/dug-activities.service.ts} (53%) create mode 100644 imxweb/projects/qam/src/lib/dug-activities/dug-activity-entity.ts create mode 100644 imxweb/projects/qam/src/lib/dug-dashboards/dug-dashboards.component.html create mode 100644 imxweb/projects/qam/src/lib/dug-dashboards/dug-dashboards.component.scss create mode 100644 imxweb/projects/qam/src/lib/dug-dashboards/dug-dashboards.component.ts rename imxweb/projects/{qbm/src/lib/select/check-match.validator.ts => qam/src/lib/dug-dashboards/dug-dashboards.service.ts} (65%) create mode 100644 imxweb/projects/qam/src/lib/dug-overview/dug-overview.component.html create mode 100644 imxweb/projects/qam/src/lib/dug-overview/dug-overview.component.scss create mode 100644 imxweb/projects/qam/src/lib/dug-overview/dug-overview.component.ts create mode 100644 imxweb/projects/qam/src/lib/dug-overview/dug-overview.service.ts create mode 100644 imxweb/projects/qam/src/lib/dug/access-comparison.component.html create mode 100644 imxweb/projects/qam/src/lib/dug/access-comparison.component.ts create mode 100644 imxweb/projects/qam/src/lib/dug/dug-access-analysis.component.html create mode 100644 imxweb/projects/qam/src/lib/dug/dug-access-analysis.component.ts create mode 100644 imxweb/projects/qam/src/lib/dug/dug-access-analysis.service.ts create mode 100644 imxweb/projects/qam/src/lib/dug/dug-access-detail.component.html create mode 100644 imxweb/projects/qam/src/lib/dug/dug-access-detail.component.scss create mode 100644 imxweb/projects/qam/src/lib/dug/dug-access-detail.component.ts create mode 100644 imxweb/projects/qam/src/lib/dug/dug-access/assigned-permissions/assigned-permissions.component.html create mode 100644 imxweb/projects/qam/src/lib/dug/dug-access/assigned-permissions/assigned-permissions.component.scss create mode 100644 imxweb/projects/qam/src/lib/dug/dug-access/assigned-permissions/assigned-permissions.component.ts create mode 100644 imxweb/projects/qam/src/lib/dug/dug-access/assigned-permissions/trustee-entity.ts create mode 100644 imxweb/projects/qam/src/lib/dug/dug-access/box-icon/box-icon.component.html create mode 100644 imxweb/projects/qam/src/lib/dug/dug-access/box-icon/box-icon.component.scss create mode 100644 imxweb/projects/qam/src/lib/dug/dug-access/box-icon/box-icon.component.ts create mode 100644 imxweb/projects/qam/src/lib/dug/dug-access/dug-access.component.html create mode 100644 imxweb/projects/qam/src/lib/dug/dug-access/dug-access.component.scss create mode 100644 imxweb/projects/qam/src/lib/dug/dug-access/dug-access.component.ts rename imxweb/projects/{qbm/src/lib/select/select.module.ts => qam/src/lib/dug/dug-access/dug-access.module.ts} (50%) create mode 100644 imxweb/projects/qam/src/lib/dug/dug-access/effective-permission/effective-permission-tree-database.ts create mode 100644 imxweb/projects/qam/src/lib/dug/dug-access/effective-permission/effective-permission.component.html create mode 100644 imxweb/projects/qam/src/lib/dug/dug-access/effective-permission/effective-permission.component.scss create mode 100644 imxweb/projects/qam/src/lib/dug/dug-access/effective-permission/effective-permission.component.ts create mode 100644 imxweb/projects/qam/src/lib/dug/dug-access/effective-permission/permission-member/permission-member.component.html create mode 100644 imxweb/projects/qam/src/lib/dug/dug-access/effective-permission/permission-member/permission-member.component.scss create mode 100644 imxweb/projects/qam/src/lib/dug/dug-access/effective-permission/permission-member/permission-member.component.ts create mode 100644 imxweb/projects/qam/src/lib/dug/dug-access/effective-permission/trustee-entity-hierarchy.ts create mode 100644 imxweb/projects/qam/src/lib/dug/dug-activity/dug-activity.component.html create mode 100644 imxweb/projects/qam/src/lib/dug/dug-activity/dug-activity.component.scss create mode 100644 imxweb/projects/qam/src/lib/dug/dug-activity/dug-activity.component.ts rename imxweb/projects/{o3t/src/lib/o3t-config.module.ts => qam/src/lib/dug/dug-activity/dug-activity.module.ts} (74%) create mode 100644 imxweb/projects/qam/src/lib/dug/dug-reports/dug-report-entity.ts create mode 100644 imxweb/projects/qam/src/lib/dug/dug-reports/dug-reports.component.html create mode 100644 imxweb/projects/qam/src/lib/dug/dug-reports/dug-reports.component.scss create mode 100644 imxweb/projects/qam/src/lib/dug/dug-reports/dug-reports.component.ts create mode 100644 imxweb/projects/qam/src/lib/dug/dug-reports/dug-reports.service.ts create mode 100644 imxweb/projects/qam/src/lib/dug/dug-sidesheet.component.html create mode 100644 imxweb/projects/qam/src/lib/dug/dug-sidesheet.component.scss create mode 100644 imxweb/projects/qam/src/lib/dug/dug-sidesheet.component.ts create mode 100644 imxweb/projects/qam/src/lib/identity/identity.component.html create mode 100644 imxweb/projects/qam/src/lib/identity/identity.component.scss create mode 100644 imxweb/projects/qam/src/lib/identity/identity.component.ts create mode 100644 imxweb/projects/qam/src/lib/init.service.ts rename imxweb/projects/{o3t/src/lib/api.service.ts => qam/src/lib/qam-api-client.service.ts} (63%) create mode 100644 imxweb/projects/qam/src/lib/qam-config.module.ts create mode 100644 imxweb/projects/qam/src/lib/qam.scss rename imxweb/projects/{o3t/src/lib/api.service.spec.ts => qam/src/public_api.ts} (84%) create mode 100644 imxweb/projects/qam/src/test.ts rename imxweb/projects/{o3t => qam}/tsconfig.lib.json (68%) rename imxweb/projects/{o3t => qam}/tsconfig.lib.prod.json (75%) rename imxweb/projects/{o3t => qam}/tsconfig.spec.json (100%) rename imxweb/projects/{aad => qam}/tslint.json (100%) create mode 100644 imxweb/projects/qbm-app-landingpage/.eslintrc.json create mode 100644 imxweb/projects/qbm-app-landingpage/README.md create mode 100644 imxweb/projects/qbm-app-landingpage/project.json delete mode 100644 imxweb/projects/qbm-app-landingpage/tslint.json create mode 100644 imxweb/projects/qbm/.eslintrc.json create mode 100644 imxweb/projects/qbm/project.json create mode 100644 imxweb/projects/qbm/src/lib/admin/about/admin-about.service.ts rename imxweb/projects/qbm/src/lib/{temp-billboard/temp-billboard.module.ts => base/elemental-defaults.ts} (58%) rename imxweb/projects/qbm/src/lib/{menu/menu-item/group-menu-item.ts => base/sidesheet-helper.ts} (59%) create mode 100644 imxweb/projects/qbm/src/lib/captcha/captcha.component.scss create mode 100644 imxweb/projects/qbm/src/lib/cdr/edit-bitmask/edit-bitmask.component.html create mode 100644 imxweb/projects/qbm/src/lib/cdr/edit-bitmask/edit-bitmask.component.scss create mode 100644 imxweb/projects/qbm/src/lib/cdr/edit-bitmask/edit-bitmask.component.ts delete mode 100644 imxweb/projects/qbm/src/lib/data-source-toolbar/data-source-paginator.component.scss create mode 100644 imxweb/projects/qbm/src/lib/data-source-toolbar/filter-wizard/filter-tree-sidesheet/filter-tree-sidesheet.component.html create mode 100644 imxweb/projects/qbm/src/lib/data-source-toolbar/filter-wizard/filter-tree-sidesheet/filter-tree-sidesheet.component.scss create mode 100644 imxweb/projects/qbm/src/lib/data-source-toolbar/filter-wizard/filter-tree-sidesheet/filter-tree-sidesheet.component.ts create mode 100644 imxweb/projects/qbm/src/lib/data-source-toolbar/filter-wizard/filter-tree-sidesheet/filter-tree-sidesheet.model.ts delete mode 100644 imxweb/projects/qbm/src/lib/data-table/data-table-generic-column.component.scss create mode 100644 imxweb/projects/qbm/src/lib/data-view/data-view-auto-table/data-view-auto-table.component.html create mode 100644 imxweb/projects/qbm/src/lib/data-view/data-view-auto-table/data-view-auto-table.component.scss create mode 100644 imxweb/projects/qbm/src/lib/data-view/data-view-auto-table/data-view-auto-table.component.ts create mode 100644 imxweb/projects/qbm/src/lib/data-view/data-view-chipbar/data-view-chipbar.component.html create mode 100644 imxweb/projects/qbm/src/lib/data-view/data-view-chipbar/data-view-chipbar.component.scss create mode 100644 imxweb/projects/qbm/src/lib/data-view/data-view-chipbar/data-view-chipbar.component.ts create mode 100644 imxweb/projects/qbm/src/lib/data-view/data-view-filter/data-view-filter.component.html create mode 100644 imxweb/projects/qbm/src/lib/data-view/data-view-filter/data-view-filter.component.scss create mode 100644 imxweb/projects/qbm/src/lib/data-view/data-view-filter/data-view-filter.component.ts create mode 100644 imxweb/projects/qbm/src/lib/data-view/data-view-group/data-view-group.component.html create mode 100644 imxweb/projects/qbm/src/lib/data-view/data-view-group/data-view-group.component.ts create mode 100644 imxweb/projects/qbm/src/lib/data-view/data-view-nested-table/data-view-nested-table.component.html create mode 100644 imxweb/projects/qbm/src/lib/data-view/data-view-nested-table/data-view-nested-table.component.ts create mode 100644 imxweb/projects/qbm/src/lib/data-view/data-view-paginator/data-view-paginator.component.html create mode 100644 imxweb/projects/qbm/src/lib/data-view/data-view-paginator/data-view-paginator.component.scss create mode 100644 imxweb/projects/qbm/src/lib/data-view/data-view-paginator/data-view-paginator.component.ts create mode 100644 imxweb/projects/qbm/src/lib/data-view/data-view-search/data-view-search.component.html create mode 100644 imxweb/projects/qbm/src/lib/data-view/data-view-search/data-view-search.component.scss create mode 100644 imxweb/projects/qbm/src/lib/data-view/data-view-search/data-view-search.component.ts create mode 100644 imxweb/projects/qbm/src/lib/data-view/data-view-selection/data-view-selection.component.html create mode 100644 imxweb/projects/qbm/src/lib/data-view/data-view-selection/data-view-selection.component.scss create mode 100644 imxweb/projects/qbm/src/lib/data-view/data-view-selection/data-view-selection.component.ts create mode 100644 imxweb/projects/qbm/src/lib/data-view/data-view-settings/data-view-settings.component.html create mode 100644 imxweb/projects/qbm/src/lib/data-view/data-view-settings/data-view-settings.component.ts create mode 100644 imxweb/projects/qbm/src/lib/data-view/data-view-source-factory.service.ts create mode 100644 imxweb/projects/qbm/src/lib/data-view/data-view-source.spec.ts create mode 100644 imxweb/projects/qbm/src/lib/data-view/data-view-source.ts create mode 100644 imxweb/projects/qbm/src/lib/data-view/data-view-status/data-view-status.component.html create mode 100644 imxweb/projects/qbm/src/lib/data-view/data-view-status/data-view-status.component.scss rename imxweb/projects/qbm/src/lib/{menu/menu-item/navigation-menu-item.ts => data-view/data-view-status/data-view-status.component.ts} (65%) create mode 100644 imxweb/projects/qbm/src/lib/data-view/data-view-toolbar/data-view-toolbar.component.html create mode 100644 imxweb/projects/qbm/src/lib/data-view/data-view-toolbar/data-view-toolbar.component.scss create mode 100644 imxweb/projects/qbm/src/lib/data-view/data-view-toolbar/data-view-toolbar.component.ts create mode 100644 imxweb/projects/qbm/src/lib/data-view/data-view.interface.ts create mode 100644 imxweb/projects/qbm/src/lib/data-view/data-view.module.ts delete mode 100644 imxweb/projects/qbm/src/lib/doc/doc-chapter.service.ts delete mode 100644 imxweb/projects/qbm/src/lib/info-modal-dialog/info-badge/info-badge.component.scss delete mode 100644 imxweb/projects/qbm/src/lib/master-detail/master-detail.component.html delete mode 100644 imxweb/projects/qbm/src/lib/master-detail/master-detail.component.ts delete mode 100644 imxweb/projects/qbm/src/lib/menu/menu.component.html delete mode 100644 imxweb/projects/qbm/src/lib/menu/menu.component.scss delete mode 100644 imxweb/projects/qbm/src/lib/menu/menu.component.ts delete mode 100644 imxweb/projects/qbm/src/lib/menu/menu.module.ts rename imxweb/projects/{o3t/src/public_api.ts => qbm/src/lib/message-dialog/message-dialog.service.ts} (73%) delete mode 100644 imxweb/projects/qbm/src/lib/plugins/plugin-loader.service.ts create mode 100644 imxweb/projects/qbm/src/lib/processing-queue/processing-queue.interface.ts create mode 100644 imxweb/projects/qbm/src/lib/processing-queue/processing-queue.service.ts create mode 100644 imxweb/projects/qbm/src/lib/processing-queue/processing-queue.spec.ts delete mode 100644 imxweb/projects/qbm/src/lib/progressbar/progressbar.component.scss delete mode 100644 imxweb/projects/qbm/src/lib/select/autocomplete.component.html delete mode 100644 imxweb/projects/qbm/src/lib/select/autocomplete.component.scss delete mode 100644 imxweb/projects/qbm/src/lib/select/autocomplete.component.ts delete mode 100644 imxweb/projects/qbm/src/lib/select/select-data-source.ts delete mode 100644 imxweb/projects/qbm/src/lib/select/select.component.html delete mode 100644 imxweb/projects/qbm/src/lib/select/select.component.scss delete mode 100644 imxweb/projects/qbm/src/lib/select/select.component.ts delete mode 100644 imxweb/projects/qbm/src/lib/services/device-state.service.ts delete mode 100644 imxweb/projects/qbm/src/lib/side-navigation-view/side-navigation-view.component.scss create mode 100644 imxweb/projects/qbm/src/lib/sidenav-tree/custom-tree-control.component.html create mode 100644 imxweb/projects/qbm/src/lib/sidenav-tree/custom-tree-control.component.scss create mode 100644 imxweb/projects/qbm/src/lib/sidenav-tree/custom-tree-control.component.ts delete mode 100644 imxweb/projects/qbm/src/lib/temp-billboard/temp-billboard.component.ts delete mode 100644 imxweb/projects/qbm/src/lib/tile/tile-variables.scss create mode 100644 imxweb/projects/qbm/src/lib/timeline/timeline.model.ts delete mode 100644 imxweb/projects/qbm/tslint.json create mode 100644 imxweb/projects/qer-app-operationssupport/.eslintrc.json create mode 100644 imxweb/projects/qer-app-operationssupport/prebuild.js create mode 100644 imxweb/projects/qer-app-operationssupport/project.json delete mode 100644 imxweb/projects/qer-app-operationssupport/tslint.json create mode 100644 imxweb/projects/qer-app-portal/.eslintrc.json create mode 100644 imxweb/projects/qer-app-portal/project.json delete mode 100644 imxweb/projects/qer-app-portal/src/app/portal-doc-configuration.service.ts delete mode 100644 imxweb/projects/qer-app-portal/tslint.json create mode 100644 imxweb/projects/qer-app-pwdportal/.eslintrc.json create mode 100644 imxweb/projects/qer-app-pwdportal/project.json delete mode 100644 imxweb/projects/qer-app-pwdportal/tslint.json create mode 100644 imxweb/projects/qer/.eslintrc.json create mode 100644 imxweb/projects/qer/project.json create mode 100644 imxweb/projects/qer/src/lib/about/portal-about.service.ts delete mode 100644 imxweb/projects/qer/src/lib/addressbook/addressbook-detail/addressbook-detail.component.scss delete mode 100644 imxweb/projects/qer/src/lib/approval-workflows/approval-workflow-edit/approval-workflow-edit-info/approval-workflow-edit-info.component.html delete mode 100644 imxweb/projects/qer/src/lib/approval-workflows/approval-workflow-edit/approval-workflow-edit-info/approval-workflow-edit-info.component.scss delete mode 100644 imxweb/projects/qer/src/lib/approval-workflows/approval-workflow-styles.scss create mode 100644 imxweb/projects/qer/src/lib/delegation/delegation-guard.service.ts delete mode 100644 imxweb/projects/qer/src/lib/dynamic-exclusion-dialog/dynamic-exclusion-dialog.component.scss create mode 100644 imxweb/projects/qer/src/lib/filter-sqlwizard/filter-sqlwizard.service.ts delete mode 100644 imxweb/projects/qer/src/lib/guards/data-explorer-guard.service.ts delete mode 100644 imxweb/projects/qer/src/lib/itshop/request-info/service-item-detail/service-item-detail.component.scss create mode 100644 imxweb/projects/qer/src/lib/metadata/portal-metadata.service.ts rename imxweb/projects/{qbm/src/lib/select/select-content-provider.interface.ts => qer/src/lib/new-request/constants.ts} (82%) delete mode 100644 imxweb/projects/qer/src/lib/new-request/new-request-peer-group/peer-group-discard-selected.component.scss rename imxweb/projects/qer/src/lib/object-hyperview/{object-hyperview-interface.ts => object-hyperview.interface.ts} (96%) create mode 100644 imxweb/projects/qer/src/lib/ops/about/ops-about.service.ts create mode 100644 imxweb/projects/qer/src/lib/ops/metadata/ops-metadata.service.ts rename imxweb/projects/{qer-app-operationssupport/src/app/sync/sync-journal/sync-summary.service.ts => qer/src/lib/ops/ops.service.ts} (66%) create mode 100644 imxweb/projects/qer/src/lib/ops/permissions/ops-permissions-helper.ts rename imxweb/projects/{qbm/src/lib/temp-billboard/temp-billboard.service.ts => qer/src/lib/ops/permissions/ops-permissions.service.ts} (63%) delete mode 100644 imxweb/projects/qer/src/lib/org-chart/variables.scss rename imxweb/projects/qer/src/lib/{profile => }/password-questions/confirm-password-matcher.ts (96%) rename imxweb/projects/qer/src/lib/{profile => }/password-questions/password-question.service.ts (83%) create mode 100644 imxweb/projects/qer/src/lib/password-questions/password-questions-sidesheet/password-questions-sidesheet.component.html create mode 100644 imxweb/projects/qer/src/lib/password-questions/password-questions-sidesheet/password-questions-sidesheet.component.scss rename imxweb/projects/qer/src/lib/{profile => }/password-questions/password-questions-sidesheet/password-questions-sidesheet.component.ts (66%) rename imxweb/projects/qer/src/lib/{profile => }/password-questions/password-questions-validator.ts (80%) create mode 100644 imxweb/projects/qer/src/lib/password-questions/password-questions.component.html create mode 100644 imxweb/projects/qer/src/lib/password-questions/password-questions.component.scss rename imxweb/projects/qer/src/lib/{profile => }/password-questions/password-questions.component.ts (75%) rename imxweb/projects/{o3t/src/lib/teams/teams.module.ts => qer/src/lib/password-questions/password-questions.module.ts} (50%) create mode 100644 imxweb/projects/qer/src/lib/password/about/pwd-about.service.ts create mode 100644 imxweb/projects/qer/src/lib/password/metadata/pwd-metadata.service.ts delete mode 100644 imxweb/projects/qer/src/lib/pattern-item-list/pattern-item-list.component.scss delete mode 100644 imxweb/projects/qer/src/lib/profile/password-questions/password-questions-sidesheet/password-questions-sidesheet.component.html delete mode 100644 imxweb/projects/qer/src/lib/profile/password-questions/password-questions-sidesheet/password-questions-sidesheet.component.scss delete mode 100644 imxweb/projects/qer/src/lib/profile/password-questions/password-questions.component.html delete mode 100644 imxweb/projects/qer/src/lib/profile/password-questions/password-questions.component.scss delete mode 100644 imxweb/projects/qer/src/lib/profile/security-keys/security-keys-sidesheet/security-keys-sidesheet.component.scss delete mode 100644 imxweb/projects/qer/src/lib/profile/security-keys/security-keys.component.scss create mode 100644 imxweb/projects/qer/src/lib/queue/queue-sidesheet/queue-sidesheet.component.html create mode 100644 imxweb/projects/qer/src/lib/queue/queue-sidesheet/queue-sidesheet.component.scss create mode 100644 imxweb/projects/qer/src/lib/queue/queue-sidesheet/queue-sidesheet.component.ts create mode 100644 imxweb/projects/qer/src/lib/queue/queue-status/queue-status.component.html create mode 100644 imxweb/projects/qer/src/lib/queue/queue-status/queue-status.component.scss create mode 100644 imxweb/projects/qer/src/lib/queue/queue-status/queue-status.component.ts create mode 100644 imxweb/projects/qer/src/lib/role-management/api-wrapper.ts delete mode 100644 imxweb/projects/qer/src/lib/service-item-tags/service-item-tags.component.scss create mode 100644 imxweb/projects/qer/src/lib/shopping-cart/cart-items-extension.service.ts create mode 100644 imxweb/projects/qer/src/lib/shopping-cart/cart-items.model.ts create mode 100644 imxweb/projects/qer/src/lib/shopping-cart/shopping-cart-button/shopping-cart-button.component.html create mode 100644 imxweb/projects/qer/src/lib/shopping-cart/shopping-cart-button/shopping-cart-button.component.scss create mode 100644 imxweb/projects/qer/src/lib/shopping-cart/shopping-cart-button/shopping-cart-button.component.ts create mode 100644 imxweb/projects/qer/src/lib/statistics/charts/chart-tile/table-stat-visual/table-stat-visual.component.html create mode 100644 imxweb/projects/qer/src/lib/statistics/charts/chart-tile/table-stat-visual/table-stat-visual.component.scss create mode 100644 imxweb/projects/qer/src/lib/statistics/charts/chart-tile/table-stat-visual/table-stat-visual.component.ts delete mode 100644 imxweb/projects/qer/src/lib/statistics/statistics-home-page/statistics-ordering-sidesheet/statistics-ordering-sidesheet-dialog/statistics-ordering-sidesheet-dialog.component.html delete mode 100644 imxweb/projects/qer/src/lib/statistics/statistics-home-page/statistics-ordering-sidesheet/statistics-ordering-sidesheet-dialog/statistics-ordering-sidesheet-dialog.component.scss create mode 100644 imxweb/projects/qer/src/lib/team-responsibilities/team-responsibility-assign-sidesheet/team-responsibility-assign-sidesheet.component.html create mode 100644 imxweb/projects/qer/src/lib/team-responsibilities/team-responsibility-assign-sidesheet/team-responsibility-assign-sidesheet.component.scss create mode 100644 imxweb/projects/qer/src/lib/team-responsibilities/team-responsibility-assign-sidesheet/team-responsibility-assign-sidesheet.component.ts create mode 100644 imxweb/projects/qer/src/lib/team-responsibilities/team-responsibility-dialog/team-responsibility-dialog.component.html create mode 100644 imxweb/projects/qer/src/lib/team-responsibilities/team-responsibility-dialog/team-responsibility-dialog.component.scss create mode 100644 imxweb/projects/qer/src/lib/team-responsibilities/team-responsibility-dialog/team-responsibility-dialog.component.ts create mode 100644 imxweb/projects/qer/src/lib/team-responsibilities/team-responsibility-sidesheet/team-responsibility-sidesheet.component.scss create mode 100644 imxweb/projects/qer/src/lib/team-responsibilities/team-responsibility-status-dialog/team-responsibility-status-dialog.component.html create mode 100644 imxweb/projects/qer/src/lib/team-responsibilities/team-responsibility-status-dialog/team-responsibility-status-dialog.component.scss create mode 100644 imxweb/projects/qer/src/lib/team-responsibilities/team-responsibility-status-dialog/team-responsibility-status-dialog.component.ts delete mode 100644 imxweb/projects/qer/src/lib/tiles/notification-tile/notification-tile.component.scss delete mode 100644 imxweb/projects/qer/tslint.json create mode 100644 imxweb/projects/rmb/.eslintrc.json create mode 100644 imxweb/projects/rmb/project.json delete mode 100644 imxweb/projects/rmb/src/lib/team-role/team-role.component.scss delete mode 100644 imxweb/projects/rmb/tslint.json create mode 100644 imxweb/projects/rms/.eslintrc.json create mode 100644 imxweb/projects/rms/project.json delete mode 100644 imxweb/projects/rms/tslint.json create mode 100644 imxweb/projects/rps/.eslintrc.json create mode 100644 imxweb/projects/rps/project.json delete mode 100644 imxweb/projects/rps/src/lib/report-button/parameter-sidesheet/parameter-sidesheet.component.scss create mode 100644 imxweb/projects/rps/src/lib/report-button/report-button-mail.component.html create mode 100644 imxweb/projects/rps/src/lib/report-button/report-button-mail.component.scss create mode 100644 imxweb/projects/rps/src/lib/report-button/report-button-mail.component.ts delete mode 100644 imxweb/projects/rps/tslint.json create mode 100644 imxweb/projects/sac/.eslintrc.json create mode 100644 imxweb/projects/sac/project.json delete mode 100644 imxweb/projects/sac/tslint.json create mode 100644 imxweb/projects/tsb/.eslintrc.json create mode 100644 imxweb/projects/tsb/project.json delete mode 100644 imxweb/projects/tsb/tslint.json create mode 100644 imxweb/projects/uci/.eslintrc.json create mode 100644 imxweb/projects/uci/ng-package.dynamic-ops.json create mode 100644 imxweb/projects/uci/project.json delete mode 100644 imxweb/projects/uci/tslint.json delete mode 100644 imxweb/shared/assets/variables.scss create mode 100644 imxweb/shared/scss/base/colors.scss create mode 100644 imxweb/shared/scss/base/fonts.scss create mode 100644 imxweb/shared/scss/base/margins-paddings.scss create mode 100644 imxweb/shared/scss/base/mixins.scss rename imxweb/shared/scss/{ => base}/theme.scss (67%) create mode 100644 imxweb/shared/scss/base/variables.scss delete mode 100644 imxweb/shared/scss/common-table.scss create mode 100644 imxweb/shared/scss/common/captcha-login.scss create mode 100644 imxweb/shared/scss/common/mitigating-controls.scss create mode 100644 imxweb/shared/scss/common/select.scss create mode 100644 imxweb/shared/scss/components/alert.scss create mode 100644 imxweb/shared/scss/components/autocomplete.scss create mode 100644 imxweb/shared/scss/components/badge.scss create mode 100644 imxweb/shared/scss/components/button-toggle.scss create mode 100644 imxweb/shared/scss/components/button.scss create mode 100644 imxweb/shared/scss/components/card.scss create mode 100644 imxweb/shared/scss/components/chart.scss create mode 100644 imxweb/shared/scss/components/checkbox.scss create mode 100644 imxweb/shared/scss/components/chips.scss create mode 100644 imxweb/shared/scss/components/clickable.scss create mode 100644 imxweb/shared/scss/components/data-source-toolbar.scss create mode 100644 imxweb/shared/scss/components/date-picker.scss create mode 100644 imxweb/shared/scss/components/dialog.scss create mode 100644 imxweb/shared/scss/components/divider.scss create mode 100644 imxweb/shared/scss/components/download.scss create mode 100644 imxweb/shared/scss/components/expansion-panel.scss create mode 100644 imxweb/shared/scss/components/form-field.scss create mode 100644 imxweb/shared/scss/components/icon.scss create mode 100644 imxweb/shared/scss/components/input.scss create mode 100644 imxweb/shared/scss/components/layout-grid.scss create mode 100644 imxweb/shared/scss/components/list.scss create mode 100644 imxweb/shared/scss/components/logo.scss create mode 100644 imxweb/shared/scss/components/masthead.scss create mode 100644 imxweb/shared/scss/components/menu.scss create mode 100644 imxweb/shared/scss/components/paginator.scss create mode 100644 imxweb/shared/scss/components/progress-bar.scss create mode 100644 imxweb/shared/scss/components/radio-button.scss create mode 100644 imxweb/shared/scss/components/ripple.scss create mode 100644 imxweb/shared/scss/components/scrollbar.scss create mode 100644 imxweb/shared/scss/components/search.scss create mode 100644 imxweb/shared/scss/components/select.scss create mode 100644 imxweb/shared/scss/components/side-navigation.scss create mode 100644 imxweb/shared/scss/components/sidesheet.scss create mode 100644 imxweb/shared/scss/components/slide-toggle.scss create mode 100644 imxweb/shared/scss/components/slider.scss create mode 100644 imxweb/shared/scss/components/snackbar.scss create mode 100644 imxweb/shared/scss/components/sort-header.scss create mode 100644 imxweb/shared/scss/components/spinner.scss create mode 100644 imxweb/shared/scss/components/stepper.scss create mode 100644 imxweb/shared/scss/components/table.scss create mode 100644 imxweb/shared/scss/components/tabs.scss create mode 100644 imxweb/shared/scss/components/theme-switcher.scss create mode 100644 imxweb/shared/scss/components/time-picker.scss create mode 100644 imxweb/shared/scss/components/toolbar.scss create mode 100644 imxweb/shared/scss/components/tooltip.scss create mode 100644 imxweb/shared/scss/components/top-navigation.scss create mode 100644 imxweb/shared/scss/components/tree.scss delete mode 100644 imxweb/shared/scss/side-navigation.scss rename imxweb/shared/{assets => scss}/styles.scss (63%) delete mode 100644 imxweb/tslint.json diff --git a/.commit b/.commit new file mode 100644 index 000000000..e56f9f7ad --- /dev/null +++ b/.commit @@ -0,0 +1 @@ +e4d4f7c0648e4c8f5418f2bdfa18b3e0f138b4d6 diff --git a/.github/workflows/npm-build.yml b/.github/workflows/npm-build.yml index bb14d7c9e..4ca9b807a 100644 --- a/.github/workflows/npm-build.yml +++ b/.github/workflows/npm-build.yml @@ -1,10 +1,10 @@ -name: Build Angular applications +name: Build Angular workspace on: push: branches: [ master ] pull_request: - branches: [ master, v82, v90, v92, v93 ] + branches: [ master, v93 ] jobs: build: @@ -12,8 +12,9 @@ jobs: strategy: matrix: - os: [windows-latest, ubuntu-latest] - node-version: [18.x] + # Currently only can run ubuntu on github agents, windows isn't correctly installing packages + os: [ubuntu-latest, windows-latest] + node-version: [20.x] steps: - uses: actions/checkout@v3 @@ -25,89 +26,14 @@ jobs: - name: Install packages working-directory: ./imxweb - run: npm install + run: npm install --skip-dialog - - name: Build qbm + - name: Build All working-directory: ./imxweb - run: npm run build qbm - - - name: Build qer - working-directory: ./imxweb - run: npm run build qer - - - name: Build tsb - working-directory: ./imxweb - run: npm run build tsb - - - name: Build att - working-directory: ./imxweb - run: npm run build att - - - name: Build rms - working-directory: ./imxweb - run: npm run build rms - - - name: Build aad - working-directory: ./imxweb - run: npm run build aad - - - name: Build aob - working-directory: ./imxweb - run: npm run build aob - - - name: Build uci - working-directory: ./imxweb - run: npm run build uci - - - name: Build cpl - working-directory: ./imxweb - run: npm run build cpl - - - name: Build dpr - working-directory: ./imxweb - run: npm run build dpr - - - name: Build rmb - working-directory: ./imxweb - run: npm run build rmb + run: npm run nx:build-all + timeout-minutes: 25 - - name: Build rps + - name: Test All working-directory: ./imxweb - run: npm run build rps - - - name: Build o3t - working-directory: ./imxweb - run: npm run build o3t - - - name: Build olg - working-directory: ./imxweb - run: npm run build olg - - - name: Build hds - working-directory: ./imxweb - run: npm run build hds - - - name: Build pol - working-directory: ./imxweb - run: npm run build pol - - - name: Build qer-app-portal - working-directory: ./imxweb - run: npm run build qer-app-portal - - - name: Build qbm-app-landingpage - working-directory: ./imxweb - run: npm run build qbm-app-landingpage - - - name: Build qer-app-operationssupport - working-directory: ./imxweb - run: npm run build qer-app-operationssupport - - - name: Build qer-app-pwdportal - working-directory: ./imxweb - run: npm run build qer-app-pwdportal - - - name: Build custom-app - working-directory: ./imxweb - run: npm run build custom-app - + run: npm run nx:test-ci + timeout-minutes: 25 \ No newline at end of file diff --git a/imxweb/.eslintignore b/imxweb/.eslintignore new file mode 100644 index 000000000..3c3629e64 --- /dev/null +++ b/imxweb/.eslintignore @@ -0,0 +1 @@ +node_modules diff --git a/imxweb/.eslintrc.json b/imxweb/.eslintrc.json new file mode 100644 index 000000000..9f0f9060d --- /dev/null +++ b/imxweb/.eslintrc.json @@ -0,0 +1,64 @@ +{ + "root": true, + "ignorePatterns": ["projects/**/*"], + "overrides": [ + { + "files": ["*.ts"], + "parserOptions": { + "project": ["tsconfig.json"], + "createDefaultProgram": true + }, + "extends": [ + "eslint:recommended", + "plugin:@typescript-eslint/recommended", + "plugin:@angular-eslint/recommended", + "plugin:prettier/recommended" + ], + "rules": { + "@angular-eslint/directive-selector": [ + "error", + { + "type": "attribute", + "prefix": "imx", + "style": "camelCase" + } + ], + "@angular-eslint/component-selector": [ + "error", + { + "type": "element", + "prefix": "imx", + "style": "kebab-case" + } + ], + "max-classes-per-file": ["error", { "ignoreExpressions": true, "max": 1 }], + "no-bitwise": ["error"], + "prettier/prettier": [ + "error", + { + "endOfLine": "auto" + } + ] + } + }, + { + "files": ["*.html"], + "extends": ["plugin:@angular-eslint/template/recommended", "plugin:prettier/recommended"], + "rules": { + "@angular-eslint/template/accessibility-valid-aria": ["error"] + } + }, + { + "files": ["*.ts", "*.tsx"], + "extends": ["plugin:@nx/typescript"], + "rules": {} + }, + { + "files": ["*.spec.ts"], + "env": { + "jest": true + }, + "rules": {} + } + ] +} diff --git a/imxweb/.gitignore b/imxweb/.gitignore index 81c0b3a54..4a322fb8e 100644 --- a/imxweb/.gitignore +++ b/imxweb/.gitignore @@ -27,7 +27,7 @@ speed-measure-plugin.json # IDE - VSCode .vscode/* -!.vscode/settings.json +.vscode/settings.json !.vscode/tasks.json !.vscode/launch.json !.vscode/extensions.json @@ -54,3 +54,5 @@ documentation !.gitkeep debug.log .angular +.nx +*.env diff --git a/imxweb/.npmrc b/imxweb/.npmrc index cafe685a1..a702b5875 100644 --- a/imxweb/.npmrc +++ b/imxweb/.npmrc @@ -1 +1,3 @@ -package-lock=true +@imx-modules:registry=https://pkgs.dev.azure.com/1id/_packaging/OneIdentity/npm/registry/ +@elemental-ui:registry=https://pkgs.dev.azure.com/1id/_packaging/OneIdentity/npm/registry/ +# always-auth=true diff --git a/imxweb/.prettierignore b/imxweb/.prettierignore new file mode 100644 index 000000000..103bd516d --- /dev/null +++ b/imxweb/.prettierignore @@ -0,0 +1,5 @@ +# Add files here to ignore them from prettier formatting +/dist +/coverage +/.nx/cache +.angular diff --git a/imxweb/.prettierrc.json b/imxweb/.prettierrc.json new file mode 100644 index 000000000..05fd50599 --- /dev/null +++ b/imxweb/.prettierrc.json @@ -0,0 +1,7 @@ +{ + "trailingComma": "all", + "tabWidth": 2, + "semi": true, + "printWidth": 140, + "singleQuote": true +} \ No newline at end of file diff --git a/imxweb/.vscode/launch.json b/imxweb/.vscode/launch.json index f47b5aa84..3ab226a61 100644 --- a/imxweb/.vscode/launch.json +++ b/imxweb/.vscode/launch.json @@ -25,21 +25,21 @@ "request": "launch", "type": "pwa-chrome", "url": "http://localhost:4200/", - "webRoot": "${workspaceFolder}", + "webRoot": "${workspaceFolder}" }, { "name": "QER App Portal (Chrome)", "request": "launch", "type": "pwa-chrome", "url": "http://localhost:4200/", - "webRoot": "${workspaceFolder}", + "webRoot": "${workspaceFolder}" }, { "name": "QER App Portal (Chrome - SSL)", "request": "launch", "type": "pwa-chrome", "url": "https://localhost:4200/", - "webRoot": "${workspaceFolder}", + "webRoot": "${workspaceFolder}" }, { "name": "QER App Portal (Chrome, API Server)", @@ -91,7 +91,6 @@ "webpack:///ng://qbm/lib/*": "${workspaceFolder}/projects/qbm/src/lib/*", "webpack:///ng://qer/lib/*": "${workspaceFolder}/projects/qer/src/lib/*" } - }, - + } ] } diff --git a/imxweb/.vscode/settings.json b/imxweb/.vscode/settings.json index 4aad9f8c8..7c221c22c 100644 --- a/imxweb/.vscode/settings.json +++ b/imxweb/.vscode/settings.json @@ -1,8 +1,24 @@ { - "explorer.compactFolders": false, - "editor.tabSize": 2, - "git.ignoreLimitWarning": true, - "cSpell.words": [ - "requestable" - ] -} \ No newline at end of file + "explorer.compactFolders": false, + "editor.tabSize": 2, + "git.ignoreLimitWarning": true, + "editor.wordWrapColumn": 140, + "editor.wordWrap": "wordWrapColumn", + "editor.defaultFormatter": "esbenp.prettier-vscode", + "editor.formatOnSave": true, + "editor.codeActionsOnSave": { + "source.organizeImports": "explicit" + }, + "typescript.updateImportsOnFileMove.enabled": "always", + "eslint.options": { + "extensions": [".ts", ".html"] + }, + "eslint.validate": ["javascript", "typescript", "html"], + "eslint.format.enable": true, + "[html]": { + "editor.defaultFormatter": "esbenp.prettier-vscode" + }, + "[typescript]": { + "editor.defaultFormatter": "esbenp.prettier-vscode" + } +} diff --git a/imxweb/angular.json b/imxweb/angular.json index dd712a936..c039f325a 100644 --- a/imxweb/angular.json +++ b/imxweb/angular.json @@ -40,11 +40,10 @@ "options": { "stylePreprocessorOptions": { "includePaths": [ - "./shared/assets", - "./shared/scss", "./node_modules", "./node_modules/@elemental-ui/cadence-icon", - "./node_modules/@elemental-ui/core" + "./node_modules/@elemental-ui/core", + "./shared/scss" ] }, "main": "projects/qbm/src/test.ts", @@ -53,10 +52,9 @@ } }, "lint": { - "builder": "@angular-devkit/build-angular:tslint", + "builder": "@angular-eslint/builder:lint", "options": { - "tsConfig": ["projects/qbm/tsconfig.lib.json", "projects/qbm/tsconfig.spec.json"], - "exclude": ["**/node_modules/**", "**/*.spec.ts", "**/*.json"] + "lintFilePatterns": ["projects/qbm/**/*.ts", "projects/qbm/**/*.html"] } } } @@ -98,11 +96,10 @@ "options": { "stylePreprocessorOptions": { "includePaths": [ - "./shared/assets", - "./shared/scss", "./node_modules", "./node_modules/@elemental-ui/cadence-icon", - "./node_modules/@elemental-ui/core" + "./node_modules/@elemental-ui/core", + "./shared/scss" ] }, "main": "projects/qer/src/test.ts", @@ -111,10 +108,9 @@ } }, "lint": { - "builder": "@angular-devkit/build-angular:tslint", + "builder": "@angular-eslint/builder:lint", "options": { - "tsConfig": ["projects/qer/tsconfig.lib.json", "projects/qer/tsconfig.spec.json"], - "exclude": ["**/node_modules/**", "**/*.spec.ts", "**/*.json"] + "lintFilePatterns": ["projects/qer/**/*.ts", "projects/qer/**/*.html"] } } } @@ -156,20 +152,18 @@ "karmaConfig": "projects/apc/karma.conf.js", "stylePreprocessorOptions": { "includePaths": [ - "./shared/assets", - "./shared/scss", "./node_modules", "./node_modules/@elemental-ui/cadence-icon", - "./node_modules/@elemental-ui/core" + "./node_modules/@elemental-ui/core", + "./shared/scss" ] } } }, "lint": { - "builder": "@angular-devkit/build-angular:tslint", + "builder": "@angular-eslint/builder:lint", "options": { - "tsConfig": ["projects/apc/tsconfig.lib.json", "projects/apc/tsconfig.spec.json"], - "exclude": ["**/node_modules/**", "**/*.spec.ts", "**/*.json"] + "lintFilePatterns": ["projects/apc/**/*.ts", "projects/apc/**/*.html"] } } } @@ -201,6 +195,9 @@ "dynamic": { "project": "projects/att/ng-package.dynamic.json" }, + "dynamic-pwd": { + "project": "projects/att/ng-package.dynamic-pwd.json" + }, "remote-dev": { "tsConfig": "projects/att/tsconfig.lib.json" }, @@ -217,20 +214,18 @@ "karmaConfig": "projects/att/karma.conf.js", "stylePreprocessorOptions": { "includePaths": [ - "./shared/assets", - "./shared/scss", "./node_modules", "./node_modules/@elemental-ui/cadence-icon", - "./node_modules/@elemental-ui/core" + "./node_modules/@elemental-ui/core", + "./shared/scss" ] } } }, "lint": { - "builder": "@angular-devkit/build-angular:tslint", + "builder": "@angular-eslint/builder:lint", "options": { - "tsConfig": ["projects/att/tsconfig.lib.json", "projects/att/tsconfig.spec.json"], - "exclude": ["**/node_modules/**", "**/*.spec.ts", "**/*.json"] + "lintFilePatterns": ["projects/att/**/*.ts", "projects/att/**/*.html"] } } } @@ -279,20 +274,18 @@ "codeCoverageExclude": ["projects/o3t/src/**/test/*"], "stylePreprocessorOptions": { "includePaths": [ - "./shared/assets", - "./shared/scss", "./node_modules", "./node_modules/@elemental-ui/cadence-icon", - "./node_modules/@elemental-ui/core" + "./node_modules/@elemental-ui/core", + "./shared/scss" ] } } }, "lint": { - "builder": "@angular-devkit/build-angular:tslint", + "builder": "@angular-eslint/builder:lint", "options": { - "tsConfig": ["projects/aad/tsconfig.lib.json", "projects/aad/tsconfig.spec.json"], - "exclude": ["**/node_modules/**", "**/*.spec.ts", "**/*.json"] + "lintFilePatterns": ["projects/aad/**/*.ts", "projects/aad/**/*.html"] } } } @@ -340,20 +333,18 @@ "karmaConfig": "projects/cpl/karma.conf.js", "stylePreprocessorOptions": { "includePaths": [ - "./shared/assets", - "./shared/scss", "./node_modules", "./node_modules/@elemental-ui/cadence-icon", - "./node_modules/@elemental-ui/core" + "./node_modules/@elemental-ui/core", + "./shared/scss" ] } } }, "lint": { - "builder": "@angular-devkit/build-angular:tslint", + "builder": "@angular-eslint/builder:lint", "options": { - "tsConfig": ["projects/cpl/tsconfig.lib.json", "projects/cpl/tsconfig.spec.json"], - "exclude": ["**/node_modules/**", "**/*.spec.ts", "**/*.json"] + "lintFilePatterns": ["projects/cpl/**/*.ts", "projects/cpl/**/*.html"] } } } @@ -401,20 +392,18 @@ "karmaConfig": "projects/dpr/karma.conf.js", "stylePreprocessorOptions": { "includePaths": [ - "./shared/assets", - "./shared/scss", "./node_modules", "./node_modules/@elemental-ui/cadence-icon", - "./node_modules/@elemental-ui/core" + "./node_modules/@elemental-ui/core", + "./shared/scss" ] } } }, "lint": { - "builder": "@angular-devkit/build-angular:tslint", + "builder": "@angular-eslint/builder:lint", "options": { - "tsConfig": ["projects/dpr/tsconfig.lib.json", "projects/dpr/tsconfig.spec.json"], - "exclude": ["**/node_modules/**", "**/*.spec.ts", "**/*.json"] + "lintFilePatterns": ["projects/dpr/**/*.ts", "projects/dpr/**/*.html"] } } } @@ -463,82 +452,18 @@ "codeCoverageExclude": ["projects/hds/src/**/test/*"], "stylePreprocessorOptions": { "includePaths": [ - "./shared/assets", - "./shared/scss", - "./node_modules", - "./node_modules/@elemental-ui/cadence-icon", - "./node_modules/@elemental-ui/core" - ] - } - } - }, - "lint": { - "builder": "@angular-devkit/build-angular:tslint", - "options": { - "tsConfig": ["projects/hds/tsconfig.lib.json", "projects/hds/tsconfig.spec.json"], - "exclude": ["**/node_modules/**", "**/*.spec.ts", "**/*.json"] - } - } - } - }, - "o3t": { - "root": "projects/o3t", - "sourceRoot": "projects/o3t/src", - "projectType": "library", - "schematics": { - "@schematics/angular:component": { - "style": "scss" - } - }, - "prefix": "imx", - "architect": { - "build": { - "builder": "@angular-devkit/build-angular:ng-packagr", - "options": { - "tsConfig": "projects/o3t/tsconfig.lib.json", - "project": "projects/o3t/ng-package.json" - }, - "configurations": { - "production": { - "tsConfig": "projects/o3t/tsconfig.lib.prod.json" - }, - "development": { - "tsConfig": "projects/o3t/tsconfig.lib.json" - }, - "dynamic": { - "project": "projects/o3t/ng-package.dynamic.json" - }, - "remote-dev": { - "tsConfig": "projects/o3t/tsconfig.lib.json" - }, - "remote-qs": { - "tsConfig": "projects/o3t/tsconfig.lib.json" - } - } - }, - "test": { - "builder": "@angular-devkit/build-angular:karma", - "options": { - "main": "projects/o3t/src/test.ts", - "tsConfig": "projects/o3t/tsconfig.spec.json", - "karmaConfig": "projects/o3t/karma.conf.js", - "codeCoverageExclude": ["projects/o3t/src/**/test/*"], - "stylePreprocessorOptions": { - "includePaths": [ - "./shared/assets", - "./shared/scss", "./node_modules", "./node_modules/@elemental-ui/cadence-icon", - "./node_modules/@elemental-ui/core" + "./node_modules/@elemental-ui/core", + "./shared/scss" ] } } }, "lint": { - "builder": "@angular-devkit/build-angular:tslint", + "builder": "@angular-eslint/builder:lint", "options": { - "tsConfig": ["projects/o3t/tsconfig.lib.json", "projects/o3t/tsconfig.spec.json"], - "exclude": ["**/node_modules/**", "**/*.spec.ts", "**/*.json"] + "lintFilePatterns": ["projects/hds/**/*.ts", "projects/hds/**/*.html"] } } } @@ -587,20 +512,18 @@ "codeCoverageExclude": ["projects/olg/src/**/test/*"], "stylePreprocessorOptions": { "includePaths": [ - "./shared/assets", - "./shared/scss", "./node_modules", "./node_modules/@elemental-ui/cadence-icon", - "./node_modules/@elemental-ui/core" + "./node_modules/@elemental-ui/core", + "./shared/scss" ] } } }, "lint": { - "builder": "@angular-devkit/build-angular:tslint", + "builder": "@angular-eslint/builder:lint", "options": { - "tsConfig": ["projects/olg/tsconfig.lib.json", "projects/olg/tsconfig.spec.json"], - "exclude": ["**/node_modules/**", "**/*.spec.ts", "**/*.json"] + "lintFilePatterns": ["projects/olg/**/*.ts", "projects/olg/**/*.html"] } } } @@ -648,20 +571,18 @@ "karmaConfig": "projects/pol/karma.conf.js", "stylePreprocessorOptions": { "includePaths": [ - "./shared/assets", - "./shared/scss", "./node_modules", "./node_modules/@elemental-ui/cadence-icon", - "./node_modules/@elemental-ui/core" + "./node_modules/@elemental-ui/core", + "./shared/scss" ] } } }, "lint": { - "builder": "@angular-devkit/build-angular:tslint", + "builder": "@angular-eslint/builder:lint", "options": { - "tsConfig": ["projects/pol/tsconfig.lib.json", "projects/pol/tsconfig.spec.json"], - "exclude": ["**/node_modules/**", "**/*.spec.ts", "**/*.json"] + "lintFilePatterns": ["projects/pol/**/*.ts", "projects/pol/**/*.html"] } } } @@ -709,20 +630,18 @@ "karmaConfig": "projects/rmb/karma.conf.js", "stylePreprocessorOptions": { "includePaths": [ - "./shared/assets", - "./shared/scss", "./node_modules", "./node_modules/@elemental-ui/cadence-icon", - "./node_modules/@elemental-ui/core" + "./node_modules/@elemental-ui/core", + "./shared/scss" ] } } }, "lint": { - "builder": "@angular-devkit/build-angular:tslint", + "builder": "@angular-eslint/builder:lint", "options": { - "tsConfig": ["projects/rmb/tsconfig.lib.json", "projects/rmb/tsconfig.spec.json"], - "exclude": ["**/node_modules/**", "**/*.spec.ts", "**/*.json"] + "lintFilePatterns": ["projects/rmb/**/*.ts", "projects/rmb/**/*.html"] } } } @@ -770,20 +689,18 @@ "karmaConfig": "projects/rms/karma.conf.js", "stylePreprocessorOptions": { "includePaths": [ - "./shared/assets", - "./shared/scss", "./node_modules", "./node_modules/@elemental-ui/cadence-icon", - "./node_modules/@elemental-ui/core" + "./node_modules/@elemental-ui/core", + "./shared/scss" ] } } }, "lint": { - "builder": "@angular-devkit/build-angular:tslint", + "builder": "@angular-eslint/builder:lint", "options": { - "tsConfig": ["projects/rms/tsconfig.lib.json", "projects/rms/tsconfig.spec.json"], - "exclude": ["**/node_modules/**", "**/*.spec.ts", "**/*.json"] + "lintFilePatterns": ["projects/rms/**/*.ts", "projects/rms/**/*.html"] } } } @@ -831,20 +748,18 @@ "karmaConfig": "projects/rps/karma.conf.js", "stylePreprocessorOptions": { "includePaths": [ - "./shared/assets", - "./shared/scss", "./node_modules", "./node_modules/@elemental-ui/cadence-icon", - "./node_modules/@elemental-ui/core" + "./node_modules/@elemental-ui/core", + "./shared/scss" ] } } }, "lint": { - "builder": "@angular-devkit/build-angular:tslint", + "builder": "@angular-eslint/builder:lint", "options": { - "tsConfig": ["projects/rps/tsconfig.lib.json", "projects/rps/tsconfig.spec.json"], - "exclude": ["**/node_modules/**", "**/*.spec.ts", "**/*.json"] + "lintFilePatterns": ["projects/rps/**/*.ts", "projects/rps/**/*.html"] } } } @@ -870,6 +785,9 @@ "production": { "tsConfig": "projects/sac/tsconfig.lib.prod.json" }, + "development": { + "tsConfig": "projects/sac/tsconfig.lib.json" + }, "dynamic": { "project": "projects/sac/ng-package.dynamic.json" } @@ -882,18 +800,14 @@ "tsConfig": "projects/sac/tsconfig.spec.json", "karmaConfig": "projects/sac/karma.conf.js", "stylePreprocessorOptions": { - "includePaths": [ - "./shared/assets", - "./shared/scss" - ] + "includePaths": ["./shared/assets", "./shared/scss"] } } }, "lint": { - "builder": "@angular-devkit/build-angular:tslint", + "builder": "@angular-eslint/builder:lint", "options": { - "tsConfig": ["projects/sac/tsconfig.lib.json", "projects/sac/tsconfig.spec.json"], - "exclude": ["**/node_modules/**", "**/*.spec.ts", "**/*.json"] + "lintFilePatterns": ["projects/sac/**/*.ts", "projects/sac/**/*.html"] } } } @@ -941,20 +855,18 @@ "karmaConfig": "projects/tsb/karma.conf.js", "stylePreprocessorOptions": { "includePaths": [ - "./shared/assets", - "./shared/scss", "./node_modules", "./node_modules/@elemental-ui/cadence-icon", - "./node_modules/@elemental-ui/core" + "./node_modules/@elemental-ui/core", + "./shared/scss" ] } } }, "lint": { - "builder": "@angular-devkit/build-angular:tslint", + "builder": "@angular-eslint/builder:lint", "options": { - "tsConfig": ["projects/tsb/tsconfig.lib.json", "projects/tsb/tsconfig.spec.json"], - "exclude": ["**/node_modules/**", "**/*.spec.ts", "**/*.json"] + "lintFilePatterns": ["projects/tsb/**/*.ts", "projects/tsb/**/*.html"] } } } @@ -978,8 +890,8 @@ "development": { "tsConfig": "projects/uci/tsconfig.lib.json" }, - "dynamic": { - "project": "projects/uci/ng-package.dynamic.json" + "dynamic-ops": { + "project": "projects/uci/ng-package.dynamic-ops.json" }, "remote-dev": { "tsConfig": "projects/uci/tsconfig.lib.json" @@ -997,26 +909,24 @@ "karmaConfig": "projects/uci/karma.conf.js", "stylePreprocessorOptions": { "includePaths": [ - "./shared/assets", - "./shared/scss", "./node_modules", "./node_modules/@elemental-ui/cadence-icon", - "./node_modules/@elemental-ui/core" + "./node_modules/@elemental-ui/core", + "./shared/scss" ] } } }, "lint": { - "builder": "@angular-devkit/build-angular:tslint", + "builder": "@angular-eslint/builder:lint", "options": { - "tsConfig": ["projects/uci/tsconfig.lib.json", "projects/uci/tsconfig.spec.json"], - "exclude": ["**/node_modules/**", "**/*.spec.ts", "**/*.json"] + "lintFilePatterns": ["projects/uci/**/*.ts", "projects/uci/**/*.html"] } } } }, "qbm-app-landingpage": { - "root": "projects/qbm-app-landingpage/", + "root": "projects/qbm-app-landingpage", "sourceRoot": "projects/qbm-app-landingpage/src", "projectType": "application", "prefix": "imx", @@ -1027,13 +937,36 @@ }, "architect": { "build": { - "builder": "@angular-devkit/build-angular:browser", + "builder": "@angular-devkit/build-angular:application", "options": { "aot": true, - "outputPath": "dist/qbm-app-landingpage", + "outputPath": { + "base": "dist/qbm-app-landingpage", + "browser": "" + }, + "allowedCommonJsDependencies": [ + "lodash", + "highlight.js", + "file-saver", + "billboard.js", + "moment-timezone", + "core-js/fn/map", + "core-js/fn/set", + "core-js/fn/weak-map", + "core-js/fn/array/from", + "core-js/fn/object/assign", + "core-js/es/array/from", + "core-js/es/object/assign", + "core-js/es/map", + "core-js/es/set", + "core-js/es/weak-map", + "lodash.debounce", + "lodash.clamp", + "moment", + "@elemental-ui/cadence-icon/codepoints" + ], "index": "projects/qbm-app-landingpage/src/index.html", - "main": "projects/qbm-app-landingpage/src/main.ts", - "polyfills": "projects/qbm-app-landingpage/src/polyfills.ts", + "polyfills": ["projects/qbm-app-landingpage/src/polyfills.ts"], "tsConfig": "projects/qbm-app-landingpage/tsconfig.app.json", "assets": [ "projects/qbm-app-landingpage/src/assets", @@ -1050,25 +983,23 @@ } ], "styles": [ + "shared/scss/styles.scss", "projects/qbm-app-landingpage/src/styles.scss", - "shared/assets/styles.scss", - "shared/assets/variables.scss", "node_modules/swagger-ui-dist/swagger-ui.css" ], "stylePreprocessorOptions": { "includePaths": [ - "./shared/assets", - "./shared/scss", "./node_modules", "./node_modules/@elemental-ui/cadence-icon", - "./node_modules/@elemental-ui/core" + "./node_modules/@elemental-ui/core", + "./shared/scss" ] }, "scripts": [ - "node_modules/systemjs/dist/system.src.js", "node_modules/swagger-ui-dist/swagger-ui-bundle.js", "node_modules/swagger-ui-dist/swagger-ui-standalone-preset.js" - ] + ], + "browser": "projects/qbm-app-landingpage/src/main.ts" }, "configurations": { "production": { @@ -1081,11 +1012,9 @@ "optimization": true, "outputHashing": "all", "sourceMap": false, - "namedChunks": false, + "namedChunks": true, "aot": true, "extractLicenses": true, - "vendorChunk": false, - "buildOptimizer": true, "budgets": [ { "type": "initial", @@ -1099,9 +1028,7 @@ ] }, "development": { - "buildOptimizer": false, "optimization": false, - "vendorChunk": true, "extractLicenses": false, "sourceMap": true, "namedChunks": true @@ -1113,9 +1040,7 @@ "with": "../imxweb_envs/qbm-app-landingpage/environments/environment.remote-dev.ts" } ], - "buildOptimizer": false, "optimization": false, - "vendorChunk": true, "extractLicenses": false, "sourceMap": true, "namedChunks": true @@ -1127,9 +1052,7 @@ "with": "../imxweb_envs/qbm-app-landingpage/environments/environment.remote-qs.ts" } ], - "buildOptimizer": false, "optimization": false, - "vendorChunk": true, "extractLicenses": false, "sourceMap": true, "namedChunks": true @@ -1142,31 +1065,31 @@ "serve": { "builder": "@angular-devkit/build-angular:dev-server", "options": { - "browserTarget": "qbm-app-landingpage:build", - "disableHostCheck": true + "disableHostCheck": true, + "buildTarget": "qbm-app-landingpage:build" }, "configurations": { "production": { - "browserTarget": "qbm-app-landingpage:build:production" + "buildTarget": "qbm-app-landingpage:build:production" }, "development": { - "browserTarget": "qbm-app-landingpage:build:development" + "buildTarget": "qbm-app-landingpage:build:development" }, "remote-dev": { - "browserTarget": "qbm-app-landingpage:build:remote-dev" + "buildTarget": "qbm-app-landingpage:build:remote-dev" }, "remote-qs": { - "browserTarget": "qbm-app-landingpage:build:remote-qs" + "buildTarget": "qbm-app-landingpage:build:remote-qs" }, "es5": { - "browserTarget": "qbm-app-landingpage:build:es5" + "buildTarget": "qbm-app-landingpage:build:es5" } } }, "extract-i18n": { "builder": "@angular-devkit/build-angular:extract-i18n", "options": { - "browserTarget": "qbm-app-landingpage:build" + "buildTarget": "qbm-app-landingpage:build" } }, "test": { @@ -1186,29 +1109,27 @@ "output": "./assets" } ], - "styles": ["projects/qbm-app-landingpage/src/styles.scss", "shared/assets/styles.scss"], + "styles": ["projects/qbm-app-landingpage/src/styles.scss"], "stylePreprocessorOptions": { "includePaths": [ - "./shared/assets", - "./shared/scss", "./node_modules", "./node_modules/@elemental-ui/cadence-icon", - "./node_modules/@elemental-ui/core" + "./node_modules/@elemental-ui/core", + "./shared/scss" ] } } }, "lint": { - "builder": "@angular-devkit/build-angular:tslint", + "builder": "@angular-eslint/builder:lint", "options": { - "tsConfig": ["projects/qbm-app-landingpage/tsconfig.app.json", "projects/qbm-app-landingpage/tsconfig.spec.json"], - "exclude": ["**/node_modules/**", "**/*.spec.ts", "**/*.json"] + "lintFilePatterns": ["projects/qbm-app-landingpage//**/*.ts", "projects/qbm-app-landingpage//**/*.html"] } } } }, "qer-app-operationssupport": { - "root": "projects/qer-app-operationssupport/", + "root": "projects/qer-app-operationssupport", "sourceRoot": "projects/qer-app-operationssupport/src", "projectType": "application", "prefix": "imx", @@ -1222,10 +1143,30 @@ "builder": "@angular-devkit/build-angular:browser", "options": { "aot": true, + "allowedCommonJsDependencies": [ + "lodash", + "highlight.js", + "file-saver", + "billboard.js", + "moment-timezone", + "core-js/fn/map", + "core-js/fn/set", + "core-js/fn/weak-map", + "core-js/fn/array/from", + "core-js/fn/object/assign", + "core-js/es/array/from", + "core-js/es/object/assign", + "core-js/es/map", + "core-js/es/set", + "core-js/es/weak-map", + "lodash.debounce", + "lodash.clamp", + "moment", + "@elemental-ui/cadence-icon/codepoints" + ], "outputPath": "dist/qer-app-operationssupport", "index": "projects/qer-app-operationssupport/src/index.html", - "main": "projects/qer-app-operationssupport/src/main.ts", - "polyfills": "projects/qer-app-operationssupport/src/polyfills.ts", + "polyfills": ["projects/qer-app-operationssupport/src/polyfills.ts"], "tsConfig": "projects/qer-app-operationssupport/tsconfig.app.json", "assets": [ "projects/qer-app-operationssupport/src/assets", @@ -1244,33 +1185,22 @@ "glob": "**/*", "input": "./node_modules/@elemental-ui/core/assets", "output": "./assets" - }, - { - "glob": "**/*", - "input": "./node_modules/systemjs-plugin-babel/", - "output": "./systemjs-plugin-babel" } ], "styles": [ "projects/qer-app-operationssupport/src/styles.scss", - "shared/assets/styles.scss", - "projects/qbm/src/lib/styles/imx-page-title.scss", - "shared/assets/variables.scss" + "shared/scss/styles.scss", + "projects/qbm/src/lib/styles/imx-page-title.scss" ], "stylePreprocessorOptions": { "includePaths": [ - "./shared/assets", - "./shared/scss", "./node_modules", "./node_modules/@elemental-ui/cadence-icon", - "./node_modules/@elemental-ui/core" + "./node_modules/@elemental-ui/core", + "./shared/scss" ] }, - "scripts": [ - "node_modules/systemjs/dist/system.src.js", - "node_modules/systemjs-plugin-babel/plugin-babel.js", - "node_modules/systemjs-plugin-babel/systemjs-babel-browser.js" - ] + "main": "projects/qer-app-operationssupport/src/main.ts" }, "configurations": { "production": { @@ -1283,11 +1213,9 @@ "optimization": true, "outputHashing": "all", "sourceMap": false, - "namedChunks": false, + "namedChunks": true, "aot": true, "extractLicenses": true, - "vendorChunk": false, - "buildOptimizer": true, "budgets": [ { "type": "initial", @@ -1301,9 +1229,7 @@ ] }, "development": { - "buildOptimizer": false, "optimization": false, - "vendorChunk": true, "extractLicenses": false, "sourceMap": true, "namedChunks": true @@ -1315,9 +1241,7 @@ "with": "../imxweb_envs/qer-app-operationssupport/environments/environment.remote-dev.ts" } ], - "buildOptimizer": false, "optimization": false, - "vendorChunk": true, "extractLicenses": false, "sourceMap": true, "namedChunks": true @@ -1329,9 +1253,7 @@ "with": "../imxweb_envs/qer-app-operationssupport/environments/environment.remote-qs.ts" } ], - "buildOptimizer": false, "optimization": false, - "vendorChunk": true, "extractLicenses": false, "sourceMap": true, "namedChunks": true @@ -1344,31 +1266,31 @@ "serve": { "builder": "@angular-devkit/build-angular:dev-server", "options": { - "browserTarget": "qer-app-operationssupport:build", - "disableHostCheck": true + "disableHostCheck": true, + "buildTarget": "qer-app-operationssupport:build" }, "configurations": { "production": { - "browserTarget": "qer-app-operationssupport:build:production" + "buildTarget": "qer-app-operationssupport:build:production" }, "development": { - "browserTarget": "qer-app-operationssupport:build:development" + "buildTarget": "qer-app-operationssupport:build:development" }, "remote-dev": { - "browserTarget": "qer-app-operationssupport:build:remote-dev" + "buildTarget": "qer-app-operationssupport:build:remote-dev" }, "remote-qs": { - "browserTarget": "qer-app-operationssupport:build:remote-dev" + "buildTarget": "qer-app-operationssupport:build:remote-dev" }, "es5": { - "browserTarget": "qer-app-operationssupport:build:es5" + "buildTarget": "qer-app-operationssupport:build:es5" } } }, "extract-i18n": { "builder": "@angular-devkit/build-angular:extract-i18n", "options": { - "browserTarget": "qer-app-operationssupport:build" + "buildTarget": "qer-app-operationssupport:build" } }, "test": { @@ -1378,17 +1300,15 @@ "polyfills": "projects/qer-app-operationssupport/src/polyfills.ts", "tsConfig": "projects/qer-app-operationssupport/tsconfig.spec.json", "karmaConfig": "projects/qer-app-operationssupport/karma.conf.js", - "styles": ["projects/qer-app-operationssupport/src/styles.scss", "shared/assets/styles.scss"], + "styles": ["projects/qer-app-operationssupport/src/styles.scss"], "stylePreprocessorOptions": { "includePaths": [ - "./shared/assets", - "./shared/scss", "./node_modules", "./node_modules/@elemental-ui/cadence-icon", - "./node_modules/@elemental-ui/core" + "./node_modules/@elemental-ui/core", + "./shared/scss" ] }, - "scripts": ["node_modules/systemjs/dist/system.src.js"], "assets": [ "projects/qer-app-operationssupport/src/assets", "projects/qer-app-operationssupport/src/appconfig.json", @@ -1401,16 +1321,15 @@ } }, "lint": { - "builder": "@angular-devkit/build-angular:tslint", + "builder": "@angular-eslint/builder:lint", "options": { - "tsConfig": ["projects/qer-app-operationssupport/tsconfig.app.json", "projects/qer-app-operationssupport/tsconfig.spec.json"], - "exclude": ["**/node_modules/**", "**/*.spec.ts", "**/*.json"] + "lintFilePatterns": ["projects/qer-app-operationssupport//**/*.ts", "projects/qer-app-operationssupport//**/*.html"] } } } }, "qer-app-portal": { - "root": "projects/qer-app-portal/", + "root": "projects/qer-app-portal", "sourceRoot": "projects/qer-app-portal/src", "projectType": "application", "prefix": "imx", @@ -1424,10 +1343,30 @@ "builder": "@angular-devkit/build-angular:browser", "options": { "aot": true, + "allowedCommonJsDependencies": [ + "lodash", + "highlight.js", + "file-saver", + "billboard.js", + "moment-timezone", + "core-js/fn/map", + "core-js/fn/set", + "core-js/fn/weak-map", + "core-js/fn/array/from", + "core-js/fn/object/assign", + "core-js/es/array/from", + "core-js/es/object/assign", + "core-js/es/map", + "core-js/es/set", + "core-js/es/weak-map", + "lodash.debounce", + "lodash.clamp", + "moment", + "@elemental-ui/cadence-icon/codepoints" + ], "outputPath": "dist/qer-app-portal", "index": "projects/qer-app-portal/src/index.html", - "main": "projects/qer-app-portal/src/main.ts", - "polyfills": "projects/qer-app-portal/src/polyfills.ts", + "polyfills": ["projects/qer-app-portal/src/polyfills.ts"], "tsConfig": "projects/qer-app-portal/tsconfig.app.json", "assets": [ "projects/qer-app-portal/src/assets", @@ -1446,35 +1385,24 @@ "glob": "**/*", "input": "./node_modules/@elemental-ui/core/assets", "output": "./assets" - }, - { - "glob": "**/*", - "input": "./node_modules/systemjs-plugin-babel/", - "output": "./systemjs-plugin-babel" } ], "styles": [ + "shared/scss/styles.scss", "projects/qer-app-portal/src/styles.scss", "projects/qbm/src/lib/styles/imx-page-title.scss", "projects/qbm/src/lib/styles/data-explorer-common.scss", - "projects/qbm/src/lib/styles/data-explorer-details-common.scss", - "shared/assets/styles.scss", - "shared/assets/variables.scss" + "projects/qbm/src/lib/styles/data-explorer-details-common.scss" ], "stylePreprocessorOptions": { "includePaths": [ - "./shared/assets", - "./shared/scss", "./node_modules", "./node_modules/@elemental-ui/cadence-icon", - "./node_modules/@elemental-ui/core" + "./node_modules/@elemental-ui/core", + "./shared/scss" ] }, - "scripts": [ - "node_modules/systemjs/dist/system.src.js", - "node_modules/systemjs-plugin-babel/plugin-babel.js", - "node_modules/systemjs-plugin-babel/systemjs-babel-browser.js" - ] + "main": "projects/qer-app-portal/src/main.ts" }, "configurations": { "production": { @@ -1487,11 +1415,9 @@ "optimization": true, "outputHashing": "all", "sourceMap": false, - "namedChunks": false, + "namedChunks": true, "aot": true, "extractLicenses": true, - "vendorChunk": false, - "buildOptimizer": true, "budgets": [ { "type": "initial", @@ -1505,9 +1431,7 @@ ] }, "development": { - "buildOptimizer": false, "optimization": false, - "vendorChunk": true, "extractLicenses": false, "sourceMap": true, "namedChunks": true @@ -1519,9 +1443,7 @@ "with": "../imxweb_envs/qer-app-portal/environments/environment.remote-dev.ts" } ], - "buildOptimizer": false, "optimization": false, - "vendorChunk": true, "extractLicenses": false, "sourceMap": true, "namedChunks": true @@ -1533,9 +1455,7 @@ "with": "../imxweb_envs/qer-app-portal/environments/environment.remote-qs.ts" } ], - "buildOptimizer": false, "optimization": false, - "vendorChunk": true, "extractLicenses": false, "sourceMap": true, "namedChunks": true @@ -1548,30 +1468,30 @@ "serve": { "builder": "@angular-devkit/build-angular:dev-server", "options": { - "browserTarget": "qer-app-portal:build" + "buildTarget": "qer-app-portal:build" }, "configurations": { "production": { - "browserTarget": "qer-app-portal:build:production" + "buildTarget": "qer-app-portal:build:production" }, "development": { - "browserTarget": "qer-app-portal:build:development" + "buildTarget": "qer-app-portal:build:development" }, "remote-dev": { - "browserTarget": "qer-app-portal:build:remote-dev" + "buildTarget": "qer-app-portal:build:remote-dev" }, "remote-qs": { - "browserTarget": "qer-app-portal:build:remote-qs" + "buildTarget": "qer-app-portal:build:remote-qs" }, "es5": { - "browserTarget": "qer-app-portal:build:es5" + "buildTarget": "qer-app-portal:build:es5" } } }, "extract-i18n": { "builder": "@angular-devkit/build-angular:extract-i18n", "options": { - "browserTarget": "qer-app-portal:build" + "buildTarget": "qer-app-portal:build" } }, "test": { @@ -1584,22 +1504,19 @@ "styles": ["projects/qer-app-portal/src/styles.scss"], "stylePreprocessorOptions": { "includePaths": [ - "./shared/assets", - "./shared/scss", "./node_modules", "./node_modules/@elemental-ui/cadence-icon", - "./node_modules/@elemental-ui/core" + "./node_modules/@elemental-ui/core", + "./shared/scss" ] }, - "scripts": ["node_modules/systemjs/dist/system.src.js"], "assets": ["projects/qer-app-portal/src/appconfig.json", "projects/qer-app-portal/src/assets"] } }, "lint": { - "builder": "@angular-devkit/build-angular:tslint", + "builder": "@angular-eslint/builder:lint", "options": { - "tsConfig": ["projects/qer-app-portal/tsconfig.app.json", "projects/qer-app-portal/tsconfig.spec.json"], - "exclude": ["**/node_modules/**", "**/*.spec.ts", "**/*.json"] + "lintFilePatterns": ["projects/qer-app-portal//**/*.ts", "projects/qer-app-portal//**/*.html"] } } } @@ -1633,8 +1550,7 @@ }, "remote-dev": { "tsConfig": "projects/aob/tsconfig.lib.json" - } - , + }, "remote-qs": { "tsConfig": "projects/aob/tsconfig.lib.json" } @@ -1648,20 +1564,18 @@ "karmaConfig": "projects/aob/karma.conf.js", "stylePreprocessorOptions": { "includePaths": [ - "./shared/assets", - "./shared/scss", "./node_modules", "./node_modules/@elemental-ui/cadence-icon", - "./node_modules/@elemental-ui/core" + "./node_modules/@elemental-ui/core", + "./shared/scss" ] } } }, "lint": { - "builder": "@angular-devkit/build-angular:tslint", + "builder": "@angular-eslint/builder:lint", "options": { - "tsConfig": ["projects/aob/tsconfig.lib.json", "projects/aob/tsconfig.spec.json"], - "exclude": ["**/node_modules/**", "**/*.spec.ts", "**/*.json"] + "lintFilePatterns": ["projects/aob/**/*.ts", "projects/aob/**/*.html"] } } } @@ -1680,10 +1594,30 @@ "build": { "builder": "@angular-devkit/build-angular:browser", "options": { + "allowedCommonJsDependencies": [ + "lodash", + "highlight.js", + "file-saver", + "billboard.js", + "moment-timezone", + "core-js/fn/map", + "core-js/fn/set", + "core-js/fn/weak-map", + "core-js/fn/array/from", + "core-js/fn/object/assign", + "core-js/es/array/from", + "core-js/es/object/assign", + "core-js/es/map", + "core-js/es/set", + "core-js/es/weak-map", + "lodash.debounce", + "lodash.clamp", + "moment", + "@elemental-ui/cadence-icon/codepoints" + ], "outputPath": "dist/qer-app-pwdportal", "index": "projects/qer-app-pwdportal/src/index.html", - "main": "projects/qer-app-pwdportal/src/main.ts", - "polyfills": "projects/qer-app-pwdportal/src/polyfills.ts", + "polyfills": ["projects/qer-app-pwdportal/src/polyfills.ts"], "tsConfig": "projects/qer-app-pwdportal/tsconfig.app.json", "aot": true, "assets": [ @@ -1703,33 +1637,22 @@ "glob": "**/*", "input": "./node_modules/@elemental-ui/core/assets", "output": "./assets" - }, - { - "glob": "**/*", - "input": "./node_modules/systemjs-plugin-babel/", - "output": "./systemjs-plugin-babel" } ], "styles": [ + "shared/scss/styles.scss", "projects/qer-app-pwdportal/src/styles.scss", - "projects/qbm/src/lib/styles/imx-page-title.scss", - "shared/assets/styles.scss", - "shared/assets/variables.scss" + "projects/qbm/src/lib/styles/imx-page-title.scss" ], "stylePreprocessorOptions": { "includePaths": [ - "./shared/assets", - "./shared/scss", "./node_modules", "./node_modules/@elemental-ui/cadence-icon", - "./node_modules/@elemental-ui/core" + "./node_modules/@elemental-ui/core", + "./shared/scss" ] }, - "scripts": [ - "node_modules/systemjs/dist/system.src.js", - "node_modules/systemjs-plugin-babel/plugin-babel.js", - "node_modules/systemjs-plugin-babel/systemjs-babel-browser.js" - ] + "main": "projects/qer-app-pwdportal/src/main.ts" }, "configurations": { "production": { @@ -1742,10 +1665,8 @@ "optimization": true, "outputHashing": "all", "sourceMap": false, - "namedChunks": false, + "namedChunks": true, "extractLicenses": true, - "vendorChunk": false, - "buildOptimizer": true, "budgets": [ { "type": "initial", @@ -1759,9 +1680,7 @@ ] }, "development": { - "buildOptimizer": false, "optimization": false, - "vendorChunk": true, "extractLicenses": false, "sourceMap": true, "namedChunks": true @@ -1773,9 +1692,7 @@ "with": "../imxweb_envs/qer-app-pwdportal/environments/environment.remote-dev.ts" } ], - "buildOptimizer": false, "optimization": false, - "vendorChunk": true, "extractLicenses": false, "sourceMap": true, "namedChunks": true @@ -1787,9 +1704,7 @@ "with": "../imxweb_envs/qer-app-pwdportal/environments/environment.remote-qs.ts" } ], - "buildOptimizer": false, "optimization": false, - "vendorChunk": true, "extractLicenses": false, "sourceMap": true, "namedChunks": true @@ -1802,30 +1717,30 @@ "serve": { "builder": "@angular-devkit/build-angular:dev-server", "options": { - "browserTarget": "qer-app-pwdportal:build" + "buildTarget": "qer-app-pwdportal:build" }, "configurations": { "production": { - "browserTarget": "qer-app-pwdportal:build:production" + "buildTarget": "qer-app-pwdportal:build:production" }, "development": { - "browserTarget": "qer-app-pwdportal:build:development" + "buildTarget": "qer-app-pwdportal:build:development" }, "remote-dev": { - "browserTarget": "qer-app-pwdportal:build:remote-dev" + "buildTarget": "qer-app-pwdportal:build:remote-dev" }, "remote-qs": { - "browserTarget": "qer-app-pwdportal:build:remote-qs" + "buildTarget": "qer-app-pwdportal:build:remote-qs" }, "es5": { - "browserTarget": "qer-app-pwdportal:build:es5" + "buildTarget": "qer-app-pwdportal:build:es5" } } }, "extract-i18n": { "builder": "@angular-devkit/build-angular:extract-i18n", "options": { - "browserTarget": "qer-app-pwdportal:build" + "buildTarget": "qer-app-pwdportal:build" } }, "test": { @@ -1837,6 +1752,60 @@ "karmaConfig": "projects/qer-app-pwdportal/karma.conf.js", "assets": ["projects/qer-app-pwdportal/src/appconfig.json", "projects/qer-app-pwdportal/src/assets"], "styles": ["projects/qer-app-pwdportal/src/styles.scss"], + "stylePreprocessorOptions": { + "includePaths": [ + "./node_modules", + "./node_modules/@elemental-ui/cadence-icon", + "./node_modules/@elemental-ui/core", + "./shared/scss" + ] + } + } + }, + "lint": { + "builder": "@angular-eslint/builder:lint", + "options": { + "lintFilePatterns": ["projects/qer-app-pwdportal/**/*.ts", "projects/qer-app-pwdportal/**/*.html"] + } + } + } + }, + "qam": { + "root": "projects/qam", + "sourceRoot": "projects/qam/src", + "projectType": "library", + "prefix": "imx", + "architect": { + "build": { + "builder": "@angular-devkit/build-angular:ng-packagr", + "options": { + "tsConfig": "projects/qam/tsconfig.lib.json", + "project": "projects/qam/ng-package.json" + }, + "configurations": { + "production": { + "tsConfig": "projects/qam/tsconfig.lib.prod.json" + }, + "development": { + "tsConfig": "projects/qam/tsconfig.lib.json" + }, + "dynamic": { + "project": "projects/qam/ng-package.dynamic.json" + }, + "remote-dev": { + "tsConfig": "projects/qam/tsconfig.lib.json" + }, + "remote-qs": { + "tsConfig": "projects/qam/tsconfig.lib.json" + } + } + }, + "test": { + "builder": "@angular-devkit/build-angular:karma", + "options": { + "main": "projects/qam/src/test.ts", + "tsConfig": "projects/qam/tsconfig.spec.json", + "karmaConfig": "projects/qam/karma.conf.js", "stylePreprocessorOptions": { "includePaths": [ "./shared/assets", @@ -1845,15 +1814,14 @@ "./node_modules/@elemental-ui/cadence-icon", "./node_modules/@elemental-ui/core" ] - }, - "scripts": ["node_modules/systemjs/dist/system.src.js"] + } } }, "lint": { "builder": "@angular-devkit/build-angular:tslint", "options": { - "tsConfig": ["projects/qer-app-pwdportal/tsconfig.app.json", "projects/qer-app-pwdportal/tsconfig.spec.json"], - "exclude": ["**/node_modules/**"] + "tsConfig": ["projects/uci/tsconfig.lib.json", "projects/uci/tsconfig.spec.json"], + "exclude": ["**/node_modules/**", "**/*.spec.ts", "**/*.json"] } } } @@ -1870,12 +1838,35 @@ }, "architect": { "build": { - "builder": "@angular-devkit/build-angular:browser", - "options": { - "outputPath": "dist/custom-app", + "builder": "@angular-devkit/build-angular:application", + "options": { + "outputPath": { + "base": "dist/custom-app", + "browser": "" + }, + "allowedCommonJsDependencies": [ + "lodash", + "highlight.js", + "file-saver", + "billboard.js", + "moment-timezone", + "core-js/fn/map", + "core-js/fn/set", + "core-js/fn/weak-map", + "core-js/fn/array/from", + "core-js/fn/object/assign", + "core-js/es/array/from", + "core-js/es/object/assign", + "core-js/es/map", + "core-js/es/set", + "core-js/es/weak-map", + "lodash.debounce", + "lodash.clamp", + "moment", + "@elemental-ui/cadence-icon/codepoints" + ], "index": "projects/custom-app/src/index.html", - "main": "projects/custom-app/src/main.ts", - "polyfills": "projects/custom-app/src/polyfills.ts", + "polyfills": ["projects/custom-app/src/polyfills.ts"], "tsConfig": "projects/custom-app/tsconfig.app.json", "aot": true, "assets": [ @@ -1895,33 +1886,18 @@ "glob": "**/*", "input": "./node_modules/@elemental-ui/core/assets", "output": "./assets" - }, - { - "glob": "**/*", - "input": "./node_modules/systemjs-plugin-babel/", - "output": "./systemjs-plugin-babel" } ], - "styles": [ - "projects/custom-app/src/styles.scss", - "projects/qbm/src/lib/styles/imx-page-title.scss", - "shared/assets/styles.scss", - "shared/assets/variables.scss" - ], + "styles": ["projects/custom-app/src/styles.scss", "projects/qbm/src/lib/styles/imx-page-title.scss"], "stylePreprocessorOptions": { "includePaths": [ - "./shared/assets", - "./shared/scss", "./node_modules", "./node_modules/@elemental-ui/cadence-icon", - "./node_modules/@elemental-ui/core" + "./node_modules/@elemental-ui/core", + "./shared/scss" ] }, - "scripts": [ - "node_modules/systemjs/dist/system.src.js", - "node_modules/systemjs-plugin-babel/plugin-babel.js", - "node_modules/systemjs-plugin-babel/systemjs-babel-browser.js" - ] + "browser": "projects/custom-app/src/main.ts" }, "configurations": { "production": { @@ -1936,8 +1912,6 @@ "sourceMap": false, "namedChunks": false, "extractLicenses": true, - "vendorChunk": false, - "buildOptimizer": true, "budgets": [ { "type": "initial", @@ -1951,9 +1925,7 @@ ] }, "development": { - "buildOptimizer": false, "optimization": false, - "vendorChunk": true, "extractLicenses": false, "sourceMap": true, "namedChunks": true @@ -1965,9 +1937,7 @@ "with": "../imxweb_envs/custom-app/environments/environment.remote-dev.ts" } ], - "buildOptimizer": false, "optimization": false, - "vendorChunk": true, "extractLicenses": false, "sourceMap": true, "namedChunks": true @@ -1979,9 +1949,7 @@ "with": "../imxweb_envs/custom-app/environments/environment.remote-qs.ts" } ], - "buildOptimizer": false, "optimization": false, - "vendorChunk": true, "extractLicenses": false, "sourceMap": true, "namedChunks": true @@ -1994,30 +1962,30 @@ "serve": { "builder": "@angular-devkit/build-angular:dev-server", "options": { - "browserTarget": "custom-app:build" + "buildTarget": "custom-app:build" }, "configurations": { "production": { - "browserTarget": "custom-app:build:production" + "buildTarget": "custom-app:build:production" }, "development": { - "browserTarget": "custom-app:build:development" + "buildTarget": "custom-app:build:development" }, "remote-dev": { - "browserTarget": "custom-app:build:remote-dev" + "buildTarget": "custom-app:build:remote-dev" }, "remote-qs": { - "browserTarget": "custom-app:build:remote-qs" + "buildTarget": "custom-app:build:remote-qs" }, "es5": { - "browserTarget": "custom-app:build:es5" + "buildTarget": "custom-app:build:es5" } } }, "extract-i18n": { "builder": "@angular-devkit/build-angular:extract-i18n", "options": { - "browserTarget": "custom-app:build" + "buildTarget": "custom-app:build" } }, "test": { @@ -2031,27 +1999,25 @@ "styles": ["projects/custom-app/src/styles.scss"], "stylePreprocessorOptions": { "includePaths": [ - "./shared/assets", - "./shared/scss", "./node_modules", "./node_modules/@elemental-ui/cadence-icon", - "./node_modules/@elemental-ui/core" + "./node_modules/@elemental-ui/core", + "./shared/scss" ] - }, - "scripts": ["node_modules/systemjs/dist/system.src.js"] + } } }, "lint": { - "builder": "@angular-devkit/build-angular:tslint", + "builder": "@angular-eslint/builder:lint", "options": { - "tsConfig": ["projects/custom-app/tsconfig.app.json", "projects/custom-app/tsconfig.spec.json"], - "exclude": ["**/node_modules/**"] + "lintFilePatterns": ["projects/custom-app/**/*.ts", "projects/custom-app/**/*.html"] } } } } }, "cli": { - "analytics": "406eb5c5-3afb-4dab-b878-0cb0ade8d2aa" + "analytics": "406eb5c5-3afb-4dab-b878-0cb0ade8d2aa", + "schematicCollections": ["@angular-eslint/schematics", "@angular-eslint/schematics"] } } diff --git a/imxweb/build-docs.js b/imxweb/build-docs.js new file mode 100644 index 000000000..c41f487ca --- /dev/null +++ b/imxweb/build-docs.js @@ -0,0 +1,40 @@ +// Script to generate documentation via compodoc. +// Use: node build-docs.js +// must correspond to the physical path i.e qer-app-portal + +if (process.argv.length < 3) +{ + console.error("No project(s) given. Please provide at least one project name as an argument."); + process.exit(1); +} + +const child_process = require('child_process'); +const fs = require('fs'); +const path = require('path'); +const projects = process.argv.slice(2); + +projects.forEach(project => generateDoc(project)); + +function generateDoc(project = "") { + console.log(`Generating documentation for ${project}...`); + let tsconfig = path.join('projects', project, 'tsconfig.lib.json'); + if (!fs.existsSync(tsconfig)) { + // If lib doesn't exist, try app + tsconfig = path.join('projects', project, 'tsconfig.app.json'); + } + + if (!fs.existsSync(tsconfig)) { + // Both app and lib don't exist, bad dir + console.error(`${project} doesn't have a tsconfig.lib.json or tsconfig.app.json. Moving on...\n`); + return; + } + + const outputpath = path.join('documentation', project); + const child = child_process.spawnSync('compodoc', ['-p', tsconfig, '-d', outputpath], { encoding: 'utf8', shell: true }); + if (child.error) { + console.log('ERROR: ', child.error); + return; + } + + console.log(`Finished - documentation available at ${outputpath}\n`); +} diff --git a/imxweb/build/imx-prepare-workspace/Build.proj b/imxweb/build/imx-prepare-workspace/Build.proj index 9e5805132..f262aebd8 100644 --- a/imxweb/build/imx-prepare-workspace/Build.proj +++ b/imxweb/build/imx-prepare-workspace/Build.proj @@ -6,13 +6,13 @@ imxweb\build\imx-prepare-workspace $(VI_PROJECTDIR)\imxweb $(VI_PROJECTDIR)\bin\npm - --scripts-prepend-node-path=true + --scripts-prepend-node-path=true - - - + + + - \ No newline at end of file + diff --git a/imxweb/build/nx/Build.proj b/imxweb/build/nx/Build.proj new file mode 100644 index 000000000..4b0902df7 --- /dev/null +++ b/imxweb/build/nx/Build.proj @@ -0,0 +1,41 @@ + + + + + + imxweb\build\nx + $(VI_PROJECTDIR)\imxweb + $(VI_PROJECTDIR)\Assemblies + $(VI_PROJECTDIR)\imxweb\node_modules\@elemental-ui + $(VI_PROJECTDIR)\bin\npm + $(VI_PROJECTDIR)\bin\npx + + + + + + + true + + + + + false + + + + + + + + + + + + + + + + + + diff --git a/imxweb/changes/changesFrom9.1.1To9.2.0.md b/imxweb/changes/changesFrom9.1.1To9.2.0.md deleted file mode 100644 index cc1664eb8..000000000 --- a/imxweb/changes/changesFrom9.1.1To9.2.0.md +++ /dev/null @@ -1,1575 +0,0 @@ -# apc -*PackageAdded* - - -# att `(39 changes)` -EditPolicyGroupSidesheetComponent (*Class added*) - -OpenSidesheetComponent (*Class added*) - -PolicyGroupListComponent (*Class added*) - -PolicyGroupModule (*Class added*) - -AttestationCasesComponent (*1 change*) - -| Type | Change | -| -------- | ------- | -| *Property added* | hasSampleData | - - -AttestationHistoryComponent (*7 changes*) - -| Type | Change | -| -------- | ------- | -| *Property added* | attestorFilter | -| *Property added* | busyService | -| *Method added* | deleteConfigById | -| *Property added* | selectable | -| *Method added* | updateConfig | -| *Method added* | viewAssignmentAnalysis | -| *Property added* | withAssignmentAnalysis | - - -AttestationHistoryService (*2 changes*) - -| Type | Change | -| -------- | ------- | -| *Method added* | exportAttestation | -| *MemberMismatch* | getGroupInfo(parameters?:AttestationCaseLoadParameters):Promise; | - - -canSeeAttestationPolicies (*1 change*) - -| Type | Change | -| -------- | ------- | -| *MemberMismatch* | export declare function canSeeAttestationPolicies(~~groups:string[]):boolean;,~~**features:string[]):boolean;** | - - -EditMasterDataComponent (*9 changes*) - -| Type | Change | -| -------- | ------- | -| *Property added* | contextId | -| *Property added* | objectType | -| *Property added* | objectUid | -| *Property added* | policyEditor | -| *Method added* | updateReadOnlySchedule | -| *MemberMismatch* | addControl(evt:UntypedFormControl, columnName:string):void; | -| *MemberMismatch* | readonly formArray:UntypedFormArray; | -| *MemberMismatch* | readonly formGroup:UntypedFormGroup; | -| *MemberMismatch* | objectProperties:{ [key: string]: { cdr:ColumnDependentReference; formControl?:UntypedFormControl; }; }; | - - -PolicyListComponent (*4 changes*) - -| Type | Change | -| -------- | ------- | -| *Property added* | busyService | -| *Method added* | deleteConfigById | -| *Property added* | menuLoading | -| *Method added* | updateConfig | - - -PolicyService (*4 changes*) - -| Type | Change | -| -------- | ------- | -| *Method added* | exportPolicies | -| *MemberMismatch* | canSeeAllAttestations(preProps:string[],~~groups:string[]):boolean;,~~ **features:string[]):boolean;** | -| *MemberMismatch* | canSeeAttestations(preProps:string[],~~groups:string[]):boolean;,~~ **features:string[]):boolean;** | -| *MemberMismatch* | getGroupInfo(parameters?:{ by?: string; def?: string; } &CollectionLoadParameters):Promise; | - - -RunsComponent (*2 changes*) - -| Type | Change | -| -------- | ------- | -| *Method deleted* | onHelperDismissed | -| *Property deleted* | showHelper | - - -RunsGridComponent (*5 changes*) - -| Type | Change | -| -------- | ------- | -| *Method added* | deleteConfigById | -| *Property added* | entitySchema | -| *Method added* | getExportMethod | -| *Method added* | updateConfig | -| *MemberMismatch* | attestationRunConfig:RunStatisticsConfig| undefined; | - - - - -# cpl `(1 change)` -MitigatingControlsRulesService (*Class added*) - - - -# dpr `(8 changes)` -OutstandingComponent (*8 changes*) - -| Type | Change | -| -------- | ------- | -| *Property added* | busy | -| *Property added* | busyLoadingTable | -| *Method added* | canDeleteAllSelected | -| *Property added* | LdsOutstandingText | -| *Property added* | loadingTableData | -| *Method added* | onShowAllData | -| *Property added* | showAllData | -| *Property added* | tableDataCount | - - - - -# olg `(27 changes)` -MfaFormControlComponent (*Class added*) - -MfaComponent (*26 changes*) - -| Type | Change | -| -------- | ------- | -| *Property deleted* | activatedFactor | -| *Method deleted* | activateFactor | -| *Property deleted* | authCDRs | -| *Property deleted* | authFactors | -| *Property deleted* | checkingOTP | -| *Property deleted* | checkingPoll | -| *Property deleted* | formArray | -| *Property deleted* | formGroup | -| *Property deleted* | isActivated | -| *Method deleted* | isAuthenticator | -| *Method deleted* | isCDRValid | -| *Method deleted* | isOTP | -| *Method deleted* | isProtect | -| *Method deleted* | ngAfterContentChecked | -| *Method deleted* | ngOnInit | -| *Method deleted* | onClose | -| *Method deleted* | resetState | -| *Property deleted* | showCDRs | -| *Method deleted* | verifyPoll | -| *Method deleted* | verifyWithOTP | -| *Method deleted* | verifyWithOTPAndDevice | -| *Property added* | authForm | -| *Property added* | busyService | -| *Property added* | hasAuthenticators | -| *Property added* | isLoading | -| *Method added* | ngOnDestroy | - - - - -# pol `(11 changes)` -PolicyViolationApproverGuardService (*Class deleted*) - -PolicyAdminGuardService (*Class added*) - -PermissionsService (*2 changes*) - -| Type | Change | -| -------- | ------- | -| *Method deleted* | isExceptionApprover | -| *Method added* | isQERPolicyAdmin | - - -PolicyViolationsComponent (*7 changes*) - -| Type | Change | -| -------- | ------- | -| *Property added* | busyService | -| *Method added* | deleteConfigById | -| *Property added* | entitySchema | -| *Property added* | isMControlPerViolation | -| *Property added* | selectedCompanyPolicy | -| *Method added* | updateConfig | -| *MemberMismatch* | viewDetails(~~selectedRulesViolation:PolicyViolation):Promise;,~~**selectedPolicyViolation:PolicyViolation):Promise;** | - - - - -# qbm `(320 changes)` -ImxTimeline (*Class deleted*) - -ImxTimelineItem (*Interface deleted*) - -ImxTimelineOptions (*Interface deleted*) - -MultiLanguageCaptions (*Interface deleted*) - -ObjectSheetInterface (*Interface deleted*) - -TabControlHelper (*Class deleted*) - -TimelineLocales (*Class deleted*) - -Busy (*Interface added*) - -BusyIndicatorComponent (*Class added*) - -BusyIndicatorModule (*Class added*) - -BusyService (*Class added*) - -CacheService (*Class added*) - -CdrFactoryService (*Class added*) - -CdrSidesheetComponent (*Class added*) - -CdrSidesheetConfig (*Interface added*) - -ConnectionComponent (*Class added*) - -CustomThemeModule (*Class added*) - -CustomThemeService (*Class added*) - -DataModelWrapper (*Interface added*) - -DataSourceToolbarExportMethod (*Interface added*) - -DataSourceToolbarViewConfig (*Interface added*) - -DocChapter (*Interface added*) - -DocChapterService (*Class added*) - -DocDocument (*Interface added*) - -DSTViewConfig (*Interface added*) - -DynamicDataApiControls (*Class added*) - -DynamicDataSource (*Class added*) - -ExcludedColumnsPipe (*Class added*) - -FilterTreeComponent (*Class added*) - -FilterWizardComponent (*Class added*) - -FilterWizardModule (*Class added*) - -getParameterSubsetForGrouping (*Function added*) - -HELP_CONTEXTUAL (*Variable added*) - -HelpContextualComponent (*Class added*) - -HelpContextualModule (*Class added*) - -HelpContextualService (*Class added*) - -HelpContextualValues (*TypeAlias added*) - -InfoBadgeComponent (*Class added*) - -InfoButtonComponent (*Class added*) - -InfoModalDialogModule (*Class added*) - -isConfigDefault (*Function added*) - -isDefaultId (*Function added*) - -LogDetailsSidesheetComponent (*Class added*) - -ObjectHistoryGridviewComponent (*Class added*) - -ParameterizedTextService (*Class added*) - -SelectedElementsComponent (*Class added*) - -SelectedElementsModule (*Class added*) - -SideNavigationComponent (*Interface added*) - -SideNavigationExtension (*Interface added*) - -SideNavigationFactory (*TypeAlias added*) - -SideNavigationViewComponent (*Class added*) - -SideNavigationViewModule (*Class added*) - -SidenavTreeComponent (*Class added*) - -SidenavTreeModule (*Class added*) - -TempBillboardComponent (*Class added*) - -TempBillboardModule (*Class added*) - -TextToken (*Interface added*) - -TranslationEditorComponent (*Class added*) - -TreeNodeInfo (*Interface added*) - -ApiClientFetch (*1 change*) - -| Type | Change | -| -------- | ------- | -| *MemberMismatch* | processRequest(methodDescriptor:MethodDescriptor, **opts?:{ signal?:AbortSignal; }):Promise;** | - - -AppConfigService (*2 changes*) - -| Type | Change | -| -------- | ------- | -| *Method deleted* | getImxConfig | -| *Property added* | initializedSubject | - - -BaseCdr (*4 changes*) - -| Type | Change | -| -------- | ------- | -| *Property added* | isReadOnlyColumn | -| *Property added* | minLength | -| *Property added* | minlengthSubject | -| *Method added* | updateMinLength | - - -BulkPropertyEditorComponent (*1 change*) - -| Type | Change | -| -------- | ------- | -| *MemberMismatch* | formGroup:UntypedFormGroup; | - - -CdrEditor (*1 change*) - -| Type | Change | -| -------- | ------- | -| *PropertySignature added* | updateRequested | - - -CdrEditorComponent (*5 changes*) - -| Type | Change | -| -------- | ------- | -| *Property added* | description | -| *Property added* | editor | -| *Property added* | infotitle | -| *Method added* | update | -| *MemberMismatch* | controlCreated:EventEmitter>; | - - -ClientPropertyForTableColumns (*1 change*) - -| Type | Change | -| -------- | ------- | -| *PropertySignature added* | untranslatedDisplay | - - -ColumnDependentReference (*3 changes*) - -| Type | Change | -| -------- | ------- | -| *PropertySignature deleted* | title | -| *PropertySignature added* | minlengthSubject | -| *PropertySignature added* | valueConstraint | - - -ColumnOptions (*3 changes*) - -| Type | Change | -| -------- | ------- | -| *Property added* | isDefaultConfig | -| *Property added* | viewConfig | -| *MemberMismatch* | currentViewSettings:DataModelViewConfig|DSTViewConfig; | - - -ConfirmationService (*1 change*) - -| Type | Change | -| -------- | ------- | -| *Method added* | confirmGeneral | - - -createGroupData (*1 change*) - -| Type | Change | -| -------- | ------- | -| *MemberMismatch* | export declare function createGroupData(dataModel:DataModel, getGroupInfo:(parameters:GroupInfoLoadParameters) =>Promise, excludedColumns?:string[]):DataSourceToolbarGroupData; | - - -DataSourcePaginatorComponent (*4 changes*) - -| Type | Change | -| -------- | ------- | -| *Constructor added* | | -| *Property added* | hidePaginator | -| *Property added* | isLoading | -| *Property added* | showFirstLastButtons | - - -DataSourceToolbarComponent (*66 changes*) - -| Type | Change | -| -------- | ------- | -| *Method deleted* | showSelectedItems | -| *Method added* | addSearchFilter | -| *Method added* | applyConfig | -| *Method added* | applyDynamicPropsAsSelectedFilters | -| *Method added* | applyGroupBy | -| *Method added* | applySort | -| *Property added* | ascendingSortControl | -| *Property added* | busyService | -| *Property added* | canApplySort | -| *Property added* | canClearSort | -| *Property added* | canExport | -| *Property added* | canSave | -| *Method added* | canShowFilterWizard | -| *Method added* | changeConfigName | -| *Method added* | clearSearch | -| *Method added* | clearSort | -| *Property added* | currentFilterDisplayData | -| *Property added* | currentSortColumn | -| *Property added* | deleteConfigById | -| *Property added* | descArg | -| *Property added* | disableFilterWizard | -| *Property added* | disableSearch | -| *Property added* | filterWizardExpression | -| *Method added* | findAndSelectSortColumn | -| *Method added* | getSelectedFilterFromName | -| *Property added* | hasSavedConfigs | -| *Property added* | hasSortFunction | -| *Property added* | hasSortOptions | -| *Method added* | isConfigDefault | -| *Method added* | isDefaultId | -| *Property added* | isDescending | -| *Property added* | isEnterDisabled | -| *Method added* | isRedundant | -| *Property added* | isRegex | -| *Property added* | isSortApplied | -| *Property added* | isSortDesc | -| *Property added* | isStandaloneToolbar | -| *Property added* | localSearchColumns | -| *Method added* | onSelectedFilterRemoved | -| *Method added* | openExportSidesheet | -| *Method added* | removeConfigIndex | -| *Method added* | removeFilterWizard | -| *Method added* | removeSearchTerm | -| *Method added* | saveConfig | -| *Property added* | savedConfigsTrigger | -| *Property added* | searchApi | -| *Property added* | searchResults$ | -| *Property added* | searchTerms | -| *Property added* | selectedFilterType | -| *Property added* | selectedSortControl | -| *Property added* | selection | -| *Method added* | selectSort | -| *Property added* | showClearFilterOption | -| *Method added* | showFilterWizard | -| *Property added* | sortControl | -| *Property added* | sortOptions | -| *Property added* | sortOptionsFilter | -| *Property added* | sortWarningThreshold | -| *Method added* | toggleDefaultConfig | -| *Method added* | toggleSort | -| *Property added* | updateConfig | -| *Property added* | useThemedStyle | -| *MemberMismatch* | clearFilters(**emit?:boolean):void;** | -| *MemberMismatch* | clearGroupedBy(**emit?:boolean):void;** | -| *MemberMismatch* | resetView(**emit?:boolean):Promise;** | -| *MemberMismatch* | searchControl:FormControl; | - - -DataSourceToolbarFilter (*1 change*) - -| Type | Change | -| -------- | ------- | -| *PropertySignature added* | Column | - - -DataSourceToolBarGroup (*2 changes*) - -| Type | Change | -| -------- | ------- | -| *PropertySignature added* | navigationState | -| *MemberMismatch* | getData:(parameter?:CollectionLoadParameters) =>Promise; | - - -DataSourceToolbarGroupData (*1 change*) - -| Type | Change | -| -------- | ------- | -| *MemberMismatch* | currentGrouping?:{ display: string; getData: (parameter?:CollectionLoadParameters) =>Promise; navigationState?:CollectionLoadParameters; }; | - - -DataSourceToolbarSelectedFilter (*1 change*) - -| Type | Change | -| -------- | ------- | -| *MemberMismatch* | selectedOption:DataModelFilterOptionExtended; | - - -DataSourceToolbarSettings (*3 changes*) - -| Type | Change | -| -------- | ------- | -| *PropertySignature deleted* | identifierForSessionStore | -| *PropertySignature added* | exportMethod | -| *PropertySignature added* | viewConfig | - - -DataSourceWrapper (*2 changes*) - -| Type | Change | -| -------- | ------- | -| *MemberMismatch* | getDstSettings(parameters?:CollectionLoadParameters, **requestOpts?:ApiRequestOptions):Promise;** | -| *MemberMismatch* | getGroupDstSettings(parameters:CollectionLoadParameters, **requestOpts?:ApiRequestOptions):Promise;** | - - -DataTableComponent (*7 changes*) - -| Type | Change | -| -------- | ------- | -| *Method deleted* | onOpenSelectionDialog | -| *Property added* | debouncedHighlightRow | -| *Property added* | groupPaginatorInformation | -| *Property added* | isLoading | -| *Method added* | overallGroupingStateChanged | -| *Property added* | showGroupPaginator | -| *MemberMismatch* | highlightRow(entity:TypedEntity, **event?:MouseEvent):void;** | - - -DataTileBadge (*1 change*) - -| Type | Change | -| -------- | ------- | -| *PropertySignature added* | textColor | - - -DataTileComponent (*2 changes*) - -| Type | Change | -| -------- | ------- | -| *Property deleted* | selectedHint | -| *Property added* | selected | - - -DataTilesComponent (*5 changes*) - -| Type | Change | -| -------- | ------- | -| *Constructor added* | | -| *Property added* | isLoading | -| *Method added* | onTileSelected | -| *Property added* | selected | -| *Property added* | selectedEntity | - - -DataTreeComponent (*14 changes*) - -| Type | Change | -| -------- | ------- | -| *Property deleted* | dialog | -| *Method deleted* | onOpenSelectionDialog | -| *Method added* | add | -| *Method added* | deleteNode | -| *Method added* | expandNode | -| *Method added* | getEntityById | -| *Method added* | hasChildren | -| *Method added* | isExpanded | -| *Property added* | isLoading | -| *Property added* | isNodeSelectable | -| *Method added* | onOpenSelectionSidesheet | -| *Property added* | sidesheet | -| *Property added* | treeRendered | -| *Method added* | updateNode | - - -DataTreeWrapperComponent (*10 changes*) - -| Type | Change | -| -------- | ------- | -| *Method added* | add | -| *Method added* | deleteNode | -| *Method added* | expandNode | -| *Method added* | getEntityById | -| *Method added* | hasChildren | -| *Property added* | hideSelection | -| *Method added* | isExpanded | -| *Property added* | isNodeSelectable | -| *Property added* | treeRendered | -| *Method added* | updateNode | - - -DateComponent (*3 changes*) - -| Type | Change | -| -------- | ------- | -| *MemberMismatch* | shadowDate:UntypedFormControl; | -| *MemberMismatch* | shadowText:UntypedFormControl; | -| *MemberMismatch* | shadowTime:UntypedFormControl; | - - -EditBinaryComponent (*1 change*) - -| Type | Change | -| -------- | ------- | -| *MemberMismatch* | readonly control:UntypedFormControl; | - - -EditBooleanComponent (*1 change*) - -| Type | Change | -| -------- | ------- | -| *MemberMismatch* | readonly control:UntypedFormControl; | - - -EditDateComponent (*2 changes*) - -| Type | Change | -| -------- | ------- | -| *Property added* | updateRequested | -| *MemberMismatch* | readonly control:UntypedFormControl; | - - -EditDefaultComponent (*1 change*) - -| Type | Change | -| -------- | ------- | -| *MemberMismatch* | readonly control:UntypedFormControl; | - - -EditFkComponent (*3 changes*) - -| Type | Change | -| -------- | ------- | -| *Property added* | candidatesTotalCount | -| *Property added* | updateRequested | -| *MemberMismatch* | readonly control:UntypedFormControl; | - - -EditLimitedValueComponent (*2 changes*) - -| Type | Change | -| -------- | ------- | -| *Method added* | removeAssignment | -| *MemberMismatch* | readonly control:UntypedFormControl; | - - -EditMultiLimitedValueComponent (*2 changes*) - -| Type | Change | -| -------- | ------- | -| *Property added* | updateRequested | -| *MemberMismatch* | control:UntypedFormArray; | - - -EditMultilineComponent (*1 change*) - -| Type | Change | -| -------- | ------- | -| *MemberMismatch* | readonly control:UntypedFormControl; | - - -EditMultiValueComponent (*1 change*) - -| Type | Change | -| -------- | ------- | -| *MemberMismatch* | readonly control:UntypedFormControl; | - - -EditNumberComponent (*1 change*) - -| Type | Change | -| -------- | ------- | -| *MemberMismatch* | readonly control:UntypedFormControl; | - - -EntityColumnContainer (*1 change*) - -| Type | Change | -| -------- | ------- | -| *Property deleted* | title | - - -EntityColumnEditorComponent (*2 changes*) - -| Type | Change | -| -------- | ------- | -| *Property added* | editor | -| *Method added* | update | - - -EntitySelectComponent (*2 changes*) - -| Type | Change | -| -------- | ------- | -| *MemberMismatch* | readonly control:UntypedFormControl; | -| *MemberMismatch* | controlCreated:EventEmitter>; | - - -FkAdvancedPickerComponent (*3 changes*) - -| Type | Change | -| -------- | ------- | -| *Method deleted* | showSelected | -| *Property added* | selectedEntityCandidates | -| *Property added* | tableNames | - - -FkCandidatesComponent (*2 changes*) - -| Type | Change | -| -------- | ------- | -| *Property added* | busyService | -| *Property added* | entitySchema | - - -FkSelectorComponent (*2 changes*) - -| Type | Change | -| -------- | ------- | -| *Property added* | busyService | -| *Method added* | setSelectedClass | - - -GlobalErrorHandler (*1 change*) - -| Type | Change | -| -------- | ------- | -| *Method added* | resetMessage | - - -HyperviewComponent (*17 changes*) - -| Type | Change | -| -------- | ------- | -| *Method deleted* | getConnectors | -| *Method deleted* | getHeight | -| *Method deleted* | getWidth | -| *Property added* | _shapes | -| *Property added* | containerElem | -| *Method added* | ngAfterViewInit | -| *Method added* | ngOnDestroy | -| *Method added* | onReset | -| *Method added* | onViewChanged | -| *Property added* | rootElem | -| *Method added* | setupLayout | -| *Property added* | shapeList | -| *Property added* | showResetButton | -| *Property added* | viewChanged | -| *MemberMismatch* | connectors:Connector[]; | -| *MemberMismatch* | elRef:ElementRef; | -| *MemberMismatch* | set shapes(value:ShapeData[]); | - - -ImxTranslationProviderService (*4 changes*) - -| Type | Change | -| -------- | ------- | -| *Property deleted* | MultiLanguageCaptions | -| *Property added* | CultureFormat | -| *Method added* | GetCultures | -| *MemberMismatch* | init(culture?:string, **cultureFormat?:string):Promise;** | - - -ISessionState (*1 change*) - -| Type | Change | -| -------- | ------- | -| *PropertySignature added* | cultureFormat | - - -LineChartOptions (*1 change*) - -| Type | Change | -| -------- | ------- | -| *MemberMismatch* | additionalLines:GridLineOptions[]; | - - -LoginComponent (*2 changes*) - -| Type | Change | -| -------- | ------- | -| *Method added* | createNewAccount | -| *Property added* | newUserConfigProvider | - - -MastHeadComponent (*6 changes*) - -| Type | Change | -| -------- | ------- | -| *Property added* | extensions | -| *Method added* | getDynamicExtensions | -| *Property added* | menuItems | -| *Method added* | openConnection | -| *Property added* | productName | -| *Method added* | showExtension | - - -MastHeadService (*1 change*) - -| Type | Change | -| -------- | ------- | -| *Method added* | getConnectionData | - - -MenuService (*2 changes*) - -| Type | Change | -| -------- | ------- | -| *Constructor added* | | -| *MemberMismatch* | getMenuItems(preProps:string[],~~**groups:string[]**,~~ **features:string[]**, allowEmpty?:boolean, projectConfig?:ProjectConfig, groups?:string[]):Promise; | - - -MessageParameter (*1 change*) - -| Type | Change | -| -------- | ------- | -| *PropertySignature added* | Parameter | - - -MultiSelectFormcontrolComponent (*1 change*) - -| Type | Change | -| -------- | ------- | -| *MemberMismatch* | readonly searchControl:UntypedFormControl; | - - -ObjectHistoryApiService (*1 change*) - -| Type | Change | -| -------- | ------- | -| *Method added* | getHistoryComparisonData | - - -ObjectHistoryComponent (*24 changes*) - -| Type | Change | -| -------- | ------- | -| *Property deleted* | effectiveViewMode | -| *Property deleted* | viewMode | -| *Property deleted* | viewModeTimeline | -| *Property added* | compareDateFormControl | -| *Property added* | historyComparisonData | -| *Property added* | lookIcons | -| *Property added* | looks | -| *Method added* | ngOnDestroy | -| *Method added* | onLookSelectionChanged | -| *Method added* | onViewModeChange | -| *Property added* | selectedLook | -| *Method added* | setTimeline | -| *Property added* | stateOverviewItems | -| *Property added* | timelineFrom | -| *Property added* | timelineFromDateFormControl | -| *Property added* | timelineFromString | -| *Property added* | timelineFromTimeFormControl | -| *Property added* | timelineTo | -| *Property added* | timelineToDateFormControl | -| *Property added* | timelineToString | -| *Property added* | timelineToTimeFormControl | -| *Property added* | viewModeStateComparison | -| *Property added* | viewModeStateOverview | -| *MemberMismatch* | refresh(**fetchRemote:boolean):Promise;** | - - -OrderedListComponent (*5 changes*) - -| Type | Change | -| -------- | ------- | -| *Method deleted* | ngOnInit | -| *Property added* | isReadOnly | -| *Property added* | placeholder | -| *Property added* | theme | -| *Property added* | valueChanged | - - -ParameterizedTextComponent (*1 change*) - -| Type | Change | -| -------- | ------- | -| *Property added* | textReady | - - -SearchBarComponent (*1 change*) - -| Type | Change | -| -------- | ------- | -| *MemberMismatch* | tables:UntypedFormControl; | - - -SelectComponent (*1 change*) - -| Type | Change | -| -------- | ------- | -| *MemberMismatch* | readonly chipListCtrl:UntypedFormControl; | - - -SessionState (*1 change*) - -| Type | Change | -| -------- | ------- | -| *Property added* | cultureFormat | - - -SqlWizardApiService (*1 change*) - -| Type | Change | -| -------- | ------- | -| *Property added* | implemented | - - -SqlWizardComponent (*10 changes*) - -| Type | Change | -| -------- | ------- | -| *Property added* | andConditionLabel | -| *Property added* | expressionList | -| *Property added* | isImplemented | -| *Method added* | logOpText | -| *Method added* | ngAfterViewInit | -| *Method added* | onOperatorChanged | -| *Property added* | orConditionLabel | -| *Method added* | removeAllExpressions | -| *MemberMismatch* | emitChanges():Promise; | -| *MemberMismatch* | ngOnChanges(changes:SimpleChanges):Promise; | - - -SystemInfoService (*1 change*) - -| Type | Change | -| -------- | ------- | -| *Method added* | getImxConfig | - - -TileComponent (*1 change*) - -| Type | Change | -| -------- | ------- | -| *Property added* | loadingState | - - -TreeDatabase (*3 changes*) - -| Type | Change | -| -------- | ------- | -| *Property added* | busyService | -| *Method added* | createNode | -| *Method added* | getId | - - -TypedEntitySelectComponent (*2 changes*) - -| Type | Change | -| -------- | ------- | -| *MemberMismatch* | readonly control:UntypedFormControl; | -| *MemberMismatch* | readonly controlCreated:EventEmitter; | - - - - -# qer `(225 changes)` -DefaultSheetComponent (*Class deleted*) - -IDataExplorerComponent (*Interface deleted*) - -ObjectSheetComponent (*Class deleted*) - -ObjectSheetModule (*Class deleted*) - -ObjectsheetPersonModule (*Class deleted*) - -ObjectSheetService (*Class deleted*) - -additionalColumnsForServiceItemsKey (*Variable added*) - -ApprovalWorkFlowModule (*Class added*) - -ArchivedRequestsComponent (*Class added*) - -ArchivedRequestsModule (*Class added*) - -AuthenticationFactors (*Interface added*) - -ChartInfoTyped (*Class added*) - -DashboardService (*Class added*) - -DataManagementService (*Class added*) - -DecisionStepSevice (*Class added*) - -isAuditor (*Function added*) - -isRoleAdmin (*Function added*) - -isRoleStatistics (*Function added*) - -MyResponsibilitiesRegistryService (*Class added*) - -MyResponsibilitiesViewModule (*Class added*) - -NewRequestComponent (*Class added*) - -NewRequestModule (*Class added*) - -NewRequestSelectionService (*Class added*) - -NotificationRegistryService (*Class added*) - -NotificationStreamService (*Class added*) - -ObjectHyperviewComponent (*Class added*) - -ObjectHyperviewModule (*Class added*) - -ObjectHyperviewService (*Class added*) - -OpSupportUserService (*Class added*) - -ParameterContainer (*Class added*) - -PasswordQuestionsComponent (*Class added*) - -RecommendationSidesheetComponent (*Class added*) - -RelatedApplicationsModule (*Class added*) - -RequestHistoryFilterComponent (*Class added*) - -RequestTableComponent (*Class added*) - -ResourcesModule (*Class added*) - -RiskConfigComponent (*Class added*) - -RiskConfigModule (*Class added*) - -RoleDetailComponent (*Class added*) - -RoleEntitlementActionService (*Class added*) - -RoleRecommendationResultItem (*Class added*) - -RoleRecommendationsComponent (*Class added*) - -SettingsComponent (*Class added*) - -StatisticsForObjectsComponent (*Class added*) - -StatisticsModule (*Class added*) - -TeamResponsibilitiesModule (*Class added*) - -TermsOfUseItem (*Interface added*) - -TermsOfUseService (*Class added*) - -TermsOfUseViewerComponent (*Class added*) - -UserProcessComponent (*Class added*) - -UserProcessModule (*Class added*) - -ViewConfigService (*Class added*) - -ViewDevicesComponent (*Class added*) - -ViewDevicesModule (*Class added*) - -ViewDevicesSidesheetComponent (*Class added*) - -AddressbookComponent (*1 change*) - -| Type | Change | -| -------- | ------- | -| *Property added* | busyService | - - -BadgeTileComponent (*1 change*) - -| Type | Change | -| -------- | ------- | -| *Property added* | loadingState | - - -BaseTreeEntitlement (*1 change*) - -| Type | Change | -| -------- | ------- | -| *MemberMismatch* | getCollection(id:string, navigationState?:CollectionLoadParameters, **objectKeyForFiltering?:string):Promise>; | - - -DataExplorerIdentitiesComponent (*12 changes*) - -| Type | Change | -| -------- | ------- | -| *Property deleted* | downloadOptions | -| *Property added* | busyService | -| *Property added* | contextId | -| *Method added* | deleteConfigById | -| *Property added* | dynamicReport | -| *Property added* | extensions | -| *Method added* | getDynamicMenuItems | -| *Property added* | isAuditor | -| *Property added* | isPersonAdmin | -| *Method added* | personsManagedReport | -| *Method added* | showDynamicReport | -| *Method added* | updateConfig | - - -DataExplorerRegistryService (*2 changes*) - -| Type | Change | -| -------- | ------- | -| *MemberMismatch* | getNavItems(preProps:string[],~~**groups:string[]):IDataExplorerExtension[];**,~~ **features:string[]**, **projectConfig?:ProjectConfig**, groups?:string[]):SideNavigationExtension[]; | -| *MemberMismatch* | registerFactory(...factories:SideNavigationFactory[]):void; | - - -DecisionReasonComponent (*7 changes*) - -| Type | Change | -| -------- | ------- | -| *Method deleted* | checkReason | -| *Method added* | ngOnInit | -| *Method added* | updateMinLength | -| *MemberMismatch* | addReasonStandard(~~**control:AbstractControl):void;**,~~control?:AbstractControl):void; | -| *MemberMismatch* | controlCreated:EventEmitter>; | -| *MemberMismatch* | reasonFreetext:BaseCdr; | -| *MemberMismatch* | reasonStandard:BaseCdr; | - - -DelegationComponent (*20 changes*) - -| Type | Change | -| -------- | ------- | -| *Property deleted* | isLoadingElements | -| *Property deleted* | projectConfig | -| *Method deleted* | resetForms | -| *Method deleted* | showSelected | -| *Property added* | busyService | -| *Property added* | cdrPersonSender | -| *Property added* | delegationObjects | -| *Property added* | initialized | -| *Property added* | isLoading | -| *Property added* | isManager | -| *Method added* | resetDelegation | -| *Property added* | senderFormGroup | -| *Property added* | stepper | -| *Property added* | withSubordinates | -| *MemberMismatch* | addControl(group:UntypedFormGroup, name:string, control:AbstractControl):void; | -| *MemberMismatch* | readonly delegationForm:UntypedFormGroup; | -| *MemberMismatch* | readonly delegationTypeForm:UntypedFormGroup; | -| *MemberMismatch* | readonly recipientFormGroup:UntypedFormGroup; | -| *MemberMismatch* | readonly rolesForm:UntypedFormGroup; | -| *MemberMismatch* | searchControl:UntypedFormControl; | - - -DynamicExclusionDialogComponent (*1 change*) - -| Type | Change | -| -------- | ------- | -| *MemberMismatch* | dynamicExclusionForm:UntypedFormGroup; | - - -IconTileComponent (*1 change*) - -| Type | Change | -| -------- | ------- | -| *Property added* | loadingState | - - -IdentitiesReportsService (*3 changes*) - -| Type | Change | -| -------- | ------- | -| *Method added* | viewReport | -| *MemberMismatch* | personsManagedReport(~~historyDays:number,~~personId:string, **subtitle:string):Promise;** | -| *MemberMismatch* | **personsReport(~~historyDays:numb~~personId:string):string;**,~~er,~~person:PortalPersonReports|PortalAdminPerson):Promise; | - - -IdentitiesService (*5 changes*) - -| Type | Change | -| -------- | ------- | -| *Method added* | exportAdminPerson | -| *Method added* | exportPerson | -| *MemberMismatch* | createEmptyEntity():Promise; | -| *MemberMismatch* | getGroupedAllPerson(columns:string, navigationState:CollectionLoadParameters):Promise; | -| *MemberMismatch* | getPersonInteractive(uid:string):Promise>; | - - -IdentityRoleMembershipsComponent (*1 change*) - -| Type | Change | -| -------- | ------- | -| *Property added* | busyService | - - -IdentitySidesheetComponent (*9 changes*) - -| Type | Change | -| -------- | ------- | -| *Property deleted* | managedReportDownload | -| *Property deleted* | reportDownload | -| *Method added* | personsManagedReport | -| *Method added* | personsReport | -| *Property added* | tabs | -| *MemberMismatch* | data:{ isAdmin: boolean; projectConfig:QerProjectConfig; selectedIdentity:PortalPersonReports|PortalAdminPerson; canEdit: boolean; }; | -| *MemberMismatch* | readonly detailsFormGroup:UntypedFormGroup; | -| *MemberMismatch* | isActiveFormControl:UntypedFormControl; | -| *MemberMismatch* | isSecurityIncidentFormControl:UntypedFormControl; | - - -IRoleEntitlements (*1 change*) - -| Type | Change | -| -------- | ------- | -| *MemberMismatch* | getCollection(id:string, navigationState?:CollectionLoadParameters, **objectKeyForFiltering?:string):Promise>; | - - -ItshopRequest (*2 changes*) - -| Type | Change | -| -------- | ------- | -| *Property added* | canCopyItems | -| *Property added* | isArchived | - - -ItshopService (*1 change*) - -| Type | Change | -| -------- | ------- | -| *MemberMismatch* | getPeerGroupMemberships(parameters:(CollectionLoadParameters|ServiceItemParameters), **requestOpts?:ApiRequestOptions):Promise>; | - - -JustificationService (*1 change*) - -| Type | Change | -| -------- | ------- | -| *MemberMismatch* | createCdr(justificationType:JustificationType~~reasonType?:number):Promise;,~~):Promise; | - - -JustificationType (*2 changes*) - -| Type | Change | -| -------- | ------- | -| *EnumMember added* | approvePolicyViolation | -| *EnumMember added* | denyPolicyViolation | - - -OwnerControlComponent (*2 changes*) - -| Type | Change | -| -------- | ------- | -| *MemberMismatch* | formControlCreated:EventEmitter>; | -| *MemberMismatch* | ownerSelectionCtrl:UntypedFormControl; | - - -ParameterDataService (*4 changes*) - -| Type | Change | -| -------- | ------- | -| *Property added* | entityService | -| *Property added* | logger | -| *MemberMismatch* | createInteractiveParameterCategoryColumns(parameterCategories:ParameterCategory[],~~**getFkProviderItems:(parameter:ParameterData) =>FkProviderItem[]**,~~ getFkProvider:(parameter:ParameterData) =>IFkCandidateProvider, typedEntity:ReadWriteExtTypedEntity<{ Parameters?: { [key: string]:ParameterData[][]; }; },CategoryParameterWrite>, callbackOnChange?:() => void):ParameterCategoryColumn[]; | -| *MemberMismatch* | createInteractiveParameterColumns(parameters:ParameterData[],~~**getFkProviderItems:(parameter:ParameterData) =>FkProviderItem[]**,~~ getFkProvider:(parameter:ParameterData) =>IFkCandidateProvider, typedEntity:ReadWriteExtTypedEntity):IEntityColumn[]; | - - -PasscodeViewerComponent (*1 change*) - -| Type | Change | -| -------- | ------- | -| *Property added* | LdsExplanation | - - -PersonService (*2 changes*) - -| Type | Change | -| -------- | ------- | -| *MemberMismatch* | createFkProviderItem(fkRelation:MetaTableRelationData, **filter?:FilterData[]):FkProviderItem;** | -| *MemberMismatch* | getGroupInfo(parameters?:PersonAllLoadParameters):Promise; | - - -ProfileComponent (*5 changes*) - -| Type | Change | -| -------- | ------- | -| *Property added* | canManageSecurityKeys | -| *Property added* | canShowEntitlementsHyperview | -| *Property added* | isShowEntitlementsHyperview | -| *Property added* | selectedContextId | -| *MemberMismatch* | form:UntypedFormGroup; | - - -QerPermissionsService (*11 changes*) - -| Type | Change | -| -------- | ------- | -| *Method added* | hasFeatures | -| *Method added* | isAuditor | -| *Method added* | isCancelPwO | -| *Method added* | isPasswordHelpdesk | -| *Method added* | isResourceAdmin | -| *Method added* | isRoleAdmin | -| *Method added* | isRoleStatistics | -| *Method added* | isRuleAdmin | -| *Method added* | isShopStatistics | -| *Method added* | isStatistics | -| *Method added* | isStructStatistics | - - -RequestInfoComponent (*3 changes*) - -| Type | Change | -| -------- | ------- | -| *Property added* | isApproval | -| *Property added* | isLoading | -| *Method added* | ngOnDestroy | - - -RequestParameterDataEntity (*1 change*) - -| Type | Change | -| -------- | ------- | -| *PropertySignature added* | isArchived | - - -RequestsComponent (*1 change*) - -| Type | Change | -| -------- | ------- | -| *Property added* | busyService | - - -RequestsService (*3 changes*) - -| Type | Change | -| -------- | ------- | -| *Property deleted* | LdsShelfExplanation | -| *Property deleted* | LdsShopDetails | -| *Property deleted* | LdsShopEntitlements | - - -RiskAnalysisComponent (*23 changes*) - -| Type | Change | -| -------- | ------- | -| *Property deleted* | Description | -| *Method deleted* | DisplayTypeOfCalculation | -| *Method deleted* | DisplayWeight | -| *Method deleted* | GetDisplayValue1 | -| *Method deleted* | GetResultRisk | -| *Method deleted* | GetRiskCalcFormula | -| *Method deleted* | GetRiskObjectTop | -| *Method deleted* | IsFromAttribute | -| *Method deleted* | IsIncOrDec | -| *Method deleted* | IsShowChildSourceDisplay | -| *Property deleted* | LdsMaximumOfAllAssignments | -| *Property deleted* | RiskObject | -| *Property added* | description | -| *Method added* | displayTypeOfCalculation | -| *Method added* | displayWeight | -| *Method added* | getDisplayValue1 | -| *Method added* | getResultRisk | -| *Method added* | getRiskCalcFormula | -| *Method added* | getRiskObjectTop | -| *Method added* | isFromAttribute | -| *Method added* | isIncOrDec | -| *Method added* | isShowChildSourceDisplay | -| *Property added* | riskObject | - - -RoleService (*13 changes*) - -| Type | Change | -| -------- | ------- | -| *Property deleted* | AERoleTag | -| *Property deleted* | DepartmentTag | -| *Property deleted* | LocalityTag | -| *Property deleted* | ProfitCenterTag | -| *Method added* | canCreate | -| *Property added* | canEdit | -| *Method added* | canHaveStatistics | -| *Method added* | getExportMethod | -| *Method added* | getRecommendations | -| *Method added* | getRoleTranslateKeys | -| *Method added* | hasHierarchy | -| *MemberMismatch* | getEntitlements(args:{ id: string; navigationState?:CollectionLoadParameters; objectKey?: string; }):Promise>; | -| *MemberMismatch* | setSidesheetData(args:{ ownershipInfo:OwnershipInformation; entity:IEntity; isAdmin: boolean; canEdit: boolean; }):void; | - - -RolesOverviewComponent (*12 changes*) - -| Type | Change | -| -------- | ------- | -| *Property added* | busyService | -| *Property added* | canCreate | -| *Property added* | contextId | -| *Method added* | createNew | -| *Method added* | deleteConfigById | -| *Method added* | getChildCreationText | -| *Method added* | getCreationText | -| *Property added* | hasHierarchy | -| *Method added* | ngOnDestroy | -| *Method added* | updateConfig | -| *Property added* | viewConfig | -| *Property added* | viewConfigPath | - - -ServiceCategoriesService (*1 change*) - -| Type | Change | -| -------- | ------- | -| *MemberMismatch* | getById(uidAccProductGroup:string):Promise>; | - - -ServiceItemsEditFormComponent (*10 changes*) - -| Type | Change | -| -------- | ------- | -| *Property deleted* | formArray | -| *Property added* | alertExtId | -| *Property added* | busyService | -| *Method added* | getColumn | -| *Property added* | ServiceItemsEditFormComponent | -| *MemberMismatch* | formControlCreated:EventEmitter>; | -| *MemberMismatch* | readonly formGroup:FormGroup; | -| *MemberMismatch* | isInActiveFormControl:FormControl; | -| *MemberMismatch* | onRequestableToggleChanged(checkboxChange:MatSlideToggleChange):Promise; | -| *MemberMismatch* | serviceItem:TypedEntity; | - - -ServiceItemTagsComponent (*2 changes*) - -| Type | Change | -| -------- | ------- | -| *MemberMismatch* | readonly control:UntypedFormControl; | -| *MemberMismatch* | readonly controlCreated:EventEmitter>; | - - -SourceDetectiveComponent (*2 changes*) - -| Type | Change | -| -------- | ------- | -| *Property added* | busy | -| *Method added* | grabText | - - -UserModelService (*2 changes*) - -| Type | Change | -| -------- | ------- | -| *Method added* | getFeatures | -| *MemberMismatch* | getDirectReports(**uidperson?:string):Promise;** | - - -WorkflowDataWrapper (*1 change*) - -| Type | Change | -| -------- | ------- | -| *Method added* | userAskedLastQuestion | - - - - -# rps `(3 changes)` -ReportButtonComponent (*1 change*) - -| Type | Change | -| -------- | ------- | -| *Method added* | ngOnDestroy | - - -SubscriptionsComponent (*2 changes*) - -| Type | Change | -| -------- | ------- | -| *Property added* | busyService | -| *Method added* | viewReportSubscription | - - - - -# sac -*PackageAdded* - - -# tsb `(28 changes)` -AccountsExtComponent (*1 change*) - -| Type | Change | -| -------- | ------- | -| *Property added* | busyService | - - -AccountSidesheetComponent (*3 changes*) - -| Type | Change | -| -------- | ------- | -| *MemberMismatch* | readonly detailsFormGroup:UntypedFormGroup; | -| *MemberMismatch* | get formArray():UntypedFormArray; | -| *MemberMismatch* | neverConnectFormControl:UntypedFormControl; | - - -AccountsService (*1 change*) - -| Type | Change | -| -------- | ------- | -| *Method added* | exportAccounts | - - -DataExplorerAccountsComponent (*4 changes*) - -| Type | Change | -| -------- | ------- | -| *Property added* | busyService | -| *Property added* | contextId | -| *Method added* | deleteConfigById | -| *Method added* | updateConfig | - - -DataExplorerGroupsComponent (*11 changes*) - -| Type | Change | -| -------- | ------- | -| *Property deleted* | dataExplorerFilters | -| *Property added* | busyService | -| *Property added* | contextId | -| *Method added* | deleteConfigById | -| *Property added* | itemsAreNotRequestable | -| *Property added* | itemsAreRequestable | -| *Property added* | ó | -| *Method added* | updateConfig | -| *Property added* | usedInSidesheet | -| *MemberMismatch* | bulkUpdateSelected(**request:boolean):Promise;** | -| *MemberMismatch* | requestableBulkUpdateCtrl:UntypedFormControl; | - - -DataExplorerNoDataComponent (*2 changes*) - -| Type | Change | -| -------- | ------- | -| *Constructor deleted* | | -| *Property deleted* | webApp | - - -GroupSidesheetComponent (*4 changes*) - -| Type | Change | -| -------- | ------- | -| *MemberMismatch* | readonly detailsFormGroup:UntypedFormGroup; | -| *MemberMismatch* | get formArray():UntypedFormArray; | -| *MemberMismatch* | readonly serviceItemFormGroup:UntypedFormGroup; | -| *MemberMismatch* | get siFormArray():UntypedFormArray; | - - -GroupsService (*2 changes*) - -| Type | Change | -| -------- | ------- | -| *Method added* | exportGroups | -| *Method added* | exportGroupsResp | - - - - diff --git a/imxweb/compodoc/assets/images/dashboard/1-dashboard.png b/imxweb/compodoc/assets/images/dashboard/1-dashboard.png index edf1cfc1024745a5efb4a7f3e74d6d1abddc5e1e..8d6bedbc375b67ffd3e77e8975c655288288da91 100644 GIT binary patch literal 18301 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 literal 55956 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 Z=og4PKmSyXZ}9<=exd-$6np;qe*h0igGK-V diff --git a/imxweb/compodoc/assets/images/dashboard/2-dashboard.png b/imxweb/compodoc/assets/images/dashboard/2-dashboard.png new file mode 100644 index 0000000000000000000000000000000000000000..09412a43c3c089146ffa4138543e92316a87e099 GIT binary patch literal 18085 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�MxA^Mf2;M%nlpmDYFn`8ICgh-L?OjU8z^sWP!{bHFg6L4(h zUBzx!7O45`Y(+y&WuwaX>!2{B@-i1F`1>CWFVYpw25N}!9j|_%zfxY*B4^(ke zI}VP^IRpoBv5w^lLq6-d_`Tz%*o~U%p-#^LkYk|@IuanGC_rr2<%_Yg)!+h!6#RAa zb;YA`nps`leiuLk17i!T0?wb-3tzs-{P;P$-;+w@Zg`8)dqH6$ZJhVCydBLA-?Koc z^M9*`$rkyN{S)^z&ubP_gh0i=d@Eag{bBp`^Ty4;cQd0`2z2?VOvI|iNJB{R>anF^ zzmfVMWRTo|S>W3|Gq-@v$d7%>%Rx8tt_mqZ(FZj zccRt$zV(&pn^kS%(;GLs%4u|u-ct~5nUY7fixY|A&j*lAY;CIcNBWK^>m+r$?fWcY zjjKK914J9ZsqY8?_XF{)KY7Orjz&rf@grC%7M~OGg2Y=?hK`pb8yqKUb~q<#3W99! zqT7RUPc}&WoWpQm(4g$s?QfjQ%6%&pwfu{k%^BgG-dBU({J97CL2sdEdC!{ypBOw2 zLGoN?e*i@#Xnl+Ljh=3Qr|9|Z;kG~n?ovyA$o!qzi+5c#{62fj=T4TlRO1Wh$LU4 zQ<_+|Z+-2;4>(`54ml!YkGmHR1lXV%`wrH~q4g*mPqE1BK)XWRvUM9qm%mB!?OzBg z%T`>`DyaEp@mT{oV5z|arn5UzmftauHsOM>2y|L$vi(24cF`F`P0UxPXRJ5`joyejg@vF)r0LV^7Qewww6B(}d2;@tNir4|_d{9orq@ab)<@F+J2T)3J(XQ8^+ zr6lW|O&I_e=kxK`a|dZOWxYMGRV5F)=t>K4<$OLb9w^ z_yV96^-O?VO-RdF#p>SY15~Ob0DaKFoeqH1Q7kMN$mj1~GyBgd_qYB22O6SkH2zUI zCqxujpi#BGaDRP7`3?|P{NEHu;mZJsreuorL$&IliG#N(a9 z52*L}Yd%{JvkyNonzh*k*vC5-!%6V>(s>&=paFQqx8Imk&;Ix74KV8efyDm@PKWCO zQ5z>V#|)Fn0{j8V`_-$edBS%G!gQ6k+n~eA>)*7`NBiHD{eKFmHziotb1iOLPv*8H ze)hP{P8ApIjLi)R);f!2oLI5WH4yxBhP%F=ID|-V$`EDhsL8&`p6kQfglbitxx1s z2#?_4b=z>hb$j?5Rx-{0<}pccE6$r#28iPH0tHGtzm1N={eW`WZj&bf&)*g-z(#3* zp$(ta`^ADR!J`3ov8M)5Fwp#hD8v5DHa*^*-*)6*2+>}>DJr`2^*G4qAY3Raq}O&N z(+uq3a6C%wLU#8bWr==e!=an=l1N``>x#GhV3k_4R3Pg0 zDr#S-ND`W*>4zUqlr~6cOO*cDr$B29R!=;e;8+y0N7~sXOP6=p+6S`s0L&__51X~L zZwR}%XDiaj*Y}#WwK2`P##h3Z-0Gtq7u_x^jbv#`M{rK(=)-=Djb-j_6m}lhrJb=> zHB}A`g^u?sD}DU9AH2=5s)IvV55rIp%3pZW9{eM-1!kkX`|^*te6g*?$W=7ut{RXY zm=zZldDPZE_&(q*oE@#1X7=D>9UP?YK$-vO+$ci^V*%M&2ZshiD(`+k=o_%Hcds5X zGX?on6=`eZDaG?|=C#9td_wPN2-a!1wgwK;{5&ZLJwMxy=tP>#&7fN(26is>>TAwt z7K;hdM4k3Wb@gxe=oxasC@YyX9*TOB%6ex@ySud%4kQ&nQ0UU2ySuYL;`R~_MKQqw upPBhuX*=WrRY?Bz_Um7^9sfR4$Tpx)V|7cPmV^s5$LN~b)v{llAN?;Z4vUol literal 0 HcmV?d00001 diff --git a/imxweb/compodoc/assets/images/dashboard/5-block-identity-button.png b/imxweb/compodoc/assets/images/dashboard/5-block-identity-button.png index 8acfc5764d7588290f03014e0d0d0dbb7396f417..09048c72c7f17f57435c264a801f843adfd5c105 100644 GIT binary patch literal 31801 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 literal 71872 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%0Dd-!5%yD0_zyxtuPB988?KnH#V&kIzs!c3 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 H=db=h4>1SA diff --git a/imxweb/compodoc/assets/images/data_table/1-overall-structure.png b/imxweb/compodoc/assets/images/data_table/1-overall-structure.png index 75393aaad261a5c747d12ecfc699dc4e6a24bc77..11799acfbefbe95187114811475a98e2f81443ae 100644 GIT binary patch literal 18487 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 soIxX8EY>!h{33dTxj4|gs#yj3b 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�!{Ard&PsDEc!YZ7YHO}iorY}@oV<;^ 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 H!~OpUK81q& diff --git a/imxweb/compodoc/assets/images/menu/1-menu-bar.png b/imxweb/compodoc/assets/images/menu/1-menu-bar.png index 51181e40a5ae7ef305f2e885263070fc7bb6bb56..0e0b321446137587c383b2cc435ded3a4d224811 100644 GIT binary patch literal 9717 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 literal 6914 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 Code ``` html

{{ '#LDS#Identities' | translate }}

@@ -34,7 +35,6 @@ The "Hello World" version of the Data Table component looks like as follow. ``` -> Code ``` ts @Component({ @@ -83,11 +83,10 @@ export class SelectIdentityComponent implements OnInit { ``` -The minimum set of properties that must be set are "EntitySchema", "DisplayColumns" and "CollectionLoadParameters". +The minimum set of properties that must be specified are `EntitySchema`, `DisplayColumns` and `CollectionLoadParameters`. -Three places in the .ts Datei are worth to be highlighted. +The following parts of the .ts Datei are important. -> Code ``` ts this.displayedColumns = [ this.schema.Columns[DisplayColumns.DISPLAY_PROPERTYNAME], @@ -95,9 +94,8 @@ Three places in the .ts Datei are worth to be highlighted. ]; ``` -"displayedColumns" defines which columns the table should display. +`displayedColumns` defines which columns the table should display. -> Code ``` ts public async onNavigationStateChanged(newState?: CollectionLoadParameters): Promise { if (newState) { @@ -107,9 +105,8 @@ Three places in the .ts Datei are worth to be highlighted. } ``` -This event handler is called every time the state of the data changes, e.g. when the user navigates to the next page. +This event handler is called every time the state of the data changes, for example when the user navigates to the next page. -> Code ``` ts private async navigate(): Promise { const data = await this.qerApiClient.typedClient.PortalPersonAll.Get(this.navigationState); @@ -122,7 +119,7 @@ This event handler is called every time the state of the data changes, e.g. when }; } ``` -The "navigate()" method retrievs data from the API server. The actual request is made by calling the API client ("this.qerApiClient.typedClient.PortalPersonAll.Get(this.navigationState)"). The concept of API clients is described in a separate sample. +The `navigate()` method retrieves data from the API Server. The actual request is made by calling the API client (`this.qerApiClient.typedClient.PortalPersonAll.Get(this.navigationState)`). The concept of API clients is described in another example. The first version of the component looks like this. @@ -130,9 +127,8 @@ The first version of the component looks like this. ## Designing the table -The table above shows two fields that are rendered automatically. It is also possible to design columns manually. Whether the table is rendered automatically or manually is controlled by the "mode" input field. +The table now shows two fields that are rendered automatically. It is also possible to design columns manually. Whether the table is rendered automatically or manually is controlled by the `mode` input field. -> Code ``` html ``` -"mode" can take two values: "auto" and "manual". +`mode` can take two values: `auto` and `manual`. -To display the previous table in manual mode, we need to add the two columns to the html template. +To display the table in manual mode, the two columns must be added to the html template. -> Code ``` html @@ -160,11 +155,8 @@ To display the previous table in manual mode, we need to add the two columns to ``` -In the next step we will add a new column to the table containing a button and slightly modify the first column. - -The first column currently shows the default display of the object. We want to add a second row that indicates whether the person is a primary identity or not. +The first column currently shows the default display name of the object. A second row that indicates whether the person is a primary identity or not is added. -> Code ``` html @@ -181,10 +173,9 @@ The first column currently shows the default display of the object. We want to a ``` -Next we will add a third column that will contain a button. To display data of an object the table uses the "" tag. To display other types of elements, such as buttons, we use the "" tag. -Before we can display the button, we need to add the new synthetic column to the columns to be displayed. This is done in the *.ts file. +In the following, a third column that contains a button is added. To display data of an object, the table uses the `` tag. To display other types of elements, such as buttons, the `` tag is used. +Before the button can be displayed, the new column must be added to the columns to be displayed. This is done in the `*.ts` file. -> Code ``` ts this.displayedColumns = [ this.schema.Columns[DisplayColumns.DISPLAY_PROPERTYNAME], @@ -197,7 +188,6 @@ Before we can display the button, we need to add the new synthetic column to the ``` -> Code ``` html @@ -221,14 +211,13 @@ Before we can display the button, we need to add the new synthetic column to the ``` -The extended component now looks like this. +The final result looks like this. -![Version with search enabled](../../assets/images/data_table/4-table-with-search.png) +![Version with buttons](../../assets/images/data_table/4-table-with-buttons.png) ## Adding search -Enabling search is pretty straightforward. -To do this, you must first enable the "search" option and secondly implement a method that processes the output of the "search" output parameter. +To add a search bar, the `search` option must be enabled and a method that processes the output of the `search` output parameter must be implemented. The following code snippets shows these changes. @@ -254,8 +243,3 @@ The following code snippets shows these changes. ![Version with search enabled](../../assets/images/data_table/3-table-with-search-enabled.png) - - - - - diff --git a/imxweb/compodoc/samples/menu.md b/imxweb/compodoc/samples/menu.md index 421a402b8..c3e7debbc 100644 --- a/imxweb/compodoc/samples/menu.md +++ b/imxweb/compodoc/samples/menu.md @@ -1,8 +1,4 @@ -# Adding a menu to the Portal - -In the previous example, we added a tile component to the dashboard to block a user's account. - -In this example, we want to add a new item to the portal main menu to achieve the same functionality. +# Adding a menu to the Web Portal The main menu (projects\qbm\src\lib\menu) is a central component, just like the dashboard. @@ -10,15 +6,25 @@ The main menu (projects\qbm\src\lib\menu) is a central component, just like the New menus and menu items are dynamically added to the main menu via a plugin system. -Before we implement the menu, we have to add a route that navigates to the (currently empty) component where you can select the identity you want to block. +## Adding a "Block Identity" menu to the menu bar + +This example is based on the following fictitious scenario:\ +There is a security breach and an administrator wants to block the account of the affected identity using a menu in the menu bar. + +### Creating a "Select Identity" component -We will name the new component SelectIdentityComponent. +At first, the `Select Identity` component has to be created in which the identity that should be blocked can be selected. -![Select Identity Component](../../assets/images/menu/2-example-folder.png) +The component consists of the following files: +- `select-identity.component.html` +- `select-identity.component.scss` +- `select-identity.component.ts` -First we add a new entry to the routing table. +### Routing to the "Select Identity" component -> Code +Before the menu is implemented, a route must be added that leads to the `Select Identity` component. + +A new entry to the routing table must be added. ``` ts const routes: Routes = [ @@ -30,9 +36,7 @@ const routes: Routes = [ ]; ``` -Now we can add the new menu with the associated route. Again, as in the previous example, this can be done in the init service (init-service.ts). In the code snippet below, only the part where the menu is added is shown, the rest is hidden. - -> Code +The new menu with the associated route can now be added. This can be done in the `init` service (init-service.ts). In the code snippet below, only the part where the menu is added is shown. ``` ts : @@ -74,14 +78,12 @@ export class InitService { } ``` -You can add menus and menu items via the menu service (projects\qbm\src\lib\menu). The structure of the menu and the menu items is defined by the menu-item.interface.ts file. The most important properties are "id" and "title". If you add a menu item, the "route" property specifies the route of the component to be displayed. - -Here is an extract of the file. +Menus and menu items can be added via the `menu` service (projects\qbm\src\lib\menu). The structure of the menu and the menu items is defined by the `menu-item.interface.ts` file. The most important properties are `id` and `title`. If a menu item is added, the `route` property specifies the route of the component to be displayed. -> Code +Extract of the file: ``` ts -import { ProjectConfig } from 'imx-api-qbm'; +import { ProjectConfig } from '@imx-modules/imx-api-qbm'; import { NavigationCommandsMenuItem } from './navigation-commands-menu-item.interface'; /** Represents a single menu item. */ @@ -90,7 +92,7 @@ export interface MenuItem { readonly id?: string; /** Display name. */ - readonly title: string; + readonly title?: string; /** Returns a descriptive text, intended for tooltips. */ readonly description?: string; diff --git a/imxweb/compodoc/samples/tiles.md b/imxweb/compodoc/samples/tiles.md index a63df6f71..ac287402a 100644 --- a/imxweb/compodoc/samples/tiles.md +++ b/imxweb/compodoc/samples/tiles.md @@ -1,49 +1,47 @@ # Adding a tile component to the dashboard -The IMX Portal landing page consists of the IMX Dashboard component, which can be found in the QER library (projects\qer\src\lib\wport\start). +The landing page of the Web Portal consists of the `IMX Dashboard` component, which can be found in the QER library (projects\qer\src\lib\wport\start). -It is composed of 3 sections with different tiles. +It consists of three sections with different tiles. ![Dashboard](../../assets/images/dashboard/1-dashboard.png) - -Tiles can be added dynamically to the dashboard. The following example gives an overview of the different types of tiles and demonstrates how to add a new element - the blue bordered tile - to the dashboard. +Tiles can be added dynamically to the dashboard. In the following example you can get an overview of the different types of tiles and learn how to add a new element (the `Block Identity` tile) to the dashboard. ## Dashboard tiles -The Tiles modules (projects\qbm\src\lib\tile) and (projects\qer\src\lib\tiles) offer different base components : - -- TileComponent (QBM) -- BadgeTileComponent (QER) -- IconTileComponent (QER) -- NotificationTileComponent (QER) - +The `Tiles` modules (projects\qbm\src\lib\tile and projects\qer\src\lib\tiles) offer different base components: -These components are variations of the same concept. In the further course we will implement a new tile based on the IconTileComponent. +- [`TileComponent`](../../components/TileComponent.html) (QBM) +- `BadgeTileComponent` (QER) +- `IconTileComponent` (QER) +- `NotificationTileComponent`(QER) +These components are variations of the same concept. -## Implementing the "Block Identity" Tile +The new tile that is added in this example is based on the `IconTileComponent`. -What is the fictitious but realistic scenario we will implement? -There is a security breach and an administrator wants to block the account of the affected identity. The implementation of this scenario will span several examples. Here we will first create the tile that can trigger that process. +## Implementing a "Block Identity" tile -### Creating the "Block Identity" Component +This example is based on the following fictitious scenario:\ +There is a security breach and an administrator wants to block the account of the affected identity using a tile on the dashboard. The implementation of this scenario consists of several examples. -First we need to create the "Block Identity" component. We assume that the reader has a basic knowledge of the Angular framework and knows how to create components, services, etc. +![BlockTile](../../assets/images/dashboard/2-dashboard.png) -The component consists of 3 files, but we will not pay further attention to the stylesheet. -![Block Identity Component](../../assets/images/dashboard/2-block-identity-component.png) +### Creating the "Block Identity" component -### The anatomy of the "Block Identity" component +At first, the `Block Identity` component has to be created. -Basically, the component consists of 2 parts, a Typescript file and the corresponding HTML template. +The component consists of the following files: +- `block-identity.component.html` +- `block-identity.component.scss` +- `block-identity.component.ts` +The main parts of the component are a Typescript file and the corresponding HTML template. -The HTML template is based on the previously mentioned IconTileComponent component. - -> Code +The HTML template is based on the previously mentioned `IconTileComponent` component. ``` html @@ -57,15 +55,12 @@ The HTML template is based on the previously mentioned IconTileComponent compone ``` -The IconTileComponent expects some input fields like "caption", "image" or "subtitle". Which tiles components expect which inputs can be found in the Tiles Module. - -> NOTE +The `IconTileComponent` expects some input fields like `caption`, `image` or `subtitle`. You can find out which tile components expect which inputs in the `Tiles` module. -> IMX components and applications are based on the One Identity Elemental UI framework, which in turn extends Angular Material. The "eui-icon" tag is such an Elemental UI component (https://elemental.dev.oneidentity.com/) +NOTE: IMX components and applications are based on the One Identity Elemental UI framework, which extends Angular Material. The `eui-icon` tag is such an Elemental UI component (https://elemental.dev.oneidentity.com/). -The corresponding *.ts component is not very exciting. On the other hand it sets the "Description" property/input used in the template and implements the (dummy) "block()" method. +The corresponding `*.ts` component sets the `Description` property/input used in the template and implements the "block()" method. -> Code ``` ts import { Component } from '@angular/core'; @@ -86,16 +81,12 @@ export class BlockIdentityComponent { } ``` -That's all we need at this time for the "Block Identity" component. - -## Wiring it up -The next step is to include the component into the dashboard. -To do this, we must make it available to the web application, in this case the portal. -This is done in the init service of the corresponding library (don't worry, there will be more samples on the topic). +### Integrating the "Block Identity" component -Here is the relevant section of the service. +To include the component into the dashboard, it must be made available to the web application (in this case the Web Portal). +This is done in the `init` service of the corresponding library. -> Code +The relevant section of the service: ``` ts @Injectable({ providedIn: 'root' }) @@ -110,10 +101,4 @@ export class InitService { The final result looks like this. - ![block-identity.component.ts](../../assets/images/dashboard/5-block-identity-button.png) - - - - - diff --git a/imxweb/custom-theme/custom-theme.scss b/imxweb/custom-theme/custom-theme.scss index 3b4abeec5..f81b97d79 100644 --- a/imxweb/custom-theme/custom-theme.scss +++ b/imxweb/custom-theme/custom-theme.scss @@ -3,7 +3,7 @@ $theme_font_family: 'Source Sans Pro, "Helvetica Neue", sans-serif' !default; @use 'sass:math'; @use '@angular/material' as mat; @use '@elemental-ui/core/src/styles/theming/theme' as theme; -@use '../shared/scss/theme' as imx-theme; +@use '../shared/scss/base/theme' as imx-theme; @import '@elemental-ui/core/src/styles/functions/to_number'; @@ -19,28 +19,28 @@ $theme_font_family: 'Source Sans Pro, "Helvetica Neue", sans-serif' !default; @import '@elemental-ui/core/src/styles/clickables'; @import '@elemental-ui/core/src/styles/common'; -$custom-typography: mat.define-typography-config( +$custom-typography: mat.m2-define-typography-config( $font-family: $theme_font_family, - $button: mat.define-typography-level(14px, 14px, 400), + $button: mat.m2-define-typography-level(14px, 14px, 400), ); -@include mat.core($custom-typography); +@include mat.core(); // Define the custom theme. -$primary: mat.define-palette($gunmetal-palette); -$accent: mat.define-palette($corbin-orange-palette); -$warn: mat.define-palette($phoenix-red-palette); +$primary: mat.m2-define-palette($corbin-orange-palette); +$accent: mat.m2-define-palette($gunmetal-palette); +$warn: mat.m2-define-palette($phoenix-red-palette); -$theme: mat.define-light-theme( +$theme: mat.m2-define-light-theme( ( color: ( primary: $primary, accent: $accent, warn: $warn, ), + typography: $custom-typography ) ); // Rename the $theme-name variable to your theme's name. (e.g.space-theme) $theme-name: 'custom-theme'; - @include theme.theme($theme-name, $theme); @include imx-theme.theme($theme-name, $theme); diff --git a/imxweb/custom-theme/package.json b/imxweb/custom-theme/package.json index e7f5dfe70..cfa30ae7b 100644 --- a/imxweb/custom-theme/package.json +++ b/imxweb/custom-theme/package.json @@ -1,8 +1,8 @@ { "name": "custom-theme", - "version": "9.2.1", + "version": "9.3.0", "private": true, "scripts": { "build": "sass custom-theme.scss:custom-theme.css --load-path=..\\node_modules" } -} \ No newline at end of file +} diff --git a/imxweb/custom-theme/readme.md b/imxweb/custom-theme/readme.md index a53c7452b..19ca69988 100644 --- a/imxweb/custom-theme/readme.md +++ b/imxweb/custom-theme/readme.md @@ -1,40 +1,44 @@ # Theming the application - -The HTML5 applications support the integration of **custom themes**. Before proceeding, we recommend that you read the [Angular Material Theming](https://material.angular.io/guide/theming) guide. +The web applications support the integration of custom themes. For more detailed information about themes, see the [Angular Material Theming Guide](https://material.angular.io/guide/theming). ## Compiling a custom theme - -- Change the variables in the file [custom-theme.scss](./custom-theme.scss) as required: - - `$font-family` - - `$primary` - - `$accent` - - `$warn` -- Rename the `$theme-name` variable to your theme's name. (e.g. `space-theme`) -- In a terminal, change to the `imxweb/custom-theme` folder and run the `npm run build` command -- Take the `custom-theme.css` file and create a .zip file. The naming convention is to use `Html_.zip` (for example `Html_space-theme.zip`). -- Copy the .zip file to the `imxweb` folder. -- Create a folder inside the `imxweb` folder with the name of your .zip file (e.g. `Html_space-theme`). -- Create a `imx-theme-config.json` file inside in this folder. Use this text as a content template, filling in the correct values for your theme. - - `Name`: a unique name and identifier of the theme - - `DisplayName`: a user friendly name for display purposes - - `Class`: the CSS class identifier which is used for theming (e.g. `eui-light-theme` in default) - - `Urls`: a list of all relevant files for this theme (also pictures, icons or other resources which are referenced if required) - -```json -{ - "Themes": [ +To compile a custom theme, perform the following steps: +1. Open the [custom-theme.scss](./custom-theme.scss) file. +1. Make your changes to the [custom-theme.scss](./custom-theme.scss) file. +1. Change the name of the `$theme-name` variable to the corresponding name of your custom theme (for example, `$theme-name: 'company-theme'`). +1. Save the file. +1. In the `imxweb/custom-theme` folder, open a command line program. +1. On the command line, run the command `npm run build`. +1. Add the `custom-theme.css` file to a new ZIP file with the name `Html_.zip`. Replace `` with the corresponding name of the theme. +1. Copy the ZIP file to the `bin\imxweb` subfolder of your IIS installation. +1. In the `bin\imxweb` folder, create a new folder with the name `Html_`. Replace `` with the corresponding name of the theme. +1. In the newly created folder, create a new JSON file with the name `imx-theme-config.json` and the following parameters: + - `Name`: Unique identifier of the theme + - `DisplayName`: Theme name displayed in the web applications + - `Class`: CSS class ID used for the theme (such as `eui-light-theme` in the default) + - `Urls`: List of all relevant files for this theme (including images, icons, or other resources that are referenced if required) \ + TIP: You can define multiple themes in this file. However, each theme still requires its own ZIP file. + ```json { - "Name": "space-theme", - "DisplayName": "Space Theme", - "Class": "space-theme", - "Urls": ["../space-theme/custom-theme.css"] + "Themes": [ + { + "Name": "CompanyTheme", + "DisplayName": "Company Theme", + "Class": "company-theme", + "Urls": [ + "../company-theme/custom-theme.css" + ] + }, + { + "Name": "DarkCompanyTheme", + "DisplayName": "Dark Company Theme", + "Class": "dark-company-theme", + "Urls": [ + "../dark-company-theme/custom-theme.css" + ] + } + ] } - ] -} -``` - -- Upload the .zip file and the `imx-theme-config.json` file with Software Loader like you would with an Angular plugin. -- Restart your API server. -- Login to Web Portal > Click on your username > Select "User Interface Settings" > Change the application's theme to your custom theme. - -_Note_: Multiple theme definition files are possible. Multiple themes can also be declared inside one theme `imx-theme-config.json` file, however every theme needs to be provided as single .zip file. + ``` +1. Import the ZIP file and the `imx-theme-config.json` file into your One Identity Manager database using the Software Loader. +1. Restart your API Server. \ No newline at end of file diff --git a/imxweb/imx-modules/elemental-ui-cadence-icon-3.1.107.tgz b/imxweb/imx-modules/elemental-ui-cadence-icon-3.1.107.tgz new file mode 100644 index 0000000000000000000000000000000000000000..41db7489e30cecf4fe3eeabb9afa3eb612004188 GIT binary patch literal 377024 zcmV)!K#;#5iwFP!00002|Lna9cpKH#H-65n+NGJ1G?rw`mSm0W*zuy(i4(_3Y-bN4 zd*Uo)PauRqNPqx|vakmT`xYpKKxkQ7mhb{?sVQaa+d@lQx>E@#rOVqEN@-(TlYj19 z$x9a6es7=u_k7P&E5DgLbMM@H=gzt3o_o%@H=9?iI%mbYHI1t`Y`L&;;)>O4HmzDS za>}anHjPX)G&eLiWg6C;cOm@m{+gPa(#d4isqQz$GnsfiUImF%x~aK2oo-52K~r-g zlTKAZ6a4@1w{^>fD=vVh|8-eS#$VOI`Tvo>n|C05bU6Y7V_Y-9vor=_Ka%tGStmY& z#dE`q=a-zEqXQPz4ES zfM#fhCdiyJk7BV_$N~#Zljh8uP<35&I{>x-z}z$DG{z_X_RKE;;64DDzv|o-o3$0@ z4ghfVe)7?c0F}1_PAgx(X2t4}X5Uu;AO`^H_3PKHa53hy0pM!@P`&=# z3oo7w$BqHu2LSvd8_!#{;;wIWeF#wgH2~(Fb5~rvnYo+!2ms3fplZ{KbJqmt{_b(W zv%dnsD4WmQa-q zp2J$W9-fA`a4uM26x;@P!Eca*tFaB|<3jMDf)n5}oQE>>!ndItmLb3^um<+PTKEe5 z1((2^Fd7utjByCTyYNd0!&X$`7}f!c0{U?poDHwR2uwg9%)=yn41a|suoOh71`aj! z!r$Oi_zd2LC*cyTfG@&AY=4YSPn;FER2KyfpYi=-ROZJRKN;2 zglSlfqi_;VMiUeu1xa`Vyf70w;8i#eegZ$nb?`pKp$0y{7T60r;Y@f6EpP;$#i`%` z8`!Z6J8=b`h0Adnd=I`0Iy?hDD1!i0!R5FHH{g0W2oJ!m@N*O)0(amdSOjV4fyFQf zegMso04IDOK7_Mi6}%2Vg?^OqOl-xmI0mP{A7K+zf(qxtMl6GyaVAcOzr($79b5@l z!7TK_ub~zip#erhJ=B38$H5=q_n5)O*o_OY90Tw>=!D5I4bFgxFbSr@44432Fa@TA z3ncgg{5R~!GoS?)z&6OY^HacY0CE8eByCep0apX$Dk!iGAQz;-`2e{}3S0<~ ztD*o>mkc_uK>B}6hPW=1_dky$jzhx(zni_07471D9AXUJCgzl zEzG7sLf3OB;BNrAxfJjzKyDrddC@*^0BMs8D1f}j77927kh_oq35{>1fYkuGZ4^l8`XUM>v~w{9656?hf+!Yp+bN&` zkh_!uNFTb40tj7QP62NK zA0OxUS5P2n?<*u(X0LgnF1&}&kPXUCM zZ=isuj`RB)DUk5z{S0tGyCoZsJ1 z0c1RRfC9)kbC3eac=8|xkn!OV1(0w15CxKc@GyljULU4FLi>+U0Lkx*6hO-P5(SX< zc$5Nuew^PwMuCL4JWc^*%z1(WNZWjw0tpZJ3I&kxlN3N``zZ?OInM8&rU1exo}mE3 zhmKId503NuXDNV;8~;TCgnvFq0c4zio&vsqoZr7d0UsXc_g|#|@?E}00fbL{odRAz z&hKBOfS(@c_urs^{^R_*M_XClo;Bg`ZLY8S{Te z0fblooB{~1{sje@Z{~hU0c4zgmjcLm`YQ?~yf;Sye>l$X^Azy=i00fZ<2i2?|3`7;HOvFu|CAo9W|6hQdNUnqdk$)^-RzTICbfXJ<%Q2?RCzfl0; z6Mv@wLL)~hfbhIt3MBRHqX5E7`ze65Nr3_gPt_@a@P=a)unmATHv!xPkVgu52q4c; z;6#8tOM$Zi@*D-40rETr(J|x&3fKjZ7b%X<3?Xl#fGj}XN&$}pJ?3Stt;2Pxn|fP5tdl6zGY7y-zKD3HX5 zDKH9lLkdIS9D?mO$0faV^6fhnjpQ1n#PE+7$ zfP97mN!?p0;Lia0Q55hUfc$6*_$@%bl>)v2kRL+`8En%3XmU10fcVb zDS*)6cnTnSOrXG70Qrd&NYZprAfd5N3iuO1zKa5W0g#_W0Y3xCPo{ti0rFEQ;1+=V zR0?143J+$0T%(}7gNBC0QqhT_&Pv-2?eoc z<(E>xqX7A36mShdemMnf2gsjAfrNHeP{6MM@+&FeM*#U%6iE8VY6>9nYbfAOfc#nt zxD+72jsgjPT2Fz57j2+`cL4HdQ@{@a^5;;%eE|856!2Am{J9iF17vXZx6y?cGv&+y z=3Um!UckP}J;7V}E`G0I5xyk!iW9_r;yb1e(_YgPX3cz``Dd2dmglU3b*^=X^)s7h z%i4ZopYOQa@ogtKtDSRQEv}8OM_eCD)zV7o5$P8)$Z0t%zpE@%9&yig_j~4gdb}&W zS#_b2E9(Qx!T+G_3YSWRqq?2k1s)Q+j$T>F&~t`X1Fadqjs z{`yZEcQ?M?lx=#Z+10$Q`Qdmr-k)eo>`!vZ9m$W9dg}IcIK43aRHiJmFmq?-n=Rg! z9W7sL`DE1SQ8$m?Jo=edf9v!y$+5w)9b?~VgSHFX4zztbZp64p#;+cqn=pMs&&1%w z4?8w@U*OnEs_1t{IzVd~;^Q z%v)!_J!i+9p1I7t?ekuo-?nhf!dn+Hi#}ZJT|8#-bKOk$?CuwqRWG}6*$d14%NH(x z?yQw(-FH^+ioL7$t@_34F{}5jDO)plUD>*s>vpfZfBjh-{(R0)Hrh5W+xX%p$EL1L zFP?Yjd9R-L$Ia_EKeM^_{8{I3KmXtbGcWkXmbNXQT)2O$ZEM@s-fcHu#9h>N(Tt%eG}-$iB0yY}cV(f8V`n_o3ZC z+tae=qrLvUoA&9xbeo<_j~tWxc}{&+HN{GwHbMRlROe5QQuU#1ek2ZSKA;=fzvR5i-DKnY;2UyJpx=^9@c<<~Sn^V;|>2G%cHkVvHy3zG}i zFG?&-B$J5+i`bVnKY4k-rhfyY{>p%cQGc*p!)O4(xX_z#k)ugPe?*Q3aA!cnmli+V zuK9HcM8`dhKTjnVEP8wKg2WBUg~{Z?YCvNg+=t z6_SeY&4#298rP|i*nTt{h(-fU&oN-(7%)A7XtcW*1kizeEdmjufqn=?>34|+I0!`h zfz9e!@{f)TM%h_#LM3FN6~+;%7o|`tsYQylXhr^n>%sbYjQXX9)Q>mrc|r(WHX7(N z>exQ)f^Vk*EY=*2n)d?-g<`#R;Id4%og^wiAUZV6WQ+H**=#hxLLhqlA%oh0YQ_MB z!yE|h3Gh=Rxq4VcCuVK(mdNNyplrKDt98Fmo~ z3r-Z=l^DcUjHkz8I@yQ~$h~V%s5nEl`xC1EwCd=;gI+rV#(5pDblDeW_&2Hx?eTf>_`KEg;_usbzs<*23_-}EUXEBQHRwfSnGs(^s}>c7&h?{{^U9W*GUI1YqL$Oa zJ{kS|9?6DK40%Es{G2{{slHYJ>hJU;m_33n>^WV>EIf=Izsnxc|6KC95sryKIfB%H zb*Kp*DHIke(5MONiliE$czP@*HQ^hDmoOUG8Hg5oj9Rou{k!~8hV&gS%e4EWs09iy zMFZJDwD6LVVw`b7y^_fLj)y9u5u`kZQhOpqXkV*CiQIBv1-gTXkyKKvLsF9ntxhX? zXm!S7f>wv?DfA!|jGilG1JTM*doQp(1_xxG>4^rm2coZ%$XAUZsWP??v_>@0pR%&q z{%mq#k^r;DJM|b99uh2mE8)k&k3fM4(M6bX9LAi8F^|znz3~htP|d{B4UDLYF(Js9 zQABT?^jmH;?zrZv?hoqp-Paa=qbQ4&l*0Iq6uw!1q+X7!xMIS+NA8uYSM25X>h~SN zm2z6{mf4SRNBswjue?Uzea(@=he}FWtSF2hFQ`9KKjDfM5&6K80~7YHs4lePiX-|L zj7&?sN!%gsfkv1KXTn9W6ZVj~i_vq89~s6ZG{bFR06osnTz*F>ol^R6V z>k>P|JFvBuxV~V-NB4R{ID2a%az?c}x#1d*IA*$l)5lgyv?>UfJFn8{P zmb>=u?p{{o6nI{6)-37XwfoNG;sp!3Q+Ms%y<};vL*RK{|L)8e*3Q!lb5^ZfG4ssE zc{b~qww+t=x&_;Ax$_TgW5%@g{jH&!n>gzCH??h8vu4BC6_4+!u2hu3jA`eczh`v! zf(465FMaF^&1W{5Ed33ho7{U2TzBA!Y!=s?Is3*NcV9nc(!O2Sa~~bpv%7oA2nVgn zvhLk`?`kn>c<0_-OO_h<`Jwj<${8E|Ue!OQb=H}SzVP&yA3VHsE2+%y@4Qw2<}G(J z&9~vW{l6bwW;UD6Ww9$BT{h`Wq z;)Ovu=+~YV_~e;m2O%<6$_m z?YgaFYNP4 z^wj^sKz@meibRmolJEy{7etAr0)VQsNPh?Pbkv* zE?$C&QNIDHePDnN4IQeD`P3i_GKPC`+|k_uO$)TUoi8{%>@njsE}&_Bhh@9oW|w6< ze$y`VF3qpM6wt;x-EQaDHiz5oXww2X&aWKp`F|+{p;&t zv&9>wI*Gf01rY*9tpKAEkNil6bc9H#M6ZcZJcw+Rm&_RDr6|{q@9P!16_4OE`gAti zxvjGgx=5Go;-Pa}XQ6O;;WB0~v!`znexR3gi+T!QdWF5@@yEZkypP0pZtLV}di}M& zzW&ejUKGZ^%5?V(%ma6U4a%UISP+VAg|ZlyRKz2NNTuq~6C;vnV#u^C5ke_}LO6z6 zavY}Pm1rD-CI(f?W9-nM zt*B-hhkmoeft%z^ZD|0k%@p5hm$(a5Xd*TqGo~AGSe}N`BF@G$ZJ0^BVniyd5{dNY zGK4iHUXeqPC8-%R?10{`B^BK->%TUh!Hp;7C1g*|p~VOToa%kO zZ8$LdATQp4A`0%P+jy<2lir$lpY*0wYW=rWll_72Ck=;djE2KCq~Ub`@P-?j~F$}2%8oxwD+DDDs|ETT!W+bnj;Wj=berq0qj zf_eCSv2ET|7qiFO-=Aec^ww0EdEU&ih#XtE+%%W zZ3J4H=Zb5^vx=H0k2{D|rJ|A9W=KlJ+prO}uoDHMa3Q*=2BZoYZyS!qkQ50Man6|0 zHDH9xVpdBkAIdTzDm}ZDR4%8alwY~Ax_qThB6Et8BNRs?$sF$23RVY>bCc|*0J$Tl z6ypt-;*jKec4c`rx__mll$;T%4=D%+Xa>Ydpb~327Du;;QDxFMRHM(Bi?24IMJs+$ z7FeST^c!8^Zdt~)N>V#c)ORaMt>5@+tnt;>%6Pw_dyGD0Q25<)TGsC-RpQ>pwdDLz zG;pjGjces}scw@Dod&6!R2n)WMLv}=TF+c;<Q> z5QpVS-%JUg)PpG3V#6nKD%zX=ZEWV>)*)d~heLH%pR2Jty`JiHim4%b>Oo!c|4L8% zf1)4$7q!AAx_V7CeB^K>5=KI%a|2^^R3oZfuWCoaL4ufx4v+`$C7NALIH)hfgR0%$ zZcnKCGRp6ksR?_#-LB$6eOWOI4^mnL%4;{}|sh#@v+c$=HRSiese;9K-!0go0nUXlz?1L>@kBx` zm2AbhR}Ekr4h?vSiHapt(XbY?Vllvz#$ZxOjeO`-(wK!M;zU3(lx59CEf#h#9=Df# zZjYNx+Zs`egh`_q4H!12YLPIR4Q1LeL6jc}H!+DhiFDn7G4f0?Ymub)xV?$Ep@bWY z8X6Ci!W^iUv<2w~%rqcX>>1iTuMwguy*6Zy@Q%^4O<28@bGn)&2e)jU;BaM}$T0f_ zrz0sj*(FPOyOeY~1ZJ0a$&y*As?7MgjnPbMT*7IxTkK|+&Fgb0p4!fIRqKQWBP+*_ zs_v|G3cSPAzhYEp)%Z%Qh39Q1d*%GZ*{c|bm9s|8F0)OxbZwZv@Z2Tk5x=#(e9Y*& z+F-lS$qNDQYX_fv?BPFtl>4SdV$4tf>Z8JoJ#XxHGXAH`lSU>RGch~soZUFLN_AAS zg2NOIlsRo2|Bfs;t+Kuquam7dN#Bh7C7YAyOroBUZ4MXi(zCM7DqC&dvJvC7rpcaw zGvccbtD;hFbBY4b2^_a|A33V?n0&%*N>^D~grPb@BSigM3u@AFvXSe5@XaER&SeW(-A>0mLQ|BLe$% zJjioD`)MBW0=%gAZhh?s?=x<`@XB}J#BWbULqv*uc#L7x?Q!yieGmLIdfwoWO*&|$nNKwsT))mR6C0h9jO0aq zIvaD~u!mYPMOc6XMF-N9BrSV;V8*2S`bjeaK1ssI%BN4RtD8K%yiAe`uQOHMg*^8K z6a=T}6hxoJ>T^k6ug`V)gI{`Kh(Pe{^Iv@MGG}!xQdQ~pD*BZ;vx}en{A%31X7%K$ z?M~$+n-cTQxCQKgp*t$J8 z?%R76_fWtYY@gX4be5M*n4te8;0lhPF+S)D_$G`$z*Ke@a<2%2Z$|YrwMmjjc|0Th zWfc{EdDo;VLxqYdT{~Sh$#hFcYU-wS;_BzR_^#;<4YTL`c+n=L>w{w=>P@m!XhK9kuL;RYFr`s^~#1Ms3gpCk$l9V9w zMz1lD2oQ)G<9U0wH_KxOi589_nfx0UV~geugt6t zCzh-Iv*k*sFSsvzj4a3h{DO^U{r8vM|D(dAZ1(?7**f%Rxqqr`N>eCa1rg#=jG<&Y zla|M#G09EQsV;H(AYHWr-Le`)o{B^%5qiPzTXlB4`OBL)Q>vnNTEnIB{q5*xoA*Nm#i1PK= z7Kmzoy}kc&#qXEdx!<6Q*HT&Y#rY*aBhy z^?5w2J*}SpK2NJ>wZ~Js?&~+MPf=S3e?$M+KAIf8eSIGE8V?N5V1Vw)n8=e=6R1^* zo)8*#cP*BoQiIcwU=7uM%utZHD^U;!%vWAjq!w^uw~|6qI-^nvqY=}YL_E#IMfx8v zVt`Da-tbO2LM4qmkI$vDf#{u7);Kc7`v&>?gYoxoz8c}`&G!$D7sqsTezibk{ClrF zLL=@>k;hVZ(ua;*d9NXr3`F0*GR%J5?+mTFe=vcuFA4}f;&`xv6O;jus2J2yokcXn z6Xrsc#*tJ)8iG*56H$ucQXJoY40JNT&1RWwKV*x4SPG$WPRvUUUib^QT-g6c`Bb~ssj;$$y8cBmDAgVU%I4h)eNiX$|Y z9M&&iazm`9CU(P;<=-0&u3x`+f#KY?_E$w*i%&eVjS_GqA|K!zn_wBpIg)ZGU>^j(eY@>qMY zx~{ssLatbvXij#vuWo6rJF|VnIeIgDo6BGBPgI0CZ!}asKhaWIzGm!%bZbb{B5k85 zjY~IF-_{kcviRNQLCGT!)df*iv_}Jd#`wrXAlgS<;L4F%7;7JyoL#5bDwbqaUvha{ z=b~|QOgG^VWSc{)>#mSpjmec05>3gfaL4pt&YD^iE%Q|Cx6a6n4R{srkn!5^gA0*$ zS;I64IKcYJSdhwu)KJ`uhQH*1C#Bbzwi1)pb=x{Rwq3WalQ4;+Ma4{(fhqavR4&=9VloqL6)zGFS2tG&yjxmo z3P01*T=(P7GSyY@QvHjUj&5DL*vFK0FB>yv`C^~ys&%P0i}V1`j;v;G8T<~H3#~8` z+R55sqIHcm5Ly<4s1_-(5{G#FWDHG$R}E<~ElP>iAk~b=&>57}3rs307wOllhLXiE z=W$b&gOPe&)2Nms7jORhq}J(9xq0NIh4m4{xAs0Ve-+D&NiLW^bME$dQzK)?33i^- zudY}apEfeymRdG*88WQdQh06r%*oTgnB9KGH9Pk{dF46hO_*fWUukZsw(yuX@fTl zd&qiCGp30V)a@Xe+axoe>2N1CE$J?NP2pn9WH&|weVd7no|#0PuH=C+)M<<*WE3Hq zOS0d^888RBVL7aWb6|_%jYagCW(-N@!E+2FDPo!onK9yti7DbHl~OaFglI-75mO_Q z7?UDmLc&-`L{9`oPXw8;bH7zwYEj6*0 z7$)=&9{%f_hhsH|V-M>ee2CTCaBhqK*tTt0p`ROj>n+UJ)aaG?g8u%tZ8)z*e{@?L zmOuR2TZe06hhq<8`G@*1in(voKfs&yu9_Nr@69)P5x1bIA2n*!OOCWI%xseW(H5My zO+R#)l+hB4mFk1P(BH>fK6^{Atf|3#Og|SZwiOe%Y}4P@-+z-7Tcdxl^>9HSQqyvM z(`Rqud$E`vtihZ054II!GF!2{CRTI!tv3%B>0nQZ4uqn8UPZ5)-(2`Ar30o@VZU2= zj?e+OKM+NC;dv!plBfHHC1l-}d5Do*H5cVj;e-B*)QLVlSyr~CY+@N!F~2CAs9spc zFYI6I^Wl%wuCi@qW%^H<-}`(Q`a0?ASO9UQ@K-}4Lj7n~!?~~xcEUAqGu#6Y!sGB? z@J;w{_#wQH3A_;hgr8wAV__VO%tV+N)5%O><}eGGOPI^a9v4z9#Ht};*+;79ART`k zaXU(9;t4Mad(^n0GHk>FkHJXMW6)V-BSA#NiJ}41V#%9AG_Kpw8!JWeT8#Ksc)Xdo z*HE*R5~q^sSllZLS|&O8d@QaKUX)e|yNwJ)8Js#s+@eHxEF9B@r1!c7nrXsYiC&N3 z#ITl0DkWFMAXAA0PKiYJHr|T7XgZaoUX8{p8ZYI<7*W!SLtnHK-IYimrH>o=QF(yK zRc?GY(y=UR%4`8Chb*4Pa;JG2sM#5s%2c0{Jq9EFs>sc^8v5R zm@%FbeUYaU-NlLuu?RUvibZ5n5syllyPd1JYt#-4Gt7z4P<5_W>hibR=ve9O<$~}`HE>`B&Le7Ow1@R+=!`|kx7w;iZW#- zie&g0crueFxr!_B=tM-}#lX>vglmqzC`Kmu$}cEyiq*|;A30JT;qfQafpOVcp?KN6 zE>9R0rmWn#wIkBi-LUBFSr;VQv}sGS*^u3C;vL)@lB$M1=;@HleBpBc$g;2(Jz@W1 zDG&&iVVVA*iZ-_$$2lZae3FbVm#n&-qZ|t2IFx5voi5ek%y^KoTHI*1xzJ^;Lb<{r zxm|XvvjweO5LGL0^4n#(Omel`CCTq_+89RQP-L9E#fp=VEWzyuk5W)`0K)R zu1lioeRtJlm#c6gpDr4?>4=tE?X=}9B6An1cpH{rBVr8lcz2aU zvhe(EvSbZTsd7173M1J>n^_1>sqixVV%h6tg_IVWs__DA=bbjr8xWC`S;i!qg(($? zX1BFriH|dh4p}gVO4B!+1CrhBaabMZs7W-L7~b~nmAL9TWLTbOS>DXB$XEo2RWe(gqTR-t zO%lV_Rn>+>mzforeO=9K7%nU`HYAA!o4KkzilT-0I?Sf{8VhSOAv0ecsbYwEmwC6W zHzN7?=X>v{44@!XidK$ySOtL-hFgEf(eXa+$=qe6A~;KE-FZSZB*t z4|;9ROPpm+SD7=bTC5}2q8xBC0f)TQ>6h$5=S0E6v2G`_+*FCUOiG*N3JF~m@(zY& zM2o_r-J&uN^A?x6qjpS#+05`PXSQ-8E1Fn`h-S1%Oqn7!sd35?s zmRVz13(Lr6!EQ252*1*3QWZAc)RbZnc{DLRau#7qb2BEJn!3%3-RH7!EYFH&i>Q`Y zR&gzhIMLy7x~#m3L5{JTctJ38g2*r?2Adn1G9^{VnR#T+U|XA-KIE;lYB-)y10(WE z#3Lf7*jOpdB7>r^ZKOJKU~V8h$Il^SH)e*6*W+HIlIqJvR=E6s9XFS$F7; z;;Mx0a*7<}LVYpNJuIFZsVKSwKN-?MmnbQvcp_DDmRhgaW>l9JHC8PQ_u*tu)mGv} z$#?WkUv;%li2EXM77j^Csc=Y^7f5jhe}+Gk6Vd`%oG4>8NfwEaWQ7Wnf>|OZr3JFA zNAc$*ePVzX_{GBW1}zZ%h}qEA2^uLmgXuW;`;))^uq@A)6H>8V6Y_jn*0mFwz4uc&Aqn0+lawdFI_v@BZ3hu`niYELAM+yFO8@}&tQo|ed^NTC4)S>M@gztId8S{Wqyl5m3(R1bS z$fpUVeS)9R8qg7d^!*zpoJie1)}8+>-#b-Xoxu0V z2i7%RqaV1`!%n1y5rkNNrfWvmlSvmW92&y+ir)?Jv~I(28t==~e~1%kBKCPSK}~H5 ziE6b^OAYPV~6F#22mf zXof^I6w8PjC&Q3QQZt>47c;?tZ+=1>!Gvq;Gnx9DFxHGn&u{Ku==Uu!ZjY$TWa?^* zw}tDQ=ASda$v7-eosmkNk?Mcbhmy%z5l{k>XqBo0ZIhNLHKD5N2G-_|1jodhJl_79 zvfp3r$H4ot-yik+Q7oPvRj9Npz54|_f}I{N(&>$jft?9o?FdP0BC$O+HEdS-p$qfZCr{N=)OqFFODCrY;F6M4Qc zO+OoNFG@;h>l=!U`*!{8BDcQ-Z#V8S8}JUigUVO>2E2og`1%I&h#@T8p>HtmmF!Tv z#PQ&UYGe0+^~3G_D(&D6$PP83#J!$jtR*_sD>E7yOh(PJ#VjH;U*d8^8G;D?)RQv8 zX5X;*m2m4S>efnKT8Fw*;t-e1zCu+giDJ*%m2hjs$mdy$YnEM6cp&R_h=1oB7TLi* zO_u*qGY<8-7|dvh>t;_W`hK#I3#(|g`r$8jqlm#VsgwV2V|_YZact04tbuVbqJuHC ze1>a88;YY{YbOV)&9Z-COH*RRtzZ4-!FBd&7f(R+`xb3&=h`|i3YR&UzfWE-3G9ei zYL;7K7G0hSZalQovE-^5?X9C0GngXkSgp~L!tf$ zh+7*EAyqeS;(j%xXX*cFLHo>y!e`)tda^H+VU-;qwE?k%*k{crc@3(5B#V@+KcPRNq~sb!!9zqiJ**gcq!c_8XDcZsrYO20a&;>T_d=sRq4vJ1I_xCC zC%lf*9xJ=VtTBo%B)gGfIy3y&hN&VGa~tavhy0{raS}OEhnl2@B@J)16i`Zw^q8w1 zHPvI{Q%5d8J27umXHA1+%v8h4WL zVp4l!EaVPH%VN!~bC&H=){LXBIISzZrMRF}Q59=u-f^!UOXJ3_cK7{m;Hq^6cZja~ z%hFRX6c+&w@Eo3>by~Xs|B2p87FV#!Rv#%$}}7rzxw{pN`WV6umc2)jRo-D20UfLBnvg?;-q#KAr=89KK|DjAcv1 z;4$dSB8%MR1M3esp$BBBgnF_w_u$%AskGE)*m~^HX)lDAd$$uG*B(5^yyn-mzJr5o z5SI=KFCPpG-_ZR1JN%l?W1r?{cl))%u0f7@szYf#kgyjjjrs<0a2to=8$NhdHtLNM z%ZHcVh*4{X${NX;FD`rStj(*=8$XR>BB8OXuHSpxO}p34Ts*RxWn0qc;#t+)W#Q0R ze$CA7$oHcAla;p_;`m|2(m|AiC+@rJ5923J9RG*A?!zU6;U})X z{Nm?{Bf;|*UyiQ9u+CRys$Q&0S0Tq;K56sJC6^5=)Q^7)QsJj*cx?Z|N94-82C;a;!TkZphvd z#++*|EF?RvpT128wpyW|BXGem_65!4qra9nAv^=$0+RPBZP+; zg5sDX%y!n$aenJa;mU3jJ#0TNvR1enI*k3vRIw4oSf&w;&5J5Aql%R%Hev(gz#x-p zV^E9~Q>4aWETfLYL@|}eiK-Y=PUT%ATyHtIb=?KC&Inu{ymp%9+%an}m^CwSS@4?W zmeDghYxu^g(QuR8f2{VY+P&EwUFm)M(p@{Udxu|+t{*XZ+7r_zkEkCAVC>q8%gblZ zx?tUybFI^^Ex)XM#;gn0jy>1tplS=t51g|#di zOTURAM#>aj5JnN87oas+UAJ*E*C3E z*C85SN9kxu$jQ*v6GcxWuZPQ`v9zIJZ16$eBil0TPV;j>^3Zz_`l*j%;Q?m0-ClUY>h+e9r=o%TEq1%*19B*S z3nJqYU0FNKHN57oA~I}B3yYqZAgZEQ&8X>2ETi$Uj21gFV)zbFfkUMWc%s-?%2 z;%v79Lk2%eHXsoi8;k)hh#AsyC(L%4@2o6uEMHN@tR7bxAK#v+9JiXq!{b)7l`AS5 zDoXdq$C>XAu13Uc;rIv3M)lT}Bwi3lUOrx4#a6B;Z=4xv4a*9dmMC(#)oYf^6CS&9 z>}}VL{T~7h$%ntAYPH$Cx~e`ET2QAfTBOu12&Eoh5K7gbaG&{~fwhhd`D9tL3{vl= zDNLrO5jG!vNIwv6jRch0vz0)kHGH3JwtEug#*ry(W3G*q6}FW{B4y0AWsw12Mij3H zH)s%tF0wB%7QGUvJA%R2Gie;woTPziV~R$@@~3FhD4jBrJs_9_vw7;86)V=<67cx~ zw+w`s*9O|Ct2I1nNHgJ;!`i73)rpFM$yR12R*SAF!?Q6${Vxo>b+|PW{Ja;>c5dy` zftjpz#r>sqM`V0+kpCgU*gLGW6gn(m(WkF8fo8Hy7TZhP8|gi)(GLpbD7Nc8WXn3T zkE5n*n!nFjn#7Tfj0W0zmjFY2g#m}}-C=l(5pU6$u{&WZL>4KLl>zjvii;N`Wc91T zWOUkbv*ZS5jmda%_Djx8R;RAP4DkpasyiJ+ck-$d1t7z?7sxQ41~QCmSXy&6xVcf0 ze@FwHD+$|oJ#tV#c<>SZSjU739f*${#AOE`K_pj&E9t`1E@S7u7wA&c7YugMC2Y@< zB>J&aJ>K`-Q#>(zeV8%UwUS+bk@}&;1|$wDoDT6PC%*xSg9;!;c?AC#Vv5*4&A({j z-mAV~RO|~^?OnLYKaCLTsc#qPlF`e~Ue`6r_cTfOv~N<^y0b4k^=&Tu4|5!LyI}vv zc@DXKqKz(fDjNaWQAQd<1eugpA_8Mm7eWNXZ3drU#HY`z_HFk^^m+bj#A+Wt79p4T zs6TR|>ELD~RV3oaMwobFS%kW$J>oP_He9m9ZDE(m9 zihFPF5*L6QMnVQ=!6LYT{C`C_=*nI-;CXHMHB}itQj#GNRgt?XNkB5v21$?L|6!8P z&%|(01kC4fXXtzrPp=^uGX4K(N178!Qh7%Y(HR{b;Hbl|oU_e-%w>7)@z+)mBsl zgB2C0O%dg8Ffut^5-p_-{9j&%|F_kUV(C7pWS((7+ywWL9lOa|P)d-=bZAHz$%YSF zjF?NjYG~+%a@v?-7sE0b+$JnExMA3kWm9AW8KMd$0|Zh|NI7I^=mpy|ut=2|*vL-n z_wV#;OtpWvab(z`SM2Gd`iEU{!>*7uM$LXY`Dj0Rgy`)l62RTXbCw)S{|ebiDu$6{ z4VKObC*CQYj}63d*C|wj%0?z zq1K4h>#z+qv8Yr~V?@PcaqGMJWo}x+JK^iC4TA|fv%cWX#yg} zB&cIyDy?PG;~1jT5Dmpfrlbef1nPYl8_;qj+6Emmy_vKiQVqzU`qAT7MdEzvRZDAc zRbxyN=)FqRjC&cut7g13p^+?BOiX@*J7dPQjFw5K$a1L+vDkUM1Malsry4IH7%TKi zn-BwF#!*}woQSJ2nqPdt&)%!139q3+O(5$@V#V^@qM!+6Vwd)+gcXq{Fy2B43!0oZHIr{K$aI>#{07vzZIBlD*a< zNp2tO646$fX^7X$E^C=XFf%AveY{{2tTv0uB)A2O)$T$wZ?<5$+bWuQv#H!`t9G&` zRLlHkwM=p;R#7rLd`?@`DwX-Yc5h8cZ7pxA*m2Q?i9^1%QiC? zRvK$g9nH+9pSkW5f&AfwY z&5W)cDLXipVf|LtVe^y;oJ&NLz_Efw6d2CL3k+`|>nm7f1lGhA)+VJeS;s#bVlNmVSes@6#se}z<8W>xHEK8ML6m?aC(3T89! zs<6*+I_d>eOI>Tg+eUTFlT*+VOaBw&h`ZsYXxsM3l5is zak4yH;i|Ss-6Ig~}Ig4Po2qw{lB3fCF z<*g1MZ{|4{HzJaW2ifwG0lVAjNvv&}RncIRO&FD30?V+1}!5evhxtlMk0@QSm_YeR=g zQfXI9YL(QjZgp$#&E4vDFJ9VqdtdR2jdw$W0TaM7O8}c40)apv5Fi1PFa)xZgeH@1 zo^J@rB>5)mWM(qiLzu~m?N;&6y``;-(OP1-zy)2w+!7yQt>{~xz*esE~@281TZ|M0;_Kk0w&v4{RJK1rkLsj=q{Jpa;% z?!M#Tk^ZvHx^~^2D_+>~5LJsZ;V69c-Krup(zr7kMTgqlw1kq z9Gn9LF!oCvZeJy2n^jWCtpR7Eq z)36M^RO1KsVXolQ6^@#t3?t>u+LWSNc{g}UB24E=thx$0Ifm(>OF8_yi}4&^!f!wq zz86bbBCU`D#RQmfvJf$_4pO8*9v}sm+1(c(*eUIlwpB(s)?`7nP59S~)^=wz-7|-F zrWBt~NwL+@xf49hy;M^pz!|sXn;+93Te9RXkFzspUl{ykvg^6-&LuAIyHxofVAUIM zVvfhzS;F>MHV7W|**B?qI3|QgIqz_E^qX(9=M(SHe9g}K1%I51P}gBCE~xVy7E4VM z5rdE*4a7ns*aag6wbi#@EG4-4$gNzKQF$%l#-;*~(*qlhVw}rIS~vXoDzDj42n{3b z>}KaVS(}Nu8#gcd{2n9iw>$OVg$^@!?JNC*>>9b??78Be2Od8s3UJlt{qs|OAG`^u zy_vZ;vk7gtRZIG+pW`v!0K< zVe_KpM#}NwUEA-71;--E=igI7Q?lH%w|`)M*x;(o`{$<{U$Al0ig;u!7|3sqwKvj- z2a22969h>U+hLM>7Lub_7(pAI1!xT$G&taJe_J4){0L5d1>$&$7$k58yL};|VBeY@ zTBeFCgfMOH-@QAh>u5GHS+FzJKOrhq zm`qHffmve16aLg@5qq8VS%3Tte#2lK#%$a__ky`n2^FGdF&VjWX2#Xp&8}76S z9)N_2i}7kj|D{2Agu)nN8a4=z^j{j@t=U=9A-_p_X-q~KXLr9Nfl@8jgZYtEDnl(G z*~f3;Z#8%kA!_hJ%%eRq`to83Y=~rNC7MOXARpKLm>Ur7!8lyPm#E+3b)NK2dQUpN zdZr2Yy4DqO2mvjw0JQ(2rOZACF;6t=(SIE4aaR9Hl2F>&6RTbzU9GBDONL=$V0GT4 zK#6Ms!4YwJ+o7dg@8>y+zoy13m!ry9x$tl0mCH8B(L*4=Z8f^mjKj<}Lpk|o5lx?W zaZ8c=VzaDUn(b9v+HT!XYwV}BPJ{aj_^YWDVHVX|$A!_>oIs3kF$^T!7h{kMVF)PX zNyZ!wL)YGZ>+1}*yS+SVwRa)Qyt?IYqlS%^hZLWNdJk0+t*A?Bo_rHpWZ^~XCe{8IM_#W zlI?<%M<+-_4IIcnai{SUZUPo_QeQmxG91?LpdZyW?)2O%@#;nN`h=m*Ub8jr#4p}Q z4O0uL4Okty&fBQf&=ZAo=5e>cl1t=hc-0*El7O55TE(l2JdPH*RViO%RKX8Kk{tFUtIU%OUua-E!w>x9U#o+cM6UMw}P zQnTBrU!}s^T_)zi>n=W69)r>H!Ha=y6tDYd;}XrC6|MS}^DfWb<}l2DO?ZdPvv90@ z@M8V!#Ru`VsW&_K#oD!zX1yL%(O)!s;Ufm8rcdkmip^fhWNPnF6K|q;O2oWxCOQEL zkTLNw?&t{9A_u4F2f;nJYYSbzU~cvT{Wm?#^BGVw7#PgPckM!t&=2Xqp1aUkum1)V z{qyWUWc1%;;=6Xmxptqg8GFBhXUV=4tY&Qj74ZJl1P{Dwa4GT}wx10{^qlUPJlYDq z7k%oR)g=??;)&|*li!TdH$=Y~O)yM)Ce`!IS&H5rlI(UVG`G3l0h0%e{!DGFOD3v! zeDj-sVAkTTdQvlKhB+PI4stnbgS5-mEg5RDN!t`g<@7! z;(zl(v@*q<+R#0@Y13r)hEq)H=EPWnHvMhOn0tn%yRTf}yXq?6f-AeHhq`XDSZ?Y1 z8<#a~+zM0YADz!YA9>purj-G-g+G*OEm!^uSgO8%rox?n|MJ_;wC+E4-eT+CTYIA#pQ}_aL=RNWo9Gp6%w5MO zxMTD9yggK$M2FrM>C^HycD2wn8bAZ;Q%^o}8XL){AHimOqdX-wP9WZ(Q^k0k(~n@o z`rK{K91k`wI_zphgZ(YzClz!1nuw*t1Ae#+>Ae!PrklMr1*(~r$sf|avah<_C+l8W zhF{1&^qdb*^>>{EB_!y7mSxFflaQljs!BbTc0#Xu%-ynxTHfl{Jh zt0R{-(czEFXHsga%?UQEOAVlZ=S48{)suoK3apJ6;ic++n3>yl6aDZk{X1S1 z`D$2>`|SWyTS{fW8&F+VJAlYPD40b4%u3dg~;1 zq9yoRETL&7)*>1OBY03FuE1Jaai>hYYt3Ok#!O?HAXOo4h5<(haK2H^7UkZ>@;vj&AI6`3_qGKYSz@@3*l7Qv@R{i7tEhmlzj`;V#|G{TJaO+Lq?jM?7yg-%xF&B3*9Euw0Oqi?uo-Ls4Z5Mpe1BK?*9cfRilqm^;?Q%b5`R)wQt zS{o}Z>>s~i(Qr29Q(1=P6mxN{$eB!K6QWH+OS@ctmg$<%e%=jbaB_CW#azE+dZ_=~ zH{JSyD}S*A%%Z*f=f9`vOv03GUo>3kXxC_4hhMa0c-o%eEeNH;Yp-BnD2epbud{B^ zDMp1nAHRHT+-T(8Kdk2<;Lvk-O~EJ@!Sp)VbkCJ)xm-LRw_`WZJXi>i(<1Z_e=YPg z#W#MX($(L$@y59J^{-c_jldg=Uny8(1cN?S|MH$bZx~*sX?kjWa>vuZtbVLsB|6yT z$7K!MF-i3i6+I=^NCO)LWdvFWjgcs))`QeAPZ-}s zrJ$}p!F{`mnf$A-$=I7HBN>0~aWdVtVXhy^L>{1kBail zCqMp$>i*Hgqf--ekA38`Uw{o&^9QazxNmp_fOB5EW7j3u;F$-mF&6RCwL5mbi>#-G zp6+EUF8Gn;j|3d5^!(7C!LUcMJ9#FZ#>*Xnh+o3XcMpXF$CLVC|hZ|aWE2wSM5$ZT~JM}Qu8TZ2cTO68fZ6wZ5{}1P39&FRa(dW$n z|7{=pxA61v2KFm8sq5eQi`i`u**2fkS{Zi#jVWXzQn#jtS8$^m8c1774bx5v4$*)Vi8$Xn(uUK&8IYG45``1ieZ$S zmvuRB6Rx676@$Uz)U+|tn(UUW6HzY0R*2YIc>=~Sn?SpbIb3V*>yw7+-o(UZ ze7V^uo|Idqv6|&a>kXZ{Y(gI<6SAAfCh7`)6ZEyUCQo4&%(`|APnisM^*Trr17t9k zM#@RUfGP~JP0!8_ZJB9nOIAWrjE2S;eRQQ~%8}l%K|S+2D@jAm_zt$k6e>lHQWMl- z?Dv!BJ1`>&;_`&^E~U?3Hz&ogM;Cvd<830kQncAb{R=6Z_(zdGeeM$e+y!&L$DU$C z>zQ9BSoA)N!(o97ERGcxNA-wuP z3Db2usG%wF4pu*m(r;tx&tX%aen%I3GiS2Mmnel=NW93kuyVs%PBY*(xX_GrP$;U! z5{YV^JMJYfTMoNsag=%(*gn?+x6fl{9>I zk&TNM4NJ0+S-EbJ{#~C#l)!7TtSIyqOKXyXDs?1CJNiG}e8VgK0|R}p+;H-~3s + + + (search)="onSearch($event)" + > - - - - - + + + - + diff --git a/imxweb/projects/aad/src/lib/azure-ad/aad-group/aad-group-denied-plans.component.ts b/imxweb/projects/aad/src/lib/azure-ad/aad-group/aad-group-denied-plans.component.ts index 5eadf67ac..2a03d624b 100644 --- a/imxweb/projects/aad/src/lib/azure-ad/aad-group/aad-group-denied-plans.component.ts +++ b/imxweb/projects/aad/src/lib/azure-ad/aad-group/aad-group-denied-plans.component.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -26,25 +26,24 @@ import { Component, OnInit, ViewChild } from '@angular/core'; -import { PortalTargetsystemAadgroupDeniedserviceplans } from 'imx-api-aad'; -import { CollectionLoadParameters, DisplayColumns, EntitySchema, IClientProperty } from 'imx-qbm-dbts'; +import { PortalTargetsystemAadgroupDeniedserviceplans } from '@imx-modules/imx-api-aad'; +import { CollectionLoadParameters, DisplayColumns, EntitySchema, IClientProperty } from '@imx-modules/imx-qbm-dbts'; import { ClassloggerService, DataSourceToolbarFilter, DataSourceToolbarSettings, DataTableComponent, DynamicTabDataProviderDirective, - SettingsService + SettingsService, } from 'qbm'; import { AzureAdService } from '../azure-ad.service'; @Component({ selector: 'imx-aad-group-denied-plans', templateUrl: './aad-group-denied-plans.component.html', - styleUrls: ['../azure-ad-common.scss'] + styleUrls: ['../azure-ad-common.scss'], }) export class AadGroupDeniedPlansComponent implements OnInit { - @ViewChild('dataTable', { static: false }) public dataTable: DataTableComponent; public dstSettings: DataSourceToolbarSettings; public navigationState: CollectionLoadParameters; @@ -53,13 +52,13 @@ export class AadGroupDeniedPlansComponent implements OnInit { public readonly DisplayColumns = DisplayColumns; private displayedColumns: IClientProperty[] = []; - private referrer: { objecttable: string; objectuid: string; }; + private referrer: { objecttable: string; objectuid: string }; constructor( private readonly logger: ClassloggerService, private readonly aadService: AzureAdService, settings: SettingsService, - dataProvider: DynamicTabDataProviderDirective + dataProvider: DynamicTabDataProviderDirective, ) { this.navigationState = { PageSize: settings.DefaultPageSize, StartIndex: 0 }; this.entitySchemaAadGroupDeniedPlan = this.aadService.aadGroupDeniedPlansSchema; @@ -68,8 +67,8 @@ export class AadGroupDeniedPlansComponent implements OnInit { public async ngOnInit(): Promise { this.displayedColumns = [ - this.entitySchemaAadGroupDeniedPlan.Columns.UID_AADDeniedServicePlan, - this.entitySchemaAadGroupDeniedPlan.Columns.XOrigin + this.entitySchemaAadGroupDeniedPlan.Columns?.UID_AADDeniedServicePlan, + this.entitySchemaAadGroupDeniedPlan.Columns?.XOrigin, ]; await this.navigate(); } @@ -89,7 +88,6 @@ export class AadGroupDeniedPlansComponent implements OnInit { } private async navigate(): Promise { - this.aadService.handleOpenLoader(); try { const data = await this.aadService.getAadGroupDeniedPlans(this.referrer.objectuid, this.navigationState); @@ -100,10 +98,9 @@ export class AadGroupDeniedPlansComponent implements OnInit { navigationState: this.navigationState, filters: this.filterOptions, }; - this.logger.debug(this, `Head at ${data.Data.length + this.navigationState.StartIndex} of ${data.totalCount} item(s)`); + this.logger.debug(this, `Head at ${data.Data.length + (this.navigationState.StartIndex ?? 0)} of ${data.totalCount} item(s)`); } finally { this.aadService.handleCloseLoader(); } } - } diff --git a/imxweb/projects/aad/src/lib/azure-ad/aad-group/aad-group-subscriptions.component.html b/imxweb/projects/aad/src/lib/azure-ad/aad-group/aad-group-subscriptions.component.html index 20dd930be..b62e48724 100644 --- a/imxweb/projects/aad/src/lib/azure-ad/aad-group/aad-group-subscriptions.component.html +++ b/imxweb/projects/aad/src/lib/azure-ad/aad-group/aad-group-subscriptions.component.html @@ -1,23 +1,30 @@
-

#LDS#Heading Azure Active Directory Subscriptions

- - #LDS#Heading Azure Active Directory Subscriptions + + + (search)="onSearch($event)" + > - - - - - + + + -
diff --git a/imxweb/projects/aad/src/lib/azure-ad/aad-group/aad-group-subscriptions.component.ts b/imxweb/projects/aad/src/lib/azure-ad/aad-group/aad-group-subscriptions.component.ts index 01b5fe5f9..c742496c1 100644 --- a/imxweb/projects/aad/src/lib/azure-ad/aad-group/aad-group-subscriptions.component.ts +++ b/imxweb/projects/aad/src/lib/azure-ad/aad-group/aad-group-subscriptions.component.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -26,24 +26,24 @@ import { Component, OnInit, ViewChild } from '@angular/core'; -import { PortalTargetsystemAadgroupSubsku } from 'imx-api-aad'; -import { CollectionLoadParameters, DisplayColumns, EntitySchema, IClientProperty } from 'imx-qbm-dbts'; +import { PortalTargetsystemAadgroupSubsku } from '@imx-modules/imx-api-aad'; +import { CollectionLoadParameters, DisplayColumns, EntitySchema, IClientProperty } from '@imx-modules/imx-qbm-dbts'; import { ClassloggerService, DataSourceToolbarFilter, - DataSourceToolbarSettings, DataTableComponent, + DataSourceToolbarSettings, + DataTableComponent, DynamicTabDataProviderDirective, - SettingsService + SettingsService, } from 'qbm'; import { AzureAdService } from '../azure-ad.service'; @Component({ selector: 'imx-aad-group-subscriptions', templateUrl: './aad-group-subscriptions.component.html', - styleUrls: ['../azure-ad-common.scss'] + styleUrls: ['../azure-ad-common.scss'], }) export class AadGroupSubscriptionsComponent implements OnInit { - @ViewChild('dataTable', { static: false }) public dataTable: DataTableComponent; public dstSettings: DataSourceToolbarSettings; public navigationState: CollectionLoadParameters; @@ -52,13 +52,13 @@ export class AadGroupSubscriptionsComponent implements OnInit { public readonly DisplayColumns = DisplayColumns; private displayedColumns: IClientProperty[] = []; - private referrer: { objecttable: string; objectuid: string; }; + private referrer: { objecttable: string; objectuid: string }; constructor( private readonly logger: ClassloggerService, private readonly aadService: AzureAdService, settings: SettingsService, - dataProvider: DynamicTabDataProviderDirective + dataProvider: DynamicTabDataProviderDirective, ) { this.navigationState = { PageSize: settings.DefaultPageSize, StartIndex: 0 }; this.entitySchemaAadGroupSub = this.aadService.aadGroupSubSchema; @@ -66,10 +66,7 @@ export class AadGroupSubscriptionsComponent implements OnInit { } public async ngOnInit(): Promise { - this.displayedColumns = [ - this.entitySchemaAadGroupSub.Columns.UID_AADSubSku, - this.entitySchemaAadGroupSub.Columns.XOrigin - ]; + this.displayedColumns = [this.entitySchemaAadGroupSub.Columns.UID_AADSubSku, this.entitySchemaAadGroupSub.Columns?.XOrigin]; await this.navigate(); } @@ -87,7 +84,6 @@ export class AadGroupSubscriptionsComponent implements OnInit { await this.navigate(); } - private async navigate(): Promise { this.aadService.handleOpenLoader(); try { @@ -99,7 +95,7 @@ export class AadGroupSubscriptionsComponent implements OnInit { navigationState: this.navigationState, filters: this.filterOptions, }; - this.logger.debug(this, `Head at ${data.Data.length + this.navigationState.StartIndex} of ${data.totalCount} item(s)`); + this.logger.debug(this, `Head at ${data.Data.length + (this.navigationState.StartIndex ?? 0)} of ${data.totalCount} item(s)`); } finally { this.aadService.handleCloseLoader(); } diff --git a/imxweb/projects/aad/src/lib/azure-ad/aad-user/aad-user-create-dialog.component.html b/imxweb/projects/aad/src/lib/azure-ad/aad-user/aad-user-create-dialog.component.html index 1d5cfd097..d15fc739c 100644 --- a/imxweb/projects/aad/src/lib/azure-ad/aad-user/aad-user-create-dialog.component.html +++ b/imxweb/projects/aad/src/lib/azure-ad/aad-user/aad-user-create-dialog.component.html @@ -1,17 +1,22 @@
-
-

{{ data.title | translate }}

-
- -
+
+

{{ data.title | translate }}

+
+ +
-
+
-
diff --git a/imxweb/projects/aad/src/lib/azure-ad/aad-user/aad-user-create-dialog.component.scss b/imxweb/projects/aad/src/lib/azure-ad/aad-user/aad-user-create-dialog.component.scss deleted file mode 100644 index 3e9e3148a..000000000 --- a/imxweb/projects/aad/src/lib/azure-ad/aad-user/aad-user-create-dialog.component.scss +++ /dev/null @@ -1,8 +0,0 @@ -@import '@elemental-ui/core/src/styles/_palette.scss'; - -.aad-user-create-dialog { - - h1 { - margin-bottom: 10px; - } -} diff --git a/imxweb/projects/aad/src/lib/azure-ad/aad-user/aad-user-create-dialog.component.ts b/imxweb/projects/aad/src/lib/azure-ad/aad-user/aad-user-create-dialog.component.ts index 9e38d6723..e245f11fc 100644 --- a/imxweb/projects/aad/src/lib/azure-ad/aad-user/aad-user-create-dialog.component.ts +++ b/imxweb/projects/aad/src/lib/azure-ad/aad-user/aad-user-create-dialog.component.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -26,9 +26,9 @@ import { Component, Inject, OnInit } from '@angular/core'; import { UntypedFormArray, UntypedFormBuilder, UntypedFormGroup } from '@angular/forms'; -import { MatDialogRef, MAT_DIALOG_DATA } from '@angular/material/dialog'; +import { MAT_DIALOG_DATA, MatDialogRef } from '@angular/material/dialog'; -import { IWriteValue } from 'imx-qbm-dbts'; +import { IWriteValue } from '@imx-modules/imx-qbm-dbts'; import { BaseCdr, ColumnDependentReference } from 'qbm'; export interface AadUserCreateDialogData { @@ -39,17 +39,15 @@ export interface AadUserCreateDialogData { @Component({ selector: 'imx-aad-user-create-dialog', templateUrl: './aad-user-create-dialog.component.html', - styleUrls: ['./aad-user-create-dialog.component.scss'] }) export class AadUserCreateDialogComponent implements OnInit { - public readonly detailsFormGroup: UntypedFormGroup; public cdrList: ColumnDependentReference[] = []; constructor( formBuilder: UntypedFormBuilder, public dialogRef: MatDialogRef, - @Inject(MAT_DIALOG_DATA) public data: AadUserCreateDialogData + @Inject(MAT_DIALOG_DATA) public data: AadUserCreateDialogData, ) { this.detailsFormGroup = new UntypedFormGroup({ formArray: formBuilder.array([]) }); } @@ -67,9 +65,6 @@ export class AadUserCreateDialogComponent implements OnInit { } private setup(): void { - this.cdrList = [ - new BaseCdr(this.data.property.Column) - ]; + this.cdrList = [new BaseCdr(this.data.property.Column)]; } - } diff --git a/imxweb/projects/aad/src/lib/azure-ad/aad-user/aad-user-denied-plans.component.html b/imxweb/projects/aad/src/lib/azure-ad/aad-user/aad-user-denied-plans.component.html index 10966a22b..9e1f40f3c 100644 --- a/imxweb/projects/aad/src/lib/azure-ad/aad-user/aad-user-denied-plans.component.html +++ b/imxweb/projects/aad/src/lib/azure-ad/aad-user/aad-user-denied-plans.component.html @@ -1,37 +1,49 @@
-

#LDS#Heading Disabled Azure Active Directory Service Plans

- - #LDS#Heading Disabled Azure Active Directory Service Plans + + + [searchBoxText]="'#LDS#Search' | translate" + (navigationStateChanged)="onNavigationStateChanged($event)" + data-imx-identifier="aad-user-disabled-plans-toolbar" + (search)="onSearch($event)" + > - - - - - + + + - - +
- - -
diff --git a/imxweb/projects/aad/src/lib/azure-ad/aad-user/aad-user-denied-plans.component.ts b/imxweb/projects/aad/src/lib/azure-ad/aad-user/aad-user-denied-plans.component.ts index 24527b981..2c06a180d 100644 --- a/imxweb/projects/aad/src/lib/azure-ad/aad-user/aad-user-denied-plans.component.ts +++ b/imxweb/projects/aad/src/lib/azure-ad/aad-user/aad-user-denied-plans.component.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -27,15 +27,15 @@ import { Component, Input, OnInit, ViewChild } from '@angular/core'; import { MatDialog } from '@angular/material/dialog'; -import { PortalTargetsystemAaduserDeniedserviceplans } from 'imx-api-aad'; -import { CollectionLoadParameters, DbObjectKey, DisplayColumns, EntitySchema, IClientProperty } from 'imx-qbm-dbts'; +import { PortalTargetsystemAaduserDeniedserviceplans } from '@imx-modules/imx-api-aad'; +import { CollectionLoadParameters, DisplayColumns, EntitySchema, IClientProperty, TypedEntity } from '@imx-modules/imx-qbm-dbts'; import { ClassloggerService, DataSourceToolbarFilter, DataSourceToolbarSettings, DataTableComponent, DynamicTabDataProviderDirective, - SettingsService + SettingsService, } from 'qbm'; import { AzureAdService } from '../azure-ad.service'; import { AadUserCreateDialogComponent } from './aad-user-create-dialog.component'; @@ -43,11 +43,10 @@ import { AadUserCreateDialogComponent } from './aad-user-create-dialog.component @Component({ selector: 'imx-aad-user-denied-plans', templateUrl: './aad-user-denied-plans.component.html', - styleUrls: ['../azure-ad-common.scss'] + styleUrls: ['../azure-ad-common.scss'], }) export class AadUserDeniedPlansComponent implements OnInit { - - @Input() public referrer: { objecttable: string; objectuid: string; }; + @Input() public referrer: { objecttable: string; objectuid: string }; @ViewChild('dataTable', { static: false }) public dataTable: DataTableComponent; public dstSettings: DataSourceToolbarSettings; @@ -64,7 +63,7 @@ export class AadUserDeniedPlansComponent implements OnInit { private readonly logger: ClassloggerService, private readonly aadService: AzureAdService, settings: SettingsService, - dataProvider: DynamicTabDataProviderDirective + dataProvider: DynamicTabDataProviderDirective, ) { this.navigationState = { PageSize: settings.DefaultPageSize, StartIndex: 0 }; this.entitySchemaAadUserDeniedPlan = this.aadService.aadUserDeniedPlansSchema; @@ -73,8 +72,8 @@ export class AadUserDeniedPlansComponent implements OnInit { public async ngOnInit(): Promise { this.displayedColumns = [ - this.entitySchemaAadUserDeniedPlan.Columns.UID_AADDeniedServicePlan, - this.entitySchemaAadUserDeniedPlan.Columns.XOrigin, + this.entitySchemaAadUserDeniedPlan.Columns?.UID_AADDeniedServicePlan, + this.entitySchemaAadUserDeniedPlan.Columns?.XOrigin, ]; await this.navigate(); } @@ -93,21 +92,20 @@ export class AadUserDeniedPlansComponent implements OnInit { await this.navigate(); } - public onDeniedPlanSelected(selected: PortalTargetsystemAaduserDeniedserviceplans[]): void { + public onDeniedPlanSelected(selected: TypedEntity[]): void { this.logger.debug(this, `Selected aad user disabled plans changed`); this.logger.trace(`New aad user disabled plan selections`, selected); - this.selectedUserDeniedPlans = selected; + this.selectedUserDeniedPlans = selected as PortalTargetsystemAaduserDeniedserviceplans[]; } public async showCreateModal(): Promise { - const aadDeniedPlan: PortalTargetsystemAaduserDeniedserviceplans = - this.aadService.generateAadUserDeniedPlanEntity(this.getUserKey()); + const aadDeniedPlan: PortalTargetsystemAaduserDeniedserviceplans = this.aadService.generateAadUserDeniedPlanEntity(this.getUserKey()); const dialogRef = this.dialog.open(AadUserCreateDialogComponent, { width: '600px', data: { property: aadDeniedPlan.UID_AADDeniedServicePlan, - title: '#LDS#Heading Assign Disabled Service Plan' - } + title: '#LDS#Heading Assign Disabled Service Plan', + }, }); dialogRef.afterClosed().subscribe(async (result) => { @@ -135,7 +133,6 @@ export class AadUserDeniedPlansComponent implements OnInit { } private async navigate(): Promise { - this.aadService.handleOpenLoader(); try { const data = await this.aadService.getAadUserDeniedPlans(this.getUserKey(), this.navigationState); @@ -146,7 +143,7 @@ export class AadUserDeniedPlansComponent implements OnInit { navigationState: this.navigationState, filters: this.filterOptions, }; - this.logger.debug(this, `Head at ${data.Data.length + this.navigationState.StartIndex} of ${data.totalCount} item(s)`); + this.logger.debug(this, `Head at ${data.Data.length + (this.navigationState.StartIndex ?? 0)} of ${data.totalCount} item(s)`); } finally { this.aadService.handleCloseLoader(); } @@ -155,5 +152,4 @@ export class AadUserDeniedPlansComponent implements OnInit { private getUserKey(): string { return this.referrer.objectuid; } - } diff --git a/imxweb/projects/aad/src/lib/azure-ad/aad-user/aad-user-subscriptions.component.html b/imxweb/projects/aad/src/lib/azure-ad/aad-user/aad-user-subscriptions.component.html index 97ea40946..e82d68353 100644 --- a/imxweb/projects/aad/src/lib/azure-ad/aad-user/aad-user-subscriptions.component.html +++ b/imxweb/projects/aad/src/lib/azure-ad/aad-user/aad-user-subscriptions.component.html @@ -1,35 +1,48 @@
-

#LDS#Heading Azure Active Directory Subscriptions

- - #LDS#Heading Azure Active Directory Subscriptions + + + [searchBoxText]="'#LDS#Search' | translate" + (navigationStateChanged)="onNavigationStateChanged($event)" + data-imx-identifier="aad-user-subscriptions-toolbar" + [itemStatus]="itemStatus" + (search)="onSearch($event)" + > - - - - - + + + - - +
-
- - -
diff --git a/imxweb/projects/aad/src/lib/azure-ad/aad-user/aad-user-subscriptions.component.ts b/imxweb/projects/aad/src/lib/azure-ad/aad-user/aad-user-subscriptions.component.ts index f459468a0..9b015af99 100644 --- a/imxweb/projects/aad/src/lib/azure-ad/aad-user/aad-user-subscriptions.component.ts +++ b/imxweb/projects/aad/src/lib/azure-ad/aad-user/aad-user-subscriptions.component.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -24,18 +24,18 @@ * */ -import { Component, Input, OnInit, ViewChild } from '@angular/core'; +import { Component, OnInit, ViewChild } from '@angular/core'; import { MatDialog } from '@angular/material/dialog'; -import { PortalTargetsystemAaduserSubsku } from 'imx-api-aad'; -import { CollectionLoadParameters, DbObjectKey, DisplayColumns, EntitySchema, IClientProperty, XOrigin } from 'imx-qbm-dbts'; +import { PortalTargetsystemAaduserSubsku } from '@imx-modules/imx-api-aad'; +import { CollectionLoadParameters, DisplayColumns, EntitySchema, IClientProperty, TypedEntity, XOrigin } from '@imx-modules/imx-qbm-dbts'; import { ClassloggerService, DataSourceToolbarFilter, DataSourceToolbarSettings, DataTableComponent, DynamicTabDataProviderDirective, - SettingsService + SettingsService, } from 'qbm'; import { AzureAdService } from '../azure-ad.service'; import { AadUserCreateDialogComponent } from './aad-user-create-dialog.component'; @@ -43,10 +43,9 @@ import { AadUserCreateDialogComponent } from './aad-user-create-dialog.component @Component({ selector: 'imx-aad-user-subscriptions', templateUrl: './aad-user-subscriptions.component.html', - styleUrls: ['../azure-ad-common.scss'] + styleUrls: ['../azure-ad-common.scss'], }) export class AadUserSubscriptionsComponent implements OnInit { - @ViewChild('dataTable', { static: false }) public dataTable: DataTableComponent; public dstSettings: DataSourceToolbarSettings; @@ -58,11 +57,11 @@ export class AadUserSubscriptionsComponent implements OnInit { public readonly itemStatus = { enabled: (item: PortalTargetsystemAaduserSubsku): boolean => { return item.XOrigin.value === XOrigin.Direct; - } + }, }; private displayedColumns: IClientProperty[] = []; - private referrer: { objecttable: string; objectuid: string; }; + private referrer: { objecttable: string; objectuid: string }; constructor( private dialog: MatDialog, @@ -77,10 +76,7 @@ export class AadUserSubscriptionsComponent implements OnInit { } public async ngOnInit(): Promise { - this.displayedColumns = [ - this.entitySchemaAadUser.Columns.ObjectKeyAADSubSku, - this.entitySchemaAadUser.Columns.XOrigin - ]; + this.displayedColumns = [this.entitySchemaAadUser.Columns.ObjectKeyAADSubSku, this.entitySchemaAadUser.Columns?.XOrigin]; await this.navigate(); } @@ -98,10 +94,10 @@ export class AadUserSubscriptionsComponent implements OnInit { await this.navigate(); } - public onUserSubSelected(selected: PortalTargetsystemAaduserSubsku[]): void { + public onUserSubSelected(selected: TypedEntity[]): void { this.logger.debug(this, `Selected aad user subscriptions changed`); this.logger.trace(`New aad user subscription selections`, selected); - this.selectedUserSubs = selected; + this.selectedUserSubs = selected as PortalTargetsystemAaduserSubsku[]; } public async removeUserSubscriptions(): Promise { @@ -116,14 +112,13 @@ export class AadUserSubscriptionsComponent implements OnInit { } public async showCreateModal(): Promise { - const aadSub: PortalTargetsystemAaduserSubsku = - this.aadService.generateAadUserSubscriptionEntity(this.getUserKey()); + const aadSub: PortalTargetsystemAaduserSubsku = this.aadService.generateAadUserSubscriptionEntity(this.getUserKey()); const dialogRef = this.dialog.open(AadUserCreateDialogComponent, { width: '600px', data: { property: aadSub.ObjectKeyAADSubSku, - title: '#LDS#Heading Add Subscription' - } + title: '#LDS#Heading Add Subscription', + }, }); dialogRef.afterClosed().subscribe(async (result) => { @@ -140,7 +135,6 @@ export class AadUserSubscriptionsComponent implements OnInit { } private async navigate(): Promise { - this.aadService.handleOpenLoader(); try { const data = await this.aadService.getAadUserSubscriptions(this.getUserKey(), this.navigationState); @@ -151,7 +145,7 @@ export class AadUserSubscriptionsComponent implements OnInit { navigationState: this.navigationState, filters: this.filterOptions, }; - this.logger.debug(this, `Head at ${data.Data.length + this.navigationState.StartIndex} of ${data.totalCount} item(s)`); + this.logger.debug(this, `Head at ${data.Data.length + (this.navigationState.StartIndex ?? 0)} of ${data.totalCount} item(s)`); } finally { this.aadService.handleCloseLoader(); } @@ -160,5 +154,4 @@ export class AadUserSubscriptionsComponent implements OnInit { private getUserKey(): string { return this.referrer.objectuid; } - } diff --git a/imxweb/projects/aad/src/lib/azure-ad/azure-ad-common.scss b/imxweb/projects/aad/src/lib/azure-ad/azure-ad-common.scss index 936953d6d..1a59b654f 100644 --- a/imxweb/projects/aad/src/lib/azure-ad/azure-ad-common.scss +++ b/imxweb/projects/aad/src/lib/azure-ad/azure-ad-common.scss @@ -1,21 +1,11 @@ -@import "@elemental-ui/core/src/styles/_palette.scss"; +@import 'base/mixins'; :host { - display: flex; - flex-direction: column; - height: 100%; -} - -.imx-content-card { - display: flex; - flex-direction: column; - overflow: hidden; + @include flex-column-container($height: 100%); } .imx-content { - height: 100%; - display: flex; - flex-direction: column; + @include flex-column-container($height: 100%); flex: 1 1 auto; overflow-y: auto; margin-bottom: -16px; @@ -24,19 +14,9 @@ .imx-card { margin: 0; margin-bottom: -16px; - - .governance-sidesheet-action-buttons { - .justify-start { - eui-icon { - font-size: 14px; - margin-right: 4px; - } - } - } } @media screen and (max-width: 480px) { - .imx-button-bar { flex-direction: column; display: block; diff --git a/imxweb/projects/aad/src/lib/azure-ad/azure-ad.module.ts b/imxweb/projects/aad/src/lib/azure-ad/azure-ad.module.ts index a35ef1970..1fa9eb267 100644 --- a/imxweb/projects/aad/src/lib/azure-ad/azure-ad.module.ts +++ b/imxweb/projects/aad/src/lib/azure-ad/azure-ad.module.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -47,7 +47,7 @@ import { LicenceOverviewButtonComponent } from '../aad-extension/licence-overvie AadUserDeniedPlansComponent, AadGroupSubscriptionsComponent, AadGroupDeniedPlansComponent, - LicenceOverviewButtonComponent + LicenceOverviewButtonComponent, ], imports: [ CommonModule, @@ -61,16 +61,13 @@ import { LicenceOverviewButtonComponent } from '../aad-extension/licence-overvie DataSourceToolbarModule, DataTableModule, ], - providers: [ - AzureAdService, - AadPermissionsService - ], + providers: [AzureAdService, AadPermissionsService], exports: [ AadUserSubscriptionsComponent, AadUserDeniedPlansComponent, AadGroupSubscriptionsComponent, AadGroupDeniedPlansComponent, - LicenceOverviewButtonComponent + LicenceOverviewButtonComponent, ], }) export class AzureAdModule {} diff --git a/imxweb/projects/aad/src/lib/azure-ad/azure-ad.service.ts b/imxweb/projects/aad/src/lib/azure-ad/azure-ad.service.ts index 587706171..e8f0f9353 100644 --- a/imxweb/projects/aad/src/lib/azure-ad/azure-ad.service.ts +++ b/imxweb/projects/aad/src/lib/azure-ad/azure-ad.service.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -24,7 +24,6 @@ * */ -import { OverlayRef } from '@angular/cdk/overlay'; import { Injectable } from '@angular/core'; import { EuiLoadingService } from '@elemental-ui/core'; import { @@ -32,17 +31,18 @@ import { PortalTargetsystemAadgroupSubsku, PortalTargetsystemAaduserDeniedserviceplans, PortalTargetsystemAaduserSubsku, -} from 'imx-api-aad'; -import { CollectionLoadParameters, EntitySchema, TypedEntityCollectionData } from 'imx-qbm-dbts'; +} from '@imx-modules/imx-api-aad'; +import { CollectionLoadParameters, EntitySchema, TypedEntityCollectionData } from '@imx-modules/imx-qbm-dbts'; import { ApiService } from '../api.service'; @Injectable({ providedIn: 'root', }) export class AzureAdService { - private busyIndicator: OverlayRef; - - constructor(private readonly aadApiClient: ApiService, private readonly busyService: EuiLoadingService) { } + constructor( + private readonly aadApiClient: ApiService, + private readonly busyService: EuiLoadingService, + ) {} public get aadUserSchema(): EntitySchema { return this.aadApiClient.typedClient.PortalTargetsystemAaduserSubsku.GetSchema(); @@ -62,28 +62,28 @@ export class AzureAdService { public async getAadUserSubscriptions( uidAadUser: string, - navigationState: CollectionLoadParameters + navigationState: CollectionLoadParameters, ): Promise> { return this.aadApiClient.typedClient.PortalTargetsystemAaduserSubsku.Get(uidAadUser, navigationState); } public async getAadUserDeniedPlans( uidAadUser: string, - navigationState: CollectionLoadParameters + navigationState: CollectionLoadParameters, ): Promise> { return this.aadApiClient.typedClient.PortalTargetsystemAaduserDeniedserviceplans.Get(uidAadUser, navigationState); } public async getAadGroupDeniedPlans( uidAadGroup: string, - navigationState: CollectionLoadParameters + navigationState: CollectionLoadParameters, ): Promise> { return this.aadApiClient.typedClient.PortalTargetsystemAadgroupDeniedserviceplans.Get(uidAadGroup, navigationState); } public async getAadGroupSubscriptions( uidAadGroup: string, - navigationState: CollectionLoadParameters + navigationState: CollectionLoadParameters, ): Promise> { return this.aadApiClient.typedClient.PortalTargetsystemAadgroupSubsku.Get(uidAadGroup, navigationState); } @@ -92,37 +92,37 @@ export class AzureAdService { return this.aadApiClient.typedClient.PortalTargetsystemAaduserSubsku.createEntity({ Columns: { UID_AADUser: { - Value: uidAaduser - } - } + Value: uidAaduser, + }, + }, }); } public generateAadUserDeniedPlanEntity(uidAaduser: string): PortalTargetsystemAaduserDeniedserviceplans { return this.aadApiClient.typedClient.PortalTargetsystemAaduserDeniedserviceplans.createEntity({ Columns: { UID_AADUser: { - Value: uidAaduser - } - } + Value: uidAaduser, + }, + }, }); } public createAadUserSubscription( uidAadUser: string, - aadUserSubscription: PortalTargetsystemAaduserSubsku + aadUserSubscription: PortalTargetsystemAaduserSubsku, ): Promise> { return this.aadApiClient.typedClient.PortalTargetsystemAaduserSubsku.Post(uidAadUser, aadUserSubscription); } public createAadUserDeniedPlan( uidAadUser: string, - aadUserDeniedPlan: PortalTargetsystemAaduserDeniedserviceplans + aadUserDeniedPlan: PortalTargetsystemAaduserDeniedserviceplans, ): Promise> { return this.aadApiClient.typedClient.PortalTargetsystemAaduserDeniedserviceplans.Post(uidAadUser, aadUserDeniedPlan); } public async removeAadUserSubscriptions(uidAadUser: string, userSubscriptions: PortalTargetsystemAaduserSubsku[]): Promise { - const promises = []; + const promises: Promise[] = []; userSubscriptions.forEach((userSub) => { const key = userSub.GetEntity().GetKeys().join(); promises.push(this.aadApiClient.client.portal_targetsystem_aaduser_subsku_delete(uidAadUser, key)); @@ -131,7 +131,7 @@ export class AzureAdService { } public async removeAadUserDeniedPlans(uidAadUser: string, userDeniedPlans: PortalTargetsystemAaduserDeniedserviceplans[]): Promise { - const promises = []; + const promises: Promise[] = []; userDeniedPlans.forEach((deniedPlan) => { const deniedPlanValue = deniedPlan.UID_AADDeniedServicePlan.value; promises.push(this.aadApiClient.client.portal_targetsystem_aaduser_deniedserviceplans_delete(uidAadUser, deniedPlanValue)); @@ -140,17 +140,10 @@ export class AzureAdService { } public handleOpenLoader(): void { - if (!this.busyIndicator) { - this.busyIndicator = this.busyService.show(); - } + this.busyService.show(); } public handleCloseLoader(): void { - if (this.busyIndicator) { - setTimeout(() => { - this.busyService.hide(this.busyIndicator); - this.busyIndicator = undefined; - }); - } + this.busyService.hide(); } } diff --git a/imxweb/projects/aad/src/lib/init.service.ts b/imxweb/projects/aad/src/lib/init.service.ts index 1d9da174d..74ad0957b 100644 --- a/imxweb/projects/aad/src/lib/init.service.ts +++ b/imxweb/projects/aad/src/lib/init.service.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -28,47 +28,49 @@ import { Injectable } from '@angular/core'; import { ExtService, TabItem } from 'qbm'; import { LicenceOverviewButtonComponent } from './aad-extension/licence-overview-button/licence-overview-button.component'; -import { AadGroupSubscriptionsComponent } from './azure-ad/aad-group/aad-group-subscriptions.component'; +import { AadPermissionsService } from './admin/aad-permissions.service'; import { AadGroupDeniedPlansComponent } from './azure-ad/aad-group/aad-group-denied-plans.component'; -import { AadUserSubscriptionsComponent } from './azure-ad/aad-user/aad-user-subscriptions.component'; +import { AadGroupSubscriptionsComponent } from './azure-ad/aad-group/aad-group-subscriptions.component'; import { AadUserDeniedPlansComponent } from './azure-ad/aad-user/aad-user-denied-plans.component'; -import { AadPermissionsService } from './admin/aad-permissions.service'; +import { AadUserSubscriptionsComponent } from './azure-ad/aad-user/aad-user-subscriptions.component'; @Injectable({ providedIn: 'root' }) export class InitService { constructor( private readonly extService: ExtService, - private permission: AadPermissionsService - ) { - } + private permission: AadPermissionsService, + ) {} public onInit(): void { this.extService.register('buttonBarExtensionComponent', { instance: LicenceOverviewButtonComponent }); this.extService.register('groupSidesheet', { - instance: AadGroupSubscriptionsComponent, inputData: { + instance: AadGroupSubscriptionsComponent, + inputData: { id: 'subscriptions', label: '#LDS#Heading Azure Active Directory Subscriptions', - checkVisibility: async ref => this.isAadAccount(ref) && (this.permission.canReadInAzure()) + checkVisibility: async (ref) => this.isAadAccount(ref) && this.permission.canReadInAzure(), }, - sortOrder: 10 + sortOrder: 10, } as TabItem); this.extService.register('groupSidesheet', { - instance: AadGroupDeniedPlansComponent, inputData: { + instance: AadGroupDeniedPlansComponent, + inputData: { id: 'deniedPlans', label: '#LDS#Heading Disabled Azure Active Directory Service Plans', - checkVisibility: async ref => this.isAadAccount(ref) && (this.permission.canReadInAzure()) + checkVisibility: async (ref) => this.isAadAccount(ref) && this.permission.canReadInAzure(), }, - sortOrder: 20 + sortOrder: 20, } as TabItem); this.extService.register('accountSidesheet', { - instance: AadUserSubscriptionsComponent, inputData: { + instance: AadUserSubscriptionsComponent, + inputData: { id: 'subscriptions', label: '#LDS#Heading Azure Active Directory Subscriptions', - checkVisibility: async ref => this.isAadAccount(ref) && (this.permission.canReadInAzure()) + checkVisibility: async (ref) => this.isAadUser(ref) && this.permission.canReadInAzure(), }, - sortOrder: 10 + sortOrder: 10, } as TabItem); this.extService.register('accountSidesheet', { @@ -76,17 +78,20 @@ export class InitService { inputData: { id: 'deniedPlans', label: '#LDS#Heading Disabled Azure Active Directory Service Plans', - checkVisibility: async ref => this.isAadAccount(ref) && (this.permission.canReadInAzure()) + checkVisibility: async (ref) => this.isAadUser(ref) && this.permission.canReadInAzure(), }, - sortOrder: 20 + sortOrder: 20, } as TabItem); } - private isAadAccount(referrer: any): boolean { let isAad = false; isAad = referrer ? referrer.objecttable === 'AADGroup' : false; return isAad; } - + private isAadUser(referrer: any): boolean { + let isAad = false; + isAad = referrer ? referrer.objecttable === 'AADUser' : false; + return isAad; + } } diff --git a/imxweb/projects/aad/src/public_api.ts b/imxweb/projects/aad/src/public_api.ts index 61174781e..51abf2a8e 100644 --- a/imxweb/projects/aad/src/public_api.ts +++ b/imxweb/projects/aad/src/public_api.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -36,4 +36,4 @@ export { AadUserDeniedPlansComponent } from './lib/azure-ad/aad-user/aad-user-de export { AadGroupSubscriptionsComponent } from './lib/azure-ad/aad-group/aad-group-subscriptions.component'; export { AadGroupDeniedPlansComponent } from './lib/azure-ad/aad-group/aad-group-denied-plans.component'; export { AzureAdModule } from './lib/azure-ad/azure-ad.module'; -export { LicenceOverviewButtonComponent} from './lib/aad-extension/licence-overview-button/licence-overview-button.component' +export { LicenceOverviewButtonComponent } from './lib/aad-extension/licence-overview-button/licence-overview-button.component'; diff --git a/imxweb/projects/aad/src/test.ts b/imxweb/projects/aad/src/test.ts index f7ac7d548..159c87d7d 100644 --- a/imxweb/projects/aad/src/test.ts +++ b/imxweb/projects/aad/src/test.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -26,24 +26,14 @@ // This file is required by karma.conf.js and loads recursively all the .spec and framework files -import 'core-js/es7/reflect'; -import 'zone.js/dist/zone'; -import 'zone.js/dist/zone-testing'; +// Zone must be imported first. Be careful with prettier import organizing +import 'zone.js'; +import 'zone.js/testing'; + import { getTestBed } from '@angular/core/testing'; -import { - BrowserDynamicTestingModule, - platformBrowserDynamicTesting -} from '@angular/platform-browser-dynamic/testing'; +import { BrowserDynamicTestingModule, platformBrowserDynamicTesting } from '@angular/platform-browser-dynamic/testing'; +import 'core-js/es/reflect'; import { TestHelperModule } from 'qbm'; -declare const require: any; - // First, initialize the Angular testing environment. -getTestBed().initTestEnvironment( - [BrowserDynamicTestingModule, TestHelperModule], - platformBrowserDynamicTesting() -); -// Then we find all the tests. -const context = require.context('./', true, /\.spec\.ts$/); -// And load the modules. -context.keys().map(context); +getTestBed().initTestEnvironment([BrowserDynamicTestingModule, TestHelperModule], platformBrowserDynamicTesting()); diff --git a/imxweb/projects/aad/src/test/aad-common-test-mocks.ts b/imxweb/projects/aad/src/test/aad-common-test-mocks.ts index 80c586410..ebdd63a81 100644 --- a/imxweb/projects/aad/src/test/aad-common-test-mocks.ts +++ b/imxweb/projects/aad/src/test/aad-common-test-mocks.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -24,106 +24,104 @@ * */ -import { IEntityColumn, IEntity } from 'imx-qbm-dbts'; +import { IEntityColumn, IEntity } from '@imx-modules/imx-qbm-dbts'; import { ISessionState } from 'qbm'; import { Subject } from 'rxjs'; export class AadCommonTestData { - public static mockConfigService: any = { getConfig: () => { return Promise.resolve({ PersonConfig: { VI_MyData_WhitePages_ResultAttributes: { - Columns: ['col1', 'col2'] + Columns: ['col1', 'col2'], }, VI_PersonalData_Fields: { - Columns: ['col1', 'col2'] - } - } + Columns: ['col1', 'col2'], + }, + }, }); - } + }, }; public static mockAppConfigService: any = { Config: { Title: '', routeConfig: { - start: 'dashboard' - } + start: 'dashboard', + }, }, client: { imx_multilanguage_getcaptions_get: () => Promise.resolve({}), - imx_multilanguage_translations_get: () => Promise.resolve({}) - } + imx_multilanguage_translations_get: () => Promise.resolve({}), + }, }; public static mockAuthenticationServiceStub = { onSessionResponse: new Subject(), - update: jasmine.createSpy('update') + update: jasmine.createSpy('update'), }; public static mockSessionService: any = { TypedClient: { PortalTargetsystemUnsGroup: { - Get: () => Promise.resolve({}) + Get: () => Promise.resolve({}), }, PortalTargetsystemUnsAccount: { - Get: () => Promise.resolve({}) + Get: () => Promise.resolve({}), }, PortalPersonAll: { - Get: () => Promise.resolve({}) + Get: () => Promise.resolve({}), }, PortalAdminPerson: { - Get: () => Promise.resolve({}) + Get: () => Promise.resolve({}), }, PortalPerson: { - Get: () => Promise.resolve({Data: ['test1', 'test2']}) + Get: () => Promise.resolve({ Data: ['test1', 'test2'] }), }, - } + }, }; public static aadUserSchema: any = { Columns: { UID_AADUser: {}, XOrigin: {}, - ObjectKeyAADSubSku: {} - } + ObjectKeyAADSubSku: {}, + }, }; public static aadUserDeniedPlansSchema: any = { Columns: { UID_AADUser: {}, XOrigin: {}, - UID_AADDeniedServicePlan: {} - } + UID_AADDeniedServicePlan: {}, + }, }; public static aadGroupSubSchema: any = { Columns: { UID_AADGroup: {}, XOrigin: {}, - UID_AADSubSku: {} - } + UID_AADSubSku: {}, + }, }; public static aadGroupDeniedPlansSchema: any = { Columns: { UID_AADGroup: {}, XOrigin: {}, - UID_AADDeniedServicePlan: {} - } + UID_AADDeniedServicePlan: {}, + }, }; - public static mockAzureAdService = { aadUserSchema: AadCommonTestData.aadUserSchema, aadUserDeniedPlansSchema: AadCommonTestData.aadUserDeniedPlansSchema, aadGroupSubSchema: AadCommonTestData.aadGroupSubSchema, aadGroupDeniedPlansSchema: AadCommonTestData.aadGroupDeniedPlansSchema, - getAadUserSubscriptions: jasmine.createSpy('getAadUserSubscriptions').and.returnValue(Promise.resolve({ Data: []})), - getAadUserDeniedPlans: jasmine.createSpy('getAadUserDeniedPlans').and.returnValue(Promise.resolve({ Data: []})), - getAadGroupSubscriptions: jasmine.createSpy('getAadGroupSubscriptions').and.returnValue(Promise.resolve({ Data: []})), + getAadUserSubscriptions: jasmine.createSpy('getAadUserSubscriptions').and.returnValue(Promise.resolve({ Data: [] })), + getAadUserDeniedPlans: jasmine.createSpy('getAadUserDeniedPlans').and.returnValue(Promise.resolve({ Data: [] })), + getAadGroupSubscriptions: jasmine.createSpy('getAadGroupSubscriptions').and.returnValue(Promise.resolve({ Data: [] })), handleOpenLoader: jasmine.createSpy('handleOpenLoader'), handleCloseLoader: jasmine.createSpy('handleCloseLoader'), }; @@ -132,33 +130,30 @@ export class AadCommonTestData { ColumnName: '', GetMetadata: () => { return { - CanEdit: () => false, + CanEdit: () => false, GetDisplay: () => '', - GetMinLength: () => 0 + GetMinLength: () => 0, }; }, - GetValue: () => '' - + GetValue: () => '', } as IEntityColumn; public static mockEntityColumnWithValue = { ColumnName: '', GetMetadata: () => { return { - CanEdit: () => false, + CanEdit: () => false, GetDisplay: () => '', - GetMinLength: () => 0 + GetMinLength: () => 0, }; }, - GetValue: () => 'Test value 1' - + GetValue: () => 'Test value 1', } as IEntityColumn; public static mockEntity = { GetDisplay: () => 'Display value', GetKeys: () => ['1'], GetColumn: (name) => AadCommonTestData.mockEntityColumn, - Commit: () => Promise.resolve() + Commit: () => Promise.resolve(), } as IEntity; - } diff --git a/imxweb/projects/aad/tsconfig.lib.json b/imxweb/projects/aad/tsconfig.lib.json index b77b13c01..293b2f101 100644 --- a/imxweb/projects/aad/tsconfig.lib.json +++ b/imxweb/projects/aad/tsconfig.lib.json @@ -1,15 +1,16 @@ /* To learn more about this file see: https://angular.io/config/tsconfig. */ { "extends": "../../tsconfig.json", + "angularCompilerOptions": { + "strictTemplates": true + }, "compilerOptions": { "outDir": "../../out-tsc/lib", + "strictNullChecks": true, "declaration": true, "declarationMap": true, "inlineSources": true, "types": [] }, - "exclude": [ - "src/test.ts", - "**/*.spec.ts" - ] + "exclude": ["src/test.ts", "**/*.spec.ts"] } diff --git a/imxweb/projects/aad/tsconfig.lib.prod.json b/imxweb/projects/aad/tsconfig.lib.prod.json index 61c7592e7..fb40dbbb0 100644 --- a/imxweb/projects/aad/tsconfig.lib.prod.json +++ b/imxweb/projects/aad/tsconfig.lib.prod.json @@ -3,8 +3,5 @@ "extends": "./tsconfig.lib.json", "compilerOptions": { "declarationMap": false - }, - "angularCompilerOptions": { - "enableIvy": true } } diff --git a/imxweb/projects/aad/tsconfig.spec.json b/imxweb/projects/aad/tsconfig.spec.json index 16da33db0..6bd74e1f7 100644 --- a/imxweb/projects/aad/tsconfig.spec.json +++ b/imxweb/projects/aad/tsconfig.spec.json @@ -1,17 +1,10 @@ { "extends": "../../tsconfig.json", "compilerOptions": { + "strictNullChecks": false, "outDir": "../../out-tsc/spec", - "types": [ - "jasmine", - "node" - ] + "types": ["jasmine", "node"] }, - "files": [ - "src/test.ts" - ], - "include": [ - "**/*.spec.ts", - "**/*.d.ts" - ] + "files": ["src/test.ts"], + "include": ["**/*.spec.ts", "**/*.d.ts"] } diff --git a/imxweb/projects/aob/.compodocrc.json b/imxweb/projects/aob/.compodocrc.json index 6bac08861..7a85827e2 100644 --- a/imxweb/projects/aob/.compodocrc.json +++ b/imxweb/projects/aob/.compodocrc.json @@ -1,6 +1,6 @@ { "name": "IMX Web - AOB Library", - "output": "../../documentation/v92/aob", + "output": "../../documentation/v93/aob", "theme": "material", "assetsFolder": "../../compodoc/assets", "customLogo": "../../compodoc/assets/images/oneidentity-logo.png", diff --git a/imxweb/projects/aob/.eslintrc.json b/imxweb/projects/aob/.eslintrc.json new file mode 100644 index 000000000..5b8133bf5 --- /dev/null +++ b/imxweb/projects/aob/.eslintrc.json @@ -0,0 +1,35 @@ +{ + "extends": "../../.eslintrc.json", + "ignorePatterns": ["!**/*", "**/*.spec.ts"], + "overrides": [ + { + "files": ["*.ts"], + "parserOptions": { + "project": ["imxweb/projects/aob/tsconfig.lib.json", "imxweb/projects/aob/tsconfig.spec.json"], + "createDefaultProgram": true + }, + "rules": { + "@angular-eslint/directive-selector": [ + "error", + { + "type": "attribute", + "prefix": "imx", + "style": "camelCase" + } + ], + "@angular-eslint/component-selector": [ + "error", + { + "type": "element", + "prefix": "imx", + "style": "kebab-case" + } + ] + } + }, + { + "files": ["*.html"], + "rules": {} + } + ] +} diff --git a/imxweb/projects/aob/imx-plugin-config.json b/imxweb/projects/aob/imx-plugin-config.json index e60c4738a..d327d6ee2 100644 --- a/imxweb/projects/aob/imx-plugin-config.json +++ b/imxweb/projects/aob/imx-plugin-config.json @@ -1,8 +1,8 @@ { "qer-app-portal": [ - { - "Container": "aob", - "Name": "AobConfigModule" - } + { + "Container": "aob", + "Name": "AobConfigModule" + } ] } diff --git a/imxweb/projects/aob/karma.conf.js b/imxweb/projects/aob/karma.conf.js index 9d7592d3b..382501758 100644 --- a/imxweb/projects/aob/karma.conf.js +++ b/imxweb/projects/aob/karma.conf.js @@ -12,10 +12,10 @@ module.exports = function (config) { require('karma-jasmine-html-reporter'), require('karma-coverage-istanbul-reporter'), require('@angular-devkit/build-angular/plugins/karma'), - require('karma-junit-reporter') + require('karma-junit-reporter'), ], client: { - clearContext: false // leave Jasmine Spec Runner output visible in browser + clearContext: false, // leave Jasmine Spec Runner output visible in browser }, coverageIstanbulReporter: { dir: require('path').join(__dirname, 'results'), @@ -26,7 +26,7 @@ module.exports = function (config) { branches: 0, functions: 2, lines: 0, - } + }, }, junitReporter: { outputDir: require('path').join(__dirname, 'results'), @@ -36,18 +36,19 @@ module.exports = function (config) { colors: true, captureTimeout: 210000, browserDisconnectTolerance: 3, - browserDisconnectTimeout : 210000, - browserNoActivityTimeout : 210000, + browserDisconnectTimeout: 210000, + browserNoActivityTimeout: 210000, logLevel: config.LOG_INFO, autoWatch: true, browsers: ['Chrome'], customLaunchers: { ChromeDebug: { base: 'Chrome', - flags: [ '--remote-debugging-port=9333' ] - } + flags: ['--remote-debugging-port=9333'], + }, }, singleRun: false, - restartOnFileChange: true + failOnEmptyTestSuite: false, + restartOnFileChange: true, }); }; diff --git a/imxweb/projects/aob/ng-package.dynamic.json b/imxweb/projects/aob/ng-package.dynamic.json index c13920961..b79a60632 100644 --- a/imxweb/projects/aob/ng-package.dynamic.json +++ b/imxweb/projects/aob/ng-package.dynamic.json @@ -16,12 +16,11 @@ "@elemental-ui/core", "@ngx-translate/core", "@ngx-translate/http-loader", - "applicationinsights-js", "billboard.js" ], - "dest": "../../html/aob", + "dest": "../../html/qer-app-portal/aob", "lib": { "entryFile": "src/public-api.ts", - "styleIncludePaths": ["../../shared/assets"] + "styleIncludePaths": ["../../shared/scss"] } } diff --git a/imxweb/projects/aob/ng-package.json b/imxweb/projects/aob/ng-package.json index b01d50055..e86e49790 100644 --- a/imxweb/projects/aob/ng-package.json +++ b/imxweb/projects/aob/ng-package.json @@ -3,6 +3,6 @@ "dest": "../../dist/aob", "lib": { "entryFile": "src/public-api.ts", - "styleIncludePaths": ["../../shared/assets"] + "styleIncludePaths": ["../../shared/scss"] } } diff --git a/imxweb/projects/aob/package.json b/imxweb/projects/aob/package.json index 5c8ce28bf..fec28616d 100644 --- a/imxweb/projects/aob/package.json +++ b/imxweb/projects/aob/package.json @@ -1,9 +1,8 @@ { "name": "aob", - "version": "9.2.1", + "version": "9.3.0", "private": true, "bundledDependencies": [ "imx-api-aob" ] } - diff --git a/imxweb/projects/aob/project.json b/imxweb/projects/aob/project.json new file mode 100644 index 000000000..0649ede03 --- /dev/null +++ b/imxweb/projects/aob/project.json @@ -0,0 +1,64 @@ +{ + "$schema": "../../node_modules/nx/schemas/project-schema.json", + "name": "aob", + "sourceRoot": "projects/aob/src", + "implicitDependencies": ["qer"], + "projectType": "library", + "prefix": "imx", + "generators": { + "@schematics/angular:component": { + "style": "scss" + } + }, + "targets": { + "build": { + "executor": "@angular-devkit/build-angular:ng-packagr", + "options": { + "tsConfig": "projects/aob/tsconfig.lib.json", + "project": "projects/aob/ng-package.json" + }, + "configurations": { + "production": { + "tsConfig": "projects/aob/tsconfig.lib.prod.json" + }, + "development": { + "tsConfig": "projects/aob/tsconfig.lib.json" + }, + "dynamic": { + "project": "projects/aob/ng-package.dynamic.json" + }, + "remote-dev": { + "tsConfig": "projects/aob/tsconfig.lib.json" + }, + "remote-qs": { + "tsConfig": "projects/aob/tsconfig.lib.json" + } + }, + "outputs": ["{workspaceRoot}/dist/aob"] + }, + "test": { + "executor": "@angular-devkit/build-angular:karma", + "options": { + "main": "projects/aob/src/test.ts", + "tsConfig": "projects/aob/tsconfig.spec.json", + "karmaConfig": "projects/aob/karma.conf.js", + "stylePreprocessorOptions": { + "includePaths": [ + "./shared/assets", + "./shared/scss", + "./node_modules", + "./node_modules/@elemental-ui/cadence-icon", + "./node_modules/@elemental-ui/core" + ] + } + } + }, + "lint": { + "executor": "@angular-devkit/build-angular:tslint", + "options": { + "tsConfig": ["projects/aob/tsconfig.lib.json", "projects/aob/tsconfig.spec.json"], + "exclude": ["**/node_modules/**", "**/*.spec.ts", "**/*.json"] + } + } + } +} diff --git a/imxweb/projects/aob/src/lib/accounts/accounts.module.ts b/imxweb/projects/aob/src/lib/accounts/accounts.module.ts index 5ba5e7b0f..9f8e51ed9 100644 --- a/imxweb/projects/aob/src/lib/accounts/accounts.module.ts +++ b/imxweb/projects/aob/src/lib/accounts/accounts.module.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -31,11 +31,7 @@ import { AccountsService } from './accounts.service'; @NgModule({ declarations: [], - imports: [ - CommonModule - ], - providers: [ - AccountsService - ] + imports: [CommonModule], + providers: [AccountsService], }) -export class AccountsModule { } +export class AccountsModule {} diff --git a/imxweb/projects/aob/src/lib/accounts/accounts.service.ts b/imxweb/projects/aob/src/lib/accounts/accounts.service.ts index 8574c5c9e..18b254a79 100644 --- a/imxweb/projects/aob/src/lib/accounts/accounts.service.ts +++ b/imxweb/projects/aob/src/lib/accounts/accounts.service.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -26,28 +26,28 @@ import { Injectable } from '@angular/core'; -import { ClassloggerService, ApiClientService } from 'qbm'; +import { PortalApplication, PortalApplicationusesaccount } from '@imx-modules/imx-api-aob'; import { CollectionLoadParameters, - FilterType, CompareOperator, - IForeignKeyInfo, - TypedEntityBuilder, DbObjectKey, - TypedEntity, EntityCollectionData, - ExtendedTypedEntityCollection -} from 'imx-qbm-dbts'; -import { PortalApplication, PortalApplicationusesaccount } from 'imx-api-aob'; -import { AobAccountContainer } from './aob-account-container'; + ExtendedTypedEntityCollection, + FilterType, + IForeignKeyInfo, + TypedEntity, + TypedEntityBuilder, +} from '@imx-modules/imx-qbm-dbts'; +import { ApiClientService, ClassloggerService } from 'qbm'; import { AobApiService } from '../aob-api-client.service'; +import { AobAccountContainer } from './aob-account-container'; @Injectable({ - providedIn: 'root' + providedIn: 'root', }) export class AccountsService { public get display(): string { - return this.aobClient.typedClient.PortalApplicationusesaccount.GetSchema().Display; + return this.aobClient.typedClient.PortalApplicationusesaccount.GetSchema().Display || ''; } private readonly builder = new TypedEntityBuilder(AobAccountContainer); @@ -57,25 +57,26 @@ export class AccountsService { constructor( private readonly aobClient: AobApiService, private readonly logger: ClassloggerService, - private readonly apiProvider: ApiClientService - ) { } + private readonly apiProvider: ApiClientService, + ) {} public async updateApplicationUsesAccounts( application: PortalApplication, - changeSet: { add: TypedEntity[], remove: TypedEntity[] } + changeSet: { add: TypedEntity[]; remove: TypedEntity[] }, ): Promise { const assignResult = await this.assign(application, changeSet.add); return assignResult && this.unassign(application, changeSet.remove); } public getCandidateTables(): ReadonlyArray { - return this.aobClient.typedClient.PortalApplicationusesaccountNew.createEntity() - .ObjectKeyAccount.GetMetadata().GetFkRelations(); + return this.aobClient.typedClient.PortalApplicationusesaccountNew.createEntity().ObjectKeyAccount.GetMetadata().GetFkRelations(); } public async getSelectedAccountLength(uidApplication: string): Promise { - return (await this.apiProvider.request(() => - this.aobClient.typedClient.PortalApplicationusesaccount.Get(uidApplication, { PageSize: -1 }))).totalCount; + return ( + (await this.apiProvider.request(() => this.aobClient.typedClient.PortalApplicationusesaccount.Get(uidApplication, { PageSize: -1 }))) + ?.totalCount || 0 + ); } public async getAssigned(application: string, parameters: CollectionLoadParameters = {}): Promise { @@ -84,56 +85,60 @@ export class AccountsService { this.logger.debug(this, 'getting assigned accounts...'); const appUsesAccountCollection = await this.apiProvider.request(() => - this.aobClient.typedClient.PortalApplicationusesaccount.Get(application, parameters)); + this.aobClient.typedClient.PortalApplicationusesaccount.Get(application, parameters), + ); return this.accountsWithTableInfo(appUsesAccountCollection, parameters); } - public async getFirstAndCount(uidApplication: string): Promise<{ first: TypedEntity, count: number }> { + public async getFirstAndCount(uidApplication: string): Promise<{ first: TypedEntity | undefined; count: number }> { const elements = await this.apiProvider.request(() => - this.aobClient.typedClient.PortalApplicationusesaccount.Get(uidApplication, { PageSize: 1 })); + this.aobClient.typedClient.PortalApplicationusesaccount.Get(uidApplication, { PageSize: 1 }), + ); - const accounts = await this.accountsWithTableInfo(elements, { PageSize: 1 }); + let accounts: AobAccountContainer[] = []; + if (!!elements) { + accounts = await this.accountsWithTableInfo(elements, { PageSize: 1 }); + } return { first: accounts.length === 0 ? undefined : accounts[0], - count: elements.totalCount + count: elements?.totalCount || 0, }; } - private async accountsWithTableInfo(appUsesAccountCollection: ExtendedTypedEntityCollection, - parameters: CollectionLoadParameters): Promise { - - const accountsAssigned = []; + private async accountsWithTableInfo( + appUsesAccountCollection: ExtendedTypedEntityCollection | undefined, + parameters: CollectionLoadParameters, + ): Promise { + const accountsAssigned: AobAccountContainer[] = []; const tables = this.getCandidateTables(); - if (appUsesAccountCollection && appUsesAccountCollection.Data && tables) { + if (!!appUsesAccountCollection && appUsesAccountCollection.Data && tables) { for (const appUsesAccount of appUsesAccountCollection.Data) { const tableName = DbObjectKey.FromXml(appUsesAccount.ObjectKeyAccount.value).TableName; - const table = tables.find(fkr => fkr.TableName === tableName); + const table = tables.find((fkr) => fkr.TableName === tableName); if (table) { - const accountCollection = await table.Get( - { - ...parameters, - ...{ - filter: [ - { - ColumnName: table.ColumnName, - Type: FilterType.Compare, - CompareOp: CompareOperator.Like, - Value1: `%${appUsesAccount.ObjectKeyAccount.value}%` - } - ], - search: undefined - } - } - ); - - if (accountCollection?.Entities?.length > 0) { + const accountCollection = await table.Get({ + ...parameters, + ...{ + filter: [ + { + ColumnName: table.ColumnName, + Type: FilterType.Compare, + CompareOp: CompareOperator.Like, + Value1: `%${appUsesAccount.ObjectKeyAccount.value}%`, + }, + ], + search: undefined, + }, + }); + + if (!!accountCollection?.Entities?.length) { const entity = this.builder.buildReadWriteEntity({ entitySchema: AobAccountContainer.GetEntitySchema(), - entityData: accountCollection.Entities[0] + entityData: accountCollection.Entities?.[0], }); this.appUsesAccounts[entity.GetEntity().GetKeys().join()] = appUsesAccount; accountsAssigned.push(entity); @@ -166,7 +171,7 @@ export class AccountsService { this.logger.debug(this, 'unassigning account from application...'); await this.aobClient.client.portal_applicationusesaccount_delete( application.UID_AOBApplication.value, - this.appUsesAccounts[account.GetEntity().GetKeys().join()].UID_AOBAppUsesAccount.value + this.appUsesAccounts[account.GetEntity().GetKeys().join()].UID_AOBAppUsesAccount.value, ); count++; } @@ -177,25 +182,23 @@ export class AccountsService { private async searchCandidates( table: IForeignKeyInfo, keyword: string, - parameters: CollectionLoadParameters = {} + parameters: CollectionLoadParameters = {}, ): Promise { this.logger.debug(this, 'searching accounts...'); - return table.Get( - { - ...parameters, - ...{ - filter: [ - { - ColumnName: table.ColumnName, - Type: FilterType.Compare, - CompareOp: CompareOperator.Like, - Value1: `%${keyword}%` - } - ], - search: undefined - } - } - ); + return table.Get({ + ...parameters, + ...{ + filter: [ + { + ColumnName: table.ColumnName, + Type: FilterType.Compare, + CompareOp: CompareOperator.Like, + Value1: `%${keyword}%`, + }, + ], + search: undefined, + }, + }); } } diff --git a/imxweb/projects/aob/src/lib/accounts/aob-account-container.ts b/imxweb/projects/aob/src/lib/accounts/aob-account-container.ts index d11617014..1e828dd12 100644 --- a/imxweb/projects/aob/src/lib/accounts/aob-account-container.ts +++ b/imxweb/projects/aob/src/lib/accounts/aob-account-container.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -24,19 +24,19 @@ * */ -import { TypedEntity, EntitySchema, ValType, DisplayColumns } from 'imx-qbm-dbts'; +import { TypedEntity, EntitySchema, ValType, DisplayColumns } from '@imx-modules/imx-qbm-dbts'; export class AobAccountContainer extends TypedEntity { - public static GetEntitySchema(): EntitySchema { - const columns = { - XObjectKey: { - Type: ValType.String, - ColumnName: 'XObjectKey' - } - }; + public static GetEntitySchema(): EntitySchema { + const columns = { + XObjectKey: { + Type: ValType.String, + ColumnName: 'XObjectKey', + }, + }; - columns[DisplayColumns.DISPLAY_PROPERTYNAME] = DisplayColumns.DISPLAY_PROPERTY; + columns[DisplayColumns.DISPLAY_PROPERTYNAME] = DisplayColumns.DISPLAY_PROPERTY; - return { Columns: columns }; - } + return { Columns: columns }; + } } diff --git a/imxweb/projects/aob/src/lib/aob-api-client.service.ts b/imxweb/projects/aob/src/lib/aob-api-client.service.ts index d20883d33..aae2888dc 100644 --- a/imxweb/projects/aob/src/lib/aob-api-client.service.ts +++ b/imxweb/projects/aob/src/lib/aob-api-client.service.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -25,12 +25,12 @@ */ import { Injectable } from '@angular/core'; -import { V2Client, TypedClient } from 'imx-api-aob'; -import { ApiClient } from 'imx-qbm-dbts'; +import { V2Client, TypedClient } from '@imx-modules/imx-api-aob'; +import { ApiClient } from '@imx-modules/imx-qbm-dbts'; import { AppConfigService, ClassloggerService, ImxTranslationProviderService } from 'qbm'; @Injectable({ - providedIn: 'root' + providedIn: 'root', }) export class AobApiService { private tc: TypedClient; @@ -50,7 +50,8 @@ export class AobApiService { constructor( private readonly config: AppConfigService, private readonly logger: ClassloggerService, - private readonly translationProvider: ImxTranslationProviderService) { + private readonly translationProvider: ImxTranslationProviderService, + ) { try { this.logger.debug(this, 'Initializing AOB API service'); diff --git a/imxweb/projects/aob/src/lib/aob-config.module.ts b/imxweb/projects/aob/src/lib/aob-config.module.ts index 5d56d0d0b..312fed21a 100644 --- a/imxweb/projects/aob/src/lib/aob-config.module.ts +++ b/imxweb/projects/aob/src/lib/aob-config.module.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -26,30 +26,30 @@ import { CommonModule } from '@angular/common'; import { NgModule } from '@angular/core'; -import { Routes, RouterModule } from '@angular/router'; +import { RouterModule, Routes } from '@angular/router'; import { TranslateModule } from '@ngx-translate/core'; import { EuiCoreModule, EuiMaterialModule } from '@elemental-ui/core'; -import { ClassloggerService, DocChapterService, DocDocument, HELP_CONTEXTUAL, RouteGuardService } from 'qbm'; +import { ClassloggerService, HELP_CONTEXTUAL, RouteGuardService } from 'qbm'; import { TilesModule } from 'qer'; import { AobService } from './aob.service'; -import { ApplicationsComponent } from './applications/applications.component'; -import { ApplicationNavigationComponent } from './applications/application-navigation/application-navigation.component'; import { ApplicationDetailComponent } from './applications/application-detail.component'; +import { ApplicationNavigationComponent } from './applications/application-navigation/application-navigation.component'; +import { ApplicationsComponent } from './applications/applications.component'; import { ApplicationsModule } from './applications/applications.module'; import { EntitlementsModule } from './entitlements/entitlements.module'; -import { StartPageModule } from './start-page/start-page.module'; -import { AobApplicationsGuardService } from './guards/aob-applications-guard.service'; +import { LockInfoAlertComponent } from './extensions/service-items-edit/lock-info-alert/lock-info-alert.component'; import { GlobalKpiComponent } from './global-kpi/global-kpi.component'; +import { AobApplicationsGuardService } from './guards/aob-applications-guard.service'; import { AobKpiGuardService } from './guards/aob-kpi-guard.service'; -import { LockInfoAlertComponent } from './extensions/service-items-edit/lock-info-alert/lock-info-alert.component'; +import { StartPageModule } from './start-page/start-page.module'; const routes: Routes = [ { path: 'applications/kpi', component: GlobalKpiComponent, canActivate: [RouteGuardService, AobKpiGuardService], - resolve: [RouteGuardService] + resolve: [RouteGuardService], }, { path: 'applications', @@ -62,9 +62,9 @@ const routes: Routes = [ component: ApplicationNavigationComponent, canActivate: [RouteGuardService], resolve: [RouteGuardService], - data:{ - contextId: HELP_CONTEXTUAL.Applications - } + data: { + contextId: HELP_CONTEXTUAL.Applications, + }, }, { path: 'detail', @@ -75,7 +75,7 @@ const routes: Routes = [ }, { path: ':create:id', redirectTo: 'applications', pathMatch: 'full' }, ], - } + }, ]; @NgModule({ @@ -90,34 +90,15 @@ const routes: Routes = [ TranslateModule, RouterModule.forChild(routes), ], - declarations: [ - LockInfoAlertComponent - ], + declarations: [LockInfoAlertComponent], }) export class AobConfigModule { - constructor(private readonly initializer: AobService, - private readonly docSvc: DocChapterService, - private readonly logger: ClassloggerService) { + constructor( + private readonly initializer: AobService, + private readonly logger: ClassloggerService, + ) { this.logger.info(this, '🔥 AOB loaded'); this.initializer.onInit(routes); - this.configureDocPaths(); this.logger.info(this, '▶️ AOB initialized'); } - - private configureDocPaths() { - // Web Portal for Application Governance User Guide - var appgovDoc: DocDocument = { - paths: { - "en-US": "imx/doc/OneIM_AOB_UserGuide_en-us.html5/OneIM_AOB_UserGuide.html", - "de-DE": "imx/doc/OneIM_AOB_UserGuide_de-de.html5/OneIM_AOB_UserGuide.html", - "de-CH": "imx/doc/OneIM_AOB_UserGuide_de-de.html5/OneIM_AOB_UserGuide.html", - "de-AT": "imx/doc/OneIM_AOB_UserGuide_de-de.html5/OneIM_AOB_UserGuide.html" - } - }; - - this.docSvc.chapters["applications"] = { - chapterUid: "35FE656D-A608-4B16-A55F-B758D5B72F75", - document: appgovDoc - }; - } } diff --git a/imxweb/projects/aob/src/lib/aob.service.ts b/imxweb/projects/aob/src/lib/aob.service.ts index 7b7517653..3a42520a4 100644 --- a/imxweb/projects/aob/src/lib/aob.service.ts +++ b/imxweb/projects/aob/src/lib/aob.service.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -25,22 +25,22 @@ */ import { Injectable } from '@angular/core'; -import { Router, Route } from '@angular/router'; +import { Route, Router } from '@angular/router'; import { additionalColumnsForServiceItemsKey } from 'qer'; import { ExtService, MenuItem, MenuService } from 'qbm'; +import { LockInfoAlertExtension } from './extensions/service-items-edit/lock-info-alert/lock-info-alert-extension'; import { KpiTileComponent } from './global-kpi/kpi-tile/kpi-tile.component'; import { isAobApplicationAdmin, isAobApplicationOwner } from './permissions/aob-permissions-helper'; -import { LockInfoAlertExtension } from './extensions/service-items-edit/lock-info-alert/lock-info-alert-extension'; @Injectable({ - providedIn: 'root' + providedIn: 'root', }) export class AobService { constructor( private readonly router: Router, private readonly extService: ExtService, - private readonly menuService: MenuService + private readonly menuService: MenuService, ) { this.setupMenu(); } @@ -50,11 +50,11 @@ export class AobService { this.extService.register(additionalColumnsForServiceItemsKey, { inputData: { - columnName: 'UID_AOBApplication' - } + columnName: 'UID_AOBApplication', + }, }); this.extService.register('Dashboard-MediumTiles', { - instance: KpiTileComponent + instance: KpiTileComponent, }); this.extService.register(LockInfoAlertExtension.id, new LockInfoAlertExtension()); @@ -62,7 +62,7 @@ export class AobService { private addRoutes(routes: Route[]): void { const config = this.router.config; - routes.forEach(route => { + routes.forEach((route) => { config.unshift(route); }); this.router.resetConfig(config); @@ -72,24 +72,22 @@ export class AobService { this.menuService.addMenuFactories((preProps: string[], features: string[]) => { const items: MenuItem[] = []; if (isAobApplicationAdmin(features) || isAobApplicationOwner(features)) { - items.push( - { - id: 'AOB_Data_Applications', - title: '#LDS#Applications', - navigationCommands: { commands: ['/applications', { outlets: { primary: ['navigation'], content: ['detail'] } }] }, - sorting: '40-20', - } - ); + items.push({ + id: 'AOB_Data_Applications', + title: '#LDS#Applications', + navigationCommands: { commands: ['/applications', { outlets: { primary: ['navigation'], content: ['detail'] } }] }, + sorting: '40-20', + }); } if (items.length === 0) { - return null; + return undefined; } return { id: 'ROOT_Data', title: '#LDS#Data administration', sorting: '40', - items + items, }; }); } diff --git a/imxweb/projects/aob/src/lib/application-property/application-property.component.html b/imxweb/projects/aob/src/lib/application-property/application-property.component.html index 1f80df5e8..6659c3743 100644 --- a/imxweb/projects/aob/src/lib/application-property/application-property.component.html +++ b/imxweb/projects/aob/src/lib/application-property/application-property.component.html @@ -1,5 +1,5 @@ - +
{{ display }} -
\ No newline at end of file +
diff --git a/imxweb/projects/aob/src/lib/application-property/application-property.component.scss b/imxweb/projects/aob/src/lib/application-property/application-property.component.scss index 76c11896c..449272d08 100644 --- a/imxweb/projects/aob/src/lib/application-property/application-property.component.scss +++ b/imxweb/projects/aob/src/lib/application-property/application-property.component.scss @@ -8,18 +8,6 @@ min-height: 40px; } -.imx-user-icon { - color: $black-3; - background-color: $black-c; - opacity: 0.6; - border-radius: 50%; - text-align: center; - line-height: 35px; - min-width: 35px; - min-height: 35px; - margin-right: 12px; -} - .imx-application-property { display: flex; flex-direction: column; @@ -34,21 +22,3 @@ text-overflow: ellipsis; } } - -.eui-dark-theme { - :host { - .imx-user-icon { - color: $color-gray-20; - background-color: $color-gray-80; - } - } -} - -.eui-contrast-theme { - :host { - .imx-user-icon { - color: $color-gray-10; - background-color: $color-gray-100; - } - } -} diff --git a/imxweb/projects/aob/src/lib/application-property/application-property.component.ts b/imxweb/projects/aob/src/lib/application-property/application-property.component.ts index c9dd08a25..22181708e 100644 --- a/imxweb/projects/aob/src/lib/application-property/application-property.component.ts +++ b/imxweb/projects/aob/src/lib/application-property/application-property.component.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -29,7 +29,7 @@ import { Component, Input } from '@angular/core'; @Component({ selector: 'imx-application-property', templateUrl: './application-property.component.html', - styleUrls: ['./application-property.component.scss'] + styleUrls: ['./application-property.component.scss'], }) export class ApplicationPropertyComponent { @Input() public display: string; diff --git a/imxweb/projects/aob/src/lib/application-property/application-property.module.ts b/imxweb/projects/aob/src/lib/application-property/application-property.module.ts index e86c8cebc..b212a6906 100644 --- a/imxweb/projects/aob/src/lib/application-property/application-property.module.ts +++ b/imxweb/projects/aob/src/lib/application-property/application-property.module.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -31,15 +31,8 @@ import { EuiCoreModule } from '@elemental-ui/core'; import { ApplicationPropertyComponent } from './application-property.component'; @NgModule({ - declarations: [ - ApplicationPropertyComponent - ], - exports: [ - ApplicationPropertyComponent, - ], - imports: [ - CommonModule, - EuiCoreModule - ] + declarations: [ApplicationPropertyComponent], + exports: [ApplicationPropertyComponent], + imports: [CommonModule, EuiCoreModule], }) -export class ApplicationPropertyModule { } +export class ApplicationPropertyModule {} diff --git a/imxweb/projects/aob/src/lib/applications/application-content.interface.ts b/imxweb/projects/aob/src/lib/applications/application-content.interface.ts index 13e9765cb..320a0b4cd 100644 --- a/imxweb/projects/aob/src/lib/applications/application-content.interface.ts +++ b/imxweb/projects/aob/src/lib/applications/application-content.interface.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -24,12 +24,12 @@ * */ -import { PortalApplication, PortalApplicationNew } from 'imx-api-aob'; +import { PortalApplication, PortalApplicationNew } from '@imx-modules/imx-api-aob'; import { Subject } from 'rxjs'; export interface ApplicationContent { - application: PortalApplication | PortalApplicationNew; - totalCount?: number; - keywords?: string; - loadingSubject?: Subject + application: PortalApplication | PortalApplicationNew | undefined; + totalCount?: number; + keywords?: string; + loadingSubject?: Subject; } diff --git a/imxweb/projects/aob/src/lib/applications/application-create/application-create.component.html b/imxweb/projects/aob/src/lib/applications/application-create/application-create.component.html index 653af41a9..29efc534d 100644 --- a/imxweb/projects/aob/src/lib/applications/application-create/application-create.component.html +++ b/imxweb/projects/aob/src/lib/applications/application-create/application-create.component.html @@ -2,31 +2,51 @@

#LDS#Add an icon, name and description to the application and assign a manager to it.

- + (controlCreated)="form.addControl(imageColumn.ColumnName, $event)" + > - + - + - + - + - + - - - +
diff --git a/imxweb/projects/aob/src/lib/applications/application-create/application-create.component.scss b/imxweb/projects/aob/src/lib/applications/application-create/application-create.component.scss index 93f46628c..744836116 100644 --- a/imxweb/projects/aob/src/lib/applications/application-create/application-create.component.scss +++ b/imxweb/projects/aob/src/lib/applications/application-create/application-create.component.scss @@ -1,54 +1,27 @@ -@import '@elemental-ui/core/src/styles/_palette.scss'; @import '@elemental-ui/core/src/styles/_eui_palette.scss'; +@import 'base/mixins'; :host { overflow-y: auto; - display: flex; - flex-direction: column; - height: 100%; - background-color: $asher-gray; + @include flex-column-container($height: 100%); + background-color: $color-gray-2; } .imx-content { - display: flex; - flex-direction: column; + @include flex-column-container-fill(); margin: 30px; overflow-y: auto; - flex: 1 1 auto; max-height: calc(100% - 60px); } -.imx-button-bar { - display: flex; - justify-content: flex-end; - margin-bottom: 0; - padding: 16px 32px; - border-top: 1px solid rgba(0, 0, 0, 0.12); - background-color: $white; - - button { - margin-left: 10px; - } - - .justify-start { - margin-right: auto; - } -} - .eui-dark-theme { :host { - background-color: $color-gray-80; - .imx-button-bar { - background-color: $color-gray-70; - } + background-color: $color-gray-80; } } .eui-contrast-theme { :host { - background-color: $color-gray-100; - .imx-button-bar { - background-color: $color-gray-90; - } + background-color: $color-gray-100; } } diff --git a/imxweb/projects/aob/src/lib/applications/application-create/application-create.component.ts b/imxweb/projects/aob/src/lib/applications/application-create/application-create.component.ts index dcfce96b1..a19b671d1 100644 --- a/imxweb/projects/aob/src/lib/applications/application-create/application-create.component.ts +++ b/imxweb/projects/aob/src/lib/applications/application-create/application-create.component.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -26,18 +26,18 @@ import { Component, Inject, OnDestroy } from '@angular/core'; import { UntypedFormGroup } from '@angular/forms'; -import { EuiSidesheetRef, EUI_SIDESHEET_DATA } from '@elemental-ui/core'; +import { EUI_SIDESHEET_DATA, EuiSidesheetRef } from '@elemental-ui/core'; import { Subscription } from 'rxjs'; -import { PortalApplicationNew } from 'imx-api-aob'; -import { IEntityColumn, IWriteValue, ValueStruct } from 'imx-qbm-dbts'; -import { BaseCdr, ColumnDependentReference, ConfirmationService } from 'qbm'; +import { PortalApplicationNew } from '@imx-modules/imx-api-aob'; +import { IEntityColumn, IWriteValue, ValueStruct } from '@imx-modules/imx-qbm-dbts'; import { TranslateService } from '@ngx-translate/core'; +import { BaseCdr, ColumnDependentReference, ConfirmationService } from 'qbm'; @Component({ selector: 'imx-application-create', templateUrl: './application-create.component.html', - styleUrls: ['./application-create.component.scss'] + styleUrls: ['./application-create.component.scss'], }) export class ApplicationCreateComponent implements OnDestroy { public readonly form = new UntypedFormGroup({}); @@ -53,10 +53,10 @@ export class ApplicationCreateComponent implements OnDestroy { private readonly subscriptions: Subscription[] = []; constructor( - @Inject(EUI_SIDESHEET_DATA) data: { application: PortalApplicationNew; }, + @Inject(EUI_SIDESHEET_DATA) data: { application: PortalApplicationNew }, private readonly sidesheetRef: EuiSidesheetRef, private readonly translateService: TranslateService, - confirmation: ConfirmationService + confirmation: ConfirmationService, ) { this.imageColumn = data.application.JPegPhoto.Column; @@ -65,35 +65,44 @@ export class ApplicationCreateComponent implements OnDestroy { this.description = new BaseCdr(data.application.Description.Column); - this.serviceCategory = new class { + this.serviceCategory = new (class { public get hint(): string { - return this.property.value?.length > 0 ? '' : - this.translateService.instant('#LDS#If you do not select a service category, a service category with the same name as the application is created and assigned.'); + return this.property.value?.length > 0 + ? '' + : this.translateService.instant( + '#LDS#If you do not select a service category, a service category with the same name as the application is created and assigned.', + ); } - public readonly column = this.property.Column; + public readonly column: IEntityColumn; constructor( private readonly property: IWriteValue, private readonly translateService: TranslateService, - ) {} + ) { + this.column = this.property.Column; + } public readonly isReadOnly = () => !this.property.GetMetadata().CanEdit(); - }(data.application.UID_AccProductGroup, this.translateService); + })(data.application.UID_AccProductGroup, this.translateService); this.manager = new BaseCdr(data.application.UID_PersonHead.Column); this.owner = new BaseCdr(data.application.UID_AERoleOwner.Column); - this.subscriptions.push(sidesheetRef.closeClicked().subscribe(async () => { - if ((data.application.GetEntity().GetDiffData()?.Data?.length > 0 || !this.form.pristine) && - !(await confirmation.confirmLeaveWithUnsavedChanges())) { - return; - } - - sidesheetRef.close(false); - })); + this.subscriptions.push( + sidesheetRef.closeClicked().subscribe(async () => { + if ( + (!!data.application.GetEntity().GetDiffData()?.Data?.length || !this.form.pristine) && + !(await confirmation.confirmLeaveWithUnsavedChanges()) + ) { + return; + } + + sidesheetRef.close(false); + }), + ); } public ngOnDestroy(): void { - this.subscriptions.forEach(s => s.unsubscribe()); + this.subscriptions.forEach((s) => s.unsubscribe()); } public async updateName(value: ValueStruct): Promise { diff --git a/imxweb/projects/aob/src/lib/applications/application-detail.component.html b/imxweb/projects/aob/src/lib/applications/application-detail.component.html index 1e33c4b47..b5391bde5 100644 --- a/imxweb/projects/aob/src/lib/applications/application-detail.component.html +++ b/imxweb/projects/aob/src/lib/applications/application-detail.component.html @@ -1,19 +1,26 @@
- + - +
-
{{ application.GetEntity().GetDisplay() }}
- +

{{ application.GetEntity().GetDisplay() }}

+
{{ application.Description.Column.GetDisplayValue() }}
-
- + @@ -21,7 +28,7 @@ - + @@ -43,14 +50,14 @@
-

- #LDS#Here you can get an overview of identities that have access to at least one application entitlement of this application. Additionally, you can view which application entitlements the respective identities have access to. +

+ {{ ldsIdentitiesWithAccessInfoText | translate }}

-
- +
+ {{ '#LDS#No Application Selected' | translate }} {{ '#LDS#Select an application to view its details.' | translate }} @@ -59,7 +66,14 @@ {{ (keywords ? '#LDS#No application found' : '#LDS#No applications available') | translate }} - diff --git a/imxweb/projects/aob/src/lib/applications/application-detail.component.scss b/imxweb/projects/aob/src/lib/applications/application-detail.component.scss index 244ed9bff..72b867aee 100644 --- a/imxweb/projects/aob/src/lib/applications/application-detail.component.scss +++ b/imxweb/projects/aob/src/lib/applications/application-detail.component.scss @@ -1,8 +1,7 @@ @use '@angular/material' as mat; @import '@elemental-ui/core/src/styles/_eui_palette.scss'; -@import '../../../../../shared/assets/variables.scss'; - -$imx-component-height: calc(100vh - 180px); +@import 'base/mixins'; +@import 'base/variables'; :host { display: flex; @@ -11,14 +10,6 @@ $imx-component-height: calc(100vh - 180px); height: 100%; } -:host ::ng-deep .mat-tab-body-wrapper { - .mat-tab-body-content { - overflow: hidden; - height: 100%; - display: flex; - } -} - .imx-application-details { display: flex; overflow-x: hidden; @@ -28,7 +19,7 @@ $imx-component-height: calc(100vh - 180px); display: flex; flex-direction: column; flex: 1 1 auto; - height: $imx-component-height; + height: $IMX_Application_Details_Component_Height; overflow: hidden; } @@ -67,21 +58,9 @@ $imx-component-height: calc(100vh - 180px); flex-grow: 1; } -.imx-application-details-icon { - grid-column-start: 1; - grid-column-end: 2; - grid-row-start: 1; - grid-row-end: 3; +.imx-application-details-image { width: 42px; height: 42px; - align-self: center; - object-fit: cover; -} - -@mixin textOverflowEllipsis { - overflow: hidden; - text-overflow: ellipsis; - white-space: nowrap; } .imx-application-details-title { @@ -93,7 +72,7 @@ $imx-component-height: calc(100vh - 180px); font-size: 24px; min-height: 40px; margin: 0 15px 0 10px; - @include textOverflowEllipsis; + @include text-overflow-ellipsis; display: flex; flex-direction: row; align-items: center; @@ -106,7 +85,7 @@ $imx-component-height: calc(100vh - 180px); grid-row-end: 2; font-size: 14px; margin: 0 15px 0 10px; - @include textOverflowEllipsis; + @include text-overflow-ellipsis; } .imx-info { @@ -115,41 +94,19 @@ $imx-component-height: calc(100vh - 180px); margin-right: 50px; } -.mat-tab-group { - overflow: hidden; - height: 100%; -} - imx-application-hyperview { overflow: auto; flex-grow: 1; padding: 1em; } -// TODO: .mat-tab-body-wrapper does not pass information of the height to its child nodes, -// because it does not stretch to the height of its parent container (which is a mat-tab-group). -// Right now the only fix is to use the ng-deep selector. -::ng-deep .mat-tab-body-wrapper { - height: inherit; - - .mat-tab-body-content { - overflow: visible; - } -} :host { - ::ng-deep .mat-tab-body-content { - background-color: rgba($color-gray-10, 0.1); - } + .imx-application-content { background-color: $color-gray-0; } - .imx-application-content-no-app { - > .eui-icon { - color: $color-gray-30; - } - } .imx-application-details-subtitle { color: $color-gray-70; } @@ -157,28 +114,18 @@ imx-application-hyperview { .eui-dark-theme { :host { - ::ng-deep .mat-tab-labels { - - background-color:$color-gray-70; - } - .imx-application-content { - background-color:$color-gray-70; - } - ::ng-deep .mat-tab-body-content { - background-color:rgba($color-gray-70, 0.55); + .imx-application-content { + background-color: $color-gray-70; } - .imx-application-content-no-app { .imx-application-content-no-app-text, .imx-application-content-no-app-description { color: $color-gray-20; } - > .eui-icon { - color: $color-gray-60; - } } + .imx-application-details-subtitle { color: $color-gray-50; } @@ -187,21 +134,10 @@ imx-application-hyperview { .eui-contrast-theme { :host { - ::ng-deep .mat-tab-labels { - background-color: $color-gray-100; - } - - ::ng-deep .mat-tab-body-content { - background-color: $color-gray-100; - } .imx-application-content { background-color: $color-gray-100; } - .imx-application-content-no-app { - > .eui-icon { - color: $color-gray-90; - } - } + .imx-application-details-subtitle { color: $color-gray-50; } diff --git a/imxweb/projects/aob/src/lib/applications/application-detail.component.ts b/imxweb/projects/aob/src/lib/applications/application-detail.component.ts index c634cdc66..593277162 100644 --- a/imxweb/projects/aob/src/lib/applications/application-detail.component.ts +++ b/imxweb/projects/aob/src/lib/applications/application-detail.component.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -30,21 +30,21 @@ import { SafeUrl } from '@angular/platform-browser'; import { ActivatedRoute } from '@angular/router'; import { Subject, Subscription } from 'rxjs'; +import { PortalApplication } from '@imx-modules/imx-api-aob'; import { Base64ImageService, ClassloggerService } from 'qbm'; import { UserModelService } from 'qer'; -import { PortalApplication } from 'imx-api-aob'; -import { ApplicationsService } from './applications.service'; -import { ApplicationContent } from './application-content.interface'; import { AobPermissionsService } from '../permissions/aob-permissions.service'; +import { ApplicationContent } from './application-content.interface'; +import { ApplicationsService } from './applications.service'; @Component({ templateUrl: './application-detail.component.html', styleUrls: ['./application-detail.component.scss'], }) export class ApplicationDetailComponent implements ApplicationContent, OnInit, OnDestroy { - @Input() public application: PortalApplication; - - @Input() public loadingSubject: Subject; + @Input() public application: PortalApplication | undefined; + + @Input() public loadingSubject: Subject; public totalCount: number; public keywords: string; @@ -52,7 +52,10 @@ export class ApplicationDetailComponent implements ApplicationContent, OnInit, O public selectedTabIndex = 0; public showHelper = true; public isLoading = false; - + public hyperviewTableName = 'AOBApplication'; + public ldsIdentitiesWithAccessInfoText = + '#LDS#Here you can get an overview of identities that have access to at least one application entitlement of this application. Additionally, you can view which application entitlements the respective identities have access to.'; + private subscription: Subscription; constructor( @@ -60,21 +63,20 @@ export class ApplicationDetailComponent implements ApplicationContent, OnInit, O private readonly logger: ClassloggerService, private readonly applicationsProvider: ApplicationsService, public readonly userService: UserModelService, - public route:ActivatedRoute, - private readonly aobPermissionsService: AobPermissionsService + public route: ActivatedRoute, + private readonly aobPermissionsService: AobPermissionsService, ) { this.route.queryParams.subscribe(async (params) => { - if (Object.keys(params).length === 0) this.application = null; + if (Object.keys(params).length === 0) this.application = undefined; }); } - + public ngOnDestroy(): void { this.subscription?.unsubscribe(); } public async ngOnInit(): Promise { - - this.subscription = this.loadingSubject.subscribe(elem=> this.isLoading = elem); + this.subscription = this.loadingSubject.subscribe((elem) => (this.isLoading = elem)); this.isAdmin = await this.aobPermissionsService.isAobApplicationAdmin(); } @@ -89,7 +91,7 @@ export class ApplicationDetailComponent implements ApplicationContent, OnInit, O } public async reloadApplication(): Promise { - this.application = await this.applicationsProvider.reload(this.application.UID_AOBApplication.value); + this.application = await this.applicationsProvider.reload(this.application?.UID_AOBApplication.value || ''); } public createApplication(): void { diff --git a/imxweb/projects/aob/src/lib/applications/application-details/account-details.interface.ts b/imxweb/projects/aob/src/lib/applications/application-details/account-details.interface.ts index 164e2f064..1281a5921 100644 --- a/imxweb/projects/aob/src/lib/applications/application-details/account-details.interface.ts +++ b/imxweb/projects/aob/src/lib/applications/application-details/account-details.interface.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -24,10 +24,10 @@ * */ -import { TypedEntity } from 'imx-qbm-dbts'; +import { TypedEntity } from '@imx-modules/imx-qbm-dbts'; export interface AccountDetails { count: number; - first: TypedEntity; + first: TypedEntity | undefined; uidApplication: string; } diff --git a/imxweb/projects/aob/src/lib/applications/application-details/application-details.component.html b/imxweb/projects/aob/src/lib/applications/application-details/application-details.component.html index b05ef7815..6c09e57ae 100644 --- a/imxweb/projects/aob/src/lib/applications/application-details/application-details.component.html +++ b/imxweb/projects/aob/src/lib/applications/application-details/application-details.component.html @@ -7,8 +7,12 @@ - - + +
{{ '-' + ('#LDS#None assigned' | translate) + '-' }} @@ -20,7 +24,7 @@ data-imx-identifier="imx-application-details-button-show-more-shops" *ngIf="assignedShops.length > 1" > - {{ '#LDS#and {0} more...' | translate | ldsReplace : assignedShops.length - 1 }} + {{ '#LDS#and {0} more...' | translate | ldsReplace: assignedShops.length - 1 }}
@@ -39,11 +43,11 @@ {{ '#LDS#Will be published' | translate }} - check_circle + check_circle {{ '#LDS#Published' | translate }}
- {{ application.ActivationDate.value | shortDate }} + {{ application?.ActivationDate?.value?.toString() || '' | shortDate }}
@@ -53,29 +57,64 @@ -
- check_circle - {{ (application ? '#LDS#ScreenReader_Checked' : '#LDS#ScreenReader_Unchecked') | translate }} +
+ + check_circle + + + {{ (application ? '#LDS#ScreenReader_Checked' : '#LDS#ScreenReader_Unchecked') | translate }} + {{ '#LDS#Application created' | translate }}
-
- check_circle - {{ (hasOwner ? '#LDS#ScreenReader_Checked' : '#LDS#ScreenReader_Unchecked') | translate }} +
+ + check_circle + + + {{ (hasOwner ? '#LDS#ScreenReader_Checked' : '#LDS#ScreenReader_Unchecked') | translate }} + {{ '#LDS#Manager assigned' | translate }}
-
- check_circle - {{ (assignedShops?.length > 0 ? '#LDS#ScreenReader_Checked' : '#LDS#ScreenReader_Unchecked') | translate }} +
+ + check_circle + + + {{ (!!assignedShops?.length ? '#LDS#ScreenReader_Checked' : '#LDS#ScreenReader_Unchecked') | translate }} + {{ '#LDS#Shop assigned' | translate }}
-
- check_circle - {{ (hasAssignedEntitlements ? '#LDS#ScreenReader_Checked' : '#LDS#ScreenReader_Unchecked') | translate }} +
+ + check_circle + + + {{ (hasAssignedEntitlements ? '#LDS#ScreenReader_Checked' : '#LDS#ScreenReader_Unchecked') | translate }} + {{ '#LDS#Application entitlements assigned' | translate }}
-
- check_circle - {{ (hasPublishedEntitlements ? '#LDS#ScreenReader_Checked' : '#LDS#ScreenReader_Unchecked') | translate }} +
+ + check_circle + + + {{ (hasPublishedEntitlements ? '#LDS#ScreenReader_Checked' : '#LDS#ScreenReader_Unchecked') | translate }} + {{ '#LDS#Application entitlements published' | translate }}
@@ -87,12 +126,12 @@ - - + +
{{ '-' + ('#LDS#None selected' | translate) + '-' }} - {{ accountsInformation.first.GetEntity().GetDisplay() }} + {{ accountsInformation.first?.GetEntity()?.GetDisplay() }}
- - - - - - - - - - - + + + + + + + + + + +
- - - - + + diff --git a/imxweb/projects/aob/src/lib/applications/application-details/application-details.component.scss b/imxweb/projects/aob/src/lib/applications/application-details/application-details.component.scss index 6d41c0cc3..2d342bd7a 100644 --- a/imxweb/projects/aob/src/lib/applications/application-details/application-details.component.scss +++ b/imxweb/projects/aob/src/lib/applications/application-details/application-details.component.scss @@ -1,11 +1,9 @@ @use '@angular/material' as mat; @import '@elemental-ui/core/src/styles/_eui_palette.scss'; +@import 'base/mixins'; :host { - display: flex; - flex-direction: column; - overflow: hidden; - flex: 1 1 auto; + @include flex-column-container-fill(); min-height: 100%; .imx-application-details-content .imx-application-details-grid.hidden { @@ -14,46 +12,27 @@ } .imx-application-details-content { - display: flex; + @include flex-row-container-fill(); overflow: hidden; - flex: 1 1 auto; imx-busy-indicator { flex: 0 0 0; } .imx-application-details-grid { - display: flex; + @include flex-row-container($max-width: 1500px, $max-height: 800px, $overflow: auto); flex-wrap: wrap; padding: 16px 24px; - overflow: auto; - max-width: 1500px; - max-height: 800px; - > .mat-card { + > .mat-mdc-card { background-color: transparent; } - .mat-card-title { + .mat-mdc-card-title { font-size: 18px; line-height: 36px; } - .mat-button { - vertical-align: middle; - padding: 0 2px; - min-width: 0; - margin-left: 5px; - - ::ng-deep .mat-button-wrapper { - vertical-align: text-bottom; - } - } - - .mat-button[hidden] { - display: none; - } - .mat-divider-horizontal { width: 50px; margin-bottom: 12px; @@ -66,9 +45,8 @@ min-width: 200px; box-shadow: none; - .mat-card-content { - display: flex; - flex-direction: column; + .mat-mdc-card-content { + @include flex-column-container(); margin-bottom: -15px; > * { @@ -77,37 +55,8 @@ } } -.imx-button-area { - background-color: transparent; - display: flex; - flex-direction: row; - justify-content: flex-end; - - .justify-start { - margin-right: auto; - justify-self: start; - } - - .imx-additional-actions { - margin-right: 5px; - margin-left: 5px; - } - - .mat-stroked-button, - .mat-raised-button { - eui-icon { - font-size: 14px; - margin-right: 4px; - } - } - > button:not(:last-of-type) { - margin-right: 16px; - } -} - .imx-application-property-multi { - display: flex; - flex-direction: column; + @include flex-column-container(); > span { font-weight: 600; @@ -115,9 +64,7 @@ text-overflow: ellipsis; } - > .mat-button { - width: auto; - padding: 0px; + > .mat-mdc-button { line-height: 1.3rem; align-self: flex-start; } @@ -127,10 +74,8 @@ li { list-style-type: none; margin: 10px; - .mat-card { - display: flex; - flex-direction: row; - height: 3.2rem; + .mat-mdc-card { + @include flex-row-container(); > .imx-card-title { font-size: 16px; @@ -143,22 +88,16 @@ li { } } -.mat-dialog-content { - flex: 1; - display: flex; - flex-direction: column; - height: inherit; -} - .imx-application-state { - display: flex; + @include flex-row-container(); + flex-wrap: wrap; flex: 0 0 64%; align-content: flex-start; box-shadow: none; padding: 0; - > .mat-card { + > .mat-mdc-card { background-color: transparent; } } @@ -170,22 +109,19 @@ li { padding-left: 5px; padding-right: 0; - .mat-card-content { - display: flex; - align-items: center; - } + .mat-mdc-card-content { + @include flex-row-container(); - .mat-chip { - border-radius: 3px; - width: max-content; - user-select: none; + align-items: center; } - @mixin publish-state-style { + .imx-application-unpublished-state, + .imx-application-willbepublished-state, + .imx-application-published-state { + @include flex-row-container(); + align-items: center; font-weight: 600; font-size: 12px; - display: flex; - align-items: center; .eui-icon, .mat-icon { @@ -193,21 +129,6 @@ li { } } - .imx-application-unpublished-state, - .imx-application-willbepublished-state { - @include publish-state-style; - } - - .imx-application-published-state { - @include publish-state-style; - - .mat-icon { - font-size: 14px; - width: 14px; - height: 14px; - } - } - .imx-application-publish-date { margin-left: 10px; font-size: 14px; @@ -220,7 +141,7 @@ li { padding-left: 0; padding-right: 0; - .mat-card-title { + .mat-mdc-card-title { line-height: 45px; } @@ -228,24 +149,13 @@ li { margin-bottom: 8px; } - .mat-icon { - margin-right: 5px; - font-size: 16px; - width: 16px; - height: 16px; - visibility: hidden; - } - - .checked .mat-icon { - visibility: visible; - } - span { font-size: 14px; } - .mat-card-content > div { - display: flex; + .mat-mdc-card-content > div { + @include flex-row-container(); + align-items: center; } } @@ -255,12 +165,13 @@ li { box-shadow: none; overflow: hidden; - .mat-card-title { + .mat-mdc-card-title { line-height: 45px; } - .mat-card-content { - display: flex; + .mat-mdc-card-content { + @include flex-row-container(); + flex-wrap: wrap; imx-column-info, @@ -276,18 +187,6 @@ li { margin: 10px 0; } -.mat-card-avatar { - padding: 5px; - height: 25px; - width: 25px; - user-select: none; -} - -:host ::ng-deep body .mat-dialog-container { - display: flex; - flex-direction: column; -} - //Themeing :host { .imx-application-property-multi { @@ -304,17 +203,6 @@ li { .imx-application-published-state { color: $color-green-60; } - - .imx-application-progress { - .mat-icon { - color: $color-green-60; - } - } - - .mat-card-avatar { - background-color: $color-gray-30; - color: $color-gray-0; - } } .eui-dark-theme { @@ -325,11 +213,6 @@ li { } } - .mat-card-avatar { - background-color: $color-gray-60; - color: $color-gray-80; - } - .imx-application-publish { .imx-application-unpublished-state, .imx-application-willbepublished-state { @@ -340,12 +223,6 @@ li { color: $color-green-40; } } - - .imx-application-progress { - .mat-icon { - color: $color-green-40; - } - } } } @@ -361,12 +238,7 @@ li { background-color: $color-gray-90; } - .mat-card-avatar { - background-color: $color-gray-80; - color: $color-gray-70; - } - - .mat-card { + .mat-mdc-card { border-color: $color-gray-90; } @@ -380,11 +252,5 @@ li { color: $color-green-20; } } - - .imx-application-progress { - .mat-icon { - color: $color-green-20; - } - } } } diff --git a/imxweb/projects/aob/src/lib/applications/application-details/application-details.component.ts b/imxweb/projects/aob/src/lib/applications/application-details/application-details.component.ts index 242752d74..a0feabdde 100644 --- a/imxweb/projects/aob/src/lib/applications/application-details/application-details.component.ts +++ b/imxweb/projects/aob/src/lib/applications/application-details/application-details.component.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -24,29 +24,28 @@ * */ -import { OverlayRef } from '@angular/cdk/overlay'; -import { Component, Input, OnChanges, ViewChild, TemplateRef, OnInit } from '@angular/core'; +import { Platform } from '@angular/cdk/platform'; +import { Component, Input, OnChanges, OnInit, TemplateRef, ViewChild } from '@angular/core'; import { MatDialog } from '@angular/material/dialog'; import { MatMenuTrigger } from '@angular/material/menu'; import { EuiLoadingService, EuiSidesheetService } from '@elemental-ui/core'; -import { Platform } from '@angular/cdk/platform'; import { TranslateService } from '@ngx-translate/core'; -import { PortalApplication } from 'imx-api-aob'; -import { BusyService, ClassloggerService, ConfirmationService, SnackBarService, TextContainer } from 'qbm'; -import { ShopsService } from '../../shops/shops.service'; -import { EntitlementsService } from '../../entitlements/entitlements.service'; -import { EntitlementFilter } from '../../entitlements/entitlement-filter'; -import { TypedEntity } from 'imx-qbm-dbts'; +import { PortalApplication } from '@imx-modules/imx-api-aob'; +import { TypedEntity } from '@imx-modules/imx-qbm-dbts'; +import { BusyService, calculateSidesheetWidth, ClassloggerService, ConfirmationService, SnackBarService, TextContainer } from 'qbm'; import { AccountsService } from '../../accounts/accounts.service'; -import { LifecycleAction } from '../../lifecycle-actions/lifecycle-action.enum'; +import { AobApiService } from '../../aob-api-client.service'; +import { EntitlementFilter } from '../../entitlements/entitlement-filter'; +import { EntitlementsService } from '../../entitlements/entitlements.service'; import { LifecycleActionComponent } from '../../lifecycle-actions/lifecycle-action.component'; +import { LifecycleAction } from '../../lifecycle-actions/lifecycle-action.enum'; +import { AobPermissionsService } from '../../permissions/aob-permissions.service'; +import { ShopsService } from '../../shops/shops.service'; import { ApplicationsService } from '../applications.service'; -import { AobApiService } from '../../aob-api-client.service'; import { EditApplicationComponent } from '../edit-application/edit-application.component'; -import { AccountDetails } from './account-details.interface'; -import { AobPermissionsService } from '../../permissions/aob-permissions.service'; import { ServiceCategoryComponent } from '../edit-application/service-category/service-category.component'; +import { AccountDetails } from './account-details.interface'; @Component({ selector: 'imx-application-details', @@ -57,7 +56,7 @@ export class ApplicationDetailsComponent implements OnChanges, OnInit { /** * The {@link PortalApplication | AobApplication} */ - @Input() public application: PortalApplication; + @Input() public application: PortalApplication | undefined; @ViewChild('multiValueControl', { static: true }) public chartDialog: TemplateRef; @@ -91,18 +90,18 @@ export class ApplicationDetailsComponent implements OnChanges, OnInit { private readonly translateService: TranslateService, private readonly confirmation: ConfirmationService, private readonly sidesheetService: EuiSidesheetService, - private readonly permissions: AobPermissionsService + private readonly permissions: AobPermissionsService, ) { - this.shopsDisplay = this.aobApiService.typedClient.PortalShops.GetSchema().Display; - this.accountsDisplay = this.aobApiService.typedClient.PortalApplicationusesaccount.GetSchema().Display; + this.shopsDisplay = this.aobApiService.typedClient.PortalShops.GetSchema().Display || ''; + this.accountsDisplay = this.aobApiService.typedClient.PortalApplicationusesaccount.GetSchema().Display || ''; this.busyService.busyStateChanged.subscribe((elem) => (this.isLoading = elem)); } public ngOnInit(): void { this.accountsInformation = { count: 0, - first: null, - uidApplication: this.application.UID_AOBApplication.value, + first: undefined, + uidApplication: this.application?.UID_AOBApplication.value || '', }; } @@ -120,12 +119,15 @@ export class ApplicationDetailsComponent implements OnChanges, OnInit { Message: '#LDS#Are you sure you want to delete the application?', }) ) { - let overlayRef: OverlayRef; - setTimeout(() => ((overlayRef = this.euiBusyService.show()))); + if (this.euiBusyService.overlayRefs.length === 0) { + this.euiBusyService.show(); + } try { - await this.applicationprovider.deleteApplication(this.application.UID_AOBApplication.value); + if (!!this.application) { + await this.applicationprovider.deleteApplication(this.application.UID_AOBApplication.value); + } } finally { - setTimeout(() => this.euiBusyService.hide(overlayRef)); + this.euiBusyService.hide(); } } } @@ -137,8 +139,8 @@ export class ApplicationDetailsComponent implements OnChanges, OnInit { await this.sidesheetService .open(EditApplicationComponent, { title: await this.translateService.get('#LDS#Heading Edit Application').toPromise(), - subTitle: this.application.GetEntity().GetDisplay(), - width: '768px', + subTitle: this.application?.GetEntity().GetDisplay(), + width: calculateSidesheetWidth(800), padding: '0', data: this.application, testId: 'edit-application', @@ -147,7 +149,9 @@ export class ApplicationDetailsComponent implements OnChanges, OnInit { .afterClosed() .toPromise(); this.applicationprovider.applicationRefresh.next(true); - this.application = await this.applicationprovider.reload(this.application.UID_AOBApplication.value); + if (this.application) { + this.application = await this.applicationprovider.reload(this.application?.UID_AOBApplication.value); + } this.reloadData(); } @@ -171,10 +175,10 @@ export class ApplicationDetailsComponent implements OnChanges, OnInit { if (publishData) { this.logger.debug( this, - `Publishing application) ${publishData.date && publishData.publishFuture ? `on ${publishData.date}` : 'now'}` + `Publishing application) ${publishData.date && publishData.publishFuture ? `on ${publishData.date}` : 'now'}`, ); - if (await this.applicationprovider.publish(this.application, publishData)) { + if (!!this.application && (await this.applicationprovider.publish(this.application, publishData))) { let publishMessage: TextContainer = { key: '#LDS#The application was successfully published. It takes a moment for the changes to take effect.', }; @@ -211,10 +215,10 @@ export class ApplicationDetailsComponent implements OnChanges, OnInit { if (result) { this.logger.debug(this, 'Unpublish application...'); - if (await this.applicationprovider.unpublish(this.application)) { + if (this.application && (await this.applicationprovider.unpublish(this.application))) { this.snackbar.open( { key: '#LDS#The application was successfully unpublished. It takes a moment for the changes to take effect.' }, - '#LDS#Close' + '#LDS#Close', ); } else { this.logger.error(this, 'Attempt to unpublish the application failed'); @@ -229,28 +233,28 @@ export class ApplicationDetailsComponent implements OnChanges, OnInit { * Checks if the specified {@link PortalApplication|application} can be publish. */ public get isPublishable(): boolean { - return this.application != null && this.application.ActivationDate.GetMetadata().CanEdit() && !this.published(); + return this.application != null && this.application?.ActivationDate.GetMetadata().CanEdit() && !this.published(); } /** * Checks if the specified {@link PortalApplication|application} can be unnpublish. */ public get isUnpublishable(): boolean { - return this.application != null && this.application.IsInActive.GetMetadata().CanEdit() && !this.notPublished(); + return this.application != null && this.application?.IsInActive.GetMetadata().CanEdit() && !this.notPublished(); } // TODO 222863: Use the same filter as for entitlements: public notPublished(): boolean { - return this.application.IsInActive && this.application.IsInActive.value && !this.application.ActivationDate.value; + return !!this.application?.IsInActive && !!this.application?.IsInActive.value && !this.application?.ActivationDate.value; } public willPublish(): boolean { - return this.application.IsInActive && this.application.IsInActive.value && this.application.ActivationDate.value != null; + return !!this.application?.IsInActive && !!this.application?.IsInActive.value && this.application?.ActivationDate.value != null; } public published(): boolean { - return !this.application.IsInActive.value; + return !this.application?.IsInActive.value; } /** @@ -272,34 +276,37 @@ export class ApplicationDetailsComponent implements OnChanges, OnInit { public showMore(elements: TypedEntity[], title: string, iconText?: string): void { const content = { parts: elements.map((part) => part.GetEntity().GetDisplay()), caption: title, icon: iconText }; - this.dialog.open(this.chartDialog, { data: content, width: '600px', height: '400px' }); + this.dialog.open(this.chartDialog, { data: content, width: '600px' }); } /** * Shows a dialog, that displays additionals accounts (because in the beginning there are only 3 elements displayed) */ public async showMoreAccounts(): Promise { - let overlayRef: OverlayRef; - setTimeout(() => ((overlayRef = this.euiBusyService.show()))); + if (this.euiBusyService.overlayRefs.length === 0) { + this.euiBusyService.show(); + } try { - const elements = await this.accountsProvider.getAssigned(this.application.UID_AOBApplication.value, { - PageSize: this.accountsInformation.count, - }); - this.showMore(elements, this.accountsDisplay); + if (!!this.application) { + const elements = await this.accountsProvider.getAssigned(this.application.UID_AOBApplication.value, { + PageSize: this.accountsInformation.count, + }); + this.showMore(elements, this.accountsDisplay); + } } finally { - setTimeout(() => this.euiBusyService.hide(overlayRef)); + this.euiBusyService.hide(); } } public async editServiceCategories(): Promise { await this.sidesheetService .open(ServiceCategoryComponent, { - title: await this.translateService.get('#LDS#Heading Edit Service Categories').toPromise(), - subTitle: this.application.GetEntity().GetDisplay(), - width: 'max(700px,70%)', + title: await this.translateService.get('#LDS#Heading Manage Service Categories').toPromise(), + subTitle: this.application?.GetEntity().GetDisplay(), + width: calculateSidesheetWidth(), padding: '0', data: this.application, - testId: 'edit-application-servicecategory' + testId: 'edit-application-servicecategory', }) .afterClosed() .toPromise(); @@ -308,27 +315,32 @@ export class ApplicationDetailsComponent implements OnChanges, OnInit { private async reloadData(): Promise { const isBusy = this.busyService.beginBusy(); try { - if (this.application.AuthenticationRoot.value) { - this.application.AuthenticationRootHelper.value = this.application.AuthenticationRoot.value; + if (this.application?.AuthenticationRoot.value) { + this.application.AuthenticationRootHelper.value = this.application?.AuthenticationRoot.value; } - this.hasOwner = this.application.UID_PersonHead.value != null && this.application.UID_PersonHead.value !== ''; + this.hasOwner = this.application?.UID_PersonHead.value != null && this.application?.UID_PersonHead.value !== ''; await this.updateShops(); - const accountInfo = await this.accountsProvider.getFirstAndCount(this.application.UID_AOBApplication.value); + const accountInfo = !!this.application + ? await this.accountsProvider.getFirstAndCount(this.application.UID_AOBApplication.value) + : { count: 0, first: undefined }; + this.accountsInformation = { ...this.accountsInformation, ...{ count: accountInfo.count, first: accountInfo.first }, ...{ count: accountInfo.count, first: accountInfo.first }, }; - const applicationEntitlements = await this.entitlementsProvider.getEntitlementsForApplication(this.application); - if (applicationEntitlements) { + const applicationEntitlements = !!this.application + ? await this.entitlementsProvider.getEntitlementsForApplication(this.application) + : undefined; + if (!!applicationEntitlements) { const entitlementFilter = new EntitlementFilter(); this.hasPublishedEntitlements = applicationEntitlements.Data.filter(entitlementFilter.published).length > 0; this.hasAssignedEntitlements = applicationEntitlements.Data.length > 0; const publishedAndWillBePublished = applicationEntitlements.Data.filter( - (elem) => entitlementFilter.published(elem) || entitlementFilter.willPublish(elem) + (elem) => entitlementFilter.published(elem) || entitlementFilter.willPublish(elem), ); this.canBeDeleted = (await this.permissions.isAobApplicationAdmin()) && publishedAndWillBePublished.length === 0; } else { @@ -340,12 +352,15 @@ export class ApplicationDetailsComponent implements OnChanges, OnInit { } private async updateShops(): Promise { - const appInShop = await this.shopsProvider.getApplicationInShop(this.application.UID_AOBApplication.value); - if (appInShop == null) { - this.logger.error(this, 'TypedEntityCollectionData is undefined'); - return false; + const appInShop = !!this.application + ? await this.shopsProvider.getApplicationInShop(this.application.UID_AOBApplication.value) + : undefined; + if (!!appInShop) { + this.assignedShops = appInShop.Data; + return true; } - this.assignedShops = appInShop.Data; - return true; + this.logger.error(this, 'TypedEntityCollectionData is undefined'); + this.assignedShops = []; + return false; } } diff --git a/imxweb/projects/aob/src/lib/applications/application-hyperview/application-hyperview.component.html b/imxweb/projects/aob/src/lib/applications/application-hyperview/application-hyperview.component.html deleted file mode 100644 index 8ce8b016d..000000000 --- a/imxweb/projects/aob/src/lib/applications/application-hyperview/application-hyperview.component.html +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/imxweb/projects/aob/src/lib/applications/application-hyperview/application-hyperview.component.scss b/imxweb/projects/aob/src/lib/applications/application-hyperview/application-hyperview.component.scss deleted file mode 100644 index f19569117..000000000 --- a/imxweb/projects/aob/src/lib/applications/application-hyperview/application-hyperview.component.scss +++ /dev/null @@ -1,23 +0,0 @@ -@import '@elemental-ui/core/src/styles/_eui_palette.scss'; -:host { - background-color: transparent; - display: flex; - flex-direction: column; - - imx-busy-service { - justify-self: center; - align-self: center; - } -} - -.eui-dark-theme { - :host { - background-color: transparent; - } -} - -.eui-contrast-theme { - :host { - background-color: $color-gray-100; - } -} diff --git a/imxweb/projects/aob/src/lib/applications/application-hyperview/application-hyperview.component.ts b/imxweb/projects/aob/src/lib/applications/application-hyperview/application-hyperview.component.ts deleted file mode 100644 index bc41dcd87..000000000 --- a/imxweb/projects/aob/src/lib/applications/application-hyperview/application-hyperview.component.ts +++ /dev/null @@ -1,65 +0,0 @@ -/* - * ONE IDENTITY LLC. PROPRIETARY INFORMATION - * - * This software is confidential. One Identity, LLC. or one of its affiliates or - * subsidiaries, has supplied this software to you under terms of a - * license agreement, nondisclosure agreement or both. - * - * You may not copy, disclose, or use this software except in accordance with - * those terms. - * - * - * Copyright 2023 One Identity LLC. - * ALL RIGHTS RESERVED. - * - * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR - * WARRANTIES ABOUT THE SUITABILITY OF THE SOFTWARE, - * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED - * TO THE IMPLIED WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE, OR - * NON-INFRINGEMENT. ONE IDENTITY LLC. SHALL NOT BE - * LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE - * AS A RESULT OF USING, MODIFYING OR DISTRIBUTING - * THIS SOFTWARE OR ITS DERIVATIVES. - * - */ - -import { Component, Input, OnChanges } from '@angular/core'; - - -import { BusyService, ClassloggerService } from 'qbm'; -import { ShapeData } from 'imx-api-qer'; -import { ApplicationHyperviewService } from './application-hyperview.service'; - -@Component({ - selector: 'imx-application-hyperview', - templateUrl: './application-hyperview.component.html', - styleUrls: ['./application-hyperview.component.scss'], -}) -export class ApplicationHyperviewComponent implements OnChanges { - public shapes: ShapeData[]; - - @Input() public uidApplication: string; - - public busyService = new BusyService(); - public isLoading = false; - - constructor(private classlogger: ClassloggerService, private hyperviewprovider: ApplicationHyperviewService) { - this.busyService.busyStateChanged.subscribe((elem) => (this.isLoading = elem)); - } - - public async ngOnChanges(): Promise { - const isBusy = this.busyService.beginBusy(); - try { - this.shapes = await this.hyperviewprovider.get(this.uidApplication); - if (this.shapes) { - this.classlogger.debug(this, 'hyperview loaded'); - this.classlogger.trace(this, this.shapes); - } else { - this.classlogger.error(this, 'ShapeData[] is undefined'); - } - } finally { - isBusy.endBusy(); - } - } -} diff --git a/imxweb/projects/aob/src/lib/applications/application-hyperview/application-hyperview.module.ts b/imxweb/projects/aob/src/lib/applications/application-hyperview/application-hyperview.module.ts deleted file mode 100644 index 6f6502844..000000000 --- a/imxweb/projects/aob/src/lib/applications/application-hyperview/application-hyperview.module.ts +++ /dev/null @@ -1,44 +0,0 @@ -/* - * ONE IDENTITY LLC. PROPRIETARY INFORMATION - * - * This software is confidential. One Identity, LLC. or one of its affiliates or - * subsidiaries, has supplied this software to you under terms of a - * license agreement, nondisclosure agreement or both. - * - * You may not copy, disclose, or use this software except in accordance with - * those terms. - * - * - * Copyright 2023 One Identity LLC. - * ALL RIGHTS RESERVED. - * - * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR - * WARRANTIES ABOUT THE SUITABILITY OF THE SOFTWARE, - * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED - * TO THE IMPLIED WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE, OR - * NON-INFRINGEMENT. ONE IDENTITY LLC. SHALL NOT BE - * LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE - * AS A RESULT OF USING, MODIFYING OR DISTRIBUTING - * THIS SOFTWARE OR ITS DERIVATIVES. - * - */ - -import { NgModule } from '@angular/core'; -import { CommonModule } from '@angular/common'; -import { TranslateModule } from '@ngx-translate/core'; -import { MatButtonModule } from '@angular/material/button'; -import { MatDialogModule } from '@angular/material/dialog'; - -import { ApplicationHyperviewComponent } from './application-hyperview.component'; -import { HyperViewModule, BusyIndicatorModule } from 'qbm'; -import { ApplicationHyperviewService} from './application-hyperview.service'; -import { EuiCoreModule } from '@elemental-ui/core'; - -@NgModule({ - declarations: [ApplicationHyperviewComponent], - imports: [CommonModule, HyperViewModule, TranslateModule, MatDialogModule, MatButtonModule, EuiCoreModule, BusyIndicatorModule], - providers: [ApplicationHyperviewService], - exports: [ApplicationHyperviewComponent], -}) -export class ApplicationHyperviewModule {} diff --git a/imxweb/projects/aob/src/lib/applications/application-image-select/application-image-select.component.html b/imxweb/projects/aob/src/lib/applications/application-image-select/application-image-select.component.html index 9dbabd3d1..1d10ae9f4 100644 --- a/imxweb/projects/aob/src/lib/applications/application-image-select/application-image-select.component.html +++ b/imxweb/projects/aob/src/lib/applications/application-image-select/application-image-select.component.html @@ -1,6 +1,2 @@ - + diff --git a/imxweb/projects/aob/src/lib/applications/application-image-select/application-image-select.component.scss b/imxweb/projects/aob/src/lib/applications/application-image-select/application-image-select.component.scss index 3364f1f4f..c9e89c84d 100644 --- a/imxweb/projects/aob/src/lib/applications/application-image-select/application-image-select.component.scss +++ b/imxweb/projects/aob/src/lib/applications/application-image-select/application-image-select.component.scss @@ -1 +1 @@ -// styles \ No newline at end of file +// styles diff --git a/imxweb/projects/aob/src/lib/applications/application-image-select/application-image-select.component.ts b/imxweb/projects/aob/src/lib/applications/application-image-select/application-image-select.component.ts index fee0c8d96..94d09ef54 100644 --- a/imxweb/projects/aob/src/lib/applications/application-image-select/application-image-select.component.ts +++ b/imxweb/projects/aob/src/lib/applications/application-image-select/application-image-select.component.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -28,14 +28,14 @@ import { AfterViewInit, Component, EventEmitter, Input, OnChanges, Output, Simpl import { UntypedFormControl } from '@angular/forms'; import { MatDialog, MatDialogConfig } from '@angular/material/dialog'; -import { IEntityColumn } from 'imx-qbm-dbts'; +import { IEntityColumn } from '@imx-modules/imx-qbm-dbts'; import { Base64ImageService, EntityColumnContainer } from 'qbm'; import { ImageSelectorDialogComponent } from './image-selector-dialog/image-selector-dialog.component'; @Component({ selector: 'imx-application-image-select', templateUrl: './application-image-select.component.html', - styleUrls: ['./application-image-select.component.scss'] + styleUrls: ['./application-image-select.component.scss'], }) export class ApplicationImageSelectComponent implements OnChanges, AfterViewInit { public readonly control = new UntypedFormControl(); @@ -47,32 +47,37 @@ export class ApplicationImageSelectComponent implements OnChanges, AfterViewInit @Output() public controlCreated = new EventEmitter(); private readonly icons = { - // tslint:disable-next-line:max-line-length - application: 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAADIAAAAlCAYAAAAA7LqSAAAAAXNSR0IArs4c6QAAAeJJREFUWAntWbFKA0EQde/CYSGk0SqIiEhEVNBW/YLkD4SQIsc1/oCVtZWlJLlK0C/w6ivE1kIiIiJcKgtttNKId74Jd7JcYrMwa052YZm5eTs782Z2mz0xhRGGYSmKohnSizaazeabECIWnU5nD8kfJ0kyVzQSlC9I9DFdCwSOdJNA4HfkcD+ucMC+YO+Nw1IbYXGGI/cFzEMLhkpm1CSfEHje87wVy7L25ZhEEFgV2DrsdRkj3bbtHcLgt5kSHi6BT4WIaB1I4ALJvFBQJHQK8VNd6JfAHgmDDLD2mfR0PLRarSvSXde9gbhO7UOhnQiqV2+327MUPY7jBoScwy6wJcIga1gr39tl3/e3Cet2uxsQW6RnQ8AhyT50yfQI9RGvmo9JRwYE7mBfG4MBSm5hX8WUCxCV8ot1fCOZacQZIUGxgdkQIyRSTPyG5YmcYOEBORVgnCHHWpZnnsgHLtlrBk6yxJX4lPOTz5lsL5xuiExay0xHTEeYKmCOFlNhlbc1HVEuHZOj6QhTYZW3NR1RLh2To+kIU2GVtzUdUS4dk6PpCFNhlbc1HVEuHZPjv+nInzyZMjQloo7Ir+EMMbRsGRORQEsoxiB4+A5KjuM0BoMBPe8vMsZi2xr/WHrlcvn8Gxm0iGtOIek+AAAAAElFTkSuQmCC', - // tslint:disable-next-line:max-line-length + // eslint-disable-next-line max-len + application: + 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAADIAAAAlCAYAAAAA7LqSAAAAAXNSR0IArs4c6QAAAeJJREFUWAntWbFKA0EQde/CYSGk0SqIiEhEVNBW/YLkD4SQIsc1/oCVtZWlJLlK0C/w6ivE1kIiIiJcKgtttNKId74Jd7JcYrMwa052YZm5eTs782Z2mz0xhRGGYSmKohnSizaazeabECIWnU5nD8kfJ0kyVzQSlC9I9DFdCwSOdJNA4HfkcD+ucMC+YO+Nw1IbYXGGI/cFzEMLhkpm1CSfEHje87wVy7L25ZhEEFgV2DrsdRkj3bbtHcLgt5kSHi6BT4WIaB1I4ALJvFBQJHQK8VNd6JfAHgmDDLD2mfR0PLRarSvSXde9gbhO7UOhnQiqV2+327MUPY7jBoScwy6wJcIga1gr39tl3/e3Cet2uxsQW6RnQ8AhyT50yfQI9RGvmo9JRwYE7mBfG4MBSm5hX8WUCxCV8ot1fCOZacQZIUGxgdkQIyRSTPyG5YmcYOEBORVgnCHHWpZnnsgHLtlrBk6yxJX4lPOTz5lsL5xuiExay0xHTEeYKmCOFlNhlbc1HVEuHZOj6QhTYZW3NR1RLh2To+kIU2GVtzUdUS4dk6PpCFNhlbc1HVEuHZPjv+nInzyZMjQloo7Ir+EMMbRsGRORQEsoxiB4+A5KjuM0BoMBPe8vMsZi2xr/WHrlcvn8Gxm0iGtOIek+AAAAAElFTkSuQmCC', + // eslint-disable-next-line max-len box: 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAADIAAAAyCAYAAAAeP4ixAAABqklEQVRoQ+1YPUvDQBh+riSiBJRubo7FWXD1B7h3L4gHyWQGF62DH4tDnBo4Ebp39we4Cs7i6OZWFIJiQk4OtFiqJL3cBYnvrXnf573ng9wlDA1ZrCE8QET+mpPkCDliSQGKliVhtWHJEW3pLDU20xEhxApjbCvP83VLwhmBbbVa91LKG8758xfgxJHRaLQwHo9PAOwbmWYf5Lzdbve73e67GjUhEkXRkud5FwC4/T0YmSCSJNkLw/CViBjRszoIOVJdQ7MI5IhZPauj/ezIcDhcTNP0QEq5WX2GfQTG2K3rume9Xu9t6vVrf7TdCc28a9nVzC76r44IIfoAju2Onxv9iHOu7oMzi4jMraWZhloceQSwm6bpXZk9u667AeASwFqZ+s+aWohMHVBFm9P8bKiFyHWWZTtBEDwVkVDPB4PBquM4VwC2y9TX6Yia9QBARazMUpHqlCn8VlOLI3PuSauciNCBqBWc4iaKFkWrOCVaFRQtipZWcIqbKFoUreKUaFX842jFcdxxHOdUSrmspZ3hJsbYS5Zlh77vq0+FmUX/tQwLXhmuMY58ANUk7zNkl1kaAAAAAElFTkSuQmCC', - // tslint:disable-next-line:max-line-length - openfolder: 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAADIAAAAyCAYAAAAeP4ixAAAC80lEQVRoQ+2Zz2sTQRTHv28zadUiklp602tP4lH/AoUePElErYdQs1uSWmi9qNBa6UUKpoptdJtDD9KDVUEPRdSbJ68qiKIX9VoTtBRt2cyTDSQQJbNhmgnTkr0F9v34zHf2fWc3hF1y0S7hQAfENiU7inQUMbQCna1laGG109YpsrCwcEgIcZqZu3QzEtFWEASPs9nsd90cOnE1kJWVla5SqXQTwLhOon9i5hKJxJVkMrnVglxNpaiB5HK5vT09PXMAvKYi1Tf5Gxsb4xMTE79bkKupFKZAngK4J6U0oogQoiylfOd53s8qpSmQplZxmzfNJhKJyer23ckgddtXBfKVmR8BWNvmypkK/9bb2/skUhEiGnRd97mpLlqdt5Ei7wEkPc/72OqCpvI1AnlbLpfPZDKZT2Hh6elpp7+//4CU0jHViG7eeDweuK77KxKEmalQKIwx823dYobj1gFcigTxfX8fgDsALhpuSDs9M+cjQebn5w8KIZaJ6KR2JfOBU5Eg+Xx+IBaLPQRw1Hw/ehWIaCgSpFAoHJdSvgSwX6+M+ShmPhEJsri4eIqZn5lvR7vCuuM40SC+74fH+px2GfOBFatQKtLX1/elWCzOENFV8/3oVWDmF0EQnFeCxGKx8C3P6tEL4IEQIqsEkVKu2T56Qw/p7u6+rAQJxbZ99AKY8jxvRgkSj8cTto/e0ENc111WggghBiwfvQg9ZGRk5FXUwz5o+eiteEg6nX7TEISZzwEYsnn0Aqi9bjQEkVKmHMfJWH7qrXjI6OjoDxVIlogmLT/1VjxkeHh4XbW1rhPRDZtPvVUPSaVSf1Qgd4ko/PJo7am36iGh3zUEAbAK4JreCag9UVUPUYIQ0QdmPtuelvSqVD1EBfIZQBHAMb0SbYmqeYgKpC2dbLNI3Ser2jOytLS0Z3Nz8xYRhd6xE67Vcrl8IZPJlOoUCX/4vn8EwBiAw5aTFInofjqdfk1E/B+I5c0r2+v8q2ubeh1FOooYWoG/nVypz2zv/LMAAAAASUVORK5CYII=', - // tslint:disable-next-line:max-line-length - server: 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAADIAAAAyCAYAAAAeP4ixAAACM0lEQVRoQ+2ZMWvbUBDH717jOMWQYA8eswfSvdDQD1ACHQJa4sWLJAcSqAvdWkS7FeJCCrakxYuzCDIEQj5AaSB7Ct0zerBJwLSu23elpTG1ooCe7GfLL8+bhd7d/f7/QzpOCIr8UBEO0CBpc1I7kmpHPM97BAB7ALCatkJD9VwCwIFlWRc314et1Ww2l/r9/j4i7qQc4m95RFTPZrMvy+Xy9z//hyC1Wu1hLpf7AADWPIAAgNfr9V5Uq9VvIiA7nPOvYUDG2BoA1GcELg7COd+oVCpn4YIbjcYTxthnDTKeAuKOAIAarTWecNJOJ3JEWjVjBI4GCYJgsdPpbM3By/CG/bJQKBwZhvFj5PE7hjKpOKrm0Og4DisWiyucc5YKme8ogjHG2+32leM4/NasFQTBg263WwWA92mG+K+2V/l8vmYYxi+RESWNbOKPXyI6R8TrMA0RLSPi4xlRioPoWUuuVffYEbnCJo4u7kjiVHIPKg5CROj7/vJgMFiQK+RkomcymZ+maV4jIumhcTKaTjbKyPSrF3STFTdWNL2g0wu6WI2S6CbxF6Iy069e0CXqmNiHxFsrdujp3hhvQccYe0pEzyJqaxHRF5k1I+I6AJTCORDxlHP+6d/1eAs6z/NeA8DbiGAl0zQPZYL4vr9NRK2IHG8sy3oXlfvOBZ0yIK7r7iLiZsTmpG7b9rFMR1zXfR71LZOITmzb/ijkiMxCZcRWc/crQ6lpxdSOTEvpuHmUceQ3am+oQn9k2zIAAAAASUVORK5CYII=', - // tslint:disable-next-line:max-line-length - hdd: 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAADIAAAAyCAYAAAAeP4ixAAAETklEQVRoQ+2ZTWhjVRTH/+e91kZSnSaLSgdk3MksdDcKulDQcasDQ1BnHJAmvYkfwWZRdKD6tDhKF4lUSt5LUgaGGUfCDKPoShwYEcWPhagL6U4XnWAXDWObmkjfO3JLMoSQvps2uamG3uW795x7fvece+659xEGpNGAcOAA5L/myQOP/C89UigUwq7rvgbg4T4DfG+a5gfRaHRNNW9HoeU4zjSAtEqZpv6UECKj0t0pyCyAd1TKNPW/KYSYU+nWBfIVgBsAfvQ8ryKNMAwjCOAYgMcBPKYyrKm/7yBrzJxh5vPxePwmEXE7Y5mZbNs+TEQvEpEM2bACqn8gRHTZdd2ziUTi912sNLLZ7H2maZ5j5ud85PoGYlUqlflUKvX3biAaY9Pp9J3BYHAGgLWDvH4QIjpbrVbTyWSytheIhszCwsJIIBBIMfO5Nnr0ghDRhWq1+moymfyrG4gmmLsDgcCHzHymRZ9WkN8Mw3g2Fov90guIho58Pv+g53kfAzjar6w1FwqF3o5EIm4vQYrFolkul98CIM+tRtPmkZLnec8kEokfegnR0JXNZh8yDOMTABP1b3pAiOgKM0eFELdUIJZlGePj44fkuNXV1VuWZXkqGcdxDhFRgZlPagVh5vfC4fCsKqwKhcKRra2tDBGdkAYx87WhoaHpaDT6hx+MDK+1tbU5InpDKwiAuBDC8TNGptORkZF5AMmWcQu1Wm1Gla4dxxEAbK0gRHR6amrqkh+I9Ibruh8BeKRl3LemaT6v8koulzvFzBf3HWRpaemw67qXmFkWiLcbEd0wTfPU5OTkTb+F6AsIAOX9oJ5GUwBkeDW3mVAolFbtr5b7j56sBSATCoVej0Qi//itqqyhRkdHp5hZVrggoszGxkZOVZMVi8U7yuXy+wC25QBoA/kSwBkhREmVSvfS7ziOPD8uAHhSN8g6M5+Ix+PX92KoSsa27SeI6BqAu3SDSP1OpVKZVoWJyujW/npJL+/nMv02mrbQkhOsAzgphPhit8b6jXcc5ykAV5q8oXWPbNtCRN+4rnt6p1uhZVlDExMTwVKptN5JaZLP5496nne+zZOTVo80YD4lIhGLxf5sXul6iMjU+wqAZXm4maZ5dWVlZbkdVD6fv4eZHWZ+uo3H9IPISdvVUIuLi/cODw9fZuZHWwz7FcBFwzA+a0C11mT7BlKfeFm+e9VqtauyjvI5EJvtlFDy2eg4gPt99k5/PNJsADN/bRhGplqtXh8bG3M3NzfnieilLhOCVhDpAcfzvJ8MwzgC4OX649ttm5n5OyKSj3MPABjvAkYbyM8AXhBCyNDYborN2gXDtqgeEGaeFUK82/qSaNv2cSLq6blSXwE9IDvdR3K53DFm/rzLMGrnPT0gA+MRAIOxR5rODd+s1e0Ob5LXE1o9NLBTVT0FGYxfbwPzM7TTGNjPcR39Q9xPAzud+wCk05Xq17gDj/RrpTud51+Swm1RKPvqDgAAAABJRU5ErkJggg==' + // eslint-disable-next-line max-len + openfolder: + 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAADIAAAAyCAYAAAAeP4ixAAAC80lEQVRoQ+2Zz2sTQRTHv28zadUiklp602tP4lH/AoUePElErYdQs1uSWmi9qNBa6UUKpoptdJtDD9KDVUEPRdSbJ68qiKIX9VoTtBRt2cyTDSQQJbNhmgnTkr0F9v34zHf2fWc3hF1y0S7hQAfENiU7inQUMbQCna1laGG109YpsrCwcEgIcZqZu3QzEtFWEASPs9nsd90cOnE1kJWVla5SqXQTwLhOon9i5hKJxJVkMrnVglxNpaiB5HK5vT09PXMAvKYi1Tf5Gxsb4xMTE79bkKupFKZAngK4J6U0oogQoiylfOd53s8qpSmQplZxmzfNJhKJyer23ckgddtXBfKVmR8BWNvmypkK/9bb2/skUhEiGnRd97mpLlqdt5Ei7wEkPc/72OqCpvI1AnlbLpfPZDKZT2Hh6elpp7+//4CU0jHViG7eeDweuK77KxKEmalQKIwx823dYobj1gFcigTxfX8fgDsALhpuSDs9M+cjQebn5w8KIZaJ6KR2JfOBU5Eg+Xx+IBaLPQRw1Hw/ehWIaCgSpFAoHJdSvgSwX6+M+ShmPhEJsri4eIqZn5lvR7vCuuM40SC+74fH+px2GfOBFatQKtLX1/elWCzOENFV8/3oVWDmF0EQnFeCxGKx8C3P6tEL4IEQIqsEkVKu2T56Qw/p7u6+rAQJxbZ99AKY8jxvRgkSj8cTto/e0ENc111WggghBiwfvQg9ZGRk5FXUwz5o+eiteEg6nX7TEISZzwEYsnn0Aqi9bjQEkVKmHMfJWH7qrXjI6OjoDxVIlogmLT/1VjxkeHh4XbW1rhPRDZtPvVUPSaVSf1Qgd4ko/PJo7am36iGh3zUEAbAK4JreCag9UVUPUYIQ0QdmPtuelvSqVD1EBfIZQBHAMb0SbYmqeYgKpC2dbLNI3Ser2jOytLS0Z3Nz8xYRhd6xE67Vcrl8IZPJlOoUCX/4vn8EwBiAw5aTFInofjqdfk1E/B+I5c0r2+v8q2ubeh1FOooYWoG/nVypz2zv/LMAAAAASUVORK5CYII=', + // eslint-disable-next-line max-len + server: + 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAADIAAAAyCAYAAAAeP4ixAAACM0lEQVRoQ+2ZMWvbUBDH717jOMWQYA8eswfSvdDQD1ACHQJa4sWLJAcSqAvdWkS7FeJCCrakxYuzCDIEQj5AaSB7Ct0zerBJwLSu23elpTG1ooCe7GfLL8+bhd7d/f7/QzpOCIr8UBEO0CBpc1I7kmpHPM97BAB7ALCatkJD9VwCwIFlWRc314et1Ww2l/r9/j4i7qQc4m95RFTPZrMvy+Xy9z//hyC1Wu1hLpf7AADWPIAAgNfr9V5Uq9VvIiA7nPOvYUDG2BoA1GcELg7COd+oVCpn4YIbjcYTxthnDTKeAuKOAIAarTWecNJOJ3JEWjVjBI4GCYJgsdPpbM3By/CG/bJQKBwZhvFj5PE7hjKpOKrm0Og4DisWiyucc5YKme8ogjHG2+32leM4/NasFQTBg263WwWA92mG+K+2V/l8vmYYxi+RESWNbOKPXyI6R8TrMA0RLSPi4xlRioPoWUuuVffYEbnCJo4u7kjiVHIPKg5CROj7/vJgMFiQK+RkomcymZ+maV4jIumhcTKaTjbKyPSrF3STFTdWNL2g0wu6WI2S6CbxF6Iy069e0CXqmNiHxFsrdujp3hhvQccYe0pEzyJqaxHRF5k1I+I6AJTCORDxlHP+6d/1eAs6z/NeA8DbiGAl0zQPZYL4vr9NRK2IHG8sy3oXlfvOBZ0yIK7r7iLiZsTmpG7b9rFMR1zXfR71LZOITmzb/ijkiMxCZcRWc/crQ6lpxdSOTEvpuHmUceQ3am+oQn9k2zIAAAAASUVORK5CYII=', + // eslint-disable-next-line max-len + hdd: 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAADIAAAAyCAYAAAAeP4ixAAAETklEQVRoQ+2ZTWhjVRTH/+e91kZSnSaLSgdk3MksdDcKulDQcasDQ1BnHJAmvYkfwWZRdKD6tDhKF4lUSt5LUgaGGUfCDKPoShwYEcWPhagL6U4XnWAXDWObmkjfO3JLMoSQvps2uamG3uW795x7fvece+659xEGpNGAcOAA5L/myQOP/C89UigUwq7rvgbg4T4DfG+a5gfRaHRNNW9HoeU4zjSAtEqZpv6UECKj0t0pyCyAd1TKNPW/KYSYU+nWBfIVgBsAfvQ8ryKNMAwjCOAYgMcBPKYyrKm/7yBrzJxh5vPxePwmEXE7Y5mZbNs+TEQvEpEM2bACqn8gRHTZdd2ziUTi912sNLLZ7H2maZ5j5ud85PoGYlUqlflUKvX3biAaY9Pp9J3BYHAGgLWDvH4QIjpbrVbTyWSytheIhszCwsJIIBBIMfO5Nnr0ghDRhWq1+moymfyrG4gmmLsDgcCHzHymRZ9WkN8Mw3g2Fov90guIho58Pv+g53kfAzjar6w1FwqF3o5EIm4vQYrFolkul98CIM+tRtPmkZLnec8kEokfegnR0JXNZh8yDOMTABP1b3pAiOgKM0eFELdUIJZlGePj44fkuNXV1VuWZXkqGcdxDhFRgZlPagVh5vfC4fCsKqwKhcKRra2tDBGdkAYx87WhoaHpaDT6hx+MDK+1tbU5InpDKwiAuBDC8TNGptORkZF5AMmWcQu1Wm1Gla4dxxEAbK0gRHR6amrqkh+I9Ibruh8BeKRl3LemaT6v8koulzvFzBf3HWRpaemw67qXmFkWiLcbEd0wTfPU5OTkTb+F6AsIAOX9oJ5GUwBkeDW3mVAolFbtr5b7j56sBSATCoVej0Qi//itqqyhRkdHp5hZVrggoszGxkZOVZMVi8U7yuXy+wC25QBoA/kSwBkhREmVSvfS7ziOPD8uAHhSN8g6M5+Ix+PX92KoSsa27SeI6BqAu3SDSP1OpVKZVoWJyujW/npJL+/nMv02mrbQkhOsAzgphPhit8b6jXcc5ykAV5q8oXWPbNtCRN+4rnt6p1uhZVlDExMTwVKptN5JaZLP5496nne+zZOTVo80YD4lIhGLxf5sXul6iMjU+wqAZXm4maZ5dWVlZbkdVD6fv4eZHWZ+uo3H9IPISdvVUIuLi/cODw9fZuZHWwz7FcBFwzA+a0C11mT7BlKfeFm+e9VqtauyjvI5EJvtlFDy2eg4gPt99k5/PNJsADN/bRhGplqtXh8bG3M3NzfnieilLhOCVhDpAcfzvJ8MwzgC4OX649ttm5n5OyKSj3MPABjvAkYbyM8AXhBCyNDYborN2gXDtqgeEGaeFUK82/qSaNv2cSLq6blSXwE9IDvdR3K53DFm/rzLMGrnPT0gA+MRAIOxR5rODd+s1e0Ob5LXE1o9NLBTVT0FGYxfbwPzM7TTGNjPcR39Q9xPAzud+wCk05Xq17gDj/RrpTud51+Swm1RKPvqDgAAAABJRU5ErkJggg==', }; private readonly defaultIcon = this.icons.application; - constructor(private readonly dialog: MatDialog, private readonly imageProvider: Base64ImageService) { } + constructor( + private readonly dialog: MatDialog, + private readonly imageProvider: Base64ImageService, + ) {} public ngOnChanges(changes: SimpleChanges): void { if (changes.column && this.column) { - const cdr = new class { + const cdr = new (class { public get hint(): string { - return !this.column.GetValue()?.length ? - '#LDS#If you do not select an icon, the default icon will be used.' : ''; + return !this.column.GetValue()?.length ? '#LDS#If you do not select an icon, the default icon will be used.' : ''; } constructor(public readonly column: IEntityColumn) {} public readonly isReadOnly = () => !this.column.GetMetadata().CanEdit(); - }(this.column); + })(this.column); this.columnContainer.init(cdr); @@ -91,8 +96,8 @@ export class ApplicationImageSelectComponent implements OnChanges, AfterViewInit title: '#LDS#Edit Application Icon', icons: this.icons, imageUrl: this.control.value, - defaultIcon: 'application' - } + defaultIcon: 'application', + }, }; const result = await this.dialog.open(ImageSelectorDialogComponent, imageSelectorDialogParams).afterClosed().toPromise(); diff --git a/imxweb/projects/aob/src/lib/applications/application-image-select/image-selector-dialog/image-selector-dialog-parameter.interface.ts b/imxweb/projects/aob/src/lib/applications/application-image-select/image-selector-dialog/image-selector-dialog-parameter.interface.ts index 1129f4419..62dd5d540 100644 --- a/imxweb/projects/aob/src/lib/applications/application-image-select/image-selector-dialog/image-selector-dialog-parameter.interface.ts +++ b/imxweb/projects/aob/src/lib/applications/application-image-select/image-selector-dialog/image-selector-dialog-parameter.interface.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -36,7 +36,7 @@ export interface ImageSelectorDialogParameter { /** * the predefined list of icons */ - icons: { [name: string]: string; }; + icons: { [name: string]: string }; /** * the default icon to select diff --git a/imxweb/projects/aob/src/lib/applications/application-image-select/image-selector-dialog/image-selector-dialog.component.html b/imxweb/projects/aob/src/lib/applications/application-image-select/image-selector-dialog/image-selector-dialog.component.html index 8c2b44ca8..8b899c6f2 100644 --- a/imxweb/projects/aob/src/lib/applications/application-image-select/image-selector-dialog/image-selector-dialog.component.html +++ b/imxweb/projects/aob/src/lib/applications/application-image-select/image-selector-dialog/image-selector-dialog.component.html @@ -1,35 +1,52 @@
-

{{ title | translate }}

+

{{ title | translate }}

- {{'#LDS#Select an Icon' | translate}} -
- + {{ '#LDS#Select an Icon' | translate }} +
+
- {{'#LDS#WC_Or' | translate}} - + {{ '#LDS#WC_Or' | translate }} + - - + + - - -
{{'#LDS#Please select an image in PNG format.' | translate}}
+
+ +
+ +
{{ '#LDS#Please select an image in PNG format.' | translate }}
-
- -
diff --git a/imxweb/projects/aob/src/lib/applications/application-image-select/image-selector-dialog/image-selector-dialog.component.scss b/imxweb/projects/aob/src/lib/applications/application-image-select/image-selector-dialog/image-selector-dialog.component.scss index c77f97766..7a0fc3b52 100644 --- a/imxweb/projects/aob/src/lib/applications/application-image-select/image-selector-dialog/image-selector-dialog.component.scss +++ b/imxweb/projects/aob/src/lib/applications/application-image-select/image-selector-dialog/image-selector-dialog.component.scss @@ -1,60 +1,15 @@ @import '@elemental-ui/core/src/styles/_palette.scss'; +@import 'base/mixins'; -.mat-dialog-title { - font-weight: 600; - font-size: 24px; -} - -.mat-dialog-content { - display: flex; - flex-direction: column; +.mat-mdc-dialog-content { + @include flex-column-container(); align-items: center; - >span { + > span { font-size: 20px; } - - >.mat-raised-button { - background-color: $corbin-orange; - margin-bottom: 30px; - margin-top: 20px - } -} - -.mat-dialog-actions { - display: flex; - justify-content: flex-end; - - button { - margin-bottom: 10px; - margin-left: 10px; - } } .imx-hidden-element { display: none; } - -.imx-image-selector-list { - flex-direction: row; - display: flex; -} - -.imx-default-preview-image { - box-shadow: none; -} - -.eui-icon { - color: $black-9; - user-select: none; -} - -.mat-card { - box-shadow: none; - border: 3px solid transparent; - cursor: pointer; -} - -.mat-card.selected { - border: 3px solid $iris-blue; -} diff --git a/imxweb/projects/aob/src/lib/applications/application-image-select/image-selector-dialog/image-selector-dialog.component.ts b/imxweb/projects/aob/src/lib/applications/application-image-select/image-selector-dialog/image-selector-dialog.component.ts index e88f3b6a0..0ed9a7d53 100644 --- a/imxweb/projects/aob/src/lib/applications/application-image-select/image-selector-dialog/image-selector-dialog.component.ts +++ b/imxweb/projects/aob/src/lib/applications/application-image-select/image-selector-dialog/image-selector-dialog.component.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -25,12 +25,12 @@ */ import { Component, Inject, OnDestroy } from '@angular/core'; -import { MatDialogRef, MAT_DIALOG_DATA } from '@angular/material/dialog'; +import { MAT_DIALOG_DATA, MatDialogRef } from '@angular/material/dialog'; import { SafeUrl } from '@angular/platform-browser'; import { Subscription } from 'rxjs'; -import { ImageSelectorDialogParameter } from './image-selector-dialog-parameter.interface'; import { Base64ImageService, ClassloggerService, FileSelectorService } from 'qbm'; +import { ImageSelectorDialogParameter } from './image-selector-dialog-parameter.interface'; /** * A dialog to select an icon from a predefined list or upload an own one. @@ -38,10 +38,12 @@ import { Base64ImageService, ClassloggerService, FileSelectorService } from 'qbm @Component({ selector: 'imx-image-selector-dialog', templateUrl: './image-selector-dialog.component.html', - styleUrls: ['./image-selector-dialog.component.scss'] + styleUrls: ['./image-selector-dialog.component.scss'], }) export class ImageSelectorDialogComponent implements OnDestroy { - public get imageIsSelected(): boolean { return this.selectedIconName == null; } + public get imageIsSelected(): boolean { + return this.selectedIconName == null; + } public imageUrl: string; public fileFormatError = false; @@ -49,9 +51,9 @@ export class ImageSelectorDialogComponent implements OnDestroy { public readonly iconNames: string[] = []; public readonly title: string; - private selectedIconName: string; + private selectedIconName: string | undefined; - private readonly icons: { [name: string]: string; }; + private readonly icons: { [name: string]: string }; private readonly subscriptions: Subscription[] = []; constructor( @@ -59,19 +61,17 @@ export class ImageSelectorDialogComponent implements OnDestroy { public readonly imageHandler: Base64ImageService, private logger: ClassloggerService, @Inject(MAT_DIALOG_DATA) data: ImageSelectorDialogParameter, - private readonly fileSelector: FileSelectorService + private readonly fileSelector: FileSelectorService, ) { this.subscriptions.push( - this.fileSelector.fileFormatError.subscribe(() => this.fileFormatError = true), - this.fileSelector.fileSelected.subscribe(imageUrl => this.selectImage(imageUrl)) + this.fileSelector.fileFormatError.subscribe(() => (this.fileFormatError = true)), + this.fileSelector.fileSelected.subscribe((imageUrl) => this.selectImage(imageUrl)), ); this.title = data.title; this.icons = data.icons; - Object.keys(data.icons).forEach(iconName => - this.iconNames.push(iconName) - ); + Object.keys(data.icons).forEach((iconName) => this.iconNames.push(iconName)); if (data.imageUrl) { this.logger.debug(this, 'show and select actual assigned icon'); @@ -83,7 +83,7 @@ export class ImageSelectorDialogComponent implements OnDestroy { } public ngOnDestroy(): void { - this.subscriptions.forEach(s => s.unsubscribe()); + this.subscriptions.forEach((s) => s.unsubscribe()); } public onSave(): void { @@ -106,8 +106,11 @@ export class ImageSelectorDialogComponent implements OnDestroy { this.selectedIconName = name; } - public emitFiles(files: FileList): void { - this.fileSelector.emitFiles(files, 'image/png'); + public emitFiles(event: EventTarget | null): void { + const files: FileList | null = (event as HTMLInputElement)?.files; + if (files) { + this.fileSelector.emitFiles(files, 'image/png'); + } } public resetFileFormatErrorState(): void { diff --git a/imxweb/projects/aob/src/lib/applications/application-navigation/application-navigation.component.html b/imxweb/projects/aob/src/lib/applications/application-navigation/application-navigation.component.html index c93f3de85..13bf4970f 100644 --- a/imxweb/projects/aob/src/lib/applications/application-navigation/application-navigation.component.html +++ b/imxweb/projects/aob/src/lib/applications/application-navigation/application-navigation.component.html @@ -1,15 +1,26 @@ -
+
-

{{'#LDS#Applications' | translate}}

+

{{ '#LDS#Applications' | translate }}

-
- + {{ '#LDS#Only show applications with KPI issues' | translate }} - {{'#LDS#Applications' | translate}} [itemStatus]="status" [busyService]="busyService" (search)="onSearch($event)" - [alwaysVisible]="true"> + [alwaysVisible]="true" + > - + (selected)="onTileSelected($event)" + > - +
- diff --git a/imxweb/projects/aob/src/lib/applications/application-navigation/application-navigation.component.scss b/imxweb/projects/aob/src/lib/applications/application-navigation/application-navigation.component.scss index 23d277629..297eb4d82 100644 --- a/imxweb/projects/aob/src/lib/applications/application-navigation/application-navigation.component.scss +++ b/imxweb/projects/aob/src/lib/applications/application-navigation/application-navigation.component.scss @@ -8,12 +8,11 @@ $imx-component-width: 400px; height: inherit; max-width: $imx-component-width; - h1 { - font-size: 24px; + h2 { font-weight: 600; } - .mat-checkbox { + .mat-mdc-checkbox { margin-top: 10px; font-size: 12px; } @@ -22,11 +21,6 @@ $imx-component-width: 400px; flex-grow: 1; } - imx-data-source-paginator { - margin-top: 10px; - min-width: $imx-component-width; - } - .imx-main-container { display: flex; height: inherit; @@ -49,7 +43,6 @@ $imx-component-width: 400px; } .imx-icon-button { - line-height: 27px; background-color: $color-gray-0; margin-left: 15px; } @@ -66,10 +59,6 @@ $imx-component-width: 400px; } } - ::ng-deep .mat-badge-warn .mat-badge-content { - background-color: $color-gray-60; - } - ::ng-deep .badgeContainer { width: 355px; } @@ -78,10 +67,10 @@ $imx-component-width: 400px; margin-left: 0px; } - ::ng-deep .mat-card.imx-data-tile-container { + ::ng-deep .mat-mdc-card.imx-data-tile-container { padding: 35px 50px 0 25px; - .imx-data-tile-subtitle.mat-subheading-1 { + .imx-data-tile-subtitle.mat-body-2 { align-self: baseline; top: 10px; white-space: normal; @@ -92,7 +81,7 @@ $imx-component-width: 400px; line-height: 18px; } - .imx-data-tile-subtitle.mat-subheading-1:after { + .imx-data-tile-subtitle.mat-body-2:after { content: ''; text-align: right; position: absolute; @@ -105,14 +94,14 @@ $imx-component-width: 400px; // If line-clamp is supported, use it instead (Firefox 68+, Chrome 14+, Edge 17+) @supports (-webkit-line-clamp: 3) { - .imx-data-tile-subtitle.mat-subheading-1 { + .imx-data-tile-subtitle.mat-body-2 { display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; height: auto; top: 0px; } - .imx-data-tile-subtitle.mat-subheading-1:after { + .imx-data-tile-subtitle.mat-body-2:after { display: none; } } @@ -125,12 +114,8 @@ $imx-component-width: 400px; background-color: $color-gray-90; } - ::ng-deep .mat-badge-warn .mat-badge-content { - background-color: $color-gray-40; - } - .imx-icon-button { - background-color: $color-gray-80; + background-color: $color-gray-70; } ::ng-deep .imx-selected-icon-container { @@ -145,10 +130,6 @@ $imx-component-width: 400px; background-color: $color-gray-90; } - ::ng-deep .mat-badge-warn .mat-badge-content { - background-color: $color-gray-40; - } - .imx-icon-button { background-color: $color-gray-80; } @@ -158,11 +139,3 @@ $imx-component-width: 400px; } } } - -.eui-dark-theme { - :host { - .mat-icon-button{ - background-color: $color-gray-70; - } - } -} diff --git a/imxweb/projects/aob/src/lib/applications/application-navigation/application-navigation.component.ts b/imxweb/projects/aob/src/lib/applications/application-navigation/application-navigation.component.ts index 0cbfa7985..fa321b593 100644 --- a/imxweb/projects/aob/src/lib/applications/application-navigation/application-navigation.component.ts +++ b/imxweb/projects/aob/src/lib/applications/application-navigation/application-navigation.component.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -24,18 +24,25 @@ * */ -import { Component, Output, EventEmitter, OnInit, ViewChild } from '@angular/core'; import { Overlay } from '@angular/cdk/overlay'; +import { Component, EventEmitter, OnInit, Output, ViewChild } from '@angular/core'; import { ActivatedRoute } from '@angular/router'; import { Subject } from 'rxjs'; -import { PortalApplication, PortalApplicationNew } from 'imx-api-aob'; -import { CollectionLoadParameters, TypedEntityCollectionData, TypedEntity } from 'imx-qbm-dbts'; -import { BusyService, ClassloggerService, DataSourceToolbarSettings, DataTileBadge, DataTilesComponent, SettingsService } from 'qbm'; -import { ApplicationsService } from '../applications.service'; +import { PortalApplication, PortalApplicationNew } from '@imx-modules/imx-api-aob'; +import { CollectionLoadParameters, TypedEntity, TypedEntityCollectionData } from '@imx-modules/imx-qbm-dbts'; +import { + BusyService, + ClassloggerService, + DataSourceItemStatus, + DataSourceToolbarSettings, + DataTileBadge, + DataTilesComponent, + SettingsService, +} from 'qbm'; import { UserModelService } from 'qer'; import { AobPermissionsService } from '../../permissions/aob-permissions.service'; - +import { ApplicationsService } from '../applications.service'; /** * This component shows a list of {@link PortalApplication[]|applications} each in an @@ -47,7 +54,7 @@ import { AobPermissionsService } from '../../permissions/aob-permissions.service styleUrls: ['./application-navigation.component.scss'], }) export class ApplicationNavigationComponent implements OnInit { - public dstSettings: DataSourceToolbarSettings; + public dstSettings: DataSourceToolbarSettings | undefined; public readonly entitySchema = PortalApplication.GetEntitySchema(); public selectable = true; public multiselect = false; @@ -64,7 +71,7 @@ export class ApplicationNavigationComponent implements OnInit { */ @Output() public readonly dataSourceChanged = new EventEmitter<{ keywords?: string; - dataSource: TypedEntityCollectionData; + dataSource?: TypedEntityCollectionData; }>(); /** @@ -75,9 +82,10 @@ export class ApplicationNavigationComponent implements OnInit { /** * a status that defines, how badges are calculated */ - public readonly status = { + public readonly status: DataSourceItemStatus = { getBadges: (application: PortalApplication | PortalApplicationNew): DataTileBadge[] => this.appService.getApplicationBadges(application), + enabled: (item: TypedEntity) => true, }; private navigationState: CollectionLoadParameters & { @@ -94,13 +102,11 @@ export class ApplicationNavigationComponent implements OnInit { private readonly route: ActivatedRoute, private readonly applicationsProvider: ApplicationsService, private readonly aobPermissionsService: AobPermissionsService, - public overlay: Overlay + public overlay: Overlay, ) {} - public async ngOnInit(): Promise { - - this.isAdmin = await this.aobPermissionsService.isAobApplicationAdmin(); + this.isAdmin = await this.aobPermissionsService.isAobApplicationAdmin(); this.applicationsProvider.applicationRefresh.subscribe((res) => { if (res) { @@ -114,10 +120,10 @@ export class ApplicationNavigationComponent implements OnInit { * Emits the applicationSelected event, if the selected tile changes * @param selection the {@link PortalApplication | application} that is selected */ - public async onSelectionChanged(selection: PortalApplication[]): Promise { + public async onSelectionChanged(selection: TypedEntity[]): Promise { const app = selection[0]; if (app) { - this.applicationSelected.emit(app.UID_AOBApplication.value); + this.applicationSelected.emit(app.GetEntity().GetColumn('UID_AOBApplication').GetValue()); } } /** @@ -156,9 +162,9 @@ export class ApplicationNavigationComponent implements OnInit { this.dataSourceChanged.emit({ keywords, dataSource }); this.route.queryParams.subscribe(async (params) => { - if (params.id) { - let app = dataSource.Data.find((x) => x.UID_AOBApplication.value == params.id); - this.selectedEntity = app; + const selectedEntity = dataSource?.Data.find((x) => x.UID_AOBApplication.value == params.id); + if (params.id && selectedEntity) { + this.selectedEntity = selectedEntity; } }); } finally { @@ -181,7 +187,7 @@ export class ApplicationNavigationComponent implements OnInit { this.navigationState.StartIndex = 0; if (keywords == null || keywords.length === 0) { - this.navigationState.search = null; + this.navigationState.search = ''; } else { this.navigationState.search = keywords; } diff --git a/imxweb/projects/aob/src/lib/applications/applications-routing.module.ts b/imxweb/projects/aob/src/lib/applications/applications-routing.module.ts index d2dfc6e76..fcceed600 100644 --- a/imxweb/projects/aob/src/lib/applications/applications-routing.module.ts +++ b/imxweb/projects/aob/src/lib/applications/applications-routing.module.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -42,27 +42,27 @@ const routes: Routes = [ path: 'navigation', component: ApplicationNavigationComponent, canActivate: [RouteGuardService], - resolve: [RouteGuardService] + resolve: [RouteGuardService], }, { path: 'detail', component: ApplicationDetailComponent, outlet: 'content', canActivate: [RouteGuardService], - resolve: [RouteGuardService] + resolve: [RouteGuardService], }, { path: '', redirectTo: 'navigation', - pathMatch: 'full' - } - ] + pathMatch: 'full', + }, + ], }, - { path: ':create:id', redirectTo: 'applications', pathMatch: 'full' } + { path: ':create:id', redirectTo: 'applications', pathMatch: 'full' }, ]; @NgModule({ imports: [RouterModule.forChild(routes)], - exports: [RouterModule] + exports: [RouterModule], }) -export class ApplicationsRoutingModule { } +export class ApplicationsRoutingModule {} diff --git a/imxweb/projects/aob/src/lib/applications/applications.component.html b/imxweb/projects/aob/src/lib/applications/applications.component.html index e5f971373..0b77541ab 100644 --- a/imxweb/projects/aob/src/lib/applications/applications.component.html +++ b/imxweb/projects/aob/src/lib/applications/applications.component.html @@ -2,5 +2,5 @@
- +
diff --git a/imxweb/projects/aob/src/lib/applications/applications.component.scss b/imxweb/projects/aob/src/lib/applications/applications.component.scss index a556393a6..574fcaba3 100644 --- a/imxweb/projects/aob/src/lib/applications/applications.component.scss +++ b/imxweb/projects/aob/src/lib/applications/applications.component.scss @@ -1,7 +1,6 @@ @import '@elemental-ui/core/src/styles/_palette.scss'; @import '@elemental-ui/core/src/styles/_eui_palette.scss'; - :host { display: flex; margin: 0; @@ -20,19 +19,11 @@ overflow: hidden; } -.mat-raised-button { - justify-self: center; - margin-top: 30px; -} - .eui-dark-theme { :host { .imx-application-content { background-color: $color-gray-80; } - ::ng-deep .imx-application-content .mat-tab-body{ - background-color: $color-gray-80; - } } } @@ -41,8 +32,5 @@ .imx-application-content { background-color: $color-gray-90; } - ::ng-deep .imx-application-content .mat-tab-body{ - background-color: $color-gray-90; - } } } diff --git a/imxweb/projects/aob/src/lib/applications/applications.component.ts b/imxweb/projects/aob/src/lib/applications/applications.component.ts index 23874dd17..b4800df23 100644 --- a/imxweb/projects/aob/src/lib/applications/applications.component.ts +++ b/imxweb/projects/aob/src/lib/applications/applications.component.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -25,18 +25,18 @@ */ import { Component, OnDestroy, OnInit } from '@angular/core'; -import { Router, ActivatedRoute } from '@angular/router'; +import { ActivatedRoute, Router } from '@angular/router'; import { Subject, Subscription } from 'rxjs'; import { EuiLoadingService } from '@elemental-ui/core'; -import { PortalApplication } from 'imx-api-aob'; +import { PortalApplication } from '@imx-modules/imx-api-aob'; +import { TypedEntityCollectionData } from '@imx-modules/imx-qbm-dbts'; import { ClassloggerService, SnackBarService } from 'qbm'; -import { TypedEntityCollectionData } from 'imx-qbm-dbts'; -import { ApplicationsService } from './applications.service'; -import { ApplicationNavigationComponent } from './application-navigation/application-navigation.component'; -import { ApplicationDetailComponent } from './application-detail.component'; import { ApplicationContent } from './application-content.interface'; +import { ApplicationDetailComponent } from './application-detail.component'; +import { ApplicationNavigationComponent } from './application-navigation/application-navigation.component'; +import { ApplicationsService } from './applications.service'; @Component({ selector: 'imx-applications', @@ -44,7 +44,7 @@ import { ApplicationContent } from './application-content.interface'; styleUrls: ['./applications.component.scss'], }) export class ApplicationsComponent implements OnDestroy, OnInit { - private selectedApplication: PortalApplication; + private selectedApplication: PortalApplication | undefined; private dataSource: TypedEntityCollectionData; private applicationNavigation: ApplicationNavigationComponent; private applicationContent: ApplicationContent; @@ -57,7 +57,7 @@ export class ApplicationsComponent implements OnDestroy, OnInit { private readonly busyService: EuiLoadingService, private readonly router: Router, private readonly route: ActivatedRoute, - private readonly snackbar: SnackBarService + private readonly snackbar: SnackBarService, ) { this.subscriptions.push( this.applicationsProvider.onApplicationCreated.subscribe(async (uidApplication: string) => { @@ -75,19 +75,23 @@ export class ApplicationsComponent implements OnDestroy, OnInit { this.applicationContent.application = this.selectedApplication; return this.redirectToAppDetails(this.selectedApplication.UID_AOBApplication.value); - }) + }), ); this.subscriptions.push( this.applicationsProvider.onApplicationDeleted.subscribe(async (uidApplication: string) => { - const index = this.dataSource.Data.findIndex(elem => elem.UID_AOBApplication.value === uidApplication); + const index = this.dataSource.Data.findIndex((elem) => elem.UID_AOBApplication.value === uidApplication); if (index < 0) { - return this.redirectToAppDetails(null); + return this.redirectToAppDetails(''); } const removed = this.dataSource.Data.splice(index, 1); - this.applicationContent.application = null; - this.snackbar.open({ key: '#LDS#The application "{0}" has been successfully deleted.', parameters: [removed[0].GetEntity().GetDisplay()] }); - return this.redirectToAppDetails(null); - })); + this.applicationContent.application = undefined; + this.snackbar.open({ + key: '#LDS#The application "{0}" has been successfully deleted.', + parameters: [removed[0].GetEntity().GetDisplay()], + }); + return this.redirectToAppDetails(''); + }), + ); } public ngOnInit(): void { @@ -102,8 +106,9 @@ export class ApplicationsComponent implements OnDestroy, OnInit { if (params.id) { this.selectedApplication = await this.applicationsProvider.reload(params.id); } - - this.applicationContent.application = this.selectedApplication; + if (this.selectedApplication) { + this.applicationContent.application = this.selectedApplication; + } if (!this.selectedApplication) { this.applicationNavigation.clearSelection(); @@ -126,18 +131,17 @@ export class ApplicationsComponent implements OnDestroy, OnInit { this.applicationNavigation.loadingSubject = this.loadingSubject; this.subscriptions.push( - this.applicationNavigation.applicationSelected.subscribe((uidApplication: string) => - this.redirectToAppDetails(uidApplication) - ) + this.applicationNavigation.applicationSelected.subscribe((uidApplication: string) => this.redirectToAppDetails(uidApplication)), ); this.subscriptions.push( - this.applicationNavigation.dataSourceChanged.subscribe((changeSet: - { keywords: string; dataSource: TypedEntityCollectionData }) => { - this.dataSource = changeSet?.dataSource; - this.applicationContent.totalCount = this.dataSource?.totalCount ?? 0; - this.applicationContent.keywords = changeSet?.keywords; - }) + this.applicationNavigation.dataSourceChanged.subscribe( + (changeSet: { keywords: string; dataSource: TypedEntityCollectionData }) => { + this.dataSource = changeSet?.dataSource; + this.applicationContent.totalCount = this.dataSource?.totalCount ?? 0; + this.applicationContent.keywords = changeSet?.keywords; + }, + ), ); } @@ -151,7 +155,7 @@ export class ApplicationsComponent implements OnDestroy, OnInit { } // reload app: - this.selectedApplication = await this.applicationsProvider.reload(this.selectedApplication.UID_AOBApplication.value) + this.selectedApplication = await this.applicationsProvider.reload(this.selectedApplication.UID_AOBApplication.value); if (applicationContent instanceof ApplicationDetailComponent) { this.applicationContent.application = this.selectedApplication; @@ -162,16 +166,17 @@ export class ApplicationsComponent implements OnDestroy, OnInit { return ( route.children && route.children.length > 1 && - route.children[1].routeConfig.outlet.toLowerCase() === 'content' && - route.children[1].routeConfig.path.toLowerCase() === 'edit' + route.children[1].routeConfig?.outlet?.toLowerCase() === 'content' && + route.children[1].routeConfig?.path?.toLowerCase() === 'edit' ); } private async redirectToAppDetails(uidApplication: string): Promise { this.logger.trace(this, 'Redirecting to details view.'); - return this.router.navigate( - ['applications', { outlets: { content: ['detail'] } }], - uidApplication ? { queryParams: { id: uidApplication } } : undefined) + return this.router.navigate( + ['applications', { outlets: { content: ['detail'] } }], + uidApplication ? { queryParams: { id: uidApplication } } : undefined, + ); } } diff --git a/imxweb/projects/aob/src/lib/applications/applications.module.ts b/imxweb/projects/aob/src/lib/applications/applications.module.ts index 3fa03370a..2e9733c35 100644 --- a/imxweb/projects/aob/src/lib/applications/applications.module.ts +++ b/imxweb/projects/aob/src/lib/applications/applications.module.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -24,9 +24,11 @@ * */ -import { NgModule } from '@angular/core'; +import { OverlayModule } from '@angular/cdk/overlay'; +import { PortalModule } from '@angular/cdk/portal'; import { CommonModule } from '@angular/common'; -import { EuiCoreModule, EuiMaterialModule } from '@elemental-ui/core'; +import { NgModule } from '@angular/core'; +import { FormsModule, ReactiveFormsModule } from '@angular/forms'; import { MatAutocompleteModule } from '@angular/material/autocomplete'; import { MatBadgeModule } from '@angular/material/badge'; import { MatButtonModule } from '@angular/material/button'; @@ -35,53 +37,50 @@ import { MatDialogModule } from '@angular/material/dialog'; import { MatDividerModule } from '@angular/material/divider'; import { MatIconModule } from '@angular/material/icon'; import { MatInputModule } from '@angular/material/input'; -import { MatTabsModule } from '@angular/material/tabs'; -import { TranslateModule } from '@ngx-translate/core'; -import { FormsModule, ReactiveFormsModule } from '@angular/forms'; -import { OverlayModule } from '@angular/cdk/overlay'; import { RouterModule } from '@angular/router'; -import { PortalModule } from '@angular/cdk/portal'; +import { EuiCoreModule, EuiMaterialModule } from '@elemental-ui/core'; +import { TranslateModule } from '@ngx-translate/core'; -import { ApplicationDetailComponent } from './application-detail.component'; -import { ApplicationDetailsComponent } from './application-details/application-details.component'; -import { ApplicationHyperviewModule } from './application-hyperview/application-hyperview.module'; -import { ApplicationNavigationComponent } from './application-navigation/application-navigation.component'; -import { ApplicationsComponent } from './applications.component'; -import { ApplicationsService } from './applications.service'; -import { ColumnInfoModule } from '../column-info/column-info.module'; -import { EditApplicationComponent } from './edit-application/edit-application.component'; -import { EntitlementsModule } from '../entitlements/entitlements.module'; -import { KpiModule } from '../kpi/kpi.module'; +import { MatTooltipModule } from '@angular/material/tooltip'; import { + BusyIndicatorModule, + CdrModule, ClassloggerModule, DataSourceToolbarModule, + DataTableModule, DataTilesModule, - QbmModule, - SelectModule, - LdsReplaceModule, - FkAdvancedPickerModule, + DataTreeModule, + DataTreeWrapperModule, + DataViewModule, + DateModule, EntityModule, + FkAdvancedPickerModule, + HelpContextualModule, ImageModule, - CdrModule, - DataTableModule, - DateModule, InfoModalDialogModule, - HelpContextualModule, - BusyIndicatorModule, - DataTreeModule, - DataTreeWrapperModule + LdsReplaceModule, + QbmModule, } from 'qbm'; -import { AobUserModule } from '../user/user.module'; +import { ObjectHyperviewModule } from 'qer'; import { ApplicationPropertyModule } from '../application-property/application-property.module'; +import { ColumnInfoModule } from '../column-info/column-info.module'; +import { EntitlementsModule } from '../entitlements/entitlements.module'; +import { KpiModule } from '../kpi/kpi.module'; +import { AobUserModule } from '../user/user.module'; import { ApplicationCreateComponent } from './application-create/application-create.component'; +import { ApplicationDetailComponent } from './application-detail.component'; +import { ApplicationDetailsComponent } from './application-details/application-details.component'; import { ApplicationImageSelectComponent } from './application-image-select/application-image-select.component'; import { ImageSelectorDialogComponent } from './application-image-select/image-selector-dialog/image-selector-dialog.component'; +import { ApplicationNavigationComponent } from './application-navigation/application-navigation.component'; +import { ApplicationsComponent } from './applications.component'; +import { ApplicationsService } from './applications.service'; import { AuthenticationRootComponent } from './edit-application/authentication-root/authentication-root.component'; +import { EditApplicationComponent } from './edit-application/edit-application.component'; +import { EditServiceCategoryInformationComponent } from './edit-application/service-category/edit-service-category-information/edit-service-category-information.component'; +import { ServiceCategoryComponent } from './edit-application/service-category/service-category.component'; import { IdentitiesComponent } from './identities/identities.component'; import { IdentityDetailComponent } from './identities/identity-detail/identity-detail.component'; -import { ServiceCategoryComponent } from './edit-application/service-category/service-category.component'; -import { MatTooltipModule } from '@angular/material/tooltip'; -import { EditServiceCategoryInformationComponent } from './edit-application/service-category/edit-service-category-information/edit-service-category-information.component'; @NgModule({ declarations: [ @@ -97,11 +96,10 @@ import { EditServiceCategoryInformationComponent } from './edit-application/serv IdentitiesComponent, IdentityDetailComponent, ServiceCategoryComponent, - EditServiceCategoryInformationComponent + EditServiceCategoryInformationComponent, ], imports: [ CommonModule, - ApplicationHyperviewModule, ApplicationPropertyModule, ClassloggerModule, ColumnInfoModule, @@ -118,8 +116,6 @@ import { EditServiceCategoryInformationComponent } from './edit-application/serv MatDividerModule, MatIconModule, MatInputModule, - MatTabsModule, - SelectModule, MatDialogModule, MatTooltipModule, QbmModule, @@ -142,12 +138,10 @@ import { EditServiceCategoryInformationComponent } from './edit-application/serv InfoModalDialogModule, HelpContextualModule, BusyIndicatorModule, + ObjectHyperviewModule, + DataViewModule, ], - providers: [ - ApplicationsService - ], - exports: [ - ApplicationsComponent, - ], + providers: [ApplicationsService], + exports: [ApplicationsComponent], }) -export class ApplicationsModule { } +export class ApplicationsModule {} diff --git a/imxweb/projects/aob/src/lib/applications/applications.service.ts b/imxweb/projects/aob/src/lib/applications/applications.service.ts index 4199479a6..01f4a9bfd 100644 --- a/imxweb/projects/aob/src/lib/applications/applications.service.ts +++ b/imxweb/projects/aob/src/lib/applications/applications.service.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -24,15 +24,14 @@ * */ -import { OverlayRef } from '@angular/cdk/overlay'; -import { Injectable, ErrorHandler } from '@angular/core'; +import { ErrorHandler, Injectable } from '@angular/core'; import { EuiLoadingService, EuiSidesheetService, EuiTheme } from '@elemental-ui/core'; import { TranslateService } from '@ngx-translate/core'; import { BehaviorSubject, Subject } from 'rxjs'; -import { PortalApplication, PortalApplicationInteractive, PortalApplicationNew } from 'imx-api-aob'; -import { TypedEntityCollectionData, CollectionLoadParameters, EntitySchema } from 'imx-qbm-dbts'; -import { ApiClientService, ClassloggerService, DataTileBadge, SnackBarService } from 'qbm'; +import { PortalApplication, PortalApplicationNew } from '@imx-modules/imx-api-aob'; +import { CollectionLoadParameters, EntitySchema, TypedEntityCollectionData } from '@imx-modules/imx-qbm-dbts'; +import { ApiClientService, calculateSidesheetWidth, ClassloggerService, DataTileBadge, SnackBarService } from 'qbm'; import { AobApiService } from '../aob-api-client.service'; import { ApplicationCreateComponent } from './application-create/application-create.component'; @@ -65,10 +64,10 @@ export class ApplicationsService { return bodyClasses.contains(EuiTheme.LIGHT) ? EuiTheme.LIGHT : bodyClasses.contains(EuiTheme.DARK) - ? EuiTheme.DARK - : bodyClasses.contains(EuiTheme.CONTRAST) - ? EuiTheme.CONTRAST - : ''; + ? EuiTheme.DARK + : bodyClasses.contains(EuiTheme.CONTRAST) + ? EuiTheme.CONTRAST + : ''; } constructor( @@ -79,7 +78,7 @@ export class ApplicationsService { private readonly translateService: TranslateService, private readonly sidesheet: EuiSidesheetService, private readonly snackbar: SnackBarService, - private readonly busyService: EuiLoadingService + private readonly busyService: EuiLoadingService, ) { this.translateService.get('#LDS#Published').subscribe((trans: string) => (this.publishedText = trans)); this.translateService.get('#LDS#KPI issues').subscribe((trans: string) => (this.kpiErrorsText = trans)); @@ -89,16 +88,16 @@ export class ApplicationsService { /** * Encapsules the aob/applications GET endpoint and delivers a list of {@link PortalApplication[]|applications}. */ - public async get(parameters: CollectionLoadParameters = {}): Promise> { + public async get(parameters: CollectionLoadParameters = {}): Promise | undefined> { if (this.aobClient.typedClient == null) { - return new Promise>((resolve) => resolve(null)); + return new Promise((resolve) => resolve(undefined)); } return this.apiProvider.request(() => this.aobClient.typedClient.PortalApplication.Get(parameters)); } - public async reload(uidApplication: string): Promise { + public async reload(uidApplication: string): Promise { return await this.apiProvider.request( - async () => (await this.aobClient.typedClient.PortalApplicationInteractive.Get_byid(uidApplication)).Data[0] + async () => (await this.aobClient.typedClient.PortalApplicationInteractive.Get_byid(uidApplication)).Data[0], ); } @@ -187,7 +186,7 @@ export class ApplicationsService { .open(ApplicationCreateComponent, { title: await this.translateService.get('#LDS#Heading Create Application').toPromise(), padding: '0px', - width: 'max(600px, 60%)', + width: calculateSidesheetWidth(), disableClose: true, testId: 'create-aob-application', data: { @@ -198,8 +197,9 @@ export class ApplicationsService { .toPromise(); if (result) { - let overlayRef: OverlayRef; - setTimeout(() => (overlayRef = this.busyService.show())); + if (this.busyService.overlayRefs.length === 0) { + this.busyService.show(); + } try { await application.GetEntity().Commit(true); @@ -208,7 +208,7 @@ export class ApplicationsService { } catch (error) { this.errorHandler.handleError(error); } finally { - setTimeout(() => this.busyService.hide(overlayRef)); + this.busyService.hide(); } } else { this.snackbar.open({ key: '#LDS#The creation of the application has been canceled.' }); @@ -245,7 +245,7 @@ export class ApplicationsService { /** * Updates the badges, that are used on the application tiles, according to the used theme - * + * * @param theme Currently used EuiTheme */ private updateBadges(theme: string): void { diff --git a/imxweb/projects/aob/src/lib/applications/edit-application/authentication-root/authentication-root.component.html b/imxweb/projects/aob/src/lib/applications/edit-application/authentication-root/authentication-root.component.html index 9b3e68fb0..a5f803630 100644 --- a/imxweb/projects/aob/src/lib/applications/edit-application/authentication-root/authentication-root.component.html +++ b/imxweb/projects/aob/src/lib/applications/edit-application/authentication-root/authentication-root.component.html @@ -1,11 +1,16 @@ - + - {{ '#LDS#Please specify a value for {0}.' | translate | ldsReplace:application.AuthenticationRoot.GetMetadata().GetDisplay() }} + {{ '#LDS#Please specify a value for {0}.' | translate | ldsReplace: application.AuthenticationRoot.GetMetadata().GetDisplay() }} - + (valueChange)="form.updateValueAndValidity()" +> diff --git a/imxweb/projects/aob/src/lib/applications/edit-application/authentication-root/authentication-root.component.scss b/imxweb/projects/aob/src/lib/applications/edit-application/authentication-root/authentication-root.component.scss index 3364f1f4f..c9e89c84d 100644 --- a/imxweb/projects/aob/src/lib/applications/edit-application/authentication-root/authentication-root.component.scss +++ b/imxweb/projects/aob/src/lib/applications/edit-application/authentication-root/authentication-root.component.scss @@ -1 +1 @@ -// styles \ No newline at end of file +// styles diff --git a/imxweb/projects/aob/src/lib/applications/edit-application/authentication-root/authentication-root.component.ts b/imxweb/projects/aob/src/lib/applications/edit-application/authentication-root/authentication-root.component.ts index 6c1654663..fa6507ccf 100644 --- a/imxweb/projects/aob/src/lib/applications/edit-application/authentication-root/authentication-root.component.ts +++ b/imxweb/projects/aob/src/lib/applications/edit-application/authentication-root/authentication-root.component.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -27,16 +27,16 @@ import { Component, EventEmitter, Input, OnInit, Output } from '@angular/core'; import { AbstractControl, UntypedFormGroup } from '@angular/forms'; -import { PortalApplication } from 'imx-api-aob'; +import { PortalApplication } from '@imx-modules/imx-api-aob'; import { BaseCdr } from 'qbm'; @Component({ selector: 'imx-authentication-root', templateUrl: './authentication-root.component.html', - styleUrls: ['./authentication-root.component.scss'] + styleUrls: ['./authentication-root.component.scss'], }) export class AuthenticationRootComponent implements OnInit { - public readonly form = new UntypedFormGroup({}, __ => { + public readonly form = new UntypedFormGroup({}, (__) => { if (this.application == null) { return null; } @@ -46,7 +46,7 @@ export class AuthenticationRootComponent implements OnInit { return !authenticationRootValue?.length && isAuthenticationIntegrated ? { relationInvalid: true } : null; }); - public authenticationRootWrapper: BaseCdr; + public authenticationRootWrapper: BaseCdr; @Input() public application: PortalApplication; @@ -58,7 +58,7 @@ export class AuthenticationRootComponent implements OnInit { if (!authenticationRootHelper.value?.length) { await authenticationRootHelper.Column.PutValueStruct({ DataValue: this.application.AuthenticationRoot.value, - DisplayValue: this.application.AuthenticationRoot.Column.GetDisplayValue() + DisplayValue: this.application.AuthenticationRoot.Column.GetDisplayValue(), }); } diff --git a/imxweb/projects/aob/src/lib/applications/edit-application/edit-application.component.html b/imxweb/projects/aob/src/lib/applications/edit-application/edit-application.component.html index 9320c4a3c..95fa82ee8 100644 --- a/imxweb/projects/aob/src/lib/applications/edit-application/edit-application.component.html +++ b/imxweb/projects/aob/src/lib/applications/edit-application/edit-application.component.html @@ -1,19 +1,27 @@
- -
-
- + + +
+ - + + + - - + - + - + - + - + + + + + + + - + - - + - + - - + - + - - + - +
@@ -54,13 +65,13 @@
- -
diff --git a/imxweb/projects/aob/src/lib/applications/edit-application/edit-application.component.scss b/imxweb/projects/aob/src/lib/applications/edit-application/edit-application.component.scss deleted file mode 100644 index b890d9141..000000000 --- a/imxweb/projects/aob/src/lib/applications/edit-application/edit-application.component.scss +++ /dev/null @@ -1,26 +0,0 @@ -.imx-form { - display: flex; - justify-content: space-between; - margin-right: 10px; -} - -.imx-input-fields { - display: flex; - flex-direction: column; - flex-grow: 1; - max-width: 600px; -} - -.imx-checkbox-error { - margin-left: 24px; -} - -.eui-sidesheet-actions { - .justify-start { - margin-right: auto; - } - - button:not(:last-of-type):not(.justify-start) { - margin-right: 10px; - } -} diff --git a/imxweb/projects/aob/src/lib/applications/edit-application/edit-application.component.ts b/imxweb/projects/aob/src/lib/applications/edit-application/edit-application.component.ts index 41fd09e75..6fb93d1f2 100644 --- a/imxweb/projects/aob/src/lib/applications/edit-application/edit-application.component.ts +++ b/imxweb/projects/aob/src/lib/applications/edit-application/edit-application.component.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -24,33 +24,31 @@ * */ -import { Component, Output, EventEmitter, ErrorHandler, Inject } from '@angular/core'; -import { UntypedFormGroup } from '@angular/forms'; -import { EuiLoadingService, EuiSidesheetRef, EUI_SIDESHEET_DATA } from '@elemental-ui/core'; +import { Component, ErrorHandler, EventEmitter, Inject, Output } from '@angular/core'; +import { AbstractControl, UntypedFormGroup } from '@angular/forms'; +import { EUI_SIDESHEET_DATA, EuiLoadingService, EuiSidesheetRef } from '@elemental-ui/core'; import { TranslateService } from '@ngx-translate/core'; -import { PortalApplication, PortalShops } from 'imx-api-aob'; -import { DbObjectKey, TypedEntity } from 'imx-qbm-dbts'; -import { ShopsService } from '../../shops/shops.service'; -import { AccountsService } from '../../accounts/accounts.service'; +import { MatDialog } from '@angular/material/dialog'; +import { PortalApplication, PortalShops } from '@imx-modules/imx-api-aob'; +import { DbObjectKey, TypedEntity } from '@imx-modules/imx-qbm-dbts'; import { ClassloggerService, - SnackBarService, - TypedEntitySelectionData, ConfirmationService, LdsReplacePipe, - TranslationEditorComponent + SnackBarService, + TranslationEditorComponent, + TypedEntitySelectionData, } from 'qbm'; -import { SelectionContainer } from './selection-container'; +import { AccountsService } from '../../accounts/accounts.service'; +import { ShopsService } from '../../shops/shops.service'; import { ApplicationContent } from '../application-content.interface'; -import { MatDialog } from '@angular/material/dialog'; +import { SelectionContainer } from './selection-container'; @Component({ selector: 'imx-edit-application', templateUrl: './edit-application.component.html', - styleUrls: ['./edit-application.component.scss'] }) - export class EditApplicationComponent implements ApplicationContent { public readonly applicationForm = new UntypedFormGroup({}); @@ -74,7 +72,7 @@ export class EditApplicationComponent implements ApplicationContent { private readonly translate: TranslateService, private readonly ldsReplace: LdsReplacePipe, @Inject(EUI_SIDESHEET_DATA) public application: PortalApplication, - private readonly dialog: MatDialog + private readonly dialog: MatDialog, ) { this.sidesheetRef.closeClicked().subscribe(async () => { if (!this.hasUnsavedChanges()) { @@ -91,8 +89,8 @@ export class EditApplicationComponent implements ApplicationContent { this.shopsData = this.getShopsData(); } - public shopSelectionChanged(selection: PortalShops[]): void { - this.shopsSelection.selected = selection; + public shopSelectionChanged(selection: TypedEntity[]): void { + this.shopsSelection.selected = selection as PortalShops[]; } public accountSelectionChanged(selection: TypedEntity[]): void { @@ -108,7 +106,9 @@ export class EditApplicationComponent implements ApplicationContent { } public async submitData(): Promise { - const overlayRef = this.busyService.show(); + if (this.busyService.overlayRefs.length === 0) { + this.busyService.show(); + } try { await this.saveShops(); @@ -123,7 +123,7 @@ export class EditApplicationComponent implements ApplicationContent { } catch (error) { this.errorHandler.handleError(error); } finally { - setTimeout(() => this.busyService.hide(overlayRef)); + this.busyService.hide(); this.sidesheetRef.close(); } } @@ -138,41 +138,48 @@ export class EditApplicationComponent implements ApplicationContent { this.sidesheetRef.close(); } - public editTranslation(){ - const dialogConfig = { - data: this.application, - width: '600px' - } - this.dialog.open(TranslationEditorComponent,dialogConfig); + public editTranslation() { + const dialogConfig = { + data: this.application, + width: '600px', + }; + this.dialog.open(TranslationEditorComponent, dialogConfig); } - private getShopsData(): TypedEntitySelectionData { + public addAndValidate(event: { name: string; control: AbstractControl }) { + this.applicationForm.addControl(event.name, event.control); + event.control.updateValueAndValidity(); + } + + private getShopsData(): TypedEntitySelectionData { return { title: '#LDS#Heading Edit IT Shop Structures', valueWrapper: { display: this.shopsProvider.display, name: 'shops', - canEdit: true + canEdit: true, }, getInitialDisplay: async () => { const info = await this.shopsProvider.getFirstAndCount(this.application.UID_AOBApplication.value); - return this.buildInitalValue(info.first, info.count); + if (info.first) { + return this.buildInitalValue(info.first, info.count); + } + return ''; }, getSelected: async () => { - this.shopsSelection.init((await this.shopsProvider.getApplicationInShop( - this.application.UID_AOBApplication.value, { PageSize: 100000 } - ))?.Data); + this.shopsSelection.init( + (await this.shopsProvider.getApplicationInShop(this.application.UID_AOBApplication.value, { PageSize: 100000 }))?.Data || [], + ); return this.shopsSelection.selected; }, - getTyped: parameters => this.shopsProvider.get(parameters), + getTyped: (parameters) => this.shopsProvider.get(parameters), }; } private async saveShops(): Promise { if (this.shopsData) { this.logger.debug(this, 'submitData - update shops...'); - const result = - await this.shopsProvider.updateApplicationInShops(this.application, this.shopsSelection.getChangeSet()); + const result = await this.shopsProvider.updateApplicationInShops(this.application, this.shopsSelection.getChangeSet()); if (!result) { this.logger.error(this, 'Attempt to update the shops failed'); } @@ -185,27 +192,29 @@ export class EditApplicationComponent implements ApplicationContent { valueWrapper: { display: this.accountsProvider.display, name: 'accounts', - canEdit: true + canEdit: true, }, getInitialDisplay: async () => { const info = await this.accountsProvider.getFirstAndCount(this.application.UID_AOBApplication.value); - return this.buildInitalValue(info.first, info.count); + if (info.first) { + return this.buildInitalValue(info.first, info.count); + } + return ''; }, getSelected: async () => { - this.accountsSelection.init(await this.accountsProvider.getAssigned( - this.application.UID_AOBApplication.value, - { PageSize: 100000 } - )); + this.accountsSelection.init( + await this.accountsProvider.getAssigned(this.application.UID_AOBApplication.value, { PageSize: 100000 }), + ); return this.accountsSelection.selected; }, dynamicFkRelation: { tables: this.accountsProvider.getCandidateTables(), - getSelectedTableName: selected => { + getSelectedTableName: (selected) => { if (selected?.length > 0) { return DbObjectKey.FromXml(selected[0].GetEntity().GetColumn('XObjectKey').GetValue()).TableName; } - return undefined; - } + return ''; + }, }, }; } @@ -213,8 +222,7 @@ export class EditApplicationComponent implements ApplicationContent { private async saveAccounts(): Promise { if (this.accountsData) { this.logger.debug(this, 'submitData - update accounts...'); - const result = - await this.accountsProvider.updateApplicationUsesAccounts(this.application, this.accountsSelection.getChangeSet()); + const result = await this.accountsProvider.updateApplicationUsesAccounts(this.application, this.accountsSelection.getChangeSet()); if (!result) { this.logger.error(this, 'Attempt to update the accounts failed'); } @@ -222,8 +230,10 @@ export class EditApplicationComponent implements ApplicationContent { } private async buildInitalValue(entity: TypedEntity, count: number): Promise { - return count < 1 ? '' : - count === 1 ? entity.GetEntity().GetDisplay() : - this.ldsReplace.transform(await this.translate.get('#LDS#{0} items selected').toPromise(), count); + return count < 1 + ? '' + : count === 1 + ? entity.GetEntity().GetDisplay() + : this.ldsReplace.transform(await this.translate.get('#LDS#{0} items selected').toPromise(), count); } } diff --git a/imxweb/projects/aob/src/lib/applications/edit-application/selection-container.spec.ts b/imxweb/projects/aob/src/lib/applications/edit-application/selection-container.spec.ts index 01c178e9c..359399c82 100644 --- a/imxweb/projects/aob/src/lib/applications/edit-application/selection-container.spec.ts +++ b/imxweb/projects/aob/src/lib/applications/edit-application/selection-container.spec.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -31,45 +31,46 @@ describe('SelectionContainer', () => { { assigned: [], selected: [], - expected: { adds: 0, removes: 0 } + expected: { adds: 0, removes: 0 }, }, { assigned: [0], selected: [], - expected: { adds: 0, removes: 1 } + expected: { adds: 0, removes: 1 }, }, { assigned: [0], selected: [0], - expected: { adds: 0, removes: 0 } + expected: { adds: 0, removes: 0 }, }, { assigned: [], selected: [0], - expected: { adds: 1, removes: 0 } + expected: { adds: 1, removes: 0 }, }, { assigned: [1], selected: [0], - expected: { adds: 1, removes: 1 } + expected: { adds: 1, removes: 1 }, }, { - assigned: [0,1], - selected: [0,1], - expected: { adds: 0, removes: 0 } + assigned: [0, 1], + selected: [0, 1], + expected: { adds: 0, removes: 0 }, }, { - assigned: [0,1], + assigned: [0, 1], selected: [], - expected: { adds: 0, removes: 2 } - } - ].forEach(testcase => - it('creates the correct changeSet, assigned ' + testcase.assigned + ', selected ' + testcase.selected, () => { - const selected = new SelectionContainer<{ id: string }>(item => item.id); - selected.init(testcase.assigned.map(id => ({ id: id.toString() }))); - selected.selected = testcase.selected.map(id => ({ id: id.toString() })); - const change = selected.getChangeSet(); - expect(change.add.length).toEqual(testcase.expected.adds); - expect(change.remove.length).toEqual(testcase.expected.removes); - })); -}); \ No newline at end of file + expected: { adds: 0, removes: 2 }, + }, + ].forEach((testcase) => + it('creates the correct changeSet, assigned ' + testcase.assigned + ', selected ' + testcase.selected, () => { + const selected = new SelectionContainer<{ id: string }>((item) => item.id); + selected.init(testcase.assigned.map((id) => ({ id: id.toString() }))); + selected.selected = testcase.selected.map((id) => ({ id: id.toString() })); + const change = selected.getChangeSet(); + expect(change.add.length).toEqual(testcase.expected.adds); + expect(change.remove.length).toEqual(testcase.expected.removes); + }), + ); +}); diff --git a/imxweb/projects/aob/src/lib/applications/edit-application/selection-container.ts b/imxweb/projects/aob/src/lib/applications/edit-application/selection-container.ts index 9ca5eabbf..b33253c41 100644 --- a/imxweb/projects/aob/src/lib/applications/edit-application/selection-container.ts +++ b/imxweb/projects/aob/src/lib/applications/edit-application/selection-container.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -25,27 +25,28 @@ */ export class SelectionContainer { - public selected: T[] = []; + public selected: T[] = []; - private assigned: T[] = []; + private assigned: T[] = []; - constructor(private getKey: (item: T) => string) { } + constructor(private getKey: (item: T) => string) {} - public init(assigned: T[]): void { - this.assigned = assigned; - this.selected = assigned.slice(); - } + public init(assigned: T[]): void { + this.assigned = assigned; + this.selected = assigned.slice(); + } - public getChangeSet(): { add: T[], remove: T[] } { - return { - add: this.selected.filter(item => this.assigned.find(itemAssigned => this.equals(item, itemAssigned)) == null), - remove: this.selected == null || this.selected.length === 0 ? - this.assigned : - this.assigned.filter(itemAssigned => this.selected.find(item => this.equals(item, itemAssigned)) == null) - }; - } + public getChangeSet(): { add: T[]; remove: T[] } { + return { + add: this.selected.filter((item) => this.assigned.find((itemAssigned) => this.equals(item, itemAssigned)) == null), + remove: + this.selected == null || this.selected.length === 0 + ? this.assigned + : this.assigned.filter((itemAssigned) => this.selected.find((item) => this.equals(item, itemAssigned)) == null), + }; + } - private equals(item1: T, item2: T): boolean { - return this.getKey(item1) === this.getKey(item2); - } + private equals(item1: T, item2: T): boolean { + return this.getKey(item1) === this.getKey(item2); + } } diff --git a/imxweb/projects/aob/src/lib/applications/edit-application/service-category/edit-service-category-information/edit-service-category-information.component.html b/imxweb/projects/aob/src/lib/applications/edit-application/service-category/edit-service-category-information/edit-service-category-information.component.html index e21239303..6b0183ab1 100644 --- a/imxweb/projects/aob/src/lib/applications/edit-application/service-category/edit-service-category-information/edit-service-category-information.component.html +++ b/imxweb/projects/aob/src/lib/applications/edit-application/service-category/edit-service-category-information/edit-service-category-information.component.html @@ -4,7 +4,7 @@ @@ -12,7 +12,13 @@
-
diff --git a/imxweb/projects/aob/src/lib/applications/edit-application/service-category/edit-service-category-information/edit-service-category-information.component.ts b/imxweb/projects/aob/src/lib/applications/edit-application/service-category/edit-service-category-information/edit-service-category-information.component.ts index ecb7cd33c..44559480a 100644 --- a/imxweb/projects/aob/src/lib/applications/edit-application/service-category/edit-service-category-information/edit-service-category-information.component.ts +++ b/imxweb/projects/aob/src/lib/applications/edit-application/service-category/edit-service-category-information/edit-service-category-information.component.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -25,11 +25,11 @@ */ import { Component, Inject, OnInit } from '@angular/core'; +import { FormArray, FormGroup } from '@angular/forms'; import { EUI_SIDESHEET_DATA, EuiSidesheetRef } from '@elemental-ui/core'; -import { IEntity } from 'imx-qbm-dbts'; +import { IEntity } from '@imx-modules/imx-qbm-dbts'; import { BaseCdr, CdrFactoryService, ColumnDependentReference, ConfirmationService } from 'qbm'; import { ServiceCategoryService } from '../service-category.service'; -import { FormArray, FormGroup } from '@angular/forms'; interface ServiceItemForm { cdrArray: FormArray; @@ -40,7 +40,7 @@ interface ServiceItemForm { styleUrls: ['./edit-service-category-information.component.scss'], }) export class EditServiceCategoryInformationComponent implements OnInit { - public cdrList: ColumnDependentReference[]; + public cdrList: (ColumnDependentReference | undefined)[]; public readonly formGroup: FormGroup; @@ -53,10 +53,10 @@ export class EditServiceCategoryInformationComponent implements OnInit { private readonly confirm: ConfirmationService, private readonly ref: EuiSidesheetRef, private readonly cdrFactoryService: CdrFactoryService, - @Inject(EUI_SIDESHEET_DATA) public data: { serviceCategory: IEntity; isNew: boolean } + @Inject(EUI_SIDESHEET_DATA) public data: { serviceCategory: IEntity; isNew: boolean }, ) { - this.formGroup = new FormGroup({ - cdrArray: new FormArray([]), + this.formGroup = new FormGroup({ + cdrArray: new FormArray([]), }); this.ref.closeClicked().subscribe(async () => { @@ -75,11 +75,11 @@ export class EditServiceCategoryInformationComponent implements OnInit { schema.Columns.UID_PWODecisionMethod, schema.Columns.UID_OrgAttestator, schema.Columns.JPegPhoto, - ].map(elem=> elem.ColumnName); + ].map((elem) => elem.ColumnName || ''); this.cdrList = this.cdrFactoryService.buildCdrFromColumnList(this.data.serviceCategory, columnNames); - if (!this.data.isNew) { + if (!this.data.isNew && schema.Columns.UID_AccProductGroupParent.ColumnName) { this.cdrList.push(new BaseCdr(this.data.serviceCategory.GetColumn(schema.Columns.UID_AccProductGroupParent.ColumnName))); } } diff --git a/imxweb/projects/aob/src/lib/applications/edit-application/service-category/service-category-tree-database.ts b/imxweb/projects/aob/src/lib/applications/edit-application/service-category/service-category-tree-database.ts index 5975c22c1..86373023c 100644 --- a/imxweb/projects/aob/src/lib/applications/edit-application/service-category/service-category-tree-database.ts +++ b/imxweb/projects/aob/src/lib/applications/edit-application/service-category/service-category-tree-database.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -27,10 +27,10 @@ import { OverlayRef } from '@angular/cdk/overlay'; import { EuiLoadingService } from '@elemental-ui/core'; -import { CollectionLoadParameters, IEntity, TypedEntityCollectionData } from 'imx-qbm-dbts'; -import { PortalServicecategories } from 'imx-api-qer'; +import { PortalServicecategories } from '@imx-modules/imx-api-qer'; +import { CollectionLoadParameters, TypedEntityCollectionData } from '@imx-modules/imx-qbm-dbts'; -import { TreeDatabase, TreeNodeResultParameter, SettingsService } from 'qbm'; +import { SettingsService, TreeDatabase, TreeNodeResultParameter } from 'qbm'; import { ServiceCategoryService } from './service-category.service'; /** Provider of servicecategory-data for the imx-data-tree */ @@ -39,7 +39,7 @@ export class ServiceCategoryTreeDatabase extends TreeDatabase { private readonly loadingServiceElemental: EuiLoadingService, private readonly settings: SettingsService, private readonly serviceCategoriesProvider: ServiceCategoryService, - private readonly uidRootElement: string + private readonly uidRootElement: string, ) { super(); this.identifierColumnName = 'FullPath'; @@ -56,10 +56,9 @@ export class ServiceCategoryTreeDatabase extends TreeDatabase { private async loadRoot(showLoading: boolean) { let entities: TreeNodeResultParameter; - let overlayRef: OverlayRef; - if (showLoading) { - setTimeout(() => (overlayRef = this.loadingServiceElemental.show())); + if (showLoading && this.loadingServiceElemental.overlayRefs.length === 0) { + this.loadingServiceElemental.show(); } try { const opts: CollectionLoadParameters = { @@ -81,7 +80,7 @@ export class ServiceCategoryTreeDatabase extends TreeDatabase { }; } finally { if (showLoading) { - setTimeout(() => this.loadingServiceElemental.hide(overlayRef)); + this.loadingServiceElemental.hide(); } } @@ -92,8 +91,8 @@ export class ServiceCategoryTreeDatabase extends TreeDatabase { let entities: TreeNodeResultParameter; let overlayRef: OverlayRef; - if (showLoading) { - setTimeout(() => (overlayRef = this.loadingServiceElemental.show())); + if (showLoading && this.loadingServiceElemental.overlayRefs.length === 0) { + this.loadingServiceElemental.show(); } try { const opts = { @@ -110,7 +109,7 @@ export class ServiceCategoryTreeDatabase extends TreeDatabase { }; } finally { if (showLoading) { - setTimeout(() => this.loadingServiceElemental.hide(overlayRef)); + this.loadingServiceElemental.hide(); } } diff --git a/imxweb/projects/aob/src/lib/applications/edit-application/service-category/service-category.component.html b/imxweb/projects/aob/src/lib/applications/edit-application/service-category/service-category.component.html index a561cecad..e2b3577ae 100644 --- a/imxweb/projects/aob/src/lib/applications/edit-application/service-category/service-category.component.html +++ b/imxweb/projects/aob/src/lib/applications/edit-application/service-category/service-category.component.html @@ -1,5 +1,5 @@
- +
- - diff --git a/imxweb/projects/aob/src/lib/applications/edit-application/service-category/service-category.component.scss b/imxweb/projects/aob/src/lib/applications/edit-application/service-category/service-category.component.scss deleted file mode 100644 index cd288b7c8..000000000 --- a/imxweb/projects/aob/src/lib/applications/edit-application/service-category/service-category.component.scss +++ /dev/null @@ -1,11 +0,0 @@ -:host { - .eui-sidesheet-content{ - display: flex; - flex-direction: column; - .mat-card { - display: flex; - flex-direction: column; - flex: 1 1 auto; - } - } -} \ No newline at end of file diff --git a/imxweb/projects/aob/src/lib/applications/edit-application/service-category/service-category.component.ts b/imxweb/projects/aob/src/lib/applications/edit-application/service-category/service-category.component.ts index 1faf1943b..d3e1a98cf 100644 --- a/imxweb/projects/aob/src/lib/applications/edit-application/service-category/service-category.component.ts +++ b/imxweb/projects/aob/src/lib/applications/edit-application/service-category/service-category.component.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -25,20 +25,26 @@ */ import { Component, Inject, ViewChild } from '@angular/core'; -import { ServiceCategoryService } from './service-category.service'; import { EUI_SIDESHEET_DATA, EuiLoadingService, EuiSidesheetService } from '@elemental-ui/core'; -import { PortalApplication } from 'imx-api-aob'; +import { PortalApplication } from '@imx-modules/imx-api-aob'; import { TranslateService } from '@ngx-translate/core'; +import { ServiceCategoryService } from './service-category.service'; -import { IEntity } from 'imx-qbm-dbts'; -import { SettingsService, DataTreeWrapperComponent, SnackBarService, TreeDatabase, ConfirmationService } from 'qbm'; -import { ServiceCategoryTreeDatabase } from './service-category-tree-database'; +import { IEntity } from '@imx-modules/imx-qbm-dbts'; +import { + calculateSidesheetWidth, + ConfirmationService, + DataTreeWrapperComponent, + SettingsService, + SnackBarService, + TreeDatabase, +} from 'qbm'; import { EditServiceCategoryInformationComponent } from './edit-service-category-information/edit-service-category-information.component'; +import { ServiceCategoryTreeDatabase } from './service-category-tree-database'; @Component({ selector: 'imx-service-category', templateUrl: './service-category.component.html', - styleUrls: ['./service-category.component.scss'], }) export class ServiceCategoryComponent { public treeDatabase: ServiceCategoryTreeDatabase; @@ -53,7 +59,7 @@ export class ServiceCategoryComponent { private readonly sidesheet: EuiSidesheetService, private readonly translate: TranslateService, private readonly confirm: ConfirmationService, - @Inject(EUI_SIDESHEET_DATA) public application: PortalApplication + @Inject(EUI_SIDESHEET_DATA) public application: PortalApplication, ) { this.initializeTree(); } @@ -65,17 +71,19 @@ export class ServiceCategoryComponent { const overlay = this.busyService.show(); try { await entity.Commit(true); - } catch(exception){ + } catch (exception) { await entity.DiscardChanges(); throw exception; - } - finally { + } finally { this.busyService.hide(overlay); } this.treeDatabase.updateNodeItem(entity); if (oldParent !== entity.GetColumn('UID_AccProductGroupParent').GetValue()) { this.tryToMoveElement(entity, entity.GetColumn('UID_AccProductGroupParent').GetValue()); - this.snackbar.open({ key: '#LDS#The changes have been successfully saved.' }); + this.snackbar.open({ + key: '#LDS#The parent of the service category "{0}" has been successfully changed.', + parameters: [entity.GetDisplay()], + }); } } else { await entity.DiscardChanges(); @@ -85,7 +93,12 @@ export class ServiceCategoryComponent { public async onDelete(evt: Event, entity: IEntity): Promise { evt.stopPropagation(); - if(!(await this.confirm.confirmDelete('#LDS#Heading Delete Service Category', '#LDS#Are you sure you want to delete the service category?'))){ + if ( + !(await this.confirm.confirmDelete( + '#LDS#Heading Delete Service Category', + '#LDS#Are you sure you want to delete the service category?', + )) + ) { return; } @@ -97,7 +110,7 @@ export class ServiceCategoryComponent { } this.dataTreeWrapper.deleteNode(entity, false); - this.snackbar.open({ key: '#LDS#The changes have been successfully saved.' }); + this.snackbar.open({ key: '#LDS#The service category "{0}" has been successfully deleted.', parameters: [entity.GetDisplay()] }); } public async addChildCategory(evt: Event, entity: IEntity): Promise { @@ -115,7 +128,7 @@ export class ServiceCategoryComponent { } finally { this.busyService.hide(overlay); } - this.snackbar.open({ key: '#LDS#The changes have been successfully saved.' }); + this.snackbar.open({ key: '#LDS#The service category "{0}" has been successfully created.', parameters: [newEntity.GetDisplay()] }); this.add(entity, newEntity); } else { await entity.DiscardChanges(); @@ -162,7 +175,7 @@ export class ServiceCategoryComponent { this.busyService, this.settingsService, this.categoryService, - this.application.UID_AccProductGroup.value + this.application.UID_AccProductGroup.value, ); this.treeDatabase.initialized.subscribe(async () => { @@ -176,12 +189,12 @@ export class ServiceCategoryComponent { private async editServiceCategory(serviceCategory: IEntity, mode: 'edit' | 'create'): Promise { return await this.sidesheet .open(EditServiceCategoryInformationComponent, { - title: await this.translate - .get(mode === 'edit' ? '#LDS#Heading Edit Service Category' : '#LDS#Heading Create Service Category') - .toPromise(), + title: await this.translate.instant( + mode === 'edit' ? '#LDS#Heading Edit Service Category' : '#LDS#Heading Create Service Category', + ), subTitle: mode === 'edit' ? serviceCategory.GetDisplay() : '', padding: '0px', - width: 'max(650px, 65%)', + width: calculateSidesheetWidth(1000), disableClose: true, testId: mode === 'edit' ? 'edit-service-category' : 'create-service-category', data: { serviceCategory, isNew: mode === 'create' }, diff --git a/imxweb/projects/aob/src/lib/applications/edit-application/service-category/service-category.service.ts b/imxweb/projects/aob/src/lib/applications/edit-application/service-category/service-category.service.ts index 780e02074..9ba94186c 100644 --- a/imxweb/projects/aob/src/lib/applications/edit-application/service-category/service-category.service.ts +++ b/imxweb/projects/aob/src/lib/applications/edit-application/service-category/service-category.service.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -25,8 +25,14 @@ */ import { Injectable } from '@angular/core'; -import { PortalServicecategories } from 'imx-api-qer'; -import { CollectionLoadParameters, EntityCollectionData, EntitySchema, IEntity, TypedEntityCollectionData } from 'imx-qbm-dbts'; +import { PortalServicecategories } from '@imx-modules/imx-api-qer'; +import { + CollectionLoadParameters, + EntityCollectionData, + EntitySchema, + IEntity, + TypedEntityCollectionData, +} from '@imx-modules/imx-qbm-dbts'; import { QerApiService } from 'qer'; @Injectable({ diff --git a/imxweb/projects/aob/src/lib/applications/identities/identities.component.html b/imxweb/projects/aob/src/lib/applications/identities/identities.component.html index e35148562..75c23dd5a 100644 --- a/imxweb/projects/aob/src/lib/applications/identities/identities.component.html +++ b/imxweb/projects/aob/src/lib/applications/identities/identities.component.html @@ -1,42 +1,49 @@
- - - - - - - - - -
\ No newline at end of file + + + + + + + + +
diff --git a/imxweb/projects/aob/src/lib/applications/identities/identities.component.scss b/imxweb/projects/aob/src/lib/applications/identities/identities.component.scss index bfd53f420..df80448df 100644 --- a/imxweb/projects/aob/src/lib/applications/identities/identities.component.scss +++ b/imxweb/projects/aob/src/lib/applications/identities/identities.component.scss @@ -14,25 +14,4 @@ flex: 1 1 auto; overflow: hidden; } - - ::ng-deep .mat-paginator { - background-color: transparent; - } -} - -.eui-dark-theme { - :host { - ::ng-deep .mat-paginator { - background-color: transparent; - } - } -} - -.eui-contrast-theme { - :host { - background-color: $color-gray-100; - } - ::ng-deep .mat-paginator { - background-color: transparent; - } } diff --git a/imxweb/projects/aob/src/lib/applications/identities/identities.component.ts b/imxweb/projects/aob/src/lib/applications/identities/identities.component.ts index bbbb8700d..a593949a7 100644 --- a/imxweb/projects/aob/src/lib/applications/identities/identities.component.ts +++ b/imxweb/projects/aob/src/lib/applications/identities/identities.component.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -26,8 +26,7 @@ import { Component, Input, OnChanges, SimpleChanges, ViewChild } from '@angular/core'; import { EuiSidesheetService } from '@elemental-ui/core'; -import { TranslateService } from '@ngx-translate/core'; -import { PortalApplication, PortalApplicationIdentities } from 'imx-api-aob'; +import { PortalApplication, PortalApplicationIdentities } from '@imx-modules/imx-api-aob'; import { CollectionLoadParameters, DisplayColumns, @@ -35,8 +34,9 @@ import { ExtendedTypedEntityCollection, IClientProperty, TypedEntity, -} from 'imx-qbm-dbts'; -import { BusyService, DataSourceToolbarSettings, DataTableComponent, DataTileMenuItem } from 'qbm'; +} from '@imx-modules/imx-qbm-dbts'; +import { TranslateService } from '@ngx-translate/core'; +import { BusyService, calculateSidesheetWidth, DataSourceToolbarSettings, DataTableComponent, DataTileMenuItem } from 'qbm'; import { IdentityDetailData } from './identity-detail-data'; import { IdentityDetailComponent } from './identity-detail/identity-detail.component'; import { IdentityService } from './identity.service'; @@ -65,7 +65,7 @@ export class IdentitiesComponent implements OnChanges { constructor( private readonly identityService: IdentityService, private readonly sidesheetService: EuiSidesheetService, - private readonly translateService: TranslateService + private readonly translateService: TranslateService, ) { this.entitySchema = this.identityService.getSchema(); this.initNavigationState(); @@ -130,7 +130,7 @@ export class IdentitiesComponent implements OnChanges { * Opens a side sheet that displays identity details * @param item the identity, that details should be opened */ - public async onOpenDetails(item: TypedEntity): Promise { + public async onOpenDetails(item?: TypedEntity): Promise { const data: IdentityDetailData = { application: this.application, selectedItem: item, @@ -138,8 +138,8 @@ export class IdentitiesComponent implements OnChanges { this.sidesheetService.open(IdentityDetailComponent, { title: await this.translateService.get('#LDS#Heading View Application Entitlements').toPromise(), - subTitle: data.selectedItem.GetEntity().GetDisplay(), - width: 'max(768px, 70%)', + subTitle: data.selectedItem?.GetEntity().GetDisplay(), + width: calculateSidesheetWidth(1100, 0.7), testId: 'identity-view-application-entitlements', data: data, }); @@ -171,7 +171,7 @@ export class IdentitiesComponent implements OnChanges { this.navigationState = { PageSize: 25, StartIndex: 0, - search: null, + search: '', }; } } diff --git a/imxweb/projects/aob/src/lib/applications/identities/identity-detail-data.ts b/imxweb/projects/aob/src/lib/applications/identities/identity-detail-data.ts index 4d4c67e0c..86cea3e74 100644 --- a/imxweb/projects/aob/src/lib/applications/identities/identity-detail-data.ts +++ b/imxweb/projects/aob/src/lib/applications/identities/identity-detail-data.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -24,10 +24,10 @@ * */ -import { PortalApplication } from "imx-api-aob"; -import { TypedEntity } from "imx-qbm-dbts"; +import { PortalApplication } from '@imx-modules/imx-api-aob'; +import { TypedEntity } from '@imx-modules/imx-qbm-dbts'; export interface IdentityDetailData { - application: PortalApplication, - selectedItem: TypedEntity; + application: PortalApplication; + selectedItem: TypedEntity | undefined; } diff --git a/imxweb/projects/aob/src/lib/applications/identities/identity-detail/identity-detail.component.html b/imxweb/projects/aob/src/lib/applications/identities/identity-detail/identity-detail.component.html index ac9ac5ac0..4012e34e3 100644 --- a/imxweb/projects/aob/src/lib/applications/identities/identity-detail/identity-detail.component.html +++ b/imxweb/projects/aob/src/lib/applications/identities/identity-detail/identity-detail.component.html @@ -1,21 +1,28 @@ - - - - - - - + + + + + {{ entitySchema?.Columns?.[DisplayColumns.DISPLAY_PROPERTYNAME]?.Display }} + + + {{ item.GetEntity().GetDisplay() }} + + + + {{ entitySchema.Columns.OrderState.Display }} + +
{{ item.OrderState?.Column.GetDisplayValue() }}
+ +
+ + {{ entitySchema.Columns.ValidUntil.Display }} +
{{ translateProvider.GetColumnDisplay('ValidUntil', entitySchema) + ': ' + (item.ValidUntil.value | shortDate) }}
-
-
-
- + + + + diff --git a/imxweb/projects/aob/src/lib/applications/identities/identity-detail/identity-detail.component.ts b/imxweb/projects/aob/src/lib/applications/identities/identity-detail/identity-detail.component.ts index 27ffd3885..36686f013 100644 --- a/imxweb/projects/aob/src/lib/applications/identities/identity-detail/identity-detail.component.ts +++ b/imxweb/projects/aob/src/lib/applications/identities/identity-detail/identity-detail.component.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -25,16 +25,16 @@ */ import { Component, Inject, OnInit } from '@angular/core'; -import { EuiLoadingService, EUI_SIDESHEET_DATA } from '@elemental-ui/core'; -import { PortalApplicationIdentitiesbyidentity } from 'imx-api-aob'; +import { EUI_SIDESHEET_DATA } from '@elemental-ui/core'; +import { PortalApplicationIdentitiesbyidentity } from '@imx-modules/imx-api-aob'; import { CollectionLoadParameters, DisplayColumns, EntitySchema, ExtendedTypedEntityCollection, IClientProperty, -} from 'imx-qbm-dbts'; -import { DataSourceToolbarSettings, ImxTranslationProviderService } from 'qbm'; +} from '@imx-modules/imx-qbm-dbts'; +import { DataSourceToolbarSettings, DataViewSource, ImxTranslationProviderService } from 'qbm'; import { IdentityDetailData } from '../identity-detail-data'; import { IdentityService } from '../identity.service'; @@ -42,6 +42,7 @@ import { IdentityService } from '../identity.service'; selector: 'imx-identity-detail', templateUrl: './identity-detail.component.html', styleUrls: ['./identity-detail.component.scss'], + providers: [DataViewSource], }) export class IdentityDetailComponent implements OnInit { public dstSettings: DataSourceToolbarSettings; @@ -53,15 +54,10 @@ export class IdentityDetailComponent implements OnInit { constructor( @Inject(EUI_SIDESHEET_DATA) public data: IdentityDetailData, private readonly identityService: IdentityService, - private readonly busyService: EuiLoadingService, public readonly translateProvider: ImxTranslationProviderService, + public dataSource: DataViewSource, ) { this.entitySchema = this.identityService.getByIdentitySchema(); - this.navigationState = { - PageSize: 25, - StartIndex: 0, - search: null, - }; this.displayedColumns = [ this.entitySchema.Columns[DisplayColumns.DISPLAY_PROPERTYNAME], this.entitySchema.Columns['OrderState'], @@ -70,35 +66,15 @@ export class IdentityDetailComponent implements OnInit { } public async ngOnInit(): Promise { - await this.setDst(); - } - - public async onNavigationStateChanged(navigationState: CollectionLoadParameters): Promise { - this.navigationState = navigationState; - this.setDst(); - } - - public async onSearch(keywords: string): Promise { - this.navigationState.StartIndex = 0; - this.navigationState.search = keywords; - this.setDst(); - } - - private async setDst(): Promise { - this.dstSettings = { - dataSource: await this.getData(), - entitySchema: this.entitySchema, - navigationState: this.navigationState, - displayedColumns: this.displayedColumns, - }; - } - - private async getData(): Promise> { - this.busyService.show(); - try { - return await this.identityService.getByIdentity(this.data.application.GetEntity().GetKeys()[0], this.data.selectedItem.GetEntity().GetKeys()[0], this.navigationState); - } finally { - this.busyService.hide(); - } + this.dataSource.init({ + execute: (params: CollectionLoadParameters): Promise> => + this.identityService.getByIdentity( + this.data.application.GetEntity().GetKeys()[0], + this.data.selectedItem?.GetEntity().GetKeys()[0] || '', + params, + ), + schema: this.entitySchema, + columnsToDisplay: this.displayedColumns, + }); } } diff --git a/imxweb/projects/aob/src/lib/applications/identities/identity.service.ts b/imxweb/projects/aob/src/lib/applications/identities/identity.service.ts index 922ac573f..4bec7b212 100644 --- a/imxweb/projects/aob/src/lib/applications/identities/identity.service.ts +++ b/imxweb/projects/aob/src/lib/applications/identities/identity.service.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -25,18 +25,20 @@ */ import { Injectable } from '@angular/core'; -import { PortalApplicationIdentities, PortalApplicationIdentitiesbyidentity } from 'imx-api-aob'; -import { CollectionLoadParameters, EntitySchema, ExtendedTypedEntityCollection } from 'imx-qbm-dbts'; +import { PortalApplicationIdentities, PortalApplicationIdentitiesbyidentity } from '@imx-modules/imx-api-aob'; +import { CollectionLoadParameters, EntitySchema, ExtendedTypedEntityCollection } from '@imx-modules/imx-qbm-dbts'; import { AobApiService } from '../../aob-api-client.service'; @Injectable({ - providedIn: 'root' + providedIn: 'root', }) export class IdentityService { + constructor(private readonly api: AobApiService) {} - constructor(private readonly api: AobApiService) { } - - public async get(applicationId: string, params?: CollectionLoadParameters): Promise> { + public async get( + applicationId: string, + params?: CollectionLoadParameters, + ): Promise> { return await this.api.typedClient.PortalApplicationIdentities.Get(applicationId, params); } @@ -44,12 +46,15 @@ export class IdentityService { return this.api.typedClient.PortalApplicationIdentities.GetSchema(); } - public async getByIdentity(applicationId: string, identityId: string, params?: CollectionLoadParameters): Promise> { + public async getByIdentity( + applicationId: string, + identityId: string, + params?: CollectionLoadParameters, + ): Promise> { return await this.api.typedClient.PortalApplicationIdentitiesbyidentity.Getbyidentity(applicationId, identityId, params); } public getByIdentitySchema(): EntitySchema { return this.api.typedClient.PortalApplicationIdentitiesbyidentity.GetSchema(); } - } diff --git a/imxweb/projects/aob/src/lib/column-info/column-info.component.html b/imxweb/projects/aob/src/lib/column-info/column-info.component.html index 1f7f32672..4488436a5 100644 --- a/imxweb/projects/aob/src/lib/column-info/column-info.component.html +++ b/imxweb/projects/aob/src/lib/column-info/column-info.component.html @@ -1,5 +1,5 @@ - +
- {{ property?.Column.GetDisplayValue() || ('-' + (placeholder || ('#LDS#Not set' | translate)) + '-') }} + {{ property?.Column?.GetDisplayValue() || '-' + (placeholder || ('#LDS#Not set' | translate)) + '-' }}
-
\ No newline at end of file +
diff --git a/imxweb/projects/aob/src/lib/column-info/column-info.component.scss b/imxweb/projects/aob/src/lib/column-info/column-info.component.scss index 19f8c1fcc..1ced8b697 100644 --- a/imxweb/projects/aob/src/lib/column-info/column-info.component.scss +++ b/imxweb/projects/aob/src/lib/column-info/column-info.component.scss @@ -5,7 +5,7 @@ overflow: hidden; text-overflow: ellipsis; - >span { + > span { font-weight: 600; color: $black-6; } @@ -14,7 +14,7 @@ .eui-dark-theme { :host { .imx-user-properties { - >span { + > span { color: $color-gray-10; } } @@ -24,7 +24,7 @@ .eui-contrast-theme { :host { .imx-user-properties { - >span { + > span { color: $color-gray-0; } } diff --git a/imxweb/projects/aob/src/lib/column-info/column-info.component.ts b/imxweb/projects/aob/src/lib/column-info/column-info.component.ts index 76e163352..5944444c4 100644 --- a/imxweb/projects/aob/src/lib/column-info/column-info.component.ts +++ b/imxweb/projects/aob/src/lib/column-info/column-info.component.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -26,12 +26,12 @@ import { Component, Input } from '@angular/core'; -import { EntityValue } from 'imx-qbm-dbts'; +import { EntityValue } from '@imx-modules/imx-qbm-dbts'; @Component({ selector: 'imx-column-info', templateUrl: './column-info.component.html', - styleUrls: ['./column-info.component.scss'] + styleUrls: ['./column-info.component.scss'], }) export class ColumnInfoComponent { @Input() public property: EntityValue; diff --git a/imxweb/projects/aob/src/lib/column-info/column-info.module.ts b/imxweb/projects/aob/src/lib/column-info/column-info.module.ts index 284305d82..739aa8ada 100644 --- a/imxweb/projects/aob/src/lib/column-info/column-info.module.ts +++ b/imxweb/projects/aob/src/lib/column-info/column-info.module.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -49,8 +49,8 @@ import { ApplicationPropertyModule } from '../application-property/application-p ReactiveFormsModule, MatButtonModule, MatFormFieldModule, - MatInputModule + MatInputModule, ], - exports: [ColumnInfoComponent] + exports: [ColumnInfoComponent], }) -export class ColumnInfoModule { } +export class ColumnInfoModule {} diff --git a/imxweb/projects/aob/src/lib/entitlements/entitlement-add/entitlements-add.component.html b/imxweb/projects/aob/src/lib/entitlements/entitlement-add/entitlements-add.component.html index 2587ada98..8124ed285 100644 --- a/imxweb/projects/aob/src/lib/entitlements/entitlement-add/entitlements-add.component.html +++ b/imxweb/projects/aob/src/lib/entitlements/entitlement-add/entitlements-add.component.html @@ -1,75 +1,89 @@
- - {{LdsInfoAlert | translate}} + + {{ LdsInfoAlert | translate }} - -
- - {{'#LDS#Application entitlement type' | translate }} - - - {{entitlementSourceType.display}} - - - -
- - - - - - - + + +
+ + {{ '#LDS#Application entitlement type' | translate }} + + + {{ entitlementSourceType.display }} + + + + +
+ + + {{ entitySchema?.Columns?.[DisplayColumns.DISPLAY_PROPERTYNAME]?.Display }} + + +
{{ item?.GetEntity().GetDisplay() }}
+
+ +
{{ item?.GetEntity().GetDisplay() }}
+
{{ item?.Description?.Column.GetDisplayValue() }}
+
+
- - - -
{{ data?.GetEntity().GetDisplay() }}
-
{{ data?.Description.Column.GetDisplayValue()}}
-
-
- - - - - - + + {{ entitySchema?.Columns?.CanonicalName?.Display }} + +
{{ item.CanonicalName?.Column.GetDisplayValue() }}
+
-
- + + {{ entitySchema?.Columns?.UID_UNSRoot?.Display }} + +
{{ item.UID_UNSRoot?.Column.GetDisplayValue() }}
+ +
+ +
+ + +
-
-

- - {{selections?.length || 0}} - {{'#LDS#Selected application entitlements' | translate }} -

- - -
diff --git a/imxweb/projects/aob/src/lib/entitlements/entitlement-add/entitlements-add.component.scss b/imxweb/projects/aob/src/lib/entitlements/entitlement-add/entitlements-add.component.scss index bd50127f4..89541e189 100644 --- a/imxweb/projects/aob/src/lib/entitlements/entitlement-add/entitlements-add.component.scss +++ b/imxweb/projects/aob/src/lib/entitlements/entitlement-add/entitlements-add.component.scss @@ -1,42 +1,11 @@ -@import "@elemental-ui/core/src/styles/_palette.scss"; +@import '@elemental-ui/core/src/styles/_palette.scss'; +@import 'base/mixins.scss'; -.imx-helper-alert { - margin: 10px 0 20px auto; - width: 100%; +.eui-sidesheet-content{ + @include flex-column-container() } - -.imx-selected-entitlements { - margin: 0; - line-height: 36px; - flex: auto; - - ::ng-deep .imx-badge.eui-badge .eui-badge-content { - font-size: 14px; - line-height: 14px; - } -} - -.imx-badge { - background-color: inherit; -} - -.eui-sidesheet-content { - display: flex; - flex-direction: column; - .imx-sidesheet-content { - flex: 1 1 auto; - height: inherit; - overflow: hidden; - display: flex; - flex-direction: column; - } -} - .eui-sidesheet-actions { > * { align-self: center; } - > *:not(:last-child) { - margin-right: 10px; - } } diff --git a/imxweb/projects/aob/src/lib/entitlements/entitlement-add/entitlements-add.component.ts b/imxweb/projects/aob/src/lib/entitlements/entitlement-add/entitlements-add.component.ts index d683dde62..95b657f5b 100644 --- a/imxweb/projects/aob/src/lib/entitlements/entitlement-add/entitlements-add.component.ts +++ b/imxweb/projects/aob/src/lib/entitlements/entitlement-add/entitlements-add.component.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -24,25 +24,34 @@ * */ -import { OverlayRef } from '@angular/cdk/overlay'; -import { Component, OnInit, Inject } from '@angular/core'; -import { EuiLoadingService, EuiSidesheetRef, EuiSidesheetService, EUI_SIDESHEET_DATA } from '@elemental-ui/core'; -import { TranslateService } from '@ngx-translate/core'; +import { Component, Inject, OnInit } from '@angular/core'; import { MatSelectChange } from '@angular/material/select'; +import { EUI_SIDESHEET_DATA, EuiLoadingService, EuiSidesheetRef, EuiSidesheetService } from '@elemental-ui/core'; +import { TranslateService } from '@ngx-translate/core'; +import { EntitlementSystemRoleInput } from '@imx-modules/imx-api-aob'; import { - DataSourceToolbarSettings, + CollectionLoadParameters, + DataModel, + DisplayColumns, + EntitySchema, + IClientProperty, + TypedEntity, + TypedEntityCollectionData, +} from '@imx-modules/imx-qbm-dbts'; +import { + calculateSidesheetWidth, + CdrFactoryService, ClassloggerService, + DataViewInitParameters, + DataViewSource, HELPER_ALERT_KEY_PREFIX, - StorageService, MetadataService, - DataSourceToolbarFilter, - CdrFactoryService, + SettingsService, + StorageService, } from 'qbm'; -import { CollectionLoadParameters, IClientProperty, EntitySchema, DisplayColumns, TypedEntity, FilterData } from 'imx-qbm-dbts'; -import { EntitlementsService } from '../entitlements.service'; import { AddEntitlementParameter, EntitlementSourceType, EntitlementsType } from '../entitlements.model'; -import { EntitlementSystemRoleInput } from 'imx-api-aob'; +import { EntitlementsService } from '../entitlements.service'; import { SystemRoleConfigComponent } from './system-role-config/system-role-config.component'; const helperAlertKey = `${HELPER_ALERT_KEY_PREFIX}_addNewEntitlements`; @@ -54,15 +63,13 @@ const helperAlertKey = `${HELPER_ALERT_KEY_PREFIX}_addNewEntitlements`; selector: 'imx-entitlements-add', templateUrl: './entitlements-add.component.html', styleUrls: ['./entitlements-add.component.scss'], + providers: [DataViewSource], }) export class EntitlementsAddComponent implements OnInit { public readonly EntitlementsType = EntitlementsType; // Enables use of this Enum in Angular Templates. public readonly DisplayColumns = DisplayColumns; // Enables use of this static class in Angular Templates. - public settings: DataSourceToolbarSettings; public entitySchema: EntitySchema; - public navigationState: CollectionLoadParameters; public displayedColumns: IClientProperty[] = []; - public highlightedEntity: TypedEntity; public selectedSourceType: EntitlementsType = EntitlementsType.UnsGroup; public isSystemRolesEnabled: boolean; public entitlementsLabel: string; @@ -74,8 +81,6 @@ export class EntitlementsAddComponent implements OnInit { return !this.storageService.isHelperAlertDismissed(helperAlertKey); } - private filters: DataSourceToolbarFilter[]; - constructor( public readonly sidesheetRef: EuiSidesheetRef, @Inject(EUI_SIDESHEET_DATA) private data: AddEntitlementParameter, @@ -86,6 +91,8 @@ export class EntitlementsAddComponent implements OnInit { private readonly metaData: MetadataService, private readonly sidesheet: EuiSidesheetService, private readonly translateService: TranslateService, + public dataSource: DataViewSource, + public readonly settingsService: SettingsService, ) { this.selectedSourceType = data.defaultType; this.isSystemRolesEnabled = data.isSystemRolesEnabled; @@ -97,14 +104,14 @@ export class EntitlementsAddComponent implements OnInit { await this.metaData.updateNonExisting(['ESet', 'UNSGroup', 'QERResource', 'RPSReport', 'TSBAccountDef']); this.entitlementSourceTypes = [ - { entitlementsType: EntitlementsType.UnsGroup, display: this.metaData.tables.UNSGroup.Display }, - { entitlementsType: EntitlementsType.Qerresource, display: this.metaData.tables.QERResource.Display }, - { entitlementsType: EntitlementsType.Rpsreport, display: this.metaData.tables.RPSReport.Display }, - { entitlementsType: EntitlementsType.Tsbaccountdef, display: this.metaData.tables.TSBAccountDef.Display }, + { entitlementsType: EntitlementsType.UnsGroup, display: this.metaData.tables.UNSGroup?.Display || '' }, + { entitlementsType: EntitlementsType.Qerresource, display: this.metaData.tables.QERResource?.Display || '' }, + { entitlementsType: EntitlementsType.Rpsreport, display: this.metaData.tables.RPSReport?.Display || '' }, + { entitlementsType: EntitlementsType.Tsbaccountdef, display: this.metaData.tables.TSBAccountDef?.Display || '' }, ]; if (this.isSystemRolesEnabled) { - this.entitlementSourceTypes.unshift({ entitlementsType: EntitlementsType.Eset, display: this.metaData.tables.ESet.Display }); + this.entitlementSourceTypes.unshift({ entitlementsType: EntitlementsType.Eset, display: this.metaData.tables.ESet?.Display || '' }); } await this.useSource(this.selectedSourceType); @@ -132,10 +139,9 @@ export class EntitlementsAddComponent implements OnInit { public async onCreateRole(): Promise { const entitlementSystemRoleInput: EntitlementSystemRoleInput = await this.sidesheet .open(SystemRoleConfigComponent, { - // TODO: make LDS Heading - title: await this.translateService.get('#LDS#Create new system role').toPromise(), + title: await this.translateService.get('#LDS#Heading Create Empty System Role').toPromise(), padding: '0px', - width: 'max(500px, 50%)', + width: calculateSidesheetWidth(800, 0.5), testId: 'create-role-sidesheet', data: { uid: this.data.uidApplication, createOnly: true }, }) @@ -158,7 +164,7 @@ export class EntitlementsAddComponent implements OnInit { .open(SystemRoleConfigComponent, { title: await this.translateService.get('#LDS#Heading Merge Application Entitlements into System Role').toPromise(), padding: '0px', - width: 'max(500px, 50%)', + width: calculateSidesheetWidth(800, 0.5), testId: 'add-to-existing-role-sidesheet', data: { uid: this.data.uidApplication, createOnly: false }, }) @@ -188,77 +194,41 @@ export class EntitlementsAddComponent implements OnInit { this.selections = selection; } - public onHighlightedEntityChanged(entity: TypedEntity): void { - this.highlightedEntity = entity; - } - - public onNavigationStateChanged(newState: CollectionLoadParameters): void { - this.navigationState = newState; - this.updateCandidates(); - } - - public onSearch(keywords: string): void { - this.logger.debug(this, `Searching for: ${keywords}`); - this.navigationState.StartIndex = 0; - this.navigationState.search = keywords; - this.updateCandidates(); - } - - public async onFilterByTree(filters: FilterData[]): Promise { - this.navigationState.filter = filters; - this.updateCandidates(); - } - private async useSource(type: EntitlementsType): Promise { this.selectedSourceType = type; this.entitySchema = this.entitlementsProvider.candidateSchema(type); - let overlayRef: OverlayRef; - setTimeout(() => (overlayRef = this.busyService.show())); - try { - this.filters = (await this.entitlementsProvider.getDataModel(type))?.Filters; - } finally { - setTimeout(() => this.busyService.hide(overlayRef)); - } - - this.displayedColumns = this.getDisplayedColumnsForEntitlement(this.entitySchema, type); - this.navigationState = { StartIndex: 0, PageSize: 25 }; - this.highlightedEntity = null; - - this.updateCandidates(); - } - private async updateCandidates(): Promise { - let overlayRef: OverlayRef; - setTimeout(() => (overlayRef = this.busyService.show())); + let dataModel: DataModel | undefined = undefined; + if (this.busyService.overlayRefs.length === 0) { + this.busyService.show(); + } try { - this.logger.debug(this, 'Get candidates from the server...'); - const data = await this.entitlementsProvider.getCandidates(this.selectedSourceType, this.navigationState); - - this.settings = { - dataSource: data, - displayedColumns: this.displayedColumns, - entitySchema: this.entitySchema, - navigationState: this.navigationState, - filters: this.filters, - filterTree: - this.selectedSourceType === EntitlementsType.UnsGroup - ? { - filterMethode: async (parentkey) => { - return this.entitlementsProvider.getEntitlementsFilterTree({ - parentkey, - }); - }, - multiSelect: false, - } - : undefined, - }; - - if (data == null) { - this.logger.error(this, 'TypedEntityCollectionData is undefined'); - } + dataModel = await this.entitlementsProvider.getDataModel(type); } finally { - setTimeout(() => this.busyService.hide(overlayRef)); + this.busyService.hide(); } + this.displayedColumns = this.getDisplayedColumnsForEntitlement(this.entitySchema, type); + this.dataSource.state.set({ PageSize: this.settingsService?.DefaultPageSize, StartIndex: 0 }); + const dataViewInitParameters: DataViewInitParameters = { + execute: (params: CollectionLoadParameters): Promise | undefined> => + this.entitlementsProvider.getCandidates(this.selectedSourceType, params), + schema: this.entitySchema, + columnsToDisplay: this.displayedColumns, + dataModel, + selectionChange: (selection: Array) => this.onSelectionChanged(selection), + filterTree: + this.selectedSourceType === EntitlementsType.UnsGroup + ? { + filterMethode: async (parentkey) => { + return this.entitlementsProvider.getEntitlementsFilterTree({ + parentkey, + }); + }, + multiSelect: false, + } + : undefined, + }; + await this.dataSource.init(dataViewInitParameters); } private getDisplayedColumnsForEntitlement(entitySchema: EntitySchema, type: EntitlementsType): IClientProperty[] { diff --git a/imxweb/projects/aob/src/lib/entitlements/entitlement-add/system-role-config/system-role-config.component.html b/imxweb/projects/aob/src/lib/entitlements/entitlement-add/system-role-config/system-role-config.component.html index d8e762dd4..0bae06b32 100644 --- a/imxweb/projects/aob/src/lib/entitlements/entitlement-add/system-role-config/system-role-config.component.html +++ b/imxweb/projects/aob/src/lib/entitlements/entitlement-add/system-role-config/system-role-config.component.html @@ -1,31 +1,38 @@ -
- - {{ LdsAddOrCreate | translate }} +
+ + {{ (data.createOnly ? LdsCreate : LdsAddOrCreate) | translate }} - - + - {{'#LDS#Create new system role' | translate}} + {{ '#LDS#Create new system role' | translate }} - {{'#LDS#Add to existing system role' | translate}} + {{ '#LDS#Add to existing system role' | translate }}
#LDS#Name - +
- - + + - + [attr.data-imx-identifier]="'multi-select-formcontrol-list' + candidate.GetEntity().GetKeys()[0]" + >
{{ candidate.GetEntity().GetDisplay() }}
@@ -37,17 +44,28 @@

#LDS#There are currently no system roles.

-
-
- -
diff --git a/imxweb/projects/aob/src/lib/entitlements/entitlement-add/system-role-config/system-role-config.component.scss b/imxweb/projects/aob/src/lib/entitlements/entitlement-add/system-role-config/system-role-config.component.scss index 250a9b378..9067d07bf 100644 --- a/imxweb/projects/aob/src/lib/entitlements/entitlement-add/system-role-config/system-role-config.component.scss +++ b/imxweb/projects/aob/src/lib/entitlements/entitlement-add/system-role-config/system-role-config.component.scss @@ -1,4 +1,5 @@ -@import '@elemental-ui/core/src/styles/_palette.scss'; +@import '@elemental-ui/core/src/styles/_eui_palette.scss'; +@import 'base/mixins'; .imx-viewport { height: 300px; @@ -6,27 +7,12 @@ overflow-x: hidden; } -.imx-helper-alert { - margin: 10px 0 20px auto; - width: 100%; -} - -.mat-radio-button { +.mat-mdc-radio-button { margin-right: 20px; } -.mat-radio-group { - padding: 10px 10px 30px 10px; - display: flex; - flex-direction: row; -} - .eui-sidesheet-content { - height: inherit; - overflow: hidden; - display: flex; - flex-direction: column; - + @include flex-column-container($overflow: hidden, $height: inherit); .imx-content-card { flex: 1 1 auto; @@ -37,14 +23,9 @@ text-align: center; margin: 20px 0; - .eui-icon { - font-size: 100px; - color: rgba($black-c, 0.55); - } - p { margin: 0; font-size: 18px; - color: $black-9; + color: $color-gray-40; } } diff --git a/imxweb/projects/aob/src/lib/entitlements/entitlement-add/system-role-config/system-role-config.component.ts b/imxweb/projects/aob/src/lib/entitlements/entitlement-add/system-role-config/system-role-config.component.ts index 58b5dcf8c..a4e765841 100644 --- a/imxweb/projects/aob/src/lib/entitlements/entitlement-add/system-role-config/system-role-config.component.ts +++ b/imxweb/projects/aob/src/lib/entitlements/entitlement-add/system-role-config/system-role-config.component.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -25,28 +25,26 @@ */ import { ListRange } from '@angular/cdk/collections'; -import { OverlayRef } from '@angular/cdk/overlay'; import { CdkVirtualScrollViewport } from '@angular/cdk/scrolling'; -import { Subscription } from 'rxjs'; import { AfterViewInit, ChangeDetectorRef, Component, Inject, OnDestroy, ViewChild } from '@angular/core'; import { UntypedFormControl, UntypedFormGroup, Validators } from '@angular/forms'; import { MatSelectionListChange } from '@angular/material/list'; import { MatRadioChange } from '@angular/material/radio'; -import { EuiLoadingService, EuiSidesheetRef, EUI_SIDESHEET_DATA } from '@elemental-ui/core'; +import { EUI_SIDESHEET_DATA, EuiLoadingService, EuiSidesheetRef } from '@elemental-ui/core'; +import { Subscription } from 'rxjs'; -import { CollectionLoadParameters, TypedEntity } from 'imx-qbm-dbts'; +import { CollectionLoadParameters, TypedEntity } from '@imx-modules/imx-qbm-dbts'; import { SettingsService } from 'qbm'; import { SystemRoleConfigService } from './system-role-config.service'; @Component({ templateUrl: './system-role-config.component.html', - styleUrls: ['./system-role-config.component.scss'] + styleUrls: ['./system-role-config.component.scss'], }) export class SystemRoleConfigComponent implements AfterViewInit, OnDestroy { - public readonly form: UntypedFormGroup; public type: 'new' | 'existing' = 'new'; - public selectedRole: string; + public selectedRole: string | undefined; public showHelperAlert = true; @@ -56,9 +54,8 @@ export class SystemRoleConfigComponent implements AfterViewInit, OnDestroy { private parameters: CollectionLoadParameters; private readonly subscriptions: Subscription[] = []; - constructor( - @Inject(EUI_SIDESHEET_DATA) public readonly data: { uid: string, createOnly: boolean }, + @Inject(EUI_SIDESHEET_DATA) public readonly data: { uid: string; createOnly: boolean }, private readonly sidesheetRef: EuiSidesheetRef, private readonly busyService: EuiLoadingService, private readonly addToExistingProvider: SystemRoleConfigService, @@ -72,40 +69,44 @@ export class SystemRoleConfigComponent implements AfterViewInit, OnDestroy { this.parameters = { PageSize: this.settingsService.DefaultPageSize, StartIndex: 0 }; if (this.viewport) { - this.subscriptions.push(this.viewport.renderedRangeStream.subscribe(async (range: ListRange) => { - if (range.end === (this.settingsService.DefaultPageSize + this.parameters.StartIndex)) { - this.parameters.StartIndex += this.settingsService.DefaultPageSize; + this.subscriptions.push( + this.viewport.renderedRangeStream.subscribe(async (range: ListRange) => { + if (range.end === this.settingsService.DefaultPageSize + (this.parameters.StartIndex || 0)) { + this.parameters.StartIndex = (this.parameters.StartIndex || 0) + this.settingsService.DefaultPageSize; - const tmpCandidates = Object.assign([], this.candidates); - await this.loadData(this.parameters); + const tmpCandidates = Object.assign([], this.candidates); + await this.loadData(this.parameters); - this.candidates.unshift(...tmpCandidates); - this.changeDetectorRef.detectChanges(); - } - })); + this.candidates.unshift(...tmpCandidates); + this.changeDetectorRef.detectChanges(); + } + }), + ); } } public ngOnDestroy(): void { - this.subscriptions.forEach(s => s.unsubscribe()); + this.subscriptions.forEach((s) => s.unsubscribe()); } public async typeChanged(evt: MatRadioChange): Promise { if (evt.value === 'existing') { if (this.viewport) { - this.subscriptions.push(this.viewport.renderedRangeStream.subscribe(async (range: ListRange) => { - if (range.end === (this.settingsService.DefaultPageSize + this.parameters.StartIndex)) { - this.parameters.StartIndex += this.settingsService.DefaultPageSize; - - const tmpCandidates = Object.assign([], this.candidates); - await this.loadData(this.parameters); - - this.candidates.unshift(...tmpCandidates); - this.changeDetectorRef.detectChanges(); - } - })); + this.subscriptions.push( + this.viewport.renderedRangeStream.subscribe(async (range: ListRange) => { + if (range.end === this.settingsService.DefaultPageSize + (this.parameters.StartIndex || 0)) { + this.parameters.StartIndex = (this.parameters.StartIndex || 0) + this.settingsService.DefaultPageSize; + + const tmpCandidates = Object.assign([], this.candidates); + await this.loadData(this.parameters); + + this.candidates.unshift(...tmpCandidates); + this.changeDetectorRef.detectChanges(); + } + }), + ); } - this.selectedRole = null; + this.selectedRole = undefined; await this.loadData({ ...this.parameters, ...{ StartIndex: 0 } }); } } @@ -120,23 +121,26 @@ export class SystemRoleConfigComponent implements AfterViewInit, OnDestroy { public close(createNew: boolean): void { if (createNew) { - this.sidesheetRef.close({ NameNewEset: this.form.get('name').value }); + this.sidesheetRef.close({ NameNewEset: this.form.get('name')?.value }); } else { this.sidesheetRef.close({ UidEset: this.selectedRole }); } } private async loadData(newState?: CollectionLoadParameters): Promise { - let overlayRef: OverlayRef; - setTimeout(() => overlayRef = this.busyService.show()); + if (this.busyService.overlayRefs.length === 0) { + this.busyService.show(); + } try { - this.candidates = (await this.addToExistingProvider.getExistingRoles(this.data.uid, newState)) - .Data; + this.candidates = (await this.addToExistingProvider.getExistingRoles(this.data.uid, newState || {})).Data; } finally { - setTimeout(() => this.busyService.hide(overlayRef)); + this.busyService.hide(); } } - public LdsAddOrCreate = '#LDS#Here you can merge the application entitlements into a new system role or add the application entitlements to an existing system role. The system role will then be assigned to the application as an application entitlement.'; + public LdsAddOrCreate = + '#LDS#Here you can merge the application entitlements into a new system role or add the application entitlements to an existing system role. The system role will then be assigned to the application as an application entitlement.'; + public LdsCreate = + '#LDS#Here you can create an empty system role. The system role will then be assigned to the application as an application entitlement.'; } diff --git a/imxweb/projects/aob/src/lib/entitlements/entitlement-add/system-role-config/system-role-config.service.ts b/imxweb/projects/aob/src/lib/entitlements/entitlement-add/system-role-config/system-role-config.service.ts index 5f1760132..48d06ef2c 100644 --- a/imxweb/projects/aob/src/lib/entitlements/entitlement-add/system-role-config/system-role-config.service.ts +++ b/imxweb/projects/aob/src/lib/entitlements/entitlement-add/system-role-config/system-role-config.service.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -25,27 +25,25 @@ */ import { Injectable } from '@angular/core'; -import { PortalEntitlementSystemrole } from 'imx-api-aob'; +import { PortalEntitlementSystemrole } from '@imx-modules/imx-api-aob'; -import { CollectionLoadParameters, EntitySchema, TypedEntityCollectionData } from 'imx-qbm-dbts'; +import { CollectionLoadParameters, EntitySchema, TypedEntityCollectionData } from '@imx-modules/imx-qbm-dbts'; import { AobApiService } from '../../../aob-api-client.service'; @Injectable({ - providedIn: 'root' + providedIn: 'root', }) export class SystemRoleConfigService { - - constructor( - private readonly aobClient: AobApiService, - ) { - } + constructor(private readonly aobClient: AobApiService) {} public get roleSchema(): EntitySchema { return this.aobClient.typedClient.PortalEntitlementcandidatesEset.GetSchema(); } - public async getExistingRoles(application: string, parameters: CollectionLoadParameters): - Promise> { + public async getExistingRoles( + application: string, + parameters: CollectionLoadParameters, + ): Promise> { return this.aobClient.typedClient.PortalEntitlementSystemrole.Get(application, parameters); } } diff --git a/imxweb/projects/aob/src/lib/entitlements/entitlement-detail/entitlement-detail.component.html b/imxweb/projects/aob/src/lib/entitlements/entitlement-detail/entitlement-detail.component.html index d76de4206..17d2d95d5 100644 --- a/imxweb/projects/aob/src/lib/entitlements/entitlement-detail/entitlement-detail.component.html +++ b/imxweb/projects/aob/src/lib/entitlements/entitlement-detail/entitlement-detail.component.html @@ -2,5 +2,6 @@ [entitlement]="data?.entitlement" [serviceItem]="data?.serviceItem" (controlCreated)="form.addControl('entitlementedit', $event)" - (saved)="afterSave($event)"> + (saved)="afterSave($event)" +> diff --git a/imxweb/projects/aob/src/lib/entitlements/entitlement-detail/entitlement-detail.component.scss b/imxweb/projects/aob/src/lib/entitlements/entitlement-detail/entitlement-detail.component.scss index 3364f1f4f..c9e89c84d 100644 --- a/imxweb/projects/aob/src/lib/entitlements/entitlement-detail/entitlement-detail.component.scss +++ b/imxweb/projects/aob/src/lib/entitlements/entitlement-detail/entitlement-detail.component.scss @@ -1 +1 @@ -// styles \ No newline at end of file +// styles diff --git a/imxweb/projects/aob/src/lib/entitlements/entitlement-detail/entitlement-detail.component.ts b/imxweb/projects/aob/src/lib/entitlements/entitlement-detail/entitlement-detail.component.ts index c598d71e3..0bff3fd8e 100644 --- a/imxweb/projects/aob/src/lib/entitlements/entitlement-detail/entitlement-detail.component.ts +++ b/imxweb/projects/aob/src/lib/entitlements/entitlement-detail/entitlement-detail.component.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -26,17 +26,17 @@ import { Component, Inject, OnDestroy } from '@angular/core'; import { UntypedFormGroup } from '@angular/forms'; -import { EuiSidesheetRef, EUI_SIDESHEET_DATA } from '@elemental-ui/core'; +import { EUI_SIDESHEET_DATA, EuiSidesheetRef } from '@elemental-ui/core'; import { Subscription } from 'rxjs'; +import { TypedEntity } from '@imx-modules/imx-qbm-dbts'; import { ConfirmationService, SnackBarService } from 'qbm'; -import { TypedEntity } from 'imx-qbm-dbts'; import { EntitlementWrapper } from '../entitlement-wrapper.interface'; @Component({ selector: 'imx-entitlement-detail', templateUrl: './entitlement-detail.component.html', - styleUrls: ['./entitlement-detail.component.scss'] + styleUrls: ['./entitlement-detail.component.scss'], }) export class EntitlementDetailComponent implements OnDestroy { public readonly form = new UntypedFormGroup({}); @@ -47,35 +47,37 @@ export class EntitlementDetailComponent implements OnDestroy { @Inject(EUI_SIDESHEET_DATA) public readonly data: EntitlementWrapper, private readonly sidesheetRef: EuiSidesheetRef, private readonly snackbar: SnackBarService, - confirmation: ConfirmationService + confirmation: ConfirmationService, ) { - this.subscriptions.push(this.sidesheetRef.closeClicked().subscribe(async () => { - const entitlementHasChanges = this.entityHasChanges(this.data.entitlement); - const serviceItemHasChanges = this.entityHasChanges(this.data.serviceItem); - const hasChanges = entitlementHasChanges || serviceItemHasChanges || !this.form.pristine; + this.subscriptions.push( + this.sidesheetRef.closeClicked().subscribe(async () => { + const entitlementHasChanges = this.entityHasChanges(this.data.entitlement); + const serviceItemHasChanges = this.entityHasChanges(this.data?.serviceItem); + const hasChanges = entitlementHasChanges || serviceItemHasChanges || !this.form.pristine; - if (hasChanges && !(await confirmation.confirmLeaveWithUnsavedChanges())) { - return; - } + if (hasChanges && !(await confirmation.confirmLeaveWithUnsavedChanges())) { + return; + } - if (entitlementHasChanges) { - await this.data.entitlement.GetEntity().DiscardChanges(); - } + if (entitlementHasChanges) { + await this.data.entitlement?.GetEntity().DiscardChanges(); + } - if (serviceItemHasChanges) { - await this.data.serviceItem.GetEntity().DiscardChanges(); - } + if (serviceItemHasChanges) { + await this.data?.serviceItem?.GetEntity().DiscardChanges(); + } - if (hasChanges) { - this.snackbar.open({ key: '#LDS#The changes were discarded.' }); - } + if (hasChanges) { + this.snackbar.open({ key: '#LDS#The changes were discarded.' }); + } - this.sidesheetRef.close(false); - })); + this.sidesheetRef.close(false); + }), + ); } public ngOnDestroy(): void { - this.subscriptions.forEach(s => s.unsubscribe()); + this.subscriptions.forEach((s) => s.unsubscribe()); } public afterSave(success: boolean): void { @@ -86,7 +88,7 @@ export class EntitlementDetailComponent implements OnDestroy { this.sidesheetRef.close(true); } - private entityHasChanges(entity: TypedEntity): boolean { - return entity != null && entity.GetEntity().GetDiffData()?.Data?.length > 0; + private entityHasChanges(entity: TypedEntity | undefined): boolean { + return entity != null && !!entity?.GetEntity().GetDiffData()?.Data?.length; } } diff --git a/imxweb/projects/aob/src/lib/entitlements/entitlement-edit-auto-add/entitlement-edit-auto-add.component.html b/imxweb/projects/aob/src/lib/entitlements/entitlement-edit-auto-add/entitlement-edit-auto-add.component.html index 317f5c16a..0bfcc1428 100644 --- a/imxweb/projects/aob/src/lib/entitlements/entitlement-edit-auto-add/entitlement-edit-auto-add.component.html +++ b/imxweb/projects/aob/src/lib/entitlements/entitlement-edit-auto-add/entitlement-edit-auto-add.component.html @@ -1,13 +1,32 @@ -
- - - - +
+ + + +
-
- + -
diff --git a/imxweb/projects/aob/src/lib/entitlements/entitlement-edit-auto-add/entitlement-edit-auto-add.component.scss b/imxweb/projects/aob/src/lib/entitlements/entitlement-edit-auto-add/entitlement-edit-auto-add.component.scss deleted file mode 100644 index bbfe24996..000000000 --- a/imxweb/projects/aob/src/lib/entitlements/entitlement-edit-auto-add/entitlement-edit-auto-add.component.scss +++ /dev/null @@ -1,24 +0,0 @@ -.eui-sidesheet-content { - height: inherit; - overflow: hidden; - display: flex; - flex-direction: column; - - .imx-content-card { - flex: 1 1 auto; - overflow: auto; - } -} - -.eui-sidesheet-actions { - .justify-start { - margin-right: auto; - display: flex; - flex-direction: column; - justify-content: center; - } - - button:not(:last-of-type):not(.justify-start) { - margin-right: 10px; - } -} \ No newline at end of file diff --git a/imxweb/projects/aob/src/lib/entitlements/entitlement-edit-auto-add/entitlement-edit-auto-add.component.ts b/imxweb/projects/aob/src/lib/entitlements/entitlement-edit-auto-add/entitlement-edit-auto-add.component.ts index 9054ec639..9a6d97453 100644 --- a/imxweb/projects/aob/src/lib/entitlements/entitlement-edit-auto-add/entitlement-edit-auto-add.component.ts +++ b/imxweb/projects/aob/src/lib/entitlements/entitlement-edit-auto-add/entitlement-edit-auto-add.component.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -24,23 +24,21 @@ * */ -import { OverlayRef } from '@angular/cdk/overlay'; import { Component, Inject, OnDestroy } from '@angular/core'; -import { EuiLoadingService, EuiSidesheetRef, EuiSidesheetService, EUI_SIDESHEET_DATA } from '@elemental-ui/core'; +import { EUI_SIDESHEET_DATA, EuiLoadingService, EuiSidesheetRef, EuiSidesheetService } from '@elemental-ui/core'; import { TranslateService } from '@ngx-translate/core'; -import { Subscription } from 'rxjs'; import _ from 'lodash'; +import { Subscription } from 'rxjs'; -import { EntitlementToAddData, PortalApplication } from 'imx-api-aob'; -import { isExpressionInvalid, SqlExpression, SqlWizardExpression } from 'imx-qbm-dbts'; -import { ConfirmationService, SnackBarService } from 'qbm'; +import { EntitlementToAddData, PortalApplication, SqlWizardWrite } from '@imx-modules/imx-api-aob'; +import { isExpressionInvalid, SqlExpression, SqlWizardExpression } from '@imx-modules/imx-qbm-dbts'; +import { calculateSidesheetWidth, ConfirmationService, SnackBarService } from 'qbm'; import { EntitlementEditAutoAddService } from './entitlement-edit-auto-add.service'; import { EntitlementToAddDataWrapperService } from './entitlement-to-add-data-wrapper.service'; import { MappedEntitlementsPreviewComponent } from './mapped-entitlements-preview/mapped-entitlements-preview.component'; @Component({ templateUrl: './entitlement-edit-auto-add.component.html', - styleUrls: ['./entitlement-edit-auto-add.component.scss'], }) export class EntitlementEditAutoAddComponent implements OnDestroy { private subscriptions: Subscription[] = []; @@ -66,12 +64,12 @@ export class EntitlementEditAutoAddComponent implements OnDestroy { private readonly snackbar: SnackBarService, private readonly sidesheet: EuiSidesheetService, private readonly translateService: TranslateService, - confirm: ConfirmationService + confirm: ConfirmationService, ) { this.subscriptions.push( sidesheetRef.closeClicked().subscribe(async () => { if (this.exprHasntChanged || (await confirm.confirmLeaveWithUnsavedChanges())) sidesheetRef.close(this.reload); - }) + }), ); this.sqlExpression = _.cloneDeep(data.sqlExpression); } @@ -81,29 +79,25 @@ export class EntitlementEditAutoAddComponent implements OnDestroy { } public async showResults(withSave: boolean): Promise { - let overlay: OverlayRef; - setTimeout(() => { - overlay = this.busyService.show(); - }); + this.showBusyIndicator(); let elements: EntitlementToAddData; try { await this.setExtendedData(this.sqlExpression.Expression); elements = await this.svc.showEntitlementsToMap(this.data.application.InteractiveEntityStateData); } finally { - setTimeout(() => { - this.busyService.hide(overlay); - }); + this.busyService.hide(); } if (!elements) { return; } const entitlementToAdd = this.entitlementToAddWrapperService.buildTypedEntities(elements); - const saveChanges: { save: boolean; map: boolean } = await this.sidesheet.open(MappedEntitlementsPreviewComponent, { + const saveChanges: { save: boolean; map: boolean } = await this.sidesheet + .open(MappedEntitlementsPreviewComponent, { title: await this.translateService.get('#LDS#Heading View Matching Application Entitlements').toPromise(), subTitle: this.data.application.GetEntity().GetDisplay(), padding: '0px', - width: 'max(550px, 55%)', + width: calculateSidesheetWidth(1000), testId: 'mapped-entitlements-preview-sidesheet', data: { entitlementToAdd, @@ -116,18 +110,14 @@ export class EntitlementEditAutoAddComponent implements OnDestroy { this.reload = true; if (withSave && saveChanges?.save) { - setTimeout(() => { - overlay = this.busyService.show(); - }); + this.showBusyIndicator(); try { await this.data.application.GetEntity().Commit(false); if (saveChanges.map) { this.svc.mapEntitlementsToApplication(this.data.application.UID_AOBApplication.value); } } finally { - setTimeout(() => { - this.busyService.hide(overlay); - }); + this.busyService.hide(); } this.sidesheetRef.close(true); this.snackbar.open({ @@ -137,15 +127,11 @@ export class EntitlementEditAutoAddComponent implements OnDestroy { }); } else { // reset the extended data if you do not save the data - setTimeout(() => { - overlay = this.busyService.show(); - }); + this.showBusyIndicator(); try { await this.setExtendedData(this.data.sqlExpression.Expression); } finally { - setTimeout(() => { - this.busyService.hide(overlay); - }); + this.busyService.hide(); } } } @@ -154,28 +140,38 @@ export class EntitlementEditAutoAddComponent implements OnDestroy { // check if the sqlWizard has a valid expression return ( this.exprHasntChanged || - this.sqlExpression?.Expression?.Expressions.length === 0 || + this.sqlExpression?.Expression?.Expressions?.length === 0 || isExpressionInvalid(this.sqlExpression) || - !this.hasValuesSet(this.sqlExpression.Expression) + !this.hasValuesSet(this.sqlExpression?.Expression) ); } - private hasValuesSet(sqlExpression: SqlExpression, checkCurrent: boolean = false): boolean { - const current = !checkCurrent || sqlExpression.Value != null; + private hasValuesSet(sqlExpression: SqlExpression | undefined, checkCurrent: boolean = false): boolean { + const current = !checkCurrent || sqlExpression?.Value != null; - if (sqlExpression.Expressions?.length > 0) { - return current && sqlExpression.Expressions.every((elem) => this.hasValuesSet(elem, true)); + if (!!sqlExpression?.Expressions?.length) { + return current && !!sqlExpression?.Expressions?.every((elem) => this.hasValuesSet(elem, true)); } return current; } - private async setExtendedData(sqlExpression: SqlExpression): Promise { + private async setExtendedData(sqlExpression: SqlExpression | undefined): Promise { + const SqlExpression: SqlWizardWrite = { Filters: [] }; + if (sqlExpression) { + SqlExpression.Filters?.push(sqlExpression); + } return this.data.application.setExtendedData({ ...this.data.application.extendedData, ...{ - SqlExpression: { Filters: [sqlExpression] }, + SqlExpression, }, }); } + + private showBusyIndicator(): void { + if (this.busyService.overlayRefs.length === 0) { + this.busyService.show(); + } + } } diff --git a/imxweb/projects/aob/src/lib/entitlements/entitlement-edit-auto-add/entitlement-edit-auto-add.service.ts b/imxweb/projects/aob/src/lib/entitlements/entitlement-edit-auto-add/entitlement-edit-auto-add.service.ts index c30249983..0bfde95d2 100644 --- a/imxweb/projects/aob/src/lib/entitlements/entitlement-edit-auto-add/entitlement-edit-auto-add.service.ts +++ b/imxweb/projects/aob/src/lib/entitlements/entitlement-edit-auto-add/entitlement-edit-auto-add.service.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -26,17 +26,17 @@ import { Injectable } from '@angular/core'; -import { EntitlementToAddData } from 'imx-api-aob'; -import { CollectionLoadParameters, EntityCollectionData, FilterProperty, InteractiveEntityStateData } from 'imx-qbm-dbts'; +import { EntitlementToAddData } from '@imx-modules/imx-api-aob'; +import { CollectionLoadParameters, EntityCollectionData, FilterProperty, InteractiveEntityStateData } from '@imx-modules/imx-qbm-dbts'; import { SqlWizardApiService } from 'qbm'; import { AobApiService } from '../../aob-api-client.service'; @Injectable({ providedIn: 'root' }) export class EntitlementEditAutoAddService implements SqlWizardApiService { - constructor(private readonly api: AobApiService) { } + constructor(private readonly api: AobApiService) {} public async getFilterProperties(table: string): Promise { - return (await this.api.client.portal_application_sqlwizard_tables_columns_get(table)).Properties; + return (await this.api.client.portal_application_sqlwizard_tables_columns_get(table)).Properties || []; } public async getCandidates(parentTable: string, options?: CollectionLoadParameters): Promise { @@ -44,11 +44,13 @@ export class EntitlementEditAutoAddService implements SqlWizardApiService { } public async showEntitlementsToMap(state: InteractiveEntityStateData): Promise { - return this.api.client.portal_application_interactive_entitlementstoadd_get( - state.EntityId, { keys: state.Keys, state: state.State }); + return this.api.client.portal_application_interactive_entitlementstoadd_get(state?.EntityId || '', { + keys: state.Keys, + state: state.State, + }); } public async mapEntitlementsToApplication(uidApplication: string): Promise { - return this.api.client.portal_application_map_post(uidApplication); + return this.api.client.portal_application_map_post(uidApplication); } } diff --git a/imxweb/projects/aob/src/lib/entitlements/entitlement-edit-auto-add/entitlement-to-add-data-wrapper.service.ts b/imxweb/projects/aob/src/lib/entitlements/entitlement-edit-auto-add/entitlement-to-add-data-wrapper.service.ts index 26078436f..ea6426c20 100644 --- a/imxweb/projects/aob/src/lib/entitlements/entitlement-edit-auto-add/entitlement-to-add-data-wrapper.service.ts +++ b/imxweb/projects/aob/src/lib/entitlements/entitlement-edit-auto-add/entitlement-to-add-data-wrapper.service.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -26,31 +26,26 @@ import { Injectable } from '@angular/core'; -import { EntitlementData, EntitlementToAddData } from 'imx-api-aob'; -import { - EntityColumnData, - EntityData, - TypedEntityBuilder, - TypedEntityCollectionData -} from 'imx-qbm-dbts'; +import { EntitlementData, EntitlementToAddData } from '@imx-modules/imx-api-aob'; +import { EntityColumnData, EntityData, TypedEntityBuilder, TypedEntityCollectionData } from '@imx-modules/imx-qbm-dbts'; import { EntitlementToAddTyped } from './entitlement-to-add-typed'; @Injectable({ - providedIn: 'root' + providedIn: 'root', }) export class EntitlementToAddDataWrapperService { - public readonly entitySchema = EntitlementToAddTyped.GetEntitySchema(); private readonly builder = new TypedEntityBuilder(EntitlementToAddTyped); public buildTypedEntities(data: EntitlementToAddData): TypedEntityCollectionData { - const entities = data.Data.map((element, index) => this.buildEntityData(element, `${index}`)); + const entities = data.Data?.map((element, index) => this.buildEntityData(element, `${index}`)); return this.builder.buildReadWriteEntities( { - TotalCount: entities.length, - Entities: entities.sort((a, b) => this.compareElement(a, b)) + TotalCount: entities?.length || 0, + Entities: entities?.sort((a, b) => this.compareElement(a, b)), }, - this.entitySchema); + this.entitySchema, + ); } private buildEntityData(data: EntitlementData, key: string): EntityData { @@ -60,18 +55,17 @@ export class EntitlementToAddDataWrapperService { ret.IsAssignedToOther = { Value: data.IsAssignedToOther, IsReadOnly: true }; ret.DisplayName = { Value: data.DisplayName, IsReadOnly: true }; ret.CanonicalName = { Value: data.CanonicalName, IsReadOnly: true }; - ret.UID_AOBApplicationConflicted = - { + ret.UID_AOBApplicationConflicted = { Value: data.UID_AOBApplicationConflicted, IsReadOnly: true, - DisplayValue: data.DisplayApplicationConflicted + DisplayValue: data.DisplayApplicationConflicted, }; return { Columns: ret, Keys: [key] }; } private compareElement(a: EntityData, b: EntityData): number { - const val1 = `${(a.Columns.IsAssignedToMe.Value ? 1 : a.Columns.IsAssignedToOther.Value ? 0 : 2)} ${a.Columns.DisplayName.Value}`; - const val2 = `${(b.Columns.IsAssignedToMe.Value ? 1 : b.Columns.IsAssignedToOther.Value ? 0 : 2)} ${b.Columns.DisplayName.Value}`; + const val1 = `${a.Columns?.IsAssignedToMe.Value ? 1 : a.Columns?.IsAssignedToOther.Value ? 0 : 2} ${a.Columns?.DisplayName.Value}`; + const val2 = `${b.Columns?.IsAssignedToMe.Value ? 1 : b.Columns?.IsAssignedToOther.Value ? 0 : 2} ${b.Columns?.DisplayName.Value}`; return val1.localeCompare(val2); } } diff --git a/imxweb/projects/aob/src/lib/entitlements/entitlement-edit-auto-add/entitlement-to-add-typed.ts b/imxweb/projects/aob/src/lib/entitlements/entitlement-edit-auto-add/entitlement-to-add-typed.ts index ab76aa0b7..f521328d9 100644 --- a/imxweb/projects/aob/src/lib/entitlements/entitlement-edit-auto-add/entitlement-to-add-typed.ts +++ b/imxweb/projects/aob/src/lib/entitlements/entitlement-edit-auto-add/entitlement-to-add-typed.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -24,10 +24,9 @@ * */ -import { DisplayPattern, EntitySchema, IClientProperty, IReadValue, TypedEntity, ValType } from 'imx-qbm-dbts'; +import { DisplayPattern, EntitySchema, IClientProperty, IReadValue, TypedEntity, ValType } from '@imx-modules/imx-qbm-dbts'; export class EntitlementToAddTyped extends TypedEntity { - public readonly IsAssignedToMe: IReadValue = this.GetEntityValue('IsAssignedToMe'); public readonly IsAssignedToOther: IReadValue = this.GetEntityValue('IsAssignedToOther'); public readonly DisplayName: IReadValue = this.GetEntityValue('DisplayName'); @@ -39,29 +38,29 @@ export class EntitlementToAddTyped extends TypedEntity { ret.IsAssignedToMe = { Type: ValType.Bool, - ColumnName: 'IsAssignedToMe' + ColumnName: 'IsAssignedToMe', }; ret.IsAssignedToOther = { Type: ValType.Bool, - ColumnName: 'IsAssignedToOther' + ColumnName: 'IsAssignedToOther', }; ret.DisplayName = { Type: ValType.String, - ColumnName: 'DisplayName' + ColumnName: 'DisplayName', }; ret.CanonicalName = { Type: ValType.String, - ColumnName: 'CanonicalName' + ColumnName: 'CanonicalName', }; ret.UID_AOBApplicationConflicted = { Type: ValType.String, - ColumnName: 'UID_AOBApplicationConflicted' + ColumnName: 'UID_AOBApplicationConflicted', }; return { TypeName: 'EntitlementToAddTyped', DisplayPattern: new DisplayPattern('%DisplayName%'), - Columns: ret + Columns: ret, }; } } diff --git a/imxweb/projects/aob/src/lib/entitlements/entitlement-edit-auto-add/mapped-entitlements-preview/mapped-entitlements-preview.component.html b/imxweb/projects/aob/src/lib/entitlements/entitlement-edit-auto-add/mapped-entitlements-preview/mapped-entitlements-preview.component.html index dc599c38e..e170daa82 100644 --- a/imxweb/projects/aob/src/lib/entitlements/entitlement-edit-auto-add/mapped-entitlements-preview/mapped-entitlements-preview.component.html +++ b/imxweb/projects/aob/src/lib/entitlements/entitlement-edit-auto-add/mapped-entitlements-preview/mapped-entitlements-preview.component.html @@ -1,66 +1,73 @@
- +
- {{alertText}} + {{ alertText }}
- {{speedupText}} + {{ speedupText }}
- +
#LDS#Matching application entitlements - {{getCount('')}} + {{ getCount('') }} #LDS#Application entitlements to add - {{getCount('add')}} + {{ getCount('add') }} #LDS#Application entitlements already assigned to this application - {{getCount('assigned')}} + {{ getCount('assigned') }} #LDS#Application entitlements assigned to another application - {{getCount('conflicted')}} + {{ getCount('conflicted') }}
- -
- - - -
{{ entity.DisplayName.Column.GetDisplayValue() }}
-
{{ entity.CanonicalName.Column.GetDisplayValue()}}
-
-
- - - - {{(entity.IsAssignedToMe.value ? '#LDS#Already assigned to this application' :'#LDS#Assigned to other application') | - translate}} + + + {{ '#LDS#Application entitlement' | translate }} + +
{{ item.DisplayName.Column.GetDisplayValue() }}
+
{{ item.CanonicalName.Column.GetDisplayValue() }}
+ +
+ + + + + {{ + (item.IsAssignedToMe.value ? '#LDS#Already assigned to this application' : '#LDS#Assigned to other application') | translate + }} -
-
- - - -
- - + + + + {{ '#LDS#Already assigned to following application' | translate }} + +
{{ item.UID_AOBApplicationConflicted?.Column.GetDisplayValue() }}
+ +
+
-
- - {{'#LDS#Assign application entitlements after saving' |translate}} +
+ + {{ '#LDS#Assign application entitlements after saving' | translate }} -
diff --git a/imxweb/projects/aob/src/lib/entitlements/entitlement-edit-auto-add/mapped-entitlements-preview/mapped-entitlements-preview.component.scss b/imxweb/projects/aob/src/lib/entitlements/entitlement-edit-auto-add/mapped-entitlements-preview/mapped-entitlements-preview.component.scss index b86f6a61e..12a1910bd 100644 --- a/imxweb/projects/aob/src/lib/entitlements/entitlement-edit-auto-add/mapped-entitlements-preview/mapped-entitlements-preview.component.scss +++ b/imxweb/projects/aob/src/lib/entitlements/entitlement-edit-auto-add/mapped-entitlements-preview/mapped-entitlements-preview.component.scss @@ -1,35 +1,7 @@ -.eui-sidesheet-content { - height: inherit; - overflow: hidden; - display: flex; - flex-direction: column; - - .imx-content-card { - flex: 1 1 auto; - overflow: hidden; - - .imx-table-container { - display: flex; - flex-direction: column; - overflow: hidden; - height: calc(100% - 80px); - flex: 1 1 auto; - } - } -} - -.eui-sidesheet-actions { - .justify-start { - margin-right: auto; - display: flex; - flex-direction: column; - justify-content: center; - height: auto; - } +@import 'base/mixins'; - button:not(:last-of-type):not(.justify-start) { - margin-right: 10px; - } +.eui-sidesheet-content { + @include flex-column-container($overflow: hidden, $height: inherit); } .imx-info-text { diff --git a/imxweb/projects/aob/src/lib/entitlements/entitlement-edit-auto-add/mapped-entitlements-preview/mapped-entitlements-preview.component.ts b/imxweb/projects/aob/src/lib/entitlements/entitlement-edit-auto-add/mapped-entitlements-preview/mapped-entitlements-preview.component.ts index 14c060d29..aaebe4ab4 100644 --- a/imxweb/projects/aob/src/lib/entitlements/entitlement-edit-auto-add/mapped-entitlements-preview/mapped-entitlements-preview.component.ts +++ b/imxweb/projects/aob/src/lib/entitlements/entitlement-edit-auto-add/mapped-entitlements-preview/mapped-entitlements-preview.component.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -25,21 +25,20 @@ */ import { Component, Inject, OnInit } from '@angular/core'; -import { EuiSidesheetRef, EUI_SIDESHEET_DATA } from '@elemental-ui/core'; +import { EUI_SIDESHEET_DATA, EuiSidesheetRef } from '@elemental-ui/core'; -import { CollectionLoadParameters, DisplayColumns, EntitySchema, TypedEntityCollectionData } from 'imx-qbm-dbts'; -import { DataSourceToolbarSettings } from 'qbm'; +import { DisplayColumns, EntitySchema, TypedEntityCollectionData } from '@imx-modules/imx-qbm-dbts'; +import { DataViewSource } from 'qbm'; import { EntitlementToAddTyped } from '../entitlement-to-add-typed'; @Component({ templateUrl: './mapped-entitlements-preview.component.html', styleUrls: ['./mapped-entitlements-preview.component.scss'], + providers: [DataViewSource], }) export class MappedEntitlementsPreviewComponent implements OnInit { - public settings: DataSourceToolbarSettings; public readonly DisplayColumns = DisplayColumns; public entitySchema: EntitySchema; - public navigationState: CollectionLoadParameters = {StartIndex:0, PageSize:20}; public alertText = '#LDS#Here you can get an overview of application entitlements that will be added to this application by the conditions. Application entitlements that are already assigned to an application will be skipped.'; @@ -52,7 +51,8 @@ export class MappedEntitlementsPreviewComponent implements OnInit { withSave: boolean; entitlementToAdd: TypedEntityCollectionData; }, - private readonly sidesheetRef: EuiSidesheetRef + private readonly sidesheetRef: EuiSidesheetRef, + public dataSource: DataViewSource, ) {} public apply(map: boolean): void { @@ -72,29 +72,19 @@ export class MappedEntitlementsPreviewComponent implements OnInit { return this.data.entitlementToAdd.totalCount; } - public navigate(source: CollectionLoadParameters): void { - this.entitySchema = EntitlementToAddTyped.GetEntitySchema(); - this.navigationState = { ...this.navigationState, ...source }; - - const data = this.data.entitlementToAdd.Data.slice(this.navigationState.StartIndex, this.navigationState.StartIndex + this.navigationState.PageSize); - const displayedColumns = [ - this.entitySchema.Columns.DisplayName, - this.entitySchema.Columns.IsAssignedToMe, - this.entitySchema.Columns.UID_AOBApplicationConflicted, - ]; - this.settings = { - displayedColumns: displayedColumns, - dataSource: { - Data: data, - totalCount: this.data.entitlementToAdd.totalCount, - }, - entitySchema: this.entitySchema, - navigationState: this.navigationState, - }; - } - public async ngOnInit(): Promise { + this.entitySchema = EntitlementToAddTyped.GetEntitySchema(); - this.navigate({}); + const displayedColumns = [ + this.entitySchema.Columns.DisplayName, + this.entitySchema.Columns.IsAssignedToMe, + this.entitySchema.Columns.UID_AOBApplicationConflicted, + ]; + this.dataSource.init({ + execute: (): Promise> => Promise.resolve(this.data.entitlementToAdd), + schema: this.entitySchema, + columnsToDisplay: displayedColumns, + localSource: true, + }); } } diff --git a/imxweb/projects/aob/src/lib/entitlements/entitlement-edit/entitlement-edit.component.html b/imxweb/projects/aob/src/lib/entitlements/entitlement-edit/entitlement-edit.component.html index 64acc8ffe..b2f0d7960 100644 --- a/imxweb/projects/aob/src/lib/entitlements/entitlement-edit/entitlement-edit.component.html +++ b/imxweb/projects/aob/src/lib/entitlements/entitlement-edit/entitlement-edit.component.html @@ -1,23 +1,45 @@
- +
- + - + (controlCreated)="form.addControl('tags', $event)" + > - +
- - + +
diff --git a/imxweb/projects/aob/src/lib/entitlements/entitlement-edit/entitlement-edit.component.scss b/imxweb/projects/aob/src/lib/entitlements/entitlement-edit/entitlement-edit.component.scss index 76f0a2a43..7536ad2ef 100644 --- a/imxweb/projects/aob/src/lib/entitlements/entitlement-edit/entitlement-edit.component.scss +++ b/imxweb/projects/aob/src/lib/entitlements/entitlement-edit/entitlement-edit.component.scss @@ -1,11 +1,5 @@ -:host { - display: flex; - flex-direction: column; - height: 100%; +@import 'base/mixins'; - .eui-sidesheet-content { - display: flex; - flex-direction: column; - overflow: auto; - } +:host { + @include flex-column-container($height: 100%); } diff --git a/imxweb/projects/aob/src/lib/entitlements/entitlement-edit/entitlement-edit.component.ts b/imxweb/projects/aob/src/lib/entitlements/entitlement-edit/entitlement-edit.component.ts index 140d8ce4a..40108bcd7 100644 --- a/imxweb/projects/aob/src/lib/entitlements/entitlement-edit/entitlement-edit.component.ts +++ b/imxweb/projects/aob/src/lib/entitlements/entitlement-edit/entitlement-edit.component.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -24,16 +24,16 @@ * */ -import { Component, Input, ErrorHandler, OnChanges, SimpleChanges, OnInit, Output, EventEmitter } from '@angular/core'; -import { UntypedFormGroup, AbstractControl } from '@angular/forms'; -import { OverlayRef } from '@angular/cdk/overlay'; +import { Component, ErrorHandler, EventEmitter, Input, OnChanges, OnInit, Output, SimpleChanges } from '@angular/core'; +import { AbstractControl, UntypedFormGroup } from '@angular/forms'; import { EuiLoadingService } from '@elemental-ui/core'; -import { PortalEntitlement, PortalEntitlementServiceitem } from 'imx-api-aob'; +import { Router } from '@angular/router'; +import { PortalEntitlement, PortalEntitlementServiceitem } from '@imx-modules/imx-api-aob'; +import { DbObjectKey, TypedEntity } from '@imx-modules/imx-qbm-dbts'; import { CdrFactoryService, ClassloggerService, ColumnDependentReference } from 'qbm'; -import { DbObjectKey, TypedEntity } from 'imx-qbm-dbts'; import { ServiceItemTagsService } from 'qer'; -import { Router } from '@angular/router'; +import { AobPermissionsService } from '../../permissions/aob-permissions.service'; /** * A component that provides a form for viewing and editing entitlements/roles. @@ -41,7 +41,7 @@ import { Router } from '@angular/router'; @Component({ selector: 'imx-entitlement-edit', templateUrl: './entitlement-edit.component.html', - styleUrls: ['./entitlement-edit.component.scss'] + styleUrls: ['./entitlement-edit.component.scss'], }) export class EntitlementEditComponent implements OnChanges, OnInit { public readonly form = new UntypedFormGroup({}); @@ -49,9 +49,10 @@ export class EntitlementEditComponent implements OnChanges, OnInit { public productTagsInitial: string[] = []; public productTagsSelected: string[]; public loadingTags: boolean; - - public cdrList: ColumnDependentReference[] = []; - public cdrListServiceItem: ColumnDependentReference[] = []; + + public cdrList: (ColumnDependentReference | undefined)[] = []; + public cdrListServiceItem: (ColumnDependentReference | undefined)[] = []; + public isEditableEntitlement: boolean; @Input() public entitlement: PortalEntitlement; @Input() public serviceItem: PortalEntitlementServiceitem; @@ -65,31 +66,30 @@ export class EntitlementEditComponent implements OnChanges, OnInit { private readonly router: Router, private readonly errorHandler: ErrorHandler, private readonly cdrFactoryService: CdrFactoryService, - private readonly busyService: EuiLoadingService - ) { } + private readonly permissions: AobPermissionsService, + private readonly busyService: EuiLoadingService, + ) {} - public ngOnInit(): void { + public async ngOnInit(): Promise { this.controlCreated.emit(this.form); - const entitlementColumns = [ - 'Ident_AOBEntitlement', - 'Description', - 'ObjectKeyAdditionalApprover' - ]; + const entitlementColumns = ['Ident_AOBEntitlement', 'Description', 'ObjectKeyAdditionalApprover']; this.cdrList = this.cdrFactoryService.buildCdrFromColumnList(this.entitlement.GetEntity(), entitlementColumns); - + if (this.serviceItem) { const serviceIemColumns = [ - 'UID_OrgRuler', - 'UID_PWODecisionMethod', - 'UID_QERTermsOfUse', - 'UID_AccProductParamCategory', + 'UID_OrgRuler', + 'UID_PWODecisionMethod', + 'UID_QERTermsOfUse', + 'UID_AccProductParamCategory', 'UID_AccProductGroup', - 'ProductURL', - 'IsApproveRequiresMfa' + 'ProductURL', + 'IsApproveRequiresMfa', ]; this.cdrListServiceItem = this.cdrFactoryService.buildCdrFromColumnList(this.serviceItem.GetEntity(), serviceIemColumns); } + + this.isEditableEntitlement = await this.editableEntitlement(); } public async ngOnChanges(changes: SimpleChanges): Promise { @@ -117,8 +117,9 @@ export class EntitlementEditComponent implements OnChanges, OnInit { private async initTags(entitlement: PortalEntitlement): Promise { this.loadingTags = true; - this.productTagsInitial = (await this.tagProvider.getTags(entitlement.UID_AccProduct.value)) - .Data.map(elem => elem.Ident_DialogTag.value); + this.productTagsInitial = (await this.tagProvider.getTags(entitlement.UID_AccProduct.value)).Data.map( + (elem) => elem.Ident_DialogTag.value, + ); this.productTagsSelected = this.productTagsInitial.slice(); this.loadingTags = false; @@ -127,8 +128,9 @@ export class EntitlementEditComponent implements OnChanges, OnInit { private async tryCommit(typedEntities: TypedEntity[]): Promise { let success = false; - let overlayRef: OverlayRef; - setTimeout(() => overlayRef = this.busyService.show()); + if (this.busyService.overlayRefs.length === 0) { + this.busyService.show(); + } try { for (const typedEntity of typedEntities) { @@ -148,7 +150,7 @@ export class EntitlementEditComponent implements OnChanges, OnInit { } catch (error) { this.errorHandler.handleError(error); } finally { - setTimeout(() => this.busyService.hide(overlayRef)); + this.busyService.hide(); } return success; @@ -157,26 +159,23 @@ export class EntitlementEditComponent implements OnChanges, OnInit { private async saveTags(): Promise { const changeSet = this.getTagsChangeSet(); - return this.tagProvider.updateTags( - this.entitlement.UID_AccProduct.value, - changeSet.add, - changeSet.remove - ); + return this.tagProvider.updateTags(this.entitlement.UID_AccProduct.value, changeSet.add, changeSet.remove); } - private getTagsChangeSet(): { add: string[], remove: string[] } { + private getTagsChangeSet(): { add: string[]; remove: string[] } { this.logger.trace(this, 'save tags initial', this.productTagsInitial); this.logger.trace(this, 'save tags selected', this.productTagsSelected); return { - add: this.productTagsSelected.filter(elem => this.productTagsInitial.indexOf(elem) < 0), - remove: this.productTagsInitial.filter(elem => this.productTagsSelected.indexOf(elem) < 0) + add: this.productTagsSelected.filter((elem) => this.productTagsInitial.indexOf(elem) < 0), + remove: this.productTagsInitial.filter((elem) => this.productTagsSelected.indexOf(elem) < 0), }; } - public get isEditableEntitlement() { - // TODO: only if IsOwnerOrAdmin is set - return DbObjectKey.FromXml(this.entitlement.ObjectKeyElement.value).TableName == "ESet"; + public async editableEntitlement(): Promise { + return (await this.permissions.isAobApplicationOwnerOrAdmin()) + ? DbObjectKey.FromXml(this.entitlement.ObjectKeyElement.value).TableName == 'ESet' + : false; } public manageEntitlement() { diff --git a/imxweb/projects/aob/src/lib/entitlements/entitlement-edit/entitlement-edit.module.ts b/imxweb/projects/aob/src/lib/entitlements/entitlement-edit/entitlement-edit.module.ts index 57e7546e0..052b95537 100644 --- a/imxweb/projects/aob/src/lib/entitlements/entitlement-edit/entitlement-edit.module.ts +++ b/imxweb/projects/aob/src/lib/entitlements/entitlement-edit/entitlement-edit.module.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -40,12 +40,8 @@ import { CdrModule } from 'qbm'; import { ServiceItemTagsModule } from 'qer'; @NgModule({ - declarations: [ - EntitlementEditComponent - ], - exports: [ - EntitlementEditComponent - ], + declarations: [EntitlementEditComponent], + exports: [EntitlementEditComponent], imports: [ CdrModule, CommonModule, @@ -58,7 +54,7 @@ import { ServiceItemTagsModule } from 'qer'; MatInputModule, ReactiveFormsModule, ServiceItemTagsModule, - TranslateModule - ] + TranslateModule, + ], }) -export class EntitlementEditModule { } +export class EntitlementEditModule {} diff --git a/imxweb/projects/aob/src/lib/entitlements/entitlement-filter.spec.ts b/imxweb/projects/aob/src/lib/entitlements/entitlement-filter.spec.ts index 64ce883e8..2714d3dd7 100644 --- a/imxweb/projects/aob/src/lib/entitlements/entitlement-filter.spec.ts +++ b/imxweb/projects/aob/src/lib/entitlements/entitlement-filter.spec.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -25,13 +25,13 @@ */ import { EntitlementFilter } from './entitlement-filter'; -import { PortalEntitlement } from 'imx-api-aob'; -import { DbVal } from 'imx-qbm-dbts'; +import { PortalEntitlement } from '@imx-modules/imx-api-aob'; +import { DbVal } from '@imx-modules/imx-qbm-dbts'; describe('EntitlementFilter', () => { const entitlementNotPublished = { IsInActive: { value: true }, - ActivationDate: { value: null } + ActivationDate: { value: null }, }; const dateLaterThanMinDate = DbVal.MinDate; @@ -39,19 +39,15 @@ describe('EntitlementFilter', () => { const entitlementWillPublish = { IsInActive: { value: true }, - ActivationDate: { value: dateLaterThanMinDate } + ActivationDate: { value: dateLaterThanMinDate }, }; const entitlementPublished = { IsInActive: { value: false }, - ActivationDate: { value: null } + ActivationDate: { value: null }, }; - const mockEntitlementData = [ - entitlementNotPublished, - entitlementWillPublish, - entitlementPublished - ]; + const mockEntitlementData = [entitlementNotPublished, entitlementWillPublish, entitlementPublished]; it('notPublished', () => { const filter = new EntitlementFilter(); diff --git a/imxweb/projects/aob/src/lib/entitlements/entitlement-filter.ts b/imxweb/projects/aob/src/lib/entitlements/entitlement-filter.ts index 71d710a7a..a1944a9d6 100644 --- a/imxweb/projects/aob/src/lib/entitlements/entitlement-filter.ts +++ b/imxweb/projects/aob/src/lib/entitlements/entitlement-filter.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -24,7 +24,7 @@ * */ -import { PortalEntitlement } from 'imx-api-aob'; +import { PortalEntitlement } from '@imx-modules/imx-api-aob'; export class EntitlementFilter { public notPublished(entitlement: PortalEntitlement): boolean { diff --git a/imxweb/projects/aob/src/lib/entitlements/entitlement-wrapper.interface.ts b/imxweb/projects/aob/src/lib/entitlements/entitlement-wrapper.interface.ts index 1035d0da2..226e9dad4 100644 --- a/imxweb/projects/aob/src/lib/entitlements/entitlement-wrapper.interface.ts +++ b/imxweb/projects/aob/src/lib/entitlements/entitlement-wrapper.interface.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -24,9 +24,9 @@ * */ -import { PortalEntitlement, PortalEntitlementServiceitem } from 'imx-api-aob'; +import { PortalEntitlement, PortalEntitlementServiceitem } from '@imx-modules/imx-api-aob'; export interface EntitlementWrapper { - entitlement: PortalEntitlement; - serviceItem: PortalEntitlementServiceitem; + entitlement?: PortalEntitlement; + serviceItem?: PortalEntitlementServiceitem; } diff --git a/imxweb/projects/aob/src/lib/entitlements/entitlements.component.html b/imxweb/projects/aob/src/lib/entitlements/entitlements.component.html index c36bd8bb1..ddea33ea8 100644 --- a/imxweb/projects/aob/src/lib/entitlements/entitlements.component.html +++ b/imxweb/projects/aob/src/lib/entitlements/entitlements.component.html @@ -1,112 +1,119 @@ -
- - - - - - - - - +
+
+
- - - - - - - - - - - - - - - - - - - -
- + + + + + + + +
+ +
+ + + {{ entitySchema?.Columns?.Ident_AOBEntitlement?.Display }} + +
{{ item.Ident_AOBEntitlement.Column.GetDisplayValue() }}
+
{{ item.Description.Column.GetDisplayValue() }}
+ +
+ + {{ '#LDS#Type' | translate }} + + + {{ getType(item) }} + + + + + + +
+
+ {{ '#LDS#Automatic' | translate }} +
+
+ +
+
+ +
+ + {{ entitySchema?.Columns?.UID_AERoleOwner?.Display }} + +
{{ item.UID_AERoleOwner.Column.GetDisplayValue() }}
+ +
+ + {{ '#LDS#Assigned' | translate }} + +
{{ item.XDateInserted.Column.GetDisplayValue() }}
+ +
+ + {{ '#LDS#Status' | translate }} + +
{{ '#LDS#Not published' | translate }}
+
+
{{ '#LDS#Will be published' | translate }}
+
{{ item.ActivationDate.Column.GetDisplayValue() }}
+
+
+
{{ '#LDS#Published' | translate }}
+
{{ '#LDS#(not yet requestable)' | translate }}
+
+ +
+
+
+ + +
+
+
+
+

{{ '#LDS#No application entitlements assigned' | translate }} @@ -116,23 +123,25 @@

- -
- - - - - - +
-

- -

+

diff --git a/imxweb/projects/aob/src/lib/entitlements/entitlements.component.scss b/imxweb/projects/aob/src/lib/entitlements/entitlements.component.scss index 39d13c33e..13f763d3f 100644 --- a/imxweb/projects/aob/src/lib/entitlements/entitlements.component.scss +++ b/imxweb/projects/aob/src/lib/entitlements/entitlements.component.scss @@ -1,6 +1,5 @@ -@use '@angular/material' as mat; @import '@elemental-ui/core/src/styles/_eui_palette.scss'; -@import '@angular/material/theming'; +@import 'base/mixins'; :host { display: flex; @@ -11,31 +10,20 @@ } .imx-entitlements-site { + &.imx-hidden{ + display:none; + } padding: 16px 40px; height: 100%; display: flex; flex-direction: column; flex: 1 1 auto; -} - -.imx-badge-container { - > div { - display: table-cell; - - > .eui-badge { - margin: 0 5px; - - ::ng-deep .eui-badge-content { - white-space: nowrap; - } - } + .imx-entitlements-row-actions{ + display: flex; + gap: 8px; } } - -// Create a config with the default typography levels. -$config: mat.define-typography-config(); - imx-data-source-toolbar-custom button { margin-right: 5px; } @@ -56,10 +44,6 @@ imx-data-source-toolbar-custom button { margin-top: 30px; } - > .eui-icon { - color: $color-gray-30; - } - .imx-aob-entitlements-empty-description { margin-bottom: 10px; } @@ -68,7 +52,7 @@ imx-data-source-toolbar-custom button { display: flex; flex-direction: column; - > .mat-raised-button { + > .mat-mdc-unelevated-button { margin-bottom: 15px; } > :last-child { @@ -77,34 +61,6 @@ imx-data-source-toolbar-custom button { } } -.imx-aob-entitlements-header { - display: flex; - flex-wrap: wrap; - margin: 10px 0 8px 0; - - > h3 { - font-size: 18px; - margin-right: 10px; - font-weight: normal; - line-height: 36px; - } - - > button { - text-transform: uppercase; - } - - > span { - line-height: 36px; - font-size: mat.font-size($config, button); - } -} - -.imx-mat-card-title { - overflow: hidden; - text-overflow: ellipsis; - white-space: nowrap; -} - .imx-aob-data-container { flex-grow: 1; align-content: flex-start; @@ -115,20 +71,8 @@ div[subtitle] { color: $color-gray-40; } -.eui-dark-theme { - :host { - .imx-aob-entitlements-empty > .eui-icon { - color: $color-gray-60; - } - } -} - .eui-contrast-theme { :host { - .imx-aob-entitlements-empty > .eui-icon { - color: $color-gray-40; - } - .imx-entitlements-site { background-color: $color-gray-100; } diff --git a/imxweb/projects/aob/src/lib/entitlements/entitlements.component.ts b/imxweb/projects/aob/src/lib/entitlements/entitlements.component.ts index 3321f6199..7d695e6ea 100644 --- a/imxweb/projects/aob/src/lib/entitlements/entitlements.component.ts +++ b/imxweb/projects/aob/src/lib/entitlements/entitlements.component.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -24,41 +24,48 @@ * */ -import { Component, EventEmitter, Input, OnChanges, Output, SimpleChanges, ViewChild } from '@angular/core'; +import { Platform } from '@angular/cdk/platform'; +import { Component, effect, EventEmitter, Input, OnChanges, Output, SimpleChanges } from '@angular/core'; import { MatDialog } from '@angular/material/dialog'; import { EuiLoadingService, EuiSidesheetService } from '@elemental-ui/core'; -import { OverlayRef } from '@angular/cdk/overlay'; -import { Platform } from '@angular/cdk/platform'; import { TranslateService } from '@ngx-translate/core'; +import { EntitlementSystemRoleInput, PortalApplication, PortalEntitlement, PortalEntitlementServiceitem } from '@imx-modules/imx-api-aob'; import { - SnackBarService, - DataSourceToolbarSettings, + CollectionLoadParameters, + DbObjectKey, + DisplayColumns, + EntitySchema, + TypedEntity, + TypedEntityCollectionData, + ValType, +} from '@imx-modules/imx-qbm-dbts'; +import { + BusyService, + calculateSidesheetWidth, ClassloggerService, + DataTableComponent, DataTileBadge, - TextContainer, + DataViewInitParameters, + DataViewSource, + MetadataService, SettingsService, + SnackBarService, SystemInfoService, - MetadataService, - DataTableComponent, - DataTilesComponent, - ClientPropertyForTableColumns, - BusyService, + TextContainer, } from 'qbm'; -import { PortalEntitlement, PortalApplication, PortalEntitlementServiceitem, EntitlementSystemRoleInput } from 'imx-api-aob'; -import { CollectionLoadParameters, IClientProperty, ValType, DisplayColumns, EntitySchema, TypedEntity, DbObjectKey } from 'imx-qbm-dbts'; -import { EntitlementsService } from './entitlements.service'; -import { LifecycleAction } from '../lifecycle-actions/lifecycle-action.enum'; import { LifecycleActionComponent } from '../lifecycle-actions/lifecycle-action.component'; -import { EntitlementsAddComponent } from './entitlement-add/entitlements-add.component'; -import { EntitlementsType } from './entitlements.model'; -import { EntitlementFilter } from './entitlement-filter'; -import { ShopsService } from '../shops/shops.service'; +import { LifecycleAction } from '../lifecycle-actions/lifecycle-action.enum'; import { ServiceItemsService } from '../service-items/service-items.service'; +import { ShopsService } from '../shops/shops.service'; +import { EntitlementsAddComponent } from './entitlement-add/entitlements-add.component'; import { EntitlementDetailComponent } from './entitlement-detail/entitlement-detail.component'; -import { EntitlementWrapper } from './entitlement-wrapper.interface'; import { EntitlementEditAutoAddComponent } from './entitlement-edit-auto-add/entitlement-edit-auto-add.component'; import { EntitlementEditAutoAddService } from './entitlement-edit-auto-add/entitlement-edit-auto-add.service'; +import { EntitlementFilter } from './entitlement-filter'; +import { EntitlementWrapper } from './entitlement-wrapper.interface'; +import { EntitlementsType } from './entitlements.model'; +import { EntitlementsService } from './entitlements.service'; /** * A component for viewing, editing and acting all {@link PortalEntitlement|entitlements} for a given {@link PortalApplication|application}. @@ -73,37 +80,36 @@ import { EntitlementEditAutoAddService } from './entitlement-edit-auto-add/entit selector: 'imx-entitlements', templateUrl: './entitlements.component.html', styleUrls: ['./entitlements.component.scss'], + providers: [DataViewSource], }) export class EntitlementsComponent implements OnChanges { /** The {@link PortalApplication|application} */ @Input() public application: PortalApplication; @Output() public reloadRequested = new EventEmitter(); - @ViewChild('table') public table: DataTableComponent; - @ViewChild('tiles') public tiles: DataTilesComponent; public readonly DisplayColumns = DisplayColumns; // Enables use of this static class in Angular Templates. public readonly EntitlementsType = EntitlementsType; // Enables use of this static class in Angular Templates. - public dstSettings: DataSourceToolbarSettings; - public navigationState: CollectionLoadParameters; + public selections: PortalEntitlement[] = []; public publishDisabled = true; public unpublishDisabled = true; public unassignedDisabled = true; public isUsedInDialog = false; - public readonly entitySchema: EntitySchema; + public entitySchema: EntitySchema; public readonly filter = new EntitlementFilter(); public busyService = new BusyService(); public isSystemRoleEnabled: boolean; public isLoading = false; + public hideTable = false; /** * Checks, if there's a dynamic assignment rule attached to this application */ public get hasConditionForDynamicAssignment(): boolean { return ( - this.application.extendedDataRead?.SqlExpression?.Expressions?.length && - this.application.extendedDataRead?.SqlExpression?.Expressions[0].Expression.Expressions.length > 0 + !!this.application.extendedDataRead?.SqlExpression?.Expressions?.length && + !!this.application.extendedDataRead?.SqlExpression?.Expressions?.[0].Expression?.Expressions?.length ); } @@ -117,7 +123,6 @@ export class EntitlementsComponent implements OnChanges { }, }; - private readonly displayedColumns: ClientPropertyForTableColumns[]; private readonly updatedTableNames: string[] = []; constructor( @@ -136,34 +141,16 @@ export class EntitlementsComponent implements OnChanges { private readonly systemInfo: SystemInfoService, private readonly metadata: MetadataService, private readonly autoAddService: EntitlementEditAutoAddService, + public dataSource: DataViewSource, ) { this.entitySchema = entitlementsProvider.entitlementSchema; - this.displayedColumns = [ - this.entitySchema.Columns.Ident_AOBEntitlement, - { - Type: ValType.String, - ColumnName: 'badges', - untranslatedDisplay: '#LDS#Badges', - }, - { - Type: ValType.String, - ColumnName: 'type', - untranslatedDisplay: '#LDS#Type', - }, - this.entitySchema.Columns.UID_AERoleOwner, - { - Type: ValType.Date, - ColumnName: 'assigned', - untranslatedDisplay: '#LDS#Assigned', - }, - { - Type: ValType.String, - ColumnName: 'status', - untranslatedDisplay: '#LDS#Status', - }, - ]; this.busyService.busyStateChanged.subscribe((elem) => (this.isLoading = elem)); + effect(() => { + if (!!this.dataSource.collectionData()) { + this.updateTableNames(this.dataSource.collectionData().Data); + } + }); } public async ngOnChanges(changes: SimpleChanges): Promise { @@ -172,8 +159,8 @@ export class EntitlementsComponent implements OnChanges { } const isBusy = this.busyService.beginBusy(); try { - this.isSystemRoleEnabled = (await this.systemInfo.get()).PreProps.includes('ESET'); - this.getData(true); + this.isSystemRoleEnabled = !!(await this.systemInfo.get()).PreProps?.includes('ESET'); + this.getData(); } finally { isBusy.endBusy(); } @@ -203,8 +190,9 @@ export class EntitlementsComponent implements OnChanges { const candidates = await this.sidesheet .open(EntitlementsAddComponent, { title: await this.translateService.get('#LDS#Heading Assign Application Entitlements').toPromise(), + subTitle: this.application.GetEntity().GetDisplay(), padding: '0px', - width: 'max(600px, 60%)', + width: calculateSidesheetWidth(), testId: 'entitlements-sidesheet', data: { defaultType: this.isSystemRoleEnabled ? EntitlementsType.Eset : EntitlementsType.UnsGroup, @@ -231,12 +219,11 @@ export class EntitlementsComponent implements OnChanges { * Applys the dynamic assignment rule, that is defined for the application */ public async applyMappingForDynamicAssignments(): Promise { - let overlayRef: OverlayRef; - setTimeout(() => (overlayRef = this.euiBusyService.show())); + this.showBusyIndicator(); try { this.autoAddService.mapEntitlementsToApplication(this.application.UID_AOBApplication.value); } finally { - setTimeout(() => this.euiBusyService.hide(overlayRef)); + this.euiBusyService.hide(); } this.snackbar.open({ key: '#LDS#The application entitlements are added now. This may take some time.' }); } @@ -255,10 +242,10 @@ export class EntitlementsComponent implements OnChanges { subTitle: this.application.GetEntity().GetDisplay(), padding: '0px', disableClose: true, - width: 'max(600px, 60%)', + width: calculateSidesheetWidth(), testId: 'entitlements-edit-auto-add-sidesheet', data: { - sqlExpression: this.application.extendedDataRead.SqlExpression.Expressions[0], + sqlExpression: this.application.extendedDataRead.SqlExpression?.Expressions?.[0], application: this.application, }, }) @@ -269,12 +256,11 @@ export class EntitlementsComponent implements OnChanges { return; } - let overlayRef: OverlayRef; - setTimeout(() => (overlayRef = this.euiBusyService.show())); + this.showBusyIndicator(); try { this.reloadRequested.emit(); } finally { - setTimeout(() => this.euiBusyService.hide(overlayRef)); + this.euiBusyService.hide(); } } @@ -282,7 +268,7 @@ export class EntitlementsComponent implements OnChanges { * Call to publish the specified {@link PortalEntitlement|entitlement} or the list of selected {@link PortalEntitlement|entitlements}. * @param aobEntitlement the {@link PortalEntitlement|entitlement} to publish */ - public async publish(aobEntitlement: PortalEntitlement = null): Promise { + public async publish(aobEntitlement?: PortalEntitlement): Promise { const shops = await this.shopsProvider.getApplicationInShop(this.application.UID_AOBApplication.value); if (shops == null) { @@ -330,7 +316,7 @@ export class EntitlementsComponent implements OnChanges { }; } this.snackbar.open(publishMessage, '#LDS#Close'); - await this.getData(); + await this.dataSource.updateState(); } if (publishCount < selectedEntitlements.length) { @@ -349,7 +335,7 @@ export class EntitlementsComponent implements OnChanges { * Call to unpublish the specified {@link PortalEntitlement|entitlement} or the list of selected {@link PortalEntitlement|entitlements}. * @param aobEntitlement the {@link PortalEntitlement|entitlement} to unpublish */ - public async unpublish(aobEntitlement: PortalEntitlement = null): Promise { + public async unpublish(aobEntitlement?: PortalEntitlement): Promise { const selectedEntitlements = aobEntitlement != null ? [aobEntitlement] : this.selections; const dialogConfig = { data: { action: LifecycleAction.Unpublish, elements: selectedEntitlements, type: 'AobEntitlement' }, @@ -371,7 +357,7 @@ export class EntitlementsComponent implements OnChanges { this.logger.debug(this, 'Deselect unpublished entitlement(s)/role(s)'); this.clearSelections(); this.snackbar.open({ key: '#LDS#Application entitlements unpublished' }, '#LDS#Close'); - await this.getData(); + await this.dataSource.updateState(); } if (unpublishCount < selectedEntitlements.length) { @@ -391,7 +377,7 @@ export class EntitlementsComponent implements OnChanges { * from the associated {@link PortalApplication|application}. * @param aobEntitlement the {@link PortalEntitlement|entitlement} to unassign */ - public async unassign(aobEntitlement: PortalEntitlement = null): Promise { + public async unassign(aobEntitlement?: PortalEntitlement): Promise { const selectedEntitlements = aobEntitlement != null ? [aobEntitlement] : this.selections; const dialogConfig = { data: { action: LifecycleAction.Unassign, elements: selectedEntitlements, type: 'AobEntitlement' }, @@ -403,19 +389,18 @@ export class EntitlementsComponent implements OnChanges { if (result) { this.logger.debug(this, 'Remove entitlement(s) from application'); if (selectedEntitlements.length > 0) { - let overlayRef: OverlayRef; - setTimeout(() => (overlayRef = this.euiBusyService.show())); + this.showBusyIndicator(); try { const unassignResult = await this.entitlementsProvider.unassign(selectedEntitlements); if (unassignResult) { this.clearSelections(); - await this.getData(); + await this.dataSource.updateState(); this.snackbar.open({ key: '#LDS#Application entitlements unassigned' }, '#LDS#Close'); } else { this.logger.error(this, 'Attempt to unassign entitlement(s)/role(s) failed'); } } finally { - setTimeout(() => this.euiBusyService.hide(overlayRef)); + this.euiBusyService.hide(); } } this.matDialog.closeAll(); @@ -427,25 +412,53 @@ export class EntitlementsComponent implements OnChanges { /** * Call to get data from server depending on the {@link CollectionLoadParameters}. - * @param resetNavigationState Indicates wether the navigation state should be reset or not. - * @param newState Optional argument for loading new date for the given {@link CollectionLoadParameters}. */ - public async getData(resetNavigationState: boolean = false, newState?: CollectionLoadParameters): Promise { - if (resetNavigationState) { - this.navigationState = { PageSize: this.settingsService.DefaultPageSize, StartIndex: 0 }; - } else if (newState) { - this.navigationState = newState; + public async getData(): Promise { + this.hideTable = false; + this.dataSource.state.set({ PageSize: this.settingsService?.DefaultPageSize, StartIndex: 0 }); + this.dataSource.itemStatus = this.status; + const columnsToDisplay = [ + this.entitySchema.Columns.Ident_AOBEntitlement, + { + ColumnName: 'badges', + Type: ValType.String, + }, + { + ColumnName: 'type', + Type: ValType.String, + }, + this.entitySchema.Columns.UID_AERoleOwner, + { + ColumnName: 'assigned', + Type: ValType.Date, + }, + { + ColumnName: 'status', + Type: ValType.String, + }, + ]; + const dataViewInitParameters: DataViewInitParameters = { + execute: (params: CollectionLoadParameters): Promise | undefined> => + this.entitlementsProvider.getEntitlementsForApplication(this.application, params), + schema: this.entitySchema, + columnsToDisplay, + highlightEntity: (entitlement: PortalEntitlement) => { + this.editEntitlement(entitlement); + }, + selectionChange: (selection: Array) => this.onSelectionChanged(selection), + }; + await this.dataSource.init(dataViewInitParameters); + if (this.dataSource.collectionData().Data.length === 0) { + this.hideTable = true; } - - await this.navigate(); } /** * Opens a side sheet to edit entitlement information * @param entitlement the entitlement to edit */ - public async editEntitlement(entitlement: PortalEntitlement): Promise { - const entitlementWrapper = await this.createEntitlementWrapper(entitlement); + public async editEntitlement(entitlement: TypedEntity): Promise { + const entitlementWrapper = await this.createEntitlementWrapper(entitlement as PortalEntitlement); if (entitlementWrapper?.entitlement == null) { this.logger.error(this, 'AobEntitlement is undefined'); @@ -456,7 +469,7 @@ export class EntitlementsComponent implements OnChanges { title: await this.translateService.get('#LDS#Heading Edit Application Entitlement').toPromise(), subTitle: entitlementWrapper.entitlement.GetEntity().GetDisplay(), padding: '0', - width: 'max(600px, 60%)', + width: calculateSidesheetWidth(), disableClose: true, data: entitlementWrapper, testId: 'application-entitlement-edit-sidesheet', @@ -467,17 +480,16 @@ export class EntitlementsComponent implements OnChanges { * Triggered action from the {@link DataTableComponent} or {@link TilesComponent} after the selection have changed. */ public onSelectionChanged(selection: PortalEntitlement[]): void { - this.selections = selection; - this.unassignedDisabled = true; this.publishDisabled = true; this.unpublishDisabled = true; + this.selections = selection; if (this.selections == null || this.selections.length === 0) { return; } - this.unassignedDisabled = selection.some((elem) => elem.IsDynamic.value === true); + this.unassignedDisabled = this.selections.some((elem) => elem.IsDynamic.value === true); let foundPublished = false; let foundUnpublished = false; @@ -510,82 +522,51 @@ export class EntitlementsComponent implements OnChanges { } } - /** - * Triggered action from the {@link DataSourceToolbar|DataSourceToolbar} after the grouping have changed. - */ - public onGroupingChanged(col: IClientProperty): void { - this.logger.trace(this, 'grouping changed', col); - } - public getType(data: PortalEntitlement): string { if (data?.ObjectKeyElement?.value == null) { return ''; } const tableName = DbObjectKey.FromXml(data.ObjectKeyElement.value)?.TableName; - return tableName != null && this.metadata.tables[tableName] ? this.metadata.tables[tableName]?.DisplaySingular : ''; + return tableName != null && this.metadata.tables[tableName] ? this.metadata.tables[tableName]?.DisplaySingular || '' : ''; } private async addDirectEntitlements(candidates: TypedEntity[]): Promise { - let overlayRef: OverlayRef; - setTimeout(() => (overlayRef = this.euiBusyService.show())); + this.showBusyIndicator(); try { const assignedCount = await this.entitlementsProvider.assign(this.application, candidates); if (assignedCount > 0) { - await this.getData(); + await this.dataSource.updateState(); } if (assignedCount < candidates.length) { this.logger.error(this, 'Attempt to assign entitlement(s)/role(s) failed'); } } finally { - setTimeout(() => this.euiBusyService.hide(overlayRef)); + this.euiBusyService.hide(); } } private async buildRoleAndAddItToApplication(entitlementSystemRoleInput: EntitlementSystemRoleInput): Promise { - let overlayRef: OverlayRef; - setTimeout(() => (overlayRef = this.euiBusyService.show())); + this.showBusyIndicator(); let success = true; try { await this.entitlementsProvider.addElementsToRole(entitlementSystemRoleInput); } catch { success = false; } finally { - setTimeout(() => this.euiBusyService.hide(overlayRef)); + this.euiBusyService.hide(); } if (success) { this.snackbar.open( { key: '#LDS#The application entitlements have been successfully merged into the system role and added to application.' }, '#LDS#Close', ); - await this.getData(); + await this.dataSource.updateState(); } } private clearSelections(): void { - this.selections = []; - this.table?.clearSelection(); - this.tiles?.clearSelection(); - } - - private async navigate(): Promise { - const isBusy = this.busyService.beginBusy(); - try { - const data = await this.entitlementsProvider.getEntitlementsForApplication(this.application, this.navigationState); - await this.updateTableNames(data.Data); - if (data) { - this.dstSettings = { - displayedColumns: this.displayedColumns, - dataSource: data, - entitySchema: this.entitySchema, - navigationState: this.navigationState, - }; - } else { - this.logger.error(this, 'TypedEntityCollectionData is undefined'); - } - } finally { - isBusy.endBusy(); - } + this.dataSource.selection.clear(); } private async updateTableNames(objs: PortalEntitlement[]): Promise { @@ -602,11 +583,10 @@ export class EntitlementsComponent implements OnChanges { } private async createEntitlementWrapper(entitlement: PortalEntitlement): Promise { - let entitlementReloaded: PortalEntitlement; - let serviceItem: PortalEntitlementServiceitem; + let entitlementReloaded: PortalEntitlement | undefined; + let serviceItem: PortalEntitlementServiceitem | undefined = undefined; - let overlayRef: OverlayRef; - setTimeout(() => (overlayRef = this.euiBusyService.show())); + this.showBusyIndicator(); try { entitlementReloaded = await this.entitlementsProvider.reload(entitlement); @@ -614,7 +594,7 @@ export class EntitlementsComponent implements OnChanges { serviceItem = (await this.serviceItemsProvider.get(entitlement))?.Data?.[0]; } } finally { - setTimeout(() => this.euiBusyService.hide(overlayRef)); + this.euiBusyService.hide(); } return { @@ -622,4 +602,10 @@ export class EntitlementsComponent implements OnChanges { serviceItem, }; } + + private showBusyIndicator(): void { + if (this.euiBusyService.overlayRefs.length === 0) { + this.euiBusyService.show(); + } + } } diff --git a/imxweb/projects/aob/src/lib/entitlements/entitlements.model.ts b/imxweb/projects/aob/src/lib/entitlements/entitlements.model.ts index df8882ba6..58da102cf 100644 --- a/imxweb/projects/aob/src/lib/entitlements/entitlements.model.ts +++ b/imxweb/projects/aob/src/lib/entitlements/entitlements.model.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -24,14 +24,14 @@ * */ -import { IEntityColumn, TypedEntity } from "imx-qbm-dbts"; +import { IEntityColumn, TypedEntity } from '@imx-modules/imx-qbm-dbts'; export enum EntitlementsType { UnsGroup, Eset, Qerresource, Rpsreport, - Tsbaccountdef + Tsbaccountdef, } export interface AddEntitlementParameter { diff --git a/imxweb/projects/aob/src/lib/entitlements/entitlements.module.ts b/imxweb/projects/aob/src/lib/entitlements/entitlements.module.ts index 17ef753a5..cd8fbeae6 100644 --- a/imxweb/projects/aob/src/lib/entitlements/entitlements.module.ts +++ b/imxweb/projects/aob/src/lib/entitlements/entitlements.module.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -24,49 +24,51 @@ * */ -import { NgModule } from '@angular/core'; +import { ScrollingModule } from '@angular/cdk/scrolling'; import { CommonModule } from '@angular/common'; +import { NgModule } from '@angular/core'; import { FormsModule, ReactiveFormsModule } from '@angular/forms'; import { MatBadgeModule } from '@angular/material/badge'; import { MatButtonModule } from '@angular/material/button'; import { MatButtonToggleModule } from '@angular/material/button-toggle'; import { MatCardModule } from '@angular/material/card'; import { MatCheckboxModule } from '@angular/material/checkbox'; +import { MatDividerModule } from '@angular/material/divider'; import { MatFormFieldModule } from '@angular/material/form-field'; import { MatIconModule } from '@angular/material/icon'; import { MatInputModule } from '@angular/material/input'; +import { MatMenuModule } from '@angular/material/menu'; import { MatRadioModule } from '@angular/material/radio'; -import { MatTableModule } from '@angular/material/table'; -import { MatTooltipModule } from '@angular/material/tooltip'; import { MatSlideToggleModule } from '@angular/material/slide-toggle'; -import { MatMenuModule } from '@angular/material/menu'; +import { MatTooltipModule } from '@angular/material/tooltip'; import { EuiCoreModule, EuiMaterialModule } from '@elemental-ui/core'; import { TranslateModule } from '@ngx-translate/core'; -import { ScrollingModule } from '@angular/cdk/scrolling'; -import { MatDividerModule } from '@angular/material/divider'; +import { MatTableModule } from '@angular/material/table'; import { + CdrModule, ClassloggerModule, - DataTilesModule, DataSourceToolbarModule, DataTableModule, + DataTilesModule, + DataViewModule, DisableControlModule, - QbmModule, + InfoModalDialogModule, LdsReplaceModule, - CdrModule, + QbmModule, + SelectedElementsModule, SqlWizardModule, - InfoModalDialogModule } from 'qbm'; -import { EntitlementsAddComponent } from './entitlement-add/entitlements-add.component'; -import { EntitlementsComponent } from './entitlements.component'; -import { EntitlementsService } from './entitlements.service'; -import { AobUserModule } from '../user/user.module'; import { LifecycleActionsModule } from '../lifecycle-actions/lifecycle-actions.module'; -import { EntitlementEditModule } from './entitlement-edit/entitlement-edit.module'; -import { EntitlementDetailComponent } from './entitlement-detail/entitlement-detail.component'; +import { AobUserModule } from '../user/user.module'; +import { EntitlementsAddComponent } from './entitlement-add/entitlements-add.component'; import { SystemRoleConfigComponent } from './entitlement-add/system-role-config/system-role-config.component'; +import { EntitlementDetailComponent } from './entitlement-detail/entitlement-detail.component'; import { EntitlementEditAutoAddComponent } from './entitlement-edit-auto-add/entitlement-edit-auto-add.component'; import { MappedEntitlementsPreviewComponent } from './entitlement-edit-auto-add/mapped-entitlements-preview/mapped-entitlements-preview.component'; +import { EntitlementEditModule } from './entitlement-edit/entitlement-edit.module'; +import { EntitlementsComponent } from './entitlements.component'; +import { EntitlementsService } from './entitlements.service'; @NgModule({ declarations: [ @@ -75,7 +77,7 @@ import { MappedEntitlementsPreviewComponent } from './entitlement-edit-auto-add/ EntitlementDetailComponent, SystemRoleConfigComponent, EntitlementEditAutoAddComponent, - MappedEntitlementsPreviewComponent + MappedEntitlementsPreviewComponent, ], imports: [ ClassloggerModule, @@ -111,13 +113,11 @@ import { MappedEntitlementsPreviewComponent } from './entitlement-edit-auto-add/ CdrModule, ScrollingModule, SqlWizardModule, - InfoModalDialogModule - ], - providers: [ - EntitlementsService - ], - exports: [ - EntitlementsComponent + InfoModalDialogModule, + SelectedElementsModule, + DataViewModule, ], + providers: [EntitlementsService], + exports: [EntitlementsComponent], }) -export class EntitlementsModule { } +export class EntitlementsModule {} diff --git a/imxweb/projects/aob/src/lib/entitlements/entitlements.service.ts b/imxweb/projects/aob/src/lib/entitlements/entitlements.service.ts index 4c45939d2..af97941ae 100644 --- a/imxweb/projects/aob/src/lib/entitlements/entitlements.service.ts +++ b/imxweb/projects/aob/src/lib/entitlements/entitlements.service.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -24,23 +24,33 @@ * */ -import { Injectable, ErrorHandler } from '@angular/core'; +import { ErrorHandler, Injectable } from '@angular/core'; import { TranslateService } from '@ngx-translate/core'; -import { CollectionLoadParameters, TypedEntityCollectionData, IWriteValue, FilterType, CompareOperator, EntitySchema, TypedEntity, DataModel, ExtendedTypedEntityCollection, FilterData, FilterTreeData } from 'imx-qbm-dbts'; -import { DataTileBadge, ApiClientService, ClassloggerService } from 'qbm'; import { - PortalEntitlement, - PortalApplication, EntitlementSystemRoleInput, portal_entitlementcandidates_UNSGroup_filtertree_get_args, -} from 'imx-api-aob'; -import { EntitlementFilter } from './entitlement-filter'; + PortalApplication, + PortalEntitlement, +} from '@imx-modules/imx-api-aob'; +import { + CollectionLoadParameters, + CompareOperator, + DataModel, + EntitySchema, + FilterTreeData, + FilterType, + IWriteValue, + TypedEntity, + TypedEntityCollectionData, +} from '@imx-modules/imx-qbm-dbts'; +import { ApiClientService, ClassloggerService, DataTileBadge } from 'qbm'; import { AobApiService } from '../aob-api-client.service'; +import { EntitlementFilter } from './entitlement-filter'; import { EntitlementsType } from './entitlements.model'; @Injectable({ - providedIn: 'root' + providedIn: 'root', }) export class EntitlementsService { private readonly filter = new EntitlementFilter(); @@ -52,27 +62,34 @@ export class EntitlementsService { private readonly apiProvider: ApiClientService, private readonly logger: ClassloggerService, private readonly errorHandler: ErrorHandler, - translate: TranslateService) { - translate.get('#LDS#Published').subscribe((value: string) => this.badgePublished = { - content: value, - color: '#618f3e' - }); - - translate.get('#LDS#Will be published').subscribe((value: string) => this.badgeWillPublish = { - content: value, - color: '#f4770b' - }); + translate: TranslateService, + ) { + translate.get('#LDS#Published').subscribe( + (value: string) => + (this.badgePublished = { + content: value, + color: '#618f3e', + }), + ); + + translate.get('#LDS#Will be published').subscribe( + (value: string) => + (this.badgeWillPublish = { + content: value, + color: '#f4770b', + }), + ); } public get entitlementSchema(): EntitySchema { return this.aobClient.typedClient.PortalEntitlement.GetSchema(); } - public async get(parameters: CollectionLoadParameters = {}): Promise> { + public async get(parameters: CollectionLoadParameters = {}): Promise | undefined> { return this.apiProvider.request(() => this.aobClient.typedClient.PortalEntitlement.Get(parameters)); } - public async getInteractive(uid: string): Promise> { + public async getInteractive(uid: string): Promise | undefined> { return this.apiProvider.request(() => this.aobClient.typedClient.PortalEntitlementInteractive.Get_byid(uid)); } @@ -97,9 +114,10 @@ export class EntitlementsService { } } - - public async getCandidates(type: EntitlementsType, parameters: CollectionLoadParameters = {}): - Promise> { + public async getCandidates( + type: EntitlementsType, + parameters: CollectionLoadParameters = {}, + ): Promise | undefined> { switch (type) { case EntitlementsType.Eset: return this.apiProvider.request(() => this.aobClient.typedClient.PortalEntitlementcandidatesEset.Get(parameters)); @@ -116,42 +134,40 @@ export class EntitlementsService { } } - public async getDataModel(type: EntitlementsType): Promise { + public async getDataModel(type: EntitlementsType): Promise { if (type === EntitlementsType.UnsGroup) { return this.aobClient.client.portal_entitlementcandidates_UNSGroup_datamodel_get(undefined); } return undefined; } - - - public async getEntitlementsForApplication(application: PortalApplication, collectionLoadParameters: CollectionLoadParameters = {}): - Promise> { + public async getEntitlementsForApplication( + application: PortalApplication, + collectionLoadParameters: CollectionLoadParameters = {}, + ): Promise | undefined> { return this.get({ ...collectionLoadParameters, ...{ filter: [ + ...(collectionLoadParameters.filter || []), { ColumnName: 'UID_AOBApplication', Type: FilterType.Compare, CompareOp: CompareOperator.Equal, - Value1: application.UID_AOBApplication.value - } - ] - } + Value1: application.UID_AOBApplication.value, + }, + ], + }, }); } - public async reload(entitlement: PortalEntitlement): Promise { + public async reload(entitlement: PortalEntitlement): Promise { const collection = await this.getInteractive(entitlement.UID_AOBEntitlement.value); return collection && collection.Data && collection.Data.length > 0 ? collection.Data[0] : undefined; } - public async assign( - application: PortalApplication, - candidates: TypedEntity[] - ): Promise { + public async assign(application: PortalApplication, candidates: TypedEntity[]): Promise { let assignCount = 0; for (const candidate of candidates) { @@ -170,7 +186,7 @@ export class EntitlementsService { public async unassign(entitlements: PortalEntitlement[]): Promise { return this.apiProvider.request(async () => { - let result = null; + let result; for (const entitlement of entitlements) { result = await this.aobClient.client.portal_entitlement_delete(entitlement.UID_AOBEntitlement.value); } @@ -178,15 +194,16 @@ export class EntitlementsService { }); } - public async publish(entitlements: PortalEntitlement[], publishData: { publishFuture: boolean, date: Date }): Promise { + public async publish(entitlements: PortalEntitlement[], publishData: { publishFuture: boolean; date: Date }): Promise { let publishCount = 0; for (const entitlement of entitlements) { - const interactive = (await this.aobClient.typedClient.PortalEntitlementInteractive.Get_byid(entitlement.GetEntity().GetKeys()[0])).Data[0]; + const interactive = (await this.aobClient.typedClient.PortalEntitlementInteractive.Get_byid(entitlement.GetEntity().GetKeys()[0])) + .Data[0]; if (!publishData.publishFuture) { - await interactive.IsInActive.Column.PutValue(publishData.publishFuture); + await interactive.IsInActive.Column.PutValue(publishData.publishFuture); } else { - await interactive.ActivationDate.Column.PutValue(publishData.date); + await interactive.ActivationDate.Column.PutValue(publishData.date); } this.logger.debug(this, 'Commit change: publish entitlement...'); @@ -202,7 +219,8 @@ export class EntitlementsService { let unpublishCount = 0; for (const entitlement of entitlements) { - const interactive = (await this.aobClient.typedClient.PortalEntitlementInteractive.Get_byid(entitlement.GetEntity().GetKeys()[0])).Data[0]; + const interactive = (await this.aobClient.typedClient.PortalEntitlementInteractive.Get_byid(entitlement.GetEntity().GetKeys()[0])) + .Data[0]; await interactive.IsInActive.Column.PutValue(true); await interactive.ActivationDate.Column.PutValue(null); @@ -228,7 +246,6 @@ export class EntitlementsService { } public getEntitlementBadges(entitlement: PortalEntitlement): DataTileBadge[] { - if (this.filter.published(entitlement)) { return [this.badgePublished]; } @@ -240,17 +257,14 @@ export class EntitlementsService { return []; } - public async getEntitlementsFilterTree(options: portal_entitlementcandidates_UNSGroup_filtertree_get_args): Promise{ + public async getEntitlementsFilterTree(options: portal_entitlementcandidates_UNSGroup_filtertree_get_args): Promise { return this.aobClient.client.portal_entitlementcandidates_UNSGroup_filtertree_get(options); } - private async createNew( - element: TypedEntity, - uidAobApplication: IWriteValue - ): Promise { + private async createNew(element: TypedEntity, uidAobApplication: IWriteValue): Promise { const entitlement = (await this.aobClient.typedClient.PortalEntitlementInteractive.Get()).Data[0]; - entitlement.ObjectKeyElement.value = element.GetEntity().GetColumn('XObjectKey').GetValue(), - entitlement.UID_AOBApplication.value = uidAobApplication.value; + (entitlement.ObjectKeyElement.value = element.GetEntity().GetColumn('XObjectKey').GetValue()), + (entitlement.UID_AOBApplication.value = uidAobApplication.value); return entitlement; } } diff --git a/imxweb/projects/aob/src/lib/entitlements/publish-data.interface.ts b/imxweb/projects/aob/src/lib/entitlements/publish-data.interface.ts index d89dc8cde..6220520cc 100644 --- a/imxweb/projects/aob/src/lib/entitlements/publish-data.interface.ts +++ b/imxweb/projects/aob/src/lib/entitlements/publish-data.interface.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -25,6 +25,6 @@ */ export interface PublishData { - publishFuture: boolean; - date?: Date; + publishFuture: boolean; + date?: Date; } diff --git a/imxweb/projects/aob/src/lib/extensions/service-items-edit/lock-info-alert/lock-info-alert-extension.ts b/imxweb/projects/aob/src/lib/extensions/service-items-edit/lock-info-alert/lock-info-alert-extension.ts index 60939276c..8cad4313b 100644 --- a/imxweb/projects/aob/src/lib/extensions/service-items-edit/lock-info-alert/lock-info-alert-extension.ts +++ b/imxweb/projects/aob/src/lib/extensions/service-items-edit/lock-info-alert/lock-info-alert-extension.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR diff --git a/imxweb/projects/aob/src/lib/extensions/service-items-edit/lock-info-alert/lock-info-alert.component.html b/imxweb/projects/aob/src/lib/extensions/service-items-edit/lock-info-alert/lock-info-alert.component.html index 62feb96cf..6b79d7831 100644 --- a/imxweb/projects/aob/src/lib/extensions/service-items-edit/lock-info-alert/lock-info-alert.component.html +++ b/imxweb/projects/aob/src/lib/extensions/service-items-edit/lock-info-alert/lock-info-alert.component.html @@ -1,5 +1,8 @@ - + - {{'#LDS#You cannot edit all properties, because the service item is assigned to an application and therefore some properties are locked.' | translate }} + {{ + '#LDS#You cannot edit all properties, because the service item is assigned to an application and therefore some properties are locked.' + | translate + }} - \ No newline at end of file + diff --git a/imxweb/projects/aob/src/lib/extensions/service-items-edit/lock-info-alert/lock-info-alert.component.scss b/imxweb/projects/aob/src/lib/extensions/service-items-edit/lock-info-alert/lock-info-alert.component.scss index f7902c16a..3722d7c34 100644 --- a/imxweb/projects/aob/src/lib/extensions/service-items-edit/lock-info-alert/lock-info-alert.component.scss +++ b/imxweb/projects/aob/src/lib/extensions/service-items-edit/lock-info-alert/lock-info-alert.component.scss @@ -1,9 +1,5 @@ +@import 'base/mixins'; + :host { - display: flex; - flex-direction: column; - - .imx-helper-alert { - margin-bottom: 20px; - width: 100%; - } + @include flex-column-container(); } diff --git a/imxweb/projects/aob/src/lib/extensions/service-items-edit/lock-info-alert/lock-info-alert.component.spec.ts b/imxweb/projects/aob/src/lib/extensions/service-items-edit/lock-info-alert/lock-info-alert.component.spec.ts index f561a4463..ec978ec68 100644 --- a/imxweb/projects/aob/src/lib/extensions/service-items-edit/lock-info-alert/lock-info-alert.component.spec.ts +++ b/imxweb/projects/aob/src/lib/extensions/service-items-edit/lock-info-alert/lock-info-alert.component.spec.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -34,9 +34,8 @@ describe('LockInfoAlertComponent', () => { beforeEach(async () => { await TestBed.configureTestingModule({ - declarations: [ LockInfoAlertComponent ] - }) - .compileComponents(); + declarations: [LockInfoAlertComponent], + }).compileComponents(); }); beforeEach(() => { diff --git a/imxweb/projects/aob/src/lib/extensions/service-items-edit/lock-info-alert/lock-info-alert.component.ts b/imxweb/projects/aob/src/lib/extensions/service-items-edit/lock-info-alert/lock-info-alert.component.ts index 39a32b3f8..245b77506 100644 --- a/imxweb/projects/aob/src/lib/extensions/service-items-edit/lock-info-alert/lock-info-alert.component.ts +++ b/imxweb/projects/aob/src/lib/extensions/service-items-edit/lock-info-alert/lock-info-alert.component.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -26,15 +26,14 @@ import { Component, Input, OnInit } from '@angular/core'; -import { PortalServiceitems } from 'imx-api-qer'; +import { PortalServiceitems } from '@imx-modules/imx-api-qer'; @Component({ selector: 'imx-lock-info-alert', templateUrl: './lock-info-alert.component.html', - styleUrls: ['./lock-info-alert.component.scss'] + styleUrls: ['./lock-info-alert.component.scss'], }) -export class LockInfoAlertComponent implements OnInit { - +export class LockInfoAlertComponent implements OnInit { @Input() public serviceItem: PortalServiceitems; public isLocked = false; @@ -42,5 +41,4 @@ export class LockInfoAlertComponent implements OnInit { public ngOnInit(): void { this.isLocked = this.serviceItem?.GetEntity()?.GetColumn('LockInfo')?.GetValue(); } - } diff --git a/imxweb/projects/aob/src/lib/global-kpi/global-kpi.component.html b/imxweb/projects/aob/src/lib/global-kpi/global-kpi.component.html index bab33a2aa..155fea935 100644 --- a/imxweb/projects/aob/src/lib/global-kpi/global-kpi.component.html +++ b/imxweb/projects/aob/src/lib/global-kpi/global-kpi.component.html @@ -1,15 +1,31 @@ +

+ {{ '#LDS#Global KPIs' | translate }} +

- {{ '#LDS#Global KPIs' | translate }} - {{ '#LDS#These KPIs give you an overview of your applications, their contents and states.' | translate }} + {{ + '#LDS#These KPIs give you an overview of your applications, their contents and states.' | translate + }}
  • - {{!kpi.calculated ? '-' : !kpi.currentDataValue ? '' : kpi.currentDataValue.toLocaleString(this.browserCulture, - { minimumFractionDigits: 0, maximumFractionDigits: 3 })}} + {{ + !kpi.calculated + ? '-' + : !kpi.currentDataValue + ? '' + : kpi.currentDataValue.toLocaleString(this.browserCulture, { minimumFractionDigits: 0, maximumFractionDigits: 3 }) + }} {{ kpi.chartData.Display }} - +
@@ -17,26 +33,30 @@
-
-
{{data.chartData.Display }}
-
-

{{ data.chartData.Description}}

-
- +

{{ data.chartData.Description }}

+
+
-

{{'#LDS#History' | translate}}

-
+

{{ '#LDS#History' | translate }}

+
-
diff --git a/imxweb/projects/aob/src/lib/global-kpi/global-kpi.component.scss b/imxweb/projects/aob/src/lib/global-kpi/global-kpi.component.scss index 9075b2fda..d655716f5 100644 --- a/imxweb/projects/aob/src/lib/global-kpi/global-kpi.component.scss +++ b/imxweb/projects/aob/src/lib/global-kpi/global-kpi.component.scss @@ -1,9 +1,4 @@ -@import "@elemental-ui/core/src/styles/_palette.scss"; - -:host { - margin: 10px; - display: flex; -} +@import '@elemental-ui/core/src/styles/_palette.scss'; li { list-style-type: none; @@ -13,7 +8,7 @@ li { > .imx-kpi-display { display: table-cell; - width: 100% + width: 100%; } :nth-child(3n) { @@ -30,15 +25,12 @@ li { } } -.mat-card { - width: 771px; - height: auto; - margin: 40px 10px 0px; +.mat-mdc-card { display: flex; flex-direction: column; } -.mat-card-content { +.mat-mdc-card-content { padding: 0 10px 0 35px; overflow: auto; @@ -47,16 +39,14 @@ li { } } -.mat-card-title { +.mat-mdc-card-title { padding: 20px 33px 0px; - font-size: 24px; font-weight: 600; margin-bottom: 0; } -.mat-card-subtitle { +.mat-mdc-card-subtitle { font-size: 16px; - color: $black-3; font-weight: 400; padding: 5px 33px 20px; margin-bottom: 0; @@ -69,7 +59,7 @@ p { margin-top: 0; } -h1 { +h2 { font-size: 16px; font-weight: 600; margin: 30px 0 15px 0; @@ -82,18 +72,11 @@ h1 { display: table; } -.imx-chart { - display: flex; - justify-content: center; - flex-direction: row; -} - -.mat-dialog-title { - display: flex; +.mat-mdc-dialog-title { margin: 0; } -.mat-dialog-content { +.mat-mdc-dialog-content { max-height: 100%; } @@ -108,11 +91,6 @@ h1 { margin: 0; } -.imx-close-dialog-button { - right: -15px; - top: -15px; -} - .imx-aob-kpi-empty { display: flex; flex-direction: column; @@ -123,10 +101,6 @@ h1 { span { margin-left: 24px; } - - > .eui-icon { - color: $black-b; - } } ::ng-deep .bb-chart-arc text { diff --git a/imxweb/projects/aob/src/lib/global-kpi/global-kpi.component.ts b/imxweb/projects/aob/src/lib/global-kpi/global-kpi.component.ts index 95ed9c5c2..05452228a 100644 --- a/imxweb/projects/aob/src/lib/global-kpi/global-kpi.component.ts +++ b/imxweb/projects/aob/src/lib/global-kpi/global-kpi.component.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -24,23 +24,22 @@ * */ -import { Component, OnInit, ViewChild, TemplateRef } from '@angular/core'; -import { TranslateService } from '@ngx-translate/core'; -import { EuiLoadingService } from '@elemental-ui/core'; -import { OverlayRef } from '@angular/cdk/overlay'; -import { MatDialog } from '@angular/material/dialog'; -import { ChartOptions, pie } from 'billboard.js'; import { KeyValue } from '@angular/common'; +import { Component, OnInit, TemplateRef, ViewChild } from '@angular/core'; +import { MatDialog } from '@angular/material/dialog'; +import { EuiLoadingService } from '@elemental-ui/core'; +import { TranslateService } from '@ngx-translate/core'; +import { ChartOptions, pie, PrimitiveArray } from 'billboard.js'; -import { ChartDto, ChartDataPoint } from 'imx-api-aob'; -import { LineChartOptions, XAxisInformation, YAxisInformation, SeriesInformation, ClassloggerService } from 'qbm'; +import { ChartDataPoint, ChartDto } from '@imx-modules/imx-api-aob'; +import { ClassloggerService, LineChartOptions, SeriesInformation, XAxisInformation, YAxisInformation } from 'qbm'; import { GlobalKpiService } from './global-kpi.service'; import { KpiData } from './kpi-data.interface'; @Component({ selector: 'imx-global-kpi', templateUrl: './global-kpi.component.html', - styleUrls: ['./global-kpi.component.scss'] + styleUrls: ['./global-kpi.component.scss'], }) /** * Builds a component, that displays global KPI data (key performance indicators) @@ -60,8 +59,7 @@ export class GlobalKpiComponent implements OnInit { private business: string; private central: string; private others: string; - private readonly colors: string[] = ['#B4E6F4', '#82D5ED', '#50C4E6', '#2BB7E0', - '#05AADB', '#04A3D7', '#0499D2', '#0390CD', '#017FC4']; + private readonly colors: string[] = ['#B4E6F4', '#82D5ED', '#50C4E6', '#2BB7E0', '#05AADB', '#04A3D7', '#0499D2', '#0390CD', '#017FC4']; constructor( private readonly logger: ClassloggerService, @@ -72,27 +70,23 @@ export class GlobalKpiComponent implements OnInit { ) { this.browserCulture = this.translateService.currentLang; - translateService.get('#LDS#No data available') - .subscribe((trans: string) => this.noDataLoaded = trans); - translateService.get('#LDS#Used in business roles') - .subscribe((trans: string) => this.business = trans); - translateService.get('#LDS#Using central directory') - .subscribe((trans: string) => this.central = trans); - translateService.get('#LDS#Other') - .subscribe((trans: string) => this.others = trans); + translateService.get('#LDS#No data available').subscribe((trans: string) => (this.noDataLoaded = trans)); + translateService.get('#LDS#Used in business roles').subscribe((trans: string) => (this.business = trans)); + translateService.get('#LDS#Using central directory').subscribe((trans: string) => (this.central = trans)); + translateService.get('#LDS#Other').subscribe((trans: string) => (this.others = trans)); } /** * Loads the chartDto objects and inits the component */ public async ngOnInit(): Promise { - let overlayRef: OverlayRef; - setTimeout(() => overlayRef = this.busyService.show()); + if (this.busyService.overlayRefs.length === 0) { + this.busyService.show(); + } try { - this.kpiData = (await this.kpiProvider.get()) - .map((elem, i) => this.buildKpiData(i, elem)); + this.kpiData = (await this.kpiProvider.get())?.map((elem, i) => this.buildKpiData(i, elem)) || []; } finally { - setTimeout(() => this.busyService.hide(overlayRef)); + this.busyService.hide(); } } @@ -101,10 +95,11 @@ export class GlobalKpiComponent implements OnInit { * @param chart the data of a single chart */ public showDetails(kpi: KpiData): void { - if (kpi.chartData.Data.length === 0 ) { return; } + if (kpi.chartData.Data?.length === 0) { + return; + } kpi.chartDetails = this.buildLineOptions(kpi.chartData, kpi.pieChart != null, kpi.names); - this.matDialog.open(this.chartDialog, - { data: kpi, minWidth: 600, autoFocus: false }); + this.matDialog.open(this.chartDialog, { data: kpi, minWidth: 600, autoFocus: false }); } /** @@ -114,26 +109,26 @@ export class GlobalKpiComponent implements OnInit { */ public isCalculated(chart: ChartDto): boolean { return chart.Data != null && chart.Data.length > 0 && chart.Data[0].Points != null; - } + } /** * @ignore determines whether an application has chart data or not * @returns true, if there are any KPIs else false */ public hasKpis(): boolean { - return (this.kpiData != null && this.kpiData.length > 0 && this.kpiData.some(elem => elem != null)); + return this.kpiData != null && this.kpiData.length > 0 && this.kpiData.some((elem) => elem != null); } private buildKpiData(chartIndex: number, chart: ChartDto): KpiData { const calc = this.isCalculated(chart); if (!calc) { - return { index: chartIndex, chartData: chart, calculated: false, names : [] }; + return { index: chartIndex, chartData: chart, calculated: false, names: [] }; } - let currentData: number = null; - let pieOptions: ChartOptions = null; - let captions: string[]; + let currentData: number | undefined; + let pieOptions: ChartOptions | undefined; + let captions: string[] = []; switch (chartIndex) { case 0: @@ -142,8 +137,8 @@ export class GlobalKpiComponent implements OnInit { case 3: case 7: case 8: - currentData = chart.Data[0].Points[0].Value; - captions = chart.Data.map(ch => ch.Name); + currentData = chart.Data?.[0].Points?.[0].Value; + captions = chart.Data?.map((ch) => ch.Name || '') || []; break; case 4: pieOptions = this.buildSingleValueChart(chart, this.central); @@ -155,14 +150,14 @@ export class GlobalKpiComponent implements OnInit { break; case 5: pieOptions = this.buildPieChart(chart); - captions = chart.Data.map(ch => ch.Name); + captions = chart.Data?.map((ch) => ch.Name || '') || []; break; } return { index: chartIndex, chartData: chart, calculated: calc, names: captions, currentDataValue: currentData, pieChart: pieOptions }; } - private buildSingleValueChart(chart: ChartDto, name: string): ChartOptions { + private buildSingleValueChart(chart: ChartDto, name: string): ChartOptions | undefined { if (!this.isCalculated(chart)) { this.logger.debug(this, 'The chart is not calculated yet, therefore no chart is build'); return undefined; @@ -171,28 +166,30 @@ export class GlobalKpiComponent implements OnInit { return { size: { width: 271, height: 271 }, data: { - columns: [['data1', chart.Data[0].Points[0].Value], - ['data2', 100 - chart.Data[0].Points[0].Value]], + columns: [ + ['data1', chart.Data?.[0].Points?.[0].Value || 0], + ['data2', 100 - (chart.Data?.[0].Points?.[0].Value || 0)], + ], names: { data1: name, data2: this.others }, colors: { data1: this.colors[0], data2: '#CCC' }, type: pie(), empty: { label: { - text: this.noDataLoaded - } - } - }, pie: { + text: this.noDataLoaded, + }, + }, + }, + pie: { padAngle: 0.01, label: { - format: d => `${d.toLocaleString(this.browserCulture, - { minimumFractionDigits: 2, maximumFractionDigits: 2 })}%`, - threshold: 0.06 + format: (d) => `${d.toLocaleString(this.browserCulture, { minimumFractionDigits: 2, maximumFractionDigits: 2 })}%`, + threshold: 0.06, }, - } + }, }; } - private buildPieChart(chart: ChartDto): ChartOptions { + private buildPieChart(chart: ChartDto): ChartOptions | undefined { if (!this.isCalculated(chart)) { this.logger.debug(this, 'The chart is not calculated yet, therefore no chart is build'); return undefined; @@ -201,23 +198,27 @@ export class GlobalKpiComponent implements OnInit { return { size: { width: 271, height: 271 }, data: { - columns: chart.Data.map((ch, index) => ['data' + index, ch.Points[0].Value]) as any[], - names: this.toObject(chart.Data.map((ch, index) => ({ key: 'data' + index, value: ch.Name }))), - colors: this.toObject(chart.Data.map((ch, index) => ({ key: 'data' + index, value: this.colors[index] }))), + columns: chart?.Data?.map((ch, index): PrimitiveArray => ['data' + index, ch?.Points?.[0].Value || 0]), + names: this.toObject( + chart?.Data?.map((ch, index): KeyValue => ({ key: 'data' + index, value: ch.Name || '' })) || [], + ), + colors: this.toObject( + chart?.Data?.map((ch, index): KeyValue => ({ key: 'data' + index, value: this.colors[index] })) || [], + ), type: pie(), empty: { label: { - text: this.noDataLoaded - } - } - }, pie: { + text: this.noDataLoaded, + }, + }, + }, + pie: { padAngle: 0.01, label: { - format: d => `${d.toLocaleString(this.browserCulture, - { minimumFractionDigits: 2, maximumFractionDigits: 2 })}%`, - threshold: 0.06 + format: (d) => `${d.toLocaleString(this.browserCulture, { minimumFractionDigits: 2, maximumFractionDigits: 2 })}%`, + threshold: 0.06, }, - } + }, }; } @@ -234,7 +235,6 @@ export class GlobalKpiComponent implements OnInit { ret[elem.key] = elem.value; } return ret; - } /** @@ -243,7 +243,7 @@ export class GlobalKpiComponent implements OnInit { * @returns true, if the chart has multiple points else it return false */ private hasMultipleDataPoints(chart: ChartDto): boolean { - return this.isCalculated(chart) && chart.Data[0].Points.length > 1; + return this.isCalculated(chart) && (chart?.Data?.[0]?.Points?.length || 0) > 1; } /** @@ -252,39 +252,43 @@ export class GlobalKpiComponent implements OnInit { * @returns a ChartOptions object, that can be used by billboard.js */ private buildLineOptions(chart: ChartDto, isPercentage: boolean, names: string[]): ChartOptions { - const yAxis = new YAxisInformation(chart.Data.map((serie, id) => - new SeriesInformation(names[id], - serie.Points.map((point: ChartDataPoint) => point.Value), - this.colors[id] - ))); + const yAxis = new YAxisInformation( + chart.Data?.map( + (serie, id) => new SeriesInformation(names[id], serie.Points?.map((point: ChartDataPoint) => point.Value) || [], this.colors[id]), + ) || [], + ); yAxis.tickConfiguration = { - format: (d) => isPercentage ? `${d.toLocaleString(this.browserCulture)}%` : `${d.toLocaleString(this.browserCulture)}`, - values: this.accumulateTicks(chart) + format: (d) => (isPercentage ? `${d.toLocaleString(this.browserCulture)}%` : `${d.toLocaleString(this.browserCulture)}`), + values: this.accumulateTicks(chart), }; const lineChartOptions = new LineChartOptions( - new XAxisInformation('date', - chart.Data[0].Points.map((point: ChartDataPoint) => new Date(point.Date)), { + new XAxisInformation('date', chart.Data?.[0]?.Points?.map((point: ChartDataPoint) => new Date(point.Date)) || [], { count: 6, - format: (d: Date) => d.toLocaleDateString(this.browserCulture) + format: (d: Date) => d.toLocaleDateString(this.browserCulture), }), - yAxis + yAxis, ); lineChartOptions.useCurvedLines = false; - lineChartOptions.hideLegend = chart.Data.length === 1; + lineChartOptions.hideLegend = chart.Data?.length === 1; lineChartOptions.showPoints = !this.hasMultipleDataPoints(chart); lineChartOptions.size = { width: 500, height: 325 }; return lineChartOptions.options; } private accumulateTicks(chart: ChartDto): number[] { - const ret = []; - const max = Math.max.apply(Math, chart.Data.map(o => this.getMax(o.Points))); + const ret: number[] = []; + const max = Math.max.apply( + Math, + chart.Data?.map((o) => this.getMax(o.Points || [])), + ); const steps = Math.max(1, Math.trunc(max / 10)) + 1; ret.push(0); - if (max <= 0) { return ret; } + if (max <= 0) { + return ret; + } for (let index = 1; index <= 10; index++) { ret.push(index * steps); @@ -293,6 +297,9 @@ export class GlobalKpiComponent implements OnInit { } private getMax(points: ChartDataPoint[]): number { - return Math.max.apply(Math, points.map(o => o.Value)); + return Math.max.apply( + Math, + points.map((o) => o.Value), + ); } } diff --git a/imxweb/projects/aob/src/lib/global-kpi/global-kpi.module.ts b/imxweb/projects/aob/src/lib/global-kpi/global-kpi.module.ts index e99992a8a..ba85ab3ad 100644 --- a/imxweb/projects/aob/src/lib/global-kpi/global-kpi.module.ts +++ b/imxweb/projects/aob/src/lib/global-kpi/global-kpi.module.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -39,16 +39,8 @@ import { TilesModule } from 'qer'; @NgModule({ declarations: [GlobalKpiComponent, KpiTileComponent], - imports: [ - CommonModule, - MatCardModule, - MatButtonModule, - MatDialogModule, - EuiCoreModule, - TranslateModule, - TilesModule - ], + imports: [CommonModule, MatCardModule, MatButtonModule, MatDialogModule, EuiCoreModule, TranslateModule, TilesModule], providers: [GlobalKpiService], - exports: [GlobalKpiComponent] + exports: [GlobalKpiComponent], }) -export class GlobalKpiModule { } +export class GlobalKpiModule {} diff --git a/imxweb/projects/aob/src/lib/global-kpi/global-kpi.service.ts b/imxweb/projects/aob/src/lib/global-kpi/global-kpi.service.ts index efcf78222..72009c409 100644 --- a/imxweb/projects/aob/src/lib/global-kpi/global-kpi.service.ts +++ b/imxweb/projects/aob/src/lib/global-kpi/global-kpi.service.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -26,26 +26,26 @@ import { Injectable } from '@angular/core'; +import { ChartDto } from '@imx-modules/imx-api-aob'; import { ApiClientService } from 'qbm'; -import { ChartDto } from 'imx-api-aob'; import { AobApiService } from '../aob-api-client.service'; @Injectable({ - providedIn: 'root' + providedIn: 'root', }) /** * A service that provides endpoints for KPI features */ export class GlobalKpiService { - constructor( private aobClient: AobApiService, - private readonly apiProvider: ApiClientService) { } + private readonly apiProvider: ApiClientService, + ) {} /** * Encapsules the aob/kpi GET endpoint */ - public async get(): Promise { + public async get(): Promise { return this.apiProvider.request(() => this.aobClient.client.portal_kpi_get()); } } diff --git a/imxweb/projects/aob/src/lib/global-kpi/kpi-data.interface.ts b/imxweb/projects/aob/src/lib/global-kpi/kpi-data.interface.ts index 9f2507c2c..ad85cc749 100644 --- a/imxweb/projects/aob/src/lib/global-kpi/kpi-data.interface.ts +++ b/imxweb/projects/aob/src/lib/global-kpi/kpi-data.interface.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -26,14 +26,14 @@ import { ChartOptions } from 'billboard.js'; -import { ChartDto } from 'imx-api-aob'; +import { ChartDto } from '@imx-modules/imx-api-aob'; export interface KpiData { - index: number; - chartData: ChartDto; - chartDetails?: ChartOptions; - currentDataValue?: number; - pieChart?: ChartOptions; - calculated: boolean; - names: string[]; + index: number; + chartData: ChartDto; + chartDetails?: ChartOptions; + currentDataValue?: number; + pieChart?: ChartOptions; + calculated: boolean; + names: string[]; } diff --git a/imxweb/projects/aob/src/lib/global-kpi/kpi-tile/kpi-tile.component.html b/imxweb/projects/aob/src/lib/global-kpi/kpi-tile/kpi-tile.component.html index fb955bfb2..2024fb70f 100644 --- a/imxweb/projects/aob/src/lib/global-kpi/kpi-tile/kpi-tile.component.html +++ b/imxweb/projects/aob/src/lib/global-kpi/kpi-tile/kpi-tile.component.html @@ -1,13 +1,14 @@ - - - - - \ No newline at end of file + + + + + diff --git a/imxweb/projects/aob/src/lib/global-kpi/kpi-tile/kpi-tile.component.scss b/imxweb/projects/aob/src/lib/global-kpi/kpi-tile/kpi-tile.component.scss deleted file mode 100644 index f3903437e..000000000 --- a/imxweb/projects/aob/src/lib/global-kpi/kpi-tile/kpi-tile.component.scss +++ /dev/null @@ -1,9 +0,0 @@ -:host { - .mat-button{ - text-transform: uppercase; - } - - .mat-button ::ng-deep eui-icon{ - margin-left: 15px; - } -} \ No newline at end of file diff --git a/imxweb/projects/aob/src/lib/global-kpi/kpi-tile/kpi-tile.component.ts b/imxweb/projects/aob/src/lib/global-kpi/kpi-tile/kpi-tile.component.ts index 0a9a482cd..68f657902 100644 --- a/imxweb/projects/aob/src/lib/global-kpi/kpi-tile/kpi-tile.component.ts +++ b/imxweb/projects/aob/src/lib/global-kpi/kpi-tile/kpi-tile.component.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -31,13 +31,12 @@ import { AobPermissionsService } from '../../permissions/aob-permissions.service @Component({ selector: 'imx-kpi-tile', templateUrl: './kpi-tile.component.html', - styleUrls: ['./kpi-tile.component.scss'], }) export class KpiTileComponent { - - constructor(private readonly router: Router, + constructor( + private readonly router: Router, private readonly aobPermissionService: AobPermissionsService, - ) { } + ) {} public isAobOwner: boolean; @@ -48,5 +47,4 @@ export class KpiTileComponent { public goToGlobalKpi(): void { this.router.navigate(['applications/kpi']); } - } diff --git a/imxweb/projects/aob/src/lib/guards/aob-applications-guard.service.ts b/imxweb/projects/aob/src/lib/guards/aob-applications-guard.service.ts index d21fdd464..86cba3acb 100644 --- a/imxweb/projects/aob/src/lib/guards/aob-applications-guard.service.ts +++ b/imxweb/projects/aob/src/lib/guards/aob-applications-guard.service.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -25,7 +25,7 @@ */ import { Injectable, OnDestroy } from '@angular/core'; -import { CanActivate, Router } from '@angular/router'; +import { Router } from '@angular/router'; import { Observable, Subscription } from 'rxjs'; import { AppConfigService, AuthenticationService, ISessionState } from 'qbm'; @@ -34,15 +34,15 @@ import { AobPermissionsService } from '../permissions/aob-permissions.service'; @Injectable({ providedIn: 'root', }) -export class AobApplicationsGuardService implements CanActivate, OnDestroy { +export class AobApplicationsGuardService implements OnDestroy { private onSessionResponse: Subscription; constructor( private readonly aobPermissionService: AobPermissionsService, private readonly authentication: AuthenticationService, private readonly appConfig: AppConfigService, - private readonly router: Router - ) { } + private readonly router: Router, + ) {} public canActivate(): Observable { return new Observable((observer) => { @@ -51,7 +51,7 @@ export class AobApplicationsGuardService implements CanActivate, OnDestroy { const isApplicationOwner = await this.aobPermissionService.isAobApplicationOwner(); const isApplicationAdmin = await this.aobPermissionService.isAobApplicationAdmin(); if (!isApplicationOwner && !isApplicationAdmin) { - this.router.navigate([this.appConfig.Config.routeConfig.start], { queryParams: {} }); + this.router.navigate([this.appConfig.Config.routeConfig?.start], { queryParams: {} }); } observer.next(isApplicationOwner || isApplicationAdmin); observer.complete(); diff --git a/imxweb/projects/aob/src/lib/guards/aob-kpi-guard.service.ts b/imxweb/projects/aob/src/lib/guards/aob-kpi-guard.service.ts index 53569b5e9..c728dcabf 100644 --- a/imxweb/projects/aob/src/lib/guards/aob-kpi-guard.service.ts +++ b/imxweb/projects/aob/src/lib/guards/aob-kpi-guard.service.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -25,7 +25,7 @@ */ import { Injectable, OnDestroy } from '@angular/core'; -import { CanActivate, Router } from '@angular/router'; +import { Router } from '@angular/router'; import { Observable, Subscription } from 'rxjs'; import { AppConfigService, AuthenticationService, ISessionState } from 'qbm'; @@ -34,15 +34,15 @@ import { AobPermissionsService } from '../permissions/aob-permissions.service'; @Injectable({ providedIn: 'root', }) -export class AobKpiGuardService implements CanActivate, OnDestroy { +export class AobKpiGuardService implements OnDestroy { private onSessionResponse: Subscription; constructor( private readonly aobPermissionService: AobPermissionsService, private readonly authentication: AuthenticationService, private readonly appConfig: AppConfigService, - private readonly router: Router - ) { } + private readonly router: Router, + ) {} public canActivate(): Observable { return new Observable((observer) => { @@ -50,7 +50,7 @@ export class AobKpiGuardService implements CanActivate, OnDestroy { if (sessionState.IsLoggedIn) { const isApplicationAdmin = await this.aobPermissionService.isAobApplicationAdmin(); if (!isApplicationAdmin) { - this.router.navigate([this.appConfig.Config.routeConfig.start], { queryParams: {} }); + this.router.navigate([this.appConfig.Config.routeConfig?.start], { queryParams: {} }); } observer.next(isApplicationAdmin); observer.complete(); diff --git a/imxweb/projects/aob/src/lib/images/image.service.ts b/imxweb/projects/aob/src/lib/images/image.service.ts index c6b0d7a41..09ad7de55 100644 --- a/imxweb/projects/aob/src/lib/images/image.service.ts +++ b/imxweb/projects/aob/src/lib/images/image.service.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -31,18 +31,19 @@ import { ApiClientService } from 'qbm'; import { QerApiService } from 'qer'; @Injectable({ - providedIn: 'root' + providedIn: 'root', }) export class ImageService { constructor( private readonly qerClient: QerApiService, private readonly sanitizer: DomSanitizer, - private readonly apiProvider: ApiClientService) { } + private readonly apiProvider: ApiClientService, + ) {} /** * Gets the person image URL converted to a SafeUrl */ - public async getPersonImageUrl(uid: string): Promise { + public async getPersonImageUrl(uid: string | undefined): Promise { if (uid && uid.length > 0) { const imageData = await this.apiProvider.request(() => this.qerClient.client.portal_person_image_get(uid)); diff --git a/imxweb/projects/aob/src/lib/kpi/kpi-overview/kpi-overview.component.html b/imxweb/projects/aob/src/lib/kpi/kpi-overview/kpi-overview.component.html index 996a1dd5d..511f9049d 100644 --- a/imxweb/projects/aob/src/lib/kpi/kpi-overview/kpi-overview.component.html +++ b/imxweb/projects/aob/src/lib/kpi/kpi-overview/kpi-overview.component.html @@ -1,14 +1,14 @@ -
-

- {{ '#LDS#KPIs That Affect This Application' | translate }} -

- -
-

{{ '#LDS#Failed' | translate }}

-
    -
  • - +
    +

    + {{ '#LDS#KPIs That Affect This Application' | translate }} +

    + +
    +

    {{ '#LDS#Failed' | translate }}

    +
      +
    • +
      @@ -16,47 +16,61 @@

      {{ '#LDS#Failed' | translate }}

      {{ chart.Display }}
      - - + + -
      -
    • -
    -

    {{ '#LDS#Passed' | translate }}

    -
      -
    • - + +
    • +
    +

    {{ '#LDS#Passed' | translate }}

    +
      +
    • +
      - -
      {{ chart.Display }}
      -
      -
      - - - -
      -
    • -
    + +
    {{ chart.Display }}
    +
    +
    + + + + +
  • +
+
-
-
-
{{ (data.failed ? '#LDS#Failed': '#LDS#Passed') | translate }}
-

{{ data.chart.display }}

{{ data.chart.description }}

-
+
@@ -64,8 +78,8 @@

{{ data.chart.display }}

-
- +
+

{{ '#LDS#There are no KPIs affecting this application.' | translate }}

diff --git a/imxweb/projects/aob/src/lib/kpi/kpi-overview/kpi-overview.component.scss b/imxweb/projects/aob/src/lib/kpi/kpi-overview/kpi-overview.component.scss index 71f3c2ee9..ca7887dab 100644 --- a/imxweb/projects/aob/src/lib/kpi/kpi-overview/kpi-overview.component.scss +++ b/imxweb/projects/aob/src/lib/kpi/kpi-overview/kpi-overview.component.scss @@ -5,7 +5,7 @@ flex: 1 1 auto; display: flex; flex-direction: column; - .mat-card > .mat-card-actions:last-child { + .mat-mdc-card > .mat-mdc-card-actions:last-child { margin-bottom: 0; } } @@ -25,11 +25,12 @@ li { margin: 0 10px 10px 0; } -.mat-card { +.mat-mdc-card { padding: 5px 10px; width: 340px; height: 68px; display: flex; + flex-direction: row; } h2 { @@ -42,10 +43,6 @@ p { margin-top: 0; } -eui-billboard { - width: 500px; -} - h3 { margin-top: 20px; font-size: 18px; @@ -58,10 +55,6 @@ h4 { margin: 30px 0 15px 0; } -.imx-card-clickable { - cursor: pointer; -} - .imx-kpi-text { margin: 0; vertical-align: middle; @@ -73,6 +66,7 @@ h4 { align-self: center; margin-bottom: 0; margin-right: 5px; + font-size: 14px; } .imx-spacer { @@ -105,29 +99,13 @@ h4 { padding: 20px 0 0 20px; } -.imx-chart { - display: flex; - justify-content: center; - flex-direction: column; -} - -.mat-dialog-title { - display: flex; - margin: 0px 0 10px; -} - .imx-title-text { text-align: center; margin: 0 24px 0 60px; flex: 1; } -.imx-close-dialog-button { - right: -15px; - top: -15px; -} - -.imx-aob-kpi-empty { +.imx-no-results { display: flex; flex-direction: column; justify-content: center; @@ -142,7 +120,7 @@ h4 { .eui-light-theme { :host { li { - .mat-card { + .mat-mdc-card { background-color: $color-gray-0; } } @@ -175,14 +153,9 @@ h4 { .eui-dark-theme { :host { - .imx-kpi-list > li > .mat-card { + .imx-kpi-list > li > .mat-mdc-card { background-color: $color-gray-60; } - .imx-aob-kpi-empty { - > .eui-icon { - color: $color-gray-5; - } - } .imx-pass { color: $color-green-40; @@ -210,16 +183,9 @@ h4 { .eui-contrast-theme { :host { - .imx-kpi-list > li > .mat-card { + .imx-kpi-list > li > .mat-mdc-card { background-color: $color-gray-80; } - .imx-aob-kpi-empty { - background-color: $color-gray-90; - - > .eui-icon { - color: $color-gray-0; - } - } .imx-pass { color: $color-green-20; diff --git a/imxweb/projects/aob/src/lib/kpi/kpi-overview/kpi-overview.component.ts b/imxweb/projects/aob/src/lib/kpi/kpi-overview/kpi-overview.component.ts index 1a0753638..078fe030e 100644 --- a/imxweb/projects/aob/src/lib/kpi/kpi-overview/kpi-overview.component.ts +++ b/imxweb/projects/aob/src/lib/kpi/kpi-overview/kpi-overview.component.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -24,13 +24,13 @@ * */ -import { Component, OnChanges, Input, TemplateRef, ViewChild, SimpleChanges } from '@angular/core'; +import { Component, Input, OnChanges, SimpleChanges, TemplateRef, ViewChild } from '@angular/core'; import { MatDialog } from '@angular/material/dialog'; -import { ChartOptions } from 'billboard.js'; import { TranslateService } from '@ngx-translate/core'; +import { ChartOptions } from 'billboard.js'; -import { XAxisInformation, LineChartOptions, YAxisInformation, SeriesInformation, ClassloggerService, BusyService } from 'qbm'; -import { ChartDto, PortalApplication, ChartDataPoint } from 'imx-api-aob'; +import { ChartDataPoint, ChartDto, PortalApplication } from '@imx-modules/imx-api-aob'; +import { BusyService, ClassloggerService, LineChartOptions, SeriesInformation, XAxisInformation, YAxisInformation } from 'qbm'; import { KpiOverviewService } from './kpi-overview.service'; /** @@ -79,7 +79,7 @@ export class KpiOverviewComponent implements OnChanges { readonly translateService: TranslateService, private kpiOverviewProvider: KpiOverviewService, private logger: ClassloggerService, - private matDialog: MatDialog + private matDialog: MatDialog, ) { translateService.get('#LDS#Error threshold').subscribe((trans: string) => (this.errorThreshhold = trans)); this.busyService.busyStateChanged.subscribe((elem) => (this.isLoading = elem)); @@ -89,17 +89,16 @@ export class KpiOverviewComponent implements OnChanges { * Displays a busyIndicator and initializes the data, when the OnChanges life cycle hook is called */ public async ngOnChanges(changes: SimpleChanges): Promise { - if (changes.application?.currentValue?.UID_AOBApplication.value === changes.application?.previousValue?.UID_AOBApplication.value) { return; - } - + } + const isBusy = this.busyService.beginBusy(); try { const data = await this.kpiOverviewProvider.get(this.application.UID_AOBApplication.value); if (data) { - this.chartDataPass = data.filter((kpi) => kpi.Data.length > 0 && kpi.Data[0].Points[0].Value < kpi.ErrorThreshold); - this.chartDataFail = data.filter((kpi) => kpi.Data.length > 0 && kpi.Data[0].Points[0].Value >= kpi.ErrorThreshold); + this.chartDataPass = data.filter((kpi) => !!kpi.Data?.length && (kpi.Data?.[0].Points?.[0].Value || 0) < kpi.ErrorThreshold); + this.chartDataFail = data.filter((kpi) => !!kpi.Data?.length && (kpi.Data?.[0].Points?.[0].Value || 0) >= kpi.ErrorThreshold); } else { this.logger.error(this, 'ChartDto[] is undefined'); } @@ -113,8 +112,15 @@ export class KpiOverviewComponent implements OnChanges { * @param chart the data of a single chart */ public showDetails(chart: ChartDto, isFail: boolean): void { - if (!this.hasDetails(chart)) { return; } - this.matDialog.open(this.chartDialog, { data: { chart: this.getChartData(chart), failed: isFail }, width: '600px', autoFocus: false, panelClass: 'kpi-overview-modal' }); + if (!this.hasDetails(chart)) { + return; + } + this.matDialog.open(this.chartDialog, { + data: { chart: this.getChartData(chart), failed: isFail }, + width: '600px', + autoFocus: false, + panelClass: 'kpi-overview-modal', + }); } /** @@ -148,7 +154,7 @@ export class KpiOverviewComponent implements OnChanges { * @returns true, if the chart has multiple points else it return false */ private hasMultipleDataPoints(chart: ChartDto): boolean { - return this.hasDetails(chart) && chart.Data[0].Points.length > 1; + return this.hasDetails(chart) && (chart.Data?.[0].Points?.length || 0) > 1; } /** @@ -167,13 +173,9 @@ export class KpiOverviewComponent implements OnChanges { */ private buildOptions(chart: ChartDto): ChartOptions { const yAxis = new YAxisInformation( - chart.Data.map( - (serie) => - new SeriesInformation( - chart.Display, - serie.Points.map((point: ChartDataPoint) => point.Value) - ) - ) + chart.Data?.map( + (serie) => new SeriesInformation(chart.Display || '', serie.Points?.map((point: ChartDataPoint) => point.Value) || []), + ) || [], ); const browserCulture = this.translateService.currentLang; @@ -181,15 +183,11 @@ export class KpiOverviewComponent implements OnChanges { yAxis.tickConfiguration = { format: (d) => d.toLocaleString(browserCulture), values: this.accumulateTicks(chart) }; const lineChartOptions = new LineChartOptions( - new XAxisInformation( - 'date', - chart.Data[0].Points.map((point: ChartDataPoint) => new Date(point.Date)), - { - count: 6, - format: (d: Date) => d.toLocaleDateString(browserCulture), - } - ), - yAxis + new XAxisInformation('date', chart.Data?.[0].Points?.map((point: ChartDataPoint) => new Date(point.Date)) || [], { + count: 6, + format: (d: Date) => d.toLocaleDateString(browserCulture), + }), + yAxis, ); lineChartOptions.useCurvedLines = false; lineChartOptions.hideLegend = true; @@ -202,17 +200,17 @@ export class KpiOverviewComponent implements OnChanges { ]; lineChartOptions.size = { height: 400, - width: 500 - } + width: 500, + }; this.logger.debug(this, 'Options', lineChartOptions.options); return lineChartOptions.options; } private accumulateTicks(chart: ChartDto): number[] { - const ret = []; + let ret: number[] = []; const max = Math.max.apply( Math, - chart.Data[0].Points.map((o) => o.Value) + chart.Data?.[0].Points?.map((o) => o.Value), ); const steps = Math.max(1, Math.trunc(max / 10)) + 1; diff --git a/imxweb/projects/aob/src/lib/kpi/kpi-overview/kpi-overview.service.ts b/imxweb/projects/aob/src/lib/kpi/kpi-overview/kpi-overview.service.ts index 93968c199..88e26c27c 100644 --- a/imxweb/projects/aob/src/lib/kpi/kpi-overview/kpi-overview.service.ts +++ b/imxweb/projects/aob/src/lib/kpi/kpi-overview/kpi-overview.service.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -26,20 +26,20 @@ import { Injectable } from '@angular/core'; +import { ChartDto } from '@imx-modules/imx-api-aob'; import { ApiClientService } from 'qbm'; -import { ChartDto } from 'imx-api-aob'; import { AobApiService } from '../../aob-api-client.service'; @Injectable({ - providedIn: 'root' + providedIn: 'root', }) export class KpiOverviewService { - constructor( private readonly aobClient: AobApiService, - private readonly apiProvider: ApiClientService) { } + private readonly apiProvider: ApiClientService, + ) {} - public async get(uidapplication: string): Promise { + public async get(uidapplication: string): Promise { return this.apiProvider.request(() => this.aobClient.client.portal_application_kpi_get(uidapplication)); } } diff --git a/imxweb/projects/aob/src/lib/kpi/kpi.module.ts b/imxweb/projects/aob/src/lib/kpi/kpi.module.ts index e867e9ec7..cf85dc90a 100644 --- a/imxweb/projects/aob/src/lib/kpi/kpi.module.ts +++ b/imxweb/projects/aob/src/lib/kpi/kpi.module.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR diff --git a/imxweb/projects/aob/src/lib/lifecycle-actions/lifecycle-action-parameter.interface.ts b/imxweb/projects/aob/src/lib/lifecycle-actions/lifecycle-action-parameter.interface.ts index bb1723b6f..f64fb4719 100644 --- a/imxweb/projects/aob/src/lib/lifecycle-actions/lifecycle-action-parameter.interface.ts +++ b/imxweb/projects/aob/src/lib/lifecycle-actions/lifecycle-action-parameter.interface.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -24,14 +24,13 @@ * */ -import { PortalEntitlement, PortalApplicationinshop, PortalApplication } from 'imx-api-aob'; +import { PortalEntitlement, PortalApplicationinshop, PortalApplication } from '@imx-modules/imx-api-aob'; import { LifecycleAction } from './lifecycle-action.enum'; /** * Interface for the {@link MAT_DIALOG_DATA|MAT_DIALOG_DATA} of the {@link LifecycleActionComponent|LifecycleActionComponent} */ export interface LifecycleActionParameter { - /** The mode to show the dialog. */ action: LifecycleAction; diff --git a/imxweb/projects/aob/src/lib/lifecycle-actions/lifecycle-action.component.html b/imxweb/projects/aob/src/lib/lifecycle-actions/lifecycle-action.component.html index afcc34a60..5ff294111 100644 --- a/imxweb/projects/aob/src/lib/lifecycle-actions/lifecycle-action.component.html +++ b/imxweb/projects/aob/src/lib/lifecycle-actions/lifecycle-action.component.html @@ -1,75 +1,105 @@ -

{{ dialogTitle }}

-
+

{{ dialogTitle }}

+
- - - - - -
{{ data?.GetEntity().GetDisplay() }}
-
{{ data?.Description.Column.GetDisplayValue()}}
-
-
- - -
+ + + + {{ tableDisplay }} + + +
{{ item?.GetEntity().GetDisplay() }}
+
{{ item?.Description.Column.GetDisplayValue() }}
+ +
+ + {{ entitySchema.Columns.UID_AERoleOwner.Display }} + +
{{ item.UID_AERoleOwner?.Column.GetDisplayValue() }}
+ +
+
- {{'#LDS#*If you unassign an application entitlement from this application, it is removed from this application. The application entitlement can still be reassigned as required.' | translate }} + {{ + '#LDS#*If you unassign an application entitlement from this application, it is removed from this application. The application entitlement can still be reassigned as required.' + | translate + }}
{{ ('#LDS#Shops' | translate) + (data.type === 'AobEntitlement' ? '*' : '') }}
- {{ shop.GetEntity().GetDisplay() }} + {{ shop.GetEntity().GetDisplay() }} - {{ (data.type === 'AobEntitlement' ? '#LDS#Application entitlements cannot be published. No shop is assigned to the application. Please assign at least one shop to the application.': - '#LDS#No shop is assigned to the application. Without a shop, the assigned application entitlements cannot be requested. Please assign at least one shop to the application.' - ) | translate }} + {{ + (data.type === 'AobEntitlement' + ? '#LDS#Application entitlements cannot be published. No shop is assigned to the application. Please assign at least one shop to the application.' + : '#LDS#No shop is assigned to the application. Without a shop, the assigned application entitlements cannot be requested. Please assign at least one shop to the application.' + ) | translate + }} - *{{'#LDS#IT Shops are set at the application level.' | translate }} -
-
-
-
{{ '#LDS#Publication Date' | translate }}
- - {{ '#LDS#Now' | translate }} - {{ '#LDS#Later' | translate }} - - - {{(isApplication()? '#LDS#The application will be published immediately. The exact time may vary.': - '#LDS#The application entitlement will be published immediately. The exact time may vary.')| translate}} - - - - - - {{ '#LDS#Please specify a date that lies in the future.' | translate }} - - - {{ '#LDS#Please enter a valid date or select a date from the calendar.' | translate }} - - - - {{ (isApplication() - ? '#LDS#The application will be published on {0} at {1} (your local time).' - : '#LDS#The application entitlement will be published on {0} at {1} (your local time) if the application is published.') - | translate | ldsReplace: dateString : timeString }} -
+ *{{ '#LDS#IT Shops are set at the application level.' | translate }}
+
+
{{ '#LDS#Publication Date' | translate }}
+ + {{ '#LDS#Now' | translate }} + {{ '#LDS#Later' | translate }} + + + {{ + (isApplication() + ? '#LDS#The application will be published immediately. The exact time may vary.' + : '#LDS#The application entitlement will be published immediately. The exact time may vary.' + ) | translate + }} + + + + + + {{ '#LDS#Please specify a date that lies in the future.' | translate }} + + + {{ '#LDS#Please enter a valid date or select a date from the calendar.' | translate }} + + + + {{ + (isApplication() + ? '#LDS#The application will be published on {0} at {1} (your local time).' + : '#LDS#The application entitlement will be published on {0} at {1} (your local time) if the application is published.' + ) + | translate + | ldsReplace: dateString : timeString + }} +
-
+
- -
diff --git a/imxweb/projects/aob/src/lib/lifecycle-actions/lifecycle-action.component.scss b/imxweb/projects/aob/src/lib/lifecycle-actions/lifecycle-action.component.scss index 1fc29a6b2..573cdfea4 100644 --- a/imxweb/projects/aob/src/lib/lifecycle-actions/lifecycle-action.component.scss +++ b/imxweb/projects/aob/src/lib/lifecycle-actions/lifecycle-action.component.scss @@ -1,5 +1,6 @@ @import '@elemental-ui/core/src/styles/_palette.scss'; @import '@elemental-ui/core/src/styles/_eui_palette.scss'; +@import 'base/mixins'; :host { display: flex; @@ -11,15 +12,7 @@ imx-data-source-toolbar { display: none; } -.mat-table { - box-shadow: none; - - .mat-cell { - max-width: 20vw; - } -} - -.mat-card-avatar { +.mat-mdc-card-avatar { background-color: $black-b; color: $white; padding: 5px; @@ -28,14 +21,6 @@ imx-data-source-toolbar { user-select: none; } -.mat-dialog-content { - overflow: hidden; - flex: 1; - display: flex; - flex-direction: column; - height: inherit; -} - .mat-column-__Display { max-width: 500px; } @@ -69,19 +54,9 @@ div[imxActionsLabel] { overflow: auto; } -.mat-dialog-actions { - display: flex; - justify-content: flex-end; - - button { - margin-left: 10px; - margin-top: 10px; - } -} - -@mixin imx-entitlements-settings-block { - display: flex; - flex-direction: column; +.imx-entitlements-publish-itshops, +.imx-entitlements-publish-date { + @include flex-column-container(); padding-bottom: 20px; h5 { @@ -90,12 +65,11 @@ div[imxActionsLabel] { } .imx-entitlements-publish-itshops { - @include imx-entitlements-settings-block; overflow: auto; width: 380px; margin-right: 20px; - .mat-card { + .mat-mdc-card { display: flex; align-items: center; height: 50px; @@ -103,11 +77,9 @@ div[imxActionsLabel] { margin-bottom: 15px; } - .mat-card-title { + .mat-mdc-card-title { font-size: 16px; margin-left: 10px; - text-overflow: ellipsis; - overflow: hidden; white-space: nowrap; } @@ -116,25 +88,17 @@ div[imxActionsLabel] { color: $black-9; } - .mat-error { + .mat-mdc-form-field-error { font-size: 12px; margin-right: 15px; } } .imx-entitlements-publish-date { - @include imx-entitlements-settings-block; + @include flex-column-container; + gap: 25px; width: 400px; - .mat-radio-button { - margin-right: 60px; - } - - .mat-form-field { - width: 159px; - margin-top: 30px; - } - .mat-small { display: block; font-size: 14px; @@ -145,18 +109,9 @@ div[imxActionsLabel] { .eui-dark-theme { :host { - .mat-card-avatar { - background-color: $color-gray-60; - color: $color-gray-80; - } - } -} - -.eui-contrast-theme { - :host { - .mat-card-avatar { - background-color: $color-gray-80; - color: $color-gray-100; + .mat-mdc-card-avatar { + background-color: #616566; + color: #2f3233; } } } diff --git a/imxweb/projects/aob/src/lib/lifecycle-actions/lifecycle-action.component.spec.ts b/imxweb/projects/aob/src/lib/lifecycle-actions/lifecycle-action.component.spec.ts index 71377784c..b85688b65 100644 --- a/imxweb/projects/aob/src/lib/lifecycle-actions/lifecycle-action.component.spec.ts +++ b/imxweb/projects/aob/src/lib/lifecycle-actions/lifecycle-action.component.spec.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -24,42 +24,55 @@ * */ -import { Pipe, PipeTransform, Component, Input } from '@angular/core'; +import { provideHttpClient, withInterceptorsFromDi } from '@angular/common/http'; +import { provideHttpClientTesting } from '@angular/common/http/testing'; +import { Component, Input, Pipe, PipeTransform } from '@angular/core'; import { ComponentFixture, TestBed, fakeAsync, tick, waitForAsync } from '@angular/core/testing'; import { FormsModule, ReactiveFormsModule } from '@angular/forms'; import { MatButtonModule } from '@angular/material/button'; import { MatCardModule } from '@angular/material/card'; import { MatDatepickerModule } from '@angular/material/datepicker'; -import { MatDialogModule, MatDialogRef, MAT_DIALOG_DATA } from '@angular/material/dialog'; +import { MAT_DIALOG_DATA, MatDialogModule, MatDialogRef } from '@angular/material/dialog'; import { MatFormFieldModule } from '@angular/material/form-field'; import { MatRadioModule } from '@angular/material/radio'; -import { HttpClientModule } from '@angular/common/http'; import { EuiCoreModule } from '@elemental-ui/core'; +import { TranslateFakeLoader, TranslateLoader, TranslateModule } from '@ngx-translate/core'; import { LoggerTestingModule } from 'ngx-logger/testing'; -import { TranslateModule, TranslateLoader, TranslateFakeLoader } from '@ngx-translate/core'; +import { MatTableModule } from '@angular/material/table'; +import { PortalApplication, PortalEntitlement } from '@imx-modules/imx-api-aob'; +import { + ClassloggerService, + ConfirmationService, + DataViewModule, + DataViewSource, + FakeDataViewSource, + LdsReplacePipe, + MessageDialogService, + MetadataService, + SqlWizardApiService, + clearStylesFromDOM, +} from 'qbm'; +import { AobApiService } from '../aob-api-client.service'; import { LifecycleActionComponent } from './lifecycle-action.component'; -import { LdsReplacePipe, clearStylesFromDOM, MetadataService } from 'qbm'; import { LifecycleAction } from './lifecycle-action.enum'; -import { AobApiService } from '../aob-api-client.service'; -import { PortalApplication, PortalEntitlement } from 'imx-api-aob'; const mockMatDialogRef = { - close: jasmine.createSpy('close') + close: jasmine.createSpy('close'), }; @Pipe({ name: 'ldsReplace' }) class MockLdsReplacePipe implements PipeTransform { - transform() { } + transform() {} } const mockLdsReplacePipe = { - transform: jasmine.createSpy('transform').and.callFake((value: string) => value) + transform: jasmine.createSpy('transform').and.callFake((value: string) => value), }; @Component({ selector: 'imx-data-source-toolbar', - template: '

MockDataSourceToolbarComponent

' + template: '

MockDataSourceToolbarComponent

', }) class MockDataSourceToolbarComponent { @Input() public dst: any; @@ -69,7 +82,7 @@ class MockDataSourceToolbarComponent { @Component({ selector: 'imx-data-table', - template: '

MockDataTableComponent

' + template: '

MockDataTableComponent

', }) class MockDataTableComponent { @Input() public dst: any; @@ -77,7 +90,7 @@ class MockDataTableComponent { @Component({ selector: 'imx-data-table-column', - template: '

MockDataTableColumnComponent

' + template: '

MockDataTableColumnComponent

', }) class MockDataTableColumnComponent { @Input() public entityColumn: any; @@ -97,8 +110,8 @@ describe('LifecycleActionComponent', () => { ImageId: '', IsDeactivated: false, IsMAllTable: false, - IsMNTable: false - }) + IsMNTable: false, + }), ); const moduleDef = { @@ -107,12 +120,11 @@ describe('LifecycleActionComponent', () => { MockDataSourceToolbarComponent, MockDataTableComponent, MockDataTableColumnComponent, - MockLdsReplacePipe + MockLdsReplacePipe, ], imports: [ EuiCoreModule, FormsModule, - HttpClientModule, LoggerTestingModule, MatButtonModule, MatCardModule, @@ -124,43 +136,52 @@ describe('LifecycleActionComponent', () => { TranslateModule.forRoot({ loader: { provide: TranslateLoader, - useClass: TranslateFakeLoader - } - }) + useClass: TranslateFakeLoader, + }, + }), + DataViewModule, + MatTableModule, ], providers: [ { provide: MatDialogRef, - useValue: mockMatDialogRef + useValue: mockMatDialogRef, }, { provide: MAT_DIALOG_DATA, - useValue: { action: LifecycleAction.Publish, elements: [], shops: [], type: 'AobApplication' } + useValue: { action: LifecycleAction.Publish, elements: [], shops: [], type: 'AobApplication' }, }, { provide: LdsReplacePipe, - useValue: mockLdsReplacePipe + useValue: mockLdsReplacePipe, }, { provide: AobApiService, useValue: { typedClient: { PortalApplication: { - GetSchema: () => PortalApplication.GetEntitySchema() + GetSchema: () => PortalApplication.GetEntitySchema(), }, PortalEntitlement: { - GetSchema: () => PortalEntitlement.GetEntitySchema() - } - } - } + GetSchema: () => PortalEntitlement.GetEntitySchema(), + }, + }, + }, }, { provide: MetadataService, useClass: class { GetTableMetadata = getTableMetadataSpy; - } - } - ] + }, + }, + { provide: MessageDialogService, useValue: {} }, + { provide: ClassloggerService, useValue: { debug: () => {}, info: () => {} } }, + { provide: SqlWizardApiService, useValue: {} }, + { provide: ConfirmationService, useValue: {} }, + { provide: DataViewSource, useValue: FakeDataViewSource }, + provideHttpClient(withInterceptorsFromDi()), + provideHttpClientTesting(), + ], }; beforeEach(waitForAsync(() => { @@ -185,98 +206,105 @@ describe('LifecycleActionComponent', () => { tick(); - expect(component.dstSettings.dataSource).toBeTruthy(); + expect(component.dataSource).toBeTruthy(); })); [ { whenToPublish: 'now', - expectedIsInActive: false + expectedIsInActive: false, }, { whenToPublish: 'future', - expectedIsInActive: false - } - ].forEach(testcase => + expectedIsInActive: false, + }, + ].forEach((testcase) => it('should return publishData of entitlements in publish mode', () => { initComponent(); component.data.action = LifecycleAction.Publish; component.data.elements = []; - component.whenToPublish = testcase.whenToPublish as ('now' | 'future'); + component.whenToPublish = testcase.whenToPublish as 'now' | 'future'; component.submitData(); - expect(mockMatDialogRef.close).toHaveBeenCalledWith({ publishFuture: testcase.expectedIsInActive, date: component.datepickerFormControl.value.toDate() }); - })); + expect(mockMatDialogRef.close).toHaveBeenCalledWith({ + publishFuture: testcase.expectedIsInActive, + date: component.datepickerFormControl.value.toDate(), + }); + }), + ); [ { action: LifecycleAction.Unassign, - mode: 'Unassign' + mode: 'Unassign', }, { action: LifecycleAction.Unpublish, - mode: 'Unpublish' - } - ].forEach(testcase => + mode: 'Unpublish', + }, + ].forEach((testcase) => it(`should return true in ${testcase.mode} mode`, () => { initComponent(); component.data.action = testcase.action; component.data.elements = []; component.submitData(); expect(mockMatDialogRef.close).toHaveBeenCalledWith(true); - }) + }), ); - [ { - type: 'AobApplication' as 'AobEntitlement' | 'AobApplication' + type: 'AobApplication' as 'AobEntitlement' | 'AobApplication', }, { - type: 'AobEntitlement' as 'AobEntitlement' | 'AobApplication' - } - ].forEach(maintestcase => + type: 'AobEntitlement' as 'AobEntitlement' | 'AobApplication', + }, + ].forEach((maintestcase) => [ { action: LifecycleAction.Unassign, mode: 'Unassign', - entitlementsCount: 1 + entitlementsCount: 1, }, { action: LifecycleAction.Unassign, mode: 'Unassign', - entitlementsCount: 2 + entitlementsCount: 2, }, { action: LifecycleAction.Publish, mode: 'Publish', - entitlementsCount: 1 + entitlementsCount: 1, }, { action: LifecycleAction.Publish, mode: 'Publish', - entitlementsCount: 2 + entitlementsCount: 2, }, { action: LifecycleAction.Unpublish, mode: 'Unpublish', - entitlementsCount: 1 + entitlementsCount: 1, }, { action: LifecycleAction.Unpublish, mode: 'Unpublish', - entitlementsCount: 2 - } - ].forEach(testcase => + entitlementsCount: 2, + }, + ].forEach((testcase) => it(`should init the component with mode=${testcase.mode} and ${testcase.entitlementsCount} entitlements`, () => { - - let dummyEntitlements = []; + let dummyEntitlements: any[] = []; for (let n = 0; n < testcase.entitlementsCount; n++) { dummyEntitlements.push({}); } moduleDef.providers[1] = { provide: MAT_DIALOG_DATA, - useValue: { action: testcase.action, elements: dummyEntitlements, shops: [], type: (maintestcase.type as 'AobEntitlement' | 'AobApplication') } + useValue: { + action: testcase.action, + elements: dummyEntitlements, + shops: [], + type: maintestcase.type as 'AobEntitlement' | 'AobApplication', + }, }; TestBed.configureTestingModule(moduleDef).compileComponents(); @@ -293,7 +321,7 @@ describe('LifecycleActionComponent', () => { expect(component.isUnassign()).toBe(testcase.action === LifecycleAction.Unassign); expect(component.isPublish()).toBe(testcase.action === LifecycleAction.Publish); expect(component.isUnpublish()).toBe(testcase.action === LifecycleAction.Unpublish); - }))); - - + }), + ), + ); }); diff --git a/imxweb/projects/aob/src/lib/lifecycle-actions/lifecycle-action.component.ts b/imxweb/projects/aob/src/lib/lifecycle-actions/lifecycle-action.component.ts index 203acd483..eeb0ae923 100644 --- a/imxweb/projects/aob/src/lib/lifecycle-actions/lifecycle-action.component.ts +++ b/imxweb/projects/aob/src/lib/lifecycle-actions/lifecycle-action.component.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -24,20 +24,26 @@ * */ +import { Platform } from '@angular/cdk/platform'; import { Component, Inject, OnDestroy, OnInit } from '@angular/core'; -import { UntypedFormControl, ValidatorFn, AbstractControl, UntypedFormGroup } from '@angular/forms'; -import { MatDialogRef, MAT_DIALOG_DATA } from '@angular/material/dialog'; +import { AbstractControl, FormGroup, UntypedFormControl, ValidatorFn } from '@angular/forms'; +import { MAT_DIALOG_DATA, MatDialogRef } from '@angular/material/dialog'; import { TranslateService } from '@ngx-translate/core'; -import { Subscription } from 'rxjs'; -import { Platform } from '@angular/cdk/platform'; import moment from 'moment-timezone'; +import { Subscription } from 'rxjs'; -import { LdsReplacePipe, ClassloggerService, DataSourceToolbarSettings, MetadataService } from 'qbm'; -import { MetaTableData } from 'imx-api-qbm'; +import { + DisplayColumns, + EntitySchema, + IClientProperty, + MetaTableData, + TypedEntity, + TypedEntityCollectionData, +} from '@imx-modules/imx-qbm-dbts'; +import { ClassloggerService, DataViewSource, LdsReplacePipe, MetadataService } from 'qbm'; +import { AobApiService } from '../aob-api-client.service'; import { LifecycleActionParameter } from './lifecycle-action-parameter.interface'; import { LifecycleAction } from './lifecycle-action.enum'; -import { EntitySchema, DisplayColumns, TypedEntityCollectionData, TypedEntity, IClientProperty } from 'imx-qbm-dbts'; -import { AobApiService } from '../aob-api-client.service'; /** * A component that represents a dialog for submitting an {@link LifecycleAction|action} on the @@ -47,12 +53,11 @@ import { AobApiService } from '../aob-api-client.service'; @Component({ selector: 'imx-entitlements-action', templateUrl: './lifecycle-action.component.html', - styleUrls: ['./lifecycle-action.component.scss'] + styleUrls: ['./lifecycle-action.component.scss'], + providers: [DataViewSource], }) export class LifecycleActionComponent implements OnDestroy, OnInit { - public readonly DisplayColumns = DisplayColumns; // Enables use of this static class in Angular Templates. - public dstSettings: DataSourceToolbarSettings; public entitySchema: EntitySchema; @@ -70,7 +75,7 @@ export class LifecycleActionComponent implements OnDestroy, OnInit { public publishFuture: boolean; - public readonly publishDateForm: UntypedFormGroup; + public readonly publishDateForm: FormGroup<{ datepickerFormControl: UntypedFormControl; whenToPublish: UntypedFormControl }>; public readonly datepickerFormControl: UntypedFormControl; public readonly browserCulture: string; @@ -85,8 +90,6 @@ export class LifecycleActionComponent implements OnDestroy, OnInit { return this.datepickerFormControl.value.toDate().toLocaleTimeString(this.browserCulture); } - private dataSource: TypedEntityCollectionData; - /** * @ignore * List of subscriptions. @@ -104,7 +107,9 @@ export class LifecycleActionComponent implements OnDestroy, OnInit { private readonly translateService: TranslateService, private readonly metadataProvider: MetadataService, private readonly aobApiService: AobApiService, - private readonly platform: Platform) { + private readonly platform: Platform, + public dataSource: DataViewSource, + ) { this.browserCulture = this.translateService.currentLang; this.initCaptions(); @@ -114,53 +119,47 @@ export class LifecycleActionComponent implements OnDestroy, OnInit { // set date to tomorrow this.minDate = moment(curDate); - this.datepickerFormControl = new UntypedFormControl(this.minDate, this.validateDate(this.minDate, () => this.publishFuture)); + this.datepickerFormControl = new UntypedFormControl( + this.minDate, + this.validateDate(this.minDate, () => this.publishFuture), + ); - this.publishDateForm = new UntypedFormGroup({ + this.publishDateForm = new FormGroup<{ datepickerFormControl: UntypedFormControl; whenToPublish: UntypedFormControl }>({ datepickerFormControl: this.datepickerFormControl, whenToPublish: new UntypedFormControl('now'), }); - this.subscriptions.push(this.publishDateForm.get('whenToPublish').valueChanges - .subscribe((when: 'now' | 'future') => { + this.subscriptions.push( + this.publishDateForm.controls.whenToPublish.valueChanges.subscribe((when: 'now' | 'future') => { this.whenToPublish = when; this.publishFuture = this.whenToPublish === 'future'; - })); + }), + ); this.publishFuture = false; - - this.dataSource = { - Data: data.elements, - totalCount: data.elements.length - }; } /** * @ignore Used internally. */ public async ngOnInit(): Promise { - this.entitySchema = this.isApplication() ? this.aobApiService.typedClient.PortalApplication.GetSchema() : this.aobApiService.typedClient.PortalEntitlement.GetSchema(); - this.displayedColumns = [ - this.entitySchema.Columns[DisplayColumns.DISPLAY_PROPERTYNAME], - this.entitySchema.Columns.UID_AERoleOwner - ]; - - this.dstSettings = { - dataSource: this.dataSource, - entitySchema: this.entitySchema, - displayedColumns: this.displayedColumns, - navigationState: { - StartIndex: 0 - } - }; + this.displayedColumns = [this.entitySchema.Columns[DisplayColumns.DISPLAY_PROPERTYNAME], this.entitySchema.Columns.UID_AERoleOwner]; + + this.dataSource.init({ + execute: (): Promise> => + Promise.resolve({ Data: this.data.elements, totalCount: this.data.elements.length }), + schema: this.entitySchema, + columnsToDisplay: this.displayedColumns, + localSource: true, + }); await this.metadataProvider - .GetTableMetadata(this.entitySchema.TypeName) - .then((metadata: MetaTableData) => (this.tableDisplay = metadata.DisplaySingular)); + .GetTableMetadata(this.entitySchema.TypeName || '') + .then((metadata: MetaTableData) => (this.tableDisplay = metadata.DisplaySingular || '')); } /** @@ -168,7 +167,7 @@ export class LifecycleActionComponent implements OnDestroy, OnInit { * Unsubscribes all listeners. */ public ngOnDestroy(): void { - this.subscriptions.forEach(subscription => subscription.unsubscribe()); + this.subscriptions.forEach((subscription) => subscription.unsubscribe()); } /** @@ -176,9 +175,10 @@ export class LifecycleActionComponent implements OnDestroy, OnInit { */ public submitData(): void { this.logger.debug(this, `Close the ${this.data.action} dialog for ${this.data.elements.length} ${this.data.type}(s).`); - const result = this.data.action === LifecycleAction.Publish - ? { publishFuture: this.publishFuture, date: this.datepickerFormControl.value.toDate() } - : true; + const result = + this.data.action === LifecycleAction.Publish + ? { publishFuture: this.publishFuture, date: this.datepickerFormControl.value.toDate() } + : true; this.dialogRef.close(result); } @@ -219,7 +219,9 @@ export class LifecycleActionComponent implements OnDestroy, OnInit { this.logger.debug(this, `Init captions for the ${this.data.action.toString()}-mode depending on the application count.`); const multipleEntitlements = this.data != null && this.data.elements != null && this.data.elements.length > 1; - let dialogTitle = multipleEntitlements ? '#LDS#Heading Unassign {0} Application Entitlements' : '#LDS#Heading Unassign Application Entitlement'; + let dialogTitle = multipleEntitlements + ? '#LDS#Heading Unassign {0} Application Entitlements' + : '#LDS#Heading Unassign Application Entitlement'; let buttonText = multipleEntitlements ? '#LDS#Unassign' : '#LDS#Unassign'; if (this.data.type === 'AobApplication') { @@ -232,7 +234,9 @@ export class LifecycleActionComponent implements OnDestroy, OnInit { dialogTitle = multipleEntitlements ? '#LDS#Heading Publish {0} Applications' : '#LDS#Heading Publish Application'; buttonText = multipleEntitlements ? '#LDS#Publish' : '#LDS#Publish'; } else { - dialogTitle = multipleEntitlements ? '#LDS#Heading Publish {0} Application Entitlements' : '#LDS#Heading Publish Application Entitlement'; + dialogTitle = multipleEntitlements + ? '#LDS#Heading Publish {0} Application Entitlements' + : '#LDS#Heading Publish Application Entitlement'; buttonText = multipleEntitlements ? '#LDS#Publish' : '#LDS#Publish'; } } else if (this.isUnpublish()) { @@ -240,16 +244,18 @@ export class LifecycleActionComponent implements OnDestroy, OnInit { dialogTitle = multipleEntitlements ? '#LDS#Heading Unpublish {0} Applications' : '#LDS#Heading Unpublish Application'; buttonText = multipleEntitlements ? '#LDS#Unpublish' : '#LDS#Unpublish'; } else { - dialogTitle = multipleEntitlements ? '#LDS#Heading Unpublish {0} Application Entitlements' : '#LDS#Heading Unpublish Application Entitlement'; + dialogTitle = multipleEntitlements + ? '#LDS#Heading Unpublish {0} Application Entitlements' + : '#LDS#Heading Unpublish Application Entitlement'; buttonText = multipleEntitlements ? '#LDS#Unpublish' : '#LDS#Unpublish'; } } - this.translateService.get(dialogTitle) - .subscribe((trans: string) => this.dialogTitle = this.ldsReplace.transform(trans, this.data.elements.length)); + this.translateService + .get(dialogTitle) + .subscribe((trans: string) => (this.dialogTitle = this.ldsReplace.transform(trans, this.data.elements.length))); - this.translateService.get(buttonText). - subscribe((trans: string) => this.actionButtonText = trans); + this.translateService.get(buttonText).subscribe((trans: string) => (this.actionButtonText = trans)); } private validateDate(minDate: any, publishFuture: () => boolean): ValidatorFn { diff --git a/imxweb/projects/aob/src/lib/lifecycle-actions/lifecycle-action.enum.ts b/imxweb/projects/aob/src/lib/lifecycle-actions/lifecycle-action.enum.ts index 35cd2b5bd..f9a124126 100644 --- a/imxweb/projects/aob/src/lib/lifecycle-actions/lifecycle-action.enum.ts +++ b/imxweb/projects/aob/src/lib/lifecycle-actions/lifecycle-action.enum.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -30,5 +30,5 @@ export enum LifecycleAction { Publish, Unpublish, - Unassign + Unassign, } diff --git a/imxweb/projects/aob/src/lib/lifecycle-actions/lifecycle-actions.module.ts b/imxweb/projects/aob/src/lib/lifecycle-actions/lifecycle-actions.module.ts index 8c31f8a22..6d8fbcb57 100644 --- a/imxweb/projects/aob/src/lib/lifecycle-actions/lifecycle-actions.module.ts +++ b/imxweb/projects/aob/src/lib/lifecycle-actions/lifecycle-actions.module.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -24,9 +24,9 @@ * */ -import { NgModule } from '@angular/core'; import { CommonModule } from '@angular/common'; -import { LifecycleActionComponent } from './lifecycle-action.component'; +import { NgModule } from '@angular/core'; +import { FormsModule, ReactiveFormsModule } from '@angular/forms'; import { MatButtonModule } from '@angular/material/button'; import { MatCardModule } from '@angular/material/card'; import { MatDatepickerModule } from '@angular/material/datepicker'; @@ -34,10 +34,11 @@ import { MatDialogModule } from '@angular/material/dialog'; import { MatFormFieldModule } from '@angular/material/form-field'; import { MatInputModule } from '@angular/material/input'; import { MatRadioModule } from '@angular/material/radio'; +import { MatTableModule } from '@angular/material/table'; import { EuiCoreModule } from '@elemental-ui/core'; -import { FormsModule, ReactiveFormsModule } from '@angular/forms'; import { TranslateModule } from '@ngx-translate/core'; -import { QbmModule, DataSourceToolbarModule, DataTableModule, LdsReplaceModule } from 'qbm'; +import { DataSourceToolbarModule, DataTableModule, DataViewModule, LdsReplaceModule, QbmModule } from 'qbm'; +import { LifecycleActionComponent } from './lifecycle-action.component'; @NgModule({ declarations: [LifecycleActionComponent], imports: [ @@ -56,7 +57,9 @@ import { QbmModule, DataSourceToolbarModule, DataTableModule, LdsReplaceModule } MatRadioModule, ReactiveFormsModule, QbmModule, - TranslateModule + TranslateModule, + DataViewModule, + MatTableModule, ], }) -export class LifecycleActionsModule { } +export class LifecycleActionsModule {} diff --git a/imxweb/projects/aob/src/lib/permissions/aob-permissions-helper.ts b/imxweb/projects/aob/src/lib/permissions/aob-permissions-helper.ts index 353224cfe..c24194e76 100644 --- a/imxweb/projects/aob/src/lib/permissions/aob-permissions-helper.ts +++ b/imxweb/projects/aob/src/lib/permissions/aob-permissions-helper.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -25,9 +25,9 @@ */ export function isAobApplicationOwner(features: string[]): boolean { - return features.find(item => item === 'Portal_UI_ApplicationOwner') != null; + return features.find((item) => item === 'Portal_UI_ApplicationOwner') != null; } export function isAobApplicationAdmin(features: string[]): boolean { - return features.find(item => item === 'Portal_UI_ApplicationAdmin') != null; + return features.find((item) => item === 'Portal_UI_ApplicationAdmin') != null; } diff --git a/imxweb/projects/aob/src/lib/permissions/aob-permissions.service.ts b/imxweb/projects/aob/src/lib/permissions/aob-permissions.service.ts index 2bc69324e..fd0731d53 100644 --- a/imxweb/projects/aob/src/lib/permissions/aob-permissions.service.ts +++ b/imxweb/projects/aob/src/lib/permissions/aob-permissions.service.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -30,16 +30,21 @@ import { UserModelService } from 'qer'; import { isAobApplicationAdmin, isAobApplicationOwner } from './aob-permissions-helper'; @Injectable({ - providedIn: 'root' + providedIn: 'root', }) export class AobPermissionsService { - constructor(private readonly userService: UserModelService) { } + constructor(private readonly userService: UserModelService) {} public async isAobApplicationOwner(): Promise { - return isAobApplicationOwner((await this.userService.getFeatures()).Features); + return isAobApplicationOwner((await this.userService.getFeatures()).Features || []); } public async isAobApplicationAdmin(): Promise { - return isAobApplicationAdmin((await this.userService.getFeatures()).Features); + return isAobApplicationAdmin((await this.userService.getFeatures()).Features || []); + } + + public async isAobApplicationOwnerOrAdmin(): Promise { + const features = (await this.userService.getFeatures()).Features || []; + return isAobApplicationAdmin(features) || isAobApplicationOwner(features); } } diff --git a/imxweb/projects/aob/src/lib/service-items/service-items.module.ts b/imxweb/projects/aob/src/lib/service-items/service-items.module.ts index e31542951..929f95faa 100644 --- a/imxweb/projects/aob/src/lib/service-items/service-items.module.ts +++ b/imxweb/projects/aob/src/lib/service-items/service-items.module.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -28,8 +28,6 @@ import { NgModule } from '@angular/core'; import { CommonModule } from '@angular/common'; @NgModule({ - imports: [ - CommonModule - ] + imports: [CommonModule], }) -export class ServiceItemsModule { } +export class ServiceItemsModule {} diff --git a/imxweb/projects/aob/src/lib/service-items/service-items.service.ts b/imxweb/projects/aob/src/lib/service-items/service-items.service.ts index 49c38003e..1d54e75a1 100644 --- a/imxweb/projects/aob/src/lib/service-items/service-items.service.ts +++ b/imxweb/projects/aob/src/lib/service-items/service-items.service.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -26,24 +26,29 @@ import { Injectable } from '@angular/core'; +import { PortalEntitlement, PortalEntitlementServiceitem } from '@imx-modules/imx-api-aob'; +import { CollectionLoadParameters, ExtendedTypedEntityCollection } from '@imx-modules/imx-qbm-dbts'; import { ApiClientService } from 'qbm'; -import { PortalEntitlement, PortalEntitlementServiceitem } from 'imx-api-aob'; -import { CollectionLoadParameters, TypedEntityCollectionData } from 'imx-qbm-dbts'; import { AobApiService } from '../aob-api-client.service'; @Injectable({ - providedIn: 'root' + providedIn: 'root', }) export class ServiceItemsService { - constructor(private readonly aobClient: AobApiService, private readonly apiProvider: ApiClientService) { } + constructor( + private readonly aobClient: AobApiService, + private readonly apiProvider: ApiClientService, + ) {} public async get( entitlement: PortalEntitlement, - parameters: CollectionLoadParameters = { } - ): Promise> { - return this.apiProvider.request(() => this.aobClient.typedClient.PortalEntitlementServiceitem.Get({ - ...{ uid_aobentitlement: entitlement.UID_AOBEntitlement.value }, - ...parameters - })); + parameters: CollectionLoadParameters = {}, + ): Promise | undefined> { + return this.apiProvider.request(() => + this.aobClient.typedClient.PortalEntitlementServiceitem.Get({ + ...{ uid_aobentitlement: entitlement.UID_AOBEntitlement.value }, + ...parameters, + }), + ); } } diff --git a/imxweb/projects/aob/src/lib/shops/shops.service.ts b/imxweb/projects/aob/src/lib/shops/shops.service.ts index 5159a4639..68525edd0 100644 --- a/imxweb/projects/aob/src/lib/shops/shops.service.ts +++ b/imxweb/projects/aob/src/lib/shops/shops.service.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -26,65 +26,77 @@ import { Injectable } from '@angular/core'; -import { ClassloggerService, ApiClientService } from 'qbm'; -import { CollectionLoadParameters, TypedEntity, TypedEntityCollectionData } from 'imx-qbm-dbts'; -import { PortalShops, PortalApplicationinshop, PortalApplication } from 'imx-api-aob'; +import { PortalApplication, PortalApplicationinshop, PortalShops } from '@imx-modules/imx-api-aob'; +import { CollectionLoadParameters, TypedEntity, TypedEntityCollectionData } from '@imx-modules/imx-qbm-dbts'; +import { ApiClientService, ClassloggerService } from 'qbm'; import { AobApiService } from '../aob-api-client.service'; @Injectable({ - providedIn: 'root' + providedIn: 'root', }) export class ShopsService { public get display(): string { - return this.aobClient.typedClient.PortalShops.GetSchema().Display; + return this.aobClient.typedClient.PortalShops.GetSchema().Display || ''; } constructor( private readonly aobClient: AobApiService, private readonly logger: ClassloggerService, - private readonly apiProvider: ApiClientService - ) { } + private readonly apiProvider: ApiClientService, + ) {} - public async get(parameters: CollectionLoadParameters = { ParentKey: '' }): Promise> { + public async get(parameters: CollectionLoadParameters = { ParentKey: '' }): Promise | undefined> { this.logger.debug(this, 'get'); - return this.apiProvider.request(() => this.aobClient.typedClient.PortalShops.Get(parameters)); + return this.apiProvider.request( + () => this.aobClient.typedClient.PortalShops.Get(parameters) as Promise>, + ); } - public async getApplicationInShop(application: string, parameters: CollectionLoadParameters = {}): - Promise> { + public async getApplicationInShop( + application: string, + parameters: CollectionLoadParameters = {}, + ): Promise | undefined> { this.logger.debug(this, 'getApplicationInShop'); if (application) { - return this.apiProvider.request(() => - this.aobClient.typedClient.PortalApplicationinshop.Get(application, parameters)); + return this.apiProvider.request(() => this.aobClient.typedClient.PortalApplicationinshop.Get(application, parameters)); } } - public async getFirstAndCount(uidApplication: string): Promise<{ first: TypedEntity, count: number }> { - + public async getFirstAndCount(uidApplication: string): Promise<{ first: TypedEntity | undefined; count: number }> { const shops = await this.getApplicationInShop(uidApplication, { PageSize: 1 }); return { - first: shops.Data.length === 0 ? undefined : shops.Data[0], - count: shops.totalCount + first: shops?.Data.length === 0 ? undefined : shops?.Data[0], + count: shops?.totalCount || 0, }; } - public async updateApplicationInShops(application: PortalApplication, changeSet: { add: PortalShops[], remove: PortalShops[] }): Promise { + public async updateApplicationInShops( + application: PortalApplication, + changeSet: { add: PortalShops[]; remove: PortalShops[] }, + ): Promise { this.logger.debug(this, 'updateApplicationInShops'); const applicationInShop = await this.getApplicationInShop(application.UID_AOBApplication.value); - return applicationInShop && - await this.addShops(application, changeSet.add.filter(shop => !ShopsService.isAssigned(shop, applicationInShop.Data))) && - this.removeShops(application, changeSet.remove.filter(shop => ShopsService.isAssigned(shop, applicationInShop.Data))); + return ( + !!applicationInShop && + (await this.addShops( + application, + changeSet.add.filter((shop) => !ShopsService.isAssigned(shop, applicationInShop.Data)), + )) && + (await this.removeShops( + application, + changeSet.remove.filter((shop) => ShopsService.isAssigned(shop, applicationInShop.Data)), + )) + ); } private async addShops(application: PortalApplication, shops: PortalShops[]): Promise { let count = 0; await this.apiProvider.request(async () => { for (const shop of shops) { - await this.aobClient.client. - portal_applicationinshop_put(application.UID_AOBApplication.value, shop.UID_ITShopOrg.value, []); + await this.aobClient.client.portal_applicationinshop_put(application.UID_AOBApplication.value, shop.UID_ITShopOrg.value, []); count++; } }); @@ -95,8 +107,11 @@ export class ShopsService { let count = 0; await this.apiProvider.request(async () => { for (const shop of shops) { - await this.aobClient.client - .portal_applicationinshop_delete(application.UID_AOBApplication.value, shop.UID_ITShopOrg.value, undefined); + await this.aobClient.client.portal_applicationinshop_delete( + application.UID_AOBApplication.value, + shop.UID_ITShopOrg.value, + '', + ); count++; } }); @@ -104,6 +119,6 @@ export class ShopsService { } public static isAssigned(shop: PortalShops, shopsAssigned: PortalApplicationinshop[]): boolean { - return shopsAssigned && shopsAssigned.find(shopAssigned => shopAssigned.UID_ITShopOrg.value === shop.UID_ITShopOrg.value) != null; + return shopsAssigned && shopsAssigned.find((shopAssigned) => shopAssigned.UID_ITShopOrg.value === shop.UID_ITShopOrg.value) != null; } } diff --git a/imxweb/projects/aob/src/lib/start-page/start-page.component.html b/imxweb/projects/aob/src/lib/start-page/start-page.component.html index 75084f4a5..f03ed29fd 100644 --- a/imxweb/projects/aob/src/lib/start-page/start-page.component.html +++ b/imxweb/projects/aob/src/lib/start-page/start-page.component.html @@ -1,19 +1,19 @@
- - account_circle + + account_circle
-
{{ '#LDS#Welcome'| translate }}, 
+
{{ '#LDS#Welcome' | translate }}, 
{{ name }}
- {{ '#LDS#Applications' | translate }} + {{ '#LDS#Applications' | translate }} - {{ '#LDS#{0} Applications' | translate | ldsReplace:numberOfApplications }} + {{ '#LDS#{0} Applications' | translate | ldsReplace: numberOfApplications }} @@ -21,11 +21,23 @@ - - + + diff --git a/imxweb/projects/aob/src/lib/start-page/start-page.component.scss b/imxweb/projects/aob/src/lib/start-page/start-page.component.scss index 044196a80..ce1524134 100644 --- a/imxweb/projects/aob/src/lib/start-page/start-page.component.scss +++ b/imxweb/projects/aob/src/lib/start-page/start-page.component.scss @@ -1,4 +1,4 @@ -@import "@elemental-ui/core/src/styles/_palette.scss"; +@import '@elemental-ui/core/src/styles/_palette.scss'; // Host :host { @@ -13,7 +13,7 @@ img { } // material classes -.mat-card { +.mat-mdc-card { width: 365px; height: 179px; margin: 50px 20px 0px; @@ -22,34 +22,30 @@ img { flex: 0 0 auto; } - - -.mat-card-title { +.mat-mdc-card-title { padding: 20px 33px 0px; - font-size: 24px; font-weight: 600; margin-bottom: 0; } - -.mat-card > .mat-card-actions:last-child { +.mat-mdc-card > .mat-mdc-card-actions:last-child { padding-bottom: 25px; } -.mat-card-content { +.mat-mdc-card-content { font-size: 16px; padding: 5px 33px 10px; margin-bottom: 0; flex-grow: 1; } -.mat-card-actions { +.mat-mdc-card-actions { display: flex; flex-direction: row; padding: 0 25px; } -.mat-button { +.mat-mdc-button { font-size: 16px; } @@ -79,10 +75,3 @@ img { text-overflow: ellipsis; text-align: left; } - -.imx-user-icon { - font-size: 100px; - text-align: center; - display: inline; - color: $iris-blue; -} diff --git a/imxweb/projects/aob/src/lib/start-page/start-page.component.ts b/imxweb/projects/aob/src/lib/start-page/start-page.component.ts index 6d9b5b0a5..557f2e9ad 100644 --- a/imxweb/projects/aob/src/lib/start-page/start-page.component.ts +++ b/imxweb/projects/aob/src/lib/start-page/start-page.component.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -24,7 +24,6 @@ * */ -import { OverlayRef } from '@angular/cdk/overlay'; import { Component, OnDestroy, OnInit } from '@angular/core'; import { SafeUrl } from '@angular/platform-browser'; import { EuiLoadingService } from '@elemental-ui/core'; @@ -39,13 +38,13 @@ import { AobPermissionsService } from '../permissions/aob-permissions.service'; @Component({ selector: 'imx-start', templateUrl: './start-page.component.html', - styleUrls: ['./start-page.component.scss'] + styleUrls: ['./start-page.component.scss'], }) export class StartPageComponent implements OnInit, OnDestroy { public numberOfApplications = 0; public isAdmin: boolean; public name: string; - public imageUrl: SafeUrl; + public imageUrl: SafeUrl | undefined; private authSubscription: Subscription; @@ -58,11 +57,10 @@ export class StartPageComponent implements OnInit, OnDestroy { private readonly aobPermissionsService: AobPermissionsService, authentication: AuthenticationService, ) { - this.authSubscription = authentication.onSessionResponse?.subscribe(async sessionState => { - this.name = sessionState.Username; - this.imageUrl = await this.imageProvider.getPersonImageUrl(sessionState.UserUid); - } - ); + this.authSubscription = authentication.onSessionResponse?.subscribe(async (sessionState) => { + this.name = sessionState.Username || ''; + this.imageUrl = await this.imageProvider.getPersonImageUrl(this.name); + }); } public ngOnDestroy(): void { @@ -70,8 +68,9 @@ export class StartPageComponent implements OnInit, OnDestroy { } public async ngOnInit(): Promise { - let overlayRef: OverlayRef; - setTimeout(() => overlayRef = this.busyService.show()); + if (this.busyService.overlayRefs.length === 0) { + this.busyService.show(); + } try { this.logger.debug(this, 'get number of applications...'); const apps = await this.applicationsProvider.get(); @@ -82,9 +81,8 @@ export class StartPageComponent implements OnInit, OnDestroy { } this.isAdmin = await this.aobPermissionsService.isAobApplicationAdmin(); - } finally { - setTimeout(() => this.busyService.hide(overlayRef)); + this.busyService.hide(); } } } diff --git a/imxweb/projects/aob/src/lib/start-page/start-page.module.ts b/imxweb/projects/aob/src/lib/start-page/start-page.module.ts index b30574409..2e8973a03 100644 --- a/imxweb/projects/aob/src/lib/start-page/start-page.module.ts +++ b/imxweb/projects/aob/src/lib/start-page/start-page.module.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -37,7 +37,6 @@ import { StartPageComponent } from './start-page.component'; import { AobUserModule } from '../user/user.module'; import { GlobalKpiModule } from '../global-kpi/global-kpi.module'; - @NgModule({ declarations: [StartPageComponent], imports: [ @@ -51,10 +50,8 @@ import { GlobalKpiModule } from '../global-kpi/global-kpi.module'; AobUserModule, QbmModule, RouterModule, - GlobalKpiModule - ], - exports: [ - StartPageComponent + GlobalKpiModule, ], + exports: [StartPageComponent], }) -export class StartPageModule { } +export class StartPageModule {} diff --git a/imxweb/projects/aob/src/lib/user/user.component.html b/imxweb/projects/aob/src/lib/user/user.component.html index 36c691313..6864cff87 100644 --- a/imxweb/projects/aob/src/lib/user/user.component.html +++ b/imxweb/projects/aob/src/lib/user/user.component.html @@ -1,5 +1,5 @@ -
- person +
+ person
{{ primaryValue }} {{ secondaryValue }} diff --git a/imxweb/projects/aob/src/lib/user/user.component.scss b/imxweb/projects/aob/src/lib/user/user.component.scss index 62df0e484..c59521191 100644 --- a/imxweb/projects/aob/src/lib/user/user.component.scss +++ b/imxweb/projects/aob/src/lib/user/user.component.scss @@ -29,14 +29,14 @@ flex: 1 1 auto; overflow: hidden; - >span { + > span { font-weight: 600; font-size: 12px; overflow: hidden; text-overflow: ellipsis; } - >span:last-child { + > span:last-child { font-size: 10px; color: $black-b; } @@ -50,11 +50,11 @@ } .imx-user-properties { - >span { + > span { font-size: 16px; } - >span:last-child { + > span:last-child { font-size: 12px; } } @@ -66,14 +66,14 @@ background-color: $corbin-pastel; } - .imx-user-properties>span { + .imx-user-properties > span { font-size: 12px; } } .imx-user.large.noUser { .imx-user-properties { - >span { + > span { font-size: 14px; } } @@ -86,7 +86,7 @@ background-color: $color-gray-60; } .imx-user-properties { - >span:last-child { + > span:last-child { color: $color-gray-60; } } @@ -100,7 +100,7 @@ background-color: $color-gray-80; } .imx-user-properties { - >span:last-child { + > span:last-child { color: $color-gray-80; } } diff --git a/imxweb/projects/aob/src/lib/user/user.component.ts b/imxweb/projects/aob/src/lib/user/user.component.ts index 9d73ad046..42e1c0362 100644 --- a/imxweb/projects/aob/src/lib/user/user.component.ts +++ b/imxweb/projects/aob/src/lib/user/user.component.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -28,13 +28,13 @@ import { Component, Input, OnChanges } from '@angular/core'; import { SafeUrl } from '@angular/platform-browser'; import { TranslateService } from '@ngx-translate/core'; -import { IReadValue, IWriteValue } from 'imx-qbm-dbts'; +import { IReadValue, IWriteValue } from '@imx-modules/imx-qbm-dbts'; import { ClassloggerService } from 'qbm'; @Component({ selector: 'imx-user', templateUrl: './user.component.html', - styleUrls: ['./user.component.scss'] + styleUrls: ['./user.component.scss'], }) export class UserComponent implements OnChanges { @Input() public uid: IReadValue | IWriteValue; @@ -49,8 +49,8 @@ export class UserComponent implements OnChanges { constructor( private readonly translateService: TranslateService, - private readonly logger: ClassloggerService) { - } + private readonly logger: ClassloggerService, + ) {} public ngOnChanges(): void { if (!this.noUserText || this.noUserText.length < 1) { @@ -60,7 +60,7 @@ export class UserComponent implements OnChanges { if (!this.hasValidUser()) { this.logger.debug(this, 'Show noUserText because of an empty value.'); - this.translateService.get(this.noUserText).subscribe((trans: string) => this.secondaryValue = trans); + this.translateService.get(this.noUserText).subscribe((trans: string) => (this.secondaryValue = trans)); this.primaryValue = ''; } else { this.primaryValue = this.uid.Column.GetDisplayValue(); diff --git a/imxweb/projects/aob/src/lib/user/user.module.ts b/imxweb/projects/aob/src/lib/user/user.module.ts index ee2618721..34047927f 100644 --- a/imxweb/projects/aob/src/lib/user/user.module.ts +++ b/imxweb/projects/aob/src/lib/user/user.module.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -32,16 +32,8 @@ import { UserComponent } from './user.component'; import { UserModule } from 'qer'; @NgModule({ - declarations: [ - UserComponent - ], - imports: [ - CommonModule, - MatIconModule, - UserModule - ], - exports: [ - UserComponent - ], + declarations: [UserComponent], + imports: [CommonModule, MatIconModule, UserModule], + exports: [UserComponent], }) -export class AobUserModule { } +export class AobUserModule {} diff --git a/imxweb/projects/aob/src/public-api.ts b/imxweb/projects/aob/src/public-api.ts index aed73106c..522ce3139 100644 --- a/imxweb/projects/aob/src/public-api.ts +++ b/imxweb/projects/aob/src/public-api.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -28,7 +28,7 @@ * Hier kommen die zu exportierenden Komponenten hin */ -export { AobConfigModule } from './lib/aob-config.module' +export { AobConfigModule } from './lib/aob-config.module'; export { StartPageComponent } from './lib/start-page/start-page.component'; export { ApplicationsComponent } from './lib/applications/applications.component'; export { ApplicationsModule } from './lib/applications/applications.module'; diff --git a/imxweb/projects/aob/src/test.ts b/imxweb/projects/aob/src/test.ts index f53ca02e8..287a3f2d5 100644 --- a/imxweb/projects/aob/src/test.ts +++ b/imxweb/projects/aob/src/test.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -26,23 +26,13 @@ // This file is required by karma.conf.js and loads recursively all the .spec and framework files -import 'core-js/es7/reflect'; -import 'zone.js/dist/zone'; -import 'zone.js/dist/zone-testing'; -import { getTestBed } from '@angular/core/testing'; -import { - BrowserDynamicTestingModule, - platformBrowserDynamicTesting -} from '@angular/platform-browser-dynamic/testing'; +// Zone must be imported first. Be careful with prettier import organizing +import 'zone.js'; +import 'zone.js/testing'; -declare const require: any; +import { getTestBed } from '@angular/core/testing'; +import { BrowserDynamicTestingModule, platformBrowserDynamicTesting } from '@angular/platform-browser-dynamic/testing'; +import 'core-js/es/reflect'; // First, initialize the Angular testing environment. -getTestBed().initTestEnvironment( - BrowserDynamicTestingModule, - platformBrowserDynamicTesting() -); -// Then we find all the tests. -const context = require.context('./', true, /\.spec\.ts$/); -// And load the modules. -context.keys().map(context); +getTestBed().initTestEnvironment(BrowserDynamicTestingModule, platformBrowserDynamicTesting()); diff --git a/imxweb/projects/aob/tsconfig.lib.json b/imxweb/projects/aob/tsconfig.lib.json index 6bc419f84..9786008a7 100644 --- a/imxweb/projects/aob/tsconfig.lib.json +++ b/imxweb/projects/aob/tsconfig.lib.json @@ -7,10 +7,11 @@ "declarationMap": true, "sourceMap": true, "inlineSources": true, - "types": [] + "types": [], + "strictNullChecks": true }, - "exclude": [ - "src/test.ts", - "**/*.spec.ts" - ] + "angularCompilerOptions": { + "strictTemplates": true + }, + "exclude": ["src/test.ts", "**/*.spec.ts"] } diff --git a/imxweb/projects/aob/tsconfig.lib.prod.json b/imxweb/projects/aob/tsconfig.lib.prod.json index 61c7592e7..fb40dbbb0 100644 --- a/imxweb/projects/aob/tsconfig.lib.prod.json +++ b/imxweb/projects/aob/tsconfig.lib.prod.json @@ -3,8 +3,5 @@ "extends": "./tsconfig.lib.json", "compilerOptions": { "declarationMap": false - }, - "angularCompilerOptions": { - "enableIvy": true } } diff --git a/imxweb/projects/aob/tsconfig.spec.json b/imxweb/projects/aob/tsconfig.spec.json index 16da33db0..6bd74e1f7 100644 --- a/imxweb/projects/aob/tsconfig.spec.json +++ b/imxweb/projects/aob/tsconfig.spec.json @@ -1,17 +1,10 @@ { "extends": "../../tsconfig.json", "compilerOptions": { + "strictNullChecks": false, "outDir": "../../out-tsc/spec", - "types": [ - "jasmine", - "node" - ] + "types": ["jasmine", "node"] }, - "files": [ - "src/test.ts" - ], - "include": [ - "**/*.spec.ts", - "**/*.d.ts" - ] + "files": ["src/test.ts"], + "include": ["**/*.spec.ts", "**/*.d.ts"] } diff --git a/imxweb/projects/aob/tslint.json b/imxweb/projects/aob/tslint.json deleted file mode 100644 index 8bab15f53..000000000 --- a/imxweb/projects/aob/tslint.json +++ /dev/null @@ -1,17 +0,0 @@ -{ - "extends": "../../tslint.json", - "rules": { - "directive-selector": [ - true, - "attribute", - "imx", - "camelCase" - ], - "component-selector": [ - true, - "element", - "imx", - "kebab-case" - ] - } -} diff --git a/imxweb/projects/apc/.compodocrc.json b/imxweb/projects/apc/.compodocrc.json index 442e29f03..e4eccd87e 100644 --- a/imxweb/projects/apc/.compodocrc.json +++ b/imxweb/projects/apc/.compodocrc.json @@ -1,6 +1,6 @@ { "name": "IMX Web - APC Library", - "output": "../../documentation/v92/apc", + "output": "../../documentation/v93/apc", "theme": "material", "assetsFolder": "../../compodoc/assets", "customLogo": "../../compodoc/assets/images/oneidentity-logo.png", diff --git a/imxweb/projects/apc/.eslintrc.json b/imxweb/projects/apc/.eslintrc.json new file mode 100644 index 000000000..a6da13b8c --- /dev/null +++ b/imxweb/projects/apc/.eslintrc.json @@ -0,0 +1,35 @@ +{ + "extends": "../../.eslintrc.json", + "ignorePatterns": ["!**/*", "**/*.spec.ts"], + "overrides": [ + { + "files": ["*.ts"], + "parserOptions": { + "project": ["imxweb/projects/apc/tsconfig.lib.json", "imxweb/projects/apc/tsconfig.spec.json"], + "createDefaultProgram": true + }, + "rules": { + "@angular-eslint/directive-selector": [ + "error", + { + "type": "attribute", + "prefix": "imx", + "style": "camelCase" + } + ], + "@angular-eslint/component-selector": [ + "error", + { + "type": "element", + "prefix": "imx", + "style": "kebab-case" + } + ] + } + }, + { + "files": ["*.html"], + "rules": {} + } + ] +} diff --git a/imxweb/projects/apc/imx-plugin-config.json b/imxweb/projects/apc/imx-plugin-config.json index 0d6786142..c17d294bc 100644 --- a/imxweb/projects/apc/imx-plugin-config.json +++ b/imxweb/projects/apc/imx-plugin-config.json @@ -5,4 +5,4 @@ "Name": "ApcConfigModule" } ] -} \ No newline at end of file +} diff --git a/imxweb/projects/apc/karma.conf.js b/imxweb/projects/apc/karma.conf.js index 211193c9d..3e53a3ac8 100644 --- a/imxweb/projects/apc/karma.conf.js +++ b/imxweb/projects/apc/karma.conf.js @@ -15,7 +15,7 @@ module.exports = function (config) { require('karma-junit-reporter'), ], client: { - clearContext: false // leave Jasmine Spec Runner output visible in browser + clearContext: false, // leave Jasmine Spec Runner output visible in browser }, coverageIstanbulReporter: { dir: require('path').join(__dirname, 'results'), @@ -23,7 +23,7 @@ module.exports = function (config) { fixWebpackSourcePaths: true, 'report-config': { html: { - subdir: 'coverage-html' + subdir: 'coverage-html', }, }, thresholds: { @@ -40,13 +40,14 @@ module.exports = function (config) { port: 9876, captureTimeout: 210000, browserDisconnectTolerance: 3, - browserDisconnectTimeout : 210000, - browserNoActivityTimeout : 210000, + browserDisconnectTimeout: 210000, + browserNoActivityTimeout: 210000, colors: true, logLevel: config.LOG_INFO, autoWatch: true, browsers: ['Chrome'], singleRun: false, - restartOnFileChange: true + failOnEmptyTestSuite: false, + restartOnFileChange: true, }); }; diff --git a/imxweb/projects/apc/ng-package.dynamic.json b/imxweb/projects/apc/ng-package.dynamic.json index d03b39616..b039b9514 100644 --- a/imxweb/projects/apc/ng-package.dynamic.json +++ b/imxweb/projects/apc/ng-package.dynamic.json @@ -16,12 +16,11 @@ "@elemental-ui/core", "@ngx-translate/core", "@ngx-translate/http-loader", - "applicationinsights-js", "billboard.js" ], - "dest": "../../html/apc", + "dest": "../../html/qer-app-portal/apc", "lib": { "entryFile": "src/public_api.ts", - "styleIncludePaths": ["../../shared/assets"] + "styleIncludePaths": ["../../shared/scss"] } } diff --git a/imxweb/projects/apc/ng-package.json b/imxweb/projects/apc/ng-package.json index 18180a00a..c9cc87bfc 100644 --- a/imxweb/projects/apc/ng-package.json +++ b/imxweb/projects/apc/ng-package.json @@ -3,6 +3,6 @@ "dest": "../../dist/apc", "lib": { "entryFile": "src/public_api.ts", - "styleIncludePaths": ["../../shared/assets"] + "styleIncludePaths": ["../../shared/scss"] } } diff --git a/imxweb/projects/apc/package.json b/imxweb/projects/apc/package.json index 344a4c47d..640a40043 100644 --- a/imxweb/projects/apc/package.json +++ b/imxweb/projects/apc/package.json @@ -1,6 +1,6 @@ { "name": "apc", - "version": "9.2.1", + "version": "9.3.0", "private": true, "bundledDependencies": [ "imx-api-apc" diff --git a/imxweb/projects/apc/project.json b/imxweb/projects/apc/project.json new file mode 100644 index 000000000..c44bda316 --- /dev/null +++ b/imxweb/projects/apc/project.json @@ -0,0 +1,58 @@ +{ + "$schema": "../../node_modules/nx/schemas/project-schema.json", + "name": "apc", + "sourceRoot": "projects/apc/src", + "implicitDependencies": ["qer"], + "projectType": "library", + "prefix": "imx", + "generators": { + "@schematics/angular:component": { + "style": "scss" + } + }, + "targets": { + "build": { + "executor": "@angular-devkit/build-angular:ng-packagr", + "options": { + "tsConfig": "projects/apc/tsconfig.lib.json", + "project": "projects/apc/ng-package.json" + }, + "configurations": { + "production": { + "tsConfig": "projects/apc/tsconfig.lib.prod.json" + }, + "development": { + "tsConfig": "projects/apc/tsconfig.lib.json" + }, + "dynamic": { + "project": "projects/apc/ng-package.dynamic.json" + } + }, + "outputs": ["{workspaceRoot}/dist/apc"] + }, + "test": { + "executor": "@angular-devkit/build-angular:karma", + "options": { + "main": "projects/apc/src/test.ts", + "tsConfig": "projects/apc/tsconfig.spec.json", + "karmaConfig": "projects/apc/karma.conf.js", + "stylePreprocessorOptions": { + "includePaths": [ + "./shared/assets", + "./shared/scss", + "./node_modules", + "./node_modules/@elemental-ui/cadence-icon", + "./node_modules/@elemental-ui/core" + ] + } + } + }, + "lint": { + "executor": "@angular-devkit/build-angular:tslint", + "options": { + "tsConfig": ["projects/apc/tsconfig.lib.json", "projects/apc/tsconfig.spec.json"], + "exclude": ["**/node_modules/**", "**/*.spec.ts", "**/*.json"] + } + } + } +} diff --git a/imxweb/projects/apc/src/lib/apc-api-client.service.ts b/imxweb/projects/apc/src/lib/apc-api-client.service.ts index 89e8bd1b5..5bef90164 100644 --- a/imxweb/projects/apc/src/lib/apc-api-client.service.ts +++ b/imxweb/projects/apc/src/lib/apc-api-client.service.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -25,11 +25,11 @@ */ import { Injectable } from '@angular/core'; -import { V2Client, TypedClient } from 'imx-api-apc'; +import { V2Client, TypedClient } from '@imx-modules/imx-api-apc'; import { AppConfigService, ClassloggerService, ImxTranslationProviderService } from 'qbm'; @Injectable({ - providedIn: 'root' + providedIn: 'root', }) export class ApcApiService { private tc: TypedClient; @@ -45,7 +45,8 @@ export class ApcApiService { constructor( config: AppConfigService, private readonly logger: ClassloggerService, - private readonly translationProvider: ImxTranslationProviderService) { + private readonly translationProvider: ImxTranslationProviderService, + ) { try { // Use schema loaded by QBM client const schemaProvider = config.client; diff --git a/imxweb/projects/apc/src/lib/apc-config.module.ts b/imxweb/projects/apc/src/lib/apc-config.module.ts index 9e858f4d9..778710f1b 100644 --- a/imxweb/projects/apc/src/lib/apc-config.module.ts +++ b/imxweb/projects/apc/src/lib/apc-config.module.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -32,19 +32,17 @@ import { SoftwareComponent } from './software/software.component'; import { InitService } from './init.service'; import { SoftwareModule } from './software/software.module'; -const routes: Routes = [{ - path: 'resp/Application', - component: SoftwareComponent, - canActivate: [RouteGuardService], - resolve: [RouteGuardService], -}, +const routes: Routes = [ + { + path: 'resp/Application', + component: SoftwareComponent, + canActivate: [RouteGuardService], + resolve: [RouteGuardService], + }, ]; @NgModule({ - imports: [ - RouterModule.forChild(routes), - SoftwareModule - ] + imports: [RouterModule.forChild(routes), SoftwareModule], }) export class ApcConfigModule { constructor(private readonly initializer: InitService) { diff --git a/imxweb/projects/apc/src/lib/app-info.model.ts b/imxweb/projects/apc/src/lib/app-info.model.ts index 0c8ec00b1..e93c577fa 100644 --- a/imxweb/projects/apc/src/lib/app-info.model.ts +++ b/imxweb/projects/apc/src/lib/app-info.model.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -24,7 +24,7 @@ * */ -import { EntitySchema, DataModel, FilterData } from 'imx-qbm-dbts'; +import { EntitySchema, DataModel, FilterData } from '@imx-modules/imx-qbm-dbts'; export interface ResourceDataModel { getModel(filter: FilterData[]): Promise; @@ -32,7 +32,7 @@ export interface ResourceDataModel { export interface ResourceInfo { table: string; - caption?:string; + caption?: string; admin?: ResourceInfoApiWrapper; resp?: ResourceInfoApiWrapper; accProduct?: any; diff --git a/imxweb/projects/apc/src/lib/init.service.ts b/imxweb/projects/apc/src/lib/init.service.ts index 3617591ee..45769bd4e 100644 --- a/imxweb/projects/apc/src/lib/init.service.ts +++ b/imxweb/projects/apc/src/lib/init.service.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -30,11 +30,12 @@ import { MyResponsibilitiesRegistryService } from 'qer'; import { SoftwareComponent } from './software/software.component'; import { HELP_CONTEXTUAL } from 'qbm'; - - @Injectable({ providedIn: 'root' }) export class InitService { - constructor(private readonly router: Router, private readonly myResponsibilitiesRegistryService: MyResponsibilitiesRegistryService) {} + constructor( + private readonly router: Router, + private readonly myResponsibilitiesRegistryService: MyResponsibilitiesRegistryService, + ) {} public onInit(routes: Route[]): void { this.addRoutes(routes); @@ -59,7 +60,7 @@ export class InitService { TableName: 'Application', Count: 0, }, - contextId: HELP_CONTEXTUAL.MyResponsibilitiesApplication + contextId: HELP_CONTEXTUAL.MyResponsibilitiesApplication, })); } } diff --git a/imxweb/projects/apc/src/lib/software/software-sidesheet/software-memberships/software-memberships.component.html b/imxweb/projects/apc/src/lib/software/software-sidesheet/software-memberships/software-memberships.component.html index 2dd1dd15a..6e40d22a2 100644 --- a/imxweb/projects/apc/src/lib/software/software-sidesheet/software-memberships/software-memberships.component.html +++ b/imxweb/projects/apc/src/lib/software/software-sidesheet/software-memberships/software-memberships.component.html @@ -1,77 +1,99 @@ -
- +
+ {{ membershipHint | translate }} - {{ - LdsNotUnsubscribableHint | translate - }} + {{ LdsNotUnsubscribableHint | translate }}
- -
- - - - - - - +
+ + + + + {{ entitySchema?.Columns?.[DisplayColumns.DISPLAY_PROPERTYNAME]?.Display }} + + +
{{ item.GetEntity().GetDisplay() }}
+ +
+ + + +
- {{ item?.GetEntity()?.GetDisplay() }} + + {{ entitySchema.Columns.XMarkedForDeletion.Display }} +
- - - - -
-
- - {{ entitySchema.Columns.XMarkedForDeletion.Display }} - -
-
- - {{ '#LDS#Membership is ineffective' | translate }} - -
+
+ + {{ '#LDS#Membership is ineffective' | translate }} +
- - - - - - - - -
- +
+ +
+ + + {{ entitySchema?.Columns?.UID_Person?.Display }} + + +
{{ item.entity.columns.UID_Person.GetDisplayValue() }}
+ +
+ + + {{ entitySchema?.Columns?.XOrigin?.Display }} + + +
{{ item.entity.columns.XOrigin.GetDisplayValue() }}
+ +
+ + + {{ entitySchema?.Columns?.XDateInserted?.Display }} + + +
{{ item.entity.columns.XDateInserted.GetDisplayValue() }}
+ +
+ + + {{ entitySchema?.Columns?.ValidUntil?.Display }} + + +
{{ item.entity.columns.ValidUntil.GetDisplayValue() }}
+ +
+
+ +
+
- -
- - diff --git a/imxweb/projects/apc/src/lib/software/software-sidesheet/software-memberships/software-memberships.component.scss b/imxweb/projects/apc/src/lib/software/software-sidesheet/software-memberships/software-memberships.component.scss index 99132f227..1c333575c 100644 --- a/imxweb/projects/apc/src/lib/software/software-sidesheet/software-memberships/software-memberships.component.scss +++ b/imxweb/projects/apc/src/lib/software/software-sidesheet/software-memberships/software-memberships.component.scss @@ -1,32 +1,15 @@ +@import 'base/mixins'; + :host { - display: flex; - flex-direction: column; - flex: 1 1 auto; - overflow: hidden; - - eui-icon { - font-size: 14px; - margin-right: 4px; - } + @include flex-column-container-fill(); } .hidden { display: none; } -.mat-card { - flex: 1 1 auto; - display: flex; - flex-direction: column; - overflow: hidden; - margin: 20px; -} - .imx-table-content { - flex: 1 1 auto; - display: flex; - flex-direction: column; - overflow: hidden; + @include flex-column-container-fill(); } imx-busy-indicator { @@ -35,38 +18,6 @@ imx-busy-indicator { align-items: center; } -.helper-alert { - margin: 12px; -} - -.helper-alert-container { - margin: 0px 20px; -} - imx-selected-elements { margin-left: 10px; } - -.imx-menu-spacer{ - flex: 1 1 auto; -} - -.eui-sidesheet-actions { - button:not(:last-of-type) { - margin-right: 12px; - } -} - -.imx-badge-container { - > div { - display: table-cell; - - > .eui-badge { - margin: 0 5px; - - ::ng-deep .eui-badge-content { - white-space: nowrap; - } - } - } -} diff --git a/imxweb/projects/apc/src/lib/software/software-sidesheet/software-memberships/software-memberships.component.ts b/imxweb/projects/apc/src/lib/software/software-sidesheet/software-memberships/software-memberships.component.ts index 33550b97a..8cdaa9c03 100644 --- a/imxweb/projects/apc/src/lib/software/software-sidesheet/software-memberships/software-memberships.component.ts +++ b/imxweb/projects/apc/src/lib/software/software-sidesheet/software-memberships/software-memberships.component.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -24,13 +24,23 @@ * */ -import { Component, Input, OnChanges, SimpleChanges, ViewChild } from '@angular/core'; +import { Component, Input, OnChanges, SimpleChanges } from '@angular/core'; import { EuiSidesheetService } from '@elemental-ui/core'; import { TranslateService } from '@ngx-translate/core'; -import { PortalResourcesApplicationsMembership } from 'imx-api-apc'; -import { CollectionLoadParameters, DbObjectKey, DisplayColumns, IClientProperty, ValType, XOrigin } from 'imx-qbm-dbts'; -import { BusyService, ConfirmationService, DataSourceToolbarSettings, DataTableComponent, SnackBarService } from 'qbm'; +import { PortalResourcesApplicationsMembership } from '@imx-modules/imx-api-apc'; +import { + CollectionLoadParameters, + DbObjectKey, + DisplayColumns, + EntitySchema, + IClientProperty, + TypedEntity, + TypedEntityCollectionData, + ValType, + XOrigin, +} from '@imx-modules/imx-qbm-dbts'; +import { BusyService, calculateSidesheetWidth, ConfirmationService, DataViewInitParameters, DataViewSource, SnackBarService } from 'qbm'; import { SourceDetectiveSidesheetComponent, SourceDetectiveSidesheetData, SourceDetectiveType } from 'qer'; import { SoftwareService } from '../../software.service'; @@ -38,11 +48,11 @@ import { SoftwareService } from '../../software.service'; selector: 'imx-software-memberships', templateUrl: './software-memberships.component.html', styleUrls: ['./software-memberships.component.scss'], + providers: [DataViewSource], }) export class SoftwareMembershipsComponent implements OnChanges { - public dstSettings: DataSourceToolbarSettings; public DisplayColumns = DisplayColumns; - public entitySchema = this.softwareService.membershipSchema; + public entitySchema: EntitySchema; public selections: PortalResourcesApplicationsMembership[] = []; public showUnsubscribeWarning = false; @@ -54,16 +64,13 @@ export class SoftwareMembershipsComponent implements OnChanges { }; private displayColumns: IClientProperty[]; - private navigationState: CollectionLoadParameters = {}; public busyService = new BusyService(); @Input() public uidSoftware: string; - @ViewChild('membersTable') public membersTable: DataTableComponent; - public membershipHint = - '#LDS#Here you can manage the memberships of the software application. You can remove memberships and view the assignment analysis for each membership.'; - public LdsNotUnsubscribableHint = + '#LDS#Here you can specify which identities have access to the software application. You can remove memberships and view the assignment analysis for each membership.'; + public LdsNotUnsubscribableHint = '#LDS#There is at least one membership you cannot unsubscribe. You can only unsubscribe memberships you have requested.'; public get canDeleteSelected(): boolean { @@ -71,7 +78,7 @@ export class SoftwareMembershipsComponent implements OnChanges { } public get canUnsubscribeSelected(): boolean { - return this.selections.length > 0 && this.selections.every((item) => (item.UID_PersonWantsOrg?.value ?? '') !== ''); + return this.selections.length > 0 && this.selections.every((item) => (item.UID_PersonWantsOrg?.value ?? '') !== ''); } constructor( @@ -79,11 +86,13 @@ export class SoftwareMembershipsComponent implements OnChanges { private readonly sideSheet: EuiSidesheetService, private readonly translate: TranslateService, private readonly confirmationService: ConfirmationService, - private readonly snackBarService: SnackBarService + private readonly snackBarService: SnackBarService, + public dataSource: DataViewSource, ) { + this.entitySchema = this.softwareService.membershipSchema; this.displayColumns = [ this.entitySchema.Columns.UID_Person, - this.entitySchema.Columns.XOrigin, + this.entitySchema.Columns?.XOrigin, this.entitySchema.Columns.XDateInserted, this.entitySchema.Columns.ValidUntil, { ColumnName: 'badges', Type: ValType.String }, @@ -92,22 +101,18 @@ export class SoftwareMembershipsComponent implements OnChanges { public async ngOnChanges(changes: SimpleChanges): Promise { if (changes.uidSoftware && changes.uidSoftware.currentValue) { - return this.getData({}); + return this.getData(); } } - public async onSearch(keyword: string): Promise { - this.getData({ search: keyword, StartIndex: 0 }); - } - - public onSelectionChanged(selection: PortalResourcesApplicationsMembership[]): void { - this.selections = selection; + public onSelectionChanged(selection: readonly TypedEntity[]): void { + this.selections = selection as PortalResourcesApplicationsMembership[]; } - public async showDetails(item: PortalResourcesApplicationsMembership): Promise { - const uidPerson = item.UID_Person.value; + public async showDetails(item: TypedEntity): Promise { + const uidPerson = item.GetEntity().GetColumn('UID_Person').GetValue(); - const objectKey = DbObjectKey.FromXml(item.XObjectKey.value); + const objectKey = DbObjectKey.FromXml(item.GetEntity().GetColumn('XObjectKey').GetValue()); const data: SourceDetectiveSidesheetData = { UID_Person: uidPerson, @@ -119,27 +124,26 @@ export class SoftwareMembershipsComponent implements OnChanges { title: await this.translate.get('#LDS#Heading View Assignment Analysis').toPromise(), subTitle: item.GetEntity().GetDisplay(), padding: '0px', - width: 'max(60%,600px)', + width: calculateSidesheetWidth(), disableClose: false, testId: 'software-memberships-assingment-analysis', data, }); } - public async getData(navigationState: CollectionLoadParameters): Promise { - this.navigationState = navigationState; - - const isBusy = this.busyService.beginBusy(); - try { - this.dstSettings = { - dataSource: await this.softwareService.getMemberShips(this.uidSoftware, this.navigationState), - entitySchema: this.entitySchema, - navigationState: this.navigationState, - displayedColumns: this.displayColumns, - }; - } finally { - isBusy.endBusy(); - } + public async getData(): Promise { + this.dataSource.itemStatus = this.status; + const dataViewInitParameters: DataViewInitParameters = { + execute: (params: CollectionLoadParameters): Promise> => + this.softwareService.getMemberShips(this.uidSoftware, params), + schema: this.entitySchema, + columnsToDisplay: this.displayColumns, + highlightEntity: (entity: TypedEntity) => { + this.showDetails(entity); + }, + selectionChange: (selection) => this.onSelectionChanged(selection), + }; + this.dataSource.init(dataViewInitParameters); } public async deleteSelected(): Promise { @@ -155,11 +159,11 @@ export class SoftwareMembershipsComponent implements OnChanges { try { await this.softwareService.deleteGroupMembers( this.uidSoftware, - this.selections.map((i) => i.GetEntity().GetColumn('UID_Person').GetValue()) + this.selections.map((i) => i.GetEntity().GetColumn('UID_Person').GetValue()), ); - this.membersTable.clearSelection(); + this.dataSource.selection.clear(); this.snackBarService.open({ key: '#LDS#The memberships have been successfully removed.' }, '#LDS#Close'); - await this.getData({ search: this.navigationState.search }); + await this.dataSource.updateState(); } finally { isBusy.endBusy(); } @@ -175,7 +179,7 @@ export class SoftwareMembershipsComponent implements OnChanges { const notSubscribable = this.selections.some((entity) => entity.GetEntity().GetColumn('IsRequestCancellable').GetValue() === false); if (notSubscribable) { this.showUnsubscribeWarning = true; - this.membersTable.clearSelection(); + this.dataSource.selection.clear(); return; } if ( @@ -193,8 +197,8 @@ export class SoftwareMembershipsComponent implements OnChanges { }); } finally { isBusy.endBusy(); - this.membersTable.clearSelection(); - await this.getData({ search: this.navigationState.search }); + this.dataSource.selection.clear(); + await this.dataSource.updateState(); } } } diff --git a/imxweb/projects/apc/src/lib/software/software-sidesheet/software-sidesheet.component.html b/imxweb/projects/apc/src/lib/software/software-sidesheet/software-sidesheet.component.html index bb0ff2074..09183770f 100644 --- a/imxweb/projects/apc/src/lib/software/software-sidesheet/software-sidesheet.component.html +++ b/imxweb/projects/apc/src/lib/software/software-sidesheet/software-sidesheet.component.html @@ -1,23 +1,39 @@ - +
#LDS#Heading Main Data  - +
- +
- +
-
@@ -37,16 +53,27 @@
#LDS#Heading Service Item  - +
- +
- +
diff --git a/imxweb/projects/apc/src/lib/software/software-sidesheet/software-sidesheet.component.scss b/imxweb/projects/apc/src/lib/software/software-sidesheet/software-sidesheet.component.scss index fbaf7c85f..5c2d1fc5a 100644 --- a/imxweb/projects/apc/src/lib/software/software-sidesheet/software-sidesheet.component.scss +++ b/imxweb/projects/apc/src/lib/software/software-sidesheet/software-sidesheet.component.scss @@ -1,117 +1,14 @@ -@import '@elemental-ui/core/src/styles/_eui_palette.scss'; - +@import 'base/mixins'; :host { - display: flex; - flex-direction: column; - overflow: hidden; - height: 100%; + @include flex-column-container($height: 100%, $overflow: hidden); - .mat-tab-group { - flex-grow: 1; + .imx-cdr-group { + flex: 1 1 auto; overflow: auto; - } - - ::ng-deep .mat-tab-body-wrapper { - height: 100%; - } - - ::ng-deep .mat-tab-body-content { - display: flex; - flex-direction: column; - } - - ::ng-deep .mat-tab-group { - height: 100%; - - .mat-tab-header { - padding: 0 32px; - } - } - - .imx-tab-content { - display: flex; - flex-direction: column; - height: 100%; - - .imx-tab-content-body { - flex: 1 1 auto; - overflow: hidden; - display: flex; - flex-direction: column; - - .mat-card { - height: 100%; - display: flex; - flex-direction: column; - overflow: hidden; - padding: 16px; - - > form { - padding-right: 10px; - overflow: auto; - } - } - } - - .imx-cdr-group { - flex: 1 1 auto; - overflow: auto; - padding-right: 10px; - } + padding-right: 10px; } .hidden { display: none; } - - .imx-content-card { - margin: 20px; - display: flex; - flex-direction: column; - overflow: hidden; - - .imx-service-item-form { - display: flex; - flex-direction: column; - flex: 1 1 auto; - overflow: auto; - } - } -} - -:host { - .imx-tab-content { - .imx-action-buttons { - background-color: $color-gray-0; - } - } - - .eui-sidesheet-content { - ::ng-deep .mat-tab-group { - .mat-tab-header { - background-color: $color-gray-0; - } - } - } -} - -.eui-dark-theme { - :host { - .imx-tab-content { - .imx-action-buttons { - background-color: $color-gray-70; - } - } - - .eui-sidesheet-content { - ::ng-deep .mat-tab-group { - .mat-tab-header { - background-color: $color-gray-80; - } - } - } - .imx-tab-content .imx-action-buttons { - background-color: $color-gray-70; - } - } } diff --git a/imxweb/projects/apc/src/lib/software/software-sidesheet/software-sidesheet.component.ts b/imxweb/projects/apc/src/lib/software/software-sidesheet/software-sidesheet.component.ts index 16f33c1a4..c9a78f6c5 100644 --- a/imxweb/projects/apc/src/lib/software/software-sidesheet/software-sidesheet.component.ts +++ b/imxweb/projects/apc/src/lib/software/software-sidesheet/software-sidesheet.component.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -25,12 +25,12 @@ */ import { ChangeDetectorRef, Component, Inject, OnDestroy, OnInit } from '@angular/core'; -import { UntypedFormArray, FormGroup, FormArray } from '@angular/forms'; +import { FormGroup, UntypedFormArray } from '@angular/forms'; +import { EUI_SIDESHEET_DATA, EuiSidesheetRef } from '@elemental-ui/core'; import { Subscription } from 'rxjs'; -import { EuiSidesheetRef, EUI_SIDESHEET_DATA } from '@elemental-ui/core'; -import { IEntityColumn, TypedEntity } from 'imx-qbm-dbts'; -import { PortalRespApplication } from 'imx-api-apc'; +import { PortalRespApplication } from '@imx-modules/imx-api-apc'; +import { IEntityColumn, TypedEntity } from '@imx-modules/imx-qbm-dbts'; import { BusyService, CdrFactoryService, ColumnDependentReference, ConfirmationService } from 'qbm'; import { SoftwareService } from '../software.service'; @@ -44,8 +44,8 @@ interface ServiceItemGroup { /** * internal interface for the service item form */ -interface SoftwareFormGroup{ - array: UntypedFormArray +interface SoftwareFormGroup { + array: UntypedFormArray; } @Component({ @@ -53,14 +53,13 @@ interface SoftwareFormGroup{ styleUrls: ['./software-sidesheet.component.scss'], }) export class SoftwareSidesheetComponent implements OnInit, OnDestroy { - public cdrList: ColumnDependentReference[]; public softwareFormGroup = new FormGroup({ array: new UntypedFormArray([]) }); - public serviceItemGroup = new FormGroup({ serviceItemParameter: new FormArray([]) }); + public serviceItemGroup = new FormGroup({ serviceItemParameter: new UntypedFormArray([]) }); public isLoading = false; - public serviceItem: TypedEntity; + public serviceItem: TypedEntity | null; public get withProduct(): boolean { const value = this.productColumn?.GetValue(); @@ -74,7 +73,7 @@ export class SoftwareSidesheetComponent implements OnInit, OnDestroy { private subscriptions: Subscription[] = []; private entity: PortalRespApplication; private editableFields: string[]; - private busyService = new BusyService(); + public busyService = new BusyService(); constructor( @Inject(EUI_SIDESHEET_DATA) @@ -85,7 +84,7 @@ export class SoftwareSidesheetComponent implements OnInit, OnDestroy { private readonly changeDetector: ChangeDetectorRef, private readonly softwareService: SoftwareService, sidesheetRef: EuiSidesheetRef, - confirmation: ConfirmationService + confirmation: ConfirmationService, ) { this.subscriptions.push( sidesheetRef.closeClicked().subscribe(async () => { @@ -93,14 +92,14 @@ export class SoftwareSidesheetComponent implements OnInit, OnDestroy { return; } sidesheetRef.close(false); - }) + }), ); this.subscriptions.push( this.busyService.busyStateChanged.subscribe((state: boolean) => { this.isLoading = state; this.changeDetector.detectChanges(); - }) + }), ); } @@ -146,6 +145,9 @@ export class SoftwareSidesheetComponent implements OnInit, OnDestroy { * Saves the service item and reloads the form for further editing */ public async saveServiceItem(): Promise { + if (!this.serviceItem) { + return; + } const isBusy = this.busyService.beginBusy(); try { await this.serviceItem.GetEntity().Commit(); diff --git a/imxweb/projects/apc/src/lib/software/software.component.html b/imxweb/projects/apc/src/lib/software/software.component.html index 271eaba84..5282e0f0e 100644 --- a/imxweb/projects/apc/src/lib/software/software.component.html +++ b/imxweb/projects/apc/src/lib/software/software.component.html @@ -1,33 +1,30 @@ - - -
-
- {{ tablenameDisplay }} + +
+
+

{{ tablenameDisplay }}

-
- - - - - -
- {{ item?.GetEntity()?.GetDisplay() }} -
-
-
- -
- +
+ + + + + {{ entitySchema?.Columns?.[DisplayColumns.DISPLAY_PROPERTYNAME]?.Display }} + + +
{{ item.GetEntity().GetDisplay() }}
+ +
+ + + {{ entitySchema?.Columns?.Requestable?.Display }} + + +
{{ item.entity.columns.Requestable.GetDisplayValue() }}
+ +
+
+
diff --git a/imxweb/projects/apc/src/lib/software/software.component.scss b/imxweb/projects/apc/src/lib/software/software.component.scss index 55e1a13ed..03e367108 100644 --- a/imxweb/projects/apc/src/lib/software/software.component.scss +++ b/imxweb/projects/apc/src/lib/software/software.component.scss @@ -16,37 +16,6 @@ imx-data-table { color: $color-gray-30; } -.data-explorer-card-header { - background-color: $color-gray-0; - border-top-left-radius: 4px; - border-top-right-radius: 4px; - z-index: 100; - border: 1px solid rgba( $color-blue-60, 0.6); - margin-bottom: 20px; - - .data-explorer-card-header-bg { - border-top-left-radius: 4px; - border-top-right-radius: 4px; - background-color: $color-blue-20; - padding: 10px 24px; - display: flex; - align-items: center; - justify-content: flex-start; - height:45px; - - & > span { - font-size: 20px; - } - } -} - -.imx-page-card { - display: flex; - flex-direction: column; - flex: 1 1 auto; - overflow: hidden; -} - .imx-data-tree-container { overflow: hidden; background-color: $color-gray-0; @@ -65,13 +34,6 @@ imx-data-table { margin-top: 16px; } -.imx-card-content { - display: flex; - flex-direction: column; - flex: 1 1 auto; - overflow: hidden; -} - .data-explorer-bottom-button-row { display: flex; flex-direction: row; @@ -84,22 +46,11 @@ imx-data-table { } } -.imx-row-icon { - align-self: center; - margin-right: 15px; - text-align: right; - display: block; -} - .eui-dark-theme { :host { - .imx-data-tree-container, - .data-explorer-card-header-bg { + .imx-data-tree-container { background: $color-gray-70; } - .data-explorer-card-header .data-explorer-card-header-bg { - background: $color-blue-80; - } } } diff --git a/imxweb/projects/apc/src/lib/software/software.component.ts b/imxweb/projects/apc/src/lib/software/software.component.ts index cb659972d..bcd68499b 100644 --- a/imxweb/projects/apc/src/lib/software/software.component.ts +++ b/imxweb/projects/apc/src/lib/software/software.component.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -28,14 +28,25 @@ import { Component, Input, OnInit } from '@angular/core'; import { EuiSidesheetService } from '@elemental-ui/core'; import { TranslateService } from '@ngx-translate/core'; -import { CollectionLoadParameters, DataModel, DisplayColumns, EntitySchema, IClientProperty, TypedEntity } from 'imx-qbm-dbts'; +import { + CollectionLoadParameters, + DataModel, + DisplayColumns, + EntitySchema, + IClientProperty, + TypedEntity, + TypedEntityCollectionData, +} from '@imx-modules/imx-qbm-dbts'; import { BusyService, DataSourceToolbarSettings, + DataViewInitParameters, + DataViewSource, HelpContextualValues, LdsReplacePipe, MetadataService, SideNavigationComponent, + calculateSidesheetWidth, } from 'qbm'; import { SoftwareSidesheetComponent } from './software-sidesheet/software-sidesheet.component'; import { SoftwareService } from './software.service'; @@ -43,6 +54,7 @@ import { SoftwareService } from './software.service'; @Component({ templateUrl: './software.component.html', styleUrls: ['./software.component.scss'], + providers: [DataViewSource], }) export class SoftwareComponent implements OnInit, SideNavigationComponent { @Input() public contextId: HelpContextualValues; @@ -64,6 +76,7 @@ export class SoftwareComponent implements OnInit, SideNavigationComponent { private readonly sidesheet: EuiSidesheetService, private readonly ldsReplace: LdsReplacePipe, private readonly translate: TranslateService, + public dataSource: DataViewSource, ) {} public async ngOnInit(): Promise { @@ -76,35 +89,31 @@ export class SoftwareComponent implements OnInit, SideNavigationComponent { isBusy.endBusy(); } - this.tablenameDisplay = this.metadata.tables['Application'].Display; + this.tablenameDisplay = this.metadata.tables?.['Application']?.Display ?? ''; this.displayColumns = [this.entitySchema.Columns[DisplayColumns.DISPLAY_PROPERTYNAME]]; if (this.entitySchema.Columns.Requestable) { this.displayColumns.splice(1, 0, this.entitySchema.Columns.Requestable); } - this.navigate(); - } - - public async onNavigationStateChanged(newState?: CollectionLoadParameters): Promise { - if (newState) { - this.navigationState = newState; - } - await this.navigate(); - } - - public async onSearch(keywords: string): Promise { - this.navigationState.StartIndex = 0; - this.navigationState.search = keywords; - await this.navigate(); + const dataViewInitParameters: DataViewInitParameters = { + execute: (params: CollectionLoadParameters): Promise> => this.resourceProvider.get(params), + schema: this.entitySchema, + columnsToDisplay: this.displayColumns, + dataModel: this.dataModel, + highlightEntity: (entity: TypedEntity) => { + this.showDetails(entity); + }, + }; + this.dataSource.init(dataViewInitParameters); } public async showDetails(item: TypedEntity): Promise { const sidesheetRef = this.sidesheet.open(SoftwareSidesheetComponent, { title: this.ldsReplace.transform(await this.translate.get('#LDS#Heading Edit {0}').toPromise(), this.tablenameDisplay), - headerColour: 'blue', + subTitle: item.GetEntity().GetDisplay(), padding: '0px', - width: 'max(600px, 60%)', + width: calculateSidesheetWidth(), disableClose: true, testId: 'software-sidesheet', data: { @@ -114,24 +123,8 @@ export class SoftwareComponent implements OnInit, SideNavigationComponent { sidesheetRef.afterClosed().subscribe(async (result) => { if (result) { - await this.navigate(); + await this.dataSource.updateState(); } }); } - - private async navigate(): Promise { - const isBusy = this.busyService.beginBusy(); - try { - this.dstSettings = { - dataSource: await this.resourceProvider.get(this.navigationState), - entitySchema: this.entitySchema, - navigationState: this.navigationState, - displayedColumns: this.displayColumns, - filters: this.dataModel.Filters, - dataModel: this.dataModel, - }; - } finally { - isBusy.endBusy(); - } - } } diff --git a/imxweb/projects/apc/src/lib/software/software.module.ts b/imxweb/projects/apc/src/lib/software/software.module.ts index 081d210e5..08435a657 100644 --- a/imxweb/projects/apc/src/lib/software/software.module.ts +++ b/imxweb/projects/apc/src/lib/software/software.module.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -24,21 +24,27 @@ * */ -import { NgModule } from '@angular/core'; import { CommonModule } from '@angular/common'; -import { SoftwareComponent } from './software.component'; -import { SoftwareSidesheetComponent } from './software-sidesheet/software-sidesheet.component'; -import { BusyIndicatorModule, CdrModule, DataSourceToolbarModule, DataTableModule, HelpContextualModule, SelectedElementsModule } from 'qbm'; -import { TranslateModule } from '@ngx-translate/core'; +import { NgModule } from '@angular/core'; import { ReactiveFormsModule } from '@angular/forms'; -import { MatCardModule } from '@angular/material/card'; import { MatButtonModule } from '@angular/material/button'; -import { EuiCoreModule, EuiMaterialModule } from '@elemental-ui/core'; +import { MatCardModule } from '@angular/material/card'; import { MatTabsModule } from '@angular/material/tabs'; -import { SoftwareMembershipsComponent } from './software-sidesheet/software-memberships/software-memberships.component'; +import { EuiCoreModule, EuiMaterialModule } from '@elemental-ui/core'; +import { TranslateModule } from '@ngx-translate/core'; +import { + BusyIndicatorModule, + CdrModule, + DataSourceToolbarModule, + DataTableModule, + DataViewModule, + HelpContextualModule, + SelectedElementsModule, +} from 'qbm'; import { ServiceItemsEditFormModule } from 'qer'; - - +import { SoftwareMembershipsComponent } from './software-sidesheet/software-memberships/software-memberships.component'; +import { SoftwareSidesheetComponent } from './software-sidesheet/software-sidesheet.component'; +import { SoftwareComponent } from './software.component'; @NgModule({ declarations: [SoftwareComponent, SoftwareSidesheetComponent, SoftwareMembershipsComponent], @@ -57,7 +63,8 @@ import { ServiceItemsEditFormModule } from 'qer'; BusyIndicatorModule, SelectedElementsModule, ServiceItemsEditFormModule, - HelpContextualModule + HelpContextualModule, + DataViewModule, ], }) export class SoftwareModule {} diff --git a/imxweb/projects/apc/src/lib/software/software.service.ts b/imxweb/projects/apc/src/lib/software/software.service.ts index 2c187fec1..8bba419d6 100644 --- a/imxweb/projects/apc/src/lib/software/software.service.ts +++ b/imxweb/projects/apc/src/lib/software/software.service.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -26,8 +26,12 @@ import { Injectable } from '@angular/core'; -import { PortalResourcesApplicationsMembership, PortalRespApplication } from 'imx-api-apc'; -import { ProjectConfig, QerProjectConfig } from 'imx-api-qer'; +import { + PortalResourcesApplicationServiceitemWrapper, + PortalResourcesApplicationsMembership, + PortalRespApplication, +} from '@imx-modules/imx-api-apc'; +import { ProjectConfig, QerProjectConfig } from '@imx-modules/imx-api-qer'; import { CollectionLoadParameters, CompareOperator, @@ -40,7 +44,7 @@ import { TypedEntity, TypedEntityBuilder, TypedEntityCollectionData, -} from 'imx-qbm-dbts'; +} from '@imx-modules/imx-qbm-dbts'; import { ProjectConfigurationService, QerApiService } from 'qer'; import { ApcApiService } from '../apc-api-client.service'; import { ResourceInfo } from '../app-info.model'; @@ -56,26 +60,31 @@ export class SoftwareService { constructor( protected readonly project: ProjectConfigurationService, private readonly api: ApcApiService, - private readonly qerClient: QerApiService - ) {} - - private appInfo = { - table: 'Application', - caption: '#LDS#Software', - accProduct: this.api.typedClient.PortalResourcesApplicationServiceitem, - resp: { - type: PortalRespApplication, - get: async (parameter: any) => this.api.client.portal_resp_application_get(parameter), - schema: this.api.typedClient.PortalRespApplication.GetSchema(), - dataModel: async (filter?: FilterData[]) => this.api.client.portal_resp_application_datamodel_get({ filter }), - interactive: this.api.typedClient.PortalRespApplicationInteractive, - }, + private readonly qerClient: QerApiService, + ) { + this.appInfo = { + table: 'Application', + caption: '#LDS#Software', + accProduct: this.api.typedClient.PortalResourcesApplicationServiceitem, + resp: { + type: PortalRespApplication, + get: async (parameter: any) => this.api.client.portal_resp_application_get(parameter), + schema: this.api.typedClient.PortalRespApplication.GetSchema(), + dataModel: async (filter?: FilterData[]) => this.api.client.portal_resp_application_datamodel_get({ filter }), + interactive: this.api.typedClient.PortalRespApplicationInteractive, + }, + }; + } + + private appInfo: { + table: string; + caption: string; + accProduct: PortalResourcesApplicationServiceitemWrapper; + resp: any; }; public async get(parameter: CollectionLoadParameters): Promise> { const conf = this.appInfo.resp; - - if (!conf) return null; const builder = new TypedEntityBuilder(conf.type); const data = await conf.get(parameter); @@ -102,11 +111,11 @@ export class SoftwareService { this.config = await this.project.getConfig(); } - const list = primary ? this.config.OwnershipConfig.PrimaryFields : this.config.OwnershipConfig.EditableFields; - return list[objectType].filter((name) => entity.GetSchema().Columns[name]); + const list = primary ? this.config?.OwnershipConfig?.PrimaryFields : this.config?.OwnershipConfig?.EditableFields; + return list && list[objectType] ? list[objectType].filter((name) => entity.GetSchema().Columns[name]) : []; } - public async getServiceItem(uidAccProduct: string): Promise { + public async getServiceItem(uidAccProduct: string): Promise { const filter: FilterData[] = [ { Type: FilterType.Compare, @@ -118,12 +127,12 @@ export class SoftwareService { const item = await this.appInfo.accProduct.Get({ filter }); - return item.Data.length > 0 ? item.Data[0] : undefined; + return item.Data.length > 0 ? item.Data[0] : null; } public async getMemberShips( uidApplication: string, - parameter: CollectionLoadParameters + parameter: CollectionLoadParameters, ): Promise> { return this.api.typedClient.PortalResourcesApplicationsMembership.Get(uidApplication, parameter); } @@ -131,8 +140,9 @@ export class SoftwareService { public async deleteGroupMembers(uidSoftware: string, uidPersonList: string[]): Promise { return await Promise.all( uidPersonList.map(async (item) => { - (await this.api.typedClient.PortalResourcesApplicationsMembership.Delete(uidSoftware,item)).Data[0] - })); + (await this.api.typedClient.PortalResourcesApplicationsMembership.Delete(uidSoftware, item)).Data[0]; + }), + ); } public async unsubscribeMembership(item: TypedEntity): Promise { diff --git a/imxweb/projects/apc/src/public_api.ts b/imxweb/projects/apc/src/public_api.ts index 43d0ad019..5a8d374b3 100644 --- a/imxweb/projects/apc/src/public_api.ts +++ b/imxweb/projects/apc/src/public_api.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR diff --git a/imxweb/projects/apc/src/test.ts b/imxweb/projects/apc/src/test.ts index f7ac7d548..159c87d7d 100644 --- a/imxweb/projects/apc/src/test.ts +++ b/imxweb/projects/apc/src/test.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -26,24 +26,14 @@ // This file is required by karma.conf.js and loads recursively all the .spec and framework files -import 'core-js/es7/reflect'; -import 'zone.js/dist/zone'; -import 'zone.js/dist/zone-testing'; +// Zone must be imported first. Be careful with prettier import organizing +import 'zone.js'; +import 'zone.js/testing'; + import { getTestBed } from '@angular/core/testing'; -import { - BrowserDynamicTestingModule, - platformBrowserDynamicTesting -} from '@angular/platform-browser-dynamic/testing'; +import { BrowserDynamicTestingModule, platformBrowserDynamicTesting } from '@angular/platform-browser-dynamic/testing'; +import 'core-js/es/reflect'; import { TestHelperModule } from 'qbm'; -declare const require: any; - // First, initialize the Angular testing environment. -getTestBed().initTestEnvironment( - [BrowserDynamicTestingModule, TestHelperModule], - platformBrowserDynamicTesting() -); -// Then we find all the tests. -const context = require.context('./', true, /\.spec\.ts$/); -// And load the modules. -context.keys().map(context); +getTestBed().initTestEnvironment([BrowserDynamicTestingModule, TestHelperModule], platformBrowserDynamicTesting()); diff --git a/imxweb/projects/apc/tsconfig.lib.json b/imxweb/projects/apc/tsconfig.lib.json index 6bc419f84..534c734a0 100644 --- a/imxweb/projects/apc/tsconfig.lib.json +++ b/imxweb/projects/apc/tsconfig.lib.json @@ -1,16 +1,17 @@ /* To learn more about this file see: https://angular.io/config/tsconfig. */ { "extends": "../../tsconfig.json", + "angularCompilerOptions": { + "strictTemplates": true + }, "compilerOptions": { "outDir": "../../out-tsc/lib", + "strictNullChecks": true, "declaration": true, "declarationMap": true, "sourceMap": true, "inlineSources": true, "types": [] }, - "exclude": [ - "src/test.ts", - "**/*.spec.ts" - ] + "exclude": ["src/test.ts", "**/*.spec.ts"] } diff --git a/imxweb/projects/apc/tsconfig.lib.prod.json b/imxweb/projects/apc/tsconfig.lib.prod.json index 61c7592e7..fb40dbbb0 100644 --- a/imxweb/projects/apc/tsconfig.lib.prod.json +++ b/imxweb/projects/apc/tsconfig.lib.prod.json @@ -3,8 +3,5 @@ "extends": "./tsconfig.lib.json", "compilerOptions": { "declarationMap": false - }, - "angularCompilerOptions": { - "enableIvy": true } } diff --git a/imxweb/projects/apc/tsconfig.spec.json b/imxweb/projects/apc/tsconfig.spec.json index 16da33db0..6bd74e1f7 100644 --- a/imxweb/projects/apc/tsconfig.spec.json +++ b/imxweb/projects/apc/tsconfig.spec.json @@ -1,17 +1,10 @@ { "extends": "../../tsconfig.json", "compilerOptions": { + "strictNullChecks": false, "outDir": "../../out-tsc/spec", - "types": [ - "jasmine", - "node" - ] + "types": ["jasmine", "node"] }, - "files": [ - "src/test.ts" - ], - "include": [ - "**/*.spec.ts", - "**/*.d.ts" - ] + "files": ["src/test.ts"], + "include": ["**/*.spec.ts", "**/*.d.ts"] } diff --git a/imxweb/projects/apc/tslint.json b/imxweb/projects/apc/tslint.json deleted file mode 100644 index 8bab15f53..000000000 --- a/imxweb/projects/apc/tslint.json +++ /dev/null @@ -1,17 +0,0 @@ -{ - "extends": "../../tslint.json", - "rules": { - "directive-selector": [ - true, - "attribute", - "imx", - "camelCase" - ], - "component-selector": [ - true, - "element", - "imx", - "kebab-case" - ] - } -} diff --git a/imxweb/projects/att/.compodocrc.json b/imxweb/projects/att/.compodocrc.json index 14353b30b..fb57684b2 100644 --- a/imxweb/projects/att/.compodocrc.json +++ b/imxweb/projects/att/.compodocrc.json @@ -1,6 +1,6 @@ { "name": "IMX Web - ATT Library", - "output": "../../documentation/v92/att", + "output": "../../documentation/v93/att", "theme": "material", "assetsFolder": "../../compodoc/assets", "customLogo": "../../compodoc/assets/images/oneidentity-logo.png", diff --git a/imxweb/projects/att/.eslintrc.json b/imxweb/projects/att/.eslintrc.json new file mode 100644 index 000000000..105acb604 --- /dev/null +++ b/imxweb/projects/att/.eslintrc.json @@ -0,0 +1,35 @@ +{ + "extends": "../../.eslintrc.json", + "ignorePatterns": ["!**/*", "**/*.spec.ts"], + "overrides": [ + { + "files": ["*.ts"], + "parserOptions": { + "project": ["imxweb/projects/att/tsconfig.lib.json", "imxweb/projects/att/tsconfig.spec.json"], + "createDefaultProgram": true + }, + "rules": { + "@angular-eslint/directive-selector": [ + "error", + { + "type": "attribute", + "prefix": "imx", + "style": "camelCase" + } + ], + "@angular-eslint/component-selector": [ + "error", + { + "type": "element", + "prefix": "imx", + "style": "kebab-case" + } + ] + } + }, + { + "files": ["*.html"], + "rules": {} + } + ] +} diff --git a/imxweb/projects/att/imx-plugin-config.json b/imxweb/projects/att/imx-plugin-config.json index 933ae1799..cdad7725e 100644 --- a/imxweb/projects/att/imx-plugin-config.json +++ b/imxweb/projects/att/imx-plugin-config.json @@ -1,14 +1,14 @@ { - "qer-app-portal": [ - { - "Container": "att", - "Name": "AttConfigModule" - } - ], - "qer-app-pwdportal": [ - { - "Container": "att", - "Name": "NewUserModule" - } - ] -} \ No newline at end of file + "qer-app-portal": [ + { + "Container": "att", + "Name": "AttConfigModule" + } + ], + "qer-app-pwdportal": [ + { + "Container": "att", + "Name": "NewUserModule" + } + ] +} diff --git a/imxweb/projects/att/karma.conf.js b/imxweb/projects/att/karma.conf.js index d7a9db062..3e53a3ac8 100644 --- a/imxweb/projects/att/karma.conf.js +++ b/imxweb/projects/att/karma.conf.js @@ -15,7 +15,7 @@ module.exports = function (config) { require('karma-junit-reporter'), ], client: { - clearContext: false // leave Jasmine Spec Runner output visible in browser + clearContext: false, // leave Jasmine Spec Runner output visible in browser }, coverageIstanbulReporter: { dir: require('path').join(__dirname, 'results'), @@ -23,14 +23,14 @@ module.exports = function (config) { fixWebpackSourcePaths: true, 'report-config': { html: { - subdir: 'coverage-html' + subdir: 'coverage-html', }, }, thresholds: { statements: 0, branches: 0, functions: 0, - lines: 0 + lines: 0, }, }, junitReporter: { @@ -40,13 +40,14 @@ module.exports = function (config) { port: 9876, captureTimeout: 210000, browserDisconnectTolerance: 3, - browserDisconnectTimeout : 210000, - browserNoActivityTimeout : 210000, + browserDisconnectTimeout: 210000, + browserNoActivityTimeout: 210000, colors: true, logLevel: config.LOG_INFO, autoWatch: true, browsers: ['Chrome'], singleRun: false, - restartOnFileChange: true + failOnEmptyTestSuite: false, + restartOnFileChange: true, }); }; diff --git a/imxweb/projects/o3t/ng-package.dynamic.json b/imxweb/projects/att/ng-package.dynamic-pwd.json similarity index 84% rename from imxweb/projects/o3t/ng-package.dynamic.json rename to imxweb/projects/att/ng-package.dynamic-pwd.json index 13fdffef2..3599d8f82 100644 --- a/imxweb/projects/o3t/ng-package.dynamic.json +++ b/imxweb/projects/att/ng-package.dynamic-pwd.json @@ -16,12 +16,11 @@ "@elemental-ui/core", "@ngx-translate/core", "@ngx-translate/http-loader", - "applicationinsights-js", "billboard.js" ], - "dest": "../../html/o3t", + "dest": "../../html/qer-app-pwdportal/att", "lib": { "entryFile": "src/public_api.ts", - "styleIncludePaths": ["../../shared/assets"] + "styleIncludePaths": ["../../shared/scss"] } } diff --git a/imxweb/projects/att/ng-package.dynamic.json b/imxweb/projects/att/ng-package.dynamic.json index addb5f02e..4d95ec994 100644 --- a/imxweb/projects/att/ng-package.dynamic.json +++ b/imxweb/projects/att/ng-package.dynamic.json @@ -16,12 +16,11 @@ "@elemental-ui/core", "@ngx-translate/core", "@ngx-translate/http-loader", - "applicationinsights-js", "billboard.js" ], - "dest": "../../html/att", + "dest": "../../html/qer-app-portal/att", "lib": { "entryFile": "src/public_api.ts", - "styleIncludePaths": ["../../shared/assets"] + "styleIncludePaths": ["../../shared/scss"] } } diff --git a/imxweb/projects/att/ng-package.json b/imxweb/projects/att/ng-package.json index fbcdd099d..afa86ad20 100644 --- a/imxweb/projects/att/ng-package.json +++ b/imxweb/projects/att/ng-package.json @@ -4,6 +4,6 @@ "allowedNonPeerDependencies": ["imx-api-att"], "lib": { "entryFile": "src/public_api.ts", - "styleIncludePaths": ["../../shared/assets"] + "styleIncludePaths": ["../../shared/scss"] } } diff --git a/imxweb/projects/att/package.json b/imxweb/projects/att/package.json index b6ccecc96..8194febc6 100644 --- a/imxweb/projects/att/package.json +++ b/imxweb/projects/att/package.json @@ -1,6 +1,6 @@ { "name": "att", - "version": "9.2.1", + "version": "9.3.0", "private": true, "bundledDependencies": [ "imx-api-att" diff --git a/imxweb/projects/att/project.json b/imxweb/projects/att/project.json new file mode 100644 index 000000000..032a8a2fb --- /dev/null +++ b/imxweb/projects/att/project.json @@ -0,0 +1,78 @@ +{ + "$schema": "../../node_modules/nx/schemas/project-schema.json", + "name": "att", + "sourceRoot": "projects/att/src", + "implicitDependencies": [ + "qer" + ], + "projectType": "library", + "prefix": "imx", + "generators": { + "@schematics/angular:component": { + "style": "scss" + } + }, + "targets": { + "build": { + "executor": "@angular-devkit/build-angular:ng-packagr", + "options": { + "tsConfig": "projects/att/tsconfig.lib.json", + "project": "projects/att/ng-package.json" + }, + "configurations": { + "production": { + "tsConfig": "projects/att/tsconfig.lib.prod.json" + }, + "development": { + "tsConfig": "projects/att/tsconfig.lib.json" + }, + "dynamic": { + "project": "projects/att/ng-package.dynamic.json" + }, + "dynamic-pwd": { + "project": "projects/att/ng-package.dynamic-pwd.json" + }, + "remote-dev": { + "tsConfig": "projects/att/tsconfig.lib.json" + }, + "remote-qs": { + "tsConfig": "projects/att/tsconfig.lib.json" + } + }, + "outputs": [ + "{workspaceRoot}/dist/att" + ] + }, + "test": { + "executor": "@angular-devkit/build-angular:karma", + "options": { + "main": "projects/att/src/test.ts", + "tsConfig": "projects/att/tsconfig.spec.json", + "karmaConfig": "projects/att/karma.conf.js", + "stylePreprocessorOptions": { + "includePaths": [ + "./shared/assets", + "./shared/scss", + "./node_modules", + "./node_modules/@elemental-ui/cadence-icon", + "./node_modules/@elemental-ui/core" + ] + } + } + }, + "lint": { + "executor": "@angular-devkit/build-angular:tslint", + "options": { + "tsConfig": [ + "projects/att/tsconfig.lib.json", + "projects/att/tsconfig.spec.json" + ], + "exclude": [ + "**/node_modules/**", + "**/*.spec.ts", + "**/*.json" + ] + } + } + } +} diff --git a/imxweb/projects/att/src/default-mocks.spec.ts b/imxweb/projects/att/src/default-mocks.spec.ts index 344736214..3c5dc3413 100644 --- a/imxweb/projects/att/src/default-mocks.spec.ts +++ b/imxweb/projects/att/src/default-mocks.spec.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -28,7 +28,7 @@ import { of, Subject } from 'rxjs'; import { ngMocks } from 'ng-mocks'; import { EuiSidesheetService } from '@elemental-ui/core'; import { TranslateService } from '@ngx-translate/core'; -import { ISessionState,AuthenticationService,RouteGuardService } from 'qbm'; +import { ISessionState, AuthenticationService, RouteGuardService } from 'qbm'; export class AttDefaultMocks { public static readonly afterClosedSubject = new Subject(); diff --git a/imxweb/projects/att/src/lib/admin/permissions-helper.ts b/imxweb/projects/att/src/lib/admin/permissions-helper.ts index 098826dbb..c30662f52 100644 --- a/imxweb/projects/att/src/lib/admin/permissions-helper.ts +++ b/imxweb/projects/att/src/lib/admin/permissions-helper.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -25,13 +25,13 @@ */ export function canSeeAttestationPolicies(features: string[]): boolean { - return features.find(item => item === 'Portal_UI_PolicyAdmin' || - item === 'Portal_UI_PolicyStatistics' || - item === 'Portal_UI_PolicyOwner') != null; + return ( + features.find( + (item) => item === 'Portal_UI_PolicyAdmin' || item === 'Portal_UI_PolicyStatistics' || item === 'Portal_UI_PolicyOwner', + ) != null + ); } export function isAttestationAdmin(features: string[]): boolean { - return features.find(item => item === 'Portal_UI_PolicyAdmin') != null; + return features.find((item) => item === 'Portal_UI_PolicyAdmin') != null; } - - diff --git a/imxweb/projects/att/src/lib/admin/permissions.service.ts b/imxweb/projects/att/src/lib/admin/permissions.service.ts index 8f75395d5..a483f7288 100644 --- a/imxweb/projects/att/src/lib/admin/permissions.service.ts +++ b/imxweb/projects/att/src/lib/admin/permissions.service.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -30,16 +30,16 @@ import { UserModelService } from 'qer'; import { canSeeAttestationPolicies, isAttestationAdmin } from './permissions-helper'; @Injectable({ - providedIn: 'root' + providedIn: 'root', }) export class PermissionsService { - constructor(private readonly userService: UserModelService) { } + constructor(private readonly userService: UserModelService) {} public async canSeeAttestationPolicies(): Promise { - return canSeeAttestationPolicies((await this.userService.getFeatures()).Features); + return canSeeAttestationPolicies((await this.userService.getFeatures()).Features || []); } public async isAttestationAdmin(): Promise { - return isAttestationAdmin((await this.userService.getFeatures()).Features); + return isAttestationAdmin((await this.userService.getFeatures()).Features || []); } } diff --git a/imxweb/projects/att/src/lib/api.service.ts b/imxweb/projects/att/src/lib/api.service.ts index 181d7de82..50630024a 100644 --- a/imxweb/projects/att/src/lib/api.service.ts +++ b/imxweb/projects/att/src/lib/api.service.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -26,12 +26,12 @@ import { Injectable } from '@angular/core'; -import { V2Client, TypedClient } from 'imx-api-att'; -import { ApiClient } from 'imx-qbm-dbts'; +import { V2Client, TypedClient } from '@imx-modules/imx-api-att'; +import { ApiClient } from '@imx-modules/imx-qbm-dbts'; import { AppConfigService, ClassloggerService, ImxTranslationProviderService } from 'qbm'; @Injectable({ - providedIn: 'root' + providedIn: 'root', }) export class ApiService { private tc: TypedClient; @@ -51,7 +51,8 @@ export class ApiService { constructor( private readonly config: AppConfigService, private readonly logger: ClassloggerService, - private readonly translationProvider: ImxTranslationProviderService) { + private readonly translationProvider: ImxTranslationProviderService, + ) { try { this.logger.debug(this, 'Initializing API service'); diff --git a/imxweb/projects/att/src/lib/att-config.module.ts b/imxweb/projects/att/src/lib/att-config.module.ts index 40e8b54e1..2d5ed5ef5 100644 --- a/imxweb/projects/att/src/lib/att-config.module.ts +++ b/imxweb/projects/att/src/lib/att-config.module.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -126,9 +126,7 @@ const routes: Routes = [ ]; @NgModule({ - declarations: [ - DashboardPluginComponent - ], + declarations: [DashboardPluginComponent], imports: [ CommonModule, TilesModule, @@ -139,11 +137,13 @@ const routes: Routes = [ MatListModule, TranslateModule, EuiCoreModule, - ] + ], }) export class AttConfigModule { constructor( - private readonly initializer: InitService, private readonly logger: ClassloggerService) { + private readonly initializer: InitService, + private readonly logger: ClassloggerService, + ) { this.logger.info(this, '🔥 ATT loaded'); this.initializer.onInit(routes); this.logger.info(this, '▶️ ATT initialized'); diff --git a/imxweb/projects/att/src/lib/attestation-action/attestation-action.component.html b/imxweb/projects/att/src/lib/attestation-action/attestation-action.component.html index 97c031299..de2875fb3 100644 --- a/imxweb/projects/att/src/lib/attestation-action/attestation-action.component.html +++ b/imxweb/projects/att/src/lib/attestation-action/attestation-action.component.html @@ -1,5 +1,5 @@ -
- +
+ {{ data.description | translate }} @@ -32,7 +32,7 @@ (controlCreated)="formGroup.addControl('attestation-parameters', $event)" > - +
-
+
@@ -20,18 +23,38 @@
- + +
+ + +
+ + {{ '#LDS#Related objects' | translate }} + + + {{ relatedOption.Display }} + + + + + +
+
+
- - @@ -58,7 +98,7 @@ - - -
diff --git a/imxweb/projects/att/src/lib/attestation-history/attestation-history-wrapper.component.scss b/imxweb/projects/att/src/lib/attestation-history/attestation-history-wrapper.component.scss index f71091d5f..4318c9d88 100644 --- a/imxweb/projects/att/src/lib/attestation-history/attestation-history-wrapper.component.scss +++ b/imxweb/projects/att/src/lib/attestation-history/attestation-history-wrapper.component.scss @@ -1,4 +1,4 @@ -@import '../../../../../shared/scss/common-table.scss'; +@import 'base/mixins'; :host { display: flex; @@ -7,18 +7,10 @@ height: inherit; } -.imx-history-card { - @include imx-flex-fill-control-hidden-overflow(); - - imx-attestation-history { - flex: 1 1 auto; - } -} - -.mat-stroked-button { - @include imx-icon-for-image-button(); +imx-attestation-history { + height: 100%; } -.imx-button-bar { - @include imx-button-bar(); +.mat-mdc-outlined-button { + @include image-button-icon(); } diff --git a/imxweb/projects/att/src/lib/attestation-history/attestation-history-wrapper.component.ts b/imxweb/projects/att/src/lib/attestation-history/attestation-history-wrapper.component.ts index 1d1a9077b..680e5d4c4 100644 --- a/imxweb/projects/att/src/lib/attestation-history/attestation-history-wrapper.component.ts +++ b/imxweb/projects/att/src/lib/attestation-history/attestation-history-wrapper.component.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -24,27 +24,32 @@ * */ -import { Component, OnDestroy } from '@angular/core'; +import { AfterViewInit, ChangeDetectorRef, Component, OnDestroy, ViewChild } from '@angular/core'; import { Subscription } from 'rxjs'; -import { AuthenticationService } from 'qbm'; +import { TypedEntity } from '@imx-modules/imx-qbm-dbts'; +import { AuthenticationService, DataViewSource } from 'qbm'; import { AttestationHistoryActionService } from './attestation-history-action.service'; import { AttestationHistoryCase } from './attestation-history-case'; +import { AttestationHistoryComponent } from './attestation-history.component'; @Component({ selector: 'imx-attestation-history-wrapper', templateUrl: './attestation-history-wrapper.component.html', - styleUrls: ['./attestation-history-wrapper.component.scss'] + styleUrls: ['./attestation-history-wrapper.component.scss'], }) -export class AttestationHistoryWrapperComponent implements OnDestroy { +export class AttestationHistoryWrapperComponent implements OnDestroy, AfterViewInit { + @ViewChild('attestationHistoryComponent', { static: false }) public attestationHistoryComponent: AttestationHistoryComponent; + public dataSource: DataViewSource; public get canPerformActions(): boolean { - return this.selectedCases.length > 0 && ( - this.canRecallDecision - || this.canWithdrawDelegation - ); + return this.selectedCases.length > 0 && (this.canRecallDecision || this.canWithdrawDelegation); + } + public get canWithdrawDelegation(): boolean { + return this.selectedCases.every((item) => item.canWithdrawDelegation(this.userUid)); + } + public get canRecallDecision(): boolean { + return this.selectedCases.every((item) => item.canRecallDecision); } - public get canWithdrawDelegation(): boolean { return this.selectedCases.every(item => item.canWithdrawDelegation(this.userUid)); } - public get canRecallDecision(): boolean { return this.selectedCases.every(item => item.canRecallDecision); } public selectedCases: AttestationHistoryCase[] = []; @@ -52,15 +57,24 @@ export class AttestationHistoryWrapperComponent implements OnDestroy { private readonly subscriptions: Subscription[] = []; - constructor(public readonly attestationAction: AttestationHistoryActionService, authentication: AuthenticationService) { - this.subscriptions.push(authentication.onSessionResponse?.subscribe(sessionState => this.userUid = sessionState?.UserUid)); + constructor( + public readonly attestationAction: AttestationHistoryActionService, + authentication: AuthenticationService, + public changeDetectionRef: ChangeDetectorRef, + ) { + this.subscriptions.push(authentication.onSessionResponse?.subscribe((sessionState) => (this.userUid = sessionState?.UserUid || ''))); } public ngOnDestroy(): void { - this.subscriptions.forEach(s => s.unsubscribe()); + this.subscriptions.forEach((s) => s.unsubscribe()); + } + + ngAfterViewInit(): void { + this.dataSource = this.attestationHistoryComponent?.dataSource; + this.changeDetectionRef.detectChanges(); } - public onSelectionChanged(items: AttestationHistoryCase[]): void { - this.selectedCases = items; + public onSelectionChanged(items: TypedEntity[]): void { + this.selectedCases = items as AttestationHistoryCase[]; } } diff --git a/imxweb/projects/att/src/lib/attestation-history/attestation-history.component.html b/imxweb/projects/att/src/lib/attestation-history/attestation-history.component.html index 41ddb23d6..02b42ecaf 100644 --- a/imxweb/projects/att/src/lib/attestation-history/attestation-history.component.html +++ b/imxweb/projects/att/src/lib/attestation-history/attestation-history.component.html @@ -1,63 +1,58 @@ - -
- -
-
- - - - - - - - - -
-
- - {{ item.AttestationState.Column.GetDisplayValue() }} +
+

+ {{ title | translate }} + +

+ +
+ + + + {{ entitySchema?.Columns?.UiText?.Display }} + + + + + + + +
+
+ + {{ item.AttestationState.Column.GetDisplayValue() }} +
+
+ + {{ item.AttestationState.Column.GetDisplayValue() }} +
+
+ + {{ item.AttestationState.Column.GetDisplayValue() }} +
+
+ + {{ item.RiskIndex.GetMetadata().GetDisplay() + ': ' + item.RiskIndex.Column.GetDisplayValue() }} +
-
- - {{ item.AttestationState.Column.GetDisplayValue() }} -
-
- - {{ item.AttestationState.Column.GetDisplayValue() }} -
-
- - {{ item.RiskIndex.GetMetadata().GetDisplay() + ': ' + item.RiskIndex.Column.GetDisplayValue() }} -
-
- - - - - - - - - + + + + + + + + + + + diff --git a/imxweb/projects/att/src/lib/attestation-history/attestation-history.component.scss b/imxweb/projects/att/src/lib/attestation-history/attestation-history.component.scss index 086102e88..335e190a4 100644 --- a/imxweb/projects/att/src/lib/attestation-history/attestation-history.component.scss +++ b/imxweb/projects/att/src/lib/attestation-history/attestation-history.component.scss @@ -1,98 +1,20 @@ -@import '../../../../../shared/scss/common-table.scss'; -@import '@elemental-ui/core/src/styles/_eui_palette.scss'; +@import 'base/mixins'; :host { - overflow: hidden; - display: flex; - flex-direction: column; -} - -.imx-icons-container { - padding-right: 15px; - .table-icon { - display: flex; - align-items: center; - color: $color-gray-60; - font-weight: 600; - height: 14px; - &--warning { - .eui-icon { - color: $color-orange-60; - } - } - &--new { - .eui-icon { - color: $color-green-60; - } - } - &--alert { - .eui-icon, - span { - color: $color-red-60; - } - } - &--primary { - .eui-icon, - span { - color: $color-blue-60; - } - } - &:not(:first-of-type) { - margin-left: 8px; - border-left: 1px solid $color-gray-20; - padding-left: 8px; - } - .mat-icon, - .eui-icon { - padding-right: 6px; - } - } + @include flex-column-container($overflow: hidden); } imx-data-table { flex-grow: 2; } +.imx-history-card { + @include flex-column-container-fill(); +} .imx-display-column { display: flex; :last-child { flex-grow: 1; - } -} - -.imx-button-column { - @include imx-button-column-right(); -} - -.eui-dark-theme, -.eui-contrast-theme { - :host { - .imx-icons-container { - .table-icon { - color: $color-gray-10; - &--warning { - .eui-icon { - color: $color-orange-40; - } - } - &--new { - .mat-icon { - color: $color-green-40; - } - } - &--alert { - .eui-icon, - span { - color: $color-red-40; - } - } - &--primary { - .eui-icon, - span { - color: $color-blue-60; - } - } - } - } + display:block; } } diff --git a/imxweb/projects/att/src/lib/attestation-history/attestation-history.component.ts b/imxweb/projects/att/src/lib/attestation-history/attestation-history.component.ts index 24f7ddb05..2734c311d 100644 --- a/imxweb/projects/att/src/lib/attestation-history/attestation-history.component.ts +++ b/imxweb/projects/att/src/lib/attestation-history/attestation-history.component.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -24,80 +24,69 @@ * */ -import { OverlayRef } from '@angular/cdk/overlay'; -import { Component, EventEmitter, Input, OnDestroy, OnInit, Output, ViewChild } from '@angular/core'; +import { Component, EventEmitter, Input, OnDestroy, OnInit, Output } from '@angular/core'; import { EuiLoadingService, EuiSidesheetService } from '@elemental-ui/core'; -import { TranslateService } from '@ngx-translate/core'; -import { Subscription } from 'rxjs'; +import { ViewConfigData } from '@imx-modules/imx-api-qer'; import { + CollectionLoadParameters, CompareOperator, + DataModel, + DbObjectKey, DisplayColumns, EntitySchema, + FilterData, FilterType, TypedEntity, - FilterData, - DataModel, + TypedEntityCollectionData, ValType, - DbObjectKey, -} from 'imx-qbm-dbts'; +} from '@imx-modules/imx-qbm-dbts'; +import { TranslateService } from '@ngx-translate/core'; import { + BusyService, + calculateSidesheetWidth, + ClientPropertyForTableColumns, DataSourceItemStatus, - DataSourceToolbarFilter, - DataSourceToolbarGroupData, - DataSourceToolbarSettings, - DataTableComponent, + DataSourceToolbarViewConfig, DataTableGroupedData, - SettingsService, + DataViewInitParameters, + DataViewSource, + setFilterDisplay, UserMessageService, - ClientPropertyForTableColumns, - DataSourceToolbarViewConfig, - BusyService, } from 'qbm'; -import { AttestationHistoryFilterComponent } from './attestation-history-filter/attestation-history-filter.component'; -import { AttestationHistoryCase } from './attestation-history-case'; -import { AttestationCaseLoadParameters } from './attestation-case-load-parameters.interface'; -import { AttestationHistoryService } from './attestation-history.service'; -import { AttestationHistoryDetailsComponent } from './attestation-history-details/attestation-history-details.component'; +import { SourceDetectiveSidesheetComponent, SourceDetectiveSidesheetData, SourceDetectiveType, ViewConfigService } from 'qer'; +import { Subscription } from 'rxjs'; import { Approvers } from '../decision/approvers.interface'; -import { AttestationHistoryActionService } from './attestation-history-action.service'; import { AttestationCasesService } from '../decision/attestation-cases.service'; -import { createGroupData } from '../datamodel/datamodel-helper'; -import { SourceDetectiveSidesheetComponent, SourceDetectiveSidesheetData, SourceDetectiveType, ViewConfigService } from 'qer'; -import { ViewConfigData } from 'imx-api-qer'; +import { AttestationHistoryActionService } from './attestation-history-action.service'; +import { AttestationHistoryCase } from './attestation-history-case'; +import { AttestationHistoryDetailsComponent } from './attestation-history-details/attestation-history-details.component'; +import { AttestationHistoryService } from './attestation-history.service'; @Component({ selector: 'imx-attestation-history', templateUrl: './attestation-history.component.html', styleUrls: ['./attestation-history.component.scss'], + providers: [DataViewSource], }) export class AttestationHistoryComponent implements OnInit, OnDestroy { @Input() public parameters: { objecttable: string; objectuid: string; filter?: FilterData[] }; @Input() public itemStatus: DataSourceItemStatus = { enabled: (__) => true }; @Input() public withAssignmentAnalysis: boolean = false; - @Input() public selectable : boolean = true; + @Input() public selectable: boolean = true; + @Input() title: string; - @ViewChild('attestorFilter', { static: false }) public attestorFilter: AttestationHistoryFilterComponent; - - public dstSettings: DataSourceToolbarSettings; public readonly DisplayColumns = DisplayColumns; public readonly entitySchema: EntitySchema; public groupedData: { [key: string]: DataTableGroupedData } = {}; - @Output() public selectionChanged = new EventEmitter(); + @Output() public selectionChanged = new EventEmitter(); public busyService = new BusyService(); - private filterOptions: DataSourceToolbarFilter[] = []; private dataModel: DataModel; - - private navigationState: AttestationCaseLoadParameters; - - private groupData: DataSourceToolbarGroupData; private displayedColumns: ClientPropertyForTableColumns[]; private readonly subscriptions: Subscription[] = []; - - @ViewChild(DataTableComponent) private readonly table: DataTableComponent; private viewConfig: DataSourceToolbarViewConfig; private viewConfigPath = 'attestation/case'; @@ -109,22 +98,21 @@ export class AttestationHistoryComponent implements OnInit, OnDestroy { private readonly busyServiceElemental: EuiLoadingService, private readonly sideSheet: EuiSidesheetService, private readonly translator: TranslateService, - private readonly settingsService: SettingsService, - private readonly messageService: UserMessageService + private readonly messageService: UserMessageService, + public dataSource: DataViewSource, ) { this.entitySchema = attestationCaseService.attestationCaseSchema; this.subscriptions.push( this.attestationAction.applied.subscribe(async () => { - await this.getData(); - this.table?.clearSelection(); - }) + this.dataSource.updateState(); + this.dataSource.selection.clear(); + }), ); } public async ngOnInit(): Promise { this.displayedColumns = [this.entitySchema.Columns.UiText, this.entitySchema.Columns.AttestationState]; - if (this.withAssignmentAnalysis) { this.displayedColumns.push({ ColumnName: 'actions', @@ -133,50 +121,19 @@ export class AttestationHistoryComponent implements OnInit, OnDestroy { untranslatedDisplay: '#LDS#View assignment analysis', }); } - this.navigationState = { ...this.parameters, ...{ PageSize: this.settingsService.DefaultPageSize, StartIndex: 0 } }; const isBusy = this.busyService.beginBusy(); try { this.dataModel = await this.historyService.getDataModel( this.parameters?.objecttable, this.parameters?.objectuid, - this.parameters?.filter - ); - this.filterOptions = this.dataModel.Filters; - this.groupData = createGroupData( - this.dataModel, - (parameters) => { - const uidpolicy = this.filterOptions.find((elem) => elem.Name === 'uidpolicy')?.CurrentValue; - const risk = this.filterOptions.find((elem) => elem.Name === 'risk')?.CurrentValue; - const state = this.filterOptions.find((elem) => elem.Name === 'state')?.CurrentValue; - return this.historyService.getGroupInfo({ - ...{ - PageSize: this.navigationState.PageSize, - StartIndex: 0, - objecttable: this.parameters?.objecttable, - objectuid: this.parameters?.objectuid, - groupFilter: this.parameters?.filter, - risk, - state, - uidpolicy, - }, - ...parameters, - }); - }, - [] + this.parameters?.filter, ); this.viewConfig = await this.viewConfigService.getInitialDSTExtension(this.dataModel, this.viewConfigPath); - // We will check the configs for default state only on ini - if (!this.viewConfigService.isDefaultConfigSet()) { - // If we have no default settings, we will use the due date to sort - this.navigationState.OrderBy = 'ToSolveTill'; - } - await this.getData(); + await this.initTable(); } finally { - setTimeout(() => { - isBusy.endBusy(); - }); + isBusy.endBusy(); } } @@ -187,84 +144,57 @@ export class AttestationHistoryComponent implements OnInit, OnDestroy { public async updateConfig(config: ViewConfigData): Promise { await this.viewConfigService.putViewConfig(config); this.viewConfig = await this.viewConfigService.getDSTExtensionChanges(this.viewConfigPath); - this.dstSettings.viewConfig = this.viewConfig; + this.dataSource.viewConfig.set(this.viewConfig); } public async deleteConfigById(id: string): Promise { await this.viewConfigService.deleteViewConfig(id); this.viewConfig = await this.viewConfigService.getDSTExtensionChanges(this.viewConfigPath); - this.dstSettings.viewConfig = this.viewConfig; - } - - public async onSearch(search: string): Promise { - return this.getData({ search }); + this.dataSource.viewConfig.set(this.viewConfig); } - public async onGroupingChange(groupKey: string): Promise { - const isBusy = this.busyService.beginBusy(); - - try { - const groupedData = this.groupedData[groupKey]; - let filter = groupedData.navigationState?.filter; - if (this.parameters?.filter) { - filter = [...(groupedData.navigationState?.filter ?? []), ...(this.parameters?.filter ?? [])].filter((elem) => elem != null); - } - const navigationState = { ...groupedData.navigationState, filter }; - groupedData.data = await this.historyService.getAttestations(navigationState); - groupedData.settings = { - displayedColumns: this.dstSettings.displayedColumns, - dataModel: this.dstSettings.dataModel, - dataSource: groupedData.data, - entitySchema: this.dstSettings.entitySchema, - navigationState: groupedData.navigationState, - }; - } finally { - isBusy.endBusy(); - } - } - - public async getData(newState?: AttestationCaseLoadParameters): Promise { - this.navigationState = { - ...(this.dstSettings?.navigationState ?? this.navigationState), - uid_persondecision: this.attestorFilter?.selectedUid, - ...newState, + public async initTable(): Promise { + this.dataSource.itemStatus = this.itemStatus; + const dataViewInitParameters: DataViewInitParameters = { + execute: (params: CollectionLoadParameters, signal: AbortSignal): Promise> => + this.historyService.getAttestations({ ...this.parameters, ...params }), + schema: this.entitySchema, + columnsToDisplay: this.displayedColumns, + dataModel: this.dataModel, + groupExecute: (column: string, params: CollectionLoadParameters, signal: AbortSignal) => + Promise.resolve( + this.historyService + .getGroupInfo({ + ...params, + ...this.parameters, + StartIndex: 0, + def: column, + }) + .then((groupInfoData) => { + groupInfoData.Groups?.map((group) => { + setFilterDisplay(group); + return group; + }); + return groupInfoData; + }), + ), + viewConfig: this.viewConfig, + highlightEntity: (entity: AttestationHistoryCase) => { + this.viewDetails(entity); + }, + selectionChange: (selection: Array) => this.selectionChanged.emit(selection), + exportFunction: this.historyService.exportAttestation(this.dataSource.state()), }; - - const isBusy = this.busyService.beginBusy(); - - try { - const data = await this.historyService.getAttestations(this.navigationState); - const exportMethod = this.historyService.exportAttestation(this.navigationState); - exportMethod.initialColumns = this.displayedColumns.map((col) => col.ColumnName); - if (data) { - this.dstSettings = { - dataSource: { - totalCount: data.totalCount, - Data: data.Data ? data.Data : undefined, - }, - filters: this.filterOptions, - groupData: this.groupData, - displayedColumns: this.displayedColumns, - entitySchema: this.entitySchema, - navigationState: this.navigationState, - dataModel: this.dataModel, - viewConfig: this.viewConfig, - exportMethod, - }; - } else { - this.dstSettings = undefined; - } - } finally { - isBusy.endBusy(); - } + this.dataSource.init(dataViewInitParameters); } - public async viewDetails(attestationCase: AttestationHistoryCase): Promise { + public async viewDetails(entity: AttestationHistoryCase): Promise { + const attestationCase = entity as AttestationHistoryCase; let attestationCaseWithPolicy: AttestationHistoryCase; - let approvers: Approvers; - - let busyIndicator: OverlayRef; - setTimeout(() => (busyIndicator = this.busyServiceElemental.show())); + let approvers: Approvers | undefined; + if (this.busyServiceElemental.overlayRefs.length === 0) { + this.busyServiceElemental.show(); + } try { attestationCaseWithPolicy = ( @@ -290,7 +220,7 @@ export class AttestationHistoryComponent implements OnInit, OnDestroy { approvers = await this.attestationCaseService.getApprovers(attestationCaseWithPolicy); } } finally { - setTimeout(() => this.busyServiceElemental.hide(busyIndicator)); + this.busyServiceElemental.hide(); } if (attestationCaseWithPolicy) { @@ -298,7 +228,7 @@ export class AttestationHistoryComponent implements OnInit, OnDestroy { title: await this.translator.get('#LDS#Heading View Attestation Case Details').toPromise(), subTitle: attestationCaseWithPolicy.GetEntity().GetDisplay(), padding: '0', - width: '600px', + width: calculateSidesheetWidth(), testId: 'attestation-history-case-sidesheet', data: { case: attestationCaseWithPolicy, @@ -314,7 +244,6 @@ export class AttestationHistoryComponent implements OnInit, OnDestroy { } public async viewAssignmentAnalysis(event: Event, attestationCase: AttestationHistoryCase): Promise { - event.stopPropagation(); const uidPerson = attestationCase.UID_Person.value; @@ -330,7 +259,7 @@ export class AttestationHistoryComponent implements OnInit, OnDestroy { title: await this.translator.get('#LDS#Heading View Assignment Analysis').toPromise(), subTitle: attestationCase.GetEntity().GetDisplay(), padding: '0px', - width: 'max(50%,500px)', + width: calculateSidesheetWidth(800, 0.5), disableClose: false, testId: 'attestation-history-details-assignment-analysis', data, diff --git a/imxweb/projects/att/src/lib/attestation-history/attestation-history.module.ts b/imxweb/projects/att/src/lib/attestation-history/attestation-history.module.ts index abfb545af..b3018f6e1 100644 --- a/imxweb/projects/att/src/lib/attestation-history/attestation-history.module.ts +++ b/imxweb/projects/att/src/lib/attestation-history/attestation-history.module.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -24,25 +24,27 @@ * */ -import { NgModule } from '@angular/core'; import { CommonModule } from '@angular/common'; -import { TranslateModule } from '@ngx-translate/core'; -import { MatButtonModule} from '@angular/material/button'; -import { EuiCoreModule } from '@elemental-ui/core'; -import { MatMenuModule } from '@angular/material/menu'; +import { NgModule } from '@angular/core'; +import { MatButtonModule } from '@angular/material/button'; import { MatCardModule } from '@angular/material/card'; +import { MatMenuModule } from '@angular/material/menu'; import { MatTabsModule } from '@angular/material/tabs'; +import { EuiCoreModule, EuiMaterialModule } from '@elemental-ui/core'; +import { TranslateModule } from '@ngx-translate/core'; -import { DataSourceToolbarModule, DataTableModule, CdrModule, SelectedElementsModule, HelpContextualModule } from 'qbm'; -import { AttestationHistoryComponent } from './attestation-history.component'; -import { AttestationHistoryService } from './attestation-history.service'; -import { AttestationHistoryDetailsComponent } from './attestation-history-details/attestation-history-details.component'; -import { AttestationDecisionModule } from '../decision/attestation-decision.module'; -import { AttestationHistoryWrapperComponent } from './attestation-history-wrapper.component'; +import { FormsModule, ReactiveFormsModule } from '@angular/forms'; +import { MatIconModule } from '@angular/material/icon'; +import { CdrModule, DataSourceToolbarModule, DataTableModule, DataViewModule, HelpContextualModule, SelectedElementsModule } from 'qbm'; +import { ObjectHyperviewModule } from 'qer'; import { AttestationDisplayModule } from '../attestation-display/attestation-display.module'; import { AttestationSnapshotModule } from '../attestation-snapshot/attestation-snapshot.module'; -import {AttestationHistoryFilterComponent} from './attestation-history-filter/attestation-history-filter.component'; -import { MatIconModule } from '@angular/material/icon'; +import { AttestationDecisionModule } from '../decision/attestation-decision.module'; +import { AttestationHistoryDetailsComponent } from './attestation-history-details/attestation-history-details.component'; +import { AttestationHistoryFilterComponent } from './attestation-history-filter/attestation-history-filter.component'; +import { AttestationHistoryWrapperComponent } from './attestation-history-wrapper.component'; +import { AttestationHistoryComponent } from './attestation-history.component'; +import { AttestationHistoryService } from './attestation-history.service'; import { MyAttestationCasesComponent } from './my-attestation-cases/my-attestation-cases.component'; @NgModule({ @@ -65,13 +67,18 @@ import { MyAttestationCasesComponent } from './my-attestation-cases/my-attestati MatMenuModule, MatTabsModule, MatIconModule, + FormsModule, + ReactiveFormsModule, TranslateModule, EuiCoreModule, + EuiMaterialModule, AttestationDecisionModule, AttestationDisplayModule, AttestationSnapshotModule, SelectedElementsModule, HelpContextualModule, + ObjectHyperviewModule, + DataViewModule, ], providers: [AttestationHistoryService], }) diff --git a/imxweb/projects/att/src/lib/attestation-history/attestation-history.service.ts b/imxweb/projects/att/src/lib/attestation-history/attestation-history.service.ts index 09e5f0ffc..9a4e2e07b 100644 --- a/imxweb/projects/att/src/lib/attestation-history/attestation-history.service.ts +++ b/imxweb/projects/att/src/lib/attestation-history/attestation-history.service.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -26,6 +26,7 @@ import { Injectable } from '@angular/core'; +import { AttCaseDataRead, PortalAttestationCase, V2ApiClientMethodFactory } from '@imx-modules/imx-api-att'; import { DataModel, EntityCollectionData, @@ -36,22 +37,24 @@ import { MethodDefinition, MethodDescriptor, TypedEntityCollectionData, -} from 'imx-qbm-dbts'; -import { AttCaseDataRead, PortalAttestationCase, V2ApiClientMethodFactory } from 'imx-api-att'; -import { ParameterDataService, ParameterDataLoadParameters } from 'qer'; +} from '@imx-modules/imx-qbm-dbts'; +import { DataSourceToolbarExportMethod } from 'qbm'; +import { ParameterDataLoadParameters, ParameterDataService } from 'qer'; import { ApiService } from '../api.service'; -import { AttestationHistoryCase } from './attestation-history-case'; import { AttestationCaseLoadParameters } from './attestation-case-load-parameters.interface'; -import { DataSourceToolbarExportMethod } from 'qbm'; +import { AttestationHistoryCase } from './attestation-history-case'; @Injectable({ providedIn: 'root', }) export class AttestationHistoryService { - constructor(private readonly attClient: ApiService, private readonly parameterDataService: ParameterDataService) {} + constructor( + private readonly attClient: ApiService, + private readonly parameterDataService: ParameterDataService, + ) {} public async get( - parameters: AttestationCaseLoadParameters + parameters?: AttestationCaseLoadParameters, ): Promise> { return this.attClient.typedClient.PortalAttestationCase.Get(parameters); } @@ -66,7 +69,7 @@ export class AttestationHistoryService { item.GetEntity(), { ...collection.extendedData, ...{ index } }, (parameters) => this.getParameterCandidates(parameters), - (treefilterparameter) => this.getFilterTree(treefilterparameter) + (treefilterparameter) => this.getFilterTree(treefilterparameter), ); return new AttestationHistoryCase(item, parameterDataContainer, { ...collection.extendedData, ...{ index } }); @@ -80,13 +83,13 @@ export class AttestationHistoryService { getMethod: (withProperties: string, PageSize?: number) => { let method: MethodDescriptor; if (PageSize) { - method = factory.portal_attestation_case_get({...loadParameters, withProperties, PageSize, StartIndex: 0}) + method = factory.portal_attestation_case_get({ ...loadParameters, withProperties, PageSize, StartIndex: 0 }); } else { - method = factory.portal_attestation_case_get({...loadParameters, withProperties}) + method = factory.portal_attestation_case_get({ ...loadParameters, withProperties }); } return new MethodDefinition(method); - } - } + }, + }; } public async getDataModel(objecttable?: string, objectuid?: string, groupFilter?: FilterData[]): Promise { @@ -99,31 +102,32 @@ export class AttestationHistoryService { public getGroupInfo(parameters: AttestationCaseLoadParameters = {}): Promise { // remove groupFilter from parameters - const {withProperties, groupFilter, search, OrderBy, ...paramsWithoutGroupFilter } = parameters; + const { withProperties, groupFilter, search, OrderBy, ...paramsWithoutGroupFilter } = parameters; return this.attClient.client.portal_attestation_case_group_get({ ...paramsWithoutGroupFilter, - ...{ withcount: true, filter: parameters.groupFilter }, + withcount: true, + filter: [...(parameters.groupFilter || []), ...(parameters.filter || [])], }); } private async getParameterCandidates(parameters: ParameterDataLoadParameters): Promise { return this.attClient.client.portal_attestation_case_parameter_candidates_post( parameters.columnName, - parameters.fkTableName, - parameters.diffData, - parameters + parameters.fkTableName || '', + parameters.diffData || {}, + parameters, ); } private async getFilterTree(parameters: ParameterDataLoadParameters): Promise { return this.attClient.client.portal_attestation_case_parameter_candidates_filtertree_post( parameters.columnName, - parameters.fkTableName, - parameters.diffData, + parameters.fkTableName || '', + parameters.diffData || {}, { ...parameters, parentkey: parameters.ParentKey, - } + }, ); } } diff --git a/imxweb/projects/att/src/lib/attestation-history/my-attestation-cases/my-attestation-cases.component.html b/imxweb/projects/att/src/lib/attestation-history/my-attestation-cases/my-attestation-cases.component.html index 296a7f3ac..5bfe89f28 100644 --- a/imxweb/projects/att/src/lib/attestation-history/my-attestation-cases/my-attestation-cases.component.html +++ b/imxweb/projects/att/src/lib/attestation-history/my-attestation-cases/my-attestation-cases.component.html @@ -1,7 +1,8 @@ -

- {{ '#LDS#Heading My Attestations' | translate }} - -

- - - + + + diff --git a/imxweb/projects/att/src/lib/attestation-history/my-attestation-cases/my-attestation-cases.component.scss b/imxweb/projects/att/src/lib/attestation-history/my-attestation-cases/my-attestation-cases.component.scss index c624cb40a..964be29d8 100644 --- a/imxweb/projects/att/src/lib/attestation-history/my-attestation-cases/my-attestation-cases.component.scss +++ b/imxweb/projects/att/src/lib/attestation-history/my-attestation-cases/my-attestation-cases.component.scss @@ -8,10 +8,3 @@ flex: 1 1 auto; } } - -.mat-card { - display: flex; - flex: 1 1 auto; - overflow: hidden; - margin: 3px; -} diff --git a/imxweb/projects/att/src/lib/attestation-history/my-attestation-cases/my-attestation-cases.component.ts b/imxweb/projects/att/src/lib/attestation-history/my-attestation-cases/my-attestation-cases.component.ts index da7e48b6a..77a42133f 100644 --- a/imxweb/projects/att/src/lib/attestation-history/my-attestation-cases/my-attestation-cases.component.ts +++ b/imxweb/projects/att/src/lib/attestation-history/my-attestation-cases/my-attestation-cases.component.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -42,7 +42,7 @@ export class MyAttestationCasesComponent implements OnDestroy { this.attestationParameters = session.IsLoggedIn ? { objecttable: 'Person', - objectuid: session.UserUid, + objectuid: session.UserUid || '', } : undefined; }); diff --git a/imxweb/projects/att/src/lib/attestation-snapshot/attestation-snapshot.component.html b/imxweb/projects/att/src/lib/attestation-snapshot/attestation-snapshot.component.html index 073c75862..5c6042a16 100644 --- a/imxweb/projects/att/src/lib/attestation-snapshot/attestation-snapshot.component.html +++ b/imxweb/projects/att/src/lib/attestation-snapshot/attestation-snapshot.component.html @@ -1,9 +1,15 @@ - + - {{ obj.Data.Display }} - {{'#LDS#Object type' | translate}}: {{ obj.TableDisplay }} + {{ obj.Data?.Display }} - {{ '#LDS#Object type' | translate }}: {{ obj.TableDisplay }}
@@ -19,8 +25,8 @@
  • - {{ col.value.Caption }} - {{ col.value.DisplayValue }} + {{ getColumnCaption(col.value) }} + {{ getColumnDisplayValue(col.value) }}
diff --git a/imxweb/projects/att/src/lib/attestation-snapshot/attestation-snapshot.component.scss b/imxweb/projects/att/src/lib/attestation-snapshot/attestation-snapshot.component.scss index ae29e8c1c..f0f1461cf 100644 --- a/imxweb/projects/att/src/lib/attestation-snapshot/attestation-snapshot.component.scss +++ b/imxweb/projects/att/src/lib/attestation-snapshot/attestation-snapshot.component.scss @@ -1,19 +1,11 @@ @import '@elemental-ui/core/src/styles/_eui_palette.scss'; +@import 'base/mixins'; :host { margin-top: 20px; display: block; } -.helper-alert { - display: flex; - margin-bottom: 20px; - - span { - display: block; - } -} - .property { margin-bottom: 20px; span { @@ -27,13 +19,10 @@ } } -.mat-card { +.mat-mdc-card { + @include flex-column-container-fill(); margin-bottom: 1em; - height: 100%; padding: 20px; - overflow: hidden; - display: flex; - flex-direction: column; } .imx-snapshot-content { diff --git a/imxweb/projects/att/src/lib/attestation-snapshot/attestation-snapshot.component.ts b/imxweb/projects/att/src/lib/attestation-snapshot/attestation-snapshot.component.ts index d463221d2..3dfd34b49 100644 --- a/imxweb/projects/att/src/lib/attestation-snapshot/attestation-snapshot.component.ts +++ b/imxweb/projects/att/src/lib/attestation-snapshot/attestation-snapshot.component.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -27,7 +27,9 @@ import { Component, Input, OnInit } from '@angular/core'; import { EuiLoadingService } from '@elemental-ui/core'; -import { AttestationSnapshotData } from 'imx-api-att'; +import { AttestationSnapshotData } from '@imx-modules/imx-api-att'; +import { EntityColumnData } from '@imx-modules/imx-qbm-dbts'; +import { TranslateService } from '@ngx-translate/core'; import { ApiService } from '../api.service'; @Component({ @@ -39,10 +41,11 @@ export class AttestationSnapshotComponent implements OnInit { public snapshot: AttestationSnapshotData; @Input() public uidCase: string; - @Input() public date :string; + @Input() public date: string; constructor( private readonly attApi: ApiService, - private readonly busy: EuiLoadingService + private readonly busy: EuiLoadingService, + private translate: TranslateService, ) {} public async ngOnInit(): Promise { @@ -54,6 +57,13 @@ export class AttestationSnapshotComponent implements OnInit { this.busy.hide(overlay); } } + public getColumnDisplayValue(column: any): string { + return (column as EntityColumnData).DisplayValue || this.translate.instant('#LDS#Not set'); + } + + public getColumnCaption(column: any): string { + return (column as EntityColumnData).Caption || ''; + } public get attestationDate(): string { return this.date; @@ -63,11 +73,11 @@ export class AttestationSnapshotComponent implements OnInit { * Ordering Objects array by Display (if Displays are equal, then by TableDisplay) in ascending order */ private sortObjectsByDisplay(): void { - this.snapshot.Objects.sort((obj1, obj2) => { - const display1 = obj1.Data.Display; - const display2 = obj2.Data.Display; - const tableDisplay1 = obj1.TableDisplay; - const tableDisplay2 = obj2.TableDisplay; + this.snapshot.Objects?.sort((obj1, obj2) => { + const display1 = obj1.Data?.Display || ''; + const display2 = obj2.Data?.Display || ''; + const tableDisplay1 = obj1.TableDisplay || ''; + const tableDisplay2 = obj2.TableDisplay || ''; if (display1 === display2) return tableDisplay1 < tableDisplay2 ? -1 : 1; diff --git a/imxweb/projects/att/src/lib/attestation-snapshot/attestation-snapshot.module.ts b/imxweb/projects/att/src/lib/attestation-snapshot/attestation-snapshot.module.ts index 806291d64..5d2396ab1 100644 --- a/imxweb/projects/att/src/lib/attestation-snapshot/attestation-snapshot.module.ts +++ b/imxweb/projects/att/src/lib/attestation-snapshot/attestation-snapshot.module.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -24,33 +24,18 @@ * */ -import { CommonModule } from "@angular/common"; -import { NgModule } from "@angular/core"; -import { MatButtonModule } from "@angular/material/button"; -import { MatCardModule } from "@angular/material/card"; -import { EuiCoreModule, EuiMaterialModule } from "@elemental-ui/core"; -import { TranslateModule } from "@ngx-translate/core"; -import { CdrModule, LdsReplaceModule } from "qbm"; -import { AttestationSnapshotComponent } from "./attestation-snapshot.component"; +import { CommonModule } from '@angular/common'; +import { NgModule } from '@angular/core'; +import { MatButtonModule } from '@angular/material/button'; +import { MatCardModule } from '@angular/material/card'; +import { EuiCoreModule, EuiMaterialModule } from '@elemental-ui/core'; +import { TranslateModule } from '@ngx-translate/core'; +import { CdrModule, LdsReplaceModule } from 'qbm'; +import { AttestationSnapshotComponent } from './attestation-snapshot.component'; @NgModule({ - declarations: [ - AttestationSnapshotComponent - ], - imports: [ - CommonModule, - CdrModule, - EuiCoreModule, - EuiMaterialModule, - LdsReplaceModule, - TranslateModule, - MatCardModule, - MatButtonModule, - ], - exports: [ - AttestationSnapshotComponent - ] + declarations: [AttestationSnapshotComponent], + imports: [CommonModule, CdrModule, EuiCoreModule, EuiMaterialModule, LdsReplaceModule, TranslateModule, MatCardModule, MatButtonModule], + exports: [AttestationSnapshotComponent], }) -export class AttestationSnapshotModule { - -} \ No newline at end of file +export class AttestationSnapshotModule {} diff --git a/imxweb/projects/att/src/lib/claim-device/claim-device.component.html b/imxweb/projects/att/src/lib/claim-device/claim-device.component.html index 662f79252..e601b3ad6 100644 --- a/imxweb/projects/att/src/lib/claim-device/claim-device.component.html +++ b/imxweb/projects/att/src/lib/claim-device/claim-device.component.html @@ -1,10 +1,21 @@ -

+

{{ '#LDS#Heading Assign an Owner for a Device' | translate }} -

+ - - + +
@@ -12,7 +23,7 @@

+

diff --git a/imxweb/projects/att/src/lib/claim-device/claim-device.component.scss b/imxweb/projects/att/src/lib/claim-device/claim-device.component.scss index eeb7cee7a..1c1cc3b58 100644 --- a/imxweb/projects/att/src/lib/claim-device/claim-device.component.scss +++ b/imxweb/projects/att/src/lib/claim-device/claim-device.component.scss @@ -3,11 +3,6 @@ max-width: 100%; } -mat-radio-group { - display: flex; - flex-direction: column; -} - .imx-button-previous { margin-right: 10px; } diff --git a/imxweb/projects/att/src/lib/claim-device/claim-device.component.spec.ts b/imxweb/projects/att/src/lib/claim-device/claim-device.component.spec.ts index 17a6ebb96..daf24126d 100644 --- a/imxweb/projects/att/src/lib/claim-device/claim-device.component.spec.ts +++ b/imxweb/projects/att/src/lib/claim-device/claim-device.component.spec.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -30,15 +30,15 @@ import { MatRadioChange } from '@angular/material/radio'; import { EuiLoadingService } from '@elemental-ui/core'; import { BehaviorSubject } from 'rxjs'; -import { AuthenticationService, clearStylesFromDOM, ISessionState, LdsReplaceModule } from 'qbm'; +import { MockBuilder, MockedComponentFixture, MockRender } from 'ng-mocks'; +import { AuthenticationService, clearStylesFromDOM, ISessionState } from 'qbm'; import { PersonService } from 'qer'; import { ClaimDeviceComponent } from './claim-device.component'; import { ClaimDeviceService } from './claim-device.service'; -import { MockBuilder, MockedComponentFixture, MockRender } from 'ng-mocks'; @Component({ selector: 'imx-cdr-editor', - template: '

MockCdrEditor

' + template: '

MockCdrEditor

', }) class MockCdrEditor { @Input() public cdr: any; @@ -48,7 +48,7 @@ describe('ClaimDeviceComponent', () => { let component: ClaimDeviceComponent; let fixture: MockedComponentFixture; - const claimGroupServiceStub = new class { + const claimGroupServiceStub = new (class { numberOfSuggestedOwners = 0; hasSuggestedOwners = jasmine.createSpy('hasSuggestedOwners').and.callFake(() => Promise.resolve(this.numberOfSuggestedOwners > 0)); @@ -57,13 +57,13 @@ describe('ClaimDeviceComponent', () => { column: { ColumnName: 'UID_Hardware', GetValue: () => 'device-key', - GetDisplayValue: () => 'displayvalue for some device' - } + GetDisplayValue: () => 'displayvalue for some device', + }, }); createColumnSuggestedOwner = jasmine.createSpy('createColumnSuggestedOwner').and.returnValue({ ColumnName: 'some column name', - GetValue: () => 'some value' + GetValue: () => 'some value', }); reset() { @@ -73,38 +73,39 @@ describe('ClaimDeviceComponent', () => { this.createColumnSuggestedOwner.calls.reset(); this.numberOfSuggestedOwners = 0; } - }(); + })(); const personServiceStub = { createColumnCandidatesPerson: jasmine.createSpy('createColumnCandidatesPerson').and.returnValue({ ColumnName: 'personColumn', - GetValue: () => 'some value' - }) + GetValue: () => 'some value', + }), }; const authStub = { onSessionResponse: new BehaviorSubject({ - UserUid: "", - Username: "" - }) - } + UserUid: '', + Username: '', + }), + }; + + const euiLoadingServiceStud = { + overlayRefs: [], + }; beforeEach(() => { return MockBuilder(ClaimDeviceComponent) .mock(ClaimDeviceService, claimGroupServiceStub) .mock(PersonService, personServiceStub) - .mock(EuiLoadingService) + .mock(EuiLoadingService, euiLoadingServiceStud) .mock(AuthenticationService, authStub) - .beforeCompileComponents(testBed => { + .beforeCompileComponents((testBed) => { testBed.configureTestingModule({ - declarations: [ - ClaimDeviceComponent, - MockCdrEditor - ], - schemas: [CUSTOM_ELEMENTS_SCHEMA] + declarations: [ClaimDeviceComponent, MockCdrEditor], + schemas: [CUSTOM_ELEMENTS_SCHEMA], + }); }); - }); - }) + }); beforeEach(() => { claimGroupServiceStub.reset(); @@ -123,16 +124,13 @@ describe('ClaimDeviceComponent', () => { const cdr = { display: 'some display' }; component.ownerCandidateListChange({ - value: { createOwnerCdr: () => cdr } + value: { createOwnerCdr: () => cdr }, } as MatRadioChange); expect(component.ownerCdr.display).toEqual(cdr.display); }); - for (const method of [ - () => component.loadSuggestedOwners(), - () => component.stepChange({ selectedIndex: 2 } as StepperSelectionEvent) - ]) { + for (const method of [() => component.loadSuggestedOwners(), () => component.stepChange({ selectedIndex: 2 } as StepperSelectionEvent)]) { it('loads owner candidates', async () => { await method(); expect(component.ownershipOptions.length).toEqual(2); diff --git a/imxweb/projects/att/src/lib/claim-device/claim-device.component.ts b/imxweb/projects/att/src/lib/claim-device/claim-device.component.ts index 62fa2f933..b765f374b 100644 --- a/imxweb/projects/att/src/lib/claim-device/claim-device.component.ts +++ b/imxweb/projects/att/src/lib/claim-device/claim-device.component.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -27,7 +27,6 @@ import { StepperSelectionEvent } from '@angular/cdk/stepper'; import { Component, ErrorHandler, OnDestroy, OnInit } from '@angular/core'; import { UntypedFormGroup } from '@angular/forms'; -import { OverlayRef } from '@angular/cdk/overlay'; import { MatRadioChange } from '@angular/material/radio'; import { EuiLoadingService } from '@elemental-ui/core'; import { Subscription } from 'rxjs'; @@ -38,14 +37,16 @@ import { ClaimDeviceService } from './claim-device.service'; @Component({ styleUrls: ['./claim-device.component.scss'], - templateUrl: './claim-device.component.html' + templateUrl: './claim-device.component.html', }) export class ClaimDeviceComponent implements OnDestroy, OnInit { - public get ownerDisplay(): string { return this.ownerCdr ? this.ownerCdr.column.GetDisplayValue() : this.user.name; } + public get ownerDisplay(): string { + return this.ownerCdr ? this.ownerCdr.column.GetDisplayValue() : this.user.name || ''; + } public deviceCdr: BaseCdr; public ownerCdr: BaseCdr; - public ownershipOptions: { title: string; createOwnerCdr: () => BaseCdr; }[]; + public ownershipOptions: { title: string; createOwnerCdr: () => BaseCdr | undefined }[] = []; public ownerAssigned = false; public canClaimDevice = false; @@ -53,7 +54,7 @@ export class ClaimDeviceComponent implements OnDestroy, OnInit { public readonly ownerForm = new UntypedFormGroup({}); private deviceKey: string; - private readonly user: { uid?: string; name?: string; } = {}; + private readonly user: { uid?: string; name?: string } = {}; private readonly subscriptions: Subscription[] = []; constructor( @@ -61,30 +62,33 @@ export class ClaimDeviceComponent implements OnDestroy, OnInit { private readonly personService: PersonService, private readonly busyService: EuiLoadingService, private readonly authentication: AuthenticationService, - private readonly errorHandler: ErrorHandler + private readonly errorHandler: ErrorHandler, ) { this.initDeviceCdr(); - this.subscriptions.push(this.authentication.onSessionResponse.subscribe(async (sessionState: ISessionState) => { - if (sessionState) { - this.user.uid = sessionState.UserUid; - this.user.name = sessionState.Username; - } - })); + this.subscriptions.push( + this.authentication.onSessionResponse.subscribe(async (sessionState: ISessionState) => { + if (sessionState) { + this.user.uid = sessionState.UserUid || ''; + this.user.name = sessionState.Username || ''; + } + }), + ); } public async ngOnInit(): Promise { - let overlayRef: OverlayRef; - setTimeout(() => overlayRef = this.busyService.show()); + if (this.busyService.overlayRefs.length === 0) { + this.busyService.show(); + } try { - this.canClaimDevice = await this.claimDeviceService.canClaimDevice(); + this.canClaimDevice = await this.claimDeviceService.canClaimDevice(); } finally { - setTimeout(() => this.busyService.hide(overlayRef)); + this.busyService.hide(); } } public ngOnDestroy(): void { - this.subscriptions.forEach(subscription => subscription.unsubscribe()); + this.subscriptions.forEach((subscription) => subscription.unsubscribe()); } public resetForms(): void { @@ -107,7 +111,7 @@ export class ClaimDeviceComponent implements OnDestroy, OnInit { } public async loadSuggestedOwners(): Promise { - const fkValue = this.deviceCdr.column.GetValue(); + const fkValue = this.deviceCdr.column.GetValue(); if (this.deviceKey === fkValue) { return; @@ -118,46 +122,42 @@ export class ClaimDeviceComponent implements OnDestroy, OnInit { this.ownershipOptions = []; this.ownershipOptions.push({ title: '#LDS#I want to take ownership of this device', - createOwnerCdr: () => undefined + createOwnerCdr: () => undefined, }); this.ownershipOptions.push({ title: '#LDS#Select another owner', - createOwnerCdr: () => new BaseCdr( - this.personService.createColumnCandidatesPerson(), - display - ) + createOwnerCdr: () => new BaseCdr(this.personService.createColumnCandidatesPerson(), display), }); this.initOwnerCdr(this.ownershipOptions[0].createOwnerCdr()); } public async assignOwner(): Promise { - let overlayRef: OverlayRef; - setTimeout(() => overlayRef = this.busyService.show()); + if (this.busyService.overlayRefs.length === 0) { + this.busyService.show(); + } try { - await this.claimDeviceService.assignOwner( - this.deviceKey, - this.ownerCdr ? this.ownerCdr.column.GetValue() : this.user.uid - ); + await this.claimDeviceService.assignOwner(this.deviceKey, this.ownerCdr ? this.ownerCdr.column.GetValue() : this.user.uid); this.ownerAssigned = true; } catch (error) { this.errorHandler.handleError(error); } finally { - setTimeout(() => this.busyService.hide(overlayRef)); + this.busyService.hide(); } } private initDeviceCdr(): void { - Object.keys(this.deviceForm.controls).forEach(name => this.deviceForm.removeControl(name)); + Object.keys(this.deviceForm.controls).forEach((name) => this.deviceForm.removeControl(name)); this.deviceCdr = this.claimDeviceService.createCdrForDevice(); } - private initOwnerCdr(cdr: BaseCdr): void { - Object.keys(this.ownerForm.controls).forEach(name => this.ownerForm.removeControl(name)); - - this.ownerCdr = cdr; + private initOwnerCdr(cdr?: BaseCdr): void { + if (cdr) { + Object.keys(this.ownerForm.controls).forEach((name) => this.ownerForm.removeControl(name)); + this.ownerCdr = cdr; + } } } diff --git a/imxweb/projects/att/src/lib/claim-device/claim-device.module.ts b/imxweb/projects/att/src/lib/claim-device/claim-device.module.ts index b8cf5b6f8..f89b8d63c 100644 --- a/imxweb/projects/att/src/lib/claim-device/claim-device.module.ts +++ b/imxweb/projects/att/src/lib/claim-device/claim-device.module.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -37,9 +37,7 @@ import { CdrModule, HelpContextualModule, LdsReplaceModule } from 'qbm'; import { ClaimDeviceComponent } from './claim-device.component'; @NgModule({ - declarations: [ - ClaimDeviceComponent - ], + declarations: [ClaimDeviceComponent], imports: [ CdrModule, CommonModule, @@ -52,7 +50,6 @@ import { ClaimDeviceComponent } from './claim-device.component'; ReactiveFormsModule, TranslateModule, HelpContextualModule, - ] + ], }) -export class ClaimDeviceModule { -} +export class ClaimDeviceModule {} diff --git a/imxweb/projects/att/src/lib/claim-device/claim-device.service.ts b/imxweb/projects/att/src/lib/claim-device/claim-device.service.ts index 1a2ea7453..65ab2dd48 100644 --- a/imxweb/projects/att/src/lib/claim-device/claim-device.service.ts +++ b/imxweb/projects/att/src/lib/claim-device/claim-device.service.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -26,15 +26,18 @@ import { Injectable } from '@angular/core'; -import { CollectionLoadParameters, EntityCollectionData, IEntityColumn, MetaTableRelationData, ValType } from 'imx-qbm-dbts'; +import { CollectionLoadParameters, EntityCollectionData, IEntityColumn, MetaTableRelationData, ValType } from '@imx-modules/imx-qbm-dbts'; import { BaseCdr, EntityService } from 'qbm'; import { ApiService } from '../api.service'; @Injectable({ - providedIn: 'root' + providedIn: 'root', }) export class ClaimDeviceService { - constructor(private readonly apiService: ApiService, private readonly entityService: EntityService) { } + constructor( + private readonly apiService: ApiService, + private readonly entityService: EntityService, + ) {} public async canClaimDevice(): Promise { return (await this.apiService.client.portal_attestation_userconfig_get()).CanClaimDevice; @@ -50,9 +53,9 @@ export class ClaimDeviceService { ChildColumnName: 'UID_Hardware', IsMemberRelation: false, ParentTableName: 'Hardware', - ParentColumnName: 'XObjectKey' + ParentColumnName: 'XObjectKey', }, - parameters => this.apiService.client.portal_claimdevice_devices_get(parameters), + (parameters) => this.apiService.client.portal_claimdevice_devices_get(parameters), ); return new BaseCdr(column, '#LDS#Device' /* TODO: globalize */); @@ -67,30 +70,22 @@ export class ClaimDeviceService { ColumnName: fkRelation.ChildColumnName, Type: ValType.String, MinLen: 1, - FkRelation: fkRelation + FkRelation: fkRelation, }, - [{ - columnName: fkRelation.ChildColumnName, - fkTableName: fkRelation.ParentTableName, - parameterNames: [ - 'OrderBy', - 'StartIndex', - 'PageSize', - 'filter', - 'search', - ], - load: async (_, parameters: CollectionLoadParameters = {}) => loadFkCandidates(parameters), - getDataModel: async () => ({ Filters: [] }), - getFilterTree: async () => ({ Elements: [] }) - }] + [ + { + columnName: fkRelation.ChildColumnName || '', + fkTableName: fkRelation.ParentTableName || '', + parameterNames: ['OrderBy', 'StartIndex', 'PageSize', 'filter', 'search'], + load: async (_, parameters: CollectionLoadParameters = {}) => loadFkCandidates(parameters), + getDataModel: async () => ({ Filters: [] }), + getFilterTree: async () => ({ Elements: [] }), + }, + ], ); } - - - private async getOwnerCandidates( - parameters: CollectionLoadParameters = {} - ): Promise { + private async getOwnerCandidates(parameters: CollectionLoadParameters = {}): Promise { const collection = await this.apiService.client.portal_candidates_Person_get(parameters); return collection; diff --git a/imxweb/projects/att/src/lib/dashboard-plugin/dashboard-plugin.component.html b/imxweb/projects/att/src/lib/dashboard-plugin/dashboard-plugin.component.html index 41e5513e2..81c31cf46 100644 --- a/imxweb/projects/att/src/lib/dashboard-plugin/dashboard-plugin.component.html +++ b/imxweb/projects/att/src/lib/dashboard-plugin/dashboard-plugin.component.html @@ -1,8 +1,8 @@ @@ -10,8 +10,8 @@ diff --git a/imxweb/projects/att/src/lib/dashboard-plugin/dashboard-plugin.component.ts b/imxweb/projects/att/src/lib/dashboard-plugin/dashboard-plugin.component.ts index eac2a020d..07f3c5489 100644 --- a/imxweb/projects/att/src/lib/dashboard-plugin/dashboard-plugin.component.ts +++ b/imxweb/projects/att/src/lib/dashboard-plugin/dashboard-plugin.component.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -31,10 +31,9 @@ import { DashboardService, PendingItemsType, UserModelService } from 'qer'; import { AttestationFeatureGuardService } from '../attestation-feature-guard.service'; @Component({ - templateUrl: './dashboard-plugin.component.html' + templateUrl: './dashboard-plugin.component.html', }) export class DashboardPluginComponent implements OnInit { - public pendingItems: PendingItemsType; public attEnabled: boolean; @@ -42,11 +41,10 @@ export class DashboardPluginComponent implements OnInit { public readonly router: Router, private readonly dashboardSvc: DashboardService, private readonly userModelSvc: UserModelService, - private readonly attFeatureGuard: AttestationFeatureGuardService - ) { } + private readonly attFeatureGuard: AttestationFeatureGuardService, + ) {} public async ngOnInit(): Promise { - const busy = this.dashboardSvc.beginBusy(); try { @@ -58,6 +56,6 @@ export class DashboardPluginComponent implements OnInit { } public goToAttestationInquiries(): void { - this.router.navigate(['attestation', 'decision'], {queryParams: {inquiries:true}}); + this.router.navigate(['attestation', 'decision'], { queryParams: { inquiries: true } }); } } diff --git a/imxweb/projects/att/src/lib/datamodel/datamodel-helper.ts b/imxweb/projects/att/src/lib/datamodel/datamodel-helper.ts deleted file mode 100644 index 6246f915c..000000000 --- a/imxweb/projects/att/src/lib/datamodel/datamodel-helper.ts +++ /dev/null @@ -1,91 +0,0 @@ -/* - * ONE IDENTITY LLC. PROPRIETARY INFORMATION - * - * This software is confidential. One Identity, LLC. or one of its affiliates or - * subsidiaries, has supplied this software to you under terms of a - * license agreement, nondisclosure agreement or both. - * - * You may not copy, disclose, or use this software except in accordance with - * those terms. - * - * - * Copyright 2023 One Identity LLC. - * ALL RIGHTS RESERVED. - * - * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR - * WARRANTIES ABOUT THE SUITABILITY OF THE SOFTWARE, - * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED - * TO THE IMPLIED WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE, OR - * NON-INFRINGEMENT. ONE IDENTITY LLC. SHALL NOT BE - * LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE - * AS A RESULT OF USING, MODIFYING OR DISTRIBUTING - * THIS SOFTWARE OR ITS DERIVATIVES. - * - */ - -import { - CollectionLoadParameters, - DataModel, - DataModelFilterOption, - DataModelGroupInfo, - DataModelProperty, - GroupInfoData, -} from 'imx-qbm-dbts'; -import { DataSourceToolbarGroupData } from 'qbm'; - -export function createGroupData( - dataModel: DataModel, - getGroupInfo: (parameters: { by?: string; def?: string } & CollectionLoadParameters) => Promise, - disableGroupingFor: string[] -): DataSourceToolbarGroupData { - const groups = []; - const groupingCategories = []; - - if (dataModel.Properties) { - for (const property of dataModel.Properties.filter( - (p) => p.IsGroupable && disableGroupingFor.every((elem) => elem !== p.Property?.ColumnName) - )) { - groups.push({ - property, - getData: async (parameters) => await getGroupInfo({ ...{ by: property.Property.ColumnName }, ...parameters }), - }); - } - } - - const getGroupInfoGroups = (options: DataModelFilterOption[]) => - options.map((property) => ({ - property: property as DataModelProperty & DataModelGroupInfo, - getData: async (parameters) => { - const original = await getGroupInfo({ ...{ def: property.Value }, ...parameters }); - const groupDisplay = original.Groups.map((item) => { - item.Display.forEach((display) => - item.Filters.forEach((filter) => { - if (filter.Value1 != null) { - display.Display = display.Display.replace(`%${filter.ColumnName}%`, filter.Value1); - } - }) - ); - return item; - }); - return { Groups: groupDisplay, TotalCount: original.TotalCount }; - }, - })); - - if (dataModel.GroupInfo?.length === 1) { - getGroupInfoGroups(dataModel.GroupInfo[0].Options).forEach((group) => groups.push(group)); - } else { - dataModel.GroupInfo?.forEach((dataModelGroupInfo) => - groupingCategories.push({ - property: dataModelGroupInfo, - groups: getGroupInfoGroups(dataModelGroupInfo.Options), - }) - ); - } - - if (groups.length > 0 || groupingCategories.length > 0) { - return { groups, groupingCategories }; - } - - return undefined; -} diff --git a/imxweb/projects/att/src/lib/decision/approvers.interface.ts b/imxweb/projects/att/src/lib/decision/approvers.interface.ts index fb048cf2f..df086c2f9 100644 --- a/imxweb/projects/att/src/lib/decision/approvers.interface.ts +++ b/imxweb/projects/att/src/lib/decision/approvers.interface.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -24,10 +24,10 @@ * */ - -import { EntityData } from 'imx-qbm-dbts'; +import { EntityData } from '@imx-modules/imx-qbm-dbts'; export interface Approvers { current: EntityData[]; future: EntityData[]; + canSeeSteps: boolean; } diff --git a/imxweb/projects/att/src/lib/decision/approvers/approvers.component.html b/imxweb/projects/att/src/lib/decision/approvers/approvers.component.html index 14e16ae81..cbbe73f2a 100644 --- a/imxweb/projects/att/src/lib/decision/approvers/approvers.component.html +++ b/imxweb/projects/att/src/lib/decision/approvers/approvers.component.html @@ -1,36 +1,38 @@ -
  • +
  • - {{'#LDS#The next approval step is currently being calculated.' | translate}} + {{ + (approvers.canSeeSteps + ? '#LDS#The next approval step is currently being calculated.' + : '#LDS#You do not have permission to see the next approval step.' + ) | translate + }}
  • -
  • +
  • - {{'#LDS#The following identities are currently entitled to approve this attestation case.' | translate}} + {{ '#LDS#The following identities are currently entitled to approve this attestation case.' | translate }}
    - {{ approver.Columns.UID_PersonHead.DisplayValue }} + {{ approver.Columns?.UID_PersonHead?.DisplayValue }}
  • -
  • +
  • - {{'#LDS#The following identities are entitled to approve this attestation case after the current workflow step.' | translate}} + {{ '#LDS#The following identities are entitled to approve this attestation case after the current workflow step.' | translate }}
    - {{ approver.Columns.UID_PersonHead.DisplayValue }} + {{ approver.Columns?.UID_PersonHead?.DisplayValue }}
    -
  • \ No newline at end of file + diff --git a/imxweb/projects/att/src/lib/decision/approvers/approvers.component.scss b/imxweb/projects/att/src/lib/decision/approvers/approvers.component.scss index 73de9af8b..bac5a01cd 100644 --- a/imxweb/projects/att/src/lib/decision/approvers/approvers.component.scss +++ b/imxweb/projects/att/src/lib/decision/approvers/approvers.component.scss @@ -15,7 +15,7 @@ li.imx-event::before { background-color: $color-gray-0; height: 24px; width: 28px; - content: ""; + content: ''; float: left; margin-top: -2px; } @@ -29,15 +29,14 @@ li.imx-event.imx-pending::before { font-family: Cadence-Icon; font-size: 24px; color: $color-gray-30; - content: "\e009"; + content: '\e009'; } -.mat-card-header { - margin-left: -16px; +.mat-mdc-card-header { margin-bottom: 10px; } -.mat-card-header .mat-card-title { +.mat-mdc-card-header .mat-mdc-card-title { font-size: 1.05em; margin-bottom: 0; } @@ -48,13 +47,12 @@ li.imx-event.imx-pending::before { .eui-dark-theme { :host { - li.imx-event::before{ + li.imx-event::before { background-color: $color-gray-70; } - li{ - .mat-card - { + li { + .mat-mdc-card { background-color: $color-gray-60; } } @@ -63,13 +61,12 @@ li.imx-event.imx-pending::before { .eui-contrast-theme { :host { - li.imx-event::before{ + li.imx-event::before { background-color: $color-gray-90; } - li{ - .mat-card - { + li { + .mat-mdc-card { background-color: $color-gray-80; } } diff --git a/imxweb/projects/att/src/lib/decision/approvers/approvers.component.ts b/imxweb/projects/att/src/lib/decision/approvers/approvers.component.ts index c762de8a3..857ac1d84 100644 --- a/imxweb/projects/att/src/lib/decision/approvers/approvers.component.ts +++ b/imxweb/projects/att/src/lib/decision/approvers/approvers.component.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -31,7 +31,7 @@ import { Approvers } from '../approvers.interface'; @Component({ selector: 'imx-approvers', templateUrl: './approvers.component.html', - styleUrls: ['./approvers.component.scss'] + styleUrls: ['./approvers.component.scss'], }) export class ApproversComponent { @Input() public approvers: Approvers; diff --git a/imxweb/projects/att/src/lib/decision/attestation-case.component.html b/imxweb/projects/att/src/lib/decision/attestation-case.component.html index e5721a072..39228badd 100644 --- a/imxweb/projects/att/src/lib/decision/attestation-case.component.html +++ b/imxweb/projects/att/src/lib/decision/attestation-case.component.html @@ -1,8 +1,8 @@ - +
    - + #LDS#Based on the peer group analysis, it is recommended that you approve this attestation case. @@ -23,7 +23,10 @@
    - +
    @@ -31,7 +34,11 @@
      - + +
    @@ -40,34 +47,40 @@ -
    +
    - -
    + +
    - +
    - -
    + +
    - +
    - +
    - + {{ '#LDS#Related objects' | translate }} @@ -75,7 +88,8 @@ - + +
    @@ -83,7 +97,7 @@
    - - - - @@ -183,11 +222,16 @@ - diff --git a/imxweb/projects/att/src/lib/decision/attestation-case.component.scss b/imxweb/projects/att/src/lib/decision/attestation-case.component.scss index 066678e2a..71d9822b8 100644 --- a/imxweb/projects/att/src/lib/decision/attestation-case.component.scss +++ b/imxweb/projects/att/src/lib/decision/attestation-case.component.scss @@ -1,43 +1,9 @@ -@import "@elemental-ui/core/src/styles/_eui_palette.scss"; +@import '@elemental-ui/core/src/styles/_eui_palette.scss'; :host { display: flex; flex-direction: column; justify-content: space-between; - - ::ng-deep .mat-tab-body-wrapper { - flex: 1 1 auto; - - .mat-tab-body { - display: flex; - flex-direction: column; - flex: 1 1 auto; - } - } - - ::ng-deep .mat-tab-body-content { - display: flex; - flex-direction: column; - } - - .mat-expansion-panel { - margin-bottom: 10px; - } -} -.mat-tab-group { - overflow-y: auto; - height: 100%; -} - -.imx-mat-tab-container { - padding: 20px; -} - -.imx-mat-tab-container-full { - height: 100%; - flex: 1 1 auto; - display: flex; - flex-direction: column; } .imx-attestation-case-information, @@ -53,62 +19,10 @@ margin: 10px; } } -.imx-attestation-case-hyperview{ +.imx-attestation-case-hyperview { display: flex; flex-direction: column; } .imx-attestation-case-loss-preview { margin: 0 15px; } - -.imx-helper-alert { - width: 100%; - - ::ng-deep .eui-alert { - margin-bottom: 20px; - } -} - -.eui-sidesheet-actions { - button:not(.imx-justify-right) { - margin-left: 16px; - .mat-icon { - margin-right: 5px; - font-size: 24px; - } - } - .imx-justify-right - { - margin-right: auto; - } -} - -:host { - ::ng-deep .mat-tab-labels { - background-color: $color-gray-0; - } -} - -.eui-dark-theme { - :host { - ::ng-deep .mat-tab-labels { - background-color: $color-gray-80; - } - - .imx-button-bar { - background-color: $color-gray-70; - } - } -} - -.eui-contrast-theme { - :host { - ::ng-deep .mat-tab-labels { - background-color: $color-gray-100; - } - - .imx-button-bar { - background-color: $color-gray-90; - } - } -} diff --git a/imxweb/projects/att/src/lib/decision/attestation-case.component.ts b/imxweb/projects/att/src/lib/decision/attestation-case.component.ts index 6b10c4673..7ec8f444a 100644 --- a/imxweb/projects/att/src/lib/decision/attestation-case.component.ts +++ b/imxweb/projects/att/src/lib/decision/attestation-case.component.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -25,17 +25,18 @@ */ import { Component, Inject, OnDestroy, OnInit } from '@angular/core'; -import { EuiDownloadOptions, EuiLoadingService, EuiSidesheetRef, EuiSidesheetService, EUI_SIDESHEET_DATA } from '@elemental-ui/core'; -import { Subscription } from 'rxjs'; -import { MatTabChangeEvent } from '@angular/material/tabs'; import { MatDialog } from '@angular/material/dialog'; +import { MatTabChangeEvent } from '@angular/material/tabs'; +import { EUI_SIDESHEET_DATA, EuiDownloadOptions, EuiLoadingService, EuiSidesheetRef, EuiSidesheetService } from '@elemental-ui/core'; import { TranslateService } from '@ngx-translate/core'; +import { Subscription } from 'rxjs'; -import { DbObjectKey } from 'imx-qbm-dbts'; -import { AttestationRelatedObject, PortalAttestationCaseHistory } from 'imx-api-att'; +import { AttestationRelatedObject, PortalAttestationCaseHistory } from '@imx-modules/imx-api-att'; +import { DbObjectKey } from '@imx-modules/imx-qbm-dbts'; import { AuthenticationService, BaseReadonlyCdr, + calculateSidesheetWidth, ClassloggerService, ColumnDependentReference, MetadataService, @@ -50,9 +51,9 @@ import { TermsOfUseViewerComponent, } from 'qer'; import { AttestationActionService } from '../attestation-action/attestation-action.service'; +import { Approvers } from './approvers.interface'; import { AttestationCase } from './attestation-case'; import { AttestationCasesService } from './attestation-cases.service'; -import { Approvers } from './approvers.interface'; import { LossPreview } from './loss-preview.interface'; import { MitigatingControlsComponent } from './mitigating-controls/mitigating-controls.component'; @@ -131,7 +132,7 @@ export class AttestationCaseComponent implements OnDestroy, OnInit { this.reportDownload = this.attestationCasesService.getReportDownloadOptions(this.case); this.subscriptions$.push(this.attestationAction.applied.subscribe(() => this.sidesheetRef.close())); - this.subscriptions$.push(authentication.onSessionResponse.subscribe((sessionState) => (this.userUid = sessionState?.UserUid))); + this.subscriptions$.push(authentication.onSessionResponse.subscribe((sessionState) => (this.userUid = sessionState?.UserUid || ''))); } public async ngOnInit(): Promise { @@ -141,7 +142,7 @@ export class AttestationCaseComponent implements OnDestroy, OnInit { this.complianceTabTitle = await this.translate.get('#LDS#Heading Rule Violations').toPromise(); this.policyTabTitle = await this.translate.get('#LDS#Heading Policy Violations').toPromise(); const info = await this.systemInfoService.get(); - this.canAnalyzeRisk = info.PreProps.includes('RISKINDEX') && this.case.RiskIndex.value > 0; + this.canAnalyzeRisk = !!info.PreProps?.includes('RISKINDEX') && this.case.RiskIndex.value > 0; } finally { this.busyService.hide(overlay); } @@ -156,7 +157,7 @@ export class AttestationCaseComponent implements OnDestroy, OnInit { title: await this.translate.get('#LDS#Heading View Terms of Use').toPromise(), subTitle: this.case.GetEntity().GetDisplay(), padding: '0px', - width: '60%', + width: calculateSidesheetWidth(), icon: 'accesscertification', testId: 'attestation-view-terms-of-use', data: this.case.UID_QERTermsOfUse, @@ -169,7 +170,7 @@ export class AttestationCaseComponent implements OnDestroy, OnInit { title: await this.translate.get('#LDS#Heading Analyze Risk').toPromise(), subTitle: this.case.GetEntity().GetDisplay(), padding: '0px', - width: 'max(600px,60%)', + width: calculateSidesheetWidth(), data: { objectKey: key }, }); } @@ -223,7 +224,7 @@ export class AttestationCaseComponent implements OnDestroy, OnInit { title: await this.translate.get('#LDS#Heading View Assignment Analysis').toPromise(), subTitle: this.case.GetEntity().GetDisplay(), padding: '0px', - width: 'max(60%,600px)', + width: calculateSidesheetWidth(), disableClose: false, testId: 'attestation-history-details-assignment-analysis', data, @@ -233,21 +234,23 @@ export class AttestationCaseComponent implements OnDestroy, OnInit { public async setRelatedOptions(): Promise { this.relatedOptions = (await Promise.all( - this.data.case.data?.RelatedObjects.map(async (relatedObject) => { - const objectType = DbObjectKey.FromXml(relatedObject.ObjectKey); - if (!this.metadataService.tables[objectType.TableName]) { - await this.metadataService.updateNonExisting([objectType.TableName]); - } + this.data.case.data?.RelatedObjects?.map(async (relatedObject) => { + const objectType = DbObjectKey.FromXml(relatedObject.ObjectKey || ''); + await this.metadataService.updateNonExisting([objectType.TableName]); return { - ObjectKey: relatedObject.ObjectKey, - Display: `${relatedObject.Display} - ${this.metadataService.tables[objectType.TableName].DisplaySingular}`, + ObjectKey: relatedObject.ObjectKey || '', + Display: `${relatedObject.Display} - ${this.metadataService.tables[objectType.TableName]?.DisplaySingular}`, }; - }), + }) || [], )) || []; + if (this.relatedOptions?.length > 0) { + this.selectedOption = this.relatedOptions[0]; + this.setHyperviewObject(this.selectedOption); + } } public setHyperviewObject(selectedRelatedObject: AttestationRelatedObject): void { - const dbKey = DbObjectKey.FromXml(selectedRelatedObject.ObjectKey); + const dbKey = DbObjectKey.FromXml(selectedRelatedObject.ObjectKey || ''); this.selectedHyperviewType = dbKey.TableName; this.selectedHyperviewUID = dbKey.Keys.join(','); } diff --git a/imxweb/projects/att/src/lib/decision/attestation-case.spec.ts b/imxweb/projects/att/src/lib/decision/attestation-case.spec.ts index c06b94b87..0569926ff 100644 --- a/imxweb/projects/att/src/lib/decision/attestation-case.spec.ts +++ b/imxweb/projects/att/src/lib/decision/attestation-case.spec.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -24,8 +24,8 @@ * */ -import { AttCaseDataRead, PortalAttestationApprove } from 'imx-api-att'; -import { IClientProperty, IEntity, IEntityColumn } from 'imx-qbm-dbts'; +import { AttCaseDataRead, PortalAttestationApprove } from '@imx-modules/imx-api-att'; +import { IClientProperty, IEntity, IEntityColumn } from '@imx-modules/imx-qbm-dbts'; import { AttestationCase } from './attestation-case'; describe('AttestationCase', () => { @@ -33,45 +33,44 @@ describe('AttestationCase', () => { return { GetMetadata: () => ({ CanEdit: () => true }), GetValue: () => value, - GetDisplayValue: () => '' + GetDisplayValue: () => '', } as IEntityColumn; } function createEntitySchema(columnNames) { const clientProperties = {}; - columnNames.forEach(name => - clientProperties[name] = {} as IClientProperty - ); + columnNames.forEach((name) => (clientProperties[name] = {} as IClientProperty)); return { Columns: clientProperties }; } function createEntity(columns: { [name: string]: IEntityColumn } = {}, key?) { return { GetDisplay: () => '', - GetColumn: name => columns[name] || createColumn(), + GetColumn: (name) => columns[name] || createColumn(), GetKeys: () => [key], - GetSchema: () => createEntitySchema(Object.keys(columns ?? {})) + GetSchema: () => createEntitySchema(Object.keys(columns ?? {})), } as IEntity; } [ { value: true, expected: 1 }, { value: false, expected: 0 }, - { value: undefined, expected: 0 } - ].forEach(testcase => - it('adds IsCrossFunctional to propertyInfo only if it is "true"', () => { - const entity = createEntity({ - IsCrossFunctional: createColumn(testcase.value), - UiText: createColumn('some ui text') - }); + { value: undefined, expected: 0 }, + ].forEach((testcase) => + it('adds IsCrossFunctional to propertyInfo only if it is "true"', () => { + const entity = createEntity({ + IsCrossFunctional: createColumn(testcase.value), + UiText: createColumn('some ui text'), + }); - const approval = new AttestationCase( - { GetEntity: () => entity } as PortalAttestationApprove, - false, // no chief approval - undefined, - {} as { index: number } & AttCaseDataRead - ); + const approval = new AttestationCase( + { GetEntity: () => entity } as PortalAttestationApprove, + false, // no chief approval + undefined, + {} as { index: number } & AttCaseDataRead, + ); - expect(approval.propertyInfo.length).toEqual(testcase.expected); - })); + expect(approval.propertyInfo.length).toEqual(testcase.expected); + }), + ); }); diff --git a/imxweb/projects/att/src/lib/decision/attestation-case.ts b/imxweb/projects/att/src/lib/decision/attestation-case.ts index 4b1fdf9f0..566db9c5b 100644 --- a/imxweb/projects/att/src/lib/decision/attestation-case.ts +++ b/imxweb/projects/att/src/lib/decision/attestation-case.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -24,10 +24,10 @@ * */ -import { AttCaseDataRead, AttestationCaseData, AttestationCaseUiData, PortalAttestationApprove } from 'imx-api-att'; -import { IEntity, IEntityColumn, TypedEntity } from 'imx-qbm-dbts'; -import { ParameterDataContainer, WorkflowDataWrapper } from 'qer'; +import { AttCaseDataRead, AttestationCaseData, AttestationCaseUiData, PortalAttestationApprove } from '@imx-modules/imx-api-att'; +import { IEntity, IEntityColumn, TypedEntity } from '@imx-modules/imx-qbm-dbts'; import { BaseCdr, ColumnDependentReference } from 'qbm'; +import { ParameterDataContainer, WorkflowDataWrapper } from 'qer'; import { AttestationCaseAction } from '../attestation-action/attestation-case-action.interface'; export class AttestationCase extends PortalAttestationApprove implements AttestationCaseAction { @@ -41,18 +41,18 @@ export class AttestationCase extends PortalAttestationApprove implements Attesta return this.parameterDataContainer.columns; } public get canAskAQuestion(): boolean { - return this.data.CanAskForHelp; + return !!this.data?.CanAskForHelp; } public readonly propertyInfo: ColumnDependentReference[]; public readonly key: string; - public readonly data: AttestationCaseData; + public readonly data: AttestationCaseData | undefined; public readonly typedEntity: TypedEntity; // from interface AttestationAction public readonly propertiesForAction: IEntityColumn[]; // from interface AttestationAction - public readonly uiData: AttestationCaseUiData; + public readonly uiData: AttestationCaseUiData | undefined; - public get hasPolicyViolation() { - return this.data?.PolicyViolations?.length > 0; + public get hasPolicyViolation(): boolean { + return !!this.data?.PolicyViolations?.length; } private directDecisionTarget = 0; @@ -62,7 +62,7 @@ export class AttestationCase extends PortalAttestationApprove implements Attesta private readonly baseObject: PortalAttestationApprove, private readonly isChiefApproval: boolean, private readonly parameterDataContainer: ParameterDataContainer, - extendedCollectionData: { index: number } & AttCaseDataRead + extendedCollectionData: { index: number } & AttCaseDataRead, ) { super(baseObject.GetEntity()); @@ -92,11 +92,13 @@ export class AttestationCase extends PortalAttestationApprove implements Attesta .filter((property) => property.value != null && property.value !== '') .map((property) => new BaseCdr(property.Column, extendedCollectionData[property.Column.ColumnName])); - this.data = extendedCollectionData.Data ? extendedCollectionData.Data[extendedCollectionData.index] : undefined; + this.data = extendedCollectionData.Data + ? { ...extendedCollectionData.Data[extendedCollectionData.index], WorkflowSteps: extendedCollectionData.WorkflowSteps } + : undefined; this.uiData = extendedCollectionData.UiData ? extendedCollectionData.UiData[extendedCollectionData.index] : undefined; if (this.data) { - this.workflowWrapper = new WorkflowDataWrapper(this.data); + this.workflowWrapper = new WorkflowDataWrapper({ ...this.data, WorkflowSteps: extendedCollectionData.WorkflowSteps }); } } @@ -106,12 +108,12 @@ export class AttestationCase extends PortalAttestationApprove implements Attesta public async commit(reload = true): Promise { this.baseObject.extendedData = this.parameterDataContainer.getEntityWriteDataColumns(); - if (this.baseObject.extendedData.DialogParameter[0].length > 0 || this.baseObject.GetEntity().GetDiffData().Data.length > 0) { + if (this.baseObject.extendedData.DialogParameter[0].length > 0 || !!this.baseObject.GetEntity().GetDiffData().Data?.length) { try { await this.baseObject.GetEntity().Commit(reload); } catch (error) { await this.baseObject.GetEntity().DiscardChanges(); - this.baseObject.extendedData = undefined; + this.baseObject.extendedData = {}; throw error; } } diff --git a/imxweb/projects/att/src/lib/decision/attestation-cases.service.ts b/imxweb/projects/att/src/lib/decision/attestation-cases.service.ts index 3f7d4a8f3..2a9b5dfe5 100644 --- a/imxweb/projects/att/src/lib/decision/attestation-cases.service.ts +++ b/imxweb/projects/att/src/lib/decision/attestation-cases.service.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -27,20 +27,6 @@ import { Injectable } from '@angular/core'; import { EuiDownloadOptions } from '@elemental-ui/core'; -import { - CollectionLoadParameters, - EntityCollectionData, - GroupInfoData, - DataModel, - MethodDefinition, - TypedEntity, - TypedEntityBuilder, - TypedEntityCollectionData, - EntitySchema, - IReadValue, - FilterTreeData, - MethodDescriptor, -} from 'imx-qbm-dbts'; import { ApiClientMethodFactory, AttestationCaseData, @@ -54,14 +40,29 @@ import { PwoQueryInput, ReasonInput, V2ApiClientMethodFactory, -} from 'imx-api-att'; +} from '@imx-modules/imx-api-att'; +import { + CollectionLoadParameters, + DataModel, + EntityCollectionData, + EntitySchema, + FilterTreeData, + GroupInfoData, + IReadValue, + MethodDefinition, + MethodDescriptor, + TypedEntity, + TypedEntityBuilder, + TypedEntityCollectionData, +} from '@imx-modules/imx-qbm-dbts'; +import { AppConfigService, DataSourceToolbarExportMethod, ElementalUiConfigService } from 'qbm'; +import { ApproverContainer, ParameterDataLoadParameters, ParameterDataService } from 'qer'; import { ApiService } from '../api.service'; +import { AttestationCaseLoadParameters } from '../attestation-history/attestation-case-load-parameters.interface'; +import { AttestationHistoryCase } from '../attestation-history/attestation-history-case'; +import { Approvers } from './approvers.interface'; import { AttestationCase } from './attestation-case'; -import { ParameterDataService, ParameterDataLoadParameters, ApproverContainer } from 'qer'; -import { AppConfigService, DataSourceToolbarExportMethod, ElementalUiConfigService, ParameterizedTextComponent } from 'qbm'; import { AttestationDecisionLoadParameters } from './attestation-decision-load-parameters'; -import { Approvers } from './approvers.interface'; -import { AttestationCaseLoadParameters } from '../attestation-history/attestation-case-load-parameters.interface'; @Injectable({ providedIn: 'root', @@ -75,7 +76,7 @@ export class AttestationCasesService { private readonly attClient: ApiService, private readonly parameterDataService: ParameterDataService, private readonly elementalUiConfigService: ElementalUiConfigService, - private readonly config: AppConfigService + private readonly config: AppConfigService, ) {} public get attestationApproveSchema(): EntitySchema { @@ -86,11 +87,18 @@ export class AttestationCasesService { return this.attClient.typedClient.PortalAttestationCase.GetSchema(); } - public async get(attDecisionParameters?: AttestationDecisionLoadParameters, isUserEscalationApprover= false): Promise> { + public async get( + attDecisionParameters?: AttestationDecisionLoadParameters, + isUserEscalationApprover = false, + signal?: AbortSignal, + ): Promise> { + const navigationState = { + ...attDecisionParameters, + Escalation: + ((attDecisionParameters?.uid_attestationcase ?? '') !== '' && isUserEscalationApprover) || attDecisionParameters?.Escalation, + }; - const navigationState = { ...attDecisionParameters, Escalation: (attDecisionParameters.uid_attestationcase !== '' && isUserEscalationApprover) || attDecisionParameters.Escalation }; - - const collection = await this.attClient.typedClient.PortalAttestationApprove.Get(navigationState); + const collection = await this.attClient.typedClient.PortalAttestationApprove.Get(navigationState, { signal }); return { tableName: collection.tableName, totalCount: collection.totalCount, @@ -99,7 +107,7 @@ export class AttestationCasesService { item.GetEntity(), { ...collection.extendedData, ...{ index } }, (parameters) => this.getParameterCandidates(parameters), - (treefilterparameter) => this.getFilterTree(treefilterparameter) + (treefilterparameter) => this.getFilterTree(treefilterparameter), ); return new AttestationCase(item, this.isChiefApproval, parameterDataContainer, { ...collection.extendedData, ...{ index } }); @@ -113,13 +121,13 @@ export class AttestationCasesService { getMethod: (withProperties: string, PageSize?: number) => { let method: MethodDescriptor; if (PageSize) { - method = factory.portal_attestation_approve_get({...attDecisionParameters, withProperties, PageSize, StartIndex: 0}) + method = factory.portal_attestation_approve_get({ ...attDecisionParameters, withProperties, PageSize, StartIndex: 0 }); } else { - method = factory.portal_attestation_approve_get({...attDecisionParameters, withProperties}) + method = factory.portal_attestation_approve_get({ ...attDecisionParameters, withProperties }); } return new MethodDefinition(method); - } - } + }, + }; } public async getNumberOfPending(parameters: AttestationCaseLoadParameters): Promise { @@ -141,31 +149,41 @@ export class AttestationCasesService { } public async getApprovers( - attestationCase: TypedEntity & { - DecisionLevel: IReadValue; - UID_QERWorkingMethod: IReadValue; - data: AttestationCaseData; - } + attestationCase: + | (TypedEntity & { + DecisionLevel: IReadValue; + UID_QERWorkingMethod: IReadValue; + data: AttestationCaseData; + }) + | AttestationHistoryCase + | AttestationCase, ): Promise { + const pwoData = { + WorkflowHistory: attestationCase.data?.WorkflowHistory, + WorkflowData: attestationCase.data?.WorkflowData, + WorkflowSteps: attestationCase.data?.WorkflowSteps, + }; const approverContainer = new ApproverContainer({ decisionLevel: attestationCase.DecisionLevel.value, qerWorkingMethod: attestationCase.UID_QERWorkingMethod.value, - pwoData: attestationCase.data, - approvers: (await this.attClient.client.portal_attestation_persondecision_get(this.getKey(attestationCase))).Entities.map( - (item) => item.Columns.UID_Person.Value - ), + pwoData, + approvers: + (await this.attClient.client.portal_attestation_persondecision_get(this.getKey(attestationCase))).Entities?.map( + (item) => item.Columns?.UID_Person.Value, + ) || [], }); return { current: approverContainer.approverNow, future: approverContainer.approverFuture, + canSeeSteps: approverContainer.canSeeSteps, }; } - public createHistoryTypedEntities(data: AttestationCaseData): TypedEntityCollectionData { + public createHistoryTypedEntities(data?: AttestationCaseData): TypedEntityCollectionData { return this.historyBuilder.buildReadWriteEntities( - data.WorkflowHistory, - this.attClient.typedClient.PortalAttestationCaseHistory.GetSchema() + data?.WorkflowHistory || { TotalCount: 0 }, + this.attClient.typedClient.PortalAttestationCaseHistory.GetSchema(), ); } @@ -295,9 +313,9 @@ export class AttestationCasesService { }; return this.attClient.client.portal_attestation_approve_parameter_candidates_post( parameters.columnName, - parameters.fkTableName, - parameters.diffData, - parameter + parameters.fkTableName || '', + parameters.diffData || {}, + parameter, ); } @@ -308,9 +326,9 @@ export class AttestationCasesService { }; return this.attClient.client.portal_attestation_approve_parameter_candidates_filtertree_post( parameters.columnName, - parameters.fkTableName, - parameters.diffData, - parameter + parameters.fkTableName || '', + parameters.diffData || {}, + parameter, ); } } diff --git a/imxweb/projects/att/src/lib/decision/attestation-decision-load-parameters.ts b/imxweb/projects/att/src/lib/decision/attestation-decision-load-parameters.ts index 5e5ce769e..48eb6782d 100644 --- a/imxweb/projects/att/src/lib/decision/attestation-decision-load-parameters.ts +++ b/imxweb/projects/att/src/lib/decision/attestation-decision-load-parameters.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -24,7 +24,7 @@ * */ -import { CollectionLoadParameters } from 'imx-qbm-dbts'; +import { CollectionLoadParameters } from '@imx-modules/imx-qbm-dbts'; export interface AttestationDecisionLoadParameters extends CollectionLoadParameters { Escalation?: boolean; @@ -38,5 +38,5 @@ export enum AttestationDecisionAction { approve, deny, denydecision, - showcase + showcase, } diff --git a/imxweb/projects/att/src/lib/decision/attestation-decision.component.html b/imxweb/projects/att/src/lib/decision/attestation-decision.component.html index e252c7fd4..02a25f215 100644 --- a/imxweb/projects/att/src/lib/decision/attestation-decision.component.html +++ b/imxweb/projects/att/src/lib/decision/attestation-decision.component.html @@ -1,10 +1,18 @@ -

    - {{ '#LDS#Heading Pending Attestations' | translate }} - -

    +
    +

    + {{ '#LDS#Heading Pending Attestations' | translate }} + +

    + +
    - + @@ -24,132 +32,130 @@

    - -
    - - {{ '#LDS#Show attestation cases to be approved by chief approval team' | translate }} - -
    - + - -
    - - - - - - - - -
    -
    - - {{ '#LDS#Policy violation' | translate }} -
    -
    - add_circle - {{ '#LDS#New' | translate }} -
    -
    - - {{ item.RiskIndex.Column.GetDisplayValue() }} -
    -
    - - {{ '#LDS#Overdue' | translate }} -
    -
    - - {{ '#LDS#Rule violation' | translate }} -
    -
    - - {{ '#LDS#Reserved' | translate }} -
    -
    -
    -
    - - -
    - - -
    -
    -
    - - -
    - -
    -
    -
    -
    -
    - -
    + {{ '#LDS#Show attestation cases to be approved by chief approval team' | translate }} + +

    + + + + {{ entitySchema?.Columns?.UiText?.Display }} + + + + + + + + +
    +
    + + {{ '#LDS#Policy violation' | translate }} +
    +
    + add_circle + {{ '#LDS#New' | translate }} +
    +
    + + {{ item.RiskIndex.Column.GetDisplayValue() }} +
    +
    + + {{ '#LDS#Overdue' | translate }} +
    +
    + + {{ '#LDS#Rule violation' | translate }} +
    +
    + + {{ '#LDS#Reserved' | translate }} +
    +
    + +
    + + + +
    + + +
    + +
    + + + +
    + +
    + +
    +
    + -
    - -
    +
    + + + + + diff --git a/imxweb/projects/att/src/lib/decision/attestation-decision.component.scss b/imxweb/projects/att/src/lib/decision/attestation-decision.component.scss index aa00c1cd3..e2d2ac0b0 100644 --- a/imxweb/projects/att/src/lib/decision/attestation-decision.component.scss +++ b/imxweb/projects/att/src/lib/decision/attestation-decision.component.scss @@ -1,5 +1,6 @@ @import '@elemental-ui/core/src/styles/_eui_palette.scss'; -@import '../../../../../shared/scss/common-table.scss'; +@import 'base/mixins'; + :host { display: flex; flex-direction: column; @@ -14,51 +15,27 @@ overflow: hidden; } - .hidden { - display: none; - } - - .mat-tab-group { - height: 100%; - overflow: hidden; - - ::ng-deep .mat-tab-body-wrapper { - flex: 1 1 auto; - - .mat-tab-body-content { - height: 100%; - overflow: hidden; - display: flex; - flex-direction: column; - } - } - } - - .mat-stroked-button, - .mat-raised-button { - @include imx-icon-for-image-button(); - } - - .imx-table-container { - @include imx-flex-fill-control-hidden-overflow(); + .mat-mdc-outlined-button, + .mat-mdc-unelevated-button { + @include image-button-icon(); } > * { margin-right: 16px; } +} - .mat-icon { - margin-right: 5px; - font-size: 24px; - } +.hidden { + display: none; } + .imx-attestationcase-table { flex-grow: 1; overflow: auto; } .imx-decision { - @include imx-button-column-right(); + @include button-column-right(); > button:not(:last-of-type) { margin-right: 5px; } @@ -71,51 +48,6 @@ justify-content: center; } -.imx-button-bar { - @include imx-button-bar(); -} - -.imx-icons-container { - padding-right: 15px; - .table-icon { - display: flex; - align-items: center; - color: $color-gray-60; - font-weight: 600; - height: 14px; - &--warning { - .eui-icon { - color: $color-orange-60; - } - } - &--new { - .mat-icon { - color: $color-green-60; - } - } - &--info { - .mat-icon { - color: $color-gray-60; - } - } - &--alert { - .eui-icon, - span { - color: $color-red-60; - } - } - &:not(:first-of-type) { - margin-left: 8px; - border-left: 1px solid $color-gray-20; - padding-left: 8px; - } - .mat-icon, - .eui-icon { - padding-right: 6px; - } - } -} - .toggle-wrapper { margin-bottom: 1em; } @@ -125,82 +57,3 @@ display: none; } } - -// Theming -:host { - ::ng-deep .mat-tab-labels { - background-color: $color-gray-0; - } - - .recommendation-approve-icon { - color: $color-green-60; - } - - .recommendation-deny-icon { - color: $color-red-60; - } -} - -.eui-dark-theme { - :host { - ::ng-deep .mat-tab-labels { - background-color: $color-gray-80; - } - - .recommendation-approve-icon { - color: $color-green-40; - } - - .recommendation-deny-icon { - color: $color-red-40; - } - .imx-icons-container { - .table-icon { - color: $color-gray-10; - &--warning { - .eui-icon { - color: $color-orange-40; - } - } - &--new { - .mat-icon { - color: $color-green-40; - } - } - &--info { - .mat-icon { - color: $color-gray-10; - } - } - &--alert { - .eui-icon, - span { - color: $color-red-40; - } - } - } - } - } -} - -.eui-contrast-theme { - :host { - ::ng-deep .mat-tab-labels { - background-color: $color-gray-100; - } - - .recommendation-approve-icon { - color: $color-green-40; - } - - .recommendation-deny-icon { - color: $color-red-40; - } - - .imx-icons-container { - .table-icon { - color: inherit; - } - } - } -} diff --git a/imxweb/projects/att/src/lib/decision/attestation-decision.component.ts b/imxweb/projects/att/src/lib/decision/attestation-decision.component.ts index 0c8d00108..b36ce7e06 100644 --- a/imxweb/projects/att/src/lib/decision/attestation-decision.component.ts +++ b/imxweb/projects/att/src/lib/decision/attestation-decision.component.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -24,53 +24,60 @@ * */ -import { OverlayRef } from '@angular/cdk/overlay'; -import { Component, OnDestroy, OnInit, ViewChild } from '@angular/core'; +import { Component, OnDestroy, OnInit } from '@angular/core'; import { MatDialog } from '@angular/material/dialog'; import { ActivatedRoute } from '@angular/router'; import { EuiLoadingService, EuiSidesheetService } from '@elemental-ui/core'; +import { TranslateService } from '@ngx-translate/core'; import { Subscription } from 'rxjs'; import { first } from 'rxjs/operators'; -import { TranslateService } from '@ngx-translate/core'; -import { CollectionLoadParameters, CompareOperator, DataModel, FilterType, TypedEntity, ValType } from 'imx-qbm-dbts'; +import { EntitlementLossDto, RecommendationEnum } from '@imx-modules/imx-api-att'; +import { ViewConfigData } from '@imx-modules/imx-api-qer'; +import { + CollectionLoadParameters, + CompareOperator, + DataModel, + EntitySchema, + FilterType, + TypedEntityCollectionData, + ValType, +} from '@imx-modules/imx-qbm-dbts'; import { AuthenticationService, BusyService, - DataSourceToolbarFilter, - DataSourceToolbarGroupData, - DataSourceToolbarSettings, DataSourceToolbarViewConfig, - DataTableComponent, - DataTableGroupedData, + DataViewInitParameters, + DataViewSource, MessageDialogComponent, - SettingsService, + QueuedActionState, UserMessageService, + calculateSidesheetWidth, + isMobile, + setFilterDisplay, } from 'qbm'; -import { AttestationCasesService } from './attestation-cases.service'; -import { AttestationCaseComponent } from './attestation-case.component'; +import { PendingItemsType, RecommendationSidesheetComponent, UserModelService, ViewConfigService } from 'qer'; +import { ApiService } from '../api.service'; import { AttestationActionService } from '../attestation-action/attestation-action.service'; -import { AttestationCase } from './attestation-case'; +import { AttestationFeatureGuardService } from '../attestation-feature-guard.service'; import { Approvers } from './approvers.interface'; +import { AttestationCase } from './attestation-case'; +import { AttestationCaseComponent } from './attestation-case.component'; +import { AttestationCasesService } from './attestation-cases.service'; import { AttestationDecisionAction, AttestationDecisionLoadParameters } from './attestation-decision-load-parameters'; -import { ApiService } from '../api.service'; -import { createGroupData } from '../datamodel/datamodel-helper'; -import { AttestationFeatureGuardService } from '../attestation-feature-guard.service'; -import { EntitlementLossDto, RecommendationEnum } from 'imx-api-att'; import { LossPreviewDialogComponent } from './loss-preview-dialog/loss-preview-dialog.component'; import { LossPreview } from './loss-preview.interface'; -import { PendingItemsType, RecommendationSidesheetComponent, UserModelService, ViewConfigService } from 'qer'; -import { ViewConfigData } from 'imx-api-qer'; @Component({ templateUrl: './attestation-decision.component.html', styleUrls: ['./attestation-decision.component.scss'], + providers: [DataViewSource], }) export class AttestationDecisionComponent implements OnInit, OnDestroy { - public dstSettings: DataSourceToolbarSettings; + public stateOptions = QueuedActionState; public selectedCases: AttestationCase[] = []; public userUid: string; - public hideToolbar:boolean = false; + public hideToolbar: boolean = false; public recApprove = RecommendationEnum.Approve; public recDeny = RecommendationEnum.Deny; @@ -90,37 +97,51 @@ export class AttestationDecisionComponent implements OnInit, OnDestroy { public get canDenyApproval(): boolean { return this.selectedCases.every((item) => item.canDenyApproval(this.userUid)); } - public get canEscalateDecisions(): boolean { + public get canEscalateDecision(): boolean { return this.selectedCases.every((item) => item.canEscalateDecision(this.userUid)); } + public get canSendInquiry(): boolean { + return this.selectedCases.every((item) => item.canAskAQuestion); + } + public get canRecallInquiry(): boolean { + return this.selectedCases.every((item) => item.IsReserved.value && item.hasAskedLastQuestion(this.userUid)); + } + public get canCancelReservation(): boolean { + return this.selectedCases.every( + (item) => item.IsReserved.value && (item.hasAskedLastQuestion(this.userUid) || this.isUserEscalationApprover), + ); + } public get canPerformActions(): boolean { return ( this.selectedCases.length > 0 && - (this.canWithdrawAddApprover || this.canAddApprover || this.canDelegateDecision || this.canDenyApproval || this.canReRouteDecision) + (this.canWithdrawAddApprover || + this.canAddApprover || + this.canDelegateDecision || + this.canDenyApproval || + this.canReRouteDecision || + this.canEscalateDecision || + this.canRecallInquiry || + this.canSendInquiry || + this.canCancelReservation) ); } public isUserEscalationApprover = false; public mitigatingControlsPerViolation: boolean; - public groupedData: { [key: string]: DataTableGroupedData } = {}; public allLossPreviewItems: EntitlementLossDto[]; public lossPreview: LossPreview; public hasInquiries: boolean; public tabIndex = 0; public busyService = new BusyService(); - public entitySchema = this.attestationCases.attestationApproveSchema; + public entitySchema: EntitySchema; - private approvalThreshold: number; + private approvalThreshold: number | undefined; private autoRemovalScope: boolean; - private navigationState: AttestationDecisionLoadParameters; - private filterOptions: DataSourceToolbarFilter[] = []; private dataModel: DataModel; - private groupData: DataSourceToolbarGroupData; private decisionAction: AttestationDecisionAction = AttestationDecisionAction.none; - private readonly collectionLoadParameters; + private additionalParameter: { uid_attestationhelper?: string; uid_attestationcase?: string } = {}; private readonly subscriptions: Subscription[] = []; - @ViewChild(DataTableComponent) private readonly table: DataTableComponent; private viewConfig: DataSourceToolbarViewConfig; private viewConfigPath = 'attestation/approve'; @@ -139,22 +160,21 @@ export class AttestationDecisionComponent implements OnInit, OnDestroy { private viewConfigService: ViewConfigService, private dialog: MatDialog, private readonly usermodelService: UserModelService, - settingsService: SettingsService, - authentication: AuthenticationService + authentication: AuthenticationService, + public dataSource: DataViewSource, ) { - this.collectionLoadParameters = { PageSize: settingsService.DefaultPageSize, StartIndex: 0 }; - this.navigationState = this.collectionLoadParameters; + this.entitySchema = this.attestationCases.attestationApproveSchema; this.subscriptions.push( this.attestationAction.applied.subscribe(() => { - this.getData(); - this.table?.clearSelection(); - }) + this.dataSource.updateState(); + this.dataSource.selection.clear(); + }), ); this.subscriptions.push( authentication.onSessionResponse.subscribe((sessionState) => { - this.userUid = sessionState?.UserUid; + this.userUid = sessionState?.UserUid || ''; this.attestationCases.isChiefApproval = false; - }) + }), ); this.attFeatureService.getAttestationConfig().then((config) => { @@ -163,10 +183,6 @@ export class AttestationDecisionComponent implements OnInit, OnDestroy { }); } - get isMobile(): boolean { - return document.body.offsetWidth <= 768; - } - public get viewEscalation(): boolean { return this.attestationCases.isChiefApproval; } @@ -174,18 +190,12 @@ export class AttestationDecisionComponent implements OnInit, OnDestroy { this.attestationCases.isChiefApproval = val; // reload data model for changed filter options when the user toggles escalation mode - this.initDataModel(); - } - - public switchEscalation(): Promise { - return this.getData(); + this.getData(); } public async ngOnInit(): Promise { - let isBusy: any; - setTimeout(() => { - isBusy = this.busyService.beginBusy(); - }); + const isBusy = this.busyService.beginBusy(); + try { const config = await this.attService.client.portal_attestation_config_get(); const pendingItems: PendingItemsType = await this.usermodelService.getPendingItems(); @@ -202,19 +212,16 @@ export class AttestationDecisionComponent implements OnInit, OnDestroy { Person: '#LDS#Affected identity', }, }; - if (params.inquiries) { + if (params?.inquiries) { this.tabIndex = 1; this.hasInquiries = true; } - await this.initDataModel(true); await this.parseParams(); await this.getData(); this.handleDecision(); } finally { - setTimeout(() => { - isBusy.endBusy(); - }); + isBusy.endBusy(); } } @@ -225,13 +232,13 @@ export class AttestationDecisionComponent implements OnInit, OnDestroy { public async updateConfig(config: ViewConfigData): Promise { await this.viewConfigService.putViewConfig(config); this.viewConfig = await this.viewConfigService.getDSTExtensionChanges(this.viewConfigPath); - this.dstSettings.viewConfig = this.viewConfig; + this.dataSource.viewConfig.set(this.viewConfig); } public async deleteConfigById(id: string): Promise { await this.viewConfigService.deleteViewConfig(id); this.viewConfig = await this.viewConfigService.getDSTExtensionChanges(this.viewConfigPath); - this.dstSettings.viewConfig = this.viewConfig; + this.dataSource.viewConfig.set(this.viewConfig); } public isNewLoss(loss: EntitlementLossDto): boolean { @@ -244,8 +251,9 @@ export class AttestationDecisionComponent implements OnInit, OnDestroy { this.attestationAction[func](cases); return; } - let busyIndicator: OverlayRef; - setTimeout(() => (busyIndicator = this.busyServiceElemental.show())); + if (this.busyServiceElemental.overlayRefs.length === 0) { + this.busyServiceElemental.show(); + } try { // Accumulate all losses this.allLossPreviewItems = []; @@ -257,10 +265,10 @@ export class AttestationDecisionComponent implements OnInit, OnDestroy { this.allLossPreviewItems.push(loss); } }); - }) + }), ); } finally { - setTimeout(() => this.busyServiceElemental.hide(busyIndicator)); + this.busyServiceElemental.hide(); } if (this.allLossPreviewItems.length === 0) { // There are no losses, go ahead with handle @@ -271,8 +279,8 @@ export class AttestationDecisionComponent implements OnInit, OnDestroy { this.lossPreview.LossPreviewItems = this.allLossPreviewItems; const selection = await this.dialog .open(LossPreviewDialogComponent, { - width: this.isMobile ? '90vw' : '60vw', - maxWidth: this.isMobile ? '90vw' : '80vw', + width: isMobile() ? '90vw' : '60vw', + maxWidth: isMobile() ? '90vw' : '80vw', height: '70vh', maxHeight: '70vh', data: this.lossPreview, @@ -286,76 +294,69 @@ export class AttestationDecisionComponent implements OnInit, OnDestroy { } } - public async search(search: string): Promise { - return this.getData({ ...this.navigationState, ...{ search } }); - } - - public async getData(newState?: CollectionLoadParameters): Promise { - if (newState) { - this.navigationState = newState; - } - - const isBusy = this.busyService.beginBusy(); - + public async getData(): Promise { + const displayedColumns = [ + this.entitySchema.Columns.UiText, + { + ColumnName: 'badges', + Type: ValType.String, + untranslatedDisplay: '#LDS#Badges', + }, + { + ColumnName: 'decision', + Type: ValType.String, + afterAdditionals: true, + untranslatedDisplay: '#LDS#Decision', + }, + { + ColumnName: 'recommendations', + Type: ValType.String, + afterAdditionals: true, + untranslatedDisplay: '#LDS#Recommendation', + }, + ]; + let busyIndicator = this.busyServiceElemental.show(); try { - const params: AttestationDecisionLoadParameters = { - Escalation: this.attestationCases.isChiefApproval, - ...this.navigationState, - }; - const dataSource = await this.attestationCases.get(params,this.isUserEscalationApprover); - const exportMethod = this.attestationCases.exportData(params); - this.dstSettings = { - dataSource, - entitySchema: this.entitySchema, - navigationState: this.navigationState, - filters: this.filterOptions, - dataModel: this.dataModel, - groupData: this.groupData, - displayedColumns: [ - this.entitySchema.Columns.UiText, - { - ColumnName: 'badges', - Type: ValType.String, - untranslatedDisplay: '#LDS#Badges', - }, - { - ColumnName: 'decision', - Type: ValType.String, - afterAdditionals: true, - untranslatedDisplay: '#LDS#Decision', - }, - { - ColumnName: 'recommendations', - Type: ValType.String, - afterAdditionals: true, - untranslatedDisplay: '#LDS#Recommendation', - }, - ], - exportMethod, - viewConfig: this.viewConfig, - }; + this.dataModel = await this.attestationCases.getDataModel(); + this.viewConfig = await this.viewConfigService.getInitialDSTExtension(this.dataModel, this.viewConfigPath); } finally { - isBusy.endBusy(); + this.busyServiceElemental.hide(busyIndicator); } - } - - public async onGroupingChange(groupKey: string): Promise { - const isBusy = this.busyService.beginBusy(); - try { - const groupedData = this.groupedData[groupKey]; - const navigationState = { ...groupedData.navigationState, Escalation: this.viewEscalation }; - groupedData.data = await this.attestationCases.get(navigationState,this.isUserEscalationApprover); - groupedData.settings = { - displayedColumns: this.dstSettings.displayedColumns, - dataModel: this.dstSettings.dataModel, - dataSource: groupedData.data, - entitySchema: this.dstSettings.entitySchema, - navigationState, - }; - } finally { - isBusy.endBusy(); - } + const dataViewInitParameters: DataViewInitParameters = { + execute: (params: CollectionLoadParameters, signal: AbortSignal): Promise> => { + const newParams: AttestationDecisionLoadParameters = { + Escalation: this.viewEscalation, + ...params, + }; + if (this.additionalParameter.uid_attestationcase) { + newParams.uid_attestationcase = this.additionalParameter.uid_attestationcase; + } + if (this.additionalParameter.uid_attestationhelper) { + newParams.uid_attestationhelper = this.additionalParameter.uid_attestationhelper; + } + return this.attestationCases.get(newParams, this.isUserEscalationApprover, signal); + }, + schema: this.entitySchema, + columnsToDisplay: displayedColumns, + dataModel: this.dataModel, + exportFunction: this.attestationCases.exportData(this.dataSource.state()), + viewConfig: this.viewConfig, + highlightEntity: (identity: AttestationCase) => { + this.edit(identity); + }, + groupExecute: (column: string, params: CollectionLoadParameters, signal: AbortSignal) => { + return this.attestationCases.getGroupInfo(this.getGroupParams(column, params)).then((groupData) => { + groupData.Groups?.map((group) => { + setFilterDisplay(group); + return group; + }); + return groupData; + }); + }, + selectionChange: (selection: AttestationCase[]) => this.onSelectionChanged(selection), + }; + await this.dataSource.init(dataViewInitParameters); } public onSelectionChanged(cases: AttestationCase[]): void { @@ -364,38 +365,44 @@ export class AttestationDecisionComponent implements OnInit, OnDestroy { public async edit(attestationCase: AttestationCase): Promise { let attestationCaseWithPolicy: AttestationCase; - let approvers: Approvers; - - let busyIndicator: OverlayRef; - setTimeout(() => (busyIndicator = this.busyServiceElemental.show())); + let approvers: Approvers | undefined; + if (this.busyServiceElemental.overlayRefs.length === 0) { + this.busyServiceElemental.show(); + } try { attestationCaseWithPolicy = ( - await this.attestationCases.get({ - Escalation: this.viewEscalation, - uidpolicy: attestationCase.UID_AttestationPolicy.value, - filter: [ - { - ColumnName: 'UID_AttestationCase', - Type: FilterType.Compare, - CompareOp: CompareOperator.Equal, - Value1: attestationCase.GetEntity().GetKeys()[0], - }, - ], - },this.isUserEscalationApprover) + await this.attestationCases.get( + { + Escalation: this.isUserEscalationApprover, + uidpolicy: attestationCase.UID_AttestationPolicy.value, + filter: [ + { + ColumnName: 'UID_AttestationCase', + Type: FilterType.Compare, + CompareOp: CompareOperator.Equal, + Value1: attestationCase.GetEntity().GetKeys()[0], + }, + ], + }, + this.isUserEscalationApprover, + ) ).Data[0]; // Add additional violation data to this case - attestationCaseWithPolicy.data.CanSeeComplianceViolations = attestationCase.data.CanSeeComplianceViolations; - attestationCaseWithPolicy.data.ComplianceViolations = attestationCase.data.ComplianceViolations; - attestationCaseWithPolicy.data.CanSeePolicyViolations = attestationCase.data.CanSeePolicyViolations; - attestationCaseWithPolicy.data.PolicyViolations = attestationCase.data.PolicyViolations; + if (attestationCaseWithPolicy?.data) { + attestationCaseWithPolicy.data.CanSeeComplianceViolations = !!attestationCase.data?.CanSeeComplianceViolations; + attestationCaseWithPolicy.data.ComplianceViolations = attestationCase.data?.ComplianceViolations || []; + attestationCaseWithPolicy.data.CanSeePolicyViolations = !!attestationCase.data?.CanSeePolicyViolations; + attestationCaseWithPolicy.data.PolicyViolations = attestationCase.data?.PolicyViolations || []; + attestationCaseWithPolicy.data.WorkflowSteps = attestationCase.data?.WorkflowSteps; + } if (attestationCaseWithPolicy && !['approved', 'denied'].includes(attestationCaseWithPolicy.AttestationState.value)) { approvers = await this.attestationCases.getApprovers(attestationCaseWithPolicy); } this.lossPreview.Case = attestationCase; } finally { - setTimeout(() => this.busyServiceElemental.hide(busyIndicator)); + this.busyServiceElemental.hide(); } if (attestationCaseWithPolicy) { @@ -403,7 +410,7 @@ export class AttestationDecisionComponent implements OnInit, OnDestroy { title: await this.translate.get('#LDS#Heading View Attestation Case Details').toPromise(), subTitle: attestationCaseWithPolicy.GetEntity().GetDisplay(), padding: '0px', - width: 'max(70%,768px)', + width: calculateSidesheetWidth(1000), testId: 'attestation-case-sidesheet', data: { case: attestationCaseWithPolicy, @@ -430,9 +437,17 @@ export class AttestationDecisionComponent implements OnInit, OnDestroy { subTitle: attestationCase.GetEntity().GetDisplay(), panelClass: 'imx-sidesheet', padding: '0', - width: 'max(700px, 60%)', + width: calculateSidesheetWidth(1000), testId: 'attestation-recommendation-sidesheet', - data: attestationCase.data.Recommendation, + data: { + recommendations: attestationCase.data?.Recommendation, + informationTexts: { + approve: '#LDS#Based on an analysis of currently available data, it is recommended that you approve this attestation case.', + reject: '#LDS#Based on an analysis of currently available data, it is recommended that you deny this attestation case.', + noRecord: + '#LDS#Based on an analysis of currently available data, no definitive recommendation can be made for this attestation case.', + }, + }, }) .afterClosed() .toPromise(); @@ -444,40 +459,12 @@ export class AttestationDecisionComponent implements OnInit, OnDestroy { } } - private async initDataModel(checkConfigs = false): Promise { - this.dataModel = await this.attestationCases.getDataModel(); - this.viewConfig = await this.viewConfigService.getInitialDSTExtension(this.dataModel, this.viewConfigPath); - if (checkConfigs) { - // We will check the configs for default state only on ini - if (!this.viewConfigService.isDefaultConfigSet()) { - // If we have no default settings, we will use the due date to sort - this.navigationState.OrderBy = 'ToSolveTill'; - } - } - - this.filterOptions = this.dataModel?.Filters ?? []; - - this.groupData = createGroupData( - this.dataModel, - (parameters) => - this.attestationCases.getGroupInfo({ - ...{ - PageSize: this.collectionLoadParameters.PageSize, - StartIndex: 0, - }, - ...parameters, - }), - [] - ); - } - private async parseParams(): Promise { - const queryParams = await this.activatedRoute.queryParams.pipe(first()).toPromise(); + const queryParams = (await this.activatedRoute.queryParams.pipe(first()).toPromise()) || []; // Cases: VI_BuildAttestationLink_Approve, VI_BuildAttestationLink_Deny, VI_BuildAttestationLink_Reject if (queryParams['uid_attestationhelper'] && queryParams['decision']) { - this.navigationState.uid_attestationhelper = queryParams['uid_attestationhelper']; - + this.additionalParameter.uid_attestationhelper = queryParams['uid_attestationhelper']; // Will otherwise result in a string this.decisionAction = AttestationDecisionAction[queryParams['decision'].toLowerCase()] as unknown as AttestationDecisionAction; return; @@ -485,13 +472,13 @@ export class AttestationDecisionComponent implements OnInit, OnDestroy { // Case: VI_BuildAttestationLink_Show if (queryParams['uid_attestationhelper']) { - this.navigationState.uid_attestationhelper = queryParams['uid_attestationhelper']; + this.additionalParameter.uid_attestationhelper = queryParams['uid_attestationhelper']; return; } // Case: VI_BuildAttestationLink_ViewDetails if (queryParams['uid_attestationcase']) { - this.navigationState.uid_attestationcase = queryParams['uid_attestationcase']; + this.additionalParameter.uid_attestationcase = queryParams['uid_attestationcase']; this.decisionAction = AttestationDecisionAction.showcase; this.hideToolbar = true; return; @@ -506,16 +493,14 @@ export class AttestationDecisionComponent implements OnInit, OnDestroy { return; } - if (this.dstSettings.dataSource.Data == null || this.dstSettings.dataSource.Data.length === 0) { + if (this.dataSource.data.length === 0) { const dialogRef = this.noCaseDialog.open(MessageDialogComponent, { data: { ShowOk: true, - Title: await this.translate.get('#LDS#Heading Cannot Find Attestation Case').toPromise(), - Message: await this.translate - .get( - '#LDS#The attestation case does not exist (anymore). To view all attestation cases, close this page and reopen the Pending Attestions page.' - ) - .toPromise(), + Title: await this.translate.instant('#LDS#Heading Cannot Find Attestation Case'), + Message: await this.translate.instant( + '#LDS#The attestation case does not exist (anymore). To view all attestation cases, close this page and reopen the Pending Attestions page.', + ), }, }); return; @@ -523,17 +508,25 @@ export class AttestationDecisionComponent implements OnInit, OnDestroy { switch (this.decisionAction) { case AttestationDecisionAction.approve: - this.attestationAction.approve(this.dstSettings.dataSource.Data as AttestationCase[]); + this.attestationAction.approve(this.dataSource.data); break; case AttestationDecisionAction.deny: - this.attestationAction.deny(this.dstSettings.dataSource.Data as AttestationCase[]); + this.attestationAction.deny(this.dataSource.data); break; case AttestationDecisionAction.denydecision: - this.attestationAction.denyDecisions(this.dstSettings.dataSource.Data as AttestationCase[]); + this.attestationAction.denyDecisions(this.dataSource.data); break; case AttestationDecisionAction.showcase: - this.edit(this.dstSettings.dataSource.Data[0] as AttestationCase); + this.edit(this.dataSource.data[0]); break; } } + + private getGroupParams(column: string, params: CollectionLoadParameters): { by?: string; def?: string } & CollectionLoadParameters { + if (this.dataModel.Properties?.find((property) => property.Property?.ColumnName === column)) { + return { ...params, by: column }; + } else { + return { ...params, def: column }; + } + } } diff --git a/imxweb/projects/att/src/lib/decision/attestation-decision.module.ts b/imxweb/projects/att/src/lib/decision/attestation-decision.module.ts index e274c5ea1..56056c8f3 100644 --- a/imxweb/projects/att/src/lib/decision/attestation-decision.module.ts +++ b/imxweb/projects/att/src/lib/decision/attestation-decision.module.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -28,31 +28,41 @@ import { CommonModule } from '@angular/common'; import { NgModule } from '@angular/core'; import { FormsModule, ReactiveFormsModule } from '@angular/forms'; import { MatButtonModule } from '@angular/material/button'; -import { MatExpansionModule } from '@angular/material/expansion'; import { MatCardModule } from '@angular/material/card'; +import { MatExpansionModule } from '@angular/material/expansion'; import { RouterModule } from '@angular/router'; import { EuiCoreModule, EuiMaterialModule } from '@elemental-ui/core'; import { TranslateModule } from '@ngx-translate/core'; -import { DataSourceToolbarModule, DataTableModule, CdrModule, EntityModule, BulkPropertyEditorModule, DateModule, SelectedElementsModule, HelpContextualModule } from 'qbm'; -import { AttestationDecisionComponent } from './attestation-decision.component'; -import { AttestationCaseComponent } from './attestation-case.component'; -import { AttestationActionComponent } from '../attestation-action/attestation-action.component'; +import { MatDividerModule } from '@angular/material/divider'; +import { MatIconModule } from '@angular/material/icon'; +import { MatTooltipModule } from '@angular/material/tooltip'; +import { + BulkPropertyEditorModule, + CdrModule, + DataSourceToolbarModule, + DataTableModule, + DataViewModule, + DateModule, + EntityModule, + HelpContextualModule, + SelectedElementsModule, +} from 'qbm'; import { JustificationModule, ObjectHyperviewModule, TermsOfUseModule } from 'qer'; -import { DecisionHistoryItemComponent } from './decision-history-item/decision-history-item.component'; -import { ApproversComponent } from './approvers/approvers.component'; -import { EntityPropertyEditorComponent } from '../entity-property-editor/entity-property-editor.component'; +import { AttestationActionComponent } from '../attestation-action/attestation-action.component'; import { AttestationDisplayModule } from '../attestation-display/attestation-display.module'; -import { MatTooltipModule } from '@angular/material/tooltip'; import { AttestationSnapshotModule } from '../attestation-snapshot/attestation-snapshot.module'; -import { LossPreviewDialogComponent } from './loss-preview-dialog/loss-preview-dialog.component'; -import { LossPreviewTableComponent } from './loss-preview-table/loss-preview-table.component'; +import { EntityPropertyEditorComponent } from '../entity-property-editor/entity-property-editor.component'; +import { ApproversComponent } from './approvers/approvers.component'; +import { AttestationCaseComponent } from './attestation-case.component'; +import { AttestationDecisionComponent } from './attestation-decision.component'; +import { AttestationInquiriesComponent } from './attestation-inquiries/attestation-inquiries.component'; import { DecisionComplianceViolationComponent } from './decision-compliance-violation/decision-compliance-violation.component'; +import { DecisionHistoryItemComponent } from './decision-history-item/decision-history-item.component'; import { DecisionPolicyViolationComponent } from './decision-policy-violation/decision-policy-violation.component'; +import { LossPreviewDialogComponent } from './loss-preview-dialog/loss-preview-dialog.component'; +import { LossPreviewTableComponent } from './loss-preview-table/loss-preview-table.component'; import { MitigatingControlsComponent } from './mitigating-controls/mitigating-controls.component'; -import { AttestationInquiriesComponent } from './attestation-inquiries/attestation-inquiries.component'; -import { MatDividerModule } from '@angular/material/divider'; -import { MatIconModule } from '@angular/material/icon'; @NgModule({ declarations: [ AttestationCaseComponent, @@ -66,7 +76,7 @@ import { MatIconModule } from '@angular/material/icon'; DecisionComplianceViolationComponent, DecisionPolicyViolationComponent, MitigatingControlsComponent, - AttestationInquiriesComponent + AttestationInquiriesComponent, ], imports: [ AttestationSnapshotModule, @@ -96,11 +106,9 @@ import { MatIconModule } from '@angular/material/icon'; SelectedElementsModule, MatIconModule, HelpContextualModule, - ObjectHyperviewModule + ObjectHyperviewModule, + DataViewModule, ], - exports: [ - DecisionHistoryItemComponent, - ApproversComponent - ] + exports: [DecisionHistoryItemComponent, ApproversComponent], }) -export class AttestationDecisionModule { } +export class AttestationDecisionModule {} diff --git a/imxweb/projects/att/src/lib/decision/attestation-inquiries/attestation-inquiries.component.html b/imxweb/projects/att/src/lib/decision/attestation-inquiries/attestation-inquiries.component.html index ba445dc1d..6144eed7c 100644 --- a/imxweb/projects/att/src/lib/decision/attestation-inquiries/attestation-inquiries.component.html +++ b/imxweb/projects/att/src/lib/decision/attestation-inquiries/attestation-inquiries.component.html @@ -1,53 +1,59 @@ - - + - - -
    - - - - - - - - - {{ getInquiryText(item) }} - - - - - {{ getInquirer(item) }} - - - - + [showGrouping]="false" + > + + + {{ entitySchema?.Columns?.UiText?.Display }} + + + + + + + {{ AttestationInquiry.queryCaption | translate }} + + +
    {{ getInquiryText(item) }}
    + +
    + + + {{ AttestationInquiry.headCaption | translate }} + + +
    {{ getInquirer(item) }}
    + +
    + + + {{ AttestationInquiry.queryDate | translate }} + + +
    {{ getQueryDate(item) | shortDate }} - - - - - -
    -
    + + + + + +
    + -
    -
    -
    - -
    - +
    + + + +
    diff --git a/imxweb/projects/att/src/lib/decision/attestation-inquiries/attestation-inquiries.component.scss b/imxweb/projects/att/src/lib/decision/attestation-inquiries/attestation-inquiries.component.scss index 2ac72973f..0e1751f10 100644 --- a/imxweb/projects/att/src/lib/decision/attestation-inquiries/attestation-inquiries.component.scss +++ b/imxweb/projects/att/src/lib/decision/attestation-inquiries/attestation-inquiries.component.scss @@ -1,28 +1,9 @@ -@import '../../../../../../shared/scss/common-table.scss'; - +@import 'base/mixins'; :host { - display: flex; - flex-direction: column; - overflow: hidden; + @include flex-column-container($overflow: hidden); flex-grow: 1; } -.imx-table-container { - flex-grow: 1; - overflow: auto; -} - -.imx-mat-card-container { - overflow: hidden; - display: flex; - flex-direction: column; - height: 100%; -} - -.imx-button-column { - @include imx-button-column-right(); -} - -.mat-stroked-button { - @include imx-icon-for-image-button(); -} +.mat-mdc-card.imx-card-fill{ + margin: 0 0 3px 0; +} \ No newline at end of file diff --git a/imxweb/projects/att/src/lib/decision/attestation-inquiries/attestation-inquiries.component.ts b/imxweb/projects/att/src/lib/decision/attestation-inquiries/attestation-inquiries.component.ts index af5474ef2..873d1b31e 100644 --- a/imxweb/projects/att/src/lib/decision/attestation-inquiries/attestation-inquiries.component.ts +++ b/imxweb/projects/att/src/lib/decision/attestation-inquiries/attestation-inquiries.component.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -24,61 +24,55 @@ * */ -import { OverlayRef } from '@angular/cdk/overlay'; -import { Component, OnDestroy, OnInit, ViewChild } from '@angular/core'; +import { Component, OnDestroy, OnInit } from '@angular/core'; import { EuiLoadingService, EuiSidesheetService } from '@elemental-ui/core'; -import { Subscription } from 'rxjs'; import { TranslateService } from '@ngx-translate/core'; +import { Subscription } from 'rxjs'; -import { PwoExtendedData, ViewConfigData } from 'imx-api-qer'; +import { PwoExtendedData, ViewConfigData } from '@imx-modules/imx-api-qer'; import { - ValType, - ExtendedTypedEntityCollection, - TypedEntity, - EntitySchema, - DataModel, CollectionLoadParameters, - FilterType, CompareOperator, -} from 'imx-qbm-dbts'; + DataModel, + EntitySchema, + ExtendedTypedEntityCollection, + FilterType, + TypedEntityCollectionData, + ValType, +} from '@imx-modules/imx-qbm-dbts'; import { - DataSourceToolbarSettings, - ClassloggerService, AuthenticationService, - DataTableComponent, - SettingsService, - SnackBarService, - UserMessageService, - ClientPropertyForTableColumns, BusyService, + calculateSidesheetWidth, + ClientPropertyForTableColumns, DataSourceToolbarViewConfig, + DataViewInitParameters, + DataViewSource, + UserMessageService, } from 'qbm'; +import { ViewConfigService } from 'qer'; +import { AttestationActionService } from '../../attestation-action/attestation-action.service'; +import { AttestationFeatureGuardService } from '../../attestation-feature-guard.service'; +import { Approvers } from '../approvers.interface'; import { AttestationCase } from '../attestation-case'; import { AttestationCaseComponent } from '../attestation-case.component'; import { AttestationCasesService } from '../attestation-cases.service'; -import { AttestationActionService } from '../../attestation-action/attestation-action.service'; -import { Approvers } from '../approvers.interface'; -import { AttestationFeatureGuardService } from '../../attestation-feature-guard.service'; import { LossPreview } from '../loss-preview.interface'; import { AttestationInquiry } from './attestation-inquiry.model'; -import { ViewConfigService } from 'qer'; @Component({ templateUrl: './attestation-inquiries.component.html', selector: 'imx-attestation-inquiries', styleUrls: ['./attestation-inquiries.component.scss'], + providers: [DataViewSource], }) export class AttestationInquiriesComponent implements OnInit, OnDestroy { - public dstSettings: DataSourceToolbarSettings; public readonly entitySchema: EntitySchema; public attestationCasesCollection: ExtendedTypedEntityCollection; public hasData = false; public isUserEscalationApprover = false; public mitigatingControlsPerViolation: boolean; - @ViewChild(DataTableComponent) private readonly table: DataTableComponent; public lossPreview: LossPreview; - - private navigationState: CollectionLoadParameters; private displayedColumns: ClientPropertyForTableColumns[]; private readonly subscriptions: Subscription[] = []; private dataModel: DataModel; @@ -95,14 +89,11 @@ export class AttestationInquiriesComponent implements OnInit, OnDestroy { private viewConfigService: ViewConfigService, private readonly sidesheet: EuiSidesheetService, private readonly messageService: UserMessageService, - private readonly logger: ClassloggerService, private readonly busyServiceElemental: EuiLoadingService, private readonly translate: TranslateService, - snackbar: SnackBarService, - settingsService: SettingsService, - authentication: AuthenticationService + authentication: AuthenticationService, + public dataSource: DataViewSource, ) { - this.navigationState = { PageSize: settingsService.DefaultPageSize, StartIndex: 0 }; this.entitySchema = attestationCasesService.attestationApproveSchema; (this.displayedColumns = [ { @@ -130,18 +121,16 @@ export class AttestationInquiriesComponent implements OnInit, OnDestroy { this.subscriptions.push( this.actionService.applied.subscribe(async () => { this.getData(); - this.table.clearSelection(); - }) + }), ); this.attFeatureService.getAttestationConfig().then((config) => { this.isUserEscalationApprover = config.IsUserInChiefApprovalTeam; this.mitigatingControlsPerViolation = config.MitigatingControlsPerViolation; }); - this.subscriptions.push(authentication.onSessionResponse.subscribe((session) => (this.userUid = session.UserUid))); + this.subscriptions.push(authentication.onSessionResponse.subscribe((session) => (this.userUid = session.UserUid || ''))); } public async ngOnInit(): Promise { - this.navigationState.forinquiry = true; const isBusy = this.busyService.beginBusy(); try { @@ -168,32 +157,32 @@ export class AttestationInquiriesComponent implements OnInit, OnDestroy { this.subscriptions.forEach((s) => s.unsubscribe()); } - public async getData(parameters?: CollectionLoadParameters): Promise { - if (parameters) { - this.navigationState = parameters; - } - - const isBusy = this.busyService.beginBusy(); - - try { - this.attestationCasesCollection = await this.attestationCasesService.get(this.navigationState); - this.hasData = this.attestationCasesCollection.totalCount > 0 || (this.navigationState.search ?? '') !== ''; - this.updateTable(); - } finally { - isBusy.endBusy(); - } + public async getData(): Promise { + const dataViewInitParameters: DataViewInitParameters = { + execute: (params: CollectionLoadParameters, signal: AbortSignal): Promise> => + this.attestationCasesService.get({ ...params, forinquiry: true }), + schema: this.entitySchema, + columnsToDisplay: this.displayedColumns, + dataModel: this.dataModel, + exportFunction: this.attestationCasesService.exportData(this.dataSource.state()), + viewConfig: this.viewConfig, + highlightEntity: (identity: AttestationCase) => { + this.editCase(identity); + }, + }; + await this.dataSource.init(dataViewInitParameters); } public async updateConfig(config: ViewConfigData): Promise { await this.viewConfigService.putViewConfig(config); this.viewConfig = await this.viewConfigService.getDSTExtensionChanges(this.viewConfigPath); - this.dstSettings.viewConfig = this.viewConfig; + this.dataSource.viewConfig.set(this.viewConfig); } public async deleteConfigById(id: string): Promise { await this.viewConfigService.deleteViewConfig(id); this.viewConfig = await this.viewConfigService.getDSTExtensionChanges(this.viewConfigPath); - this.dstSettings.viewConfig = this.viewConfig; + this.dataSource.viewConfig.set(this.viewConfig); } /** @@ -203,10 +192,10 @@ export class AttestationInquiriesComponent implements OnInit, OnDestroy { */ public async editCase(attestationCase: AttestationCase): Promise { let attestationCaseWithPolicy: AttestationCase; - let approvers: Approvers; - - let busyIndicator: OverlayRef; - setTimeout(() => (busyIndicator = this.busyServiceElemental.show())); + let approvers: Approvers | undefined; + if (this.busyServiceElemental.overlayRefs.length === 0) { + this.busyServiceElemental.show(); + } try { attestationCaseWithPolicy = ( @@ -226,17 +215,19 @@ export class AttestationInquiriesComponent implements OnInit, OnDestroy { ).Data[0]; // Add additional violation data to this case - attestationCaseWithPolicy.data.CanSeeComplianceViolations = attestationCase.data.CanSeeComplianceViolations; - attestationCaseWithPolicy.data.ComplianceViolations = attestationCase.data.ComplianceViolations; - attestationCaseWithPolicy.data.CanSeePolicyViolations = attestationCase.data.CanSeePolicyViolations; - attestationCaseWithPolicy.data.PolicyViolations = attestationCase.data.PolicyViolations; + if (attestationCaseWithPolicy.data) { + attestationCaseWithPolicy.data.CanSeeComplianceViolations = !!attestationCase.data?.CanSeeComplianceViolations; + attestationCaseWithPolicy.data.ComplianceViolations = attestationCase.data?.ComplianceViolations || []; + attestationCaseWithPolicy.data.CanSeePolicyViolations = !!attestationCase.data?.CanSeePolicyViolations; + attestationCaseWithPolicy.data.PolicyViolations = attestationCase.data?.PolicyViolations || []; + } if (attestationCaseWithPolicy && !['approved', 'denied'].includes(attestationCaseWithPolicy.AttestationState.value)) { approvers = await this.attestationCasesService.getApprovers(attestationCaseWithPolicy); } this.lossPreview.LossPreviewItems = await this.attestationCasesService.getLossPreviewEntities(attestationCase); } finally { - setTimeout(() => this.busyServiceElemental.hide(busyIndicator)); + this.busyServiceElemental.hide(); } if (attestationCaseWithPolicy) { @@ -244,7 +235,7 @@ export class AttestationInquiriesComponent implements OnInit, OnDestroy { title: await this.translate.get('#LDS#Heading View Attestation Case Details').toPromise(), subTitle: attestationCaseWithPolicy.GetEntity().GetDisplay(), padding: '0px', - width: 'max(60%,700px)', + width: calculateSidesheetWidth(1000), testId: 'attestation-case-sidesheet', data: { case: attestationCaseWithPolicy, @@ -264,43 +255,12 @@ export class AttestationInquiriesComponent implements OnInit, OnDestroy { } public getInquiryText(pwo: AttestationCase): string { - return this.actionService.getCaseData(pwo).Columns.ReasonHead.Value; + return this.actionService.getCaseData(pwo)?.Columns?.ReasonHead.Value || ''; } public getInquirer(pwo: AttestationCase): string { - return this.actionService.getCaseData(pwo).Columns.DisplayPersonHead.Value; - } - public getQueryDate(pwo: AttestationCase): Date { - return new Date(this.actionService.getCaseData(pwo).Columns.DateHead.Value); - } - - public onSearch(keywords: string): Promise { - const navigationState = { - ...this.navigationState, - ...{ - StartIndex: 0, - search: keywords, - }, - }; - - return this.getData(navigationState); + return this.actionService.getCaseData(pwo)?.Columns?.DisplayPersonHead.Value || ''; } - - private updateTable(): void { - if (this.attestationCasesCollection) { - const exportMethod = this.attestationCasesService.exportData(this.navigationState); - exportMethod.initialColumns = this.displayedColumns.map((col) => col.ColumnName); - this.dstSettings = { - dataSource: this.attestationCasesCollection, - extendedData: this.attestationCasesCollection?.extendedData?.Data, - entitySchema: this.entitySchema, - navigationState: this.navigationState, - displayedColumns: this.displayedColumns, - dataModel: this.dataModel, - viewConfig: this.viewConfig, - exportMethod, - }; - } else { - this.dstSettings = undefined; - } + public getQueryDate(pwo: AttestationCase): string { + return this.actionService.getCaseData(pwo)?.Columns?.DateHead.Value || ''; } } diff --git a/imxweb/projects/att/src/lib/decision/attestation-inquiries/attestation-inquiry.model.ts b/imxweb/projects/att/src/lib/decision/attestation-inquiries/attestation-inquiry.model.ts index 1470de200..66e9f472c 100644 --- a/imxweb/projects/att/src/lib/decision/attestation-inquiries/attestation-inquiry.model.ts +++ b/imxweb/projects/att/src/lib/decision/attestation-inquiries/attestation-inquiry.model.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -24,8 +24,8 @@ * */ -export class AttestationInquiry{ +export class AttestationInquiry { public static headCaption = '#LDS#Inquiry made by'; public static queryCaption = '#LDS#Inquiry'; public static queryDate = '#LDS#Inquiry made on'; -} \ No newline at end of file +} diff --git a/imxweb/projects/att/src/lib/decision/decision-compliance-violation/decision-compliance-violation.component.html b/imxweb/projects/att/src/lib/decision/decision-compliance-violation/decision-compliance-violation.component.html index 4e8a7f71a..d769e2e50 100644 --- a/imxweb/projects/att/src/lib/decision/decision-compliance-violation/decision-compliance-violation.component.html +++ b/imxweb/projects/att/src/lib/decision/decision-compliance-violation/decision-compliance-violation.component.html @@ -1,95 +1,103 @@
    -
    - - - {{'#LDS#Here you can get an overview of all rule violations of this attestation case.' | translate }} - - -
    + + + {{ '#LDS#Here you can get an overview of all rule violations of this attestation case.' | translate }} + +
    - - - - - {{complianceViolation.DisplayRule}} - - {{'#LDS#Exception allowed' | translate}} - - - {{'#LDS#Exception forbidden' | translate}} - - - -
    -
    -
    {{'#LDS#Affected identity' | translate}}
    -
    {{complianceViolation.DisplayPerson}}
    -
    -
    -
    {{'#LDS#Contributing entitlements' | translate}}
    -
    -
    {{entitlement?.Display}}
    -
    {{entitlement?.Type}}
    -
    -
    {{'#LDS#Related SAP entitlements' | translate}}
    -
      -
    • -
      {{source?.Display}}
      -
      {{source?.Type}}
      -
    • -
    - {{'#LDS#Not set' | translate}} -
    + + + + + {{ complianceViolation.DisplayRule }} + + {{ '#LDS#Exception allowed' | translate }} + + + {{ '#LDS#Exception forbidden' | translate }} + + + +
    +
    +
    {{ '#LDS#Affected identity' | translate }}
    +
    {{ complianceViolation.DisplayPerson }}
    +
    +
    +
    {{ '#LDS#Contributing entitlements' | translate }}
    +
    +
    {{ entitlement?.Display }}
    +
    {{ entitlement?.Type }}
    +
    +
    {{ '#LDS#Related SAP entitlements' | translate }}
    +
      +
    • +
      {{ source?.Display }}
      +
      {{ source?.Type }}
      +
    • +
    + {{ '#LDS#Not set' | translate }}
    -
    -
    {{ '#LDS#The following mitigating controls are available for the rule violation:' | translate }}
    -
      -
    • - {{control.Display}} -
    • -
    -
    - +
    +
    {{ '#LDS#The following mitigating controls are available for the rule violation:' | translate }}
    +
      +
    • + {{ control.Display }} +
    • +
    +
    +
    +
    - - - - - {{complianceViolation.DisplayRule}} - - {{'#LDS#Exception allowed' | translate}} + + + {{ complianceViolation.DisplayRule }} + + {{ '#LDS#Exception allowed' | translate }} - - {{'#LDS#Exception forbidden' | translate}} + + {{ '#LDS#Exception forbidden' | translate }} - - -
    -
    {{'#LDS#Affected object' | translate}}
    -
    {{complianceViolation.DisplayObject}}
    -
    -
    -
    {{ '#LDS#The following mitigating controls are available for the rule violation:' | translate }}
    -
      -
    • - {{control.Display}} -
    • -
    -
    -
    -
    +
    + +
    +
    {{ '#LDS#Affected object' | translate }}
    +
    {{ complianceViolation.DisplayObject }}
    +
    +
    +
    {{ '#LDS#The following mitigating controls are available for the rule violation:' | translate }}
    +
      +
    • + {{ control.Display }} +
    • +
    +
    +
    +
    - - {{'#LDS#There are currently no mitigating controls assigned to the rule violation.' |translate}} + + {{ '#LDS#There are currently no mitigating controls assigned to the rule violation.' | translate }} diff --git a/imxweb/projects/att/src/lib/decision/decision-compliance-violation/decision-compliance-violation.component.scss b/imxweb/projects/att/src/lib/decision/decision-compliance-violation/decision-compliance-violation.component.scss index 34b7b59e9..658494b6e 100644 --- a/imxweb/projects/att/src/lib/decision/decision-compliance-violation/decision-compliance-violation.component.scss +++ b/imxweb/projects/att/src/lib/decision/decision-compliance-violation/decision-compliance-violation.component.scss @@ -1,49 +1,17 @@ -@import "@elemental-ui/core/src/styles/_eui_palette.scss"; - -@mixin imx-flex-row-container { - display: flex; - flex-direction: row; -} +@import '@elemental-ui/core/src/styles/_eui_palette.scss'; +@import 'base/mixins'; .heading-wrapper { - @include imx-flex-row-container(); + @include flex-row-container(); flex: 0 0 auto; - - .helper-alert { - display: flex; - margin-bottom: 15px; - } - - .alert-wrapper { - width: 100%; - margin: 0 0 0 auto; - align-self: flex-end; - } } -.mat-card-title { +.mat-mdc-card-title { display: flex; align-items: center; margin-bottom: 17px; } -.mat-expansion-panel { - margin-bottom: 20px; - - &-header-title { - font-size: 24px; - font-weight: 500; - } - - ::ng-deep .eui-alert { - width: auto; - } -} - -.eui-badge { - padding-left: 10px; -} - .imx-container > * { margin-bottom: 10px; } @@ -53,11 +21,13 @@ margin-top: 5px; margin-bottom: 5px; } -.imx-entitlement-subtitle, .imx-source-subtitle { +.imx-entitlement-subtitle, +.imx-source-subtitle { color: $color-gray-40; } -.imx-risk-reduction-item, .imx-source-item { +.imx-risk-reduction-item, +.imx-source-item { list-style-type: circle; margin-left: 20px; } diff --git a/imxweb/projects/att/src/lib/decision/decision-compliance-violation/decision-compliance-violation.component.ts b/imxweb/projects/att/src/lib/decision/decision-compliance-violation/decision-compliance-violation.component.ts index 466a3e58c..1206aa83e 100644 --- a/imxweb/projects/att/src/lib/decision/decision-compliance-violation/decision-compliance-violation.component.ts +++ b/imxweb/projects/att/src/lib/decision/decision-compliance-violation/decision-compliance-violation.component.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -25,12 +25,12 @@ */ import { Component, Input } from '@angular/core'; -import { ComplianceViolation } from 'imx-api-att'; +import { ComplianceViolation } from '@imx-modules/imx-api-att'; @Component({ selector: 'imx-decision-compliance-violation', templateUrl: './decision-compliance-violation.component.html', - styleUrls: ['./decision-compliance-violation.component.scss'] + styleUrls: ['./decision-compliance-violation.component.scss'], }) export class DecisionComplianceViolationComponent { @Input() public complianceViolations: ComplianceViolation[]; diff --git a/imxweb/projects/att/src/lib/decision/decision-history-item/decision-history-item.component.html b/imxweb/projects/att/src/lib/decision/decision-history-item/decision-history-item.component.html index c0848a6c1..bcfb15ed0 100644 --- a/imxweb/projects/att/src/lib/decision/decision-history-item/decision-history-item.component.html +++ b/imxweb/projects/att/src/lib/decision/decision-history-item/decision-history-item.component.html @@ -1,45 +1,55 @@ -
  • +
  • - {{ - workflowHistoryEntity.DecisionType?.Column?.GetDisplayValue() }} -  - {{ - workflowHistoryEntity.XDateInserted.value | localizedDate }} + {{ workflowHistoryEntity.DecisionType?.Column?.GetDisplayValue() }} +  - {{ workflowHistoryEntity.XDateInserted.value | localizedDate }} - {{workflowHistoryEntity.Ident_PWODecisionStep?.Column?.GetDisplayValue()}} + {{ workflowHistoryEntity.Ident_PWODecisionStep?.Column?.GetDisplayValue() }} + - {{'#LDS#Approval decision by chief approval team'|translate}} + {{ '#LDS#Approval decision by chief approval team' | translate }} - - + +
    {{ - decisionHistory.getColumnDescriptionForDisplayPersonHead(workflowHistoryEntity.DecisionType?.value) | translate }} - {{workflowHistoryEntity.DisplayPersonHead?.Column?.GetDisplayValue()}} + decisionHistory.getColumnDescriptionForDisplayPersonHead(workflowHistoryEntity.DecisionType?.value || '') | translate + }} + {{ workflowHistoryEntity.DisplayPersonHead?.Column?.GetDisplayValue() }}
    -
    +
    - {{ "#LDS#Query"| translate }} - {{workflowHistoryEntity.ReasonHead?.Column?.GetDisplayValue()}} + {{ '#LDS#Query' | translate }} + {{ workflowHistoryEntity.ReasonHead?.Column?.GetDisplayValue() }}
    -
    +
    - {{ "#LDS#Answer"| translate }} - {{workflowHistoryEntity.ReasonHead?.Column?.GetDisplayValue()}} + {{ '#LDS#Answer' | translate }} + {{ workflowHistoryEntity.ReasonHead?.Column?.GetDisplayValue() }}
    @@ -47,20 +57,23 @@ - + - +
    - {{ "#LDS#Recipient"| translate }} - {{workflowHistoryEntity.UID_PersonRelated?.Column?.GetDisplayValue()}} + {{ '#LDS#Recipient' | translate }} + {{ workflowHistoryEntity.UID_PersonRelated?.Column?.GetDisplayValue() }}
    -
  • \ No newline at end of file + diff --git a/imxweb/projects/att/src/lib/decision/decision-history-item/decision-history-item.component.scss b/imxweb/projects/att/src/lib/decision/decision-history-item/decision-history-item.component.scss index a5aea9e8b..590c9827c 100644 --- a/imxweb/projects/att/src/lib/decision/decision-history-item/decision-history-item.component.scss +++ b/imxweb/projects/att/src/lib/decision/decision-history-item/decision-history-item.component.scss @@ -1,4 +1,4 @@ -@import "@elemental-ui/core/src/styles/_eui_palette.scss"; +@import '@elemental-ui/core/src/styles/_eui_palette.scss'; :host { display: flex; @@ -18,7 +18,7 @@ } } -.mat-card-title { +.mat-mdc-card-title { margin-bottom: 15px; :first-child { font-weight: bold; @@ -29,16 +29,15 @@ } } -.mat-card-header { - margin-left: -16px; +.mat-mdc-card-header { margin-bottom: 10px; - .mat-card-title { + .mat-mdc-card-title { font-size: 1.05em; margin-bottom: 0; } - .mat-card-subtitle.imx-workflowhistory-pwodecisionstep { + .mat-mdc-card-subtitle.imx-workflowhistory-pwodecisionstep { margin: 5px 0; } } @@ -66,7 +65,7 @@ li.imx-event::before { background-color: $color-gray-0; height: 24px; width: 28px; - content: ""; + content: ''; float: left; margin-top: -2px; } @@ -80,7 +79,7 @@ li.imx-event.imx-positive::before { font-family: Cadence-Icon; font-size: 24px; color: $color-green-60; - content: "\e049"; + content: '\e049'; } li.imx-event.imx-negative { @@ -92,7 +91,7 @@ li.imx-event.imx-negative::before { font-family: Cadence-Icon; font-size: 24px; color: $color-red-60; - content: "\e05c"; + content: '\e05c'; } li.imx-event.imx-question { @@ -104,7 +103,7 @@ li.imx-event.imx-question::before { font-family: Cadence-Icon; font-size: 24px; color: $color-blue-60; - content: "\e009"; + content: '\e009'; } li.imx-event.imx-info { @@ -116,7 +115,7 @@ li.imx-event.imx-info::before { font-family: Cadence-Icon; font-size: 24px; color: $color-blue-60; - content: "\e010"; + content: '\e010'; } li.imx-event.imx-pending { @@ -128,22 +127,17 @@ li.imx-event.imx-pending::before { font-family: Cadence-Icon; font-size: 24px; color: $color-gray-30; - content: "\e009"; -} - -.chief-approval-badge { - margin-bottom: .5em; + content: '\e009'; } .eui-dark-theme { :host { - li.imx-event::before{ + li.imx-event::before { background-color: $color-gray-70; } - li{ - .mat-card - { + li { + .mat-mdc-card { background-color: $color-gray-60; } } @@ -152,13 +146,12 @@ li.imx-event.imx-pending::before { .eui-contrast-theme { :host { - li.imx-event::before{ + li.imx-event::before { background-color: $color-gray-90; } - li{ - .mat-card - { + li { + .mat-mdc-card { background-color: $color-gray-80; } } diff --git a/imxweb/projects/att/src/lib/decision/decision-history-item/decision-history-item.component.ts b/imxweb/projects/att/src/lib/decision/decision-history-item/decision-history-item.component.ts index 2954b1f02..d1ac55899 100644 --- a/imxweb/projects/att/src/lib/decision/decision-history-item/decision-history-item.component.ts +++ b/imxweb/projects/att/src/lib/decision/decision-history-item/decision-history-item.component.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -26,12 +26,12 @@ import { Component, Input } from '@angular/core'; -import { PortalAttestationCaseHistory } from 'imx-api-att'; +import { PortalAttestationCaseHistory } from '@imx-modules/imx-api-att'; import { DecisionHistoryService } from 'qer'; @Component({ selector: 'imx-decision-history-item', templateUrl: './decision-history-item.component.html', - styleUrls: ['./decision-history-item.component.scss'] + styleUrls: ['./decision-history-item.component.scss'], }) export class DecisionHistoryItemComponent { @Input() public workflowHistoryEntity: PortalAttestationCaseHistory; diff --git a/imxweb/projects/att/src/lib/decision/decision-policy-violation/decision-policy-violation.component.html b/imxweb/projects/att/src/lib/decision/decision-policy-violation/decision-policy-violation.component.html index b93b8f6b9..3b4079755 100644 --- a/imxweb/projects/att/src/lib/decision/decision-policy-violation/decision-policy-violation.component.html +++ b/imxweb/projects/att/src/lib/decision/decision-policy-violation/decision-policy-violation.component.html @@ -1,76 +1,92 @@
    -
    - - - {{'#LDS#Here you can get an overview of all policy violations of this attestation case.' | translate }} - - -
    + + + {{ '#LDS#Here you can get an overview of all policy violations of this attestation case.' | translate }} + +
    - - - - - {{policyViolation.DisplayPolicy}} - - {{'#LDS#Exception allowed' | translate}} - - - {{'#LDS#Exception forbidden' | translate}} - - - -
    -
    {{'#LDS#Affected object' | translate}}
    -
    {{policyViolation.DisplayObject}}
    -
    -
    -
    {{ '#LDS#The following mitigating controls are available for the policy violation:' | translate }}
    -
      -
    • - {{control.Display}} -
    • -
    -
    -
    + + + + + {{ policyViolation.DisplayPolicy }} + + +
    +
    {{ '#LDS#State' | translate }}
    + + {{ stateDisplay(policyViolation) | translate }} + +
    +
    +
    {{ '#LDS#Exception allowed' | translate }}
    +
    {{ (policyViolation.IsExceptionAllowed ? '#LDS#Company policy allows exceptions' : '#LDS#Company policy forbids exceptions') | translate }}
    +
    +
    +
    {{ '#LDS#Affected object' | translate }}
    +
    {{ policyViolation.DisplayObject }}
    +
    +
    +
    {{ '#LDS#The following mitigating controls are available for the policy violation:' | translate }}
    +
      +
    • + {{ control.Display }} +
    • +
    +
    +
    - - - - - {{policyViolation.DisplayPolicy}} - - {{'#LDS#Exception allowed' | translate}} + + + {{ policyViolation.DisplayPolicy }} + +
    +
    {{ '#LDS#State' | translate }}
    + + {{ stateDisplay(policyViolation) | translate }} - - {{'#LDS#Exception forbidden' | translate}} - - - -
    -
    {{'#LDS#Affected object' | translate}}
    -
    {{policyViolation.DisplayObject}}
    -
    -
    {{ '#LDS#The following mitigating controls are available for the policy violation:' | translate }}
    -
      -
    • - {{control.Display}} -
    • -
    +
    +
    {{ '#LDS#Exception allowed' | translate }}
    +
    {{ (policyViolation.IsExceptionAllowed ? '#LDS#Company policy allows exceptions' : '#LDS#Company policy forbids exceptions') | translate }}
    - - +
    +
    {{ '#LDS#Affected object' | translate }}
    +
    {{ policyViolation.DisplayObject }}
    +
    + +
    +
    {{ '#LDS#The following mitigating controls are available for the policy violation:' | translate }}
    +
      +
    • + {{ control.Display }} +
    • +
    +
    +
    + - - {{'#LDS#There are currently no mitigating controls assigned to the policy violation.' |translate}} + + {{ '#LDS#There are currently no mitigating controls assigned to the policy violation.' | translate }} diff --git a/imxweb/projects/att/src/lib/decision/decision-policy-violation/decision-policy-violation.component.scss b/imxweb/projects/att/src/lib/decision/decision-policy-violation/decision-policy-violation.component.scss index f3b6073a7..433c77c9b 100644 --- a/imxweb/projects/att/src/lib/decision/decision-policy-violation/decision-policy-violation.component.scss +++ b/imxweb/projects/att/src/lib/decision/decision-policy-violation/decision-policy-violation.component.scss @@ -1,26 +1,11 @@ -@import "@elemental-ui/core/src/styles/_eui_palette.scss"; - -@mixin imx-flex-row-container { - display: flex; - flex-direction: row; -} +@import '@elemental-ui/core/src/styles/_eui_palette.scss'; +@import 'base/mixins'; .heading-wrapper { - @include imx-flex-row-container(); + @include flex-row-container(); flex: 0 0 auto; - - .helper-alert { - display: flex; - margin-bottom: 15px; - } - - .alert-wrapper { - width: 100%; - margin: 0 0 0 auto; - align-self: flex-end; - } } -.mat-card { +.mat-mdc-card { padding-left: 24px; padding-right: 24px; @@ -31,23 +16,6 @@ } } -.mat-expansion-panel { - margin-bottom: 20px; - - &-header-title { - font-size: 24px; - font-weight: 500; - } - - ::ng-deep .eui-alert { - width: auto; - } -} - -.eui-badge { - padding-left: 10px; -} - .imx-container > * { margin-bottom: 10px; } @@ -63,9 +31,3 @@ list-style-type: circle; margin-left: 20px; } - -.imx-top-alert { - display: block; - margin: 1em 0; -} - diff --git a/imxweb/projects/att/src/lib/decision/decision-policy-violation/decision-policy-violation.component.ts b/imxweb/projects/att/src/lib/decision/decision-policy-violation/decision-policy-violation.component.ts index 6ec3a5272..21e84b617 100644 --- a/imxweb/projects/att/src/lib/decision/decision-policy-violation/decision-policy-violation.component.ts +++ b/imxweb/projects/att/src/lib/decision/decision-policy-violation/decision-policy-violation.component.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -25,16 +25,25 @@ */ import { Component, Input } from '@angular/core'; -import { PolicyViolation } from 'imx-api-att'; +import { PolicyViolation, ViolationState } from '@imx-modules/imx-api-att'; @Component({ selector: 'imx-decision-policy-violation', templateUrl: './decision-policy-violation.component.html', - styleUrls: ['./decision-policy-violation.component.scss'] + styleUrls: ['./decision-policy-violation.component.scss'], }) export class DecisionPolicyViolationComponent { @Input() public policyViolations: PolicyViolation[]; @Input() public mitigatingControlsPerViolation: boolean; constructor() {} + + public stateDisplay(violation: PolicyViolation) { + switch (violation.State){ + case ViolationState.ExceptionApproved: return '#LDS#Exception granted'; + case ViolationState.ExceptionDenied: return '#LDS#Exception denied'; + } + + return '#LDS#Approval decision pending'; + } } diff --git a/imxweb/projects/att/src/lib/decision/loss-preview-dialog/loss-preview-dialog.component.html b/imxweb/projects/att/src/lib/decision/loss-preview-dialog/loss-preview-dialog.component.html index 802b23c72..94c117f37 100644 --- a/imxweb/projects/att/src/lib/decision/loss-preview-dialog/loss-preview-dialog.component.html +++ b/imxweb/projects/att/src/lib/decision/loss-preview-dialog/loss-preview-dialog.component.html @@ -2,11 +2,11 @@ -
    +
    -
    diff --git a/imxweb/projects/att/src/lib/decision/loss-preview-dialog/loss-preview-dialog.component.scss b/imxweb/projects/att/src/lib/decision/loss-preview-dialog/loss-preview-dialog.component.scss index 5956a2b77..859c6f75f 100644 --- a/imxweb/projects/att/src/lib/decision/loss-preview-dialog/loss-preview-dialog.component.scss +++ b/imxweb/projects/att/src/lib/decision/loss-preview-dialog/loss-preview-dialog.component.scss @@ -5,26 +5,22 @@ flex-direction: column; height: 100%; - .mat-card { + .mat-mdc-card { margin: 0 -10px; flex: 1; } - - .mat-dialog-actions { - gap: 10px; - } } // Theming :host { - .mat-card { + .mat-mdc-card { background-color: $color-gray-10; } } .eui-dark-theme { :host { - .mat-card { + .mat-mdc-card { background-color: $color-gray-80; } } @@ -32,7 +28,7 @@ .eui-contrast-theme { :host { - .mat-card { + .mat-mdc-card { background-color: $color-gray-90; } } diff --git a/imxweb/projects/att/src/lib/decision/loss-preview-dialog/loss-preview-dialog.component.ts b/imxweb/projects/att/src/lib/decision/loss-preview-dialog/loss-preview-dialog.component.ts index 62923695c..dcc6daa7a 100644 --- a/imxweb/projects/att/src/lib/decision/loss-preview-dialog/loss-preview-dialog.component.ts +++ b/imxweb/projects/att/src/lib/decision/loss-preview-dialog/loss-preview-dialog.component.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -31,7 +31,7 @@ import { LossPreview } from '../loss-preview.interface'; @Component({ selector: 'imx-loss-preview-dialog', templateUrl: './loss-preview-dialog.component.html', - styleUrls: ['./loss-preview-dialog.component.scss'] + styleUrls: ['./loss-preview-dialog.component.scss'], }) export class LossPreviewDialogComponent implements OnInit { public lossPreview: LossPreview; @@ -39,10 +39,9 @@ export class LossPreviewDialogComponent implements OnInit { constructor( public dialogRef: MatDialogRef, @Inject(MAT_DIALOG_DATA) public readonly data: LossPreview, - ) { - } + ) {} public ngOnInit(): void { - this.lossPreview = this.data; + this.lossPreview = this.data; } public onDeny(): void { diff --git a/imxweb/projects/att/src/lib/decision/loss-preview-table/loss-preview-table.component.html b/imxweb/projects/att/src/lib/decision/loss-preview-table/loss-preview-table.component.html index 9843d893d..4780ff513 100644 --- a/imxweb/projects/att/src/lib/decision/loss-preview-table/loss-preview-table.component.html +++ b/imxweb/projects/att/src/lib/decision/loss-preview-table/loss-preview-table.component.html @@ -1,14 +1,19 @@
    -

    - {{'#LDS#Heading Entitlement Loss' | translate}} -

    -
    - - - {{'#LDS#Here you can get an overview of all entitlements that will be withdrawn if the attestation case is denied.' | translate }} - - -
    +

    + {{ '#LDS#Heading Entitlement Loss' | translate }} +

    + + + {{ '#LDS#Here you can get an overview of all entitlements that will be withdrawn if the attestation case is denied.' | translate }} + +
    @@ -19,28 +24,28 @@

    - + - + - + - +
    {{ lossPreviewDisplayKeys.Display | translate }}{{ lossPreviewDisplayKeys.Display || '' | translate }}
    {{ row?.Display }}
    - {{row?.Table}} + {{ row?.Table }}
    {{ lossPreviewDisplayKeys.ObjectDisplay | translate }}{{ lossPreviewDisplayKeys.ObjectDisplay || '' | translate }} - {{row?.ObjectDisplay}} + {{ row?.ObjectDisplay }} {{ lossPreviewDisplayKeys.Person | translate }}{{ lossPreviewDisplayKeys.Person || '' | translate }} {{ row?.Person }}
    diff --git a/imxweb/projects/att/src/lib/decision/loss-preview-table/loss-preview-table.component.scss b/imxweb/projects/att/src/lib/decision/loss-preview-table/loss-preview-table.component.scss index fc32cc929..93badb901 100644 --- a/imxweb/projects/att/src/lib/decision/loss-preview-table/loss-preview-table.component.scss +++ b/imxweb/projects/att/src/lib/decision/loss-preview-table/loss-preview-table.component.scss @@ -28,32 +28,6 @@ flex: 0 0 auto; margin-top: 15px; align-items: center; - - .helper-alert { - display: flex; - } - - .alert-wrapper { - width: 100%; - margin: 0 0 0 auto; - align-self: flex-end; - } - - .alert-wrapper--shortened { - width: 70%; - } -} - -th.mat-header-cell:not(:last-child), td.mat-cell:not(:last-child) { - padding-right: 10px; -} - -table.mat-table { - box-shadow: none; - padding: 1px; -} -.table-row-tall { - padding: 5px 0; } .table-subtitle { diff --git a/imxweb/projects/att/src/lib/decision/loss-preview-table/loss-preview-table.component.ts b/imxweb/projects/att/src/lib/decision/loss-preview-table/loss-preview-table.component.ts index a8d2a19cb..e4716422e 100644 --- a/imxweb/projects/att/src/lib/decision/loss-preview-table/loss-preview-table.component.ts +++ b/imxweb/projects/att/src/lib/decision/loss-preview-table/loss-preview-table.component.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -25,9 +25,9 @@ */ import { Component, Input, OnInit } from '@angular/core'; -import { EntitlementLossDto } from 'imx-api-att'; -import { LossPreview } from '../loss-preview.interface'; +import { EntitlementLossDto } from '@imx-modules/imx-api-att'; import { AttestationCasesService } from '../attestation-cases.service'; +import { LossPreview } from '../loss-preview.interface'; @Component({ selector: 'imx-loss-preview-table', @@ -57,7 +57,9 @@ export class LossPreviewTableComponent implements OnInit { public async loadData(): Promise { this.isLoading = true; try { - this.lossPreview.LossPreviewItems = await this.caseService.getLossPreviewEntities(this.lossPreview.Case); + if (!!this.lossPreview.Case) { + this.lossPreview.LossPreviewItems = await this.caseService.getLossPreviewEntities(this.lossPreview.Case); + } } finally { this.isLoading = false; } diff --git a/imxweb/projects/att/src/lib/decision/loss-preview.interface.ts b/imxweb/projects/att/src/lib/decision/loss-preview.interface.ts index 406a865a7..95838e383 100644 --- a/imxweb/projects/att/src/lib/decision/loss-preview.interface.ts +++ b/imxweb/projects/att/src/lib/decision/loss-preview.interface.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -24,7 +24,7 @@ * */ -import { EntitlementLossDto } from 'imx-api-att'; +import { EntitlementLossDto } from '@imx-modules/imx-api-att'; import { AttestationCase } from './attestation-case'; export interface LossPreview { diff --git a/imxweb/projects/att/src/lib/decision/mitigating-controls/mitigating-controls.component.html b/imxweb/projects/att/src/lib/decision/mitigating-controls/mitigating-controls.component.html index 10db3c147..3c9a136e9 100644 --- a/imxweb/projects/att/src/lib/decision/mitigating-controls/mitigating-controls.component.html +++ b/imxweb/projects/att/src/lib/decision/mitigating-controls/mitigating-controls.component.html @@ -1,16 +1,27 @@ -

    {{ '#LDS#Heading Assign Mitigating Controls' | translate}}

    +

    {{ '#LDS#Heading Assign Mitigating Controls' | translate }}

    - +
    - - - - \ No newline at end of file + + diff --git a/imxweb/projects/att/src/lib/decision/mitigating-controls/mitigating-controls.component.scss b/imxweb/projects/att/src/lib/decision/mitigating-controls/mitigating-controls.component.scss index 418290f98..a23c84eea 100644 --- a/imxweb/projects/att/src/lib/decision/mitigating-controls/mitigating-controls.component.scss +++ b/imxweb/projects/att/src/lib/decision/mitigating-controls/mitigating-controls.component.scss @@ -1 +1 @@ -// You can add css code here \ No newline at end of file +// You can add css code here diff --git a/imxweb/projects/att/src/lib/decision/mitigating-controls/mitigating-controls.component.ts b/imxweb/projects/att/src/lib/decision/mitigating-controls/mitigating-controls.component.ts index 69690b750..af787d88a 100644 --- a/imxweb/projects/att/src/lib/decision/mitigating-controls/mitigating-controls.component.ts +++ b/imxweb/projects/att/src/lib/decision/mitigating-controls/mitigating-controls.component.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -28,25 +28,24 @@ import { Component, Inject } from '@angular/core'; import { UntypedFormGroup } from '@angular/forms'; import { MatDialogRef, MAT_DIALOG_DATA } from '@angular/material/dialog'; -import { IEntityColumn } from 'imx-qbm-dbts'; +import { IEntityColumn } from '@imx-modules/imx-qbm-dbts'; import { BaseCdr, ColumnDependentReference } from 'qbm'; @Component({ selector: 'imx-mitigating-controls', templateUrl: './mitigating-controls.component.html', - styleUrls: ['./mitigating-controls.component.scss'] + styleUrls: ['./mitigating-controls.component.scss'], }) export class MitigatingControlsComponent { - public mitigatingControlCdr: ColumnDependentReference; public formGroup = new UntypedFormGroup({}); constructor( - @Inject(MAT_DIALOG_DATA) public readonly data: { - column: IEntityColumn + @Inject(MAT_DIALOG_DATA) + public readonly data: { + column: IEntityColumn; }, - public dialogRef: MatDialogRef + public dialogRef: MatDialogRef, ) { this.mitigatingControlCdr = new BaseCdr(this.data.column); } - } diff --git a/imxweb/projects/att/src/lib/entity-property-editor/entity-property-editor.component.html b/imxweb/projects/att/src/lib/entity-property-editor/entity-property-editor.component.html index 660035667..e75995806 100644 --- a/imxweb/projects/att/src/lib/entity-property-editor/entity-property-editor.component.html +++ b/imxweb/projects/att/src/lib/entity-property-editor/entity-property-editor.component.html @@ -1 +1 @@ - \ No newline at end of file + diff --git a/imxweb/projects/att/src/lib/entity-property-editor/entity-property-editor.component.scss b/imxweb/projects/att/src/lib/entity-property-editor/entity-property-editor.component.scss index e77cdc598..965d16769 100644 --- a/imxweb/projects/att/src/lib/entity-property-editor/entity-property-editor.component.scss +++ b/imxweb/projects/att/src/lib/entity-property-editor/entity-property-editor.component.scss @@ -1 +1 @@ -// TODO: Styles \ No newline at end of file +// TODO: Styles diff --git a/imxweb/projects/att/src/lib/entity-property-editor/entity-property-editor.component.ts b/imxweb/projects/att/src/lib/entity-property-editor/entity-property-editor.component.ts index dba19db4f..c39fc6338 100644 --- a/imxweb/projects/att/src/lib/entity-property-editor/entity-property-editor.component.ts +++ b/imxweb/projects/att/src/lib/entity-property-editor/entity-property-editor.component.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -26,16 +26,16 @@ import { Component, Input, OnChanges, SimpleChanges } from '@angular/core'; -import { EntityValue } from 'imx-qbm-dbts'; +import { EntityValue } from '@imx-modules/imx-qbm-dbts'; import { BaseCdr, ColumnDependentReference } from 'qbm'; @Component({ selector: 'imx-entity-property-editor', templateUrl: './entity-property-editor.component.html', - styleUrls: ['./entity-property-editor.component.scss'] + styleUrls: ['./entity-property-editor.component.scss'], }) export class EntityPropertyEditorComponent implements OnChanges { - public cdr: ColumnDependentReference; + public cdr: ColumnDependentReference | undefined; @Input() public property: EntityValue; @Input() public hideIfEmpty = true; @@ -43,8 +43,10 @@ export class EntityPropertyEditorComponent implements OnChanges { public ngOnChanges(changes: SimpleChanges): void { if (changes.property) { - this.cdr = this.property && (!this.hideIfEmpty || (this.property.value != null && this.property.value !== '')) ? - new BaseCdr(this.property.Column, this.caption) : undefined; + this.cdr = + this.property && (!this.hideIfEmpty || (this.property.value != null && this.property.value !== '')) + ? new BaseCdr(this.property.Column, this.caption) + : undefined; } } } diff --git a/imxweb/projects/att/src/lib/guards/attestation-admin-guard.service.ts b/imxweb/projects/att/src/lib/guards/attestation-admin-guard.service.ts index d235b918a..1e642e47c 100644 --- a/imxweb/projects/att/src/lib/guards/attestation-admin-guard.service.ts +++ b/imxweb/projects/att/src/lib/guards/attestation-admin-guard.service.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -25,7 +25,7 @@ */ import { Injectable, OnDestroy } from '@angular/core'; -import { CanActivate, ActivatedRouteSnapshot, RouterStateSnapshot, Router } from '@angular/router'; +import { ActivatedRouteSnapshot, Router, RouterStateSnapshot } from '@angular/router'; import { Observable, Subscription } from 'rxjs'; import { AppConfigService, AuthenticationService, ISessionState } from 'qbm'; @@ -34,14 +34,14 @@ import { PermissionsService } from '../admin/permissions.service'; @Injectable({ providedIn: 'root', }) -export class AttestionAdminGuardService implements CanActivate, OnDestroy { +export class AttestionAdminGuardService implements OnDestroy { private onSessionResponse: Subscription; constructor( private readonly attPermissionService: PermissionsService, private readonly authentication: AuthenticationService, private readonly appConfig: AppConfigService, - private readonly router: Router + private readonly router: Router, ) {} public canActivate(route: ActivatedRouteSnapshot, _: RouterStateSnapshot): Observable { @@ -49,8 +49,8 @@ export class AttestionAdminGuardService implements CanActivate, OnDestroy { this.onSessionResponse = this.authentication.onSessionResponse.subscribe(async (sessionState: ISessionState) => { if (sessionState.IsLoggedIn) { const userIsAttestationAdmin = await this.attPermissionService.isAttestationAdmin(); - if (!userIsAttestationAdmin) { - this.router.navigate([this.appConfig.Config.routeConfig.start], { queryParams: {} } ); + if (!userIsAttestationAdmin) { + this.router.navigate([this.appConfig.Config.routeConfig?.start], { queryParams: {} }); } observer.next(userIsAttestationAdmin ? true : false); observer.complete(); diff --git a/imxweb/projects/att/src/lib/guards/attestation-policies-guard.service.ts b/imxweb/projects/att/src/lib/guards/attestation-policies-guard.service.ts index a6bc0720a..32815dbb1 100644 --- a/imxweb/projects/att/src/lib/guards/attestation-policies-guard.service.ts +++ b/imxweb/projects/att/src/lib/guards/attestation-policies-guard.service.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -25,7 +25,7 @@ */ import { Injectable } from '@angular/core'; -import { CanActivate, Router } from '@angular/router'; +import { Router } from '@angular/router'; import { AppConfigService } from 'qbm'; import { PermissionsService } from '../admin/permissions.service'; @@ -33,17 +33,17 @@ import { PermissionsService } from '../admin/permissions.service'; @Injectable({ providedIn: 'root', }) -export class AttestationPoliciesGuardService implements CanActivate { +export class AttestationPoliciesGuardService { constructor( private readonly permissionService: PermissionsService, private readonly appConfig: AppConfigService, - private readonly router: Router - ) { } + private readonly router: Router, + ) {} public async canActivate(): Promise { const userCanSeeAttestationPolicies = await this.permissionService.canSeeAttestationPolicies(); if (!userCanSeeAttestationPolicies) { - this.router.navigate([this.appConfig.Config.routeConfig.start], { queryParams: {} }); + this.router.navigate([this.appConfig.Config.routeConfig?.start], { queryParams: {} }); return false; } return userCanSeeAttestationPolicies; diff --git a/imxweb/projects/att/src/lib/hardware-guard.service.ts b/imxweb/projects/att/src/lib/hardware-guard.service.ts index b323cdee4..14789d368 100644 --- a/imxweb/projects/att/src/lib/hardware-guard.service.ts +++ b/imxweb/projects/att/src/lib/hardware-guard.service.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -26,7 +26,7 @@ import { Injectable } from '@angular/core'; import { CanActivate, Router } from '@angular/router'; -import { SystemInfoService } from 'qbm'; +import { AppConfigService, SystemInfoService } from 'qbm'; import { ProjectConfigurationService } from 'qer'; @Injectable({ @@ -34,19 +34,20 @@ import { ProjectConfigurationService } from 'qer'; }) export class HardwareGuardService implements CanActivate { constructor( + private readonly config: AppConfigService, private readonly projectConfig: ProjectConfigurationService, private readonly systemInfo: SystemInfoService, - private readonly router: Router + private readonly router: Router, ) {} public async canActivate(): Promise { - const preprops = (await this.systemInfo.get()).PreProps; - const hardware = (await this.projectConfig.getConfig()).DeviceConfig.VI_Hardware_Enabled; + const preprops = (await this.systemInfo.get()).PreProps || []; + const hardware = !!(await this.projectConfig.getConfig()).DeviceConfig?.VI_Hardware_Enabled; if (hardware && preprops.includes('MAC')) { return true; } - this.router.navigate(['']); + this.router.navigate([this.config.Config.routeConfig?.start], { queryParams: {} }); return false; } } diff --git a/imxweb/projects/att/src/lib/identity-attestation.service.ts b/imxweb/projects/att/src/lib/identity-attestation.service.ts index 47f46d828..38bf4b5f7 100644 --- a/imxweb/projects/att/src/lib/identity-attestation.service.ts +++ b/imxweb/projects/att/src/lib/identity-attestation.service.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -27,7 +27,7 @@ import { Injectable } from '@angular/core'; import { Subject } from 'rxjs'; -import { CompareOperator, FilterType } from 'imx-qbm-dbts'; +import { CompareOperator, FilterType } from '@imx-modules/imx-qbm-dbts'; import { AttestationHistoryService } from './attestation-history/attestation-history.service'; import { AttestationCasesService } from './decision/attestation-cases.service'; import { AttestationHistoryActionService } from './attestation-history/attestation-history-action.service'; @@ -35,40 +35,44 @@ import { AttestationCaseLoadParameters } from './attestation-history/attestation import { ObjectAttestationStatistics } from 'qer'; @Injectable({ - providedIn: 'root' + providedIn: 'root', }) export class IdentityAttestationService { - public get applied(): Subject { return this.attestationAction.applied; } + public get applied(): Subject { + return this.attestationAction.applied; + } constructor( private readonly attestationHistory: AttestationHistoryService, private readonly attestationApprove: AttestationCasesService, - private readonly attestationAction: AttestationHistoryActionService - ) { } + private readonly attestationAction: AttestationHistoryActionService, + ) {} public async getNumberOfPendingForUser(parameters: AttestationCaseLoadParameters): Promise { const attestations = await this.attestationHistory.get({ ...parameters, - ...{ PageSize: -1 } + ...{ PageSize: -1 }, }); - const filter = [{ - ColumnName: 'IsClosed', - Type: FilterType.Compare, - CompareOp: CompareOperator.Equal, - Value1: 0 - }]; + const filter = [ + { + ColumnName: 'IsClosed', + Type: FilterType.Compare, + CompareOp: CompareOperator.Equal, + Value1: 0, + }, + ]; const pendingAttestations = await this.attestationHistory.get({ ...parameters, ...{ filter }, - ...{ PageSize: -1 } + ...{ PageSize: -1 }, }); return { total: attestations?.totalCount ?? 0, pendingTotal: pendingAttestations?.totalCount ?? 0, - pendingForUser: await this.attestationApprove.getNumberOfPending(parameters) + pendingForUser: await this.attestationApprove.getNumberOfPending(parameters), }; } } diff --git a/imxweb/projects/att/src/lib/init.service.ts b/imxweb/projects/att/src/lib/init.service.ts index b3a0963b8..1381727d3 100644 --- a/imxweb/projects/att/src/lib/init.service.ts +++ b/imxweb/projects/att/src/lib/init.service.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -25,15 +25,15 @@ */ import { Injectable } from '@angular/core'; -import { Router, Route } from '@angular/router'; +import { Route, Router } from '@angular/router'; +import { ProjectConfig, QerProjectConfig } from '@imx-modules/imx-api-qer'; import { ExtService, MenuItem, MenuService, TabItem } from 'qbm'; import { NotificationRegistryService } from 'qer'; import { canSeeAttestationPolicies, isAttestationAdmin } from './admin/permissions-helper'; import { PermissionsService } from './admin/permissions.service'; import { DashboardPluginComponent } from './dashboard-plugin/dashboard-plugin.component'; import { AttestationWrapperComponent } from './runs/attestation/attestation-wrapper/attestation-wrapper.component'; -import { ProjectConfig, QerProjectConfig } from 'imx-api-qer'; @Injectable({ providedIn: 'root' }) export class InitService { @@ -42,7 +42,7 @@ export class InitService { private readonly router: Router, private readonly menuService: MenuService, private readonly notificationService: NotificationRegistryService, - private readonly permissions: PermissionsService + private readonly permissions: PermissionsService, ) { this.setupMenu(); } @@ -65,7 +65,17 @@ export class InitService { inputData: { id: 'attestations', label: '#LDS#Attestation', - checkVisibility: async (_) => (await this.permissions.isAttestationAdmin()), + checkVisibility: async (_) => await this.permissions.isAttestationAdmin(), + }, + sortOrder: 0, + } as TabItem); + + this.extService.register('dugSidesheet',{ + instance: AttestationWrapperComponent, + inputData: { + id: 'attestations', + label: '#LDS#Attestation', + checkVisibility: async (_) => true, }, sortOrder: 0, } as TabItem); @@ -94,10 +104,11 @@ export class InitService { } private setupMenu(): void { - this.menuService.addMenuFactories((preProps: string[], features: string[]) => { - if (!preProps.includes('ATTESTATION')) { - return null; - } + this.menuService.addMenuFactories( + (preProps: string[], features: string[]) => { + if (!preProps.includes('ATTESTATION')) { + return undefined; + } const menu: MenuItem = { id: 'ROOT_Attestation', @@ -126,7 +137,7 @@ export class InitService { }; if (canSeeAttestationPolicies(features)) { - menu.items.push({ + menu.items?.push({ id: 'ATT_Attestation_AttestationRuns', route: 'attestation/runs', title: '#LDS#Menu Entry Attestation runs', @@ -134,7 +145,7 @@ export class InitService { sorting: '20-40', }); - menu.items.push({ + menu.items?.push({ id: 'ATT_Attestation_AttestationPolicies', route: 'attestation/policies', title: '#LDS#Menu Entry Attestation policies', @@ -142,7 +153,7 @@ export class InitService { sorting: '20-50', }); - menu.items.push({ + menu.items?.push({ id: 'ATT_Attestation_AttestationPolicyGroup', route: 'attestation/policy-group', title: '#LDS#Menu Entry Policy collections', @@ -151,22 +162,22 @@ export class InitService { }); } - if (isAttestationAdmin(features)) { - menu.items.push({ - id: 'ATT_Attestation_AttestationPreselection', - route: 'attestation/preselection', - title: '#LDS#Menu Entry Sample data', - description: '#LDS#Shows an overview of samples.', - sorting: '20-50', - }); - } + if (isAttestationAdmin(features)) { + menu.items?.push({ + id: 'ATT_Attestation_AttestationPreselection', + route: 'attestation/preselection', + title: '#LDS#Menu Entry Sampling data', + description: '#LDS#Shows an overview of samples.', + sorting: '20-50', + }); + } return menu; }, function (preProps: string[], __: string[], projectConfig: QerProjectConfig & ProjectConfig) { - const deviceEnabled = projectConfig.DeviceConfig.VI_Hardware_Enabled; - if (!preProps.includes('MAC') || !preProps.includes('ITSHOP') || ! deviceEnabled) { - return null; + const deviceEnabled = !!projectConfig.DeviceConfig?.VI_Hardware_Enabled; + if (!preProps.includes('MAC') || !preProps.includes('ITSHOP') || !deviceEnabled) { + return undefined; } return { @@ -182,7 +193,7 @@ export class InitService { }, ], }; - } + }, ); } } diff --git a/imxweb/projects/att/src/lib/new-user/confirm-dialog.component.html b/imxweb/projects/att/src/lib/new-user/confirm-dialog.component.html index bf924f244..eed5173d3 100644 --- a/imxweb/projects/att/src/lib/new-user/confirm-dialog.component.html +++ b/imxweb/projects/att/src/lib/new-user/confirm-dialog.component.html @@ -1,9 +1,9 @@ -

    {{'#LDS#Success' | translate }}

    +

    {{ '#LDS#Success' | translate }}

    -
    +
    -
    \ No newline at end of file +
    diff --git a/imxweb/projects/att/src/lib/new-user/confirm-dialog.component.ts b/imxweb/projects/att/src/lib/new-user/confirm-dialog.component.ts index 82c38d9b6..242fbd4f0 100644 --- a/imxweb/projects/att/src/lib/new-user/confirm-dialog.component.ts +++ b/imxweb/projects/att/src/lib/new-user/confirm-dialog.component.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -29,11 +29,8 @@ import { MAT_DIALOG_DATA } from '@angular/material/dialog'; import { ParameterizedText } from 'qbm'; @Component({ - templateUrl: './confirm-dialog.component.html' + templateUrl: './confirm-dialog.component.html', }) export class ConfirmDialogComponent { - - constructor( - @Inject(MAT_DIALOG_DATA) public ptext: ParameterizedText - ) { } + constructor(@Inject(MAT_DIALOG_DATA) public ptext: ParameterizedText) {} } diff --git a/imxweb/projects/aob/src/lib/applications/application-hyperview/application-hyperview.service.ts b/imxweb/projects/att/src/lib/new-user/new-user-metadata.service.ts similarity index 64% rename from imxweb/projects/aob/src/lib/applications/application-hyperview/application-hyperview.service.ts rename to imxweb/projects/att/src/lib/new-user/new-user-metadata.service.ts index fb1e8204e..16e406f07 100644 --- a/imxweb/projects/aob/src/lib/applications/application-hyperview/application-hyperview.service.ts +++ b/imxweb/projects/att/src/lib/new-user/new-user-metadata.service.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -25,21 +25,23 @@ */ import { Injectable } from '@angular/core'; +import { MetaTableData } from '@imx-modules/imx-qbm-dbts'; -import { ApiClientService } from 'qbm'; -import { ShapeData } from 'imx-api-qer'; -import { QerApiService } from 'qer'; +import { ApiClientService, MetadataService } from 'qbm'; +import { ApiService } from '../api.service'; @Injectable({ - providedIn: 'root' + providedIn: 'root', }) -export class ApplicationHyperviewService { - +export class NewUserMetadataService extends MetadataService { constructor( - private readonly apiClient: QerApiService, - private readonly apiProvider: ApiClientService) { } + private readonly apiClient: ApiService, + private readonly apiProvider: ApiClientService, + ) { + super(); + } - public async get(uidApplication: string): Promise { - return this.apiProvider.request(() => this.apiClient.client.portal_hyperview_get('AOBApplication', uidApplication)); + protected async getTable(tableName: string, options?: any): Promise { + return this.apiProvider.request(() => this.apiClient.client.register_metadata_table_get(tableName, options)); } } diff --git a/imxweb/projects/att/src/lib/new-user/new-user.component.html b/imxweb/projects/att/src/lib/new-user/new-user.component.html index f5e3283fb..48ed66823 100644 --- a/imxweb/projects/att/src/lib/new-user/new-user.component.html +++ b/imxweb/projects/att/src/lib/new-user/new-user.component.html @@ -1,39 +1,27 @@
    -

    #LDS#Fill out the following fields.

    - +
    - -
    - - {{ ldsCaptchaInfo | translate }} - -
    - -
    - - - -
    - +
    -
    - -
    diff --git a/imxweb/projects/att/src/lib/new-user/new-user.component.scss b/imxweb/projects/att/src/lib/new-user/new-user.component.scss index 7a7729443..672c46cc9 100644 --- a/imxweb/projects/att/src/lib/new-user/new-user.component.scss +++ b/imxweb/projects/att/src/lib/new-user/new-user.component.scss @@ -1,7 +1,3 @@ -.alert-container { - margin-bottom: 1em; -} - .captcha-container { display: flex; @@ -16,21 +12,6 @@ } } -.eui-sidesheet-content { - display: flex; - flex-direction: column; -} - -.eui-sidesheet-actions { - .justify-start { - margin-right: auto; - } - - button:not(:last-of-type):not(.justify-start) { - margin-right: 10px; - } -} - .errormessages { display: block; margin: 1em 0 1em 0; diff --git a/imxweb/projects/att/src/lib/new-user/new-user.component.ts b/imxweb/projects/att/src/lib/new-user/new-user.component.ts index 6be17eba9..36494b378 100644 --- a/imxweb/projects/att/src/lib/new-user/new-user.component.ts +++ b/imxweb/projects/att/src/lib/new-user/new-user.component.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -24,7 +24,6 @@ * */ -import { OverlayRef } from '@angular/cdk/overlay'; import { ChangeDetectorRef, Component, OnDestroy, OnInit } from '@angular/core'; import { UntypedFormBuilder, UntypedFormGroup } from '@angular/forms'; import { MatDialog } from '@angular/material/dialog'; @@ -32,26 +31,43 @@ import { EuiLoadingService, EuiSidesheetRef } from '@elemental-ui/core'; import { TranslateService } from '@ngx-translate/core'; import { Subscription } from 'rxjs'; -import { RegisterPerson } from 'imx-api-att'; -import { CaptchaService, ColumnDependentReference, ConfirmationService, ErrorService, ParameterizedText, UserMessageService, CdrFactoryService } from 'qbm'; +import { RegisterPerson } from '@imx-modules/imx-api-att'; +import { + CaptchaService, + CdrFactoryService, + ColumnDependentReference, + ConfirmationService, + ErrorService, + MetadataService, + ParameterizedText, + UserMessageService, +} from 'qbm'; import { ApiService } from '../api.service'; import { ConfirmDialogComponent } from './confirm-dialog.component'; +import { NewUserMetadataService } from './new-user-metadata.service'; @Component({ templateUrl: './new-user.component.html', - styleUrls: ['./new-user.component.scss'] + styleUrls: ['./new-user.component.scss'], + providers: [ + { + provide: MetadataService, + useClass: NewUserMetadataService, + }, + CaptchaService, + ], }) export class NewUserComponent implements OnInit, OnDestroy { - public readonly profileForm: UntypedFormGroup; public busy = false; public person: RegisterPerson; - public cdrList: ColumnDependentReference[] = []; + public cdrList: (ColumnDependentReference | undefined)[] = []; - public ldsCaptchaInfo = '#LDS#Please enter the characters from the image.'; - public ldsAccountInfo = '#LDS#Your account "%CentralAccount%" has been successfully created and the email address "%DefaultEmailAddress%" has been assigned to the account. Once your account is approved, it will be activated.'; + public ldsCaptchaInfo = '#LDS#Enter the characters from the image.'; + public ldsAccountInfo = + '#LDS#Your account "%CentralAccount%" has been successfully created and the email address "%DefaultEmailAddress%" has been assigned to the account. Once your account is approved, it will be activated.'; private disposable: () => void; private readonly subscriptions: Subscription[] = []; @@ -68,25 +84,28 @@ export class NewUserComponent implements OnInit, OnDestroy { private readonly cdrFactoryService: CdrFactoryService, errorService: ErrorService, formBuilder: UntypedFormBuilder, - confirmation: ConfirmationService + confirmation: ConfirmationService, ) { + this.captchaSvc.captchaImageUrl = 'register/captchaimage'; this.profileForm = new UntypedFormGroup({ formArray: formBuilder.array([]) }); this.disposable = errorService.setTarget('sidesheet'); - this.subscriptions.push(this.sidesheetRef.closeClicked().subscribe(async (result) => { - if (!this.profileForm.pristine) { - const close = await confirmation.confirmLeaveWithUnsavedChanges(); - if (close) { - this.sidesheetRef.close(); + this.subscriptions.push( + this.sidesheetRef.closeClicked().subscribe(async (result) => { + if (!this.profileForm.pristine) { + const close = await confirmation.confirmLeaveWithUnsavedChanges(); + if (close) { + this.sidesheetRef.close(); + } + } else { + this.sidesheetRef.close(result); } - } else { - this.sidesheetRef.close(result); - } - })); + }), + ); } public ngOnDestroy(): void { - this.subscriptions.forEach(s => s.unsubscribe()); + this.subscriptions.forEach((s) => s.unsubscribe()); this.disposable(); } public async ngOnInit(): Promise { @@ -94,7 +113,10 @@ export class NewUserComponent implements OnInit, OnDestroy { try { const data = await this.attApiClient.client.register_config_get(); - this.cdrList =this.cdrFactoryService.buildCdrFromColumnList(this.person.GetEntity(),data.WritablePropertiesForUnregisteredUsers); + this.cdrList = this.cdrFactoryService.buildCdrFromColumnList( + this.person.GetEntity(), + data.WritablePropertiesForUnregisteredUsers || [], + ); } finally { this.busy = false; this.cd.detectChanges(); @@ -103,10 +125,11 @@ export class NewUserComponent implements OnInit, OnDestroy { public async save(): Promise { // reset the error message - this.messageSvc.subject.next(undefined); + this.messageSvc.subject.next({ text: '' }); - let overlayRef: OverlayRef; - setTimeout(() => overlayRef = this.busyService.show()); + if (this.busyService.overlayRefs.length === 0) { + this.busyService.show(); + } try { // use response code this.person.extendedData = { Code: this.captchaSvc.Response }; @@ -118,17 +141,16 @@ export class NewUserComponent implements OnInit, OnDestroy { const parameterizedText: ParameterizedText = { value: template, marker: { start: '"%', end: '%"' }, - getParameterValue: columnName => this.person.GetEntity().GetColumn(columnName).GetDisplayValue() + getParameterValue: (columnName) => this.person.GetEntity().GetColumn(columnName).GetDisplayValue(), }; this.sidesheetRef.close(); this.disposable(); this.dialog.open(ConfirmDialogComponent, { data: parameterizedText }); - } catch (e) { throw e; } finally { this.captchaSvc.ReinitCaptcha(); - setTimeout(() => this.busyService.hide(overlayRef)); + this.busyService.hide(); } } } diff --git a/imxweb/projects/att/src/lib/new-user/new-user.module.ts b/imxweb/projects/att/src/lib/new-user/new-user.module.ts index 6a677a047..5dc32f3d1 100644 --- a/imxweb/projects/att/src/lib/new-user/new-user.module.ts +++ b/imxweb/projects/att/src/lib/new-user/new-user.module.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -78,7 +78,12 @@ const routes: Routes = [ declarations: [OpenSidesheetComponent, NewUserComponent, UserActivationComponent, ConfirmDialogComponent], }) export class NewUserModule { - constructor(authService: AuthenticationService, router: Router, apiService: ApiService, private readonly logger: ClassloggerService) { + constructor( + authService: AuthenticationService, + router: Router, + apiService: ApiService, + private readonly logger: ClassloggerService, + ) { const newUserAuthProvider: AuthConfigProvider = { display: '#LDS#Create new account', name: 'NewUser', diff --git a/imxweb/projects/att/src/lib/new-user/open-sidesheet.component.scss b/imxweb/projects/att/src/lib/new-user/open-sidesheet.component.scss deleted file mode 100644 index dac3e7996..000000000 --- a/imxweb/projects/att/src/lib/new-user/open-sidesheet.component.scss +++ /dev/null @@ -1,5 +0,0 @@ -@import "variables.scss"; - -.mat-raised-button { - background-color: $VI_Common_Color_Blue_3; -} \ No newline at end of file diff --git a/imxweb/projects/att/src/lib/new-user/open-sidesheet.component.ts b/imxweb/projects/att/src/lib/new-user/open-sidesheet.component.ts index 8f25f3e61..057e2d5f4 100644 --- a/imxweb/projects/att/src/lib/new-user/open-sidesheet.component.ts +++ b/imxweb/projects/att/src/lib/new-user/open-sidesheet.component.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -28,27 +28,26 @@ import { Component, OnInit } from '@angular/core'; import { EuiSidesheetConfig, EuiSidesheetService } from '@elemental-ui/core'; import { TranslateService } from '@ngx-translate/core'; +import { calculateSidesheetWidth } from 'qbm'; import { NewUserComponent } from './new-user.component'; @Component({ template: '', - styleUrls: ['./open-sidesheet.component.scss'] }) -export class OpenSidesheetComponent implements OnInit{ - +export class OpenSidesheetComponent implements OnInit { constructor( private readonly sidesheet: EuiSidesheetService, - private readonly translate: TranslateService) { - } - public async ngOnInit(): Promise { - const config: EuiSidesheetConfig = { - title: await this.translate.get('#LDS#Heading Create New Account').toPromise(), - width: 'max(650px, 60%)', - panelClass: 'imx-sidesheet', - padding: '0px', - disableClose: true, - testId: 'register-new-user', - }; - this.sidesheet.open(NewUserComponent, config); + private readonly translate: TranslateService, + ) {} + public async ngOnInit(): Promise { + const config: EuiSidesheetConfig = { + title: await this.translate.get('#LDS#Heading Create New Account').toPromise(), + width: calculateSidesheetWidth(1000), + panelClass: 'imx-sidesheet', + padding: '0px', + disableClose: true, + testId: 'register-new-user', + }; + this.sidesheet.open(NewUserComponent, config); } } diff --git a/imxweb/projects/att/src/lib/new-user/user-activation.component.html b/imxweb/projects/att/src/lib/new-user/user-activation.component.html index 6caf4ffdf..68cf5eb6f 100644 --- a/imxweb/projects/att/src/lib/new-user/user-activation.component.html +++ b/imxweb/projects/att/src/lib/new-user/user-activation.component.html @@ -1,23 +1,20 @@
    +

    {{ '#LDS#Heading Confirm Email Address' | translate }}

    -

    {{ '#LDS#Heading Confirm Email Address' | translate }}

    + - + + {{ ldsText | translate }} +
    + - - - - {{ldsText| translate}} -
    - - - -
    -
    + +
    +
    diff --git a/imxweb/projects/att/src/lib/new-user/user-activation.component.scss b/imxweb/projects/att/src/lib/new-user/user-activation.component.scss index ab44607d5..c8eb92fe9 100644 --- a/imxweb/projects/att/src/lib/new-user/user-activation.component.scss +++ b/imxweb/projects/att/src/lib/new-user/user-activation.component.scss @@ -6,14 +6,6 @@ left: 0; } -.button-bar { - margin-top: 1em; - - button:not(:last-child) { - margin-right: 1em; - } -} - .pagecontent { margin: 1em; } diff --git a/imxweb/projects/att/src/lib/new-user/user-activation.component.ts b/imxweb/projects/att/src/lib/new-user/user-activation.component.ts index a451e84c3..ae1049a9c 100644 --- a/imxweb/projects/att/src/lib/new-user/user-activation.component.ts +++ b/imxweb/projects/att/src/lib/new-user/user-activation.component.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -27,9 +27,9 @@ import { Component, OnDestroy } from '@angular/core'; import { ActivatedRoute, Router } from '@angular/router'; import { EuiLoadingService } from '@elemental-ui/core'; +import { PersonActivationDto } from '@imx-modules/imx-api-att'; import { TranslateService } from '@ngx-translate/core'; -import { PersonActivationDto } from 'imx-api-att'; -import { AuthenticationService, SessionState, SnackBarService, SplashService } from 'qbm'; +import { AuthenticationService, ConfirmationService, Message, SessionState, SnackBarService, SplashService, UserMessageService } from 'qbm'; import { Subscription } from 'rxjs'; import { ApiService } from '../api.service'; @@ -43,9 +43,10 @@ export class UserActivationComponent implements OnDestroy { public ldsText: string; public hasProblems = false; - private readonly subscription: Subscription; + private readonly subscriptions: Subscription[] = []; private passcode: string; private uidCase: string; + public message: Message | undefined; constructor( private readonly attApiService: ApiService, @@ -55,28 +56,43 @@ export class UserActivationComponent implements OnDestroy { private readonly translateService: TranslateService, private readonly busyService: EuiLoadingService, private readonly splashService: SplashService, - private readonly router: Router + private readonly router: Router, + private readonly confirmationService: ConfirmationService, + private readonly userMessageService: UserMessageService, ) { - this.subscription = route.queryParamMap.subscribe(async (params) => { - this.busy = true; - try { - this.uidCase = params.get('aeweb_UID_AttestationCase'); - this.passcode = params.get('aeweb_PassCode'); - if (!this.hasFormat) { - return; + this.subscriptions.push( + route.queryParamMap.subscribe(async (params) => { + this.busy = true; + try { + this.uidCase = params.get('aeweb_UID_AttestationCase') || ''; + this.passcode = params.get('aeweb_PassCode') || ''; + if (!this.hasFormat) { + return; + } + this.data = await this.attApiService.client.passwordreset_activation_init_post(this.uidCase); + + // Apply culture + this.data?.Culture ? this.useCulture(this.data.Culture) : null; + } catch { + this.hasProblems = true; + } finally { + this.determineText(); + this.splashService.close(); + this.busy = false; } - this.data = await this.attApiService.client.passwordreset_activation_init_post(this.uidCase); + }), + ); - // Apply culture - this.data?.Culture ? this.useCulture(this.data.Culture) : null; - } catch { - this.hasProblems = true; - } finally { - this.determineText(); - this.splashService.close(); - this.busy = false; - } - }); + this.subscriptions.push( + this.userMessageService.subject.subscribe((message) => { + this.message = message; + if (!!this.message) { + this.confirmationService.showErrorMessage({ + Message: this.message?.text, + }); + } + }), + ); } public get hasFormat(): boolean { @@ -84,7 +100,7 @@ export class UserActivationComponent implements OnDestroy { } public ngOnDestroy(): void { - this.subscription?.unsubscribe(); + this.subscriptions.forEach((subscription) => subscription.unsubscribe()); } public async resendMail(): Promise { @@ -134,8 +150,7 @@ export class UserActivationComponent implements OnDestroy { this.ldsText = '#LDS#Your registration was denied.'; break; default: - this.ldsText = - '#LDS#There was an unexpected error. Please try again.'; + this.ldsText = '#LDS#There was an unexpected error. Please try again.'; } return; } diff --git a/imxweb/projects/att/src/lib/pick-category/pick-category-common.scss b/imxweb/projects/att/src/lib/pick-category/pick-category-common.scss index e46bdd2ad..402d7ab9e 100644 --- a/imxweb/projects/att/src/lib/pick-category/pick-category-common.scss +++ b/imxweb/projects/att/src/lib/pick-category/pick-category-common.scss @@ -1,30 +1,7 @@ -@mixin imx-flex-column-container { - display: flex; - flex-direction: column; -} - -@mixin imx-flex-row-container { - display: flex; - flex-direction: row; -} - -.eui-sidesheet-content { - @include imx-flex-column-container(); -} +@import 'base/mixins'; .heading-wrapper { - @include imx-flex-row-container(); + @include flex-row-container(); flex: 0 0 auto; align-items: flex-start; - - .helper-alert { - display: flex; - margin-bottom: 15px; - } - - .alert-wrapper { - margin: 0 0 0 auto; - align-self: flex-end; - width: 50%; - } } diff --git a/imxweb/projects/att/src/lib/pick-category/pick-category-create/pick-category-create.component.html b/imxweb/projects/att/src/lib/pick-category/pick-category-create/pick-category-create.component.html index f216c170a..09dd85e9a 100644 --- a/imxweb/projects/att/src/lib/pick-category/pick-category-create/pick-category-create.component.html +++ b/imxweb/projects/att/src/lib/pick-category/pick-category-create/pick-category-create.component.html @@ -1,6 +1,6 @@
    - - + +
    -
    - -
    @@ -40,28 +46,28 @@ {{ '#LDS#The following sample will be created:' | translate }} - +
    {{ '#LDS#Assigned identities:' | translate }}
    - - - - - - + + + + {{ entitySchema?.Columns?.[DisplayColumns.DISPLAY_PROPERTYNAME]?.Display }} + + {{ item.GetEntity().GetDisplay() }} + +
    - +
    -
    diff --git a/imxweb/projects/att/src/lib/pick-category/pick-category-create/pick-category-create.component.scss b/imxweb/projects/att/src/lib/pick-category/pick-category-create/pick-category-create.component.scss index ff4eba68b..6538ce992 100644 --- a/imxweb/projects/att/src/lib/pick-category/pick-category-create/pick-category-create.component.scss +++ b/imxweb/projects/att/src/lib/pick-category/pick-category-create/pick-category-create.component.scss @@ -1,110 +1,25 @@ -@import "../pick-category-common.scss"; -@import "@elemental-ui/core/src/styles/_eui_palette.scss"; +@import 'base/mixins'; +@import '../pick-category-common.scss'; +@import '@elemental-ui/core/src/styles/_eui_palette.scss'; :host { background-color: $color-gray-2; .eui-sidesheet-content { - > .mat-card { - display: flex; - flex-direction: column; - overflow: hidden; - } - .imx-dst-selected-identities { display: none; } - - div.imx-table-container { - display: flex; - flex-direction: column; - overflow: hidden; - height: inherit; - margin-bottom: 20px; - } - - .mat-stepper-vertical { - @include imx-flex-column-container(); - max-height: 100%; - - ::ng-deep .mat-step { - @include imx-flex-column-container(); - max-height: calc(100% - 144px); - flex: 1 1 auto; - - .mat-vertical-content-container { - @include imx-flex-column-container(); - height: calc(100% - 72px); - - .mat-vertical-content { - @include imx-flex-column-container(); - height: 100%; - flex: 1 1 auto; - - imx-pick-category-select-identities { - @include imx-flex-column-container(); - max-height: calc(100% - 36px); - - imx-data-source-toolbar { - background-color: $color-gray-0; - } - } - - .imx-stepper-button-container { - @include imx-flex-row-container(); - gap: 20px; - } - } - } - } - - .imx-summary-intro { - margin: 15px 0; - } - } } } .eui-dark-theme { :host { background-color: $color-gray-80; - - .eui-sidesheet-content { - .mat-stepper-vertical { - ::ng-deep .mat-step { - .mat-vertical-content-container { - .mat-vertical-content { - imx-pick-category-select-identities { - imx-data-source-toolbar { - background-color: $color-gray-80; - } - } - } - } - } - } - } } } .eui-contrast-theme { :host { background-color: $color-gray-100; - - .eui-sidesheet-content { - .mat-stepper-vertical { - ::ng-deep .mat-step { - .mat-vertical-content-container { - .mat-vertical-content { - imx-pick-category-select-identities { - imx-data-source-toolbar { - background-color: $color-gray-100; - } - } - } - } - } - } - } } } diff --git a/imxweb/projects/att/src/lib/pick-category/pick-category-create/pick-category-create.component.spec.ts b/imxweb/projects/att/src/lib/pick-category/pick-category-create/pick-category-create.component.spec.ts index e79243f27..aa21ec0d2 100644 --- a/imxweb/projects/att/src/lib/pick-category/pick-category-create/pick-category-create.component.spec.ts +++ b/imxweb/projects/att/src/lib/pick-category/pick-category-create/pick-category-create.component.spec.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -27,24 +27,25 @@ import { CUSTOM_ELEMENTS_SCHEMA } from '@angular/core'; import { ComponentFixture, TestBed } from '@angular/core/testing'; import { FormsModule, ReactiveFormsModule } from '@angular/forms'; -import { EuiSidesheetRef, EUI_SIDESHEET_DATA } from '@elemental-ui/core'; +import { EUI_SIDESHEET_DATA, EuiSidesheetRef } from '@elemental-ui/core'; +import { PortalPickcategoryItems } from '@imx-modules/imx-api-qer'; import { of } from 'rxjs'; -import { PortalPickcategoryItems } from 'imx-api-qer'; -import { ConfirmationService } from 'qbm'; +import { PortalPersonAll } from '@imx-modules/imx-api-qer'; +import { ClassloggerService, ConfirmationService, MessageDialogService, SqlWizardApiService } from 'qbm'; import { PickCategoryService } from '../pick-category.service'; import { PickCategoryCreateComponent } from './pick-category-create.component'; +import { IdentitiesService } from 'qer'; + describe('PickCategoryCreateComponent', () => { let component: PickCategoryCreateComponent; let fixture: ComponentFixture; - let confirm = true; const mockConfirmationService = { - confirm: jasmine.createSpy('confirm') - .and.callFake(() => Promise.resolve(confirm)) - } + confirm: jasmine.createSpy('confirm').and.callFake(() => Promise.resolve(confirm)), + }; const sidesheetData = { pickCategory: { @@ -59,16 +60,9 @@ describe('PickCategoryCreateComponent', () => { beforeEach(async () => { await TestBed.configureTestingModule({ - declarations: [ - PickCategoryCreateComponent - ], - schemas: [ - CUSTOM_ELEMENTS_SCHEMA - ], - imports: [ - FormsModule, - ReactiveFormsModule - ], + declarations: [PickCategoryCreateComponent], + schemas: [CUSTOM_ELEMENTS_SCHEMA], + imports: [FormsModule, ReactiveFormsModule], providers: [ { provide: EUI_SIDESHEET_DATA, @@ -77,13 +71,13 @@ describe('PickCategoryCreateComponent', () => { { provide: EuiSidesheetRef, useValue: { - close: jasmine.createSpy('close'), + close: jasmine.createSpy('close'), closeClicked: jasmine.createSpy('closeClicked').and.returnValue(of(undefined)), - } + }, }, { provide: ConfirmationService, - useValue: mockConfirmationService + useValue: mockConfirmationService, }, { provide: PickCategoryService, @@ -92,12 +86,20 @@ describe('PickCategoryCreateComponent', () => { deletePickCategoryItems: jasmine.createSpy('deletePickCategoryItems').and.returnValue({}), getPickCategoryItems: jasmine.createSpy('getPickCategoryItems').and.returnValue({}), handleOpenLoader: jasmine.createSpy('handleOpenLoader').and.callThrough(), - handleCloseLoader: jasmine.createSpy('handleCloseLoader').and.callThrough() - } - } - ] - }) - .compileComponents(); + handleCloseLoader: jasmine.createSpy('handleCloseLoader').and.callThrough(), + }, + }, + { + provide: IdentitiesService, + useValue: { + personAllSchema: PortalPersonAll.GetEntitySchema(), + }, + }, + { provide: ClassloggerService, useValue: { debug: () => {} } }, + { provide: MessageDialogService, useValue: {} }, + { provide: SqlWizardApiService, useValue: {} }, + ], + }).compileComponents(); }); beforeEach(() => { diff --git a/imxweb/projects/att/src/lib/pick-category/pick-category-create/pick-category-create.component.ts b/imxweb/projects/att/src/lib/pick-category/pick-category-create/pick-category-create.component.ts index 8706d411d..7e1131188 100644 --- a/imxweb/projects/att/src/lib/pick-category/pick-category-create/pick-category-create.component.ts +++ b/imxweb/projects/att/src/lib/pick-category/pick-category-create/pick-category-create.component.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -27,69 +27,56 @@ import { StepperSelectionEvent } from '@angular/cdk/stepper'; import { Component, Inject, OnDestroy, OnInit, ViewChild } from '@angular/core'; import { UntypedFormGroup } from '@angular/forms'; -import { EuiSidesheetRef, EUI_SIDESHEET_DATA } from '@elemental-ui/core'; +import { EUI_SIDESHEET_DATA, EuiSidesheetRef } from '@elemental-ui/core'; import { Subscription } from 'rxjs'; -import { PortalPickcategory, PortalPickcategoryItems } from 'imx-api-qer'; -import { DisplayColumns } from 'imx-qbm-dbts'; +import { PortalPersonAll, PortalPickcategory, PortalPickcategoryItems } from '@imx-modules/imx-api-qer'; +import { DisplayColumns, EntitySchema, TypedEntityCollectionData } from '@imx-modules/imx-qbm-dbts'; -import { - BaseCdr, - ColumnDependentReference, - ConfirmationService, - DataSourceToolbarSettings, - DataSourceWrapper, -} from 'qbm'; +import { BaseCdr, ColumnDependentReference, ConfirmationService, DataViewInitParameters, DataViewSource } from 'qbm'; +import { IdentitiesService } from 'qer'; import { PickCategorySelectIdentitiesComponent } from '../pick-category-select-identities/pick-category-select-identities.component'; import { PickCategoryService } from '../pick-category.service'; @Component({ selector: 'imx-pick-category-create', templateUrl: './pick-category-create.component.html', - styleUrls: ['./pick-category-create.component.scss'] + styleUrls: ['./pick-category-create.component.scss'], + providers: [DataViewSource], }) export class PickCategoryCreateComponent implements OnInit, OnDestroy { - public readonly displayNameForm = new UntypedFormGroup({}); - - public readonly dstWrapper: DataSourceWrapper; - public dstSettings: DataSourceToolbarSettings; - + public readonly DisplayColumns = DisplayColumns; public selectedItems: PortalPickcategoryItems[] = []; - public displayNameCdr: ColumnDependentReference; public displayNameReadonlyCdr: ColumnDependentReference; - + public entitySchema: EntitySchema; + private readonly subscriptions: Subscription[] = []; @ViewChild(PickCategorySelectIdentitiesComponent) public selectIndentities: PickCategorySelectIdentitiesComponent; constructor( - @Inject(EUI_SIDESHEET_DATA) public data: { - pickCategory: PortalPickcategory + @Inject(EUI_SIDESHEET_DATA) + public data: { + pickCategory: PortalPickcategory; }, private readonly sidesheetRef: EuiSidesheetRef, - readonly pickCategoryService: PickCategoryService, - confirmation: ConfirmationService + readonly pickCategoryService: PickCategoryService, + confirmation: ConfirmationService, + private readonly identityService: IdentitiesService, + public dataSource: DataViewSource, ) { - const entitySchema = pickCategoryService.pickcategoryItemsSchema; - - this.dstWrapper = new DataSourceWrapper( - () => Promise.resolve({ - totalCount: this.selectIndentities.selection?.length, - Data: this.selectIndentities.selection + this.entitySchema = this.identityService.personAllSchema; + this.subscriptions.push( + sidesheetRef.closeClicked().subscribe(async () => { + if (!this.displayNameForm.pristine && !(await confirmation.confirmLeaveWithUnsavedChanges())) { + return; + } + + sidesheetRef.close(false); }), - [entitySchema.Columns[DisplayColumns.DISPLAY_PROPERTYNAME]], - entitySchema ); - - this.subscriptions.push(sidesheetRef.closeClicked().subscribe(async () => { - if (!this.displayNameForm.pristine && !(await confirmation.confirmLeaveWithUnsavedChanges())) { - return; - } - - sidesheetRef.close(false); - })); } public async ngOnInit(): Promise { @@ -99,7 +86,7 @@ export class PickCategoryCreateComponent implements OnInit, OnDestroy { } public ngOnDestroy(): void { - this.subscriptions.forEach(s => s.unsubscribe()); + this.subscriptions.forEach((s) => s.unsubscribe()); } public async stepChange(change: StepperSelectionEvent): Promise { @@ -117,11 +104,18 @@ export class PickCategoryCreateComponent implements OnInit, OnDestroy { this.sidesheetRef.close({ create: true, pickCategory: this.data.pickCategory, - pickedItems: this.selectIndentities?.selection + pickedItems: this.selectIndentities?.selection, }); } private async getData(): Promise { - this.dstSettings = await this.dstWrapper.getDstSettings(); + const dataViewInitParameters: DataViewInitParameters = { + execute: (): Promise> => + Promise.resolve({ Data: this.selectIndentities.selection, totalCount: this.selectIndentities.selection.length }), + schema: this.entitySchema, + columnsToDisplay: [this.entitySchema.Columns[DisplayColumns.DISPLAY_PROPERTYNAME]], + localSource: true, + }; + this.dataSource.init(dataViewInitParameters); } } diff --git a/imxweb/projects/att/src/lib/pick-category/pick-category-select-identities/pick-category-select-identities.component.html b/imxweb/projects/att/src/lib/pick-category/pick-category-select-identities/pick-category-select-identities.component.html index a73245314..892e992e7 100644 --- a/imxweb/projects/att/src/lib/pick-category/pick-category-select-identities/pick-category-select-identities.component.html +++ b/imxweb/projects/att/src/lib/pick-category/pick-category-select-identities/pick-category-select-identities.component.html @@ -1,45 +1,36 @@ - - +
    - - +
    -
    -

    - - {{'#LDS#Selected identities' | translate}} - - - {{selection?.length > 0 ? selection.length : 0}} - -

    -
    - - - - - - - - - - + + + + + + {{ entitySchema?.Columns?.[DisplayColumns.DISPLAY_PROPERTYNAME]?.Display }} + + {{ item.GetEntity().GetDisplay() }} + + + diff --git a/imxweb/projects/att/src/lib/pick-category/pick-category-select-identities/pick-category-select-identities.component.scss b/imxweb/projects/att/src/lib/pick-category/pick-category-select-identities/pick-category-select-identities.component.scss index 74ca43dc5..9c7bc0c1f 100644 --- a/imxweb/projects/att/src/lib/pick-category/pick-category-select-identities/pick-category-select-identities.component.scss +++ b/imxweb/projects/att/src/lib/pick-category/pick-category-select-identities/pick-category-select-identities.component.scss @@ -1,43 +1,11 @@ -@import "../pick-category-common.scss"; -@import "@elemental-ui/core/src/styles/_eui_palette.scss"; +@import '../pick-category-common.scss'; :host { - background-color: $color-gray-2; - ::ng-deep .cdk-column-select { width: 50px; } - .imx-selected-items { - margin: 0; - line-height: 36px; - display: flex; - flex: 1 0 auto; - margin: auto; - align-items: center; - - .imx-badge { - background-color: transparent; - ::ng-deep .eui-badge-content { - font-size: 14px; - line-height: 14px; - } - } - } - - button { - margin-left: 10px; - } -} - -.eui-dark-theme { - :host { - background-color: $color-gray-80; - } -} - -.eui-contrast-theme { - :host { - background-color: $color-gray-100; + .justify-start { + margin-right: auto; } } diff --git a/imxweb/projects/att/src/lib/pick-category/pick-category-select-identities/pick-category-select-identities.component.spec.ts b/imxweb/projects/att/src/lib/pick-category/pick-category-select-identities/pick-category-select-identities.component.spec.ts index b4a4149dc..594c1cea9 100644 --- a/imxweb/projects/att/src/lib/pick-category/pick-category-select-identities/pick-category-select-identities.component.spec.ts +++ b/imxweb/projects/att/src/lib/pick-category/pick-category-select-identities/pick-category-select-identities.component.spec.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -26,10 +26,10 @@ import { CUSTOM_ELEMENTS_SCHEMA } from '@angular/core'; import { ComponentFixture, TestBed, waitForAsync } from '@angular/core/testing'; -import { EuiSidesheetRef, EUI_SIDESHEET_DATA } from '@elemental-ui/core'; -import { PortalPersonAll } from 'imx-api-qer'; +import { EUI_SIDESHEET_DATA, EuiSidesheetRef } from '@elemental-ui/core'; +import { PortalPersonAll } from '@imx-modules/imx-api-qer'; -import { MetadataService } from 'qbm'; +import { ClassloggerService, ConfirmationService, MessageDialogService, MetadataService, SqlWizardApiService } from 'qbm'; import { IdentitiesService } from 'qer'; import { PickCategoryService } from '../pick-category.service'; import { PickCategorySelectIdentitiesComponent } from './pick-category-select-identities.component'; @@ -51,17 +51,13 @@ describe('PickCategorySelectIdentitiesComponent', () => { const metadataServiceStub = { tables: {}, - update: jasmine.createSpy('update') + update: jasmine.createSpy('update'), }; beforeEach(waitForAsync(() => { TestBed.configureTestingModule({ - declarations: [ - PickCategorySelectIdentitiesComponent - ], - schemas: [ - CUSTOM_ELEMENTS_SCHEMA - ], + declarations: [PickCategorySelectIdentitiesComponent], + schemas: [CUSTOM_ELEMENTS_SCHEMA], providers: [ { provide: EUI_SIDESHEET_DATA, @@ -69,40 +65,41 @@ describe('PickCategorySelectIdentitiesComponent', () => { }, { provide: EuiSidesheetRef, - useValue: {} + useValue: {}, }, { provide: MetadataService, - useValue: metadataServiceStub + useValue: metadataServiceStub, }, { provide: PickCategoryService, useValue: { handleOpenLoader: jasmine.createSpy('handleOpenLoader').and.callThrough(), - handleCloseLoader: jasmine.createSpy('handleCloseLoader').and.callThrough() - } + handleCloseLoader: jasmine.createSpy('handleCloseLoader').and.callThrough(), + }, }, { provide: IdentitiesService, useValue: { personAllSchema: PortalPersonAll.GetEntitySchema(), - getAllPerson: jasmine.createSpy('getAllPerson').and.returnValue(Promise.resolve( - { totalCount: 100, Data: ['1', '2', '3'] } - )), - } + getAllPerson: jasmine.createSpy('getAllPerson').and.returnValue(Promise.resolve({ totalCount: 100, Data: ['1', '2', '3'] })), + }, }, - ] - }) - .compileComponents(); + { provide: ClassloggerService, useValue: { debug: () => {} } }, + { provide: MessageDialogService, useValue: {} }, + { provide: ConfirmationService, useValue: {} }, + { provide: SqlWizardApiService, useValue: {} }, + ], + }).compileComponents(); })); -beforeEach(() => { - fixture = TestBed.createComponent(PickCategorySelectIdentitiesComponent); - component = fixture.componentInstance; - fixture.detectChanges(); -}); + beforeEach(() => { + fixture = TestBed.createComponent(PickCategorySelectIdentitiesComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); -it('should create', () => { - expect(component).toBeTruthy(); -}); + it('should create', () => { + expect(component).toBeTruthy(); + }); }); diff --git a/imxweb/projects/att/src/lib/pick-category/pick-category-select-identities/pick-category-select-identities.component.ts b/imxweb/projects/att/src/lib/pick-category/pick-category-select-identities/pick-category-select-identities.component.ts index 3f64c9fdf..d808d6ffa 100644 --- a/imxweb/projects/att/src/lib/pick-category/pick-category-select-identities/pick-category-select-identities.component.ts +++ b/imxweb/projects/att/src/lib/pick-category/pick-category-select-identities/pick-category-select-identities.component.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -25,36 +25,35 @@ */ import { Component, Inject, Input, OnInit } from '@angular/core'; -import { EuiSidesheetRef, EUI_SIDESHEET_DATA } from '@elemental-ui/core'; +import { EUI_SIDESHEET_DATA, EuiSidesheetRef } from '@elemental-ui/core'; -import { PortalPersonAll, PortalPickcategoryItems } from 'imx-api-qer'; +import { PortalPersonAll, PortalPickcategoryItems } from '@imx-modules/imx-api-qer'; import { CollectionLoadParameters, CompareOperator, DbObjectKey, DisplayColumns, + EntitySchema, FilterData, FilterType, IClientProperty, - TypedEntity -} from 'imx-qbm-dbts'; + TypedEntityCollectionData, +} from '@imx-modules/imx-qbm-dbts'; -import { DataSourceToolbarSettings, DataSourceWrapper, MetadataService } from 'qbm'; +import { DataViewInitParameters, DataViewSource, MetadataService } from 'qbm'; import { IdentitiesService } from 'qer'; -import { PickCategoryService } from '../pick-category.service'; @Component({ selector: 'imx-pick-category-select-identities', templateUrl: './pick-category-select-identities.component.html', styleUrls: ['./pick-category-select-identities.component.scss'], + providers: [DataViewSource], }) - export class PickCategorySelectIdentitiesComponent implements OnInit { - - public readonly dstWrapper: DataSourceWrapper; - public dstSettings: DataSourceToolbarSettings; public displayColumns: IClientProperty[]; - public selection: TypedEntity[]; + public selection: PortalPersonAll[]; + public entitySchema: EntitySchema; + public DisplayColumns = DisplayColumns; @Input() public embeddedMode = false; @@ -62,37 +61,30 @@ export class PickCategorySelectIdentitiesComponent implements OnInit { @Inject(EUI_SIDESHEET_DATA) public selectedItems: PortalPickcategoryItems[], private readonly sidesheetRef: EuiSidesheetRef, private readonly identityService: IdentitiesService, - private readonly pickCategoryService: PickCategoryService, private readonly metadataService: MetadataService, + public dataSource: DataViewSource, ) { - const entitySchema = this.identityService.personAllSchema; - - this.dstWrapper = new DataSourceWrapper( - state => this.identityService.getAllPerson(state), - [entitySchema.Columns[DisplayColumns.DISPLAY_PROPERTYNAME]], - entitySchema - ); + this.entitySchema = this.identityService.personAllSchema; } public async ngOnInit(): Promise { await this.getData(); } - public async getData(navigationState?: CollectionLoadParameters): Promise { - this.pickCategoryService.handleOpenLoader(); - - try { - navigationState = { - ...navigationState, - ... { filter: await this.getFilter() } - }; - this.dstSettings = await this.dstWrapper.getDstSettings(navigationState); - } finally { - this.pickCategoryService.handleCloseLoader(); - } + public async getData(): Promise { + const dataViewInitParameters: DataViewInitParameters = { + execute: async (params: CollectionLoadParameters, signal: AbortSignal): Promise> => { + const filters = await this.getFilter(); + return this.identityService.getAllPerson({ ...params, filter: [...(params.filter || []), ...filters] }, signal); + }, + schema: this.entitySchema, + columnsToDisplay: [this.entitySchema.Columns[DisplayColumns.DISPLAY_PROPERTYNAME]], + selectionChange: (selection: Array) => this.onSelectionChanged(selection), + }; + this.dataSource.init(dataViewInitParameters); } - public onSelectionChanged(selection: TypedEntity[]): void { + public onSelectionChanged(selection: PortalPersonAll[]): void { this.selection = selection; } @@ -102,21 +94,20 @@ export class PickCategorySelectIdentitiesComponent implements OnInit { private async getFilter(): Promise { if (this.selectedItems && this.selectedItems.length > 0) { - const tableName = DbObjectKey.FromXml(this.selectedItems[0].ObjectKeyItem.value).TableName; await this.metadataService.updateNonExisting([tableName]); const tableMetadata = this.metadataService.tables[tableName]; - return this.selectedItems.map(item => { + return this.selectedItems.map((item) => { return { - ColumnName: tableMetadata.PrimaryKeyColumns[0], + ColumnName: tableMetadata?.PrimaryKeyColumns?.[0] || '', Type: FilterType.Compare, CompareOp: CompareOperator.NotEqual, - Value1: DbObjectKey.FromXml(item.ObjectKeyItem.value).Keys[0] + Value1: DbObjectKey.FromXml(item.ObjectKeyItem.value).Keys[0], }; }); } + return []; } - } diff --git a/imxweb/projects/att/src/lib/pick-category/pick-category-sidesheet/pick-category-sidesheet.component.html b/imxweb/projects/att/src/lib/pick-category/pick-category-sidesheet/pick-category-sidesheet.component.html index 7ea95b1a8..44a110f4d 100644 --- a/imxweb/projects/att/src/lib/pick-category/pick-category-sidesheet/pick-category-sidesheet.component.html +++ b/imxweb/projects/att/src/lib/pick-category/pick-category-sidesheet/pick-category-sidesheet.component.html @@ -1,40 +1,53 @@
    - + - - {{'#LDS#Assigned identities' | translate}} - - - - - - - - -
    - -
    -
    - +
    +
    diff --git a/imxweb/projects/att/src/lib/pick-category/pick-category-sidesheet/pick-category-sidesheet.component.scss b/imxweb/projects/att/src/lib/pick-category/pick-category-sidesheet/pick-category-sidesheet.component.scss index 3bdae3d1e..bd1d96cb0 100644 --- a/imxweb/projects/att/src/lib/pick-category/pick-category-sidesheet/pick-category-sidesheet.component.scss +++ b/imxweb/projects/att/src/lib/pick-category/pick-category-sidesheet/pick-category-sidesheet.component.scss @@ -1,31 +1,12 @@ -@import "../pick-category-common.scss"; -@import "@elemental-ui/core/src/styles/_eui_palette.scss"; +@import 'base/mixins'; +@import '../pick-category-common.scss'; +@import '@elemental-ui/core/src/styles/_eui_palette.scss'; :host { background-color: $color-gray-2; - - .imx-table-container { - @include imx-flex-column-container(); - overflow: hidden; - - > span { - margin-bottom: 10px; - display: block; - } - - .buttons { - @include imx-flex-row-container(); - justify-content: flex-end; - - .justify-start { - margin-right: auto; - - eui-icon { - font-size: 14px; - margin-right: 4px; - } - } - } + .eui-sidesheet-content{ + display: flex; + flex-direction: column; } } diff --git a/imxweb/projects/att/src/lib/pick-category/pick-category-sidesheet/pick-category-sidesheet.component.spec.ts b/imxweb/projects/att/src/lib/pick-category/pick-category-sidesheet/pick-category-sidesheet.component.spec.ts index 3a9e8a5d2..44e7abd65 100644 --- a/imxweb/projects/att/src/lib/pick-category/pick-category-sidesheet/pick-category-sidesheet.component.spec.ts +++ b/imxweb/projects/att/src/lib/pick-category/pick-category-sidesheet/pick-category-sidesheet.component.spec.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -24,18 +24,17 @@ * */ - import { CUSTOM_ELEMENTS_SCHEMA } from '@angular/core'; import { ComponentFixture, TestBed } from '@angular/core/testing'; import { FormsModule, ReactiveFormsModule } from '@angular/forms'; -import { EuiSidesheetService, EUI_SIDESHEET_DATA } from '@elemental-ui/core'; import { MatSnackBarModule } from '@angular/material/snack-bar'; +import { EUI_SIDESHEET_DATA, EuiSidesheetService } from '@elemental-ui/core'; -import { IClientProperty } from 'imx-qbm-dbts'; -import { ClassloggerService, ConfirmationService } from 'qbm'; +import { IClientProperty } from '@imx-modules/imx-qbm-dbts'; +import { ClassloggerService, ConfirmationService, SqlWizardApiService } from 'qbm'; -import { PickCategorySidesheetComponent } from './pick-category-sidesheet.component'; import { PickCategoryService } from '../pick-category.service'; +import { PickCategorySidesheetComponent } from './pick-category-sidesheet.component'; describe('PickCategorySidesheetComponent', () => { let component: PickCategorySidesheetComponent; @@ -49,30 +48,21 @@ describe('PickCategorySidesheetComponent', () => { GetColumn: () => ({ GetValue: () => ({}) }), }), }, - isNew: false + isNew: false, }; let confirm = true; const mockConfirmationService = { - confirm: jasmine.createSpy('confirm') - .and.callFake(() => Promise.resolve(confirm)) - } + confirm: jasmine.createSpy('confirm').and.callFake(() => Promise.resolve(confirm)), + }; const deletePickedItemsSpy = jasmine.createSpy('deletePickedItems').and.returnValue(Promise.resolve({})); beforeEach(async () => { await TestBed.configureTestingModule({ - declarations: [ - PickCategorySidesheetComponent - ], - schemas: [ - CUSTOM_ELEMENTS_SCHEMA - ], - imports: [ - FormsModule, - ReactiveFormsModule, - MatSnackBarModule - ], + declarations: [PickCategorySidesheetComponent], + schemas: [CUSTOM_ELEMENTS_SCHEMA], + imports: [FormsModule, ReactiveFormsModule, MatSnackBarModule], providers: [ { provide: EUI_SIDESHEET_DATA, @@ -80,18 +70,18 @@ describe('PickCategorySidesheetComponent', () => { }, { provide: EuiSidesheetService, - useValue: {} + useValue: {}, }, { provide: ConfirmationService, - useValue: mockConfirmationService + useValue: mockConfirmationService, }, { provide: ClassloggerService, useValue: { debug: jasmine.createSpy('debug').and.callThrough(), - trace: jasmine.createSpy('trace').and.callThrough() - } + trace: jasmine.createSpy('trace').and.callThrough(), + }, }, { provide: PickCategoryService, @@ -100,12 +90,12 @@ describe('PickCategorySidesheetComponent', () => { deletePickedItems: deletePickedItemsSpy, getPickCategoryItems: jasmine.createSpy('getPickCategoryItems').and.returnValue({}), handleOpenLoader: jasmine.createSpy('handleOpenLoader').and.callThrough(), - handleCloseLoader: jasmine.createSpy('handleCloseLoader').and.callThrough() - } - } - ] - }) - .compileComponents(); + handleCloseLoader: jasmine.createSpy('handleCloseLoader').and.callThrough(), + }, + }, + { provide: SqlWizardApiService, useValue: {} }, + ], + }).compileComponents(); }); beforeEach(() => { @@ -120,15 +110,12 @@ describe('PickCategorySidesheetComponent', () => { }); describe('removePickedItems() tests', () => { - for (const testcase of [ - { confirm: true }, - { confirm: false } - ]) { + for (const testcase of [{ confirm: true }, { confirm: false }]) { it('should make a call to delete the picked items, if the user confirm the dialog', async () => { confirm = testcase.confirm; await component.removePickedItems(); - if(testcase.confirm) { + if (testcase.confirm) { expect(deletePickedItemsSpy).toHaveBeenCalled(); } else { expect(deletePickedItemsSpy).not.toHaveBeenCalled(); diff --git a/imxweb/projects/att/src/lib/pick-category/pick-category-sidesheet/pick-category-sidesheet.component.ts b/imxweb/projects/att/src/lib/pick-category/pick-category-sidesheet/pick-category-sidesheet.component.ts index fe345c3de..5b57ac0f7 100644 --- a/imxweb/projects/att/src/lib/pick-category/pick-category-sidesheet/pick-category-sidesheet.component.ts +++ b/imxweb/projects/att/src/lib/pick-category/pick-category-sidesheet/pick-category-sidesheet.component.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -24,61 +24,55 @@ * */ -import { Component, Inject, OnInit, ViewChild } from '@angular/core'; -import { EuiSidesheetService, EUI_SIDESHEET_DATA } from '@elemental-ui/core'; +import { Component, Inject, OnInit } from '@angular/core'; +import { EUI_SIDESHEET_DATA, EuiSidesheetService } from '@elemental-ui/core'; import { TranslateService } from '@ngx-translate/core'; -import { PortalPickcategory, PortalPickcategoryItems } from 'imx-api-qer'; -import { CollectionLoadParameters, DisplayColumns, TypedEntity } from 'imx-qbm-dbts'; +import { PortalPickcategory, PortalPickcategoryItems } from '@imx-modules/imx-api-qer'; +import { CollectionLoadParameters, DisplayColumns, EntitySchema, TypedEntity, TypedEntityCollectionData } from '@imx-modules/imx-qbm-dbts'; +import { UntypedFormGroup } from '@angular/forms'; import { BaseCdr, + calculateSidesheetWidth, ClassloggerService, ConfirmationService, - DataSourceToolbarSettings, - DataSourceWrapper, - DataTableComponent, + DataViewInitParameters, + DataViewSource, SnackBarService, } from 'qbm'; import { PickCategorySelectIdentitiesComponent } from '../pick-category-select-identities/pick-category-select-identities.component'; import { PickCategoryService } from '../pick-category.service'; -import { UntypedFormGroup } from '@angular/forms'; @Component({ selector: 'imx-pick-category-sidesheet', templateUrl: './pick-category-sidesheet.component.html', - styleUrls: ['./pick-category-sidesheet.component.scss'] + styleUrls: ['./pick-category-sidesheet.component.scss'], + providers: [DataViewSource], }) export class PickCategorySidesheetComponent implements OnInit { - - public readonly dstWrapper: DataSourceWrapper; public readonly form = new UntypedFormGroup({}); - public dstSettings: DataSourceToolbarSettings; public selectedPickedItems: PortalPickcategoryItems[] = []; public displayNameCdr: any; - - @ViewChild(DataTableComponent) private table: DataTableComponent; + public entitySchema: EntitySchema; + public DisplayColumns = DisplayColumns; private uidPickCategory: string; constructor( - @Inject(EUI_SIDESHEET_DATA) public data: { - pickCategory: PortalPickcategory + @Inject(EUI_SIDESHEET_DATA) + public data: { + pickCategory: PortalPickcategory; }, private readonly sidesheet: EuiSidesheetService, private readonly snackBar: SnackBarService, private readonly confirmationService: ConfirmationService, private readonly pickCategoryService: PickCategoryService, private readonly translate: TranslateService, - private readonly logger: ClassloggerService + private readonly logger: ClassloggerService, + public dataSource: DataViewSource, ) { - const entitySchema = this.pickCategoryService.pickcategoryItemsSchema; - - this.dstWrapper = new DataSourceWrapper( - state => this.pickCategoryService.getPickCategoryItems(this.uidPickCategory, state), - [entitySchema.Columns[DisplayColumns.DISPLAY_PROPERTYNAME]], - entitySchema - ); + this.entitySchema = this.pickCategoryService.pickcategoryItemsSchema; } public async ngOnInit(): Promise { @@ -88,50 +82,55 @@ export class PickCategorySidesheetComponent implements OnInit { await this.getData(); } - public async getData(newState?: CollectionLoadParameters): Promise { - this.pickCategoryService.handleOpenLoader(); - try { - this.dstSettings = await this.dstWrapper.getDstSettings(newState); - } finally { - this.pickCategoryService.handleCloseLoader(); - } + public async getData(): Promise { + const dataViewInitParameters: DataViewInitParameters = { + execute: (params: CollectionLoadParameters): Promise> => + this.pickCategoryService.getPickCategoryItems(this.uidPickCategory, params), + schema: this.entitySchema, + columnsToDisplay: [this.entitySchema.Columns[DisplayColumns.DISPLAY_PROPERTYNAME]], + selectionChange: (selection: Array) => this.onSelectionChanged(selection), + }; + this.dataSource.init(dataViewInitParameters); } public selectedItemsCanBeDeleted(): boolean { - return this.selectedPickedItems != null && - this.selectedPickedItems.length > 0 && - this.data.pickCategory.IsManual.value; + return this.selectedPickedItems != null && this.selectedPickedItems.length > 0 && this.data.pickCategory.IsManual.value; } - public onSelectionChanged(items: PortalPickcategoryItems[]): void { + public onSelectionChanged(items: TypedEntity[]): void { this.logger.trace(this, 'selection changed', items); - this.selectedPickedItems = items; + this.selectedPickedItems = items as PortalPickcategoryItems[]; } public async assignPickedItems(): Promise { - const selection = await this.sidesheet.open(PickCategorySelectIdentitiesComponent, { - title: await this.translate.get('#LDS#Heading Assign Identities').toPromise(), - subTitle: this.data.pickCategory.GetEntity().GetDisplay(), - padding: '0px', - width: '700px', - disableClose: false, - testId: 'pick-category-select-identities', - data: this.dstSettings.dataSource.Data - }).afterClosed().toPromise(); + const selection = await this.sidesheet + .open(PickCategorySelectIdentitiesComponent, { + title: await this.translate.get('#LDS#Heading Assign Identities').toPromise(), + subTitle: this.data.pickCategory.GetEntity().GetDisplay(), + padding: '0px', + width: calculateSidesheetWidth(700, 0.4), + disableClose: false, + testId: 'pick-category-select-identities', + data: this.dataSource?.data, + }) + .afterClosed() + .toPromise(); if (selection && (await this.pickCategoryService.createPickedItems(selection, this.uidPickCategory)) > 0) { - await this.getData(); + this.dataSource.updateState(); } } public async removePickedItems(): Promise { - if (await this.confirmationService.confirm({ - Title: '#LDS#Heading Remove Identities', - Message: '#LDS#Are you sure you want to remove the selected identities?' - })) { - if (await this.pickCategoryService.deletePickedItems(this.uidPickCategory, this.selectedPickedItems) > 0) { - await this.getData(); - this.table?.clearSelection(); + if ( + await this.confirmationService.confirm({ + Title: '#LDS#Heading Remove Identities', + Message: '#LDS#Are you sure you want to remove the selected identities?', + }) + ) { + if ((await this.pickCategoryService.deletePickedItems(this.uidPickCategory, this.selectedPickedItems)) > 0) { + this.dataSource.updateState(); + this.dataSource.selection.clear(); } } } @@ -149,5 +148,4 @@ export class PickCategorySidesheetComponent implements OnInit { } } } - } diff --git a/imxweb/projects/att/src/lib/pick-category/pick-category.component.html b/imxweb/projects/att/src/lib/pick-category/pick-category.component.html index 02f0b87b9..f7efadae5 100644 --- a/imxweb/projects/att/src/lib/pick-category/pick-category.component.html +++ b/imxweb/projects/att/src/lib/pick-category/pick-category.component.html @@ -1,47 +1,43 @@
    -
    -

    - {{ '#LDS#Heading Sample Data' | translate }} +
    +

    + {{ '#LDS#Heading Sampling Data' | translate }} -

    +

    +
    -
    - - - - - - - +
    + + + {{ entitySchema?.Columns?.DisplayName?.Display }} + + {{ item.GetEntity().GetColumn('DisplayName').GetDisplayValue() }} + + + + {{ entitySchema?.Columns?.IsManual?.Display }} + + {{ item.GetEntity().GetColumn('IsManual').GetDisplayValue() }} + + + +
    -
    - -
    - - diff --git a/imxweb/projects/att/src/lib/pick-category/pick-category.component.scss b/imxweb/projects/att/src/lib/pick-category/pick-category.component.scss index f1608e184..7c9b371f9 100644 --- a/imxweb/projects/att/src/lib/pick-category/pick-category.component.scss +++ b/imxweb/projects/att/src/lib/pick-category/pick-category.component.scss @@ -1,43 +1,17 @@ -@import '../../../../../shared/scss/common-table.scss'; +@import 'base/mixins'; @import 'pick-category-common.scss'; :host { - @include imx-flex-column-container(); - overflow: hidden; - height: inherit; - display: flex; - flex-direction: column; - max-width: 100%; + @include flex-column-container($overflow: hidden, $height: inherit, $max-width: 100%); } .imx-pickcategory-page { background-color: inherit; - @include imx-flex-column-container(); - overflow: hidden; - display: flex; - flex-direction: column; + @include flex-column-container($overflow: hidden); flex: 1 1 auto; - div.imx-table-container { - @include imx-flex-column-container(); - overflow: hidden; - height: inherit; - flex: 1 1 auto; - display: flex; - flex-direction: column; - - .imx-pickcategory-table { - flex-grow: 1; - overflow: auto; - } - } - - .imx-button-bar { - @include imx-button-bar(); - } - - .mat-card { - @include imx-flex-fill-control-hidden-overflow(); + .mat-mdc-card { + @include flex-column-container-fill(); } } @@ -45,11 +19,6 @@ .imx-pickcategory-page { .heading-wrapper { display: block; - - .alert-wrapper { - margin: 0 0 20px 0; - width: 100%; - } } } } diff --git a/imxweb/projects/att/src/lib/pick-category/pick-category.component.spec.ts b/imxweb/projects/att/src/lib/pick-category/pick-category.component.spec.ts index 0648abdec..2c2224191 100644 --- a/imxweb/projects/att/src/lib/pick-category/pick-category.component.spec.ts +++ b/imxweb/projects/att/src/lib/pick-category/pick-category.component.spec.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -27,9 +27,9 @@ import { CUSTOM_ELEMENTS_SCHEMA } from '@angular/core'; import { ComponentFixture, TestBed } from '@angular/core/testing'; import { EuiSidesheetService } from '@elemental-ui/core'; -import { IClientProperty } from 'imx-qbm-dbts'; +import { IClientProperty } from '@imx-modules/imx-qbm-dbts'; -import { ClassloggerService, ConfirmationService, HelpContextualService, UserMessageService } from 'qbm'; +import { ClassloggerService, ConfirmationService, HelpContextualService, SqlWizardApiService, UserMessageService } from 'qbm'; import { Subject } from 'rxjs'; import { PickCategoryComponent } from './pick-category.component'; @@ -39,71 +39,70 @@ describe('PickCategoryComponent', () => { let component: PickCategoryComponent; let fixture: ComponentFixture; - const sidesheetServiceStub = { - open: jasmine.createSpy('open') + open: jasmine.createSpy('open'), }; let confirm = true; const mockConfirmationService = { - confirm: jasmine.createSpy('confirm') - .and.callFake(() => Promise.resolve(confirm)) - } + confirm: jasmine.createSpy('confirm').and.callFake(() => Promise.resolve(confirm)), + }; const deletePickCategoriesSpy = jasmine.createSpy('deletePickCategories').and.returnValue(Promise.resolve({})); const mockHelpContextualService = { - setHelpContextId: jasmine.createSpy('setHelpContextId') - .and.callFake(() => Promise.resolve()) - } + setHelpContextId: jasmine.createSpy('setHelpContextId').and.callFake(() => Promise.resolve()), + }; beforeEach(async () => { await TestBed.configureTestingModule({ - declarations: [ - PickCategoryComponent - ], - schemas: [ - CUSTOM_ELEMENTS_SCHEMA - ], + declarations: [PickCategoryComponent], + schemas: [CUSTOM_ELEMENTS_SCHEMA], providers: [ { provide: PickCategoryService, useValue: { - pickcategorySchema: { Columns: { __Display: { ColumnName: '__Display' } as IClientProperty } }, + pickcategorySchema: { + Columns: { + __Display: { ColumnName: '__Display' } as IClientProperty, + IsManual: { ColumnName: 'IsManual' } as IClientProperty, + DisplayName: { ColumnName: 'DisplayName' } as IClientProperty, + }, + }, getPickCategories: jasmine.createSpy('getPickCategories').and.returnValue({}), deletePickCategories: deletePickCategoriesSpy, createPickCategory: jasmine.createSpy('createPickCategory').and.returnValue({}), handleOpenLoader: jasmine.createSpy('handleOpenLoader').and.callThrough(), handleCloseLoader: jasmine.createSpy('handleCloseLoader').and.callThrough(), - } + }, }, { provide: EuiSidesheetService, - useValue: sidesheetServiceStub + useValue: sidesheetServiceStub, }, { provide: ConfirmationService, - useValue: mockConfirmationService + useValue: mockConfirmationService, }, { provide: UserMessageService, useValue: { - subject: new Subject() - } + subject: new Subject(), + }, }, { provide: ClassloggerService, useValue: { debug: jasmine.createSpy('debug').and.callThrough(), - trace: jasmine.createSpy('trace').and.callThrough() - } + trace: jasmine.createSpy('trace').and.callThrough(), + }, }, { provide: HelpContextualService, - useValue: mockHelpContextualService - } - ] - }) - .compileComponents(); + useValue: mockHelpContextualService, + }, + { provide: SqlWizardApiService, useValue: {} }, + ], + }).compileComponents(); }); beforeEach(() => { @@ -118,15 +117,12 @@ describe('PickCategoryComponent', () => { }); describe('delete() tests', () => { - for (const testcase of [ - { confirm: true }, - { confirm: false } - ]) { + for (const testcase of [{ confirm: true }, { confirm: false }]) { it('should make a call to delete the PickCategories, if the user confirm the dialog', async () => { confirm = testcase.confirm; await component.delete(); - if(testcase.confirm) { + if (testcase.confirm) { expect(deletePickCategoriesSpy).toHaveBeenCalled(); } else { expect(deletePickCategoriesSpy).not.toHaveBeenCalled(); diff --git a/imxweb/projects/att/src/lib/pick-category/pick-category.component.ts b/imxweb/projects/att/src/lib/pick-category/pick-category.component.ts index 0c14cb8a3..0adbc0080 100644 --- a/imxweb/projects/att/src/lib/pick-category/pick-category.component.ts +++ b/imxweb/projects/att/src/lib/pick-category/pick-category.component.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -24,23 +24,23 @@ * */ -import { Component, OnDestroy, OnInit, ViewChild } from '@angular/core'; +import { Component, OnInit } from '@angular/core'; import { EuiSidesheetService } from '@elemental-ui/core'; import { TranslateService } from '@ngx-translate/core'; -import { PortalPickcategory } from 'imx-api-qer'; -import { CollectionLoadParameters, DisplayColumns, TypedEntity, ValType } from 'imx-qbm-dbts'; +import { PortalPickcategory } from '@imx-modules/imx-api-qer'; +import { CollectionLoadParameters, EntitySchema, TypedEntityCollectionData } from '@imx-modules/imx-qbm-dbts'; import { + calculateSidesheetWidth, ClassloggerService, - DataSourceToolbarSettings, - UserMessageService, - DataTableComponent, - DataSourceWrapper, ConfirmationService, + DataViewInitParameters, + DataViewSource, + HELP_CONTEXTUAL, HelpContextualComponent, HelpContextualService, - HELP_CONTEXTUAL + UserMessageService, } from 'qbm'; import { PickCategoryCreateComponent } from './pick-category-create/pick-category-create.component'; import { PickCategorySidesheetComponent } from './pick-category-sidesheet/pick-category-sidesheet.component'; @@ -49,15 +49,12 @@ import { PickCategoryService } from './pick-category.service'; @Component({ selector: 'imx-pick-category', templateUrl: './pick-category.component.html', - styleUrls: ['./pick-category.component.scss'] + styleUrls: ['./pick-category.component.scss'], + providers: [DataViewSource], }) -export class PickCategoryComponent implements OnInit, OnDestroy { - - public readonly dstWrapper: DataSourceWrapper; - public dstSettings: DataSourceToolbarSettings; +export class PickCategoryComponent implements OnInit { public selectedPickCategoryItems: PortalPickcategory[] = []; - - @ViewChild(DataTableComponent) private table: DataTableComponent; + public entitySchema: EntitySchema; constructor( private readonly pickCategoryService: PickCategoryService, @@ -66,84 +63,82 @@ export class PickCategoryComponent implements OnInit, OnDestroy { private readonly translate: TranslateService, private readonly messageService: UserMessageService, private readonly logger: ClassloggerService, - private readonly helpContextualService: HelpContextualService + private readonly helpContextualService: HelpContextualService, + public dataSource: DataViewSource, ) { - - const entitySchema = this.pickCategoryService.pickcategorySchema; - - this.dstWrapper = new DataSourceWrapper( - state => this.pickCategoryService.getPickCategories(state), - [ - entitySchema.Columns[DisplayColumns.DISPLAY_PROPERTYNAME], - entitySchema.Columns.IsManual - ], - entitySchema - ); + this.entitySchema = this.pickCategoryService.pickcategorySchema; } public async ngOnInit(): Promise { await this.getData(); } - public ngOnDestroy(): void { - this.table?.clearSelection(); - } - public onSelectionChanged(items: PortalPickcategory[]): void { this.logger.trace(this, 'selection changed', items); this.selectedPickCategoryItems = items; } public selectedItemsCanBeDeleted(): boolean { - return this.selectedPickCategoryItems != null && + return ( + this.selectedPickCategoryItems != null && this.selectedPickCategoryItems.length > 0 && - this.selectedPickCategoryItems.every(item => item.IsManual.value); + this.selectedPickCategoryItems.every((item) => item.IsManual.value) + ); } - public async getData(newState?: CollectionLoadParameters): Promise { - this.pickCategoryService.handleOpenLoader(); - try { - this.dstSettings = await this.dstWrapper.getDstSettings(newState); - } finally { - this.pickCategoryService.handleCloseLoader(); - } + public async getData(): Promise { + const dataViewInitParameters: DataViewInitParameters = { + execute: (params: CollectionLoadParameters, signal: AbortSignal): Promise> => + this.pickCategoryService.getPickCategories(params, signal), + schema: this.entitySchema, + columnsToDisplay: [this.entitySchema.Columns.DisplayName, this.entitySchema.Columns.IsManual], + highlightEntity: (entity: PortalPickcategory) => { + this.viewDetails(entity); + }, + selectionChange: (selection: Array) => this.onSelectionChanged(selection), + }; + this.dataSource.init(dataViewInitParameters); } public async viewDetails(pickCategory: PortalPickcategory): Promise { if (pickCategory) { - this.helpContextualService.setHelpContextId(HELP_CONTEXTUAL.AttestationPreselectionEdit) - const result = await this.sideSheet.open(PickCategorySidesheetComponent, { - title: await this.translate.get('#LDS#Heading Edit Sample').toPromise(), - subTitle: pickCategory.GetEntity().GetDisplay(), - panelClass: 'imx-sidesheet', - padding: '0', - width: '600px', - testId: 'pickCategory-details-sidesheet', - data: { - pickCategory - }, - headerComponent: HelpContextualComponent - }).afterClosed().toPromise(); + this.helpContextualService.setHelpContextId(HELP_CONTEXTUAL.AttestationPreselectionEdit); + const result = await this.sideSheet + .open(PickCategorySidesheetComponent, { + title: await this.translate.get('#LDS#Heading Edit Sample').toPromise(), + subTitle: pickCategory.GetEntity().GetDisplay(), + panelClass: 'imx-sidesheet', + padding: '0', + width: calculateSidesheetWidth(), + testId: 'pickCategory-details-sidesheet', + data: { + pickCategory, + }, + headerComponent: HelpContextualComponent, + }) + .afterClosed() + .toPromise(); if (result) { - this.getData(); + this.dataSource.updateState(); } - } - else { + } else { this.messageService.subject.next({ - text: '#LDS#You cannot edit the sample. The sample does not exist (anymore). Please reload the page.' + text: '#LDS#You cannot edit the sample. The sample does not exist (anymore). Please reload the page.', }); } } public async delete(): Promise { - if (await this.confirmationService.confirm({ - Title: '#LDS#Heading Delete Sample', - Message: '#LDS#Are you sure you want to delete the sample?' - })) { - if (await this.pickCategoryService.deletePickCategories(this.selectedPickCategoryItems) > 0) { - await this.getData(); - this.table?.clearSelection(); + if ( + await this.confirmationService.confirm({ + Title: '#LDS#Heading Delete Samples', + Message: '#LDS#Are you sure you want to delete the selected samples?', + }) + ) { + if ((await this.pickCategoryService.deletePickCategories(this.selectedPickCategoryItems)) > 0) { + this.dataSource.selection.clear(); + this.dataSource.updateState(); } } } @@ -153,29 +148,30 @@ export class PickCategoryComponent implements OnInit, OnDestroy { this.logger.trace(this, 'new pick category created', newPickCategory); if (newPickCategory) { - - this.helpContextualService.setHelpContextId(HELP_CONTEXTUAL.AttestationPreselectionCreate) - const result = await this.sideSheet.open(PickCategoryCreateComponent, { - title: await this.translate.get('#LDS#Heading Create Sample').toPromise(), - panelClass: 'imx-sidesheet', - padding: '0', - width: '700px', - disableClose: true, - testId: 'pickCategory-create-sidesheet', - data: { - pickCategory: newPickCategory - }, - headerComponent: HelpContextualComponent - }).afterClosed().toPromise(); + this.helpContextualService.setHelpContextId(HELP_CONTEXTUAL.AttestationPreselectionCreate); + const result = await this.sideSheet + .open(PickCategoryCreateComponent, { + title: await this.translate.get('#LDS#Heading Create Sample').toPromise(), + panelClass: 'imx-sidesheet', + padding: '0', + width: calculateSidesheetWidth(700, 0.4), + disableClose: true, + testId: 'pickCategory-create-sidesheet', + data: { + pickCategory: newPickCategory, + }, + headerComponent: HelpContextualComponent, + }) + .afterClosed() + .toPromise(); if (result?.create) { await this.pickCategoryService.saveNewPickCategoryAndItems(result.pickCategory, result.pickedItems); - this.getData(); + this.dataSource.updateState(); } - } - else { + } else { this.messageService.subject.next({ - text: '#LDS#The sample could not be created. Please reload the page and try again.' + text: '#LDS#The sample could not be created. Please reload the page and try again.', }); } } diff --git a/imxweb/projects/att/src/lib/pick-category/pick-category.module.ts b/imxweb/projects/att/src/lib/pick-category/pick-category.module.ts index 2ce7c3bc2..ce30959b3 100644 --- a/imxweb/projects/att/src/lib/pick-category/pick-category.module.ts +++ b/imxweb/projects/att/src/lib/pick-category/pick-category.module.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -24,32 +24,27 @@ * */ -import { NgModule } from '@angular/core'; import { CommonModule } from '@angular/common'; +import { NgModule } from '@angular/core'; import { ReactiveFormsModule } from '@angular/forms'; import { MatButtonModule } from '@angular/material/button'; import { MatCardModule } from '@angular/material/card'; import { MatDialogModule } from '@angular/material/dialog'; import { MatSnackBarModule } from '@angular/material/snack-bar'; import { MatStepperModule } from '@angular/material/stepper'; -import { TranslateModule } from '@ngx-translate/core'; import { EuiCoreModule } from '@elemental-ui/core'; +import { TranslateModule } from '@ngx-translate/core'; -import { DataSourceToolbarModule, DataTableModule, CdrModule, SelectedElementsModule, HelpContextualModule } from 'qbm'; +import { CdrModule, DataSourceToolbarModule, DataTableModule, DataViewModule, HelpContextualModule, SelectedElementsModule } from 'qbm'; -import { PickCategoryComponent } from './pick-category.component'; -import { PickCategorySidesheetComponent } from './pick-category-sidesheet/pick-category-sidesheet.component'; -import { PickCategorySelectIdentitiesComponent } from './pick-category-select-identities/pick-category-select-identities.component'; +import { MatTableModule } from '@angular/material/table'; import { PickCategoryCreateComponent } from './pick-category-create/pick-category-create.component'; - +import { PickCategorySelectIdentitiesComponent } from './pick-category-select-identities/pick-category-select-identities.component'; +import { PickCategorySidesheetComponent } from './pick-category-sidesheet/pick-category-sidesheet.component'; +import { PickCategoryComponent } from './pick-category.component'; @NgModule({ - declarations: [ - PickCategoryComponent, - PickCategorySidesheetComponent, - PickCategorySelectIdentitiesComponent, - PickCategoryCreateComponent, - ], + declarations: [PickCategoryComponent, PickCategorySidesheetComponent, PickCategorySelectIdentitiesComponent, PickCategoryCreateComponent], imports: [ CommonModule, CdrModule, @@ -65,6 +60,8 @@ import { PickCategoryCreateComponent } from './pick-category-create/pick-categor TranslateModule, SelectedElementsModule, HelpContextualModule, - ] + MatTableModule, + DataViewModule, + ], }) -export class PickCategoryModule { } +export class PickCategoryModule {} diff --git a/imxweb/projects/att/src/lib/pick-category/pick-category.service.spec.ts b/imxweb/projects/att/src/lib/pick-category/pick-category.service.spec.ts index 86c5dcc5a..9d26fcc88 100644 --- a/imxweb/projects/att/src/lib/pick-category/pick-category.service.spec.ts +++ b/imxweb/projects/att/src/lib/pick-category/pick-category.service.spec.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -27,8 +27,8 @@ import { TestBed, waitForAsync } from '@angular/core/testing'; import { EuiLoadingService } from '@elemental-ui/core'; -import { PortalPickcategory, PortalPickcategoryItems } from 'imx-api-qer'; -import { IEntity } from 'imx-qbm-dbts'; +import { PortalPickcategory, PortalPickcategoryItems } from '@imx-modules/imx-api-qer'; +import { IEntity } from '@imx-modules/imx-qbm-dbts'; import { ClassloggerService, SnackBarService } from 'qbm'; import { QerApiService } from 'qer'; @@ -41,7 +41,7 @@ describe('PickCategoryService', () => { const euiLoadingServiceStub = { hide: jasmine.createSpy('hide'), - show: jasmine.createSpy('show') + show: jasmine.createSpy('show'), }; beforeEach(() => { @@ -51,18 +51,18 @@ describe('PickCategoryService', () => { provide: ClassloggerService, useValue: { debug: jasmine.createSpy('debug').and.callThrough(), - trace: jasmine.createSpy('trace').and.callThrough() - } + trace: jasmine.createSpy('trace').and.callThrough(), + }, }, { provide: EuiLoadingService, - useValue: euiLoadingServiceStub + useValue: euiLoadingServiceStub, }, { provide: SnackBarService, useValue: { - open: jasmine.createSpy('open') - } + open: jasmine.createSpy('open'), + }, }, { provide: QerApiService, @@ -73,30 +73,32 @@ describe('PickCategoryService', () => { Post: jasmine.createSpy('Post').and.returnValue(Promise.resolve({ Data: [{}] })), GetSchema: () => ({ Columns: [] }), createEntity: jasmine.createSpy('createEntity').and.returnValue({ - GetEntity: () => ({ - Commit: commitSpy - }) as unknown as IEntity, - ObjectKeyDelegated: { Value: '' } - } as unknown as PortalPickcategory) + GetEntity: () => + ({ + Commit: commitSpy, + }) as unknown as IEntity, + ObjectKeyDelegated: { Value: '' }, + } as unknown as PortalPickcategory), }, PortalPickcategoryItems: { Get: jasmine.createSpy('Get').and.stub(), - Post: jasmine.createSpy('Post').and.returnValue(Promise.resolve({ Data: [{}]})), + Post: jasmine.createSpy('Post').and.returnValue(Promise.resolve({ Data: [{}] })), GetSchema: () => ({ Columns: [] }), createEntity: jasmine.createSpy('createEntity').and.returnValue({ - GetEntity: () => ({ - Commit: commitSpy - }) as unknown as IEntity, - ObjectKeyDelegated: { Value: '' } - } as unknown as PortalPickcategoryItems) - } + GetEntity: () => + ({ + Commit: commitSpy, + }) as unknown as IEntity, + ObjectKeyDelegated: { Value: '' }, + } as unknown as PortalPickcategoryItems), + }, }, client: { - portal_hyperview_get: jasmine.createSpy('portal_hyperview_get').and.callFake(() => Promise.resolve([1, 2, 3])) + portal_hyperview_get: jasmine.createSpy('portal_hyperview_get').and.callFake(() => Promise.resolve([1, 2, 3])), }, - } - } - ] + }, + }, + ], }); service = TestBed.inject(PickCategoryService); }); diff --git a/imxweb/projects/att/src/lib/pick-category/pick-category.service.ts b/imxweb/projects/att/src/lib/pick-category/pick-category.service.ts index 11c83673d..d881d6fc8 100644 --- a/imxweb/projects/att/src/lib/pick-category/pick-category.service.ts +++ b/imxweb/projects/att/src/lib/pick-category/pick-category.service.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -25,35 +25,25 @@ */ import { ErrorHandler, Injectable } from '@angular/core'; -import { OverlayRef } from '@angular/cdk/overlay'; import { EuiLoadingService } from '@elemental-ui/core'; -import { - CollectionLoadParameters, - EntityCollectionData, - EntitySchema, - ExtendedTypedEntityCollection, -} from 'imx-qbm-dbts'; -import { PortalPersonAll, PortalPickcategory, PortalPickcategoryItems } from 'imx-api-qer'; +import { PortalPersonAll, PortalPickcategory, PortalPickcategoryItems } from '@imx-modules/imx-api-qer'; +import { CollectionLoadParameters, EntityCollectionData, EntitySchema, ExtendedTypedEntityCollection } from '@imx-modules/imx-qbm-dbts'; -import { QerApiService } from 'qer'; import { ClassloggerService, SnackBarService } from 'qbm'; - +import { QerApiService } from 'qer'; @Injectable({ - providedIn: 'root' + providedIn: 'root', }) export class PickCategoryService { - - private busyIndicator: OverlayRef; - constructor( private readonly qerClient: QerApiService, private readonly busyService: EuiLoadingService, private readonly snackbar: SnackBarService, private readonly logger: ClassloggerService, private readonly errorHandler: ErrorHandler, - ) { } + ) {} public get pickcategorySchema(): EntitySchema { return this.qerClient.typedClient.PortalPickcategory.GetSchema(); @@ -63,9 +53,11 @@ export class PickCategoryService { return this.qerClient.typedClient.PortalPickcategoryItems.GetSchema(); } - public async getPickCategories(navigationState: CollectionLoadParameters): - Promise> { - return this.qerClient.typedClient.PortalPickcategory.Get(navigationState); + public async getPickCategories( + navigationState: CollectionLoadParameters, + signal?: AbortSignal, + ): Promise> { + return this.qerClient.typedClient.PortalPickcategory.Get(navigationState, { signal }); } /** @@ -84,10 +76,13 @@ export class PickCategoryService { try { deletedObjects = (await this.bulkDeletePickCategories(pickCategories)).length; if (deletedObjects > 0) { - this.snackbar.open({ - key: '#LDS#{0} samples have been successfully deleted.', - parameters: [deletedObjects] - }, '#LDS#Close'); + this.snackbar.open( + { + key: '#LDS#{0} samples have been successfully deleted.', + parameters: [deletedObjects], + }, + '#LDS#Close', + ); } } finally { this.handleCloseLoader(); @@ -99,18 +94,23 @@ export class PickCategoryService { return this.qerClient.typedClient.PortalPickcategory.createEntity(); } - public async getPickCategoryItems(uidQERPickCategory: string, navigationState: CollectionLoadParameters): - Promise> { + public async getPickCategoryItems( + uidQERPickCategory: string, + navigationState: CollectionLoadParameters, + ): Promise> { return this.qerClient.typedClient.PortalPickcategoryItems.Get(uidQERPickCategory, navigationState); } - public async deletePickCategoryItems(uidPickCategory: string, pickCategoriesItems: PortalPickcategoryItems[]) - : Promise { + public async deletePickCategoryItems( + uidPickCategory: string, + pickCategoriesItems: PortalPickcategoryItems[], + ): Promise { return this.handlePromiseLoader( Promise.all( - pickCategoriesItems.map(pickedItem => - this.qerClient.client.portal_pickcategory_items_delete(uidPickCategory, pickedItem.GetEntity().GetKeys().join(','))) - ) + pickCategoriesItems.map((pickedItem) => + this.qerClient.client.portal_pickcategory_items_delete(uidPickCategory, pickedItem.GetEntity().GetKeys().join(',')), + ), + ), ); } @@ -119,7 +119,7 @@ export class PickCategoryService { try { await this.qerClient.client.portal_pickcategory_items_post(uidPickCategory, { Reload: true, - Objects: pickCategoriesItems.map(item => item.EntityWriteDataSingle) + Objects: pickCategoriesItems.map((item) => item.EntityWriteDataSingle), }); assignedObjectsCounter++; this.logger.trace(this, `${pickCategoriesItems.length} pick category items assigned`); @@ -137,10 +137,13 @@ export class PickCategoryService { try { deletedObjects = (await this.deletePickCategoryItems(uidPickCategory, selectedPickedItems)).length; if (deletedObjects > 0) { - this.snackbar.open({ - key: '#LDS#{0} identities have been successfully removed.', - parameters: [deletedObjects] - }, '#LDS#Close'); + this.snackbar.open( + { + key: '#LDS#{0} identities have been successfully removed.', + parameters: [deletedObjects], + }, + '#LDS#Close', + ); } } finally { this.handleCloseLoader(); @@ -149,43 +152,41 @@ export class PickCategoryService { } public async createPickedItems(selection: any, uidPickCategory: string, showResultInSnackbar: boolean = true): Promise { - - const newAssignedObjects = (await this.handlePromiseLoader( - Promise.all( - selection.map(async (selectedItem: { XObjectKey: { value: string; }; }) => { - const pickedItem = this.qerClient.typedClient.PortalPickcategoryItems.createEntity(); - pickedItem.UID_QERPickCategory.value = uidPickCategory; - pickedItem.ObjectKeyItem.value = selectedItem.XObjectKey.value; - await pickedItem.GetEntity().Commit(true); - }) + const newAssignedObjects = ( + await this.handlePromiseLoader( + Promise.all( + selection.map(async (selectedItem: { XObjectKey: { value: string } }) => { + const pickedItem = this.qerClient.typedClient.PortalPickcategoryItems.createEntity(); + pickedItem.UID_QERPickCategory.value = uidPickCategory; + pickedItem.ObjectKeyItem.value = selectedItem.XObjectKey.value; + await pickedItem.GetEntity().Commit(true); + }), + ), ) - )).length; + ).length; if (newAssignedObjects > 0 && showResultInSnackbar) { - this.snackbar.open({ - key: '#LDS#{0} identities have been successfully assigned.', - parameters: [newAssignedObjects] - }, '#LDS#Close'); + this.snackbar.open( + { + key: '#LDS#{0} identities have been successfully assigned.', + parameters: [newAssignedObjects], + }, + '#LDS#Close', + ); } return newAssignedObjects; } public handleOpenLoader(): void { - if (!this.busyIndicator) { - setTimeout(() => this.busyIndicator = this.busyService.show()); + if (this.busyService.overlayRefs.length === 0) { + this.busyService.show(); } } public handleCloseLoader(): void { - if (this.busyIndicator) { - setTimeout(() => { - this.busyService.hide(this.busyIndicator); - this.busyIndicator = undefined; - }); - } + this.busyService.hide(); } public async saveNewPickCategoryAndItems(pickCategory: PortalPickcategory, pickedItems: PortalPersonAll[]): Promise { - this.handleOpenLoader(); try { const uidPickCategory = await this.postPickCategory(pickCategory); @@ -194,23 +195,26 @@ export class PickCategoryService { if (pickedItems && pickedItems.length > 0) { await this.createPickedItems(pickedItems, uidPickCategory, false); } - } finally { this.handleCloseLoader(); } - this.snackbar.open({ - key: '#LDS#The sample has been successfully created.', - parameters: [pickCategory.GetEntity().GetDisplay()] - }, '#LDS#Close'); - + this.snackbar.open( + { + key: '#LDS#The sample has been successfully created.', + parameters: [pickCategory.GetEntity().GetDisplay()], + }, + '#LDS#Close', + ); } private async bulkDeletePickCategories(pickCategories: PortalPickcategory[]): Promise { return this.handlePromiseLoader( Promise.all( - pickCategories.map(pickCategory => this.qerClient.client.portal_pickcategory_delete(pickCategory.GetEntity().GetKeys().join(','))) - ) + pickCategories.map((pickCategory) => + this.qerClient.client.portal_pickcategory_delete(pickCategory.GetEntity().GetKeys().join(',')), + ), + ), ); } diff --git a/imxweb/projects/att/src/lib/policies/attestation-cases/attestation-cases-component-parameter.interface.ts b/imxweb/projects/att/src/lib/policies/attestation-cases/attestation-cases-component-parameter.interface.ts index 3e25d60e6..ebb8af828 100644 --- a/imxweb/projects/att/src/lib/policies/attestation-cases/attestation-cases-component-parameter.interface.ts +++ b/imxweb/projects/att/src/lib/policies/attestation-cases/attestation-cases-component-parameter.interface.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -24,14 +24,14 @@ * */ -import { PolicyFilterElement} from 'imx-api-att'; +import { PolicyFilterElement } from '@imx-modules/imx-api-att'; export interface AttestationCasesComponentParameter { - subtitle?: string; - uidPickCategory: string; - uidobject: string; - filter: PolicyFilterElement[]; - concat: string; - canCreateRuns: boolean; - uidpolicy?: string; + subtitle?: string; + uidPickCategory: string; + uidobject: string; + filter: PolicyFilterElement[]; + concat: string; + canCreateRuns: boolean; + uidpolicy?: string; } diff --git a/imxweb/projects/att/src/lib/policies/attestation-cases/attestation-cases-tree-database.service.ts b/imxweb/projects/att/src/lib/policies/attestation-cases/attestation-cases-tree-database.service.ts deleted file mode 100644 index 2948f3332..000000000 --- a/imxweb/projects/att/src/lib/policies/attestation-cases/attestation-cases-tree-database.service.ts +++ /dev/null @@ -1,122 +0,0 @@ -/* - * ONE IDENTITY LLC. PROPRIETARY INFORMATION - * - * This software is confidential. One Identity, LLC. or one of its affiliates or - * subsidiaries, has supplied this software to you under terms of a - * license agreement, nondisclosure agreement or both. - * - * You may not copy, disclose, or use this software except in accordance with - * those terms. - * - * - * Copyright 2023 One Identity LLC. - * ALL RIGHTS RESERVED. - * - * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR - * WARRANTIES ABOUT THE SUITABILITY OF THE SOFTWARE, - * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED - * TO THE IMPLIED WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE, OR - * NON-INFRINGEMENT. ONE IDENTITY LLC. SHALL NOT BE - * LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE - * AS A RESULT OF USING, MODIFYING OR DISTRIBUTING - * THIS SOFTWARE OR ITS DERIVATIVES. - * - */ - -import { CollectionLoadParameters, EntityData, EntitySchema, HierarchyData, IEntity, TypedEntityBuilder, ValType } from 'imx-qbm-dbts'; -import { BusyService, SettingsService, TreeDatabase, TreeNodeResultParameter } from 'qbm'; -import { PolicyService } from '../policy.service'; -import { AttestationCasesComponentParameter } from './attestation-cases-component-parameter.interface'; -import { PortalAttestationFilterMatchingobjects } from 'imx-api-att'; - -export class AttestationCasesTreeDatabaseService extends TreeDatabase { - private entitySchema: EntitySchema; - private builder: TypedEntityBuilder; - - constructor( - private readonly policyService: PolicyService, - private readonly settingsService: SettingsService, - private readonly data: AttestationCasesComponentParameter, - public busyService: BusyService, - ) { - super(); - this.canSearch = false; - this.builder = new TypedEntityBuilder(PortalAttestationFilterMatchingobjects); - } - - public async getData( - showLoading: boolean, - parameter: CollectionLoadParameters = { ParentKey: '' /* first level */ } - ): Promise { - if (this.data == null) { - return { entities: [], canLoadMore: false, totalCount: 0 }; - } - - const isBusy = showLoading ? this.busyService.beginBusy() : undefined; - - try { - const navigationState = { - ...parameter, - ...{ - PageSize: parameter.PageSize ?? this.settingsService.DefaultPageSize, - StartIndex: parameter.StartIndex ?? 0, - }, - }; - - const data = await this.policyService.getObjectsForFilterUntyped( - this.data.uidobject, - this.data.uidPickCategory, - { Elements: this.data.filter, ConcatenationType: this.data.concat }, - navigationState - ); - - if (data) { - const nodeEntities = await Promise.all( - data.Entities.map(async (elem): Promise => { - return (await this.buildEntityWithHasChildren(elem, data.Hierarchy))?.GetEntity(); - }) - ); - this.dataChanged.emit(nodeEntities.filter((elem) => elem != null)); - return { - entities: nodeEntities.filter((elem) => elem != null), - canLoadMore: navigationState.StartIndex + navigationState.PageSize < data.TotalCount, - totalCount: data.TotalCount, - }; - } - return { entities: [], canLoadMore: false, totalCount: 0 }; - } finally { - isBusy?.endBusy(); - } - } - - public async prepare(entitySchema: EntitySchema, withReload: boolean): Promise { - this.entitySchema = entitySchema; - if (withReload) { - this.reloadData(); - } - } - - /** adds a hasChildren column to the entity */ - private async buildEntityWithHasChildren(entityData: EntityData, data: HierarchyData): Promise { - if (!this.entitySchema) { - return undefined; - } - const entity = this.builder.buildReadWriteEntity({ entitySchema: this.entitySchema, entityData }); - entity.GetEntity().AddColumns([ - { - Type: ValType.Bool, - IsMultiValued: true, - ColumnName: 'HasChildren', - MinLen: 0, - Display: '', - }, - ]); - await entity - .GetEntity() - .GetColumn('HasChildren') - .PutValue(data ? data.EntitiesWithHierarchy.some((elem) => entityData.Keys.some((key) => key === elem)) : false); - - return entity; - } -} diff --git a/imxweb/projects/att/src/lib/policies/attestation-cases/attestation-cases.component.html b/imxweb/projects/att/src/lib/policies/attestation-cases/attestation-cases.component.html index 818858588..21a92379a 100644 --- a/imxweb/projects/att/src/lib/policies/attestation-cases/attestation-cases.component.html +++ b/imxweb/projects/att/src/lib/policies/attestation-cases/attestation-cases.component.html @@ -1,23 +1,43 @@ -
    +
    - +
    {{ '#LDS#Here you can select the objects to be attested.' | translate }}
    -
    {{ '#LDS#Note: After you have started an attestation, it may take some time until the associated attestation cases are created.' | translate }}
    +
    + {{ + '#LDS#Note: After you have started an attestation, it may take some time until the associated attestation cases are created.' + | translate + }} +
    - -
    {{ '#LDS#This policy affects many objects. Running this policy may take some time and generate notifications to many approvers.' | translate }}
    + +
    + {{ + '#LDS#This policy affects many objects. Running this policy may take some time and generate notifications to many approvers.' + | translate + }} +
    -
    +
    -

    {{ '#LDS#A sample is assigned to this attestation policy. You can start the attestation only for all objects in the sample.' | translate }}

    -

    {{ '#LDS#Note: After you have started an attestation, it may take some time until the associated attestation cases are created.' | translate }}

    +

    + {{ + '#LDS#A sample is assigned to this attestation policy. You can start the attestation only for all objects in the sample.' + | translate + }} +

    +

    + {{ + '#LDS#Note: After you have started an attestation, it may take some time until the associated attestation cases are created.' + | translate + }} +

    - - - - - + + + + {{ entitySchemaPolicy?.Columns?.[DisplayColumns.DISPLAY_PROPERTYNAME]?.Display }} + + +
    {{ item.GetEntity().GetDisplay() }}
    +
    + {{ item.GetEntity().GetDisplayLong() }} +
    + +
    + + {{ entitySchemaPolicy?.Columns?.DisplayName?.Display }} + + + + +
    +
    @@ -65,7 +84,7 @@ {{ '#LDS#Start attestation for all' | translate }}
    - - - - - diff --git a/imxweb/projects/att/src/lib/policies/attestation-cases/attestation-cases.component.scss b/imxweb/projects/att/src/lib/policies/attestation-cases/attestation-cases.component.scss index e49457660..651b5fcde 100644 --- a/imxweb/projects/att/src/lib/policies/attestation-cases/attestation-cases.component.scss +++ b/imxweb/projects/att/src/lib/policies/attestation-cases/attestation-cases.component.scss @@ -1,10 +1,9 @@ -@import "@elemental-ui/core/src/styles/_eui_palette.scss"; +@import '@elemental-ui/core/src/styles/_eui_palette.scss'; +@import 'base/mixins'; :host { + @include flex-column-container($height: 100%); overflow-y: auto; - display: flex; - flex-direction: column; - height: 100%; background-color: $color-gray-2; imx-data-table { @@ -12,141 +11,43 @@ } } -.eui-sidesheet-content { - display: flex; - flex-direction: column; - flex: 1 1 auto; -} - h2 { margin-bottom: 10px; } -.imx-sidesheet-content { - flex: 1 1 auto; - overflow: auto; -} - .imx-cases-card { - display: flex; - flex-direction: column; + @include flex-column-container(); margin: 0px; overflow-y: auto; flex: 1 1 auto; } -:host ::ng-deep imx-data-table .mat-row .mat-cell { - padding: 0 10px; - max-width: 100px; - div[imxTitle] { - overflow: hidden; - text-overflow: ellipsis; - white-space: nowrap; - } -} - -.imx-dialog-actions { - display: flex; - justify-content: flex-end; - margin-bottom: 0; - padding: 16px 32px; - border-top: 1px solid rgba(0, 0, 0, 0.12); - background-color: $color-gray-0; - - button { - margin-left: 10px; - } - - .justify-start { - margin-right: auto; - } -} .eui-sidesheet-actions { padding: 16px; - .justify-start { - margin-right: auto; - } - - button:not(:last-of-type):not(.justify-start) { - margin-right: 10px; - } } imx-data-table { flex-grow: 2; } -:host ::ng-deep imx-data-table .mat-header-row .mat-header-cell { - font-weight: 600; - font-size: 14px; - padding: 0 10px; -} - -:host ::ng-deep imx-data-table .mat-row .mat-cell { - padding: 0 10px; - max-width: 100px; - div[imxTitle] { - overflow: hidden; - text-overflow: ellipsis; - white-space: nowrap; - .button-row { - border-top-style: solid; - border-top-width: 0px; - display: flex; - flex-direction: row; - justify-content: flex-end; - } - div[subtitle] { - font-size: smaller; - color: $color-gray-40; - overflow: hidden; - text-overflow: ellipsis; - white-space: nowrap; - } - } -} - -.mat-card-title { - font-size: large; -} - .eui-sidesheet-actions { - .mat-stroked-button { + .mat-mdc-outlined-button { align-self: flex-start; } } -.mat-toolbar { - background-color: inherit; -} - .imx-mat-card-header-line { display: grid; grid-template-columns: 1fr 3fr; padding: 30px 30px 0 30px; } -.mat-toolbar > button { - margin-left: 5px; -} - -.mat-toolbar { - color: $color-gray-100; -} - .imx-toolbar-spacer { flex: 1 1 auto; } .heading-wrapper { - display: flex; - flex-direction: column; - - .helper-alert { - margin: 0px 0px 30px 0px; - align-self: flex-end; - width: 100%; - } + @include flex-column-container(); .imx-helper-title { font-size: larger; @@ -155,18 +56,12 @@ imx-data-table { } .imx-sample-data-info { + @include flex-column-container(); text-align: center; margin: 20px 0; flex: 1 1 auto; - display: flex; - flex-direction: column; justify-content: center; - .eui-icon { - font-size: 100px; - color: $color-gray-10; - } - p { margin: 0; font-size: 18px; @@ -183,23 +78,21 @@ imx-data-table { } } +.hidden { + display: none !important; + height: 0px; +} + +.imx-attestation-tree-container { + @include flex-column-container(); + flex: 1 1 auto; +} + .eui-dark-theme { :host { background-color: $color-gray-80; - .imx-dialog-actions { - background-color: $color-gray-70; - } - - .mat-toolbar { - color: $color-gray-10; - } - .imx-sample-data-info { - .eui-icon { - color: $color-gray-20; - } - p { color: $color-gray-10; } @@ -210,13 +103,5 @@ imx-data-table { .eui-contrast-theme { :host { background-color: $color-gray-100; - - .imx-dialog-actions { - background-color: $color-gray-90; - } - - .mat-toolbar { - color: $color-gray-0; - } } } diff --git a/imxweb/projects/att/src/lib/policies/attestation-cases/attestation-cases.component.ts b/imxweb/projects/att/src/lib/policies/attestation-cases/attestation-cases.component.ts index f4f617698..1e5e9983a 100644 --- a/imxweb/projects/att/src/lib/policies/attestation-cases/attestation-cases.component.ts +++ b/imxweb/projects/att/src/lib/policies/attestation-cases/attestation-cases.component.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -24,47 +24,42 @@ * */ -import { OverlayRef } from '@angular/cdk/overlay'; import { Component, Inject, OnInit } from '@angular/core'; import { EUI_SIDESHEET_DATA, EuiLoadingService, EuiSidesheetRef } from '@elemental-ui/core'; import { TranslateService } from '@ngx-translate/core'; -import { PortalAttestationFilterMatchingobjects } from 'imx-api-att'; -import { CollectionLoadParameters, DisplayColumns, EntitySchema, ValType } from 'imx-qbm-dbts'; +import { PortalAttestationFilterMatchingobjects } from '@imx-modules/imx-api-att'; +import { CollectionLoadParameters, DisplayColumns, EntitySchema, TypedEntityCollectionData, ValType } from '@imx-modules/imx-qbm-dbts'; import { - BusyService, ClassloggerService, ClientPropertyForTableColumns, ConfirmationService, - DataSourceToolbarSettings, + DataViewInitParameters, + DataViewSource, LdsReplacePipe, - SettingsService, SnackBarService, } from 'qbm'; import { PolicyService } from '../policy.service'; import { AttestationCasesComponentParameter } from './attestation-cases-component-parameter.interface'; -import { AttestationCasesTreeDatabaseService } from './attestation-cases-tree-database.service'; @Component({ templateUrl: './attestation-cases.component.html', styleUrls: ['./attestation-cases.component.scss'], + providers: [DataViewSource], }) export class AttestationCasesComponent implements OnInit { - public dstSettings: DataSourceToolbarSettings; public readonly entitySchemaPolicy: EntitySchema; public DisplayColumns = DisplayColumns; public isAdmin: boolean; public deactivatedChecked = false; - public selectedItems: PortalAttestationFilterMatchingobjects[] = []; - public treeDatabase: AttestationCasesTreeDatabaseService; + public selectedItems: (PortalAttestationFilterMatchingobjects | undefined)[] = []; public entitySchema = PortalAttestationFilterMatchingobjects.GetEntitySchema(); - private navigationState: CollectionLoadParameters; private displayedColumns: ClientPropertyForTableColumns[]; private threshold = -1; public hierarchical: boolean; - private busyService = new BusyService(); + public isLoading = false; constructor( public readonly sidesheetRef: EuiSidesheetRef, @@ -73,12 +68,11 @@ export class AttestationCasesComponent implements OnInit { private readonly busyServiceEui: EuiLoadingService, private readonly snackbar: SnackBarService, private readonly confirmationService: ConfirmationService, - private readonly settingsService: SettingsService, private readonly translate: TranslateService, private readonly ldsReplace: LdsReplacePipe, - private readonly logger: ClassloggerService + private readonly logger: ClassloggerService, + public dataSource: DataViewSource, ) { - this.navigationState = { PageSize: settingsService.DefaultPageSize, StartIndex: 0, ParentKey: '' }; this.entitySchemaPolicy = policyService.AttestationMatchingObjectsSchema; this.displayedColumns = [this.entitySchemaPolicy.Columns[DisplayColumns.DISPLAY_PROPERTYNAME]]; @@ -92,124 +86,95 @@ export class AttestationCasesComponent implements OnInit { } public get showWarning() { - return this.threshold > 0 && this.threshold < (this.dstSettings?.dataSource?.totalCount ?? 0); + return this.threshold > 0 && this.threshold < (this.dataSource.collectionData().totalCount ?? 0); } public async ngOnInit(): Promise { - let overlayRef: OverlayRef; - setTimeout(() => (overlayRef = this.busyServiceEui.show())); + this.showBusyIndicator(); try { this.threshold = await this.policyService.getCasesThreshold(); - this.hierarchical = - ( - await this.policyService.getObjectsForFilterUntyped( - this.data.uidobject, - this.data.uidPickCategory, - { Elements: this.data.filter, ConcatenationType: this.data.concat }, - { PageSize: -1 } - ) - ).Hierarchy != null; - - this.treeDatabase = new AttestationCasesTreeDatabaseService(this.policyService, this.settingsService, this.data, this.busyService); - await this.treeDatabase.prepare(this.entitySchema, false); } finally { - setTimeout(async () => { - this.busyServiceEui.hide(overlayRef); - }); + this.busyServiceEui.hide(); } - return this.hierarchical ? this.navigateTree() : this.navigate(); + return this.navigate(); } public get hasSampleData(): boolean { return this.data.uidPickCategory != null && this.data.uidPickCategory !== ''; } - public async onNavigationStateChanged(newState: CollectionLoadParameters): Promise { - this.navigationState = newState; - await this.navigate(); - } - public onSelectionChanged(items: PortalAttestationFilterMatchingobjects[]): void { this.selectedItems = items; } - public async createRun(data: PortalAttestationFilterMatchingobjects[]): Promise { - const count = data.length > 0 ? data.length : this.dstSettings?.dataSource.totalCount; + public async createRun(data: (PortalAttestationFilterMatchingobjects | undefined)[]): Promise { + const count = data.length > 0 ? data.length : this.dataSource.collectionData().totalCount || 0; if (count <= this.threshold || (await this.confirmCreation())) { - let overlayRef: OverlayRef; - setTimeout(() => (overlayRef = this.busyServiceEui.show())); + this.showBusyIndicator(); try { await this.policyService.createAttestationRun( - this.data.uidpolicy, - data.map((elem) => elem.Key.value) + this.data.uidpolicy || '', + data.map((elem) => elem?.Key.value ?? ''), ); this.logger.trace( this, 'attestation run created for', this.data.uidpolicy, - data.map((elem) => elem.Key.value) + data.map((elem) => elem?.Key.value ?? ''), ); this.snackbar.open( { key: '#LDS#The attestation has been started successfully. It may take some time until the associated attestation cases are created.', }, - '#LDS#Close' + '#LDS#Close', ); } finally { - setTimeout(async () => { - this.busyServiceEui.hide(overlayRef); - this.sidesheetRef.close(true); - }); + this.busyServiceEui.hide(); + this.sidesheetRef.close(true); } } } - private async navigateTree(): Promise { - await this.treeDatabase.prepare(this.entitySchema, true); - } - private async navigate(): Promise { - let overlayRef: OverlayRef; - setTimeout(() => (overlayRef = this.busyServiceEui.show())); - - try { - const dataSource = await this.policyService.getObjectsForFilter( - this.data.uidobject, - this.data.uidPickCategory, - { Elements: this.data.filter, ConcatenationType: this.data.concat }, - this.navigationState - ); - - this.dstSettings = { - displayedColumns: this.displayedColumns, - dataSource, - entitySchema: this.entitySchemaPolicy, - navigationState: this.navigationState, - }; - - this.logger.debug(this, 'matching objects table navigated to', this.navigationState); - } finally { - setTimeout(() => this.busyServiceEui.hide(overlayRef)); - } + const dataViewInitParameters: DataViewInitParameters = { + execute: (params: CollectionLoadParameters): Promise> => + this.policyService.getObjectsForFilter( + this.data.uidobject, + this.data.uidPickCategory, + { Elements: this.data.filter, ConcatenationType: this.data.concat }, + params, + ), + schema: this.entitySchemaPolicy, + columnsToDisplay: this.displayedColumns, + selectionChange: (selection: PortalAttestationFilterMatchingobjects[]) => this.onSelectionChanged(selection), + localSource: true, + }; + this.dataSource.init(dataViewInitParameters); } private async confirmCreation(): Promise { const message = this.ldsReplace.transform( await this.translate .get( - '#LDS#You have selected more than {0} objects. Attestation of the selected objects may take some time and generate notifications to many approvers. Are you sure you want to start the attestation for the selected objects?' + '#LDS#You have selected more than {0} objects. Attestation of the selected objects may take some time and generate notifications to many approvers. Are you sure you want to start the attestation for the selected objects?', ) .toPromise(), - this.threshold + this.threshold, ); return this.confirmationService.confirm({ Title: await this.translate.get('#LDS#Heading Many Objects Affected').toPromise(), Message: message, }); } + + private showBusyIndicator(): void { + if (this.busyServiceEui.overlayRefs.length === 0) { + this.busyServiceEui.show(); + } + } } diff --git a/imxweb/projects/att/src/lib/policies/confirm-deactivation/confirm-deactivation.component.html b/imxweb/projects/att/src/lib/policies/confirm-deactivation/confirm-deactivation.component.html index 2fb3804b1..b4d94e981 100644 --- a/imxweb/projects/att/src/lib/policies/confirm-deactivation/confirm-deactivation.component.html +++ b/imxweb/projects/att/src/lib/policies/confirm-deactivation/confirm-deactivation.component.html @@ -1,13 +1,13 @@ -

    {{'#LDS#Heading Deactivate Attestation Policy' | translate}}

    - -

    {{'#LDS#Do you want to deactivate this attestation policy?' | translate}}

    -

    {{'#LDS#This will cause automatic cancelation of pending attestation cases when saving your changes.' | translate}} -

    -
    - - - - \ No newline at end of file +

    {{ '#LDS#Heading Deactivate Attestation Policy' | translate }}

    + +

    {{ '#LDS#Do you want to deactivate this attestation policy?' | translate }}

    +

    {{ '#LDS#This will cause automatic cancelation of pending attestation cases when saving your changes.' | translate }}

    +
    + + + + diff --git a/imxweb/projects/att/src/lib/policies/confirm-deactivation/confirm-deactivation.component.scss b/imxweb/projects/att/src/lib/policies/confirm-deactivation/confirm-deactivation.component.scss index 766288fdb..1e489f874 100644 --- a/imxweb/projects/att/src/lib/policies/confirm-deactivation/confirm-deactivation.component.scss +++ b/imxweb/projects/att/src/lib/policies/confirm-deactivation/confirm-deactivation.component.scss @@ -1,9 +1,8 @@ - .imx-confirm-content { - overflow: auto; - white-space: pre-line; - word-wrap: break-word; - max-height: 400px; - max-width: 600px; - margin-bottom: 40px; - } + overflow: auto; + white-space: pre-line; + word-wrap: break-word; + max-height: 400px; + max-width: 600px; + margin-bottom: 40px; +} diff --git a/imxweb/projects/att/src/lib/policies/confirm-deactivation/confirm-deactivation.component.ts b/imxweb/projects/att/src/lib/policies/confirm-deactivation/confirm-deactivation.component.ts index 029f44f65..0fc742e2a 100644 --- a/imxweb/projects/att/src/lib/policies/confirm-deactivation/confirm-deactivation.component.ts +++ b/imxweb/projects/att/src/lib/policies/confirm-deactivation/confirm-deactivation.component.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -29,7 +29,6 @@ import { Component } from '@angular/core'; @Component({ selector: 'imx-confirm-deactivation', templateUrl: './confirm-deactivation.component.html', - styleUrls: ['./confirm-deactivation.component.scss'] + styleUrls: ['./confirm-deactivation.component.scss'], }) - export class ConfirmDeactivationComponent {} diff --git a/imxweb/projects/att/src/lib/policies/edit-master-data/edit-master-data.component.html b/imxweb/projects/att/src/lib/policies/edit-master-data/edit-master-data.component.html index 4d90e7b35..e613912bd 100644 --- a/imxweb/projects/att/src/lib/policies/edit-master-data/edit-master-data.component.html +++ b/imxweb/projects/att/src/lib/policies/edit-master-data/edit-master-data.component.html @@ -1,78 +1,129 @@ -
    - +
    + -
    +
    -

    - {{'#LDS#Heading Attestation Policy Settings' | translate}} - -

    - - - #LDS#The sample assigned to the original attestation policy has been removed for the copy. Samples can be assigned to only one attestation policy at a time. - #LDS#However, you can assign a different sample to this attestation policy. - - - - +

    + {{ '#LDS#Heading Attestation Policy Settings' | translate }} + +

    + + + {{ LdsKeySampleRemoved }} + #LDS#However, you can assign a different sample to this attestation policy. + + + + - + - + + + + - + + + - - - + + - + - - + - + - + + + + + -
    - +
    @@ -86,10 +137,16 @@

    [disabled]="!policy.policy?.IsOob?.value || hasAttestations" (click)="delete()" > - + {{ '#LDS#Delete' | translate }} -

    @@ -97,7 +154,7 @@

    -
    +
    diff --git a/imxweb/projects/att/src/lib/policies/edit-master-data/edit-master-data.component.scss b/imxweb/projects/att/src/lib/policies/edit-master-data/edit-master-data.component.scss index ed572bc3a..94f7ed2be 100644 --- a/imxweb/projects/att/src/lib/policies/edit-master-data/edit-master-data.component.scss +++ b/imxweb/projects/att/src/lib/policies/edit-master-data/edit-master-data.component.scss @@ -4,25 +4,6 @@ overflow: hidden; height: 100%; - .tab-group-wrapper { - display: flex; - overflow: auto; - flex: 1; - - .mat-tab-group { - width: 100%; - } - - ::ng-deep .mat-tab-body-content { - display: flex; - flex-direction: column; - } - - ::ng-deep .mat-tab-body-wrapper { - flex: 1; - } - } - .imx-policy-edit-form { display: flex; flex-direction: column; @@ -31,24 +12,20 @@ overflow-x: hidden; } - h2 { + h3 { font-size: x-large; font-weight: 600; margin-bottom: 10px; } - ::ng-deep textarea.mat-input-element { - max-height: 300px; - } - .imx-master-data-cdrs { display: flex; flex-direction: column; margin: 2px 10px 2px 2px; overflow-x: hidden; overflow-y: auto; - h2{ - display:flex; + h3 { + display: flex; align-items: center; } } @@ -59,33 +36,6 @@ overflow: hidden; } - .imx-checkbox-property-list { - display: flex; - flex-direction: column; - } - - .eui-sidesheet-content { - display: flex; - padding-bottom: 10px; - } - - .eui-sidesheet-actions { - padding: 16px; - margin: 10px 0 0 0; - .justify-start { - margin-right: auto; - - eui-icon { - font-size: 14px; - margin-right: 4px; - } - } - - button:not(:last-of-type):not(.justify-start) { - margin-right: 10px; - } - } - .imx-confirm-content { overflow: auto; white-space: pre-line; @@ -93,18 +43,6 @@ max-height: 400px; max-width: 600px; } - - .imx-helper-alert { - width: 100%; - - ::ng-deep .eui-alert { - margin-bottom: 20px; - } - - span { - display: block; - } - } } @media only screen and (max-width: 1024px) { @@ -120,7 +58,7 @@ grid-column-end: 3; } - imx-policy-editor{ + imx-policy-editor { margin-right: 5px; margin-top: 20px; } diff --git a/imxweb/projects/att/src/lib/policies/edit-master-data/edit-master-data.component.ts b/imxweb/projects/att/src/lib/policies/edit-master-data/edit-master-data.component.ts index 2da7efa3e..049693336 100644 --- a/imxweb/projects/att/src/lib/policies/edit-master-data/edit-master-data.component.ts +++ b/imxweb/projects/att/src/lib/policies/edit-master-data/edit-master-data.component.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -25,23 +25,32 @@ */ import { Component, Inject, OnDestroy, OnInit, ViewChild } from '@angular/core'; +import { AbstractControl, UntypedFormArray, UntypedFormGroup } from '@angular/forms'; import { MatDialog } from '@angular/material/dialog'; -import { UntypedFormGroup, UntypedFormArray, UntypedFormControl } from '@angular/forms'; -import { EuiLoadingService, EuiSidesheetRef, EUI_SIDESHEET_DATA } from '@elemental-ui/core'; -import { OverlayRef } from '@angular/cdk/overlay'; +import { EUI_SIDESHEET_DATA, EuiLoadingService, EuiSidesheetRef } from '@elemental-ui/core'; import { BehaviorSubject, Subscription } from 'rxjs'; -import { ColumnDependentReference, BaseCdr, SnackBarService, ClassloggerService, LdsReplacePipe } from 'qbm'; +import { PolicyFilter } from '@imx-modules/imx-api-att'; +import { EntitySchema } from '@imx-modules/imx-qbm-dbts'; +import { TranslateService } from '@ngx-translate/core'; +import { + BaseCdr, + BusyService, + ClassloggerService, + ColumnDependentReference, + ConfirmationService, + HELP_CONTEXTUAL, + HelpContextualValues, + LdsReplacePipe, + SnackBarService, +} from 'qbm'; import { UserModelService } from 'qer'; +import { ConfirmDeactivationComponent } from '../confirm-deactivation/confirm-deactivation.component'; +import { FilterElementColumnService } from '../editors/filter-element-column.service'; import { FilterModel } from '../policy-editor/filter-model'; +import { PolicyEditorComponent } from '../policy-editor/policy-editor.component'; import { Policy } from '../policy.interface'; import { PolicyService } from '../policy.service'; -import { FilterElementColumnService } from '../editors/filter-element-column.service'; -import { ConfirmDeactivationComponent } from '../confirm-deactivation/confirm-deactivation.component'; -import { ConfirmationService, HELP_CONTEXTUAL, HelpContextualValues } from 'qbm'; -import { EntitySchema } from 'imx-qbm-dbts'; -import { TranslateService } from '@ngx-translate/core'; -import { PolicyEditorComponent } from '../policy-editor/policy-editor.component'; @Component({ templateUrl: './edit-master-data.component.html', @@ -50,16 +59,16 @@ import { PolicyEditorComponent } from '../policy-editor/policy-editor.component' export class EditMasterDataComponent implements OnInit, OnDestroy { public readonly formGroup: UntypedFormGroup; public readonly schema: EntitySchema; - public objectProperties: { [key: string]: { cdr: ColumnDependentReference; formControl?: UntypedFormControl } } = {}; + public objectProperties: { [key: string]: { cdr: ColumnDependentReference; formControl?: AbstractControl } } = {}; public readonly formArray: UntypedFormArray; public reload = false; public filterModel: FilterModel; public hasAttestations: boolean; public contextId: HelpContextualValues; + public busyService: BusyService = new BusyService(); @ViewChild('filterControl', { static: true }) policyEditor: PolicyEditorComponent; - private isPoliyEditorEnabled = true; private valueChangedSubscription: Subscription; private closeSubscription: Subscription; private threshold = -1; @@ -67,7 +76,7 @@ export class EditMasterDataComponent implements OnInit, OnDestroy { constructor( @Inject(EUI_SIDESHEET_DATA) public readonly policy: Policy, public readonly sidesheetRef: EuiSidesheetRef, - private readonly busyService: EuiLoadingService, + private readonly euiBusyService: EuiLoadingService, private readonly snackBar: SnackBarService, private readonly dialog: MatDialog, private readonly policyService: PolicyService, @@ -76,7 +85,7 @@ export class EditMasterDataComponent implements OnInit, OnDestroy { private readonly userService: UserModelService, private readonly confirmationService: ConfirmationService, private readonly translate: TranslateService, - private readonly ldsReplace: LdsReplacePipe + private readonly ldsReplace: LdsReplacePipe, ) { this.schema = policyService.AttestationPolicyEditSchema; this.initOrRefreshCdrDictionary(); @@ -91,7 +100,7 @@ export class EditMasterDataComponent implements OnInit, OnDestroy { } }); - this.filterModel = new FilterModel(this.columnService, new BehaviorSubject(true), new BehaviorSubject(undefined)); + this.filterModel = new FilterModel(this.columnService, new BehaviorSubject('')); this.filterModel.uidAttestationObject = this.policy.policy.UID_AttestationObject.value; this.filterModel.policyFilterData = this.policy.filterData; } @@ -105,6 +114,15 @@ export class EditMasterDataComponent implements OnInit, OnDestroy { } } + public async onFilterChanged(filter: PolicyFilter) { + const isBusy = this.busyService.beginBusy(); + try { + await this.policy.policy.setExtendedData([filter]); + } finally { + isBusy.endBusy(); + } + } + public get objectType(): string { return this.policy.policy.GetEntity().TypeName; } @@ -114,39 +132,38 @@ export class EditMasterDataComponent implements OnInit, OnDestroy { } public async ngOnInit(): Promise { - let overlayRef: OverlayRef; - setTimeout(() => (overlayRef = this.busyService.show())); + if (this.euiBusyService.overlayRefs.length === 0) { + this.euiBusyService.show(); + } try { this.hasAttestations = (await this.policyService.getRunCountForPolicy(this.policy.policy.GetEntity().GetKeys()[0])) > 0; this.threshold = await this.policyService.getCasesThreshold(); } finally { - setTimeout(() => this.busyService.hide(overlayRef)); + this.euiBusyService.hide(); } if (this.policy.isNew) { this.formGroup.markAsDirty(); } - this.logger.trace('call isEnabledSubject with', this.policy.policy.UID_QERPickCategory.value == null); - this.filterModel.isEnabledSubject.next( - this.policy.policy.UID_QERPickCategory.value == null || this.policy.policy.UID_QERPickCategory.value === '' - ); - this.contextId = this.policy.isNew ? HELP_CONTEXTUAL.AttestationPoliciesCreate : HELP_CONTEXTUAL.AttestationPoliciesEdit + this.contextId = this.policy.isNew ? HELP_CONTEXTUAL.AttestationPoliciesCreate : HELP_CONTEXTUAL.AttestationPoliciesEdit; } - public addControl(evt: UntypedFormControl, columnName: string): void { + public addControl(evt: AbstractControl, columnName?: string): void { setTimeout(() => { - this.formGroup.removeControl(columnName); - this.objectProperties[columnName].formControl = evt; - this.formGroup.addControl(columnName, evt); - this.logger.debug(this, 'new Control added to form group'); - - if (columnName === 'IsInActive') { - if (this.valueChangedSubscription) { - this.valueChangedSubscription.unsubscribe(); + if (columnName) { + this.formGroup.removeControl(columnName); + this.objectProperties[columnName].formControl = evt; + this.formGroup.addControl(columnName, evt); + this.logger.debug(this, 'new Control added to form group'); + + if (columnName === 'IsInActive') { + if (this.valueChangedSubscription) { + this.valueChangedSubscription.unsubscribe(); + } + this.valueChangedSubscription = evt.valueChanges.subscribe((value) => { + this.confirmDeactivation(value); + }); } - this.valueChangedSubscription = evt.valueChanges.subscribe((value) => { - this.confirmDeactivation(value); - }); } }); } @@ -167,67 +184,28 @@ export class EditMasterDataComponent implements OnInit, OnDestroy { this.logger.debug(this, 'Attestator cdr updated'); } - public async updateReadOnlySchedule(){ + public async updateReadOnlySchedule() { this.objectProperties.UID_DialogSchedule.cdr = new BaseCdr(this.policy.policy.UID_DialogSchedule.Column); this.logger.debug(this, 'UID_DialogSchedule cdr updated'); } - public async updatePickCategory(): Promise { - const showConfirmation = - this.isPoliyEditorEnabled && - this.filterModel.policyFilterData?.Filter.Elements.length && - this.policy.policy.UID_QERPickCategory.value?.length > 0; - - this.logger.debug(this, 'Checked for existing filters if sample data was changed from null to value', showConfirmation); - - if (showConfirmation) { - const confirmed = await this.confirmationService.confirm({ - Title: '#LDS#Heading Use Sample Data', - Message: '#LDS#Do you want to use the selected sample data instead of the specified conditions?', - }); - if (confirmed) { - this.policy.filterData = { - IsReadOnly: this.policy.filterData.IsReadOnly, - Filter: { Elements: [] }, - InfoDisplay: [], - }; - this.logger.debug(this, 'filter removed due to sample data seleted'); - } else { - let overlayRef: OverlayRef; - setTimeout(() => (overlayRef = this.busyService.show())); - try { - await this.policy.policy.UID_QERPickCategory.Column.PutValue(undefined); - } finally { - setTimeout(() => this.busyService.hide(overlayRef)); - } - this.objectProperties.UID_QERPickCategory.cdr = new BaseCdr(this.policy.policy.UID_QERPickCategory.Column); - this.logger.debug(this, 'Sample data is removed'); - } - } - - this.isPoliyEditorEnabled = this.policy.policy.UID_QERPickCategory.value == null || this.policy.policy.UID_QERPickCategory.value === ''; - this.filterModel.isEnabledSubject.next(this.isPoliyEditorEnabled); - this.logger.debug(this, 'Visibility of the policy editor:', this.isPoliyEditorEnabled ? 'visible' : 'hidden'); - } - public async submit(): Promise { if (!(await this.confirmCreation())) { return; } - let overlayRef: OverlayRef; - setTimeout(() => (overlayRef = this.busyService.show())); + if (this.euiBusyService.overlayRefs.length === 0) { + this.euiBusyService.show(); + } try { - const filter = this.filterModel.policyFilterData.Filter; + const filter = this.filterModel.policyFilterData?.Filter; - this.policy.policy.extendedData = [ - this.policy.policy.UID_QERPickCategory.value == null || this.policy.policy.UID_QERPickCategory.value === '' ? filter : null, - ]; + this.policy.policy.extendedData = !!filter ? [filter] : []; await this.policy.policy.GetEntity().Commit(false); this.logger.debug(this, 'data submitted'); this.sidesheetRef.close(true); } finally { - setTimeout(() => this.busyService.hide(overlayRef)); + this.euiBusyService.hide(); } this.snackBar.open( @@ -235,7 +213,7 @@ export class EditMasterDataComponent implements OnInit, OnDestroy { key: '#LDS#The attestation policy "{0}" has been successfully saved.', parameters: [this.policy.policy.GetEntity().GetDisplay()], }, - '#LDS#Close' + '#LDS#Close', ); this.reload = true; } @@ -255,7 +233,7 @@ export class EditMasterDataComponent implements OnInit, OnDestroy { key: '#LDS#The attestation policy "{0}" has been successfully deleted.', parameters: [this.policy.policy.GetEntity().GetDisplay()], }, - '#LDS#Close' + '#LDS#Close', ); this.sidesheetRef.close(true); } @@ -268,10 +246,10 @@ export class EditMasterDataComponent implements OnInit, OnDestroy { const message = this.ldsReplace.transform( await this.translate .get( - '#LDS#This attestation policy affects more than {0} objects. Running this attestation policy may take some time and generate notifications to many approvers. Are you sure you want to save the attestation policy?' + '#LDS#This attestation policy affects more than {0} objects. Running this attestation policy may take some time and generate notifications to many approvers. Are you sure you want to save the attestation policy?', ) .toPromise(), - this.threshold + this.threshold, ); return this.confirmationService.confirm({ Title: '#LDS#Heading Many Objects Affected', @@ -342,4 +320,7 @@ export class EditMasterDataComponent implements OnInit, OnDestroy { } } } + + public LdsKeySampleRemoved = + '#LDS#The sample assigned to the original attestation policy has been removed for the copy. Samples can be assigned to only one attestation policy at a time.'; } diff --git a/imxweb/projects/att/src/lib/policies/editors/edit-generic.component.html b/imxweb/projects/att/src/lib/policies/editors/edit-generic.component.html index 669564403..bcd347d73 100644 --- a/imxweb/projects/att/src/lib/policies/editors/edit-generic.component.html +++ b/imxweb/projects/att/src/lib/policies/editors/edit-generic.component.html @@ -1,2 +1 @@ - - \ No newline at end of file + diff --git a/imxweb/projects/att/src/lib/policies/editors/edit-generic.component.ts b/imxweb/projects/att/src/lib/policies/editors/edit-generic.component.ts index 8e32b99c8..e1254b1da 100644 --- a/imxweb/projects/att/src/lib/policies/editors/edit-generic.component.ts +++ b/imxweb/projects/att/src/lib/policies/editors/edit-generic.component.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -24,10 +24,10 @@ * */ -import { Component, Input, Output, EventEmitter, OnChanges } from '@angular/core'; +import { Component, EventEmitter, Input, OnChanges, Output } from '@angular/core'; -import { MultiValue, ValueStruct } from 'imx-qbm-dbts'; -import { ColumnDependentReference, BaseCdr, ClassloggerService, MetadataService } from 'qbm'; +import { MultiValue, ValueStruct } from '@imx-modules/imx-qbm-dbts'; +import { BaseCdr, ClassloggerService, ColumnDependentReference, MetadataService } from 'qbm'; import { FilterChangedArgument } from './filter-changed-argument.interface'; import { FilterElementModel } from './filter-element-model'; @@ -56,7 +56,7 @@ export class EditGenericComponent implements OnChanges { await this.metaData.updateNonExisting([this.filterElementModel.getTableName()]); this.cdr = new BaseCdr( this.filterElementModel.columnForFilter, - this.metaData.tables[this.filterElementModel.getTableName()].Columns[this.filterElementModel.getColumnName()].Display, + this.metaData.tables[this.filterElementModel.getTableName()]?.Columns?.[this.filterElementModel.getColumnName()].Display, ); } } diff --git a/imxweb/projects/att/src/lib/policies/editors/edit-name.component.html b/imxweb/projects/att/src/lib/policies/editors/edit-name.component.html index caaf5587c..41e60457d 100644 --- a/imxweb/projects/att/src/lib/policies/editors/edit-name.component.html +++ b/imxweb/projects/att/src/lib/policies/editors/edit-name.component.html @@ -1,2 +1 @@ - - \ No newline at end of file + diff --git a/imxweb/projects/att/src/lib/policies/editors/edit-name.component.ts b/imxweb/projects/att/src/lib/policies/editors/edit-name.component.ts index baf0ba0f8..cfeedc382 100644 --- a/imxweb/projects/att/src/lib/policies/editors/edit-name.component.ts +++ b/imxweb/projects/att/src/lib/policies/editors/edit-name.component.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -34,10 +34,9 @@ import { FilterElementModel } from './filter-element-model'; @Component({ templateUrl: './edit-name.component.html', - selector: 'imx-edit-name' + selector: 'imx-edit-name', }) export class EditNameComponent implements OnChanges, OnDestroy { - @Input() public filterElementModel: FilterElementModel; @Input() public identifier: string; @Input() public testId = ''; @@ -62,10 +61,10 @@ export class EditNameComponent implements OnChanges, OnDestroy { if (this.valueChangedSubscription) { this.valueChangedSubscription.unsubscribe(); } - this.valueChangedSubscription = control.valueChanges.subscribe(value => { + this.valueChangedSubscription = control.valueChanges.subscribe((value) => { this.valueChanged.emit({ ParameterValue: value, - displays: [value] + displays: [value], }); }); } diff --git a/imxweb/projects/att/src/lib/policies/editors/edit-origin.component.html b/imxweb/projects/att/src/lib/policies/editors/edit-origin.component.html index 8331c3b81..ebcc0afe7 100644 --- a/imxweb/projects/att/src/lib/policies/editors/edit-origin.component.html +++ b/imxweb/projects/att/src/lib/policies/editors/edit-origin.component.html @@ -1,9 +1,14 @@ - {{'#LDS#Origins' | translate}} - -
    - - {{candidate?.Display}} - -
    -
    \ No newline at end of file + {{ '#LDS#Origins' | translate }} + +
    + + + {{ candidate?.Display }} + +
    + diff --git a/imxweb/projects/att/src/lib/policies/editors/edit-origin.component.scss b/imxweb/projects/att/src/lib/policies/editors/edit-origin.component.scss index bed561c13..f5c5b5477 100644 --- a/imxweb/projects/att/src/lib/policies/editors/edit-origin.component.scss +++ b/imxweb/projects/att/src/lib/policies/editors/edit-origin.component.scss @@ -1,4 +1,4 @@ .imx-multi-value-container { - display: flex; - flex-flow: column; - } \ No newline at end of file + display: flex; + flex-flow: column; +} diff --git a/imxweb/projects/att/src/lib/policies/editors/edit-origin.component.spec.ts b/imxweb/projects/att/src/lib/policies/editors/edit-origin.component.spec.ts index 15aaa9ad3..853898e1b 100644 --- a/imxweb/projects/att/src/lib/policies/editors/edit-origin.component.spec.ts +++ b/imxweb/projects/att/src/lib/policies/editors/edit-origin.component.spec.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -24,7 +24,7 @@ * */ -import { ParmOpt } from 'imx-api-att'; +import { ParmOpt } from '@imx-modules/imx-api-att'; import { ClassloggerService, clearStylesFromDOM } from 'qbm'; import { EditOriginComponent } from './edit-origin.component'; import { FilterElementColumnService } from './filter-element-column.service'; @@ -32,77 +32,76 @@ import { FilterElementModel } from './filter-element-model'; import { MockBuilder, MockedComponentFixture, MockRender } from 'ng-mocks'; import { CUSTOM_ELEMENTS_SCHEMA, NO_ERRORS_SCHEMA } from '@angular/core'; - function buildFilterModel(config: ParmOpt[], value: string): FilterElementModel { - const ret = new FilterElementModel([{ Uid: '1', Options: config }], - ['1 Display'], { ParameterValue: value, AttestationSubType: '1' }, - '', - ({ buildColumn: jasmine.createSpy('buildColumn') } as unknown) as FilterElementColumnService - ); - - return ret; + const ret = new FilterElementModel( + [{ Uid: '1', Options: config }], + ['1 Display'], + { ParameterValue: value, AttestationSubType: '1' }, + '', + { buildColumn: jasmine.createSpy('buildColumn') } as unknown as FilterElementColumnService, + ); + + return ret; } describe('EditOriginComponent', () => { - let component: EditOriginComponent; - let fixture: MockedComponentFixture; - - beforeEach(() => { - return MockBuilder(EditOriginComponent) - .mock(ClassloggerService) - .beforeCompileComponents(testbed => { - testbed.configureTestingModule({ - schemas: [CUSTOM_ELEMENTS_SCHEMA, NO_ERRORS_SCHEMA] - }) - }) - }) - - - beforeEach(() => { - fixture = MockRender(EditOriginComponent) - component = fixture.point.componentInstance; - fixture.detectChanges(); - }); - - afterAll(() => { - clearStylesFromDOM(); - }); - - it('should create', () => { - expect(component).toBeTruthy(); - }); - - it('inits controls', () => { - const options = [ - { Display: 'One', Uid: '1' }, - { Display: 'Two', Uid: '2' }, - { Display: 'Three', Uid: '3' }, - ]; - component.filterElementModel = buildFilterModel(options, '"1","2"'); - component.ngOnInit(); - - expect(component.control.controls.length).toEqual(3); - expect(component.control.controls[0].value).toBeTruthy(); - expect(component.control.controls[1].value).toBeTruthy(); - expect(component.control.controls[2].value).toBeFalsy(); - }); - - it('emits changes', () => { - const options = [ - { Display: 'One', Uid: '1' }, - { Display: 'Two', Uid: '2' }, - { Display: 'Three', Uid: '3' }, - ]; - - component.filterElementModel = buildFilterModel(options, '\'2\',\'3\'') - component.ngOnInit(); - - const spy = spyOn(component.valueChanged, 'emit'); - - component.control.controls[0].setValue(false); - component.control.controls[2].setValue(true); - - expect(spy.calls.mostRecent().args).toEqual([{ ParameterValue: '\'2\',\'3\'', displays: ['\'Two\'', '\'Three\''] }]); - - }); + let component: EditOriginComponent; + let fixture: MockedComponentFixture; + + beforeEach(() => { + return MockBuilder(EditOriginComponent) + .mock(ClassloggerService) + .beforeCompileComponents((testbed) => { + testbed.configureTestingModule({ + schemas: [CUSTOM_ELEMENTS_SCHEMA, NO_ERRORS_SCHEMA], + }); + }); + }); + + beforeEach(() => { + fixture = MockRender(EditOriginComponent); + component = fixture.point.componentInstance; + fixture.detectChanges(); + }); + + afterAll(() => { + clearStylesFromDOM(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); + + it('inits controls', () => { + const options = [ + { Display: 'One', Uid: '1' }, + { Display: 'Two', Uid: '2' }, + { Display: 'Three', Uid: '3' }, + ]; + component.filterElementModel = buildFilterModel(options, '"1","2"'); + component.ngOnInit(); + + expect(component.control.controls.length).toEqual(3); + expect(component.control.controls[0].value).toBeTruthy(); + expect(component.control.controls[1].value).toBeTruthy(); + expect(component.control.controls[2].value).toBeFalsy(); + }); + + it('emits changes', () => { + const options = [ + { Display: 'One', Uid: '1' }, + { Display: 'Two', Uid: '2' }, + { Display: 'Three', Uid: '3' }, + ]; + + component.filterElementModel = buildFilterModel(options, "'2','3'"); + component.ngOnInit(); + + const spy = spyOn(component.valueChanged, 'emit'); + + component.control.controls[0].setValue(false); + component.control.controls[2].setValue(true); + + expect(spy.calls.mostRecent().args).toEqual([{ ParameterValue: "'2','3'", displays: ["'Two'", "'Three'"] }]); + }); }); diff --git a/imxweb/projects/att/src/lib/policies/editors/edit-origin.component.ts b/imxweb/projects/att/src/lib/policies/editors/edit-origin.component.ts index ff8f558a3..70d7b9ee9 100644 --- a/imxweb/projects/att/src/lib/policies/editors/edit-origin.component.ts +++ b/imxweb/projects/att/src/lib/policies/editors/edit-origin.component.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -25,10 +25,10 @@ */ import { Component, EventEmitter, Input, OnDestroy, OnInit, Output } from '@angular/core'; -import { UntypedFormArray, UntypedFormControl } from '@angular/forms'; +import { FormArray, FormGroup, UntypedFormControl } from '@angular/forms'; import { Subscription } from 'rxjs'; -import { ParmOpt } from 'imx-api-att'; +import { ParmOpt } from '@imx-modules/imx-api-att'; import { ClassloggerService } from 'qbm'; import { FilterChangedArgument } from './filter-changed-argument.interface'; import { FilterElementModel } from './filter-element-model'; @@ -36,12 +36,12 @@ import { FilterElementModel } from './filter-element-model'; @Component({ templateUrl: './edit-origin.component.html', selector: 'imx-edit-origin', - styleUrls: ['./edit-origin.component.scss'] + styleUrls: ['./edit-origin.component.scss'], }) export class EditOriginComponent implements OnInit, OnDestroy { - public candidates: ParmOpt[]; - public readonly control = new UntypedFormArray([]); + public readonly control = new FormArray([]); + public form: FormGroup<{ candidates: FormArray }> = new FormGroup({ candidates: this.control }); @Input() public filterElementModel: FilterElementModel; @Input() public identifier: string; @@ -52,18 +52,17 @@ export class EditOriginComponent implements OnInit, OnDestroy { private selectedParameter: string[]; private valueChangedSubscription: Subscription; - constructor(private readonly logger: ClassloggerService) { } + constructor(private readonly logger: ClassloggerService) {} public ngOnInit(): void { - if (this.filterElementModel == null) { return; } - this.candidates = this.filterElementModel.getParameterData(this.filterElementModel?.attestationSubType).Options; + this.candidates = this.filterElementModel.getParameterData(this.filterElementModel?.attestationSubType).Options || []; this.selectedParameter = this.splitStringAndRemoveQuotes(this.filterElementModel?.parameterValue, ','); - this.candidates.forEach(elem => { + this.candidates.forEach((elem) => { this.control.push(new UntypedFormControl(this.isSelected(elem))); this.logger.trace(this, 'control added for candidate', elem); }); @@ -71,8 +70,8 @@ export class EditOriginComponent implements OnInit, OnDestroy { this.valueChangedSubscription = this.control.valueChanges.subscribe(() => this.valueChanged.emit({ ParameterValue: this.buildNewParameterValue(), - displays: this.buildDisplay() - }) + displays: this.buildDisplay(), + }), ); } @@ -84,7 +83,7 @@ export class EditOriginComponent implements OnInit, OnDestroy { private buildNewParameterValue(): string { const elements = this.control.value; - const returnValue = []; + const returnValue: string[] = []; elements.forEach((element: any, index: number) => { if (element) { returnValue.push(`'${this.candidates[index].Uid}'`); @@ -97,7 +96,7 @@ export class EditOriginComponent implements OnInit, OnDestroy { private buildDisplay(): string[] { const elements = this.control.value; - const returnValue = []; + const returnValue: string[] = []; elements.forEach((element: any, index: number) => { if (element) { returnValue.push(`'${this.candidates[index].Display}'`); @@ -108,12 +107,11 @@ export class EditOriginComponent implements OnInit, OnDestroy { } private isSelected(option: ParmOpt): boolean { - return this.selectedParameter.includes(option.Uid); + return this.selectedParameter.includes(option.Uid || ''); } private splitStringAndRemoveQuotes(listString: string, separator: string): string[] { const splitted = listString.split(separator); - return splitted.map(str => str.substring(1, str.length - 1)); + return splitted.map((str) => str.substring(1, str.length - 1)); } - } diff --git a/imxweb/projects/att/src/lib/policies/editors/edit-threshold.component.html b/imxweb/projects/att/src/lib/policies/editors/edit-threshold.component.html index 8d18fb61e..920383960 100644 --- a/imxweb/projects/att/src/lib/policies/editors/edit-threshold.component.html +++ b/imxweb/projects/att/src/lib/policies/editors/edit-threshold.component.html @@ -1,16 +1,30 @@ -

    {{'#LDS#Heading Risk Index' | translate}}

    +

    {{ '#LDS#Heading Risk Index' | translate }}

    - - {{'#LDS#Lower limit' | translate}} - - - {{'#LDS#Specify a value between 0 and 1 for the lower limit.' |translate}} - - - {{'#LDS#Upper limit' | translate}} - - - {{'#LDS#Specify a value between 0 and 1 for the upper limit.' |translate}} - + + {{ '#LDS#Lower limit' | translate }} + + {{ '#LDS#Specify a value between 0 and 1 for the lower limit.' | translate }} + + + {{ '#LDS#Upper limit' | translate }} + + {{ '#LDS#Specify a value between 0 and 1 for the upper limit.' | translate }} +
    diff --git a/imxweb/projects/att/src/lib/policies/editors/edit-threshold.component.scss b/imxweb/projects/att/src/lib/policies/editors/edit-threshold.component.scss index a47cfc603..82b25916d 100644 --- a/imxweb/projects/att/src/lib/policies/editors/edit-threshold.component.scss +++ b/imxweb/projects/att/src/lib/policies/editors/edit-threshold.component.scss @@ -1,12 +1,12 @@ h4 { - font-size: smaller; - font-weight: 600; + font-size: smaller; + font-weight: 600; } div { - display: grid; - grid-template-columns: 1fr 1fr; - grid-gap: 5px; + display: grid; + grid-template-columns: 1fr 1fr; + grid-gap: 5px; } @media only screen and (max-width: 1024px) { @@ -14,4 +14,4 @@ div { display: flex; flex-direction: column; } -} \ No newline at end of file +} diff --git a/imxweb/projects/att/src/lib/policies/editors/edit-threshold.component.ts b/imxweb/projects/att/src/lib/policies/editors/edit-threshold.component.ts index 562d41769..a6a78d3db 100644 --- a/imxweb/projects/att/src/lib/policies/editors/edit-threshold.component.ts +++ b/imxweb/projects/att/src/lib/policies/editors/edit-threshold.component.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -35,10 +35,9 @@ import { FilterElementModel } from './filter-element-model'; @Component({ templateUrl: './edit-threshold.component.html', selector: 'imx-edit-threshold', - styleUrls: ['./edit-threshold.component.scss'] + styleUrls: ['./edit-threshold.component.scss'], }) export class EditThresholdComponent implements OnInit, OnDestroy { - public readonly riskIndexForm: UntypedFormGroup; public readonly lowerControl: UntypedFormControl; public readonly upperControl: UntypedFormControl; @@ -56,7 +55,7 @@ export class EditThresholdComponent implements OnInit, OnDestroy { this.upperControl = new UntypedFormControl(undefined, { updateOn: 'blur', validators: [Validators.min(0), Validators.max(1)] }); this.riskIndexForm = new UntypedFormGroup({ lowerBounds: this.lowerControl, - upperBounds: this.upperControl + upperBounds: this.upperControl, }); } @@ -68,9 +67,12 @@ export class EditThresholdComponent implements OnInit, OnDestroy { this.valueChanged.emit({ ParameterValue: this.lowerControl.value?.toLocaleString('en-us'), ParameterValue2: this.upperControl.value?.toLocaleString('en-us'), - displays: [(this.lowerControl.value * 100).toLocaleString(this.translateService.currentLang) - + ' - ' + (this.upperControl.value * 100).toLocaleString(this.translateService.currentLang)] - }) + displays: [ + (this.lowerControl.value * 100).toLocaleString(this.translateService.currentLang) + + ' - ' + + (this.upperControl.value * 100).toLocaleString(this.translateService.currentLang), + ], + }), ); } diff --git a/imxweb/projects/att/src/lib/policies/editors/edit-uint.component.html b/imxweb/projects/att/src/lib/policies/editors/edit-uint.component.html index e5bc7f5d1..4999f524b 100644 --- a/imxweb/projects/att/src/lib/policies/editors/edit-uint.component.html +++ b/imxweb/projects/att/src/lib/policies/editors/edit-uint.component.html @@ -1,6 +1,5 @@ - {{'#LDS#Number of days' | translate}} - - - {{'#LDS#The number of days must be positive.' | translate}} + {{ '#LDS#Number of days' | translate }} + + {{ '#LDS#The number of days must be positive.' | translate }} diff --git a/imxweb/projects/att/src/lib/policies/editors/edit-uint.component.ts b/imxweb/projects/att/src/lib/policies/editors/edit-uint.component.ts index 9ca000d2f..772739e53 100644 --- a/imxweb/projects/att/src/lib/policies/editors/edit-uint.component.ts +++ b/imxweb/projects/att/src/lib/policies/editors/edit-uint.component.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -34,10 +34,9 @@ import { FilterElementModel } from './filter-element-model'; @Component({ templateUrl: './edit-uint.component.html', - selector: 'imx-edit-uint' + selector: 'imx-edit-uint', }) export class EditUintComponent implements OnInit, OnDestroy { - public control: UntypedFormControl; @Input() public filterElementModel: FilterElementModel; @Input() public identifier: string; @@ -59,8 +58,8 @@ export class EditUintComponent implements OnInit, OnDestroy { this.valueChangedSubscription = this.control.valueChanges.subscribe(() => this.valueChanged.emit({ ParameterValue: this.control.value, - displays: [this.control.value.toLocaleString(this.translateService.currentLang)] - }) + displays: [this.control.value.toLocaleString(this.translateService.currentLang)], + }), ); } diff --git a/imxweb/projects/att/src/lib/policies/editors/filter-changed-argument.interface.ts b/imxweb/projects/att/src/lib/policies/editors/filter-changed-argument.interface.ts index 4bed5acc9..9f3b82828 100644 --- a/imxweb/projects/att/src/lib/policies/editors/filter-changed-argument.interface.ts +++ b/imxweb/projects/att/src/lib/policies/editors/filter-changed-argument.interface.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -24,9 +24,9 @@ * */ -import { PolicyFilterElement } from 'imx-api-att'; +import { PolicyFilterElement } from '@imx-modules/imx-api-att'; -export interface FilterChangedArgument extends PolicyFilterElement { - displays?: string[]; - setName?: boolean; +export interface FilterChangedArgument extends PolicyFilterElement { + displays?: string[]; + setName?: boolean; } diff --git a/imxweb/projects/att/src/lib/policies/editors/filter-editor.component.html b/imxweb/projects/att/src/lib/policies/editors/filter-editor.component.html index f28c46e2a..4834d6d2e 100644 --- a/imxweb/projects/att/src/lib/policies/editors/filter-editor.component.html +++ b/imxweb/projects/att/src/lib/policies/editors/filter-editor.component.html @@ -1,23 +1,43 @@ - + - + - + - + - - \ No newline at end of file + + diff --git a/imxweb/projects/att/src/lib/policies/editors/filter-editor.component.scss b/imxweb/projects/att/src/lib/policies/editors/filter-editor.component.scss index e110d11b2..248a268c5 100644 --- a/imxweb/projects/att/src/lib/policies/editors/filter-editor.component.scss +++ b/imxweb/projects/att/src/lib/policies/editors/filter-editor.component.scss @@ -1 +1 @@ -// add styles if necessary \ No newline at end of file +// add styles if necessary diff --git a/imxweb/projects/att/src/lib/policies/editors/filter-editor.component.ts b/imxweb/projects/att/src/lib/policies/editors/filter-editor.component.ts index 4b28ed2be..3bf8156e9 100644 --- a/imxweb/projects/att/src/lib/policies/editors/filter-editor.component.ts +++ b/imxweb/projects/att/src/lib/policies/editors/filter-editor.component.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -24,7 +24,7 @@ * */ -import { EventEmitter, forwardRef, Component, Input, Output } from '@angular/core'; +import { Component, EventEmitter, forwardRef, Input, Output } from '@angular/core'; import { ControlValueAccessor, NG_VALUE_ACCESSOR } from '@angular/forms'; import { ClassloggerService } from 'qbm'; @@ -39,9 +39,9 @@ import { FilterElementModel } from './filter-element-model'; provide: NG_VALUE_ACCESSOR, useExisting: forwardRef(() => FilterEditorComponent), multi: true, - } + }, ], - styleUrls: ['./filter-editor.component.scss'] + styleUrls: ['./filter-editor.component.scss'], }) export class FilterEditorComponent implements ControlValueAccessor { public onChange: (event: FilterElementModel) => void; @@ -52,7 +52,7 @@ export class FilterEditorComponent implements ControlValueAccessor { @Output() public filterChanged = new EventEmitter(); - constructor(private readonly logger: ClassloggerService) { } + constructor(private readonly logger: ClassloggerService) {} public writeValue(filter: FilterElementModel): void { this.filterElementModel = filter; @@ -69,14 +69,13 @@ export class FilterEditorComponent implements ControlValueAccessor { } public invokeFilterChangedElement(arg: FilterChangedArgument): void { - this.filterElementModel.parameterValue = arg.ParameterValue; - this.filterElementModel.parameterValue2 = arg.ParameterValue2; + this.filterElementModel.parameterValue = arg.ParameterValue || ''; + this.filterElementModel.parameterValue2 = arg.ParameterValue2 || ''; this.writeValue(this.filterElementModel); this.onTouch(this.filterElementModel); this.onChange(this.filterElementModel); this.filterChanged.emit(arg); - } } diff --git a/imxweb/projects/att/src/lib/policies/editors/filter-element-column.service.ts b/imxweb/projects/att/src/lib/policies/editors/filter-element-column.service.ts index e2b2f3af9..8e56cec1d 100644 --- a/imxweb/projects/att/src/lib/policies/editors/filter-element-column.service.ts +++ b/imxweb/projects/att/src/lib/policies/editors/filter-element-column.service.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -27,20 +27,21 @@ import { Injectable } from '@angular/core'; import { TranslateService } from '@ngx-translate/core'; -import { ParmData } from 'imx-api-att'; -import { EntityColumnData, IEntityColumn, MultiValue, ValType } from 'imx-qbm-dbts'; +import { ParmData } from '@imx-modules/imx-api-att'; +import { EntityColumnData, FkProviderItem, IEntityColumn, MultiValue, ValType } from '@imx-modules/imx-qbm-dbts'; import { EntityService } from 'qbm'; import { PolicyService } from '../policy.service'; import { FilterElementModel } from './filter-element-model'; @Injectable({ - providedIn: 'root' + providedIn: 'root', }) export class FilterElementColumnService { constructor( public readonly policyService: PolicyService, private readonly translateService: TranslateService, - private readonly entityService: EntityService) { } + private readonly entityService: EntityService, + ) {} public buildColumn( parmdata: ParmData, @@ -48,52 +49,56 @@ export class FilterElementColumnService { value: string, caption: string, displays: string[], - withfk: boolean): IEntityColumn { - + withfk: boolean, + ): IEntityColumn | undefined { if (parmdata == null) { return undefined; } const propertyName = parmdata.RequiredParameter; - return this.entityService.createLocalEntityColumn({ - Type: ValType.String, - IsMultiValued: withfk, - ColumnName: parmdata.ColumnName || propertyName, - MinLen: withfk ? 1 : 0, - Display: caption ? this.translateService.instant(caption) : '', - FkRelation: withfk ? { - IsMemberRelation: false, - ParentTableName: parmdata.TableName, - ParentColumnName: parmdata.ColumnName - } : undefined - }, withfk ? [{ - columnName: parmdata.ColumnName, - fkTableName: parmdata.TableName, - parameterNames: [ - 'OrderBy', - 'StartIndex', - 'PageSize', - 'filter', - 'search', - ], - load: async (__, parameters?) => { - return this.policyService.getFilterCandidates(parameters, uidParameter); + let fkProviderItem: FkProviderItem[] = []; + if (withfk) { + fkProviderItem.push({ + columnName: parmdata.ColumnName || '', + fkTableName: parmdata.TableName || '', + parameterNames: ['OrderBy', 'StartIndex', 'PageSize', 'filter', 'search'], + load: async (__, parameters?) => { + return this.policyService.getFilterCandidates(parameters || {}, uidParameter); + }, + getDataModel: async () => ({}), + getFilterTree: async () => ({}), + }); + } + return this.entityService.createLocalEntityColumn( + { + Type: ValType.String, + IsMultiValued: withfk, + ColumnName: parmdata.ColumnName || propertyName, + MinLen: withfk ? 1 : 0, + Display: caption ? this.translateService.instant(caption) : '', + FkRelation: withfk + ? { + IsMemberRelation: false, + ParentTableName: parmdata.TableName, + ParentColumnName: parmdata.ColumnName, + } + : undefined, }, - getDataModel: async () => ({}), - getFilterTree: async ()=>({}) - }] : [], this.getValue(withfk, value, displays)); + fkProviderItem, + this.getValue(withfk, value, displays), + ); } private getValue(withfk: boolean, value: string, displays: string[]): EntityColumnData { if (withfk) { return { Value: FilterElementModel.buildMultiValueSeparatedList(value), - DisplayValue: displays ? new MultiValue(displays).GetStringValue() : '' + DisplayValue: displays ? new MultiValue(displays).GetStringValue() : '', }; } return { Value: value, - DisplayValue: displays ? new MultiValue(displays).GetStringValue() : '' + DisplayValue: displays ? new MultiValue(displays).GetStringValue() : '', }; } } diff --git a/imxweb/projects/att/src/lib/policies/editors/filter-element-model.ts b/imxweb/projects/att/src/lib/policies/editors/filter-element-model.ts index 3c949ed82..7b0bc7b1c 100644 --- a/imxweb/projects/att/src/lib/policies/editors/filter-element-model.ts +++ b/imxweb/projects/att/src/lib/policies/editors/filter-element-model.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -26,38 +26,40 @@ import { BehaviorSubject } from 'rxjs'; -import { ParmData, PolicyFilterElement } from 'imx-api-att'; -import { IEntityColumn, MultiValueProperty } from 'imx-qbm-dbts'; +import { ParmData, PolicyFilterElement } from '@imx-modules/imx-api-att'; +import { IEntityColumn, MultiValueProperty } from '@imx-modules/imx-qbm-dbts'; import { SelectecObjectsInfo } from '../selected-objects/selected-objects-info.interface'; import { FilterElementColumnService } from './filter-element-column.service'; export class FilterElementModel { public columnForFilter: IEntityColumn; - public selectedObjectsSubject: BehaviorSubject = new BehaviorSubject(undefined); + public selectedObjectsSubject: BehaviorSubject = new BehaviorSubject( + undefined, + ); public get parameterName(): string { - return this.filterElement.ParameterName; + return this.filterElement.ParameterName || ''; } public set parameterName(value: string) { this.filterElement.ParameterName = value; } public get attestationSubType(): string { - return this.filterElement.AttestationSubType; + return this.filterElement.AttestationSubType || ''; } public set attestationSubType(value: string) { this.filterElement.AttestationSubType = value; } public get parameterValue(): string { - return this.filterElement.ParameterValue; + return this.filterElement.ParameterValue || ''; } public set parameterValue(value: string) { this.filterElement.ParameterValue = value; } public get parameterValue2(): string { - return this.filterElement.ParameterValue2; + return this.filterElement.ParameterValue2 || ''; } public set parameterValue2(value: string) { this.filterElement.ParameterValue2 = value; @@ -68,16 +70,16 @@ export class FilterElementModel { public displays: string[], public readonly filterElement: PolicyFilterElement, private readonly uidAttestationObject: string, - private readonly columnFactory: FilterElementColumnService + private readonly columnFactory: FilterElementColumnService, ) { this.setColumnForFilter(); } public updateColumn(filter: PolicyFilterElement, displays: string[]): void { - this.attestationSubType = filter.AttestationSubType; - this.parameterName = filter.ParameterName; - this.parameterValue = filter.ParameterValue; - this.parameterValue2 = filter.ParameterValue2; + this.attestationSubType = filter.AttestationSubType || ''; + this.parameterName = filter.ParameterName || ''; + this.parameterValue = filter.ParameterValue || ''; + this.parameterValue2 = filter.ParameterValue2 || ''; this.displays = displays; this.setColumnForFilter(); this.recalculateMatching(); @@ -103,7 +105,7 @@ export class FilterElementModel { } public getParameterData(parameterType: string): ParmData { - return FilterElementModel.getParameterData(this.parameterConfig, parameterType); + return FilterElementModel.getParameterData(this.parameterConfig, parameterType) || {}; } public hasFk(): boolean { @@ -114,11 +116,11 @@ export class FilterElementModel { } public getColumnName(): string { - return this.getParameterData(this.attestationSubType)?.ColumnName; + return this.getParameterData(this.attestationSubType)?.ColumnName || ''; } public getTableName(): string { - return this.getParameterData(this.attestationSubType)?.TableName; + return this.getParameterData(this.attestationSubType)?.TableName || ''; } public filterErrors(): { [key: string]: boolean } | null { @@ -148,14 +150,17 @@ export class FilterElementModel { } private setColumnForFilter(): void { - this.columnForFilter = this.columnFactory.buildColumn( + const column = this.columnFactory.buildColumn( this.getParameterData(this.attestationSubType), this.attestationSubType, this.parameterValue, this.getColumnDisplay(), this.displays, - this.hasFk() + this.hasFk(), ); + if (column) { + this.columnForFilter = column; + } } private getColumnDisplay(): string { @@ -173,10 +178,10 @@ export class FilterElementModel { return parameterName === this.getParameterData(parameterType)?.RequiredParameter; } - public static getParameterData(parameters: ParmData[], parameterType: string): ParmData { + public static getParameterData(parameters: ParmData[], parameterType: string): ParmData | undefined { const arr = parameters.filter((p) => p.Uid === parameterType); if (arr.length !== 1) { - return null; + return undefined; } return arr[0]; @@ -210,7 +215,7 @@ export class FilterElementModel { if (str === '') { return ''; } - const seperated = this.replaceAll(this.replaceAll(str, '\'', ''), ',', MultiValueProperty.DefaultSeparator); + const seperated = this.replaceAll(this.replaceAll(str, "'", ''), ',', MultiValueProperty.DefaultSeparator); return seperated; } diff --git a/imxweb/projects/att/src/lib/policies/policy-details/policy-details.component.html b/imxweb/projects/att/src/lib/policies/policy-details/policy-details.component.html index e5cfbe2b0..cb00834bd 100644 --- a/imxweb/projects/att/src/lib/policies/policy-details/policy-details.component.html +++ b/imxweb/projects/att/src/lib/policies/policy-details/policy-details.component.html @@ -1,17 +1,18 @@ -
    - +
    - -
    {{'#LDS#Total number of attestation cases of all attestation runs' | translate}}:
    -
    {{policy?.CountCases.value}}
    -
    {{'#LDS#Total number of pending attestation cases of all attestation runs' | translate}}:
    -
    {{policy?.CountOpenCases.value}}
    + +
    {{ '#LDS#Total number of attestation cases of all attestation runs' | translate }}:
    +
    {{ policy?.CountCases?.value }}
    +
    + {{ '#LDS#Total number of pending attestation cases of all attestation runs' | translate }}: +
    +
    {{ policy?.CountOpenCases?.value }}
    - -
    {{'#LDS#Status' |translate}}:
    -
    {{status | translate}}
    + +
    {{ '#LDS#Status' | translate }}:
    +
    {{ status | translate }}
    diff --git a/imxweb/projects/att/src/lib/policies/policy-details/policy-details.component.scss b/imxweb/projects/att/src/lib/policies/policy-details/policy-details.component.scss index d3d0712af..910fd26c5 100644 --- a/imxweb/projects/att/src/lib/policies/policy-details/policy-details.component.scss +++ b/imxweb/projects/att/src/lib/policies/policy-details/policy-details.component.scss @@ -1,38 +1,19 @@ -:host { - display: flex; - flex-direction: column; - overflow: hidden; -} +@import 'base/mixins'; -.imx-title-card { - margin: 20px; +:host { + @include flex-column-container($overflow: hidden); } .eui-sidesheet-content { - display: flex; - flex-direction: column; - height: 100%; - padding: 0px; + @include flex-column-container($height: 100%); + padding: 0; } -.eui-sidesheet-actions{ - display: flex; - flex-direction: row; - margin: 0px; - } - .imx-runs-grid { - display: flex; - flex-direction: column; - overflow: hidden; - flex: 1 1 auto; - - ::ng-deep .imx-table-card{ - margin: 0px 20px; - } + @include flex-column-container-fill; } -.mat-card-content { +.mat-mdc-card-content { display: flex; } @@ -41,7 +22,3 @@ grid-template-columns: auto auto; gap: 0 10px; } - -.mat-card { - margin-bottom: 30px; -} \ No newline at end of file diff --git a/imxweb/projects/att/src/lib/policies/policy-details/policy-details.component.ts b/imxweb/projects/att/src/lib/policies/policy-details/policy-details.component.ts index c98d0cb4c..a95ed818d 100644 --- a/imxweb/projects/att/src/lib/policies/policy-details/policy-details.component.ts +++ b/imxweb/projects/att/src/lib/policies/policy-details/policy-details.component.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -27,31 +27,29 @@ import { Component, Inject } from '@angular/core'; import { EUI_SIDESHEET_DATA } from '@elemental-ui/core'; -import { PortalAttestationPolicy } from 'imx-api-att'; +import { PortalAttestationPolicy } from '@imx-modules/imx-api-att'; @Component({ selector: 'imx-policy-details', templateUrl: './policy-details.component.html', - styleUrls: ['./policy-details.component.scss'] + styleUrls: ['./policy-details.component.scss'], }) export class PolicyDetailsComponent { - public uidAttestationPolicy: string; public status: string; public get policy(): PortalAttestationPolicy { return this.data.policy; - } + } - constructor( - @Inject(EUI_SIDESHEET_DATA) public readonly data: { policy: PortalAttestationPolicy }, - ) { + constructor(@Inject(EUI_SIDESHEET_DATA) public readonly data: { policy: PortalAttestationPolicy }) { this.uidAttestationPolicy = data.policy.GetEntity().GetKeys()[0]; - this.status = data.policy.IsProcessing.value ? '#LDS#Processing' + this.status = data.policy.IsProcessing.value + ? '#LDS#Processing' : data.policy.CountCases.value === 0 - ? '#LDS#Not run yet' : - data.policy.CountOpenCases.value === 0 ? '#LDS#Completed' - : '#LDS#Pending'; + ? '#LDS#Not run yet' + : data.policy.CountOpenCases.value === 0 + ? '#LDS#Completed' + : '#LDS#Pending'; } - } diff --git a/imxweb/projects/att/src/lib/policies/policy-editor/filter-model.ts b/imxweb/projects/att/src/lib/policies/policy-editor/filter-model.ts index 6928e1265..727153ef9 100644 --- a/imxweb/projects/att/src/lib/policies/policy-editor/filter-model.ts +++ b/imxweb/projects/att/src/lib/policies/policy-editor/filter-model.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -26,41 +26,25 @@ import { BehaviorSubject } from 'rxjs'; -import { ParmData, PolicyFilterData, PolicyFilterElement } from 'imx-api-att'; -import { SelectecObjectsInfo } from '../selected-objects/selected-objects-info.interface'; +import { ParmData, PolicyFilterData, PolicyFilterElement } from '@imx-modules/imx-api-att'; import { FilterElementColumnService } from '../editors/filter-element-column.service'; import { FilterElementModel } from '../editors/filter-element-model'; +import { SelectecObjectsInfo } from '../selected-objects/selected-objects-info.interface'; export class FilterModel { - public totalSelectedObjectsSubject: BehaviorSubject = new BehaviorSubject(undefined); - public policyFilterData: PolicyFilterData; + public totalSelectedObjectsSubject: BehaviorSubject = new BehaviorSubject< + SelectecObjectsInfo | undefined + >(undefined); + public policyFilterData: PolicyFilterData | undefined; public parameterConfig: ParmData[] = []; public uidAttestationObject: string; constructor( public readonly columnFactory: FilterElementColumnService, - public readonly isEnabledSubject: BehaviorSubject, - public readonly attestationObjectSubject: BehaviorSubject) { - isEnabledSubject.subscribe(elem => { - if (!elem && this.policyFilterData && this.policyFilterData.Filter.Elements.length > 0) { - this.policyFilterData = { - IsReadOnly: this.policyFilterData ? this.policyFilterData.IsReadOnly : true, - Filter: { Elements: [], ConcatenationType: 'OR' }, - InfoDisplay: [] - }; - } - if (elem && this.policyFilterData == null) { - this.policyFilterData = { - IsReadOnly: this.policyFilterData ? this.policyFilterData.IsReadOnly : true, - Filter: { Elements: [], ConcatenationType: 'OR' }, - InfoDisplay: [] - }; - } - this.totalSelectedObjectsSubject.next(undefined); - }); - attestationObjectSubject.subscribe(elem => { + public readonly attestationObjectSubject: BehaviorSubject, + ) { + attestationObjectSubject.subscribe((elem) => { this.uidAttestationObject = elem; - }); } @@ -74,45 +58,50 @@ export class FilterModel { public addCondition(): FilterElementModel { const newCondition = this.buildPolicyModel({}, []); - this.policyFilterData.Filter.Elements.push(newCondition.filterElement); - this.policyFilterData.InfoDisplay.push(['']); + this.policyFilterData?.Filter?.Elements?.push(newCondition.filterElement); + this.policyFilterData?.InfoDisplay?.push(['']); return newCondition; } public deleteCondition(index: number): void { - this.policyFilterData.Filter.Elements.splice(index, 1); - this.policyFilterData.InfoDisplay.splice(index, 1); + this.policyFilterData?.Filter?.Elements?.splice(index, 1); + this.policyFilterData?.InfoDisplay?.splice(index, 1); } public filterHasChanged(filterElements: FilterElementModel[], type: string): void { - this.totalSelectedObjectsSubject.next(this.filtersAreValid(filterElements) ? - { - policyFilter: { - Elements: filterElements.map(filter => filter.filterElement), - ConcatenationType: type - }, - uidPickCategory: '', - uidAttestationObject: this.uidAttestationObject - } - : undefined); + this.totalSelectedObjectsSubject.next( + this.filtersAreValid(filterElements) + ? { + policyFilter: { + Elements: filterElements.map((filter) => filter.filterElement), + ConcatenationType: type, + }, + uidPickCategory: '', + uidAttestationObject: this.uidAttestationObject, + } + : undefined, + ); } public updateConcatination(concat: string): void { - this.policyFilterData.Filter.ConcatenationType = concat; + if (this.policyFilterData?.Filter) { + this.policyFilterData.Filter.ConcatenationType = concat; + } } public buildPolicyModel(filterElement: PolicyFilterElement, displays?: string[]): FilterElementModel { - const model = new FilterElementModel(this.parameterConfig, - displays, + const model = new FilterElementModel( + this.parameterConfig, + displays || [], filterElement, this.uidAttestationObject, - this.columnFactory + this.columnFactory, ); return model; } private filtersAreValid(filterElements: FilterElementModel[]): boolean { - return filterElements.filter(elem => elem.filterErrors() == null).length === filterElements.length; + return filterElements.filter((elem) => elem.filterErrors() == null).length === filterElements.length; } } diff --git a/imxweb/projects/att/src/lib/policies/policy-editor/policy-editor.component.html b/imxweb/projects/att/src/lib/policies/policy-editor/policy-editor.component.html index 593e1a95f..a7e4d288f 100644 --- a/imxweb/projects/att/src/lib/policies/policy-editor/policy-editor.component.html +++ b/imxweb/projects/att/src/lib/policies/policy-editor/policy-editor.component.html @@ -1,5 +1,5 @@
    -

    {{ '#LDS#Heading Objects to be Attested by this Attestation Policy' | translate }}

    +

    {{ '#LDS#Heading Objects to be Attested by this Attestation Policy' | translate }}

    {{ '#LDS#Heading Objects to be Attested by this At >
    - -
    {{ '#LDS#This policy affects many objects. Running this policy may take some time and generate notifications to many approvers.' | translate }}
    + +
    + {{ + '#LDS#This policy affects many objects. Running this policy may take some time and generate notifications to many approvers.' + | translate + }} +
    +
    + +
    + {{ mismatch | translate }} +
    - + - {{ '#LDS#How many conditions must be met?' | translate }} - + {{ + '#LDS#How many conditions must be met?' | translate + }} + {{ '#LDS#All conditions have to be met.' | translate }} @@ -28,20 +44,21 @@

    {{ '#LDS#Heading Objects to be Attested by this At - + {{ '#LDS#Add at least one condition.' | translate }} - + + + +
    {{ filterElementModel?.getParameterData(filterElementModel?.attestationSubType || '')?.Display }}
    + + +
    + + {{ '#LDS#New condition' | translate }} + + - - {{'#LDS#Condition type' | translate}} - - - {{elem.Display}} - - - + + {{ '#LDS#Condition type' | translate }} + + + {{ elem.Display }} + + + - - - - {{'#LDS#Please select a condition type.' | translate}} - + + + + + {{ '#LDS#Please select a condition type.' | translate }} + - \ No newline at end of file + diff --git a/imxweb/projects/att/src/lib/policies/policy-filter-element/policy-filter-element.component.scss b/imxweb/projects/att/src/lib/policies/policy-filter-element/policy-filter-element.component.scss index b5051339c..c40b22667 100644 --- a/imxweb/projects/att/src/lib/policies/policy-filter-element/policy-filter-element.component.scss +++ b/imxweb/projects/att/src/lib/policies/policy-filter-element/policy-filter-element.component.scss @@ -1,52 +1,13 @@ -@import "@elemental-ui/core/src/styles/_eui_palette.scss"; - - -:host ::ng-deep .mat-expansion-panel-body { - display: flex; - flex-direction: column; - background-color: $color-gray-2; - padding-top: 10px; -} - -.imx-panel-title-with-number, -.imx-title { - display: flex; - flex-direction: row; - align-items: center; -} - -.imx-panel-title-with-number > :first-child { - flex: 1; - overflow: hidden; - white-space: nowrap; - text-overflow: ellipsis; -} +.imx-panel-title-with-number{ + max-width: calc(100% - 52px); + &> :first-child { + flex: 1; + overflow: hidden; + white-space: nowrap; + text-overflow: ellipsis; + } + } .imx-small-error { font-size: small; } - -.mat-expansion-panel-header-title { - align-items: center; - margin-right: 0; -} - -.eui-icon { - color: $color-gray-50; -} - -.eui-dark-theme { - :host { - ::ng-deep .mat-expansion-panel-body{ - background-color: $color-gray-80; - } - } -} - -.eui-contrast-theme { - :host { - ::ng-deep .mat-expansion-panel-body{ - background-color: $color-gray-100; - } - } -} diff --git a/imxweb/projects/att/src/lib/policies/policy-filter-element/policy-filter-element.component.ts b/imxweb/projects/att/src/lib/policies/policy-filter-element/policy-filter-element.component.ts index 218f35a51..e5df5d414 100644 --- a/imxweb/projects/att/src/lib/policies/policy-filter-element/policy-filter-element.component.ts +++ b/imxweb/projects/att/src/lib/policies/policy-filter-element/policy-filter-element.component.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -24,9 +24,8 @@ * */ -import { ChangeDetectorRef, EventEmitter, ViewChild } from '@angular/core'; -import { Component, Input, Output } from '@angular/core'; -import { UntypedFormGroup } from '@angular/forms'; +import { ChangeDetectorRef, Component, EventEmitter, Input, Output, ViewChild } from '@angular/core'; +import { FormGroup, UntypedFormControl, UntypedFormGroup } from '@angular/forms'; import { MatExpansionPanel } from '@angular/material/expansion'; import { MatSelectChange } from '@angular/material/select'; @@ -36,11 +35,10 @@ import { FilterElementModel } from '../editors/filter-element-model'; @Component({ selector: 'imx-policy-filter-element', templateUrl: './policy-filter-element.component.html', - styleUrls: ['./policy-filter-element.component.scss'] + styleUrls: ['./policy-filter-element.component.scss'], }) export class PolicyFilterElementComponent { - - @Input() public formGroup: UntypedFormGroup; + @Input() public formGroup: FormGroup<{ filterParameter: UntypedFormControl; type: UntypedFormControl }>; @Input() public idForTest: string; @Output() public deleteFilter = new EventEmitter(); @@ -48,18 +46,14 @@ export class PolicyFilterElementComponent { @Output() public parameterChanged = new EventEmitter(); @ViewChild(MatExpansionPanel) private panel: MatExpansionPanel; - public get filterElementModel(): FilterElementModel { - return this.formGroup?.get(this.filterParameter).value; + public get filterElementModel(): FilterElementModel | undefined { + return this.formGroup.controls.filterParameter.value; } - private readonly filterParameter = 'filterParameter'; - - constructor(private readonly cd: ChangeDetectorRef) { } + constructor(private readonly cd: ChangeDetectorRef) {} public open(): void { - if (this.panel - && (this.filterElementModel.attestationSubType == null || this.filterElementModel.attestationSubType === '') - ) { + if (this.panel && (this.filterElementModel?.attestationSubType == null || this.filterElementModel?.attestationSubType === '')) { this.panel.open(); this.cd.detectChanges(); } @@ -69,12 +63,21 @@ export class PolicyFilterElementComponent { if (this.filterElementModel == null) { return; } - this.filterElementModel.updateColumn({ - ParameterName: this.filterElementModel.getParameterData(arg.value).RequiredParameter, - AttestationSubType: arg.value, - ParameterValue: FilterElementModel.getDefaultValue(this.filterElementModel.getParameterData(arg.value).RequiredParameter, false), - ParameterValue2: FilterElementModel.getDefaultValue(this.filterElementModel.getParameterData(arg.value).RequiredParameter, true), - }, []); + this.filterElementModel.updateColumn( + { + ParameterName: this.filterElementModel.getParameterData(arg.value).RequiredParameter, + AttestationSubType: arg.value, + ParameterValue: FilterElementModel.getDefaultValue( + this.filterElementModel.getParameterData(arg.value).RequiredParameter || '', + false, + ), + ParameterValue2: FilterElementModel.getDefaultValue( + this.filterElementModel.getParameterData(arg.value).RequiredParameter || '', + true, + ), + }, + [], + ); this.formGroup.updateValueAndValidity(); this.conditionTypeChanged.emit(this.filterElementModel); } @@ -83,8 +86,7 @@ export class PolicyFilterElementComponent { if (this.filterElementModel == null) { return; } - this.filterElementModel.updateColumn(this.filterElementModel.filterElement, arg.displays); + this.filterElementModel.updateColumn(this.filterElementModel.filterElement, arg.displays || []); this.parameterChanged.emit(this.filterElementModel); } - } diff --git a/imxweb/projects/att/src/lib/policies/policy-list/attestation-policy.ts b/imxweb/projects/att/src/lib/policies/policy-list/attestation-policy.ts index 195603a5f..a6239f2c3 100644 --- a/imxweb/projects/att/src/lib/policies/policy-list/attestation-policy.ts +++ b/imxweb/projects/att/src/lib/policies/policy-list/attestation-policy.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -24,7 +24,7 @@ * */ -import { PortalAttestationPolicy } from 'imx-api-att'; +import { PortalAttestationPolicy } from '@imx-modules/imx-api-att'; export class AttestationPolicy extends PortalAttestationPolicy { public hasAttestations = false; diff --git a/imxweb/projects/att/src/lib/policies/policy-list/policy-list.component.html b/imxweb/projects/att/src/lib/policies/policy-list/policy-list.component.html index dbb3da9bc..90393c55c 100644 --- a/imxweb/projects/att/src/lib/policies/policy-list/policy-list.component.html +++ b/imxweb/projects/att/src/lib/policies/policy-list/policy-list.component.html @@ -1,91 +1,90 @@ -

    - {{ '#LDS#Heading Attestation Policies' | translate }} - -

    - -
    - - +
    +

    + {{ '#LDS#Heading Attestation Policies' | translate }} + +

    + +
    + + + + + {{ entitySchemaPolicy?.Columns?.[DisplayColumns.DISPLAY_PROPERTYNAME]?.Display }} + + +
    {{ item.GetEntity().GetDisplay() }}
    +
    +
    {{ item.Areas.Column.GetDisplayValue() }}
    +
    + +
    + + {{ entitySchemaPolicy?.Columns?.NextRun?.Display }} + + {{ item.GetEntity().GetColumn('NextRun').GetValue() | shortDate }} + + + + + +
    + +
    - - - -
    {{ data.GetEntity().GetDisplay() }}
    -
    -
    {{ data.Areas.Column.GetDisplayValue() }}
    -
    -
    -
    - - - -
    + + +
    +
    - - -
    - - -
    - - - - -
    - - - - -
    + + + + + +
    +
    +
    -
    - - - diff --git a/imxweb/projects/att/src/lib/policies/policy-list/policy-list.component.scss b/imxweb/projects/att/src/lib/policies/policy-list/policy-list.component.scss index 1d6c6e991..129919c62 100644 --- a/imxweb/projects/att/src/lib/policies/policy-list/policy-list.component.scss +++ b/imxweb/projects/att/src/lib/policies/policy-list/policy-list.component.scss @@ -1,30 +1,11 @@ @import '@elemental-ui/core/src/styles/_eui_palette.scss'; -@import '../../../../../../shared/scss/common-table.scss'; + :host { display: flex; flex-direction: column; overflow: hidden; height: inherit; - ::ng-deep imx-data-table .mat-header-row .mat-header-cell { - font-weight: 600; - font-size: 14px; - padding: 0 10px; - } - - ::ng-deep imx-data-table .mat-row .mat-cell { - padding: 0 10px; - } - - ::ng-deep eui-sidesheet .eui-sidesheet__content { - display: flex; - flex-direction: column; - } - - imx-data-table { - flex-grow: 2; - } - div[subtitle-long] { font-size: smaller; color: $color-gray-40; @@ -36,14 +17,7 @@ .imx-separate-menu-item { border-top: 1px solid $color-gray-20; } - - .imx-table-container { - display: flex; - flex-direction: column; - overflow: hidden; - height: inherit; - flex: 1 1 auto; - } + .imx-policy-footer { display: flex; @@ -54,49 +28,9 @@ min-height: 50px; } - .mat-raised-button { - align-self: flex-end; - } - - .mat-toolbar { - background-color: inherit; - margin-left: 25px; - margin-right: 0; - margin-bottom: 40px; - padding-right: 0; - } - - .mat-toolbar > button { - margin-left: 5px; - } - - .mat-toolbar > mat-button { - color: $color-gray-100; - } - .imx-toolbar-spacer { flex: 1 1 auto; } - - .mat-slide-toggle { - font-size: 16px; - } - - .button-row { - @include imx-button-bar(); - } - - .imx-button-column { - @include imx-button-column-right(); - } - - .imx-content-card { - flex: 1 1 auto; - display: flex; - flex-direction: column; - margin: 3px; - overflow: hidden; - } } .imx-menu-with-spinner { @@ -104,18 +38,10 @@ flex-direction: row; align-items: center; margin-right: 16px; - - .mat-progress-spinner { - overflow: visible; - } } .eui-dark-theme { :host { - .mat-toolbar > mat-button { - color: $color-gray-10; - } - div[subtitle-long] { color: $color-gray-60; } @@ -124,9 +50,6 @@ .eui-contrast-theme { :host { - .mat-toolbar > mat-button { - color: $color-gray-0; - } div[subtitle-long] { color: $color-gray-80; } diff --git a/imxweb/projects/att/src/lib/policies/policy-list/policy-list.component.ts b/imxweb/projects/att/src/lib/policies/policy-list/policy-list.component.ts index 98fa200f5..ac2ba6a4b 100644 --- a/imxweb/projects/att/src/lib/policies/policy-list/policy-list.component.ts +++ b/imxweb/projects/att/src/lib/policies/policy-list/policy-list.component.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -25,63 +25,61 @@ */ import { ChangeDetectorRef, Component, OnInit, ViewChild } from '@angular/core'; -import { OverlayRef } from '@angular/cdk/overlay'; +import { MatButton } from '@angular/material/button'; import { EuiDownloadOptions, EuiLoadingService, EuiSidesheetService } from '@elemental-ui/core'; import { TranslateService } from '@ngx-translate/core'; -import { MatButton } from '@angular/material/button'; +import { PolicyFilterData, PortalAttestationPolicy, PortalAttestationPolicyEdit } from '@imx-modules/imx-api-att'; +import { ViewConfigData } from '@imx-modules/imx-api-qer'; +import { + CollectionLoadParameters, + CompareOperator, + DataModel, + DisplayColumns, + EntitySchema, + ExtendedTypedEntityCollection, + FilterType, + TypedEntityCollectionData, + ValType, +} from '@imx-modules/imx-qbm-dbts'; import { + BusyService, ClassloggerService, + ClientPropertyForTableColumns, ConfirmationService, DataSourceToolbarFilter, - DataSourceToolbarGroupData, - DataSourceToolbarSettings, + DataSourceToolbarViewConfig, DataTableGroupedData, - ClientPropertyForTableColumns, + DataViewInitParameters, + DataViewSource, SettingsService, SnackBarService, SystemInfoService, - createGroupData, - DataSourceToolbarViewConfig, - BusyService, + calculateSidesheetWidth, } from 'qbm'; -import { - DisplayColumns, - ValType, - ExtendedTypedEntityCollection, - EntitySchema, - FilterType, - CompareOperator, - DataModel, -} from 'imx-qbm-dbts'; -import { PolicyFilterData, PortalAttestationPolicy, PortalAttestationPolicyEdit } from 'imx-api-att'; import { UserModelService, ViewConfigService } from 'qer'; -import { PolicyService } from '../policy.service'; -import { EditMasterDataComponent } from '../edit-master-data/edit-master-data.component'; import { AttestationCasesComponentParameter } from '../attestation-cases/attestation-cases-component-parameter.interface'; import { AttestationCasesComponent } from '../attestation-cases/attestation-cases.component'; -import { PolicyLoadParameters } from './policy-load-parameters.interface'; -import { AttestationPolicy } from './attestation-policy'; +import { EditMasterDataComponent } from '../edit-master-data/edit-master-data.component'; import { PolicyDetailsComponent } from '../policy-details/policy-details.component'; import { PolicyCopyData } from '../policy.interface'; -import { ViewConfigData } from 'imx-api-qer'; +import { PolicyService } from '../policy.service'; +import { AttestationPolicy } from './attestation-policy'; @Component({ templateUrl: './policy-list.component.html', styleUrls: ['./policy-list.component.scss'], + providers: [DataViewSource], }) export class PolicyListComponent implements OnInit { @ViewChild('deleteButton') public deleteButton: MatButton; - public dstSettings: DataSourceToolbarSettings; - public navigationState: PolicyLoadParameters; public readonly entitySchemaPolicy: EntitySchema; public readonly DisplayColumns = DisplayColumns; public groupedData: { [key: string]: DataTableGroupedData } = {}; public isComplienceFrameworkEnabled = false; public busyService = new BusyService(); public menuLoading = false; - private groupData: DataSourceToolbarGroupData; private filterOptions: DataSourceToolbarFilter[] = []; private prefilterOwner = false; @@ -101,10 +99,10 @@ export class PolicyListComponent implements OnInit { private readonly userService: UserModelService, private readonly systemInfoService: SystemInfoService, private readonly settingsService: SettingsService, - private readonly changeDetector : ChangeDetectorRef, + private readonly changeDetector: ChangeDetectorRef, private readonly logger: ClassloggerService, + public dataSource: DataViewSource, ) { - this.navigationState = { PageSize: this.settingsService.DefaultPageSize, StartIndex: 0 }; this.entitySchemaPolicy = policyService.AttestationPolicySchema; this.displayedColumns = [ this.entitySchemaPolicy.Columns[DisplayColumns.DISPLAY_PROPERTYNAME], @@ -124,8 +122,8 @@ export class PolicyListComponent implements OnInit { let prep: string[]; try { this.dataModel = await this.policyService.getDataModel(); - features = (await this.userService.getFeatures()).Features; - prep = (await this.systemInfoService.get()).PreProps; + features = (await this.userService.getFeatures()).Features || []; + prep = (await this.systemInfoService.get()).PreProps || []; this.prefilterOwner = !this.policyService.canSeeAllAttestations(prep, features); this.isComplienceFrameworkEnabled = await this.policyService.isComplienceFrameworkEnabled(); @@ -139,49 +137,13 @@ export class PolicyListComponent implements OnInit { public async updateConfig(config: ViewConfigData): Promise { await this.viewConfigService.putViewConfig(config); this.viewConfig = await this.viewConfigService.getDSTExtensionChanges(this.viewConfigPath); - this.dstSettings.viewConfig = this.viewConfig; + this.dataSource.viewConfig.set(this.viewConfig); } public async deleteConfigById(id: string): Promise { await this.viewConfigService.deleteViewConfig(id); this.viewConfig = await this.viewConfigService.getDSTExtensionChanges(this.viewConfigPath); - this.dstSettings.viewConfig = this.viewConfig; - } - - public async onNavigationStateChanged(newState: PolicyLoadParameters): Promise { - this.navigationState = newState; - this.logger.trace(this, 'navigation state change to ', this.navigationState); - await this.navigate(); - } - - public async onSearch(keywords: string): Promise { - this.navigationState = { - ...this.navigationState, - ...{ - StartIndex: 0, - search: keywords, - }, - }; - this.logger.trace(this, 'navigation state change to ', this.navigationState); - return this.navigate(); - } - - public async onGroupingChange(groupKey: string): Promise { - const isBusy = this.busyService.beginBusy(); - - try { - const groupedData = this.groupedData[groupKey]; - groupedData.data = await this.policyService.getPolicies(groupedData.navigationState); - groupedData.settings = { - displayedColumns: this.dstSettings.displayedColumns, - dataModel: this.dstSettings.dataModel, - dataSource: groupedData.data, - entitySchema: this.dstSettings.entitySchema, - navigationState: groupedData.navigationState, - }; - } finally { - isBusy.endBusy(); - } + this.dataSource.viewConfig.set(this.viewConfig); } public async menuOpened(policy: AttestationPolicy): Promise { @@ -196,76 +158,66 @@ export class PolicyListComponent implements OnInit { } } - public async editPolicy(policy: PortalAttestationPolicy): Promise { - let data: ExtendedTypedEntityCollection; - - let overlayRef: OverlayRef; - setTimeout(() => (overlayRef = this.elementalBusyService.show())); - try { - data = await this.policyService.getPolicyEditInteractive(policy.GetEntity().GetKeys()[0]); - } finally { - setTimeout(() => this.elementalBusyService.hide(overlayRef)); - if (data && data.Data.length > 0) { - await this.showPolicy( - data.Data[0], - data.extendedData[0], - await this.translator.get('#LDS#Heading Edit Attestation Policy').toPromise(), - false - ); - } + public async editPolicy(policy: AttestationPolicy): Promise { + this.elementalBusyService.show(); + let data: ExtendedTypedEntityCollection = await this.policyService.getPolicyEditInteractive( + policy.GetEntity().GetKeys()[0], + ); + this.elementalBusyService.hide(); + if (data && data.Data.length > 0) { + await this.showPolicy( + data.Data[0], + data.extendedData?.[0], + await this.translator.get('#LDS#Heading Edit Attestation Policy').toPromise(), + false, + ); } } public async newPolicy(): Promise { - let policy: PolicyCopyData; - let overlayRef: OverlayRef; - setTimeout(() => (overlayRef = this.elementalBusyService.show())); - try { - policy = await this.policyService.buildNewEntity(); - this.logger.trace(this, 'new policy created', policy); - } finally { - setTimeout(() => this.elementalBusyService.hide(overlayRef)); - if (policy) { - await this.showPolicy( - policy.data, - { - IsReadOnly: false, - Filter: { Elements: [], ConcatenationType: 'OR' }, - InfoDisplay: [], - }, - await this.translator.get('#LDS#Heading Create Attestation Policy').toPromise(), - true - ); - } + if (this.elementalBusyService.overlayRefs.length === 0) { + // Its possible we enter this function from another that has used the busy service, check if there is an overlay before showing + this.elementalBusyService.show(); + } + let policy: PolicyCopyData = await this.policyService.buildNewEntity(); + this.logger.trace(this, 'new policy created', policy); + this.elementalBusyService.hide(); + if (policy) { + await this.showPolicy( + policy.data, + { + IsReadOnly: false, + Filter: { Elements: [], ConcatenationType: 'OR' }, + InfoDisplay: [], + }, + await this.translator.get('#LDS#Heading Create Attestation Policy').toPromise(), + true, + ); } } public async copy(policy: PortalAttestationPolicy): Promise { let newPolicy: PolicyCopyData; let filter: PolicyFilterData; - let overlayRef: OverlayRef; - setTimeout(() => (overlayRef = this.elementalBusyService.show())); - try { - const data = await this.policyService.getPolicyEditInteractive(policy.GetEntity().GetKeys()[0]); + this.elementalBusyService.show(); + const data = await this.policyService.getPolicyEditInteractive(policy.GetEntity().GetKeys()[0]); - if (data == null || data.Data.length === 0) { - return this.newPolicy(); - } + if (!data || data.Data.length === 0) { + return this.newPolicy(); + } - newPolicy = await this.policyService.buildNewEntity(data.Data[0], data.extendedData[0]?.Filter); - filter = data.extendedData[0]; - this.logger.trace(this, 'copy for policy (old, new)', data, newPolicy); - } finally { - setTimeout(() => this.elementalBusyService.hide(overlayRef)); - if (newPolicy) { - await this.showPolicy( - newPolicy.data, - filter, - await this.translator.get('#LDS#Heading Copy Attestation Policy').toPromise(), - true, - newPolicy.pickCategorySkipped - ); - } + newPolicy = await this.policyService.buildNewEntity(data.Data[0], data.extendedData?.[0]?.Filter); + filter = data.extendedData?.[0] || { IsReadOnly: true }; + this.logger.trace(this, 'copy for policy (old, new)', data, newPolicy); + this.elementalBusyService.hide(); + if (newPolicy) { + await this.showPolicy( + newPolicy.data, + filter, + await this.translator.instant('#LDS#Heading Copy Attestation Policy'), + true, + newPolicy.pickCategorySkipped, + ); } } @@ -289,7 +241,7 @@ export class PolicyListComponent implements OnInit { key: '#LDS#The attestation policy "{0}" has been successfully deleted.', parameters: [policy.GetEntity().GetDisplay()], }; - this.navigate(); + this.dataSource.updateState(); this.snackbar.open(message, '#LDS#Close'); } } @@ -300,8 +252,7 @@ export class PolicyListComponent implements OnInit { public async run(policy: PortalAttestationPolicy): Promise { let data: AttestationCasesComponentParameter; - let overlayRef: OverlayRef; - setTimeout(() => (overlayRef = this.elementalBusyService.show())); + this.elementalBusyService.show(); try { const policyEdit = await this.policyService.getPolicyEditInteractive(policy.GetEntity().GetKeys()[0]); this.logger.trace(this, 'interactive policy loaded', policyEdit); @@ -321,7 +272,7 @@ export class PolicyListComponent implements OnInit { subtitle: policy.GetEntity().GetDisplay(), }; } finally { - setTimeout(() => this.elementalBusyService.hide(overlayRef)); + this.elementalBusyService.hide(); } if (data) { @@ -330,7 +281,7 @@ export class PolicyListComponent implements OnInit { title: await this.translator.get('#LDS#Heading Start Attestation').toPromise(), subTitle: policy.GetEntity().GetDisplay(), padding: '0px', - width: 'max(600px, 60%)', + width: calculateSidesheetWidth(), data, testId: 'policy-list-start-attestation-run-sidesheet', }) @@ -338,15 +289,14 @@ export class PolicyListComponent implements OnInit { .toPromise(); if (result) { - this.navigate(); + this.dataSource.updateState(); } } } public async showDetails(policy: PortalAttestationPolicy): Promise { - let singlePolicy: PortalAttestationPolicy; - let overlayRef: OverlayRef; - setTimeout(() => (overlayRef = this.elementalBusyService.show())); + let singlePolicy: PortalAttestationPolicy | undefined; + this.elementalBusyService.show(); try { const policies = await this.policyService.getPolicies({ filter: [ @@ -360,14 +310,14 @@ export class PolicyListComponent implements OnInit { }); singlePolicy = policies.Data.length > 0 ? policies.Data[0] : undefined; } finally { - setTimeout(() => this.elementalBusyService.hide(overlayRef)); + this.elementalBusyService.hide(); } if (singlePolicy) { this.sideSheet.open(PolicyDetailsComponent, { title: await this.translator.get('#LDS#Heading View Attestation Runs').toPromise(), subTitle: singlePolicy.GetEntity().GetDisplay(), padding: '0px', - width: 'max(600px, 60%)', + width: calculateSidesheetWidth(), data: { policy: singlePolicy }, testId: 'policy-list-view-details-sidesheet', }); @@ -375,27 +325,21 @@ export class PolicyListComponent implements OnInit { } private async navigate(): Promise { - const isBusy = this.busyService.beginBusy(); - - try { - const policies = await this.policyService.getPolicies(this.navigationState); - const exportMethod = this.policyService.exportPolicies(this.navigationState); - this.logger.trace(this, 'interactive policy loaded', policies); - - this.dstSettings = { - displayedColumns: this.displayedColumns, - dataSource: policies, - filters: this.filterOptions, - groupData: this.groupData, - entitySchema: this.entitySchemaPolicy, - navigationState: this.navigationState, - dataModel: this.dataModel, - viewConfig: this.viewConfig, - exportMethod, - }; - } finally { - isBusy.endBusy(); - } + const dataViewInitParameters: DataViewInitParameters = { + execute: (params: CollectionLoadParameters, signal: AbortSignal): Promise> => + this.policyService.getPolicies(params, signal), + schema: this.entitySchemaPolicy, + columnsToDisplay: this.displayedColumns, + dataModel: this.dataModel, + groupExecute: (column: string, params: CollectionLoadParameters, signal: AbortSignal) => + this.policyService.getGroupInfo({ ...params, by: column }), + exportFunction: this.policyService.exportPolicies(this.dataSource.state()), + viewConfig: this.viewConfig, + highlightEntity: (policy: AttestationPolicy) => { + this.editPolicy(policy); + }, + }; + this.dataSource.init(dataViewInitParameters); } private async showPolicy( @@ -403,16 +347,16 @@ export class PolicyListComponent implements OnInit { filterData: PolicyFilterData, display: string, isNew: boolean, - showSampleDataWarning: boolean = false + showSampleDataWarning: boolean = false, ): Promise { const sidesheetRef = this.sideSheet.open(EditMasterDataComponent, { title: display, subTitle: isNew ? '' : policy.GetEntity().GetDisplay(), padding: '0px', - width: 'max(600px, 80%)', + width: calculateSidesheetWidth(1000), disableClose: true, data: { policy, filterData, isNew, isComplienceFrameworkEnabled: this.isComplienceFrameworkEnabled, showSampleDataWarning }, - testId: 'policy-list-show-policy-sidesheet' + testId: 'policy-list-show-policy-sidesheet', }); const shouldReload = await sidesheetRef.afterClosed().toPromise(); @@ -424,29 +368,30 @@ export class PolicyListComponent implements OnInit { private async initFilterAndGrouping(): Promise { this.viewConfig = await this.viewConfigService.getInitialDSTExtension(this.dataModel, this.viewConfigPath); const defaultSet = this.viewConfigService.isDefaultConfigSet(); - this.filterOptions = this.dataModel.Filters; + this.filterOptions = this.dataModel.Filters || []; // set initial value for OnlyActivePolicies const indexActive = this.filterOptions.findIndex((elem) => elem.Name === 'OnlyActivePolicies'); if (indexActive > -1 && !defaultSet) { this.filterOptions[indexActive].InitialValue = '1'; - this.navigationState.OnlyActivePolicies = '1'; + this.filterOptions.map((filter) => { + if (filter.Name === 'OnlyActivePolicies') { + filter.CurrentValue = '1'; + } + }); + this.dataSource.state.update((state) => ({ ...state, OnlyActivePolicies: '1' })); + this.dataSource.predefinedFilters.set(this.filterOptions); } // remove filter myPolicies, if you are an owner only and not an attestation admin if (this.prefilterOwner && !defaultSet) { - this.navigationState.mypolicies = '1'; - const index = this.filterOptions.findIndex((elem) => elem.Name === 'mypolicies'); - if (index > -1) { - this.filterOptions.splice(index, 1); - } + this.filterOptions.map((filter) => { + if (filter.Name === 'mypolicies') { + filter.CurrentValue = '1'; + } + }); + this.dataSource.state.update((state) => ({ ...state, mypolicies: '1' })); + this.dataSource.predefinedFilters.set(this.filterOptions); } - - this.groupData = createGroupData(this.dataModel, (parameters) => - this.policyService.getGroupInfo({ - ...{ PageSize: this.navigationState.PageSize, StartIndex: 0 }, - ...parameters, - }) - ); } } diff --git a/imxweb/projects/att/src/lib/policies/policy-list/policy-load-parameters.interface.ts b/imxweb/projects/att/src/lib/policies/policy-list/policy-load-parameters.interface.ts index 790797bff..8748e5a20 100644 --- a/imxweb/projects/att/src/lib/policies/policy-list/policy-load-parameters.interface.ts +++ b/imxweb/projects/att/src/lib/policies/policy-list/policy-load-parameters.interface.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -24,7 +24,7 @@ * */ -import { CollectionLoadParameters } from 'imx-qbm-dbts'; +import { CollectionLoadParameters } from '@imx-modules/imx-qbm-dbts'; export interface PolicyLoadParameters extends CollectionLoadParameters { OnlyActivePolicies?: string; diff --git a/imxweb/projects/att/src/lib/policies/policy.interface.ts b/imxweb/projects/att/src/lib/policies/policy.interface.ts index 75965de61..610b95b4b 100644 --- a/imxweb/projects/att/src/lib/policies/policy.interface.ts +++ b/imxweb/projects/att/src/lib/policies/policy.interface.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -24,7 +24,7 @@ * */ -import { PolicyFilterData, PortalAttestationPolicyEdit } from 'imx-api-att'; +import { PolicyFilterData, PortalAttestationPolicyEdit } from '@imx-modules/imx-api-att'; export interface Policy { policy: PortalAttestationPolicyEdit; filterData: PolicyFilterData; diff --git a/imxweb/projects/att/src/lib/policies/policy.module.ts b/imxweb/projects/att/src/lib/policies/policy.module.ts index 877695653..e9ccfbcb9 100644 --- a/imxweb/projects/att/src/lib/policies/policy.module.ts +++ b/imxweb/projects/att/src/lib/policies/policy.module.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -24,95 +24,100 @@ * */ -import { NgModule } from '@angular/core'; import { CommonModule } from '@angular/common'; +import { NgModule } from '@angular/core'; import { FormsModule, ReactiveFormsModule } from '@angular/forms'; -import { MatInputModule } from '@angular/material/input'; import { MatButtonModule } from '@angular/material/button'; -import { MatRadioModule } from '@angular/material/radio'; +import { MatCheckboxModule } from '@angular/material/checkbox'; import { MatDialogModule } from '@angular/material/dialog'; import { MatExpansionModule } from '@angular/material/expansion'; -import { MatCheckboxModule } from '@angular/material/checkbox'; +import { MatInputModule } from '@angular/material/input'; import { MatMenuModule } from '@angular/material/menu'; +import { MatProgressSpinnerModule } from '@angular/material/progress-spinner'; +import { MatRadioModule } from '@angular/material/radio'; import { MatSlideToggleModule } from '@angular/material/slide-toggle'; +import { MatTooltipModule } from '@angular/material/tooltip'; import { EuiCoreModule, EuiMaterialModule } from '@elemental-ui/core'; import { TranslateModule } from '@ngx-translate/core'; -import { MatTooltipModule } from '@angular/material/tooltip'; -import { MatProgressSpinnerModule } from '@angular/material/progress-spinner'; -import { LdsReplaceModule, DataSourceToolbarModule, DataTableModule, CdrModule, ClassloggerModule, HelpContextualModule, DataTreeWrapperModule } from 'qbm'; -import { UserModule, StatisticsModule } from 'qer'; -import { EditNameComponent } from './editors/edit-name.component'; +import { + CdrModule, + ClassloggerModule, + DataSourceToolbarModule, + DataTableModule, + DataTreeWrapperModule, + DataViewModule, + DateModule, + HelpContextualModule, + LdsReplaceModule, +} from 'qbm'; +import { StatisticsModule, UserModule } from 'qer'; +import { AttestationRunsModule } from '../runs/attestation-runs.module'; +import { AttestationCasesComponent } from './attestation-cases/attestation-cases.component'; +import { ConfirmDeactivationComponent } from './confirm-deactivation/confirm-deactivation.component'; +import { EditMasterDataComponent } from './edit-master-data/edit-master-data.component'; import { EditGenericComponent } from './editors/edit-generic.component'; +import { EditNameComponent } from './editors/edit-name.component'; import { EditOriginComponent } from './editors/edit-origin.component'; import { EditThresholdComponent } from './editors/edit-threshold.component'; import { EditUintComponent } from './editors/edit-uint.component'; -import { EditMasterDataComponent } from './edit-master-data/edit-master-data.component'; -import { PolicyService } from './policy.service'; -import { AttestationCasesComponent } from './attestation-cases/attestation-cases.component'; import { FilterEditorComponent } from './editors/filter-editor.component'; -import { ConfirmDeactivationComponent } from './confirm-deactivation/confirm-deactivation.component'; -import { PolicyFilterElementComponent } from './policy-filter-element/policy-filter-element.component'; +import { PolicyDetailsComponent } from './policy-details/policy-details.component'; import { PolicyEditorComponent } from './policy-editor/policy-editor.component'; +import { PolicyFilterElementComponent } from './policy-filter-element/policy-filter-element.component'; import { PolicyListComponent } from './policy-list/policy-list.component'; +import { PolicyService } from './policy.service'; import { SelectedObjectsComponent } from './selected-objects/selected-objects.component'; -import { PolicyDetailsComponent } from './policy-details/policy-details.component'; -import { AttestationRunsModule } from '../runs/attestation-runs.module'; - @NgModule({ - imports: [ - CdrModule, - CommonModule, - DataSourceToolbarModule, - DataTableModule, - EuiCoreModule, - EuiMaterialModule, - FormsModule, - LdsReplaceModule, - MatExpansionModule, - MatTooltipModule, - MatInputModule, - MatButtonModule, - MatDialogModule, - MatRadioModule, - MatProgressSpinnerModule, - MatCheckboxModule, - MatSlideToggleModule, - MatMenuModule, - ReactiveFormsModule, - TranslateModule, - UserModule, - ClassloggerModule, - AttestationRunsModule, - LdsReplaceModule, - StatisticsModule, - HelpContextualModule, - DataTreeWrapperModule, - ], - declarations: [ - EditGenericComponent, - EditNameComponent, - EditOriginComponent, - EditMasterDataComponent, - EditThresholdComponent, - EditUintComponent, - PolicyEditorComponent, - PolicyListComponent, - SelectedObjectsComponent, - AttestationCasesComponent, - FilterEditorComponent, - ConfirmDeactivationComponent, - PolicyFilterElementComponent, - PolicyDetailsComponent - ], - providers: [ - PolicyService - ], - exports: [ - PolicyListComponent, - EditMasterDataComponent, - AttestationCasesComponent - ] + imports: [ + CdrModule, + CommonModule, + DataSourceToolbarModule, + DataTableModule, + EuiCoreModule, + EuiMaterialModule, + FormsModule, + LdsReplaceModule, + MatExpansionModule, + MatTooltipModule, + MatInputModule, + MatButtonModule, + MatDialogModule, + MatRadioModule, + MatProgressSpinnerModule, + MatCheckboxModule, + MatSlideToggleModule, + MatMenuModule, + ReactiveFormsModule, + TranslateModule, + UserModule, + ClassloggerModule, + AttestationRunsModule, + LdsReplaceModule, + StatisticsModule, + HelpContextualModule, + DataTreeWrapperModule, + DataViewModule, + DateModule, + ], + declarations: [ + EditGenericComponent, + EditNameComponent, + EditOriginComponent, + EditMasterDataComponent, + EditThresholdComponent, + EditUintComponent, + PolicyEditorComponent, + PolicyListComponent, + SelectedObjectsComponent, + AttestationCasesComponent, + FilterEditorComponent, + ConfirmDeactivationComponent, + PolicyFilterElementComponent, + PolicyDetailsComponent, + ], + providers: [PolicyService], + exports: [PolicyListComponent, EditMasterDataComponent, AttestationCasesComponent], }) -export class PolicyModule { } +export class PolicyModule {} diff --git a/imxweb/projects/att/src/lib/policies/policy.service.ts b/imxweb/projects/att/src/lib/policies/policy.service.ts index e6a3e8118..94a6f9720 100644 --- a/imxweb/projects/att/src/lib/policies/policy.service.ts +++ b/imxweb/projects/att/src/lib/policies/policy.service.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -29,14 +29,14 @@ import { EuiDownloadOptions } from '@elemental-ui/core'; import { TranslateService } from '@ngx-translate/core'; import { - V2ApiClientMethodFactory, ParmData, PolicyFilter, PolicyStartInput, PortalAttestationFilterMatchingobjects, PortalAttestationPolicyEdit, PortalAttestationPolicyEditInteractive, -} from 'imx-api-att'; + V2ApiClientMethodFactory, +} from '@imx-modules/imx-api-att'; import { CollectionLoadParameters, CompareOperator, @@ -50,7 +50,7 @@ import { MethodDefinition, MethodDescriptor, TypedEntityBuilder, -} from 'imx-qbm-dbts'; +} from '@imx-modules/imx-qbm-dbts'; import { AppConfigService, ClassloggerService, DataSourceToolbarExportMethod, ElementalUiConfigService } from 'qbm'; import { ApiService } from '../api.service'; import { AttestationPolicy } from './policy-list/attestation-policy'; @@ -68,7 +68,7 @@ export class PolicyService { private readonly elementalUiConfigService: ElementalUiConfigService, private readonly translator: TranslateService, private readonly config: AppConfigService, - private readonly logger: ClassloggerService + private readonly logger: ClassloggerService, ) {} public get AttestationMatchingObjectsSchema(): EntitySchema { @@ -83,8 +83,11 @@ export class PolicyService { return this.api.typedClient.PortalAttestationPolicyEditInteractive.GetSchema(); } - public async getPolicies(parameters: PolicyLoadParameters): Promise> { - const collection = await this.api.typedClient.PortalAttestationPolicy.Get(parameters); + public async getPolicies( + parameters: PolicyLoadParameters, + signal?: AbortSignal, + ): Promise> { + const collection = await this.api.typedClient.PortalAttestationPolicy.Get(parameters, { signal }); return { tableName: collection.tableName, totalCount: collection.totalCount, @@ -121,7 +124,7 @@ export class PolicyService { } public async getParmData(uidAttestationObject: string): Promise { - return uidAttestationObject ? (await this.api.client.portal_attestation_filter_model_get(uidAttestationObject)).ParmData : []; + return uidAttestationObject ? (await this.api.client.portal_attestation_filter_model_get(uidAttestationObject)).ParmData || [] : []; } public async getFilterCandidates(parameters: CollectionLoadParameters, uidAttestationParm: string): Promise { @@ -136,13 +139,13 @@ export class PolicyService { uidAttestatation: string, uidPickCategory: string, policyfilter: PolicyFilter, - parameters: CollectionLoadParameters + parameters: CollectionLoadParameters, ): Promise> { const data = await this.getObjectsForFilterUntyped(uidAttestatation, uidPickCategory, policyfilter, parameters); return new TypedEntityBuilder(PortalAttestationFilterMatchingobjects).buildReadWriteEntities( data, - PortalAttestationFilterMatchingobjects.GetEntitySchema() + PortalAttestationFilterMatchingobjects.GetEntitySchema(), ); } @@ -150,7 +153,7 @@ export class PolicyService { uidAttestatation: string, uidPickCategory: string, policyfilter: PolicyFilter, - parameters: CollectionLoadParameters + parameters: CollectionLoadParameters, ): Promise { return this.api.client.portal_attestation_filter_matchingobjects_get(uidAttestatation, { uidpickcategory: uidPickCategory, @@ -240,7 +243,7 @@ export class PolicyService { private async copyPropertiesFrom( entity: PortalAttestationPolicyEdit, reference: PortalAttestationPolicyEdit, - filter: PolicyFilter + filter?: PolicyFilter, ): Promise { let uidPickCategorySkipped = false; for (const key in this.api.typedClient.PortalAttestationPolicyEditInteractive.GetSchema().Columns) { diff --git a/imxweb/projects/att/src/lib/policies/selected-objects/selected-objects-info.interface.ts b/imxweb/projects/att/src/lib/policies/selected-objects/selected-objects-info.interface.ts index edd99bf5e..169967b75 100644 --- a/imxweb/projects/att/src/lib/policies/selected-objects/selected-objects-info.interface.ts +++ b/imxweb/projects/att/src/lib/policies/selected-objects/selected-objects-info.interface.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -24,10 +24,10 @@ * */ -import { PolicyFilter } from 'imx-api-att'; +import { PolicyFilter } from '@imx-modules/imx-api-att'; export interface SelectecObjectsInfo { - policyFilter: PolicyFilter; - uidAttestationObject: string; - uidPickCategory: string; + policyFilter: PolicyFilter; + uidAttestationObject: string; + uidPickCategory: string; } diff --git a/imxweb/projects/att/src/lib/policies/selected-objects/selected-objects.component.html b/imxweb/projects/att/src/lib/policies/selected-objects/selected-objects.component.html index 2bb9cadf4..cb554dfa7 100644 --- a/imxweb/projects/att/src/lib/policies/selected-objects/selected-objects.component.html +++ b/imxweb/projects/att/src/lib/policies/selected-objects/selected-objects.component.html @@ -1,11 +1,16 @@ - - \ No newline at end of file +
    + (0) +
    diff --git a/imxweb/projects/att/src/lib/policies/selected-objects/selected-objects.component.scss b/imxweb/projects/att/src/lib/policies/selected-objects/selected-objects.component.scss index e6c7e2987..7676d9d02 100644 --- a/imxweb/projects/att/src/lib/policies/selected-objects/selected-objects.component.scss +++ b/imxweb/projects/att/src/lib/policies/selected-objects/selected-objects.component.scss @@ -3,7 +3,7 @@ flex-direction: row; align-items: center; - .mat-button { + .mat-mdc-button { padding-left: 5px; padding-right: 5px; min-width: auto; @@ -13,15 +13,4 @@ .imx-larger-font { font-size: large; } - - .like-button { - padding-left: 5px; - padding-right: 5px; - min-width: auto; - margin-left: 5px; - } } - - - - \ No newline at end of file diff --git a/imxweb/projects/att/src/lib/policies/selected-objects/selected-objects.component.ts b/imxweb/projects/att/src/lib/policies/selected-objects/selected-objects.component.ts index a3507a608..31b2db934 100644 --- a/imxweb/projects/att/src/lib/policies/selected-objects/selected-objects.component.ts +++ b/imxweb/projects/att/src/lib/policies/selected-objects/selected-objects.component.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -28,20 +28,19 @@ import { Component, Input, OnDestroy, OnInit } from '@angular/core'; import { EuiSidesheetService } from '@elemental-ui/core'; import { BehaviorSubject } from 'rxjs'; -import { PolicyFilter } from 'imx-api-att'; -import { ClassloggerService } from 'qbm'; -import { SelectecObjectsInfo } from './selected-objects-info.interface'; -import { PolicyService } from '../policy.service'; +import { PolicyFilter } from '@imx-modules/imx-api-att'; +import { calculateSidesheetWidth, ClassloggerService } from 'qbm'; import { AttestationCasesComponentParameter } from '../attestation-cases/attestation-cases-component-parameter.interface'; import { AttestationCasesComponent } from '../attestation-cases/attestation-cases.component'; +import { PolicyService } from '../policy.service'; +import { SelectecObjectsInfo } from './selected-objects-info.interface'; @Component({ templateUrl: './selected-objects.component.html', selector: 'imx-selected-objects', - styleUrls: ['./selected-objects.component.scss'] + styleUrls: ['./selected-objects.component.scss'], }) export class SelectedObjectsComponent implements OnInit, OnDestroy { - public filter: PolicyFilter; public uidAttestationObject: string; public uidPickCategory: string; @@ -51,12 +50,13 @@ export class SelectedObjectsComponent implements OnInit, OnDestroy { @Input() public popupSubtitle = ''; @Input() public isTotal: boolean; @Input() public testId = ''; - @Input() public filterSubject: BehaviorSubject; + @Input() public filterSubject: BehaviorSubject; constructor( private readonly sideSheet: EuiSidesheetService, private readonly policyService: PolicyService, - private readonly logger: ClassloggerService) { } + private readonly logger: ClassloggerService, + ) {} public ngOnInit(): void { if (this.filterSubject) { @@ -88,30 +88,29 @@ export class SelectedObjectsComponent implements OnInit, OnDestroy { subtitle: this.popupSubtitle, uidPickCategory: this.uidPickCategory, uidobject: this.uidAttestationObject, - filter: this.filter.Elements, - concat: this.filter ? this.filter.ConcatenationType : 'OR', - canCreateRuns: false + filter: this.filter.Elements || [], + concat: this.filter?.ConcatenationType ? this.filter.ConcatenationType : 'OR', + canCreateRuns: false, }; this.sideSheet.open(AttestationCasesComponent, { title: this.popupTitle, subTitle: this.popupSubtitle, padding: '0px', - width: 'max(600px, 60%)', + width: calculateSidesheetWidth(), testId: 'selected-objects-showmatching-sidesheet', data, }); } private async getMatchCount(filter: PolicyFilter): Promise { - if (filter.Elements.length === 0) { return -1; } - if (filter.Elements.findIndex(elem => elem.AttestationSubType == null || - elem.AttestationSubType === '') >= 0) { + if (filter.Elements?.length === 0) { + return -1; + } + if ((filter.Elements?.findIndex((elem) => elem.AttestationSubType == null || elem.AttestationSubType === '') || -1) >= 0) { return -1; } - return (await this.policyService.getObjectsForFilter(this.uidAttestationObject, - this.uidPickCategory, - filter, { PageSize: -1 })) + return (await this.policyService.getObjectsForFilter(this.uidAttestationObject, this.uidPickCategory, filter, { PageSize: -1 })) .totalCount; } } diff --git a/imxweb/projects/att/src/lib/policy-group/edit-policy-group-sidesheet/edit-policy-group-sidesheet.component.html b/imxweb/projects/att/src/lib/policy-group/edit-policy-group-sidesheet/edit-policy-group-sidesheet.component.html index fb1401fdb..d80ad1cf2 100644 --- a/imxweb/projects/att/src/lib/policy-group/edit-policy-group-sidesheet/edit-policy-group-sidesheet.component.html +++ b/imxweb/projects/att/src/lib/policy-group/edit-policy-group-sidesheet/edit-policy-group-sidesheet.component.html @@ -1,26 +1,32 @@
    -
    +
    -
    - +
    + -
    diff --git a/imxweb/projects/att/src/lib/policy-group/edit-policy-group-sidesheet/edit-policy-group-sidesheet.component.scss b/imxweb/projects/att/src/lib/policy-group/edit-policy-group-sidesheet/edit-policy-group-sidesheet.component.scss index 507ee4096..19a788d6c 100644 --- a/imxweb/projects/att/src/lib/policy-group/edit-policy-group-sidesheet/edit-policy-group-sidesheet.component.scss +++ b/imxweb/projects/att/src/lib/policy-group/edit-policy-group-sidesheet/edit-policy-group-sidesheet.component.scss @@ -4,17 +4,6 @@ h2 { margin-bottom: 10px; } -.imx-action { - display: flex; - justify-content: flex-end; +.eui-sidesheet-actions__padding { padding: 16px 32px; - - .justify-start { - margin-right: auto; - - eui-icon { - font-size: 14px; - margin-right: 4px; - } - } } diff --git a/imxweb/projects/att/src/lib/policy-group/edit-policy-group-sidesheet/edit-policy-group-sidesheet.component.ts b/imxweb/projects/att/src/lib/policy-group/edit-policy-group-sidesheet/edit-policy-group-sidesheet.component.ts index e0df9ed30..5f0bb4674 100644 --- a/imxweb/projects/att/src/lib/policy-group/edit-policy-group-sidesheet/edit-policy-group-sidesheet.component.ts +++ b/imxweb/projects/att/src/lib/policy-group/edit-policy-group-sidesheet/edit-policy-group-sidesheet.component.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -25,22 +25,21 @@ */ import { Component, Inject, OnInit } from '@angular/core'; -import { UntypedFormArray, UntypedFormControl, UntypedFormGroup } from '@angular/forms'; -import { EuiSidesheetRef, EUI_SIDESHEET_DATA } from '@elemental-ui/core'; -import { EntitySchema } from 'imx-qbm-dbts'; +import { AbstractControl, UntypedFormArray, UntypedFormControl, UntypedFormGroup } from '@angular/forms'; +import { EUI_SIDESHEET_DATA, EuiSidesheetRef } from '@elemental-ui/core'; +import { EntitySchema } from '@imx-modules/imx-qbm-dbts'; import { BaseCdr, ClassloggerService, ColumnDependentReference, ConfirmationService, SnackBarService } from 'qbm'; import { Subscription } from 'rxjs'; +import { PolicyGroup } from '../policy-group.interface'; import { PolicyGroupService } from '../policy-group.service'; -import {PolicyGroup} from '../policy-group.interface'; @Component({ templateUrl: './edit-policy-group-sidesheet.component.html', - styleUrls: ['./edit-policy-group-sidesheet.component.scss'] + styleUrls: ['./edit-policy-group-sidesheet.component.scss'], }) export class EditPolicyGroupSidesheetComponent implements OnInit { - public readonly formGroup = new UntypedFormGroup({}); public readonly schema: EntitySchema; - public objectProperties:ColumnDependentReference[]=[] + public objectProperties: ColumnDependentReference[] = []; public formArray: UntypedFormArray; public reload = false; public hasAttestations: boolean; @@ -54,16 +53,15 @@ export class EditPolicyGroupSidesheetComponent implements OnInit { private readonly snackBar: SnackBarService, private readonly policyGroupService: PolicyGroupService, private readonly logger: ClassloggerService, - private readonly confirmationService: ConfirmationService + private readonly confirmationService: ConfirmationService, ) { this.initOrRefreshCdrDictionary(); this.formGroup = new UntypedFormGroup({ - formArray: new UntypedFormArray([]) + formArray: new UntypedFormArray([]), }); this.formArray = this.formGroup.get('formArray') as UntypedFormArray; this.closeSubscription = this.sidesheetRef.closeClicked().subscribe(async () => { - if (!this.formGroup.dirty - || await confirmationService.confirmLeaveWithUnsavedChanges()) { + if (!this.formGroup.dirty || (await confirmationService.confirmLeaveWithUnsavedChanges())) { this.sidesheetRef.close(this.reload); } }); @@ -100,7 +98,7 @@ export class EditPolicyGroupSidesheetComponent implements OnInit { this.policygroup.policyGroup.UID_AERoleOwner.Column, this.policygroup.policyGroup.UID_DialogSchedule.Column, this.policygroup.policyGroup.UID_PersonOwner.Column, - this.policygroup.policyGroup.UID_QERPickCategory.Column + this.policygroup.policyGroup.UID_QERPickCategory.Column, ]; for (const column of columns) { @@ -115,16 +113,16 @@ export class EditPolicyGroupSidesheetComponent implements OnInit { } } - public addControl(columnName: string, evt: UntypedFormControl): void { - setTimeout(() => - this.formGroup.addControl(columnName, evt) - ); + public addControl(columnName: string, evt: AbstractControl): void { + setTimeout(() => this.formGroup.addControl(columnName, evt)); } public async saveChanges(): Promise { if (this.formGroup.valid) { this.policyGroupService.handleOpenLoader(); - let confirmMessage = !this.policygroup.isNew ? '#LDS#The policy collection has been successfully saved.' :'#LDS#The policy collection has been successfully created.'; + let confirmMessage = !this.policygroup.isNew + ? '#LDS#The policy collection has been successfully saved.' + : '#LDS#The policy collection has been successfully created.'; try { this.policygroup.policyGroup.GetEntity().Commit(false); this.sidesheetRef.close(true); @@ -136,10 +134,12 @@ export class EditPolicyGroupSidesheetComponent implements OnInit { } public async delete(): Promise { - if (await this.confirmationService.confirm({ - Title: '#LDS#Heading Delete Policy Collection', - Message: '#LDS#Are you sure you want to delete the policy collection?' - })) { + if ( + await this.confirmationService.confirm({ + Title: '#LDS#Heading Delete Policy Collection', + Message: '#LDS#Are you sure you want to delete the policy collection?', + }) + ) { this.policyGroupService.handleOpenLoader(); try { const key = this.policygroup.policyGroup.GetEntity().GetKeys()[0]; @@ -151,5 +151,4 @@ export class EditPolicyGroupSidesheetComponent implements OnInit { this.sidesheetRef.close(); } } - } diff --git a/imxweb/projects/att/src/lib/policy-group/policy-group-list/policy-group-list.component.html b/imxweb/projects/att/src/lib/policy-group/policy-group-list/policy-group-list.component.html index b0961cf6a..e7c659a21 100644 --- a/imxweb/projects/att/src/lib/policy-group/policy-group-list/policy-group-list.component.html +++ b/imxweb/projects/att/src/lib/policy-group/policy-group-list/policy-group-list.component.html @@ -1,47 +1,52 @@ -

    - {{ '#LDS#Heading Policy Collections' | translate }} - -

    +
    +

    + {{ '#LDS#Heading Policy Collections' | translate }} + +

    + +
    - - - -
    - - - - - - -
    - -
    -
    -
    -
    - -
    + + + + + {{ entitySchemaPolicy?.Columns?.Ident_AttestationPolicyGroup?.Display }} + + +
    {{ item.Ident_AttestationPolicyGroup.Column.GetDisplayValue() }}
    + +
    + + + {{ entitySchemaPolicy?.Columns?.UID_PersonOwner?.Display }} + + +
    {{ item.UID_PersonOwner.Column.GetDisplayValue() }}
    + +
    + + + {{ entitySchemaPolicy?.Columns?.UID_QERPickCategory?.Display }} + + +
    {{ item.UID_QERPickCategory.Column.GetDisplayValue() }}
    + +
    + + + + + + +
    +
    -
    - - diff --git a/imxweb/projects/att/src/lib/policy-group/policy-group-list/policy-group-list.component.scss b/imxweb/projects/att/src/lib/policy-group/policy-group-list/policy-group-list.component.scss index 97f7f28d2..92cf4f37b 100644 --- a/imxweb/projects/att/src/lib/policy-group/policy-group-list/policy-group-list.component.scss +++ b/imxweb/projects/att/src/lib/policy-group/policy-group-list/policy-group-list.component.scss @@ -1,35 +1,5 @@ -@import '../../../../../../shared/scss/common-table.scss'; +@import 'base/mixins'; :host { - display: flex; - flex-direction: column; - overflow: hidden; + @include flex-column-container($overflow: hidden); height: inherit; - - .button-row { - @include imx-button-bar(); - } - - .imx-button-column { - @include imx-button-column-right(); - } - - .imx-margin-right { - margin-right: 10px; - } - - .imx-content-card { - flex: 1 1 auto; - display: flex; - flex-direction: column; - margin: 3px; - overflow: hidden; - } - - .imx-table-container { - display: flex; - flex-direction: column; - overflow: hidden; - height: inherit; - flex: 1 1 auto; - } } diff --git a/imxweb/projects/att/src/lib/policy-group/policy-group-list/policy-group-list.component.ts b/imxweb/projects/att/src/lib/policy-group/policy-group-list/policy-group-list.component.ts index 5bf6ae3cb..b0754aba4 100644 --- a/imxweb/projects/att/src/lib/policy-group/policy-group-list/policy-group-list.component.ts +++ b/imxweb/projects/att/src/lib/policy-group/policy-group-list/policy-group-list.component.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -25,63 +25,59 @@ */ import { Component } from '@angular/core'; -import{PolicyGroupService} from '../policy-group.service'; +import { EuiSidesheetService } from '@elemental-ui/core'; +import { PolicyFilterData, PortalAttestationPolicygroups } from '@imx-modules/imx-api-att'; +import { + CollectionLoadParameters, + DisplayColumns, + EntitySchema, + ExtendedTypedEntityCollection, + TypedEntityCollectionData, + ValType, +} from '@imx-modules/imx-qbm-dbts'; +import { TranslateService } from '@ngx-translate/core'; import { ClassloggerService, + ClientPropertyForTableColumns, ConfirmationService, - DataSourceToolbarFilter, - DataSourceToolbarGroupData, - DataSourceToolbarSettings, DataTableGroupedData, - ClientPropertyForTableColumns, - SettingsService, - SnackBarService, + DataViewInitParameters, + DataViewSource, + HELP_CONTEXTUAL, HelpContextualComponent, HelpContextualService, - HELP_CONTEXTUAL + SettingsService, + SnackBarService, + calculateSidesheetWidth, } from 'qbm'; -import { - CollectionLoadParameters, - DisplayColumns, - ValType, - ExtendedTypedEntityCollection, - EntitySchema, - DataModel -} from 'imx-qbm-dbts'; -import { PolicyFilterData, PortalAttestationPolicygroups } from 'imx-api-att'; -import { EuiSidesheetService } from '@elemental-ui/core'; import { EditPolicyGroupSidesheetComponent } from '../edit-policy-group-sidesheet/edit-policy-group-sidesheet.component'; -import { TranslateService } from '@ngx-translate/core'; +import { PolicyGroupService } from '../policy-group.service'; @Component({ selector: 'imx-policy-group-list', templateUrl: './policy-group-list.component.html', - styleUrls: ['./policy-group-list.component.scss'] + styleUrls: ['./policy-group-list.component.scss'], + providers: [DataViewSource], }) - export class PolicyGroupListComponent { - - - public dstSettings: DataSourceToolbarSettings; public readonly entitySchemaPolicy: EntitySchema; public readonly DisplayColumns = DisplayColumns; public groupedData: { [key: string]: DataTableGroupedData } = {}; public navigationState: CollectionLoadParameters; - public isComplienceFrameworkEnabled = false; private groupData: DataSourceToolbarGroupData; - - private filterOptions: DataSourceToolbarFilter[] = []; + public isComplienceFrameworkEnabled = false; private readonly displayedColumns: ClientPropertyForTableColumns[]; - private dataModel: DataModel; - constructor( private readonly policyGroupService:PolicyGroupService , + constructor( + private readonly policyGroupService: PolicyGroupService, private readonly logger: ClassloggerService, private readonly settingsService: SettingsService, private readonly confirmationService: ConfirmationService, private readonly snackbar: SnackBarService, private readonly sideSheet: EuiSidesheetService, private readonly translator: TranslateService, - private readonly helpContextualService: HelpContextualService - ) { + private readonly helpContextualService: HelpContextualService, + public dataSource: DataViewSource, + ) { this.navigationState = { PageSize: this.settingsService.DefaultPageSize, StartIndex: 0 }; this.entitySchemaPolicy = policyGroupService.AttestationPolicyGroupSchema; this.displayedColumns = [ @@ -92,75 +88,36 @@ export class PolicyGroupListComponent { ColumnName: 'actions', Type: ValType.String, afterAdditionals: true, - untranslatedDisplay: '#LDS#Actions' - } + untranslatedDisplay: '#LDS#Actions', + }, ]; - } + } public async ngOnInit(): Promise { await this.navigate(); } private async navigate(): Promise { - this.policyGroupService.handleOpenLoader(); - try { - const policies = await this.policyGroupService.get(this.navigationState); - this.logger.trace(this, 'interactive policy loaded', policies); - - this.dstSettings = { - displayedColumns: this.displayedColumns, - dataSource: policies, - filters: this.filterOptions, - groupData: this.groupData, - entitySchema: this.entitySchemaPolicy, - navigationState: this.navigationState, - dataModel: this.dataModel - }; - } finally { - this.policyGroupService.handleCloseLoader(); - } - } - public async onSearch(keywords: string): Promise { - this.navigationState = { - ...this.navigationState, - ...{ - StartIndex: 0, - search: keywords, - } + const dataViewInitParameters: DataViewInitParameters = { + execute: (params: CollectionLoadParameters): Promise> => + this.policyGroupService.get(params), + schema: this.entitySchemaPolicy, + columnsToDisplay: this.displayedColumns, + highlightEntity: (policyGroup: PortalAttestationPolicygroups) => { + this.editPolicy(policyGroup); + }, }; - this.logger.trace(this, 'navigation state change to ', this.navigationState); - return this.navigate(); - } - - public async onNavigationStateChanged(newState: CollectionLoadParameters): Promise { - this.navigationState = newState; - this.logger.trace(this, 'navigation state change to ', this.navigationState); - await this.navigate(); - } - - public async onGroupingChange(groupKey: string): Promise { - this.policyGroupService.handleOpenLoader(); - try { - const groupedData = this.groupedData[groupKey]; - groupedData.data = await this.policyGroupService.get(groupedData.navigationState); - groupedData.settings = { - displayedColumns: this.dstSettings.displayedColumns, - dataModel: this.dstSettings.dataModel, - dataSource: groupedData.data, - entitySchema: this.dstSettings.entitySchema, - navigationState: groupedData.navigationState - }; - } finally { - this.policyGroupService.handleCloseLoader(); - } + this.dataSource.init(dataViewInitParameters); } public async delete(policyGroup: PortalAttestationPolicygroups, event: any): Promise { event.stopPropagation(); - if (await this.confirmationService.confirm({ - Title: '#LDS#Heading Delete Policy Collection', - Message: '#LDS#Are you sure you want to delete the policy collection?' - })) { + if ( + await this.confirmationService.confirm({ + Title: '#LDS#Heading Delete Policy Collection', + Message: '#LDS#Are you sure you want to delete the policy collection?', + }) + ) { this.policyGroupService.handleOpenLoader(); try { const key = policyGroup.GetEntity().GetKeys()[0]; @@ -172,26 +129,27 @@ export class PolicyGroupListComponent { const message = { key: '#LDS#The policy collection has been successfully deleted.', }; - this.navigate(); + this.dataSource.updateState(); this.snackbar.open(message, '#LDS#Close'); } } - public async editPolicy(policyGroup: PortalAttestationPolicygroups){ - let data: ExtendedTypedEntityCollection; + public async editPolicy(policyGroup: PortalAttestationPolicygroups) { + let data: ExtendedTypedEntityCollection; this.policyGroupService.handleOpenLoader(); try { data = await this.policyGroupService.getPolicyGroupEdit(policyGroup.GetEntity().GetKeys()[0]); - } finally { - this.policyGroupService.handleCloseLoader(); if (data && data.Data.length > 0) { await this.showPolicy( data.Data[0], - data.extendedData? data.extendedData[0]: undefined, + data.extendedData ? data.extendedData[0] : undefined, await this.translator.get('#LDS#Heading Edit Policy Collection').toPromise(), false, - policyGroup.GetEntity().GetDisplay()); + policyGroup.GetEntity().GetDisplay(), + ); } + } finally { + this.policyGroupService.handleCloseLoader(); } } @@ -200,39 +158,48 @@ export class PolicyGroupListComponent { filterData: PolicyFilterData, display: string, isNew: boolean, - subtitle: string + subtitle: string, ): Promise { - this.helpContextualService.setHelpContextId(isNew? HELP_CONTEXTUAL.AttestationPolicyCollectionsCreate : HELP_CONTEXTUAL.AttestationPolicyCollectionsEdit); + this.helpContextualService.setHelpContextId( + isNew ? HELP_CONTEXTUAL.AttestationPolicyCollectionsCreate : HELP_CONTEXTUAL.AttestationPolicyCollectionsEdit, + ); const sidesheetRef = this.sideSheet.open(EditPolicyGroupSidesheetComponent, { title: display, subTitle: subtitle, padding: '0px', - width: 'max(600px, 60%)', + width: calculateSidesheetWidth(), disableClose: true, data: { policyGroup, filterData, isNew, isComplienceFrameworkEnabled: this.isComplienceFrameworkEnabled }, testId: 'policy-group-list-show-policy-sidesheet', - headerComponent: HelpContextualComponent + headerComponent: HelpContextualComponent, }); const shouldReload = await sidesheetRef.afterClosed().toPromise(); - if (shouldReload) { this.navigate(); } + if (shouldReload) { + this.dataSource.updateState(); + } } public async newPolicyGroup(): Promise { - let policyGroup: PortalAttestationPolicygroups; + let policyGroup: PortalAttestationPolicygroups | undefined; this.policyGroupService.handleOpenLoader(); try { - policyGroup = await this.policyGroupService.buildNewEntity(); + policyGroup = await this.policyGroupService.buildNewEntity(); this.logger.trace(this, 'new policy group created', policyGroup); } finally { this.policyGroupService.handleCloseLoader(); if (policyGroup) { - await this.showPolicy(policyGroup, { - IsReadOnly: false, - Filter: { Elements: [], ConcatenationType: 'OR' }, - InfoDisplay: [] - }, - await this.translator.get('#LDS#Heading Create Policy Collection').toPromise(), true,""); + await this.showPolicy( + policyGroup, + { + IsReadOnly: false, + Filter: { Elements: [], ConcatenationType: 'OR' }, + InfoDisplay: [], + }, + await this.translator.get('#LDS#Heading Create Policy Collection').toPromise(), + true, + '', + ); } } } diff --git a/imxweb/projects/att/src/lib/policy-group/policy-group.interface.ts b/imxweb/projects/att/src/lib/policy-group/policy-group.interface.ts index 4aa01ee5e..1f99d02c3 100644 --- a/imxweb/projects/att/src/lib/policy-group/policy-group.interface.ts +++ b/imxweb/projects/att/src/lib/policy-group/policy-group.interface.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -24,10 +24,10 @@ * */ -import { PolicyFilterData, PortalAttestationPolicygroups } from 'imx-api-att'; +import { PolicyFilterData, PortalAttestationPolicygroups } from '@imx-modules/imx-api-att'; export interface PolicyGroup { policyGroup: PortalAttestationPolicygroups; filterData: PolicyFilterData; - isNew?: boolean; + isNew: boolean; isComplienceFrameworkEnabled: boolean; } diff --git a/imxweb/projects/att/src/lib/policy-group/policy-group.module.ts b/imxweb/projects/att/src/lib/policy-group/policy-group.module.ts index 926b6fca1..eafd3bf6e 100644 --- a/imxweb/projects/att/src/lib/policy-group/policy-group.module.ts +++ b/imxweb/projects/att/src/lib/policy-group/policy-group.module.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -24,27 +24,34 @@ * */ -import { NgModule } from '@angular/core'; import { CommonModule } from '@angular/common'; -import { LdsReplaceModule, DataSourceToolbarModule, DataTableModule, CdrModule, ClassloggerModule, HelpContextualModule } from 'qbm'; -import { PolicyGroupListComponent } from './policy-group-list/policy-group-list.component'; +import { NgModule } from '@angular/core'; import { FormsModule, ReactiveFormsModule } from '@angular/forms'; -import { MatInputModule } from '@angular/material/input'; import { MatButtonModule } from '@angular/material/button'; -import { MatRadioModule } from '@angular/material/radio'; +import { MatCheckboxModule } from '@angular/material/checkbox'; import { MatDialogModule } from '@angular/material/dialog'; import { MatExpansionModule } from '@angular/material/expansion'; -import { MatCheckboxModule } from '@angular/material/checkbox'; +import { MatInputModule } from '@angular/material/input'; import { MatMenuModule } from '@angular/material/menu'; +import { MatRadioModule } from '@angular/material/radio'; import { MatSlideToggleModule } from '@angular/material/slide-toggle'; +import { MatTooltipModule } from '@angular/material/tooltip'; import { EuiCoreModule, EuiMaterialModule } from '@elemental-ui/core'; import { TranslateModule } from '@ngx-translate/core'; -import { MatTooltipModule } from '@angular/material/tooltip'; +import { + CdrModule, + ClassloggerModule, + DataSourceToolbarModule, + DataTableModule, + DataViewModule, + HelpContextualModule, + LdsReplaceModule, +} from 'qbm'; +import { PolicyGroupListComponent } from './policy-group-list/policy-group-list.component'; import { UserModule } from 'qer'; -import { PolicyGroupService } from './policy-group.service'; import { EditPolicyGroupSidesheetComponent } from './edit-policy-group-sidesheet/edit-policy-group-sidesheet.component'; - +import { PolicyGroupService } from './policy-group.service'; @NgModule({ imports: [ @@ -70,17 +77,10 @@ import { EditPolicyGroupSidesheetComponent } from './edit-policy-group-sidesheet UserModule, ClassloggerModule, HelpContextualModule, + DataViewModule, ], - declarations: [ - PolicyGroupListComponent, - EditPolicyGroupSidesheetComponent, - ], - providers: [ - PolicyGroupService - ], - exports: [ - PolicyGroupListComponent, - EditPolicyGroupSidesheetComponent, - ] + declarations: [PolicyGroupListComponent, EditPolicyGroupSidesheetComponent], + providers: [PolicyGroupService], + exports: [PolicyGroupListComponent, EditPolicyGroupSidesheetComponent], }) -export class PolicyGroupModule { } +export class PolicyGroupModule {} diff --git a/imxweb/projects/att/src/lib/policy-group/policy-group.service.ts b/imxweb/projects/att/src/lib/policy-group/policy-group.service.ts index 9251d81cd..ad2c2ef80 100644 --- a/imxweb/projects/att/src/lib/policy-group/policy-group.service.ts +++ b/imxweb/projects/att/src/lib/policy-group/policy-group.service.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -25,112 +25,88 @@ */ import { Injectable } from '@angular/core'; -import { - CollectionLoadParameters, - CompareOperator, - DataModel, - EntityCollectionData, - EntitySchema, - ExtendedEntityCollectionData, - ExtendedTypedEntityCollection, - FilterType, - GroupInfo, - MethodDefinition, -} from 'imx-qbm-dbts'; -import { - PortalAttestationPolicygroups, - PolicyFilter -} from 'imx-api-att'; -import { ApiService } from '../api.service'; import { EuiLoadingService } from '@elemental-ui/core'; -import { OverlayRef } from '@angular/cdk/overlay'; +import { PolicyFilter, PortalAttestationPolicygroups } from '@imx-modules/imx-api-att'; +import { CollectionLoadParameters, EntityCollectionData, EntitySchema, ExtendedTypedEntityCollection } from '@imx-modules/imx-qbm-dbts'; import { TranslateService } from '@ngx-translate/core'; import { AppConfigService, ClassloggerService } from 'qbm'; +import { ApiService } from '../api.service'; @Injectable({ - providedIn: 'root' + providedIn: 'root', }) export class PolicyGroupService { - private busyIndicator: OverlayRef; constructor( private api: ApiService, - private busyService: EuiLoadingService, + private busyService: EuiLoadingService, private readonly translator: TranslateService, private readonly config: AppConfigService, - private readonly logger: ClassloggerService - ) { } + private readonly logger: ClassloggerService, + ) {} public get AttestationPolicyGroupSchema(): EntitySchema { return this.api.typedClient.PortalAttestationPolicygroups.GetSchema(); } - public async get(parameters: CollectionLoadParameters): Promise> { return this.api.typedClient.PortalAttestationPolicygroups.Get(parameters); } - - public async deleteAttestationPolicyGroup(uidAttestationpolicygroup: string): Promise { + public async deleteAttestationPolicyGroup(uidAttestationpolicygroup: string): Promise { return this.api.client.portal_attestation_policygroups_delete(uidAttestationpolicygroup); } - public async getPolicyGroupEdit(uid: string): - Promise> { + public async getPolicyGroupEdit(uid: string): Promise> { return this.api.typedClient.PortalAttestationPolicygroupsInteractive.Get_byid(uid); } - public async buildNewEntity(reference?: PortalAttestationPolicygroups, filter?: PolicyFilter): - Promise { - const entities = await this.api.typedClient.PortalAttestationPolicygroupsInteractive.Get(); - if (reference == null) { + public async buildNewEntity(reference?: PortalAttestationPolicygroups, filter?: PolicyFilter): Promise { + const entities = await this.api.typedClient.PortalAttestationPolicygroupsInteractive.Get(); + if (reference == null) { + return entities.Data[0]; + } + await this.copyPropertiesFrom(entities.Data[0], reference, filter); return entities.Data[0]; } - await this.copyPropertiesFrom(entities.Data[0], reference, filter); - return entities.Data[0]; -} - -public async copyPropertiesFrom( - entity: PortalAttestationPolicygroups, - reference: PortalAttestationPolicygroups, filter: PolicyFilter): Promise { - for (const key in this.api.typedClient.PortalAttestationPolicyEditInteractive.GetSchema().Columns) { - if (!key.startsWith('__') && entity[key].GetMetadata().CanEdit()) { - await entity[key].Column.PutValueStruct({ - DataValue: reference[key].value, - DisplayValue: reference[key].Column.GetDisplayValue() - }); + public async copyPropertiesFrom( + entity: PortalAttestationPolicygroups, + reference: PortalAttestationPolicygroups, + filter?: PolicyFilter, + ): Promise { + for (const key in this.api.typedClient.PortalAttestationPolicyEditInteractive.GetSchema().Columns) { + if (!key.startsWith('__') && entity[key].GetMetadata().CanEdit()) { + await entity[key].Column.PutValueStruct({ + DataValue: reference[key].value, + DisplayValue: reference[key].Column.GetDisplayValue(), + }); + } } - } - entity.Ident_AttestationPolicyGroup.value = - `${reference.Ident_AttestationPolicyGroup.value} (${(await this.translator.get('#LDS#New').toPromise())})`; + entity.Ident_AttestationPolicyGroup.value = `${reference.Ident_AttestationPolicyGroup.value} (${await this.translator + .get('#LDS#New') + .toPromise()})`; - this.logger.trace(this, 'properties copied from policy', reference, filter); -} + this.logger.trace(this, 'properties copied from policy', reference, filter); + } -public async getPolicyGroups(parameters: CollectionLoadParameters): -Promise> { -const collection = await this.api.typedClient.PortalAttestationPolicygroups.Get(parameters); -return { - tableName: collection.tableName, - totalCount: collection.totalCount, - Data: collection.Data.map((element, index) => - new PortalAttestationPolicygroups(element.GetEntity()) - ) -}; -} + public async getPolicyGroups( + parameters: CollectionLoadParameters, + ): Promise> { + const collection = await this.api.typedClient.PortalAttestationPolicygroups.Get(parameters); + return { + tableName: collection.tableName, + totalCount: collection.totalCount, + Data: collection.Data.map((element, index) => new PortalAttestationPolicygroups(element.GetEntity())), + }; + } public handleOpenLoader(): void { - if (!this.busyIndicator) { - setTimeout(() => this.busyIndicator = this.busyService.show()); + if (this.busyService.overlayRefs.length === 0) { + this.busyService.show(); } } public handleCloseLoader(): void { - if (this.busyIndicator) { - setTimeout(() => { - this.busyService.hide(this.busyIndicator); - this.busyIndicator = undefined; - }); - } + this.busyService.hide(); } } diff --git a/imxweb/projects/att/src/lib/runs/attestation-runs.module.ts b/imxweb/projects/att/src/lib/runs/attestation-runs.module.ts index a547712fe..e0a230a10 100644 --- a/imxweb/projects/att/src/lib/runs/attestation-runs.module.ts +++ b/imxweb/projects/att/src/lib/runs/attestation-runs.module.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -24,30 +24,39 @@ * */ -import { NgModule } from '@angular/core'; import { CommonModule } from '@angular/common'; +import { NgModule } from '@angular/core'; import { FormsModule, ReactiveFormsModule } from '@angular/forms'; import { MatButtonModule } from '@angular/material/button'; import { MatDialogModule } from '@angular/material/dialog'; import { MatProgressBarModule } from '@angular/material/progress-bar'; import { MatSidenavModule } from '@angular/material/sidenav'; import { RouterModule } from '@angular/router'; -import { EuiMaterialModule, EuiCoreModule } from '@elemental-ui/core'; +import { EuiCoreModule, EuiMaterialModule } from '@elemental-ui/core'; import { TranslateModule } from '@ngx-translate/core'; -import { DataSourceToolbarModule, DataTableModule, CdrModule, LdsReplaceModule, EntityColumnEditorComponent, SelectedElementsModule, HelpContextualModule, TempBillboardModule } from 'qbm'; +import { + CdrModule, + DataSourceToolbarModule, + DataTableModule, + DataViewModule, + DateModule, + HelpContextualModule, + LdsReplaceModule, + SelectedElementsModule, +} from 'qbm'; -import { RunsComponent } from './runs.component'; -import { RunSidesheetComponent } from './run-sidesheet.component'; +import { AttestationHistoryModule } from '../attestation-history/attestation-history.module'; +import { AttestationWrapperComponent } from './attestation/attestation-wrapper/attestation-wrapper.component'; +import { AttestationComponent } from './attestation/attestation.component'; +import { CaseChartComponent } from './case-chart/case-chart.component'; import { PendingApproversComponent } from './pending-approvers.component'; -import { SendReminderMailComponent } from './send-reminder-mail.component'; import { ProgressComponent } from './progress/progress.component'; import { RunExtendComponent } from './run-extend/run-extend.component'; -import { AttestationComponent } from './attestation/attestation.component'; -import { AttestationHistoryModule } from '../attestation-history/attestation-history.module'; +import { RunSidesheetComponent } from './run-sidesheet.component'; import { RunsGridComponent } from './runs-grid/runs-grid.component'; -import { CaseChartComponent } from './case-chart/case-chart.component'; -import { AttestationWrapperComponent } from './attestation/attestation-wrapper/attestation-wrapper.component'; +import { RunsComponent } from './runs.component'; +import { SendReminderMailComponent } from './send-reminder-mail.component'; @NgModule({ declarations: [ @@ -81,7 +90,8 @@ import { AttestationWrapperComponent } from './attestation/attestation-wrapper/a AttestationHistoryModule, SelectedElementsModule, HelpContextualModule, - TempBillboardModule, + DataViewModule, + DateModule, ], exports: [RunsComponent, RunsGridComponent, AttestationWrapperComponent], }) diff --git a/imxweb/projects/att/src/lib/runs/attestation/attestation-wrapper/attestation-wrapper.component.html b/imxweb/projects/att/src/lib/runs/attestation/attestation-wrapper/attestation-wrapper.component.html index 149ff8775..31fd1cf41 100644 --- a/imxweb/projects/att/src/lib/runs/attestation/attestation-wrapper/attestation-wrapper.component.html +++ b/imxweb/projects/att/src/lib/runs/attestation/attestation-wrapper/attestation-wrapper.component.html @@ -1,2 +1 @@ - - \ No newline at end of file + diff --git a/imxweb/projects/att/src/lib/runs/attestation/attestation-wrapper/attestation-wrapper.component.scss b/imxweb/projects/att/src/lib/runs/attestation/attestation-wrapper/attestation-wrapper.component.scss index af8548a66..e6e1c9030 100644 --- a/imxweb/projects/att/src/lib/runs/attestation/attestation-wrapper/attestation-wrapper.component.scss +++ b/imxweb/projects/att/src/lib/runs/attestation/attestation-wrapper/attestation-wrapper.component.scss @@ -1,5 +1,7 @@ -:host{ +:host { flex: 1 1 auto; display: flex; flex-direction: column; -} \ No newline at end of file + height: 100%; + overflow: hidden; +} diff --git a/imxweb/projects/att/src/lib/runs/attestation/attestation-wrapper/attestation-wrapper.component.ts b/imxweb/projects/att/src/lib/runs/attestation/attestation-wrapper/attestation-wrapper.component.ts index dc3b48939..82ff5a596 100644 --- a/imxweb/projects/att/src/lib/runs/attestation/attestation-wrapper/attestation-wrapper.component.ts +++ b/imxweb/projects/att/src/lib/runs/attestation/attestation-wrapper/attestation-wrapper.component.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -33,18 +33,22 @@ import { IdentityAttestationService } from '../../../identity-attestation.servic @Component({ templateUrl: './attestation-wrapper.component.html', - styleUrls: ['./attestation-wrapper.component.scss'] + styleUrls: ['./attestation-wrapper.component.scss'], }) -export class AttestationWrapperComponent implements OnInit, OnDestroy{ - public referrer: { objecttable: string; objectuid: string; }; +export class AttestationWrapperComponent implements OnInit, OnDestroy { + public referrer: { objecttable: string; objectuid: string }; public readonly pendingAttestations: HelperAlertContent = { loading: false }; private readonly subscriptions: Subscription[] = []; constructor( private readonly attestations: IdentityAttestationService, - dataProvider: DynamicTabDataProviderDirective){ - this.referrer = dataProvider.data; - } + dataProvider: DynamicTabDataProviderDirective, + ) { + this.referrer = { + objecttable: dataProvider.data.objecttable, + objectuid: dataProvider.data.objectuid, + }; + } public ngOnInit(): void { if (this.attestations) { @@ -52,28 +56,24 @@ export class AttestationWrapperComponent implements OnInit, OnDestroy{ this.updatePendingAttestations(); } - } public ngOnDestroy(): void { - this.subscriptions.forEach(subscription => subscription.unsubscribe()); + this.subscriptions.forEach((subscription) => subscription.unsubscribe()); } private async updatePendingAttestations(): Promise { - this.pendingAttestations.loading = true; const statistics: ObjectAttestationStatistics = await this.attestations.getNumberOfPendingForUser(this.referrer); if (!statistics?.total) { - this.pendingAttestations.infoItems = [ - { description: '#LDS#There are currently no attestation cases for this object.' } - ]; + this.pendingAttestations.infoItems = [{ description: '#LDS#There are currently no attestation cases for this object.' }]; } else { this.pendingAttestations.infoItems = [ { description: '#LDS#Here you can get an overview of all attestations cases for this object.' }, { description: '#LDS#Pending attestation cases: {0}', value: statistics.pendingTotal }, - { description: '#LDS#Pending attestation cases you can approve or deny: {0}', value: statistics.pendingForUser } + { description: '#LDS#Pending attestation cases you can approve or deny: {0}', value: statistics.pendingForUser }, ]; } diff --git a/imxweb/projects/att/src/lib/runs/attestation/attestation.component.html b/imxweb/projects/att/src/lib/runs/attestation/attestation.component.html index ec8d6670d..a8d71a9a7 100644 --- a/imxweb/projects/att/src/lib/runs/attestation/attestation.component.html +++ b/imxweb/projects/att/src/lib/runs/attestation/attestation.component.html @@ -1,29 +1,52 @@ -
    +
    - + -
    +
    - {{ infoItem.description | translate | ldsReplace : infoItem.value }} + {{ infoItem.description | translate | ldsReplace: infoItem.value }}
    - + +
    - -
    -
    - -
    diff --git a/imxweb/projects/att/src/lib/runs/attestation/attestation.component.scss b/imxweb/projects/att/src/lib/runs/attestation/attestation.component.scss index 9480989d1..3985f0357 100644 --- a/imxweb/projects/att/src/lib/runs/attestation/attestation.component.scss +++ b/imxweb/projects/att/src/lib/runs/attestation/attestation.component.scss @@ -1,86 +1,6 @@ -@import "@elemental-ui/core/src/styles/_eui_palette.scss"; - :host { display: flex; flex-direction: column; height: 100%; -} - -.imx-content { - height: 100%; - display: flex; - flex-direction: column; - flex: 1 1 auto; - overflow-y: auto; - - .imx-heading-wrapper { - display: flex; - flex-direction: column; - - .imx-helper-alert { - margin: 10px 0 20px auto; - width: 100%; - - .imx-helper-alert-infotext { - display: flex; - flex-direction: column; - } - } - } - - .imx-attestation-history-container { - overflow: hidden; - display: flex; - flex-direction: column; - height:100%; - - > :first-child { - height: 100%; - } - } -} - -imx-selected-elements { - margin: 10px 0 0 10px; -} - -.eui-sidesheet-actions { - display: flex; - justify-content: flex-end; - align-items: center; - padding: 0px 20px 20px; - margin: 16px -20px -20px; - - > * { - margin-top: 20px; - - .mat-icon { - margin-right: 5px; - font-size: 24px; - } - } - - button:not(:last-of-type) { - margin-right: 16px; - } - - button:disabled:hover { - cursor: not-allowed; - } -} - -.eui-dark-theme { - :host { - .imx-button-bar { - background-color: $color-gray-70; - } - } -} - -.eui-contrast-theme { - :host { - .imx-button-bar { - background-color: $color-gray-90; - } - } + overflow: hidden; } diff --git a/imxweb/projects/att/src/lib/runs/attestation/attestation.component.ts b/imxweb/projects/att/src/lib/runs/attestation/attestation.component.ts index 1915c3579..c5ab6694d 100644 --- a/imxweb/projects/att/src/lib/runs/attestation/attestation.component.ts +++ b/imxweb/projects/att/src/lib/runs/attestation/attestation.component.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -27,13 +27,18 @@ import { Component, EventEmitter, Input, OnDestroy, Output } from '@angular/core'; import { Subscription } from 'rxjs'; +import { FilterData, TypedEntity } from '@imx-modules/imx-qbm-dbts'; import { AuthenticationService, HELPER_ALERT_KEY_PREFIX, StorageService } from 'qbm'; -import { AttestationHistoryCase } from '../../attestation-history/attestation-history-case'; -import { AttestationHistoryActionService } from '../../attestation-history/attestation-history-action.service'; -import { FilterData } from 'imx-qbm-dbts'; import { HelperAlertContent } from 'qer'; +import { AttestationHistoryActionService } from '../../attestation-history/attestation-history-action.service'; +import { AttestationHistoryCase } from '../../attestation-history/attestation-history-case'; const helperAlertKey = `${HELPER_ALERT_KEY_PREFIX}_attestation`; +export interface AttestationParameters { + objecttable: string; + objectuid: string; + filter?: FilterData[]; +} @Component({ selector: 'imx-attestation', @@ -53,7 +58,7 @@ export class AttestationComponent implements OnDestroy { return !this.storageService.isHelperAlertDismissed(helperAlertKey); } - @Input() public parameters: { objecttable: string; objectuid: string; filter?: FilterData[] }; + @Input() public parameters: AttestationParameters; @Input() public pendingAttestations: HelperAlertContent; public readonly itemStatus = { @@ -71,17 +76,17 @@ export class AttestationComponent implements OnDestroy { constructor( public readonly attestationAction: AttestationHistoryActionService, private readonly storageService: StorageService, - authentication: AuthenticationService + authentication: AuthenticationService, ) { - this.subscriptions.push(authentication.onSessionResponse?.subscribe((sessionState) => (this.userUid = sessionState?.UserUid))); + this.subscriptions.push(authentication.onSessionResponse?.subscribe((sessionState) => (this.userUid = sessionState?.UserUid || ''))); } public ngOnDestroy(): void { this.subscriptions.forEach((s) => s.unsubscribe()); } - public onSelectionChanged(items: AttestationHistoryCase[]): void { - this.selectedCases = items; + public onSelectionChanged(items: TypedEntity[]): void { + this.selectedCases = items as AttestationHistoryCase[]; } public onHelperDismissed(): void { diff --git a/imxweb/projects/att/src/lib/runs/case-chart/case-chart.component.html b/imxweb/projects/att/src/lib/runs/case-chart/case-chart.component.html index b42f1c605..0299a4177 100644 --- a/imxweb/projects/att/src/lib/runs/case-chart/case-chart.component.html +++ b/imxweb/projects/att/src/lib/runs/case-chart/case-chart.component.html @@ -1,3 +1,3 @@ -
    - +
    +
    diff --git a/imxweb/projects/att/src/lib/runs/case-chart/case-chart.component.scss b/imxweb/projects/att/src/lib/runs/case-chart/case-chart.component.scss index 9ae16e19e..b6e2cfe32 100644 --- a/imxweb/projects/att/src/lib/runs/case-chart/case-chart.component.scss +++ b/imxweb/projects/att/src/lib/runs/case-chart/case-chart.component.scss @@ -5,9 +5,3 @@ flex: 1 1 auto; overflow: hidden; } - - .chart-wrapper { - display: flex; - flex-direction: column; - flex: 1 1 auto; - } \ No newline at end of file diff --git a/imxweb/projects/att/src/lib/runs/case-chart/case-chart.component.ts b/imxweb/projects/att/src/lib/runs/case-chart/case-chart.component.ts index 00e28348e..c402bc684 100644 --- a/imxweb/projects/att/src/lib/runs/case-chart/case-chart.component.ts +++ b/imxweb/projects/att/src/lib/runs/case-chart/case-chart.component.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -25,10 +25,10 @@ */ import { Component, ElementRef, Input, OnDestroy, OnInit, ViewChild } from '@angular/core'; +import { PortalAttestationRun } from '@imx-modules/imx-api-att'; import { TranslateService } from '@ngx-translate/core'; import { bar, Chart, ChartOptions } from 'billboard.js'; -import { PortalAttestationRun } from 'imx-api-att'; -import { Subscription, fromEvent } from 'rxjs'; +import { fromEvent, Subscription } from 'rxjs'; @Component({ selector: 'imx-case-chart', @@ -38,7 +38,7 @@ import { Subscription, fromEvent } from 'rxjs'; export class CaseChartComponent implements OnInit, OnDestroy { @Input() public run: PortalAttestationRun; - public chartData: ChartOptions; + public chartData: ChartOptions | undefined; private chart: Chart; private subscriptions$: Subscription[] = []; @@ -60,7 +60,7 @@ export class CaseChartComponent implements OnInit, OnDestroy { width: this.chartWrapper?.nativeElement.offsetWidth, }); } - }) + }), ); } @@ -76,7 +76,7 @@ export class CaseChartComponent implements OnInit, OnDestroy { }); } - private buildSingleValueChart(): ChartOptions { + private buildSingleValueChart(): ChartOptions | undefined { if ( this.run.PendingCases.value === 0 && this.run.GrantedCases.value === 0 && diff --git a/imxweb/projects/att/src/lib/runs/helpers.ts b/imxweb/projects/att/src/lib/runs/helpers.ts index f6e10bd29..e7f56f115 100644 --- a/imxweb/projects/att/src/lib/runs/helpers.ts +++ b/imxweb/projects/att/src/lib/runs/helpers.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR diff --git a/imxweb/projects/att/src/lib/runs/pending-approvers.component.html b/imxweb/projects/att/src/lib/runs/pending-approvers.component.html index 764a63eec..445c1485f 100644 --- a/imxweb/projects/att/src/lib/runs/pending-approvers.component.html +++ b/imxweb/projects/att/src/lib/runs/pending-approvers.component.html @@ -1,33 +1,53 @@
    - - #LDS#Here you can get an overview of attestors who still have to approve attestation cases in the selected attestation run. Additionally, you can select attestors and send them reminders. - + + {{ LdsKeyAttestorOverview }} + - - - -
    - - - - - - - - -
    -
    + + + + + {{ entitySchema?.Columns?.UID_PersonHead?.Display }} + + +
    {{ item.UID_PersonHead.Column.GetDisplayValue() }}
    + +
    + + + {{ '#LDS#Pending' | translate }} + + +
    {{ item.PendingCases.Column.GetDisplayValue() }}
    + +
    + + + {{ '#LDS#Closed' | translate }} + + +
    {{ item.ClosedCases.Column.GetDisplayValue() }}
    + +
    +
    +
    -
    diff --git a/imxweb/projects/att/src/lib/runs/pending-approvers.component.scss b/imxweb/projects/att/src/lib/runs/pending-approvers.component.scss index 38d167d8d..50b697580 100644 --- a/imxweb/projects/att/src/lib/runs/pending-approvers.component.scss +++ b/imxweb/projects/att/src/lib/runs/pending-approvers.component.scss @@ -1,63 +1,15 @@ -@import "@elemental-ui/core/src/styles/_eui_palette.scss"; +@import 'base/mixins'; :host { - display: flex; - flex-direction: column; - height: 100%; + @include flex-column-container($overflow: hidden, $height: 100%); } .attestationRun-pendingapprovers-content { - height: 100%; - display: flex; - flex-direction: column; - flex: 1 1 auto; + @include flex-column-container-fill; overflow-y: auto; } -.mat-card { +.mat-mdc-card { margin: 20px; overflow-y: auto; } - -.eui-sidesheet-actions { - display: flex; - justify-content: flex-end; - overflow-y: inherit; - padding: 0px 20px 20px 8px; - margin: 0; - > * { - margin-left: 10px; - margin-top: 20px; - } -} - -.helper-alert { - display: flex; - padding: 30px 20px 0; - flex-direction: column; - span { - display: block; - } -} - -.imx-pending-approvers-container{ - display: flex; - flex-direction: column; - height:100%; -} - -.eui-dark-theme { - :host { - .imx-button-bar { - background-color: $color-gray-70; - } - } -} - -.eui-contrast-theme { - :host { - .imx-button-bar { - background-color: $color-gray-90; - } - } -} diff --git a/imxweb/projects/att/src/lib/runs/pending-approvers.component.ts b/imxweb/projects/att/src/lib/runs/pending-approvers.component.ts index 37d2c7ff2..a49e600f2 100644 --- a/imxweb/projects/att/src/lib/runs/pending-approvers.component.ts +++ b/imxweb/projects/att/src/lib/runs/pending-approvers.component.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -27,44 +27,48 @@ import { Component, EventEmitter, Input, OnChanges, Output, SimpleChanges } from '@angular/core'; import { ApiService } from '../api.service'; -import { PortalAttestationRunApprovers } from 'imx-api-att'; -import { TypedEntityCollectionData } from 'imx-qbm-dbts'; +import { PortalAttestationRunApprovers } from '@imx-modules/imx-api-att'; +import { EntitySchema, TypedEntityCollectionData } from '@imx-modules/imx-qbm-dbts'; -import { DataSourceToolbarSettings } from 'qbm'; +import { DataViewInitParameters, DataViewSource } from 'qbm'; @Component({ selector: 'imx-attestation-run-approvers', templateUrl: './pending-approvers.component.html', - styleUrls: ['./pending-approvers.component.scss'] + styleUrls: ['./pending-approvers.component.scss'], + providers: [DataViewSource], }) export class PendingApproversComponent implements OnChanges { - public dstSettings: DataSourceToolbarSettings; - public selected: PortalAttestationRunApprovers[] = []; - + public entitySchema: EntitySchema; public showHelper = true; @Input() public dataSource: TypedEntityCollectionData; @Output() public readonly sendReminder = new EventEmitter(); - constructor(private readonly attApiService: ApiService) { + constructor( + private readonly attApiService: ApiService, + public dataViewSource: DataViewSource, + ) { + this.entitySchema = this.attApiService.typedClient.PortalAttestationRunApprovers.GetSchema(); } public async ngOnChanges(changes: SimpleChanges): Promise { if (changes.dataSource && this.dataSource) { - const entitySchema = this.attApiService.typedClient.PortalAttestationRunApprovers.GetSchema(); - - this.dstSettings = { - displayedColumns: [ - entitySchema.Columns.UID_PersonHead, - entitySchema.Columns.PendingCases, - entitySchema.Columns.ClosedCases + console.log(this.dataSource); + const dataViewInitParameters: DataViewInitParameters = { + execute: () => Promise.resolve(this.dataSource), + schema: this.entitySchema, + columnsToDisplay: [ + this.entitySchema.Columns.UID_PersonHead, + this.entitySchema.Columns.PendingCases, + this.entitySchema.Columns.ClosedCases, ], - dataSource: this.dataSource, - entitySchema, - navigationState: {} + localSource: true, + selectionChange: (selection: PortalAttestationRunApprovers[]) => this.onSelectionChanged(selection), }; + this.dataViewSource.init(dataViewInitParameters); } } @@ -75,4 +79,7 @@ export class PendingApproversComponent implements OnChanges { public onHelperDismissed(): void { this.showHelper = false; } + + public LdsKeyAttestorOverview = + '#LDS#Here you can get an overview of attestors who still have to approve attestation cases in the selected attestation run. Additionally, you can select attestors and send them reminders.'; } diff --git a/imxweb/projects/att/src/lib/runs/progress/progress.component.html b/imxweb/projects/att/src/lib/runs/progress/progress.component.html index d31a0ec43..32c6c2dd8 100644 --- a/imxweb/projects/att/src/lib/runs/progress/progress.component.html +++ b/imxweb/projects/att/src/lib/runs/progress/progress.component.html @@ -1,11 +1,11 @@
    - - - - {{ percentage }} % +
    + +
    {{percentage}}
    +
    + -
    \ No newline at end of file +
    diff --git a/imxweb/projects/att/src/lib/runs/progress/progress.component.scss b/imxweb/projects/att/src/lib/runs/progress/progress.component.scss deleted file mode 100644 index b268e28cb..000000000 --- a/imxweb/projects/att/src/lib/runs/progress/progress.component.scss +++ /dev/null @@ -1,10 +0,0 @@ -.imx-progress-bar-container { - display: flex; - align-items: center; - max-width: 200px; - - > span { - margin-left: 5px; - min-width: 30px; - } -} \ No newline at end of file diff --git a/imxweb/projects/att/src/lib/runs/progress/progress.component.ts b/imxweb/projects/att/src/lib/runs/progress/progress.component.ts index 9191db3a3..73493d8c7 100644 --- a/imxweb/projects/att/src/lib/runs/progress/progress.component.ts +++ b/imxweb/projects/att/src/lib/runs/progress/progress.component.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -26,13 +26,12 @@ import { Component, Input } from '@angular/core'; -import { PortalAttestationRun } from 'imx-api-att'; +import { PortalAttestationRun } from '@imx-modules/imx-api-att'; import { percentage } from '../helpers'; @Component({ selector: 'imx-progress', - templateUrl: './progress.component.html', - styleUrls: ['./progress.component.scss'] + templateUrl: './progress.component.html' }) export class ProgressComponent { public get progress(): number { diff --git a/imxweb/projects/att/src/lib/runs/run-extend/run-extend.component.html b/imxweb/projects/att/src/lib/runs/run-extend/run-extend.component.html index 116f1b1dd..c747046fd 100644 --- a/imxweb/projects/att/src/lib/runs/run-extend/run-extend.component.html +++ b/imxweb/projects/att/src/lib/runs/run-extend/run-extend.component.html @@ -1,29 +1,36 @@
    - - - #LDS#Here you can extend the attestation run and enter a reason for extending the run. - + + #LDS#Here you can extend the attestation run and enter a reason for extending the run.
    {{ '#LDS#New due date' | translate }} - + - {{ ( date?.value ? '#LDS#Specify a date that lies in the future.' : '#LDS#This field is mandatory.' ) | translate }} + {{ (date?.value ? '#LDS#Specify a date that lies in the future.' : '#LDS#This field is mandatory.') | translate }} - - +
    -
    - -
    \ No newline at end of file +
    diff --git a/imxweb/projects/att/src/lib/runs/run-extend/run-extend.component.scss b/imxweb/projects/att/src/lib/runs/run-extend/run-extend.component.scss index 89db4b066..a8d0b89c4 100644 --- a/imxweb/projects/att/src/lib/runs/run-extend/run-extend.component.scss +++ b/imxweb/projects/att/src/lib/runs/run-extend/run-extend.component.scss @@ -1,4 +1,4 @@ -@import "@elemental-ui/core/src/styles/_eui_palette.scss"; +@import '@elemental-ui/core/src/styles/_eui_palette.scss'; :host { display: flex; @@ -19,27 +19,3 @@ display: flex; flex-direction: column; } - -.mat-form-field { - width: 100%; -} - -.imx-button-bar { - display: flex; - justify-content: flex-end; - border-top: $color-gray-20 1px solid; - padding: 0px 20px 20px 8px; - > * { - margin-left: 10px; - margin-top: 20px; - } -} - -.helper-alert { - display: flex; - padding-bottom: 20px; - flex-direction: column; - span { - display: block; - } -} diff --git a/imxweb/projects/att/src/lib/runs/run-extend/run-extend.component.ts b/imxweb/projects/att/src/lib/runs/run-extend/run-extend.component.ts index 6884d61f9..3b9c1620a 100644 --- a/imxweb/projects/att/src/lib/runs/run-extend/run-extend.component.ts +++ b/imxweb/projects/att/src/lib/runs/run-extend/run-extend.component.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -25,8 +25,8 @@ */ import { Component, Inject, OnDestroy } from '@angular/core'; -import { UntypedFormControl, UntypedFormGroup } from '@angular/forms'; -import { EuiSidesheetRef, EUI_SIDESHEET_DATA } from '@elemental-ui/core'; +import { AbstractControl, UntypedFormControl, UntypedFormGroup } from '@angular/forms'; +import { EUI_SIDESHEET_DATA, EuiSidesheetRef } from '@elemental-ui/core'; import { Subscription } from 'rxjs'; import { ColumnDependentReference } from 'qbm'; @@ -34,7 +34,7 @@ import { ColumnDependentReference } from 'qbm'; @Component({ selector: 'imx-run-extend', templateUrl: './run-extend.component.html', - styleUrls: ['./run-extend.component.scss'] + styleUrls: ['./run-extend.component.scss'], }) export class RunExtendComponent implements OnDestroy { public showHelper = true; @@ -47,28 +47,26 @@ export class RunExtendComponent implements OnDestroy { private readonly subscriptions: Subscription[] = []; constructor( - @Inject(EUI_SIDESHEET_DATA) readonly data: { ProlongateUntil: Date, reason: ColumnDependentReference }, - public readonly sideSheetRef: EuiSidesheetRef + @Inject(EUI_SIDESHEET_DATA) readonly data: { ProlongateUntil: Date; reason: ColumnDependentReference }, + public readonly sideSheetRef: EuiSidesheetRef, ) { this.tomorrow = new Date(); - this.tomorrow.setDate((new Date()).getDate() + 1); + this.tomorrow.setDate(new Date().getDate() + 1); this.date = new UntypedFormControl(data.ProlongateUntil, { updateOn: 'blur' }); - this.date.valueChanges.subscribe(value => data.ProlongateUntil = value); + this.date.valueChanges.subscribe((value) => (data.ProlongateUntil = value)); this.addControl('date', this.date); this.reason = data.reason; } public ngOnDestroy(): void { - this.subscriptions.forEach(s => s.unsubscribe()); + this.subscriptions.forEach((s) => s.unsubscribe()); } public onHelperDismissed(): void { this.showHelper = false; } - public addControl(name: string, control: UntypedFormControl): void { - setTimeout(() => - this.form.addControl(name, control) - ); + public addControl(name: string, control: AbstractControl): void { + setTimeout(() => this.form.addControl(name, control)); } } diff --git a/imxweb/projects/att/src/lib/runs/run-sidesheet.component.html b/imxweb/projects/att/src/lib/runs/run-sidesheet.component.html index 521d03719..090e03988 100644 --- a/imxweb/projects/att/src/lib/runs/run-sidesheet.component.html +++ b/imxweb/projects/att/src/lib/runs/run-sidesheet.component.html @@ -1,155 +1,192 @@ - + -
    - - - - - {{ '#LDS#General' | translate }} - - {{ '#LDS#Completed' | translate}} - - - {{'#LDS#In progress' | translate}} - - - +
    + + + + + + {{ '#LDS#General' | translate }} + + {{ '#LDS#Completed' | translate }} + + + {{ '#LDS#In progress' | translate }} + + + - - - -
    - {{ '#LDS#Progress' | translate }} - -
    -
    + + + + +
    + {{ '#LDS#Progress' | translate }} + +
    + + + + + + {{ '#LDS#Attestation details' | translate }} + + +
    +
    +
    + {{ '#LDS#Cases' | translate }} + {{ run.ClosedCases.value + run.PendingCases.value }} +
    + + +
    + + + +
    + + {{ run.Speed.Column.GetMetadata().GetDisplay() }} + + + + {{ '#LDS#{0} attestations/day' | translate | ldsReplace: run.Speed.Column.GetDisplayValue() }} +
    +
    + +
    +
    - - - - {{ '#LDS#Attestation details' | translate }} - - -
    -
    -
    - {{ '#LDS#Cases' | translate }} - {{ run.ClosedCases.value + run.PendingCases.value }} + + + + {{ '#LDS#Attestation prediction' | translate }} + + + +
    + {{ '#LDS#Estimated progress on due date' | translate }} + + + + +
    + {{ '#LDS#No prediction possible because the attestation run has no due date.' | translate }} +
    + +
    {{ '#LDS#No prediction possible because the attestation run is already overdue.' | translate }}
    +
    +
    - - -
    - - - +
    {{ run.Speed.Column.GetMetadata().GetDisplay() }} - + - {{ '#LDS#{0} attestations/day' | translate | ldsReplace:run.Speed.Column.GetDisplayValue() - }} + {{ '#LDS#{0} attestations/day' | translate | ldsReplace: run.Speed.Column.GetDisplayValue() }}
    -
    - -
    - - - - - - {{ '#LDS#Attestation prediction' | translate }} - - - -
    - {{ '#LDS#Estimated progress on due date' | translate }} - - - - - -
    - {{ '#LDS#No prediction possible because the attestation run has no due date.' | translate }} -
    - -
    {{ '#LDS#No prediction possible because the attestation run is already overdue.' | translate }} -
    -
    -
    -
    - -
    - - {{ run.Speed.Column.GetMetadata().GetDisplay() }} - - - - {{ '#LDS#{0} attestations/day' | translate | ldsReplace:run.Speed.Column.GetDisplayValue() }} -
    - -
    - {{ '#LDS#Estimated completion of the attestation run' | translate }} - - {{ run.ForecastRemainingDays.value ? - ('#LDS#{0} days' | translate | - ldsReplace:(run.ForecastRemainingDays.value)) :( '#LDS#N/A' | translate) }} - -
    - - -

    - {{ categoryExplanation.message | translate | ldsReplace:categoryExplanation.limit }}

    - -
    - -

    - {{ '#LDS#The prediction is available as soon as at least {0}% of the attestation cases of this attestation run have been closed.' | translate |ldsReplace:threshold }} -

    -
    - -

    - {{ '#LDS#The prediction is not available because the attestation run has already been completed.' | translate }} -

    -
    -
    - - -
    - - - -
    + +
    + {{ '#LDS#Estimated completion of the attestation run' | translate }} + + {{ + run.ForecastRemainingDays.value + ? ('#LDS#{0} days' | translate | ldsReplace: run.ForecastRemainingDays.value) + : ('#LDS#N/A' | translate) + }} + +
    + + +

    + {{ categoryExplanation.message | translate | ldsReplace: categoryExplanation.limit }} +

    + + +

    + {{ + '#LDS#The prediction is available as soon as at least {0}% of the attestation cases of this attestation run have been closed.' + | translate + | ldsReplace: threshold + }} +

    +
    + +

    + {{ '#LDS#The prediction is not available because the attestation run has already been completed.' | translate }} +

    +
    + + + +
    +
    + + +
    - - + + - -
    - - -
    + + + diff --git a/imxweb/projects/att/src/lib/runs/run-sidesheet.component.scss b/imxweb/projects/att/src/lib/runs/run-sidesheet.component.scss index 90bea5638..cff54f121 100644 --- a/imxweb/projects/att/src/lib/runs/run-sidesheet.component.scss +++ b/imxweb/projects/att/src/lib/runs/run-sidesheet.component.scss @@ -1,4 +1,4 @@ -@import "@elemental-ui/core/src/styles/_eui_palette.scss"; +@import '@elemental-ui/core/src/styles/_eui_palette.scss'; :host { display: flex; @@ -7,26 +7,6 @@ height: 100%; } -.mat-tab-group { - flex: 1 1 auto; - overflow-y: auto; -} - -:host ::ng-deep .mat-tab-body-wrapper { - flex: 1 1 auto; - - .mat-tab-body { - display: flex; - flex-direction: column; - flex: 1 1 auto; - } -} - -:host ::ng-deep .mat-tab-body-content { - display: flex; - flex-direction: column; -} - .imx-progress-content { overflow-y: auto; flex: 1 1 auto; @@ -49,21 +29,19 @@ .imx-property-display { margin-bottom: 20px; - >span { - display: block; + > span { + display: flex; + align-items: center; } - >span:first-child { + > span:first-child { font-size: 12px; color: $color-gray-40; padding-bottom: 5px; } - .help-icon { - color: $color-blue-60; - font-size: 16px; + .imx-icon-info { margin-left: 5px; - margin-top: -3px; } } @@ -72,29 +50,6 @@ } } -.helper-alert { - display: flex; - padding: 20px 20px 0 20px; - flex-direction: column; - - span { - display: block; - } -} - -.eui-sidesheet-actions { - display: flex; - justify-content: flex-end; - padding: 0px 20px 20px 8px; - flex-wrap: wrap; - margin: 0 -20px -20px; - - > * { - margin-left: 10px; - margin-top: 20px; - } -} - .imx-readonly-view { margin-bottom: 20px; @@ -123,17 +78,12 @@ padding-bottom: 5px; } } - } -eui-badge { - margin-left: 10px; -} .imx-run-info-category-content { display: flex; flex-direction: row; - } .seperator { @@ -141,35 +91,3 @@ eui-badge { margin-bottom: 10px; margin-top: -10px; } - -.imx-tab-content-body { - display: flex; - flex-direction: column; - flex: 1; - padding: 20px; - overflow: auto; -} - -.eui-dark-theme { - :host { - ::ng-deep .mat-tab-header { - background-color: $color-gray-80; - } - - .imx-button-bar { - background-color: $color-gray-70; - } - } -} - -.eui-contrast-theme { - :host { - ::ng-deep .mat-tab-header { - background-color: $color-gray-90; - } - - .imx-button-bar { - background-color: $color-gray-80; - } - } -} diff --git a/imxweb/projects/att/src/lib/runs/run-sidesheet.component.ts b/imxweb/projects/att/src/lib/runs/run-sidesheet.component.ts index 7d0e1cae7..0cda93de4 100644 --- a/imxweb/projects/att/src/lib/runs/run-sidesheet.component.ts +++ b/imxweb/projects/att/src/lib/runs/run-sidesheet.component.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -24,29 +24,28 @@ * */ -import { OverlayRef } from '@angular/cdk/overlay'; import { Component, Inject } from '@angular/core'; import { MatTabChangeEvent } from '@angular/material/tabs'; -import { EuiLoadingService, EuiSidesheetRef, EuiSidesheetService, EUI_SIDESHEET_DATA } from '@elemental-ui/core'; +import { EUI_SIDESHEET_DATA, EuiDownloadOptions, EuiLoadingService, EuiSidesheetRef, EuiSidesheetService } from '@elemental-ui/core'; import { TranslateService } from '@ngx-translate/core'; -import { EuiDownloadOptions } from '@elemental-ui/core'; import { Subscription } from 'rxjs'; -import { CompareOperator, FilterType, TypedEntityCollectionData } from 'imx-qbm-dbts'; -import { PortalAttestationRun, PortalAttestationRunApprovers, RunStatisticsConfig } from 'imx-api-att'; -import { SnackBarService } from 'qbm'; +import { PortalAttestationRun, PortalAttestationRunApprovers, RunStatisticsConfig } from '@imx-modules/imx-api-att'; +import { CompareOperator, FilterType, TypedEntityCollectionData } from '@imx-modules/imx-qbm-dbts'; +import { calculateSidesheetWidth, SnackBarService } from 'qbm'; -import { RunsService } from './runs.service'; -import { percentage } from './helpers'; -import { RunExtendComponent } from './run-extend/run-extend.component'; +import { HelperAlertContent } from 'qer'; import { AttestationActionService } from '../attestation-action/attestation-action.service'; -import { AttestationHistoryActionService } from '../attestation-history/attestation-history-action.service'; import { AttestationCaseLoadParameters } from '../attestation-history/attestation-case-load-parameters.interface'; -import { HelperAlertContent } from 'qer'; +import { AttestationHistoryActionService } from '../attestation-history/attestation-history-action.service'; +import { AttestationParameters } from './attestation/attestation.component'; +import { percentage } from './helpers'; +import { RunExtendComponent } from './run-extend/run-extend.component'; +import { RunsService } from './runs.service'; @Component({ templateUrl: './run-sidesheet.component.html', - styleUrls: ['./run-sidesheet.component.scss'] + styleUrls: ['./run-sidesheet.component.scss'], }) export class RunSidesheetComponent { public readonly run: PortalAttestationRun; @@ -57,6 +56,10 @@ export class RunSidesheetComponent { public approvers: TypedEntityCollectionData; public readonly attestationParameters: AttestationCaseLoadParameters; + public readonly attestationFilterParam: AttestationParameters = { + objecttable: '', + objectuid: '', + }; public readonly pendingAttestations: HelperAlertContent = { loading: false }; private readonly subscriptions: Subscription[] = []; @@ -73,21 +76,23 @@ export class RunSidesheetComponent { if (this.attestationRunConfig) { if (this.run.ForecastProgress.value <= this.attestationRunConfig.LimitBad) { return { - message: '#LDS#This attestation run is categorized bad because the progress on the due date is estimated to be no more than {0}%.', - limit: percentage(this.attestationRunConfig.LimitBad) + message: + '#LDS#This attestation run is categorized bad because the progress on the due date is estimated to be no more than {0}%.', + limit: percentage(this.attestationRunConfig.LimitBad), }; } if (this.run.ForecastProgress.value <= this.attestationRunConfig.LimitGood) { return { - message: '#LDS#This attestation run is categorized as mediocre because the progress on the due date is estimated to be no more than {0}%.', - limit: percentage(this.attestationRunConfig.LimitGood) + message: + '#LDS#This attestation run is categorized as mediocre because the progress on the due date is estimated to be no more than {0}%.', + limit: percentage(this.attestationRunConfig.LimitGood), }; } return { message: '#LDS#This attestation run is categorized as good because the progress on the due date is estimated to be more than {0}%.', - limit: percentage(this.attestationRunConfig.LimitGood) + limit: percentage(this.attestationRunConfig.LimitGood), }; } @@ -95,12 +100,13 @@ export class RunSidesheetComponent { } constructor( - @Inject(EUI_SIDESHEET_DATA) public readonly data: { - run: PortalAttestationRun, - attestationRunConfig: RunStatisticsConfig, - canSeeAttestationPolicies: boolean, - threshold: number, - completed: boolean + @Inject(EUI_SIDESHEET_DATA) + public readonly data: { + run: PortalAttestationRun; + attestationRunConfig: RunStatisticsConfig; + canSeeAttestationPolicies: boolean; + threshold: number; + completed: boolean; }, public readonly runsService: RunsService, private readonly snackBarService: SnackBarService, @@ -109,66 +115,67 @@ export class RunSidesheetComponent { private readonly busyService: EuiLoadingService, private readonly sideSheetRef: EuiSidesheetRef, private readonly action: AttestationActionService, - attestationAction: AttestationHistoryActionService + attestationAction: AttestationHistoryActionService, ) { this.run = this.data.run; this.attestationRunConfig = this.data.attestationRunConfig; this.threshold = data.threshold; - this.subscriptions.push( - attestationAction.applied?.subscribe(() => this.updatePendingAttestations()) - ); + this.subscriptions.push(attestationAction.applied?.subscribe(() => this.updatePendingAttestations())); this.reportDownload = runsService.getReportDownloadOptions(this.run); this.attestationParameters = { - filter: [{ - CompareOp: CompareOperator.Equal, - Type: FilterType.Compare, - ColumnName: 'UID_AttestationRun', - Value1: this.run.GetEntity().GetKeys()[0] - },{ - CompareOp: CompareOperator.Equal, - Type: FilterType.Compare, - ColumnName: 'UID_AttestationPolicy', - Value1: this.run.UID_AttestationPolicy.value - }] + filter: [ + { + CompareOp: CompareOperator.Equal, + Type: FilterType.Compare, + ColumnName: 'UID_AttestationRun', + Value1: this.run.GetEntity().GetKeys()[0], + }, + { + CompareOp: CompareOperator.Equal, + Type: FilterType.Compare, + ColumnName: 'UID_AttestationPolicy', + Value1: this.run.UID_AttestationPolicy.value, + }, + ], }; + this.attestationFilterParam.filter = this.attestationParameters?.filter; } public async extendAttestationRun(): Promise { const data = { ProlongateUntil: this.run.DueDate.value, - reason: this.action.createCdrReason({ display: '#LDS#Reason', mandatory: true }) + reason: this.action.createCdrReason({ display: '#LDS#Reason', mandatory: true }), }; - const result = await this.sideSheet.open( - RunExtendComponent, - { + const result = await this.sideSheet + .open(RunExtendComponent, { title: await this.translate.get('#LDS#Heading Extend Attestation Run').toPromise(), subTitle: this.run.GetEntity().GetDisplay(), padding: '0px', - width: '600px', + width: calculateSidesheetWidth(600, 0.4), testId: 'attestationruns-extendrun-sidesheet', - data - } - ).afterClosed().toPromise(); + data, + }) + .afterClosed() + .toPromise(); if (result) { - let overlayRef: OverlayRef; - setTimeout(() => overlayRef = this.busyService.show()); + this.showBusyIndicator(); - let success: boolean; + let success = false; try { await this.runsService.extendRun(this.run, { ProlongateUntil: data.ProlongateUntil, - Reason: data.reason.column.GetValue() + Reason: data.reason.column.GetValue(), }); success = true; } finally { if (success) { this.snackBarService.open({ key: '#LDS#The attestation run has been successfully extended.' }); } - setTimeout(() => this.busyService.hide(overlayRef)); + this.busyService.hide(); this.sideSheetRef.close(true); } } @@ -176,22 +183,20 @@ export class RunSidesheetComponent { public async onTabChange(event: MatTabChangeEvent): Promise { if (event.index === 1) { - let overlayRef: OverlayRef; - setTimeout(() => overlayRef = this.busyService.show()); + this.showBusyIndicator(); try { this.approvers = await this.runsService.getApprovers(this.run); } finally { - setTimeout(() => this.busyService.hide(overlayRef)); + this.busyService.hide(); } } if (event.index === 2) { - let overlayRef: OverlayRef; - setTimeout(() => overlayRef = this.busyService.show()); + this.showBusyIndicator(); try { this.updatePendingAttestations(); } finally { - setTimeout(() => this.busyService.hide(overlayRef)); + this.busyService.hide(); } } } @@ -206,22 +211,26 @@ export class RunSidesheetComponent { const total = this.run.ClosedCases.value + this.run.PendingCases.value; if (total === 0) { - this.pendingAttestations.infoItems = [ - { description: '#LDS#There are currently no attestation cases for this attestation run.' } - ]; + this.pendingAttestations.infoItems = [{ description: '#LDS#There are currently no attestation cases for this attestation run.' }]; } else { const statistics = { pendingTotal: this.run.PendingCases.value, - pendingForUser: await this.runsService.getNumberOfPendingForLoggedInUser(this.attestationParameters) + pendingForUser: await this.runsService.getNumberOfPendingForLoggedInUser(this.attestationParameters), }; this.pendingAttestations.infoItems = [ { description: '#LDS#Here you can get an overview of all attestation cases in this attestation run.' }, { description: '#LDS#Pending attestation cases: {0}', value: statistics.pendingTotal }, - { description: '#LDS#Pending attestation cases you can approve or deny: {0}', value: statistics.pendingForUser } + { description: '#LDS#Pending attestation cases you can approve or deny: {0}', value: statistics.pendingForUser }, ]; } this.pendingAttestations.loading = false; } + + private showBusyIndicator(): void { + if (this.busyService.overlayRefs.length === 0) { + this.busyService.show(); + } + } } diff --git a/imxweb/projects/att/src/lib/runs/runs-grid/runs-grid.component.html b/imxweb/projects/att/src/lib/runs/runs-grid/runs-grid.component.html index 0968e95ca..9a6143604 100644 --- a/imxweb/projects/att/src/lib/runs/runs-grid/runs-grid.component.html +++ b/imxweb/projects/att/src/lib/runs/runs-grid/runs-grid.component.html @@ -1,71 +1,107 @@ - - + + - -
    - - - -
    -
    {{ item.UID_AttestationPolicy.Column.GetDisplayValue() }}
    -
    - {{ item.UID_AttestationPolicyGroup.Column.GetDisplayValue() }} -
    + + + {{ entitySchema?.Columns?.UID_AttestationPolicy?.Display }} + + +
    +
    {{ item.UID_AttestationPolicy.Column.GetDisplayValue() }}
    +
    + {{ item.UID_AttestationPolicyGroup.Column.GetDisplayValue() }}
    - - - - - - {{ item.RunCategory.Column.GetDisplayValue() }} - - - - - - - - - - - - - - - -
    - +
    +
    +
    + {{ + '#LDS#Started via policy collection "{0}"' | translate | ldsReplace: item.UID_AttestationPolicyGroup.Column.GetDisplayValue() + }} +
    +
    + + + + + + + {{ item.RunCategory.Column.GetDisplayValue() }} + + + + + + + {{ entitySchema?.Columns?.PolicyProcessed?.Display }} + + + + + {{ entitySchema?.Columns?.PolicyProcessed?.Display }} + + + +
    {{ item.PolicyProcessed.Column.GetValue() | shortDate }}
    + +
    + + + {{ entitySchema?.Columns?.DueDate?.Display }} + + +
    {{ item.DueDate.Column.GetValue() | shortDate }}
    + +
    + + + {{ '#LDS#Pending' | translate }} + + +
    {{ item.PendingCases.Column.GetDisplayValue() }}
    + +
    + + + {{ '#LDS#Closed' | translate }} + + +
    {{ item.ClosedCases.Column.GetDisplayValue() }}
    + +
    + + + {{ '#LDS#Progress' | translate }} + + + + + + + -
    -
    diff --git a/imxweb/projects/att/src/lib/runs/runs-grid/runs-grid.component.scss b/imxweb/projects/att/src/lib/runs/runs-grid/runs-grid.component.scss index 22e4bf075..ae7f3ca57 100644 --- a/imxweb/projects/att/src/lib/runs/runs-grid/runs-grid.component.scss +++ b/imxweb/projects/att/src/lib/runs/runs-grid/runs-grid.component.scss @@ -1,10 +1,7 @@ -@import '../../../../../../shared/scss/common-table.scss'; +@import 'base/mixins'; :host { - flex: 1 1 auto; - overflow: hidden; - display: flex; - flex-direction: column; + @include flex-column-container-fill(); ::ng-deep .mat-column-RunCategory, ::ng-deep .mat-column-ClosedCases, @@ -20,19 +17,5 @@ } .imx-table-card { - @include imx-flex-fill-control-hidden-overflow(); - -} - -.imx-table-container { - flex-grow: 1; - overflow: auto; -} - -.button-row { - @include imx-button-bar(); -} - -div[subtitle] { - font-size: smaller; + @include flex-column-container-fill(); } diff --git a/imxweb/projects/att/src/lib/runs/runs-grid/runs-grid.component.ts b/imxweb/projects/att/src/lib/runs/runs-grid/runs-grid.component.ts index 064067643..6dc5aaebc 100644 --- a/imxweb/projects/att/src/lib/runs/runs-grid/runs-grid.component.ts +++ b/imxweb/projects/att/src/lib/runs/runs-grid/runs-grid.component.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -24,43 +24,55 @@ * */ -import { OverlayRef } from '@angular/cdk/overlay'; import { Component, Input, OnInit } from '@angular/core'; import { EuiLoadingService, EuiSidesheetService } from '@elemental-ui/core'; import { TranslateService } from '@ngx-translate/core'; -import { CollectionLoadParameters, CompareOperator, DataModel, EntityCollectionData, EntitySchema, FilterData, FilterType, MethodDefinition, MethodDescriptor } from 'imx-qbm-dbts'; -import { PortalAttestationRun, RunStatisticsConfig, V2ApiClientMethodFactory } from 'imx-api-att'; -import { DataSourceToolbarExportMethod, DataSourceToolbarFilter, DataSourceToolbarGroupData, DataSourceToolbarSettings, DataSourceToolbarViewConfig, DataTableGroupedData, SettingsService } from 'qbm'; +import { PortalAttestationRun, RunStatisticsConfig, V2ApiClientMethodFactory } from '@imx-modules/imx-api-att'; +import { + CollectionLoadParameters, + CompareOperator, + DataModel, + EntityCollectionData, + EntitySchema, + FilterType, + MethodDefinition, + MethodDescriptor, + TypedEntityCollectionData, +} from '@imx-modules/imx-qbm-dbts'; +import { + calculateSidesheetWidth, + DataSourceToolbarExportMethod, + DataSourceToolbarFilter, + DataSourceToolbarViewConfig, + DataViewInitParameters, + DataViewSource, + SettingsService, +} from 'qbm'; + +import { ViewConfigData } from '@imx-modules/imx-api-qer'; +import { ViewConfigService } from 'qer'; +import { PermissionsService } from '../../admin/permissions.service'; import { ApiService } from '../../api.service'; -import { createGroupData } from '../../datamodel/datamodel-helper'; import { RunSidesheetComponent } from '../run-sidesheet.component'; import { RunsService } from '../runs.service'; -import { PermissionsService } from '../../admin/permissions.service'; -import { ViewConfigData } from 'imx-api-qer'; -import { ViewConfigService } from 'qer'; @Component({ selector: 'imx-runs-grid', templateUrl: './runs-grid.component.html', - styleUrls: ['./runs-grid.component.scss'] + styleUrls: ['./runs-grid.component.scss'], + providers: [DataViewSource], }) export class RunsGridComponent implements OnInit { - - /** - * Settings needed by the DataSourceToolbarComponent - */ - public dstSettings: DataSourceToolbarSettings; public readonly categoryBadgeColor = { Bad: 'red', Mediocre: 'orange', - Good: 'white' + Good: 'white', }; public entitySchema: EntitySchema; @Input() public uidAttestationPolicy; - public groupedData: { [key: string]: DataTableGroupedData } = {}; public attestationRunConfig: RunStatisticsConfig | undefined; public canSeeAttestationPolicies: boolean; @@ -70,14 +82,6 @@ export class RunsGridComponent implements OnInit { private runs: PortalAttestationRun[]; private filterOptions: DataSourceToolbarFilter[] | undefined = []; - private groupData: DataSourceToolbarGroupData; - /** - * Page size, start index, search and filtering options etc. - */ - private navigationState: CollectionLoadParameters; - private readonly orderBy = 'PolicyProcessed desc'; - - private filter: { filter: FilterData[] }; private dataModel: DataModel; private viewConfig: DataSourceToolbarViewConfig; private viewConfigPath = 'attestation/run'; @@ -90,47 +94,24 @@ export class RunsGridComponent implements OnInit { private readonly attService: ApiService, private readonly settingsService: SettingsService, private readonly permissions: PermissionsService, - private translate: TranslateService + private translate: TranslateService, + public dataSource: DataViewSource, ) { - this.entitySchema = this.attService.typedClient.PortalAttestationRun.GetSchema(); - + this.entitySchema = this.attService.typedClient.PortalAttestationRun.GetSchema(); } public async ngOnInit(): Promise { - this.filter = { - filter: this.uidAttestationPolicy == null ? [] : [{ - CompareOp: CompareOperator.Equal, - Type: FilterType.Compare, - ColumnName: 'UID_AttestationPolicy', - Value1: this.uidAttestationPolicy - }] - }; - this.navigationState = { ...{ PageSize: this.settingsService.DefaultPageSize, StartIndex: 0 }, ...this.filter }; const config = await this.attService.client.portal_attestation_config_get(); this.attestationRunConfig = config.AttestationRunConfig; this.progressCalcThreshold = config.ProgressCalculationThreshold; this.canSeeAttestationPolicies = await this.permissions.canSeeAttestationPolicies(); - let busyIndicator: OverlayRef; - setTimeout(() => busyIndicator = this.busyService.show()); + this.showBusyIndicator(); try { this.dataModel = await this.runsService.getDataModel(); this.viewConfig = await this.viewConfigService.getInitialDSTExtension(this.dataModel, this.viewConfigPath); - // We will check the configs for default state only on init - if (!this.viewConfigService.isDefaultConfigSet()) { - // If we have no default settings, we have a default - this.navigationState.OrderBy = this.orderBy; - } - this.filterOptions = this.dataModel.Filters; - this.groupData = createGroupData( - this.dataModel, - parameters => this.runsService.getGroupInfo({ ...{ PageSize: this.navigationState.PageSize, StartIndex: 0 }, ...parameters }), - this.uidAttestationPolicy == null ? [] : ['UID_AttestationPolicy'] - ); } finally { - setTimeout(() => { - this.busyService.hide(busyIndicator); - }); + this.busyService.hide(); } await this.getData(); @@ -139,51 +120,59 @@ export class RunsGridComponent implements OnInit { public async updateConfig(config: ViewConfigData): Promise { await this.viewConfigService.putViewConfig(config); this.viewConfig = await this.viewConfigService.getDSTExtensionChanges(this.viewConfigPath); - this.dstSettings.viewConfig = this.viewConfig; + this.dataSource.viewConfig.set(this.viewConfig); } public async deleteConfigById(id: string): Promise { await this.viewConfigService.deleteViewConfig(id); this.viewConfig = await this.viewConfigService.getDSTExtensionChanges(this.viewConfigPath); - this.dstSettings.viewConfig = this.viewConfig; + this.dataSource.viewConfig.set(this.viewConfig); } - public async getData(newState?: CollectionLoadParameters): Promise { - if (newState) { - const filter = this.filter.filter.concat(newState.filter ?? []); - this.navigationState = { ...newState, filter }; - } - - let overlayRef: OverlayRef; - setTimeout(() => overlayRef = this.busyService.show()); - - try { - const data = await this.attService.typedClient.PortalAttestationRun.Get(this.navigationState); - this.runs = data.Data; - this.dstSettings = { - displayedColumns: [ - this.entitySchema.Columns.UID_AttestationPolicy, - this.entitySchema.Columns.RunCategory, - this.entitySchema.Columns.PolicyProcessed, - this.entitySchema.Columns.DueDate, - this.entitySchema.Columns.PendingCases, - this.entitySchema.Columns.ClosedCases, - this.entitySchema.Columns.Progress - ], - dataSource: data, - entitySchema:this.entitySchema, - navigationState: this.navigationState, - filters: this.filterOptions, - dataModel: this.dataModel, - groupData: this.groupData, - viewConfig: this.viewConfig, - exportMethod: this.getExportMethod(), - }; - - this.hasPendingAttestations = this.runs?.some(run => run.PendingCases.value > 0); - } finally { - setTimeout(() => this.busyService.hide(overlayRef)); - } + public async getData(): Promise { + const displayedColumns = [ + this.entitySchema.Columns.UID_AttestationPolicy, + this.entitySchema.Columns.RunCategory, + this.entitySchema.Columns.PolicyProcessed, + this.entitySchema.Columns.DueDate, + this.entitySchema.Columns.PendingCases, + this.entitySchema.Columns.ClosedCases, + this.entitySchema.Columns.Progress, + ]; + const dataViewInitParameters: DataViewInitParameters = { + execute: (params: CollectionLoadParameters, signal: AbortSignal): Promise> => + this.attService.typedClient.PortalAttestationRun.Get( + { + ...params, + filter: [ + ...(params.filter || []), + ...(this.uidAttestationPolicy == null + ? [] + : [ + { + CompareOp: CompareOperator.Equal, + Type: FilterType.Compare, + ColumnName: 'UID_AttestationPolicy', + Value1: this.uidAttestationPolicy, + }, + ]), + ], + }, + { signal }, + ), + schema: this.entitySchema, + columnsToDisplay: displayedColumns, + dataModel: this.dataModel, + groupExecute: (column: string, params: CollectionLoadParameters, signal: AbortSignal) => { + return this.runsService.getGroupInfo({ ...params, by: column }); + }, + exportFunction: this.getExportMethod(), + viewConfig: this.viewConfig, + highlightEntity: (identity: PortalAttestationRun) => { + this.onRunChanged(identity); + }, + }; + this.dataSource.init(dataViewInitParameters); } public getExportMethod(): DataSourceToolbarExportMethod { @@ -192,58 +181,34 @@ export class RunsGridComponent implements OnInit { getMethod: (withProperties: string, PageSize?: number) => { let method: MethodDescriptor; if (PageSize) { - method = factory.portal_attestation_run_get({...this.navigationState, withProperties, PageSize, StartIndex: 0}); + method = factory.portal_attestation_run_get({ ...this.dataSource.state(), withProperties, PageSize, StartIndex: 0 }); } else { - method = factory.portal_attestation_run_get({...this.navigationState, withProperties}); + method = factory.portal_attestation_run_get({ ...this.dataSource.state(), withProperties }); } return new MethodDefinition(method); - } - } - } - - public async onSearch(keywords: string): Promise { - return this.getData({ - PageSize: this.navigationState.PageSize, - StartIndex: 0, - search: keywords - }); + }, + }; } public async onRunChanged(run: PortalAttestationRun): Promise { - await this.sideSheet.open(RunSidesheetComponent, { - title: await this.translate.get('#LDS#Heading View Attestation Run Details').toPromise(), - subTitle: run.GetEntity().GetDisplay(), - padding: '0px', - width: 'max(768px, 60%)', - testId: 'runs-grid-view-attestation-run-details', - data: { - run: await this.runsService.getSingleRun(run.GetEntity().GetKeys()[0]), - attestationRunConfig: this.attestationRunConfig, - canSeeAttestationPolicies: this.canSeeAttestationPolicies, - threshold: this.progressCalcThreshold, - completed: this.isCompleted(run) - } - }).afterClosed().toPromise(); - await this.getData(); - } - - public async onGroupingChange(groupKey: string): Promise { - let overlayRef: OverlayRef; - setTimeout(() => (overlayRef = this.busyService.show())); - - try { - const groupedData = this.groupedData[groupKey]; - groupedData.data = await this.attService.typedClient.PortalAttestationRun.Get(groupedData.navigationState); - groupedData.settings = { - displayedColumns: this.dstSettings.displayedColumns, - dataModel: this.dstSettings.dataModel, - dataSource: groupedData.data, - entitySchema: this.dstSettings.entitySchema, - navigationState: groupedData.navigationState - }; - } finally { - setTimeout(() => this.busyService.hide(overlayRef)); - } + await this.sideSheet + .open(RunSidesheetComponent, { + title: await this.translate.get('#LDS#Heading View Attestation Run Details').toPromise(), + subTitle: run.GetEntity().GetDisplay(), + padding: '0px', + width: calculateSidesheetWidth(1000), + testId: 'runs-grid-view-attestation-run-details', + data: { + run: await this.runsService.getSingleRun(run.GetEntity().GetKeys()[0]), + attestationRunConfig: this.attestationRunConfig, + canSeeAttestationPolicies: this.canSeeAttestationPolicies, + threshold: this.progressCalcThreshold, + completed: this.isCompleted(run), + }, + }) + .afterClosed() + .toPromise(); + await this.dataSource.updateState(); } public async sendReminderEmail(): Promise { @@ -251,6 +216,12 @@ export class RunsGridComponent implements OnInit { } public isCompleted(run: PortalAttestationRun): boolean { - return (run.ClosedCases.value + run.PendingCases.value) > 0 && run.PendingCases.value === 0; + return run.ClosedCases.value + run.PendingCases.value > 0 && run.PendingCases.value === 0; + } + + private showBusyIndicator(): void { + if (this.busyService.overlayRefs.length === 0) { + this.busyService.show(); + } } } diff --git a/imxweb/projects/att/src/lib/runs/runs-load-parameters.interface.ts b/imxweb/projects/att/src/lib/runs/runs-load-parameters.interface.ts index c368f28e8..721a60ff1 100644 --- a/imxweb/projects/att/src/lib/runs/runs-load-parameters.interface.ts +++ b/imxweb/projects/att/src/lib/runs/runs-load-parameters.interface.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -24,7 +24,7 @@ * */ -import { CollectionLoadParameters, FilterData } from 'imx-qbm-dbts'; +import { CollectionLoadParameters, FilterData } from '@imx-modules/imx-qbm-dbts'; export interface RunsLoadParameters extends CollectionLoadParameters { groupFilter?: FilterData[]; diff --git a/imxweb/projects/att/src/lib/runs/runs.component.html b/imxweb/projects/att/src/lib/runs/runs.component.html index 8fe59cc4d..fb1134d36 100644 --- a/imxweb/projects/att/src/lib/runs/runs.component.html +++ b/imxweb/projects/att/src/lib/runs/runs.component.html @@ -1,11 +1,18 @@ -
    -

    +
    +

    #LDS#Heading Attestation Runs -

    +

    + + + +
    - +
    - diff --git a/imxweb/projects/att/src/lib/runs/runs.component.scss b/imxweb/projects/att/src/lib/runs/runs.component.scss index f327036fa..f6551ebf8 100644 --- a/imxweb/projects/att/src/lib/runs/runs.component.scss +++ b/imxweb/projects/att/src/lib/runs/runs.component.scss @@ -8,17 +8,6 @@ .heading-wrapper { display: flex; align-items: flex-start; - - .helper-alert { - display: flex; - margin: 0 0 20px auto; - align-self: flex-end; - width: 50%; - - span { - display: block; - } - } } .imx-runs-grid { @@ -26,8 +15,4 @@ flex-direction: column; overflow: hidden; flex: 1 1 auto; - - ::ng-deep .eui-sidesheet-actions{ - background-color: transparent; - } } diff --git a/imxweb/projects/att/src/lib/runs/runs.component.ts b/imxweb/projects/att/src/lib/runs/runs.component.ts index e61f2f6fb..a82cdaa6f 100644 --- a/imxweb/projects/att/src/lib/runs/runs.component.ts +++ b/imxweb/projects/att/src/lib/runs/runs.component.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -24,15 +24,22 @@ * */ -import { Component } from '@angular/core'; - +import { AfterViewInit, Component, signal, ViewChild, WritableSignal } from '@angular/core'; +import { PortalAttestationRun } from '@imx-modules/imx-api-att'; +import { DataViewSource } from 'qbm'; +import { RunsGridComponent } from './runs-grid/runs-grid.component'; @Component({ templateUrl: './runs.component.html', - styleUrls: ['./runs.component.scss'] + styleUrls: ['./runs.component.scss'], }) -export class RunsComponent { +export class RunsComponent implements AfterViewInit { + public dataSource: WritableSignal | undefined> = signal(undefined); public canSeeAttestationPolicies: boolean; + @ViewChild('runsGridComponent', { static: false }) public runsGridComponent: RunsGridComponent; + ngAfterViewInit(): void { + this.dataSource.set(this.runsGridComponent?.dataSource); + } // HelpChapterID = 2A288F2C-345B-4A0D-BD88-0C488289C495 } diff --git a/imxweb/projects/att/src/lib/runs/runs.service.ts b/imxweb/projects/att/src/lib/runs/runs.service.ts index 4269f71b8..36336344d 100644 --- a/imxweb/projects/att/src/lib/runs/runs.service.ts +++ b/imxweb/projects/att/src/lib/runs/runs.service.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -24,10 +24,8 @@ * */ -import { OverlayRef } from '@angular/cdk/overlay'; import { Injectable } from '@angular/core'; -import { EuiDownloadOptions } from '@elemental-ui/core'; -import { EuiLoadingService, EuiSidesheetService } from '@elemental-ui/core'; +import { EuiDownloadOptions, EuiLoadingService, EuiSidesheetService } from '@elemental-ui/core'; import { TranslateService } from '@ngx-translate/core'; import { @@ -37,7 +35,7 @@ import { PortalAttestationRun, PortalAttestationRunApprovers, V2ApiClientMethodFactory, -} from 'imx-api-att'; +} from '@imx-modules/imx-api-att'; import { CollectionLoadParameters, @@ -49,9 +47,9 @@ import { GroupInfoData, MethodDefinition, TypedEntityCollectionData, -} from 'imx-qbm-dbts'; +} from '@imx-modules/imx-qbm-dbts'; -import { AppConfigService, ElementalUiConfigService, SnackBarService } from 'qbm'; +import { AppConfigService, calculateSidesheetWidth, ElementalUiConfigService, SnackBarService } from 'qbm'; import { ApiService } from '../api.service'; import { AttestationCaseLoadParameters } from '../attestation-history/attestation-case-load-parameters.interface'; import { AttestationCasesService } from '../decision/attestation-cases.service'; @@ -72,7 +70,7 @@ export class RunsService { private readonly translate: TranslateService, private readonly busyService: EuiLoadingService, private readonly config: AppConfigService, - private readonly attestationApprove: AttestationCasesService + private readonly attestationApprove: AttestationCasesService, ) {} public async getDataModel(): Promise { @@ -83,7 +81,7 @@ export class RunsService { const { withProperties, groupFilter, search, OrderBy, ...params } = parameters; return this.attService.client.portal_attestation_run_group_get({ ...params, - filter: parameters.groupFilter, + filter: [...(parameters.groupFilter || []), ...(parameters.filter || [])], withcount: true, }); } @@ -108,23 +106,24 @@ export class RunsService { subTitle: runs.length === 1 ? runs[0].GetEntity().GetDisplay() : '', padding: '0px', testId: 'attestationruns-sendReminder-sidesheet', - width: '600px', + width: calculateSidesheetWidth(600, 0.4), data, }) .afterClosed() .toPromise(); if (result) { - let overlayRef: OverlayRef; - setTimeout(() => (overlayRef = this.busyService.show())); + if (this.busyService.overlayRefs.length === 0) { + this.busyService.show(); + } - let success: boolean; + let success = false; try { if (approvers == null) { approvers = []; for (const run of runs) { - (await this.getApprovers(run)).Data.forEach((approver) => approvers.push(approver)); + (await this.getApprovers(run)).Data.forEach((approver) => approvers?.push(approver)); } } @@ -140,7 +139,7 @@ export class RunsService { this.snackBar.open({ key: '#LDS#The reminder mails have been sent.' }); } - setTimeout(() => this.busyService.hide(overlayRef)); + this.busyService.hide(); } } } @@ -162,7 +161,7 @@ export class RunsService { public getCasesForRun( uidRun: string, - parameter: CollectionLoadParameters + parameter: CollectionLoadParameters, ): Promise> { return this.attService.typedClient.PortalAttestationCase.Get({ ...parameter, diff --git a/imxweb/projects/att/src/lib/runs/send-reminder-mail.component.html b/imxweb/projects/att/src/lib/runs/send-reminder-mail.component.html index 1de9545d1..597a7d4e6 100644 --- a/imxweb/projects/att/src/lib/runs/send-reminder-mail.component.html +++ b/imxweb/projects/att/src/lib/runs/send-reminder-mail.component.html @@ -1,17 +1,21 @@
    - + #LDS#Here you can optionally add a custom message to the reminder. #LDS#Each attestor will receive a reminder. {{ '#LDS#Message' | translate }} - +
    -
    - -
    \ No newline at end of file +
    diff --git a/imxweb/projects/att/src/lib/runs/send-reminder-mail.component.scss b/imxweb/projects/att/src/lib/runs/send-reminder-mail.component.scss index c516f36bd..fb4877cf2 100644 --- a/imxweb/projects/att/src/lib/runs/send-reminder-mail.component.scss +++ b/imxweb/projects/att/src/lib/runs/send-reminder-mail.component.scss @@ -1,4 +1,4 @@ -@import "@elemental-ui/core/src/styles/_eui_palette.scss"; +@import '@elemental-ui/core/src/styles/_eui_palette.scss'; :host { display: flex; @@ -12,33 +12,5 @@ flex-direction: column; flex: 1 1 auto; overflow-y: auto; -} - -.mat-form-field { - width: 100%; padding: 20px; } - -textarea.mat-input-element.cdk-textarea-autosize { - box-sizing: content-box; -} - -.helper-alert { - display: flex; - padding: 20px 20px 0 20px; - flex-direction: column; - span { - display: block; - } -} - -.imx-button-bar { - display: flex; - justify-content: flex-end; - border-top: $color-gray-20 1px solid; - padding: 0px 20px 20px 8px; - > * { - margin-left: 10px; - margin-top: 20px; - } -} diff --git a/imxweb/projects/att/src/lib/runs/send-reminder-mail.component.ts b/imxweb/projects/att/src/lib/runs/send-reminder-mail.component.ts index ed5cc91f3..ed4d8139b 100644 --- a/imxweb/projects/att/src/lib/runs/send-reminder-mail.component.ts +++ b/imxweb/projects/att/src/lib/runs/send-reminder-mail.component.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -31,7 +31,7 @@ import { Subscription } from 'rxjs'; @Component({ templateUrl: './send-reminder-mail.component.html', - styleUrls: ['./send-reminder-mail.component.scss'] + styleUrls: ['./send-reminder-mail.component.scss'], }) export class SendReminderMailComponent implements OnDestroy { public showHelper = true; @@ -40,13 +40,16 @@ export class SendReminderMailComponent implements OnDestroy { private readonly subscriptions: Subscription[] = []; - constructor(@Inject(EUI_SIDESHEET_DATA) data: { message: string }, public readonly sideSheetRef: EuiSidesheetRef) { + constructor( + @Inject(EUI_SIDESHEET_DATA) data: { message: string }, + public readonly sideSheetRef: EuiSidesheetRef, + ) { this.message = new UntypedFormControl(data.message); - this.subscriptions.push(this.message.valueChanges.subscribe(value => data.message = value)); + this.subscriptions.push(this.message.valueChanges.subscribe((value) => (data.message = value))); } public ngOnDestroy(): void { - this.subscriptions.forEach(s => s.unsubscribe()); + this.subscriptions.forEach((s) => s.unsubscribe()); } public onHelperDismissed(): void { diff --git a/imxweb/projects/att/src/public_api.ts b/imxweb/projects/att/src/public_api.ts index 82114b411..939c9e39d 100644 --- a/imxweb/projects/att/src/public_api.ts +++ b/imxweb/projects/att/src/public_api.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -30,24 +30,24 @@ export { AttestationRunsModule } from './lib/runs/attestation-runs.module'; export { AttestationWrapperComponent } from './lib/runs/attestation/attestation-wrapper/attestation-wrapper.component'; export { RunsComponent } from './lib/runs/runs.component'; export { RunsGridComponent } from './lib/runs/runs-grid/runs-grid.component'; -export { PolicyListComponent} from './lib/policies/policy-list/policy-list.component'; -export { EditMasterDataComponent} from './lib/policies/edit-master-data/edit-master-data.component'; -export { AttestationCasesComponent} from './lib/policies/attestation-cases/attestation-cases.component'; -export { AttestationCasesComponentParameter} from './lib/policies/attestation-cases/attestation-cases-component-parameter.interface'; +export { PolicyListComponent } from './lib/policies/policy-list/policy-list.component'; +export { EditMasterDataComponent } from './lib/policies/edit-master-data/edit-master-data.component'; +export { AttestationCasesComponent } from './lib/policies/attestation-cases/attestation-cases.component'; +export { AttestationCasesComponentParameter } from './lib/policies/attestation-cases/attestation-cases-component-parameter.interface'; export { AttestationHistoryModule } from './lib/attestation-history/attestation-history.module'; export { PickCategoryModule } from './lib/pick-category/pick-category.module'; export { AttestationHistoryComponent } from './lib/attestation-history/attestation-history.component'; export { AttestationHistoryService } from './lib/attestation-history/attestation-history.service'; export { AttestationHistoryCase } from './lib/attestation-history/attestation-history-case'; export { AttestationHistoryActionService } from './lib/attestation-history/attestation-history-action.service'; -export { PolicyService} from './lib/policies/policy.service'; +export { PolicyService } from './lib/policies/policy.service'; export { ApiService } from './lib/api.service'; export { canSeeAttestationPolicies } from './lib/admin/permissions-helper'; export { AttestationFeatureGuardService } from './lib/attestation-feature-guard.service'; export { IdentityAttestationService } from './lib/identity-attestation.service'; export { NewUserModule } from './lib/new-user/new-user.module'; export { ClaimDeviceModule } from './lib/claim-device/claim-device.module'; -export {PolicyGroupModule} from './lib/policy-group/policy-group.module'; -export {PolicyGroupListComponent} from './lib/policy-group/policy-group-list/policy-group-list.component'; -export {EditPolicyGroupSidesheetComponent} from './lib/policy-group/edit-policy-group-sidesheet/edit-policy-group-sidesheet.component'; -export {OpenSidesheetComponent} from './lib/new-user/open-sidesheet.component'; +export { PolicyGroupModule } from './lib/policy-group/policy-group.module'; +export { PolicyGroupListComponent } from './lib/policy-group/policy-group-list/policy-group-list.component'; +export { EditPolicyGroupSidesheetComponent } from './lib/policy-group/edit-policy-group-sidesheet/edit-policy-group-sidesheet.component'; +export { OpenSidesheetComponent } from './lib/new-user/open-sidesheet.component'; diff --git a/imxweb/projects/att/src/test.ts b/imxweb/projects/att/src/test.ts index fba6795cd..c0be3629d 100644 --- a/imxweb/projects/att/src/test.ts +++ b/imxweb/projects/att/src/test.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -26,26 +26,17 @@ // This file is required by karma.conf.js and loads recursively all the .spec and framework files -import 'core-js/es7/reflect'; -import 'zone.js/dist/zone'; -import 'zone.js/dist/zone-testing'; +// Zone must be imported first. Be careful with prettier import organizing +import 'zone.js'; +import 'zone.js/testing'; + import { getTestBed } from '@angular/core/testing'; -import { - BrowserDynamicTestingModule, - platformBrowserDynamicTesting -} from '@angular/platform-browser-dynamic/testing'; +import { BrowserDynamicTestingModule, platformBrowserDynamicTesting } from '@angular/platform-browser-dynamic/testing'; +import 'core-js/es/reflect'; import { TestHelperModule } from 'qbm'; import { AttDefaultMocks } from './default-mocks.spec'; -declare const require: any; - // First, initialize the Angular testing environment. -getTestBed().initTestEnvironment( - [BrowserDynamicTestingModule, TestHelperModule], - platformBrowserDynamicTesting() -); -// Then we find all the tests. -const context = require.context('./', true, /\.spec\.ts$/); -// And load the modules. -context.keys().map(context); -AttDefaultMocks.registerDefaultMocks(); \ No newline at end of file +getTestBed().initTestEnvironment([BrowserDynamicTestingModule, TestHelperModule], platformBrowserDynamicTesting()); + +AttDefaultMocks.registerDefaultMocks(); diff --git a/imxweb/projects/att/tsconfig.lib.json b/imxweb/projects/att/tsconfig.lib.json index b77b13c01..9786008a7 100644 --- a/imxweb/projects/att/tsconfig.lib.json +++ b/imxweb/projects/att/tsconfig.lib.json @@ -5,11 +5,13 @@ "outDir": "../../out-tsc/lib", "declaration": true, "declarationMap": true, + "sourceMap": true, "inlineSources": true, - "types": [] + "types": [], + "strictNullChecks": true }, - "exclude": [ - "src/test.ts", - "**/*.spec.ts" - ] + "angularCompilerOptions": { + "strictTemplates": true + }, + "exclude": ["src/test.ts", "**/*.spec.ts"] } diff --git a/imxweb/projects/att/tsconfig.lib.prod.json b/imxweb/projects/att/tsconfig.lib.prod.json index 61c7592e7..fb40dbbb0 100644 --- a/imxweb/projects/att/tsconfig.lib.prod.json +++ b/imxweb/projects/att/tsconfig.lib.prod.json @@ -3,8 +3,5 @@ "extends": "./tsconfig.lib.json", "compilerOptions": { "declarationMap": false - }, - "angularCompilerOptions": { - "enableIvy": true } } diff --git a/imxweb/projects/att/tsconfig.spec.json b/imxweb/projects/att/tsconfig.spec.json index 16da33db0..6bd74e1f7 100644 --- a/imxweb/projects/att/tsconfig.spec.json +++ b/imxweb/projects/att/tsconfig.spec.json @@ -1,17 +1,10 @@ { "extends": "../../tsconfig.json", "compilerOptions": { + "strictNullChecks": false, "outDir": "../../out-tsc/spec", - "types": [ - "jasmine", - "node" - ] + "types": ["jasmine", "node"] }, - "files": [ - "src/test.ts" - ], - "include": [ - "**/*.spec.ts", - "**/*.d.ts" - ] + "files": ["src/test.ts"], + "include": ["**/*.spec.ts", "**/*.d.ts"] } diff --git a/imxweb/projects/att/tslint.json b/imxweb/projects/att/tslint.json deleted file mode 100644 index 8bab15f53..000000000 --- a/imxweb/projects/att/tslint.json +++ /dev/null @@ -1,17 +0,0 @@ -{ - "extends": "../../tslint.json", - "rules": { - "directive-selector": [ - true, - "attribute", - "imx", - "camelCase" - ], - "component-selector": [ - true, - "element", - "imx", - "kebab-case" - ] - } -} diff --git a/imxweb/projects/cpl/.compodocrc.json b/imxweb/projects/cpl/.compodocrc.json index a54cb8453..6312ead7f 100644 --- a/imxweb/projects/cpl/.compodocrc.json +++ b/imxweb/projects/cpl/.compodocrc.json @@ -1,6 +1,6 @@ { "name": "IMX Web - CPL Library", - "output": "../../documentation/v92/cpl", + "output": "../../documentation/v93/cpl", "theme": "material", "assetsFolder": "../../compodoc/assets", "customLogo": "../../compodoc/assets/images/oneidentity-logo.png", diff --git a/imxweb/projects/cpl/.eslintrc.json b/imxweb/projects/cpl/.eslintrc.json new file mode 100644 index 000000000..be298cb71 --- /dev/null +++ b/imxweb/projects/cpl/.eslintrc.json @@ -0,0 +1,35 @@ +{ + "extends": "../../.eslintrc.json", + "ignorePatterns": ["!**/*", "**/*.spec.ts"], + "overrides": [ + { + "files": ["*.ts"], + "parserOptions": { + "project": ["imxweb/projects/cpl/tsconfig.lib.json", "imxweb/projects/cpl/tsconfig.spec.json"], + "createDefaultProgram": true + }, + "rules": { + "@angular-eslint/directive-selector": [ + "error", + { + "type": "attribute", + "prefix": "imx", + "style": "camelCase" + } + ], + "@angular-eslint/component-selector": [ + "error", + { + "type": "element", + "prefix": "imx", + "style": "kebab-case" + } + ] + } + }, + { + "files": ["*.html"], + "rules": {} + } + ] +} diff --git a/imxweb/projects/cpl/imx-plugin-config.json b/imxweb/projects/cpl/imx-plugin-config.json index ce7c7f144..b20a3f2eb 100644 --- a/imxweb/projects/cpl/imx-plugin-config.json +++ b/imxweb/projects/cpl/imx-plugin-config.json @@ -1,8 +1,9 @@ { - "qer-app-portal": [ - { - "Container": "cpl", - "Name": "CplConfigModule" - } - ] -} \ No newline at end of file + "qer-app-portal": [ + { + "Container": "cpl", + "Condition": "COMPLIANCE", + "Name": "CplConfigModule" + } + ] +} diff --git a/imxweb/projects/cpl/karma.conf.js b/imxweb/projects/cpl/karma.conf.js index d7a9db062..3e53a3ac8 100644 --- a/imxweb/projects/cpl/karma.conf.js +++ b/imxweb/projects/cpl/karma.conf.js @@ -15,7 +15,7 @@ module.exports = function (config) { require('karma-junit-reporter'), ], client: { - clearContext: false // leave Jasmine Spec Runner output visible in browser + clearContext: false, // leave Jasmine Spec Runner output visible in browser }, coverageIstanbulReporter: { dir: require('path').join(__dirname, 'results'), @@ -23,14 +23,14 @@ module.exports = function (config) { fixWebpackSourcePaths: true, 'report-config': { html: { - subdir: 'coverage-html' + subdir: 'coverage-html', }, }, thresholds: { statements: 0, branches: 0, functions: 0, - lines: 0 + lines: 0, }, }, junitReporter: { @@ -40,13 +40,14 @@ module.exports = function (config) { port: 9876, captureTimeout: 210000, browserDisconnectTolerance: 3, - browserDisconnectTimeout : 210000, - browserNoActivityTimeout : 210000, + browserDisconnectTimeout: 210000, + browserNoActivityTimeout: 210000, colors: true, logLevel: config.LOG_INFO, autoWatch: true, browsers: ['Chrome'], singleRun: false, - restartOnFileChange: true + failOnEmptyTestSuite: false, + restartOnFileChange: true, }); }; diff --git a/imxweb/projects/cpl/ng-package.dynamic.json b/imxweb/projects/cpl/ng-package.dynamic.json index b14f6657f..3bd1e3cc7 100644 --- a/imxweb/projects/cpl/ng-package.dynamic.json +++ b/imxweb/projects/cpl/ng-package.dynamic.json @@ -16,12 +16,11 @@ "@elemental-ui/core", "@ngx-translate/core", "@ngx-translate/http-loader", - "applicationinsights-js", "billboard.js" ], - "dest": "../../html/cpl", + "dest": "../../html/qer-app-portal/cpl", "lib": { "entryFile": "src/public_api.ts", - "styleIncludePaths": ["../../shared/assets"] + "styleIncludePaths": ["../../shared/scss"] } } diff --git a/imxweb/projects/cpl/ng-package.json b/imxweb/projects/cpl/ng-package.json index e19d580ba..62e32f54a 100644 --- a/imxweb/projects/cpl/ng-package.json +++ b/imxweb/projects/cpl/ng-package.json @@ -3,6 +3,6 @@ "dest": "../../dist/cpl", "lib": { "entryFile": "src/public_api.ts", - "styleIncludePaths": ["../../shared/assets"] + "styleIncludePaths": ["../../shared/scss"] } } diff --git a/imxweb/projects/cpl/package.json b/imxweb/projects/cpl/package.json index 22d4e9b12..4d1ab29df 100644 --- a/imxweb/projects/cpl/package.json +++ b/imxweb/projects/cpl/package.json @@ -1,6 +1,6 @@ { "name": "cpl", - "version": "9.2.1", + "version": "9.3.0", "private": true, "bundledDependencies": [ "imx-api-cpl" diff --git a/imxweb/projects/cpl/project.json b/imxweb/projects/cpl/project.json new file mode 100644 index 000000000..ba9634722 --- /dev/null +++ b/imxweb/projects/cpl/project.json @@ -0,0 +1,64 @@ +{ + "$schema": "../../node_modules/nx/schemas/project-schema.json", + "name": "cpl", + "sourceRoot": "projects/cpl/src", + "implicitDependencies": ["qer"], + "projectType": "library", + "generators": { + "@schematics/angular:component": { + "style": "scss" + } + }, + "prefix": "imx", + "targets": { + "build": { + "executor": "@angular-devkit/build-angular:ng-packagr", + "options": { + "tsConfig": "projects/cpl/tsconfig.lib.json", + "project": "projects/cpl/ng-package.json" + }, + "configurations": { + "production": { + "tsConfig": "projects/cpl/tsconfig.lib.prod.json" + }, + "development": { + "tsConfig": "projects/cpl/tsconfig.lib.json" + }, + "dynamic": { + "project": "projects/cpl/ng-package.dynamic.json" + }, + "remote-dev": { + "tsConfig": "projects/cpl/tsconfig.lib.json" + }, + "remote-qs": { + "tsConfig": "projects/cpl/tsconfig.lib.json" + } + }, + "outputs": ["{workspaceRoot}/dist/cpl"] + }, + "test": { + "executor": "@angular-devkit/build-angular:karma", + "options": { + "main": "projects/cpl/src/test.ts", + "tsConfig": "projects/cpl/tsconfig.spec.json", + "karmaConfig": "projects/cpl/karma.conf.js", + "stylePreprocessorOptions": { + "includePaths": [ + "./shared/assets", + "./shared/scss", + "./node_modules", + "./node_modules/@elemental-ui/cadence-icon", + "./node_modules/@elemental-ui/core" + ] + } + } + }, + "lint": { + "executor": "@angular-devkit/build-angular:tslint", + "options": { + "tsConfig": ["projects/cpl/tsconfig.lib.json", "projects/cpl/tsconfig.spec.json"], + "exclude": ["**/node_modules/**", "**/*.spec.ts", "**/*.json"] + } + } + } +} diff --git a/imxweb/projects/cpl/src/lib/api.service.ts b/imxweb/projects/cpl/src/lib/api.service.ts index 688882b3f..63d7ed28c 100644 --- a/imxweb/projects/cpl/src/lib/api.service.ts +++ b/imxweb/projects/cpl/src/lib/api.service.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -26,12 +26,12 @@ import { Injectable } from '@angular/core'; -import { V2Client, TypedClient } from 'imx-api-cpl'; -import { ApiClient } from 'imx-qbm-dbts'; +import { V2Client, TypedClient } from '@imx-modules/imx-api-cpl'; +import { ApiClient } from '@imx-modules/imx-qbm-dbts'; import { AppConfigService, ClassloggerService, ImxTranslationProviderService } from 'qbm'; @Injectable({ - providedIn: 'root' + providedIn: 'root', }) export class ApiService { private tc: TypedClient; @@ -51,7 +51,8 @@ export class ApiService { constructor( private readonly config: AppConfigService, private readonly logger: ClassloggerService, - private readonly translationProvider: ImxTranslationProviderService) { + private readonly translationProvider: ImxTranslationProviderService, + ) { try { this.logger.debug(this, 'Initializing CPL API service'); diff --git a/imxweb/projects/cpl/src/lib/cpl-config.module.ts b/imxweb/projects/cpl/src/lib/cpl-config.module.ts index f0202e3a7..da2a76823 100644 --- a/imxweb/projects/cpl/src/lib/cpl-config.module.ts +++ b/imxweb/projects/cpl/src/lib/cpl-config.module.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -50,33 +50,30 @@ import { FormsModule, ReactiveFormsModule } from '@angular/forms'; import { ComplianceRulesGuardService } from './guards/compliance-rules-guard.service'; import { RuleViolationsGuardService } from './guards/rule-violations-guard.service'; import { MatCardModule } from '@angular/material/card'; -import { RequestModule} from './request/request.module'; +import { RequestModule } from './request/request.module'; const routes: Routes = [ { path: 'compliance/rules', component: RulesComponent, canActivate: [RouteGuardService, ComplianceRulesGuardService], resolve: [RouteGuardService], - data:{ - contextId: HELP_CONTEXTUAL.ComplianceRules - } + data: { + contextId: HELP_CONTEXTUAL.ComplianceRules, + }, }, { path: 'compliance/rulesviolations/approve', component: RulesViolationsComponent, canActivate: [RouteGuardService, RuleViolationsGuardService], resolve: [RouteGuardService], - data:{ - contextId: HELP_CONTEXTUAL.ComplianceRulesViolationsApprove - } + data: { + contextId: HELP_CONTEXTUAL.ComplianceRulesViolationsApprove, + }, }, ]; @NgModule({ - declarations: [ - DashboardPluginComponent, - CartItemComplianceCheckComponent, - ], + declarations: [DashboardPluginComponent, CartItemComplianceCheckComponent], imports: [ CommonModule, CdrModule, @@ -96,11 +93,14 @@ const routes: Routes = [ TilesModule, TranslateModule, EuiCoreModule, - IdentityRuleViolationsModule + IdentityRuleViolationsModule, ], }) export class CplConfigModule { - constructor(private readonly initializer: InitService, private readonly logger: ClassloggerService) { + constructor( + private readonly initializer: InitService, + private readonly logger: ClassloggerService, + ) { this.logger.info(this, '🔥 CPL loaded'); this.initializer.onInit(routes); this.logger.info(this, '▶︝ CPL initialized'); diff --git a/imxweb/projects/cpl/src/lib/dashboard-plugin/dashboard-plugin.component.html b/imxweb/projects/cpl/src/lib/dashboard-plugin/dashboard-plugin.component.html index 00dbfd4ae..11d748799 100644 --- a/imxweb/projects/cpl/src/lib/dashboard-plugin/dashboard-plugin.component.html +++ b/imxweb/projects/cpl/src/lib/dashboard-plugin/dashboard-plugin.component.html @@ -1,5 +1,9 @@ - - \ No newline at end of file + + diff --git a/imxweb/projects/cpl/src/lib/dashboard-plugin/dashboard-plugin.component.ts b/imxweb/projects/cpl/src/lib/dashboard-plugin/dashboard-plugin.component.ts index 9610327ad..0c3db4182 100644 --- a/imxweb/projects/cpl/src/lib/dashboard-plugin/dashboard-plugin.component.ts +++ b/imxweb/projects/cpl/src/lib/dashboard-plugin/dashboard-plugin.component.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -31,23 +31,20 @@ import { DashboardService, PendingItemsType, UserModelService } from 'qer'; import { CplPermissionsService } from '../rules/admin/cpl-permissions.service'; @Component({ - templateUrl: './dashboard-plugin.component.html' + templateUrl: './dashboard-plugin.component.html', }) export class DashboardPluginComponent implements OnInit { - public pendingItems: PendingItemsType; - public isExceptionAdmin = false; constructor( public readonly router: Router, private readonly dashboardService: DashboardService, private readonly permissionService: CplPermissionsService, - private readonly userModelSvc: UserModelService - ) { } + private readonly userModelSvc: UserModelService, + ) {} public async ngOnInit(): Promise { - const busy = this.dashboardService.beginBusy(); try { diff --git a/imxweb/projects/cpl/src/lib/guards/compliance-rules-guard.service.ts b/imxweb/projects/cpl/src/lib/guards/compliance-rules-guard.service.ts index 8a1d054f7..cc8ed34d0 100644 --- a/imxweb/projects/cpl/src/lib/guards/compliance-rules-guard.service.ts +++ b/imxweb/projects/cpl/src/lib/guards/compliance-rules-guard.service.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -25,7 +25,7 @@ */ import { Injectable } from '@angular/core'; -import { CanActivate, Router } from '@angular/router'; +import { Router } from '@angular/router'; import { AppConfigService } from 'qbm'; import { CplPermissionsService } from '../rules/admin/cpl-permissions.service'; @@ -33,17 +33,17 @@ import { CplPermissionsService } from '../rules/admin/cpl-permissions.service'; @Injectable({ providedIn: 'root', }) -export class ComplianceRulesGuardService implements CanActivate { +export class ComplianceRulesGuardService { constructor( private readonly permissionService: CplPermissionsService, private readonly appConfig: AppConfigService, - private readonly router: Router - ) { } + private readonly router: Router, + ) {} public async canActivate(): Promise { const userRuleStatistics = await this.permissionService.isRuleStatistics(); if (!userRuleStatistics) { - this.router.navigate([this.appConfig.Config.routeConfig.start], { queryParams: {} }); + this.router.navigate([this.appConfig.Config.routeConfig?.start], { queryParams: {} }); return false; } return true; diff --git a/imxweb/projects/cpl/src/lib/guards/rule-violations-guard.service.ts b/imxweb/projects/cpl/src/lib/guards/rule-violations-guard.service.ts index fdb529509..d9d8e6aa9 100644 --- a/imxweb/projects/cpl/src/lib/guards/rule-violations-guard.service.ts +++ b/imxweb/projects/cpl/src/lib/guards/rule-violations-guard.service.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -25,7 +25,7 @@ */ import { Injectable } from '@angular/core'; -import { CanActivate, Router } from '@angular/router'; +import { Router } from '@angular/router'; import { AppConfigService } from 'qbm'; import { CplPermissionsService } from '../rules/admin/cpl-permissions.service'; @@ -33,17 +33,17 @@ import { CplPermissionsService } from '../rules/admin/cpl-permissions.service'; @Injectable({ providedIn: 'root', }) -export class RuleViolationsGuardService implements CanActivate { +export class RuleViolationsGuardService { constructor( private readonly permissionService: CplPermissionsService, private readonly appConfig: AppConfigService, - private readonly router: Router - ) { } + private readonly router: Router, + ) {} public async canActivate(): Promise { const isExceptionAdmin = await this.permissionService.isExceptionAdmin(); if (!isExceptionAdmin) { - this.router.navigate([this.appConfig.Config.routeConfig.start], { queryParams: {} }); + this.router.navigate([this.appConfig.Config.routeConfig?.start], { queryParams: {} }); return false; } return isExceptionAdmin; diff --git a/imxweb/projects/cpl/src/lib/identity-rule-violations/identity-rule-violations-mitigation-control/identity-rule-violations-mitigation-control.component.html b/imxweb/projects/cpl/src/lib/identity-rule-violations/identity-rule-violations-mitigation-control/identity-rule-violations-mitigation-control.component.html index 54403ed33..61ed39837 100644 --- a/imxweb/projects/cpl/src/lib/identity-rule-violations/identity-rule-violations-mitigation-control/identity-rule-violations-mitigation-control.component.html +++ b/imxweb/projects/cpl/src/lib/identity-rule-violations/identity-rule-violations-mitigation-control/identity-rule-violations-mitigation-control.component.html @@ -1,9 +1,13 @@
    - - - + + -
    \ No newline at end of file +
    diff --git a/imxweb/projects/cpl/src/lib/identity-rule-violations/identity-rule-violations-mitigation-control/identity-rule-violations-mitigation-control.component.scss b/imxweb/projects/cpl/src/lib/identity-rule-violations/identity-rule-violations-mitigation-control/identity-rule-violations-mitigation-control.component.scss index e110d11b2..248a268c5 100644 --- a/imxweb/projects/cpl/src/lib/identity-rule-violations/identity-rule-violations-mitigation-control/identity-rule-violations-mitigation-control.component.scss +++ b/imxweb/projects/cpl/src/lib/identity-rule-violations/identity-rule-violations-mitigation-control/identity-rule-violations-mitigation-control.component.scss @@ -1 +1 @@ -// add styles if necessary \ No newline at end of file +// add styles if necessary diff --git a/imxweb/projects/cpl/src/lib/identity-rule-violations/identity-rule-violations-mitigation-control/identity-rule-violations-mitigation-control.component.ts b/imxweb/projects/cpl/src/lib/identity-rule-violations/identity-rule-violations-mitigation-control/identity-rule-violations-mitigation-control.component.ts index 2ed7d93b7..1edae39eb 100644 --- a/imxweb/projects/cpl/src/lib/identity-rule-violations/identity-rule-violations-mitigation-control/identity-rule-violations-mitigation-control.component.ts +++ b/imxweb/projects/cpl/src/lib/identity-rule-violations/identity-rule-violations-mitigation-control/identity-rule-violations-mitigation-control.component.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -24,28 +24,33 @@ * */ -import { OverlayRef } from '@angular/cdk/overlay'; import { Component, Inject, OnInit } from '@angular/core'; -import { EuiLoadingService, EUI_SIDESHEET_DATA } from '@elemental-ui/core'; -import { CollectionLoadParameters, EntitySchema, ExtendedTypedEntityCollection, IClientProperty, TypedEntity } from 'imx-qbm-dbts'; +import { EUI_SIDESHEET_DATA, EuiLoadingService } from '@elemental-ui/core'; +import { + CollectionLoadParameters, + EntitySchema, + ExtendedTypedEntityCollection, + IClientProperty, + TypedEntity, +} from '@imx-modules/imx-qbm-dbts'; import { DataSourceToolbarSettings } from 'qbm'; @Component({ selector: 'imx-identity-rule-violations-mitigation-control', templateUrl: './identity-rule-violations-mitigation-control.component.html', - styleUrls: ['./identity-rule-violations-mitigation-control.component.scss'] + styleUrls: ['./identity-rule-violations-mitigation-control.component.scss'], }) export class IdentityRuleViolationsMitigationControlComponent implements OnInit { - public dstSettings: DataSourceToolbarSettings; constructor( private readonly busy: EuiLoadingService, - @Inject(EUI_SIDESHEET_DATA) public data: { - getData: (param: CollectionLoadParameters) => Promise>, - entitySchema: EntitySchema, - displayedColumns: IClientProperty[] - } - ) { } + @Inject(EUI_SIDESHEET_DATA) + public data: { + getData: (param: CollectionLoadParameters) => Promise>; + entitySchema: EntitySchema; + displayedColumns: IClientProperty[]; + }, + ) {} public async ngOnInit(): Promise { this.getData({}); @@ -56,23 +61,20 @@ export class IdentityRuleViolationsMitigationControlComponent implements OnInit } public async getData(param: CollectionLoadParameters): Promise { - let overlay: OverlayRef; - - setTimeout(() => { overlay = this.busy.show(); }); + if (this.busy.overlayRefs.length === 0) { + this.busy.show(); + } try { - const dataSource = await this.data.getData(param); this.dstSettings = { displayedColumns: this.data.displayedColumns, dataSource, entitySchema: this.data.entitySchema, - navigationState: param + navigationState: param, }; } finally { - setTimeout(() => this.busy.hide(overlay)); + this.busy.hide(); } - } - } diff --git a/imxweb/projects/cpl/src/lib/identity-rule-violations/identity-rule-violations.component.html b/imxweb/projects/cpl/src/lib/identity-rule-violations/identity-rule-violations.component.html index 4e9aea876..8ba15ad21 100644 --- a/imxweb/projects/cpl/src/lib/identity-rule-violations/identity-rule-violations.component.html +++ b/imxweb/projects/cpl/src/lib/identity-rule-violations/identity-rule-violations.component.html @@ -1,10 +1,14 @@ -
    +
    - +
    - +
    {{ item.GetEntity().GetDisplay() }}
    @@ -13,18 +17,27 @@
    - + - + (click)="onShowDetails(dataItem)" + > + {{ '#LDS#View mitigating controls' | translate }} +
    -
    \ No newline at end of file +
    diff --git a/imxweb/projects/cpl/src/lib/identity-rule-violations/identity-rule-violations.component.scss b/imxweb/projects/cpl/src/lib/identity-rule-violations/identity-rule-violations.component.scss index 5fd06df4e..431c18088 100644 --- a/imxweb/projects/cpl/src/lib/identity-rule-violations/identity-rule-violations.component.scss +++ b/imxweb/projects/cpl/src/lib/identity-rule-violations/identity-rule-violations.component.scss @@ -1,7 +1,6 @@ -@import "@elemental-ui/core/src/styles/_palette.scss"; +@import '@elemental-ui/core/src/styles/_palette.scss'; @import '@elemental-ui/core/src/styles/_eui_palette.scss'; - :host { overflow: hidden; display: flex; @@ -16,40 +15,13 @@ overflow: auto; } -.imx-card-header { - margin-top: 10px; - background-color: $white; - border-top-left-radius: 4px; - border-top-right-radius: 4px; - z-index: 100; - border: 1px solid rgba($iris-blue, 0.6); - - .imx-card-header-bg { - border-top-left-radius: 4px; - border-top-right-radius: 4px; - background-color: $iris-pastel; - padding: 10px 24px; - display: flex; - align-items: center; - justify-content: flex-start; - - .eui-icon { - color: rgba($iris-blue, 0.6); - margin-right: 10px; - } - - & > span { - font-size: 20px; - } - } -} - .imx-content { height: 100%; display: flex; flex-direction: column; flex: 1 1 auto; overflow-y: auto; + padding: 20px; .imx-rule-violation-table-container { overflow: hidden; @@ -58,19 +30,3 @@ flex: 1 1 auto; } } - -.eui-dark-theme { - :host { - .imx-card-header { - background-color: $color-gray-80; - } - } -} - -.eui-contrast-theme { - :host { - .imx-card-header { - background-color: $color-gray-100; - } - } -} diff --git a/imxweb/projects/cpl/src/lib/identity-rule-violations/identity-rule-violations.component.ts b/imxweb/projects/cpl/src/lib/identity-rule-violations/identity-rule-violations.component.ts index 9d0fb7764..aeab2a6b2 100644 --- a/imxweb/projects/cpl/src/lib/identity-rule-violations/identity-rule-violations.component.ts +++ b/imxweb/projects/cpl/src/lib/identity-rule-violations/identity-rule-violations.component.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -24,17 +24,17 @@ * */ -import { OverlayRef } from '@angular/cdk/overlay'; import { Component, OnInit } from '@angular/core'; import { EuiLoadingService, EuiSidesheetService } from '@elemental-ui/core'; +import { PortalPersonRolemembershipsNoncompliance } from '@imx-modules/imx-api-cpl'; import { TranslateService } from '@ngx-translate/core'; -import { PortalPersonRolemembershipsNoncompliance } from 'imx-api-cpl'; -import { CollectionLoadParameters, DisplayColumns, EntitySchema, ValType } from 'imx-qbm-dbts'; +import { CollectionLoadParameters, DisplayColumns, EntitySchema, ValType } from '@imx-modules/imx-qbm-dbts'; import { + calculateSidesheetWidth, + ClientPropertyForTableColumns, DataSourceToolbarSettings, DynamicTabDataProviderDirective, - ClientPropertyForTableColumns, MetadataService, SettingsService, } from 'qbm'; @@ -49,7 +49,7 @@ export class IdentityRuleViolationsComponent implements OnInit { public dstSettings: DataSourceToolbarSettings; public readonly DisplayColumns = DisplayColumns; public displayedColumns: ClientPropertyForTableColumns[]; - public caption: string; + public caption: string | undefined; public entitySchema: EntitySchema; private referrer: { objectuid: string; objecttable: string }; @@ -83,7 +83,7 @@ export class IdentityRuleViolationsComponent implements OnInit { } finally { this.busyService.hide(overlay); } - this.caption = this.metadataService.tables[this.referrer.objecttable].Display; + this.caption = this.metadataService.tables[this.referrer.objecttable]?.Display; return this.getData(); } @@ -113,7 +113,7 @@ export class IdentityRuleViolationsComponent implements OnInit { title: await this.translate.get('#LDS#Heading View Mitigating Controls').toPromise(), subTitle: entity.GetEntity().GetDisplay(), padding: '0px', - width: 'max(600px,60%)', + width: calculateSidesheetWidth(), disableClose: false, testId: 'identity-rule-violation-mitigating-sidesheet', data, @@ -134,8 +134,9 @@ export class IdentityRuleViolationsComponent implements OnInit { } private async getData(): Promise { - let overlayRef: OverlayRef; - setTimeout(() => (overlayRef = this.busyService.show())); + if (this.busyService.overlayRefs.length === 0) { + this.busyService.show(); + } try { const dataSource = await this.roleMembershipsService.getNonCompliance(this.referrer.objectuid, this.navigationState); @@ -146,7 +147,7 @@ export class IdentityRuleViolationsComponent implements OnInit { navigationState: this.navigationState, }; } finally { - setTimeout(() => this.busyService.hide(overlayRef)); + this.busyService.hide(); } } } diff --git a/imxweb/projects/cpl/src/lib/identity-rule-violations/identity-rule-violations.module.ts b/imxweb/projects/cpl/src/lib/identity-rule-violations/identity-rule-violations.module.ts index c03063640..2187f0518 100644 --- a/imxweb/projects/cpl/src/lib/identity-rule-violations/identity-rule-violations.module.ts +++ b/imxweb/projects/cpl/src/lib/identity-rule-violations/identity-rule-violations.module.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -37,14 +37,6 @@ import { MatCardModule } from '@angular/material/card'; @NgModule({ declarations: [IdentityRuleViolationsComponent, IdentityRuleViolationsMitigationControlComponent], - imports: [ - CommonModule, - EuiCoreModule, - DataSourceToolbarModule, - DataTableModule, - TranslateModule, - MatButtonModule, - MatCardModule - ] + imports: [CommonModule, EuiCoreModule, DataSourceToolbarModule, DataTableModule, TranslateModule, MatButtonModule, MatCardModule], }) -export class IdentityRuleViolationsModule { } +export class IdentityRuleViolationsModule {} diff --git a/imxweb/projects/cpl/src/lib/identity-rule-violations/identity-rule-violations.service.ts b/imxweb/projects/cpl/src/lib/identity-rule-violations/identity-rule-violations.service.ts index b2ff2a91d..f0428deb1 100644 --- a/imxweb/projects/cpl/src/lib/identity-rule-violations/identity-rule-violations.service.ts +++ b/imxweb/projects/cpl/src/lib/identity-rule-violations/identity-rule-violations.service.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -25,19 +25,21 @@ */ import { Injectable } from '@angular/core'; -import { ComplianceFeatureConfig, PortalPersonMitigatingcontrols, PortalPersonRolemembershipsNoncompliance, PortalRulesMitigatingcontrols } from 'imx-api-cpl'; -import { CollectionLoadParameters, EntitySchema, ExtendedTypedEntityCollection } from 'imx-qbm-dbts'; +import { + ComplianceFeatureConfig, + PortalPersonMitigatingcontrols, + PortalPersonRolemembershipsNoncompliance, + PortalRulesMitigatingcontrols, +} from '@imx-modules/imx-api-cpl'; +import { CollectionLoadParameters, EntitySchema, ExtendedTypedEntityCollection } from '@imx-modules/imx-qbm-dbts'; import { ApiService } from '../api.service'; @Injectable({ - providedIn: 'root' + providedIn: 'root', }) export class IdentityRuleViolationService { - - - constructor(private readonly api: ApiService) { - } + constructor(private readonly api: ApiService) {} public get nonComplianceSchema(): EntitySchema { return this.api.typedClient.PortalPersonRolemembershipsNoncompliance.GetSchema(); @@ -51,8 +53,10 @@ export class IdentityRuleViolationService { return this.api.typedClient.PortalRulesMitigatingcontrols.GetSchema(); } - public async getNonCompliance(uidPerson: string, parameter: CollectionLoadParameters) - : Promise> { + public async getNonCompliance( + uidPerson: string, + parameter: CollectionLoadParameters, + ): Promise> { return this.api.typedClient.PortalPersonRolemembershipsNoncompliance.Get(uidPerson, parameter); } @@ -60,13 +64,18 @@ export class IdentityRuleViolationService { return this.api.client.portal_compliance_config_get(); } - public async getPersonMitigatingcontrols(uidComplianceRule: string, uidPerson: string, param: CollectionLoadParameters) - : Promise> { + public async getPersonMitigatingcontrols( + uidComplianceRule: string, + uidPerson: string, + param: CollectionLoadParameters, + ): Promise> { return this.api.typedClient.PortalPersonMitigatingcontrols.Get(uidPerson, uidComplianceRule, param); } - public async getRulesMitigatingcontrols(uidComplianceRule: string, param: CollectionLoadParameters) - : Promise> { + public async getRulesMitigatingcontrols( + uidComplianceRule: string, + param: CollectionLoadParameters, + ): Promise> { return this.api.typedClient.PortalRulesMitigatingcontrols.Get(uidComplianceRule, param); } } diff --git a/imxweb/projects/cpl/src/lib/init.service.ts b/imxweb/projects/cpl/src/lib/init.service.ts index da5edf4e8..cf542e40e 100644 --- a/imxweb/projects/cpl/src/lib/init.service.ts +++ b/imxweb/projects/cpl/src/lib/init.service.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -25,20 +25,19 @@ */ import { Injectable } from '@angular/core'; -import { Router, Route } from '@angular/router'; -import { IdentityRoleMembershipsService, NotificationRegistryService, ShoppingCartValidationDetailService } from 'qer'; +import { Route, Router } from '@angular/router'; +import { NotificationRegistryService, ShoppingCartValidationDetailService } from 'qer'; -import { ExtService, MenuItem, MenuService, TabItem} from 'qbm'; +import { ExtService, MenuItem, MenuService, TabItem } from 'qbm'; import { DashboardPluginComponent } from './dashboard-plugin/dashboard-plugin.component'; +import { IdentityRuleViolationsComponent } from './identity-rule-violations/identity-rule-violations.component'; import { CartItemComplianceCheckComponent } from './item-validator/cart-item-compliance-check/cart-item-compliance-check.component'; -import { isRuleStatistics } from './rules/admin/permissions-helper'; import { RequestRuleViolation } from './request/request-rule-violation'; import { RequestRuleViolationDetail } from './request/request-rule-violation-detail'; -import { RoleComplianceViolationsService } from './role-compliance-violations/role-compliance-violations.service'; import { RoleComplianceViolationsComponent } from './role-compliance-violations/role-compliance-violations.component'; -import { ApiService } from './api.service'; -import { IdentityRuleViolationsComponent } from './identity-rule-violations/identity-rule-violations.component'; +import { RoleComplianceViolationsService } from './role-compliance-violations/role-compliance-violations.service'; +import { isRuleStatistics } from './rules/admin/permissions-helper'; @Injectable({ providedIn: 'root' }) export class InitService { @@ -46,11 +45,9 @@ export class InitService { private readonly extService: ExtService, private readonly router: Router, private readonly menuService: MenuService, - private readonly api: ApiService, private readonly cplService: RoleComplianceViolationsService, private readonly notificationService: NotificationRegistryService, private readonly validationDetailService: ShoppingCartValidationDetailService, - private readonly identityRoleMembershipService: IdentityRoleMembershipsService ) { this.setupMenu(); } @@ -73,12 +70,12 @@ export class InitService { this.extService.register('identitySidesheet', { instance: IdentityRuleViolationsComponent, - inputData: - { + inputData: { id: 'NonCompliance', label: '#LDS#Heading Rule Violations', - checkVisibility: async _ => true - }, sortOrder: 20 + checkVisibility: async (_) => true, + }, + sortOrder: 20, } as TabItem); this.validationDetailService.register(CartItemComplianceCheckComponent, 'CartItemComplianceCheck'); @@ -86,9 +83,8 @@ export class InitService { this.notificationService.registerRedirectNotificationHandler({ id: 'OpenNonCompliance', message: '#LDS#There are new rule violations for which you can grant or deny exceptions.', - route: 'compliance/rulesviolations/approve' + route: 'compliance/rulesviolations/approve', }); - } private async checkCompliances(referrer: any): Promise { @@ -115,10 +111,10 @@ export class InitService { private setupMenu(): void { this.menuService.addMenuFactories((preProps: string[], features: string[]) => { if (!preProps.includes('COMPLIANCE') || !isRuleStatistics(features)) { - return null; + return undefined; } - const items = []; + const items: MenuItem[] = []; if (isRuleStatistics(features)) { items.push({ diff --git a/imxweb/projects/cpl/src/lib/item-validator/cart-item-compliance-check/cart-item-compliance-check.component.html b/imxweb/projects/cpl/src/lib/item-validator/cart-item-compliance-check/cart-item-compliance-check.component.html index 3e5932fcc..bcd6f8193 100644 --- a/imxweb/projects/cpl/src/lib/item-validator/cart-item-compliance-check/cart-item-compliance-check.component.html +++ b/imxweb/projects/cpl/src/lib/item-validator/cart-item-compliance-check/cart-item-compliance-check.component.html @@ -1 +1,3 @@ - + diff --git a/imxweb/projects/cpl/src/lib/item-validator/cart-item-compliance-check/cart-item-compliance-check.component.ts b/imxweb/projects/cpl/src/lib/item-validator/cart-item-compliance-check/cart-item-compliance-check.component.ts index b460803e2..8fcbf1e34 100644 --- a/imxweb/projects/cpl/src/lib/item-validator/cart-item-compliance-check/cart-item-compliance-check.component.ts +++ b/imxweb/projects/cpl/src/lib/item-validator/cart-item-compliance-check/cart-item-compliance-check.component.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -28,7 +28,8 @@ import { Component } from '@angular/core'; import { EuiSidesheetService } from '@elemental-ui/core'; import { TranslateService } from '@ngx-translate/core'; -import { ICartItemCheck } from 'imx-api-qer'; +import { ICartItemCheck } from '@imx-modules/imx-api-qer'; +import { calculateSidesheetWidth } from 'qbm'; import { ComplianceViolationDetailsComponent } from '../../request/compliance-violation-details/compliance-violation-details.component'; @Component({ @@ -40,18 +41,17 @@ export class CartItemComplianceCheckComponent { public check: ICartItemCheck; constructor( - private readonly sidesheetService: EuiSidesheetService, - private readonly translateService: TranslateService + private readonly sidesheetService: EuiSidesheetService, + private readonly translateService: TranslateService, ) {} public async onOpenDetails(): Promise { this.sidesheetService.open(ComplianceViolationDetailsComponent, { title: await this.translateService.get('#LDS#Heading View Rule Violation Details').toPromise(), - width: 'max(550px,50%)', + width: calculateSidesheetWidth(800, 0.5), padding: '0px', data: this.check, testId: 'cart-item-compliance-violation-details', }); } } - diff --git a/imxweb/projects/cpl/src/lib/item-validator/item-validator.service.ts b/imxweb/projects/cpl/src/lib/item-validator/item-validator.service.ts index cf4198ebb..89ed2709c 100644 --- a/imxweb/projects/cpl/src/lib/item-validator/item-validator.service.ts +++ b/imxweb/projects/cpl/src/lib/item-validator/item-validator.service.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -25,18 +25,18 @@ */ import { Injectable } from '@angular/core'; -import { PortalRules } from 'imx-api-cpl'; -import { EntitySchema, ExtendedTypedEntityCollection } from 'imx-qbm-dbts'; +import { PortalRules } from '@imx-modules/imx-api-cpl'; +import { EntitySchema, ExtendedTypedEntityCollection } from '@imx-modules/imx-qbm-dbts'; import { ApiService } from '../api.service'; @Injectable({ - providedIn: 'root' + providedIn: 'root', }) export class ItemValidatorService { - constructor(private readonly api: ApiService) { } + constructor(private readonly api: ApiService) {} public async getRules(): Promise> { - return await this.api.typedClient.PortalRules.Get({PageSize: 1000}); + return await this.api.typedClient.PortalRules.Get({ PageSize: 1000 }); } public getRulesSchema(): EntitySchema { diff --git a/imxweb/projects/cpl/src/lib/mitigating-control-container/mitigating-control-container.component.html b/imxweb/projects/cpl/src/lib/mitigating-control-container/mitigating-control-container.component.html index bfa1a3680..88fd4194e 100644 --- a/imxweb/projects/cpl/src/lib/mitigating-control-container/mitigating-control-container.component.html +++ b/imxweb/projects/cpl/src/lib/mitigating-control-container/mitigating-control-container.component.html @@ -1,10 +1,10 @@
    -
    +
    -
    +
    -
    +
    @@ -45,8 +45,7 @@ [matTooltip]="'#LDS#Assigns a mitigating control' | translate" data-imx-identifier="mitigating-control-container-button-add" [attr.aria-label]="'#LDS#Assign mitigating control' | translate" - mat-button - class="mat-icon-button" + mat-icon-button (click)="onCreateControl()" > diff --git a/imxweb/projects/cpl/src/lib/mitigating-control-container/mitigating-control-container.component.ts b/imxweb/projects/cpl/src/lib/mitigating-control-container/mitigating-control-container.component.ts index 5e504d199..8c1d75dde 100644 --- a/imxweb/projects/cpl/src/lib/mitigating-control-container/mitigating-control-container.component.ts +++ b/imxweb/projects/cpl/src/lib/mitigating-control-container/mitigating-control-container.component.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -24,11 +24,11 @@ * */ -import { ChangeDetectorRef, Component, EventEmitter, Input, OnInit, Output } from '@angular/core'; +import { ChangeDetectorRef, Component, EventEmitter, Input, Output } from '@angular/core'; import { FormArray } from '@angular/forms'; import { EuiSelectOption } from '@elemental-ui/core'; import { ConfirmationService } from 'qbm'; -import { MitigatingControlData } from '../request/compliance-violation-details/edit-mitigating-controls/mitigating-controls-request/mitigating-control-data.interface'; +import { ExtendedDeferredOperationsData } from '../request/compliance-violation-details/edit-mitigating-controls/mitigating-controls-request/extended-deferred-operations-data'; import { RequestMitigatingControls } from '../request/compliance-violation-details/edit-mitigating-controls/mitigating-controls-request/request-mitigating-controls'; import { PersonMitigatingControls } from '../rules-violations/mitigating-controls-person/person-mitigating-controls'; @@ -38,34 +38,50 @@ import { PersonMitigatingControls } from '../rules-violations/mitigating-control styleUrls: ['../mitigating-controls-common.scss'], }) export class MitigatingControlContainerComponent { - @Input() public mControls: MitigatingControlData[] | PersonMitigatingControls[] = []; + @Input() public mControls: Array = []; @Input() public mitigatingCaption: string; @Input() public formArray: FormArray; @Input() public options: EuiSelectOption[] = []; - @Output() public controlDeleted = new EventEmitter(); + @Output() public controlDeleted = new EventEmitter(); @Output() public controlsRequested = new EventEmitter(); - constructor(private readonly cd: ChangeDetectorRef, private readonly confirmationService: ConfirmationService) {} + constructor( + private readonly cd: ChangeDetectorRef, + private readonly confirmationService: ConfirmationService, + ) {} - public async onSelectionChange(mcontrol: RequestMitigatingControls | PersonMitigatingControls, value: string): Promise { - mcontrol.UID_MitigatingControl.value = value; + public filter = (option: EuiSelectOption, searchInputValue: string): boolean => + option.value.toString().toUpperCase() === searchInputValue.toUpperCase(); + + public async onSelectionChange( + mcontrol: RequestMitigatingControls | ExtendedDeferredOperationsData | PersonMitigatingControls, + option: EuiSelectOption | EuiSelectOption[], + ): Promise { + // Multiple is set to false so there is no array of options + mcontrol.uidMitigatingControl = (option as EuiSelectOption).value; this.formArray.updateValueAndValidity(); this.cd.detectChanges(); return; } - public onOpenChange(isopen: boolean, mControl: RequestMitigatingControls | PersonMitigatingControls): void { + public onOpenChange( + isopen: boolean, + mControl: RequestMitigatingControls | ExtendedDeferredOperationsData | PersonMitigatingControls, + ): void { if (!isopen) { - mControl.formControl.updateValueAndValidity({ onlySelf: true }); + mControl?.formControl.updateValueAndValidity({ onlySelf: true }); } } - public async onDelete(mControl: RequestMitigatingControls | PersonMitigatingControls | undefined, index: number): Promise { - if (mControl.UID_MitigatingControl.value !== '' && !(await this.confirmationService.confirmDelete())) { + public async onDelete( + mControl: RequestMitigatingControls | ExtendedDeferredOperationsData | PersonMitigatingControls | undefined, + index: number, + ): Promise { + if (mControl?.uidMitigatingControl !== '' && !(await this.confirmationService.confirmDelete())) { return; } - if (mControl.GetEntity().GetKeys() != null) { + if (!(mControl instanceof ExtendedDeferredOperationsData) && mControl?.GetEntity().GetKeys() != null) { this.controlDeleted.emit(mControl); } this.mControls.splice(index, 1); diff --git a/imxweb/projects/cpl/src/lib/mitigating-control-container/mitigating-control-container.module.ts b/imxweb/projects/cpl/src/lib/mitigating-control-container/mitigating-control-container.module.ts index a9f28a9e3..f49bcb5e4 100644 --- a/imxweb/projects/cpl/src/lib/mitigating-control-container/mitigating-control-container.module.ts +++ b/imxweb/projects/cpl/src/lib/mitigating-control-container/mitigating-control-container.module.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -33,7 +33,7 @@ import { CdrModule } from 'qbm'; @NgModule({ declarations: [MitigatingControlContainerComponent], - imports: [CommonModule, EuiCoreModule,EuiMaterialModule, CdrModule, TranslateModule.forChild()], + imports: [CommonModule, EuiCoreModule, EuiMaterialModule, CdrModule, TranslateModule.forChild()], exports: [MitigatingControlContainerComponent], }) export class MitigatingControlContainerModule {} diff --git a/imxweb/projects/cpl/src/lib/mitigating-controls-common.scss b/imxweb/projects/cpl/src/lib/mitigating-controls-common.scss index 0cfe10cae..4de661ee8 100644 --- a/imxweb/projects/cpl/src/lib/mitigating-controls-common.scss +++ b/imxweb/projects/cpl/src/lib/mitigating-controls-common.scss @@ -1,154 +1 @@ -@import "@elemental-ui/core/src/styles/_eui_palette.scss"; - -:host { - height: 100%; - display: flex; - flex-direction: column; - justify-content: space-between; - - .eui-sidesheet-actions { - padding: 16px 20px; - display: flex; - justify-content: flex-end; - } - - .imx-helper-alert { - margin-bottom: 15px; - } - - .control-container { - display: flex; - flex-direction: column; - overflow: auto; - } - - .mitigating-control { - margin-bottom: 15px; - display: flex; - justify-content: space-between; - align-items: center; - - .imx-delete-button { - margin-top: 15px; - align-self: flex-start; - } - - .mitigating-control-properties { - display: flex; - flex-direction: column; - width: 100%; - margin-right: 15px; - } - } - - .imx-no-mitigating-controls { - flex: 1 1 auto; - margin: 3px; - display: flex; - align-items: center; - justify-content: center; - } - - .imx-mitigating-control-content { - flex: 1 1 auto; - margin: 3px; - display: flex; - flex-direction: column; - overflow: hidden; - - .content { - overflow: auto; - display: flex; - flex: 1 1 auto; - flex-direction: column; - } - } - - .imx-data-no-results { - text-align: center; - margin: 20px 0; - justify-self: center; - - .eui-icon { - font-size: 100px; - } - - p { - margin: 0; - font-size: 18px; - } - - button { - margin-top: 10px; - } - } - - .button-actions { - display: flex; - justify-content: space-between; - margin-top: 20px; - } -} - -// Theming -:host { - .imx-data-no-results { - .eui-icon { - color: $color-gray-10; - } - - p { - color: $color-gray-50; - } - } - - .imx-no-mitigating-controls { - color: $color-gray-50; - } - - .mitigating-control { - border-bottom: 1px solid $color-gray-50; - } -} - -.eui-dark-theme { - :host { - .imx-data-no-results { - .eui-icon { - color: $color-gray-20; - } - - p { - color: $color-gray-10; - } - } - .imx-no-mitigating-controls { - color: $color-gray-10; - } - - .mitigating-control { - border-bottom: 1px solid $color-gray-10; - } - } -} - -.eui-contrast-theme { - :host { - .imx-data-no-results { - .eui-icon { - color: $color-gray-10; - } - - p { - color: $color-gray-0; - } - } - .imx-no-mitigating-controls { - color: $color-gray-0; - } - - .mitigating-control { - border-bottom: 1px solid $color-gray-0; - } - } -} +@import 'common/mitigating-controls'; diff --git a/imxweb/projects/cpl/src/lib/request/compliance-violation-details/compliance-violation-details.component.html b/imxweb/projects/cpl/src/lib/request/compliance-violation-details/compliance-violation-details.component.html index 54f4e2c2f..c09a0d01d 100644 --- a/imxweb/projects/cpl/src/lib/request/compliance-violation-details/compliance-violation-details.component.html +++ b/imxweb/projects/cpl/src/lib/request/compliance-violation-details/compliance-violation-details.component.html @@ -1,9 +1,11 @@
    - + {{ - (rules.length > 1 ? '#LDS#Here you can get an overview of the rule violations this request may cause.' : '#LDS#Here you can see the rule violation this request may cause.') - | translate + (rules.length > 1 + ? '#LDS#Here you can get an overview of the rule violations this request may cause.' + : '#LDS#Here you can see the rule violation this request may cause.' + ) | translate }} @@ -19,13 +21,27 @@ - - - - @@ -34,13 +50,13 @@
    -
    +

    {{ '#LDS#No data' | translate }}

    + + {{ '#LDS#Assigning this entitlement will cause a rule violation.' | translate }} + diff --git a/imxweb/projects/cpl/src/lib/request/compliance-violation-details/compliance-violation-details.component.scss b/imxweb/projects/cpl/src/lib/request/compliance-violation-details/compliance-violation-details.component.scss index 5dfdd652f..28e6effd5 100644 --- a/imxweb/projects/cpl/src/lib/request/compliance-violation-details/compliance-violation-details.component.scss +++ b/imxweb/projects/cpl/src/lib/request/compliance-violation-details/compliance-violation-details.component.scss @@ -55,21 +55,14 @@ hyphens: auto; } - -.mat-card{ - .mat-divider-horizontal { - position: inherit; - } -} - -.imx-accordion .mat-expansion-panel-header-title{ +.imx-accordion .mat-expansion-panel-header-title { flex-basis: 70%; } .imx-accordion .mat-expansion-panel-header-description { flex-basis: 30%; } -.imx-accordion .mat-expansion-panel-header-title{ +.imx-accordion .mat-expansion-panel-header-title { font-weight: bold; } @@ -79,15 +72,10 @@ color: $black-9; } -.imx-no-data { +.imx-no-results { text-align: center; margin: 20px 0; - .eui-icon { - font-size: 100px; - color: rgba($black-c, 0.55); - } - p { margin: 0; font-size: 18px; diff --git a/imxweb/projects/cpl/src/lib/request/compliance-violation-details/compliance-violation-details.component.ts b/imxweb/projects/cpl/src/lib/request/compliance-violation-details/compliance-violation-details.component.ts index fb6a1726d..fcec1d345 100644 --- a/imxweb/projects/cpl/src/lib/request/compliance-violation-details/compliance-violation-details.component.ts +++ b/imxweb/projects/cpl/src/lib/request/compliance-violation-details/compliance-violation-details.component.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -25,16 +25,16 @@ */ import { Component, Inject, Input, OnInit } from '@angular/core'; -import { EuiLoadingService, EuiSidesheetRef, EuiSidesheetService, EUI_SIDESHEET_DATA } from '@elemental-ui/core'; +import { EUI_SIDESHEET_DATA, EuiLoadingService, EuiSidesheetService } from '@elemental-ui/core'; import { TranslateService } from '@ngx-translate/core'; -import { ComplianceViolation, ContributingEntitlement, PortalRules } from 'imx-api-cpl'; -import { ICartItemCheck } from 'imx-api-qer'; -import { DbObjectKey, EntityData, EntitySchema, IEntityColumn, ValType } from 'imx-qbm-dbts'; -import { BaseReadonlyCdr, ColumnDependentReference, EntityService, MetadataService, SystemInfoService } from 'qbm'; +import { ComplianceViolation, ContributingEntitlement, PortalRules } from '@imx-modules/imx-api-cpl'; +import { ICartItemCheck } from '@imx-modules/imx-api-qer'; +import { DbObjectKey, EntityData, EntitySchema, IEntityColumn, ValType } from '@imx-modules/imx-qbm-dbts'; +import { BaseReadonlyCdr, calculateSidesheetWidth, ColumnDependentReference, EntityService, MetadataService, SystemInfoService } from 'qbm'; import { RequestParameterDataEntity } from 'qer'; -import { ApplicableRule, RuleCdrs } from '../compliance-violation-model'; import { ItemValidatorService } from '../../item-validator/item-validator.service'; +import { ApplicableRule, RuleCdrs } from '../compliance-violation-model'; import { ComplianceViolationService } from './compliance-violation.service'; import { EditMitigatingControlsComponent } from './edit-mitigating-controls/edit-mitigating-controls.component'; @@ -74,7 +74,7 @@ export class ComplianceViolationDetailsComponent implements OnInit { try { this.schema = this.validator.getRulesSchema(); this.isICartItemCheck(this.data) ? await this.loadCartItemViolations(this.data) : await this.loadRequestViolations(this.pwoId); - this.hasRiskIndex = (await this.systemInfoService.get()).PreProps.includes('RISKINDEX'); + this.hasRiskIndex = !!(await this.systemInfoService.get()).PreProps?.includes('RISKINDEX'); this.checkHistoryForViolations(); this.mitigatingControlsPerViolation = await this.complianceApi.getMitigatingControlsPerViolation(); @@ -83,6 +83,15 @@ export class ComplianceViolationDetailsComponent implements OnInit { } } + /** + * Check for org type violations, we disable the mitigation control settings for them + * @param item + * @returns if we can access the EditMitigatingControlsComponent + */ + public canEditMitigationControls(item: ApplicableRule): boolean { + return item.violationDetail.ViolationType ? !['Org'].includes(item.violationDetail.ViolationType) : !!item.violationDetail.UidPerson; + } + public async addMitigationControls(item: ApplicableRule): Promise { this.sidesheets .open(EditMitigatingControlsComponent, { @@ -90,7 +99,7 @@ export class ComplianceViolationDetailsComponent implements OnInit { subTitle: item.violationDetail.DisplayRule, padding: '0px', disableClose: true, - width: 'max(700px, 60%)', + width: calculateSidesheetWidth(1000), testId: 'compliance-violation-details-mitigating-sidesheet', data: { uidPerson: item.violationDetail.UidPerson, @@ -105,15 +114,17 @@ export class ComplianceViolationDetailsComponent implements OnInit { } private getDisplayForSource(item: ContributingEntitlement): string { - return this.metaData.tables[DbObjectKey.FromXml(item.ObjectKeyEntitlement).TableName]?.DisplaySingular ?? ''; + return this.metaData.tables[DbObjectKey.FromXml(item.ObjectKeyEntitlement || '').TableName]?.DisplaySingular ?? ''; } private async loadTableNamesForSources(violations: ComplianceViolation[]): Promise { - const sourecedRules = violations.filter((elem) => elem.Sources?.length > 0); + const sourecedRules = violations.filter((elem) => !!elem.Sources?.length); if (sourecedRules.length > 0) { for (const source of sourecedRules) { - await this.metaData.updateNonExisting(source.Sources.map((item) => DbObjectKey.FromXml(item.ObjectKeyEntitlement).TableName)); + await this.metaData.updateNonExisting( + source.Sources?.map((item) => DbObjectKey.FromXml(item.ObjectKeyEntitlement || '').TableName) || [], + ); } } } @@ -155,7 +166,7 @@ export class ComplianceViolationDetailsComponent implements OnInit { }); } - private getDisplayRuleCdr(rule: PortalRules, detail: ComplianceViolation): ColumnDependentReference { + private getDisplayRuleCdr(rule: PortalRules | undefined, detail: ComplianceViolation): ColumnDependentReference { const column = rule ? rule.GetEntity().GetColumn('DisplayRule') : this.buildColumn('DisplayRule', this.translate.instant('#LDS#Violated compliance rule'), detail.DisplayRule); @@ -163,28 +174,28 @@ export class ComplianceViolationDetailsComponent implements OnInit { return new BaseReadonlyCdr(column); } - private async buildCdrForViolations(rule: PortalRules, detail: ComplianceViolation): Promise { - const tableName = DbObjectKey.FromXml(detail.ObjectKeyElement).TableName; + private async buildCdrForViolations(rule: PortalRules | undefined, detail: ComplianceViolation): Promise { + const tableName = DbObjectKey.FromXml(detail.ObjectKeyElement || '').TableName; await this.metaData.updateNonExisting([tableName]); - const displayTitle = this.metaData.tables[tableName]?.DisplaySingular; + const displayTitle = this.metaData.tables[tableName]?.DisplaySingular || ''; //Build common elments const cdrColumns = [ this.buildColumn('DisplayElement', displayTitle, detail.DisplayElement), rule ? rule.GetEntity().GetColumn('Description') - : this.buildColumn('Description', this.schema.Columns['Description'].Display, detail.Description), + : this.buildColumn('Description', this.schema.Columns['Description'].Display || '', detail.Description), this.buildColumn('DisplayPerson', await this.translate.get('#LDS#Identity').toPromise(), detail.DisplayPerson), rule ? rule.GetEntity().GetColumn('RuleNumber') - : this.buildColumn('RuleNumber', this.schema.Columns['RuleNumber'].Display, detail.RuleNumber), + : this.buildColumn('RuleNumber', this.schema.Columns['RuleNumber'].Display || '', detail.RuleNumber), ]; if (this.hasRiskIndex) { cdrColumns.push( rule ? rule.GetEntity().GetColumn('RiskIndex') - : this.buildColumn('RiskIndex', this.schema.Columns['RiskIndex'].Display, detail.RiskIndex, ValType.Double), + : this.buildColumn('RiskIndex', this.schema.Columns['RiskIndex'].Display || '', detail.RiskIndex, ValType.Double), ); if ( @@ -195,15 +206,20 @@ export class ComplianceViolationDetailsComponent implements OnInit { } else { if (detail.RiskIndex !== detail.RiskIndexReduced) { cdrColumns.push( - this.buildColumn('RiskIndexReduced', this.schema.Columns['RiskIndexReduced'].Display, detail.RiskIndexReduced, ValType.Double), + this.buildColumn( + 'RiskIndexReduced', + this.schema.Columns['RiskIndexReduced'].Display || '', + detail.RiskIndexReduced, + ValType.Double, + ), ); } } } let sources: ColumnDependentReference[] | undefined; - if (detail.Sources?.length > 0) { - sources = detail.Sources.map( + if (!!detail.Sources?.length) { + sources = detail.Sources?.map( (source, index) => new BaseReadonlyCdr(this.buildColumn(`source ${index}`, this.getDisplayForSource(source), source.Display)), ); } diff --git a/imxweb/projects/cpl/src/lib/request/compliance-violation-details/compliance-violation.service.ts b/imxweb/projects/cpl/src/lib/request/compliance-violation-details/compliance-violation.service.ts index 653a931b1..14410caac 100644 --- a/imxweb/projects/cpl/src/lib/request/compliance-violation-details/compliance-violation.service.ts +++ b/imxweb/projects/cpl/src/lib/request/compliance-violation-details/compliance-violation.service.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -25,21 +25,20 @@ */ import { Injectable } from '@angular/core'; -import { ComplianceViolation } from 'imx-api-cpl'; +import { ComplianceViolation } from '@imx-modules/imx-api-cpl'; import { ApiService } from '../../api.service'; @Injectable({ - providedIn: 'root' + providedIn: 'root', }) export class ComplianceViolationService { - - constructor(private api: ApiService) { } + constructor(private api: ApiService) {} public async getRequestViolations(pwoId: string): Promise { return await this.api.client.portal_itshop_requests_compliance_get(pwoId); } - public async getMitigatingControlsPerViolation(): Promise{ + public async getMitigatingControlsPerViolation(): Promise { return (await this.api.client.portal_compliance_config_get()).MitigatingControlsPerViolation; } } diff --git a/imxweb/projects/cpl/src/lib/request/compliance-violation-details/edit-mitigating-controls/edit-mitigating-controls.component.scss b/imxweb/projects/cpl/src/lib/request/compliance-violation-details/edit-mitigating-controls/edit-mitigating-controls.component.scss index 434ad89af..a234f168c 100644 --- a/imxweb/projects/cpl/src/lib/request/compliance-violation-details/edit-mitigating-controls/edit-mitigating-controls.component.scss +++ b/imxweb/projects/cpl/src/lib/request/compliance-violation-details/edit-mitigating-controls/edit-mitigating-controls.component.scss @@ -1,3 +1,3 @@ -.eui-sidesheet-content{ +.eui-sidesheet-content { padding: 0px; -} \ No newline at end of file +} diff --git a/imxweb/projects/cpl/src/lib/request/compliance-violation-details/edit-mitigating-controls/edit-mitigating-controls.component.ts b/imxweb/projects/cpl/src/lib/request/compliance-violation-details/edit-mitigating-controls/edit-mitigating-controls.component.ts index 49fa63329..4c52f96a8 100644 --- a/imxweb/projects/cpl/src/lib/request/compliance-violation-details/edit-mitigating-controls/edit-mitigating-controls.component.ts +++ b/imxweb/projects/cpl/src/lib/request/compliance-violation-details/edit-mitigating-controls/edit-mitigating-controls.component.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -24,7 +24,7 @@ * */ -import { Component, Inject} from '@angular/core'; +import { Component, Inject } from '@angular/core'; import { EuiSidesheetRef, EUI_SIDESHEET_DATA } from '@elemental-ui/core'; @Component({ @@ -32,17 +32,15 @@ import { EuiSidesheetRef, EUI_SIDESHEET_DATA } from '@elemental-ui/core'; styleUrls: ['./edit-mitigating-controls.component.scss'], }) export class EditMitigatingControlsComponent { - constructor( public sidesheetRef: EuiSidesheetRef, @Inject(EUI_SIDESHEET_DATA) public data: { uidPerson: string; uidNonCompliance: string; - uidPersonWantsOrg:string; + uidPersonWantsOrg: string; readOnly: boolean; - isMControlPerViolation:boolean; + isMControlPerViolation: boolean; }, ) {} - } diff --git a/imxweb/projects/cpl/src/lib/request/compliance-violation-details/edit-mitigating-controls/mitigating-controls-request/extended-deferred-operations-data.ts b/imxweb/projects/cpl/src/lib/request/compliance-violation-details/edit-mitigating-controls/mitigating-controls-request/extended-deferred-operations-data.ts index 59fd816ba..c28abae46 100644 --- a/imxweb/projects/cpl/src/lib/request/compliance-violation-details/edit-mitigating-controls/mitigating-controls-request/extended-deferred-operations-data.ts +++ b/imxweb/projects/cpl/src/lib/request/compliance-violation-details/edit-mitigating-controls/mitigating-controls-request/extended-deferred-operations-data.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -26,28 +26,34 @@ import { FormControl } from '@angular/forms'; -import { DeferredOperationMControlData, PortalPersonMitigatingcontrols } from 'imx-api-cpl'; -import { ValType } from 'imx-qbm-dbts'; +import { DeferredOperationMControlData, PortalPersonMitigatingcontrols } from '@imx-modules/imx-api-cpl'; +import { ValType } from '@imx-modules/imx-qbm-dbts'; import { BaseReadonlyCdr, ColumnDependentReference, EntityService } from 'qbm'; import { MitigatingControlData } from './mitigating-control-data.interface'; export class ExtendedDeferredOperationsData implements MitigatingControlData { - public formControl = new FormControl(undefined); + public formControl: FormControl = new FormControl('', { nonNullable: true }); public cdrs: ColumnDependentReference[]; public isDeferredData = true; public editable: boolean = false; - public get uidMitigatingControl() { - return this.deferred.Uid; + public get uidMitigatingControl(): string { + return this.deferred.Uid || ''; + } + public set uidMitigatingControl(value: string) { + this.deferred.Uid = value; } public get displayMitigatingControls() { - return this.deferred.Display; + return this.deferred.Display || ''; } public isInActive = true; public data = undefined; - constructor(private readonly deferred: DeferredOperationMControlData, entiyService: EntityService) { + constructor( + private readonly deferred: DeferredOperationMControlData, + entiyService: EntityService, + ) { const schema = PortalPersonMitigatingcontrols.GetEntitySchema(); this.cdrs = [ new BaseReadonlyCdr( @@ -60,9 +66,9 @@ export class ExtendedDeferredOperationsData implements MitigatingControlData { { Value: deferred.Uid, DisplayValue: deferred.Display, - } + }, ), - '#LDS#Mitigating control' + '#LDS#Mitigating control', ), new BaseReadonlyCdr( entiyService.createLocalEntityColumn( @@ -74,9 +80,9 @@ export class ExtendedDeferredOperationsData implements MitigatingControlData { { Value: true, DisplayValue: '#LDS#Yes', - } + }, ), - '#LDS#Inactive' + '#LDS#Inactive', ), ]; } diff --git a/imxweb/projects/cpl/src/lib/request/compliance-violation-details/edit-mitigating-controls/mitigating-controls-request/mitigating-control-data.interface.ts b/imxweb/projects/cpl/src/lib/request/compliance-violation-details/edit-mitigating-controls/mitigating-controls-request/mitigating-control-data.interface.ts index 571124b7a..c1ec4e207 100644 --- a/imxweb/projects/cpl/src/lib/request/compliance-violation-details/edit-mitigating-controls/mitigating-controls-request/mitigating-control-data.interface.ts +++ b/imxweb/projects/cpl/src/lib/request/compliance-violation-details/edit-mitigating-controls/mitigating-controls-request/mitigating-control-data.interface.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -24,10 +24,10 @@ * */ -import { FormControl } from "@angular/forms"; +import { FormControl } from '@angular/forms'; -import { PortalPersonMitigatingcontrols } from "imx-api-cpl"; -import { ColumnDependentReference } from "qbm"; +import { PortalPersonMitigatingcontrols } from '@imx-modules/imx-api-cpl'; +import { ColumnDependentReference } from 'qbm'; export interface MitigatingControlData { cdrs: ColumnDependentReference[]; @@ -38,4 +38,4 @@ export interface MitigatingControlData { uidMitigatingControl: string; displayMitigatingControls: string; data: PortalPersonMitigatingcontrols | undefined; -} \ No newline at end of file +} diff --git a/imxweb/projects/cpl/src/lib/request/compliance-violation-details/edit-mitigating-controls/mitigating-controls-request/mitigating-controls-request.component.html b/imxweb/projects/cpl/src/lib/request/compliance-violation-details/edit-mitigating-controls/mitigating-controls-request/mitigating-controls-request.component.html index 6e5325887..2f2401e7e 100644 --- a/imxweb/projects/cpl/src/lib/request/compliance-violation-details/edit-mitigating-controls/mitigating-controls-request/mitigating-controls-request.component.html +++ b/imxweb/projects/cpl/src/lib/request/compliance-violation-details/edit-mitigating-controls/mitigating-controls-request/mitigating-controls-request.component.html @@ -1,5 +1,5 @@
    - + {{ headertext | translate }}
    @@ -15,7 +15,13 @@ - + @@ -30,7 +36,13 @@ ) | translate }}

    -
    @@ -38,7 +50,13 @@
    - @@ -51,7 +69,7 @@ {{ '#LDS#Active mitigating controls' | translate }} - + @@ -59,10 +77,10 @@ {{ '#LDS#Inactive mitigating controls' | translate }} - + - +
    diff --git a/imxweb/projects/cpl/src/lib/request/compliance-violation-details/edit-mitigating-controls/mitigating-controls-request/mitigating-controls-request.component.scss b/imxweb/projects/cpl/src/lib/request/compliance-violation-details/edit-mitigating-controls/mitigating-controls-request/mitigating-controls-request.component.scss index ce3b634d4..14c1cb17b 100644 --- a/imxweb/projects/cpl/src/lib/request/compliance-violation-details/edit-mitigating-controls/mitigating-controls-request/mitigating-controls-request.component.scss +++ b/imxweb/projects/cpl/src/lib/request/compliance-violation-details/edit-mitigating-controls/mitigating-controls-request/mitigating-controls-request.component.scss @@ -1,4 +1,4 @@ -@import "@elemental-ui/core/src/styles/_eui_palette.scss"; +@import '@elemental-ui/core/src/styles/_eui_palette.scss'; :host { .mitigating-control-readonly { diff --git a/imxweb/projects/cpl/src/lib/request/compliance-violation-details/edit-mitigating-controls/mitigating-controls-request/mitigating-controls-request.component.ts b/imxweb/projects/cpl/src/lib/request/compliance-violation-details/edit-mitigating-controls/mitigating-controls-request/mitigating-controls-request.component.ts index dee850112..648514954 100644 --- a/imxweb/projects/cpl/src/lib/request/compliance-violation-details/edit-mitigating-controls/mitigating-controls-request/mitigating-controls-request.component.ts +++ b/imxweb/projects/cpl/src/lib/request/compliance-violation-details/edit-mitigating-controls/mitigating-controls-request/mitigating-controls-request.component.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -25,13 +25,13 @@ */ import { ChangeDetectorRef, Component, Input, OnInit } from '@angular/core'; -import { FormControl, UntypedFormArray, UntypedFormBuilder, UntypedFormGroup, Validators } from '@angular/forms'; +import { AbstractControl, UntypedFormArray, UntypedFormBuilder, UntypedFormGroup, Validators } from '@angular/forms'; import { EuiLoadingService, EuiSelectOption, EuiSidesheetRef } from '@elemental-ui/core'; import { Subscription } from 'rxjs'; import { ConfirmationService, EntityService, SettingsService, SnackBarService } from 'qbm'; +import { PersonMitigatingControls } from './../../../../rules-violations/mitigating-controls-person/person-mitigating-controls'; import { ExtendedDeferredOperationsData } from './extended-deferred-operations-data'; -import { MitigatingControlData } from './mitigating-control-data.interface'; import { MitigatingControlsRequestService } from './mitigating-controls-request.service'; import { RequestMitigatingControlFilterPipe } from './request-mitigating-control-filter.pipe'; import { RequestMitigatingControls } from './request-mitigating-controls'; @@ -55,8 +55,8 @@ export class MitigatingControlsRequestComponent implements OnInit { public formGroup: UntypedFormGroup; public options: EuiSelectOption[] = []; - public mControls: MitigatingControlData[] = []; - public mControlsToDelete: MitigatingControlData[] = []; + public mControls: (RequestMitigatingControls | ExtendedDeferredOperationsData)[] = []; + public mControlsToDelete: RequestMitigatingControls[] = []; public mitigatingCaption: string; public headertext: string; @@ -69,9 +69,9 @@ export class MitigatingControlsRequestComponent implements OnInit { private snackbarService: SnackBarService, private settingService: SettingsService, private confirmationService: ConfirmationService, - private entityService: EntityService + private entityService: EntityService, ) { - this.mitigatingCaption = mControlService.mitigationSchema.Columns.UID_MitigatingControl.Display; + this.mitigatingCaption = mControlService.mitigationSchema.Columns.UID_MitigatingControl.Display || ''; this.formGroup = new UntypedFormGroup({ formArray: formBuilder.array([]) }); } @@ -79,7 +79,7 @@ export class MitigatingControlsRequestComponent implements OnInit { return this.formGroup.get('formArray') as UntypedFormArray; } - public hasItems(filter: 'active' | 'inactive' | 'deferred'):boolean { + public hasItems(filter: 'active' | 'inactive' | 'deferred'): boolean { return RequestMitigatingControlFilterPipe.getItems(this.mControls, filter)?.length > 0; } @@ -117,11 +117,9 @@ export class MitigatingControlsRequestComponent implements OnInit { if (!this.isDirty || (await this.confirmationService.confirmLeaveWithUnsavedChanges())) { this.sidesheetRef.close(); } - }) + }), ); - this.headertext = !this.readOnly - ? '#LDS#Heading Mitigating Controls Can Be Assigned Individually' - : '#LDS#Heading Mitigating Controls'; + this.headertext = !this.readOnly ? '#LDS#Heading Mitigating Controls Can Be Assigned Individually' : '#LDS#Heading Mitigating Controls'; await this.loadMitigatingControls(); } @@ -142,8 +140,10 @@ export class MitigatingControlsRequestComponent implements OnInit { } } - public onControlDeleted( mControl: RequestMitigatingControls){ - this.mControlsToDelete.push(mControl); + public onControlDeleted(mControl: RequestMitigatingControls | PersonMitigatingControls) { + if (!(mControl instanceof PersonMitigatingControls)) { + this.mControlsToDelete.push(mControl); + } } public getMControlId(mControl: RequestMitigatingControls): string { @@ -158,12 +158,11 @@ export class MitigatingControlsRequestComponent implements OnInit { mControl.formControl.setValidators([ Validators.required, - (control: FormControl) => (this.isDuplicate(control) ? { duplicated: true } : null), + (control: AbstractControl) => (this.isDuplicate(control) ? { duplicated: true } : null), ]); this.formGroup.markAsDirty(); } - public async onSave(): Promise { const overlay = this.busyService.show(); try { @@ -189,9 +188,9 @@ export class MitigatingControlsRequestComponent implements OnInit { this.uidPerson, this.uidNonCompliance, this.uidPersonWantsOrg, - ctrl.uidMitigatingControl + ctrl.uidMitigatingControl, ); - } else { + } else if (ctrl.data) { await this.mControlService.postControl(this.uidPerson, this.uidNonCompliance, ctrl.data); } } @@ -221,7 +220,7 @@ export class MitigatingControlsRequestComponent implements OnInit { const data = await this.mControlService.getControls(this.uidPerson, this.uidNonCompliance); this.mControls = data.Data.map((elem) => new RequestMitigatingControls(false, elem)); this.mControls.push( - ...data.extendedData.MitigatingControls.map((elem) => new ExtendedDeferredOperationsData(elem, this.entityService)) + ...(data.extendedData?.MitigatingControls?.map((elem) => new ExtendedDeferredOperationsData(elem, this.entityService)) || []), ); if (!this.readOnly) { @@ -233,7 +232,7 @@ export class MitigatingControlsRequestComponent implements OnInit { } } - private isDuplicate(actrl: FormControl): boolean { + private isDuplicate(actrl: AbstractControl): boolean { const test = this.mControls.findIndex((ctrl) => ctrl.formControl != actrl && ctrl?.uidMitigatingControl === actrl.value) !== -1; return test; } @@ -245,8 +244,9 @@ export class MitigatingControlsRequestComponent implements OnInit { {}, { PageSize: this.settingService.PageSizeForAllElements, - } + }, ); - this.options = optionCandidates.Entities.map((elem) => ({ display: elem.Display, value: elem.Keys[0] })); + this.options = + optionCandidates.Entities?.map((elem): EuiSelectOption => ({ display: elem.Display || '', value: elem.Keys?.[0] })) || []; } } diff --git a/imxweb/projects/cpl/src/lib/request/compliance-violation-details/edit-mitigating-controls/mitigating-controls-request/mitigating-controls-request.service.ts b/imxweb/projects/cpl/src/lib/request/compliance-violation-details/edit-mitigating-controls/mitigating-controls-request/mitigating-controls-request.service.ts index 030326003..2b6ef82b1 100644 --- a/imxweb/projects/cpl/src/lib/request/compliance-violation-details/edit-mitigating-controls/mitigating-controls-request/mitigating-controls-request.service.ts +++ b/imxweb/projects/cpl/src/lib/request/compliance-violation-details/edit-mitigating-controls/mitigating-controls-request/mitigating-controls-request.service.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -26,8 +26,8 @@ import { Injectable } from '@angular/core'; -import { DeferredOperationData, PortalPersonMitigatingcontrols } from 'imx-api-cpl'; -import { CollectionLoadParameters, EntityKeysData, EntitySchema, ExtendedTypedEntityCollection } from 'imx-qbm-dbts'; +import { DeferredOperationData, PortalPersonMitigatingcontrols } from '@imx-modules/imx-api-cpl'; +import { CollectionLoadParameters, EntityKeysData, EntitySchema, ExtendedTypedEntityCollection } from '@imx-modules/imx-qbm-dbts'; import { ApiService } from '../../../../api.service'; import { MitigatingControlData } from './mitigating-control-data.interface'; import { RequestMitigatingControls } from './request-mitigating-controls'; @@ -44,7 +44,7 @@ export class MitigatingControlsRequestService { public async getControls( uidPerson: string, - uidNonCompliance: string + uidNonCompliance: string, ): Promise> { return this.apiService.typedClient.PortalPersonMitigatingcontrols.Get(uidPerson, uidNonCompliance); } @@ -68,7 +68,7 @@ export class MitigatingControlsRequestService { uidPerson: string, uidNonCompliance: string, uidPersonWantsOrg: string, - uidMitigatinControl: string + uidMitigatinControl: string, ): Promise { const inter = (await this.apiService.typedClient.PortalPersonMitigatingcontrolsInteractive.Get(uidPerson, uidNonCompliance)).Data[0]; await inter.UID_PersonWantsOrg.Column.PutValue(uidPersonWantsOrg); @@ -76,14 +76,14 @@ export class MitigatingControlsRequestService { await this.apiService.client.portal_person_mitigatingcontrols_interactive_forrequest_get( uidPerson, uidNonCompliance, - inter.InteractiveEntityStateData.EntityId, - { keys: inter.InteractiveEntityStateData.Keys, state: inter.InteractiveEntityStateData.State } + inter.InteractiveEntityStateData.EntityId || '', + { keys: inter.InteractiveEntityStateData.Keys, state: inter.InteractiveEntityStateData.State }, ); } public async deleteControl(mControl: MitigatingControlData): Promise { - await mControl.data.GetEntity().MarkForDeletion(); - await mControl.data.GetEntity().Commit(); + await mControl.data?.GetEntity().MarkForDeletion(); + await mControl.data?.GetEntity().Commit(); } public async getCandidates(uid: string, uidNonCompliance: string, data: EntityKeysData, parameter?: CollectionLoadParameters) { @@ -91,7 +91,7 @@ export class MitigatingControlsRequestService { uid, uidNonCompliance, data, - parameter + parameter, ); } } diff --git a/imxweb/projects/cpl/src/lib/request/compliance-violation-details/edit-mitigating-controls/mitigating-controls-request/request-mitigating-control-filter.pipe.ts b/imxweb/projects/cpl/src/lib/request/compliance-violation-details/edit-mitigating-controls/mitigating-controls-request/request-mitigating-control-filter.pipe.ts index 99761abf9..76fcb21bb 100644 --- a/imxweb/projects/cpl/src/lib/request/compliance-violation-details/edit-mitigating-controls/mitigating-controls-request/request-mitigating-control-filter.pipe.ts +++ b/imxweb/projects/cpl/src/lib/request/compliance-violation-details/edit-mitigating-controls/mitigating-controls-request/request-mitigating-control-filter.pipe.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR diff --git a/imxweb/projects/cpl/src/lib/request/compliance-violation-details/edit-mitigating-controls/mitigating-controls-request/request-mitigating-controls.ts b/imxweb/projects/cpl/src/lib/request/compliance-violation-details/edit-mitigating-controls/mitigating-controls-request/request-mitigating-controls.ts index 9b59d2716..f5467b704 100644 --- a/imxweb/projects/cpl/src/lib/request/compliance-violation-details/edit-mitigating-controls/mitigating-controls-request/request-mitigating-controls.ts +++ b/imxweb/projects/cpl/src/lib/request/compliance-violation-details/edit-mitigating-controls/mitigating-controls-request/request-mitigating-controls.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -26,9 +26,9 @@ import { FormControl } from '@angular/forms'; +import { PortalPersonMitigatingcontrols } from '@imx-modules/imx-api-cpl'; +import { IWriteValue } from '@imx-modules/imx-qbm-dbts'; import { BaseCdr, ColumnDependentReference } from 'qbm'; -import { PortalPersonMitigatingcontrols } from 'imx-api-cpl'; -import { IWriteValue } from 'imx-qbm-dbts'; import { MitigatingControlData } from './mitigating-control-data.interface'; /** @@ -41,9 +41,12 @@ export class RequestMitigatingControls extends PortalPersonMitigatingcontrols im */ public cdrs: ColumnDependentReference[]; - public formControl = new FormControl(undefined); + public formControl: FormControl = new FormControl('', { nonNullable: true }); - constructor(public editable: boolean, readonly baseObject: PortalPersonMitigatingcontrols) { + constructor( + public editable: boolean, + readonly baseObject: PortalPersonMitigatingcontrols, + ) { super(baseObject.GetEntity()); this.cdrs = this.initPropertyInfo(); diff --git a/imxweb/projects/cpl/src/lib/request/compliance-violation-model.ts b/imxweb/projects/cpl/src/lib/request/compliance-violation-model.ts index 177fbccc3..9edfd650c 100644 --- a/imxweb/projects/cpl/src/lib/request/compliance-violation-model.ts +++ b/imxweb/projects/cpl/src/lib/request/compliance-violation-model.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -24,7 +24,7 @@ * */ -import { ComplianceViolation, PortalRules } from 'imx-api-cpl'; +import { ComplianceViolation, PortalRules } from '@imx-modules/imx-api-cpl'; import { ColumnDependentReference } from 'qbm'; export interface ApplicableRule { diff --git a/imxweb/projects/cpl/src/lib/request/request-rule-violation-detail.ts b/imxweb/projects/cpl/src/lib/request/request-rule-violation-detail.ts index 7e22b1b21..0605f1678 100644 --- a/imxweb/projects/cpl/src/lib/request/request-rule-violation-detail.ts +++ b/imxweb/projects/cpl/src/lib/request/request-rule-violation-detail.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -24,12 +24,10 @@ * */ -import { IExtension } from "qbm"; -import { ComplianceViolationDetailsComponent } from "./compliance-violation-details/compliance-violation-details.component"; +import { IExtension } from 'qbm'; +import { ComplianceViolationDetailsComponent } from './compliance-violation-details/compliance-violation-details.component'; export class RequestRuleViolationDetail implements IExtension { public static readonly id = 'cpl.ruleViolationDetail'; public instance = ComplianceViolationDetailsComponent; - - } diff --git a/imxweb/projects/cpl/src/lib/request/request-rule-violation.spec.ts b/imxweb/projects/cpl/src/lib/request/request-rule-violation.spec.ts index 8a83f3e30..c03776350 100644 --- a/imxweb/projects/cpl/src/lib/request/request-rule-violation.spec.ts +++ b/imxweb/projects/cpl/src/lib/request/request-rule-violation.spec.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR diff --git a/imxweb/projects/cpl/src/lib/request/request-rule-violation.ts b/imxweb/projects/cpl/src/lib/request/request-rule-violation.ts index 781d5990e..14ca4d35b 100644 --- a/imxweb/projects/cpl/src/lib/request/request-rule-violation.ts +++ b/imxweb/projects/cpl/src/lib/request/request-rule-violation.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -24,7 +24,7 @@ * */ -import { EntityData } from 'imx-qbm-dbts'; +import { EntityData } from '@imx-modules/imx-qbm-dbts'; import { DataSourceToolbarSettings, IExtension } from 'qbm'; import { ItshopRequest } from 'qer'; import { Subject } from 'rxjs'; @@ -41,11 +41,11 @@ export class RequestRuleViolation implements IExtension { this.dstSettings = dstSettings; if (this.dstSettings?.extendedData) { - for (let i = 0; i < this.dstSettings.dataSource.Data.length; i++) { - const item = this.dstSettings.dataSource.Data[i] as ItshopRequest; - item.complianceRuleViolation = item.pwoData.WorkflowHistory.Entities.filter((wh: EntityData) => - wh.Columns['UID_ComplianceRule']?.Value?.length > 0 - ).length > 0; + for (let i = 0; i < (this.dstSettings.dataSource?.Data.length || 0); i++) { + const item = this.dstSettings.dataSource?.Data[i] as ItshopRequest; + item.complianceRuleViolation = !!item.pwoData.WorkflowHistory?.Entities?.filter( + (wh: EntityData) => wh.Columns?.['UID_ComplianceRule']?.Value?.length > 0, + ).length; } } diff --git a/imxweb/projects/cpl/src/lib/request/request.module.ts b/imxweb/projects/cpl/src/lib/request/request.module.ts index a5f0fd1df..857af94d4 100644 --- a/imxweb/projects/cpl/src/lib/request/request.module.ts +++ b/imxweb/projects/cpl/src/lib/request/request.module.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -48,7 +48,7 @@ import { MitigatingControlContainerModule } from '../mitigating-control-containe EditMitigatingControlsComponent, WorkflowViolationDetailsComponent, ComplianceViolationDetailsComponent, - RequestMitigatingControlFilterPipe + RequestMitigatingControlFilterPipe, ], imports: [ CdrModule, @@ -63,9 +63,9 @@ import { MitigatingControlContainerModule } from '../mitigating-control-containe MatExpansionModule, ReactiveFormsModule, TranslateModule, - MitigatingControlContainerModule + MitigatingControlContainerModule, ], - exports: [MitigatingControlsRequestComponent] + exports: [MitigatingControlsRequestComponent], }) export class RequestModule { constructor(logger: ClassloggerService) { diff --git a/imxweb/projects/cpl/src/lib/request/workflow-violation-details/workflow-violation-details.component.html b/imxweb/projects/cpl/src/lib/request/workflow-violation-details/workflow-violation-details.component.html index cf585bc63..459bfec56 100644 --- a/imxweb/projects/cpl/src/lib/request/workflow-violation-details/workflow-violation-details.component.html +++ b/imxweb/projects/cpl/src/lib/request/workflow-violation-details/workflow-violation-details.component.html @@ -7,24 +7,24 @@ - {{ item?.Columns['UID_ComplianceRule']?.DisplayValue }} + {{ item?.Columns?.['UID_ComplianceRule']?.DisplayValue }} - {{ item?.Columns['DateHead']?.DisplayValue }} + {{ item?.Columns?.['DateHead']?.DisplayValue }} - +
    {{ '#LDS#Affected identity' | translate }}

    - {{ item?.Columns['UID_PersonRelated']?.DisplayValue }} + {{ item?.Columns?.['UID_PersonRelated']?.DisplayValue }}

    - +
    {{ '#LDS#Approval procedure' | translate }}

    - {{ item?.Columns['UID_PWODecisionRule']?.DisplayValue }} + {{ item?.Columns?.['UID_PWODecisionRule']?.DisplayValue }}

    diff --git a/imxweb/projects/cpl/src/lib/request/workflow-violation-details/workflow-violation-details.component.scss b/imxweb/projects/cpl/src/lib/request/workflow-violation-details/workflow-violation-details.component.scss index 4abc88420..53d6b3279 100644 --- a/imxweb/projects/cpl/src/lib/request/workflow-violation-details/workflow-violation-details.component.scss +++ b/imxweb/projects/cpl/src/lib/request/workflow-violation-details/workflow-violation-details.component.scss @@ -45,7 +45,6 @@ hyphens: auto; } - .imx-accordion .mat-expansion-panel-header-title, .imx-accordion .mat-expansion-panel-header-description { flex-basis: 0; @@ -55,19 +54,3 @@ justify-content: space-between; align-items: center; } - -.imx-no-data { - text-align: center; - margin: 20px 0; - - .eui-icon { - font-size: 100px; - color: rgba($black-c, 0.55); - } - - p { - margin: 0; - font-size: 18px; - color: $black-9; - } -} diff --git a/imxweb/projects/cpl/src/lib/request/workflow-violation-details/workflow-violation-details.component.ts b/imxweb/projects/cpl/src/lib/request/workflow-violation-details/workflow-violation-details.component.ts index 283d605ad..0b143f074 100644 --- a/imxweb/projects/cpl/src/lib/request/workflow-violation-details/workflow-violation-details.component.ts +++ b/imxweb/projects/cpl/src/lib/request/workflow-violation-details/workflow-violation-details.component.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -25,23 +25,22 @@ */ import { Component, Input, OnInit } from '@angular/core'; -import { PwoData } from 'imx-api-qer'; -import { EntityData } from 'imx-qbm-dbts'; +import { PwoData } from '@imx-modules/imx-api-qer'; +import { EntityData } from '@imx-modules/imx-qbm-dbts'; @Component({ selector: 'imx-workflow-violation-details', templateUrl: './workflow-violation-details.component.html', - styleUrls: ['./workflow-violation-details.component.scss'] + styleUrls: ['./workflow-violation-details.component.scss'], }) export class WorkflowViolationDetailsComponent implements OnInit { public violations: EntityData[] = []; @Input() public pwoData: PwoData; - constructor() { } + constructor() {} public ngOnInit(): void { - this.violations = this.pwoData.WorkflowHistory.Entities.filter(item => item.Columns['UID_ComplianceRule'].Value); + this.violations = this.pwoData.WorkflowHistory?.Entities?.filter((item) => item.Columns?.['UID_ComplianceRule'].Value) || []; } - } diff --git a/imxweb/projects/cpl/src/lib/role-compliance-violations/role-compliance-violation-typed-entity.ts b/imxweb/projects/cpl/src/lib/role-compliance-violations/role-compliance-violation-typed-entity.ts index 5323a7401..931d307da 100644 --- a/imxweb/projects/cpl/src/lib/role-compliance-violations/role-compliance-violation-typed-entity.ts +++ b/imxweb/projects/cpl/src/lib/role-compliance-violations/role-compliance-violation-typed-entity.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -24,20 +24,20 @@ * */ -import { TypedEntity, EntitySchema, DisplayColumns, ValType } from 'imx-qbm-dbts'; +import { TypedEntity, EntitySchema, DisplayColumns, ValType } from '@imx-modules/imx-qbm-dbts'; export class RoleComplianceViolationTypedEntity extends TypedEntity { - public static GetEntitySchema(): EntitySchema { - const columns = { - UID_ComplianceRule: { Type: ValType.String, ColumnName: 'UID_ComplianceRule' }, - RuleName: { Type: ValType.String, ColumnName: 'RuleName' }, - DbObjectKey: { Type: ValType.String, ColumnName: 'DbObjectKey' }, - ObjectDisplay: { Type: ValType.String, ColumnName: 'ObjectDisplay' }, - ObjectKeyElement: { Type: ValType.String, ColumnName: 'ObjectKeyElement' } - }; + public static GetEntitySchema(): EntitySchema { + const columns = { + UID_ComplianceRule: { Type: ValType.String, ColumnName: 'UID_ComplianceRule' }, + RuleName: { Type: ValType.String, ColumnName: 'RuleName' }, + DbObjectKey: { Type: ValType.String, ColumnName: 'DbObjectKey' }, + ObjectDisplay: { Type: ValType.String, ColumnName: 'ObjectDisplay' }, + ObjectKeyElement: { Type: ValType.String, ColumnName: 'ObjectKeyElement' }, + }; - columns[DisplayColumns.DISPLAY_PROPERTYNAME] = DisplayColumns.DISPLAY_PROPERTY; + columns[DisplayColumns.DISPLAY_PROPERTYNAME] = DisplayColumns.DISPLAY_PROPERTY; - return { Columns: columns }; - } + return { Columns: columns }; + } } diff --git a/imxweb/projects/cpl/src/lib/role-compliance-violations/role-compliance-violations-wrapper.ts b/imxweb/projects/cpl/src/lib/role-compliance-violations/role-compliance-violations-wrapper.ts index f2632c641..fa2083964 100644 --- a/imxweb/projects/cpl/src/lib/role-compliance-violations/role-compliance-violations-wrapper.ts +++ b/imxweb/projects/cpl/src/lib/role-compliance-violations/role-compliance-violations-wrapper.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -26,22 +26,21 @@ import { Injectable } from '@angular/core'; -import { RoleComplianceViolation } from 'imx-api-cpl'; -import { EntityColumnData, EntityData, TypedEntityBuilder, TypedEntityCollectionData } from 'imx-qbm-dbts'; +import { RoleComplianceViolation } from '@imx-modules/imx-api-cpl'; +import { EntityColumnData, EntityData, TypedEntityBuilder, TypedEntityCollectionData } from '@imx-modules/imx-qbm-dbts'; import { RoleComplianceViolationTypedEntity } from './role-compliance-violation-typed-entity'; @Injectable({ - providedIn: 'root' + providedIn: 'root', }) export class RoleComplianceViolationsWrapperService { - public readonly roleComplianceEntitySchema = RoleComplianceViolationTypedEntity.GetEntitySchema(); private readonly builder = new TypedEntityBuilder(RoleComplianceViolationTypedEntity); public build(data: RoleComplianceViolation[]): TypedEntityCollectionData { const violations = { TotalCount: data.length, - Entities: data.map(elem => this.buildEntityData(elem)) + Entities: data.map((elem) => this.buildEntityData(elem)), }; return this.builder.buildReadWriteEntities(violations, this.roleComplianceEntitySchema); } @@ -57,4 +56,3 @@ export class RoleComplianceViolationsWrapperService { return { Columns: ret }; } } - diff --git a/imxweb/projects/cpl/src/lib/role-compliance-violations/role-compliance-violations.component.html b/imxweb/projects/cpl/src/lib/role-compliance-violations/role-compliance-violations.component.html index 1f5fed658..e18ff64d6 100644 --- a/imxweb/projects/cpl/src/lib/role-compliance-violations/role-compliance-violations.component.html +++ b/imxweb/projects/cpl/src/lib/role-compliance-violations/role-compliance-violations.component.html @@ -1,21 +1,31 @@
    - - {{ keyDescription | translate }} - - - - - - + + {{ keyDescription | translate }} + +
    + + + - + data-imx-identifier="violations-table-column-ObjectDisplay" + > - +
    diff --git a/imxweb/projects/cpl/src/lib/role-compliance-violations/role-compliance-violations.component.scss b/imxweb/projects/cpl/src/lib/role-compliance-violations/role-compliance-violations.component.scss index 26d762986..664091826 100644 --- a/imxweb/projects/cpl/src/lib/role-compliance-violations/role-compliance-violations.component.scss +++ b/imxweb/projects/cpl/src/lib/role-compliance-violations/role-compliance-violations.component.scss @@ -1,4 +1,4 @@ -@import "@elemental-ui/core/src/styles/_palette.scss"; +@import '@elemental-ui/core/src/styles/_palette.scss'; :host { display: flex; @@ -14,13 +14,9 @@ overflow: hidden; } -.imx-tab-body{ +.imx-tab-body { flex: 1 1 auto; display: flex; flex-direction: column; overflow: auto; } - -.imx-helper-alert { - margin-bottom: 20px; -} diff --git a/imxweb/projects/cpl/src/lib/role-compliance-violations/role-compliance-violations.component.ts b/imxweb/projects/cpl/src/lib/role-compliance-violations/role-compliance-violations.component.ts index dadc4ea2c..7fed0a7b7 100644 --- a/imxweb/projects/cpl/src/lib/role-compliance-violations/role-compliance-violations.component.ts +++ b/imxweb/projects/cpl/src/lib/role-compliance-violations/role-compliance-violations.component.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -26,7 +26,7 @@ import { Component, OnInit } from '@angular/core'; -import { DisplayColumns, EntitySchema, IClientProperty } from 'imx-qbm-dbts'; +import { DisplayColumns, EntitySchema, IClientProperty } from '@imx-modules/imx-qbm-dbts'; import { DataSourceToolbarSettings, DynamicTabDataProviderDirective, MetadataService } from 'qbm'; import { RoleComplianceViolationsWrapperService } from './role-compliance-violations-wrapper'; import { RoleComplianceViolationsService } from './role-compliance-violations.service'; @@ -56,7 +56,7 @@ export class RoleComplianceViolationsComponent implements OnInit { this.entitySchema = this.entityService.roleComplianceEntitySchema; this.displayedColumns = [this.entitySchema.Columns.RuleName, this.entitySchema.Columns.ObjectDisplay]; - // tslint:disable:max-line-length + /* eslint-disable max-len */ switch ((this.tablename ?? '').toLowerCase()) { case 'aerole': this.keyDescription = @@ -87,7 +87,7 @@ export class RoleComplianceViolationsComponent implements OnInit { '#LDS#Here you can get an overview of all entitlements assigned to this object that may violate a compliance rule.'; break; } - // tslint:enable:max-line-length + /* eslint-enable max-len */ } public async ngOnInit(): Promise { @@ -101,7 +101,7 @@ export class RoleComplianceViolationsComponent implements OnInit { const data = await this.roleComplianceViolationService.getRoleComplianceViolations(this.tablename, this.uidRole); this.dstSettings = { displayedColumns: this.displayedColumns, - dataSource: this.entityService.build(data.Violations), + dataSource: this.entityService.build(data.Violations || []), entitySchema: this.entityService.roleComplianceEntitySchema, navigationState: {}, }; diff --git a/imxweb/projects/cpl/src/lib/role-compliance-violations/role-compliance-violations.module.ts b/imxweb/projects/cpl/src/lib/role-compliance-violations/role-compliance-violations.module.ts index cb70b5e9c..45481a61b 100644 --- a/imxweb/projects/cpl/src/lib/role-compliance-violations/role-compliance-violations.module.ts +++ b/imxweb/projects/cpl/src/lib/role-compliance-violations/role-compliance-violations.module.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -35,14 +35,6 @@ import { RoleComplianceViolationsComponent } from './role-compliance-violations. @NgModule({ declarations: [RoleComplianceViolationsComponent], - imports: [ - CommonModule, - EuiCoreModule, - DataSourceToolbarModule, - DataTableModule, - MatCardModule, - TranslateModule, - LdsReplaceModule - ] + imports: [CommonModule, EuiCoreModule, DataSourceToolbarModule, DataTableModule, MatCardModule, TranslateModule, LdsReplaceModule], }) -export class RoleComplianceViolationsModule { } +export class RoleComplianceViolationsModule {} diff --git a/imxweb/projects/cpl/src/lib/role-compliance-violations/role-compliance-violations.service.ts b/imxweb/projects/cpl/src/lib/role-compliance-violations/role-compliance-violations.service.ts index 6c835ec59..f7572ff44 100644 --- a/imxweb/projects/cpl/src/lib/role-compliance-violations/role-compliance-violations.service.ts +++ b/imxweb/projects/cpl/src/lib/role-compliance-violations/role-compliance-violations.service.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -28,36 +28,30 @@ import { OverlayRef } from '@angular/cdk/overlay'; import { Injectable } from '@angular/core'; import { EuiLoadingService } from '@elemental-ui/core'; -import { RoleComplianceViolations } from 'imx-api-cpl'; +import { RoleComplianceViolations } from '@imx-modules/imx-api-cpl'; import { ApiService } from '../api.service'; @Injectable({ - providedIn: 'root' + providedIn: 'root', }) export class RoleComplianceViolationsService { - - private busyIndicator: OverlayRef; + private busyIndicator: OverlayRef | undefined; constructor( private apiservice: ApiService, - private busyService: EuiLoadingService - ) { } + private busyService: EuiLoadingService, + ) {} public async getRoleComplianceViolations(table: string, uidRole: string): Promise { return this.apiservice.client.portal_roles_config_compliance_get(table, uidRole); } public handleOpenLoader(): void { - if (!this.busyIndicator) { - this.busyIndicator = this.busyService.show(); + if (this.busyService.overlayRefs.length === 0) { + this.busyService.show(); } } public handleCloseLoader(): void { - if (this.busyIndicator) { - setTimeout(() => { - this.busyService.hide(this.busyIndicator); - this.busyIndicator = undefined; - }); - } + this.busyService.hide(); } } diff --git a/imxweb/projects/cpl/src/lib/rules-violations/mitigating-controls-person/mitigating-controls-person.component.html b/imxweb/projects/cpl/src/lib/rules-violations/mitigating-controls-person/mitigating-controls-person.component.html index 38b5497d6..a77e839ef 100644 --- a/imxweb/projects/cpl/src/lib/rules-violations/mitigating-controls-person/mitigating-controls-person.component.html +++ b/imxweb/projects/cpl/src/lib/rules-violations/mitigating-controls-person/mitigating-controls-person.component.html @@ -1,18 +1,30 @@
    - + {{ '#LDS#Heading Mitigating Controls Can Be Assigned Individually' | translate }} -

    {{ '#LDS#Here you can assign mitigating controls to the rule violation. NOTE: If no mitigating controls have been assigned to the violated compliance rule, you cannot assign any mitigating controls to the rule violation either.' | translate }}

    +

    + {{ + '#LDS#Here you can assign mitigating controls to the rule violation. NOTE: If no mitigating controls have been assigned to the violated compliance rule, you cannot assign any mitigating controls to the rule violation either.' + | translate + }} +

    - + -
    +

    {{ @@ -22,15 +34,28 @@ ) | translate }}

    -
    - - diff --git a/imxweb/projects/cpl/src/lib/rules-violations/mitigating-controls-person/mitigating-controls-person.component.scss b/imxweb/projects/cpl/src/lib/rules-violations/mitigating-controls-person/mitigating-controls-person.component.scss index 39959a6ef..7bdfa5572 100644 --- a/imxweb/projects/cpl/src/lib/rules-violations/mitigating-controls-person/mitigating-controls-person.component.scss +++ b/imxweb/projects/cpl/src/lib/rules-violations/mitigating-controls-person/mitigating-controls-person.component.scss @@ -1,4 +1,4 @@ -@import "@elemental-ui/core/src/styles/_eui_palette.scss"; +@import '@elemental-ui/core/src/styles/_eui_palette.scss'; :host { height: 100%; @@ -6,10 +6,6 @@ flex-direction: column; justify-content: space-between; - .imx-helper-alert { - margin-bottom: 15px; - } - .control-container { display: flex; flex-direction: column; @@ -62,15 +58,11 @@ } } - .imx-data-no-results { + .imx-no-results { text-align: center; margin: 20px 0; justify-self: center; - .eui-icon { - font-size: 100px; - } - p { margin: 0; font-size: 18px; @@ -80,21 +72,11 @@ margin-top: 10px; } } - - .button-actions { - display: flex; - justify-content: space-between; - margin-top: 20px; - } } // Theming :host { - .imx-data-no-results { - .eui-icon { - color: $color-gray-10; - } - + .imx-no-results { p { color: $color-gray-50; } @@ -111,11 +93,7 @@ .eui-dark-theme { :host { - .imx-data-no-results { - .eui-icon { - color: $color-gray-20; - } - + .imx-no-results { p { color: $color-gray-10; } @@ -133,10 +111,6 @@ .eui-contrast-theme { :host { .imx-data-no-results { - .eui-icon { - color: $color-gray-10; - } - p { color: $color-gray-0; } diff --git a/imxweb/projects/cpl/src/lib/rules-violations/mitigating-controls-person/mitigating-controls-person.component.ts b/imxweb/projects/cpl/src/lib/rules-violations/mitigating-controls-person/mitigating-controls-person.component.ts index 09cf6b809..728e1173c 100644 --- a/imxweb/projects/cpl/src/lib/rules-violations/mitigating-controls-person/mitigating-controls-person.component.ts +++ b/imxweb/projects/cpl/src/lib/rules-violations/mitigating-controls-person/mitigating-controls-person.component.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -30,6 +30,7 @@ import { EuiLoadingService, EuiSelectOption, EuiSidesheetRef } from '@elemental- import { Subscription } from 'rxjs'; import { ConfirmationService, SettingsService, SnackBarService } from 'qbm'; +import { MitigatingControlData } from '../../request/compliance-violation-details/edit-mitigating-controls/mitigating-controls-request/mitigating-control-data.interface'; import { MitigatingControlsPersonService } from './mitigating-controls-person.service'; import { PersonMitigatingControls } from './person-mitigating-controls'; @@ -61,9 +62,9 @@ export class MitigatingControlsPersonComponent implements OnInit { private busyService: EuiLoadingService, private snackbarService: SnackBarService, private settingService: SettingsService, - private confirmationService: ConfirmationService + private confirmationService: ConfirmationService, ) { - this.mitigatingCaption = mControlService.mitigationSchema.Columns.UID_MitigatingControl.Display; + this.mitigatingCaption = mControlService.mitigationSchema.Columns.UID_MitigatingControl.Display || ''; this.formGroup = new UntypedFormGroup({ formArray: formBuilder.array([]) }); } @@ -99,7 +100,7 @@ export class MitigatingControlsPersonComponent implements OnInit { if (!this.isDirty || (await this.confirmationService.confirmLeaveWithUnsavedChanges())) { this.sidesheetRef.close(); } - }) + }), ); await this.loadMitigatingControls(); } @@ -129,17 +130,19 @@ export class MitigatingControlsPersonComponent implements OnInit { const mControl = this.mControlService.createControl(this.uidPerson, this.uidNonCompliance); this.mControls.push(mControl); this.formArray.push(mControl.formControl); - this.cd.detectChanges(); mControl.formControl.setValidators([ Validators.required, (control: FormControl) => (this.isDuplicate(control) ? { duplicated: true } : null), ]); this.formGroup.markAsDirty(); + this.cd.detectChanges(); } - public onDelete(mControl: PersonMitigatingControls): void { - this.mControlsToDelete.push(mControl); + public onDelete(mControl: MitigatingControlData | PersonMitigatingControls): void { + if (mControl instanceof PersonMitigatingControls) { + this.mControlsToDelete.push(mControl); + } } public async onSave(): Promise { @@ -208,8 +211,9 @@ export class MitigatingControlsPersonComponent implements OnInit { {}, { PageSize: this.settingService.PageSizeForAllElements, - } + }, ); - this.options = optionCandidates.Entities.map((elem) => ({ display: elem.Display, value: elem.Keys[0] })); + this.options = + optionCandidates.Entities?.map((elem): EuiSelectOption => ({ display: elem.Display || '', value: elem?.Keys?.[0] || '' })) || []; } } diff --git a/imxweb/projects/cpl/src/lib/rules-violations/mitigating-controls-person/mitigating-controls-person.service.ts b/imxweb/projects/cpl/src/lib/rules-violations/mitigating-controls-person/mitigating-controls-person.service.ts index 4ae0a3fff..47e9c6987 100644 --- a/imxweb/projects/cpl/src/lib/rules-violations/mitigating-controls-person/mitigating-controls-person.service.ts +++ b/imxweb/projects/cpl/src/lib/rules-violations/mitigating-controls-person/mitigating-controls-person.service.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -26,8 +26,8 @@ import { Injectable } from '@angular/core'; -import { DeferredOperationData, PortalPersonMitigatingcontrols } from 'imx-api-cpl'; -import { CollectionLoadParameters, EntityKeysData, EntitySchema, ExtendedTypedEntityCollection } from 'imx-qbm-dbts'; +import { DeferredOperationData, PortalPersonMitigatingcontrols } from '@imx-modules/imx-api-cpl'; +import { CollectionLoadParameters, EntityKeysData, EntitySchema, ExtendedTypedEntityCollection } from '@imx-modules/imx-qbm-dbts'; import { ApiService } from '../../api.service'; import { PersonMitigatingControls } from './person-mitigating-controls'; @@ -43,7 +43,7 @@ export class MitigatingControlsPersonService { public async getControls( uidPerson: string, - uidNonCompliance: string + uidNonCompliance: string, ): Promise> { return this.apiService.typedClient.PortalPersonMitigatingcontrols.Get(uidPerson, uidNonCompliance); } @@ -67,7 +67,7 @@ export class MitigatingControlsPersonService { uidPerson: string, uidNonCompliance: string, uidPersonWantsOrg: string, - uidMitigatinControl: string + uidMitigatinControl: string, ): Promise { const inter = (await this.apiService.typedClient.PortalPersonMitigatingcontrolsInteractive.Get(uidPerson, uidNonCompliance)).Data[0]; await inter.UID_PersonWantsOrg.Column.PutValue(uidPersonWantsOrg); @@ -75,14 +75,14 @@ export class MitigatingControlsPersonService { await this.apiService.client.portal_person_mitigatingcontrols_interactive_forrequest_get( uidPerson, uidNonCompliance, - inter.InteractiveEntityStateData.EntityId, - { keys: inter.InteractiveEntityStateData.Keys, state: inter.InteractiveEntityStateData.State } + inter.InteractiveEntityStateData.EntityId || '', + { keys: inter.InteractiveEntityStateData.Keys, state: inter.InteractiveEntityStateData.State || '' }, ); } public async deleteControl(mControl: PersonMitigatingControls): Promise { - await mControl.GetEntity().MarkForDeletion(); - await mControl.GetEntity().Commit(); + await mControl.GetEntity().MarkForDeletion(); + await mControl.GetEntity().Commit(); } public async getCandidates(uid: string, uidNonCompliance: string, data: EntityKeysData, parameter?: CollectionLoadParameters) { @@ -90,7 +90,7 @@ export class MitigatingControlsPersonService { uid, uidNonCompliance, data, - parameter + parameter, ); } } diff --git a/imxweb/projects/cpl/src/lib/rules-violations/mitigating-controls-person/person-mitigating-controls.ts b/imxweb/projects/cpl/src/lib/rules-violations/mitigating-controls-person/person-mitigating-controls.ts index 9c91483a2..5e22d5ed0 100644 --- a/imxweb/projects/cpl/src/lib/rules-violations/mitigating-controls-person/person-mitigating-controls.ts +++ b/imxweb/projects/cpl/src/lib/rules-violations/mitigating-controls-person/person-mitigating-controls.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -24,10 +24,10 @@ * */ -import { BaseCdr, ColumnDependentReference } from 'qbm'; -import { PortalPersonMitigatingcontrols } from 'imx-api-cpl'; -import { IWriteValue } from 'imx-qbm-dbts'; import { FormControl } from '@angular/forms'; +import { PortalPersonMitigatingcontrols } from '@imx-modules/imx-api-cpl'; +import { IWriteValue } from '@imx-modules/imx-qbm-dbts'; +import { BaseCdr, ColumnDependentReference } from 'qbm'; /** * Class thats extends the {@link PortalPersonMitigatingcontrols} with some additional properties that are needed for @@ -39,14 +39,24 @@ export class PersonMitigatingControls extends PortalPersonMitigatingcontrols { */ public cdrs: ColumnDependentReference[]; - public formControl = new FormControl(undefined); + public formControl: FormControl = new FormControl('', { nonNullable: true }); - constructor(public editable: boolean, readonly baseObject: PortalPersonMitigatingcontrols) { + public readonly isDeferredData = false; + constructor( + public editable: boolean, + readonly baseObject: PortalPersonMitigatingcontrols, + ) { super(baseObject.GetEntity()); this.cdrs = this.initPropertyInfo(); } + public get uidMitigatingControl(): string { + return this.baseObject.UID_MitigatingControl.value; + } + public set uidMitigatingControl(value: string) { + this.baseObject.UID_MitigatingControl.value = value; + } private initPropertyInfo(): ColumnDependentReference[] { const properties: IWriteValue[] = [this.UID_MitigatingControl, this.IsInActive]; diff --git a/imxweb/projects/cpl/src/lib/rules-violations/resolve/resolve.component.html b/imxweb/projects/cpl/src/lib/rules-violations/resolve/resolve.component.html index 75c73f175..4a9c469cc 100644 --- a/imxweb/projects/cpl/src/lib/rules-violations/resolve/resolve.component.html +++ b/imxweb/projects/cpl/src/lib/rules-violations/resolve/resolve.component.html @@ -7,9 +7,11 @@ {{ LdsContributingPermissions | translate }}
    - {{ LdsNoPermissions | translate }} + + {{ LdsNoPermissions | translate }} - + -
    -
    @@ -48,11 +56,22 @@
    - + + -
    +
    -
    @@ -62,7 +81,9 @@ - {{ LdsNoLoseAdditional | translate }} + + {{ LdsNoLoseAdditional | translate }} {{ LdsLoseEntitlements | translate }} @@ -75,9 +96,11 @@ -
    +
    - +
    diff --git a/imxweb/projects/cpl/src/lib/rules-violations/resolve/resolve.component.scss b/imxweb/projects/cpl/src/lib/rules-violations/resolve/resolve.component.scss index fd64f0da0..8ce396709 100644 --- a/imxweb/projects/cpl/src/lib/rules-violations/resolve/resolve.component.scss +++ b/imxweb/projects/cpl/src/lib/rules-violations/resolve/resolve.component.scss @@ -1,9 +1,4 @@ -@import "@elemental-ui/core/src/styles/_palette.scss"; - -eui-alert { - margin-bottom: 1em; - display: block; -} +@import '@elemental-ui/core/src/styles/_palette.scss'; .item { flex-grow: 1; @@ -17,14 +12,6 @@ eui-alert { margin-bottom: 10px; } -.imx-step-button, -.imx-step-button-save { - margin-top: 10px; - > *:not(:last-child) { - margin-right: 10px; - } -} - li.entllose { list-style-type: initial; } diff --git a/imxweb/projects/cpl/src/lib/rules-violations/resolve/resolve.component.ts b/imxweb/projects/cpl/src/lib/rules-violations/resolve/resolve.component.ts index 2a6765857..e7aedeff3 100644 --- a/imxweb/projects/cpl/src/lib/rules-violations/resolve/resolve.component.ts +++ b/imxweb/projects/cpl/src/lib/rules-violations/resolve/resolve.component.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -24,156 +24,160 @@ * */ -import { Component, OnInit, Inject } from "@angular/core"; -import { EuiLoadingService, EuiSidesheetRef, EUI_SIDESHEET_DATA } from "@elemental-ui/core"; -import { ContributingEntitlement, UiActionData } from "imx-api-cpl"; -import { BaseCdr, EntityService, MetadataService, SnackBarService } from "qbm"; -import { DbObjectKey, ValType } from "imx-qbm-dbts"; -import { ApiService } from "../../api.service"; -import { StepperSelectionEvent } from "@angular/cdk/stepper"; +import { StepperSelectionEvent } from '@angular/cdk/stepper'; +import { Component, Inject, OnInit } from '@angular/core'; +import { EUI_SIDESHEET_DATA, EuiLoadingService, EuiSidesheetRef } from '@elemental-ui/core'; +import { ContributingEntitlement, UiActionData } from '@imx-modules/imx-api-cpl'; +import { DbObjectKey, ValType } from '@imx-modules/imx-qbm-dbts'; +import { BaseCdr, EntityService, MetadataService, SnackBarService } from 'qbm'; +import { ApiService } from '../../api.service'; -type ExtendedEntitlement = (ContributingEntitlement & { Key?: DbObjectKey, TypeDisplay?: string }); +type ExtendedEntitlement = ContributingEntitlement & { Key?: DbObjectKey; TypeDisplay?: string }; @Component({ - templateUrl: "./resolve.component.html", - styleUrls: ["./resolve.component.scss"] + templateUrl: './resolve.component.html', + styleUrls: ['./resolve.component.scss'], }) export class ResolveComponent implements OnInit { - - constructor(private readonly sidesheetRef: EuiSidesheetRef, - private readonly snackbar: SnackBarService, - private readonly cplApi: ApiService, - private readonly busySvc: EuiLoadingService, - private readonly metadata: MetadataService, - private readonly entityService: EntityService, - @Inject(EUI_SIDESHEET_DATA) private readonly data: { - uidPerson: string, - uidNonCompliance: string - } - ) { - } - - public busy = false; - public completed = false; - public actions: UiActionData[] = []; - public entitlements: ExtendedEntitlement[] = []; - public entitlementsLoseAlso: ExtendedEntitlement[] = []; - public selectedEntitlements: string[] = []; - public uidActions: string[] = []; - private reasonCdr: BaseCdr; - public cdrs: BaseCdr[]; - - public async ngOnInit(): Promise { - - this.reasonCdr = new BaseCdr( - this.entityService.createLocalEntityColumn({ - ColumnName: 'ReasonHead', - Type: ValType.Text, - IsMultiLine: true - }), - '#LDS#Reason for unsubscribing' - ); - this.busy = true; - // load entitlements contributing to the rule violation - this.selectedEntitlements = []; - try { - this.entitlements = await this.cplApi.client.portal_rules_violations_entitlements_get(this.data.uidPerson, this.data.uidNonCompliance); - await this.enhanceWithTypeDisplay(this.entitlements); - } - finally { - this.busy = false; - } - } - - private async enhanceWithTypeDisplay(obj: { ObjectKeyEntitlement?: string, Key?: DbObjectKey, TypeDisplay?: string }[]) { - obj.forEach(element => { - element.Key = DbObjectKey.FromXml(element.ObjectKeyEntitlement); - }); - await this.metadata.updateNonExisting(obj.map(i => i.Key.TableName)); - obj.forEach(element => { - element.TypeDisplay = this.metadata.tables[element.Key.TableName].DisplaySingular; - }); - } - - public async selectedStepChanged(event: StepperSelectionEvent): Promise { - if (this.completed) - return; - if (event.selectedIndex === 1 && event.previouslySelectedIndex === 0) { - await this.LoadActions(); - } - else if (event.selectedIndex === 2 && event.previouslySelectedIndex === 1) { - await this.LoadEntitlementsLoseAlso(); - } - } - - private async LoadActions(): Promise { - - // load actions - this.actions = []; - this.uidActions = []; - this.busy = true; - try { - this.actions = await this.cplApi.client.portal_rules_violations_actions_post(this.data.uidPerson, this.data.uidNonCompliance, { - ObjectKeys: this.selectedEntitlements - }); - this.uidActions = this.actions.filter(a => a.IsActive).map(a => a.Id); - - // do we have any unsubscribe actions? - if (this.actions.filter(a => a.Id.endsWith(".Unsubscribe")).length > 0) { - // allow the user to enter a reason - this.cdrs = [this.reasonCdr]; - } - else { - this.cdrs = []; - } - - } finally { - this.busy = false; - } - } - - private async LoadEntitlementsLoseAlso(): Promise { - // load the entitlements that will also be lost if the selected actions are run - this.entitlementsLoseAlso = []; - this.busy = true; - try { - this.entitlementsLoseAlso = await this.cplApi.client.portal_rules_violations_analyzeloss_post(this.data.uidPerson, this.data.uidNonCompliance, { - ObjectKeys: this.selectedEntitlements, - ActionIds: this.uidActions - }); - await this.enhanceWithTypeDisplay(this.entitlementsLoseAlso); - } finally { - this.busy = false; - } - } - - public async Execute(): Promise { - const b = this.busySvc.show(); - try { - await this.cplApi.client.portal_rules_violations_result_post(this.data.uidPerson, this.data.uidNonCompliance, { - ReasonText: this.reasonCdr.column.GetValue(), - ObjectKeys: this.selectedEntitlements, - ActionIds: this.uidActions - }); - this.completed = true; - - this.sidesheetRef.close(true); - this.snackbar.open({ key: this.LdsChangesQueued }); - } finally { - this.busySvc.hide(b); - } - } - - - public LdsChangesQueued = '#LDS#Your changes have been successfully saved. It may take some time for the changes to take effect.'; - - public LdsLoseEntitlements = '#LDS#The identity will lose the following entitlements when the selected actions take effect. Check the list to avoid unintentional loss of access. To change the selection, go back to the previous page.'; - - public LdsNoPermissions = '#LDS#No entitlements were found. The cause for the violation may has already been resolved. You may close this wizard.'; - - public LdsContributingPermissions = '#LDS#The following entitlements contribute to this rule violation. Select the entitlements to be removed from the identity.'; - - public LdsNoLoseAdditional = '#LDS#The identity will not lose any additional entitlements.'; - - public LdsActionList = '#LDS#The following actions will be performed to remove the selected entitlements from the identity.'; + constructor( + private readonly sidesheetRef: EuiSidesheetRef, + private readonly snackbar: SnackBarService, + private readonly cplApi: ApiService, + private readonly busySvc: EuiLoadingService, + private readonly metadata: MetadataService, + private readonly entityService: EntityService, + @Inject(EUI_SIDESHEET_DATA) + private readonly data: { + uidPerson: string; + uidNonCompliance: string; + }, + ) {} + + public busy = false; + public completed = false; + public actions: UiActionData[] = []; + public entitlements: ExtendedEntitlement[] = []; + public entitlementsLoseAlso: ExtendedEntitlement[] = []; + public selectedEntitlements: string[] = []; + public uidActions: string[] = []; + private reasonCdr: BaseCdr; + public cdrs: BaseCdr[]; + + public async ngOnInit(): Promise { + this.reasonCdr = new BaseCdr( + this.entityService.createLocalEntityColumn({ + ColumnName: 'ReasonHead', + Type: ValType.Text, + IsMultiLine: true, + }), + '#LDS#Reason for unsubscribing', + ); + this.busy = true; + // load entitlements contributing to the rule violation + this.selectedEntitlements = []; + try { + this.entitlements = await this.cplApi.client.portal_rules_violations_entitlements_get( + this.data.uidPerson, + this.data.uidNonCompliance, + ); + await this.enhanceWithTypeDisplay(this.entitlements); + } finally { + this.busy = false; + } + } + + private async enhanceWithTypeDisplay(obj: { ObjectKeyEntitlement?: string; Key?: DbObjectKey; TypeDisplay?: string }[]) { + obj.forEach((element) => { + element.Key = DbObjectKey.FromXml(element.ObjectKeyEntitlement || ''); + }); + await this.metadata.updateNonExisting(obj.map((i) => i.Key?.TableName || '')); + obj.forEach((element) => { + if (element.Key?.TableName) { + element.TypeDisplay = this.metadata.tables[element.Key.TableName]?.DisplaySingular; + } + }); + } + + public async selectedStepChanged(event: StepperSelectionEvent): Promise { + if (this.completed) return; + if (event.selectedIndex === 1 && event.previouslySelectedIndex === 0) { + await this.LoadActions(); + } else if (event.selectedIndex === 2 && event.previouslySelectedIndex === 1) { + await this.LoadEntitlementsLoseAlso(); + } + } + + private async LoadActions(): Promise { + // load actions + this.actions = []; + this.uidActions = []; + this.busy = true; + try { + this.actions = await this.cplApi.client.portal_rules_violations_actions_post(this.data.uidPerson, this.data.uidNonCompliance, { + ObjectKeys: this.selectedEntitlements, + }); + this.uidActions = this.actions.filter((a) => a.IsActive).map((a) => a.Id || ''); + + // do we have any unsubscribe actions? + if (this.actions.filter((a) => a.Id?.endsWith('.Unsubscribe')).length > 0) { + // allow the user to enter a reason + this.cdrs = [this.reasonCdr]; + } else { + this.cdrs = []; + } + } finally { + this.busy = false; + } + } + + private async LoadEntitlementsLoseAlso(): Promise { + // load the entitlements that will also be lost if the selected actions are run + this.entitlementsLoseAlso = []; + this.busy = true; + try { + this.entitlementsLoseAlso = await this.cplApi.client.portal_rules_violations_analyzeloss_post( + this.data.uidPerson, + this.data.uidNonCompliance, + { + ObjectKeys: this.selectedEntitlements, + ActionIds: this.uidActions, + }, + ); + await this.enhanceWithTypeDisplay(this.entitlementsLoseAlso); + } finally { + this.busy = false; + } + } + + public async Execute(): Promise { + const b = this.busySvc.show(); + try { + await this.cplApi.client.portal_rules_violations_result_post(this.data.uidPerson, this.data.uidNonCompliance, { + ReasonText: this.reasonCdr.column.GetValue(), + ObjectKeys: this.selectedEntitlements, + ActionIds: this.uidActions, + }); + this.completed = true; + + this.sidesheetRef.close(true); + this.snackbar.open({ key: this.LdsChangesQueued }); + } finally { + this.busySvc.hide(b); + } + } + + public LdsChangesQueued = '#LDS#Your changes have been successfully saved. It may take some time for the changes to take effect.'; + + public LdsLoseEntitlements = + '#LDS#The identity will lose the following entitlements when the selected actions take effect. Check the list to avoid unintentional loss of access. To change the selection, go back to the previous page.'; + + public LdsNoPermissions = + '#LDS#No entitlements were found. The cause for the violation may has already been resolved. You may close this wizard.'; + + public LdsContributingPermissions = + '#LDS#The following entitlements contribute to this rule violation. Select the entitlements to be removed from the identity.'; + + public LdsNoLoseAdditional = '#LDS#The identity will not lose any additional entitlements.'; + + public LdsActionList = '#LDS#The following actions will be performed to remove the selected entitlements from the identity.'; } diff --git a/imxweb/projects/cpl/src/lib/rules-violations/rules-violations-action/rules-violations-action-parameters.interface.ts b/imxweb/projects/cpl/src/lib/rules-violations/rules-violations-action/rules-violations-action-parameters.interface.ts index 811f9dd4f..9263d65ea 100644 --- a/imxweb/projects/cpl/src/lib/rules-violations/rules-violations-action/rules-violations-action-parameters.interface.ts +++ b/imxweb/projects/cpl/src/lib/rules-violations/rules-violations-action/rules-violations-action-parameters.interface.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR diff --git a/imxweb/projects/cpl/src/lib/rules-violations/rules-violations-action/rules-violations-action.component.html b/imxweb/projects/cpl/src/lib/rules-violations/rules-violations-action/rules-violations-action.component.html index e81fab571..134c743e8 100644 --- a/imxweb/projects/cpl/src/lib/rules-violations/rules-violations-action/rules-violations-action.component.html +++ b/imxweb/projects/cpl/src/lib/rules-violations/rules-violations-action/rules-violations-action.component.html @@ -2,18 +2,22 @@

    {{ data.description | translate }}

    - - + - - +
    -
    -
    diff --git a/imxweb/projects/cpl/src/lib/rules-violations/rules-violations-action/rules-violations-action.component.scss b/imxweb/projects/cpl/src/lib/rules-violations/rules-violations-action/rules-violations-action.component.scss index c605dc0b3..e9b37918f 100644 --- a/imxweb/projects/cpl/src/lib/rules-violations/rules-violations-action/rules-violations-action.component.scss +++ b/imxweb/projects/cpl/src/lib/rules-violations/rules-violations-action/rules-violations-action.component.scss @@ -1,31 +1,15 @@ -@import "@elemental-ui/core/src/styles/_palette.scss"; - -@mixin imx-flex-column-container { - display: flex; - flex-direction: column; -} +@import '@elemental-ui/core/src/styles/_palette.scss'; +@import 'base/mixins'; :host { .eui-sidesheet-content { - @include imx-flex-column-container(); + @include flex-column-container(); .imx-rules-violations-action-form { - @include imx-flex-column-container(); - overflow: auto; + @include flex-column-container($overflow: auto); > * { - @include imx-flex-column-container(); - overflow: auto; - } - } - - .eui-sidesheet-actions { - .justify-start { - margin-right: auto; - } - - button:not(:last-of-type):not(.justify-start) { - margin-right: 10px; + @include flex-column-container($overflow: auto); } } } diff --git a/imxweb/projects/cpl/src/lib/rules-violations/rules-violations-action/rules-violations-action.component.ts b/imxweb/projects/cpl/src/lib/rules-violations/rules-violations-action/rules-violations-action.component.ts index 460421c2c..a0080c1bc 100644 --- a/imxweb/projects/cpl/src/lib/rules-violations/rules-violations-action/rules-violations-action.component.ts +++ b/imxweb/projects/cpl/src/lib/rules-violations/rules-violations-action/rules-violations-action.component.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -42,10 +42,9 @@ import { RulesViolationsAction } from './rules-violations-action.interface'; @Component({ selector: 'imx-rules-violations-action', templateUrl: './rules-violations-action.component.html', - styleUrls: ['./rules-violations-action.component.scss'] + styleUrls: ['./rules-violations-action.component.scss'], }) export class RulesViolationsActionComponent { - /** * The form group to which the created form controls will be added. */ @@ -58,6 +57,6 @@ export class RulesViolationsActionComponent { */ constructor( @Inject(EUI_SIDESHEET_DATA) public readonly data: RulesViolationsAction, - public readonly sideSheetRef: EuiSidesheetRef - ) { } + public readonly sideSheetRef: EuiSidesheetRef, + ) {} } diff --git a/imxweb/projects/cpl/src/lib/rules-violations/rules-violations-action/rules-violations-action.interface.ts b/imxweb/projects/cpl/src/lib/rules-violations/rules-violations-action/rules-violations-action.interface.ts index 0c395a953..3be6598cd 100644 --- a/imxweb/projects/cpl/src/lib/rules-violations/rules-violations-action/rules-violations-action.interface.ts +++ b/imxweb/projects/cpl/src/lib/rules-violations/rules-violations-action/rules-violations-action.interface.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR diff --git a/imxweb/projects/cpl/src/lib/rules-violations/rules-violations-action/rules-violations-action.service.ts b/imxweb/projects/cpl/src/lib/rules-violations/rules-violations-action/rules-violations-action.service.ts index f2c5e0558..8d1805882 100644 --- a/imxweb/projects/cpl/src/lib/rules-violations/rules-violations-action/rules-violations-action.service.ts +++ b/imxweb/projects/cpl/src/lib/rules-violations/rules-violations-action/rules-violations-action.service.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -25,29 +25,28 @@ */ import { Injectable } from '@angular/core'; -import { OverlayRef } from '@angular/cdk/overlay'; import { EuiLoadingService, EuiSidesheetService } from '@elemental-ui/core'; import { TranslateService } from '@ngx-translate/core'; import { Subject } from 'rxjs'; -import { NonComplianceDecisionInput } from 'imx-api-cpl'; -import { ValType } from 'imx-qbm-dbts'; -import { SnackBarService, EntityService, ColumnDependentReference, BaseCdr } from 'qbm'; +import { NonComplianceDecisionInput } from '@imx-modules/imx-api-cpl'; +import { ValType } from '@imx-modules/imx-qbm-dbts'; +import { BaseCdr, ColumnDependentReference, EntityService, SnackBarService, calculateSidesheetWidth } from 'qbm'; import { JustificationService, JustificationType, UserModelService } from 'qer'; import { ApiService } from '../../api.service'; +import { ResolveComponent } from '../resolve/resolve.component'; import { RulesViolationsApproval } from '../rules-violations-approval'; -import { RulesViolationsActionComponent } from './rules-violations-action.component'; import { RulesViolationsActionParameters } from './rules-violations-action-parameters.interface'; -import { ResolveComponent } from '../resolve/resolve.component'; +import { RulesViolationsActionComponent } from './rules-violations-action.component'; /** * Service that handles the approve and deny of one or more rules violations. */ @Injectable({ - providedIn: 'root' + providedIn: 'root', }) export class RulesViolationsActionService { - public readonly applied = new Subject(); + public readonly applied = new Subject(); constructor( private readonly justification: JustificationService, @@ -56,9 +55,9 @@ export class RulesViolationsActionService { private readonly busyService: EuiLoadingService, private readonly translate: TranslateService, private readonly snackBar: SnackBarService, + private readonly entityService: EntityService, private readonly userService: UserModelService, - private readonly entityService: EntityService - ) { } + ) {} /** * Approve the rules violation @@ -83,31 +82,30 @@ export class RulesViolationsActionService { title: await this.translate.get('#LDS#Heading Resolve Rule Violation').toPromise(), subTitle: ruleViolation.GetEntity().GetDisplay(), padding: '0px', - width: 'max(600px, 60%)', + width: calculateSidesheetWidth(), testId: 'rulesviolations-resolve-sidesheet', data: { uidPerson: ruleViolation.UID_Person.value, - uidNonCompliance: ruleViolation.UID_NonCompliance.value - } + uidNonCompliance: ruleViolation.UID_NonCompliance.value, + }, }); return sidesheetRef.afterClosed().toPromise(); } private async makeDecisions(rulesViolationsApprovals: RulesViolationsApproval[], approve: boolean): Promise { - let justification: ColumnDependentReference; + let justification: ColumnDependentReference | undefined; - let busyIndicator: OverlayRef; - setTimeout(() => busyIndicator = this.busyService.show()); + if (this.busyService.overlayRefs.length === 0) { + this.busyService.show(); + } try { justification = await this.justification.createCdr( - approve - ? JustificationType.approveRuleViolation - : JustificationType.denyRuleViolation + approve ? JustificationType.approveRuleViolation : JustificationType.denyRuleViolation, ); } finally { - setTimeout(() => this.busyService.hide(busyIndicator)); + this.busyService.hide(); } const actionParameters: RulesViolationsActionParameters = { @@ -129,7 +127,7 @@ export class RulesViolationsActionService { return this.editAction({ title: sidesheetTitle, - data: { rulesViolationsApprovals, actionParameters, approve, }, + data: { rulesViolationsApprovals, actionParameters, approve }, message: approve ? '#LDS#Exceptions have been successfully granted for {0} rule violations.' : '#LDS#Exceptions have been successfully denied for {0} rule violations.', @@ -140,7 +138,7 @@ export class RulesViolationsActionService { ExceptionValidUntil: actionParameters.validUntil?.column?.GetValue(), Decision: approve, }); - } + }, }); } /** @@ -149,37 +147,38 @@ export class RulesViolationsActionService { * @param config the configuration for the sidesheet (title) and the corresponding rules violations data */ private async editAction(config: any): Promise { - const result = await this.sidesheet.open(RulesViolationsActionComponent, { - title: await this.translate.get(config.title).toPromise(), - subTitle: config.data.rulesViolationsApprovals.length == 1 - ? config.data.rulesViolationsApprovals[0].GetEntity().GetDisplay() - : '', - panelClass: 'imx-sidesheet', - padding: '0', - width: '600px', - testId: `rulesvioalations-action-sidesheet-${config.data.approve ? 'approve' : 'deny'}`, - data: config.data - }).afterClosed().toPromise(); + const result = await this.sidesheet + .open(RulesViolationsActionComponent, { + title: await this.translate.get(config.title).toPromise(), + subTitle: config.data.rulesViolationsApprovals.length == 1 ? config.data.rulesViolationsApprovals[0].GetEntity().GetDisplay() : '', + panelClass: 'imx-sidesheet', + padding: '0', + width: calculateSidesheetWidth(600, 0.4), + testId: `rulesvioalations-action-sidesheet-${config.data.approve ? 'approve' : 'deny'}`, + data: config.data, + }) + .afterClosed() + .toPromise(); if (result) { - let busyIndicator: OverlayRef; - setTimeout(() => busyIndicator = this.busyService.show()); + if (this.busyService.overlayRefs.length === 0) { + this.busyService.show(); + } let success: boolean; try { for (const rulesViolation of config.data.rulesViolationsApprovals) { await config.apply(rulesViolation); } - success = true; + success = true; await this.userService.reloadPendingItems(); } finally { - setTimeout(() => this.busyService.hide(busyIndicator)); + this.busyService.hide(); } if (success) { - this.snackBar.open(config.getMessage ? - config.getMessage() : - { key: config.message, parameters: [config.data.rulesViolationsApprovals.length] } + this.snackBar.open( + config.getMessage ? config.getMessage() : { key: config.message, parameters: [config.data.rulesViolationsApprovals.length] }, ); this.applied.next(); } @@ -197,21 +196,22 @@ export class RulesViolationsActionService { return this.cplClient.client.portal_rules_violations_post( ruleViolationToApprove.UID_Person.value, ruleViolationToApprove.UID_NonCompliance.value, - input); + input, + ); } /** * Creates a Cdr-Editor for the reason. */ - private createCdrReason(metadata: { display?: string, mandatory?: boolean } = {}): ColumnDependentReference { + private createCdrReason(metadata: { display?: string; mandatory?: boolean } = {}): ColumnDependentReference { return new BaseCdr( this.entityService.createLocalEntityColumn({ ColumnName: 'ReasonHead', Type: ValType.Text, IsMultiLine: true, - MinLen: metadata.mandatory ? 1 : 0 + MinLen: metadata.mandatory ? 1 : 0, }), - metadata.display || '#LDS#Reason for your decision' + metadata.display || '#LDS#Reason for your decision', ); } @@ -228,13 +228,12 @@ export class RulesViolationsActionService { Type: schema.Columns.ExceptionValidUntil.Type, IsMultiLine: schema.Columns.ExceptionValidUntil.IsMultiLine, MinLen: schema.Columns.ExceptionValidUntil.MinLen, - Display: schema.Columns.ExceptionValidUntil.Display + Display: schema.Columns.ExceptionValidUntil.Display, }, undefined, - { ValueConstraint: { MinValue: minDateUntil } } + { ValueConstraint: { MinValue: minDateUntil } }, ); return new BaseCdr(validUntilColumn); } - } diff --git a/imxweb/projects/cpl/src/lib/rules-violations/rules-violations-action/rules-violations-multi-action/rules-violations-multi-action.component.html b/imxweb/projects/cpl/src/lib/rules-violations/rules-violations-action/rules-violations-multi-action/rules-violations-multi-action.component.html index 6dbd68161..78e9324c7 100644 --- a/imxweb/projects/cpl/src/lib/rules-violations/rules-violations-action/rules-violations-multi-action/rules-violations-multi-action.component.html +++ b/imxweb/projects/cpl/src/lib/rules-violations/rules-violations-action/rules-violations-multi-action/rules-violations-multi-action.component.html @@ -1,5 +1,5 @@ - + {{ '#LDS#Heading General Settings' | translate }} @@ -7,25 +7,28 @@
    - + [attr.data-imx-identifier]="'rules-violations-multi-action-' + cdr.column.ColumnName + '-' + i" + >
    - - - {{ '#LDS#Selected rules violations' | translate }} + + + {{ '#LDS#Heading Selected Rule Violations' | translate }} - + -
    +
    {{ ruleViolationApproval?.GetEntity()?.GetDisplay() }}
    -
    +
    {{ ruleViolationApproval?.stateBadge?.caption }}
    - \ No newline at end of file + diff --git a/imxweb/projects/cpl/src/lib/rules-violations/rules-violations-action/rules-violations-multi-action/rules-violations-multi-action.component.scss b/imxweb/projects/cpl/src/lib/rules-violations/rules-violations-action/rules-violations-multi-action/rules-violations-multi-action.component.scss index 00103f788..e89975998 100644 --- a/imxweb/projects/cpl/src/lib/rules-violations/rules-violations-action/rules-violations-multi-action/rules-violations-multi-action.component.scss +++ b/imxweb/projects/cpl/src/lib/rules-violations/rules-violations-action/rules-violations-multi-action/rules-violations-multi-action.component.scss @@ -1,48 +1,16 @@ -@import "@elemental-ui/core/src/styles/_palette.scss"; - -@mixin imx-flex-column-container { - display: flex; - flex-direction: column; -} +@import '@elemental-ui/core/src/styles/_palette.scss'; +@import 'base/mixins'; mat-card { + @include flex-column-container(); margin-bottom: 20px; - @include imx-flex-column-container(); - - .mat-card-title { - font-size: 20px; - } - - > .mat-selection-list { - overflow: auto; - } } .imx-items-title { font-size: 16px; } -.imx-list { +.imx-list-container { overflow: hidden; margin-bottom: 10px; - - .mat-list { - overflow: auto; - } - - mat-list-item { - font-size: 14px; - height: auto; - margin-bottom: 10px; - - .mat-line { - white-space: normal; - } - - .imx-list-item-subtitle { - font-size: smaller; - font-style: italic; - color: $black_9; - } - } } diff --git a/imxweb/projects/cpl/src/lib/rules-violations/rules-violations-action/rules-violations-multi-action/rules-violations-multi-action.component.ts b/imxweb/projects/cpl/src/lib/rules-violations/rules-violations-action/rules-violations-multi-action/rules-violations-multi-action.component.ts index 952088eff..47cf512e0 100644 --- a/imxweb/projects/cpl/src/lib/rules-violations/rules-violations-action/rules-violations-multi-action/rules-violations-multi-action.component.ts +++ b/imxweb/projects/cpl/src/lib/rules-violations/rules-violations-action/rules-violations-multi-action/rules-violations-multi-action.component.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -40,10 +40,9 @@ import { ColumnDependentReference } from 'qbm'; @Component({ selector: 'imx-rules-violations-multi-action', templateUrl: './rules-violations-multi-action.component.html', - styleUrls: ['./rules-violations-multi-action.component.scss'] + styleUrls: ['./rules-violations-multi-action.component.scss'], }) export class RulesViolationsMultiActionComponent implements OnInit { - /** * @ignore since this is only an internal component. * @@ -72,7 +71,6 @@ export class RulesViolationsMultiActionComponent implements OnInit { * Sets up the {@link columns} to be displayed/edited during OnInit lifecycle hook. */ public ngOnInit(): void { - if (this.data.actionParameters.validUntil) { this.columns.push(this.data.actionParameters.validUntil); } @@ -94,8 +92,6 @@ export class RulesViolationsMultiActionComponent implements OnInit { */ public onFormControlCreated(name: string, control: AbstractControl): void { // use setTimeout to make addControl asynchronous in order to avoid "NG0100: Expression has changed after it was checked" - setTimeout(() => - this.formGroup.addControl(name, control) - ); + setTimeout(() => this.formGroup.addControl(name, control)); } } diff --git a/imxweb/projects/cpl/src/lib/rules-violations/rules-violations-action/rules-violations-single-action/rules-violations-single-action.component.html b/imxweb/projects/cpl/src/lib/rules-violations/rules-violations-action/rules-violations-single-action/rules-violations-single-action.component.html index b96cbc102..160ad0ccd 100644 --- a/imxweb/projects/cpl/src/lib/rules-violations/rules-violations-action/rules-violations-single-action/rules-violations-single-action.component.html +++ b/imxweb/projects/cpl/src/lib/rules-violations/rules-violations-action/rules-violations-single-action/rules-violations-single-action.component.html @@ -1,10 +1,13 @@ - {{ rulesViolation.GetEntity()?.GetDisplay() }} + {{ rulesViolation.GetEntity()?.GetDisplay() }} {{ rulesViolation?.stateBadge?.caption }} - + [attr.data-imx-identifier]="'rules-violations-single-action-' + cdr.column.ColumnName + '-' + i" + > - \ No newline at end of file + diff --git a/imxweb/projects/cpl/src/lib/rules-violations/rules-violations-action/rules-violations-single-action/rules-violations-single-action.component.scss b/imxweb/projects/cpl/src/lib/rules-violations/rules-violations-action/rules-violations-single-action/rules-violations-single-action.component.scss index e8a19f444..656ed4909 100644 --- a/imxweb/projects/cpl/src/lib/rules-violations/rules-violations-action/rules-violations-single-action/rules-violations-single-action.component.scss +++ b/imxweb/projects/cpl/src/lib/rules-violations/rules-violations-action/rules-violations-single-action/rules-violations-single-action.component.scss @@ -1,17 +1,7 @@ // Create a config with the default typography levels. @use '@angular/material' as mat; // see: https://material.angular.io/guide/typography -@import "@angular/material/theming"; -$config: mat.define-typography-config(); mat-card-content { overflow: hidden; } - -mat-card-title { - font-size: mat.font-size($config, subheading-2); -} - -mat-card-subtitle { - font-size: mat.font-size($config, subheading-1); -} diff --git a/imxweb/projects/cpl/src/lib/rules-violations/rules-violations-action/rules-violations-single-action/rules-violations-single-action.component.ts b/imxweb/projects/cpl/src/lib/rules-violations/rules-violations-action/rules-violations-single-action/rules-violations-single-action.component.ts index eca205636..2a2fd4b84 100644 --- a/imxweb/projects/cpl/src/lib/rules-violations/rules-violations-action/rules-violations-single-action/rules-violations-single-action.component.ts +++ b/imxweb/projects/cpl/src/lib/rules-violations/rules-violations-action/rules-violations-single-action/rules-violations-single-action.component.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -41,10 +41,9 @@ import { RulesViolationsApproval } from '../../rules-violations-approval'; @Component({ selector: 'imx-rules-violations-single-action', templateUrl: './rules-violations-single-action.component.html', - styleUrls: ['./rules-violations-single-action.component.scss'] + styleUrls: ['./rules-violations-single-action.component.scss'], }) export class RulesViolationsSingleActionComponent implements OnInit { - /** * @ignore since this is only an internal component. * @@ -74,7 +73,6 @@ export class RulesViolationsSingleActionComponent implements OnInit { */ public rulesViolation: RulesViolationsApproval; - /** * @ignore since this is only an internal component * @@ -104,8 +102,6 @@ export class RulesViolationsSingleActionComponent implements OnInit { */ public onFormControlCreated(name: string, control: AbstractControl): void { // use setTimeout to make addControl asynchronous in order to avoid "NG0100: Expression has changed after it was checked" - setTimeout(() => - this.formGroup.addControl(name, control) - ); + setTimeout(() => this.formGroup.addControl(name, control)); } } diff --git a/imxweb/projects/cpl/src/lib/rules-violations/rules-violations-approval.ts b/imxweb/projects/cpl/src/lib/rules-violations/rules-violations-approval.ts index a5d394f22..a12d92516 100644 --- a/imxweb/projects/cpl/src/lib/rules-violations/rules-violations-approval.ts +++ b/imxweb/projects/cpl/src/lib/rules-violations/rules-violations-approval.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -26,7 +26,7 @@ import { TranslateService } from '@ngx-translate/core'; -import { PortalRulesViolations } from 'imx-api-cpl'; +import { PortalRulesViolations } from '@imx-modules/imx-api-cpl'; import { BaseCdr } from 'qbm'; /** @@ -55,7 +55,7 @@ export class RulesViolationsApproval extends PortalRulesViolations { constructor( readonly baseObject: PortalRulesViolations, private readonly hasRiskIndex: boolean, - private readonly translate: TranslateService + private readonly translate: TranslateService, ) { super(baseObject.GetEntity()); diff --git a/imxweb/projects/cpl/src/lib/rules-violations/rules-violations-details/rules-violations-details.component.html b/imxweb/projects/cpl/src/lib/rules-violations/rules-violations-details/rules-violations-details.component.html index d41f8a9a8..5433064bf 100644 --- a/imxweb/projects/cpl/src/lib/rules-violations/rules-violations-details/rules-violations-details.component.html +++ b/imxweb/projects/cpl/src/lib/rules-violations/rules-violations-details/rules-violations-details.component.html @@ -1,35 +1,48 @@ - + -
    +
    {{ data.selectedRulesViolation?.State?.GetMetadata()?.GetDisplay() }}
    - + {{ data.selectedRulesViolation?.stateBadge?.caption }}
    -
    +
    - - +
    #LDS#Heading Mitigating Controls - + - - + diff --git a/imxweb/projects/cpl/src/lib/rules-violations/rules-violations-details/rules-violations-details.component.scss b/imxweb/projects/cpl/src/lib/rules-violations/rules-violations-details/rules-violations-details.component.scss index dce5bab68..e964cb92f 100644 --- a/imxweb/projects/cpl/src/lib/rules-violations/rules-violations-details/rules-violations-details.component.scss +++ b/imxweb/projects/cpl/src/lib/rules-violations/rules-violations-details/rules-violations-details.component.scss @@ -1,49 +1,16 @@ -@import "@elemental-ui/core/src/styles/_eui_palette.scss"; +@import '@elemental-ui/core/src/styles/_eui_palette.scss'; :host { - .mat-tab-group, ::ng-deep .mat-tab-body-wrapper { - height: 100%; - } - - ::ng-deep .mat-tab-body-content { - display: flex; - flex-direction: column; - justify-content: space-between; - } - - - .imx-mat-tab-container { - display: flex; - flex-direction: column; - overflow: auto; - } - - .eui-sidesheet-content { - display: flex; - flex-direction: column; - } - - .eui-badge ::ng-deep .eui-badge-content { - font-size: 12px; - line-height: 12px; - margin-bottom: 20px; - } .imx-state-caption { font-size: 12px; padding-bottom: 5px; } - .eui-sidesheet-actions { - button:not(:last-of-type) { - margin-right: 10px; - } - } - .imx-dirty-indicator { margin-left: 5px; } - imx-ext{ + imx-ext { height: 100%; } } @@ -57,24 +24,4 @@ .imx-state-caption { color: $color-gray-40; } - - ::ng-deep .mat-tab-labels { - background-color: $color-gray-0; - } -} - -.eui-dark-theme { - :host { - ::ng-deep .mat-tab-labels { - background-color: $color-gray-70; - } - } -} - -.eui-contrast-theme { - :host { - ::ng-deep .mat-tab-labels { - background-color: $color-gray-100; - } - } } diff --git a/imxweb/projects/cpl/src/lib/rules-violations/rules-violations-details/rules-violations-details.component.ts b/imxweb/projects/cpl/src/lib/rules-violations/rules-violations-details/rules-violations-details.component.ts index 7f8ceb50a..b7316616f 100644 --- a/imxweb/projects/cpl/src/lib/rules-violations/rules-violations-details/rules-violations-details.component.ts +++ b/imxweb/projects/cpl/src/lib/rules-violations/rules-violations-details/rules-violations-details.component.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -28,8 +28,8 @@ import { Component, Inject, OnDestroy, OnInit, Type, ViewChild } from '@angular/ import { EUI_SIDESHEET_DATA, EuiSidesheetRef } from '@elemental-ui/core'; import { MatTabGroup } from '@angular/material/tabs'; +import { PortalRules } from '@imx-modules/imx-api-cpl'; import { TranslateService } from '@ngx-translate/core'; -import { PortalRules } from 'imx-api-cpl'; import { BaseCdr, ExtService, IExtension } from 'qbm'; import { Subscription } from 'rxjs'; import { RulesViolationsActionService } from '../rules-violations-action/rules-violations-action.service'; @@ -59,7 +59,7 @@ export class RulesViolationsDetailsComponent implements OnInit, OnDestroy { public uidNonCompliance: string; public uidCompliance: string; public ruleInfoCdrList: BaseCdr[] = []; - private subscriptions$: Subscription[] = []; + private subscriptions$: (Subscription | undefined)[] = []; constructor( @Inject(EUI_SIDESHEET_DATA) @@ -71,29 +71,29 @@ export class RulesViolationsDetailsComponent implements OnInit, OnDestroy { public sidesheetRef: EuiSidesheetRef, private readonly actionService: RulesViolationsActionService, private readonly extService: ExtService, - private translateService: TranslateService + private translateService: TranslateService, ) { this.uidPerson = data.selectedRulesViolation.GetEntity().GetColumn('UID_Person').GetValue(); this.uidNonCompliance = data.selectedRulesViolation.GetEntity().GetColumn('UID_NonCompliance').GetValue(); this.cdrList = data.selectedRulesViolation.propertyInfo; if (this.data.complianceRule) this.ruleInfoCdrList.push( - new BaseCdr(this.data.complianceRule.Description.Column, this.translateService.instant('#LDS#Description')), - new BaseCdr(this.data.complianceRule.RuleNumber.Column) + new BaseCdr(this.data.complianceRule.Description.Column, this.translateService.instant('#LDS#Rule description')), + new BaseCdr(this.data.complianceRule.RuleNumber.Column), ); } public ngOnInit(): void { this.subscriptions$.push( - this.sidesheetRef.componentInstance.onOpen().subscribe(() => { + this.sidesheetRef.componentInstance?.onOpen().subscribe(() => { // Recalculates header this.matTabGroup.updatePagination(); - }) + }), ); } /** - * Opens the Approve-Sidesheet for the current selected rules violations and closes the sidesheet afterwards. + * Opens the Approve-Sidesheet for the current selected rule violations and closes the sidesheet afterwards. */ public async approve(): Promise { await this.actionService.approve([this.data.selectedRulesViolation]); @@ -101,7 +101,7 @@ export class RulesViolationsDetailsComponent implements OnInit, OnDestroy { } /** - * Opens the Deny-Sidesheet for the current selected rules violations and closes the sidesheet afterwards. + * Opens the Deny-Sidesheet for the current selected rule violations and closes the sidesheet afterwards. */ public async deny(): Promise { await this.actionService.deny([this.data.selectedRulesViolation]); @@ -118,6 +118,6 @@ export class RulesViolationsDetailsComponent implements OnInit, OnDestroy { } public ngOnDestroy(): void { - this.subscriptions$.map((sub) => sub.unsubscribe()); + this.subscriptions$.map((sub) => sub?.unsubscribe()); } } diff --git a/imxweb/projects/cpl/src/lib/rules-violations/rules-violations-load-parameters.interface.ts b/imxweb/projects/cpl/src/lib/rules-violations/rules-violations-load-parameters.interface.ts index 8853ba55b..a61d8620a 100644 --- a/imxweb/projects/cpl/src/lib/rules-violations/rules-violations-load-parameters.interface.ts +++ b/imxweb/projects/cpl/src/lib/rules-violations/rules-violations-load-parameters.interface.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -24,7 +24,7 @@ * */ -import { CollectionLoadParameters } from 'imx-qbm-dbts'; +import { CollectionLoadParameters } from '@imx-modules/imx-qbm-dbts'; /** * Extends the {@link CollectionLoadParameters} with some addtional parameters for the grouping API. diff --git a/imxweb/projects/cpl/src/lib/rules-violations/rules-violations.component.html b/imxweb/projects/cpl/src/lib/rules-violations/rules-violations.component.html index 04c72193c..fdfbd4bab 100644 --- a/imxweb/projects/cpl/src/lib/rules-violations/rules-violations.component.html +++ b/imxweb/projects/cpl/src/lib/rules-violations/rules-violations.component.html @@ -1,86 +1,114 @@
    -
    -

    +
    +

    {{ '#LDS#Heading Rule Violations' | translate }} -

    +

    +
    - -
    - - - - - - - - + + + + + + {{ entitySchema?.Columns?.UID_Person?.Display }} + + + + + {{ item.UID_Person.Column.GetDisplayValue() }} + + + + + + + {{ entitySchema?.Columns?.UID_NonCompliance?.Display }} + + + + + {{ item.UID_NonCompliance.Column.GetDisplayValue() }} + + + + + + + {{ entitySchema?.Columns?.State?.Display }} + + + + {{ item?.stateBadge?.caption }} - - - - - - - - -
    - - -
    -
    -
    -
    - -
    + + + + + + + {{ entitySchema?.Columns?.RiskIndexCalculated?.Display }} + + + + + {{ item.RiskIndexCalculated.Column.GetDisplayValue() }} + + + + + + + {{ entitySchema?.Columns?.RiskIndexReduced?.Display }} + + + + + {{ item.RiskIndexReduced.Column.GetDisplayValue() }} + + + + + + + {{ entitySchema?.Columns?.CountOpen?.Display }} + + + +
    + + +
    + +
    + +
    -
    - -
    +
    + - +
    diff --git a/imxweb/projects/cpl/src/lib/rules/mitigating-controls-rules/mitigating-controls-rules.component.scss b/imxweb/projects/cpl/src/lib/rules/mitigating-controls-rules/mitigating-controls-rules.component.scss index 979bb992b..4747cbf18 100644 --- a/imxweb/projects/cpl/src/lib/rules/mitigating-controls-rules/mitigating-controls-rules.component.scss +++ b/imxweb/projects/cpl/src/lib/rules/mitigating-controls-rules/mitigating-controls-rules.component.scss @@ -6,15 +6,11 @@ flex-direction: column; justify-content: space-between; - .imx-helper-alert { - margin: 0px 0 20px auto; - width: 100%; - } - .control-container { padding: 20px; display: flex; flex-direction: column; + flex: 1 1 auto; overflow: auto; } @@ -29,23 +25,11 @@ width: 100%; margin-right: 15px; } - - eui-icon { - cursor: pointer; - display: flex; - flex-direction: column; - justify-content: center; - } } - .imx-no-mitigating-controls { + .imx-no-results { text-align: center; - margin: 20px 0; - - .eui-icon { - font-size: 100px; - color: rgba($black-c, 0.55); - } + margin: auto; p { margin: 0; @@ -53,10 +37,4 @@ color: $black-9; } } - - .button-actions { - display: flex; - justify-content: space-between; - margin-top: 20px; - } } diff --git a/imxweb/projects/cpl/src/lib/rules/mitigating-controls-rules/mitigating-controls-rules.component.spec.ts b/imxweb/projects/cpl/src/lib/rules/mitigating-controls-rules/mitigating-controls-rules.component.spec.ts index bfc10034c..178223498 100644 --- a/imxweb/projects/cpl/src/lib/rules/mitigating-controls-rules/mitigating-controls-rules.component.spec.ts +++ b/imxweb/projects/cpl/src/lib/rules/mitigating-controls-rules/mitigating-controls-rules.component.spec.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -28,14 +28,12 @@ import { ChangeDetectorRef, CUSTOM_ELEMENTS_SCHEMA } from '@angular/core'; import { UntypedFormBuilder, UntypedFormControl } from '@angular/forms'; import { EuiLoadingService, EuiSidesheetRef } from '@elemental-ui/core'; import { MockBuilder, MockedComponentFixture, MockRender } from 'ng-mocks'; -import { clearStylesFromDOM, ConfirmationService, SnackBarService, } from 'qbm'; +import { clearStylesFromDOM, ConfirmationService, SnackBarService } from 'qbm'; import { MitigatingControlsRulesComponent } from './mitigating-controls-rules.component'; import { MitigatingControlsRulesService } from './mitigating-controls-rules.service'; import { RulesMitigatingControls } from './rules-mitigating-controls'; - - describe('MitigatingControlsRulesComponent', () => { let component: MitigatingControlsRulesComponent; let fixture: MockedComponentFixture; @@ -45,13 +43,13 @@ describe('MitigatingControlsRulesComponent', () => { GetEntity: () => ({ GetKeys: () => [''], GetColumn: (column: string) => { - return {GetValue: () => ''} - } + return { GetValue: () => '' }; + }, }), UID_ComplianceRule: {}, UID_MitigatingControl: {}, UID_NonCompliance: {}, - } + }; beforeEach(() => { return MockBuilder([MitigatingControlsRulesComponent, UntypedFormBuilder, ChangeDetectorRef]) @@ -59,15 +57,15 @@ describe('MitigatingControlsRulesComponent', () => { createControl: jasmine.createSpy('createControl').and.returnValue(mockedControl), postControl: jasmine.createSpy('postControl').and.resolveTo({}), getControls: jasmine.createSpy('getControls').and.resolveTo({ - Data: [mockedControl] - }) + Data: [mockedControl], + }), }) .mock(EuiLoadingService) .mock(SnackBarService) .mock(ConfirmationService) - .beforeCompileComponents(testBed => { + .beforeCompileComponents((testBed) => { testBed.configureTestingModule({ - schemas: [CUSTOM_ELEMENTS_SCHEMA] + schemas: [CUSTOM_ELEMENTS_SCHEMA], }); }); }); @@ -78,7 +76,7 @@ describe('MitigatingControlsRulesComponent', () => { uidNonCompliance: '', uidCompliance: '', mControls: [], - sidesheetRef: new EuiSidesheetRef(null) + sidesheetRef: new EuiSidesheetRef(null), }); component = fixture.point.componentInstance; fixture.detectChanges(); @@ -86,7 +84,7 @@ describe('MitigatingControlsRulesComponent', () => { afterAll(() => { clearStylesFromDOM(); - }) + }); it('should create', () => { expect(component).toBeTruthy(); @@ -99,7 +97,7 @@ describe('MitigatingControlsRulesComponent', () => { await component.onSave(); expect(fixture.point.injector.get(MitigatingControlsRulesService).postControl).not.toHaveBeenCalled(); - }) + }); it('should create a control, save, and then delete', async () => { component.onCreateControl(); @@ -114,5 +112,5 @@ describe('MitigatingControlsRulesComponent', () => { await component.onDelete(mockedControl as RulesMitigatingControls, 0); expect(component.mControls.length).toBe(0); - }) + }); }); diff --git a/imxweb/projects/cpl/src/lib/rules/mitigating-controls-rules/mitigating-controls-rules.component.ts b/imxweb/projects/cpl/src/lib/rules/mitigating-controls-rules/mitigating-controls-rules.component.ts index c6284f10d..c929ab4d4 100644 --- a/imxweb/projects/cpl/src/lib/rules/mitigating-controls-rules/mitigating-controls-rules.component.ts +++ b/imxweb/projects/cpl/src/lib/rules/mitigating-controls-rules/mitigating-controls-rules.component.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -43,7 +43,7 @@ export class MitigatingControlsRulesComponent implements OnInit, OnDestroy { @Input() public uidCompliance: string; @Input() public mControls: RulesMitigatingControls[]; @Input() public sidesheetRef: EuiSidesheetRef; - @Input() public canEdit = true; + @Input() public canEdit = true; public subscriptions$: Subscription[] = []; public formGroup: UntypedFormGroup; @@ -53,7 +53,7 @@ export class MitigatingControlsRulesComponent implements OnInit, OnDestroy { private cd: ChangeDetectorRef, private busyService: EuiLoadingService, private snackbarService: SnackBarService, - private confirmationService: ConfirmationService + private confirmationService: ConfirmationService, ) { this.formGroup = new UntypedFormGroup({ formArray: formBuilder.array([]) }); } @@ -68,7 +68,7 @@ export class MitigatingControlsRulesComponent implements OnInit, OnDestroy { if (!this.formGroup.dirty || (await this.confirmationService.confirmLeaveWithUnsavedChanges())) { this.sidesheetRef.close(); } - }) + }), ); } @@ -113,7 +113,8 @@ export class MitigatingControlsRulesComponent implements OnInit, OnDestroy { await this.confirmationService.confirmGeneral({ ShowOk: true, Title: '#LDS#Heading Mitigating Control Assigned More Than Once', - Message: '#LDS#Saving is not possible. At least one mitigating control is assigned more than once. Remove the multiple assigned mitigating control and try again.', + Message: + '#LDS#Saving is not possible. At least one mitigating control is assigned more than once. Remove the multiple assigned mitigating control and try again.', }); return; } diff --git a/imxweb/projects/cpl/src/lib/rules/mitigating-controls-rules/mitigating-controls-rules.service.spec.ts b/imxweb/projects/cpl/src/lib/rules/mitigating-controls-rules/mitigating-controls-rules.service.spec.ts index 3a3021473..7697d56d5 100644 --- a/imxweb/projects/cpl/src/lib/rules/mitigating-controls-rules/mitigating-controls-rules.service.spec.ts +++ b/imxweb/projects/cpl/src/lib/rules/mitigating-controls-rules/mitigating-controls-rules.service.spec.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -36,9 +36,8 @@ describe('MitigatingControlsRulesService', () => { beforeEach(() => { return MockBuilder([MitigatingControlsRulesService]) .mock(ApiService) - .beforeCompileComponents(testBed => { - testBed.configureTestingModule({ - }); + .beforeCompileComponents((testBed) => { + testBed.configureTestingModule({}); }); }); diff --git a/imxweb/projects/cpl/src/lib/rules/mitigating-controls-rules/mitigating-controls-rules.service.ts b/imxweb/projects/cpl/src/lib/rules/mitigating-controls-rules/mitigating-controls-rules.service.ts index a00ac2f5c..59967c1c9 100644 --- a/imxweb/projects/cpl/src/lib/rules/mitigating-controls-rules/mitigating-controls-rules.service.ts +++ b/imxweb/projects/cpl/src/lib/rules/mitigating-controls-rules/mitigating-controls-rules.service.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -25,35 +25,32 @@ */ import { Injectable } from '@angular/core'; -import { PortalRulesMitigatingcontrols } from 'imx-api-cpl'; -import { ExtendedTypedEntityCollection } from 'imx-qbm-dbts'; +import { PortalRulesMitigatingcontrols } from '@imx-modules/imx-api-cpl'; +import { ExtendedTypedEntityCollection } from '@imx-modules/imx-qbm-dbts'; import { ApiService } from '../../api.service'; import { RulesMitigatingControls } from './rules-mitigating-controls'; @Injectable({ - providedIn: 'root' + providedIn: 'root', }) export class MitigatingControlsRulesService { - - constructor( - private apiService: ApiService, - ) { } + constructor(private apiService: ApiService) {} public async getControls(uidNonCompliance: string): Promise> { const collection = await this.apiService.typedClient.PortalRulesMitigatingcontrols.Get(uidNonCompliance); return { tableName: collection.tableName, totalCount: collection.totalCount, - Data: collection.Data.map((item: PortalRulesMitigatingcontrols) => new RulesMitigatingControls(item)) - } + Data: collection.Data.map((item: PortalRulesMitigatingcontrols) => new RulesMitigatingControls(item)), + }; } public createControl(uidCompliance: string): RulesMitigatingControls { // TODO: When API can handle permission issues uncomment. PBI: 305793 const newMControl = this.apiService.typedClient.PortalRulesWorkingcopiesMitigatingcontrols.createEntity({ Columns: { - "UID_ComplianceRule": { Value: uidCompliance } - } + UID_ComplianceRule: { Value: uidCompliance }, + }, }); return new RulesMitigatingControls(newMControl as PortalRulesMitigatingcontrols); // const newMControl = this.apiService.typedClient.PortalRulesMitigatingcontrols.createEntity({ diff --git a/imxweb/projects/cpl/src/lib/rules/mitigating-controls-rules/rules-mitigating-controls.ts b/imxweb/projects/cpl/src/lib/rules/mitigating-controls-rules/rules-mitigating-controls.ts index 1ff467db7..e2e1a95e7 100644 --- a/imxweb/projects/cpl/src/lib/rules/mitigating-controls-rules/rules-mitigating-controls.ts +++ b/imxweb/projects/cpl/src/lib/rules/mitigating-controls-rules/rules-mitigating-controls.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -24,38 +24,29 @@ * */ -import { IWriteValue } from 'imx-qbm-dbts'; +import { IWriteValue } from '@imx-modules/imx-qbm-dbts'; import { BaseCdr, ColumnDependentReference } from 'qbm'; -import { PortalRulesMitigatingcontrols } from 'imx-api-cpl'; +import { PortalRulesMitigatingcontrols } from '@imx-modules/imx-api-cpl'; /** * Class thats extends the {@link PortalRulesMitigatingcontrols} with some additional properties that are needed for * the components in the approval context. */ export class RulesMitigatingControls extends PortalRulesMitigatingcontrols { - /** * The property list depending on the value of the state of a {@link PortalRulesMitigatingcontrols}. */ public readonly propertyInfo: ColumnDependentReference[]; - - constructor( - readonly baseObject: PortalRulesMitigatingcontrols - ) { + constructor(readonly baseObject: PortalRulesMitigatingcontrols) { super(baseObject.GetEntity()); this.propertyInfo = this.initPropertyInfo(); } private initPropertyInfo(): ColumnDependentReference[] { - const properties: IWriteValue[] = - [ - this.UID_MitigatingControl, - ]; + const properties: IWriteValue[] = [this.UID_MitigatingControl]; - return properties - .map(property => new BaseCdr(property.Column)); + return properties.map((property) => new BaseCdr(property.Column)); } - } diff --git a/imxweb/projects/cpl/src/lib/rules/rule-parameter.ts b/imxweb/projects/cpl/src/lib/rules/rule-parameter.ts index eb31886b3..9822f2395 100644 --- a/imxweb/projects/cpl/src/lib/rules/rule-parameter.ts +++ b/imxweb/projects/cpl/src/lib/rules/rule-parameter.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -24,8 +24,8 @@ * */ -import { CollectionLoadParameters } from 'imx-qbm-dbts'; +import { CollectionLoadParameters } from '@imx-modules/imx-qbm-dbts'; -export interface RuleParameter extends CollectionLoadParameters{ +export interface RuleParameter extends CollectionLoadParameters { active?: string; } diff --git a/imxweb/projects/cpl/src/lib/rules/rules-sidesheet/rules-sidesheet.component.html b/imxweb/projects/cpl/src/lib/rules/rules-sidesheet/rules-sidesheet.component.html index 8ea2f0577..d4343a070 100644 --- a/imxweb/projects/cpl/src/lib/rules/rules-sidesheet/rules-sidesheet.component.html +++ b/imxweb/projects/cpl/src/lib/rules/rules-sidesheet/rules-sidesheet.component.html @@ -1,4 +1,4 @@ - +
    @@ -8,7 +8,12 @@
    -
    @@ -17,8 +22,8 @@ -
    - +
    +
    @@ -39,7 +44,11 @@
    - + +
    diff --git a/imxweb/projects/cpl/src/lib/rules/rules-sidesheet/rules-sidesheet.component.scss b/imxweb/projects/cpl/src/lib/rules/rules-sidesheet/rules-sidesheet.component.scss index 886de866f..4312f362a 100644 --- a/imxweb/projects/cpl/src/lib/rules/rules-sidesheet/rules-sidesheet.component.scss +++ b/imxweb/projects/cpl/src/lib/rules/rules-sidesheet/rules-sidesheet.component.scss @@ -1,48 +1,5 @@ -@import "@elemental-ui/core/src/styles/_palette.scss"; - -:host { - .mat-tab-group, ::ng-deep .mat-tab-body-wrapper { - height: 100%; - } - - ::ng-deep .mat-tab-body-content { - display: flex; - flex-direction: column; - justify-content: space-between; - } - - .imx-mat-tab-container { - padding: 20px; - display: flex; - flex-direction: column; - overflow: auto; - } -} +@import 'base/mixins'; .eui-sidesheet-actions { - .justify-start { - margin-right: auto; - } -} - -:host { - ::ng-deep .mat-tab-labels { - background-color: $color-gray-0; - } -} - -.eui-dark-theme { - :host { - ::ng-deep .mat-tab-labels { - background-color: $color-gray-80; - } - } -} - -.eui-contrast-theme { - :host { - ::ng-deep .mat-tab-labels { - background-color: $color-gray-100; - } - } + @include eui-sidesheet-actions__mixin_01($padding: 16px 20px); } diff --git a/imxweb/projects/cpl/src/lib/rules/rules-sidesheet/rules-sidesheet.component.ts b/imxweb/projects/cpl/src/lib/rules/rules-sidesheet/rules-sidesheet.component.ts index cff700ee8..f5d677a34 100644 --- a/imxweb/projects/cpl/src/lib/rules/rules-sidesheet/rules-sidesheet.component.ts +++ b/imxweb/projects/cpl/src/lib/rules/rules-sidesheet/rules-sidesheet.component.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -25,12 +25,12 @@ */ import { Component, Inject, OnDestroy } from '@angular/core'; -import { EuiDownloadOptions, EuiSidesheetRef, EUI_SIDESHEET_DATA } from '@elemental-ui/core'; +import { EUI_SIDESHEET_DATA, EuiDownloadOptions, EuiSidesheetRef } from '@elemental-ui/core'; import { Subscription } from 'rxjs'; -import { PortalRules } from 'imx-api-cpl'; -import { DisplayColumns } from 'imx-qbm-dbts'; -import { BaseReadonlyCdr, ColumnDependentReference, ElementalUiConfigService } from 'qbm'; +import { PortalRules } from '@imx-modules/imx-api-cpl'; +import { DisplayColumns } from '@imx-modules/imx-qbm-dbts'; +import { BaseReadonlyCdr, ElementalUiConfigService } from 'qbm'; import { RulesMitigatingControls } from '../mitigating-controls-rules/rules-mitigating-controls'; import { RulesService } from '../rules.service'; @@ -41,7 +41,7 @@ import { RulesService } from '../rules.service'; }) export class RulesSidesheetComponent implements OnDestroy { public reportDownload: EuiDownloadOptions; - public cdrList: ColumnDependentReference[]; + public cdrList: BaseReadonlyCdr[]; public uidNonCompliance: string; public uidCompliance: string; @@ -58,7 +58,7 @@ export class RulesSidesheetComponent implements OnDestroy { }, public sidesheetRef: EuiSidesheetRef, private readonly rulesProvider: RulesService, - elementalUiConfigService: ElementalUiConfigService + elementalUiConfigService: ElementalUiConfigService, ) { this.uidNonCompliance = data.selectedRule.GetEntity().GetColumn('UID_NonCompliance').GetValue(); this.uidCompliance = data.selectedRule.GetEntity().GetKeys().join(','); @@ -66,14 +66,14 @@ export class RulesSidesheetComponent implements OnDestroy { new BaseReadonlyCdr(this.data.selectedRule.GetEntity().GetColumn(DisplayColumns.DISPLAY_PROPERTYNAME)), new BaseReadonlyCdr(this.data.selectedRule.Description.Column), new BaseReadonlyCdr(this.data.selectedRule.RuleNumber.Column), - data.hasRiskIndex ? new BaseReadonlyCdr(this.data.selectedRule.RiskIndex.Column) : null, - data.hasRiskIndex && this.data.selectedRule.RiskIndex.value !== this.data.selectedRule.RiskIndexReduced.value - ? new BaseReadonlyCdr(this.data.selectedRule.RiskIndexReduced.Column) - : null, + ...(data.hasRiskIndex ? [new BaseReadonlyCdr(this.data.selectedRule.RiskIndex.Column)] : []), + ...(data.hasRiskIndex && this.data.selectedRule.RiskIndex.value !== this.data.selectedRule.RiskIndexReduced.value + ? [new BaseReadonlyCdr(this.data.selectedRule.RiskIndexReduced.Column)] + : []), new BaseReadonlyCdr(this.data.selectedRule.IsInActive.Column), new BaseReadonlyCdr(this.data.selectedRule.CountOpen.Column), new BaseReadonlyCdr(this.data.selectedRule.CountClosed.Column), - ].filter((elem) => elem != null); + ]; this.reportDownload = { ...elementalUiConfigService.Config.downloadOptions, diff --git a/imxweb/projects/cpl/src/lib/rules/rules-sidesheet/violations-per-rule/violations-per-rule.component.html b/imxweb/projects/cpl/src/lib/rules/rules-sidesheet/violations-per-rule/violations-per-rule.component.html index f944ea132..62a0ec28f 100644 --- a/imxweb/projects/cpl/src/lib/rules/rules-sidesheet/violations-per-rule/violations-per-rule.component.html +++ b/imxweb/projects/cpl/src/lib/rules/rules-sidesheet/violations-per-rule/violations-per-rule.component.html @@ -1,8 +1,8 @@
    - + {{ '#LDS#Here you can get an overview of the violations of the compliance rule.' | translate }} - + ; - public dstSettings: DataSourceToolbarSettings; + public dstSettings: DataSourceToolbarSettings | undefined; public groupedData: { [key: string]: DataTableGroupedData } = {}; public entitySchema: EntitySchema; @@ -52,7 +52,7 @@ export class ViolationsPerRuleComponent implements OnInit { constructor( private readonly rulesViolationsService: RulesViolationsService, private readonly translate: TranslateService, - private readonly sidesheet: EuiSidesheetService + private readonly sidesheet: EuiSidesheetService, ) {} async ngOnInit(): Promise { @@ -74,7 +74,7 @@ export class ViolationsPerRuleComponent implements OnInit { this.entitySchema.Columns.RiskIndexReduced, ], this.entitySchema, - this.dataModelWrapper + this.dataModelWrapper, ); await this.getData(); @@ -90,11 +90,11 @@ export class ViolationsPerRuleComponent implements OnInit { const groupedData = this.groupedData[groupKey]; groupedData.data = await this.rulesViolationsService.getRulesViolationsApprove(groupedData.navigationState); groupedData.settings = { - displayedColumns: this.dstSettings.displayedColumns, - dataModel: this.dstSettings.dataModel, + displayedColumns: this.dstSettings?.displayedColumns, + dataModel: this.dstSettings?.dataModel, dataSource: groupedData.data, - entitySchema: this.dstSettings.entitySchema, - navigationState: groupedData.navigationState, + entitySchema: this.entitySchema, + navigationState: groupedData.navigationState || {}, }; } finally { this.rulesViolationsService.handleCloseLoader(); @@ -105,7 +105,8 @@ export class ViolationsPerRuleComponent implements OnInit { * Opens rules-violations-details sidesheet, where you can manage the selected rule. * @param rule The selected rule from the Rule Violations list */ - public async showRulesViolationsDetail(rule: RulesViolationsApproval) { + public async showRulesViolationsDetail(entity: TypedEntity) { + const rule = entity as RulesViolationsApproval; const complianceRule = await this.rulesViolationsService.getComplianceRuleByUId(rule); const config = await this.rulesViolationsService.featureConfig(); await this.sidesheet @@ -113,7 +114,7 @@ export class ViolationsPerRuleComponent implements OnInit { title: await this.translate.get('#LDS#Heading View Rule Violation Details').toPromise(), subTitle: rule.GetEntity().GetDisplay(), padding: '0px', - width: 'max(1000px, 70%)', + width: calculateSidesheetWidth(1000), testId: 'rules-violations-informations-sidesheet', data: { selectedRulesViolation: rule, diff --git a/imxweb/projects/cpl/src/lib/rules/rules.component.html b/imxweb/projects/cpl/src/lib/rules/rules.component.html index ef2f25312..2adcffd25 100644 --- a/imxweb/projects/cpl/src/lib/rules/rules.component.html +++ b/imxweb/projects/cpl/src/lib/rules/rules.component.html @@ -1,58 +1,71 @@ -

    - {{ '#LDS#Heading Compliance Rules' | translate }} - -

    - -
    - - -
    - - - -
    -
    -
    {{ item.GetEntity().GetDisplay() }}
    -
    {{ item.Description.Column.GetDisplayValue() }}
    -
    - {{ '#LDS#Deactivated' | translate }} -
    -
    -
    - - - - {{ rule.CountOpen.value + rule.CountClosed.value }} - - - - - - - -
    - -
    -
    -
    -
    -
    - -
    +
    +

    + {{ '#LDS#Heading Compliance Rules' | translate }} + +

    + +
    + + + + + {{ ruleSchema?.Columns?.[DisplayColumns.DISPLAY_PROPERTYNAME]?.Display }} + + +
    +
    +
    {{ item.GetEntity().GetDisplay() }}
    +
    {{ item.Description.Column.GetDisplayValue() }}
    +
    + {{ '#LDS#Deactivated' | translate }} +
    + +
    + + + + {{ '#LDS#Rule violations' | translate }} + + + + + {{ rule.CountOpen.value + rule.CountClosed.value }} + + + + + + + {{ ruleSchema?.Columns?.CountOpen?.Display }} + + + + + {{ rule.CountOpen.Column.GetDisplayValue() }} + + + + + + + + +
    + +
    + +
    +
    +
    diff --git a/imxweb/projects/cpl/src/lib/rules/rules.component.scss b/imxweb/projects/cpl/src/lib/rules/rules.component.scss index 0fe557c68..12b0efc17 100644 --- a/imxweb/projects/cpl/src/lib/rules/rules.component.scss +++ b/imxweb/projects/cpl/src/lib/rules/rules.component.scss @@ -1,5 +1,5 @@ @import '@elemental-ui/core/src/styles/_palette.scss'; -@import '../../../../../shared/scss/common-table.scss'; +@import 'base/mixins'; div[subtitle] { font-size: smaller; @@ -13,32 +13,15 @@ div[subtitle] { height: inherit; } -.mat-card { - @include imx-flex-fill-control-hidden-overflow(); - margin: 3px; -} - -.imx-table-container { - display: flex; - flex-direction: column; - overflow: hidden; - flex: 1 1 auto; -} - -.imx-button-column { - @include imx-button-column-right(); -} - -.imx-displayColumn { - display: flex; - flex-direction: row; - - :first-child { +.imx-display-column { + width: 100% !important; + cursor: inherit !important; + &-main { flex: 1 1 auto; + display: block !important; + cursor: inherit !important; } - .imx-badge { - align-self: center; - margin-left: 15px; + align-self: flex-end; } } diff --git a/imxweb/projects/cpl/src/lib/rules/rules.component.ts b/imxweb/projects/cpl/src/lib/rules/rules.component.ts index ee27d6cea..2145c52f1 100644 --- a/imxweb/projects/cpl/src/lib/rules/rules.component.ts +++ b/imxweb/projects/cpl/src/lib/rules/rules.component.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -28,22 +28,29 @@ import { Component, OnInit } from '@angular/core'; import { EuiSidesheetService } from '@elemental-ui/core'; import { TranslateService } from '@ngx-translate/core'; -import { PortalRules } from 'imx-api-cpl'; -import { CplPermissionsService } from './admin/cpl-permissions.service'; -import { ViewConfigData } from 'imx-api-qer'; -import { CollectionLoadParameters, DataModel, DisplayColumns, EntitySchema, ValType } from 'imx-qbm-dbts'; +import { PortalRules } from '@imx-modules/imx-api-cpl'; +import { ViewConfigData } from '@imx-modules/imx-api-qer'; +import { + CollectionLoadParameters, + DataModel, + DisplayColumns, + EntitySchema, + TypedEntityCollectionData, + ValType, +} from '@imx-modules/imx-qbm-dbts'; import { - DataSourceToolbarFilter, - DataSourceToolbarSettings, + BusyService, + calculateSidesheetWidth, ClientPropertyForTableColumns, DataSourceToolbarViewConfig, + DataViewInitParameters, + DataViewSource, SystemInfoService, - BusyService, } from 'qbm'; import { ViewConfigService } from 'qer'; +import { CplPermissionsService } from './admin/cpl-permissions.service'; import { MitigatingControlsRulesService } from './mitigating-controls-rules/mitigating-controls-rules.service'; import { RulesMitigatingControls } from './mitigating-controls-rules/rules-mitigating-controls'; -import { RuleParameter } from './rule-parameter'; import { RulesSidesheetComponent } from './rules-sidesheet/rules-sidesheet.component'; import { RulesService } from './rules.service'; @@ -51,20 +58,16 @@ import { RulesService } from './rules.service'; selector: 'imx-rules', templateUrl: './rules.component.html', styleUrls: ['./rules.component.scss'], + providers: [DataViewSource], }) export class RulesComponent implements OnInit { - public dstSettings: DataSourceToolbarSettings; public readonly DisplayColumns = DisplayColumns; public ruleSchema: EntitySchema; public isMControlPerViolation: boolean; - public busyService = new BusyService(); - + public canRecalculate = false; private displayedColumns: ClientPropertyForTableColumns[] = []; private dataModel: DataModel; - private filterOptions: DataSourceToolbarFilter[] = []; - private navigationState: RuleParameter = {}; - public canRecalculate = false; private viewConfig: DataSourceToolbarViewConfig; private viewConfigPath = 'rules'; @@ -75,7 +78,8 @@ export class RulesComponent implements OnInit { private readonly sideSheetService: EuiSidesheetService, private readonly systemInfoService: SystemInfoService, private readonly translate: TranslateService, - private readonly permissionService: CplPermissionsService + private readonly permissionService: CplPermissionsService, + public dataSource: DataViewSource, ) { this.ruleSchema = rulesProvider.ruleSchema; this.displayedColumns = [ @@ -99,26 +103,15 @@ export class RulesComponent implements OnInit { const isBusy = this.busyService.beginBusy(); try { this.dataModel = await this.rulesProvider.getDataModel(); - this.filterOptions = this.dataModel.Filters; this.viewConfig = await this.viewConfigService.getInitialDSTExtension(this.dataModel, this.viewConfigPath); this.isMControlPerViolation = (await this.rulesProvider.featureConfig()).MitigatingControlsPerViolation; - // We will check the configs for default state only on init - if (!this.viewConfigService.isDefaultConfigSet()) { - // If we have no default settings, we have a default - const indexActive = this.filterOptions.findIndex((elem) => elem.Name === 'active'); - if (indexActive > -1) { - this.filterOptions[indexActive].InitialValue = '1'; - this.navigationState.active = '1'; - } - } - this.canRecalculate = await this.permissionService.isRuleStatistics(); if (!this.canRecalculate) { this.displayedColumns.pop(); } - await this.navigate({}); + await this.getData(); } finally { isBusy.endBusy(); } @@ -127,16 +120,17 @@ export class RulesComponent implements OnInit { public async updateConfig(config: ViewConfigData): Promise { await this.viewConfigService.putViewConfig(config); this.viewConfig = await this.viewConfigService.getDSTExtensionChanges(this.viewConfigPath); - this.dstSettings.viewConfig = this.viewConfig; + this.dataSource.viewConfig.set(this.viewConfig); } public async deleteConfigById(id: string): Promise { await this.viewConfigService.deleteViewConfig(id); this.viewConfig = await this.viewConfigService.getDSTExtensionChanges(this.viewConfigPath); - this.dstSettings.viewConfig = this.viewConfig; + this.dataSource.viewConfig.set(this.viewConfig); } - public async showDetails(selectedRule: PortalRules): Promise { + public async showDetails(entity: PortalRules): Promise { + const selectedRule = entity; this.rulesProvider.handleOpenLoader(); let mControls: RulesMitigatingControls[]; try { @@ -145,14 +139,14 @@ export class RulesComponent implements OnInit { this.rulesProvider.handleCloseLoader(); } - const hasRiskIndex = (await this.systemInfoService.get()).PreProps.includes('RISKINDEX'); + const hasRiskIndex = !!(await this.systemInfoService.get()).PreProps?.includes('RISKINDEX'); await this.sideSheetService .open(RulesSidesheetComponent, { title: await this.translate.get('#LDS#Heading View Compliance Rule Details').toPromise(), subTitle: selectedRule.GetEntity().GetDisplay(), padding: '0px', - width: 'max(1200px, 80%)', + width: calculateSidesheetWidth(1200, 0.7), testId: 'rule-details-sidesheet', data: { selectedRule, @@ -170,32 +164,25 @@ export class RulesComponent implements OnInit { this.rulesProvider.handleOpenLoader(); try { await this.rulesProvider.recalculate(selectedRule.GetEntity().GetKeys().join(',')); - await this.navigate(this.navigationState); + await this.dataSource.updateState(); } finally { this.rulesProvider.handleCloseLoader(); } } - public async navigate(parameter: CollectionLoadParameters): Promise { - this.navigationState = { ...this.navigationState, ...parameter }; - - const isBusy = this.busyService.beginBusy(); - try { - const data = await this.rulesProvider.getRules(this.navigationState); - const exportMethod = this.rulesProvider.exportRules(this.navigationState); - exportMethod.initialColumns = this.displayedColumns.map((col) => col.ColumnName); - this.dstSettings = { - displayedColumns: this.displayedColumns, - dataSource: data, - dataModel: this.dataModel, - entitySchema: this.ruleSchema, - navigationState: this.navigationState, - filters: this.filterOptions, - viewConfig: this.viewConfig, - exportMethod, - }; - } finally { - isBusy.endBusy(); - } + public async getData(): Promise { + const dataViewInitParameters: DataViewInitParameters = { + execute: (params: CollectionLoadParameters, signal: AbortSignal): Promise> => + this.rulesProvider.getRules(params, signal), + schema: this.ruleSchema, + columnsToDisplay: this.displayedColumns, + dataModel: this.dataModel, + exportFunction: this.rulesProvider.exportRules(this.dataSource.state()), + viewConfig: this.viewConfig, + highlightEntity: (identity: PortalRules) => { + this.showDetails(identity); + }, + }; + this.dataSource.init(dataViewInitParameters); } } diff --git a/imxweb/projects/cpl/src/lib/rules/rules.module.ts b/imxweb/projects/cpl/src/lib/rules/rules.module.ts index ba4da18d9..0c83319df 100644 --- a/imxweb/projects/cpl/src/lib/rules/rules.module.ts +++ b/imxweb/projects/cpl/src/lib/rules/rules.module.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -24,29 +24,25 @@ * */ -import { NgModule } from '@angular/core'; import { CommonModule } from '@angular/common'; -import { TranslateModule } from '@ngx-translate/core'; +import { NgModule } from '@angular/core'; import { MatButtonModule } from '@angular/material/button'; import { MatCardModule } from '@angular/material/card'; -import { EuiCoreModule } from '@elemental-ui/core'; import { MatTabsModule } from '@angular/material/tabs'; +import { EuiCoreModule } from '@elemental-ui/core'; +import { TranslateModule } from '@ngx-translate/core'; -import { CdrModule, DataSourceToolbarModule, DataTableModule, HelpContextualModule, ExtModule } from 'qbm'; -import { StatisticsModule, ObjectHyperviewModule } from 'qer'; -import { RulesComponent } from './rules.component'; -import { RulesSidesheetComponent } from './rules-sidesheet/rules-sidesheet.component'; +import { MatTableModule } from '@angular/material/table'; +import { CdrModule, DataSourceToolbarModule, DataTableModule, DataViewModule, ExtModule, HelpContextualModule } from 'qbm'; +import { ObjectHyperviewModule, StatisticsModule } from 'qer'; +import { RulesViolationsModule } from '../rules-violations/rules-violations.module'; import { MitigatingControlsRulesComponent } from './mitigating-controls-rules/mitigating-controls-rules.component'; +import { RulesSidesheetComponent } from './rules-sidesheet/rules-sidesheet.component'; import { ViolationsPerRuleComponent } from './rules-sidesheet/violations-per-rule/violations-per-rule.component'; -import { RulesViolationsModule } from '../rules-violations/rules-violations.module'; +import { RulesComponent } from './rules.component'; @NgModule({ - declarations: [ - RulesComponent, - RulesSidesheetComponent, - MitigatingControlsRulesComponent, - ViolationsPerRuleComponent, - ], + declarations: [RulesComponent, RulesSidesheetComponent, MitigatingControlsRulesComponent, ViolationsPerRuleComponent], imports: [ CommonModule, EuiCoreModule, @@ -61,7 +57,9 @@ import { RulesViolationsModule } from '../rules-violations/rules-violations.modu ObjectHyperviewModule, HelpContextualModule, ExtModule, - RulesViolationsModule + RulesViolationsModule, + DataViewModule, + MatTableModule, ], }) export class RulesModule {} diff --git a/imxweb/projects/cpl/src/lib/rules/rules.service.ts b/imxweb/projects/cpl/src/lib/rules/rules.service.ts index 7422cecd2..4cacc86af 100644 --- a/imxweb/projects/cpl/src/lib/rules/rules.service.ts +++ b/imxweb/projects/cpl/src/lib/rules/rules.service.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -24,26 +24,30 @@ * */ -import { OverlayRef } from '@angular/cdk/overlay'; import { Injectable } from '@angular/core'; import { EuiLoadingService } from '@elemental-ui/core'; -import { ComplianceFeatureConfig, PortalRules, V2ApiClientMethodFactory } from 'imx-api-cpl'; -import { } from 'imx-api-cpl'; -import { CollectionLoadParameters, DataModel, EntityCollectionData, EntitySchema, ExtendedTypedEntityCollection, MethodDefinition, MethodDescriptor } from 'imx-qbm-dbts'; +import { ComplianceFeatureConfig, PortalRules, V2ApiClientMethodFactory } from '@imx-modules/imx-api-cpl'; +import { + CollectionLoadParameters, + DataModel, + EntityCollectionData, + EntitySchema, + ExtendedTypedEntityCollection, + MethodDefinition, + MethodDescriptor, +} from '@imx-modules/imx-qbm-dbts'; import { AppConfigService, DataSourceToolbarExportMethod } from 'qbm'; import { ApiService } from '../api.service'; @Injectable({ - providedIn: 'root' + providedIn: 'root', }) export class RulesService { - private busyIndicator: OverlayRef; - constructor( private apiservice: ApiService, private busyService: EuiLoadingService, - private appConfig: AppConfigService - ) { } + private appConfig: AppConfigService, + ) {} public get ruleSchema(): EntitySchema { return this.apiservice.typedClient.PortalRules.GetSchema(); @@ -53,9 +57,11 @@ export class RulesService { return this.apiservice.client.portal_compliance_config_get(); } - public async getRules(parameter?: CollectionLoadParameters) - : Promise> { - return this.apiservice.typedClient.PortalRules.Get(parameter); + public async getRules( + parameter?: CollectionLoadParameters, + signal?: AbortSignal, + ): Promise> { + return this.apiservice.typedClient.PortalRules.Get(parameter, { signal }); } public exportRules(parameter: CollectionLoadParameters): DataSourceToolbarExportMethod { @@ -64,13 +70,13 @@ export class RulesService { getMethod: (withProperties: string, PageSize?: number) => { let method: MethodDescriptor; if (PageSize) { - method = factory.portal_rules_get({...parameter, withProperties, PageSize, StartIndex: 0}) + method = factory.portal_rules_get({ ...parameter, withProperties, PageSize, StartIndex: 0 }); } else { - method = factory.portal_rules_get({...parameter, withProperties}) + method = factory.portal_rules_get({ ...parameter, withProperties }); } return new MethodDefinition(method); - } - } + }, + }; } public async getDataModel(): Promise { @@ -87,18 +93,12 @@ export class RulesService { } public handleOpenLoader(): void { - if (!this.busyIndicator) { - this.busyIndicator = this.busyService.show(); + if (this.busyService.overlayRefs.length === 0) { + this.busyService.show(); } } public handleCloseLoader(): void { - if (this.busyIndicator) { - setTimeout(() => { - this.busyService.hide(this.busyIndicator); - this.busyIndicator = undefined; - }); - } + this.busyService.hide(); } - } diff --git a/imxweb/projects/cpl/src/public_api.ts b/imxweb/projects/cpl/src/public_api.ts index 932792d38..7d192d16f 100644 --- a/imxweb/projects/cpl/src/public_api.ts +++ b/imxweb/projects/cpl/src/public_api.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -30,7 +30,7 @@ export { CplConfigModule } from './lib/cpl-config.module'; export { ApiService } from './lib/api.service'; -export { RulesModule} from './lib/rules/rules.module'; +export { RulesModule } from './lib/rules/rules.module'; export { RequestRuleViolationDetail } from './lib/request/request-rule-violation-detail'; export { RoleComplianceViolationsModule } from './lib/role-compliance-violations/role-compliance-violations.module'; export { RequestRuleViolation } from './lib/request/request-rule-violation'; diff --git a/imxweb/projects/cpl/src/test.ts b/imxweb/projects/cpl/src/test.ts index f7ac7d548..159c87d7d 100644 --- a/imxweb/projects/cpl/src/test.ts +++ b/imxweb/projects/cpl/src/test.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -26,24 +26,14 @@ // This file is required by karma.conf.js and loads recursively all the .spec and framework files -import 'core-js/es7/reflect'; -import 'zone.js/dist/zone'; -import 'zone.js/dist/zone-testing'; +// Zone must be imported first. Be careful with prettier import organizing +import 'zone.js'; +import 'zone.js/testing'; + import { getTestBed } from '@angular/core/testing'; -import { - BrowserDynamicTestingModule, - platformBrowserDynamicTesting -} from '@angular/platform-browser-dynamic/testing'; +import { BrowserDynamicTestingModule, platformBrowserDynamicTesting } from '@angular/platform-browser-dynamic/testing'; +import 'core-js/es/reflect'; import { TestHelperModule } from 'qbm'; -declare const require: any; - // First, initialize the Angular testing environment. -getTestBed().initTestEnvironment( - [BrowserDynamicTestingModule, TestHelperModule], - platformBrowserDynamicTesting() -); -// Then we find all the tests. -const context = require.context('./', true, /\.spec\.ts$/); -// And load the modules. -context.keys().map(context); +getTestBed().initTestEnvironment([BrowserDynamicTestingModule, TestHelperModule], platformBrowserDynamicTesting()); diff --git a/imxweb/projects/cpl/tsconfig.lib.json b/imxweb/projects/cpl/tsconfig.lib.json index 6bc419f84..9786008a7 100644 --- a/imxweb/projects/cpl/tsconfig.lib.json +++ b/imxweb/projects/cpl/tsconfig.lib.json @@ -7,10 +7,11 @@ "declarationMap": true, "sourceMap": true, "inlineSources": true, - "types": [] + "types": [], + "strictNullChecks": true }, - "exclude": [ - "src/test.ts", - "**/*.spec.ts" - ] + "angularCompilerOptions": { + "strictTemplates": true + }, + "exclude": ["src/test.ts", "**/*.spec.ts"] } diff --git a/imxweb/projects/cpl/tsconfig.lib.prod.json b/imxweb/projects/cpl/tsconfig.lib.prod.json index 61c7592e7..fb40dbbb0 100644 --- a/imxweb/projects/cpl/tsconfig.lib.prod.json +++ b/imxweb/projects/cpl/tsconfig.lib.prod.json @@ -3,8 +3,5 @@ "extends": "./tsconfig.lib.json", "compilerOptions": { "declarationMap": false - }, - "angularCompilerOptions": { - "enableIvy": true } } diff --git a/imxweb/projects/cpl/tsconfig.spec.json b/imxweb/projects/cpl/tsconfig.spec.json index 16da33db0..6bd74e1f7 100644 --- a/imxweb/projects/cpl/tsconfig.spec.json +++ b/imxweb/projects/cpl/tsconfig.spec.json @@ -1,17 +1,10 @@ { "extends": "../../tsconfig.json", "compilerOptions": { + "strictNullChecks": false, "outDir": "../../out-tsc/spec", - "types": [ - "jasmine", - "node" - ] + "types": ["jasmine", "node"] }, - "files": [ - "src/test.ts" - ], - "include": [ - "**/*.spec.ts", - "**/*.d.ts" - ] + "files": ["src/test.ts"], + "include": ["**/*.spec.ts", "**/*.d.ts"] } diff --git a/imxweb/projects/cpl/tslint.json b/imxweb/projects/cpl/tslint.json deleted file mode 100644 index 8bab15f53..000000000 --- a/imxweb/projects/cpl/tslint.json +++ /dev/null @@ -1,17 +0,0 @@ -{ - "extends": "../../tslint.json", - "rules": { - "directive-selector": [ - true, - "attribute", - "imx", - "camelCase" - ], - "component-selector": [ - true, - "element", - "imx", - "kebab-case" - ] - } -} diff --git a/imxweb/projects/custom-app/.eslintrc.json b/imxweb/projects/custom-app/.eslintrc.json new file mode 100644 index 000000000..615eff834 --- /dev/null +++ b/imxweb/projects/custom-app/.eslintrc.json @@ -0,0 +1,35 @@ +{ + "extends": "../../.eslintrc.json", + "ignorePatterns": ["!**/*", "**/*.spec.ts"], + "overrides": [ + { + "files": ["*.ts"], + "parserOptions": { + "project": ["imxweb/projects/custom-app/tsconfig.app.json", "imxweb/projects/custom-app/tsconfig.spec.json"], + "createDefaultProgram": true + }, + "rules": { + "@angular-eslint/directive-selector": [ + "error", + { + "type": "attribute", + "prefix": "imx", + "style": "camelCase" + } + ], + "@angular-eslint/component-selector": [ + "error", + { + "type": "element", + "prefix": "imx", + "style": "kebab-case" + } + ] + } + }, + { + "files": ["*.html"], + "rules": {} + } + ] +} diff --git a/imxweb/projects/custom-app/karma.conf.js b/imxweb/projects/custom-app/karma.conf.js index b454fa9d7..80eeaba08 100644 --- a/imxweb/projects/custom-app/karma.conf.js +++ b/imxweb/projects/custom-app/karma.conf.js @@ -12,10 +12,10 @@ module.exports = function (config) { require('karma-jasmine-html-reporter'), require('karma-coverage-istanbul-reporter'), require('@angular-devkit/build-angular/plugins/karma'), - require('karma-junit-reporter') + require('karma-junit-reporter'), ], client: { - clearContext: false // leave Jasmine Spec Runner output visible in browser + clearContext: false, // leave Jasmine Spec Runner output visible in browser }, coverageIstanbulReporter: { dir: require('path').join(__dirname, 'results'), @@ -26,7 +26,7 @@ module.exports = function (config) { functions: 0, lines: 0, }, - fixWebpackSourcePaths: true + fixWebpackSourcePaths: true, }, junitReporter: { outputDir: require('path').join(__dirname, 'results'), @@ -35,13 +35,14 @@ module.exports = function (config) { port: 9876, captureTimeout: 210000, browserDisconnectTolerance: 3, - browserDisconnectTimeout : 210000, - browserNoActivityTimeout : 210000, + browserDisconnectTimeout: 210000, + browserNoActivityTimeout: 210000, colors: true, logLevel: config.LOG_INFO, autoWatch: true, browsers: ['Chrome'], singleRun: false, - restartOnFileChange: true + failOnEmptyTestSuite: false, + restartOnFileChange: true, }); }; diff --git a/imxweb/projects/custom-app/package.json b/imxweb/projects/custom-app/package.json index 8e65fa6ec..894562488 100644 --- a/imxweb/projects/custom-app/package.json +++ b/imxweb/projects/custom-app/package.json @@ -1,5 +1,5 @@ { "name": "custom-app", - "version": "9.2.1", + "version": "9.3.0", "private": true -} \ No newline at end of file +} diff --git a/imxweb/projects/custom-app/project.json b/imxweb/projects/custom-app/project.json new file mode 100644 index 000000000..e897cee8a --- /dev/null +++ b/imxweb/projects/custom-app/project.json @@ -0,0 +1,197 @@ +{ + "$schema": "../../node_modules/nx/schemas/project-schema.json", + "name": "custom-app", + "implicitDependencies": ["qer"], + "projectType": "application", + "sourceRoot": "projects/custom-app/src", + "prefix": "imx", + "generators": { + "@schematics/angular:component": { + "style": "scss" + } + }, + "targets": { + "build": { + "executor": "@angular-devkit/build-angular:application", + "options": { + "outputPath": { + "base": "dist/custom-app", + "browser": "" + }, + "allowedCommonJsDependencies": [ + "lodash", + "highlight.js", + "file-saver", + "billboard.js", + "moment-timezone", + "core-js/fn/map", + "core-js/fn/set", + "core-js/fn/weak-map", + "core-js/fn/array/from", + "core-js/fn/object/assign", + "core-js/es/array/from", + "core-js/es/object/assign", + "core-js/es/map", + "core-js/es/set", + "core-js/es/weak-map", + "lodash.debounce", + "lodash.clamp", + "moment", + "@elemental-ui/cadence-icon/codepoints" + ], + "index": "projects/custom-app/src/index.html", + "browser": "projects/custom-app/src/main.ts", + "polyfills": ["projects/custom-app/src/polyfills.ts"], + "tsConfig": "projects/custom-app/tsconfig.app.json", + "aot": true, + "assets": [ + "projects/custom-app/src/appconfig.json", + "projects/custom-app/src/assets", + { + "glob": "**/*", + "input": "./html", + "output": "./html" + }, + { + "glob": "**/*", + "input": "./shared/assets/", + "output": "./assets" + }, + { + "glob": "**/*", + "input": "./node_modules/@elemental-ui/core/assets", + "output": "./assets" + } + ], + "styles": ["projects/custom-app/src/styles.scss", "projects/qbm/src/lib/styles/imx-page-title.scss"], + "stylePreprocessorOptions": { + "includePaths": [ + "./shared/assets", + "./shared/scss", + "./node_modules", + "./node_modules/@elemental-ui/cadence-icon", + "./node_modules/@elemental-ui/core" + ] + } + }, + "configurations": { + "production": { + "fileReplacements": [ + { + "replace": "projects/custom-app/src/environments/environment.ts", + "with": "projects/custom-app/src/environments/environment.prod.ts" + } + ], + "optimization": true, + "outputHashing": "all", + "sourceMap": false, + "namedChunks": true, + "extractLicenses": true, + "budgets": [ + { + "type": "initial", + "maximumWarning": "20mb", + "maximumError": "40mb" + }, + { + "type": "anyComponentStyle", + "maximumWarning": "6kb" + } + ] + }, + "development": { + "optimization": false, + "extractLicenses": false, + "sourceMap": true, + "namedChunks": true + }, + "remote-dev": { + "fileReplacements": [ + { + "replace": "projects/custom-app/src/environments/environment.ts", + "with": "../imxweb_envs/custom-app/environments/environment.remote-dev.ts" + } + ], + "optimization": false, + "extractLicenses": false, + "sourceMap": true, + "namedChunks": true + }, + "remote-qs": { + "fileReplacements": [ + { + "replace": "projects/custom-app/src/environments/environment.ts", + "with": "../imxweb_envs/custom-app/environments/environment.remote-qs.ts" + } + ], + "buildOptimizer": false, + "optimization": false, + "vendorChunk": true, + "extractLicenses": false, + "sourceMap": true, + "namedChunks": true + }, + "es5": { + "tsConfig": "./projects/custom-app/tsconfig-es5.app.json" + } + }, + "outputs": ["{options.outputPath}"] + }, + "serve": { + "executor": "@angular-devkit/build-angular:dev-server", + "options": { + "browserTarget": "custom-app:build" + }, + "configurations": { + "production": { + "browserTarget": "custom-app:build:production" + }, + "development": { + "browserTarget": "custom-app:build:development" + }, + "remote-dev": { + "browserTarget": "custom-app:build:remote-dev" + }, + "remote-qs": { + "browserTarget": "custom-app:build:remote-qs" + }, + "es5": { + "browserTarget": "custom-app:build:es5" + } + } + }, + "extract-i18n": { + "executor": "@angular-devkit/build-angular:extract-i18n", + "options": { + "browserTarget": "custom-app:build" + } + }, + "test": { + "executor": "@angular-devkit/build-angular:karma", + "options": { + "main": "projects/custom-app/src/test.ts", + "polyfills": "projects/custom-app/src/polyfills.ts", + "tsConfig": "projects/custom-app/tsconfig.spec.json", + "karmaConfig": "projects/custom-app/karma.conf.js", + "assets": ["projects/custom-app/src/appconfig.json", "projects/custom-app/src/assets"], + "styles": ["projects/custom-app/src/styles.scss"], + "stylePreprocessorOptions": { + "includePaths": [ + "./shared/assets", + "./shared/scss", + "./node_modules", + "./node_modules/@elemental-ui/cadence-icon", + "./node_modules/@elemental-ui/core" + ] + } + } + }, + "lint": { + "executor": "@angular-devkit/build-angular:tslint", + "options": { + "tsConfig": ["projects/custom-app/tsconfig.app.json", "projects/custom-app/tsconfig.spec.json"], + "exclude": ["**/node_modules/**"] + } + } + } +} diff --git a/imxweb/projects/custom-app/readme.md b/imxweb/projects/custom-app/readme.md index d10e72d05..044283a17 100644 --- a/imxweb/projects/custom-app/readme.md +++ b/imxweb/projects/custom-app/readme.md @@ -16,7 +16,7 @@ The [`app.service.ts`](./src/app/app.service.ts) service is responsible for init The [`appconfig.json`](./src/appconfig.json) file sets two default routes: -``` json +```json "routeConfig": { "login": "", "start": "start" diff --git a/imxweb/projects/custom-app/src/app/app-routing.module.ts b/imxweb/projects/custom-app/src/app/app-routing.module.ts index 31f36d7cd..ecabaed49 100644 --- a/imxweb/projects/custom-app/src/app/app-routing.module.ts +++ b/imxweb/projects/custom-app/src/app/app-routing.module.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -25,7 +25,7 @@ */ import { InjectionToken, NgModule } from '@angular/core'; -import { Routes, RouterModule, ActivatedRouteSnapshot } from '@angular/router'; +import { ActivatedRouteSnapshot, RouterModule, Routes } from '@angular/router'; import { AuthenticationGuardService, LoginComponent, RouteGuardService } from 'qbm'; import { StartComponent } from './start.component'; @@ -36,19 +36,19 @@ const routes: Routes = [ path: '', component: LoginComponent, canActivate: [AuthenticationGuardService], - resolve: [RouteGuardService] + resolve: [RouteGuardService], }, { path: 'start', component: StartComponent, canActivate: [RouteGuardService], - resolve: [RouteGuardService] + resolve: [RouteGuardService], }, - { path: '**', redirectTo: 'start' } + { path: '**', redirectTo: 'start' }, ]; @NgModule({ - imports: [RouterModule.forRoot(routes, { useHash: true, relativeLinkResolution: 'legacy' })], + imports: [RouterModule.forRoot(routes, { useHash: true })], exports: [RouterModule], providers: [ { @@ -58,9 +58,8 @@ const routes: Routes = [ if (externalUrl && externalUrl.toLocaleLowerCase() !== 'undefined') { window.open(externalUrl, '_self'); } - } + }, }, ], }) - -export class AppRoutingModule { } +export class AppRoutingModule {} diff --git a/imxweb/projects/custom-app/src/app/app.component.html b/imxweb/projects/custom-app/src/app/app.component.html index ae5e1f2c2..8579568da 100644 --- a/imxweb/projects/custom-app/src/app/app.component.html +++ b/imxweb/projects/custom-app/src/app/app.component.html @@ -1,10 +1,9 @@
    - - - - -
    - - -
    -
    \ No newline at end of file + + + +
    + + +
    +
    diff --git a/imxweb/projects/custom-app/src/app/app.component.scss b/imxweb/projects/custom-app/src/app/app.component.scss index c2f8a644d..71a013c67 100644 --- a/imxweb/projects/custom-app/src/app/app.component.scss +++ b/imxweb/projects/custom-app/src/app/app.component.scss @@ -6,7 +6,7 @@ } .pageContent { - margin: 20px 30px; + margin: 24px; display: flex; flex-direction: column; overflow: hidden; diff --git a/imxweb/projects/custom-app/src/app/app.component.ts b/imxweb/projects/custom-app/src/app/app.component.ts index 879431916..23f3506ba 100644 --- a/imxweb/projects/custom-app/src/app/app.component.ts +++ b/imxweb/projects/custom-app/src/app/app.component.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -25,7 +25,7 @@ */ import { Component, OnDestroy, OnInit } from '@angular/core'; -import { NavigationCancel, NavigationEnd, NavigationError, NavigationStart, Router, RouterEvent } from '@angular/router'; +import { Event, NavigationCancel, NavigationEnd, NavigationError, NavigationStart, Router } from '@angular/router'; import { Subscription } from 'rxjs'; import { AuthenticationService, ISessionState, SplashService } from 'qbm'; @@ -33,7 +33,7 @@ import { AuthenticationService, ISessionState, SplashService } from 'qbm'; @Component({ selector: 'imx-root', styleUrls: ['./app.component.scss'], - templateUrl: './app.component.html' + templateUrl: './app.component.html', }) export class AppComponent implements OnInit, OnDestroy { public isLoggedIn = false; @@ -49,23 +49,22 @@ export class AppComponent implements OnInit, OnDestroy { ) { this.subscriptions.push( this.authentication.onSessionResponse.subscribe(async (sessionState: ISessionState) => { - if (sessionState.hasErrorState) { // Needs to close here when there is an error on sessionState this.splash.close(); - }else { + } else { if (sessionState.IsLoggedOut) { this.showPageContent = false; } } - this.isLoggedIn = sessionState.IsLoggedIn; + this.isLoggedIn = sessionState.IsLoggedIn ?? false; if (this.isLoggedIn) { // Close the splash screen that opened in app service initialisation // Needs to close here when session is already logged in. this.splash.close(); } - }) + }), ); this.setupRouter(); @@ -79,11 +78,11 @@ export class AppComponent implements OnInit, OnDestroy { } public ngOnDestroy(): void { - this.subscriptions.forEach(subscription => subscription.unsubscribe()); + this.subscriptions.forEach((subscription) => subscription.unsubscribe()); } private setupRouter(): void { - this.router.events.subscribe(((event: RouterEvent) => { + this.router.events.subscribe((event: Event) => { if (event instanceof NavigationStart) { this.hideUserMessage = true; if (this.isLoggedIn && event.url === '/') { @@ -104,6 +103,6 @@ export class AppComponent implements OnInit, OnDestroy { if (event instanceof NavigationError) { this.hideUserMessage = false; } - })); + }); } } diff --git a/imxweb/projects/custom-app/src/app/app.module.ts b/imxweb/projects/custom-app/src/app/app.module.ts index 89d693804..ef21eaf61 100644 --- a/imxweb/projects/custom-app/src/app/app.module.ts +++ b/imxweb/projects/custom-app/src/app/app.module.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -24,96 +24,81 @@ * */ -import { HttpClientModule } from '@angular/common/http'; -import { BrowserModule } from '@angular/platform-browser'; -import { BrowserAnimationsModule } from '@angular/platform-browser/animations'; -import { NgModule, APP_INITIALIZER, ErrorHandler } from '@angular/core'; -import { MatProgressSpinnerModule } from '@angular/material/progress-spinner'; -import { MatCardModule } from '@angular/material/card'; +import { provideHttpClient, withInterceptorsFromDi } from '@angular/common/http'; +import { APP_INITIALIZER, ErrorHandler, NgModule } from '@angular/core'; import { MatButtonModule } from '@angular/material/button'; +import { MatCardModule } from '@angular/material/card'; import { MatIconModule } from '@angular/material/icon'; -import { LoggerModule, NgxLoggerLevel } from 'ngx-logger'; +import { MatProgressSpinnerModule } from '@angular/material/progress-spinner'; +import { BrowserModule } from '@angular/platform-browser'; +import { BrowserAnimationsModule } from '@angular/platform-browser/animations'; import { EuiCoreModule, EuiMaterialModule } from '@elemental-ui/core'; -import { TranslateModule, TranslateLoader, MissingTranslationHandler, TranslateService } from '@ngx-translate/core'; +import { MissingTranslationHandler, TranslateLoader, TranslateModule, TranslateService } from '@ngx-translate/core'; +import { LoggerModule, NgxLoggerLevel } from 'ngx-logger'; +import { MatPaginatorIntl } from '@angular/material/paginator'; import { - ImxTranslateLoader, + AuthenticationModule, + CustomThemeModule, + GlobalErrorHandler, ImxMissingTranslationHandler, + ImxTranslateLoader, + LdsReplacePipe, MastHeadModule, - UserMessageModule, - GlobalErrorHandler, Paginator, - LdsReplacePipe, QbmModule, - AuthenticationModule, - MenuModule, - CustomThemeModule + UserMessageModule, } from 'qbm'; +import appConfigJson from '../appconfig.json'; +import { environment } from '../environments/environment'; import { AppRoutingModule } from './app-routing.module'; import { AppComponent } from './app.component'; import { AppService } from './app.service'; -import { MatPaginatorIntl } from '@angular/material/paginator'; -import { environment } from '../environments/environment'; -import appConfigJson from '../appconfig.json'; import { StartComponent } from './start.component'; - -@NgModule({ - declarations: [ - AppComponent, - StartComponent - ], - imports: [ - AppRoutingModule, - AuthenticationModule, - BrowserAnimationsModule, - BrowserModule, - EuiCoreModule, - EuiMaterialModule, - MatButtonModule, - MatCardModule, - MatIconModule, - MatProgressSpinnerModule, - HttpClientModule, - LoggerModule.forRoot({ level: NgxLoggerLevel.DEBUG, serverLogLevel: NgxLoggerLevel.OFF }), - MastHeadModule, - MenuModule, - QbmModule, - CustomThemeModule, - TranslateModule.forRoot({ - loader: { - provide: TranslateLoader, - useClass: ImxTranslateLoader - }, - missingTranslationHandler: { - provide: MissingTranslationHandler, - useClass: ImxMissingTranslationHandler - } - }), - UserMessageModule - ], - providers: [ - { provide: 'environment', useValue: environment }, - { provide: 'appConfigJson', useValue: appConfigJson }, - { - provide: APP_INITIALIZER, - useFactory: AppService.init, - deps: [AppService], - multi: true - }, - { - provide: ErrorHandler, - useClass: GlobalErrorHandler - }, - { - provide: MatPaginatorIntl, - useFactory: Paginator.Create, - deps: [ - TranslateService, - LdsReplacePipe - ] - } - ], - bootstrap: [AppComponent] -}) -export class AppModule { } +@NgModule({ declarations: [AppComponent, StartComponent], + bootstrap: [AppComponent], imports: [AppRoutingModule, + AuthenticationModule, + BrowserAnimationsModule, + BrowserModule, + EuiCoreModule, + EuiMaterialModule, + MatButtonModule, + MatCardModule, + MatIconModule, + MatProgressSpinnerModule, + LoggerModule.forRoot({ level: NgxLoggerLevel.DEBUG, serverLogLevel: NgxLoggerLevel.OFF }), + MastHeadModule, + QbmModule, + CustomThemeModule, + TranslateModule.forRoot({ + loader: { + provide: TranslateLoader, + useClass: ImxTranslateLoader, + }, + missingTranslationHandler: { + provide: MissingTranslationHandler, + useClass: ImxMissingTranslationHandler, + }, + }), + UserMessageModule], providers: [ + { provide: 'environment', useValue: environment }, + { provide: 'appConfigJson', useValue: appConfigJson }, + { + provide: APP_INITIALIZER, + useFactory: AppService.init, + deps: [AppService], + multi: true, + }, + { + provide: ErrorHandler, + useClass: GlobalErrorHandler, + }, + { + provide: MatPaginatorIntl, + useFactory: Paginator.Create, + deps: [TranslateService, LdsReplacePipe], + }, + provideHttpClient(withInterceptorsFromDi()), + ] }) +export class AppModule {} diff --git a/imxweb/projects/custom-app/src/app/app.service.ts b/imxweb/projects/custom-app/src/app/app.service.ts index 3354c9d34..9f76ba4f0 100644 --- a/imxweb/projects/custom-app/src/app/app.service.ts +++ b/imxweb/projects/custom-app/src/app/app.service.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -28,21 +28,21 @@ import { Injectable } from '@angular/core'; import { Title } from '@angular/platform-browser'; import { TranslateService } from '@ngx-translate/core'; -import { Globals } from 'imx-qbm-dbts'; +import { TypedClient } from '@imx-modules/imx-api-qbm'; +import { Globals } from '@imx-modules/imx-qbm-dbts'; import { AppConfigService, AuthenticationService, - imx_SessionService, + ISessionState, ImxTranslationProviderService, SplashService, SystemInfoService, - ISessionState + imx_SessionService, } from 'qbm'; import { environment } from '../environments/environment'; -import { TypedClient } from 'imx-api-qbm'; @Injectable({ - providedIn: 'root' + providedIn: 'root', }) export class AppService { constructor( @@ -54,19 +54,22 @@ export class AppService { private readonly title: Title, private readonly authentication: AuthenticationService, private readonly splash: SplashService, - ) { } + ) {} public async init(): Promise { this.showSplash(); await this.config.init(environment.clientUrl); - - this.translateService.addLangs(this.config.Config.Translation.Langs); - const browserCulture = this.translateService.getBrowserCultureLang(); + if (this.config.Config.Translation?.Langs) { + this.translateService.addLangs(this.config.Config.Translation.Langs); + } + const browserCulture = this.translateService.getBrowserCultureLang() as string; this.translateService.setDefaultLang(browserCulture); await this.translateService.use(browserCulture).toPromise(); // If the session defines another culture, update the translation provider - this.authentication.onSessionResponse.subscribe((sessionState: ISessionState) => this.translationProvider.init(sessionState?.culture, sessionState?.cultureFormat)); + this.authentication.onSessionResponse.subscribe((sessionState: ISessionState) => + this.translationProvider.init(sessionState?.culture, sessionState?.cultureFormat), + ); this.translateService.onLangChange.subscribe(() => { this.setTitle(); diff --git a/imxweb/projects/custom-app/src/app/start.component.html b/imxweb/projects/custom-app/src/app/start.component.html index c8aa9c84e..b972f2480 100644 --- a/imxweb/projects/custom-app/src/app/start.component.html +++ b/imxweb/projects/custom-app/src/app/start.component.html @@ -1,8 +1,7 @@ -
    Hello world!
    - + @@ -14,5 +13,4 @@
    - - \ No newline at end of file + diff --git a/imxweb/projects/custom-app/src/app/start.component.ts b/imxweb/projects/custom-app/src/app/start.component.ts index 1349f8d42..86a717218 100644 --- a/imxweb/projects/custom-app/src/app/start.component.ts +++ b/imxweb/projects/custom-app/src/app/start.component.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -24,23 +24,21 @@ * */ -import { Component } from "@angular/core"; -import { PortalPersonAll } from "imx-api-qer"; -import { QerApiService } from "qer"; +import { Component } from '@angular/core'; +import { PortalPersonAll } from '@imx-modules/imx-api-qer'; +import { QerApiService } from 'qer'; @Component({ - templateUrl: './start.component.html' + templateUrl: './start.component.html', }) export class StartComponent { - - constructor(private qerApi: QerApiService) { } + constructor(private qerApi: QerApiService) {} persons: PortalPersonAll[] = []; totalCount = 0; busy = false; async loadPersonData() { - try { this.busy = true; @@ -56,5 +54,4 @@ export class StartComponent { this.busy = false; } } - -} \ No newline at end of file +} diff --git a/imxweb/projects/custom-app/src/environments/environment.prod.ts b/imxweb/projects/custom-app/src/environments/environment.prod.ts index 413d69e7b..59f1e80ca 100644 --- a/imxweb/projects/custom-app/src/environments/environment.prod.ts +++ b/imxweb/projects/custom-app/src/environments/environment.prod.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -28,5 +28,5 @@ export const environment = { production: true, clientUrl: '', appName: 'custom-app', - appVersion: '1.0.0' + appVersion: '1.0.0', }; diff --git a/imxweb/projects/custom-app/src/environments/environment.ts b/imxweb/projects/custom-app/src/environments/environment.ts index 916ec99d4..0582c177b 100644 --- a/imxweb/projects/custom-app/src/environments/environment.ts +++ b/imxweb/projects/custom-app/src/environments/environment.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -32,7 +32,7 @@ export const environment = { production: false, clientUrl: 'http://localhost:8182', appName: 'custom-app', - appVersion: '1.0.0' + appVersion: '1.0.0', }; /* @@ -42,4 +42,4 @@ export const environment = { * This import should be commented out in production mode because it will have a negative impact * on performance if an error is thrown. */ -// import 'zone.js/dist/zone-error'; // Included with Angular CLI. +// import 'zone.js'; // Included with Angular CLI. diff --git a/imxweb/projects/custom-app/src/index.html b/imxweb/projects/custom-app/src/index.html index 4b785ba4e..f08db67fd 100644 --- a/imxweb/projects/custom-app/src/index.html +++ b/imxweb/projects/custom-app/src/index.html @@ -1,15 +1,13 @@ + + + + + + - - - - - - - - - - - + + + diff --git a/imxweb/projects/custom-app/src/main.ts b/imxweb/projects/custom-app/src/main.ts index 5b7a3816d..8cb3e4f09 100644 --- a/imxweb/projects/custom-app/src/main.ts +++ b/imxweb/projects/custom-app/src/main.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -34,5 +34,6 @@ if (environment.production) { enableProdMode(); } -platformBrowserDynamic().bootstrapModule(AppModule) - .catch(err => console.error(err)); +platformBrowserDynamic() + .bootstrapModule(AppModule) + .catch((err) => console.error(err)); diff --git a/imxweb/projects/custom-app/src/polyfills.ts b/imxweb/projects/custom-app/src/polyfills.ts index 31ad3d496..9c1e09bff 100644 --- a/imxweb/projects/custom-app/src/polyfills.ts +++ b/imxweb/projects/custom-app/src/polyfills.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -41,9 +41,8 @@ */ /*************************************************************************************************** -* BROWSER POLYFILLS -*/ - + * BROWSER POLYFILLS + */ /** IE10 and IE11 requires the following for NgClass support on SVG elements */ // import 'classlist.js'; // Run `npm install --save classlist.js`. @@ -51,13 +50,12 @@ /** IE10 and IE11 requires the following for the Reflect API. */ // import 'core-js/es6/reflect'; - /** Evergreen browsers require these. */ // Used for reflect-metadata in JIT. If you use AOT (and only Angular decorators), you can remove. -import 'core-js/es7/reflect'; +import 'core-js/es/reflect'; // Used for support array.includes -import 'core-js/es7/array'; +import 'core-js/es/array'; /** * Required to support Web Animations `@angular/platform-browser/animations`. @@ -65,17 +63,13 @@ import 'core-js/es7/array'; */ import 'web-animations-js'; - - /*************************************************************************************************** * Zone JS is required by default for Angular itself. */ -import 'zone.js/dist/zone'; // Included with Angular CLI. - - +import 'zone.js'; // Included with Angular CLI. /*************************************************************************************************** * APPLICATION IMPORTS */ -import 'whatwg-fetch'; import 'url-polyfill'; +import 'whatwg-fetch'; diff --git a/imxweb/projects/custom-app/src/styles.scss b/imxweb/projects/custom-app/src/styles.scss index b2784f9a9..c71ce0b5d 100644 --- a/imxweb/projects/custom-app/src/styles.scss +++ b/imxweb/projects/custom-app/src/styles.scss @@ -1,13 +1,8 @@ /* You can add global styles to this file, and also import other style files */ @use '@angular/material' as mat; - -$material_icons_font_path: "~node_modules/@elemental-ui/core/assets/MaterialIcons"; -$cadence_font_path: "~node_modules/@elemental-ui/core/assets/Cadence"; -$source_sans_pro_font_path: "~node_modules/@elemental-ui/core/assets/Source_Sans_Pro"; - @import '@elemental-ui/core/src/styles/core.scss'; -.imx-dialog-panel-class > .mat-dialog-container { - background-color: mat.get-color-from-palette($asher-gray-palette, 200); +.imx-dialog-panel-class > .mat-mdc-dialog-container { + background-color: mat.m2-get-color-from-palette($asher-gray-palette, 200); } diff --git a/imxweb/projects/o3t/src/test.ts b/imxweb/projects/custom-app/src/test.ts similarity index 66% rename from imxweb/projects/o3t/src/test.ts rename to imxweb/projects/custom-app/src/test.ts index f7ac7d548..159c87d7d 100644 --- a/imxweb/projects/o3t/src/test.ts +++ b/imxweb/projects/custom-app/src/test.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -26,24 +26,14 @@ // This file is required by karma.conf.js and loads recursively all the .spec and framework files -import 'core-js/es7/reflect'; -import 'zone.js/dist/zone'; -import 'zone.js/dist/zone-testing'; +// Zone must be imported first. Be careful with prettier import organizing +import 'zone.js'; +import 'zone.js/testing'; + import { getTestBed } from '@angular/core/testing'; -import { - BrowserDynamicTestingModule, - platformBrowserDynamicTesting -} from '@angular/platform-browser-dynamic/testing'; +import { BrowserDynamicTestingModule, platformBrowserDynamicTesting } from '@angular/platform-browser-dynamic/testing'; +import 'core-js/es/reflect'; import { TestHelperModule } from 'qbm'; -declare const require: any; - // First, initialize the Angular testing environment. -getTestBed().initTestEnvironment( - [BrowserDynamicTestingModule, TestHelperModule], - platformBrowserDynamicTesting() -); -// Then we find all the tests. -const context = require.context('./', true, /\.spec\.ts$/); -// And load the modules. -context.keys().map(context); +getTestBed().initTestEnvironment([BrowserDynamicTestingModule, TestHelperModule], platformBrowserDynamicTesting()); diff --git a/imxweb/projects/custom-app/tsconfig-es5.app.json b/imxweb/projects/custom-app/tsconfig-es5.app.json index e1d0d6abd..036b8797e 100644 --- a/imxweb/projects/custom-app/tsconfig-es5.app.json +++ b/imxweb/projects/custom-app/tsconfig-es5.app.json @@ -1,6 +1,6 @@ { - "extends": "./tsconfig.app.json", - "compilerOptions": { - "target": "es2020" + "extends": "./tsconfig.app.json", + "compilerOptions": { + "target": "es2020" } -} \ No newline at end of file +} diff --git a/imxweb/projects/custom-app/tsconfig.app.json b/imxweb/projects/custom-app/tsconfig.app.json index d69a5c154..136843ce2 100644 --- a/imxweb/projects/custom-app/tsconfig.app.json +++ b/imxweb/projects/custom-app/tsconfig.app.json @@ -1,14 +1,13 @@ { "extends": "../../tsconfig.json", "compilerOptions": { + "strictNullChecks": true, "outDir": "../../out-tsc/app", "types": [] }, - "files": [ - "src/main.ts", - "src/polyfills.ts" - ], - "include": [ - "projects/custom-app/src/**/*.d.ts" - ] + "angularCompilerOptions": { + "strictTemplates": true + }, + "files": ["src/main.ts", "src/polyfills.ts"], + "include": ["projects/custom-app/src/**/*.d.ts"] } diff --git a/imxweb/projects/custom-app/tsconfig.spec.json b/imxweb/projects/custom-app/tsconfig.spec.json index a809b0a66..143838d98 100644 --- a/imxweb/projects/custom-app/tsconfig.spec.json +++ b/imxweb/projects/custom-app/tsconfig.spec.json @@ -2,17 +2,8 @@ "extends": "../../tsconfig.json", "compilerOptions": { "outDir": "../../out-tsc/spec", - "types": [ - "jasmine", - "node" - ] + "types": ["jasmine", "node"] }, - "files": [ - "src/test.ts", - "src/polyfills.ts" - ], - "include": [ - "**/*.spec.ts", - "**/*.d.ts" - ] + "files": ["src/test.ts", "src/polyfills.ts"], + "include": ["**/*.spec.ts", "**/*.d.ts"] } diff --git a/imxweb/projects/custom-app/tslint.json b/imxweb/projects/custom-app/tslint.json deleted file mode 100644 index 8bab15f53..000000000 --- a/imxweb/projects/custom-app/tslint.json +++ /dev/null @@ -1,17 +0,0 @@ -{ - "extends": "../../tslint.json", - "rules": { - "directive-selector": [ - true, - "attribute", - "imx", - "camelCase" - ], - "component-selector": [ - true, - "element", - "imx", - "kebab-case" - ] - } -} diff --git a/imxweb/projects/dpr/.compodocrc.json b/imxweb/projects/dpr/.compodocrc.json index f76fe1406..0ea099834 100644 --- a/imxweb/projects/dpr/.compodocrc.json +++ b/imxweb/projects/dpr/.compodocrc.json @@ -1,6 +1,6 @@ { "name": "IMX Web - DPR Library", - "output": "../../documentation/v92/dpr", + "output": "../../documentation/v93/dpr", "theme": "material", "assetsFolder": "../../compodoc/assets", "customLogo": "../../compodoc/assets/images/oneidentity-logo.png", diff --git a/imxweb/projects/dpr/.eslintrc.json b/imxweb/projects/dpr/.eslintrc.json new file mode 100644 index 000000000..b0e65b644 --- /dev/null +++ b/imxweb/projects/dpr/.eslintrc.json @@ -0,0 +1,35 @@ +{ + "extends": "../../.eslintrc.json", + "ignorePatterns": ["!**/*", "**/*.spec.ts"], + "overrides": [ + { + "files": ["*.ts"], + "parserOptions": { + "project": ["imxweb/projects/dpr/tsconfig.lib.json", "imxweb/projects/dpr/tsconfig.spec.json"], + "createDefaultProgram": true + }, + "rules": { + "@angular-eslint/directive-selector": [ + "error", + { + "type": "attribute", + "prefix": "imx", + "style": "camelCase" + } + ], + "@angular-eslint/component-selector": [ + "error", + { + "type": "element", + "prefix": "imx", + "style": "kebab-case" + } + ] + } + }, + { + "files": ["*.html"], + "rules": {} + } + ] +} diff --git a/imxweb/projects/dpr/karma.conf.js b/imxweb/projects/dpr/karma.conf.js index d7a9db062..3e53a3ac8 100644 --- a/imxweb/projects/dpr/karma.conf.js +++ b/imxweb/projects/dpr/karma.conf.js @@ -15,7 +15,7 @@ module.exports = function (config) { require('karma-junit-reporter'), ], client: { - clearContext: false // leave Jasmine Spec Runner output visible in browser + clearContext: false, // leave Jasmine Spec Runner output visible in browser }, coverageIstanbulReporter: { dir: require('path').join(__dirname, 'results'), @@ -23,14 +23,14 @@ module.exports = function (config) { fixWebpackSourcePaths: true, 'report-config': { html: { - subdir: 'coverage-html' + subdir: 'coverage-html', }, }, thresholds: { statements: 0, branches: 0, functions: 0, - lines: 0 + lines: 0, }, }, junitReporter: { @@ -40,13 +40,14 @@ module.exports = function (config) { port: 9876, captureTimeout: 210000, browserDisconnectTolerance: 3, - browserDisconnectTimeout : 210000, - browserNoActivityTimeout : 210000, + browserDisconnectTimeout: 210000, + browserNoActivityTimeout: 210000, colors: true, logLevel: config.LOG_INFO, autoWatch: true, browsers: ['Chrome'], singleRun: false, - restartOnFileChange: true + failOnEmptyTestSuite: false, + restartOnFileChange: true, }); }; diff --git a/imxweb/projects/dpr/ng-package.dynamic.json b/imxweb/projects/dpr/ng-package.dynamic.json index be54fd15a..a9cc85ea0 100644 --- a/imxweb/projects/dpr/ng-package.dynamic.json +++ b/imxweb/projects/dpr/ng-package.dynamic.json @@ -16,12 +16,11 @@ "@elemental-ui/core", "@ngx-translate/core", "@ngx-translate/http-loader", - "applicationinsights-js", "billboard.js" ], "dest": "../../html/dpr", "lib": { "entryFile": "src/public_api.ts", - "styleIncludePaths": ["../../shared/assets"] + "styleIncludePaths": ["../../shared/scss"] } } diff --git a/imxweb/projects/dpr/ng-package.json b/imxweb/projects/dpr/ng-package.json index 06cadfbe8..ba9a58230 100644 --- a/imxweb/projects/dpr/ng-package.json +++ b/imxweb/projects/dpr/ng-package.json @@ -3,6 +3,6 @@ "dest": "../../dist/dpr", "lib": { "entryFile": "src/public_api.ts", - "styleIncludePaths": ["../../shared/assets"] + "styleIncludePaths": ["../../shared/scss"] } } diff --git a/imxweb/projects/dpr/package.json b/imxweb/projects/dpr/package.json index e33682b8d..6c17aaa10 100644 --- a/imxweb/projects/dpr/package.json +++ b/imxweb/projects/dpr/package.json @@ -1,6 +1,6 @@ { "name": "dpr", - "version": "9.2.1", + "version": "9.3.0", "private": true, "bundledDependencies": [ "imx-api" diff --git a/imxweb/projects/dpr/project.json b/imxweb/projects/dpr/project.json new file mode 100644 index 000000000..248022787 --- /dev/null +++ b/imxweb/projects/dpr/project.json @@ -0,0 +1,64 @@ +{ + "$schema": "../../node_modules/nx/schemas/project-schema.json", + "name": "dpr", + "sourceRoot": "projects/dpr/src", + "implicitDependencies": ["qbm"], + "projectType": "library", + "prefix": "imx", + "generators": { + "@schematics/angular:component": { + "style": "scss" + } + }, + "targets": { + "build": { + "executor": "@angular-devkit/build-angular:ng-packagr", + "options": { + "tsConfig": "projects/dpr/tsconfig.lib.json", + "project": "projects/dpr/ng-package.json" + }, + "configurations": { + "production": { + "tsConfig": "projects/dpr/tsconfig.lib.prod.json" + }, + "development": { + "tsConfig": "projects/dpr/tsconfig.lib.json" + }, + "dynamic": { + "project": "projects/dpr/ng-package.dynamic.json" + }, + "remote-dev": { + "tsConfig": "projects/dpr/tsconfig.lib.json" + }, + "remote-qs": { + "tsConfig": "projects/dpr/tsconfig.lib.json" + } + }, + "outputs": ["{workspaceRoot}/dist/dpr"] + }, + "test": { + "executor": "@angular-devkit/build-angular:karma", + "options": { + "main": "projects/dpr/src/test.ts", + "tsConfig": "projects/dpr/tsconfig.spec.json", + "karmaConfig": "projects/dpr/karma.conf.js", + "stylePreprocessorOptions": { + "includePaths": [ + "./shared/assets", + "./shared/scss", + "./node_modules", + "./node_modules/@elemental-ui/cadence-icon", + "./node_modules/@elemental-ui/core" + ] + } + } + }, + "lint": { + "executor": "@angular-devkit/build-angular:tslint", + "options": { + "tsConfig": ["projects/dpr/tsconfig.lib.json", "projects/dpr/tsconfig.spec.json"], + "exclude": ["**/node_modules/**", "**/*.spec.ts", "**/*.json"] + } + } + } +} diff --git a/imxweb/projects/dpr/src/lib/api.service.ts b/imxweb/projects/dpr/src/lib/api.service.ts index 2395b0415..855d094da 100644 --- a/imxweb/projects/dpr/src/lib/api.service.ts +++ b/imxweb/projects/dpr/src/lib/api.service.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -26,12 +26,12 @@ import { Injectable } from '@angular/core'; -import { V2Client, TypedClient } from 'imx-api-dpr'; -import { ApiClient } from 'imx-qbm-dbts'; +import { V2Client, TypedClient } from '@imx-modules/imx-api-dpr'; +import { ApiClient } from '@imx-modules/imx-qbm-dbts'; import { AppConfigService, ClassloggerService, ImxTranslationProviderService } from 'qbm'; @Injectable({ - providedIn: 'root' + providedIn: 'root', }) export class ApiService { private tc: TypedClient; @@ -51,7 +51,8 @@ export class ApiService { constructor( private readonly config: AppConfigService, private readonly logger: ClassloggerService, - private readonly translationProvider: ImxTranslationProviderService) { + private readonly translationProvider: ImxTranslationProviderService, + ) { try { this.logger.debug(this, 'Initializing DPR API service'); diff --git a/imxweb/projects/dpr/src/lib/outstanding/dependencies.component.html b/imxweb/projects/dpr/src/lib/outstanding/dependencies.component.html index ff1e978e1..15cfe2c60 100644 --- a/imxweb/projects/dpr/src/lib/outstanding/dependencies.component.html +++ b/imxweb/projects/dpr/src/lib/outstanding/dependencies.component.html @@ -1,13 +1,13 @@ -
    - +
    + #LDS#The following objects must also be added to the target system, as they depend on the objects to be added. - + #LDS#The following objects must also be deleted, as they depend on the objects to be deleted. - + {{ u.Display }} - {{ u.ObjectType }} @@ -15,7 +15,7 @@
    -
    diff --git a/imxweb/projects/dpr/src/lib/outstanding/dependencies.component.scss b/imxweb/projects/dpr/src/lib/outstanding/dependencies.component.scss index a81c04c69..b37f4f201 100644 --- a/imxweb/projects/dpr/src/lib/outstanding/dependencies.component.scss +++ b/imxweb/projects/dpr/src/lib/outstanding/dependencies.component.scss @@ -1,15 +1,8 @@ -.helper-alert -{ - display: block; -} - -.helper-alert, -.helper-list +.sidesheet-margin { margin: 1em; } -.object-type -{ +.object-type { font-style: italic; -} \ No newline at end of file +} diff --git a/imxweb/projects/dpr/src/lib/outstanding/dependencies.component.ts b/imxweb/projects/dpr/src/lib/outstanding/dependencies.component.ts index 82ee95337..2e3af0914 100644 --- a/imxweb/projects/dpr/src/lib/outstanding/dependencies.component.ts +++ b/imxweb/projects/dpr/src/lib/outstanding/dependencies.component.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -26,22 +26,21 @@ import { Component, Inject } from '@angular/core'; import { EuiSidesheetRef, EUI_SIDESHEET_DATA } from '@elemental-ui/core'; -import { DependencyToConfirm, OutstandingAction } from 'imx-api-dpr'; +import { DependencyToConfirm, OutstandingAction } from '@imx-modules/imx-api-dpr'; @Component({ templateUrl: './dependencies.component.html', - styleUrls: ['./dependencies.component.scss'] + styleUrls: ['./dependencies.component.scss'], }) export class DependenciesComponent { - constructor( - @Inject(EUI_SIDESHEET_DATA) public data: { - dependencies: DependencyToConfirm[], - action: OutstandingAction + @Inject(EUI_SIDESHEET_DATA) + public data: { + dependencies: DependencyToConfirm[]; + action: OutstandingAction; }, - private sidesheetRef: EuiSidesheetRef - ) { - } + private sidesheetRef: EuiSidesheetRef, + ) {} public async save(): Promise { this.sidesheetRef.close(true); diff --git a/imxweb/projects/dpr/src/lib/outstanding/outstanding-object-entity.ts b/imxweb/projects/dpr/src/lib/outstanding/outstanding-object-entity.ts index 9713ec1dc..d5f488f58 100644 --- a/imxweb/projects/dpr/src/lib/outstanding/outstanding-object-entity.ts +++ b/imxweb/projects/dpr/src/lib/outstanding/outstanding-object-entity.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -23,16 +23,14 @@ * THIS SOFTWARE OR ITS DERIVATIVES. * */ -import { IReadValue, TypedEntity } from 'imx-qbm-dbts'; +import { IReadValue, TypedEntity } from '@imx-modules/imx-qbm-dbts'; export class OutstandingObjectEntity extends TypedEntity { - public readonly ObjectType: IReadValue = this.GetEntityValue('ObjectType'); public readonly ObjectKey: IReadValue = this.GetEntityValue('ObjectKey'); public readonly Display: IReadValue = this.GetEntityValue('Display'); public readonly CanPublish: IReadValue = this.GetEntityValue('CanPublish'); public readonly CanDelete: IReadValue = this.GetEntityValue('CanDelete'); - public readonly CanDeleteRestrictionReason: IReadValue = this.GetEntityValue("CanDeleteRestrictionReason"); - public readonly CanPublishRestrictionReason: IReadValue = this.GetEntityValue("CanPublishRestrictionReason"); - + public readonly CanDeleteRestrictionReason: IReadValue = this.GetEntityValue('CanDeleteRestrictionReason'); + public readonly CanPublishRestrictionReason: IReadValue = this.GetEntityValue('CanPublishRestrictionReason'); } diff --git a/imxweb/projects/dpr/src/lib/outstanding/outstanding.component.html b/imxweb/projects/dpr/src/lib/outstanding/outstanding.component.html index 2c3c2b645..be6fa5f7a 100644 --- a/imxweb/projects/dpr/src/lib/outstanding/outstanding.component.html +++ b/imxweb/projects/dpr/src/lib/outstanding/outstanding.component.html @@ -1,54 +1,77 @@ - - -

    {{ '#LDS#Heading Outstanding Objects' | translate }}

    - +

    {{ '#LDS#Heading Outstanding Objects' | translate }}

    + {{ LdsOutstandingText | translate }} -
    - + +
    + {{ '#LDS#Target system type' | translate }} - - + + {{ pr.GetEntity().GetDisplay() }} - - + + {{ '#LDS#Object type' | translate }} - - + + {{ pr.GetEntity().GetDisplay() }} ({{ pr.CountOutstanding.value }}) - - {{ !!selectedNamespaceTitle && !loadingTableData ? - ('#LDS#Show all outstanding objects of {0} ({1})' | translate | ldsReplace: selectedNamespaceTitle : tableDataCount): - ('#LDS#Show all outstanding objects of the target system type' | translate) + + {{ + !!selectedNamespaceTitle && !loadingTableData + ? ('#LDS#Show all outstanding objects of {0} ({1})' | translate | ldsReplace: selectedNamespaceTitle : tableDataCount) + : ('#LDS#Show all outstanding objects of the target system type' | translate) }}
    - + + - - + @@ -66,15 +89,13 @@

    {{ '#LDS#Heading Outstanding Objects' | translate }} - - + + -
    - -
    +
    + {{ '#LDS#Heading Outstanding Objects' | translate }} - - - - - - - - +
    +
    + + + + + + + + + +
    - + - +
    -
    +
    {{ node.name }}
    - + {{ node.name }}
    - +

    {{ '#LDS#Upload file attachments' | translate }}

    @@ -58,7 +83,7 @@

    {{ '#LDS#Upload file attachments' | translate }}

    • {{ '#LDS#Here you can attach files to this ticket.' | translate }}
    • {{ '#LDS#Optionally, you can create folders and add files to these folders.' | translate }}
    • -
    • {{ '#LDS#The maximum file size is:' | translate }} {{convertedMaxAttachmentSize}}
    • +
    • {{ '#LDS#The maximum file size is:' | translate }} {{ convertedMaxAttachmentSize }}
    diff --git a/imxweb/projects/hds/src/lib/calls/calls-attachment/calls-attachment.component.scss b/imxweb/projects/hds/src/lib/calls/calls-attachment/calls-attachment.component.scss index a7cf47ffc..1bd9de2f2 100644 --- a/imxweb/projects/hds/src/lib/calls/calls-attachment/calls-attachment.component.scss +++ b/imxweb/projects/hds/src/lib/calls/calls-attachment/calls-attachment.component.scss @@ -1,23 +1,25 @@ @import '@elemental-ui/core/src/styles/_eui_palette.scss'; +@import 'base/mixins'; + +:host{ + @include flex-column-container-fill(); +} .calls-attachment { - height: 100%; + @include flex-column-container($height: 100%); position: relative; - display: flex; - flex-direction: column; gap: 20px; - .mat-card { - display: flex; - flex-direction: column; - height: 100%; + + .mat-mdc-card { + @include flex-column-container($height: 100%); gap: 10px; border: 1px solid rgba($color-gray-100, 0.12); + margin: 3px; } + &__information { - display: flex; - flex-direction: column; + @include flex-column-container($height: 100%); justify-content: center; - height: 100%; background-color: $color-blue-10; border: 1px solid $color-blue-20; border-radius: 4px; @@ -35,10 +37,6 @@ font-size: 48px; font-weight: 700; } - .eui-icon { - font-size: 200px !important; - line-height: 200px !important; - } } .file-size { @@ -52,41 +50,10 @@ } } } - &__new-folder { - display: flex; - align-items: flex-start; - gap: 10px; - .eui-icon { - color: $color-blue-60; - cursor: pointer; - font-size: 20px; - padding-right: 4px; - &--disabled { - color: $color-gray-30; - cursor: default; - } - } - - .deleteIcon { - margin-left: auto; - .eui-icon{ - color:inherit - } - .eui-icon--disabled { - color: inherit; - } - } - input[type='file'] { - display: none; - } - .mat-primary{ - color: $color-gray-80; - } - } &__attachments-tree { height: 100%; - &--hidden{ + &--hidden { display: none; } } @@ -95,11 +62,7 @@ font-weight: 600; } - imx-sidenav-tree { - .snavigation { - width: 100% !important; - } - } + .loading-overlay { position: absolute; z-index: 999; @@ -113,36 +76,14 @@ } :host { .imx-tree-root > eui-icon { - color: $color-blue-60; margin-right: 10px; } - .imx-tree-root--selected > eui-icon { - color: $color-orange-60; - } - ::ng-deep{ - .calls-attachment{ - &__new-folder{ - button{ - .mat-button-wrapper{ - display: flex; - align-items: center; - } - } - } - } - } } // Theming .eui-dark-theme { :host { - .imx-tree-root > eui-icon { - color: $color-blue-40; - } - .imx-tree-root--selected > eui-icon { - color: $color-orange-40; - } .calls-attachment { &__information { background-color: $color-blue-90; @@ -153,7 +94,7 @@ } } &__new-folder { - .mat-primary{ + .mat-primary { color: $color-gray-0; } } diff --git a/imxweb/projects/hds/src/lib/calls/calls-attachment/calls-attachment.component.ts b/imxweb/projects/hds/src/lib/calls/calls-attachment/calls-attachment.component.ts index 1486cbeb3..b6c71dc8a 100644 --- a/imxweb/projects/hds/src/lib/calls/calls-attachment/calls-attachment.component.ts +++ b/imxweb/projects/hds/src/lib/calls/calls-attachment/calls-attachment.component.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -25,12 +25,14 @@ */ import { Overlay, OverlayRef } from '@angular/cdk/overlay'; -import { Component, ErrorHandler, Injector, Input, OnInit } from '@angular/core'; import { FlatTreeControl } from '@angular/cdk/tree'; -import { EuiDownloadDirective } from '@elemental-ui/core'; +import { HttpClient } from '@angular/common/http'; +import { Component, ElementRef, ErrorHandler, Injector, Input, OnInit } from '@angular/core'; import { MatDialog } from '@angular/material/dialog'; -import { HelpdeskConfig, V2ApiClientMethodFactory } from 'imx-api-hds'; -import { MethodDefinition } from 'imx-qbm-dbts'; +import { EuiDownloadDirective, EuiDownloadService } from '@elemental-ui/core'; +import { HelpdeskConfig, V2ApiClientMethodFactory } from '@imx-modules/imx-api-hds'; +import { MethodDefinition } from '@imx-modules/imx-qbm-dbts'; +import { TranslateService } from '@ngx-translate/core'; import { AppConfigService, DataSourceToolbarSettings, @@ -39,11 +41,9 @@ import { ElementalUiConfigService, LdsReplacePipe, } from 'qbm'; -import { HttpClient } from '@angular/common/http'; -import { CallsAttachmentActionType, CallsAttachmentNode, CallsAttachmentType } from './calls-attachment.model'; -import { CallsAttachmentServiceService } from './calls-attachment-service.service'; import { CallsAttachmentDialogComponent } from './calls-attachment-dialog/calls-attachment-dialog.component'; -import { TranslateService } from '@ngx-translate/core'; +import { CallsAttachmentServiceService } from './calls-attachment-service.service'; +import { CallsAttachmentActionType, CallsAttachmentNode, CallsAttachmentType } from './calls-attachment.model'; @Component({ selector: 'imx-calls-attachment', @@ -55,9 +55,9 @@ export class CallsAttachmentComponent implements OnInit { // Set FlatTreeControl node order and node expendable public treeControl = new FlatTreeControl( (node) => node.level, - (node) => node.type === CallsAttachmentType.folder + (node) => node.type === CallsAttachmentType.folder, ); - public attachmentTreeData: CallsAttachmentNode = null; + public attachmentTreeData: CallsAttachmentNode; public selectedNode: CallsAttachmentNode | null = null; public showAlert = false; public overlayRef: OverlayRef; @@ -69,7 +69,7 @@ export class CallsAttachmentComponent implements OnInit { public callsConfig: HelpdeskConfig; public hasMaxAttachmentSize: boolean; public convertedMaxAttachmentSize: string; - public noResultText = '#LDS#There are no attachments.' + public noResultText = '#LDS#There are no attachments.'; public initialized: boolean; constructor( @@ -83,7 +83,8 @@ export class CallsAttachmentComponent implements OnInit { private readonly elementalUiConfigService: ElementalUiConfigService, private readonly translator: TranslateService, private readonly errorHandler: ErrorHandler, - private readonly ldsReplace: LdsReplacePipe + private readonly ldsReplace: LdsReplacePipe, + private readonly downloadService: EuiDownloadService, ) {} // Setup apiControls and dynamicDataSource and get initial attachment tree data @@ -102,7 +103,7 @@ export class CallsAttachmentComponent implements OnInit { }, getChildren: async (node: CallsAttachmentNode, onlyCheck: boolean = true): Promise => { try { - if (node.children && (node.children.length > 0) && onlyCheck) { + if (node.children && node.children.length > 0 && onlyCheck) { return node.children; } node.isLoading = true; @@ -128,7 +129,7 @@ export class CallsAttachmentComponent implements OnInit { } // Open attachment dialog and call createFolder action - public async onAddFolder(node: CallsAttachmentNode) { + public async onAddFolder(node: CallsAttachmentNode | null) { this.dialog .open(CallsAttachmentDialogComponent, { data: { @@ -139,16 +140,18 @@ export class CallsAttachmentComponent implements OnInit { .afterClosed() .subscribe((dialogResult) => { if (!!dialogResult && !!dialogResult.action && !!dialogResult.value) { - this.createFolder(dialogResult.value, node); + this.createFolder(dialogResult.value, node || undefined); } }); } - public onDeleteItem(node: CallsAttachmentNode) { - if (node.type === CallsAttachmentType.file) { - this.openDeleteFileDialog(node); - } else { - this.openDeleteFolderDialog(node); + public onDeleteItem(node: CallsAttachmentNode | null) { + if (!!node) { + if (node.type === CallsAttachmentType.file) { + this.openDeleteFileDialog(node); + } else { + this.openDeleteFolderDialog(node); + } } } @@ -175,10 +178,14 @@ export class CallsAttachmentComponent implements OnInit { * @param node Selected node */ public async openDeleteFolderDialog(node: CallsAttachmentNode): Promise { - if(!node.children || node.children.length == 0){ + if (!node.children || node.children.length == 0) { const children = await this.attachmentService.getFilesOfDirectory(this.callId, node); - if(children.length > 0){ - this.errorHandler.handleError(this.translator.instant('#LDS#You cannot delete the folder. The folder is not empty. First delete the contents of the folder and try again.')) + if (children.length > 0) { + this.errorHandler.handleError( + this.translator.instant( + '#LDS#You cannot delete the folder. The folder is not empty. First delete the contents of the folder and try again.', + ), + ); return; } } @@ -198,21 +205,29 @@ export class CallsAttachmentComponent implements OnInit { } // Attaching a file inside a folder or at parent level - public async attachFile(val) { - if(!val){ + public async attachFile(event: EventTarget | null) { + const val = (event as HTMLInputElement)?.files; + if (!val) { return; } this.changeLoadingOverlayStatus(true); const fileToUpload: File | null = val[0]; - const fileExtension: string = fileToUpload?.name.split('.').pop(); + const fileExtension = fileToUpload?.name.split('.').pop(); try { - if (fileToUpload && this.callsConfig.AttachmentFileTypes.includes(`.${fileExtension}`)) { + if (fileToUpload && this.callsConfig.AttachmentFileTypes?.includes(`.${fileExtension}`)) { const obj = { name: fileToUpload?.name, type: CallsAttachmentType.file, path: '', file: fileToUpload }; const blob = new Blob([fileToUpload], { type: fileToUpload.type }); if (this.hasMaxAttachmentSize && fileToUpload.size > this.callsConfig?.AttachmentMaxSize) { - throw new Error(this.ldsReplace.transform(await this.translator.get('#LDS#You cannot upload the file. The file is too big. You can upload files up to {0}.').toPromise(), this.convertedMaxAttachmentSize)); + throw new Error( + this.ldsReplace.transform( + await this.translator + .get('#LDS#You cannot upload the file. The file is too big. You can upload files up to {0}.') + .toPromise(), + this.convertedMaxAttachmentSize, + ), + ); } //when attaching inside a parent if (this.selectedNode) { @@ -224,7 +239,14 @@ export class CallsAttachmentComponent implements OnInit { fileToUpload && this.uploadFile(obj.path, blob, this.attachmentTreeData); } } else { - throw new Error(this.ldsReplace.transform(await this.translator.get('#LDS#You cannot upload the file. The maximum number of files has been reached. You can attach a total of {0} files.').toPromise(), this.callsConfig.AttachmentFileTypes.join(", "))); + throw new Error( + this.ldsReplace.transform( + await this.translator + .get('#LDS#You cannot upload the file. The maximum number of files has been reached. You can attach a total of {0} files.') + .toPromise(), + this.callsConfig.AttachmentFileTypes?.join(', '), + ), + ); } } catch (error) { this.errorHandler.handleError(error); @@ -237,13 +259,19 @@ export class CallsAttachmentComponent implements OnInit { public async downloadFile(node: CallsAttachmentNode) { const def = new MethodDefinition(new V2ApiClientMethodFactory().portal_calls_attachments_file_get(this.callId, node.path)); - const directive = new EuiDownloadDirective(null /* no element */, this.http, this.overlay, this.injector); + const directive = new EuiDownloadDirective( + new ElementRef('') /* no element */, + this.http, + this.overlay, + this.injector, + this.downloadService, + ); directive.downloadOptions = { ...this.elementalUiConfigService.Config.downloadOptions, fileMimeType: '', url: this.config.BaseUrl + def.path, disableElement: false, - fileName: node.name + fileName: node.name, }; directive.onClick(); @@ -251,7 +279,7 @@ export class CallsAttachmentComponent implements OnInit { public onNodeSelection(node: CallsAttachmentNode) { this.attachmentTreeData.isSelected = false; - this.updateSelectionState(this.attachmentTreeData.children); + this.updateSelectionState(this.attachmentTreeData.children || []); if (this.selectedNode == node) { this.selectedNode = null; } else { @@ -273,8 +301,8 @@ export class CallsAttachmentComponent implements OnInit { return elementFound; } - public hasChild(_: number, node: CallsAttachmentNode): CallsAttachmentNode[] { - return node.children; + public hasChild(_: number, node: CallsAttachmentNode): boolean { + return !!node.children ? node.children?.length > 0 : false; } public onAlertDismissed() { @@ -289,46 +317,59 @@ export class CallsAttachmentComponent implements OnInit { // If isLoading return true the progressbar next to the node will shown public isLoading(node: CallsAttachmentNode): boolean { - return node.isLoading; + return !!node.isLoading; } // Only empty folders and files can be deleted - public isNodeDeletable(node: CallsAttachmentNode): boolean { + public isNodeDeletable(node: CallsAttachmentNode | null): boolean { return this.isNodeFolderEmpty(node) || this.isNodeFile(node); - } // Show information instead of attachment file tree - public get showInformation():boolean{ - return this.attachmentTreeData?.children.length === 0; + public get showInformation(): boolean { + return this.attachmentTreeData?.children?.length === 0; } - private async uploadFile(path: string, blob: Blob, node: CallsAttachmentNode): Promise{ - try{ - await this.attachmentService.uploadFile(this.callId,path, blob); + private async uploadFile(path: string, blob: Blob, node: CallsAttachmentNode): Promise { + try { + await this.attachmentService.uploadFile(this.callId, path, blob); await this.apiControls.getChildren(node, false); this.expandNode(node); } catch { - this.errorHandler.handleError(this.translator.instant('#LDS#You cannot upload the file. You do not have permission to upload files.')) + this.errorHandler.handleError( + this.translator.instant('#LDS#You cannot upload the file. You do not have permission to upload files.'), + ); } } private async byteConverter(byte: number): Promise { - if (byte >= 1073741824) return this.ldsReplace.transform(await this.translator.get('#LDS#{0} GB').toPromise(), this.getFlooredFixed(byte / Math.pow(1024,3))); else - if (byte >= 1048576) return this.ldsReplace.transform(await this.translator.get('#LDS#{0} MB').toPromise(), this.getFlooredFixed(byte / Math.pow(1024,2))); else - if (byte >= 1024) return this.ldsReplace.transform(await this.translator.get('#LDS#{0} kB').toPromise(), this.getFlooredFixed(byte / Math.pow(1024,1))); else - return this.ldsReplace.transform(await this.translator.get('#LDS#{0} byte').toPromise(), byte); + if (byte >= 1073741824) + return this.ldsReplace.transform( + await this.translator.get('#LDS#{0} GB').toPromise(), + this.getFlooredFixed(byte / Math.pow(1024, 3)), + ); + else if (byte >= 1048576) + return this.ldsReplace.transform( + await this.translator.get('#LDS#{0} MB').toPromise(), + this.getFlooredFixed(byte / Math.pow(1024, 2)), + ); + else if (byte >= 1024) + return this.ldsReplace.transform( + await this.translator.get('#LDS#{0} kB').toPromise(), + this.getFlooredFixed(byte / Math.pow(1024, 1)), + ); + else return this.ldsReplace.transform(await this.translator.get('#LDS#{0} byte').toPromise(), byte); } private getFlooredFixed(value: number, fractionDigits: number = 2): string { return (Math.floor(value * Math.pow(10, fractionDigits)) / Math.pow(10, fractionDigits)).toFixed(fractionDigits); } - private isNodeFolderEmpty(node: CallsAttachmentNode): boolean { + private isNodeFolderEmpty(node: CallsAttachmentNode | null): boolean { return !!node && node.type === CallsAttachmentType.folder && (!node.children || node.children.length === 0); } - private isNodeFile(node: CallsAttachmentNode): boolean { + private isNodeFile(node: CallsAttachmentNode | null): boolean { return !!node && node.type === CallsAttachmentType.file; } @@ -340,12 +381,14 @@ export class CallsAttachmentComponent implements OnInit { if (parent) { await this.apiControls.getChildren(parent, false); this.expandNode(parent); - }else{ - this.attachmentTreeData.children = this.attachmentTreeData.children.filter((childNode) => childNode.name !== node.name); + } else { + this.attachmentTreeData.children = this.attachmentTreeData.children?.filter((childNode) => childNode.name !== node.name); this.expandNode(this.attachmentTreeData); } } catch { - this.errorHandler.handleError(this.translator.instant('#LDS#You cannot delete the folder. You do not have permission to delete folders.')) + this.errorHandler.handleError( + this.translator.instant('#LDS#You cannot delete the folder. You do not have permission to delete folders.'), + ); } finally { this.changeLoadingOverlayStatus(false); this.selectedNode = null; @@ -353,7 +396,7 @@ export class CallsAttachmentComponent implements OnInit { } private async deleteFile(node: CallsAttachmentNode) { - try{ + try { this.changeLoadingOverlayStatus(true); await this.attachmentService.deleteFile(this.callId, node.path); if (node.parent) { @@ -361,9 +404,11 @@ export class CallsAttachmentComponent implements OnInit { this.expandNode(node.parent); } this.selectedNode = null; - }catch{ - this.errorHandler.handleError(this.translator.instant('#LDS#You cannot delete the attachment. You do not have permission to delete attachments.')) - }finally{ + } catch { + this.errorHandler.handleError( + this.translator.instant('#LDS#You cannot delete the attachment. You do not have permission to delete attachments.'), + ); + } finally { this.changeLoadingOverlayStatus(false); } } @@ -381,22 +426,26 @@ export class CallsAttachmentComponent implements OnInit { }; if (node) { if (this.isDuplicateName(val, node.children)) { - this.showAlertMessage('#LDS#You cannot create the folder. A folder with the entered name already exists. Enter a different folder name.'); + this.showAlertMessage( + '#LDS#You cannot create the folder. A folder with the entered name already exists. Enter a different folder name.', + ); } else { obj.path = node.path + '/' + val; obj.level = node.level + 1; await this.apiControls.getChildren(node); await this.attachmentService.createDirectory(this.callId, obj.path); - node.children.unshift(obj); + node.children?.unshift(obj); this.expandNode(node); } } else { if (this.isDuplicateName(val, this.attachmentTreeData.children)) { - this.showAlertMessage('#LDS#You cannot create the folder. A folder with the entered name already exists. Enter a different folder name.'); + this.showAlertMessage( + '#LDS#You cannot create the folder. A folder with the entered name already exists. Enter a different folder name.', + ); } else { obj.path = `${val}`; await this.attachmentService.createDirectory(this.callId, obj.path); - this.attachmentTreeData.children.unshift(obj); + this.attachmentTreeData.children?.unshift(obj); this.expandNode(this.attachmentTreeData); } } diff --git a/imxweb/projects/hds/src/lib/calls/calls-attachment/calls-attachment.model.ts b/imxweb/projects/hds/src/lib/calls/calls-attachment/calls-attachment.model.ts index d6ffc5992..1fcd956a1 100644 --- a/imxweb/projects/hds/src/lib/calls/calls-attachment/calls-attachment.model.ts +++ b/imxweb/projects/hds/src/lib/calls/calls-attachment/calls-attachment.model.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR diff --git a/imxweb/projects/hds/src/lib/calls/calls-history-sidesheet/calls-history-sidesheet.component.html b/imxweb/projects/hds/src/lib/calls/calls-history-sidesheet/calls-history-sidesheet.component.html index 0a88b51ea..b7df58f19 100644 --- a/imxweb/projects/hds/src/lib/calls/calls-history-sidesheet/calls-history-sidesheet.component.html +++ b/imxweb/projects/hds/src/lib/calls/calls-history-sidesheet/calls-history-sidesheet.component.html @@ -1,12 +1,11 @@ -
    -
    -
    - -
    - -
    -
    -
    -
    -
    \ No newline at end of file +
    + +
    + +
    +
    +
    diff --git a/imxweb/projects/hds/src/lib/calls/calls-history-sidesheet/calls-history-sidesheet.component.scss b/imxweb/projects/hds/src/lib/calls/calls-history-sidesheet/calls-history-sidesheet.component.scss index 42b005ccf..e7de9633e 100644 --- a/imxweb/projects/hds/src/lib/calls/calls-history-sidesheet/calls-history-sidesheet.component.scss +++ b/imxweb/projects/hds/src/lib/calls/calls-history-sidesheet/calls-history-sidesheet.component.scss @@ -7,73 +7,6 @@ display: flex; flex-direction: column; overflow: hidden; - - &__tab-content { - display: flex; - flex-direction: column; - height: 100%; - } - - &__tab-content-body { - flex: 1; - padding: 32px; - overflow: auto; - - &.no-padding { - padding: 0; - } - - .helper-alert { - display: flex; - margin-bottom: 20px; - - - span { - display: block; - } - } - } - - &__action-buttons { - display: flex; - justify-content: flex-end; - background-color: $white; - padding: 16px 32px; - margin: 16px 32px; - - .justify-start { - margin-right: auto; - } - - button:not(:last-of-type):not(.justify-start) { - margin-right: 10px; - } - - button:disabled:hover { - cursor: not-allowed; - } - - .help-icon { - color: $iris-blue; - font-size: 16px; - margin-left: 5px; - cursor: auto; - } - - } - - ::ng-deep .mat-tab-group { - height: 100%; - - .mat-tab-header { - padding: 0 32px; - background-color: $white; - } - - .mat-tab-body-wrapper { - height: 100%; - } - } } @media screen and (max-width: 480px) { @@ -81,55 +14,5 @@ &__tab-content { display: block; } - - &__action-buttons { - flex-direction: column-reverse; - - button { - width: 100%; - margin-bottom: 10px; - margin-right: 0; - } - - .justify-start { - margin-right: 0; - } - } - } -} - -.eui-dark-theme { - :host { - .calls-history-sidesheet { - background-color: $color-gray-80; - - ::ng-deep .mat-tab-group { - .mat-tab-header { - background-color: $color-gray-80; - } - } - - &__action-buttons { - background-color: $color-gray-70; - } - } - } -} - -.eui-contrast-theme { - :host { - .calls-history-sidesheet { - background-color: $color-gray-100; - - ::ng-deep .mat-tab-group { - .mat-tab-header { - background-color: $color-gray-90; - } - } - - &__action-buttons { - background-color: $color-gray-80; - } - } } } diff --git a/imxweb/projects/hds/src/lib/calls/calls-history-sidesheet/calls-history-sidesheet.component.ts b/imxweb/projects/hds/src/lib/calls/calls-history-sidesheet/calls-history-sidesheet.component.ts index 052471e60..7da8bf745 100644 --- a/imxweb/projects/hds/src/lib/calls/calls-history-sidesheet/calls-history-sidesheet.component.ts +++ b/imxweb/projects/hds/src/lib/calls/calls-history-sidesheet/calls-history-sidesheet.component.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -26,38 +26,36 @@ import { Component, Inject, OnInit } from '@angular/core'; import { EuiLoadingService, EUI_SIDESHEET_DATA } from '@elemental-ui/core'; import { UntypedFormBuilder, UntypedFormGroup } from '@angular/forms'; -import { BaseCdr, ColumnDependentReference} from 'qbm'; -import { PortalCallsHistory } from 'imx-api-hds'; +import { BaseCdr, ColumnDependentReference } from 'qbm'; +import { PortalCallsHistory } from '@imx-modules/imx-api-hds'; @Component({ selector: 'imx-calls-history-sidesheet', templateUrl: './calls-history-sidesheet.component.html', - styleUrls: ['./calls-history-sidesheet.component.scss'] + styleUrls: ['./calls-history-sidesheet.component.scss'], }) export class CallsHistorySidesheetComponent implements OnInit { - public readonly detailsFormGroup: UntypedFormGroup; public cdrList: ColumnDependentReference[] = []; - constructor( + constructor( @Inject(EUI_SIDESHEET_DATA) public portalCallsHistory: PortalCallsHistory, private readonly euiLoadingService: EuiLoadingService, public formBuilder: UntypedFormBuilder, ) { this.detailsFormGroup = new UntypedFormGroup({ formArray: formBuilder.array([]) }); - } + } - public async ngOnInit(): Promise { + public async ngOnInit(): Promise { await this.setup(); } public async setup(): Promise { let entity = this.portalCallsHistory.GetEntity(); let columnNames = await this.getColumnNames(); - columnNames.forEach(columnName => { + columnNames.forEach((columnName) => { let column = entity.GetColumn(columnName); - if (column) - this.cdrList.push(new BaseCdr(column)); + if (column) this.cdrList.push(new BaseCdr(column)); }); } diff --git a/imxweb/projects/hds/src/lib/calls/calls-history/calls-history.component.html b/imxweb/projects/hds/src/lib/calls/calls-history/calls-history.component.html index 4f5a75613..d7c976d10 100644 --- a/imxweb/projects/hds/src/lib/calls/calls-history/calls-history.component.html +++ b/imxweb/projects/hds/src/lib/calls/calls-history/calls-history.component.html @@ -1,17 +1,8 @@ - - + {{ '#LDS#Here you can get an overview of all changes to this ticket.' | translate }} - - - -
    - - -
    - - -
    \ No newline at end of file + + + + + diff --git a/imxweb/projects/hds/src/lib/calls/calls-history/calls-history.component.scss b/imxweb/projects/hds/src/lib/calls/calls-history/calls-history.component.scss index 59a630f8f..b188afba9 100644 --- a/imxweb/projects/hds/src/lib/calls/calls-history/calls-history.component.scss +++ b/imxweb/projects/hds/src/lib/calls/calls-history/calls-history.component.scss @@ -1,8 +1,6 @@ -.helper-alert { - display: flex; - margin-bottom: 20px; +@import 'base/mixins'; - span { - display: block; - } - } \ No newline at end of file + +:host { +@include flex-column-container-fill(); +} \ No newline at end of file diff --git a/imxweb/projects/hds/src/lib/calls/calls-history/calls-history.component.ts b/imxweb/projects/hds/src/lib/calls/calls-history/calls-history.component.ts index 845c47d8a..ee528c8f4 100644 --- a/imxweb/projects/hds/src/lib/calls/calls-history/calls-history.component.ts +++ b/imxweb/projects/hds/src/lib/calls/calls-history/calls-history.component.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -24,40 +24,35 @@ * */ -import { Component, OnInit, Input, ErrorHandler } from '@angular/core'; -import { EuiLoadingService, EuiSidesheetService } from '@elemental-ui/core'; +import { Component, Input, OnInit } from '@angular/core'; +import { EuiSidesheetService } from '@elemental-ui/core'; +import { PortalCalls, PortalCallsHistory } from '@imx-modules/imx-api-hds'; +import { CollectionLoadParameters, EntitySchema, IClientProperty, TypedEntityCollectionData } from '@imx-modules/imx-qbm-dbts'; import { TranslateService } from '@ngx-translate/core'; -import { PortalCalls, PortalCallsHistory } from 'imx-api-hds'; +import { DataViewInitParameters, DataViewSource, calculateSidesheetWidth } from 'qbm'; import { HdsApiService } from '../../hds-api-client.service'; -import { DataSourceToolbarSettings, ClassloggerService, SettingsService, DataSourceWrapper, DataTableGroupedData, DataSourceToolbarFilter } from 'qbm'; -import { CollectionLoadParameters, EntitySchema, IClientProperty } from 'imx-qbm-dbts'; import { CallsHistorySidesheetComponent } from '../calls-history-sidesheet/calls-history-sidesheet.component'; @Component({ selector: 'imx-calls-history', templateUrl: './calls-history.component.html', - styleUrls: ['./calls-history.component.scss'] + styleUrls: ['./calls-history.component.scss'], + providers: [DataViewSource], }) export class CallsHistoryComponent implements OnInit { - - @Input() public ticket: any; + @Input() public ticket: PortalCalls; public entitySchema: EntitySchema; - public dstSettings: DataSourceToolbarSettings; public displayedColumns: IClientProperty[] = []; - public collectionLoadParameters: CollectionLoadParameters; - public filterOptions: DataSourceToolbarFilter[] = []; constructor( private readonly sidesheet: EuiSidesheetService, private readonly translate: TranslateService, - private readonly errorHandler: ErrorHandler, private readonly hdsApiService: HdsApiService, - private readonly settingsService: SettingsService, - private readonly euiLoadingService: EuiLoadingService) { - this.collectionLoadParameters = { PageSize: this.settingsService.DefaultPageSize, StartIndex: 0 }; - this.entitySchema = this.hdsApiService.typedClient.PortalCallsHistory.GetSchema(); - } - + public dataSource: DataViewSource, + ) { + this.entitySchema = this.hdsApiService.typedClient.PortalCallsHistory.GetSchema(); + } + public async ngOnInit() { this.displayedColumns = [ this.entitySchema.Columns['UID_TroubleTicket'], @@ -66,53 +61,27 @@ export class CallsHistoryComponent implements OnInit { this.entitySchema.Columns['UID_TroubleCallState'], this.entitySchema.Columns['ObjectKeySupporter'], ]; - await this.loadHistory(); - } - - private async loadHistory(): Promise { - let overlayRef = this.euiLoadingService.show(); - try { - if (this.ticket?.EntityKeysData?.Keys?.length > 0) - { - let history = await this.hdsApiService.typedClient.PortalCallsHistory.Get(this.ticket.EntityKeysData.Keys[0],this.collectionLoadParameters); - this.dstSettings = { - displayedColumns: this.displayedColumns, - dataSource: history, - entitySchema: this.entitySchema, - navigationState: this.collectionLoadParameters, - filters: this.filterOptions, - }; - } - } - catch (error) { - this.errorHandler.handleError(error); - } - finally { - this.euiLoadingService.hide(overlayRef); - } - } - - public async onNavigationStateChanged(collectionLoadParameters?: CollectionLoadParameters): Promise { - if (collectionLoadParameters) - this.collectionLoadParameters = collectionLoadParameters; - - await this.loadHistory(); - } - - public async onSearch(keywords: string): Promise { - this.collectionLoadParameters.StartIndex = 0; - this.collectionLoadParameters.search = keywords; - await this.loadHistory(); + const dataViewInitParameters: DataViewInitParameters = { + execute: (params: CollectionLoadParameters, signal: AbortSignal): Promise> => + this.hdsApiService.typedClient.PortalCallsHistory.Get(this.ticket?.EntityKeysData?.Keys?.[0] || '', params), + schema: this.entitySchema, + columnsToDisplay: this.displayedColumns, + highlightEntity: (identity: PortalCallsHistory) => { + this.onSelected(identity); + }, + }; + this.dataSource.init(dataViewInitParameters); } public async onSelected(history: PortalCallsHistory): Promise { if (history) { let title = await this.translate.get('#LDS#Heading View Change Details').toPromise(); - let sidesheetRef = this.sidesheet.open(CallsHistorySidesheetComponent, { + this.sidesheet.open(CallsHistorySidesheetComponent, { testId: 'calls-history-sidesheet', title: title, + subTitle: history.GetEntity().GetDisplay(), padding: '0px', - width: 'max(400px, 40%)', + width: calculateSidesheetWidth(700, 0.4), data: history, }); } diff --git a/imxweb/projects/hds/src/lib/calls/calls-sidesheet/calls-sidesheet.component.html b/imxweb/projects/hds/src/lib/calls/calls-sidesheet/calls-sidesheet.component.html index 13c9a836a..f1751138b 100644 --- a/imxweb/projects/hds/src/lib/calls/calls-sidesheet/calls-sidesheet.component.html +++ b/imxweb/projects/hds/src/lib/calls/calls-sidesheet/calls-sidesheet.component.html @@ -1,35 +1,43 @@
    - + -
    -
    - - -
    - -
    -
    -
    -
    - -
    +
    + + +
    + +
    +
    +
    +
    +
    -
    -
    - -
    +
    +
    -
    -
    - -
    +
    +
    diff --git a/imxweb/projects/hds/src/lib/calls/calls-sidesheet/calls-sidesheet.component.scss b/imxweb/projects/hds/src/lib/calls/calls-sidesheet/calls-sidesheet.component.scss index 2c2546751..991eed524 100644 --- a/imxweb/projects/hds/src/lib/calls/calls-sidesheet/calls-sidesheet.component.scss +++ b/imxweb/projects/hds/src/lib/calls/calls-sidesheet/calls-sidesheet.component.scss @@ -3,38 +3,13 @@ .calls-sidesheet { overflow: hidden; - height:100%; - - &__tab-content { - display: flex; - flex-direction: column; - height: 100%; - } - - &__tab-content-body { - - .helper-alert { - display: flex; - margin-bottom: 20px; - } - } - - ::ng-deep .mat-tab-group { - height: 100%; - .mat-tab-header { - padding: 0 20px; - } - - .mat-tab-body-wrapper { - height: 100%; - } - } + height: 100%; } -imx-help-contextual{ +imx-help-contextual { justify-content: end; } -.eui-sidesheet-content.eui-sidesheet-content--no-padding-top{ +.eui-sidesheet-content.eui-sidesheet-content--no-padding-top { padding-top: 0; } @@ -43,55 +18,5 @@ imx-help-contextual{ &__tab-content { display: block; } - - &__action-buttons { - flex-direction: column-reverse; - - button { - width: 100%; - margin-bottom: 10px; - margin-right: 0; - } - - .justify-start { - margin-right: 0; - } - } - } -} - -.eui-dark-theme { - :host { - .calls-sidesheet { - background-color: $color-gray-80; - - ::ng-deep .mat-tab-group { - .mat-tab-header { - background-color: $color-gray-80; - } - } - - &__action-buttons { - background-color: $color-gray-70; - } - } - } -} - -.eui-contrast-theme { - :host { - .calls-sidesheet { - background-color: $color-gray-100; - - ::ng-deep .mat-tab-group { - .mat-tab-header { - background-color: $color-gray-100; - } - } - - &__action-buttons { - background-color: $color-gray-90; - } - } } } diff --git a/imxweb/projects/hds/src/lib/calls/calls-sidesheet/calls-sidesheet.component.ts b/imxweb/projects/hds/src/lib/calls/calls-sidesheet/calls-sidesheet.component.ts index 890e967cf..af8229993 100644 --- a/imxweb/projects/hds/src/lib/calls/calls-sidesheet/calls-sidesheet.component.ts +++ b/imxweb/projects/hds/src/lib/calls/calls-sidesheet/calls-sidesheet.component.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -25,25 +25,24 @@ */ import { Component, ErrorHandler, Inject, OnInit } from '@angular/core'; -import { EuiLoadingService, EuiSidesheetRef, EUI_SIDESHEET_DATA } from '@elemental-ui/core'; import { UntypedFormBuilder, UntypedFormGroup } from '@angular/forms'; -import { PortalCalls } from 'imx-api-hds'; -import { BaseCdr, ColumnDependentReference, SnackBarService, ConfirmationService, TextContainer, HELP_CONTEXTUAL } from 'qbm'; +import { EUI_SIDESHEET_DATA, EuiLoadingService, EuiSidesheetRef } from '@elemental-ui/core'; +import { PortalCalls } from '@imx-modules/imx-api-hds'; +import { BaseCdr, ColumnDependentReference, ConfirmationService, HELP_CONTEXTUAL, SnackBarService, TextContainer } from 'qbm'; import { ProjectConfigurationService } from 'qer'; import { HdsApiService } from '../../hds-api-client.service'; export interface CallsSidesheetData { isNew: boolean; - ticket: PortalCalls + ticket: PortalCalls; } @Component({ selector: 'imx-calls-sidesheet', templateUrl: './calls-sidesheet.component.html', - styleUrls: ['./calls-sidesheet.component.scss'] + styleUrls: ['./calls-sidesheet.component.scss'], }) export class CallsSidesheetComponent implements OnInit { - public readonly detailsFormGroup: UntypedFormGroup; public cdrList: ColumnDependentReference[] = []; public ticket: PortalCalls; @@ -63,7 +62,7 @@ export class CallsSidesheetComponent implements OnInit { this.detailsFormGroup = new UntypedFormGroup({ formArray: formBuilder.array([]) }); this.sidesheetRef.closeClicked().subscribe(async () => { - if (!this.detailsFormGroup.dirty || await this.confirmationService.confirmLeaveWithUnsavedChanges()) { + if (!this.detailsFormGroup.dirty || (await this.confirmationService.confirmLeaveWithUnsavedChanges())) { this.sidesheetRef.close(); } }); @@ -77,11 +76,10 @@ export class CallsSidesheetComponent implements OnInit { this.ticket = this.sidesheetData.ticket; let entity = this.sidesheetData.ticket.GetEntity(); let columnNames = await this.getColumnNames(); - columnNames.forEach(columnName => { + columnNames.forEach((columnName) => { let column = entity.GetColumn(columnName); - if (column) - this.cdrList.push(new BaseCdr(column)); + if (column) this.cdrList.push(new BaseCdr(column)); }); } @@ -91,15 +89,11 @@ export class CallsSidesheetComponent implements OnInit { try { let config = await this.projectConfigurationService.getConfig(); - if (this.sidesheetData.isNew) - columnNames = config.OwnershipConfig.PrimaryFields['TroubleTicket']; - else - columnNames = config.OwnershipConfig.EditableFields['TroubleTicket']; - } - catch (error) { + if (this.sidesheetData.isNew) columnNames = config.OwnershipConfig?.PrimaryFields?.['TroubleTicket'] || []; + else columnNames = config.OwnershipConfig?.EditableFields?.['TroubleTicket'] || []; + } catch (error) { this.errorHandler.handleError(error); - } - finally { + } finally { this.euiLoadingService.hide(overlayRef); } return columnNames; @@ -109,23 +103,30 @@ export class CallsSidesheetComponent implements OnInit { if (this.detailsFormGroup.valid) { let overlayRef = this.euiLoadingService.show(); try { - await this.sidesheetData.ticket.GetEntity().Commit(true).then(() => { - this.detailsFormGroup.markAsPristine(); - this.sidesheetRef.close(); - let textContainer: TextContainer; - - if (this.sidesheetData.isNew) - textContainer = { key: '#LDS#The ticket with the number {0} has been successfully created.', parameters: [this.sidesheetData.ticket.CallNumber.value.toString()] }; - else - textContainer = { key: '#LDS#The ticket has been successfully saved.', parameters: [this.sidesheetData.ticket.CallNumber.value.toString()] }; - - this.snackBarService.open(textContainer, '#LDS#Close', { duration: 6000 }); - }); - } - catch (error) { + await this.sidesheetData.ticket + .GetEntity() + .Commit(true) + .then(() => { + this.detailsFormGroup.markAsPristine(); + this.sidesheetRef.close(); + let textContainer: TextContainer; + + if (this.sidesheetData.isNew) + textContainer = { + key: '#LDS#The ticket with the number {0} has been successfully created.', + parameters: [this.sidesheetData.ticket.CallNumber.value.toString()], + }; + else + textContainer = { + key: '#LDS#The ticket has been successfully saved.', + parameters: [this.sidesheetData.ticket.CallNumber.value.toString()], + }; + + this.snackBarService.open(textContainer, '#LDS#Close', { duration: 6000 }); + }); + } catch (error) { this.errorHandler.handleError(error); - } - finally { + } finally { this.euiLoadingService.hide(overlayRef); } } @@ -135,7 +136,7 @@ export class CallsSidesheetComponent implements OnInit { this.sidesheetRef.close(); } - private get getTicketId():string{ + public get getTicketId(): string { return !!this.sidesheetData.ticket.EntityKeysData.Keys ? this.sidesheetData.ticket.EntityKeysData.Keys[0] : ''; } } diff --git a/imxweb/projects/hds/src/lib/calls/calls.component.html b/imxweb/projects/hds/src/lib/calls/calls.component.html index dfeba9923..9297621cf 100644 --- a/imxweb/projects/hds/src/lib/calls/calls.component.html +++ b/imxweb/projects/hds/src/lib/calls/calls.component.html @@ -1,60 +1,145 @@ -

    - {{ '#LDS#Heading Tickets' | translate }} - -

    +
    +

    + {{ '#LDS#Heading Tickets' | translate }} + +

    + +
    - - + - -
    - - - - -
    - {{ getTicketItemValue(item, 'DescriptionHotline') }} -
    -
    -
    - - - - - - - - - - - - - -
    - {{ getTicketItemValue(item, 'ActionHotline') }} -
    -
    -
    -
    -
    - + + + {{ entitySchema?.Columns?.DescriptionHotline?.Display }} + + +
    + {{ getTicketItemValue(item, 'DescriptionHotline') }} +
    + +
    + + + {{ entitySchema?.Columns?.ActionHotline?.Display }} + + +
    + {{ getTicketItemValue(item, 'ActionHotline') }} +
    + +
    + + + {{ entitySchema?.Columns?.CallNumber?.Display }} + + +
    {{ item.CallNumber.Column.GetDisplayValue() }}
    + +
    + + + {{ entitySchema?.Columns?.IsClosed?.Display }} + + +
    {{ item.entity.columns.IsClosed.GetDisplayValue() }}
    + +
    + + + {{ entitySchema?.Columns?.IsHistory?.Display }} + + +
    {{ item.entity.columns.IsHistory.GetDisplayValue() }}
    + +
    + + + {{ entitySchema?.Columns?.IsHold?.Display }} + + +
    {{ item.entity.columns.IsHold.GetDisplayValue() }}
    + +
    + + + {{ entitySchema?.Columns?.UID_PersonHotline?.Display }} + + +
    {{ item.entity.columns.UID_PersonHotline.GetDisplayValue() }}
    + +
    + + + {{ entitySchema?.Columns?.UID_PersonInTrouble?.Display }} + + +
    {{ item.UID_PersonInTrouble.Column.GetDisplayValue() }}
    + +
    + + + {{ entitySchema?.Columns?.UID_PersonInTroubleAdditional?.Display }} + + +
    {{ item.entity.columns.UID_PersonInTroubleAdditional.GetDisplayValue() }}
    + +
    + + + {{ entitySchema?.Columns?.UID_TroubleCallState?.Display }} + + +
    {{ item.entity.columns.UID_TroubleCallState.GetDisplayValue() }}
    + +
    + + + {{ entitySchema?.Columns?.UID_TroubleEscalationLevel_E?.Display }} + + +
    {{ item.entity.columns.UID_TroubleEscalationLevel_E.GetDisplayValue() }}
    + +
    + + + {{ entitySchema?.Columns?.UID_TroubleProduct?.Display }} + + +
    {{ item.entity.columns.UID_TroubleProduct.GetDisplayValue() }}
    + +
    + + + {{ entitySchema?.Columns?.UID_TroubleSeverity?.Display }} + + +
    {{ item.UID_TroubleSeverity.Column.GetDisplayValue() }}
    + +
    + + + {{ entitySchema?.Columns?.UID_TroubleTypeHotline?.Display }} + + +
    {{ item.entity.columns.UID_TroubleTypeHotline.GetDisplayValue() }}
    + +
    + +
    -
    - +
    - - - -
    - - - - -
    diff --git a/imxweb/projects/o3t/src/lib/teams/team-channel-details/team-channel-details.component.ts b/imxweb/projects/o3t/src/lib/teams/team-channel-details/team-channel-details.component.ts deleted file mode 100644 index 16450c824..000000000 --- a/imxweb/projects/o3t/src/lib/teams/team-channel-details/team-channel-details.component.ts +++ /dev/null @@ -1,83 +0,0 @@ -/* - * ONE IDENTITY LLC. PROPRIETARY INFORMATION - * - * This software is confidential. One Identity, LLC. or one of its affiliates or - * subsidiaries, has supplied this software to you under terms of a - * license agreement, nondisclosure agreement or both. - * - * You may not copy, disclose, or use this software except in accordance with - * those terms. - * - * - * Copyright 2023 One Identity LLC. - * ALL RIGHTS RESERVED. - * - * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR - * WARRANTIES ABOUT THE SUITABILITY OF THE SOFTWARE, - * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED - * TO THE IMPLIED WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE, OR - * NON-INFRINGEMENT. ONE IDENTITY LLC. SHALL NOT BE - * LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE - * AS A RESULT OF USING, MODIFYING OR DISTRIBUTING - * THIS SOFTWARE OR ITS DERIVATIVES. - * - */ - -import { Component, Inject, OnInit } from '@angular/core'; -import { UntypedFormArray, UntypedFormBuilder, UntypedFormGroup } from '@angular/forms'; -import { EuiSidesheetRef, EUI_SIDESHEET_DATA } from '@elemental-ui/core'; -import { PortalTargetsystemTeamsChannels } from 'imx-api-o3t'; -import { BaseCdr, ColumnDependentReference, SnackBarService } from 'qbm'; -import { TeamsService } from '../teams.service'; - -@Component({ - selector: 'imx-team-channel-details', - templateUrl: './team-channel-details.component.html' -}) -export class TeamChannelDetailsComponent implements OnInit { - - public readonly formGroup: UntypedFormGroup; - public cdrList: ColumnDependentReference[] = []; - - constructor( - formBuilder: UntypedFormBuilder, - @Inject(EUI_SIDESHEET_DATA) public teamChannel: PortalTargetsystemTeamsChannels, - private teamsService: TeamsService, - private readonly sidesheetRef: EuiSidesheetRef, - private readonly snackbar: SnackBarService, - ) { - this.formGroup = new UntypedFormGroup({ formArray: formBuilder.array([]) }); - } - - get formArray(): UntypedFormArray { - return this.formGroup.get('formArray') as UntypedFormArray; - } - - public ngOnInit(): void { - this.setup(); - } - - public async saveChanges(): Promise { - this.teamsService.handleOpenLoader(); - try { - await this.teamChannel.GetEntity().Commit(true); - this.formGroup.markAsPristine(); - this.snackbar.open({ key: '#LDS#Your changes have been successfully saved.' }); - } finally { - this.teamsService.handleCloseLoader(); - } - } - - public cancel(): void { - this.sidesheetRef.close(); - } - - private setup(): void { - this.cdrList = [ - new BaseCdr(this.teamChannel.DisplayName.Column), - new BaseCdr(this.teamChannel.Description.Column), - ]; - } - -} diff --git a/imxweb/projects/o3t/src/lib/teams/team-channels/team-channels.component.html b/imxweb/projects/o3t/src/lib/teams/team-channels/team-channels.component.html deleted file mode 100644 index ce4453afc..000000000 --- a/imxweb/projects/o3t/src/lib/teams/team-channels/team-channels.component.html +++ /dev/null @@ -1,34 +0,0 @@ - -
    - - - - - -
    - - - - - - - - - - - - -
    - -
    diff --git a/imxweb/projects/o3t/src/lib/teams/team-channels/team-channels.component.ts b/imxweb/projects/o3t/src/lib/teams/team-channels/team-channels.component.ts deleted file mode 100644 index c63b5c01a..000000000 --- a/imxweb/projects/o3t/src/lib/teams/team-channels/team-channels.component.ts +++ /dev/null @@ -1,123 +0,0 @@ -/* - * ONE IDENTITY LLC. PROPRIETARY INFORMATION - * - * This software is confidential. One Identity, LLC. or one of its affiliates or - * subsidiaries, has supplied this software to you under terms of a - * license agreement, nondisclosure agreement or both. - * - * You may not copy, disclose, or use this software except in accordance with - * those terms. - * - * - * Copyright 2023 One Identity LLC. - * ALL RIGHTS RESERVED. - * - * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR - * WARRANTIES ABOUT THE SUITABILITY OF THE SOFTWARE, - * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED - * TO THE IMPLIED WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE, OR - * NON-INFRINGEMENT. ONE IDENTITY LLC. SHALL NOT BE - * LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE - * AS A RESULT OF USING, MODIFYING OR DISTRIBUTING - * THIS SOFTWARE OR ITS DERIVATIVES. - * - */ - -import { Component, Input, OnInit } from '@angular/core'; -import { EuiSidesheetService } from '@elemental-ui/core'; -import { TranslateService } from '@ngx-translate/core'; -import { PortalTargetsystemTeamsChannels } from 'imx-api-o3t'; -import { CollectionLoadParameters, DisplayColumns, EntitySchema, IClientProperty } from 'imx-qbm-dbts'; -import { ClassloggerService, DataSourceToolbarFilter, DataSourceToolbarSettings, SettingsService } from 'qbm'; -import { TeamChannelDetailsComponent } from '../team-channel-details/team-channel-details.component'; -import { TeamsService } from '../teams.service'; - -@Component({ - selector: 'imx-team-channels', - templateUrl: './team-channels.component.html' -}) -export class TeamChannelsComponent implements OnInit { - - @Input() public uidO3t: string; - public dstSettings: DataSourceToolbarSettings; - public navigationState: CollectionLoadParameters; - public filterOptions: DataSourceToolbarFilter[] = []; - public readonly entitySchemaTeamChannels: EntitySchema; - public readonly DisplayColumns = DisplayColumns; - - private displayedColumns: IClientProperty[] = []; - - constructor( - private readonly sideSheet: EuiSidesheetService, - private readonly logger: ClassloggerService, - settingsService: SettingsService, - private readonly teamsService: TeamsService, - private readonly translate: TranslateService - ) { - this.navigationState = { PageSize: settingsService.DefaultPageSize, StartIndex: 0 }; - this.entitySchemaTeamChannels = this.teamsService.teamChannelsSchema; - } - - public async ngOnInit(): Promise { - this.displayedColumns = [ - this.entitySchemaTeamChannels.Columns.DisplayName, - this.entitySchemaTeamChannels.Columns.Description, - this.entitySchemaTeamChannels.Columns.WebUrl, - ]; - - await this.navigate(); - } - - public async onNavigationStateChanged(newState?: CollectionLoadParameters): Promise { - if (newState) { - this.navigationState = newState; - } - await this.navigate(); - } - - public async onSearch(keywords: string): Promise { - this.logger.debug(this, `Searching for: ${keywords}`); - this.navigationState.StartIndex = 0; - this.navigationState.search = keywords; - await this.navigate(); - } - - public async onTeamChannelChanged(channel: PortalTargetsystemTeamsChannels): Promise { - this.logger.debug(this, `Selected channel changed`); - this.logger.trace(this, `New channel selected`, channel); - this.openDetailsSidesheet(channel); - } - - private async navigate(): Promise { - this.teamsService.handleOpenLoader(); - - try { - const data = await this.teamsService.getTeamChannels(this.uidO3t, this.navigationState); - this.dstSettings = { - displayedColumns: this.displayedColumns, - dataSource: data, - entitySchema: this.entitySchemaTeamChannels, - navigationState: this.navigationState, - filters: this.filterOptions, - }; - this.logger.debug(this, `Head at ${data.Data.length + this.navigationState.StartIndex} of ${data.totalCount} item(s)`); - } finally { - this.teamsService.handleCloseLoader(); - } - } - - private async openDetailsSidesheet(channel: PortalTargetsystemTeamsChannels): Promise { - const sidesheetRef = this.sideSheet.open(TeamChannelDetailsComponent, { - title: await this.translate.get('#LDS#Heading View Microsoft Teams Channel Details').toPromise(), - subTitle: channel.GetEntity().GetDisplay(), - padding: '0px', - width: `max(650px, 60%)`, - icon: 'usergroup', - testId: 'teams-channel-view-team-channel-details', - data: channel - }); - // After the sidesheet closes, reload the current data to refresh any changes that might have been made - sidesheetRef.afterClosed().subscribe(() => this.navigate()); - } -} diff --git a/imxweb/projects/o3t/src/lib/teams/team-details/team-details.component.html b/imxweb/projects/o3t/src/lib/teams/team-details/team-details.component.html deleted file mode 100644 index abaee2a08..000000000 --- a/imxweb/projects/o3t/src/lib/teams/team-details/team-details.component.html +++ /dev/null @@ -1,60 +0,0 @@ -
    - - - -
    - #LDS#Heading Details - - -
    -
    -
    -
    - -
    - -
    -
    -
    - - - - - - - - -
    -
    - - - -
    -
    - -
    - - - - - -
    -
    -
    - -
    - -
    diff --git a/imxweb/projects/o3t/src/lib/teams/team-details/team-details.component.ts b/imxweb/projects/o3t/src/lib/teams/team-details/team-details.component.ts deleted file mode 100644 index ef7bb6d92..000000000 --- a/imxweb/projects/o3t/src/lib/teams/team-details/team-details.component.ts +++ /dev/null @@ -1,140 +0,0 @@ -/* - * ONE IDENTITY LLC. PROPRIETARY INFORMATION - * - * This software is confidential. One Identity, LLC. or one of its affiliates or - * subsidiaries, has supplied this software to you under terms of a - * license agreement, nondisclosure agreement or both. - * - * You may not copy, disclose, or use this software except in accordance with - * those terms. - * - * - * Copyright 2023 One Identity LLC. - * ALL RIGHTS RESERVED. - * - * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR - * WARRANTIES ABOUT THE SUITABILITY OF THE SOFTWARE, - * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED - * TO THE IMPLIED WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE, OR - * NON-INFRINGEMENT. ONE IDENTITY LLC. SHALL NOT BE - * LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE - * AS A RESULT OF USING, MODIFYING OR DISTRIBUTING - * THIS SOFTWARE OR ITS DERIVATIVES. - * - */ - -import { Component, Inject, OnInit } from '@angular/core'; -import { UntypedFormArray, UntypedFormBuilder, UntypedFormGroup } from '@angular/forms'; -import { EuiSidesheetRef, EuiSidesheetService, EUI_SIDESHEET_DATA } from '@elemental-ui/core'; -import { TranslateService } from '@ngx-translate/core'; -import { PortalTargetsystemTeams } from 'imx-api-o3t'; -import { BaseCdr, ColumnDependentReference, SnackBarService } from 'qbm'; -import { GroupSidesheetComponent, GroupSidesheetData, GroupsService } from 'tsb'; -import { TeamsService } from '../teams.service'; - -@Component({ - selector: 'imx-team-details', - templateUrl: './team-details.component.html' -}) -export class TeamDetailsComponent implements OnInit { - public readonly formGroup: UntypedFormGroup; - public cdrList: ColumnDependentReference[] = []; - - constructor( - formBuilder: UntypedFormBuilder, - @Inject(EUI_SIDESHEET_DATA) public team: PortalTargetsystemTeams, - private teamsService: TeamsService, - private readonly sidesheet: EuiSidesheetService, - private readonly sidesheetRef: EuiSidesheetRef, - private readonly groupsService: GroupsService, - private readonly snackbar: SnackBarService, - private readonly translate: TranslateService - ) { - this.formGroup = new UntypedFormGroup({ formArray: formBuilder.array([]) }); - } - - get formArray(): UntypedFormArray { - return this.formGroup.get('formArray') as UntypedFormArray; - } - - get teamId(): string { - return this.team?.GetEntity().GetKeys().join(''); - } - - public ngOnInit(): void { - this.setup(); - } - - public async saveChanges(): Promise { - this.teamsService.handleOpenLoader(); - try { - this.team.GetEntity().Commit(true); - this.formGroup.markAsPristine(); - this.snackbar.open({ key: '#LDS#Your changes have been successfully saved.' }); - } finally { - this.teamsService.handleCloseLoader(); - } - } - - public cancel(): void { - this.sidesheetRef.close(); - } - - public async viewGroup(): Promise { - - let data: GroupSidesheetData; - this.teamsService.handleOpenLoader(); - try { - const unsGroupDbObjectKey: any = { TableName: 'O3EUnifiedGroup', Keys: [this.team.UID_O3EUnifiedGroup.value] }; - const o3tGroup = await this.groupsService.getGroupDetails(unsGroupDbObjectKey); - const uidAccProduct = o3tGroup?.GetEntity().GetColumn('UID_AccProduct').GetValue(); - const serviceItem = await this.groupsService.getGroupServiceItem(uidAccProduct); - - data = { - uidAccProduct, - unsGroupDbObjectKey, - group: o3tGroup, - groupServiceItem: serviceItem - }; - } finally { - this.teamsService.handleCloseLoader(); - } - - this.openGroupSidesheet(data); - } - - private async openGroupSidesheet(data: GroupSidesheetData): Promise { - this.sidesheet.open(GroupSidesheetComponent, { - title: await this.translate.get('#LDS#Heading Edit System Entitlement').toPromise(), - subTitle: this.team.GetEntity().GetDisplay(), - padding: '0px', - width: 'max(650px, 60%)', - icon: 'usergroup', - testId: 'teams-details-view-group-details', - data - }); - } - - private setup(): void { - this.cdrList = [ - new BaseCdr(this.team.tmsAllowDeleteChannels.Column), - new BaseCdr(this.team.tmsAllowCreateUpdateRemoveTabs.Column), - new BaseCdr(this.team.tmsAllowCreateUpdateRemoveConn.Column), - new BaseCdr(this.team.tmsAllowCreateUpdateChannels.Column), - new BaseCdr(this.team.tmsAllowAddRemoveApps.Column), - new BaseCdr(this.team.msAllowUserEditMessages.Column), - new BaseCdr(this.team.msAllowUserDeleteMessages.Column), - new BaseCdr(this.team.msAllowTeamMentions.Column), - new BaseCdr(this.team.msAllowOwnerDeleteMessages.Column), - new BaseCdr(this.team.msAllowChannelMentions.Column), - new BaseCdr(this.team.gsAllowDeleteChannels.Column), - new BaseCdr(this.team.IsArchived.Column), - new BaseCdr(this.team.gsAllowCreateUpdateChannels.Column), - new BaseCdr(this.team.fsGiphyContentRating.Column), - new BaseCdr(this.team.fsAllowStickersAndMemes.Column), - new BaseCdr(this.team.fsAllowGiphy.Column), - new BaseCdr(this.team.fsAllowCustomMemes.Column) - ]; - } -} diff --git a/imxweb/projects/o3t/src/lib/teams/teams.component.html b/imxweb/projects/o3t/src/lib/teams/teams.component.html deleted file mode 100644 index 3a5d7f833..000000000 --- a/imxweb/projects/o3t/src/lib/teams/teams.component.html +++ /dev/null @@ -1,42 +0,0 @@ - - -
    -
    - - #LDS#Heading Teams -
    -
    - - - - -
    - - - - - - - - - - - - -
    - - -
    diff --git a/imxweb/projects/o3t/src/lib/teams/teams.component.ts b/imxweb/projects/o3t/src/lib/teams/teams.component.ts deleted file mode 100644 index 9b4802ac4..000000000 --- a/imxweb/projects/o3t/src/lib/teams/teams.component.ts +++ /dev/null @@ -1,123 +0,0 @@ -/* - * ONE IDENTITY LLC. PROPRIETARY INFORMATION - * - * This software is confidential. One Identity, LLC. or one of its affiliates or - * subsidiaries, has supplied this software to you under terms of a - * license agreement, nondisclosure agreement or both. - * - * You may not copy, disclose, or use this software except in accordance with - * those terms. - * - * - * Copyright 2023 One Identity LLC. - * ALL RIGHTS RESERVED. - * - * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR - * WARRANTIES ABOUT THE SUITABILITY OF THE SOFTWARE, - * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED - * TO THE IMPLIED WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE, OR - * NON-INFRINGEMENT. ONE IDENTITY LLC. SHALL NOT BE - * LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE - * AS A RESULT OF USING, MODIFYING OR DISTRIBUTING - * THIS SOFTWARE OR ITS DERIVATIVES. - * - */ - -import { Component, Input, OnInit } from '@angular/core'; -import { EuiSidesheetService } from '@elemental-ui/core'; -import { TranslateService } from '@ngx-translate/core'; -import { PortalTargetsystemTeams } from 'imx-api-o3t'; -import { CollectionLoadParameters, DisplayColumns, EntitySchema, IClientProperty } from 'imx-qbm-dbts'; -import { ClassloggerService, DataSourceToolbarFilter, DataSourceToolbarSettings, SettingsService } from 'qbm'; -import { TeamDetailsComponent } from './team-details/team-details.component'; -import { TeamsService } from './teams.service'; - -@Component({ - selector: 'imx-o3t-teams', - templateUrl: './teams.component.html' -}) -export class TeamsComponent implements OnInit { - - @Input() public sidesheetWidth = '65%'; - public dstSettings: DataSourceToolbarSettings; - public navigationState: CollectionLoadParameters; - public filterOptions: DataSourceToolbarFilter[] = []; - public readonly entitySchemaTeams: EntitySchema; - public readonly DisplayColumns = DisplayColumns; - - private displayedColumns: IClientProperty[] = []; - - constructor( - private readonly sideSheet: EuiSidesheetService, - private readonly logger: ClassloggerService, - settingsService: SettingsService, - private readonly teamsService: TeamsService, - private readonly translate: TranslateService - ) { - this.navigationState = { PageSize: settingsService.DefaultPageSize, StartIndex: 0 }; - this.entitySchemaTeams = this.teamsService.teamsSchema; - } - - public async ngOnInit(): Promise { - this.displayedColumns = [ - this.entitySchemaTeams.Columns[DisplayColumns.DISPLAY_PROPERTYNAME], - this.entitySchemaTeams.Columns.UID_O3EUnifiedGroup, - this.entitySchemaTeams.Columns.WebUrl, - ]; - - await this.navigate(); - } - - public async onNavigationStateChanged(newState?: CollectionLoadParameters): Promise { - if (newState) { - this.navigationState = newState; - } - await this.navigate(); - } - - public async onSearch(keywords: string): Promise { - this.logger.debug(this, `Searching for: ${keywords}`); - this.navigationState.StartIndex = 0; - this.navigationState.search = keywords; - await this.navigate(); - } - - public async onTeamChanged(team: PortalTargetsystemTeams): Promise { - this.logger.debug(this, `Selected team changed`); - this.logger.trace(this, `New team selected`, team); - - this.openDetailsSidesheet(team); - } - - private async navigate(): Promise { - - this.teamsService.handleOpenLoader(); - try { - const data = await this.teamsService.getTeams(this.navigationState); - this.dstSettings = { - displayedColumns: this.displayedColumns, - dataSource: data, - entitySchema: this.entitySchemaTeams, - navigationState: this.navigationState, - filters: this.filterOptions, - }; - this.logger.debug(this, `Head at ${data.Data.length + this.navigationState.StartIndex} of ${data.totalCount} item(s)`); - } finally { - this.teamsService.handleCloseLoader(); - } - } - - private async openDetailsSidesheet( data: PortalTargetsystemTeams): Promise { - const sidesheetRef = this.sideSheet.open(TeamDetailsComponent, { - title: await this.translate.get('#LDS#Heading View Microsoft Teams Team Details').toPromise(), - subTitle: data.GetEntity().GetDisplay(), - padding: '0px', - width: `max(650px, ${this.sidesheetWidth})`, - icon: 'usergroup', - testId: 'teams-view-team-details', - data - }); - sidesheetRef.afterClosed().subscribe(() => this.navigate()); - } -} diff --git a/imxweb/projects/o3t/src/lib/teams/teams.service.ts b/imxweb/projects/o3t/src/lib/teams/teams.service.ts deleted file mode 100644 index 56976cd99..000000000 --- a/imxweb/projects/o3t/src/lib/teams/teams.service.ts +++ /dev/null @@ -1,75 +0,0 @@ -/* - * ONE IDENTITY LLC. PROPRIETARY INFORMATION - * - * This software is confidential. One Identity, LLC. or one of its affiliates or - * subsidiaries, has supplied this software to you under terms of a - * license agreement, nondisclosure agreement or both. - * - * You may not copy, disclose, or use this software except in accordance with - * those terms. - * - * - * Copyright 2023 One Identity LLC. - * ALL RIGHTS RESERVED. - * - * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR - * WARRANTIES ABOUT THE SUITABILITY OF THE SOFTWARE, - * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED - * TO THE IMPLIED WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE, OR - * NON-INFRINGEMENT. ONE IDENTITY LLC. SHALL NOT BE - * LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE - * AS A RESULT OF USING, MODIFYING OR DISTRIBUTING - * THIS SOFTWARE OR ITS DERIVATIVES. - * - */ - -import { Injectable } from '@angular/core'; -import { ApiService } from '../api.service'; -import { PortalTargetsystemTeams, PortalTargetsystemTeamsChannels } from 'imx-api-o3t'; -import { CollectionLoadParameters, EntitySchema, TypedEntityCollectionData } from 'imx-qbm-dbts'; -import { OverlayRef } from '@angular/cdk/overlay'; -import { EuiLoadingService } from '@elemental-ui/core'; - -@Injectable({ - providedIn: 'root', -}) -export class TeamsService { - private busyIndicator: OverlayRef; - - constructor(private readonly o3tApiClient: ApiService, private readonly busyService: EuiLoadingService) {} - - public get teamsSchema(): EntitySchema { - return this.o3tApiClient.typedClient.PortalTargetsystemTeams.GetSchema(); - } - - public get teamChannelsSchema(): EntitySchema { - return this.o3tApiClient.typedClient.PortalTargetsystemTeamsChannels.GetSchema(); - } - - public async getTeams(navigationState: CollectionLoadParameters): Promise> { - return this.o3tApiClient.typedClient.PortalTargetsystemTeams.Get(navigationState); - } - - public async getTeamChannels( - uidO3tTeam: string, - navigationState: CollectionLoadParameters - ): Promise> { - return this.o3tApiClient.typedClient.PortalTargetsystemTeamsChannels.Get(uidO3tTeam, navigationState); - } - - public handleOpenLoader(): void { - if (!this.busyIndicator) { - this.busyIndicator = this.busyService.show(); - } - } - - public handleCloseLoader(): void { - if (this.busyIndicator) { - setTimeout(() => { - this.busyService.hide(this.busyIndicator); - this.busyIndicator = undefined; - }); - } - } -} diff --git a/imxweb/projects/o3t/src/test/o3t-common-test-mocks.ts b/imxweb/projects/o3t/src/test/o3t-common-test-mocks.ts deleted file mode 100644 index df47453a2..000000000 --- a/imxweb/projects/o3t/src/test/o3t-common-test-mocks.ts +++ /dev/null @@ -1,165 +0,0 @@ -/* - * ONE IDENTITY LLC. PROPRIETARY INFORMATION - * - * This software is confidential. One Identity, LLC. or one of its affiliates or - * subsidiaries, has supplied this software to you under terms of a - * license agreement, nondisclosure agreement or both. - * - * You may not copy, disclose, or use this software except in accordance with - * those terms. - * - * - * Copyright 2023 One Identity LLC. - * ALL RIGHTS RESERVED. - * - * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR - * WARRANTIES ABOUT THE SUITABILITY OF THE SOFTWARE, - * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED - * TO THE IMPLIED WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE, OR - * NON-INFRINGEMENT. ONE IDENTITY LLC. SHALL NOT BE - * LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE - * AS A RESULT OF USING, MODIFYING OR DISTRIBUTING - * THIS SOFTWARE OR ITS DERIVATIVES. - * - */ - -import { PortalTargetsystemTeams } from 'imx-api-o3t'; -import { IEntityColumn, IEntity } from 'imx-qbm-dbts'; -import { ISessionState } from 'qbm'; -import { Subject } from 'rxjs'; - -export class O3tCommonTestData { - - public static mockConfigService: any = { - getConfig: () => { - return Promise.resolve({ - PersonConfig: { - VI_MyData_WhitePages_ResultAttributes: { - Columns: ['col1', 'col2'] - }, - VI_PersonalData_Fields: { - Columns: ['col1', 'col2'] - } - } - }); - } - }; - - public static mockAppConfigService: any = { - Config: { - Title: '', - routeConfig: { - start: 'dashboard' - } - }, - client: { - imx_multilanguage_getcaptions_get: () => Promise.resolve({}), - imx_multilanguage_translations_get: () => Promise.resolve({}) - } - }; - - public static mockAuthenticationServiceStub = { - onSessionResponse: new Subject(), - update: jasmine.createSpy('update') - }; - - public static mockSessionService: any = { - TypedClient: { - PortalTargetsystemUnsGroup: { - Get: () => Promise.resolve({}) - }, - PortalTargetsystemUnsAccount: { - Get: () => Promise.resolve({}) - }, - PortalPersonAll: { - Get: () => Promise.resolve({}) - }, - PortalAdminPerson: { - Get: () => Promise.resolve({}) - }, - PortalPerson: { - Get: () => Promise.resolve({Data: ['test1', 'test2']}) - }, - } - }; - - public static teamSchemaMock: any = { - Columns: { - __Display: {}, - UID_O3EUnifiedGroup: {}, - WebUrl: {} - } - }; - - public static teamChannelSchemaMock: any = { - Columns: { - DisplayName: {}, - Description: {}, - WebUrl: {} - } - }; - - public static mockTeamsService = { - teamsSchema: O3tCommonTestData.teamSchemaMock, - teamChannelsSchema: O3tCommonTestData.teamChannelSchemaMock, - getTeams: jasmine.createSpy('getTeams').and.returnValue(Promise.resolve({ Data: []})), - getTeamChannels: jasmine.createSpy('getTeamChannels').and.returnValue(Promise.resolve({ Data: []})), - handleOpenLoader: jasmine.createSpy('handleOpenLoader'), - handleCloseLoader: jasmine.createSpy('handleCloseLoader'), - }; - - public static mockEntityColumn = { - ColumnName: '', - GetMetadata: () => { - return { - CanEdit: () => false, - GetDisplay: () => '', - GetMinLength: () => 0 - }; - }, - GetValue: () => '' - - } as IEntityColumn; - - public static mockEntityColumnWithValue = { - ColumnName: '', - GetMetadata: () => { - return { - CanEdit: () => false, - GetDisplay: () => '', - GetMinLength: () => 0 - }; - }, - GetValue: () => 'Test value 1' - - } as IEntityColumn; - - public static mockEntity = { - GetDisplay: () => 'Display value', - GetKeys: () => ['1'], - GetColumn: (name) => O3tCommonTestData.mockEntityColumn, - Commit: () => Promise.resolve() - } as IEntity; - - public static mockTeam = { - GetEntity: () => O3tCommonTestData.mockEntity, - tmsAllowDeleteChannels: { Column: O3tCommonTestData.mockEntityColumn }, - tmsAllowCreateUpdateRemoveTabs: { Column: O3tCommonTestData.mockEntityColumn }, - tmsAllowCreateUpdateRemoveConn: { Column: O3tCommonTestData.mockEntityColumn }, - tmsAllowCreateUpdateChannels: { Column: O3tCommonTestData.mockEntityColumn }, - tmsAllowAddRemoveApps: { Column: O3tCommonTestData.mockEntityColumn }, - msAllowUserEditMessages: { Column: O3tCommonTestData.mockEntityColumn }, - msAllowUserDeleteMessages: { Column: O3tCommonTestData.mockEntityColumn }, - msAllowTeamMentions: { Column: O3tCommonTestData.mockEntityColumn }, - msAllowOwnerDeleteMessages: { Column: O3tCommonTestData.mockEntityColumn }, - msAllowChannelMentions: { Column: O3tCommonTestData.mockEntityColumn }, - gsAllowDeleteChannels: { Column: O3tCommonTestData.mockEntityColumn }, - IsArchived: { Column: O3tCommonTestData.mockEntityColumn }, - gsAllowCreateUpdateChannels: { Column: O3tCommonTestData.mockEntityColumn }, - fsGiphyContentRating: { Column: O3tCommonTestData.mockEntityColumn }, - fsAllowStickersAndMemes: { Column: O3tCommonTestData.mockEntityColumn }, - fsAllowGiphy: { Column: O3tCommonTestData.mockEntityColumn }, - fsAllowCustomMemes: { Column: O3tCommonTestData.mockEntityColumn }, - } as PortalTargetsystemTeams; -} diff --git a/imxweb/projects/o3t/tslint.json b/imxweb/projects/o3t/tslint.json deleted file mode 100644 index 8bab15f53..000000000 --- a/imxweb/projects/o3t/tslint.json +++ /dev/null @@ -1,17 +0,0 @@ -{ - "extends": "../../tslint.json", - "rules": { - "directive-selector": [ - true, - "attribute", - "imx", - "camelCase" - ], - "component-selector": [ - true, - "element", - "imx", - "kebab-case" - ] - } -} diff --git a/imxweb/projects/olg/.compodocrc.json b/imxweb/projects/olg/.compodocrc.json index 9919bd6cc..2163ad64a 100644 --- a/imxweb/projects/olg/.compodocrc.json +++ b/imxweb/projects/olg/.compodocrc.json @@ -1,6 +1,6 @@ { "name": "IMX Web - olg Library", - "output": "../../documentation/v92/olg", + "output": "../../documentation/v93/olg", "theme": "material", "assetsFolder": "../../compodoc/assets", "customLogo": "../../compodoc/assets/images/oneidentity-logo.png", diff --git a/imxweb/projects/olg/.eslintrc.json b/imxweb/projects/olg/.eslintrc.json new file mode 100644 index 000000000..627c6270d --- /dev/null +++ b/imxweb/projects/olg/.eslintrc.json @@ -0,0 +1,35 @@ +{ + "extends": "../../.eslintrc.json", + "ignorePatterns": ["!**/*", "**/*.spec.ts"], + "overrides": [ + { + "files": ["*.ts"], + "parserOptions": { + "project": ["imxweb/projects/olg/tsconfig.lib.json", "imxweb/projects/olg/tsconfig.spec.json"], + "createDefaultProgram": true + }, + "rules": { + "@angular-eslint/directive-selector": [ + "error", + { + "type": "attribute", + "prefix": "imx", + "style": "camelCase" + } + ], + "@angular-eslint/component-selector": [ + "error", + { + "type": "element", + "prefix": "imx", + "style": "kebab-case" + } + ] + } + }, + { + "files": ["*.html"], + "rules": {} + } + ] +} diff --git a/imxweb/projects/olg/imx-plugin-config.json b/imxweb/projects/olg/imx-plugin-config.json index db07225b9..29f9d31b6 100644 --- a/imxweb/projects/olg/imx-plugin-config.json +++ b/imxweb/projects/olg/imx-plugin-config.json @@ -5,4 +5,4 @@ "Name": "OlgConfigModule" } ] -} \ No newline at end of file +} diff --git a/imxweb/projects/olg/karma.conf.js b/imxweb/projects/olg/karma.conf.js index 211193c9d..3e53a3ac8 100644 --- a/imxweb/projects/olg/karma.conf.js +++ b/imxweb/projects/olg/karma.conf.js @@ -15,7 +15,7 @@ module.exports = function (config) { require('karma-junit-reporter'), ], client: { - clearContext: false // leave Jasmine Spec Runner output visible in browser + clearContext: false, // leave Jasmine Spec Runner output visible in browser }, coverageIstanbulReporter: { dir: require('path').join(__dirname, 'results'), @@ -23,7 +23,7 @@ module.exports = function (config) { fixWebpackSourcePaths: true, 'report-config': { html: { - subdir: 'coverage-html' + subdir: 'coverage-html', }, }, thresholds: { @@ -40,13 +40,14 @@ module.exports = function (config) { port: 9876, captureTimeout: 210000, browserDisconnectTolerance: 3, - browserDisconnectTimeout : 210000, - browserNoActivityTimeout : 210000, + browserDisconnectTimeout: 210000, + browserNoActivityTimeout: 210000, colors: true, logLevel: config.LOG_INFO, autoWatch: true, browsers: ['Chrome'], singleRun: false, - restartOnFileChange: true + failOnEmptyTestSuite: false, + restartOnFileChange: true, }); }; diff --git a/imxweb/projects/olg/ng-package.dynamic.json b/imxweb/projects/olg/ng-package.dynamic.json index f45879d9f..7b54797e4 100644 --- a/imxweb/projects/olg/ng-package.dynamic.json +++ b/imxweb/projects/olg/ng-package.dynamic.json @@ -16,12 +16,11 @@ "@elemental-ui/core", "@ngx-translate/core", "@ngx-translate/http-loader", - "applicationinsights-js", "billboard.js" ], - "dest": "../../html/olg", + "dest": "../../html/qer-app-portal/olg", "lib": { "entryFile": "src/public_api.ts", - "styleIncludePaths": ["../../shared/assets"] + "styleIncludePaths": ["../../shared/scss"] } } diff --git a/imxweb/projects/olg/ng-package.json b/imxweb/projects/olg/ng-package.json index b529b1d33..311edcb17 100644 --- a/imxweb/projects/olg/ng-package.json +++ b/imxweb/projects/olg/ng-package.json @@ -3,6 +3,6 @@ "dest": "../../dist/olg", "lib": { "entryFile": "src/public_api.ts", - "styleIncludePaths": ["../../shared/assets"] + "styleIncludePaths": ["../../shared/scss"] } } diff --git a/imxweb/projects/olg/package.json b/imxweb/projects/olg/package.json index 020943ccb..d2a3b1fca 100644 --- a/imxweb/projects/olg/package.json +++ b/imxweb/projects/olg/package.json @@ -1,6 +1,6 @@ { "name": "olg", - "version": "9.2.1", + "version": "9.3.0", "private": true, "bundledDependencies": [ "imx-api-olg" diff --git a/imxweb/projects/olg/project.json b/imxweb/projects/olg/project.json new file mode 100644 index 000000000..cd78c3518 --- /dev/null +++ b/imxweb/projects/olg/project.json @@ -0,0 +1,65 @@ +{ + "$schema": "../../node_modules/nx/schemas/project-schema.json", + "name": "olg", + "sourceRoot": "projects/olg/src", + "implicitDependencies": ["qer"], + "projectType": "library", + "generators": { + "@schematics/angular:component": { + "style": "scss" + } + }, + "prefix": "imx", + "targets": { + "build": { + "executor": "@angular-devkit/build-angular:ng-packagr", + "options": { + "tsConfig": "projects/olg/tsconfig.lib.json", + "project": "projects/olg/ng-package.json" + }, + "configurations": { + "production": { + "tsConfig": "projects/olg/tsconfig.lib.prod.json" + }, + "development": { + "tsConfig": "projects/olg/tsconfig.lib.json" + }, + "dynamic": { + "project": "projects/olg/ng-package.dynamic.json" + }, + "remote-dev": { + "tsConfig": "projects/olg/tsconfig.lib.json" + }, + "remote-qs": { + "tsConfig": "projects/olg/tsconfig.lib.json" + } + }, + "outputs": ["{workspaceRoot}/dist/olg"] + }, + "test": { + "executor": "@angular-devkit/build-angular:karma", + "options": { + "main": "projects/olg/src/test.ts", + "tsConfig": "projects/olg/tsconfig.spec.json", + "karmaConfig": "projects/olg/karma.conf.js", + "codeCoverageExclude": ["projects/olg/src/**/test/*"], + "stylePreprocessorOptions": { + "includePaths": [ + "./shared/assets", + "./shared/scss", + "./node_modules", + "./node_modules/@elemental-ui/cadence-icon", + "./node_modules/@elemental-ui/core" + ] + } + } + }, + "lint": { + "executor": "@angular-devkit/build-angular:tslint", + "options": { + "tsConfig": ["projects/olg/tsconfig.lib.json", "projects/olg/tsconfig.spec.json"], + "exclude": ["**/node_modules/**", "**/*.spec.ts", "**/*.json"] + } + } + } +} diff --git a/imxweb/projects/olg/src/lib/init.service.spec.ts b/imxweb/projects/olg/src/lib/init.service.spec.ts index 976ceb3c9..f5eeea165 100644 --- a/imxweb/projects/olg/src/lib/init.service.spec.ts +++ b/imxweb/projects/olg/src/lib/init.service.spec.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR diff --git a/imxweb/projects/olg/src/lib/init.service.ts b/imxweb/projects/olg/src/lib/init.service.ts index 6c3cd6684..f67ccc39b 100644 --- a/imxweb/projects/olg/src/lib/init.service.ts +++ b/imxweb/projects/olg/src/lib/init.service.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -34,7 +34,10 @@ import { MfaFormControlComponent } from './mfa-form-control/mfa-form-control.com providedIn: 'root', }) export class InitService { - constructor(private readonly extService: ExtService, private readonly router: Router) {} + constructor( + private readonly extService: ExtService, + private readonly router: Router, + ) {} public onInit(routes: Route[]): void { this.addRoutes(routes); @@ -42,7 +45,7 @@ export class InitService { this.extService.register('mfaComponent', { instance: MfaComponent, }); - + this.extService.register('authenticator', { instance: MfaFormControlComponent, }); diff --git a/imxweb/projects/olg/src/lib/mfa-form-control/mfa-form-control.component.html b/imxweb/projects/olg/src/lib/mfa-form-control/mfa-form-control.component.html index 34b0fc872..46beae954 100644 --- a/imxweb/projects/olg/src/lib/mfa-form-control/mfa-form-control.component.html +++ b/imxweb/projects/olg/src/lib/mfa-form-control/mfa-form-control.component.html @@ -8,12 +8,16 @@

    {{ '#LDS#To authenticate, use the one-time password.' | translate }}

    - {{ '#LDS#To authenticate, use either the push notification or the one-time password of your OneLogin Protector app.' | translate }} + {{ + '#LDS#To authenticate, use either the push notification or the one-time password of your OneLogin Protector app.' | translate + }} +

    +

    + {{ '#LDS#To authenticate, use the one-time password of your authentication app.' | translate }}

    -

    {{ '#LDS#To authenticate, use the one-time password of your authentication app.' | translate }}

    - +

    {{ info.authMessage | translate }}

    @@ -26,17 +30,17 @@ > {{ '#LDS#Use authentication method' | translate }} - +
    @@ -18,7 +23,10 @@
    - +
    @@ -26,7 +34,10 @@
    - +
    @@ -41,7 +52,11 @@
    - + +
    diff --git a/imxweb/projects/pol/src/lib/policies/policies-sidesheet/policies-sidesheet.component.scss b/imxweb/projects/pol/src/lib/policies/policies-sidesheet/policies-sidesheet.component.scss deleted file mode 100644 index 886de866f..000000000 --- a/imxweb/projects/pol/src/lib/policies/policies-sidesheet/policies-sidesheet.component.scss +++ /dev/null @@ -1,48 +0,0 @@ -@import "@elemental-ui/core/src/styles/_palette.scss"; - -:host { - .mat-tab-group, ::ng-deep .mat-tab-body-wrapper { - height: 100%; - } - - ::ng-deep .mat-tab-body-content { - display: flex; - flex-direction: column; - justify-content: space-between; - } - - .imx-mat-tab-container { - padding: 20px; - display: flex; - flex-direction: column; - overflow: auto; - } -} - -.eui-sidesheet-actions { - .justify-start { - margin-right: auto; - } -} - -:host { - ::ng-deep .mat-tab-labels { - background-color: $color-gray-0; - } -} - -.eui-dark-theme { - :host { - ::ng-deep .mat-tab-labels { - background-color: $color-gray-80; - } - } -} - -.eui-contrast-theme { - :host { - ::ng-deep .mat-tab-labels { - background-color: $color-gray-100; - } - } -} diff --git a/imxweb/projects/pol/src/lib/policies/policies-sidesheet/policies-sidesheet.component.ts b/imxweb/projects/pol/src/lib/policies/policies-sidesheet/policies-sidesheet.component.ts index 61345423a..fb4e0c31e 100644 --- a/imxweb/projects/pol/src/lib/policies/policies-sidesheet/policies-sidesheet.component.ts +++ b/imxweb/projects/pol/src/lib/policies/policies-sidesheet/policies-sidesheet.component.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -25,18 +25,17 @@ */ import { Component, Inject, OnDestroy } from '@angular/core'; -import { EuiDownloadOptions, EuiSidesheetRef, EUI_SIDESHEET_DATA } from '@elemental-ui/core'; +import { EUI_SIDESHEET_DATA, EuiDownloadOptions, EuiSidesheetRef } from '@elemental-ui/core'; import { Subscription } from 'rxjs'; -import { PortalPolicies } from 'imx-api-pol'; -import { DisplayColumns } from 'imx-qbm-dbts'; +import { PortalPolicies } from '@imx-modules/imx-api-pol'; +import { DisplayColumns } from '@imx-modules/imx-qbm-dbts'; import { BaseReadonlyCdr, ColumnDependentReference, ElementalUiConfigService } from 'qbm'; import { PoliciesService } from '../policies.service'; @Component({ selector: 'imx-policies-sidesheet', templateUrl: './policies-sidesheet.component.html', - styleUrls: ['./policies-sidesheet.component.scss'], }) export class PoliciesSidesheetComponent implements OnDestroy { public reportDownload: EuiDownloadOptions; @@ -55,7 +54,7 @@ export class PoliciesSidesheetComponent implements OnDestroy { }, public sidesheetRef: EuiSidesheetRef, private readonly policiesProvider: PoliciesService, - elementalUiConfigService: ElementalUiConfigService + elementalUiConfigService: ElementalUiConfigService, ) { this.uidCompliance = data.selectedPolicy.GetEntity().GetKeys().join(','); this.cdrList = [ @@ -63,13 +62,16 @@ export class PoliciesSidesheetComponent implements OnDestroy { new BaseReadonlyCdr(this.data.selectedPolicy.Description.Column), new BaseReadonlyCdr(this.data.selectedPolicy.IsExceptionAllowed.Column), new BaseReadonlyCdr(this.data.selectedPolicy.IsInActive.Column), - data.hasRiskIndex ? new BaseReadonlyCdr(this.data.selectedPolicy.RiskIndex.Column) : null, new BaseReadonlyCdr(this.data.selectedPolicy.RuleSeverity.Column), new BaseReadonlyCdr(this.data.selectedPolicy.RuleViolationThreshold.Column), new BaseReadonlyCdr(this.data.selectedPolicy.SignificancyClass.Column), new BaseReadonlyCdr(this.data.selectedPolicy.TransparencyIndex.Column), new BaseReadonlyCdr(this.data.selectedPolicy.UID_QERPolicyGroup.Column), - ].filter((elem) => elem != null); + ]; + if (data.hasRiskIndex) { + // Stick this in position 4 + this.cdrList.splice(4, 0, new BaseReadonlyCdr(this.data.selectedPolicy.RiskIndex.Column)); + } this.reportDownload = { ...elementalUiConfigService.Config.downloadOptions, diff --git a/imxweb/projects/pol/src/lib/policies/policies.component.html b/imxweb/projects/pol/src/lib/policies/policies.component.html index 49f9e55e0..d83e4b4b7 100644 --- a/imxweb/projects/pol/src/lib/policies/policies.component.html +++ b/imxweb/projects/pol/src/lib/policies/policies.component.html @@ -1,41 +1,52 @@ -

    - {{ '#LDS#Heading Company Policies' | translate }} - -

    - +
    +

    + {{ '#LDS#Heading Company Policies' | translate }} + +

    + +
    +
    - - -
    - - - -
    -
    -
    {{ item.GetEntity().GetDisplay() }}
    -
    {{ item.Description.Column.GetDisplayValue() }}
    -
    - {{ '#LDS#Deactivated' | translate }} + + + + {{ policySchema?.Columns?.[DisplayColumns.DISPLAY_PROPERTYNAME]?.Display }} + + +
    +
    +
    {{ item.GetEntity().GetDisplay() }}
    +
    {{ item.Description.Column.GetDisplayValue() }}
    - - - - - - {{ policy.CountOpen.value + policy.CountClosed.value }} - - - - - -
    - + {{ '#LDS#Deactivated' | translate }} +
    + + + + + + {{ '#LDS#Policy violations' | translate }} + + + + + {{ item.CountOpen.value + item.CountClosed.value }} + + + + + + + {{ policySchema?.Columns?.CountOpen?.Display }} + + + + + {{ item.CountOpen.Column.GetDisplayValue() }} + + + + +
    diff --git a/imxweb/projects/pol/src/lib/policies/policies.component.scss b/imxweb/projects/pol/src/lib/policies/policies.component.scss index ffe8c184e..826e8b1b2 100644 --- a/imxweb/projects/pol/src/lib/policies/policies.component.scss +++ b/imxweb/projects/pol/src/lib/policies/policies.component.scss @@ -1,4 +1,4 @@ -@import "@elemental-ui/core/src/styles/_palette.scss"; +@import '@elemental-ui/core/src/styles/_palette.scss'; div[subtitle] { font-size: smaller; @@ -10,31 +10,16 @@ div[subtitle] { flex-direction: column; overflow: hidden; height: inherit; - - .mat-card { - flex: 1 1 auto ; - display: flex; - flex-direction: column; - overflow: hidden; - margin: 3px; - } -} - -.imx-table-container { - display: flex; - flex-direction: column; - overflow: hidden; - flex: 1 1 auto; } .imx-display-column { - display: flex; - flex-direction: row; - - :first-child { - flex: 1 1 auto; + width: 100% !important; + cursor: inherit !important; + &-main { + flex: 1 1 auto; + display: block !important; + cursor: inherit !important; } - .imx-badge { align-self: flex-end; } diff --git a/imxweb/projects/pol/src/lib/policies/policies.component.ts b/imxweb/projects/pol/src/lib/policies/policies.component.ts index fe15744cd..a8d393da2 100644 --- a/imxweb/projects/pol/src/lib/policies/policies.component.ts +++ b/imxweb/projects/pol/src/lib/policies/policies.component.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -25,29 +25,45 @@ */ import { Component, OnInit } from '@angular/core'; -import { PortalPolicies } from 'imx-api-pol'; -import { CollectionLoadParameters, DisplayColumns, EntitySchema, ValType } from 'imx-qbm-dbts'; -import { BusyService, ClientPropertyForTableColumns, DataSourceToolbarFilter, DataSourceToolbarSettings, SystemInfoService } from 'qbm'; -import { PolicyParameter } from './policy-parameter'; -import { PoliciesService } from './policies.service'; import { EuiLoadingService, EuiSidesheetService } from '@elemental-ui/core'; +import { PortalPolicies } from '@imx-modules/imx-api-pol'; +import { + CollectionLoadParameters, + DataModel, + DisplayColumns, + EntitySchema, + TypedEntityCollectionData, + ValType, +} from '@imx-modules/imx-qbm-dbts'; import { TranslateService } from '@ngx-translate/core'; +import { + BusyService, + ClientPropertyForTableColumns, + DataSourceToolbarFilter, + DataSourceToolbarSettings, + DataViewInitParameters, + DataViewSource, + SystemInfoService, + calculateSidesheetWidth, +} from 'qbm'; import { PoliciesSidesheetComponent } from './policies-sidesheet/policies-sidesheet.component'; +import { PoliciesService } from './policies.service'; @Component({ selector: 'imx-policies', templateUrl: './policies.component.html', styleUrls: ['./policies.component.scss'], + providers: [DataViewSource], }) export class PoliciesComponent implements OnInit { public dstSettings: DataSourceToolbarSettings; public readonly DisplayColumns = DisplayColumns; public policySchema: EntitySchema; public busyService = new BusyService(); + public dataModel: DataModel; private displayedColumns: ClientPropertyForTableColumns[] = []; private filterOptions: DataSourceToolbarFilter[] = []; - private navigationState: PolicyParameter = {}; private isMControlPerViolation: boolean; constructor( @@ -55,7 +71,8 @@ export class PoliciesComponent implements OnInit { private readonly sideSheetService: EuiSidesheetService, private readonly systemInfoService: SystemInfoService, private readonly translate: TranslateService, - private readonly euiBusysService: EuiLoadingService + private readonly euiBusysService: EuiLoadingService, + public dataSource: DataViewSource, ) { this.policySchema = policiesProvider.policySchema; this.displayedColumns = [ @@ -71,32 +88,26 @@ export class PoliciesComponent implements OnInit { public async ngOnInit(): Promise { this.euiBusysService.show(); try { - this.filterOptions = (await this.policiesProvider.getDataModel()).Filters; + this.dataModel = await this.policiesProvider.getDataModel(); this.isMControlPerViolation = (await this.policiesProvider.featureConfig()).MitigatingControlsPerViolation; } finally { this.euiBusysService.hide(); } - - const indexActive = this.filterOptions.findIndex((elem) => elem.Name === 'active'); - if (indexActive > -1) { - this.filterOptions[indexActive].InitialValue = '1'; - this.navigationState.active = '1'; - } - await this.navigate({}); + await this.getData(); } public async showDetails(selectedPolicy: PortalPolicies): Promise { - const hasRiskIndex = (await this.systemInfoService.get()).PreProps.includes('RISKINDEX'); + const hasRiskIndex = (await this.systemInfoService.get())?.PreProps?.includes('RISKINDEX'); await this.sideSheetService .open(PoliciesSidesheetComponent, { title: await this.translate.get('#LDS#Heading View Company Policy Details').toPromise(), subTitle: selectedPolicy.GetEntity().GetDisplay(), padding: '0px', - width: 'max(700px, 60%)', + width: calculateSidesheetWidth(700, 0.4), testId: 'policy-details-sidesheet', data: { - selectedPolicy, + selectedPolicy: selectedPolicy as PortalPolicies, hasRiskIndex, isMControlPerViolation: this.isMControlPerViolation, }, @@ -105,22 +116,24 @@ export class PoliciesComponent implements OnInit { .toPromise(); } - public async navigate(parameter: CollectionLoadParameters): Promise { - const isBusy = this.busyService.beginBusy(); - - this.navigationState = { ...this.navigationState, ...parameter }; - - try { - const data = await this.policiesProvider.getPolicies(this.navigationState); - this.dstSettings = { - displayedColumns: this.displayedColumns, - dataSource: data, - entitySchema: this.policySchema, - navigationState: this.navigationState, - filters: this.filterOptions, - }; - } finally { - isBusy.endBusy(); - } + public async getData(): Promise { + this.filterOptions = this.dataModel?.Filters || []; + this.filterOptions.map((filter) => { + if (filter.Name === 'active') { + filter.CurrentValue = '1'; + } + }); + this.dataSource.state.update((state) => ({ ...state, active: '1' })); + const dataViewInitParameters: DataViewInitParameters = { + execute: (params: CollectionLoadParameters, signal: AbortSignal): Promise> => + this.policiesProvider.getPolicies(params, signal), + schema: this.policySchema, + columnsToDisplay: this.displayedColumns, + dataModel: this.dataModel, + highlightEntity: (entity: PortalPolicies) => { + this.showDetails(entity); + }, + }; + this.dataSource.init(dataViewInitParameters); } } diff --git a/imxweb/projects/pol/src/lib/policies/policies.module.ts b/imxweb/projects/pol/src/lib/policies/policies.module.ts index 116d9950a..b89ba0131 100644 --- a/imxweb/projects/pol/src/lib/policies/policies.module.ts +++ b/imxweb/projects/pol/src/lib/policies/policies.module.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -24,28 +24,23 @@ * */ -import { NgModule } from '@angular/core'; import { CommonModule } from '@angular/common'; -import { PoliciesComponent } from './policies.component'; -import { PoliciesSidesheetComponent } from './policies-sidesheet/policies-sidesheet.component'; -import { CdrModule, DataSourceToolbarModule, DataTableModule, HelpContextualModule } from 'qbm'; +import { NgModule } from '@angular/core'; import { MatButtonModule } from '@angular/material/button'; import { MatCardModule } from '@angular/material/card'; -import { TranslateModule } from '@ngx-translate/core'; -import { EuiCoreModule } from '@elemental-ui/core'; +import { MatTableModule } from '@angular/material/table'; import { MatTabsModule } from '@angular/material/tabs'; +import { EuiCoreModule } from '@elemental-ui/core'; +import { TranslateModule } from '@ngx-translate/core'; +import { CdrModule, DataSourceToolbarModule, DataTableModule, DataViewModule, HelpContextualModule } from 'qbm'; import { ObjectHyperviewModule, StatisticsModule } from 'qer'; import { PolicyViolationsModule } from '../policy-violations/policy-violations.module'; import { MitigatingControlsPolicyComponent } from './mitigating-controls-policy/mitigating-controls-policy.component'; - - +import { PoliciesSidesheetComponent } from './policies-sidesheet/policies-sidesheet.component'; +import { PoliciesComponent } from './policies.component'; @NgModule({ - declarations: [ - PoliciesComponent, - PoliciesSidesheetComponent, - MitigatingControlsPolicyComponent, - ], + declarations: [PoliciesComponent, PoliciesSidesheetComponent, MitigatingControlsPolicyComponent], imports: [ CommonModule, EuiCoreModule, @@ -60,6 +55,8 @@ import { MitigatingControlsPolicyComponent } from './mitigating-controls-policy/ ObjectHyperviewModule, HelpContextualModule, PolicyViolationsModule, - ] + DataViewModule, + MatTableModule, + ], }) -export class PoliciesModule { } +export class PoliciesModule {} diff --git a/imxweb/projects/pol/src/lib/policies/policies.service.ts b/imxweb/projects/pol/src/lib/policies/policies.service.ts index cc0652ae8..569440e01 100644 --- a/imxweb/projects/pol/src/lib/policies/policies.service.ts +++ b/imxweb/projects/pol/src/lib/policies/policies.service.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -25,8 +25,8 @@ */ import { Injectable } from '@angular/core'; -import { PolicyConfig, PortalPoliciesMitigatingcontrols, PortalPolicies } from 'imx-api-pol'; -import { CollectionLoadParameters, DataModel, EntitySchema, ExtendedTypedEntityCollection } from 'imx-qbm-dbts'; +import { PolicyConfig, PortalPolicies, PortalPoliciesMitigatingcontrols } from '@imx-modules/imx-api-pol'; +import { CollectionLoadParameters, DataModel, EntitySchema, ExtendedTypedEntityCollection } from '@imx-modules/imx-qbm-dbts'; import { AppConfigService } from 'qbm'; import { ApiService } from '../api.service'; @@ -34,7 +34,10 @@ import { ApiService } from '../api.service'; providedIn: 'root', }) export class PoliciesService { - constructor(private apiservice: ApiService, private appConfig: AppConfigService) {} + constructor( + private apiservice: ApiService, + private appConfig: AppConfigService, + ) {} public get policySchema(): EntitySchema { return this.apiservice.typedClient.PortalPolicies.GetSchema(); @@ -44,8 +47,11 @@ export class PoliciesService { return this.apiservice.client.portal_policy_config_get(); } - public async getPolicies(parameter?: CollectionLoadParameters): Promise> { - return this.apiservice.typedClient.PortalPolicies.Get(parameter); + public async getPolicies( + parameter?: CollectionLoadParameters, + signal?: AbortSignal, + ): Promise> { + return this.apiservice.typedClient.PortalPolicies.Get(parameter, { signal }); } public async getDataModel(): Promise { diff --git a/imxweb/projects/pol/src/lib/policies/policy-parameter.ts b/imxweb/projects/pol/src/lib/policies/policy-parameter.ts index 357f8d702..fee293e1e 100644 --- a/imxweb/projects/pol/src/lib/policies/policy-parameter.ts +++ b/imxweb/projects/pol/src/lib/policies/policy-parameter.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -24,8 +24,8 @@ * */ -import { CollectionLoadParameters } from 'imx-qbm-dbts'; +import { CollectionLoadParameters } from '@imx-modules/imx-qbm-dbts'; -export interface PolicyParameter extends CollectionLoadParameters{ +export interface PolicyParameter extends CollectionLoadParameters { active?: string; } diff --git a/imxweb/projects/pol/src/lib/policy-violations/mitigating-controls/mitigating-controls.component.html b/imxweb/projects/pol/src/lib/policy-violations/mitigating-controls/mitigating-controls.component.html index fe5af5044..aad79a72c 100644 --- a/imxweb/projects/pol/src/lib/policy-violations/mitigating-controls/mitigating-controls.component.html +++ b/imxweb/projects/pol/src/lib/policy-violations/mitigating-controls/mitigating-controls.component.html @@ -1,27 +1,37 @@ -
    - +
    + {{ '#LDS#Heading Mitigating Controls Can Be Assigned Individually' | translate }} - {{ '#LDS#Here you can assign mitigating controls to the policy violation. NOTE: If no mitigating controls have been assigned to the violated company policy, you cannot assign any mitigating controls to the policy violation either.' | translate }} + {{ + '#LDS#Here you can assign mitigating controls to the policy violation. NOTE: If no mitigating controls have been assigned to the violated company policy, you cannot assign any mitigating controls to the policy violation either.' + | translate + }} - -
    + +

    - +
    -

    +

    - -
    -
    - - -
    - -
    +
    +
    +
    diff --git a/imxweb/projects/pol/src/lib/policy-violations/mitigating-controls/mitigating-controls.component.scss b/imxweb/projects/pol/src/lib/policy-violations/mitigating-controls/mitigating-controls.component.scss index be50b8950..4de661ee8 100644 --- a/imxweb/projects/pol/src/lib/policy-violations/mitigating-controls/mitigating-controls.component.scss +++ b/imxweb/projects/pol/src/lib/policy-violations/mitigating-controls/mitigating-controls.component.scss @@ -1,153 +1 @@ -@import "@elemental-ui/core/src/styles/_eui_palette.scss"; - -:host { - display: flex; - flex-direction: column; - flex: 1 1 auto; - height: 100%; - - mat-card { - display: flex; - } - - .imx-helper-alert { - margin: 20px; - } - - .imx-mitigating-control { - display: flex; - flex-direction: row; - margin: 3px 3px 10px 3px; - - :first-child { - flex: 1 1 auto; - } - - button { - margin-top: 10px; - } - } - - .imx-mitigating-controls-card { - flex: 1 1 auto; - display: flex; - margin: 20px; - align-items: center; - overflow: hidden; - } - - .imx-spacer { - flex: 1 1 auto; - } - - .imx-content { - display: flex; - flex-direction: column; - overflow: hidden; - flex: 1 1 auto; - } - - .eui-sidesheet-actions { - margin: 0; - } - - .imx-save-button { - align-self: flex-end; - } - - .imx-data-no-results { - text-align: center; - flex: 1 1 auto; - - .eui-icon { - font-size: 100px; - } - - p { - margin: 0; - font-size: 18px; - } - button { - margin-top : 10px; - } - } - - .imx-mitigating-form{ - flex: 1 1 auto; - display: flex; - flex-direction: column; - align-self: flex-start; - overflow: auto; - max-height: 100%; - padding: 2px; - } - - .mat-error { - margin-top: 0.6666666667em; - margin-left: 1em; - } -} - -:host { - .delete-icon { - color: $color-red-60; - } - - .add-icon { - color: $color-blue-60; - } - - .imx-data-no-results { - .eui-icon { - color: $color-gray-10; - } - - p { - color: $color-gray-50; - } - } -} - -.eui-dark-theme { - :host { - .delete-icon { - color: $color-red-40; - } - - .add-icon { - color: $color-blue-40; - } - - .imx-data-no-results { - .eui-icon { - color: $color-gray-20; - } - - p { - color: $color-gray-10; - } - } - } -} - -.eui-contrast-theme { - :host { - .delete-icon { - color: $color-red-60; - } - - .add-icon { - color: $color-blue-60; - } - - .imx-data-no-results { - .eui-icon { - color: $color-gray-10; - } - - p { - color: $color-gray-0; - } - } - } -} +@import 'common/mitigating-controls'; diff --git a/imxweb/projects/pol/src/lib/policy-violations/mitigating-controls/mitigating-controls.component.ts b/imxweb/projects/pol/src/lib/policy-violations/mitigating-controls/mitigating-controls.component.ts index cc3553878..cf201ece2 100644 --- a/imxweb/projects/pol/src/lib/policy-violations/mitigating-controls/mitigating-controls.component.ts +++ b/imxweb/projects/pol/src/lib/policy-violations/mitigating-controls/mitigating-controls.component.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -56,10 +56,10 @@ export class MitigatingControlsComponent implements OnInit { private confirmationService: ConfirmationService, private cd: ChangeDetectorRef, private snackbar: SnackBarService, - formBuilder: UntypedFormBuilder + formBuilder: UntypedFormBuilder, ) { this.mitigatingForm = new UntypedFormGroup({ formArray: formBuilder.array([]) }); - this.mitigatingCaption = violationService.mitigationSchema.Columns.UID_MitigatingControl.Display; + this.mitigatingCaption = violationService.mitigationSchema.Columns.UID_MitigatingControl.Display ?? ''; } public filter = (option: EuiSelectOption, searchInputValue: string): boolean => @@ -99,13 +99,12 @@ export class MitigatingControlsComponent implements OnInit { } public async ngOnInit(): Promise { - this.sidesheetRef.componentInstance.disableClose = true; this.subscriptions$.push( this.sidesheetRef.closeClicked().subscribe(async () => { if (!this.isDirty || (await this.confirmationService.confirmLeaveWithUnsavedChanges())) { this.sidesheetRef.close(); } - }) + }), ); return this.loadMitigationControls(); } @@ -121,7 +120,7 @@ export class MitigatingControlsComponent implements OnInit { ); } - public async delete(index: number): Promise { + public async onDelete(index: number): Promise { const elem = this.mControls[index]; if (elem.UID_MitigatingControl.value !== '' && !(await this.confirmationService.confirmDelete())) { return; @@ -146,6 +145,8 @@ export class MitigatingControlsComponent implements OnInit { (control: FormControl) => (this.isDuplicate(control) ? { duplicated: true } : null), ]); this.cd.detectChanges(); + + this.mitigatingForm.markAsDirty(); } public async save() { @@ -172,7 +173,7 @@ export class MitigatingControlsComponent implements OnInit { try { //reload this.mControls = (await this.violationService.getMitigatingContols(this.uidViolation)).Data.map( - (elem) => new PolicyViolationExtended(false, elem) + (elem) => new PolicyViolationExtended(false, elem), ); this.mControls.forEach((elem) => this.formArray.push(elem.formControl)); await this.initOptions(); @@ -182,14 +183,15 @@ export class MitigatingControlsComponent implements OnInit { } private async initOptions(): Promise { - this.options = ( - await this.violationService.getCandidates( - this.uidViolation, - {}, - { - PageSize: 100000, - } - ) - ).Entities?.map((elem) => ({ display: elem.Display, value: elem.Keys[0] })); + this.options = + ( + await this.violationService.getCandidates( + this.uidViolation, + {}, + { + PageSize: 100000, + }, + ) + ).Entities?.map((elem) => ({ display: elem.Display ?? '', value: elem.Keys?.[0] ?? '' })) ?? []; } } diff --git a/imxweb/projects/pol/src/lib/policy-violations/mitigating-controls/policy-violation-extended.ts b/imxweb/projects/pol/src/lib/policy-violations/mitigating-controls/policy-violation-extended.ts index 330499d32..b55ef73e6 100644 --- a/imxweb/projects/pol/src/lib/policy-violations/mitigating-controls/policy-violation-extended.ts +++ b/imxweb/projects/pol/src/lib/policy-violations/mitigating-controls/policy-violation-extended.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -25,14 +25,17 @@ */ import { FormControl } from '@angular/forms'; -import { PortalPoliciesViolations } from 'imx-api-pol'; +import { PortalPoliciesViolations } from '@imx-modules/imx-api-pol'; import { BaseReadonlyCdr, ColumnDependentReference } from 'qbm'; export class PolicyViolationExtended extends PortalPoliciesViolations { - public formControl = new FormControl(undefined); + public formControl = new FormControl('', { nonNullable: true }); public mitigatingCdr: ColumnDependentReference; - constructor(public editable, readonly original: PortalPoliciesViolations) { + constructor( + public editable, + readonly original: PortalPoliciesViolations, + ) { super(original.GetEntity()); if (!editable) { this.mitigatingCdr = new BaseReadonlyCdr(original.UID_MitigatingControl.Column); diff --git a/imxweb/projects/pol/src/lib/policy-violations/policy-violation.ts b/imxweb/projects/pol/src/lib/policy-violations/policy-violation.ts index 6e97a953c..69ab12162 100644 --- a/imxweb/projects/pol/src/lib/policy-violations/policy-violation.ts +++ b/imxweb/projects/pol/src/lib/policy-violations/policy-violation.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -24,29 +24,27 @@ * */ -import { ObjectInfo, PortalPoliciesViolationslist } from 'imx-api-pol'; +import { ObjectInfo, PortalPoliciesViolationslist } from '@imx-modules/imx-api-pol'; import { BaseReadonlyCdr, ColumnDependentReference } from 'qbm'; export class PolicyViolation extends PortalPoliciesViolationslist { - public properties: ColumnDependentReference[]; /** * The color and the caption depending on the value of the state of a {@link PortalPoliciesViolationslist}. */ - public get stateBadge(): { color: 'blue' | 'orange' | 'green', caption: string } { + public get stateBadge(): { color: 'blue' | 'orange' | 'green'; caption: string } { return { color: this.stateBadgeColor, - caption: this.stateCaption + caption: this.stateCaption, }; - }; + } public readonly data: ObjectInfo[]; private stateBadgeColor: 'blue' | 'orange' | 'green'; private stateCaption: string; - constructor( private readonly baseObject: PortalPoliciesViolationslist, - extendedData: ObjectInfo[] + extendedData: ObjectInfo[], ) { super(baseObject.GetEntity()); this.initPropertyInfo(); @@ -59,25 +57,15 @@ export class PolicyViolation extends PortalPoliciesViolationslist { } private initPropertyInfo(): void { - const props: any[] = - [ - this.UID_QERPolicy, - this.Description, - this.ObjectKey - ]; + const props: any[] = [this.UID_QERPolicy, this.Description, this.ObjectKey]; if (this.State.value.toLowerCase() !== 'pending') { - props.push(...[ - this.UID_PersonDecisionMade, - this.UID_QERJustification, - this.DecisionReason, - this.DecisionDate - ]); + props.push(...[this.UID_PersonDecisionMade, this.UID_QERJustification, this.DecisionReason, this.DecisionDate]); } this.properties = props - .filter(property => property.value != null && property.value !== '') - .map(property => new BaseReadonlyCdr(property.Column)); + .filter((property) => property.value != null && property.value !== '') + .map((property) => new BaseReadonlyCdr(property.Column)); } private async initStateBadge(): Promise { diff --git a/imxweb/projects/pol/src/lib/policy-violations/policy-violations-action/policy-violations-action-multi-action/policy-violations-action-multi-action.component.html b/imxweb/projects/pol/src/lib/policy-violations/policy-violations-action/policy-violations-action-multi-action/policy-violations-action-multi-action.component.html index 770f59261..af0465eda 100644 --- a/imxweb/projects/pol/src/lib/policy-violations/policy-violations-action/policy-violations-action-multi-action/policy-violations-action-multi-action.component.html +++ b/imxweb/projects/pol/src/lib/policy-violations/policy-violations-action/policy-violations-action-multi-action/policy-violations-action-multi-action.component.html @@ -1,12 +1,16 @@ {{ '#LDS#Heading General Settings' | translate }} - {{ '#LDS#Here you can make settings that are applied to each selected policy violation.' | translate }} + {{ '#LDS#Here you can make settings that are applied to each selected policy violation.' | translate }}
    - +
    @@ -15,14 +19,15 @@ {{ '#LDS#Heading Selected Policy Violations' | translate }} -
    - - -
    - {{ policyViolationApproval?.GetEntity()?.GetDisplay() }} -
    -
    -
    -
    + + +
    + {{ policyViolationApproval?.GetEntity()?.GetDisplay() }} +
    +
    + {{ policyViolationApproval.stateBadge.caption | translate }} +
    +
    +
    -
    \ No newline at end of file +
    diff --git a/imxweb/projects/pol/src/lib/policy-violations/policy-violations-action/policy-violations-action-multi-action/policy-violations-action-multi-action.component.scss b/imxweb/projects/pol/src/lib/policy-violations/policy-violations-action/policy-violations-action-multi-action/policy-violations-action-multi-action.component.scss index 7ba872959..509e02aae 100644 --- a/imxweb/projects/pol/src/lib/policy-violations/policy-violations-action/policy-violations-action-multi-action/policy-violations-action-multi-action.component.scss +++ b/imxweb/projects/pol/src/lib/policy-violations/policy-violations-action/policy-violations-action-multi-action/policy-violations-action-multi-action.component.scss @@ -2,15 +2,6 @@ display: flex; flex-direction: column; overflow: hidden; - - ::ng-deep .mat-list-base .mat-list-item .mat-list-item-content{ - padding-left: 0%; - } - - ::ng-deep .mat-list-base .mat-list-item{ - height: auto; - margin-bottom: 16px; - } } mat-card { @@ -31,12 +22,3 @@ mat-card-content { imx-bulk-editor { margin-top: 20px; } - - -.mat-list-base .mat-list-item .mat-line{ - margin-left: 0px; - overflow: auto; - white-space: inherit; - word-wrap: break-word; - height: auto; -} diff --git a/imxweb/projects/pol/src/lib/policy-violations/policy-violations-action/policy-violations-action-multi-action/policy-violations-action-multi-action.component.ts b/imxweb/projects/pol/src/lib/policy-violations/policy-violations-action/policy-violations-action-multi-action/policy-violations-action-multi-action.component.ts index c2ddc10a2..e882fcdeb 100644 --- a/imxweb/projects/pol/src/lib/policy-violations/policy-violations-action/policy-violations-action-multi-action/policy-violations-action-multi-action.component.ts +++ b/imxweb/projects/pol/src/lib/policy-violations/policy-violations-action/policy-violations-action-multi-action/policy-violations-action-multi-action.component.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -39,10 +39,9 @@ import { PolicyViolationsAction } from '../policy-violations-action.interface'; @Component({ selector: 'imx-policy-violations-action-multi-action', templateUrl: './policy-violations-action-multi-action.component.html', - styleUrls: ['./policy-violations-action-multi-action.component.scss'] + styleUrls: ['./policy-violations-action-multi-action.component.scss'], }) -export class PolicyViolationsActionMultiActionComponent{ - +export class PolicyViolationsActionMultiActionComponent { /** * @ignore since this is only an internal component. * diff --git a/imxweb/projects/pol/src/lib/policy-violations/policy-violations-action/policy-violations-action-parameters.interface.ts b/imxweb/projects/pol/src/lib/policy-violations/policy-violations-action/policy-violations-action-parameters.interface.ts index 83f9cb52f..c485baf06 100644 --- a/imxweb/projects/pol/src/lib/policy-violations/policy-violations-action/policy-violations-action-parameters.interface.ts +++ b/imxweb/projects/pol/src/lib/policy-violations/policy-violations-action/policy-violations-action-parameters.interface.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -24,19 +24,19 @@ * */ -import { ColumnDependentReference } from 'qbm'; +import { BaseCdr } from 'qbm'; /** - * Defines the {@link ColumnDependentReference} for an action that can be performed on a policy violation + * Defines the {@link BaseCdr} for an action that can be performed on a policy violation */ export interface PolicyViolationsActionParameters { /** * A free text field for a reason */ - reason: ColumnDependentReference; + reason: BaseCdr; /** * A FK-Editor for standard justifications */ - justification?: ColumnDependentReference; + justification?: BaseCdr; } diff --git a/imxweb/projects/pol/src/lib/policy-violations/policy-violations-action/policy-violations-action-single-action/policy-violations-action-single-action.component.html b/imxweb/projects/pol/src/lib/policy-violations/policy-violations-action/policy-violations-action-single-action/policy-violations-action-single-action.component.html index 880cc8072..c2d0861ac 100644 --- a/imxweb/projects/pol/src/lib/policy-violations/policy-violations-action/policy-violations-action-single-action/policy-violations-action-single-action.component.html +++ b/imxweb/projects/pol/src/lib/policy-violations/policy-violations-action/policy-violations-action-single-action/policy-violations-action-single-action.component.html @@ -1,10 +1,13 @@ - {{ policyViolation.GetEntity()?.GetDisplay() }} + {{ policyViolation.GetEntity()?.GetDisplay() }} {{ policyViolation.State.Column.GetDisplayValue() }} - + - \ No newline at end of file +
    diff --git a/imxweb/projects/pol/src/lib/policy-violations/policy-violations-action/policy-violations-action-single-action/policy-violations-action-single-action.component.scss b/imxweb/projects/pol/src/lib/policy-violations/policy-violations-action/policy-violations-action-single-action/policy-violations-action-single-action.component.scss index fed2b0eb2..65cdb0a91 100644 --- a/imxweb/projects/pol/src/lib/policy-violations/policy-violations-action/policy-violations-action-single-action/policy-violations-action-single-action.component.scss +++ b/imxweb/projects/pol/src/lib/policy-violations/policy-violations-action/policy-violations-action-single-action/policy-violations-action-single-action.component.scss @@ -1,16 +1,8 @@ // Create a config with the default typography levels. // see: https://material.angular.io/guide/typography -@import "~@angular/material/theming"; -$config: mat-typography-config(); +@use '@angular/material' as mat; +$config: mat.m2-define-typography-config(); mat-card-content { overflow: hidden; } - -mat-card-title { - font-size: mat-font-size($config, subheading-2); -} - -mat-card-subtitle { - font-size: mat-font-size($config, subheading-1); -} diff --git a/imxweb/projects/pol/src/lib/policy-violations/policy-violations-action/policy-violations-action-single-action/policy-violations-action-single-action.component.ts b/imxweb/projects/pol/src/lib/policy-violations/policy-violations-action/policy-violations-action-single-action/policy-violations-action-single-action.component.ts index aee990624..ec9c5bd15 100644 --- a/imxweb/projects/pol/src/lib/policy-violations/policy-violations-action/policy-violations-action-single-action/policy-violations-action-single-action.component.ts +++ b/imxweb/projects/pol/src/lib/policy-violations/policy-violations-action/policy-violations-action-single-action/policy-violations-action-single-action.component.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -27,7 +27,6 @@ import { Component, Input, OnInit } from '@angular/core'; import { AbstractControl, UntypedFormGroup } from '@angular/forms'; -import { ColumnDependentReference } from 'qbm'; import { PolicyViolation } from '../../policy-violation'; import { PolicyViolationsAction } from '../policy-violations-action.interface'; @@ -41,10 +40,9 @@ import { PolicyViolationsAction } from '../policy-violations-action.interface'; @Component({ selector: 'imx-policy-violations-action-single-action', templateUrl: './policy-violations-action-single-action.component.html', - styleUrls: ['./policy-violations-action-single-action.component.scss'] + styleUrls: ['./policy-violations-action-single-action.component.scss'], }) export class PolicyViolationsActionSingleActionComponent implements OnInit { - /** * @ignore since this is only an internal component. * @@ -85,8 +83,6 @@ export class PolicyViolationsActionSingleActionComponent implements OnInit { */ public onFormControlCreated(name: string, control: AbstractControl): void { // use setTimeout to make addControl asynchronous in order to avoid "NG0100: Expression has changed after it was checked" - setTimeout(() => - this.formGroup.addControl(name, control) - ); + setTimeout(() => this.formGroup.addControl(name, control)); } } diff --git a/imxweb/projects/pol/src/lib/policy-violations/policy-violations-action/policy-violations-action.component.html b/imxweb/projects/pol/src/lib/policy-violations/policy-violations-action/policy-violations-action.component.html index e13d358b9..b18ef992c 100644 --- a/imxweb/projects/pol/src/lib/policy-violations/policy-violations-action/policy-violations-action.component.html +++ b/imxweb/projects/pol/src/lib/policy-violations/policy-violations-action/policy-violations-action.component.html @@ -1,4 +1,4 @@ -
    +

    {{ data.description | translate }}

    @@ -9,8 +9,15 @@
    -
    -
    diff --git a/imxweb/projects/pol/src/lib/policy-violations/policy-violations-action/policy-violations-action.component.scss b/imxweb/projects/pol/src/lib/policy-violations/policy-violations-action/policy-violations-action.component.scss index d8efa71bd..7e84805b0 100644 --- a/imxweb/projects/pol/src/lib/policy-violations/policy-violations-action/policy-violations-action.component.scss +++ b/imxweb/projects/pol/src/lib/policy-violations/policy-violations-action/policy-violations-action.component.scss @@ -1,18 +1,16 @@ +@import 'base/mixins'; + .eui-sidesheet-content { - padding: 32px; - overflow: hidden; - height: 100%; + @include flex-column-container($overflow: hidden, $height: 100%); flex: 1; - display: flex; - flex-direction: column; } -.eui-sidesheet-actions.mat-card { +.eui-sidesheet-actions.mat-mdc-card { margin: 16px 32px; } -.imx-policy-violation-content{ +.imx-policy-violation-content { overflow: hidden; display: flex; flex-direction: column; -} \ No newline at end of file +} diff --git a/imxweb/projects/pol/src/lib/policy-violations/policy-violations-action/policy-violations-action.component.ts b/imxweb/projects/pol/src/lib/policy-violations/policy-violations-action/policy-violations-action.component.ts index 74ce203a1..d2edac239 100644 --- a/imxweb/projects/pol/src/lib/policy-violations/policy-violations-action/policy-violations-action.component.ts +++ b/imxweb/projects/pol/src/lib/policy-violations/policy-violations-action/policy-violations-action.component.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -45,7 +45,7 @@ import { PolicyViolationsAction } from './policy-violations-action.interface'; */ @Component({ templateUrl: './policy-violations-action.component.html', - styleUrls: ['./policy-violations-action.component.scss'] + styleUrls: ['./policy-violations-action.component.scss'], }) export class PolicyViolationsActionComponent { /** @@ -60,7 +60,6 @@ export class PolicyViolationsActionComponent { */ constructor( @Inject(EUI_SIDESHEET_DATA) public readonly data: PolicyViolationsAction, - public readonly sideSheetRef: EuiSidesheetRef - ) { - } + public readonly sideSheetRef: EuiSidesheetRef, + ) {} } diff --git a/imxweb/projects/pol/src/lib/policy-violations/policy-violations-action/policy-violations-action.interface.ts b/imxweb/projects/pol/src/lib/policy-violations/policy-violations-action/policy-violations-action.interface.ts index 76f9409c2..43f771b47 100644 --- a/imxweb/projects/pol/src/lib/policy-violations/policy-violations-action/policy-violations-action.interface.ts +++ b/imxweb/projects/pol/src/lib/policy-violations/policy-violations-action/policy-violations-action.interface.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR diff --git a/imxweb/projects/pol/src/lib/policy-violations/policy-violations-sidesheet/policy-violations-sidesheet.component.html b/imxweb/projects/pol/src/lib/policy-violations/policy-violations-sidesheet/policy-violations-sidesheet.component.html index f46b6410e..0d8fbe3ac 100644 --- a/imxweb/projects/pol/src/lib/policy-violations/policy-violations-sidesheet/policy-violations-sidesheet.component.html +++ b/imxweb/projects/pol/src/lib/policy-violations/policy-violations-sidesheet/policy-violations-sidesheet.component.html @@ -1,4 +1,4 @@ - + @@ -6,15 +6,26 @@ - {{'#LDS#Heading Mitigating Controls' | translate}} - + {{ '#LDS#Heading Mitigating Controls' | translate }} + - + - +
    - + {{ '#LDS#Related objects' | translate }} @@ -22,9 +33,7 @@ - +
    @@ -37,13 +46,16 @@
    -
    {{ data?.policyViolation?.State?.GetMetadata()?.GetDisplay() }}
    - - {{ data?.policyViolation?.stateBadge?.caption | translate }} + + {{ data.policyViolation.stateBadge.caption | translate }}
    @@ -51,12 +63,14 @@ -
    - - +
    diff --git a/imxweb/projects/pol/src/lib/policy-violations/policy-violations-sidesheet/policy-violations-sidesheet.component.scss b/imxweb/projects/pol/src/lib/policy-violations/policy-violations-sidesheet/policy-violations-sidesheet.component.scss index e33fd5c3f..d15bd2ba1 100644 --- a/imxweb/projects/pol/src/lib/policy-violations/policy-violations-sidesheet/policy-violations-sidesheet.component.scss +++ b/imxweb/projects/pol/src/lib/policy-violations/policy-violations-sidesheet/policy-violations-sidesheet.component.scss @@ -6,82 +6,30 @@ overflow: hidden; height: 100%; - .tab-group-wrapper { - display: flex; - overflow: auto; - flex: 1; - - .mat-tab-group { - width: 100%; - } - - ::ng-deep .mat-tab-body-content { - display: flex; - flex-direction: column; - } - - ::ng-deep .mat-tab-body-wrapper { - flex: 1; - } - } - - ::ng-deep .mat-tab-group { - height: 100%; - flex-grow: 1; - overflow: auto; - - .mat-tab-header { - padding: 0 32px; - } - - ::ng-deep .mat-tab-body-wrapper { - height: 100%; - } - - ::ng-deep .mat-tab-body-content { - height: 100%; - display: flex; - flex-direction: column; - } - - } - .imx-dirty-indicator { margin-left: 5px; } - .imx-content{ + .imx-content { display: flex; flex: 1 1 auto; flex-direction: column; } - .eui-sidesheet-actions{ + .eui-sidesheet-actions { margin-top: auto; } - .eui-sidesheet-actions.mat-card { + .eui-sidesheet-actions.mat-mdc-card { margin: 16px 32px; } - .eui-badge ::ng-deep .eui-badge-content { - font-size: 12px; - line-height: 12px; - margin-bottom: 20px; - } - .imx-state-caption { font-size: 12px; padding-bottom: 5px; } - .eui-sidesheet-actions { - button:not(:last-of-type) { - margin-right: 10px; - } - } - - .imx-policy-violations-hyperview{ + .imx-policy-violations-hyperview { display: flex; flex-direction: column; } @@ -89,11 +37,7 @@ //Theming :host { - ::ng-deep .mat-tab-header { - background-color: $color-gray-0; - } - - .imx-state-caption { + .imx-state-caption { color: $color-gray-40; } @@ -104,10 +48,6 @@ .eui-dark-theme { :host { - ::ng-deep .mat-tab-header { - background-color: $color-gray-80; - } - .imx-state-caption { color: $color-gray-10; } @@ -120,10 +60,6 @@ .eui-contrast-theme { :host { - ::ng-deep .mat-tab-header { - background-color: $color-gray-90; - } - .imx-state-caption { color: $color-gray-0; } diff --git a/imxweb/projects/pol/src/lib/policy-violations/policy-violations-sidesheet/policy-violations-sidesheet.component.ts b/imxweb/projects/pol/src/lib/policy-violations/policy-violations-sidesheet/policy-violations-sidesheet.component.ts index 2008c08a7..6f150f5d3 100644 --- a/imxweb/projects/pol/src/lib/policy-violations/policy-violations-sidesheet/policy-violations-sidesheet.component.ts +++ b/imxweb/projects/pol/src/lib/policy-violations/policy-violations-sidesheet/policy-violations-sidesheet.component.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -24,26 +24,28 @@ * */ -import { Component, Inject } from '@angular/core'; -import { EuiSidesheetRef, EUI_SIDESHEET_DATA } from '@elemental-ui/core'; +import { Component, Inject, OnDestroy } from '@angular/core'; +import { EUI_SIDESHEET_DATA, EuiLoadingService, EuiSidesheetRef } from '@elemental-ui/core'; +import { ObjectInfo } from '@imx-modules/imx-api-pol'; +import { DbObjectKey } from '@imx-modules/imx-qbm-dbts'; import { ColumnDependentReference } from 'qbm'; +import { Subscription } from 'rxjs'; import { PolicyViolation } from '../policy-violation'; import { PolicyViolationsService } from '../policy-violations.service'; -import { ObjectInfo } from 'imx-api-pol'; -import { DbObjectKey } from 'imx-qbm-dbts'; @Component({ selector: 'imx-policy-violations-sidesheet', templateUrl: './policy-violations-sidesheet.component.html', - styleUrls: ['./policy-violations-sidesheet.component.scss'] + styleUrls: ['./policy-violations-sidesheet.component.scss'], }) -export class PolicyViolationsSidesheetComponent { - +export class PolicyViolationsSidesheetComponent implements OnDestroy { public cdrList: ColumnDependentReference[] = []; public selectedHyperviewType: string; public selectedHyperviewUID: string; - public selectedOption: ObjectInfo + public selectedOption: ObjectInfo; + public result: boolean = false; + public closeSubscription: Subscription; public get isPending(): boolean { return this.data.policyViolation.State.value?.toLocaleLowerCase() === 'pending'; @@ -58,44 +60,69 @@ export class PolicyViolationsSidesheetComponent { } constructor( - @Inject(EUI_SIDESHEET_DATA) public data: { + @Inject(EUI_SIDESHEET_DATA) + public data: { policyViolation: PolicyViolation; isMControlPerViolation: boolean; isReadOnly: boolean; }, private readonly policyViolationService: PolicyViolationsService, - public readonly sideSheetRef: EuiSidesheetRef + public readonly sideSheetRef: EuiSidesheetRef, + private readonly euiLoadingService: EuiLoadingService, ) { this.cdrList = this.data.policyViolation.properties; + this.closeSubscription = sideSheetRef.closeClicked().subscribe(() => { + sideSheetRef.close(this.result); + }); + } + + public ngOnDestroy(): void { + this.closeSubscription?.unsubscribe(); } /** - * Opens the Approve-Sidesheet for the current selected rules violations and closes the sidesheet afterwards. + * Opens the Approve-Sidesheet for the current selected rule violations. */ public async approve(): Promise { - await this.policyViolationService.approve([this.data.policyViolation]); - return this.sideSheetRef.close(true); + if (await this.policyViolationService.approve([this.data.policyViolation])) { + return this.reloadData(); + } } /** - * Opens the Deny-Sidesheet for the current selected rules violations and closes the sidesheet afterwards. + * Opens the Deny-Sidesheet for the current selected rule violations. */ public async deny(): Promise { - await this.policyViolationService.deny([this.data.policyViolation]); - return this.sideSheetRef.close(true); + if (await this.policyViolationService.deny([this.data.policyViolation])) { + return this.reloadData(); + } } - public get relatedOptions(): ObjectInfo[]{ + public get relatedOptions(): ObjectInfo[] { return this.data.policyViolation.data || []; } - public setHyperviewObject(selectedRelatedObject: ObjectInfo): void{ - const dbKey = DbObjectKey.FromXml(selectedRelatedObject.ObjectKey); + public setHyperviewObject(selectedRelatedObject: ObjectInfo): void { + const dbKey = DbObjectKey.FromXml(selectedRelatedObject.ObjectKey ?? ''); this.selectedHyperviewType = dbKey.TableName; this.selectedHyperviewUID = dbKey.Keys.join(','); } public onHyperviewOptionSelected(): void { - this.setHyperviewObject(this.selectedOption) + this.setHyperviewObject(this.selectedOption); + } + + private async reloadData() { + this.result = true; + this.euiLoadingService.show(); + try { + const value = await this.policyViolationService.get(true, { + filter: [{ ColumnName: 'ObjectKey', Value1: this.data.policyViolation.ObjectKey.value }], + }); + this.data.policyViolation = value.Data[0]; + this.cdrList = this.data.policyViolation.properties; + } finally { + this.euiLoadingService.hide(); + } } } diff --git a/imxweb/projects/pol/src/lib/policy-violations/policy-violations.component.html b/imxweb/projects/pol/src/lib/policy-violations/policy-violations.component.html index bc4266e93..a64fa8f0f 100644 --- a/imxweb/projects/pol/src/lib/policy-violations/policy-violations.component.html +++ b/imxweb/projects/pol/src/lib/policy-violations/policy-violations.component.html @@ -1,101 +1,111 @@
    -

    - {{ '#LDS#Heading Policy Violations' | translate }} - -

    - -
    - - -
    - - - -
    -
    {{ item.UID_QERPolicy.Column.GetDisplayValue() }}
    -
    {{ item.Description.Column.GetDisplayValue() }}
    -
    -
    -
    - - - - - - -
    - - -
    -
    -
    -
    -
    - -
    +
    +

    + {{ '#LDS#Heading Policy Violations' | translate }} + +

    + +
    + + + + + + + + + {{ entitySchema?.Columns?.UID_QERPolicy?.Display }} + + + +
    +
    {{ item.UID_QERPolicy.Column.GetDisplayValue() }}
    +
    {{ item.Description.Column.GetDisplayValue() }}
    +
    + +
    + + + + {{ '#LDS#Violating object' | translate }} + + + + + {{ item.ObjectKey.Column.GetDisplayValue() }} + + + + + + + {{ entitySchema?.Columns?.State?.Display }} + + + + + {{ item.State.Column.GetDisplayValue() }} + + + + + + + + +
    + + +
    + +
    +
    +
    -
    - -
    - +
    + +
    +
    + + +
    + + +
    +
    + +
    diff --git a/imxweb/projects/qam/src/lib/access-request/access-request-sidesheet.component.scss b/imxweb/projects/qam/src/lib/access-request/access-request-sidesheet.component.scss new file mode 100644 index 000000000..8b73c063a --- /dev/null +++ b/imxweb/projects/qam/src/lib/access-request/access-request-sidesheet.component.scss @@ -0,0 +1,3 @@ +.imx-manual-folder-container { + margin-top: 10px; +} \ No newline at end of file diff --git a/imxweb/projects/qam/src/lib/access-request/access-request-sidesheet.component.ts b/imxweb/projects/qam/src/lib/access-request/access-request-sidesheet.component.ts new file mode 100644 index 000000000..13402720d --- /dev/null +++ b/imxweb/projects/qam/src/lib/access-request/access-request-sidesheet.component.ts @@ -0,0 +1,209 @@ +/* + * ONE IDENTITY LLC. PROPRIETARY INFORMATION + * + * This software is confidential. One Identity, LLC. or one of its affiliates or + * subsidiaries, has supplied this software to you under terms of a + * license agreement, nondisclosure agreement or both. + * + * You may not copy, disclose, or use this software except in accordance with + * those terms. + * + * + * Copyright 2024 One Identity LLC. + * ALL RIGHTS RESERVED. + * + * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR + * WARRANTIES ABOUT THE SUITABILITY OF THE SOFTWARE, + * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED + * TO THE IMPLIED WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE, OR + * NON-INFRINGEMENT. ONE IDENTITY LLC. SHALL NOT BE + * LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE + * AS A RESULT OF USING, MODIFYING OR DISTRIBUTING + * THIS SOFTWARE OR ITS DERIVATIVES. + * + */ + +import { Component, Inject, OnInit, ViewChild } from '@angular/core'; +import { FormArray, FormControl, FormGroup } from '@angular/forms'; +import { EUI_SIDESHEET_DATA, EuiLoadingService, EuiSidesheetRef } from '@elemental-ui/core'; +import { TranslateService } from '@ngx-translate/core'; +import { Subscription } from 'rxjs'; + +import { CollectionLoadParameters, DataModel, IEntity, ValType } from '@imx-modules/imx-qbm-dbts'; +import { + BaseCdr, + ColumnDependentReference, + ConfirmationService, + DataSourceToolbarFilter, + DataTreeWrapperComponent, + EntityService, + HELPER_ALERT_KEY_PREFIX, + LdsReplacePipe, + StorageService, +} from 'qbm'; +import { AccessRequestDataService } from './access-request-data.service'; +import { AccessRequestSidesheetData } from './access-request-sidesheet-data.interface'; +import { AccessRequestTreeDatabase } from './access-request-tree-database'; +import { QamTreeNode } from './qam-resourcetree'; + +const helperAlertKey = `${HELPER_ALERT_KEY_PREFIX}_requestingFileSystemAccess`; + +interface FolderFormGroup { + folderArray: FormArray; + enterFolderManually: FormControl; +} + +/** + * Component that let the user select multiple resource for his request. + * The user can select the resources from a tree or can enter them manually. + */ +@Component({ + templateUrl: './access-request-sidesheet.component.html', + styleUrls: ['./access-request-sidesheet.component.scss'], +}) +export class AccessRequestSidesheetComponent implements OnInit { + @ViewChild('dataTreeWrapper', { static: true }) dataTreeWrapper: DataTreeWrapperComponent; + + public get showHelperAlert(): boolean { + return !this.storageService.isHelperAlertDismissed(helperAlertKey); + } + public formGroup: FormGroup; + public folderList: ColumnDependentReference[] = []; + + public treeDatabase: AccessRequestTreeDatabase; + public filterOptions: DataSourceToolbarFilter[] = []; + + public selectedNodes: IEntity[] = []; + public showTree = true; + + private dataModel: DataModel; + private readonly subscriptions: Subscription[] = []; + private dgeResourcesNodes: QamTreeNode[] = []; + + constructor( + @Inject(EUI_SIDESHEET_DATA) public data: AccessRequestSidesheetData, + confirmationService: ConfirmationService, + private readonly accessRequestDataService: AccessRequestDataService, + private readonly entityService: EntityService, + private readonly euiBusyService: EuiLoadingService, + private readonly ldsReplace: LdsReplacePipe, + private readonly sidesheetRef: EuiSidesheetRef, + private readonly storageService: StorageService, + private readonly translate: TranslateService, + ) { + this.subscriptions.push( + this.sidesheetRef.closeClicked().subscribe(async () => { + const folders = await this.getFolders(); + if (folders.length === 0 || folders.filter((folder) => folder.length === 0).length > 0) { + const close = await confirmationService.confirmLeaveWithUnsavedChanges(); + if (close) { + this.sidesheetRef.close([]); + } else { + return; + } + } else { + this.sidesheetRef.close(folders); + } + }), + ); + + this.initializeTree(); + } + + public async ngOnInit(): Promise { + this.showTree = this.data.uidAccProduct !== undefined && this.data.uidAccProduct.length > 0; + + this.formGroup = new FormGroup({ + folderArray: new FormArray([]), + enterFolderManually: new FormControl(!this.showTree, { nonNullable: true }), + }); + this.createNewCdr(); + + this.dataModel = this.data.dataModel; + this.filterOptions = this.dataModel?.Filters || []; + } + + protected createNewCdr() { + const cdr = new BaseCdr( + this.entityService.createLocalEntityColumn({ + ColumnName: 'folder', + Type: ValType.Text, + IsMultiLine: true, + }), + this.ldsReplace.transform(this.translate.instant('#LDS#Folder #{0}'), this.folderList.length + 1), + ); + this.folderList.push(cdr); + } + + /** + * Checks, if at least one folder was manually entered or selected from the tree + * @returns true, if one or more folder were entered/selected, otherwise false + */ + public foldersAreValid(): boolean { + if (this.formGroup.controls.enterFolderManually.value) { + // return the manually entered folders + return this.formGroup.controls.folderArray.value.length > 0 && this.formGroup.controls.folderArray.value[0].length > 0; + } else { + // return the selected folders from the tree + return this.selectedNodes.length > 0; + } + } + + protected submitValues(): void { + this.sidesheetRef.close(this.getFolders()); + } + + private async initializeTree(): Promise { + if (this.data.uidAccProduct && this.data.uidAccProduct.length > 0) { + this.dgeResourcesNodes = await this.getData(true); + this.treeDatabase = new AccessRequestTreeDatabase(this.dgeResourcesNodes); + } + } + + /** Returns the list of all selected or manually entered folders. */ + private async getFolders(): Promise { + if (this.formGroup.controls.enterFolderManually.value) { + // return the manually entered folders + return this.formGroup.controls.folderArray.value; + } else { + // return the selected folders from the tree + let folders: string[] = []; + + for (const node of this.selectedNodes) { + const uidQamDug = node.GetColumn('UidQamDug').GetValue(); + // get the fullpath of this dgeResource + const opts: CollectionLoadParameters = { + PageSize: 1, + StartIndex: 0, + filter: [ + { + ColumnName: 'UID_QAMDug', + Value1: uidQamDug, + }, + ], + }; + const dgeResources = await this.accessRequestDataService.getDgeResources(opts); + if (dgeResources?.Data[0]?.FullPath?.value?.length > 0) { + folders.push(dgeResources.Data[0].FullPath.value); + } + } + return folders; + } + } + + private async getData(showLoading: boolean, parameters: CollectionLoadParameters = { ParentKey: '' }): Promise { + let nodes: QamTreeNode[]; + if (showLoading && this.euiBusyService.overlayRefs.length === 0) { + this.euiBusyService.show(); + } + try { + nodes = this.data.uidAccProduct ? await this.accessRequestDataService.getDgeResourceTree(this.data.uidAccProduct) : []; + } finally { + if (showLoading) { + this.euiBusyService.hide(); + } + } + return nodes; + } +} diff --git a/imxweb/projects/qam/src/lib/access-request/access-request-tree-database.ts b/imxweb/projects/qam/src/lib/access-request/access-request-tree-database.ts new file mode 100644 index 000000000..e1745ebf5 --- /dev/null +++ b/imxweb/projects/qam/src/lib/access-request/access-request-tree-database.ts @@ -0,0 +1,89 @@ +/* + * ONE IDENTITY LLC. PROPRIETARY INFORMATION + * + * This software is confidential. One Identity, LLC. or one of its affiliates or + * subsidiaries, has supplied this software to you under terms of a + * license agreement, nondisclosure agreement or both. + * + * You may not copy, disclose, or use this software except in accordance with + * those terms. + * + * + * Copyright 2024 One Identity LLC. + * ALL RIGHTS RESERVED. + * + * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR + * WARRANTIES ABOUT THE SUITABILITY OF THE SOFTWARE, + * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED + * TO THE IMPLIED WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE, OR + * NON-INFRINGEMENT. ONE IDENTITY LLC. SHALL NOT BE + * LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE + * AS A RESULT OF USING, MODIFYING OR DISTRIBUTING + * THIS SOFTWARE OR ITS DERIVATIVES. + * + */ + +import { IEntity, TypedEntityBuilder } from '@imx-modules/imx-qbm-dbts'; + +import { TreeDatabase, TreeNode } from 'qbm'; +import { QamResourcetree, QamTreeNode } from './qam-resourcetree'; + +/** Provider of DgeResources for the imx-data-tree */ +export class AccessRequestTreeDatabase extends TreeDatabase { + private readonly builder = new TypedEntityBuilder(QamResourcetree); + + constructor(private readonly dgeResourcesNodes: QamTreeNode[]) { + super(); + this.identifierColumnName = 'UidQamDug'; + this.canSearch = false; + } + + /** Initial data from database */ + public async initialize(): Promise { + let rootNodes: TreeNode[] = []; + rootNodes = this.createTreeNodes(this.dgeResourcesNodes, 0); + this.initialized.next(); + return rootNodes; + } + /** creates recursively all {@link TreeNode | tree nodes} from the given {@link QamTreeNode | qamTree nodes} */ + public createTreeNodes(qamTreeNodes: QamTreeNode[], levelNumber: number): TreeNode[] { + let treeNodes: TreeNode[] = []; + + for (const qamTreeNode of qamTreeNodes) { + // create IEntity + const qamResourcetree = this.builder.buildReadWriteEntity({ + entitySchema: QamResourcetree.GetEntitySchema(), + entityData: QamResourcetree.buildSingleEntityData(qamTreeNode), + }); + + // create TreeNode + const treeNode = this.createNode(qamResourcetree.GetEntity(), levelNumber); + treeNode.isSelectable = qamResourcetree.IsTarget.value; + + // create TreeNodes also for the chiild nodes + if (qamTreeNode.Nodes && qamTreeNode.Nodes.length > 0) { + const childNodes = this.createTreeNodes(qamTreeNode.Nodes, levelNumber + 1); + treeNode.nodes = childNodes; + } + + // push to result + treeNodes.push(treeNode); + } + return treeNodes; + } + + /** return children for a given tree node including the information, if more elements are available on the server */ + public async getChildren(node: TreeNode, startIndex: number): Promise<{ nodes: TreeNode[]; canLoadMore: boolean }> { + return { + nodes: node.nodes as TreeNode[], + canLoadMore: false, + }; + } + + /** Returns the UID of the QamDug */ + public getId(entity: IEntity): string { + const qamNode = entity.GetColumn('UidQamDug')?.GetValue(); + return qamNode.length > 0 ? qamNode : entity.GetDisplay(); + } +} diff --git a/imxweb/projects/qbm/src/lib/sidenav-tree/sidenav-tree.module.ts b/imxweb/projects/qam/src/lib/access-request/access-request.module.ts similarity index 63% rename from imxweb/projects/qbm/src/lib/sidenav-tree/sidenav-tree.module.ts rename to imxweb/projects/qam/src/lib/access-request/access-request.module.ts index 45c8d1705..839ae13a0 100644 --- a/imxweb/projects/qbm/src/lib/sidenav-tree/sidenav-tree.module.ts +++ b/imxweb/projects/qam/src/lib/access-request/access-request.module.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -26,28 +26,31 @@ import { NgModule } from '@angular/core'; import { CommonModule } from '@angular/common'; -import { MatTreeModule } from '@angular/material/tree'; -import { EuiCoreModule, EuiMaterialModule } from '@elemental-ui/core'; -import { MatSidenavModule } from '@angular/material/sidenav'; -import { SidenavTreeComponent } from './sidenav-tree.component'; +import { AccessRequestSidesheetComponent } from './access-request-sidesheet.component'; +import { FormsModule, ReactiveFormsModule } from '@angular/forms'; import { TranslateModule } from '@ngx-translate/core'; -import { DataSourceToolbarModule } from '../data-source-toolbar/data-source-toolbar.module'; +import { CdrModule, DataTreeWrapperModule } from 'qbm'; +import { MatButtonModule } from '@angular/material/button'; +import { EuiCoreModule, EuiMaterialModule } from '@elemental-ui/core'; +import { MatCardModule } from '@angular/material/card'; +import { MatSelectModule } from '@angular/material/select'; @NgModule({ declarations: [ - SidenavTreeComponent + AccessRequestSidesheetComponent, ], imports: [ CommonModule, - MatTreeModule, + CdrModule, + DataTreeWrapperModule, EuiCoreModule, EuiMaterialModule, - MatSidenavModule, - TranslateModule, - DataSourceToolbarModule - ], - exports: [ - SidenavTreeComponent + MatButtonModule, + MatCardModule, + MatSelectModule, + FormsModule, + ReactiveFormsModule, + TranslateModule ] }) -export class SidenavTreeModule { } +export class AccessRequestModule { } diff --git a/imxweb/projects/qam/src/lib/access-request/access-request.service.ts b/imxweb/projects/qam/src/lib/access-request/access-request.service.ts new file mode 100644 index 000000000..cecf9e3d1 --- /dev/null +++ b/imxweb/projects/qam/src/lib/access-request/access-request.service.ts @@ -0,0 +1,120 @@ +/* + * ONE IDENTITY LLC. PROPRIETARY INFORMATION + * + * This software is confidential. One Identity, LLC. or one of its affiliates or + * subsidiaries, has supplied this software to you under terms of a + * license agreement, nondisclosure agreement or both. + * + * You may not copy, disclose, or use this software except in accordance with + * those terms. + * + * + * Copyright 2024 One Identity LLC. + * ALL RIGHTS RESERVED. + * + * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR + * WARRANTIES ABOUT THE SUITABILITY OF THE SOFTWARE, + * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED + * TO THE IMPLIED WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE, OR + * NON-INFRINGEMENT. ONE IDENTITY LLC. SHALL NOT BE + * LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE + * AS A RESULT OF USING, MODIFYING OR DISTRIBUTING + * THIS SOFTWARE OR ITS DERIVATIVES. + * + */ + +import { Injectable } from '@angular/core'; +import { EuiLoadingService, EuiSidesheetService } from '@elemental-ui/core'; +import { TranslateService } from '@ngx-translate/core'; +import _ from 'lodash'; + +import { PortalCartitem } from '@imx-modules/imx-api-qer'; +import { calculateSidesheetWidth } from 'qbm'; +import { ExtendedEntityWrapper, ICartItemsExtensionService, RequestableProduct } from 'qer'; +import { AccessRequestDataService } from './access-request-data.service'; +import { AccessRequestSidesheetData } from './access-request-sidesheet-data.interface'; +import { AccessRequestSidesheetComponent } from './access-request-sidesheet.component'; + +@Injectable({ + providedIn: 'root', +}) +export class AccessRequestService implements ICartItemsExtensionService { + private folders: string[] = []; + + // TODO #460645: replace UidAccProduct-workaround with if (requestable.DisplayType === 'DGEAccessRequest' ) + private fileSystemAccessUidAccProduct = 'QAM-4B31152BD53849CFBCEA4B27570BD947'; + + constructor( + private readonly accessRequestDataService: AccessRequestDataService, + private readonly busyIndicator: EuiLoadingService, + private readonly sidesheetService: EuiSidesheetService, + private readonly translate: TranslateService, + ) {} + + public async OnBeforeCreateCartItems(products: RequestableProduct[]): Promise { + this.folders = []; + let requestableProducts: RequestableProduct[] = []; + + const entitySchema = this.accessRequestDataService.getSchema(); + const dataModel = await this.accessRequestDataService.getDataModel(); + + const data: AccessRequestSidesheetData = { + entitySchema, + dataModel, + }; + this.busyIndicator.hide(); + + // TODO #460645: replace UidAccProduct-workaround with if (requestable.DisplayType === 'DGEAccessRequest' ) + const countFileSystemAccessProducts = products.filter((product) => product.UidAccProduct === this.fileSystemAccessUidAccProduct).length; + + if (countFileSystemAccessProducts > 0) { + // the user should specify which folders he want to request + data.uidAccProduct = this.fileSystemAccessUidAccProduct; + this.folders = await this.sidesheetService + .open(AccessRequestSidesheetComponent, { + title: this.translate.instant('#LDS#Heading Requesting File System Access'), + width: calculateSidesheetWidth(800, 0.5), + disableClose: true, + testId: 'access-request-sidesheet', + padding: '0px', + data, + }) + .afterClosed() + .toPromise(); + } + for (const product of products) { + if (product.UidAccProduct === this.fileSystemAccessUidAccProduct) { + if (this.folders?.length > 0) { + // create a product for each folder + for (const folder of this.folders) { + const requestable = _.cloneDeep(product); + requestable.Folder = folder; + requestableProducts.push(requestable); + } + } + } else { + requestableProducts.push(product); + } + } + + return requestableProducts; + } + + public async OnAfterCreateCartItem( + product: RequestableProduct, + cartItem: ExtendedEntityWrapper, + ): Promise> { + if ((product.Folder?.length ?? 0) > 0) { + for (const parameterCategoryColumn of cartItem.parameterCategoryColumns) { + if (parameterCategoryColumn.column.ColumnName === 'Resource') { + parameterCategoryColumn.column.PutValue(product.Folder); + } + if (parameterCategoryColumn.column.ColumnName === 'Access') { + parameterCategoryColumn.column.PutValue('Read'); + } + } + } + return cartItem; + } +} diff --git a/imxweb/projects/qam/src/lib/access-request/qam-resourcetree.ts b/imxweb/projects/qam/src/lib/access-request/qam-resourcetree.ts new file mode 100644 index 000000000..c0e28f606 --- /dev/null +++ b/imxweb/projects/qam/src/lib/access-request/qam-resourcetree.ts @@ -0,0 +1,124 @@ +/* + * ONE IDENTITY LLC. PROPRIETARY INFORMATION + * + * This software is confidential. One Identity, LLC. or one of its affiliates or + * subsidiaries, has supplied this software to you under terms of a + * license agreement, nondisclosure agreement or both. + * + * You may not copy, disclose, or use this software except in accordance with + * those terms. + * + * + * Copyright 2024 One Identity LLC. + * ALL RIGHTS RESERVED. + * + * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR + * WARRANTIES ABOUT THE SUITABILITY OF THE SOFTWARE, + * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED + * TO THE IMPLIED WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE, OR + * NON-INFRINGEMENT. ONE IDENTITY LLC. SHALL NOT BE + * LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE + * AS A RESULT OF USING, MODIFYING OR DISTRIBUTING + * THIS SOFTWARE OR ITS DERIVATIVES. + * + */ + +import { + EntityColumnData, + EntityData, + EntitySchema, + ExtendedTypedEntityCollection, + IClientProperty, + IReadValue, + TypedEntity, + TypedEntityBuilder, + ValType, +} from '@imx-modules/imx-qbm-dbts'; +import { TreeNode } from '../TypedClient'; + +import { TranslateService } from '@ngx-translate/core'; + +export class QamTreeNode implements TreeNode { + UidQamDug?: string; + Display?: string; + IsTarget: boolean; + Nodes?: TreeNode[]; +} + +export class QamResourcetree extends TypedEntity { + public readonly Display: IReadValue = this.GetEntityValue('Display'); + public readonly UidQamDug: IReadValue = this.GetEntityValue('UidQamDug'); + public readonly IsTarget: IReadValue = this.GetEntityValue('IsTarget'); + // public readonly HasChildren: IWriteValue = this.GetEntityValue('HasChildren'); + + public Nodes: QamResourcetree[] = []; + public static GetEntitySchema(translate?: TranslateService): EntitySchema { + const returnColumns: { [key: string]: IClientProperty } = {}; + + returnColumns.Display = { + Type: ValType.String, + ColumnName: 'Display', + Display: translate ? translate.instant('#LDS#Display name') : '#LDS#Display name', + }; + + returnColumns.UidQamDug = { + Type: ValType.String, + ColumnName: 'UidQamDug', + Display: translate ? translate.instant('#LDS#UidQamDug') : '#LDS#UidQamDug', + }; + + returnColumns.IsTarget = { + Type: ValType.Bool, + ColumnName: 'IsTarget', + Display: translate ? translate.instant('#LDS#Is Target') : '#LDS#Is Target', + }; + + returnColumns.HasChildren = { + Type: ValType.Bool, + ColumnName: 'HasChildren', + }; + + return { + TypeName: 'QamResourcetree', + Display: translate ? translate.instant('#LDS#QamResourcetree') : '#LDS#QamResourcetree', + Columns: returnColumns, + }; + } + + public static buildEntities( + entityData: EntityData[], + entitySchema: EntitySchema, + ): ExtendedTypedEntityCollection { + const builder = new TypedEntityBuilder(QamResourcetree); + const typedEntityCollection = builder.buildReadWriteEntities( + { + TotalCount: entityData.length, + Entities: entityData, + }, + entitySchema, + ); + return typedEntityCollection; + } + + public static buildEntityData(nodes: TreeNode[]): EntityData[] { + return nodes.map((elem) => { + const returnColumns: { [key: string]: EntityColumnData } = {}; + returnColumns.Display = { Value: elem.Display, IsReadOnly: true }; + returnColumns.IsTarget = { Value: elem.IsTarget, IsReadOnly: true }; + returnColumns.UidQamDug = { Value: elem.UidQamDug, IsReadOnly: true }; + returnColumns.HasChildren = { Value: elem.Nodes && elem.Nodes.length > 0, IsReadOnly: true }; + returnColumns.nodes = { Value: elem.Nodes, IsReadOnly: true }; + return { Columns: returnColumns, Display: elem.Display }; + }); + } + + public static buildSingleEntityData(node: TreeNode): EntityData { + const returnColumns: { [key: string]: EntityColumnData } = {}; + returnColumns.Display = { Value: node.Display, IsReadOnly: true }; + returnColumns.IsTarget = { Value: node.IsTarget, IsReadOnly: true }; + returnColumns.UidQamDug = { Value: node.UidQamDug, IsReadOnly: true }; + returnColumns.HasChildren = { Value: node.Nodes && node.Nodes.length > 0, IsReadOnly: true }; + return { Columns: returnColumns, Display: node.Display }; + } +} diff --git a/imxweb/projects/qam/src/lib/access/access.component.html b/imxweb/projects/qam/src/lib/access/access.component.html new file mode 100644 index 000000000..7910497a9 --- /dev/null +++ b/imxweb/projects/qam/src/lib/access/access.component.html @@ -0,0 +1,13 @@ +
    + + +
    +
    + {{ "#LDS#'{0}' has access to the following governed data resources." | translate | ldsReplace: referrer.display }} +
    + + +
    + +
    +
    diff --git a/imxweb/projects/qam/src/lib/access/access.component.scss b/imxweb/projects/qam/src/lib/access/access.component.scss new file mode 100644 index 000000000..4c054a88d --- /dev/null +++ b/imxweb/projects/qam/src/lib/access/access.component.scss @@ -0,0 +1,21 @@ +@import 'base/mixins'; + +:host { + @include flex-column-container-fill(); +} + +.imx-card-content.hidden { + display: none; +} + +.imx-busy { + padding: 10px; + display: flex; + flex-direction: column; + align-items: center; + height: 100%; +} + +.imx-card-content { + @include flex-column-container-fill(); +} diff --git a/imxweb/projects/qam/src/lib/access/access.component.ts b/imxweb/projects/qam/src/lib/access/access.component.ts new file mode 100644 index 000000000..1e0d77b7f --- /dev/null +++ b/imxweb/projects/qam/src/lib/access/access.component.ts @@ -0,0 +1,69 @@ +/* + * ONE IDENTITY LLC. PROPRIETARY INFORMATION + * + * This software is confidential. One Identity, LLC. or one of its affiliates or + * subsidiaries, has supplied this software to you under terms of a + * license agreement, nondisclosure agreement or both. + * + * You may not copy, disclose, or use this software except in accordance with + * those terms. + * + * + * Copyright 2024 One Identity LLC. + * ALL RIGHTS RESERVED. + * + * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR + * WARRANTIES ABOUT THE SUITABILITY OF THE SOFTWARE, + * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED + * TO THE IMPLIED WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE, OR + * NON-INFRINGEMENT. ONE IDENTITY LLC. SHALL NOT BE + * LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE + * AS A RESULT OF USING, MODIFYING OR DISTRIBUTING + * THIS SOFTWARE OR ITS DERIVATIVES. + * + */ + +import { Component, OnDestroy, OnInit } from '@angular/core'; +import { Subscription } from 'rxjs'; + +import { BusyService, DynamicTabDataProviderDirective } from 'qbm'; +import { QamApiService } from '../qam-api-client.service'; +import { TrusteeAccessData } from '../TypedClient'; + +/** Shows access information for an account or a system entitlement. */ +@Component({ + templateUrl: './access.component.html', + styleUrls: ['./access.component.scss'], +}) +export class AccessComponent implements OnInit, OnDestroy { + public data: TrusteeAccessData; + + public referrer: { objecttable: string; objectuid: string; display: string }; + + public busyService: BusyService; + public isLoading: boolean = true; + private subscription: Subscription | undefined; + + constructor( + dataProvider: DynamicTabDataProviderDirective, + private readonly qamApi: QamApiService, + ) { + this.referrer = dataProvider.data; + this.busyService = new BusyService(); + this.subscription = this.busyService.busyStateChanged.subscribe((elem) => (this.isLoading = elem)); + } + + public ngOnDestroy(): void { + this.subscription?.unsubscribe(); + } + + public async ngOnInit(): Promise { + const isBusy = this.busyService.beginBusy(); + try { + this.data = await this.qamApi.client.portal_dge_access_get(this.referrer.objecttable, this.referrer.objectuid); + } finally { + isBusy?.endBusy(); + } + } +} diff --git a/imxweb/projects/qam/src/lib/access/trustee-view.component.html b/imxweb/projects/qam/src/lib/access/trustee-view.component.html new file mode 100644 index 000000000..385b864a3 --- /dev/null +++ b/imxweb/projects/qam/src/lib/access/trustee-view.component.html @@ -0,0 +1,61 @@ + +
    + + + + + + + + +
    + + +
    + +
    + +
    +
    +
    +
    +
    + + + + {{ perm.path }} + + + + + + + + + + +
    +
    + + +
    + +

    #LDS#No groups or accounts have access to governed data.

    +
    +
    + + +
    + +

    #LDS#Please select a trustee.

    +
    +
    diff --git a/imxweb/projects/qam/src/lib/access/trustee-view.component.scss b/imxweb/projects/qam/src/lib/access/trustee-view.component.scss new file mode 100644 index 000000000..6ce1b99ba --- /dev/null +++ b/imxweb/projects/qam/src/lib/access/trustee-view.component.scss @@ -0,0 +1,73 @@ +@import 'base/mixins'; +@import '@elemental-ui/core/src/styles/_eui_palette.scss'; + +:host { + @include flex-row-container-fill(); + overflow: hidden; +} + +.imx-trustee-tree { + background-color: transparent; +} + +.imx-trustee-content { + @include flex-row-container-fill(); + overflow: hidden; + gap: 20px; + padding: 3px; + > :first-child { + width: 300px; + } +} + +.imx-selected-trustee { + @include flex-column-container-fill(); +} + +.imx-trustee-card { + box-shadow: inherit; +} + +.imx-permission-card { + margin: 20px; + .mat-mdc-card-header { + margin-bottom: 20px; + font-weight: 600; + align-items: center; + @include flex-column-container(); + } + .mat-mdc-card-content { + @include flex-row-container-fill(); + } +} + +.imx-trustee-tree-invisible { + display: none; +} + +.imx-trustee-tree ul, +.imx-trustee-tree li { + margin-top: 0; + margin-bottom: 0; + list-style-type: none; +} + +/* + * This padding sets alignment of the nested nodes. + */ +.imx-trustee-tree .mat-nested-tree-node div[role='group'] { + padding-left: 40px; +} + +/* + * Padding for leaf nodes. + * Leaf nodes need to have padding so as to align with other non-leaf nodes + * under the same parent. + */ +.imx-trustee-tree div[role='group'] > .mat-tree-node { + padding-left: 20px; +} + +.tree-button-node { + color: inherit; +} diff --git a/imxweb/projects/qam/src/lib/access/trustee-view.component.ts b/imxweb/projects/qam/src/lib/access/trustee-view.component.ts new file mode 100644 index 000000000..24af54630 --- /dev/null +++ b/imxweb/projects/qam/src/lib/access/trustee-view.component.ts @@ -0,0 +1,97 @@ +/* + * ONE IDENTITY LLC. PROPRIETARY INFORMATION + * + * This software is confidential. One Identity, LLC. or one of its affiliates or + * subsidiaries, has supplied this software to you under terms of a + * license agreement, nondisclosure agreement or both. + * + * You may not copy, disclose, or use this software except in accordance with + * those terms. + * + * + * Copyright 2024 One Identity LLC. + * ALL RIGHTS RESERVED. + * + * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR + * WARRANTIES ABOUT THE SUITABILITY OF THE SOFTWARE, + * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED + * TO THE IMPLIED WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE, OR + * NON-INFRINGEMENT. ONE IDENTITY LLC. SHALL NOT BE + * LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE + * AS A RESULT OF USING, MODIFYING OR DISTRIBUTING + * THIS SOFTWARE OR ITS DERIVATIVES. + * + */ + +import { NestedTreeControl } from '@angular/cdk/tree'; +import { Component, Input, OnChanges, OnInit, SimpleChanges } from '@angular/core'; +import { MatTreeNestedDataSource } from '@angular/material/tree'; +import { BusyService } from 'qbm'; +import { TrusteeAccessData, TrusteeData } from '../TypedClient'; +import { QamApiService } from '../qam-api-client.service'; + +interface TrusteePermissionData { + path: string; + allowRead: boolean; + allowWrite: boolean; + anyAllow: boolean; + allowFullControl: boolean; + allowChangePermissions: boolean; +} + +/** Component to display a TrusteeAccessData structure. */ +@Component({ + templateUrl: './trustee-view.component.html', + styleUrls: ['../qam.scss', './trustee-view.component.scss'], + selector: 'imx-trustee-view', +}) +export class TrusteeViewComponent implements OnInit, OnChanges { + public currentSelectedTrustee: TrusteeData | undefined; + public currentSelectedTrusteePermissions: TrusteePermissionData[] = []; + public treeControl = new NestedTreeControl((node) => node.Children); + public dataSource = new MatTreeNestedDataSource(); + @Input() public data: TrusteeAccessData | undefined; + @Input() public busyService: BusyService | undefined; + + public trusteeTypes: { [id: number]: string }; + + constructor(private readonly api: QamApiService) {} + + public async ngOnInit(): Promise { + const isBusy = this.busyService?.beginBusy(); + try { + this.trusteeTypes = await this.api.getTrusteeTypes(); + } finally { + isBusy?.endBusy(); + } + + this.dataSource.data = this.data?.Trustees ?? []; + } + + public ngOnChanges(changes: SimpleChanges) { + if (changes.data) { + this.dataSource.data = this.data?.Trustees ?? []; + } + } + + public hasChild = (_: number, node: TrusteeData) => !!node.Children && node.Children.length > 0; + + public isSelected = (node: TrusteeData) => { + return node.UidQamTrustee === this.currentSelectedTrustee?.UidQamTrustee; + }; + + public updateView(data: TrusteeData) { + this.currentSelectedTrustee = data; + this.currentSelectedTrusteePermissions = + data.Paths?.map((elem) => ({ + path: elem.Path ?? '', + allowRead: elem.Permissions?.includes('AllowRead') ?? false, + allowWrite: elem.Permissions?.includes('AllowWrite') ?? false, + allowChangePermissions: elem.Permissions?.includes('AllowChangePermissions') ?? false, + allowFullControl: elem.Permissions?.includes('AllowFullControl') ?? false, + anyAllow: elem.Permissions?.includes('AnyAllow') ?? false, + })) ?? []; + console.log('martina', this.currentSelectedTrustee, this.currentSelectedTrusteePermissions); + } +} diff --git a/imxweb/projects/qam/src/lib/access/user-access.component.html b/imxweb/projects/qam/src/lib/access/user-access.component.html new file mode 100644 index 000000000..f22394787 --- /dev/null +++ b/imxweb/projects/qam/src/lib/access/user-access.component.html @@ -0,0 +1 @@ + diff --git a/imxweb/projects/qer/src/lib/approval-workflows/approval-workflow-edit/approval-workflow-edit-info/approval-workflow-edit-info.component.ts b/imxweb/projects/qam/src/lib/access/user-access.component.ts similarity index 66% rename from imxweb/projects/qer/src/lib/approval-workflows/approval-workflow-edit/approval-workflow-edit-info/approval-workflow-edit-info.component.ts rename to imxweb/projects/qam/src/lib/access/user-access.component.ts index f981b5481..934280d7c 100644 --- a/imxweb/projects/qer/src/lib/approval-workflows/approval-workflow-edit/approval-workflow-edit-info/approval-workflow-edit-info.component.ts +++ b/imxweb/projects/qam/src/lib/access/user-access.component.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -25,20 +25,18 @@ */ import { Component, OnInit } from '@angular/core'; -import { MatDialogRef } from '@angular/material/dialog'; +import { imx_SessionService } from 'qbm'; +/** Shows access information for the authenticated user's identity. */ @Component({ - selector: 'imx-approval-workflow-edit-info', - templateUrl: './approval-workflow-edit-info.component.html', - styleUrls: ['./approval-workflow-edit-info.component.scss'] + templateUrl: './user-access.component.html', }) -export class ApprovalWorkflowEditInfoComponent { +export class UserAccessComponent implements OnInit { + constructor(private readonly session: imx_SessionService) {} - constructor( - public dialogRef: MatDialogRef - ) { } + userUid: string; - public close(): void { - this.dialogRef.close(); + ngOnInit(): void { + this.userUid = this.session.SessionState.UserUid ?? ''; } } diff --git a/imxweb/projects/qam/src/lib/dug-activities/dug-activities.component.html b/imxweb/projects/qam/src/lib/dug-activities/dug-activities.component.html new file mode 100644 index 000000000..371104b06 --- /dev/null +++ b/imxweb/projects/qam/src/lib/dug-activities/dug-activities.component.html @@ -0,0 +1,61 @@ + + + + + {{ '#LDS# Most active resources' | translate }} + + + +
    +

    + {{ + '#LDS#The following list shows the {0} most active governed resources which you are responsible for. Activity is aggregated for the last {1} days.' + | translate + | ldsReplace: topCountResource : interval + }} +

    + + + + + +
    {{ item.GetEntity().GetDisplay() }}
    +
    {{ item.GetEntity().GetDisplayLong() }}
    +
    +
    + +
    +
    +
    +
    + + + + + {{ '#LDS# Most active users' | translate }} + + + +
    +

    + {{ + '#LDS#The following list shows the {0} most active users on resources which you are responsible for. Activity is aggregated for the last {1} days.' + | translate + | ldsReplace: topCountTrustee : interval + }} +

    + + + + + +
    {{ item.GetEntity().GetDisplay() }}
    +
    {{ item.GetEntity().GetDisplayLong() }}
    +
    +
    + +
    +
    +
    +
    +
    diff --git a/imxweb/projects/qam/src/lib/dug-activities/dug-activities.component.scss b/imxweb/projects/qam/src/lib/dug-activities/dug-activities.component.scss new file mode 100644 index 000000000..b2efe27d5 --- /dev/null +++ b/imxweb/projects/qam/src/lib/dug-activities/dug-activities.component.scss @@ -0,0 +1,3 @@ +:host{ + padding-top: 16px; +} \ No newline at end of file diff --git a/imxweb/projects/qam/src/lib/dug-activities/dug-activities.component.ts b/imxweb/projects/qam/src/lib/dug-activities/dug-activities.component.ts new file mode 100644 index 000000000..f0c907272 --- /dev/null +++ b/imxweb/projects/qam/src/lib/dug-activities/dug-activities.component.ts @@ -0,0 +1,116 @@ +/* + * ONE IDENTITY LLC. PROPRIETARY INFORMATION + * + * This software is confidential. One Identity, LLC. or one of its affiliates or + * subsidiaries, has supplied this software to you under terms of a + * license agreement, nondisclosure agreement or both. + * + * You may not copy, disclose, or use this software except in accordance with + * those terms. + * + * + * Copyright 2024 One Identity LLC. + * ALL RIGHTS RESERVED. + * + * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR + * WARRANTIES ABOUT THE SUITABILITY OF THE SOFTWARE, + * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED + * TO THE IMPLIED WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE, OR + * NON-INFRINGEMENT. ONE IDENTITY LLC. SHALL NOT BE + * LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE + * AS A RESULT OF USING, MODIFYING OR DISTRIBUTING + * THIS SOFTWARE OR ITS DERIVATIVES. + * + */ + +import { Component, OnInit } from '@angular/core'; +import { EuiLoadingService } from '@elemental-ui/core'; +import { DugActivitiesService } from './dug-activities.service'; +import { ResourceActivityData, TrusteeActivityData } from '../TypedClient'; +import { DugActivityEntity } from './dug-activity-entity'; +import { TranslateService } from '@ngx-translate/core'; +import { DisplayColumns, EntitySchema } from '@imx-modules/imx-qbm-dbts'; +import { DataSourceToolbarSettings } from 'qbm'; + +@Component({ + selector: 'imx-dug-activities', + templateUrl: './dug-activities.component.html', + styleUrls: ['./dug-activities.component.scss'], +}) +export class DugActivitiesComponent implements OnInit { + private mostActiveTrustees: TrusteeActivityData[]; + private mostActiveResources: ResourceActivityData[]; + + public entitySchemaTrustee: EntitySchema; + public entitySchemaResource: EntitySchema; + + public dstSettingsTrustee: DataSourceToolbarSettings; + public dstSettingsResource: DataSourceToolbarSettings; + public DisplayColumns = DisplayColumns; + + private displayColumnsTrustee; + private displayColumnsResource; + + public topCountResource: number = 10; + public topCountTrustee: number = 10; + + public interval: number = 0; + + constructor( + public readonly activityService: DugActivitiesService, + private readonly loadingServiceEui: EuiLoadingService, + private readonly translateService: TranslateService, + ) {} + + public async ngOnInit(): Promise { + const over = this.loadingServiceEui.show(); + try { + this.entitySchemaTrustee = DugActivityEntity.GetEntitySchema('Trustee', '#LDS#Trustee', this.translateService); + this.entitySchemaResource = DugActivityEntity.GetEntitySchema('Resources', '#LDS#Resources', this.translateService); + this.mostActiveTrustees = await this.activityService.getMostActiveTrustees(); + this.mostActiveResources = await this.activityService.getMostActiveResources(); + const config = await this.activityService.getConfig(); + this.interval = config.ActivityAggregationIntervalDays; + this.displayColumnsTrustee = [ + this.entitySchemaTrustee.Columns[DisplayColumns.DISPLAY_PROPERTYNAME], + this.entitySchemaTrustee.Columns['CountActivities'], + ]; + this.displayColumnsResource = [ + this.entitySchemaResource.Columns[DisplayColumns.DISPLAY_PROPERTYNAME], + this.entitySchemaResource.Columns['CountActivities'], + ]; + this.initTrustee(); + this.initResources(); + + } finally { + this.loadingServiceEui.hide(over); + } + } + + public initTrustee() { + const data = DugActivityEntity.buildEntities( + DugActivityEntity.buildEntityDataTrustee(this.mostActiveTrustees), + this.entitySchemaTrustee, + ); + this.dstSettingsTrustee = { + displayedColumns:this.displayColumnsTrustee, + dataSource: data, + entitySchema: this.entitySchemaTrustee, + navigationState: {}, + }; + } + + public initResources() { + const data = DugActivityEntity.buildEntities( + DugActivityEntity.buildEntityDataTrustee(this.mostActiveResources), + this.entitySchemaResource, + ); + this.dstSettingsResource = { + displayedColumns:this.displayColumnsResource, + dataSource: data, + entitySchema: this.entitySchemaResource, + navigationState: {}, + }; + } +} diff --git a/imxweb/projects/qer/src/lib/statistics/statistics-home-page/statistics-ordering-sidesheet/statistics-ordering-sidesheet-dialog/statistics-ordering-sidesheet-dialog.component.ts b/imxweb/projects/qam/src/lib/dug-activities/dug-activities.service.ts similarity index 53% rename from imxweb/projects/qer/src/lib/statistics/statistics-home-page/statistics-ordering-sidesheet/statistics-ordering-sidesheet-dialog/statistics-ordering-sidesheet-dialog.component.ts rename to imxweb/projects/qam/src/lib/dug-activities/dug-activities.service.ts index c35e1a8cc..851554661 100644 --- a/imxweb/projects/qer/src/lib/statistics/statistics-home-page/statistics-ordering-sidesheet/statistics-ordering-sidesheet-dialog/statistics-ordering-sidesheet-dialog.component.ts +++ b/imxweb/projects/qam/src/lib/dug-activities/dug-activities.service.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -24,22 +24,26 @@ * */ -import { Component } from '@angular/core'; -import { MatDialogRef } from '@angular/material/dialog'; - -@Component({ - selector: 'imx-statistics-ordering-sidesheet-dialog', - templateUrl: './statistics-ordering-sidesheet-dialog.component.html', - styleUrls: ['./statistics-ordering-sidesheet-dialog.component.scss'] -}) -export class StatisticsOrderingSidesheetDialogComponent { +import { Injectable } from '@angular/core'; +import { QamApiService } from '../qam-api-client.service'; +import { DgeConfigData, ResourceActivityData, TrusteeActivityData } from '../TypedClient'; +@Injectable({ providedIn: 'root' }) +export class DugActivitiesService { constructor( - public dialogRef: MatDialogRef - ) { } + private readonly api: QamApiService, + ) {} + - public close(): void { - this.dialogRef.close(); + public async getMostActiveTrustees(): Promise { + return this.api.client.portal_dge_mostactivetrustees_get(); } -} + public async getMostActiveResources(): Promise { + return this.api.client.portal_dge_mostactiveresources_get(); + } + + public async getConfig(): Promise{ + return this.api.client.portal_dgeconfig_get(); + } +} \ No newline at end of file diff --git a/imxweb/projects/qam/src/lib/dug-activities/dug-activity-entity.ts b/imxweb/projects/qam/src/lib/dug-activities/dug-activity-entity.ts new file mode 100644 index 000000000..9c8e408e9 --- /dev/null +++ b/imxweb/projects/qam/src/lib/dug-activities/dug-activity-entity.ts @@ -0,0 +1,91 @@ +/* + * ONE IDENTITY LLC. PROPRIETARY INFORMATION + * + * This software is confidential. One Identity, LLC. or one of its affiliates or + * subsidiaries, has supplied this software to you under terms of a + * license agreement, nondisclosure agreement or both. + * + * You may not copy, disclose, or use this software except in accordance with + * those terms. + * + * + * Copyright 2024 One Identity LLC. + * ALL RIGHTS RESERVED. + * + * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR + * WARRANTIES ABOUT THE SUITABILITY OF THE SOFTWARE, + * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED + * TO THE IMPLIED WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE, OR + * NON-INFRINGEMENT. ONE IDENTITY LLC. SHALL NOT BE + * LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE + * AS A RESULT OF USING, MODIFYING OR DISTRIBUTING + * THIS SOFTWARE OR ITS DERIVATIVES. + * + */ + +import { + DisplayColumns, + EntityColumnData, + EntityData, + EntitySchema, + ExtendedTypedEntityCollection, + IClientProperty, + TypedEntity, + TypedEntityBuilder, + ValType, +} from '@imx-modules/imx-qbm-dbts'; +import { TranslateService } from '@ngx-translate/core'; +import { ResourceActivityData, TrusteeActivityData } from '../TypedClient'; + +export class DugActivityEntity extends TypedEntity { + public static GetEntitySchema(typeName: string, typeDisplay: string, translate?: TranslateService): EntitySchema { + const returnColumns: { [key: string]: IClientProperty } = {}; + + returnColumns.CountActivities = { + Type: ValType.Int, + ColumnName: 'CountActivities', + Display: translate ? translate.instant('#LDS#Activity count') : '#LDS#Activity count', + }; + + returnColumns[DisplayColumns.DISPLAY_PROPERTYNAME] = DisplayColumns.DISPLAY_PROPERTY; + + return { + TypeName: typeName, + Display: translate ? translate.instant(typeDisplay) : typeDisplay, + Columns: returnColumns, + }; + } + + public static buildEntities( + entityData: EntityData[], + entitySchema: EntitySchema, + ): ExtendedTypedEntityCollection { + const builder = new TypedEntityBuilder(DugActivityEntity); + return builder.buildReadWriteEntities( + { + TotalCount: entityData.length, + Entities: entityData, + }, + entitySchema, + ); + } + + public static buildEntityDataTrustee(trustees: TrusteeActivityData[]): EntityData[] { + return trustees.map((elem) => { + const returnColumns: { [key: string]: EntityColumnData } = {}; + returnColumns.CountActivities = { Value: elem.CountActivities, IsReadOnly: true }; + + return { Columns: returnColumns, Display: elem.Display ?? '', LongDisplay: elem.LongDisplay ?? '', Keys: [elem.UidTrustee ?? ''] }; + }); + } + + public static buildEntityDataResource(resources: ResourceActivityData[]): EntityData[] { + return resources.map((elem) => { + const returnColumns: { [key: string]: EntityColumnData } = {}; + returnColumns.CountActivities = { Value: elem.CountActivities, IsReadOnly: true }; + + return { Columns: returnColumns, Display: elem.Display ?? '', LongDisplay: elem.LongDisplay ?? '', Keys: [elem.UidQamDug ?? ''] }; + }); + } +} diff --git a/imxweb/projects/qam/src/lib/dug-dashboards/dug-dashboards.component.html b/imxweb/projects/qam/src/lib/dug-dashboards/dug-dashboards.component.html new file mode 100644 index 000000000..6be0894bc --- /dev/null +++ b/imxweb/projects/qam/src/lib/dug-dashboards/dug-dashboards.component.html @@ -0,0 +1,12 @@ +
    + + + {{ stat?.Display }} + + +
    + +
    +
    +
    +
    diff --git a/imxweb/projects/qam/src/lib/dug-dashboards/dug-dashboards.component.scss b/imxweb/projects/qam/src/lib/dug-dashboards/dug-dashboards.component.scss new file mode 100644 index 000000000..121d0768f --- /dev/null +++ b/imxweb/projects/qam/src/lib/dug-dashboards/dug-dashboards.component.scss @@ -0,0 +1,41 @@ +@import 'base/mixins'; + +:host { + height: 100%; + width: 100%; + display: flex; + flex-direction: column; + overflow: hidden; +} + +.chart-container { + display: flex; + height: fit-content; + flex-wrap: wrap; + grid-auto-rows: auto; + gap: 15px; + grid-auto-flow: dense; + padding: 10px; + overflow: auto; +} + +.mat-card-header { + justify-content: center; +} + +.center-content { + display: flex; + flex-direction: column; + margin: auto; +} + +.stat-card { + min-height: 300px; + min-width: 500px; + max-width: 600px; + display: flex; + flex-direction: column; + text-align: center; + border: 1px solid transparent; + @include eui-elevation-1; +} diff --git a/imxweb/projects/qam/src/lib/dug-dashboards/dug-dashboards.component.ts b/imxweb/projects/qam/src/lib/dug-dashboards/dug-dashboards.component.ts new file mode 100644 index 000000000..faeac10bd --- /dev/null +++ b/imxweb/projects/qam/src/lib/dug-dashboards/dug-dashboards.component.ts @@ -0,0 +1,57 @@ +/* + * ONE IDENTITY LLC. PROPRIETARY INFORMATION + * + * This software is confidential. One Identity, LLC. or one of its affiliates or + * subsidiaries, has supplied this software to you under terms of a + * license agreement, nondisclosure agreement or both. + * + * You may not copy, disclose, or use this software except in accordance with + * those terms. + * + * + * Copyright 2024 One Identity LLC. + * ALL RIGHTS RESERVED. + * + * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR + * WARRANTIES ABOUT THE SUITABILITY OF THE SOFTWARE, + * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED + * TO THE IMPLIED WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE, OR + * NON-INFRINGEMENT. ONE IDENTITY LLC. SHALL NOT BE + * LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE + * AS A RESULT OF USING, MODIFYING OR DISTRIBUTING + * THIS SOFTWARE OR ITS DERIVATIVES. + * + */ + +import { Component, OnInit } from '@angular/core'; +import { EuiLoadingService } from '@elemental-ui/core'; +import { ChartInfoTyped } from 'qer'; +import { ChartDto } from '../TypedClient'; +import { DugDashboardsService } from './dug-dashboards.service'; + +@Component({ + selector: 'imx-dug-dashboards', + templateUrl: './dug-dashboards.component.html', + styleUrls: ['./dug-dashboards.component.scss'], +}) +export class DugDashboardsComponent implements OnInit { + public stats: ChartDto[] = []; + public info: ChartInfoTyped[] = []; + constructor( + public readonly dashboardsService: DugDashboardsService, + private readonly loadingServiceEui: EuiLoadingService, + ) {} + + public async ngOnInit(): Promise { + const over = this.loadingServiceEui.show(); + try { + const test = await this.dashboardsService.getDashboards(); + this.stats = test.Data ?? []; + this.info = ChartInfoTyped.buildEntities((test.Charts ?? []).map((elem) => ChartInfoTyped.buildEntityData(elem))).Data; + console.log(this.info, this.stats); + } finally { + this.loadingServiceEui.hide(over); + } + } +} diff --git a/imxweb/projects/qbm/src/lib/select/check-match.validator.ts b/imxweb/projects/qam/src/lib/dug-dashboards/dug-dashboards.service.ts similarity index 65% rename from imxweb/projects/qbm/src/lib/select/check-match.validator.ts rename to imxweb/projects/qam/src/lib/dug-dashboards/dug-dashboards.service.ts index 99b680560..097b71090 100644 --- a/imxweb/projects/qbm/src/lib/select/check-match.validator.ts +++ b/imxweb/projects/qam/src/lib/dug-dashboards/dug-dashboards.service.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -24,18 +24,15 @@ * */ -import { AbstractControl } from '@angular/forms'; +import { Injectable } from '@angular/core'; +import { PersonalStatsData } from '../TypedClient'; +import { QamApiService } from '../qam-api-client.service'; -// tslint:disable-next-line: typedef -export function CheckMatchValidator(control: AbstractControl) { - if (control.disabled || control.pristine) { - return null; - } +@Injectable({ providedIn: 'root' }) +export class DugDashboardsService { + constructor(private readonly api: QamApiService) {} - const selection: any = control.value; - if (typeof selection === 'string' && selection !== '') { - return { matchFailed: true }; + public async getDashboards(): Promise { + return this.api.client.portal_dge_personalstats_get(); } - - return null; } diff --git a/imxweb/projects/qam/src/lib/dug-overview/dug-overview.component.html b/imxweb/projects/qam/src/lib/dug-overview/dug-overview.component.html new file mode 100644 index 000000000..129473c33 --- /dev/null +++ b/imxweb/projects/qam/src/lib/dug-overview/dug-overview.component.html @@ -0,0 +1,47 @@ + +
    +
    +

    #LDS#Heading Governed Data

    + +
    +
    + + +
    + + + + + + +
    {{ item.GetEntity().GetDisplay() }}
    +
    {{ item.GetEntity().GetDisplayLong() }}
    +
    +
    + + +
    + +
    +
    +
    + + + + + + + + + + + +
    +
    diff --git a/imxweb/projects/qam/src/lib/dug-overview/dug-overview.component.scss b/imxweb/projects/qam/src/lib/dug-overview/dug-overview.component.scss new file mode 100644 index 000000000..5f52e225e --- /dev/null +++ b/imxweb/projects/qam/src/lib/dug-overview/dug-overview.component.scss @@ -0,0 +1,11 @@ +@import 'base/mixins'; + +:host { + @include flex-column-container($overflow: hidden, $height: 100%, $max-width: 100%); + padding-bottom: 3px; +} + +.heading-wrapper { + @include flex-row-container(); + flex: 0 0 auto; +} diff --git a/imxweb/projects/qam/src/lib/dug-overview/dug-overview.component.ts b/imxweb/projects/qam/src/lib/dug-overview/dug-overview.component.ts new file mode 100644 index 000000000..031090961 --- /dev/null +++ b/imxweb/projects/qam/src/lib/dug-overview/dug-overview.component.ts @@ -0,0 +1,128 @@ +/* + * ONE IDENTITY LLC. PROPRIETARY INFORMATION + * + * This software is confidential. One Identity, LLC. or one of its affiliates or + * subsidiaries, has supplied this software to you under terms of a + * license agreement, nondisclosure agreement or both. + * + * You may not copy, disclose, or use this software except in accordance with + * those terms. + * + * + * Copyright 2024 One Identity LLC. + * ALL RIGHTS RESERVED. + * + * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR + * WARRANTIES ABOUT THE SUITABILITY OF THE SOFTWARE, + * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED + * TO THE IMPLIED WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE, OR + * NON-INFRINGEMENT. ONE IDENTITY LLC. SHALL NOT BE + * LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE + * AS A RESULT OF USING, MODIFYING OR DISTRIBUTING + * THIS SOFTWARE OR ITS DERIVATIVES. + * + */ + +import { Component, OnInit } from '@angular/core'; +import { BusyService, calculateSidesheetWidth, DataSourceToolbarSettings, HelpContextualValues, SideNavigationComponent } from 'qbm'; + +import { EuiSidesheetService } from '@elemental-ui/core'; +import { CollectionLoadParameters, DataModel, DisplayColumns, EntitySchema, IClientProperty, TypedEntity } from '@imx-modules/imx-qbm-dbts'; +import { TranslateService } from '@ngx-translate/core'; +import { DugSidesheetComponent } from '../dug/dug-sidesheet.component'; +import { DugOverviewService } from './dug-overview.service'; + +@Component({ + selector: 'imx-dug-overview', + templateUrl: './dug-overview.component.html', + styleUrls: ['./dug-overview.component.scss'], +}) +export class DugOverviewComponent implements OnInit, SideNavigationComponent { + public data?: any; + public contextId?: HelpContextualValues; + private dataModel: DataModel; + + public busyService = new BusyService(); + public navigationState: CollectionLoadParameters = {}; + public dstSettings: DataSourceToolbarSettings; + public entitySchema: EntitySchema; + private displayedColumns: IClientProperty[] = []; + public readonly DisplayColumns = DisplayColumns; + + constructor( + private readonly overviewService: DugOverviewService, + private readonly sideSheet: EuiSidesheetService, + private readonly translate: TranslateService, + ) { + this.entitySchema = overviewService.DugResourceSchema; + this.displayedColumns = [ + this.entitySchema.Columns[DisplayColumns.DISPLAY_PROPERTYNAME], + this.entitySchema.Columns.UID_QAMResourceType, + this.entitySchema.Columns.RiskIndexCalculated, + ]; + } + + public async ngOnInit(): Promise { + const isBusy = this.busyService.beginBusy(); + try { + this.dataModel = await this.overviewService.getDataModel(); + await this.getData(); + } finally { + isBusy.endBusy(); + } + } + + /** + * Occurs when the navigation state has changed - e.g. users clicks on the next page button. + * + */ + public async onNavigationStateChanged(newState?: CollectionLoadParameters): Promise { + await this.getData(newState); + } + + /** + * Occurs when user triggers search. + * + * @param keywords Search keywords. + */ + public async onSearch(keywords: string): Promise { + await this.getData({ ...this.navigationState, StartIndex: 0, search: keywords }); + } + + public async showDugResource(resource: TypedEntity): Promise { + const sidesheetRef = this.sideSheet.open(DugSidesheetComponent, { + title: this.translate.instant('#LDS#Heading Edit Governed Data'), + subTitle: resource.GetEntity().GetDisplay(), + width: calculateSidesheetWidth(1000, 0.9), + disableClose: true, + padding: '0', + testId: 'edit-dug-resource-sidesheet', + data: { uid: resource.GetEntity().GetKeys()[0] }, + }); + sidesheetRef.afterClosed().subscribe((result) => { + if (result) { + this.getData(this.navigationState); + } + }); + } + + private async getData(parameter: CollectionLoadParameters = {}): Promise { + const isBusy = this.busyService.beginBusy(); + this.navigationState = { ...parameter, owned: '1' }; + try { + const data = await this.overviewService.getData(this.navigationState); + + this.dstSettings = { + displayedColumns: this.displayedColumns, + dataSource: data, + dataModel: this.dataModel, + filters: this.dataModel?.Filters ?? [], + entitySchema: this.entitySchema, + navigationState: this.navigationState, + }; + } finally { + isBusy.endBusy(); + } + } +} diff --git a/imxweb/projects/qam/src/lib/dug-overview/dug-overview.service.ts b/imxweb/projects/qam/src/lib/dug-overview/dug-overview.service.ts new file mode 100644 index 000000000..767948248 --- /dev/null +++ b/imxweb/projects/qam/src/lib/dug-overview/dug-overview.service.ts @@ -0,0 +1,67 @@ +/* + * ONE IDENTITY LLC. PROPRIETARY INFORMATION + * + * This software is confidential. One Identity, LLC. or one of its affiliates or + * subsidiaries, has supplied this software to you under terms of a + * license agreement, nondisclosure agreement or both. + * + * You may not copy, disclose, or use this software except in accordance with + * those terms. + * + * + * Copyright 2024 One Identity LLC. + * ALL RIGHTS RESERVED. + * + * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR + * WARRANTIES ABOUT THE SUITABILITY OF THE SOFTWARE, + * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED + * TO THE IMPLIED WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE, OR + * NON-INFRINGEMENT. ONE IDENTITY LLC. SHALL NOT BE + * LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE + * AS A RESULT OF USING, MODIFYING OR DISTRIBUTING + * THIS SOFTWARE OR ITS DERIVATIVES. + * + */ + +import { Injectable } from '@angular/core'; +import { QamApiService } from '../qam-api-client.service'; +import { CollectionLoadParameters, DataModel, EntitySchema, ExtendedTypedEntityCollection } from '@imx-modules/imx-qbm-dbts'; +import { ChangeRequestType, DgeConfigData, PortalDgeResources, PortalDgeResourcesActivity, PortalDgeResourcesbyid } from '../TypedClient'; +import { SettingsService } from 'qbm'; + +@Injectable({ providedIn: 'root' }) +export class DugOverviewService { + constructor( + private readonly api: QamApiService, + private readonly settings: SettingsService, + ) {} + + public async getData(parameter: CollectionLoadParameters): Promise> { + return this.api.typedClient.PortalDgeResources.Get(parameter); + } + + public async getDataModel(): Promise{ + return this.api.client.portal_dge_resources_datamodel_get(); + } + + public get DugResourceSchema(): EntitySchema { + return this.api.typedClient.PortalDgeResources.GetSchema(); + } + + public async getDgeConfig(): Promise { + return this.api.getDgeConfig(); + } + + public async getDugResourceById(key: string): Promise { + return (await this.api.typedClient.PortalDgeResourcesInteractivebyid.Get_byid(key)).Data[0]; + } + + public async getAllResourceActivities(key: string): Promise> { + return this.api.typedClient.PortalDgeResourcesActivity.Get(key, { PageSize: this.settings.PageSizeForAllElements }); + } + + public async makeRequest(uid: string, type: ChangeRequestType, reason: string): Promise { + return this.api.client.portal_dge_resources_request_post(uid, { ChangeRequestType: type, Reason: reason }); + } +} diff --git a/imxweb/projects/qam/src/lib/dug/access-comparison.component.html b/imxweb/projects/qam/src/lib/dug/access-comparison.component.html new file mode 100644 index 000000000..cd804decf --- /dev/null +++ b/imxweb/projects/qam/src/lib/dug/access-comparison.component.html @@ -0,0 +1,13 @@ + +

    {{ LdsHeader | translate | ldsReplace: [dug.GetEntity().GetDisplay(), dugB.GetEntity().GetDisplay()] }}

    + +
    {{ LdsTitle | translate }}
    + +
    {{ LdsSubTitle | translate | ldsReplace: [dugB.GetEntity().GetDisplay(), dug.GetEntity().GetDisplay()]}}
    + +
    • + {{ trustee.display}} ({{ trusteeTypes[trustee.trusteeType] }}): A = {{trustee.accessA}}, B = {{trustee.accessB}} +
    + + +
    \ No newline at end of file diff --git a/imxweb/projects/qam/src/lib/dug/access-comparison.component.ts b/imxweb/projects/qam/src/lib/dug/access-comparison.component.ts new file mode 100644 index 000000000..cb0b56eac --- /dev/null +++ b/imxweb/projects/qam/src/lib/dug/access-comparison.component.ts @@ -0,0 +1,120 @@ +/* + * ONE IDENTITY LLC. PROPRIETARY INFORMATION + * + * This software is confidential. One Identity, LLC. or one of its affiliates or + * subsidiaries, has supplied this software to you under terms of a + * license agreement, nondisclosure agreement or both. + * + * You may not copy, disclose, or use this software except in accordance with + * those terms. + * + * + * Copyright 2024 One Identity LLC. + * ALL RIGHTS RESERVED. + * + * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR + * WARRANTIES ABOUT THE SUITABILITY OF THE SOFTWARE, + * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED + * TO THE IMPLIED WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE, OR + * NON-INFRINGEMENT. ONE IDENTITY LLC. SHALL NOT BE + * LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE + * AS A RESULT OF USING, MODIFYING OR DISTRIBUTING + * THIS SOFTWARE OR ITS DERIVATIVES. + * + */ + +import { Component, Input, OnInit } from '@angular/core'; +import { EuiLoadingService } from '@elemental-ui/core'; +import { PortalDgeResourcesbyid } from '../TypedClient'; +import { QamApiService } from '../qam-api-client.service'; + +type ComparisonData = { display: string; trusteeType: number; accessA?: string[]; accessB?: string[] }; + +/** Displays a comparison between security entries on two resources. */ +@Component({ + templateUrl: './access-comparison.component.html', + styleUrls: ['../qam.scss'], + selector: 'imx-dge-access-comparison', +}) +export class AccessComparisonComponent implements OnInit { + constructor( + private readonly qam: QamApiService, + private loadingService: EuiLoadingService, + ) {} + + @Input() dug: PortalDgeResourcesbyid; + + uidDugA: string; + uidDugB: string; + + dugB: PortalDgeResourcesbyid; + + loading = false; + + comparisonData: ComparisonData[]; + trusteeTypes: { [id: number]: string }; + + async ngOnInit() { + const over = this.loadingService.show(); + try { + this.trusteeTypes = await this.qam.getTrusteeTypes(); + const parent = this.dug.UID_QAMDuGParent.value; + this.dugB = (await this.qam.typedClient.PortalDgeResourcesInteractivebyid.Get_byid(parent)).Data[0]; + + // combine data by trustee + const map = new Map(); + + await this.mapTrusteeA(map); + await this.mapTrusteeB(map, parent); + + this.comparisonData = Array.from(map.values()); + } finally { + this.loadingService.hide(over); + } + } + + private async mapTrusteeA(map: Map): Promise { + const accessA = await this.qam.client.portal_dge_resources_trusteeandpolicyrightset_get(this.dug.UID_QAMDuG.value); + if (accessA.Trustees) { + accessA.Trustees.forEach((element) => { + if (!map.has(element.Display ?? '')) + map.set(element.Display ?? '', { + display: element.Display ?? '', + trusteeType: element.TrusteeType, + }); + + const mapA = map.get(element.Display ?? ''); + if (mapA) { + mapA.accessA = element.Permissions; + } + }); + } + } + + private async mapTrusteeB(map: Map, parent: string): Promise { + const accessB = await this.qam.client.portal_dge_resources_trusteeandpolicyrightset_get(parent); + if (accessB.Trustees) { + accessB.Trustees.forEach((element) => { + if (!map.has(element.Display ?? '')) + map.set(element.Display ?? '', { + display: element.Display ?? '', + trusteeType: element.TrusteeType, + }); + + const mapB = map.get(element.Display ?? ''); + if (mapB) { + mapB.accessB = element.Permissions; + } + }); + } + } + + public LdsHeader = "#LDS#Access rights comparison between '{0}' and '{1}'"; + + public LdsTitle = + '#LDS#The following displays a comparison of the access rights assigned on a security deviated resource and its parent structure.'; + + public LdsSubTitle = + "#LDS#The resource '{0}' has been identified as the parent resource of '{1}'. Without deviated security indexes, the resource '{1}' would have inherited the access permissions which are assigned to '{0}'."; +} diff --git a/imxweb/projects/qam/src/lib/dug/dug-access-analysis.component.html b/imxweb/projects/qam/src/lib/dug/dug-access-analysis.component.html new file mode 100644 index 000000000..515b4d608 --- /dev/null +++ b/imxweb/projects/qam/src/lib/dug/dug-access-analysis.component.html @@ -0,0 +1,17 @@ + + + + + + + + + + + +

    {{ldsAccess | translate}}

    +
      +
    • {{ identity.Display }}
    • +
    +
    +
    \ No newline at end of file diff --git a/imxweb/projects/qam/src/lib/dug/dug-access-analysis.component.ts b/imxweb/projects/qam/src/lib/dug/dug-access-analysis.component.ts new file mode 100644 index 000000000..68fd9f202 --- /dev/null +++ b/imxweb/projects/qam/src/lib/dug/dug-access-analysis.component.ts @@ -0,0 +1,58 @@ +/* + * ONE IDENTITY LLC. PROPRIETARY INFORMATION + * + * This software is confidential. One Identity, LLC. or one of its affiliates or + * subsidiaries, has supplied this software to you under terms of a + * license agreement, nondisclosure agreement or both. + * + * You may not copy, disclose, or use this software except in accordance with + * those terms. + * + * + * Copyright 2024 One Identity LLC. + * ALL RIGHTS RESERVED. + * + * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR + * WARRANTIES ABOUT THE SUITABILITY OF THE SOFTWARE, + * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED + * TO THE IMPLIED WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE, OR + * NON-INFRINGEMENT. ONE IDENTITY LLC. SHALL NOT BE + * LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE + * AS A RESULT OF USING, MODIFYING OR DISTRIBUTING + * THIS SOFTWARE OR ITS DERIVATIVES. + * + */ + +import { Component, Input, OnInit } from '@angular/core'; +import { PortalDgeResourcesbyid, ResourceAccessExpansionPerson } from '../TypedClient'; +import { DugAccessAnalysisService } from './dug-access-analysis.service'; + +@Component({ + templateUrl: './dug-access-analysis.component.html', + selector: 'imx-dge-access-analysis', +}) +export class DugAccessAnalysisComponent implements OnInit { + @Input() public dug: PortalDgeResourcesbyid; + public displayResource: string; + public dugBackingFolder: PortalDgeResourcesbyid; + public identities: ResourceAccessExpansionPerson[]; + public ldsAccess = '#LDS#The following identities have access to the selected resource.'; + + constructor(private readonly dugAccessAnalysisService: DugAccessAnalysisService) {} + + public async ngOnInit(): Promise { + this.displayResource = this.dug.UID_QAMResourceType.Column.GetDisplayValue(); + + if (this.dug.UID_QAMResourceType.value == 'QAM-52F4B02EFBCAEB7A2EE35B8A4636FAEA') { + // load backing folder for windows computer share + + const uidBackingFolder = this.dug.UID_BackingFolder.value; + if (uidBackingFolder) { + this.dugBackingFolder = await this.dugAccessAnalysisService.getBackingFolder(uidBackingFolder); + } + } + + this.identities = await this.dugAccessAnalysisService.getIdentities(this.dug.UID_QAMDuG.value); + } +} diff --git a/imxweb/projects/qam/src/lib/dug/dug-access-analysis.service.ts b/imxweb/projects/qam/src/lib/dug/dug-access-analysis.service.ts new file mode 100644 index 000000000..6e57cba80 --- /dev/null +++ b/imxweb/projects/qam/src/lib/dug/dug-access-analysis.service.ts @@ -0,0 +1,46 @@ +/* + * ONE IDENTITY LLC. PROPRIETARY INFORMATION + * + * This software is confidential. One Identity, LLC. or one of its affiliates or + * subsidiaries, has supplied this software to you under terms of a + * license agreement, nondisclosure agreement or both. + * + * You may not copy, disclose, or use this software except in accordance with + * those terms. + * + * + * Copyright 2024 One Identity LLC. + * ALL RIGHTS RESERVED. + * + * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR + * WARRANTIES ABOUT THE SUITABILITY OF THE SOFTWARE, + * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED + * TO THE IMPLIED WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE, OR + * NON-INFRINGEMENT. ONE IDENTITY LLC. SHALL NOT BE + * LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE + * AS A RESULT OF USING, MODIFYING OR DISTRIBUTING + * THIS SOFTWARE OR ITS DERIVATIVES. + * + */ + +import { Injectable } from '@angular/core'; +import { QamApiService } from '../qam-api-client.service'; +import { ChartDto, PortalDgeResourcesbyid, ResourceAccessExpansionPerson } from '../TypedClient'; + +@Injectable({ providedIn: 'root' }) +export class DugAccessAnalysisService { + constructor(private readonly api: QamApiService) {} + + public async getIdentities(uid): Promise { + return (await this.api.client.portal_dge_resources_identities_get(uid))?.Identities ?? []; + } + + public async getBackingFolder(uid): Promise { + return (await this.api.typedClient.PortalDgeResourcesInteractivebyid.Get_byid(uid)).Data[0]; + } + + public async getChartData(uid, chartid): Promise { + return this.api.client.portal_dge_resources_accesschart_get(uid, chartid); + } +} diff --git a/imxweb/projects/qam/src/lib/dug/dug-access-detail.component.html b/imxweb/projects/qam/src/lib/dug/dug-access-detail.component.html new file mode 100644 index 000000000..018fe3d33 --- /dev/null +++ b/imxweb/projects/qam/src/lib/dug/dug-access-detail.component.html @@ -0,0 +1,27 @@ + + + {{ LdsAccessDeviation | translate }} + {{ LdsInheritanceBlocked | translate }} + + + + {{ LdsAdditionalRights | translate }} + + + + + + +

    {{ LdsViewTitle | translate }}

    + +
    + + + {{ chart?.title }} + + + + + +
    +
    diff --git a/imxweb/projects/qam/src/lib/dug/dug-access-detail.component.scss b/imxweb/projects/qam/src/lib/dug/dug-access-detail.component.scss new file mode 100644 index 000000000..07c88a8e9 --- /dev/null +++ b/imxweb/projects/qam/src/lib/dug/dug-access-detail.component.scss @@ -0,0 +1,46 @@ +@import 'base/mixins'; +@import '@elemental-ui/core/src/styles/_eui_palette.scss'; + +:host { + @include flex-column-container-fill(); + height: 100%; + + .imx-wrapped-chart-container { + @include flex-row-container(); + flex-wrap: wrap; + gap: 10px; + } + + .imx-chart-container { + @include flex-column-container-fill(); + } + + .mat-card-content { + display: flex; + justify-content: center; + } +} + +/* light theme*/ + +:host { + .imx-chart-container { + background-color: $color-gray-2; + } +} + +.eui-dark-theme { + :host { + .imx-chart-container { + background-color: $color-gray-80; + } + } +} + +.eui-contrast-theme { + :host { + .imx-chart-container { + background-color: $color-gray-100; + } + } +} diff --git a/imxweb/projects/qam/src/lib/dug/dug-access-detail.component.ts b/imxweb/projects/qam/src/lib/dug/dug-access-detail.component.ts new file mode 100644 index 000000000..52a99c5ad --- /dev/null +++ b/imxweb/projects/qam/src/lib/dug/dug-access-detail.component.ts @@ -0,0 +1,151 @@ +/* + * ONE IDENTITY LLC. PROPRIETARY INFORMATION + * + * This software is confidential. One Identity, LLC. or one of its affiliates or + * subsidiaries, has supplied this software to you under terms of a + * license agreement, nondisclosure agreement or both. + * + * You may not copy, disclose, or use this software except in accordance with + * those terms. + * + * + * Copyright 2024 One Identity LLC. + * ALL RIGHTS RESERVED. + * + * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR + * WARRANTIES ABOUT THE SUITABILITY OF THE SOFTWARE, + * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED + * TO THE IMPLIED WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE, OR + * NON-INFRINGEMENT. ONE IDENTITY LLC. SHALL NOT BE + * LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE + * AS A RESULT OF USING, MODIFYING OR DISTRIBUTING + * THIS SOFTWARE OR ITS DERIVATIVES. + * + */ + +import { KeyValue } from '@angular/common'; +import { Component, Input, OnInit } from '@angular/core'; +import { TranslateService } from '@ngx-translate/core'; +import { ChartOptions, donut } from 'billboard.js'; +import { SystemInfoService } from 'qbm'; +import { ChartDto, PortalDgeResourcesbyid } from '../TypedClient'; +import { DugAccessAnalysisService } from './dug-access-analysis.service'; + +@Component({ + templateUrl: './dug-access-detail.component.html', + styleUrls: ['./dug-access-detail.component.scss'], + selector: 'imx-dge-access-detail', +}) +export class DugAccessDetailComponent implements OnInit { + public LdsViewTitle = + '#LDS#Analysis of access rights assigned to people using the organizational context such as department structures, locations and titles'; + + public LdsAnalysisTitle2 = '#LDS#Analysis of access rights assigned to people using the access right assignment methods and permissions'; + + public LdsAccessDeviation = '#LDS#The access rights at this folder are deviated from the share/parent folder.'; + + public LdsInheritanceBlocked = '#LDS#The inheritance of access rights (i.e. security inheritance) has been blocked at this folder.'; + + public LdsAdditionalRights = '#LDS#This folder has additional access rights assigned which are not on the share/parent folder.'; + + public charts: ({ + title: string; + noDataMessage: string; + data: ChartOptions; + } | null)[] = []; + + @Input() public dug: PortalDgeResourcesbyid; + + constructor( + private readonly dugAccessAnalysisService: DugAccessAnalysisService, + private readonly systemInfoService: SystemInfoService, + private readonly translate: TranslateService, + ) {} + + public async ngOnInit(): Promise { + this.charts = ( + await Promise.all([ + this.getChart( + 'QAM_AccessAnalysis_Department', + '#LDS#Access analysis by department', + '#LDS#Analysis of access rights, grouped by department, is currently unavailable.', + ), + this.getChart( + 'QAM_AccessAnalysis_PrimaryRoleTitle', + '#LDS#Access analysis by primary role title', + '#LDS#Analysis of access rights, grouped by primary role title, is currently unavailable.', + 'ORG', + ), + this.getChart( + 'QAM_AccessAnalysis_Location', + '#LDS#Access analysis by location', + '#LDS#Analysis of access rights, grouped by location, is currently unavailable.', + ), + ]) + ).filter((x) => x != null); + } + + private async getChart(id: string, titleLds: string, noDataLds: string, preprop?: string) { + if (preprop != null) { + if (!(await this.systemInfoService.get()).PreProps?.includes(preprop)) return null; + } + const noDataMessage = await this.translate.get(noDataLds).toPromise(); + return { + title: await this.translate.get(titleLds).toPromise(), + noDataMessage, + data: this.buildChartOptions(await this.dugAccessAnalysisService.getChartData(this.dug.UID_QAMDuG.value, id), noDataMessage), + }; + } + //#region chart data helper + + private buildChartOptions(chartData: ChartDto, noDataText: string): ChartOptions { + return { + data: { + type: donut(), + columns: chartData?.Data?.map((ch, index) => ['data' + index, ch?.Points?.[0].Value]) as any[], + names: this.toObject(chartData?.Data?.map((ch, index) => ({ key: 'data' + index, value: ch.Name ?? '' })) ?? []), + empty: { + label: { + text: noDataText, + }, + }, + }, + donut: { + padAngle: 0.05, + expand: { + rate: 1.005, + }, + label: { + show: false, + }, + }, + size: { width: 200, height: 200 }, + resize: { + auto: true, + }, + legend: { + show: true, + item: { + onclick: () => false, + }, + }, + padding: { + bottom: 1, + top: 0, + left: 0, + right: 0, + }, + }; + } + + private toObject(array: KeyValue[]): { [key: string]: string } { + const ret = {}; + + for (const elem of array) { + ret[elem.key] = elem.value; + } + return ret; + } + //#endregion +} diff --git a/imxweb/projects/qam/src/lib/dug/dug-access/assigned-permissions/assigned-permissions.component.html b/imxweb/projects/qam/src/lib/dug/dug-access/assigned-permissions/assigned-permissions.component.html new file mode 100644 index 000000000..72829072b --- /dev/null +++ b/imxweb/projects/qam/src/lib/dug/dug-access/assigned-permissions/assigned-permissions.component.html @@ -0,0 +1,30 @@ + + +
    + + + +
    {{ item.GetEntity().GetDisplay() }}
    +
    {{ item.TypeDisplay.value }}
    +
    +
    + + + + + + + + + + + + + +
    +
    +
    diff --git a/imxweb/projects/qam/src/lib/dug/dug-access/assigned-permissions/assigned-permissions.component.scss b/imxweb/projects/qam/src/lib/dug/dug-access/assigned-permissions/assigned-permissions.component.scss new file mode 100644 index 000000000..1be454154 --- /dev/null +++ b/imxweb/projects/qam/src/lib/dug/dug-access/assigned-permissions/assigned-permissions.component.scss @@ -0,0 +1,5 @@ +@import 'base/mixins'; + +:host { + @include flex-column-container-fill(); +} diff --git a/imxweb/projects/qam/src/lib/dug/dug-access/assigned-permissions/assigned-permissions.component.ts b/imxweb/projects/qam/src/lib/dug/dug-access/assigned-permissions/assigned-permissions.component.ts new file mode 100644 index 000000000..9c366ec9c --- /dev/null +++ b/imxweb/projects/qam/src/lib/dug/dug-access/assigned-permissions/assigned-permissions.component.ts @@ -0,0 +1,71 @@ +/* + * ONE IDENTITY LLC. PROPRIETARY INFORMATION + * + * This software is confidential. One Identity, LLC. or one of its affiliates or + * subsidiaries, has supplied this software to you under terms of a + * license agreement, nondisclosure agreement or both. + * + * You may not copy, disclose, or use this software except in accordance with + * those terms. + * + * + * Copyright 2024 One Identity LLC. + * ALL RIGHTS RESERVED. + * + * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR + * WARRANTIES ABOUT THE SUITABILITY OF THE SOFTWARE, + * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED + * TO THE IMPLIED WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE, OR + * NON-INFRINGEMENT. ONE IDENTITY LLC. SHALL NOT BE + * LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE + * AS A RESULT OF USING, MODIFYING OR DISTRIBUTING + * THIS SOFTWARE OR ITS DERIVATIVES. + * + */ + +import { Component, Input, OnChanges, SimpleChanges } from '@angular/core'; +import { DisplayColumns, EntitySchema, IClientProperty } from '@imx-modules/imx-qbm-dbts'; +import { TranslateService } from '@ngx-translate/core'; +import { DataSourceToolbarSettings } from 'qbm'; +import { AssignedResourceAccessData } from '../../../TypedClient'; +import { TrusteeEntity } from './trustee-entity'; + +@Component({ + selector: 'imx-assigned-permissions', + templateUrl: './assigned-permissions.component.html', + styleUrls: ['./assigned-permissions.component.scss'], +}) +export class AssignedPermissionsComponent implements OnChanges { + @Input() trustees: AssignedResourceAccessData; + + public dstSettings: DataSourceToolbarSettings; + public entitySchema: EntitySchema; + private displayedColumns: IClientProperty[] = []; + public readonly DisplayColumns = DisplayColumns; + + constructor(translate: TranslateService) { + this.entitySchema = TrusteeEntity.GetEntitySchema(translate); + this.displayedColumns = [ + this.entitySchema.Columns.Display, + this.entitySchema.Columns.AllowChangePermissions, + this.entitySchema.Columns.AllowFullControl, + this.entitySchema.Columns.AllowWrite, + this.entitySchema.Columns.AllowRead, + this.entitySchema.Columns.AnyAllow, + ]; + } + + public ngOnChanges(changes: SimpleChanges): void { + if (!changes?.trustees == null) { + return; + } + const data = TrusteeEntity.buildEntities(TrusteeEntity.buildEntityData(this.trustees.Trustees), this.entitySchema); + this.dstSettings = { + displayedColumns: this.displayedColumns, + dataSource: data, + entitySchema: this.entitySchema, + navigationState: {}, + }; + } +} diff --git a/imxweb/projects/qam/src/lib/dug/dug-access/assigned-permissions/trustee-entity.ts b/imxweb/projects/qam/src/lib/dug/dug-access/assigned-permissions/trustee-entity.ts new file mode 100644 index 000000000..7b4b24efb --- /dev/null +++ b/imxweb/projects/qam/src/lib/dug/dug-access/assigned-permissions/trustee-entity.ts @@ -0,0 +1,142 @@ +/* + * ONE IDENTITY LLC. PROPRIETARY INFORMATION + * + * This software is confidential. One Identity, LLC. or one of its affiliates or + * subsidiaries, has supplied this software to you under terms of a + * license agreement, nondisclosure agreement or both. + * + * You may not copy, disclose, or use this software except in accordance with + * those terms. + * + * + * Copyright 2024 One Identity LLC. + * ALL RIGHTS RESERVED. + * + * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR + * WARRANTIES ABOUT THE SUITABILITY OF THE SOFTWARE, + * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED + * TO THE IMPLIED WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE, OR + * NON-INFRINGEMENT. ONE IDENTITY LLC. SHALL NOT BE + * LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE + * AS A RESULT OF USING, MODIFYING OR DISTRIBUTING + * THIS SOFTWARE OR ITS DERIVATIVES. + * + */ + +import { + EntityColumnData, + EntityData, + EntitySchema, + ExtendedTypedEntityCollection, + IClientProperty, + IReadValue, + TypedEntity, + TypedEntityBuilder, + ValType, +} from '@imx-modules/imx-qbm-dbts'; + +import { TranslateService } from '@ngx-translate/core'; +import { AssignedResourceAccess } from '../../../TypedClient'; + +export class TrusteeEntity extends TypedEntity { + public readonly Display: IReadValue = this.GetEntityValue('Display'); + public readonly TypeDisplay: IReadValue = this.GetEntityValue('TypeDisplay'); + public readonly TrusteeType: IReadValue = this.GetEntityValue('TrusteeType'); + public readonly AllowWrite: IReadValue = this.GetEntityValue('AllowWrite'); + public readonly AllowRead: IReadValue = this.GetEntityValue('AllowRead'); + public readonly AnyAllow: IReadValue = this.GetEntityValue('AnyAllow'); + public readonly AllowFullControl: IReadValue = this.GetEntityValue('AllowFullControl'); + public readonly AllowChangePermissions: IReadValue = this.GetEntityValue('AllowChangePermissions'); + + public GetDisplay(): string { + return this.Display.value; + } + + public static GetEntitySchema(translate?: TranslateService): EntitySchema { + const returnColumns: { [key: string]: IClientProperty } = {}; + + returnColumns.Display = { + Type: ValType.String, + ColumnName: 'Display', + Display: translate ? translate.instant('#LDS#Display name') : '#LDS#Display name', + }; + + returnColumns.TypeDisplay = { + Type: ValType.String, + ColumnName: 'TypeDisplay', + Display: translate ? translate.instant('#LDS#Type display') : '#LDS#Type display', + }; + + returnColumns.TrusteeType = { + Type: ValType.Int, + ColumnName: 'TrusteeType', + Display: translate ? translate.instant('#LDS#Trustee type') : '#LDS#Trustee type', + }; + + returnColumns.AllowWrite = { + Type: ValType.Bool, + ColumnName: 'AllowWrite', + Display: translate ? translate.instant('#LDS#Allow write') : '#LDS#Allow write', + }; + + returnColumns.AllowRead = { + Type: ValType.Bool, + ColumnName: 'AllowRead', + Display: translate ? translate.instant('#LDS#Allow read') : '#LDS#Allow read', + }; + + returnColumns.AnyAllow = { + Type: ValType.Bool, + ColumnName: 'AnyAllow', + Display: translate ? translate.instant('#LDS#Any allow') : '#LDS#Any allow', + }; + + returnColumns.AllowFullControl = { + Type: ValType.Bool, + ColumnName: 'AllowFullControl', + Display: translate ? translate.instant('#LDS#Allow full control') : '#LDS#Allow full control', + }; + + returnColumns.AllowChangePermissions = { + Type: ValType.Bool, + ColumnName: 'AllowChangePermissions', + Display: translate ? translate.instant('#LDS#Allow change permissions') : '#LDS#Allow change permissions', + }; + + return { + TypeName: 'Trustee', + Display: translate ? translate.instant('#LDS#Trustee') : '#LDS#Trustee', + Columns: returnColumns, + }; + } + + public static buildEntities(entityData: EntityData[], entitySchema: EntitySchema): ExtendedTypedEntityCollection { + const builder = new TypedEntityBuilder(TrusteeEntity); + return builder.buildReadWriteEntities( + { + TotalCount: entityData.length, + Entities: entityData, + }, + entitySchema, + ); + } + + public static buildEntityData(trustees: AssignedResourceAccess[] | undefined): EntityData[] { + return !trustees + ? [] + : trustees.map((elem) => { + const returnColumns: { [key: string]: EntityColumnData } = {}; + returnColumns.Display = { Value: elem.Display, IsReadOnly: true }; + returnColumns.TrusteeType = { Value: elem.TrusteeType, IsReadOnly: true }; + returnColumns.TypeDisplay = { Value: elem.TypeDisplay, IsReadOnly: true }; + returnColumns.AllowWrite = { Value: elem.Permissions?.includes('AllowWrite'), IsReadOnly: true }; + returnColumns.AllowRead = { Value: elem.Permissions?.includes('AllowRead'), IsReadOnly: true }; + returnColumns.AnyAllow = { Value: elem.Permissions?.includes('AnyAllow'), IsReadOnly: true }; + returnColumns.AllowFullControl = { Value: elem.Permissions?.includes('AllowFullControl'), IsReadOnly: true }; + returnColumns.AllowChangePermissions = { Value: elem.Permissions?.includes('AllowChangePermissions'), IsReadOnly: true }; + + return { Columns: returnColumns, Display: elem.Display }; + }); + } +} diff --git a/imxweb/projects/qam/src/lib/dug/dug-access/box-icon/box-icon.component.html b/imxweb/projects/qam/src/lib/dug/dug-access/box-icon/box-icon.component.html new file mode 100644 index 000000000..118d744cb --- /dev/null +++ b/imxweb/projects/qam/src/lib/dug/dug-access/box-icon/box-icon.component.html @@ -0,0 +1,8 @@ +
    +
    {{ display }}
    + +
    + + + + diff --git a/imxweb/projects/qam/src/lib/dug/dug-access/box-icon/box-icon.component.scss b/imxweb/projects/qam/src/lib/dug/dug-access/box-icon/box-icon.component.scss new file mode 100644 index 000000000..68bd73218 --- /dev/null +++ b/imxweb/projects/qam/src/lib/dug/dug-access/box-icon/box-icon.component.scss @@ -0,0 +1,10 @@ +@import 'base/mixins'; + +.imx-single-permission { + @include flex-column-container($overflow: hidden); + align-items: center; + + > div { + text-align: center; + } +} diff --git a/imxweb/projects/qam/src/lib/dug/dug-access/box-icon/box-icon.component.ts b/imxweb/projects/qam/src/lib/dug/dug-access/box-icon/box-icon.component.ts new file mode 100644 index 000000000..5c4761ad7 --- /dev/null +++ b/imxweb/projects/qam/src/lib/dug/dug-access/box-icon/box-icon.component.ts @@ -0,0 +1,37 @@ +/* + * ONE IDENTITY LLC. PROPRIETARY INFORMATION + * + * This software is confidential. One Identity, LLC. or one of its affiliates or + * subsidiaries, has supplied this software to you under terms of a + * license agreement, nondisclosure agreement or both. + * + * You may not copy, disclose, or use this software except in accordance with + * those terms. + * + * + * Copyright 2024 One Identity LLC. + * ALL RIGHTS RESERVED. + * + * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR + * WARRANTIES ABOUT THE SUITABILITY OF THE SOFTWARE, + * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED + * TO THE IMPLIED WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE, OR + * NON-INFRINGEMENT. ONE IDENTITY LLC. SHALL NOT BE + * LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE + * AS A RESULT OF USING, MODIFYING OR DISTRIBUTING + * THIS SOFTWARE OR ITS DERIVATIVES. + * + */ + +import { Component, Input } from '@angular/core'; + +@Component({ + selector: 'imx-box-icon', + templateUrl: './box-icon.component.html', + styleUrls: ['./box-icon.component.scss'], +}) +export class BoxIconComponent { + @Input() public isChecked: boolean; + @Input() public display: string | undefined; +} diff --git a/imxweb/projects/qam/src/lib/dug/dug-access/dug-access.component.html b/imxweb/projects/qam/src/lib/dug/dug-access/dug-access.component.html new file mode 100644 index 000000000..e04683ce4 --- /dev/null +++ b/imxweb/projects/qam/src/lib/dug/dug-access/dug-access.component.html @@ -0,0 +1,21 @@ + + + {{ '#LDS#Show assigned permissions' | translate }} + + + {{ '#LDS#Show effective permissions' | translate }} + + + + +

    {{ ldsAssignedAccess | translate }}

    + + +
    + + +

    #LDS#The following accounts and groups have access to this resource.

    + + + +
    diff --git a/imxweb/projects/qam/src/lib/dug/dug-access/dug-access.component.scss b/imxweb/projects/qam/src/lib/dug/dug-access/dug-access.component.scss new file mode 100644 index 000000000..6f2c8adac --- /dev/null +++ b/imxweb/projects/qam/src/lib/dug/dug-access/dug-access.component.scss @@ -0,0 +1,12 @@ + +@import 'base/mixins'; +:host{ + @include flex-column-container-fill(); + height: 100% +} + + +.trusteetype { + font-style: italic; +} + diff --git a/imxweb/projects/qam/src/lib/dug/dug-access/dug-access.component.ts b/imxweb/projects/qam/src/lib/dug/dug-access/dug-access.component.ts new file mode 100644 index 000000000..0c62d7c7d --- /dev/null +++ b/imxweb/projects/qam/src/lib/dug/dug-access/dug-access.component.ts @@ -0,0 +1,86 @@ +/* + * ONE IDENTITY LLC. PROPRIETARY INFORMATION + * + * This software is confidential. One Identity, LLC. or one of its affiliates or + * subsidiaries, has supplied this software to you under terms of a + * license agreement, nondisclosure agreement or both. + * + * You may not copy, disclose, or use this software except in accordance with + * those terms. + * + * + * Copyright 2024 One Identity LLC. + * ALL RIGHTS RESERVED. + * + * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR + * WARRANTIES ABOUT THE SUITABILITY OF THE SOFTWARE, + * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED + * TO THE IMPLIED WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE, OR + * NON-INFRINGEMENT. ONE IDENTITY LLC. SHALL NOT BE + * LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE + * AS A RESULT OF USING, MODIFYING OR DISTRIBUTING + * THIS SOFTWARE OR ITS DERIVATIVES. + * + */ + +import { ChangeDetectorRef, Component, Input, OnDestroy, OnInit } from '@angular/core'; +import { QamApiService } from '../../qam-api-client.service'; +import { AssignedResourceAccessData, PortalDgeResources, ResourceAccessData } from '../../TypedClient'; +import { BusyService } from 'qbm'; +import { Subscription } from 'rxjs'; + +@Component({ + templateUrl: './dug-access.component.html', + styleUrls: ['./dug-access.component.scss'], + selector: 'imx-dge-access', +}) +export class DugAccessComponent implements OnInit, OnDestroy { + @Input() public dug: PortalDgeResources; + @Input() public IsReadOnly: boolean = false; + + public isShowEffectivePermissions: boolean = false; + + public trusteeTypes: { [id: number]: string }; + + /** assigned access permissions */ + public assigned: AssignedResourceAccessData; + + /** effective access permissions */ + public data: ResourceAccessData; + + public isLoading: boolean = false; + + public busyService = new BusyService(); + private busySubscription: Subscription; + + constructor( + private readonly api: QamApiService, + private readonly changeDetector: ChangeDetectorRef, + ) { + this.busySubscription = this.busyService.busyStateChanged.subscribe((state: boolean) => { + this.isLoading = state; + this.changeDetector.detectChanges(); + }); + } + + public ngOnDestroy(): void { + this.busySubscription?.unsubscribe(); + } + + public async ngOnInit() { + const isBusy = this.busyService.beginBusy(); + try { + const uidDug = this.dug.GetEntity().GetKeys()[0]; + this.trusteeTypes = await this.api.getTrusteeTypes(); + this.data = await this.api.client.portal_dge_resources_access_get(uidDug); + this.assigned = await this.api.client.portal_dge_resources_trusteeandpolicyrightset_get(uidDug); + } finally { + isBusy.endBusy(); + } + } + + + public ldsAssignedAccess = + '#LDS#Access permissions are assigned to the following accounts and groups. If the access permissions are not correct, you can request a modification.'; +} diff --git a/imxweb/projects/qbm/src/lib/select/select.module.ts b/imxweb/projects/qam/src/lib/dug/dug-access/dug-access.module.ts similarity index 50% rename from imxweb/projects/qbm/src/lib/select/select.module.ts rename to imxweb/projects/qam/src/lib/dug/dug-access/dug-access.module.ts index c64e27534..bda69da63 100644 --- a/imxweb/projects/qbm/src/lib/select/select.module.ts +++ b/imxweb/projects/qam/src/lib/dug/dug-access/dug-access.module.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -24,48 +24,48 @@ * */ -import { NgModule } from '@angular/core'; import { CommonModule } from '@angular/common'; -import { ReactiveFormsModule, FormsModule } from '@angular/forms'; -import { MatAutocompleteModule } from '@angular/material/autocomplete'; +import { NgModule } from '@angular/core'; +import { FormsModule } from '@angular/forms'; import { MatButtonModule } from '@angular/material/button'; -import { MatCheckboxModule } from '@angular/material/checkbox'; -import { MatChipsModule } from '@angular/material/chips'; +import { MatCardModule } from '@angular/material/card'; import { MatIconModule } from '@angular/material/icon'; -import { MatInputModule } from '@angular/material/input'; -import { MatPaginatorModule } from '@angular/material/paginator'; -import { MatProgressSpinnerModule } from '@angular/material/progress-spinner'; +import { MatRadioModule } from '@angular/material/radio'; +import { MatSidenavModule } from '@angular/material/sidenav'; +import { MatTreeModule } from '@angular/material/tree'; import { EuiCoreModule } from '@elemental-ui/core'; -import { ScrollingModule } from '@angular/cdk/scrolling'; import { TranslateModule } from '@ngx-translate/core'; -import { OverlayModule } from '@angular/cdk/overlay'; - -import { SelectComponent } from './select.component'; -import { AutocompleteComponent } from './autocomplete.component'; +import { BusyIndicatorModule, DataSourceToolbarModule, DataTableModule, DataTreeModule } from 'qbm'; +import { AssignedPermissionsComponent } from './assigned-permissions/assigned-permissions.component'; +import { BoxIconComponent } from './box-icon/box-icon.component'; +import { DugAccessComponent } from './dug-access.component'; +import { EffectivePermissionComponent } from './effective-permission/effective-permission.component'; +import { PermissionMemberComponent } from './effective-permission/permission-member/permission-member.component'; @NgModule({ declarations: [ - SelectComponent, - AutocompleteComponent + DugAccessComponent, + AssignedPermissionsComponent, + EffectivePermissionComponent, + PermissionMemberComponent, + BoxIconComponent, ], imports: [ CommonModule, - EuiCoreModule, - MatAutocompleteModule, - MatChipsModule, - MatIconModule, - MatInputModule, + DataTableModule, + DataSourceToolbarModule, + MatRadioModule, MatButtonModule, - MatCheckboxModule, - ScrollingModule, - MatProgressSpinnerModule, + MatCardModule, + MatTreeModule, + MatIconModule, + TranslateModule, FormsModule, - MatPaginatorModule, - ReactiveFormsModule, - TranslateModule - ], - exports: [ - SelectComponent + EuiCoreModule, + DataTreeModule, + MatSidenavModule, + BusyIndicatorModule, ], + exports: [DugAccessComponent, BoxIconComponent], }) -export class SelectModule { } +export class DugAccessModule {} diff --git a/imxweb/projects/qam/src/lib/dug/dug-access/effective-permission/effective-permission-tree-database.ts b/imxweb/projects/qam/src/lib/dug/dug-access/effective-permission/effective-permission-tree-database.ts new file mode 100644 index 000000000..49104b5cf --- /dev/null +++ b/imxweb/projects/qam/src/lib/dug/dug-access/effective-permission/effective-permission-tree-database.ts @@ -0,0 +1,52 @@ +/* + * ONE IDENTITY LLC. PROPRIETARY INFORMATION + * + * This software is confidential. One Identity, LLC. or one of its affiliates or + * subsidiaries, has supplied this software to you under terms of a + * license agreement, nondisclosure agreement or both. + * + * You may not copy, disclose, or use this software except in accordance with + * those terms. + * + * + * Copyright 2024 One Identity LLC. + * ALL RIGHTS RESERVED. + * + * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR + * WARRANTIES ABOUT THE SUITABILITY OF THE SOFTWARE, + * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED + * TO THE IMPLIED WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE, OR + * NON-INFRINGEMENT. ONE IDENTITY LLC. SHALL NOT BE + * LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE + * AS A RESULT OF USING, MODIFYING OR DISTRIBUTING + * THIS SOFTWARE OR ITS DERIVATIVES. + * + */ + +import { TreeDatabase, TreeNodeResultParameter } from 'qbm'; +import { TrusteeEntityHierarchy } from './trustee-entity-hierarchy'; +import { CollectionLoadParameters, IEntity } from '@imx-modules/imx-qbm-dbts'; + +export class EffectivePermissionTreeDatabase extends TreeDatabase { + public constructor(private entities: TrusteeEntityHierarchy[]) { + super(); + this.entities.forEach((entity) => (entity.HasChildren.value = this.entities.some((ent) => ent.Parent.value === entity.Display.value))); + } + + public async getData(showLoading: boolean, parameters: CollectionLoadParameters = {}): Promise { + + const entities = this.entities.filter(element => element.Parent.value === parameters.ParentKey) + return { + entities: entities.map((element) => element.GetEntity()), + canLoadMore: false, + totalCount: entities.length, + }; + } + + public getId(entity: IEntity): string { + return entity.GetColumn('Display')?.GetValue() ?? ''; + } + + +} diff --git a/imxweb/projects/qam/src/lib/dug/dug-access/effective-permission/effective-permission.component.html b/imxweb/projects/qam/src/lib/dug/dug-access/effective-permission/effective-permission.component.html new file mode 100644 index 000000000..b4d8b26f2 --- /dev/null +++ b/imxweb/projects/qam/src/lib/dug/dug-access/effective-permission/effective-permission.component.html @@ -0,0 +1,50 @@ + +

    {{ '#LDS#Trustee' | translate }}

    + + + +
    + {{ node.item?.GetDisplay() }} + + ( + {{ node.item?.columns?.TypeDisplay.GetValue() }} + ) + +
    +
    +
    +
    +
    +
    +

    {{ displayedEntity?.GetDisplay() }}

    + + + Permissions + +
    + +
    +
    +
    + +
    +
    + + +
    + +

    +
    +
    diff --git a/imxweb/projects/qam/src/lib/dug/dug-access/effective-permission/effective-permission.component.scss b/imxweb/projects/qam/src/lib/dug/dug-access/effective-permission/effective-permission.component.scss new file mode 100644 index 000000000..15b9062de --- /dev/null +++ b/imxweb/projects/qam/src/lib/dug/dug-access/effective-permission/effective-permission.component.scss @@ -0,0 +1,153 @@ +@import 'base/mixins'; +@import '@elemental-ui/core/src/styles/_eui_palette.scss'; + +:host { + @include flex-row-container-fill(); + overflow: hidden; + + h3 { + font-size: 16px; + font-weight: 600; + line-height: 20px; + padding-bottom: 5px; + } + + .dug-tree-card { + @include flex-column-container-fill(); + max-width: 500px; + min-width: 500px; + margin: 3px; + } + + .dug-tree-content { + @include flex-column-container-fill(); + margin: 3px; + } + + .effective-permission-content { + @include flex-column-container-fill(); + + h3 { + font-size: 20px; + font-weight: 600; + } + } + + .effective-permission-content-card { + @include flex-column-container-fill(); + } + + .imx-single-permission { + @include flex-column-container($overflow: hidden); + align-items: center; + } + + .imx-no-results { + flex: 1 1 auto; + } + + .imx-trustee-text { + display: flex; + justify-content: center; + align-items: center; + padding: 10px; + } + span[italic] { + font-style: italic; + } + + span[caption] { + margin-right: 10px; + font-weight: 600; + } + + .mat-mdc-card { + .mat-mdc-card-header { + margin-bottom: 20px; + font-weight: 600; + align-items: center; + @include flex-column-container(); + } + .mat-mdc-card-content { + @include flex-row-container-fill(); + } + } + + .imx-scrollable { + overflow: auto; + } +} + +:host { + .imx-no-results { + p { + color: $color-gray-50; + } + } + + .effective-permission-content { + h3 { + color: $color-gray-40; + } + } + + ::ng-deep .mat-tree { + background-color: transparent; + } + + .effective-permission-content-card { + background-color: $color-gray-2; + border: 1px solid $color-gray-10; + } +} + +.eui-dark-theme { + :host { + .imx-no-results { + p { + color: $color-gray-10; + } + } + + .effective-permission-content { + h3 { + color: $color-gray-10; + } + } + + .effective-permission-content-card { + background-color: $color-gray-80; + border: 1px solid $color-gray-90; + } + } +} + +.eui-contrast-theme { + :host { + .imx-no-results { + p { + color: $color-gray-0; + } + } + + .effective-permission-content { + h3 { + color: $color-gray-0; + } + } + + .effective-permission-content-card { + background-color: $color-gray-100; + border: 1px solid $color-gray-0; + } + } +} + +@media screen and (max-width: 1024px) { + :host { + .dug-tree-card { + max-width: 300px; + min-width: 300px; + } + } +} diff --git a/imxweb/projects/qam/src/lib/dug/dug-access/effective-permission/effective-permission.component.ts b/imxweb/projects/qam/src/lib/dug/dug-access/effective-permission/effective-permission.component.ts new file mode 100644 index 000000000..9f4d4ebaa --- /dev/null +++ b/imxweb/projects/qam/src/lib/dug/dug-access/effective-permission/effective-permission.component.ts @@ -0,0 +1,89 @@ +/* + * ONE IDENTITY LLC. PROPRIETARY INFORMATION + * + * This software is confidential. One Identity, LLC. or one of its affiliates or + * subsidiaries, has supplied this software to you under terms of a + * license agreement, nondisclosure agreement or both. + * + * You may not copy, disclose, or use this software except in accordance with + * those terms. + * + * + * Copyright 2024 One Identity LLC. + * ALL RIGHTS RESERVED. + * + * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR + * WARRANTIES ABOUT THE SUITABILITY OF THE SOFTWARE, + * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED + * TO THE IMPLIED WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE, OR + * NON-INFRINGEMENT. ONE IDENTITY LLC. SHALL NOT BE + * LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE + * AS A RESULT OF USING, MODIFYING OR DISTRIBUTING + * THIS SOFTWARE OR ITS DERIVATIVES. + * + */ + +import { Component, Input, OnChanges, SimpleChanges } from '@angular/core'; +import { EntitySchema, IClientProperty, IEntity } from '@imx-modules/imx-qbm-dbts'; +import { TranslateService } from '@ngx-translate/core'; +import { AssignedResourceAccessData, ResourceAccessMembersData, ResourceAccessTrusteeData } from '../../../TypedClient'; + +import { TreeDatabase } from 'qbm'; +import { EffectivePermissionTreeDatabase } from './effective-permission-tree-database'; +import { TrusteeEntityHierarchy } from './trustee-entity-hierarchy'; + +@Component({ + selector: 'imx-effective-permission', + templateUrl: './effective-permission.component.html', + styleUrls: ['./effective-permission.component.scss', '../../../qam.scss'], +}) +export class EffectivePermissionComponent implements OnChanges { + @Input() trustees: AssignedResourceAccessData; + @Input() accessData: ResourceAccessTrusteeData[]; + + @Input() trusteeTypes: { [id: number]: string }; + + public entitySchema: EntitySchema; + + public displayedEntity: IEntity; + public permissionColumns: IClientProperty[]; + + public treeDataBase: TreeDatabase; + + public entities: TrusteeEntityHierarchy[]; + + public members: ResourceAccessMembersData[]; + + /* */ + + constructor(translate: TranslateService) { + this.entitySchema = TrusteeEntityHierarchy.GetEntitySchema(translate); + + this.permissionColumns = [ + this.entitySchema.Columns.AllowWrite, + this.entitySchema.Columns.AllowRead, + this.entitySchema.Columns.AnyAllow, + this.entitySchema.Columns.AllowFullControl, + this.entitySchema.Columns.AllowChangePermissions, + ]; + } + + public ngOnChanges(changes: SimpleChanges): void { + if (changes?.trustees?.currentValue?.Trustees == null) { + return; + } + this.entities = TrusteeEntityHierarchy.buildEntities( + TrusteeEntityHierarchy.buildEntityData(this.trustees.Trustees), + this.entitySchema, + ).Data; + this.treeDataBase = new EffectivePermissionTreeDatabase(this.entities); + + this.treeDataBase.dataReloaded$.next(true); + } + + public async showDetails(entity: IEntity): Promise { + this.displayedEntity = entity; + this.members = this.accessData.find((elem) => elem.Display === entity.GetColumn('Display').GetValue())?.Members ?? []; + } +} diff --git a/imxweb/projects/qam/src/lib/dug/dug-access/effective-permission/permission-member/permission-member.component.html b/imxweb/projects/qam/src/lib/dug/dug-access/effective-permission/permission-member/permission-member.component.html new file mode 100644 index 000000000..a6f0f63d1 --- /dev/null +++ b/imxweb/projects/qam/src/lib/dug/dug-access/effective-permission/permission-member/permission-member.component.html @@ -0,0 +1,46 @@ + + Members + + + + + + + + + + + + + + + + + + +
    + {{ node.name }} + + ( + {{ node.item.TypeDisplay }} + ) + +
    + + + +
    + + +
    + +

    +
    +
    diff --git a/imxweb/projects/qam/src/lib/dug/dug-access/effective-permission/permission-member/permission-member.component.scss b/imxweb/projects/qam/src/lib/dug/dug-access/effective-permission/permission-member/permission-member.component.scss new file mode 100644 index 000000000..848628059 --- /dev/null +++ b/imxweb/projects/qam/src/lib/dug/dug-access/effective-permission/permission-member/permission-member.component.scss @@ -0,0 +1,85 @@ +@import 'base/mixins'; +@import '@elemental-ui/core/src/styles/_eui_palette.scss'; + +:host { + @include flex-column-container-fill(); + + .effective-permission-content-card-members { + @include flex-column-container-fill(); + } + + .imx-member-text { + display: flex; + justify-content: center; + align-items: center; + padding: 10px; + } + + .imx-warning-text { + margin-left: auto; + margin-bottom: 3px; + display: flex; + justify-content: center; + align-items: center; + + ::ng-deep .eui-alert { + padding: 10px; + } + } + .imx-no-results { + flex: 1 1 auto; + p { + font-size: 18px; + } + } + + .mat-card { + .mat-card-header { + padding-bottom: 20px; + font-weight: 600; + align-items: center; + @include flex-column-container(); + } + .mat-card-content { + @include flex-row-container-fill(); + overflow: auto; + } + } + + span[italic] { + font-style: italic; + } + + span[caption] { + margin-right: 10px; + font-weight: 600; + } +} + +:host { + .imx-no-results { + p { + color: $color-gray-50; + } + } +} + +.eui-dark-theme { + :host { + .imx-no-results { + p { + color: $color-gray-10; + } + } + } +} + +.eui-contrast-theme { + :host { + .imx-no-results { + p { + color: $color-gray-0; + } + } + } +} diff --git a/imxweb/projects/qam/src/lib/dug/dug-access/effective-permission/permission-member/permission-member.component.ts b/imxweb/projects/qam/src/lib/dug/dug-access/effective-permission/permission-member/permission-member.component.ts new file mode 100644 index 000000000..20e0040e4 --- /dev/null +++ b/imxweb/projects/qam/src/lib/dug/dug-access/effective-permission/permission-member/permission-member.component.ts @@ -0,0 +1,91 @@ +/* + * ONE IDENTITY LLC. PROPRIETARY INFORMATION + * + * This software is confidential. One Identity, LLC. or one of its affiliates or + * subsidiaries, has supplied this software to you under terms of a + * license agreement, nondisclosure agreement or both. + * + * You may not copy, disclose, or use this software except in accordance with + * those terms. + * + * + * Copyright 2024 One Identity LLC. + * ALL RIGHTS RESERVED. + * + * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR + * WARRANTIES ABOUT THE SUITABILITY OF THE SOFTWARE, + * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED + * TO THE IMPLIED WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE, OR + * NON-INFRINGEMENT. ONE IDENTITY LLC. SHALL NOT BE + * LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE + * AS A RESULT OF USING, MODIFYING OR DISTRIBUTING + * THIS SOFTWARE OR ITS DERIVATIVES. + * + */ + +import { FlatTreeControl } from '@angular/cdk/tree'; +import { Component, Input, OnChanges, SimpleChanges } from '@angular/core'; +import { MatTreeFlatDataSource, MatTreeFlattener } from '@angular/material/tree'; +import { IEntity } from '@imx-modules/imx-qbm-dbts'; +import { ResourceAccessMembersData } from '../../../../TypedClient'; + +interface ExampleFlatNode { + expandable: boolean; + name: string; + item: ResourceAccessMembersData; + level: number; +} + +@Component({ + selector: 'imx-permission-member', + templateUrl: './permission-member.component.html', + styleUrls: ['./permission-member.component.scss'], +}) +export class PermissionMemberComponent implements OnChanges { + /** Methods and functions for the tree*/ + + public treeControl = new FlatTreeControl( + (node) => node.level, + (node) => node.expandable, + ); + + private _transformer = (node: ResourceAccessMembersData, level: number) => { + return { + expandable: !!node.Members && node.Members.length > 0, + name: node.Display ?? '', + item: node, + level: level, + }; + }; + + private treeFlattener = new MatTreeFlattener( + this._transformer, + (node) => node.level, + (node) => node.expandable, + (node) => node.Members, + ); + public dataSource: MatTreeFlatDataSource | undefined = + new MatTreeFlatDataSource(this.treeControl, this.treeFlattener); + + public hasChild = (_: number, node: ExampleFlatNode) => node.expandable; + + /** Inputs */ + @Input() public members: ResourceAccessMembersData[]; + @Input() public displayedEntity: IEntity; + + /**LDS texts */ + public circularWarningText = '#LDS#There is a circular membership dependency. Please check the members inheritance.'; + + public ngOnChanges(changes: SimpleChanges): void { + if (!changes.members) { + return; + } + if (this.members == null || this.members.length <= 0) { + this.dataSource = undefined; + } else { + this.dataSource = new MatTreeFlatDataSource(this.treeControl, this.treeFlattener); + this.dataSource.data = this.members; + } + } +} diff --git a/imxweb/projects/qam/src/lib/dug/dug-access/effective-permission/trustee-entity-hierarchy.ts b/imxweb/projects/qam/src/lib/dug/dug-access/effective-permission/trustee-entity-hierarchy.ts new file mode 100644 index 000000000..aeb4d9cff --- /dev/null +++ b/imxweb/projects/qam/src/lib/dug/dug-access/effective-permission/trustee-entity-hierarchy.ts @@ -0,0 +1,190 @@ +/* + * ONE IDENTITY LLC. PROPRIETARY INFORMATION + * + * This software is confidential. One Identity, LLC. or one of its affiliates or + * subsidiaries, has supplied this software to you under terms of a + * license agreement, nondisclosure agreement or both. + * + * You may not copy, disclose, or use this software except in accordance with + * those terms. + * + * + * Copyright 2024 One Identity LLC. + * ALL RIGHTS RESERVED. + * + * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR + * WARRANTIES ABOUT THE SUITABILITY OF THE SOFTWARE, + * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED + * TO THE IMPLIED WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE, OR + * NON-INFRINGEMENT. ONE IDENTITY LLC. SHALL NOT BE + * LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE + * AS A RESULT OF USING, MODIFYING OR DISTRIBUTING + * THIS SOFTWARE OR ITS DERIVATIVES. + * + */ + +import { + EntityColumnData, + EntityData, + EntitySchema, + ExtendedTypedEntityCollection, + IClientProperty, + IReadValue, + IWriteValue, + TypedEntity, + TypedEntityBuilder, + ValType, +} from '@imx-modules/imx-qbm-dbts'; + +import { TranslateService } from '@ngx-translate/core'; +import { AssignedResourceAccess } from '../../../TypedClient'; + +export class TrusteeEntityHierarchy extends TypedEntity { + public readonly Display: IReadValue = this.GetEntityValue('Display'); + public readonly TypeDisplay: IReadValue = this.GetEntityValue('TypeDisplay'); + public readonly TrusteeType: IReadValue = this.GetEntityValue('TrusteeType'); + public readonly AllowWrite: IReadValue = this.GetEntityValue('AllowWrite'); + public readonly AllowRead: IReadValue = this.GetEntityValue('AllowRead'); + public readonly AnyAllow: IReadValue = this.GetEntityValue('AnyAllow'); + public readonly AllowFullControl: IReadValue = this.GetEntityValue('AllowFullControl'); + public readonly AllowChangePermissions: IReadValue = this.GetEntityValue('AllowChangePermissions'); + public readonly Parent: IReadValue = this.GetEntityValue('Parent'); + public readonly HasChildren: IWriteValue = this.GetEntityValue('HasChildren'); + public readonly HasPermissions: IWriteValue = this.GetEntityValue('HasPermissions'); + + public static GetEntitySchema(translate?: TranslateService): EntitySchema { + const returnColumns: { [key: string]: IClientProperty } = {}; + + returnColumns.Display = { + Type: ValType.String, + ColumnName: 'Display', + Display: translate ? translate.instant('#LDS#Display name') : '#LDS#Display name', + }; + + returnColumns.TypeDisplay = { + Type: ValType.String, + ColumnName: 'TypeDisplay', + Display: translate ? translate.instant('#LDS#Type display') : '#LDS#Type display', + }; + + returnColumns.TrusteeType = { + Type: ValType.Int, + ColumnName: 'TrusteeType', + Display: translate ? translate.instant('#LDS#Trustee type') : '#LDS#Trustee type', + }; + + returnColumns.HasPermissions = { + Type: ValType.Bool, + ColumnName: 'HasPermissions', + }; + + returnColumns.AllowWrite = { + Type: ValType.Bool, + ColumnName: 'AllowWrite', + Display: translate ? translate.instant('#LDS#Allow write') : '#LDS#Allow write', + }; + + returnColumns.AllowRead = { + Type: ValType.Bool, + ColumnName: 'AllowRead', + Display: translate ? translate.instant('#LDS#Allow read') : '#LDS#Allow read', + }; + + returnColumns.AnyAllow = { + Type: ValType.Bool, + ColumnName: 'AnyAllow', + Display: translate ? translate.instant('#LDS#Any allow') : '#LDS#Any allow', + }; + + returnColumns.AllowFullControl = { + Type: ValType.Bool, + ColumnName: 'AllowFullControl', + Display: translate ? translate.instant('#LDS#Allow full control') : '#LDS#Allow full control', + }; + + returnColumns.AllowChangePermissions = { + Type: ValType.Bool, + ColumnName: 'AllowChangePermissions', + Display: translate ? translate.instant('#LDS#Allow change permissions') : '#LDS#Allow change permissions', + }; + + returnColumns.Parent = { + Type: ValType.String, + ColumnName: 'Parent', + }; + + returnColumns.HasChildren = { + Type: ValType.Bool, + ColumnName: 'HasChildren', + }; + + return { + TypeName: 'Trustee', + Display: translate ? translate.instant('#LDS#Trustee') : '#LDS#Trustee', + Columns: returnColumns, + }; + } + + public static buildEntities( + entityData: EntityData[], + entitySchema: EntitySchema, + ): ExtendedTypedEntityCollection { + const builder = new TypedEntityBuilder(TrusteeEntityHierarchy); + return builder.buildReadWriteEntities( + { + TotalCount: entityData.length, + Entities: entityData, + }, + entitySchema, + ); + } + + public static buildEntityData(trustees: AssignedResourceAccess[] | undefined): EntityData[] { + return !trustees + ? [] + : trustees.concat(this.getMissingParent(trustees)).map((elem) => { + const returnColumns: { [key: string]: EntityColumnData } = {}; + returnColumns.Display = { Value: elem.Display, IsReadOnly: true }; + returnColumns.TrusteeType = { Value: elem.TrusteeType, IsReadOnly: true }; + returnColumns.TypeDisplay = { Value: elem.TypeDisplay, IsReadOnly: true }; + returnColumns.HasPermissions = { Value: elem.Permissions != null, IsReadOnly: true }; + returnColumns.AllowWrite = { Value: elem.Permissions?.includes('AllowWrite'), IsReadOnly: true }; + returnColumns.AllowRead = { Value: elem.Permissions?.includes('AllowRead'), IsReadOnly: true }; + returnColumns.AnyAllow = { Value: elem.Permissions?.includes('AnyAllow'), IsReadOnly: true }; + returnColumns.AllowFullControl = { Value: elem.Permissions?.includes('AllowFullControl'), IsReadOnly: true }; + returnColumns.AllowChangePermissions = { Value: elem.Permissions?.includes('AllowChangePermissions'), IsReadOnly: true }; + returnColumns.Parent = { + Value: this.getParentValue(elem.Display), + IsReadOnly: true, + DisplayValue: this.getParentDisplay(elem.Display), + }; + returnColumns.HasChildren = { IsReadOnly: false }; + + return { Columns: returnColumns, Display: elem.Display?.split('\\').pop() }; + }); + } + + private static getMissingParent(trustees: AssignedResourceAccess[]): AssignedResourceAccess[] { + const parentValues = trustees.map((elem) => this.getParentValue(elem.Display)); + const missing = [...new Set(parentValues.filter((elem) => trustees.every((trus) => trus.Display !== elem)))]; + return missing.map((elem) => ({ TrusteeType: -1, Display: elem })).filter((elem) => elem.Display !== ''); + } + + private static getParentDisplay(parent: string | undefined): string { + if (parent == null || parent?.indexOf('\\') === -1) { + return ''; + } + const parts = parent.split('\\'); + return parts[parts.length - 2]; + } + + private static getParentValue(parent: string | undefined): string { + if (parent == null || parent?.indexOf('\\') === -1) { + return ''; + } + const parts = parent.split('\\'); + parts.pop(); + return parts.join('\\'); + } +} diff --git a/imxweb/projects/qam/src/lib/dug/dug-activity/dug-activity.component.html b/imxweb/projects/qam/src/lib/dug/dug-activity/dug-activity.component.html new file mode 100644 index 000000000..7811bfe33 --- /dev/null +++ b/imxweb/projects/qam/src/lib/dug/dug-activity/dug-activity.component.html @@ -0,0 +1,14 @@ +

    + {{ '#LDS#The following activity has been logged for this resource in the last {0} days.' | translate | ldsReplace: interval }} +

    + + + + + + + + diff --git a/imxweb/projects/qam/src/lib/dug/dug-activity/dug-activity.component.scss b/imxweb/projects/qam/src/lib/dug/dug-activity/dug-activity.component.scss new file mode 100644 index 000000000..4f71d1c8b --- /dev/null +++ b/imxweb/projects/qam/src/lib/dug/dug-activity/dug-activity.component.scss @@ -0,0 +1,9 @@ + +@import 'base/mixins'; +:host{ + @include flex-column-container-fill(); + height: 100% +} +.imx-no-results .eui-icon { + font-size: 100px; +} \ No newline at end of file diff --git a/imxweb/projects/qam/src/lib/dug/dug-activity/dug-activity.component.ts b/imxweb/projects/qam/src/lib/dug/dug-activity/dug-activity.component.ts new file mode 100644 index 000000000..bd59d1dbc --- /dev/null +++ b/imxweb/projects/qam/src/lib/dug/dug-activity/dug-activity.component.ts @@ -0,0 +1,64 @@ +/* + * ONE IDENTITY LLC. PROPRIETARY INFORMATION + * + * This software is confidential. One Identity, LLC. or one of its affiliates or + * subsidiaries, has supplied this software to you under terms of a + * license agreement, nondisclosure agreement or both. + * + * You may not copy, disclose, or use this software except in accordance with + * those terms. + * + * + * Copyright 2024 One Identity LLC. + * ALL RIGHTS RESERVED. + * + * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR + * WARRANTIES ABOUT THE SUITABILITY OF THE SOFTWARE, + * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED + * TO THE IMPLIED WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE, OR + * NON-INFRINGEMENT. ONE IDENTITY LLC. SHALL NOT BE + * LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE + * AS A RESULT OF USING, MODIFYING OR DISTRIBUTING + * THIS SOFTWARE OR ITS DERIVATIVES. + * + */ + +import { Component, Input, OnInit } from '@angular/core'; +import { DisplayColumns, EntitySchema, IClientProperty } from '@imx-modules/imx-qbm-dbts'; +import { DataSourceToolbarSettings } from 'qbm'; +import { PortalDgeResourcesActivity } from '../../TypedClient'; + +@Component({ + selector: 'imx-dug-activity', + templateUrl: './dug-activity.component.html', + styleUrls: ['./dug-activity.component.scss'], +}) +export class DugActivityComponent implements OnInit { + @Input() public interval: number; + @Input() public activities: PortalDgeResourcesActivity[]; + + private displayedColumns: IClientProperty[] = []; + public readonly DisplayColumns = DisplayColumns; + public entitySchema: EntitySchema; + public dstSettings: DataSourceToolbarSettings; + + constructor() { + this.entitySchema = PortalDgeResourcesActivity.GetEntitySchema(); + this.displayedColumns = [ + this.entitySchema.Columns.UID_QAMTrustee, + this.entitySchema.Columns.Operation, + this.entitySchema.Columns.Resources, + this.entitySchema.Columns.Activities, + ]; + } + + public async ngOnInit(): Promise { + this.dstSettings = { + dataSource: { Data: this.activities, totalCount: this.activities.length }, + entitySchema: this.entitySchema, + navigationState: {}, + displayedColumns: this.displayedColumns, + }; + } +} diff --git a/imxweb/projects/o3t/src/lib/o3t-config.module.ts b/imxweb/projects/qam/src/lib/dug/dug-activity/dug-activity.module.ts similarity index 74% rename from imxweb/projects/o3t/src/lib/o3t-config.module.ts rename to imxweb/projects/qam/src/lib/dug/dug-activity/dug-activity.module.ts index ae1278783..c7a5cba5c 100644 --- a/imxweb/projects/o3t/src/lib/o3t-config.module.ts +++ b/imxweb/projects/qam/src/lib/dug/dug-activity/dug-activity.module.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -24,28 +24,27 @@ * */ -import { CommonModule } from '@angular/common'; import { NgModule } from '@angular/core'; - +import { CommonModule } from '@angular/common'; +import { DugActivityComponent } from '../dug-activity/dug-activity.component'; import { TranslateModule } from '@ngx-translate/core'; +import { DataSourceToolbarModule, DataTableModule, LdsReplaceModule } from 'qbm'; -import { EuiCoreModule } from '@elemental-ui/core'; -import { ClassloggerService } from 'qbm'; @NgModule({ declarations: [ + DugActivityComponent ], imports: [ CommonModule, TranslateModule, - EuiCoreModule + LdsReplaceModule, + DataSourceToolbarModule, + DataTableModule + ], + exports: [ + DugActivityComponent ] }) -export class O3TConfigModule { - constructor(private readonly logger: ClassloggerService) { - this.logger.info(this, '🔥 O3T loaded'); - - this.logger.info(this, '▶️ O3T initialized'); - } -} +export class DugActivityModule { } diff --git a/imxweb/projects/qam/src/lib/dug/dug-reports/dug-report-entity.ts b/imxweb/projects/qam/src/lib/dug/dug-reports/dug-report-entity.ts new file mode 100644 index 000000000..c7d460976 --- /dev/null +++ b/imxweb/projects/qam/src/lib/dug/dug-reports/dug-report-entity.ts @@ -0,0 +1,96 @@ +/* + * ONE IDENTITY LLC. PROPRIETARY INFORMATION + * + * This software is confidential. One Identity, LLC. or one of its affiliates or + * subsidiaries, has supplied this software to you under terms of a + * license agreement, nondisclosure agreement or both. + * + * You may not copy, disclose, or use this software except in accordance with + * those terms. + * + * + * Copyright 2024 One Identity LLC. + * ALL RIGHTS RESERVED. + * + * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR + * WARRANTIES ABOUT THE SUITABILITY OF THE SOFTWARE, + * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED + * TO THE IMPLIED WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE, OR + * NON-INFRINGEMENT. ONE IDENTITY LLC. SHALL NOT BE + * LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE + * AS A RESULT OF USING, MODIFYING OR DISTRIBUTING + * THIS SOFTWARE OR ITS DERIVATIVES. + * + */ + +import { + EntityColumnData, + EntityData, + EntitySchema, + ExtendedTypedEntityCollection, + IClientProperty, + TypedEntity, + TypedEntityBuilder, + ValType, +} from '@imx-modules/imx-qbm-dbts'; +import { TranslateService } from '@ngx-translate/core'; +import { ResourceReportData } from '../../TypedClient'; + +export class DugReportEntity extends TypedEntity { + public reportInfo: { uid: string; presetParameters: { [key: string]: string } }; + + public static GetEntitySchema(translate?: TranslateService): EntitySchema { + const returnColumns: { [key: string]: IClientProperty } = {}; + + returnColumns.ReportDisplayName = { + Type: ValType.String, + ColumnName: 'ReportDisplayName', + Display: translate ? translate.instant('#LDS#Display name') : '#LDS#Display name', + }; + + returnColumns.UidReport = { + Type: ValType.String, + ColumnName: 'UidReport', + }; + + return { + TypeName: 'Reports', + Display: translate ? translate.instant('#LDS#Reports') : '#LDS#Reports', + Columns: returnColumns, + }; + } + + public static buildEntities( + entityData: EntityData[], + extended: { [key: string]: string }[], + entitySchema: EntitySchema, + ): ExtendedTypedEntityCollection { + const builder = new TypedEntityBuilder(DugReportEntity); + const returnColumns = builder.buildReadWriteEntities( + { + TotalCount: entityData.length, + Entities: entityData, + ExtendedData: extended, + }, + entitySchema, + ); + + returnColumns.Data.forEach( + (elem, index) => + (elem.reportInfo = { uid: elem.entity.GetColumn('UidReport').GetValue(), presetParameters: returnColumns?.extendedData?.[index]! }), + ); + + return returnColumns; + } + + public static buildEntityData(trustees: ResourceReportData[]): EntityData[] { + return trustees.map((elem) => { + const returnColumns: { [key: string]: EntityColumnData } = {}; + returnColumns.ReportDisplayName = { Value: elem.ReportDisplayName, IsReadOnly: true }; + returnColumns.UidReport = { Value: elem.UidReport, IsReadOnly: true }; + + return { Columns: returnColumns, Display: elem.ReportDisplayName }; + }); + } +} diff --git a/imxweb/projects/qam/src/lib/dug/dug-reports/dug-reports.component.html b/imxweb/projects/qam/src/lib/dug/dug-reports/dug-reports.component.html new file mode 100644 index 000000000..98b0ab4dd --- /dev/null +++ b/imxweb/projects/qam/src/lib/dug/dug-reports/dug-reports.component.html @@ -0,0 +1,15 @@ +
    + + + + + + + + + + + + + +
    diff --git a/imxweb/projects/qam/src/lib/dug/dug-reports/dug-reports.component.scss b/imxweb/projects/qam/src/lib/dug/dug-reports/dug-reports.component.scss new file mode 100644 index 000000000..761d8b43e --- /dev/null +++ b/imxweb/projects/qam/src/lib/dug/dug-reports/dug-reports.component.scss @@ -0,0 +1,3 @@ +.preset-report-extension { + justify-content: end; +} \ No newline at end of file diff --git a/imxweb/projects/qam/src/lib/dug/dug-reports/dug-reports.component.ts b/imxweb/projects/qam/src/lib/dug/dug-reports/dug-reports.component.ts new file mode 100644 index 000000000..4bae81d65 --- /dev/null +++ b/imxweb/projects/qam/src/lib/dug/dug-reports/dug-reports.component.ts @@ -0,0 +1,73 @@ +/* + * ONE IDENTITY LLC. PROPRIETARY INFORMATION + * + * This software is confidential. One Identity, LLC. or one of its affiliates or + * subsidiaries, has supplied this software to you under terms of a + * license agreement, nondisclosure agreement or both. + * + * You may not copy, disclose, or use this software except in accordance with + * those terms. + * + * + * Copyright 2024 One Identity LLC. + * ALL RIGHTS RESERVED. + * + * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR + * WARRANTIES ABOUT THE SUITABILITY OF THE SOFTWARE, + * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED + * TO THE IMPLIED WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE, OR + * NON-INFRINGEMENT. ONE IDENTITY LLC. SHALL NOT BE + * LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE + * AS A RESULT OF USING, MODIFYING OR DISTRIBUTING + * THIS SOFTWARE OR ITS DERIVATIVES. + * + */ + +import { Component, Input, OnInit } from '@angular/core'; +import { TranslateService } from '@ngx-translate/core'; + + +import { BusyService, DataSourceToolbarSettings } from 'qbm'; +import { DisplayColumns, EntitySchema, IClientProperty, ValType } from '@imx-modules/imx-qbm-dbts'; +import { DugReportEntity } from './dug-report-entity'; +import { DugReportService } from './dug-reports.service'; + +@Component({ + selector: 'imx-dug-reports', + templateUrl: './dug-reports.component.html', + styleUrls: ['./dug-reports.component.scss'], +}) +export class DugReportsComponent implements OnInit { + @Input() public dugUid: string; + public busyService = new BusyService(); + public dstSettings: DataSourceToolbarSettings; + public entitySchema: EntitySchema; + private displayedColumns: IClientProperty[] = []; + public readonly DisplayColumns = DisplayColumns; + + constructor(private readonly dugReportService: DugReportService, translateService: TranslateService) { + this.entitySchema = DugReportEntity.GetEntitySchema(translateService); + this.displayedColumns = [this.entitySchema.Columns.ReportDisplayName, {ColumnName: 'action', Type: ValType.String}]; + } + + public async ngOnInit(): Promise { + return this.getData(); + } + + private async getData(): Promise { + const isBusy = this.busyService.beginBusy(); + try { + const data = await this.dugReportService.getReports(this.dugUid); + + this.dstSettings = { + displayedColumns: this.displayedColumns, + dataSource: data, + entitySchema: this.entitySchema, + navigationState: {}, + }; + } finally { + isBusy.endBusy(); + } + } +} diff --git a/imxweb/projects/qam/src/lib/dug/dug-reports/dug-reports.service.ts b/imxweb/projects/qam/src/lib/dug/dug-reports/dug-reports.service.ts new file mode 100644 index 000000000..ee38b6aae --- /dev/null +++ b/imxweb/projects/qam/src/lib/dug/dug-reports/dug-reports.service.ts @@ -0,0 +1,49 @@ +/* + * ONE IDENTITY LLC. PROPRIETARY INFORMATION + * + * This software is confidential. One Identity, LLC. or one of its affiliates or + * subsidiaries, has supplied this software to you under terms of a + * license agreement, nondisclosure agreement or both. + * + * You may not copy, disclose, or use this software except in accordance with + * those terms. + * + * + * Copyright 2024 One Identity LLC. + * ALL RIGHTS RESERVED. + * + * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR + * WARRANTIES ABOUT THE SUITABILITY OF THE SOFTWARE, + * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED + * TO THE IMPLIED WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE, OR + * NON-INFRINGEMENT. ONE IDENTITY LLC. SHALL NOT BE + * LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE + * AS A RESULT OF USING, MODIFYING OR DISTRIBUTING + * THIS SOFTWARE OR ITS DERIVATIVES. + * + */ + +import { Injectable } from '@angular/core'; +import { TranslateService } from '@ngx-translate/core'; + +import { ExtendedTypedEntityCollection } from '@imx-modules/imx-qbm-dbts'; +import { QamApiService } from '../../qam-api-client.service'; +import { DugReportEntity } from './dug-report-entity'; + +@Injectable({ providedIn: 'root' }) +export class DugReportService { + constructor( + private readonly api: QamApiService, + private readonly translate: TranslateService, + ) {} + + public async getReports(uid: string): Promise> { + const resource = await this.api.client.portal_dge_resources_reports_get(uid); + return DugReportEntity.buildEntities( + DugReportEntity.buildEntityData(resource), + resource.map((elem) => elem.PresetParameters!).filter((elem) => elem.presetParameters), + DugReportEntity.GetEntitySchema(this.translate), + ); + } +} diff --git a/imxweb/projects/qam/src/lib/dug/dug-sidesheet.component.html b/imxweb/projects/qam/src/lib/dug/dug-sidesheet.component.html new file mode 100644 index 000000000..1ad6b296c --- /dev/null +++ b/imxweb/projects/qam/src/lib/dug/dug-sidesheet.component.html @@ -0,0 +1,150 @@ + + + #LDS#Heading Main Data  +
    +
    +
    + + +
    + +
    +
    + + {{ orderRestrictionHint | translate }} +
    + +
    +
    +
    +
    +
    +
    + + + +
    +
    +
    + + + +
    +
    +
    +
    +
    + + + +
    +
    +
    + + + +
    +
    +
    +
    +
    + + + +
    +
    +
    + + + +
    + +
    +
    +
    +
    + + + +
    +
    +
    + + + +
    +
    +
    +
    +
    + + + +
    +
    +
    + + + +
    +
    +
    +
    +
    + + + +
    +
    +
    + + + +
    +
    +
    +
    +
    + + + +
    + +
    +
    +
    +
    +
    +
    + + + + + + + +
    diff --git a/imxweb/projects/qam/src/lib/dug/dug-sidesheet.component.scss b/imxweb/projects/qam/src/lib/dug/dug-sidesheet.component.scss new file mode 100644 index 000000000..388277934 --- /dev/null +++ b/imxweb/projects/qam/src/lib/dug/dug-sidesheet.component.scss @@ -0,0 +1,30 @@ +@import 'base/mixins'; + +:host { + @include flex-column-container-fill(); + padding-bottom: 3px; +} + +.governance-sidesheet__tab-content-body { + .mat-card { + @include flex-column-container-fill(); + } +} + +.governance-sidesheet__tab-content { + imx-hyperview { + overflow: hidden; + } +} + +.mat-card-title { + font-size: medium ; +} + +.hidden{ + display: none; +} + +.imx-busy-loader { + height: 100%; +} \ No newline at end of file diff --git a/imxweb/projects/qam/src/lib/dug/dug-sidesheet.component.ts b/imxweb/projects/qam/src/lib/dug/dug-sidesheet.component.ts new file mode 100644 index 000000000..8e18155a4 --- /dev/null +++ b/imxweb/projects/qam/src/lib/dug/dug-sidesheet.component.ts @@ -0,0 +1,256 @@ +/* + * ONE IDENTITY LLC. PROPRIETARY INFORMATION + * + * This software is confidential. One Identity, LLC. or one of its affiliates or + * subsidiaries, has supplied this software to you under terms of a + * license agreement, nondisclosure agreement or both. + * + * You may not copy, disclose, or use this software except in accordance with + * those terms. + * + * + * Copyright 2024 One Identity LLC. + * ALL RIGHTS RESERVED. + * + * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR + * WARRANTIES ABOUT THE SUITABILITY OF THE SOFTWARE, + * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED + * TO THE IMPLIED WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE, OR + * NON-INFRINGEMENT. ONE IDENTITY LLC. SHALL NOT BE + * LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE + * AS A RESULT OF USING, MODIFYING OR DISTRIBUTING + * THIS SOFTWARE OR ITS DERIVATIVES. + * + */ + +import { ChangeDetectorRef, Component, Inject, OnDestroy, OnInit, ViewChild } from '@angular/core'; +import { FormGroup, UntypedFormArray } from '@angular/forms'; +import { MatTab, MatTabChangeEvent } from '@angular/material/tabs'; +import { EUI_SIDESHEET_DATA, EuiLoadingService, EuiSidesheetRef, EuiSidesheetService } from '@elemental-ui/core'; +import { DbObjectKey, ValType } from '@imx-modules/imx-qbm-dbts'; +import { TranslateService } from '@ngx-translate/core'; +import { + BaseCdr, + BusyService, + CdrFactoryService, + ColumnDependentReference, + ConfirmationService, + EntityService, + ExtService, + SnackBarService, + SystemInfoService, + TabItem, + calculateSidesheetWidth, +} from 'qbm'; +import { RiskAnalysisSidesheetComponent, WorkflowActionComponent } from 'qer'; +import { Subscription } from 'rxjs'; +import { DugOverviewService } from '../dug-overview/dug-overview.service'; +import { ChangeRequestType, DgeConfigData, PortalDgeResourcesActivity, PortalDgeResourcesbyid } from '../TypedClient'; + +interface DugResourceFormGroup { + array: UntypedFormArray; +} + +@Component({ + selector: 'imx-dug-sidesheet', + styleUrls: ['./dug-sidesheet.component.scss'], + templateUrl: './dug-sidesheet.component.html', +}) +export class DugSidesheetComponent implements OnInit, OnDestroy { + public dug: PortalDgeResourcesbyid; + public config: DgeConfigData; + public busyService = new BusyService(); + public subscriptions: Subscription[] = []; + + public supportsActivity: boolean; + public isShare: boolean; + public canAnalyzeRisk: boolean; + public isRpsEnabled: boolean; + public isAttEnabled: boolean; + public activity: PortalDgeResourcesActivity[] = []; + public ChangeRequestType = ChangeRequestType; + public showChangePropertyButton: boolean = false; + public hideActionBar: boolean = false; + + public dugResourceFormGroup = new FormGroup({ array: new UntypedFormArray([]) }); + public dugResourceConditionsFormGroup = new FormGroup({ array: new UntypedFormArray([]) }); + public cdrList: (ColumnDependentReference | undefined)[] = []; + public isLoading = true; + public dynamicTabs: TabItem[] = []; + public readonly parameters: { objecttable: string; objectuid: string }; + + public get saveDisabled(): boolean { + return ( + (!this.dugResourceFormGroup.dirty && !this.dugResourceConditionsFormGroup.dirty) || + this.dugResourceFormGroup.invalid || + this.dugResourceConditionsFormGroup.invalid + ); + } + + public cdrListOrderConditions: (ColumnDependentReference | undefined)[] = []; + public orderRestrictionHint = + '#LDS#You can specify who can order access to this resource. If nothing is assigned, the resource can be ordered by all employees.'; + + @ViewChild('accessTab') private accessTab: MatTab; + + constructor( + @Inject(EUI_SIDESHEET_DATA) public readonly data: { uid: string }, + private readonly dugOverviewProvider: DugOverviewService, + private readonly sideSheet: EuiSidesheetService, + private readonly loadingService: EuiLoadingService, + private readonly systemInfoService: SystemInfoService, + private readonly translate: TranslateService, + private readonly cdrFactory: CdrFactoryService, + private readonly extService: ExtService, + private readonly entityService: EntityService, + private readonly snackbar: SnackBarService, + private readonly sidesheetRef: EuiSidesheetRef, + private readonly changeDetector: ChangeDetectorRef, // private readonly sidesheetRef: EuiSidesheetRef, //ToDO: DGE add apply, if Main Data changed + confirm: ConfirmationService, + ) { + this.parameters = { + objecttable: dugOverviewProvider.DugResourceSchema.TypeName ?? '', + objectuid: data.uid, + }; + + this.subscriptions.push( + this.busyService.busyStateChanged.subscribe((state: boolean) => { + this.isLoading = state; + this.changeDetector.detectChanges(); + }), + ); + this.subscriptions.push( + sidesheetRef.closeClicked().subscribe(async () => { + if (!this.saveDisabled && !(await confirm.confirmLeaveWithUnsavedChanges())) { + return; + } + + sidesheetRef.close(false); + }), + ); + } + + public async ngOnInit(): Promise { + const isBusy = this.busyService.beginBusy(); + try { + const info = await this.systemInfoService.get(); + this.canAnalyzeRisk = info.PreProps?.includes('RISKINDEX') ?? false; + this.isRpsEnabled = info.PreProps?.includes('REPORT_SUBSCRIPTION') ?? false; + this.isAttEnabled = info.PreProps?.includes('ATTESTATION') ?? false; + + this.config = await this.dugOverviewProvider.getDgeConfig(); + this.dug = await this.dugOverviewProvider.getDugResourceById(this.data.uid); + this.supportsActivity = this.dug.UID_QAMResourceType.value != 'QAM-A2EB93DC78054195837671623098181F'; + this.isShare = this.dug.UID_QAMResourceType.value == 'QAM-52F4B02EFBCAEB7A2EE35B8A4636FAEA'; + + this.cdrList = this.cdrFactory + .buildCdrFromColumnList(this.dug.GetEntity(), [ + 'UID_QAMDuG', + 'UID_QAMNode', + 'UID_QAMResourceType', + 'UID_PersonResponsible', + 'UID_AERoleOwner', + 'IsSecurityInformationIndexed', + 'UID_BackingFolder', + 'UID_QAMDuGParent', + 'DisplayName', + 'FullPath', + 'DisplayPath', + 'RiskIndexCalculated', + 'RequiresOwnership', + 'UID_QAMClassificationLevelMan', + 'IsSecurityInheritanceBlocked', + ]) + .filter((elem) => elem); + + this.cdrListOrderConditions = this.cdrFactory + .buildCdrFromColumnList(this.dug.GetEntity(), ['InProfitCenter', 'InDepartment', 'InAERole', 'InLocality', 'InOrg']) + .filter((elem) => elem); + + if (this.supportsActivity) { + this.activity = (await this.dugOverviewProvider.getAllResourceActivities(this.data.uid)).Data; + } else { + this.activity = []; + } + + this.dynamicTabs = ( + await this.extService.getFittingComponents('dugSidesheet', (ext) => ext.inputData.checkVisibility(this.parameters)) + ).sort((tab1: TabItem, tab2: TabItem) => (tab1.sortOrder ?? 0) - (tab2.sortOrder ?? 0)); + } finally { + isBusy.endBusy(); + } + } + + public ngOnDestroy(): void { + this.subscriptions?.forEach((elem) => elem?.unsubscribe()); + } + + public async save(): Promise { + const overlay = this.loadingService.show(); + try { + await this.dug.GetEntity().Commit(); + this.snackbar.open({ key: '#LDS#The resource has been saved' }); + this.sidesheetRef.close(true); + } finally { + this.loadingService.hide(overlay); + } + } + + public async analyzeRisk(): Promise { + this.sideSheet.open(RiskAnalysisSidesheetComponent, { + title: await this.translate.get('#LDS#Heading Analyze Risk').toPromise(), + padding: '0px', + width: calculateSidesheetWidth(600, 0.4), + data: { objectKey: new DbObjectKey('QAMDuG', this.data.uid).ToXmlString() }, + }); + } + + public updateCurrentTab(event: MatTabChangeEvent): void { + this.hideActionBar = this.dynamicTabs.some((elem) => this.translate.instant(elem.inputData.label) === event.tab.textLabel); + this.showChangePropertyButton = event.tab === this.accessTab; + } + + public async makeRequest(type: ChangeRequestType): Promise { + const actionParameters = { + reason: this.createCdrReason(undefined, 2), + }; + const result = await this.sideSheet + .open(WorkflowActionComponent, { + title: this.translate.instant( + type === ChangeRequestType.Change ? '#LDS#Heading Request Property Change' : '#LDS#Heading Reject Ownership', + ), + subTitle: this.dug.DisplayName.value, + padding: '0', + width: calculateSidesheetWidth(), + testId: 'dug-sidesheet-' + (type === ChangeRequestType.Change ? 'change' : 'reject-ownership'), + data: { + requests: [this.dug], + actionParameters, + }, + }) + .afterClosed() + .toPromise(); + + if (result) { + await this.dugOverviewProvider.makeRequest(this.data.uid, type, actionParameters.reason.column.GetValue()); + this.snackbar.open({ + key: + type === ChangeRequestType.Change + ? '#LDS#The change of a property has been requested' + : '#LDS#A rejection of the ownership has been requested', + }); + } + } + + private createCdrReason(display?: string, reasonType: number = 0): BaseCdr { + const column = this.entityService.createLocalEntityColumn({ + ColumnName: 'ReasonHead', + Type: ValType.Text, + IsMultiLine: true, + MinLen: reasonType === 2 ? 1 : 0, + }); + + return new BaseCdr(column, display || '#LDS#Reason for your decision'); + } +} diff --git a/imxweb/projects/qam/src/lib/identity/identity.component.html b/imxweb/projects/qam/src/lib/identity/identity.component.html new file mode 100644 index 000000000..26896c9db --- /dev/null +++ b/imxweb/projects/qam/src/lib/identity/identity.component.html @@ -0,0 +1,73 @@ +
    + + + + +
    +
    + {{ "#LDS#'{0}' has access to the following governed data resources." | translate | ldsReplace: referrer?.display }} +
    + + +
    +
    + +
    + +
    +
    + + +
    +
    + + + + + + {{ '#LDS#Path' | translate }}: + {{ path.DisplayPath }} + +
    + {{ trustee?.Display }} + +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    + + +
    + +

    #LDS#There are no resources assigned to the identity.

    +
    +
    diff --git a/imxweb/projects/qam/src/lib/identity/identity.component.scss b/imxweb/projects/qam/src/lib/identity/identity.component.scss new file mode 100644 index 000000000..61f8c2125 --- /dev/null +++ b/imxweb/projects/qam/src/lib/identity/identity.component.scss @@ -0,0 +1,42 @@ +@import 'base/mixins'; + +:host { + flex: 1 1 auto; + overflow: hidden; +} + +.imx-resource-line { + @include flex-row-container($overflow: hidden); +} + +.imx-resource-toolbar { + @include flex-row-container(); +} + +.imx-resource-line:not(:last-of-type) { + margin-bottom: 10px; +} + +span[bold] { + font-weight: 700; +} + +.imx-resource-content { + @include flex-column-container-fill(); +} + +.imx-scrollable-resoures { + @include flex-column-container-fill(); +} + +.hidden { + display: none; +} + +.imx-busy { + padding: 10px; + display: flex; + flex-direction: column; + align-items: center; + height: 100%; +} diff --git a/imxweb/projects/qam/src/lib/identity/identity.component.ts b/imxweb/projects/qam/src/lib/identity/identity.component.ts new file mode 100644 index 000000000..301f5750a --- /dev/null +++ b/imxweb/projects/qam/src/lib/identity/identity.component.ts @@ -0,0 +1,156 @@ +/* + * ONE IDENTITY LLC. PROPRIETARY INFORMATION + * + * This software is confidential. One Identity, LLC. or one of its affiliates or + * subsidiaries, has supplied this software to you under terms of a + * license agreement, nondisclosure agreement or both. + * + * You may not copy, disclose, or use this software except in accordance with + * those terms. + * + * + * Copyright 2024 One Identity LLC. + * ALL RIGHTS RESERVED. + * + * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR + * WARRANTIES ABOUT THE SUITABILITY OF THE SOFTWARE, + * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED + * TO THE IMPLIED WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE, OR + * NON-INFRINGEMENT. ONE IDENTITY LLC. SHALL NOT BE + * LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE + * AS A RESULT OF USING, MODIFYING OR DISTRIBUTING + * THIS SOFTWARE OR ITS DERIVATIVES. + * + */ + +import { ChangeDetectorRef, Component, Input, OnDestroy, OnInit, Optional, ViewChild } from '@angular/core'; +import { MatAccordion } from '@angular/material/expansion'; +import { EuiSidesheetService } from '@elemental-ui/core'; +import { TranslateService } from '@ngx-translate/core'; +import { BusyService, calculateSidesheetWidth, DynamicTabDataProviderDirective } from 'qbm'; +import { SourceDetectiveSidesheetComponent, SourceDetectiveSidesheetData, SourceDetectiveType } from 'qer'; +import { Subscription } from 'rxjs'; +import { QamApiService } from '../qam-api-client.service'; +import { TrusteeAccessData, TrusteeData } from '../TypedClient'; + +interface AccessForPath { + DisplayPath: string; + Accesses: AccessData[]; +} + +interface AccessData { + Display: string; + UidQamTrustee: string; + Permissions: string[]; +} + +/** Shows access information for an identity. */ +@Component({ + templateUrl: './identity.component.html', + styleUrls: ['./identity.component.scss', '../qam.scss'], + selector: 'imx-dge-identity', +}) +export class IdentityComponent implements OnInit, OnDestroy { + public data: TrusteeAccessData; + + public byPath: AccessForPath[] = []; + + public referrer: { objecttable: string; objectuid: string; display: string }; + + public busyService: BusyService; + public isLoading: boolean = true; + @Input() public uid: string; + @ViewChild(MatAccordion) public accordion: MatAccordion; + private subscription: Subscription | undefined; + + constructor( + @Optional() dataProvider: DynamicTabDataProviderDirective, + private translate: TranslateService, + private readonly sideSheet: EuiSidesheetService, + private readonly qamApi: QamApiService, + private change: ChangeDetectorRef, + ) { + this.referrer = dataProvider?.data; + this.busyService = new BusyService(); + this.subscription = this.busyService.busyStateChanged.subscribe((elem) => { + this.isLoading = elem; + }); + } + + public async ngOnInit() { + const isBusy = this.busyService.beginBusy(); + try { + this.data = await this.qamApi.client.portal_dge_access_identity_get(this.uid || this.referrer.objectuid); + } finally { + isBusy?.endBusy(); + } + + // pivot the data and store as byPath + var allTrustees: TrusteeData[] = []; + this.iterateRecursively(this.data.Trustees ?? [], allTrustees); + const paths = [ + ...new Set( + allTrustees + .map((d) => d.Paths) + .flat() + .map((d) => d?.Path ?? ''), + ), + ]; + this.byPath = paths.map((path) => { + return { + DisplayPath: path, + Accesses: allTrustees + .map((t) => this.buildAccessData(t, path)) + .flat() + .filter((x) => x.Permissions.length > 0), + }; + }); + this.change.detectChanges(); + } + + public ngOnDestroy(): void { + this.subscription?.unsubscribe(); + } + + public openSourceDetective(uidQamTrustee: string) { + const data: SourceDetectiveSidesheetData = { + UID_Person: this.referrer.objectuid, + Type: SourceDetectiveType.MembershipOfEntitlement, + UID: uidQamTrustee, + TableName: 'QAMTrustee', + }; + this.sideSheet.open(SourceDetectiveSidesheetComponent, { + title: this.translate.instant('#LDS#Heading View Assignment Analysis'), + padding: '0px', + width: calculateSidesheetWidth(600, 0.4), + disableClose: false, + data, + }); + } + + private iterateRecursively(t: TrusteeData[], result: TrusteeData[]) { + t.forEach((trustee) => { + result.push(trustee); + if (trustee.Children) this.iterateRecursively(trustee.Children, result); + }); + } + + private buildAccessData(t: TrusteeData, path: string): AccessData[] { + return ( + t?.Paths?.map((p) => { + if (p.Path != path) + return { + Display: '__WithoutPath', + UidQamTrustee: '', + Permissions: [], + }; + return { + Display: t.Display ?? '', + UidQamTrustee: t.UidQamTrustee || '', + Permissions: p.Permissions || [], + }; + }).filter((x) => x.Display !== '__WithoutPath') ?? [] + ); + } +} diff --git a/imxweb/projects/qam/src/lib/init.service.ts b/imxweb/projects/qam/src/lib/init.service.ts new file mode 100644 index 000000000..60abcdcd3 --- /dev/null +++ b/imxweb/projects/qam/src/lib/init.service.ts @@ -0,0 +1,118 @@ +/* + * ONE IDENTITY LLC. PROPRIETARY INFORMATION + * + * This software is confidential. One Identity, LLC. or one of its affiliates or + * subsidiaries, has supplied this software to you under terms of a + * license agreement, nondisclosure agreement or both. + * + * You may not copy, disclose, or use this software except in accordance with + * those terms. + * + * + * Copyright 2024 One Identity LLC. + * ALL RIGHTS RESERVED. + * + * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR + * WARRANTIES ABOUT THE SUITABILITY OF THE SOFTWARE, + * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED + * TO THE IMPLIED WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE, OR + * NON-INFRINGEMENT. ONE IDENTITY LLC. SHALL NOT BE + * LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE + * AS A RESULT OF USING, MODIFYING OR DISTRIBUTING + * THIS SOFTWARE OR ITS DERIVATIVES. + * + */ + +import { Injectable } from '@angular/core'; +import { Route, Router } from '@angular/router'; +import { ExtService, HELP_CONTEXTUAL, MenuService } from 'qbm'; +import { CartItemsExtensionService, MyResponsibilitiesRegistryService } from 'qer'; +import { AccessRequestService } from './access-request/access-request.service'; +import { AccessComponent } from './access/access.component'; +import { UserAccessComponent } from './access/user-access.component'; +import { DugOverviewComponent } from './dug-overview/dug-overview.component'; +import { IdentityComponent } from './identity/identity.component'; + +@Injectable({ providedIn: 'root' }) +export class InitService { + protected readonly dgeTag = 'QAMDuG'; + + constructor( + private readonly router: Router, + private readonly extService: ExtService, + private readonly cartItemExtService: CartItemsExtensionService, + private readonly menuService: MenuService, + private readonly myResponsibilitiesRegistryService: MyResponsibilitiesRegistryService, + ) {} + + public onInit(routes: Route[]): void { + // register the extension on the group sidesheet + this.extService.register('groupSidesheet', { + instance: AccessComponent, + inputData: { + id: 'access', + label: '#LDS#Access', + checkVisibility: async (ref) => this.supportsAccess(ref), + }, + }); + + // register the extension on the account sidesheet + this.extService.register('accountSidesheet', { + instance: AccessComponent, + inputData: { + id: 'access', + label: '#LDS#Access', + checkVisibility: async (ref) => this.supportsAccess(ref), + }, + }); + + // register the extension on the identity sidesheet + this.extService.register('identitySidesheet', { + instance: IdentityComponent, + inputData: { + id: 'access', + label: '#LDS#Resource Access', + checkVisibility: async (ref) => true, + }, + }); + + // register the extension on the profile + this.extService.register('profile', { + instance: UserAccessComponent, + inputData: { + id: 'access', + label: '#LDS#Resource Access', + checkVisibility: async (_) => true, + }, + }); + + this.cartItemExtService.register('AccessRequestService', AccessRequestService); + + this.myResponsibilitiesRegistryService.registerFactory(() => ({ + instance: DugOverviewComponent, + sortOrder: 7, + name: this.dgeTag, + caption: '#LDS#Menu Entry Governed Data', + data: { + TableName: this.dgeTag, + Count: 0, + }, + contextId: HELP_CONTEXTUAL.Default, //ToDo Indian Team: DGE Provide context help + })); + + this.addRoutes(routes); + } + + private supportsAccess(referrer: any): boolean { + return referrer ? ['SPSIdentity', 'SPSGroup', 'ADSAccount', 'ADSGroup'].includes(referrer.objecttable) : false; + } + + private addRoutes(routes: Route[]): void { + const config = this.router.config; + routes.forEach((route) => { + config.unshift(route); + }); + this.router.resetConfig(config); + } +} diff --git a/imxweb/projects/o3t/src/lib/api.service.ts b/imxweb/projects/qam/src/lib/qam-api-client.service.ts similarity index 63% rename from imxweb/projects/o3t/src/lib/api.service.ts rename to imxweb/projects/qam/src/lib/qam-api-client.service.ts index d9561f8a4..c642cb846 100644 --- a/imxweb/projects/o3t/src/lib/api.service.ts +++ b/imxweb/projects/qam/src/lib/qam-api-client.service.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -25,14 +25,14 @@ */ import { Injectable } from '@angular/core'; -import { V2Client, TypedClient } from 'imx-api-o3t'; -import { ApiClient } from 'imx-qbm-dbts'; +import { CachedPromise } from '@imx-modules/imx-qbm-dbts'; import { AppConfigService, ClassloggerService, ImxTranslationProviderService } from 'qbm'; +import { DgeConfigData, TypedClient, V2Client } from './TypedClient'; @Injectable({ - providedIn: 'root' + providedIn: 'root', }) -export class ApiService { +export class QamApiService { private tc: TypedClient; public get typedClient(): TypedClient { return this.tc; @@ -43,16 +43,13 @@ export class ApiService { return this.c; } - public get apiClient(): ApiClient { - return this.config.apiClient; - } - constructor( private readonly config: AppConfigService, private readonly logger: ClassloggerService, - private readonly translationProvider: ImxTranslationProviderService) { + private readonly translationProvider: ImxTranslationProviderService, + ) { try { - this.logger.debug(this, 'Initializing O3T API service'); + this.logger.debug(this, 'Initializing QAM API service'); // Use schema loaded by QBM client const schemaProvider = config.client; @@ -62,4 +59,24 @@ export class ApiService { this.logger.error(this, e); } } + + private cachedDgeConfig: CachedPromise = new CachedPromise(() => this.client.portal_dgeconfig_get()); + + public getDgeConfig() { + return this.cachedDgeConfig.get(); + } + + private cachedTrusteeTypes: CachedPromise<{ [id: number]: string }> = new CachedPromise(async () => { + const data = await this.client.portal_dge_trustees_types_get(); + var result = {}; + data.forEach((e) => { + result[e.Value] = e.Description; + }); + return result; + }); + + /** Returns the display names of the known trustee types. */ + public getTrusteeTypes(): Promise<{ [id: number]: string }> { + return this.cachedTrusteeTypes.get(); + } } diff --git a/imxweb/projects/qam/src/lib/qam-config.module.ts b/imxweb/projects/qam/src/lib/qam-config.module.ts new file mode 100644 index 000000000..d1c18ce30 --- /dev/null +++ b/imxweb/projects/qam/src/lib/qam-config.module.ts @@ -0,0 +1,131 @@ +/* + * ONE IDENTITY LLC. PROPRIETARY INFORMATION + * + * This software is confidential. One Identity, LLC. or one of its affiliates or + * subsidiaries, has supplied this software to you under terms of a + * license agreement, nondisclosure agreement or both. + * + * You may not copy, disclose, or use this software except in accordance with + * those terms. + * + * + * Copyright 2024 One Identity LLC. + * ALL RIGHTS RESERVED. + * + * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR + * WARRANTIES ABOUT THE SUITABILITY OF THE SOFTWARE, + * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED + * TO THE IMPLIED WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE, OR + * NON-INFRINGEMENT. ONE IDENTITY LLC. SHALL NOT BE + * LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE + * AS A RESULT OF USING, MODIFYING OR DISTRIBUTING + * THIS SOFTWARE OR ITS DERIVATIVES. + * + */ + +import { CommonModule } from '@angular/common'; +import { NgModule } from '@angular/core'; +import { FormsModule, ReactiveFormsModule } from '@angular/forms'; +import { MatButtonModule } from '@angular/material/button'; +import { MatExpansionModule } from '@angular/material/expansion'; +import { MatMenuModule } from '@angular/material/menu'; +import { MatRadioModule } from '@angular/material/radio'; +import { MatTabsModule } from '@angular/material/tabs'; +import { MatTooltipModule } from '@angular/material/tooltip'; +import { MatTreeModule } from '@angular/material/tree'; +import { RouterModule, Routes } from '@angular/router'; +import { EuiCoreModule, EuiMaterialModule } from '@elemental-ui/core'; +import { TranslateModule } from '@ngx-translate/core'; +import { + BusyIndicatorModule, + CdrModule, + DataSourceToolbarModule, + DataTableModule, + DynamicTabsModule, + ExtModule, + HelpContextualModule, + LdsReplaceModule, + ObjectHistoryModule, + RouteGuardService, +} from 'qbm'; +import { ObjectHyperviewModule, StatisticsModule } from 'qer'; +import { AccessRequestModule } from './access-request/access-request.module'; +import { AccessComponent } from './access/access.component'; +import { TrusteeViewComponent } from './access/trustee-view.component'; +import { UserAccessComponent } from './access/user-access.component'; +import { DugActivitiesComponent } from './dug-activities/dug-activities.component'; +import { DugDashboardsComponent } from './dug-dashboards/dug-dashboards.component'; +import { DugOverviewComponent } from './dug-overview/dug-overview.component'; +import { AccessComparisonComponent } from './dug/access-comparison.component'; +import { DugAccessAnalysisComponent } from './dug/dug-access-analysis.component'; +import { DugAccessDetailComponent } from './dug/dug-access-detail.component'; +import { DugAccessModule } from './dug/dug-access/dug-access.module'; +import { DugActivityModule } from './dug/dug-activity/dug-activity.module'; +import { DugReportsComponent } from './dug/dug-reports/dug-reports.component'; +import { DugSidesheetComponent } from './dug/dug-sidesheet.component'; +import { IdentityComponent } from './identity/identity.component'; +import { InitService } from './init.service'; + +const routes: Routes = [ + { + path: 'dge', + canActivate: [RouteGuardService], + resolve: [RouteGuardService], + component: DugSidesheetComponent, // as an example + }, +]; + +@NgModule({ + declarations: [ + AccessComponent, + TrusteeViewComponent, + IdentityComponent, + DugSidesheetComponent, + DugAccessAnalysisComponent, + DugAccessDetailComponent, + UserAccessComponent, + AccessComparisonComponent, + DugOverviewComponent, + DugReportsComponent, + DugDashboardsComponent, + DugActivitiesComponent, + ], + imports: [ + AccessRequestModule, + CommonModule, + DataSourceToolbarModule, + DataTableModule, + CdrModule, + HelpContextualModule, + DynamicTabsModule, + FormsModule, + ReactiveFormsModule, + RouterModule.forChild(routes), + TranslateModule, + LdsReplaceModule, + MatButtonModule, + MatRadioModule, + MatMenuModule, + MatTabsModule, + MatExpansionModule, + MatTreeModule, + ObjectHyperviewModule, + ObjectHistoryModule, + EuiCoreModule, + EuiMaterialModule, + DugAccessModule, + DugActivityModule, + BusyIndicatorModule, + ExtModule, + StatisticsModule, + MatTooltipModule, + ], +}) +export class QamConfigModule { + constructor(private readonly initializer: InitService) { + this.initializer.onInit(routes); + + console.log('▶️ QAM initialized'); + } +} diff --git a/imxweb/projects/qam/src/lib/qam.scss b/imxweb/projects/qam/src/lib/qam.scss new file mode 100644 index 000000000..598adc766 --- /dev/null +++ b/imxweb/projects/qam/src/lib/qam.scss @@ -0,0 +1,50 @@ +@import '@elemental-ui/core/src/styles/_eui_palette.scss'; +@import 'base/mixins'; + +.trusteetype { + font-style: italic; +} + +.imx-no-results { + display: flex; + flex-direction: column; + flex: 1 1 auto; + align-items: center; + justify-content: center; + + p { + margin: 0; + font-size: 18px; + } +} + +.imx-flex-line { + @include flex-row-container(); +} + +.eui-light-theme { + :host { + .qam-tree-content { + background-color: $color-blue-10; + border: 1px solid $color-blue-20; + } + } +} + +.eui-dark-theme { + :host { + .qam-tree-content { + background-color: $color-blue-90; + border: 1px solid $color-blue-80; + } + } +} + +.eui-contrast-theme { + :host { + .qam-tree-content { + background-color: $color-gray-90; + border: 1px solid $color-gray-0; + } + } +} diff --git a/imxweb/projects/o3t/src/lib/api.service.spec.ts b/imxweb/projects/qam/src/public_api.ts similarity index 84% rename from imxweb/projects/o3t/src/lib/api.service.spec.ts rename to imxweb/projects/qam/src/public_api.ts index 1b61024ea..73dda2de7 100644 --- a/imxweb/projects/o3t/src/lib/api.service.spec.ts +++ b/imxweb/projects/qam/src/public_api.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -24,10 +24,4 @@ * */ -describe('ApiService', () => { - - it('is a dummy test', async () => { - - expect({}).toBeDefined(); - }); -}); +export { QamConfigModule } from './lib/qam-config.module'; diff --git a/imxweb/projects/qam/src/test.ts b/imxweb/projects/qam/src/test.ts new file mode 100644 index 000000000..a10861796 --- /dev/null +++ b/imxweb/projects/qam/src/test.ts @@ -0,0 +1,40 @@ +/* + * ONE IDENTITY LLC. PROPRIETARY INFORMATION + * + * This software is confidential. One Identity, LLC. or one of its affiliates or + * subsidiaries, has supplied this software to you under terms of a + * license agreement, nondisclosure agreement or both. + * + * You may not copy, disclose, or use this software except in accordance with + * those terms. + * + * + * Copyright 2024 One Identity LLC. + * ALL RIGHTS RESERVED. + * + * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR + * WARRANTIES ABOUT THE SUITABILITY OF THE SOFTWARE, + * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED + * TO THE IMPLIED WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE, OR + * NON-INFRINGEMENT. ONE IDENTITY LLC. SHALL NOT BE + * LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE + * AS A RESULT OF USING, MODIFYING OR DISTRIBUTING + * THIS SOFTWARE OR ITS DERIVATIVES. + * + */ + +// This file is required by karma.conf.js and loads recursively all the .spec and framework files + +import 'zone.js'; +import 'zone.js/testing'; + +import { getTestBed } from '@angular/core/testing'; +import { BrowserDynamicTestingModule, platformBrowserDynamicTesting } from '@angular/platform-browser-dynamic/testing'; +import 'core-js/es/reflect'; +import { TestHelperModule } from 'qbm'; + +// First, initialize the Angular testing environment. +getTestBed().initTestEnvironment([BrowserDynamicTestingModule, TestHelperModule], platformBrowserDynamicTesting(), { + teardown: { destroyAfterEach: false }, +}); diff --git a/imxweb/projects/o3t/tsconfig.lib.json b/imxweb/projects/qam/tsconfig.lib.json similarity index 68% rename from imxweb/projects/o3t/tsconfig.lib.json rename to imxweb/projects/qam/tsconfig.lib.json index 6bc419f84..f863d8bff 100644 --- a/imxweb/projects/o3t/tsconfig.lib.json +++ b/imxweb/projects/qam/tsconfig.lib.json @@ -7,10 +7,11 @@ "declarationMap": true, "sourceMap": true, "inlineSources": true, + "strictNullChecks": true, "types": [] }, - "exclude": [ - "src/test.ts", - "**/*.spec.ts" - ] + "angularCompilerOptions": { + "strictTemplates": true + }, + "exclude": ["src/test.ts", "**/*.spec.ts"] } diff --git a/imxweb/projects/o3t/tsconfig.lib.prod.json b/imxweb/projects/qam/tsconfig.lib.prod.json similarity index 75% rename from imxweb/projects/o3t/tsconfig.lib.prod.json rename to imxweb/projects/qam/tsconfig.lib.prod.json index 61c7592e7..fb40dbbb0 100644 --- a/imxweb/projects/o3t/tsconfig.lib.prod.json +++ b/imxweb/projects/qam/tsconfig.lib.prod.json @@ -3,8 +3,5 @@ "extends": "./tsconfig.lib.json", "compilerOptions": { "declarationMap": false - }, - "angularCompilerOptions": { - "enableIvy": true } } diff --git a/imxweb/projects/o3t/tsconfig.spec.json b/imxweb/projects/qam/tsconfig.spec.json similarity index 100% rename from imxweb/projects/o3t/tsconfig.spec.json rename to imxweb/projects/qam/tsconfig.spec.json diff --git a/imxweb/projects/aad/tslint.json b/imxweb/projects/qam/tslint.json similarity index 100% rename from imxweb/projects/aad/tslint.json rename to imxweb/projects/qam/tslint.json diff --git a/imxweb/projects/qbm-app-landingpage/.compodocrc.json b/imxweb/projects/qbm-app-landingpage/.compodocrc.json index 162019b61..5caeccd1c 100644 --- a/imxweb/projects/qbm-app-landingpage/.compodocrc.json +++ b/imxweb/projects/qbm-app-landingpage/.compodocrc.json @@ -1,6 +1,6 @@ { "name": "IMX Web - QBM Landing Page", - "output": "../../documentation/v92/qbm-app-landingpage", + "output": "../../documentation/v93/qbm-app-landingpage", "theme": "material", "assetsFolder": "../../compodoc/assets", "customLogo": "../../compodoc/assets/images/oneidentity-logo.png", diff --git a/imxweb/projects/qbm-app-landingpage/.eslintrc.json b/imxweb/projects/qbm-app-landingpage/.eslintrc.json new file mode 100644 index 000000000..584d9666a --- /dev/null +++ b/imxweb/projects/qbm-app-landingpage/.eslintrc.json @@ -0,0 +1,35 @@ +{ + "extends": "../../.eslintrc.json", + "ignorePatterns": ["!**/*", "**/*.spec.ts"], + "overrides": [ + { + "files": ["*.ts"], + "parserOptions": { + "project": ["imxweb/projects/qbm-app-landingpage/tsconfig.app.json", "imxweb/projects/qbm-app-landingpage/tsconfig.spec.json"], + "createDefaultProgram": true + }, + "rules": { + "@angular-eslint/directive-selector": [ + "error", + { + "type": "attribute", + "prefix": "imx", + "style": "camelCase" + } + ], + "@angular-eslint/component-selector": [ + "error", + { + "type": "element", + "prefix": "imx", + "style": "kebab-case" + } + ] + } + }, + { + "files": ["*.html"], + "rules": {} + } + ] +} diff --git a/imxweb/projects/qbm-app-landingpage/README.md b/imxweb/projects/qbm-app-landingpage/README.md new file mode 100644 index 000000000..d2d86589f --- /dev/null +++ b/imxweb/projects/qbm-app-landingpage/README.md @@ -0,0 +1 @@ +# IMX Web - Qbm Landing Page diff --git a/imxweb/projects/qbm-app-landingpage/karma.conf.js b/imxweb/projects/qbm-app-landingpage/karma.conf.js index 65aa5dd4e..1f8775dfc 100644 --- a/imxweb/projects/qbm-app-landingpage/karma.conf.js +++ b/imxweb/projects/qbm-app-landingpage/karma.conf.js @@ -13,10 +13,10 @@ module.exports = function (config) { require('karma-coverage-istanbul-reporter'), require('@angular-devkit/build-angular/plugins/karma'), require('karma-junit-reporter'), - require('karma-viewport') + require('karma-viewport'), ], client: { - clearContext: false // leave Jasmine Spec Runner output visible in browser + clearContext: false, // leave Jasmine Spec Runner output visible in browser }, coverageIstanbulReporter: { dir: require('path').join(__dirname, 'results'), @@ -24,7 +24,7 @@ module.exports = function (config) { fixWebpackSourcePaths: true, 'report-config': { html: { - subdir: 'coverage-html' + subdir: 'coverage-html', }, }, thresholds: { @@ -41,13 +41,14 @@ module.exports = function (config) { port: 9876, captureTimeout: 210000, browserDisconnectTolerance: 3, - browserDisconnectTimeout : 210000, - browserNoActivityTimeout : 210000, + browserDisconnectTimeout: 210000, + browserNoActivityTimeout: 210000, colors: true, logLevel: config.LOG_INFO, autoWatch: true, restartOnFileChange: true, singleRun: false, - browsers: ['Chrome'] + failOnEmptyTestSuite: false, + browsers: ['Chrome'], }); }; diff --git a/imxweb/projects/qbm-app-landingpage/package.json b/imxweb/projects/qbm-app-landingpage/package.json index f5397e23a..b6ac98c62 100644 --- a/imxweb/projects/qbm-app-landingpage/package.json +++ b/imxweb/projects/qbm-app-landingpage/package.json @@ -1,8 +1,6 @@ { "name": "qbm-app-landingpage", - "version": "9.2.1", + "version": "9.3.0", "private": true, - "peerDependencies": { - - } + "peerDependencies": {} } diff --git a/imxweb/projects/qbm-app-landingpage/project.json b/imxweb/projects/qbm-app-landingpage/project.json new file mode 100644 index 000000000..5eb09a50b --- /dev/null +++ b/imxweb/projects/qbm-app-landingpage/project.json @@ -0,0 +1,209 @@ +{ + "$schema": "../../node_modules/nx/schemas/project-schema.json", + "name": "qbm-app-landingpage", + "sourceRoot": "projects/qbm-app-landingpage/src", + "implicitDependencies": ["qbm"], + "projectType": "application", + "prefix": "imx", + "generators": { + "@schematics/angular:component": { + "style": "scss" + } + }, + "targets": { + "build": { + "executor": "@angular-devkit/build-angular:application", + "options": { + "aot": true, + "outputPath": { + "base": "dist/qbm-app-landingpage", + "browser": "" + }, + "allowedCommonJsDependencies": [ + "lodash", + "highlight.js", + "file-saver", + "billboard.js", + "moment-timezone", + "core-js/fn/map", + "core-js/fn/set", + "core-js/fn/weak-map", + "core-js/fn/array/from", + "core-js/fn/object/assign", + "core-js/es/array/from", + "core-js/es/object/assign", + "core-js/es/map", + "core-js/es/set", + "core-js/es/weak-map", + "lodash.debounce", + "lodash.clamp", + "moment", + "@elemental-ui/cadence-icon/codepoints" + ], + "index": "projects/qbm-app-landingpage/src/index.html", + "browser": "projects/qbm-app-landingpage/src/main.ts", + "polyfills": ["projects/qbm-app-landingpage/src/polyfills.ts"], + "tsConfig": "projects/qbm-app-landingpage/tsconfig.app.json", + "assets": [ + "projects/qbm-app-landingpage/src/assets", + "projects/qbm-app-landingpage/src/appconfig.json", + { + "glob": "**/*", + "input": "./shared/assets/", + "output": "./assets" + }, + { + "glob": "**/*", + "input": "./node_modules/@elemental-ui/core/assets", + "output": "./assets" + } + ], + "styles": [ + "shared/scss/styles.scss", + "projects/qbm-app-landingpage/src/styles.scss", + "node_modules/swagger-ui-dist/swagger-ui.css" + ], + "stylePreprocessorOptions": { + "includePaths": [ + "./shared/scss", + "./node_modules", + "./node_modules/@elemental-ui/cadence-icon", + "./node_modules/@elemental-ui/core" + ] + }, + "scripts": ["node_modules/swagger-ui-dist/swagger-ui-bundle.js", "node_modules/swagger-ui-dist/swagger-ui-standalone-preset.js"] + }, + "configurations": { + "production": { + "fileReplacements": [ + { + "replace": "projects/qbm-app-landingpage/src/environments/environment.ts", + "with": "projects/qbm-app-landingpage/src/environments/environment.prod.ts" + } + ], + "optimization": true, + "outputHashing": "all", + "sourceMap": false, + "namedChunks": true, + "aot": true, + "extractLicenses": true, + "budgets": [ + { + "type": "initial", + "maximumWarning": "20mb", + "maximumError": "40mb" + }, + { + "type": "anyComponentStyle", + "maximumWarning": "6kb" + } + ] + }, + "development": { + "optimization": false, + "extractLicenses": false, + "sourceMap": true, + "namedChunks": true + }, + "remote-dev": { + "fileReplacements": [ + { + "replace": "projects/qbm-app-landingpage/src/environments/environment.ts", + "with": "../imxweb_envs/qbm-app-landingpage/environments/environment.remote-dev.ts" + } + ], + "buildOptimizer": false, + "optimization": false, + "vendorChunk": true, + "extractLicenses": false, + "sourceMap": true, + "namedChunks": true + }, + "remote-qs": { + "fileReplacements": [ + { + "replace": "projects/qbm-app-landingpage/src/environments/environment.ts", + "with": "../imxweb_envs/qbm-app-landingpage/environments/environment.remote-qs.ts" + } + ], + "buildOptimizer": false, + "optimization": false, + "vendorChunk": true, + "extractLicenses": false, + "sourceMap": true, + "namedChunks": true + }, + "es5": { + "tsConfig": "./projects/qbm-app-landingpage/tsconfig-es5.app.json" + } + }, + "outputs": ["{options.outputPath}"] + }, + "serve": { + "executor": "@angular-devkit/build-angular:dev-server", + "options": { + "browserTarget": "qbm-app-landingpage:build", + "disableHostCheck": true + }, + "configurations": { + "production": { + "browserTarget": "qbm-app-landingpage:build:production" + }, + "development": { + "browserTarget": "qbm-app-landingpage:build:development" + }, + "remote-dev": { + "browserTarget": "qbm-app-landingpage:build:remote-dev" + }, + "remote-qs": { + "browserTarget": "qbm-app-landingpage:build:remote-qs" + }, + "es5": { + "browserTarget": "qbm-app-landingpage:build:es5" + } + } + }, + "extract-i18n": { + "executor": "@angular-devkit/build-angular:extract-i18n", + "options": { + "browserTarget": "qbm-app-landingpage:build" + } + }, + "test": { + "executor": "@angular-devkit/build-angular:karma", + "options": { + "main": "projects/qbm-app-landingpage/src/test.ts", + "polyfills": "projects/qbm-app-landingpage/src/polyfills.ts", + "tsConfig": "projects/qbm-app-landingpage/tsconfig.spec.json", + "karmaConfig": "projects/qbm-app-landingpage/karma.conf.js", + "scripts": [], + "assets": [ + "projects/qbm-app-landingpage/src/assets", + "projects/qbm-app-landingpage/src/appconfig.json", + { + "glob": "**/*", + "input": "./shared/assets/", + "output": "./assets" + } + ], + "styles": ["projects/qbm-app-landingpage/src/styles.scss"], + "stylePreprocessorOptions": { + "includePaths": [ + "./shared/assets", + "./shared/scss", + "./node_modules", + "./node_modules/@elemental-ui/cadence-icon", + "./node_modules/@elemental-ui/core" + ] + } + } + }, + "lint": { + "executor": "@angular-devkit/build-angular:tslint", + "options": { + "tsConfig": ["projects/qbm-app-landingpage/tsconfig.app.json", "projects/qbm-app-landingpage/tsconfig.spec.json"], + "exclude": ["**/node_modules/**", "**/*.spec.ts", "**/*.json"] + } + } + } +} diff --git a/imxweb/projects/qbm-app-landingpage/src/app/app-routing.module.ts b/imxweb/projects/qbm-app-landingpage/src/app/app-routing.module.ts index 8d25aef91..03ee9b1c8 100644 --- a/imxweb/projects/qbm-app-landingpage/src/app/app-routing.module.ts +++ b/imxweb/projects/qbm-app-landingpage/src/app/app-routing.module.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -25,10 +25,9 @@ */ import { NgModule } from '@angular/core'; -import { Routes, RouterModule } from '@angular/router'; -import { AuthenticationGuardService, LoginComponent, RouteGuardService } from 'qbm'; +import { RouterModule, Routes } from '@angular/router'; +import { AdminRoutes, AuthenticationGuardService, LoginComponent, RouteGuardService } from 'qbm'; import { StartComponent } from './start/start.component'; -import { AdminRoutes } from 'qbm'; const routes: Routes = [ ...AdminRoutes, @@ -45,7 +44,7 @@ const routes: Routes = [ ]; @NgModule({ - imports: [RouterModule.forRoot(routes, { useHash: true, relativeLinkResolution: 'legacy' })], + imports: [RouterModule.forRoot(routes, { useHash: true })], exports: [RouterModule], }) export class AppRoutingModule {} diff --git a/imxweb/projects/qbm-app-landingpage/src/app/app.component.html b/imxweb/projects/qbm-app-landingpage/src/app/app.component.html index 02e1cf47a..6ba785e1a 100644 --- a/imxweb/projects/qbm-app-landingpage/src/app/app.component.html +++ b/imxweb/projects/qbm-app-landingpage/src/app/app.component.html @@ -1,8 +1,7 @@
    - - +
    -
    \ No newline at end of file +
    diff --git a/imxweb/projects/qbm-app-landingpage/src/app/app.component.scss b/imxweb/projects/qbm-app-landingpage/src/app/app.component.scss index 7c5e545e3..dff596b9d 100644 --- a/imxweb/projects/qbm-app-landingpage/src/app/app.component.scss +++ b/imxweb/projects/qbm-app-landingpage/src/app/app.component.scss @@ -1,14 +1,13 @@ .page { - display: flex; - flex-direction: column; - overflow: hidden; - height: 100vh; - } - - .pageContent { - display: flex; - flex-direction: column; - overflow: hidden; - height: inherit; - } - \ No newline at end of file + display: flex; + flex-direction: column; + overflow: hidden; + height: 100vh; +} + +.pageContent { + display: flex; + flex-direction: column; + overflow: hidden; + height: inherit; +} diff --git a/imxweb/projects/qbm-app-landingpage/src/app/app.component.ts b/imxweb/projects/qbm-app-landingpage/src/app/app.component.ts index 0f5b937c7..b14acbd06 100644 --- a/imxweb/projects/qbm-app-landingpage/src/app/app.component.ts +++ b/imxweb/projects/qbm-app-landingpage/src/app/app.component.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -26,39 +26,46 @@ import { Component } from '@angular/core'; import { Title } from '@angular/platform-browser'; -import { NavigationEnd, Router, RouterEvent } from '@angular/router'; +import { Event, NavigationEnd, Router } from '@angular/router'; import { TranslateService } from '@ngx-translate/core'; -import { Globals } from 'imx-qbm-dbts'; -import { AppConfigService, AuthenticationService, ISessionState } from 'qbm'; +import { Globals } from '@imx-modules/imx-qbm-dbts'; +import { + AppConfigService, + AuthenticationService, + ClassloggerService, + ConfirmationService, + ISessionState, + Message, + UserMessageService, +} from 'qbm'; import { Subscription } from 'rxjs'; @Component({ selector: 'imx-root', templateUrl: './app.component.html', - styleUrls: ['./app.component.scss'] + styleUrls: ['./app.component.scss'], }) export class AppComponent { - public isLoggedIn = false; public hideUserMessage = false; private readonly subscriptions: Subscription[] = []; private overviewTitle: string; private adminPortalTitle: string; + public message: Message | undefined; constructor( + private readonly logger: ClassloggerService, private readonly translate: TranslateService, private readonly titleService: Title, private readonly appConfigService: AppConfigService, private readonly router: Router, private readonly translateService: TranslateService, - private readonly authentication: AuthenticationService + private readonly authentication: AuthenticationService, + private readonly confirmationService: ConfirmationService, + private readonly userMessageService: UserMessageService, ) { - this.translate.addLangs(['en-US', 'de-DE', 'de', 'en']); - const browserCulture = this.translate.getBrowserCultureLang(); - this.translate.setDefaultLang(browserCulture); - this.translate.use(browserCulture); this.titleService.setTitle(Globals.QIM_ProductNameFull + ' ' + this.appConfigService.Config.Title); this.translateService.onLangChange.subscribe(() => { @@ -66,56 +73,68 @@ export class AppComponent { this.setTitle(this.router.url); }); - this.subscriptions.push(this.authentication.onSessionResponse.subscribe(async (sessionState: ISessionState) => { - // Close the splash screen that opened in app service initialisation - this.isLoggedIn = sessionState.IsLoggedIn; - if (this.isLoggedIn) { - this.titleService.setTitle(this.adminPortalTitle); - } - })); + this.subscriptions.push( + this.authentication.onSessionResponse.subscribe(async (sessionState: ISessionState) => { + // Close the splash screen that opened in app service initialisation + this.isLoggedIn = sessionState?.IsLoggedIn ?? false; + if (this.isLoggedIn) { + this.titleService.setTitle(this.adminPortalTitle); + } + }), + ); + + this.subscriptions.push( + this.userMessageService.subject.subscribe((message) => { + this.message = message; + if (!!this.message && this.message.type === 'error' && !this.message.target) { + this.confirmationService.showErrorMessage({ + Message: this.message?.text, + }); + } + }), + ); this.setupRouter(); - } public ngOnDestroy(): void { - this.subscriptions.forEach(s => s.unsubscribe()); + this.subscriptions.forEach((s) => s.unsubscribe()); } public async ngOnInit(): Promise { this.initTitles(); - this.authentication.update(); + await this.authentication.update(); } /** - * Logs out and kills the session. - */ + * Logs out and kills the session. + */ public async logout(): Promise { await this.authentication.logout(); this.router.navigate([''], { queryParams: {} }); } private setupRouter(): void { - this.router.events.subscribe((event: RouterEvent) => { + this.router.events.subscribe((event: Event) => { if (event instanceof NavigationEnd) { - this.setTitle(this.router.url); + this.setTitle(this.router.url); } }); } - private async initTitles(): Promise { - this.overviewTitle = await this.translate.get('#LDS#Heading Web Applications Overview').toPromise(); - this.adminPortalTitle = await this.translate.get('#LDS#Heading Administration Portal').toPromise(); + private initTitles(): void { + this.overviewTitle = this.translate.instant('#LDS#Heading Web Applications Overview'); + this.adminPortalTitle = this.translate.instant('#LDS#Heading Administration Portal'); } private setTitle(url: string): void { - if (url === "/") { - // show another title on the startpage + if (url === '/') { + // show another title on the startpage this.titleService.setTitle(Globals.QIM_ProductNameFull + ' ' + this.overviewTitle); this.appConfigService.setTitle(this.overviewTitle); - } else { + } else { this.titleService.setTitle(Globals.QIM_ProductNameFull + ' ' + this.adminPortalTitle); this.appConfigService.setTitle(this.adminPortalTitle); - } + } } } diff --git a/imxweb/projects/qbm-app-landingpage/src/app/app.module.ts b/imxweb/projects/qbm-app-landingpage/src/app/app.module.ts index b94a5d03c..11bcb8ae4 100644 --- a/imxweb/projects/qbm-app-landingpage/src/app/app.module.ts +++ b/imxweb/projects/qbm-app-landingpage/src/app/app.module.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -24,39 +24,41 @@ * */ +import { provideHttpClient, withInterceptorsFromDi } from '@angular/common/http'; +import { APP_INITIALIZER, ErrorHandler, NgModule } from '@angular/core'; +import { MatCardModule } from '@angular/material/card'; import { BrowserModule } from '@angular/platform-browser'; -import { NgModule, APP_INITIALIZER, ErrorHandler } from '@angular/core'; import { BrowserAnimationsModule } from '@angular/platform-browser/animations'; -import { HttpClientModule } from '@angular/common/http'; -import { MatCardModule } from '@angular/material/card'; import { EuiCoreModule, EuiMaterialModule } from '@elemental-ui/core'; -import { TranslateModule, TranslateLoader, MissingTranslationHandler } from '@ngx-translate/core'; +import { MissingTranslationHandler, TranslateLoader, TranslateModule } from '@ngx-translate/core'; import { LoggerModule, NgxLoggerLevel } from 'ngx-logger'; -import { AppRoutingModule } from './app-routing.module'; -import { AppComponent } from './app.component'; -import { AppcontainerService } from './appcontainer.service'; +import { RECAPTCHA_V3_SITE_KEY } from 'ng-recaptcha-2'; +import { CustomThemeModule } from 'projects/qbm/src/lib/custom-theme/custom-theme.module'; import { + AdminModule, AppConfigService, AuthenticationModule, - imx_SessionService, + ExtModule, + GlobalErrorHandler, ImxMissingTranslationHandler, ImxTranslateLoader, MastHeadModule, - UserMessageModule, - AdminModule, - ExtModule, - GlobalErrorHandler, QbmModule, + UserMessageModule, + imx_SessionService, } from 'qbm'; +import appConfigJson from '../appconfig.json'; +import { environment } from '../environments/environment'; +import { AppRoutingModule } from './app-routing.module'; +import { AppComponent } from './app.component'; import { AppService } from './app.service'; +import { AppcontainerService } from './appcontainer.service'; import { StartComponent } from './start/start.component'; -import { environment } from '../environments/environment'; -import appConfigJson from '../appconfig.json'; -import { CustomThemeModule } from 'projects/qbm/src/lib/custom-theme/custom-theme.module'; @NgModule({ declarations: [AppComponent, StartComponent], + bootstrap: [AppComponent], imports: [ AdminModule, AppRoutingModule, @@ -66,7 +68,6 @@ import { CustomThemeModule } from 'projects/qbm/src/lib/custom-theme/custom-them CustomThemeModule, EuiCoreModule, EuiMaterialModule, - HttpClientModule, MastHeadModule, UserMessageModule, TranslateModule.forRoot({ @@ -82,7 +83,7 @@ import { CustomThemeModule } from 'projects/qbm/src/lib/custom-theme/custom-them ExtModule, MatCardModule, LoggerModule.forRoot({ level: NgxLoggerLevel.DEBUG, serverLogLevel: NgxLoggerLevel.OFF }), - QbmModule + QbmModule, ], providers: [ { provide: 'environment', useValue: environment }, @@ -100,7 +101,14 @@ import { CustomThemeModule } from 'projects/qbm/src/lib/custom-theme/custom-them AppcontainerService, AppConfigService, imx_SessionService, + { + provide: RECAPTCHA_V3_SITE_KEY, + useFactory: (config: AppService) => { + return config.recaptchaSiteKeyV3; + }, + deps: [AppService], + }, + provideHttpClient(withInterceptorsFromDi()), ], - bootstrap: [AppComponent], }) export class AppModule {} diff --git a/imxweb/projects/qbm-app-landingpage/src/app/app.service.ts b/imxweb/projects/qbm-app-landingpage/src/app/app.service.ts index 2eb7b9ef2..1b5bbcc0d 100644 --- a/imxweb/projects/qbm-app-landingpage/src/app/app.service.ts +++ b/imxweb/projects/qbm-app-landingpage/src/app/app.service.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -25,15 +25,25 @@ */ import { Injectable } from '@angular/core'; +import { TypedClient } from '@imx-modules/imx-api-qbm'; import { TranslateService } from '@ngx-translate/core'; -import { TypedClient } from 'imx-api-qbm'; -import { AppConfigService, CdrRegistryService, ImxTranslationProviderService, ClassloggerService, imx_SessionService, AuthenticationService } from 'qbm'; +import { + AppConfigService, + AuthenticationService, + CaptchaService, + CdrRegistryService, + ClassloggerService, + ImxTranslationProviderService, + SystemInfoService, + imx_SessionService, +} from 'qbm'; import { environment } from '../environments/environment'; @Injectable({ - providedIn: 'root' + providedIn: 'root', }) export class AppService { + public recaptchaSiteKeyV3: string | null = null; constructor( private logger: ClassloggerService, private readonly config: AppConfigService, @@ -41,21 +51,33 @@ export class AppService { private readonly session: imx_SessionService, private readonly translationProvider: ImxTranslationProviderService, public readonly registry: CdrRegistryService, - private readonly authentication: AuthenticationService - ) { } + private readonly authentication: AuthenticationService, + private readonly systemInfoService: SystemInfoService, + private readonly captchaService: CaptchaService, + ) {} public async init(): Promise { await this.config.init(environment.clientUrl); - this.translateService.addLangs(this.config.Config.Translation.Langs); - const browserCulture = this.translateService.getBrowserCultureLang(); + if (this.config.Config.Translation?.Langs) { + this.translateService.addLangs(this.config.Config.Translation.Langs); + } + const browserCulture = this.translateService.getBrowserCultureLang() as string; this.logger.debug(this, 'Set default language to', browserCulture); this.translateService.setDefaultLang(browserCulture); await this.translateService.use(browserCulture).toPromise(); - this.authentication.onSessionResponse.subscribe(sessionState => this.translationProvider.init(sessionState?.culture)); + this.authentication.onSessionResponse.subscribe((sessionState) => this.translationProvider.init(sessionState?.culture)); this.session.TypedClient = new TypedClient(this.config.v2client, this.translationProvider); + + const imxConfig = await this.systemInfoService.getImxConfig(); + + if (imxConfig.RecaptchaPublicKey) { + this.captchaService.enableReCaptcha(imxConfig.RecaptchaPublicKey); + this.recaptchaSiteKeyV3 = imxConfig.RecaptchaPublicKey; + } + this.captchaService.captchaImageUrl = 'admin/captchaimage'; } public static init(app: AppService): () => Promise { diff --git a/imxweb/projects/qbm-app-landingpage/src/app/appcontainer.service.spec.ts b/imxweb/projects/qbm-app-landingpage/src/app/appcontainer.service.spec.ts index c4acc6e2a..7816b6d2e 100644 --- a/imxweb/projects/qbm-app-landingpage/src/app/appcontainer.service.spec.ts +++ b/imxweb/projects/qbm-app-landingpage/src/app/appcontainer.service.spec.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -30,7 +30,7 @@ import { AppcontainerService } from './appcontainer.service'; import { environment } from '../environments/environment'; import { AppConfigService } from 'qbm'; -[false, true].forEach(environmentIsProduction => { +[false, true].forEach((environmentIsProduction) => { describe('AppcontainerService Constructor with environmentIsProduction=' + environmentIsProduction, () => { let service: AppcontainerService; @@ -44,11 +44,11 @@ import { AppConfigService } from 'qbm'; public Config = { Basepath: '', Title: '', - WebAppIndex: '' + WebAppIndex: '', }; - } - } - ] + }, + }, + ], }).get(AppcontainerService); environment.production = environmentIsProduction; @@ -69,11 +69,11 @@ describe('AppcontainerService Methods', () => { Config: { Basepath: '', Title: '', - WebAppIndex: '' + WebAppIndex: '', }, client: { - imx_applications_get: jasmine.createSpy('imx_applications_get').and.returnValue(Promise.resolve(nodeAppInfo)) - } + imx_applications_get: jasmine.createSpy('imx_applications_get').and.returnValue(Promise.resolve(nodeAppInfo)), + }, }; beforeEach(() => { @@ -84,9 +84,9 @@ describe('AppcontainerService Methods', () => { AppcontainerService, { provide: AppConfigService, - useValue: appConfigServiceStub - } - ] + useValue: appConfigServiceStub, + }, + ], }).get(AppcontainerService); }); diff --git a/imxweb/projects/qbm-app-landingpage/src/app/appcontainer.service.ts b/imxweb/projects/qbm-app-landingpage/src/app/appcontainer.service.ts index 4f152c00d..98ce94d93 100644 --- a/imxweb/projects/qbm-app-landingpage/src/app/appcontainer.service.ts +++ b/imxweb/projects/qbm-app-landingpage/src/app/appcontainer.service.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -26,15 +26,15 @@ import { Injectable } from '@angular/core'; -import { NodeAppInfo } from 'imx-api-qbm'; +import { NodeAppInfo } from '@imx-modules/imx-api-qbm'; import { environment } from '../environments/environment'; import { AppConfigService } from 'qbm'; @Injectable() export class AppcontainerService { - constructor(private readonly appConfigService: AppConfigService) { } + constructor(private readonly appConfigService: AppConfigService) {} - /** Gets a flag indicating whether the user can log in to the + /** Gets a flag indicating whether the user can log in to the * Server Administration app. */ public hasServerAdministrationApp = false; @@ -54,7 +54,7 @@ export class AppcontainerService { }) .map((appInfo: NodeAppInfo) => ({ link: this.appConfigService.BaseUrl + '/html/' + appInfo.Name, - app: appInfo + app: appInfo, })); } } diff --git a/imxweb/projects/qbm-app-landingpage/src/app/start/start.component.html b/imxweb/projects/qbm-app-landingpage/src/app/start/start.component.html index f4890badb..b8336ce7e 100644 --- a/imxweb/projects/qbm-app-landingpage/src/app/start/start.component.html +++ b/imxweb/projects/qbm-app-landingpage/src/app/start/start.component.html @@ -18,7 +18,11 @@ {{ '#LDS#Heading Administration Portal' | translate }} -

    {{ '#LDS#Here you can configure your HTML applications. Additionaly, you can reset your changes to default settings.' | translate }}

    +

    + {{ + '#LDS#Here you can configure your HTML applications. Additionaly, you can reset your changes to default settings.' | translate + }} +

    diff --git a/imxweb/projects/qbm-app-landingpage/src/app/start/start.component.scss b/imxweb/projects/qbm-app-landingpage/src/app/start/start.component.scss index 80f2052da..ae48f6773 100644 --- a/imxweb/projects/qbm-app-landingpage/src/app/start/start.component.scss +++ b/imxweb/projects/qbm-app-landingpage/src/app/start/start.component.scss @@ -11,12 +11,17 @@ min-height: 270px; float: left; margin: 10px; - + padding:16px; mat-card-content { - padding: 0px 10px 10px 10px; + padding: 0px 10px 10px 10px !important; + > p { text-align: justify; + font-size:14px; } } + .mat-mdc-card-title{ + font-size: 24px; + } } } diff --git a/imxweb/projects/qbm-app-landingpage/src/app/start/start.component.ts b/imxweb/projects/qbm-app-landingpage/src/app/start/start.component.ts index daff6b514..fa5059769 100644 --- a/imxweb/projects/qbm-app-landingpage/src/app/start/start.component.ts +++ b/imxweb/projects/qbm-app-landingpage/src/app/start/start.component.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -31,7 +31,7 @@ import { AppcontainerService, AppContainer } from '../appcontainer.service'; @Component({ selector: 'imx-start', templateUrl: './start.component.html', - styleUrls: ['./start.component.scss'] + styleUrls: ['./start.component.scss'], }) export class StartComponent implements OnInit { public apps: AppContainer[] = []; @@ -39,7 +39,7 @@ export class StartComponent implements OnInit { /** do not display partial results */ public loaded: boolean; - constructor(private appcontainerService: AppcontainerService) { } + constructor(private appcontainerService: AppcontainerService) {} public async ngOnInit(): Promise { this.apps = await this.appcontainerService.getAppContainers(); diff --git a/imxweb/projects/qbm-app-landingpage/src/environments/environment.prod.ts b/imxweb/projects/qbm-app-landingpage/src/environments/environment.prod.ts index 52c300e43..7e86ef2ac 100644 --- a/imxweb/projects/qbm-app-landingpage/src/environments/environment.prod.ts +++ b/imxweb/projects/qbm-app-landingpage/src/environments/environment.prod.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -29,5 +29,5 @@ export const environment = { production: true, clientUrl: '', appName: packageJson.name, - appVersion: packageJson.version + appVersion: packageJson.version, }; diff --git a/imxweb/projects/qbm-app-landingpage/src/environments/environment.ts b/imxweb/projects/qbm-app-landingpage/src/environments/environment.ts index de9c0390d..1321fa2e3 100644 --- a/imxweb/projects/qbm-app-landingpage/src/environments/environment.ts +++ b/imxweb/projects/qbm-app-landingpage/src/environments/environment.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -35,5 +35,5 @@ export const environment = { production: false, clientUrl: 'http://localhost:8182', appName: packageJson.name, - appVersion: packageJson.version + appVersion: packageJson.version, }; diff --git a/imxweb/projects/qbm-app-landingpage/src/index.html b/imxweb/projects/qbm-app-landingpage/src/index.html index 4b785ba4e..f08db67fd 100644 --- a/imxweb/projects/qbm-app-landingpage/src/index.html +++ b/imxweb/projects/qbm-app-landingpage/src/index.html @@ -1,15 +1,13 @@ + + + + + + - - - - - - - - - - - + + + diff --git a/imxweb/projects/qbm-app-landingpage/src/main.ts b/imxweb/projects/qbm-app-landingpage/src/main.ts index 9fb380327..aa265c318 100644 --- a/imxweb/projects/qbm-app-landingpage/src/main.ts +++ b/imxweb/projects/qbm-app-landingpage/src/main.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -34,5 +34,6 @@ if (environment.production) { enableProdMode(); } -platformBrowserDynamic().bootstrapModule(AppModule) - .catch(err => console.log(err)); +platformBrowserDynamic() + .bootstrapModule(AppModule) + .catch((err) => console.log(err)); diff --git a/imxweb/projects/qbm-app-landingpage/src/polyfills.ts b/imxweb/projects/qbm-app-landingpage/src/polyfills.ts index 64a64e1c0..e38109681 100644 --- a/imxweb/projects/qbm-app-landingpage/src/polyfills.ts +++ b/imxweb/projects/qbm-app-landingpage/src/polyfills.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -41,9 +41,8 @@ */ /*************************************************************************************************** -* BROWSER POLYFILLS -*/ - + * BROWSER POLYFILLS + */ /** IE10 and IE11 requires the following for NgClass support on SVG elements */ // import 'classlist.js'; // Run `npm install --save classlist.js`. @@ -51,16 +50,15 @@ /** IE10 and IE11 requires the following for the Reflect API. */ // import 'core-js/es6/reflect'; - /** Evergreen browsers require these. */ // Used for reflect-metadata in JIT. If you use AOT (and only Angular decorators), you can remove. -import 'core-js/es7/reflect'; +import 'core-js/es/reflect'; // Used for support array.includes -import 'core-js/es7/array'; +import 'core-js/es/array'; // Used for support object.values -import 'core-js/es7/object'; +import 'core-js/es/object'; /** * Required to support Web Animations `@angular/platform-browser/animations`. @@ -68,17 +66,13 @@ import 'core-js/es7/object'; */ import 'web-animations-js'; - - /*************************************************************************************************** * Zone JS is required by default for Angular itself. */ -import 'zone.js/dist/zone'; // Included with Angular CLI. - - +import 'zone.js'; // Included with Angular CLI. /*************************************************************************************************** * APPLICATION IMPORTS */ -import 'whatwg-fetch'; import 'url-polyfill'; +import 'whatwg-fetch'; diff --git a/imxweb/projects/qbm-app-landingpage/src/styles.scss b/imxweb/projects/qbm-app-landingpage/src/styles.scss index 2609ec369..ddbe8a4a7 100644 --- a/imxweb/projects/qbm-app-landingpage/src/styles.scss +++ b/imxweb/projects/qbm-app-landingpage/src/styles.scss @@ -1,29 +1,28 @@ /* You can add global styles to this file, and also import other style files */ -@use '@angular/material' as mat; - -$material_icons_font_path: "~node_modules/@elemental-ui/core/assets/MaterialIcons"; -$cadence_font_path: "~node_modules/@elemental-ui/core/assets/Cadence"; -$source_sans_pro_font_path: "~node_modules/@elemental-ui/core/assets/Source_Sans_Pro"; - @import '@elemental-ui/core/src/styles/core.scss'; .eui-dark-theme { - .page { - color: $color-gray-5; - background-color: $color-gray-80; - } - .pageContent { - color: $color-gray-5; - background-color: $color-gray-80; - } - .eui-sidesheet { - .mat-toolbar{ - background-color: $color-blue-80; - } - } - .eui-sidesheet-actions.mat-card.eui-sidesheet-actions--white{ - background-color: $color-gray-70; - } - + .page { + color: $color-gray-5; + background-color: $color-gray-80; + } + .pageContent { + color: $color-gray-5; + background-color: $color-gray-80; + } + .eui-sidesheet-actions.mat-mdc-card.eui-sidesheet-actions--white { + background-color: $color-gray-70; + } + .page { + color: $color-gray-5; + background-color: $color-gray-80; + } + .pageContent { + color: $color-gray-5; + background-color: $color-gray-80; + } + .eui-sidesheet-actions.mat-mdc-card.eui-sidesheet-actions--white { + background-color: $color-gray-70; + } } .eui-contrast-theme { @@ -35,13 +34,7 @@ $source_sans_pro_font_path: "~node_modules/@elemental-ui/core/assets/Source_Sans color: $color-gray-0; background-color: $color-gray-100; } - .eui-sidesheet { - .mat-toolbar{ - background-color: $color-blue-80; - } - } - .eui-sidesheet-actions.mat-card.eui-sidesheet-actions--white{ - background-color: $color-gray-90; + .eui-sidesheet-actions.mat-mdc-card.eui-sidesheet-actions--white { + background-color: $color-gray-90; } - } diff --git a/imxweb/projects/qbm-app-landingpage/src/test.ts b/imxweb/projects/qbm-app-landingpage/src/test.ts index 5b533ce8e..a0cdd3bfc 100644 --- a/imxweb/projects/qbm-app-landingpage/src/test.ts +++ b/imxweb/projects/qbm-app-landingpage/src/test.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -26,16 +26,13 @@ // This file is required by karma.conf.js and loads recursively all the .spec and framework files -import 'zone.js/dist/zone-testing'; +// Zone must be imported first. Be careful with prettier import organizing +import 'zone.js'; +import 'zone.js/testing'; + import { getTestBed } from '@angular/core/testing'; import { BrowserDynamicTestingModule, platformBrowserDynamicTesting } from '@angular/platform-browser-dynamic/testing'; import { TestHelperModule } from 'qbm'; -declare const require: any; - // First, initialize the Angular testing environment. getTestBed().initTestEnvironment([BrowserDynamicTestingModule, TestHelperModule], platformBrowserDynamicTesting()); -// Then we find all the tests. -const context = require.context('./', true, /\.spec\.ts$/); -// And load the modules. -context.keys().map(context); diff --git a/imxweb/projects/qbm-app-landingpage/tsconfig-es5.app.json b/imxweb/projects/qbm-app-landingpage/tsconfig-es5.app.json index e1d0d6abd..036b8797e 100644 --- a/imxweb/projects/qbm-app-landingpage/tsconfig-es5.app.json +++ b/imxweb/projects/qbm-app-landingpage/tsconfig-es5.app.json @@ -1,6 +1,6 @@ { - "extends": "./tsconfig.app.json", - "compilerOptions": { - "target": "es2020" + "extends": "./tsconfig.app.json", + "compilerOptions": { + "target": "es2020" } -} \ No newline at end of file +} diff --git a/imxweb/projects/qbm-app-landingpage/tsconfig.app.json b/imxweb/projects/qbm-app-landingpage/tsconfig.app.json index 190ca1d58..b7c805879 100644 --- a/imxweb/projects/qbm-app-landingpage/tsconfig.app.json +++ b/imxweb/projects/qbm-app-landingpage/tsconfig.app.json @@ -1,14 +1,13 @@ { "extends": "../../tsconfig.json", "compilerOptions": { + "strictNullChecks": true, "outDir": "../../out-tsc/app", "types": [] }, - "files": [ - "src/main.ts", - "src/polyfills.ts" - ], - "include": [ - "projects/qbm-app-landingpage/src/**/*.d.ts" - ] + "angularCompilerOptions": { + "strictTemplates": true + }, + "files": ["src/main.ts", "src/polyfills.ts"], + "include": ["projects/qbm-app-landingpage/src/**/*.d.ts"] } diff --git a/imxweb/projects/qbm-app-landingpage/tsconfig.spec.json b/imxweb/projects/qbm-app-landingpage/tsconfig.spec.json index 4260637ec..eb1ff8a3b 100644 --- a/imxweb/projects/qbm-app-landingpage/tsconfig.spec.json +++ b/imxweb/projects/qbm-app-landingpage/tsconfig.spec.json @@ -2,18 +2,8 @@ "extends": "../../tsconfig.json", "compilerOptions": { "outDir": "../../out-tsc/spec", - "types": [ - "jasmine", - "node", - "karma-viewport" - ] + "types": ["jasmine", "node", "karma-viewport"] }, - "files": [ - "src/test.ts", - "src/polyfills.ts" - ], - "include": [ - "**/*.spec.ts", - "**/*.d.ts" - ] + "files": ["src/test.ts", "src/polyfills.ts"], + "include": ["**/*.spec.ts", "**/*.d.ts"] } diff --git a/imxweb/projects/qbm-app-landingpage/tslint.json b/imxweb/projects/qbm-app-landingpage/tslint.json deleted file mode 100644 index ef4889cbe..000000000 --- a/imxweb/projects/qbm-app-landingpage/tslint.json +++ /dev/null @@ -1,17 +0,0 @@ -{ - "extends": "../../tslint.json", - "rules": { - "directive-selector": [ - true, - "attribute", - "imx", - "camelCase" - ], - "component-selector": [ - true, - "element", - "imx", - "kebab-case" - ] - } -} diff --git a/imxweb/projects/qbm/.compodocrc.json b/imxweb/projects/qbm/.compodocrc.json index 60cb1367c..2b41d9a4e 100644 --- a/imxweb/projects/qbm/.compodocrc.json +++ b/imxweb/projects/qbm/.compodocrc.json @@ -1,6 +1,6 @@ { "name": "IMX Web - QBM Library", - "output": "../../documentation/v92/qbm", + "output": "../../documentation/v93/qbm", "assetsFolder": "../../compodoc/assets", "theme": "material", "customLogo": "../../compodoc/assets/images/oneidentity-logo.png", diff --git a/imxweb/projects/qbm/.eslintrc.json b/imxweb/projects/qbm/.eslintrc.json new file mode 100644 index 000000000..e384394c6 --- /dev/null +++ b/imxweb/projects/qbm/.eslintrc.json @@ -0,0 +1,35 @@ +{ + "extends": "../../.eslintrc.json", + "ignorePatterns": ["!**/*", "**/*.spec.ts"], + "overrides": [ + { + "files": ["*.ts"], + "parserOptions": { + "project": ["imxweb/projects/qbm/tsconfig.lib.json", "imxweb/projects/qbm/tsconfig.spec.json"], + "createDefaultProgram": true + }, + "rules": { + "@angular-eslint/directive-selector": [ + "error", + { + "type": "attribute", + "prefix": "imx", + "style": "camelCase" + } + ], + "@angular-eslint/component-selector": [ + "error", + { + "type": "element", + "prefix": "imx", + "style": "kebab-case" + } + ] + } + }, + { + "files": ["*.html"], + "rules": {} + } + ] +} diff --git a/imxweb/projects/qbm/README.md b/imxweb/projects/qbm/README.md index 9cc173179..ef9626aa2 100644 --- a/imxweb/projects/qbm/README.md +++ b/imxweb/projects/qbm/README.md @@ -1,22 +1,22 @@ # Configuration module -This library contains all basic components, that are used in all other projects as well. +The `qbm` library contains all basic components that are also used in all other projects. -That includes, but is not limited to, our table structure, column dependent references (CDR) and the sql wizard. +This includes, but is not limited to, the table structure, column-dependent references (CDR) and the SQL wizard. -For a more detailed view of the API structure, you can got to the following pages: +For a more detailed view of the API structure, refer to the following sections: - [Administration](additional-documentation/library-overview/administration.html) -- [Properties of an Object](additional-documentation/library-overview/property-handling.html) -- [Data Sets](additional-documentation/library-overview/data-sets.html) -- [Messages and Translation](additional-documentation/library-overview/messages.html) -- [Other Reusable Components and Services](additional-documentation/library-overview/other-reusable-components.html) +- [Properties of an object](additional-documentation/library-overview/property-handling.html) +- [Data sets](additional-documentation/library-overview/data-sets.html) +- [Messages and translation](additional-documentation/library-overview/messages.html) +- [Other reusable components and services](additional-documentation/library-overview/other-reusable-components.html) ## Helpful topics - [Theming the application](additional-documentation/theming-the-application.html) - [Samples](additional-documentation/sdk-samples.html) - [Adding a tile component to the dashboard](additional-documentation/sdk-samples/adding-a-tile-component-to-the-dashboard.html) - - [Adding a menu to the Portal](additional-documentation/sdk-samples/adding-a-menu-to-the-portal.html) + - [Adding a menu to the Web Portal](additional-documentation/sdk-samples/adding-a-menu-to-the-portal.html) - [Working with data tables](additional-documentation/sdk-samples/working-with-data-tables.html) \ No newline at end of file diff --git a/imxweb/projects/qbm/additionalDocumentation/admin.md b/imxweb/projects/qbm/additionalDocumentation/admin.md index c4ff53076..873bb8c42 100644 --- a/imxweb/projects/qbm/additionalDocumentation/admin.md +++ b/imxweb/projects/qbm/additionalDocumentation/admin.md @@ -1,20 +1,18 @@ # Administration -The Administration Portal consists of the following main components. +The Administration Portal consists of the following main components: -- [`DashboardComponent`](../../components/DashboardComponent.html) defines the main page. -- [`StatusComponent`](../../components/StatusComponent.html) shows the list of available applications. -- [`ConfigComponent`](../../components/ConfigComponent.html) exposes the API configuration layer. -- [`PackagesComponent`](../../components/PackagesComponent.html) shows the list of available packages. -- [`PluginsComponent`](../../components/PluginsComponent.html) shows the list of loaded API plugins. -- [`CacheComponent`](../../components/CacheComponent.html) shows the cache status. -- [`LogsComponent`](../../components/LogsComponent.html) provides access to the server logs. -- [`SwaggerComponent`](../../components/SwaggerComponent.html) wraps the API documentation component. +- The [`DashboardComponent`](../../components/DashboardComponent.html) defines the homepage. +- The [`StatusComponent`](../../components/StatusComponent.html) shows the list of API projects. +- The [`ConfigComponent`](../../components/ConfigComponent.html) provides the API configuration. +- The [`PackagesComponent`](../../components/PackagesComponent.html) shows the list of available packages. +- The [`PluginsComponent`](../../components/PluginsComponent.html) shows the list of loaded API plugins. +- The [`CacheComponent`](../../components/CacheComponent.html) shows the cache status. +- The [`LogsComponent`](../../components/LogsComponent.html) provides access to the server logs. +- The [`SwaggerComponent`](../../components/SwaggerComponent.html) wraps the API documentation component. ## Authentication -In this section you will find other component, that are used during authentication. +The login itself is handled by the [`AuthenticationService`](../../injectables/AuthenticationService.html). The UI component for authentication is provided by the [`LoginComponent`](../../components/LoginComponent.html). -The login itself is handled by the [`AuthenticationService`](../../injectables/AuthenticationService.html). The UI component is provided by the [`LoginComponent`](../../components/LoginComponent.html). - -To check whether the user is currently logged in, there is a special [route guard](../../guards/AuthenticationGuardService.html) to redirect the user to the login component if a login is requred. An older way doing this is using the [`imx_SessionService`](../../injectables/imx_SessionService.html). \ No newline at end of file +To check whether the user is currently logged in, there is a special [route guard](../../guards/AuthenticationGuardService.html) to redirect the user to the login component if a login is required. An older way of doing this is using the [`imx_SessionService`](../../injectables/imx_SessionService.html). \ No newline at end of file diff --git a/imxweb/projects/qbm/additionalDocumentation/datasets.md b/imxweb/projects/qbm/additionalDocumentation/datasets.md index 2e5306ed1..9d80a3555 100644 --- a/imxweb/projects/qbm/additionalDocumentation/datasets.md +++ b/imxweb/projects/qbm/additionalDocumentation/datasets.md @@ -1,10 +1,9 @@ -# Data Sets +# Data sets +In this section you can find information about components that are designed to display data sets. These cover both flat lists and hierarchical data structures. -In this section you can find components that are designed to display data sets. These cover both flat lists and hierarchical data structures. - -## 1. Data Source Toolbar +## Data source toolbar The [`DataSourceToolbarComponent`](../../components/DataSourceToolbarComponent.html) is used to handle the interaction between the data source and the actual view. -It is defined in the [`DataSourceToolbarModule`](../../modules/DataSourceToolbarModule.html), together with the other components that are used inside the toolbar. +It is defined in the [`DataSourceToolbarModule`](../../modules/DataSourceToolbarModule.html) together with other components that are used inside the toolbar. The following features are available: - Filtering @@ -13,55 +12,48 @@ The following features are available: - Sorting - Export and configuration of the view -The definition of values and functions for these features should be defined using the [`DataSourceToolbarSettings`](../../interfaces/DataSourceToolbarSettings.html) interface. - +The definition of values and functions for these features is defined using the [`DataSourceToolbarSettings`](../../interfaces/DataSourceToolbarSettings.html) interface. -## 2. Paginator -The [`DataSourcePaginatorComponent`](../../components/DataSourcePaginatorComponent.html) is used to handle pagination of the data. This is done by updating the navigation state of its linked [`DataSourceToolbarComponent`](../../components/DataSourceToolbarComponent.html). The usage of a paginator is optional. -## 3. View Components +## Paginator +The [`DataSourcePaginatorComponent`](../../components/DataSourcePaginatorComponent.html) is used to paginate the data. This is done by updating the navigation state of the associated [`DataSourceToolbarComponent`](../../components/DataSourceToolbarComponent.html). The usage of a paginator is optional. -### 3.1. Data Table -The [`DataTableComponent`](../../components/DataTableComponent.html) is the most commonly used view component for our portals. +## View components -It renders an Angular Material table with columns that can be defined by using other components. These are defined in the [`DataTableModule`](../../modules/DataTableModule.html), as well as the data table itself. +### Data table +The [`DataTableComponent`](../../components/DataTableComponent.html) is the most commonly used view component for the web applications. -### 3.2. Data Tiles +This component renders an Angular Material table with columns that can be defined by using other components. These are defined in the [`DataTableModule`](../../modules/DataTableModule.html), as well as the data table itself. +### Data tiles The [`DataTilesComponent`](../../components/DataTilesComponent.html) can be used to render a tile view which displays a [`DataTileComponent`](../../components/DataTileComponent.html) for each element in the data source. Both components are part of the [`DataTileModule`](../../modules/DataTilesModule.html), but only the [`DataTilesComponent`](../../components/DataTilesComponent.html) is exported. -### 3.3. Data Tree -The [`DataTreeComponent`](../../components/DataTreeComponent.html) can be used to display hierarchical data. Other than the table, it uses a special data source, that can be defined by extending the abstract [`TreeDatabase`](../../classes/TreeDatabase.html) class. The data tree is part of the [`DataTreeModule`](../../modules/DataTreeModule.html), together with other components that can be used with the data tree like the [`DataTreeSearchResultsComponent`](../../components/DataTreeSearchResultsComponent.html). This component shows a flat view of an entry subset, because some parameter like a filter or a search string will flatten the result. - -If you prefer to use a data tree with a data source toolbar functionality, there is a [`DataTreeWrapperComponent`](../../components/DataTreeWrapperComponent.html) defined in the [`DataTreeWrapperModule`](../../modules/DataTreeWrapperModule.html). This component combines a data tree with a data source toolbar so that the user can search and filter the tree. - -### 3.5. Other +### Data tree +The [`DataTreeComponent`](../../components/DataTreeComponent.html) can be used to display hierarchical data. Other than the data table, it uses a special data source, that can be defined by extending the abstract [`TreeDatabase`](../../classes/TreeDatabase.html) class. The data tree is part of the [`DataTreeModule`](../../modules/DataTreeModule.html) along with other components that can be used with the data tree, such as the [`DataTreeSearchResultsComponent`](../../components/DataTreeSearchResultsComponent.html). This component shows a flat view of an entry subset, because a parameter such as a filter or a search string narrows the result. -There are some other components that can be used to display a list of elements. However, these components are not compatible with the data source toolbar. +If you prefer to use a data tree with a data source toolbar functionality, there is the [`DataTreeWrapperComponent`](../../components/DataTreeWrapperComponent.html) defined in the [`DataTreeWrapperModule`](../../modules/DataTreeWrapperModule.html). This component combines a data tree with a data source toolbar so that the user can search and filter the tree. -**Select Component** +### Select component +NOTE: This component is not compatible with the data source toolbar. -The [`SelectComponent`](../../components/SelectComponent.html) can be used to show a list of entries using an auto complete control. It is defined in the [`SelectModule`](../../modules/SelectModule.html). +The [`SelectComponent`](../../components/SelectComponent.html) can be used to show a list of entries using an autocomplete control. It is defined in the [`SelectModule`](../../modules/SelectModule.html). -**Ordered List Component** +### Ordered list component +NOTE: This component is not compatible with the data source toolbar. The [`OrderedListComponent`](../../components/OrderedListComponent.html) can be used to display a simple list of `` entries. It is defined in the [`OrderedListModule`](../../modules/OrderedListModule.html). +## Related components +The following components are related to listings. -## 4. Other Components +### Selected elements +Because all view component can contain a multi-select feature, it is possible to select only some items. To check which elements are selected across pages, the [`SelectedElementsComponent`](../../) can be used. This component shows how many elements are selected and, when clicked, opens a side sheet with all selected elements in a table. -Here are some components that are connected to listings, but do not really fit into the other categories. - -### 4.1 Selected Elements -Because all view component can contain a multi-select feature, it is possible to select some items. If you like to check, which elements are selected across pages, you can use a [`SelectedElementsComponent`](../../) that shows, how many elements are selected. This component is clickable, which opens a side sheet with all elements inside a table. - -### 4.2 Foreign Key Picker -There are two foreign key picker dialogs available. - -**4.2.1 Normal Picker** +### Foreign key picker +The following foreign key picker dialogs are available. +#### Normal picker The classic data picker is defined inside the [`FkAdvancedPickerComponent`](../../components/FkAdvancedPickerComponent.html). It contains a [`FkSelectorComponent`](../../components/FkSelectorComponent.html) that could be used on other components as well. -**4.2.2 Hierarchical Picker** - -The hierarchical picker is defined in the [`FkHierarchicalDialogComponent`](../../components/FkHierarchicalDialogComponent.html) and displays the data inside a searchable tree. \ No newline at end of file +##### Hierarchical picker +The hierarchical picker is defined in the [`FkHierarchicalDialogComponent`](../../components/FkHierarchicalDialogComponent.html) and displays the data in a searchable tree. \ No newline at end of file diff --git a/imxweb/projects/qbm/additionalDocumentation/messages.md b/imxweb/projects/qbm/additionalDocumentation/messages.md index 7caefc1f2..2e7400dd7 100644 --- a/imxweb/projects/qbm/additionalDocumentation/messages.md +++ b/imxweb/projects/qbm/additionalDocumentation/messages.md @@ -1,48 +1,41 @@ -# Messages and Translation -This section describes components that are used to display messages in different languages to the user. There are the following components and services available. +# UI texts and translation +In this section you can find information about components that are used to display UI texts in different languages to the user. -## 1. Messages +## Messages -### 1.1. User Messages -User messages are displayed using the [`UserMessageComponent`](../../components/UserMessageComponent.html), which renders/uses an Elemental UI alert component. +### User messages +User messages are displayed using the [`UserMessageComponent`](../../components/UserMessageComponent.html) which renders/uses an Elemental UI alert component. -### 1.2. Message Dialog -The message dialog is defined in the [`MessageDialogComponent`](../../components/MessageDialogComponent.html). \ -It can display the same information the normal [`UserMessageComponent`](../../components/UserMessageComponent.html) is showing, but it uses an Angular Material Dialog instead. +### Message dialog +The message dialog is defined in the [`MessageDialogComponent`](../../components/MessageDialogComponent.html). It can display the same information the normal [`UserMessageComponent`](../../components/UserMessageComponent.html) is showing, but it uses an Angular Material dialog instead. [`MessageDialogComponent`](../../components/MessageDialogComponent.html) is part of the [`QbmModule`](../../modules/QbmModule.html). -### 1.3. Confirmation Dialog -The confirmation dialog is opened using the [`ConfirmationService`](../../injectables/ConfirmationService.html). \ -It allows the user to acknowledge the information it is presented. +### Confirmation dialog +The confirmation dialog is opened using the [`ConfirmationService`](../../injectables/ConfirmationService.html). It allows the user to confirm a specific action (for example, deleting an object). -### 1.4. Snackbar -A possible way to display a small notification is by using an Angular Snackbar component. To open a pre defined snackbar, you can use the [`SnackBarService`](../../injectables/SnackBarService.html). -It is part of the [`QbmModule`](../../modules/QbmModule.html) as well. +### Snackbar +To display a small notification the Angular [`SnackBarService`](../../injectables/SnackBarService.html) can be used. -### 1.5. Logging -There is a special logger, that can be used, to send messages to the command line. +### Logging +To send messages to the command line, the special [ClassLoggerService](../../injectables/ClassloggerService.html) can be used. -The code is defined in the [ClassLoggerService](../../injectables/ClassloggerService.html). - -### 1.6 Error Handling -Error handling is handled by our own `ErrorHandler`. - -It is defined in the [`GlobalErrorHandler`](../../injectables/GlobalErrorHandler.html). +### Error handling +Error handling is handled by the [`GlobalErrorHandler`](../../injectables/GlobalErrorHandler.html). --- -## 2. Translation -Our libraries are using translatable keys, identifiable by the prefix `#LDS#`. The services need to translate these keys into localized text at runtime are described below. +## Translation +The libraries are using translatable keys, identifiable by the prefix `#LDS#`. The following services are needed to translate these keys into localized text at runtime. -### 2.1. Translation -This uses the [`ImxTranslationProviderService`](../../injectables/ImxTranslationProviderService.html) to initialize the translation information. You can use this service for translation purposes as well, but it is recommended to use the `TranslateService` from `@ngx-translate`, which is used in this service anyway. +### Translation service +To initialize the translation information, the [`ImxTranslationProviderService`](../../injectables/ImxTranslationProviderService.html) is used. You can use this service for translation purposes, but it is recommended to use the `TranslateService` from `@ngx-translate`, which is used in this service anyway. -### 2.2. LDS Replace -The [`LdsReplaceModule`](../../modules/LdsReplaceModule.html) contains a pipe which can be used to replace placeholder inside LDS key translations. It is defined in the [`LdsReplacePipe`](../../injectables/LdsReplacePipe.html) class. +### LDS replace +The [`LdsReplaceModule`](../../modules/LdsReplaceModule.html) contains a [`LdsReplacePipe`](../../injectables/LdsReplacePipe.html) class which can be used to replace placeholders inside LDS key translations. -### 2.3. Parameterized Text +### Parameterized text The [`ParameterizedTextModule`](../../modules/ParameterizedTextModule.html) provides components and services to display a parameterized text that emphasizes it's parameters. The UI is defined in the [`ParameterizedTextComponent`](../../components/ParameterizedTextComponent.html). -### 2.4. Translation Editor -The [`TranslationEditorComponent`](../../) is declared in the [`QbmModule`](../../modules/QbmModule.html). It can be used to add translations to an LDS key. \ No newline at end of file +### Translation editor +The [`TranslationEditorComponent`](../../components/TranslationEditorComponent.html) can be used to to add translations to an LDS key. It is declared in the [`QbmModule`](../../modules/QbmModule.html). \ No newline at end of file diff --git a/imxweb/projects/qbm/additionalDocumentation/other.md b/imxweb/projects/qbm/additionalDocumentation/other.md index 1105fbc56..8c4192168 100644 --- a/imxweb/projects/qbm/additionalDocumentation/other.md +++ b/imxweb/projects/qbm/additionalDocumentation/other.md @@ -1,53 +1,51 @@ -# Other Reusable Components and Services - -In this section you can find components that are intended to be reused in other libraries and applications, and not covered by the other sections. - -## 1. Bulk Editor +# Other reusable components and services +In this section you can find information about components that are intended for reuse in other libraries and applications and are not covered by the other sections. +## Bulk editor The [`BulkPropertyEditorComponent`](../../components/BulkPropertyEditorComponent.html) is used to edit the same list properties for multiple objects. Each [`BulkItemComponent`](../../components/BulkItemComponent.html) has its own list of [`CdrEditorComponents`](../../components/CdrEditorComponent.html). -## 2. Busy Indicator -The [BusyIndicatorComponent](../../components/BusyIndicatorComponent.html) can be used to display a loading spinner and a predefined text. A good solution is to use it together with a [`BusyService`](../../injectables/BusyService.html) that indicates if something has started / ended loading. +## Busy indicator +The [BusyIndicatorComponent](../../components/BusyIndicatorComponent.html) can be used to display a loading spinner and a predefined text. For example, you can use it together with a [`BusyService`](../../injectables/BusyService.html) that indicates if something has started/ended loading. -## 3. Charts -In our web, charts are rendered using the `ElementalUiChartComponent`. There are some configurations defined by related classes. -- [`LineChartOptions`](../../classes/LineChartOptions.html) that defines a line chart definition. -- [`SeriesInformation`](../../classes/SeriesInformation.html), that defines one series in a line chart. -- [`XAxisInformation`](../../classes/XAxisInformation.html) and [`YAxisInformation`](classes/YAxisInformation.html) that defines the information for the line axis. +## Charts +In the web applications, charts are rendered using the `ElementalUiChartComponent`. Some configurations are defined by related classes: +- [`LineChartOptions`](../../classes/LineChartOptions.html) defines a line chart definition. +- [`SeriesInformation`](../../classes/SeriesInformation.html) defines one series in a line chart. +- [`XAxisInformation`](../../classes/XAxisInformation.html) and [`YAxisInformation`](classes/YAxisInformation.html) define the information for the line axis. -There is also a [`ChartTileComponent`](../../components/ChartTileComponent.html) that can be used to render a chart as part of a tile. +Additionally, the [`ChartTileComponent`](../../components/ChartTileComponent.html) can be used to render a chart as part of a tile. -## 4. Custom Theme +## Custom theme The [`CustomThemeService`](../../injectables/CustomThemeService.html) can be used to load all defined themes. It is also used to add the themes to the `` part of the page. -## 5. Dynamic Tabs +## Dynamic tabs Some tabs in side sheets have to be added dynamically because they are part of a dynamic module. The item is defined by a new [`TabItem`](../../interfaces/TabItem.html) and can be added to a tab control using a [`DynamicTabDataProviderDirective`](../../directives/DynamicTabDataProviderDirective.html). -## 6. Extensions -Sometimes it is necessary to add a component, that is not defined as part of a static module, but is part of a dynamic one. To display this component, a [`ExtComponent`](../../components/ExtComponent.html) can be used. It is part of the [`ExtModule`](../../modules/ExtModule.html), together with the needed service and a directive. +## Extensions +Sometimes it is necessary to add a component, that is not defined as part of a static module, but as part of a dynamic module. To display this component, a [`ExtComponent`](../../components/ExtComponent.html) can be used. It is part of the [`ExtModule`](../../modules/ExtModule.html), together with the needed service and a directive. -## 7. File Selector -If the user should be able to upload files, there is a [FileSelectorService](../../injectables/FileSelectorService.html) for that. +## File selector +If the user should be able to upload files, the [FileSelectorService](../../injectables/FileSelectorService.html) can be used. -## 8. Hyper View -A hyper view is a linked graph that visualizes the relationships of an object to other objects. The [`HyperviewComponent`](../../components/HyperviewComponent.html) and its parts are all part of the [`HyperviewModule`](../../modules/HyperViewModule.html). +## Hyperview +A hyperview is a graph that visualizes the relationships of an object to other objects and links them. The [`HyperviewComponent`](../../components/HyperviewComponent.html) and its parts are part of the [`HyperviewModule`](../../modules/HyperViewModule.html). -## 9. Masthead -In the masthead, information like the company logo, a help icon or the user menu can be displayed. It is defined inside the [`MastHeadComponent`](../../components/MastHeadComponent.html), that is part of the ['MastHeadModule'](../../modules/MastHeadModule.html). +## Masthead +In the header (i.e. the `masthead`), information like the company logo, a help icon or the user menu can be displayed. It is defined inside the [`MastHeadComponent`](../../components/MastHeadComponent.html), that is part of the ['MastHeadModule'](../../modules/MastHeadModule.html). -The [`MastHeadComponent`](../../components/MastHeadComponent.html) is also responsible for the menu line underneath it. The menu is rendered using an `ElementalUiTopNavigationComponent`. The menu items can be defined by using the [`MenuService`](../../injectables/MenuService.html). +The [`MastHeadComponent`](../../components/MastHeadComponent.html) is also responsible for the menu bar. The menu bar is rendered using an `ElementalUiTopNavigationComponent`. The menu items can be defined by using the [`MenuService`](../../injectables/MenuService.html). -## 10. Object History -The [`ObjectHistoryComponent`](../../components/ObjectHistoryComponent.html) can be used to show the course of an object. It can be display as a table or by using a [`TimelineComponent`](../../components/TimelineComponent.html). +## Object history +The [`ObjectHistoryComponent`](../../components/ObjectHistoryComponent.html) can be used to show the history of an object. It can be displayed as a table or by using a [`TimelineComponent`](../../components/TimelineComponent.html). -## 11. Side Navigation -The [`SideNavigationViewComponent`](../../components/SideNavigationViewComponent.html) is used to display a vertical menu that can be part of a page or an other component. It is collapsible for smaller screens. +## Side navigation +The [`SideNavigationViewComponent`](../../components/SideNavigationViewComponent.html) is used to display a vertical menu that can be part of a page or another component. It can collapse for smaller screens. -Another representation of a side navigation is the [`SidenavTreeComponent`](../../components/SidenavTreeComponent.html) which uses a tree view inside a collapsible panel. +Another way of displaying a side navigation is the [`SidenavTreeComponent`](../../components/SidenavTreeComponent.html) which uses a tree view inside a collapsible panel. The [`SideNavigationViewComponent`](../../components/SideNavigationViewComponent.html) is part of the [`SideNavigationViewModule`](../../modules/SideNavigationViewModule.html) while the [`SidenavTreeComponent`](../../components/SidenavTreeComponent.html) is part of the [`SidenavTreeModule`](../../modules/SidenavTreeModule.html). -## 12. SQL Wizard -The [`SqlWizardComponent`](../../components/SqlWizardComponent.html) can be used to filter the result of a larger amount of entries. It generates a filter expression that can be used as part of a normal API call. The SQL wizard is defined in the [`SqlWizardModule`](../../modules/SqlWizardModule.html) together with the sub components, that are used to build the filter. +## SQL Wizard +The [`SqlWizardComponent`](../../components/SqlWizardComponent.html) can be used to filter the result of a larger amount of entries. It creates a filter expression that can be used as part of a normal API call. The SQL Wizard is defined in the [`SqlWizardModule`](../../modules/SqlWizardModule.html) together with the sub components, that are used to build the filter. To use a [`SqlWizardComponent`](../../components/SqlWizardComponent.html) as part of the table filter in a custom project, the abstract class [`SqlWizardApiService`](../../classes/SqlWizardApiService.html) has to be extended and added as a provider. \ No newline at end of file diff --git a/imxweb/projects/qbm/additionalDocumentation/overview.md b/imxweb/projects/qbm/additionalDocumentation/overview.md index 9560d0e45..0d330ef13 100644 --- a/imxweb/projects/qbm/additionalDocumentation/overview.md +++ b/imxweb/projects/qbm/additionalDocumentation/overview.md @@ -1,7 +1,7 @@ -# Library Overview +# Library overview - [Administration](library-overview/administration.html) -- [Properties of an Object](library-overview/property-handling.html) -- [Data Sets](library-overview/data-sets.html) -- [Messages and Translation](library-overview/messages.html) -- [Other Reusable Components and Services](library-overview/other-reusable-components.html) +- [Properties of an object](library-overview/property-handling.html) +- [Data sets](library-overview/data-sets.html) +- [Messages and translation](library-overview/messages.html) +- [Other reusable components and services](library-overview/other-reusable-components.html) diff --git a/imxweb/projects/qbm/additionalDocumentation/properties.md b/imxweb/projects/qbm/additionalDocumentation/properties.md index 76db2d7a5..034ebbb82 100644 --- a/imxweb/projects/qbm/additionalDocumentation/properties.md +++ b/imxweb/projects/qbm/additionalDocumentation/properties.md @@ -1,18 +1,17 @@ -# Properties of an Object +# Properties of an object -In this section you will find useful components that can be used to edit properties of an entity (`IEntity`). +In this section you can find information about components that can be used to edit properties of an entity (`IEntity`). -The main way of doing this by using **C**olumn **D**ependent **R**eferences. They are all listed in the `cdr` folder of this project. +To edit properties of entities you can use: +- **C**olumn-**D**ependent **R**eferences (CDR) \ +CDRs are listed in the `cdr` folder of this project. \ +Typically, CDRs are represented in templates with the `` tag. For more information about this component, see [CdrEditorComponent](../../components/CdrEditorComponent.html). +- the [`EntityColumnEditorComponent`](../../components/EntityColumnEditorComponent.html) that wraps the editor -Normally column dependent references are represented in templates with the `` tag. \ -More information about this component can be found [here](../../components/CdrEditorComponent.html). +The correct definition of an editor is determined by the information provided by the CDR. \ +For this, it is necessary to register the components. The predefined components are registered in the [`DefaultCdrEditorProvider`](../../classes/DefaultCdrEditorProvider.html) and the [`FkCdrEditorProvider`](../../classes/FkCdrEditorProvider.html). -Another way is to use the [`EntityColumnEditorComponent`](../../components/EntityColumnEditorComponent.html) that wraps the editor. - -The correct definition of an editor is determined by the information provided by the column dependent reference. \ -For this it is necessary to register the components. Our predefined components are registered in the [`DefaultCdrEditorProvider`](../../classes/DefaultCdrEditorProvider.html) and the [`FkCdrEditorProvider`](../../classes/FkCdrEditorProvider.html). - -The following property types have predefined editors, that can be displayed as read only as well: +The following property types have predefined editors, that can also be displayed as read-only: * [boolean](../../components/EditBooleanComponent.html) * [date](../../components/EditDateComponent.html) * [date range](../../components/DateRangeComponent.html) diff --git a/imxweb/projects/qbm/additionalDocumentation/summary.json b/imxweb/projects/qbm/additionalDocumentation/summary.json index d357d2e81..efdeedaf1 100644 --- a/imxweb/projects/qbm/additionalDocumentation/summary.json +++ b/imxweb/projects/qbm/additionalDocumentation/summary.json @@ -1,6 +1,6 @@ [ { - "title": "Library Overview", + "title": "Library overview", "file": "overview.md", "children": [ { @@ -8,19 +8,19 @@ "file": "admin.md" }, { - "title": "Property Handling", + "title": "Properties of an object", "file": "properties.md" }, { - "title": "Data Sets", + "title": "Data sets", "file": "datasets.md" }, { - "title": "Messages", + "title": "UI texts and translation", "file": "messages.md" }, { - "title": "Other reusable components", + "title": "Other reusable components and services", "file": "other.md" } ] @@ -38,7 +38,7 @@ "file": "../../../compodoc/samples/tiles.md" }, { - "title": "Adding a menu to the Portal", + "title": "Adding a menu to the Web Portal", "file": "../../../compodoc/samples/menu.md" }, { diff --git a/imxweb/projects/qbm/karma.conf.js b/imxweb/projects/qbm/karma.conf.js index a0a6c62fd..efaf207a9 100644 --- a/imxweb/projects/qbm/karma.conf.js +++ b/imxweb/projects/qbm/karma.conf.js @@ -13,10 +13,10 @@ module.exports = function (config) { require('karma-coverage-istanbul-reporter'), require('@angular-devkit/build-angular/plugins/karma'), require('karma-junit-reporter'), - require('karma-viewport') + require('karma-viewport'), ], client: { - clearContext: false // leave Jasmine Spec Runner output visible in browser + clearContext: false, // leave Jasmine Spec Runner output visible in browser }, coverageIstanbulReporter: { dir: require('path').join(__dirname, 'results'), @@ -24,7 +24,7 @@ module.exports = function (config) { fixWebpackSourcePaths: true, 'report-config': { html: { - subdir: 'coverage-html' + subdir: 'coverage-html', }, }, thresholds: { @@ -42,41 +42,40 @@ module.exports = function (config) { port: 9876, captureTimeout: 210000, browserDisconnectTolerance: 3, - browserDisconnectTimeout : 210000, - browserNoActivityTimeout : 210000, + browserDisconnectTimeout: 210000, + browserNoActivityTimeout: 210000, colors: true, logLevel: config.LOG_INFO, autoWatch: true, browsers: ['Chrome'], singleRun: false, - files: [ - '../../node_modules/hammerjs/hammer.min.js' - ], + failOnEmptyTestSuite: false, + files: ['../../node_modules/hammerjs/hammer.min.js'], // Viewport configuration viewport: { breakpoints: [ { - name: "mobile", + name: 'mobile', size: { width: 760, - height: 1000 - } + height: 1000, + }, }, { - name: "tablet", + name: 'tablet', size: { width: 1024, - height: 1000 - } + height: 1000, + }, }, { - name: "small-desktop", + name: 'small-desktop', size: { width: 1200, - height: 1000 - } - } - ] - } + height: 1000, + }, + }, + ], + }, }); }; diff --git a/imxweb/projects/qbm/ng-package.json b/imxweb/projects/qbm/ng-package.json index 939729306..e7a7a8764 100644 --- a/imxweb/projects/qbm/ng-package.json +++ b/imxweb/projects/qbm/ng-package.json @@ -3,7 +3,7 @@ "dest": "../../dist/qbm", "lib": { "entryFile": "src/public_api.ts", - "styleIncludePaths": ["../../shared/assets"] + "styleIncludePaths": ["../../shared/scss"] }, "deleteDestPath": false } diff --git a/imxweb/projects/qbm/package.json b/imxweb/projects/qbm/package.json index b7dcf1abb..de818547a 100644 --- a/imxweb/projects/qbm/package.json +++ b/imxweb/projects/qbm/package.json @@ -1,13 +1,9 @@ { "name": "qbm", - "version": "9.2.1", + "version": "9.3.0", "private": true, - "dependencies": { - - }, - "peerDependencies": { - - }, + "dependencies": {}, + "peerDependencies": {}, "bundledDependencies": [ "imx-api-qbm" ] diff --git a/imxweb/projects/qbm/project.json b/imxweb/projects/qbm/project.json new file mode 100644 index 000000000..8fb808af0 --- /dev/null +++ b/imxweb/projects/qbm/project.json @@ -0,0 +1,60 @@ +{ + "$schema": "../../node_modules/nx/schemas/project-schema.json", + "name": "qbm", + "sourceRoot": "projects/qbm/src", + "projectType": "library", + "prefix": "imx", + "generators": { + "@schematics/angular:component": { + "style": "scss" + } + }, + "targets": { + "build": { + "executor": "@angular-devkit/build-angular:ng-packagr", + "options": { + "tsConfig": "projects/qbm/tsconfig.lib.json", + "project": "projects/qbm/ng-package.json" + }, + "configurations": { + "production": { + "tsConfig": "projects/qbm/tsconfig.lib.prod.json" + }, + "development": { + "tsConfig": "projects/qbm/tsconfig.lib.json" + }, + "remote-dev": { + "tsConfig": "projects/qbm/tsconfig.lib.json" + }, + "remote-qs": { + "tsConfig": "projects/qbm/tsconfig.lib.json" + } + }, + "outputs": ["{workspaceRoot}/dist/qbm"] + }, + "test": { + "executor": "@angular-devkit/build-angular:karma", + "options": { + "stylePreprocessorOptions": { + "includePaths": [ + "./shared/assets", + "./shared/scss", + "./node_modules", + "./node_modules/@elemental-ui/cadence-icon", + "./node_modules/@elemental-ui/core" + ] + }, + "main": "projects/qbm/src/test.ts", + "tsConfig": "projects/qbm/tsconfig.spec.json", + "karmaConfig": "projects/qbm/karma.conf.js" + } + }, + "lint": { + "executor": "@angular-devkit/build-angular:eslint", + "options": { + "tsConfig": ["projects/qbm/tsconfig.lib.json", "projects/qbm/tsconfig.spec.json"], + "exclude": ["**/node_modules/**", "**/*.spec.ts", "**/*.json"] + } + } + } +} diff --git a/imxweb/projects/qbm/src/default-mocks.spec.ts b/imxweb/projects/qbm/src/default-mocks.spec.ts index 178ff600c..be007fd96 100644 --- a/imxweb/projects/qbm/src/default-mocks.spec.ts +++ b/imxweb/projects/qbm/src/default-mocks.spec.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -32,7 +32,7 @@ import { RouteGuardService } from './lib/route-guard/route-guard.service'; import { ISessionState } from './lib/session/session-state'; import { AuthenticationService } from './lib/authentication/authentication.service'; import { CacheService } from './lib/cache/cache.service'; -import { CachedPromise } from 'imx-qbm-dbts'; +import { CachedPromise } from '@imx-modules/imx-qbm-dbts'; export class QbmDefaultMocks { public static readonly afterClosedSubject = new Subject(); @@ -44,8 +44,8 @@ export class QbmDefaultMocks { public static readonly sidesheetRefStub = { close: jasmine.createSpy('close'), - closeClicked: jasmine.createSpy('closeClicked').and.returnValue(of(undefined)) -} + closeClicked: jasmine.createSpy('closeClicked').and.returnValue(of(undefined)), + }; public static readonly authServiceStub = { onSessionResponse: new Subject(), @@ -59,11 +59,11 @@ export class QbmDefaultMocks { ngMocks.defaultMock(TranslateService, () => ({ get: jasmine.createSpy('get').and.returnValue(of()), })); - ngMocks.defaultMock(EuiSidesheetRef,()=> QbmDefaultMocks.sidesheetRefStub); + ngMocks.defaultMock(EuiSidesheetRef, () => QbmDefaultMocks.sidesheetRefStub); ngMocks.defaultMock(CacheService, () => ({ buildCache: (func) => { return new CachedPromise(func); - } + }, })); } } diff --git a/imxweb/projects/qbm/src/lib/about/About.component.html b/imxweb/projects/qbm/src/lib/about/About.component.html index 9ed2ab9ae..1118a2f13 100644 --- a/imxweb/projects/qbm/src/lib/about/About.component.html +++ b/imxweb/projects/qbm/src/lib/about/About.component.html @@ -1,5 +1,5 @@ - + @@ -24,20 +24,24 @@ {{ '#LDS#Third-Party Contributions' | translate }}
    {{ '#LDS#Source code for components marked with an asterisk (*) is available at' | translate }} - {{product['OpenSourceUrl']}} + {{ product['OpenSourceUrl'] }} .
    - +
    @@ -63,11 +67,10 @@ {{ '#LDS#System information' | translate }} - - + - - + + diff --git a/imxweb/projects/qbm/src/lib/about/About.component.scss b/imxweb/projects/qbm/src/lib/about/About.component.scss index b0e8ad0a0..3413d106a 100644 --- a/imxweb/projects/qbm/src/lib/about/About.component.scss +++ b/imxweb/projects/qbm/src/lib/about/About.component.scss @@ -1,5 +1,5 @@ -@import "variables.scss"; @import '@elemental-ui/core/src/styles/_eui_palette.scss'; +@import 'base/variables'; ::ng-deep { .imx-AboutPanel { @@ -42,7 +42,7 @@ .imx-productNameVersion { padding: 15px 0; margin: 30px 20px; - border: solid $VI_Common_Color_Gray; + border: solid $color-gray-60; border-width: 1px 0; text-align: center; } @@ -61,88 +61,68 @@ /* avoid scrollbars caused by the rotating image going out of the box */ overflow: hidden; } +} - ::ng-deep .mat-tab-label { - background-color: $white; - } - - .paragraphLargeMargin { - margin-bottom: 40px; - } - - .mat-dialog-content { - max-height: initial; - } - - .imx-legalNotice-Header { - margin-top: 10px; - margin-bottom: 6px; - font-family: $baseFontFamily; - } +.paragraphLargeMargin { + margin-bottom: 40px; +} - .imx-legalNotice { - height: 100%; - display: flex; - overflow: hidden; - flex-direction: column; - } +.mat-mdc-dialog-content { + max-height: initial; +} - .imx-legalNotice-Header > span { - font-size: 1em; - font-weight: bolder; - } +.imx-legalNotice-Header { + margin-top: 10px; + margin-bottom: 6px; + font-family: $IMX_Base_FontFamily; +} - .imx-legalNotice-Content > span { - font-size: 1em; - font-family: $baseFontFamily; - margin-right: 4px; - } +.imx-legalNotice { + height: 100%; + display: flex; + overflow: hidden; + flex-direction: column; +} - .imx-contact > div > div { - padding-top: 5px; - } +.imx-legalNotice-Header > span { + font-size: 1em; + font-weight: bolder; +} - .imx-contact-Header { - margin-top: 10px; - padding-top: 15px; - padding-bottom: 20px; - font-family: $baseFontFamily; - } +.imx-legalNotice-Content > span { + font-size: 1em; + font-family: $IMX_Base_FontFamily; + margin-right: 4px; +} - .imx-contact-Header > span { - font-size: 1.6em; - } +.imx-contact > div > div { + padding-top: 5px; +} - button { - margin-bottom: 20px; - margin-right: 10px; - } +.imx-contact-Header { + margin-top: 10px; + padding-top: 15px; + padding-bottom: 20px; + font-family: $IMX_Base_FontFamily; +} - .mat-card { - box-shadow: none; - } +.imx-contact-Header > span { + font-size: 1.6em; +} - imx-data-source-toolbar { - display: none; - } +button { + margin-bottom: 20px; + margin-right: 10px; +} - .imx-about-tabs { - height: 100%; - } +.mat-mdc-card { + box-shadow: none; } -.eui-dark-theme { - :host { - ::ng-deep .mat-tab-label { - background-color: $color-gray-80; - } - } +imx-data-source-toolbar { + display: none; } -.eui-contrast-theme { - :host { - ::ng-deep .mat-tab-label { - background-color: $color-gray-100; - } - } +.imx-about-tabs { + height: 100%; } diff --git a/imxweb/projects/qbm/src/lib/about/About.component.ts b/imxweb/projects/qbm/src/lib/about/About.component.ts index b4e706234..f98239533 100644 --- a/imxweb/projects/qbm/src/lib/about/About.component.ts +++ b/imxweb/projects/qbm/src/lib/about/About.component.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -25,23 +25,21 @@ */ import { Component, HostBinding, OnInit } from '@angular/core'; -import { OverlayRef } from '@angular/cdk/overlay'; import { EuiLoadingService } from '@elemental-ui/core'; -import { AboutService } from './About.service'; -import { ExtService } from '../ext/ext.service'; -import { Globals, CollectionLoadParameters, EntitySchema, IClientProperty } from 'imx-qbm-dbts'; +import { CollectionLoadParameters, EntitySchema, Globals, IClientProperty } from '@imx-modules/imx-qbm-dbts'; import { DataSourceToolbarSettings } from '../data-source-toolbar/data-source-toolbar-settings'; +import { ExtService } from '../ext/ext.service'; import { SettingsService } from '../settings/settings-service'; import { SystemInfoService } from '../system-info/system-info.service'; +import { AboutService } from './About.service'; @Component({ templateUrl: './About.component.html', styleUrls: ['./About.component.scss'], - selector: 'imx-about' + selector: 'imx-about', }) export class AboutComponent implements OnInit { - @HostBinding('class') public defaultHostClasses = 'imx-flex imx-flex-child'; @@ -58,14 +56,14 @@ export class AboutComponent implements OnInit { private readonly systemInfoService: SystemInfoService, private extService: ExtService, private readonly settings: SettingsService, - private readonly busyService: EuiLoadingService + private readonly busyService: EuiLoadingService, ) { this.entitySchema = aboutInfoService.EntitySchema; this.displayedColumns = [ this.entitySchema.Columns['ComponentName'], this.entitySchema.Columns['CopyRight'], this.entitySchema.Columns['EmailOrURl'], - this.entitySchema.Columns['LicenceName'] + this.entitySchema.Columns['LicenceName'], ]; this.product['Name'] = Globals.QIM_ProductNameFull; this.product['Version'] = Globals.Version; @@ -81,8 +79,7 @@ export class AboutComponent implements OnInit { public async ngOnInit(): Promise { const imxConfig = await this.systemInfoService.getImxConfig(); const name = imxConfig.ProductName; - if (name) - this.product['Name'] = name; + if (name) this.product['Name'] = name; await this.update({ PageSize: this.settings.DefaultPageSize, StartIndex: 0, OrderBy: 'ComponentName' }); } @@ -96,18 +93,21 @@ export class AboutComponent implements OnInit { this.parameters = parameters; } - let overlayRef: OverlayRef; - setTimeout(() => overlayRef = this.busyService.show()); + if (this.busyService.overlayRefs.length === 0) { + this.busyService.show(); + } try { const data = await this.aboutInfoService.get(this.parameters); - this.dstSettings = { - dataSource: data, - entitySchema: this.entitySchema, - navigationState: this.parameters, - displayedColumns: this.displayedColumns - }; + if (data) { + this.dstSettings = { + dataSource: data, + entitySchema: this.entitySchema, + navigationState: this.parameters, + displayedColumns: this.displayedColumns, + }; + } } finally { - setTimeout(() => this.busyService.hide(overlayRef)); + this.busyService.hide(); } } } diff --git a/imxweb/projects/qbm/src/lib/about/About.service.ts b/imxweb/projects/qbm/src/lib/about/About.service.ts index e0ad80ec1..3df0feaa0 100644 --- a/imxweb/projects/qbm/src/lib/about/About.service.ts +++ b/imxweb/projects/qbm/src/lib/about/About.service.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -24,24 +24,46 @@ * */ -import { Injectable } from '@angular/core'; +import { Injectable, OnDestroy } from '@angular/core'; -import { ImxSysteminfoThirdparty } from 'imx-api-qbm'; -import { imx_SessionService } from '../session/imx-session.service'; -import { TypedEntityCollectionData, CollectionLoadParameters, EntitySchema } from 'imx-qbm-dbts'; +import { AdminSysteminfoThirdparty } from '@imx-modules/imx-api-qbm'; +import { CollectionLoadParameters, EntitySchema, ExtendedTypedEntityCollection, TypedEntity } from '@imx-modules/imx-qbm-dbts'; -@Injectable({ - providedIn: 'root' -}) -export class AboutService { - constructor(private readonly session: imx_SessionService) { } +// Create a more general type from either admin or ops since it is available in qbm - use this in qer later +export type SysteminfoThirdparty = { [K in keyof AdminSysteminfoThirdparty]: AdminSysteminfoThirdparty[K] } & TypedEntity; - public get EntitySchema(): EntitySchema { - return this.session.TypedClient.ImxSysteminfoThirdparty.GetSchema(); +/** + * Abstract implementation for getting portal specific metadata. + */ +@Injectable() +export abstract class AboutService implements OnDestroy { + protected abortController: AbortController; + constructor() { + this.abortController = new AbortController(); + } + + ngOnDestroy(): void { + this.abortCall(); } - - public async get(parameters: CollectionLoadParameters = {}): - Promise> { - return this.session.TypedClient.ImxSysteminfoThirdparty.Get(parameters); + + /** + * Handles aborting any current requests managed by this service. + */ + public abortCall(): void { + this.abortController.abort(); + this.abortController = new AbortController(); } + + /** + * Abstract getter for exposing the entity schema via the service. + */ + abstract get EntitySchema(): EntitySchema; + + /** + * Abstract method for getting data from the server + * @param parameters Additional request parameters for the method + */ + abstract get( + parameters?: CollectionLoadParameters, + ): Promise | null | undefined>; } diff --git a/imxweb/projects/qbm/src/lib/admin/about/admin-about.service.ts b/imxweb/projects/qbm/src/lib/admin/about/admin-about.service.ts new file mode 100644 index 000000000..048d81f0c --- /dev/null +++ b/imxweb/projects/qbm/src/lib/admin/about/admin-about.service.ts @@ -0,0 +1,56 @@ +/* + * ONE IDENTITY LLC. PROPRIETARY INFORMATION + * + * This software is confidential. One Identity, LLC. or one of its affiliates or + * subsidiaries, has supplied this software to you under terms of a + * license agreement, nondisclosure agreement or both. + * + * You may not copy, disclose, or use this software except in accordance with + * those terms. + * + * + * Copyright 2024 One Identity LLC. + * ALL RIGHTS RESERVED. + * + * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR + * WARRANTIES ABOUT THE SUITABILITY OF THE SOFTWARE, + * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED + * TO THE IMPLIED WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE, OR + * NON-INFRINGEMENT. ONE IDENTITY LLC. SHALL NOT BE + * LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE + * AS A RESULT OF USING, MODIFYING OR DISTRIBUTING + * THIS SOFTWARE OR ITS DERIVATIVES. + * + */ + +import { Injectable } from '@angular/core'; +import { AdminSysteminfoThirdparty } from '@imx-modules/imx-api-qbm'; +import { CollectionLoadParameters, EntitySchema, TypedEntityCollectionData } from '@imx-modules/imx-qbm-dbts'; +import { AboutService } from '../../about/About.service'; +import { ApiClientService } from '../../api-client/api-client.service'; +import { imx_SessionService } from '../../session/imx-session.service'; + +@Injectable({ + providedIn: 'root', +}) +export class AdminAboutService extends AboutService { + constructor( + private session: imx_SessionService, + private readonly apiProvider: ApiClientService, + ) { + super(); + } + + get EntitySchema(): EntitySchema { + return this.session.TypedClient.AdminSysteminfoThirdparty.GetSchema(); + } + + async get(parameters?: CollectionLoadParameters): Promise | undefined> { + return this.apiProvider.request(() => + this.session.TypedClient.AdminSysteminfoThirdparty.Get(parameters, { + signal: this.abortController.signal, + }), + ); + } +} diff --git a/imxweb/projects/qbm/src/lib/admin/add-config-sidesheet.component.html b/imxweb/projects/qbm/src/lib/admin/add-config-sidesheet.component.html index c98144ecd..1d34af9e0 100644 --- a/imxweb/projects/qbm/src/lib/admin/add-config-sidesheet.component.html +++ b/imxweb/projects/qbm/src/lib/admin/add-config-sidesheet.component.html @@ -1,8 +1,7 @@
    - - - {{'#LDS#Select where to add the configuration key' | translate}} + + {{ '#LDS#Select where to add the configuration key' | translate }} @@ -12,18 +11,25 @@ - {{selectedKey.Description}} + {{ selectedKey.Description }} - - {{'#LDS#Name of the new configuration key' | translate}} - + + {{ '#LDS#Name of the new configuration key' | translate }} +
    -
    - +
    +
    diff --git a/imxweb/projects/qbm/src/lib/admin/add-config-sidesheet.component.scss b/imxweb/projects/qbm/src/lib/admin/add-config-sidesheet.component.scss index 1db9ee0e1..a9388aef4 100644 --- a/imxweb/projects/qbm/src/lib/admin/add-config-sidesheet.component.scss +++ b/imxweb/projects/qbm/src/lib/admin/add-config-sidesheet.component.scss @@ -1,13 +1,4 @@ -eui-alert { - margin-bottom: 1em; - display: block; -} - .description { padding-left: 2em; margin-bottom: 1em; } - -mat-form-field { - width: 100%; -} diff --git a/imxweb/projects/qbm/src/lib/admin/add-config-sidesheet.component.ts b/imxweb/projects/qbm/src/lib/admin/add-config-sidesheet.component.ts index 73555f076..26338ae8d 100644 --- a/imxweb/projects/qbm/src/lib/admin/add-config-sidesheet.component.ts +++ b/imxweb/projects/qbm/src/lib/admin/add-config-sidesheet.component.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -24,30 +24,30 @@ * */ -import { Component, OnInit } from "@angular/core"; -import { EuiLoadingService, EuiSidesheetRef } from "@elemental-ui/core"; -import { SnackBarService } from "../snackbar/snack-bar.service"; -import { KeyData } from "./config-section"; -import { ConfigService } from "./config.service"; +import { Component, OnInit } from '@angular/core'; +import { EuiLoadingService, EuiSidesheetRef } from '@elemental-ui/core'; +import { SnackBarService } from '../snackbar/snack-bar.service'; +import { KeyData } from './config-section'; +import { ConfigService } from './config.service'; @Component({ templateUrl: './add-config-sidesheet.component.html', - styleUrls: ['./add-config-sidesheet.component.scss'] + styleUrls: ['./add-config-sidesheet.component.scss'], }) export class AddConfigSidesheetComponent implements OnInit { - - constructor(private readonly configSvc: ConfigService, + constructor( + private readonly configSvc: ConfigService, private readonly sideSheetRef: EuiSidesheetRef, private readonly busySvc: EuiLoadingService, - private readonly snackbar: SnackBarService - ) { } + private readonly snackbar: SnackBarService, + ) {} keyData: KeyData[]; selectedKey: KeyData; newKey: string; ngOnInit(): void { - this.keyData = this.configSvc.sections.map(s => s.SettingsSupportingAdd).reduce((a, b) => a.concat(b), []); + this.keyData = this.configSvc.sections.map((s) => s.SettingsSupportingAdd).reduce((a, b) => a.concat(b), []); } public isGlobal: boolean = false; @@ -55,13 +55,13 @@ export class AddConfigSidesheetComponent implements OnInit { public async submit(): Promise { const overlay = this.busySvc.show(); try { - await this.configSvc.addKey(this.selectedKey.Path + "/" + this.newKey); + await this.configSvc.addKey(this.selectedKey.Path + '/' + this.newKey); await this.configSvc.load(); - const key = "#LDS#The configuration key has been successfully created."; - this.snackbar.open({key}); + const key = '#LDS#The configuration key has been successfully created.'; + this.snackbar.open({ key }); } finally { this.busySvc.hide(overlay); } this.sideSheetRef.close(); } -} \ No newline at end of file +} diff --git a/imxweb/projects/qbm/src/lib/admin/admin-component.interface.ts b/imxweb/projects/qbm/src/lib/admin/admin-component.interface.ts index 0e232bf62..aa41ac3ce 100644 --- a/imxweb/projects/qbm/src/lib/admin/admin-component.interface.ts +++ b/imxweb/projects/qbm/src/lib/admin/admin-component.interface.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -24,8 +24,6 @@ * */ - - export interface AdminComponent { isAdmin?: boolean; -} \ No newline at end of file +} diff --git a/imxweb/projects/qbm/src/lib/admin/admin-routes.ts b/imxweb/projects/qbm/src/lib/admin/admin-routes.ts index 5d31cf185..6742feb6b 100644 --- a/imxweb/projects/qbm/src/lib/admin/admin-routes.ts +++ b/imxweb/projects/qbm/src/lib/admin/admin-routes.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -26,19 +26,19 @@ import { Routes } from '@angular/router'; import { RouteGuardService } from '../route-guard/route-guard.service'; -import { DashboardComponent } from "./dashboard.component"; +import { DashboardComponent } from './dashboard.component'; export const AdminRoutes: Routes = [ - { - path: 'admin', - component: DashboardComponent, - canActivate: [RouteGuardService], - resolve: [RouteGuardService] - }, - { - path: 'admin/:tab', - component: DashboardComponent, - canActivate: [RouteGuardService], - resolve: [RouteGuardService] - }, + { + path: 'admin', + component: DashboardComponent, + canActivate: [RouteGuardService], + resolve: [RouteGuardService], + }, + { + path: 'admin/:tab', + component: DashboardComponent, + canActivate: [RouteGuardService], + resolve: [RouteGuardService], + }, ]; diff --git a/imxweb/projects/qbm/src/lib/admin/admin.module.ts b/imxweb/projects/qbm/src/lib/admin/admin.module.ts index cc1bcb6e2..4c5dded04 100644 --- a/imxweb/projects/qbm/src/lib/admin/admin.module.ts +++ b/imxweb/projects/qbm/src/lib/admin/admin.module.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -42,11 +42,19 @@ import { MatTooltipModule } from '@angular/material/tooltip'; import { MatTreeModule } from '@angular/material/tree'; import { EuiCoreModule, EuiMaterialModule } from '@elemental-ui/core'; import { TranslateModule } from '@ngx-translate/core'; +import { AboutService } from '../about/About.service'; +import { QbmSqlWizardService } from '../base/qbm-sqlwizard.service'; +import { BusyIndicatorModule } from '../busy-indicator/busy-indicator.module'; import { DataSourceToolbarModule } from '../data-source-toolbar/data-source-toolbar.module'; import { DateModule } from '../date/date.module'; import { LdsReplaceModule } from '../lds-replace/lds-replace.module'; +import { SideNavigationViewModule } from '../side-navigation-view/side-navigation-view.module'; +import { SqlWizardApiService } from '../sqlwizard/sqlwizard-api.service'; +import { InfoModalDialogModule } from './../info-modal-dialog/info-modal-dialog.module'; +import { AdminAboutService } from './about/admin-about.service'; import { AddConfigSidesheetComponent } from './add-config-sidesheet.component'; import { ApplyConfigSidesheetComponent } from './apply-config-sidesheet.component'; +import { CacheComponent } from './cache.component'; import { ConfigKeyPathComponent } from './config-key-path.component'; import { ConfigComponent } from './config.component'; import { ConfigService } from './config.service'; @@ -57,17 +65,11 @@ import { ListSettingComponent } from './list-setting.component'; import { LogDetailsSidesheetComponent } from './log-details-sidesheet.component'; import { LogsComponent } from './logs.component'; import { PackagesComponent } from './packages.component'; +import { PluginsComponent } from './plugins.component'; import { SelectValueComponent } from './select-value.component'; import { StatusComponent } from './status.component'; import { StatusService } from './status.service'; import { SwaggerComponent } from './swagger/swagger.component'; -import { CacheComponent } from './cache.component'; -import { PluginsComponent } from './plugins.component'; -import { InfoModalDialogModule } from './../info-modal-dialog/info-modal-dialog.module'; -import { SqlWizardApiService } from '../sqlwizard/sqlwizard-api.service'; -import { QbmSqlWizardService } from '../base/qbm-sqlwizard.service'; -import { SideNavigationViewModule } from '../side-navigation-view/side-navigation-view.module'; - @NgModule({ imports: [ CommonModule, @@ -93,6 +95,7 @@ import { SideNavigationViewModule } from '../side-navigation-view/side-navigatio ScrollingModule, InfoModalDialogModule, SideNavigationViewModule, + BusyIndicatorModule, ], providers: [ ConfigService, @@ -101,6 +104,10 @@ import { SideNavigationViewModule } from '../side-navigation-view/side-navigatio provide: SqlWizardApiService, useClass: QbmSqlWizardService, }, + { + provide: AboutService, + useClass: AdminAboutService, + }, ], declarations: [ AddConfigSidesheetComponent, diff --git a/imxweb/projects/qbm/src/lib/admin/apply-config-sidesheet.component.html b/imxweb/projects/qbm/src/lib/admin/apply-config-sidesheet.component.html index 58d278da1..877144404 100644 --- a/imxweb/projects/qbm/src/lib/admin/apply-config-sidesheet.component.html +++ b/imxweb/projects/qbm/src/lib/admin/apply-config-sidesheet.component.html @@ -1,9 +1,10 @@
    - - +
    - {{'#LDS#You have changed the following configuration settings.' | translate}} - {{'#LDS#Select how the configuration changes should be applied.' | translate}} + {{ '#LDS#You have changed the following configuration settings.' | translate }} + {{ '#LDS#Select how the configuration changes should be applied.' | translate }}
      @@ -14,18 +15,19 @@ - {{ '#LDS#Apply locally' | translate}} + {{ '#LDS#Apply locally' | translate }} -

      {{ (supportsLocalCustomizations ? LdsApplyLocally : LdsApplyLocallyNotPossible) | translate}}

      +

      {{ (supportsLocalCustomizations ? LdsApplyLocally : LdsApplyLocallyNotPossible) | translate }}

      - {{'#LDS#Apply globally' | translate}} + {{ '#LDS#Apply globally' | translate }} -

      {{LdsApplyGlobally | translate}}

      +

      {{ LdsApplyGlobally | translate }}

      - +
    - - - +
    + +
    diff --git a/imxweb/projects/qbm/src/lib/admin/apply-config-sidesheet.component.scss b/imxweb/projects/qbm/src/lib/admin/apply-config-sidesheet.component.scss index a152cc270..eeec17c20 100644 --- a/imxweb/projects/qbm/src/lib/admin/apply-config-sidesheet.component.scss +++ b/imxweb/projects/qbm/src/lib/admin/apply-config-sidesheet.component.scss @@ -1,35 +1,13 @@ -@import "@elemental-ui/core/src/styles/_palette.scss"; -@import '@elemental-ui/core/src/styles/_eui_palette.scss'; - .admin-config-apply-sidesheet { - background-color: $asher-gray; - padding: 2em; height: 100%; display: flex; flex-direction: column; overflow: hidden; - - &__action-buttons { - display: flex; - justify-content: flex-end; - background-color: $white; - padding: 16px 32px; - margin: 16px 0; - - .justify-start { - margin-right: auto; - } - - button:not(:last-of-type):not(.justify-start) { - margin-right: 10px; - } + .mat-mdc-radio-group{ + display: block; } } -mat-radio-button { - font-weight: bolder; -} - ul { margin: 1em; max-height: 200px; @@ -44,30 +22,3 @@ li { padding-left: 2em; margin-bottom: 1em; } - - -.eui-dark-theme { - :host { - .admin-config-apply-sidesheet - { - background-color: $color-gray-80; - - &__action-buttons { - background-color: $color-gray-70; - } - } - } -} - -.eui-contrast-theme { - :host { - .admin-config-apply-sidesheet - { - background-color: $color-gray-100; - - &__action-buttons { - background-color: $color-gray-90; - } - } - } -} diff --git a/imxweb/projects/qbm/src/lib/admin/apply-config-sidesheet.component.ts b/imxweb/projects/qbm/src/lib/admin/apply-config-sidesheet.component.ts index 048e1f9f4..518b121a5 100644 --- a/imxweb/projects/qbm/src/lib/admin/apply-config-sidesheet.component.ts +++ b/imxweb/projects/qbm/src/lib/admin/apply-config-sidesheet.component.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -24,19 +24,19 @@ * */ -import { Component } from "@angular/core"; -import { EuiSidesheetRef } from "@elemental-ui/core"; -import { ConfigService } from "./config.service"; +import { Component } from '@angular/core'; +import { EuiSidesheetRef } from '@elemental-ui/core'; +import { ConfigService } from './config.service'; @Component({ templateUrl: './apply-config-sidesheet.component.html', - styleUrls: ['./apply-config-sidesheet.component.scss'] + styleUrls: ['./apply-config-sidesheet.component.scss'], }) export class ApplyConfigSidesheetComponent { - - constructor(private readonly configSvc: ConfigService, + constructor( + private readonly configSvc: ConfigService, private readonly sideSheetRef: EuiSidesheetRef, - ) { + ) { this.isGlobal = !configSvc.supportsLocalCustomization; } @@ -51,13 +51,15 @@ export class ApplyConfigSidesheetComponent { this.sideSheetRef.close(); } - public LdsApplyLocally = '#LDS#Use this setting if you want to try configuration changes only on this server. The changes are reset when you restart the server.'; + public LdsApplyLocally = + '#LDS#Use this setting if you want to try configuration changes only on this server. The changes are reset when you restart the server.'; - public LdsApplyGlobally = '#LDS#Use this setting if you want to apply the configuration changes globally. The changes are stored in the global configuration file and distributed to all API servers.'; + public LdsApplyGlobally = + '#LDS#Use this setting if you want to apply the configuration changes globally. The changes are stored in the global configuration file and distributed to all API servers.'; public LdsApplyLocallyNotPossible = '#LDS#This option has been disabled by your administrator.'; - public get pendingChanges(): string[][] { + public get pendingChanges(): (string | undefined)[][] { return this.configSvc.getPendingChanges(); } -} \ No newline at end of file +} diff --git a/imxweb/projects/qbm/src/lib/admin/cache.component.html b/imxweb/projects/qbm/src/lib/admin/cache.component.html index cd19fe5f6..bb8c8a92c 100644 --- a/imxweb/projects/qbm/src/lib/admin/cache.component.html +++ b/imxweb/projects/qbm/src/lib/admin/cache.component.html @@ -1,13 +1,13 @@ -
    -

    #LDS#Heading Caches

    +
    +

    #LDS#Heading Caches

    - + @@ -15,7 +15,7 @@

    #LDS#Heading Caches

    - + @@ -35,17 +35,17 @@

    #LDS#Heading Caches

    {{'#LDS#Name' | translate}}{{ '#LDS#Name' | translate }} {{ '#LDS#Cached items' | translate }} {{ '#LDS#Cache hits' | translate }}
    - {{d}} + {{ d }} {{ cacheData[d].ObjectCount }} @@ -27,7 +27,7 @@

    #LDS#Heading Caches

    {{'#LDS#Total' | translate}}{{ '#LDS#Total' | translate }} {{ totalEntries }} {{ totalHits }}
    -
    - - -
    diff --git a/imxweb/projects/qbm/src/lib/admin/cache.component.ts b/imxweb/projects/qbm/src/lib/admin/cache.component.ts index 4bcb6dd40..f1888d80f 100644 --- a/imxweb/projects/qbm/src/lib/admin/cache.component.ts +++ b/imxweb/projects/qbm/src/lib/admin/cache.component.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -24,56 +24,71 @@ * */ -import { Component, OnInit, Input } from "@angular/core"; -import { CacheData } from "imx-api-qbm"; -import { AppConfigService } from "../appConfig/appConfig.service"; -import { SideNavigationComponent } from "../side-navigation-view/side-navigation-view-interfaces"; +import { Component, Input, OnInit } from '@angular/core'; +import { CacheData } from '@imx-modules/imx-api-qbm'; +import { AppConfigService } from '../appConfig/appConfig.service'; +import { ConfirmationService } from '../confirmation/confirmation.service'; +import { MessageParameter } from '../message-dialog/message-parameter.interface'; +import { SideNavigationComponent } from '../side-navigation-view/side-navigation-view-interfaces'; type T = CacheData & { key: string }; @Component({ templateUrl: './cache.component.html', styleUrls: ['./shared.scss'], - selector: 'imx-cache' + selector: 'imx-cache', }) export class CacheComponent implements OnInit, SideNavigationComponent { @Input() public isAdmin: boolean; - constructor(private readonly appConfigService: AppConfigService) { } - + constructor( + private readonly appConfigService: AppConfigService, + private readonly confirmService: ConfirmationService, + ) {} public cacheData: { [key: string]: CacheData } = {}; public totalEntries = 0; public totalHits = 0; - public apiProjects: string[]; + public apiProjects: (string | undefined)[]; public cacheKeys: string[] = []; async ngOnInit() { this.busy = true; - this.apiProjects = (await this.appConfigService.v2client.admin_projects_get()) - .map(p => p.AppId); + this.apiProjects = (await this.appConfigService.v2client.admin_projects_get()).map((p) => p.AppId); await this.reload(); } async reload() { const client = this.appConfigService.client; - var data = this.apiProjects.map(appid => client.admin_cache_get(appid)); + var data = this.apiProjects.map((appid) => client.admin_cache_get(appid ?? '')); await this.apply(data); } async flushall(): Promise { - const data = this.apiProjects.map(appid => this.appConfigService.v2client.admin_cache_post(appid, { - flush: true, - disable: this.isCachingDeactivated() - })); + const data = this.apiProjects.map((appid) => + this.appConfigService.v2client.admin_cache_post(appid ?? '', { + flush: true, + disable: this.isCachingDeactivated(), + }), + ); await this.apply(data); } - async switchall(): Promise { const disable = !this.isCachingDeactivated(); - const data = this.apiProjects.map(appid => this.appConfigService.v2client.admin_cache_post(appid, { disable: disable })); - await this.apply(data); + if (disable) { + const messageParameters: MessageParameter = { + Title: '#LDS#Heading Deactivate Caches', + Message: '#LDS#If you deactivate all caches, performance will be impaired. Are you sure you want to deactivate all caches?', + }; + if (await this.confirmService.confirm(messageParameters)) { + const data = this.apiProjects.map((appid) => this.appConfigService.v2client.admin_cache_post(appid ?? '', { disable: disable })); + await this.apply(data); + } + } else { + const data = this.apiProjects.map((appid) => this.appConfigService.v2client.admin_cache_post(appid ?? '', { disable: disable })); + await this.apply(data); + } } async apply(pdata: Promise<{ [key: string]: CacheData }>[]) { @@ -89,7 +104,7 @@ export class CacheComponent implements OnInit, SideNavigationComponent { IsDisabled: false, AccessCount: 0, HitCount: 0, - ObjectCount: 0 + ObjectCount: 0, }; const obj = this.cacheData[key]; @@ -97,7 +112,7 @@ export class CacheComponent implements OnInit, SideNavigationComponent { IsDisabled: obj.IsDisabled || data[key].IsDisabled, AccessCount: obj.AccessCount + data[key].AccessCount, HitCount: obj.HitCount + data[key].HitCount, - ObjectCount: obj.ObjectCount + data[key].ObjectCount + ObjectCount: obj.ObjectCount + data[key].ObjectCount, }; } } @@ -106,23 +121,22 @@ export class CacheComponent implements OnInit, SideNavigationComponent { } this.totalEntries = Object.keys(this.cacheData) - .map(a => this.cacheData[a].ObjectCount) + .map((a) => this.cacheData[a].ObjectCount) .reduce((a, b) => a + b); this.totalHits = Object.keys(this.cacheData) - .map(a => this.cacheData[a].HitCount) + .map((a) => this.cacheData[a].HitCount) .reduce((a, b) => a + b); this.cacheKeys = Object.keys(this.cacheData); } private isCachingDeactivated() { - return Object.keys(this.cacheData).filter(b => !this.cacheData[b].IsDisabled).length == 0; + return Object.keys(this.cacheData).filter((b) => !this.cacheData[b].IsDisabled).length == 0; } public GetLdsSwitchText() { - return this.isCachingDeactivated() - ? "#LDS#Activate caches" : "#LDS#Deactivate caches"; + return this.isCachingDeactivated() ? '#LDS#Activate caches' : '#LDS#Deactivate caches'; } public LdsFlushAll = '#LDS#Flush all caches'; diff --git a/imxweb/projects/qbm/src/lib/admin/config-key-path.component.html b/imxweb/projects/qbm/src/lib/admin/config-key-path.component.html index 4e9afe56f..d9987d03b 100644 --- a/imxweb/projects/qbm/src/lib/admin/config-key-path.component.html +++ b/imxweb/projects/qbm/src/lib/admin/config-key-path.component.html @@ -1,4 +1,4 @@ {{ elem }} / - \ No newline at end of file + diff --git a/imxweb/projects/qbm/src/lib/admin/config-key-path.component.scss b/imxweb/projects/qbm/src/lib/admin/config-key-path.component.scss index b6812b34d..5e948a784 100644 --- a/imxweb/projects/qbm/src/lib/admin/config-key-path.component.scss +++ b/imxweb/projects/qbm/src/lib/admin/config-key-path.component.scss @@ -1,6 +1,6 @@ -@import "@elemental-ui/core/src/styles/_palette.scss"; +@import '@elemental-ui/core/src/styles/_palette.scss'; .key-path-separator { - margin: 0 .15em; + margin: 0 0.15em; color: $black-9; } diff --git a/imxweb/projects/qbm/src/lib/admin/config-key-path.component.ts b/imxweb/projects/qbm/src/lib/admin/config-key-path.component.ts index 27f8da594..7987c5427 100644 --- a/imxweb/projects/qbm/src/lib/admin/config-key-path.component.ts +++ b/imxweb/projects/qbm/src/lib/admin/config-key-path.component.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -24,14 +24,13 @@ * */ -import { Component, Input } from "@angular/core"; +import { Component, Input } from '@angular/core'; @Component({ templateUrl: './config-key-path.component.html', selector: 'config-key-path', - styleUrls: ['./config-key-path.component.scss'] + styleUrls: ['./config-key-path.component.scss'], }) export class ConfigKeyPathComponent { - - @Input() public path: string[] = []; -} \ No newline at end of file + @Input() public path: (string | undefined)[] = []; +} diff --git a/imxweb/projects/qbm/src/lib/admin/config-section.ts b/imxweb/projects/qbm/src/lib/admin/config-section.ts index d31cddca5..a97b245a9 100644 --- a/imxweb/projects/qbm/src/lib/admin/config-section.ts +++ b/imxweb/projects/qbm/src/lib/admin/config-section.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -24,19 +24,20 @@ * */ -import { ConfigSettingData } from 'imx-api-qbm'; +import { ConfigSettingData } from '@imx-modules/imx-api-qbm'; export class ConfigSection { - constructor(public readonly Title: string, + constructor( + public readonly Title: string, public readonly Description: string, public readonly Keys: KeyData[], /** Returns the configuration nodes that support adding a new setting. */ - public readonly SettingsSupportingAdd: KeyData[]) { - } + public readonly SettingsSupportingAdd: KeyData[], + ) {} } export interface KeyData extends ConfigSettingData { Path: string; - DisplayPath: string[]; - searchTerms: string[]; -} \ No newline at end of file + DisplayPath: (string | undefined)[]; + searchTerms: (string | undefined)[]; +} diff --git a/imxweb/projects/qbm/src/lib/admin/config.component.html b/imxweb/projects/qbm/src/lib/admin/config.component.html index bc14afb32..e47e66534 100644 --- a/imxweb/projects/qbm/src/lib/admin/config.component.html +++ b/imxweb/projects/qbm/src/lib/admin/config.component.html @@ -1,10 +1,11 @@
    -

    #LDS#Configuration

    +

    #LDS#Configuration

    - + + {{ '#LDS#Show configuration for the following API project' | translate }} - + {{ pr.DisplayName }} @@ -12,7 +13,7 @@

    #LDS#Configuration

    - @@ -30,13 +31,24 @@

    #LDS#Configuration

    {{ '#LDS#Create configuration key' | translate }} -
    -
    @@ -46,26 +58,27 @@

    #LDS#Configuration

    #dataSourceToolbar [alwaysVisible]="true" [settings]="dstSettings" - (search)="onSearch($event)" - (navigationStateChanged)="getData($event)" + (search)="getData()" + (navigationStateChanged)="getData()" [options]="['search', 'filter']" > - - -
    - - - -
    {{ '#LDS#There are no configuration keys matching your search.' | translate }}
    - - + + +
    + +
    + + {{ '#LDS#There are no configuration keys matching your search.' | translate }} +
    + +

    {{ section.Title }}

    {{ section.Description }}

    - - + + @@ -92,7 +105,9 @@

    {{ section.Title }}

    - {{ conf.DisplayPath[conf.DisplayPath.length - 1] }} + {{ conf.DisplayPath[conf.DisplayPath.length - 1] }} +

    {{ conf.Description }}

    @@ -116,7 +131,15 @@

    {{ section.Title }}

    - + @@ -164,9 +187,9 @@

    {{ section.Title }}

    -
    +
    +
    diff --git a/imxweb/projects/qbm/src/lib/admin/convert-config-sidesheet.component.scss b/imxweb/projects/qbm/src/lib/admin/convert-config-sidesheet.component.scss index 93585a4f6..df2fdd66c 100644 --- a/imxweb/projects/qbm/src/lib/admin/convert-config-sidesheet.component.scss +++ b/imxweb/projects/qbm/src/lib/admin/convert-config-sidesheet.component.scss @@ -1,4 +1,4 @@ -@import "@elemental-ui/core/src/styles/_palette.scss"; +@import '@elemental-ui/core/src/styles/_palette.scss'; ul { margin: 1em; diff --git a/imxweb/projects/qbm/src/lib/admin/convert-config-sidesheet.component.ts b/imxweb/projects/qbm/src/lib/admin/convert-config-sidesheet.component.ts index 27a714191..bd0790c82 100644 --- a/imxweb/projects/qbm/src/lib/admin/convert-config-sidesheet.component.ts +++ b/imxweb/projects/qbm/src/lib/admin/convert-config-sidesheet.component.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -24,17 +24,17 @@ * */ -import { Component } from "@angular/core"; -import { EuiSidesheetRef } from "@elemental-ui/core"; -import { ConfigService } from "./config.service"; +import { Component } from '@angular/core'; +import { EuiSidesheetRef } from '@elemental-ui/core'; +import { ConfigService } from './config.service'; @Component({ templateUrl: './convert-config-sidesheet.component.html', - styleUrls: ['./convert-config-sidesheet.component.scss'] + styleUrls: ['./convert-config-sidesheet.component.scss'], }) export class ConvertConfigSidesheetComponent { - - constructor(private readonly configSvc: ConfigService, + constructor( + private readonly configSvc: ConfigService, private readonly sideSheetRef: EuiSidesheetRef, ) { this.customizationsToConvert = this.configSvc.getLocalCustomizations(); @@ -42,12 +42,13 @@ export class ConvertConfigSidesheetComponent { public isGlobal: boolean = false; - public customizationsToConvert: string[][]; + public customizationsToConvert: (string | undefined)[][]; public submit() { this.configSvc.convert(); this.sideSheetRef.close(); } - public LdsInfoText = '#LDS#You can globally apply the following configuration changes that are currently used locally. The changes are stored in the global configuration file and distributed to all API Servers.'; -} \ No newline at end of file + public LdsInfoText = + '#LDS#You can globally apply the following configuration changes that are currently used locally. The changes are stored in the global configuration file and distributed to all API Servers.'; +} diff --git a/imxweb/projects/qbm/src/lib/admin/dashboard.component.scss b/imxweb/projects/qbm/src/lib/admin/dashboard.component.scss index 47d42ab68..683ae23fa 100644 --- a/imxweb/projects/qbm/src/lib/admin/dashboard.component.scss +++ b/imxweb/projects/qbm/src/lib/admin/dashboard.component.scss @@ -1,165 +1,3 @@ -@import '@elemental-ui/core/src/styles/_palette.scss'; -@import '@elemental-ui/core/src/styles/_eui_palette.scss'; -@import '../../../../../shared/scss/side-navigation.scss'; - :host { height: 100%; } - -.snavigation { - height: 100%; - - .mat-sidenav-container { - height: 100%; - background-color: $asher-gray; - - .mat-sidenav { - width: 230px; - - .snavigation-side { - display: flex; - flex-direction: column; - height: 100%; - - .snavigation-side-content { - flex: 1; - padding: 32px; - padding-bottom: 16px; - } - - .snavigation-side-footer { - padding: 16px 32px; - border-top: 1px solid rgba($black-c, 0.5); - } - } - - .snavigation-side-toggle { - display: none; - padding: 16px 12px 0; - margin-bottom: 10px; - - .mat-button { - min-width: 0; - padding: 0 4px; - height: 28px; - - .mat-icon { - margin-top: -12px; - } - } - } - - .snavigation-side-heading { - font-size: 14px; - font-weight: bold; - margin-bottom: 10px; - white-space: nowrap; - } - - .snavigation-item { - margin: 0 -32px; - padding: 10px 32px; - display: flex; - align-items: center; - justify-content: flex-start; - cursor: pointer; - - & > .eui-icon { - margin-right: 8px; - color: rgba($black, 0.4); - } - - & > span { - flex: 1; - } - - &:hover:not(.snavigation-item--selected) { - background-color: rgba($iris-tint, 0.5); - } - - &.snavigation-item--selected { - background-color: $iris-blue; - color: $white; - } - } - } - - .mat-sidenav-content { - padding: 32px; - position: relative; - display: flex; - - &.snavigation--backdrop-showing { - overflow: hidden; - } - - .snavigation-backdrop { - position: absolute; - top: 0; - left: 0; - right: 0; - bottom: 0; - background-color: rgba($black, 0.32); - z-index: 200; - } - - .mat-table tr:hover td { - background-color: rgba($black, 0.04); - cursor: pointer; - } - } - } -} - -@media only screen and (max-width: 768px) { - .snavigation .mat-sidenav-container { - .mat-sidenav { - transition: width 0.5s; - - .snavigation-side { - .snavigation-side-content, - .snavigation-side-footer { - padding: 16px; - } - } - - .snavigation-side-toggle { - display: block; - } - - &:not(.snavigation-side--expanded) { - width: 58px; - - .snavigation-side-content, - .snavigation-side-footer { - display: none; - } - } - } - } -} - -.eui-dark-theme { - :host { - .snavigation { - .mat-sidenav-container{ - background-color: $color-gray-80; - } - } - } -} - -.eui-contrast-theme { - :host { - .snavigation { - .mat-sidenav-container{ - background-color: $color-gray-90; - } - - .snavigation-item--selected { - border-top: 1px solid $color-gray-0; - border-bottom: 1px solid $color-gray-0; - } - } - } -} diff --git a/imxweb/projects/qbm/src/lib/admin/dashboard.component.ts b/imxweb/projects/qbm/src/lib/admin/dashboard.component.ts index f5253bd47..00d8326d3 100644 --- a/imxweb/projects/qbm/src/lib/admin/dashboard.component.ts +++ b/imxweb/projects/qbm/src/lib/admin/dashboard.component.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -27,6 +27,7 @@ import { Component, OnDestroy, OnInit } from '@angular/core'; import { ConfigService } from './config.service'; +import { EuiTheme, EuiThemeService } from '@elemental-ui/core'; import { Subscription } from 'rxjs'; import { AppConfigService } from '../appConfig/appConfig.service'; import { SideNavigationExtension } from '../side-navigation-view/side-navigation-view-interfaces'; @@ -131,10 +132,17 @@ export class DashboardComponent implements OnInit, OnDestroy { documentationUiEnabled: boolean = true; - constructor(private readonly appConfigService: AppConfigService, private readonly configService: ConfigService) {} + constructor( + private readonly appConfigService: AppConfigService, + private readonly configService: ConfigService, + private readonly euiThemeService: EuiThemeService, + ) { + this.euiThemeService.setTheme(EuiTheme.LIGHT); + } async ngOnInit() { this.loadDocumentationUi(); + this.subscriptions.push(this.configService.submitChanges?.subscribe(() => this.loadDocumentationUi())); } diff --git a/imxweb/projects/qbm/src/lib/admin/delete-config-sidesheet.component.html b/imxweb/projects/qbm/src/lib/admin/delete-config-sidesheet.component.html index abfb5d660..a908cfe99 100644 --- a/imxweb/projects/qbm/src/lib/admin/delete-config-sidesheet.component.html +++ b/imxweb/projects/qbm/src/lib/admin/delete-config-sidesheet.component.html @@ -1,8 +1,7 @@
    - - {{'#LDS#Configuration key to be deleted' | translate}} + {{ '#LDS#Configuration key to be deleted' | translate }} @@ -12,7 +11,8 @@
    -
    - +
    +
    diff --git a/imxweb/projects/qbm/src/lib/admin/delete-config-sidesheet.component.ts b/imxweb/projects/qbm/src/lib/admin/delete-config-sidesheet.component.ts index 40db19e8c..d4a7dea1b 100644 --- a/imxweb/projects/qbm/src/lib/admin/delete-config-sidesheet.component.ts +++ b/imxweb/projects/qbm/src/lib/admin/delete-config-sidesheet.component.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -24,29 +24,28 @@ * */ -import { Component, OnInit } from "@angular/core"; -import { EuiLoadingService, EuiSidesheetRef } from "@elemental-ui/core"; -import { SnackBarService } from "../snackbar/snack-bar.service"; -import { KeyData } from "./config-section"; -import { ConfigService } from "./config.service"; +import { Component, OnInit } from '@angular/core'; +import { EuiLoadingService, EuiSidesheetRef } from '@elemental-ui/core'; +import { SnackBarService } from '../snackbar/snack-bar.service'; +import { KeyData } from './config-section'; +import { ConfigService } from './config.service'; @Component({ templateUrl: './delete-config-sidesheet.component.html', - styleUrls: ['./add-config-sidesheet.component.scss'] + styleUrls: ['./add-config-sidesheet.component.scss'], }) export class DeleteConfigSidesheetComponent implements OnInit { - - constructor(private readonly configSvc: ConfigService, + constructor( + private readonly configSvc: ConfigService, private readonly sideSheetRef: EuiSidesheetRef, private readonly busySvc: EuiLoadingService, - private readonly snackbar: SnackBarService - ) { } + private readonly snackbar: SnackBarService, + ) {} keyData: KeyData[]; selectedKey: KeyData; ngOnInit(): void { - this.keyData = this.configSvc.deletableKeys; } @@ -57,11 +56,11 @@ export class DeleteConfigSidesheetComponent implements OnInit { try { await this.configSvc.deleteKey(this.selectedKey.Path); await this.configSvc.load(); - const key = "#LDS#The configuration key has been successfully deleted."; + const key = '#LDS#The configuration key has been successfully deleted.'; this.snackbar.open({ key }); } finally { this.busySvc.hide(overlay); } this.sideSheetRef.close(); } -} \ No newline at end of file +} diff --git a/imxweb/projects/qbm/src/lib/admin/list-setting.component.html b/imxweb/projects/qbm/src/lib/admin/list-setting.component.html index ca9f84287..42a274f44 100644 --- a/imxweb/projects/qbm/src/lib/admin/list-setting.component.html +++ b/imxweb/projects/qbm/src/lib/admin/list-setting.component.html @@ -1,26 +1,29 @@
    -
    +
    - - + - + - {{pr.Display}} ({{pr.Value}}) + {{ pr.Display }} ({{ pr.Value }}) -
    -
    - -
    \ No newline at end of file +
    + +
    diff --git a/imxweb/projects/qbm/src/lib/admin/list-setting.component.scss b/imxweb/projects/qbm/src/lib/admin/list-setting.component.scss index 058d87280..b637e8551 100644 --- a/imxweb/projects/qbm/src/lib/admin/list-setting.component.scss +++ b/imxweb/projects/qbm/src/lib/admin/list-setting.component.scss @@ -1,17 +1,13 @@ -@import "variables.scss"; - -.buttonbar -{ - margin: 1em 0; -} +@import '@elemental-ui/core/src/styles/_eui_palette.scss'; +@import 'base/variables'; .setting-value-list { width: 500px; max-width: 100%; - border: solid 1px $VI_Common_Color_LightGray; + border: solid 1px $color-gray-30; min-height: 45px; display: block; - background: white; + background: $color-gray-0; border-radius: 4px; overflow: hidden; cursor: move; @@ -29,21 +25,22 @@ .setting-value-box { padding: 10px; position: relative; - border-bottom: solid 1px $VI_Common_Color_LightGray; + border-bottom: solid 1px $color-gray-30; display: flex; flex-direction: row; align-items: center; justify-content: space-between; box-sizing: border-box; - background: white; + background: $color-gray-0; } .cdk-drag-preview { box-sizing: border-box; border-radius: 4px; - box-shadow: 0 5px 5px -3px rgba(0, 0, 0, 0.2), - 0 8px 10px 1px rgba(0, 0, 0, 0.14), - 0 3px 14px 2px rgba(0, 0, 0, 0.12); + box-shadow: + 0 5px 5px -3px rgba(0, 0, 0, 0.2), + 0 8px 10px 1px rgba(0, 0, 0, 0.14), + 0 3px 14px 2px rgba(0, 0, 0, 0.12); } .cdk-drag-placeholder { diff --git a/imxweb/projects/qbm/src/lib/admin/list-setting.component.ts b/imxweb/projects/qbm/src/lib/admin/list-setting.component.ts index 60288c529..12c5a2fef 100644 --- a/imxweb/projects/qbm/src/lib/admin/list-setting.component.ts +++ b/imxweb/projects/qbm/src/lib/admin/list-setting.component.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -24,22 +24,23 @@ * */ -import { Component, Input, OnChanges, OnInit, SimpleChanges } from '@angular/core'; import { CdkDragDrop, moveItemInArray } from '@angular/cdk/drag-drop'; +import { Component, Input, OnChanges, OnInit, SimpleChanges } from '@angular/core'; +import { ConfigSettingType, ConfigSettingValidValue } from '@imx-modules/imx-api-qbm'; import { imx_SessionService } from '../session/imx-session.service'; import { KeyData } from './config-section'; -import { ConfigSettingType, ConfigSettingValidValue } from 'imx-api-qbm'; import { ConfigService } from './config.service'; @Component({ - selector: "imx-list-setting", + selector: 'imx-list-setting', templateUrl: './list-setting.component.html', - styleUrls: ['./list-setting.component.scss'] + styleUrls: ['./list-setting.component.scss'], }) export class ListSettingComponent implements OnInit, OnChanges { - - constructor(private readonly session: imx_SessionService, private readonly configSvc: ConfigService) { - } + constructor( + private readonly session: imx_SessionService, + private readonly configSvc: ConfigService, + ) {} @Input() public setting: KeyData; @@ -60,7 +61,7 @@ export class ListSettingComponent implements OnInit, OnChanges { this.hasLimitedValues = this.setting.Type == ConfigSettingType.LimitedValues; if (this.hasLimitedValues) { this.validvalues = await this.session.Client.admin_apiconfig_values_get(this.configSvc.appId, this.setting.Path); - }; + } } drop(event: CdkDragDrop) { diff --git a/imxweb/projects/qbm/src/lib/admin/log-details-sidesheet.component.html b/imxweb/projects/qbm/src/lib/admin/log-details-sidesheet.component.html index d609b0b72..0616f2a0e 100644 --- a/imxweb/projects/qbm/src/lib/admin/log-details-sidesheet.component.html +++ b/imxweb/projects/qbm/src/lib/admin/log-details-sidesheet.component.html @@ -2,42 +2,37 @@
    - {{'#LDS#Sequence ID' | translate}} - {{data.SequenceID}} + {{ '#LDS#Sequence ID' | translate }} + {{ data.SequenceID }}
    - {{'#LDS#Level' | translate}} - {{data.Level}} + {{ '#LDS#Level' | translate }} + {{ data.Level }}
    - {{'#LDS#Logger name' | translate}} - {{data.LoggerName}} + {{ '#LDS#Logger name' | translate }} + {{ data.LoggerName }}
    - {{'#LDS#Messages' | translate}} + {{ '#LDS#Messages' | translate }} - - + {{ data.Message?.trim() }} +
    -
    - {{'#LDS#Error messages' | translate}} +
    + {{ (data.Level === 'Error' ? '#LDS#Error messages' : '#LDS#Nested messages') | translate }} - + {{ data.Exception?.Messages?.join('\n')?.trim() }}
    -
    - {{'#LDS#Stack trace' | translate}} +
    + {{ '#LDS#Stack trace' | translate }} - +
    - diff --git a/imxweb/projects/qbm/src/lib/admin/log-details-sidesheet.component.scss b/imxweb/projects/qbm/src/lib/admin/log-details-sidesheet.component.scss index 1f100bb6d..44986aaad 100644 --- a/imxweb/projects/qbm/src/lib/admin/log-details-sidesheet.component.scss +++ b/imxweb/projects/qbm/src/lib/admin/log-details-sidesheet.component.scss @@ -17,14 +17,13 @@ float: left; width: 33.33%; } - - + .row:after { - content: ""; + content: ''; display: table; clear: both; } - + textarea { white-space: pre-line; text-align: justify; @@ -37,4 +36,4 @@ textarea { .stacktrace { height: 200px; -} \ No newline at end of file +} diff --git a/imxweb/projects/qbm/src/lib/admin/log-details-sidesheet.component.ts b/imxweb/projects/qbm/src/lib/admin/log-details-sidesheet.component.ts index 9b844cc4b..5d68788f3 100644 --- a/imxweb/projects/qbm/src/lib/admin/log-details-sidesheet.component.ts +++ b/imxweb/projects/qbm/src/lib/admin/log-details-sidesheet.component.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -26,18 +26,17 @@ import { Component, Inject, OnInit } from '@angular/core'; import { EuiSidesheetRef, EUI_SIDESHEET_DATA } from '@elemental-ui/core'; -import { ApiLogEntry } from 'imx-api-qbm'; +import { ApiLogEntry } from '@imx-modules/imx-api-qbm'; @Component({ selector: 'imx-log-details-sidesheet', templateUrl: './log-details-sidesheet.component.html', - styleUrls: ['./log-details-sidesheet.component.scss'] + styleUrls: ['./log-details-sidesheet.component.scss'], }) export class LogDetailsSidesheetComponent implements OnInit { - - constructor(@Inject(EUI_SIDESHEET_DATA) public readonly data: ApiLogEntry, - public readonly sidesheetRef: EuiSidesheetRef) { } - ngOnInit(): void { - - } + constructor( + @Inject(EUI_SIDESHEET_DATA) public readonly data: ApiLogEntry, + public readonly sidesheetRef: EuiSidesheetRef, + ) {} + ngOnInit(): void {} } diff --git a/imxweb/projects/qbm/src/lib/admin/logs.component.html b/imxweb/projects/qbm/src/lib/admin/logs.component.html index 6b6bdbc37..5cf59b358 100644 --- a/imxweb/projects/qbm/src/lib/admin/logs.component.html +++ b/imxweb/projects/qbm/src/lib/admin/logs.component.html @@ -1,4 +1,4 @@ - +
    @@ -13,14 +13,11 @@ [alwaysVisible]="true" > - + #LDS#Use regular expressions - -

    {{ '#LDS#You can use regular expressions when searching.' | translate }}

    -
    @@ -29,22 +26,28 @@ #LDS#The regular expression you entered is invalid.
    - + - -
    {{ log.Message }}
    -
    {{ log.TimeStamp | localizedDate }}
    + +
    {{ log.Message }}
    +
    {{ log.TimeStamp | localizedDate }}
    -
    +

    {{ '#LDS#There are currently no log entries.' | translate }}

    -
    +

    {{ '#LDS#There is no data matching your search.' | translate }}

    - - + +
    @@ -62,16 +65,17 @@ [alwaysVisible]="true" > - + #LDS#Use regular expressions

    {{ '#LDS#You can use regular expressions when searching.' | translate }}

    -
    +
    @@ -79,20 +83,26 @@
    - -
    {{ log.Message }}
    -
    {{ log.TimeStamp | localizedDate }}
    + +
    {{ log.Message }}
    +
    {{ log.TimeStamp | localizedDate }}
    -
    +

    {{ '#LDS#There are currently no log entries.' | translate }}

    -
    +

    {{ '#LDS#There is no data matching your search.' | translate }}

    - +
    @@ -100,13 +110,17 @@
    -
    {{ log.File }}
    -
    {{ log.LastModified | localizedDate }}
    +
    {{ log.File }}
    +
    {{ log.LastModified | localizedDate }}
    -
    {{ '#LDS#There are currently no log entries.' | translate }}
    +
    {{ '#LDS#There are currently no log entries.' | translate }}
    + + +

    {{ '#LDS#You can use regular expressions when searching.' | translate }}

    +
    diff --git a/imxweb/projects/qbm/src/lib/admin/logs.component.scss b/imxweb/projects/qbm/src/lib/admin/logs.component.scss index cfe7372df..b4d56ed61 100644 --- a/imxweb/projects/qbm/src/lib/admin/logs.component.scss +++ b/imxweb/projects/qbm/src/lib/admin/logs.component.scss @@ -4,45 +4,28 @@ width: 100%; height: 100%; - mat-tab-group { - height: inherit; - } - .imx-log-timeline-container { height: inherit; display: flex; flex-direction: column; overflow: hidden; + .imx-slide-toggle{ + margin:auto; + } } -.flex-container { - display: flex; - align-items: stretch; - margin-top: 2em; -} - -.imx-error-icon { - color: $color-red-60; -} - -.imx-warning-icon { - color: $color-orange-60; -} - -.imx-primary-icon { - color: $color-blue-60; -} - -.no-data, .no-result { - height: 100%; - display: flex; - flex-direction: column; - justify-content: center; - align-items: center; + .flex-container { + display: flex; + align-items: stretch; + margin-top: 2em; + } - .eui-icon { - font-size: 100px; - } + .imx-no-results { + height: 100%; + display: flex; + flex-direction: column; + justify-content: center; + align-items: center; p { margin: 0; @@ -50,14 +33,8 @@ } } -.mat-spinner { - align-self: center; - margin: auto; - margin-top: 100px; -} - - mat-nav-list { - height: calc(100vh - 280px); + .mdc-list { + height: 100%; overflow: auto; } @@ -67,22 +44,9 @@ transition: 1s; } -.slide-toggle { - margin-left: 10px; - margin-top: 13px; - overflow: hidden; - white-space: nowrap; - text-overflow: ellipsis; -} - -.imx-info-button { - margin-top: 5px; -} - p { color: $color-gray-40; } - } .imx-error-message { @@ -93,7 +57,6 @@ eui-icon { margin-right: 8px; } - } @media only screen and (max-width: 1024px) { diff --git a/imxweb/projects/qbm/src/lib/admin/logs.component.ts b/imxweb/projects/qbm/src/lib/admin/logs.component.ts index 5c26317b7..b5038e1ad 100644 --- a/imxweb/projects/qbm/src/lib/admin/logs.component.ts +++ b/imxweb/projects/qbm/src/lib/admin/logs.component.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -24,25 +24,25 @@ * */ -import { OverlayRef } from '@angular/cdk/overlay'; -import { Component, ViewChild, OnInit, Input } from '@angular/core'; +import { Component, Input, OnInit, ViewChild } from '@angular/core'; +import { MatPaginator, PageEvent } from '@angular/material/paginator'; +import { MatSlideToggleChange } from '@angular/material/slide-toggle'; +import { MatTabChangeEvent } from '@angular/material/tabs'; import { EuiDownloadOptions, EuiLoadingService, EuiSidesheetConfig, EuiSidesheetService } from '@elemental-ui/core'; +import { ApiLogEntry, LogFileInfo, V2ApiClientMethodFactory } from '@imx-modules/imx-api-qbm'; +import { FilterData, MethodDefinition, ValType } from '@imx-modules/imx-qbm-dbts'; import { TranslateService } from '@ngx-translate/core'; -import { ApiLogEntry, LogFileInfo, V2ApiClientMethodFactory } from 'imx-api-qbm'; +import moment from 'moment-timezone'; import { AppConfigService } from '../appConfig/appConfig.service'; -import { LogDetailsSidesheetComponent } from './log-details-sidesheet.component'; +import { calculateSidesheetWidth } from '../base/sidesheet-helper'; import { ClassloggerService } from '../classlogger/classlogger.service'; -import { LocalizedDatePipe } from '../date/localized-date.pipe'; -import { MatTabChangeEvent } from '@angular/material/tabs'; -import { CollectionLoadParameters, FilterData, MethodDefinition, TypedEntity, ValType } from 'imx-qbm-dbts'; -import { MatSlideToggleChange } from '@angular/material/slide-toggle'; -import { DataSourceToolbarComponent } from '../data-source-toolbar/data-source-toolbar.component'; import { ElementalUiConfigService } from '../configuration/elemental-ui-config.service'; -import { DataSourceToolbarSettings } from '../data-source-toolbar/data-source-toolbar-settings'; -import { MatPaginator, PageEvent } from '@angular/material/paginator'; -import moment from 'moment-timezone'; import { DataSourceToolbarFilter } from '../data-source-toolbar/data-source-toolbar-filters.interface'; +import { DataSourceToolbarSettings } from '../data-source-toolbar/data-source-toolbar-settings'; +import { DataSourceToolbarComponent } from '../data-source-toolbar/data-source-toolbar.component'; +import { LocalizedDatePipe } from '../date/localized-date.pipe'; import { SideNavigationComponent } from '../side-navigation-view/side-navigation-view-interfaces'; +import { LogDetailsSidesheetComponent } from './log-details-sidesheet.component'; @Component({ selector: 'imx-logs', @@ -87,16 +87,16 @@ export class LogsComponent implements OnInit, SideNavigationComponent { private datePipe: LocalizedDatePipe, private logger: ClassloggerService, private elementalUiConfigService: ElementalUiConfigService, - private translator: TranslateService + private translator: TranslateService, ) {} public async ngOnInit(): Promise { - const overlayRef = this.busyService.show(); + this.showBusyIndicator(); try { const timeFilter: DataSourceToolbarFilter = { Name: 'TimeFilter', - Description: this.translator.instant('#LDS#Time'), + Description: this.translator.instant('#LDS#Time period'), Options: [ { Display: this.translator.instant('#LDS#Last hour'), @@ -165,23 +165,23 @@ export class LogsComponent implements OnInit, SideNavigationComponent { this.stream.onmessage = (evt) => { this.logger.trace('Logs data', evt.data); this.liveLogs.push(JSON.parse(evt.data)); - this.onLiveLogSearch(this.dstSettingsLive.navigationState.search); + this.onLiveLogSearch(this.dstSettingsLive?.navigationState?.search ?? '', true); }; this.stream.onerror = (err) => { this.logger.error('An error occured in data stream:', err); }; } finally { - setTimeout(() => this.busyService.hide(overlayRef)); + this.busyService.hide(); } } private async getSessionData(): Promise { - const overlayRef = this.busyService.show(); + this.showBusyIndicator(); try { return await this.appConfigService.client.admin_systeminfo_log_session_get(); } finally { - setTimeout(() => this.busyService.hide(overlayRef)); + this.busyService.hide(); } } @@ -191,32 +191,33 @@ export class LogsComponent implements OnInit, SideNavigationComponent { this.currentTab = event.index; if (this.currentTab === 2) { - const overlayRef = this.busyService.show(); + this.showBusyIndicator(); try { this.logFiles = await this.appConfigService.client.admin_systeminfo_logs_get(); this.logFiles.forEach((log) => { - var dir = log.Path.split('\\'); - const url = - this.appConfigService.BaseUrl + - new MethodDefinition(new V2ApiClientMethodFactory().admin_systeminfo_log_get(dir[0], dir[1])).path; - this.logDownloads.push({ - ...this.elementalUiConfigService.Config.downloadOptions, - fileMimeType: '', - url, - fileName: log.File, - }); + var dir = log.Path?.split('\\'); + if (dir && dir.length > 1) { + const url = + this.appConfigService.BaseUrl + + new MethodDefinition(new V2ApiClientMethodFactory().admin_systeminfo_log_get(dir[0], dir[1])).path; + this.logDownloads.push({ + ...this.elementalUiConfigService.Config.downloadOptions, + fileMimeType: '', + url, + fileName: log.File, + }); + } }); } finally { - setTimeout(() => this.busyService.hide(overlayRef)); + this.busyService.hide(); } } } public onSessionLogSearch(keywords: string): void { - const sessionKeywords: ({ IsRegex?: boolean } & FilterData)[] = this.dstSettingsSession.navigationState.filter?.filter( - (filter) => filter.Type === 1 - ); + const sessionKeywords: ({ IsRegex?: boolean } & FilterData)[] = + this.dstSettingsSession.navigationState.filter?.filter((filter) => filter.Type === 1) ?? []; this.sessionLogsFiltered = this.sessionLogs; //Handles keyword filters @@ -224,16 +225,16 @@ export class LogsComponent implements OnInit, SideNavigationComponent { this.sessionLogsFiltered = this.sessionLogsFiltered.filter((log) => sessionKeywords.every((keyword) => keyword.IsRegex - ? this.regexTest(keyword.Value1.toLowerCase(), log.Message?.toLowerCase()) - : log.Message?.toLowerCase().includes(keyword.Value1.toLowerCase()) - ) + ? this.regexTest(keyword.Value1.toLowerCase(), log.Message?.toLowerCase() ?? '') + : log.Message?.toLowerCase().includes(keyword.Value1.toLowerCase()), + ), ); } //Handles time filters if (this.dstSettingsSession.navigationState.TimeFilter) { this.sessionLogsFiltered = this.sessionLogsFiltered.filter((log) => - moment(log.TimeStamp).isAfter(this.dstSettingsSession.navigationState.TimeFilter) + moment(log.TimeStamp).isAfter(this.dstSettingsSession.navigationState.TimeFilter), ); } @@ -254,10 +255,9 @@ export class LogsComponent implements OnInit, SideNavigationComponent { this.setSessionPage(); } - public onLiveLogSearch(keywords: string): void { - const liveKeywords: ({ IsRegex?: boolean } & FilterData)[] = this.dstSettingsLive.navigationState.filter?.filter( - (filter) => filter.Type === 1 - ); + public onLiveLogSearch(keywords: string, stream = false): void { + const liveKeywords: ({ IsRegex?: boolean } & FilterData)[] = + this.dstSettingsLive.navigationState.filter?.filter((filter) => filter.Type === 1) ?? []; this.liveLogsFiltered = this.liveLogs; //Handles keyword filters @@ -265,16 +265,16 @@ export class LogsComponent implements OnInit, SideNavigationComponent { this.liveLogsFiltered = this.liveLogsFiltered.filter((log) => liveKeywords.every((keyword) => keyword.IsRegex - ? this.regexTest(keyword.Value1.toLowerCase(), log.Message?.toLowerCase()) - : log.Message?.toLowerCase().includes(keyword.Value1.toLowerCase()) - ) + ? this.regexTest(keyword.Value1.toLowerCase(), log.Message?.toLowerCase() ?? '') + : log.Message?.toLowerCase().includes(keyword.Value1.toLowerCase()), + ), ); } //Handles time filters if (this.dstSettingsLive.navigationState.TimeFilter) { this.liveLogsFiltered = this.liveLogsFiltered.filter((log) => - moment(log.TimeStamp).isAfter(this.dstSettingsLive.navigationState.TimeFilter) + moment(log.TimeStamp).isAfter(this.dstSettingsLive.navigationState.TimeFilter), ); } @@ -291,7 +291,9 @@ export class LogsComponent implements OnInit, SideNavigationComponent { } this.liveTotalCount = this.liveLogsFiltered.length; - this.livePaginator.pageIndex = 0; + if (!stream) { + this.livePaginator.pageIndex = 0; + } this.setLivePage(); } @@ -303,19 +305,21 @@ export class LogsComponent implements OnInit, SideNavigationComponent { public onRegexSessionLogSearch(keywords: string): void { this.sessionLogsFiltered = keywords - ? this.sessionLogsFiltered.filter((log) => this.regexTest(keywords, log.Message)) + ? this.sessionLogsFiltered.filter((log) => this.regexTest(keywords, log.Message ?? '')) : this.sessionLogsFiltered; } public onRegexLiveLogSearch(keywords: string): void { - this.liveLogsFiltered = keywords ? this.liveLogsFiltered.filter((log) => this.regexTest(keywords, log.Message)) : this.liveLogsFiltered; + this.liveLogsFiltered = keywords + ? this.liveLogsFiltered.filter((log) => this.regexTest(keywords, log.Message ?? '')) + : this.liveLogsFiltered; } public onRegexToggle(event: MatSlideToggleChange): void { this.searchBoxText = event.checked ? '#LDS#Search using regular expressions' : '#LDS#Search'; - if (this.currentTab === 0) this.onSessionLogSearch(this.dstSession.settings.navigationState.search); - if (this.currentTab === 1) this.onLiveLogSearch(this.dstLive.settings.navigationState.search); + if (this.currentTab === 0) this.onSessionLogSearch(this.dstSession.settings.navigationState.search ?? ''); + if (this.currentTab === 1) this.onLiveLogSearch(this.dstLive.settings.navigationState.search ?? ''); } public validateRegex(keywords: string): boolean { @@ -373,33 +377,32 @@ export class LogsComponent implements OnInit, SideNavigationComponent { } public getIconColor(changeType: string): string { - let color = 'imx-primary-icon'; + let color = 'imx-icon-info'; switch (changeType) { case 'Error': - color = 'imx-error-icon'; + color = 'imx-icon-error'; break; case 'Warn': - color = 'imx-warning-icon'; + color = 'imx-icon-warning'; break; } return color; } public async openLogSideSheet(log: ApiLogEntry): Promise { - let overlayRef: OverlayRef; - setTimeout(() => (overlayRef = this.busyService.show())); + this.showBusyIndicator(); let config: EuiSidesheetConfig; try { config = { title: await this.translateService.get('#LDS#Heading View Log Entry Details').toPromise(), subTitle: this.datePipe.transform(log.TimeStamp), padding: '0', - width: 'max(600px, 60%)', + width: calculateSidesheetWidth(), testId: 'log-details-sidesheet', data: log, }; } finally { - setTimeout(() => this.busyService.hide(overlayRef)); + this.busyService.hide(); } this.sidesheet.open(LogDetailsSidesheetComponent, config); } @@ -407,4 +410,10 @@ export class LogsComponent implements OnInit, SideNavigationComponent { public ngOnDestroy(): void { if (this.stream) this.stream.close(); } + + private showBusyIndicator(): void { + if (this.busyService.overlayRefs.length === 0) { + this.busyService.show(); + } + } } diff --git a/imxweb/projects/qbm/src/lib/admin/packages.component.html b/imxweb/projects/qbm/src/lib/admin/packages.component.html index e9c0d564b..4439d4da3 100644 --- a/imxweb/projects/qbm/src/lib/admin/packages.component.html +++ b/imxweb/projects/qbm/src/lib/admin/packages.component.html @@ -1,4 +1,4 @@ -

    #LDS#Packages

    +

    #LDS#Heading Packages

    diff --git a/imxweb/projects/qbm/src/lib/admin/packages.component.scss b/imxweb/projects/qbm/src/lib/admin/packages.component.scss index 8e348ee30..2e5fdde2f 100644 --- a/imxweb/projects/qbm/src/lib/admin/packages.component.scss +++ b/imxweb/projects/qbm/src/lib/admin/packages.component.scss @@ -1,5 +1,4 @@ - -:host{ +:host { display: flex; flex-flow: column; flex: 1; @@ -8,7 +7,7 @@ padding: 0.5em 0.5em 0.5em 0; overflow: auto; - &.loading{ + &.loading { justify-content: center; flex: 1; align-content: center; diff --git a/imxweb/projects/qbm/src/lib/admin/packages.component.ts b/imxweb/projects/qbm/src/lib/admin/packages.component.ts index 99f4cca21..e4f459260 100644 --- a/imxweb/projects/qbm/src/lib/admin/packages.component.ts +++ b/imxweb/projects/qbm/src/lib/admin/packages.component.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -24,25 +24,26 @@ * */ -import { Component, OnInit, Input } from "@angular/core"; -import { PackageInfo } from "imx-api-qbm"; -import { AppConfigService } from "../appConfig/appConfig.service"; -import { imx_SessionService } from "../session/imx-session.service"; -import { SideNavigationComponent } from "../side-navigation-view/side-navigation-view-interfaces"; +import { Component, Input, OnInit } from '@angular/core'; +import { PackageInfo } from '@imx-modules/imx-api-qbm'; +import { AppConfigService } from '../appConfig/appConfig.service'; +import { imx_SessionService } from '../session/imx-session.service'; +import { SideNavigationComponent } from '../side-navigation-view/side-navigation-view-interfaces'; type ExtendedPackageInfo = PackageInfo & { App?: string }; @Component({ templateUrl: './packages.component.html', selector: 'imx-packages', - styleUrls: ['./packages.component.scss'] + styleUrls: ['./packages.component.scss'], }) export class PackagesComponent implements OnInit, SideNavigationComponent { @Input() public isAdmin: boolean; - constructor(private readonly session: imx_SessionService, - private readonly appConfigService: AppConfigService) { - } + constructor( + private readonly session: imx_SessionService, + private readonly appConfigService: AppConfigService, + ) {} public busy = true; public displayedColumns: string[] = ['Name', 'App', 'RelativePath', 'LastChangeDate', 'Fingerprint']; @@ -53,13 +54,11 @@ export class PackagesComponent implements OnInit, SideNavigationComponent { this.packages = await this.session.Client.admin_packages_get(); const apps = await this.session.Client.imx_applications_get(); for (var p of this.packages) { - p.Fingerprint = p.Fingerprint.substring(0, 8); + p.Fingerprint = p.Fingerprint?.substring(0, 8); - var app = apps.filter(a => a.Name == p.Name); - if (app.length > 0) - p.App = app[0].DisplayName; + var app = apps.filter((a) => a.Name == p.Name); + if (app.length > 0) p.App = app[0].DisplayName; } - } finally { this.busy = false; } diff --git a/imxweb/projects/qbm/src/lib/admin/plugins.component.html b/imxweb/projects/qbm/src/lib/admin/plugins.component.html index 79abc313c..ee93622cc 100644 --- a/imxweb/projects/qbm/src/lib/admin/plugins.component.html +++ b/imxweb/projects/qbm/src/lib/admin/plugins.component.html @@ -1,11 +1,11 @@
    -

    #LDS#Plugins

    +

    #LDS#Heading Plugins

    - {{p.Plugin}} + {{ p.Plugin }} @@ -14,10 +14,10 @@

    #LDS#Plugins

    check - {{'#LDS#Running' |translate}} + {{ '#LDS#Running' | translate }}
    -
    \ No newline at end of file +
    diff --git a/imxweb/projects/qbm/src/lib/admin/plugins.component.ts b/imxweb/projects/qbm/src/lib/admin/plugins.component.ts index 437da1e93..49d956453 100644 --- a/imxweb/projects/qbm/src/lib/admin/plugins.component.ts +++ b/imxweb/projects/qbm/src/lib/admin/plugins.component.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -25,7 +25,7 @@ */ import { Component, Input, OnInit } from '@angular/core'; -import { LoadedPlugin } from 'imx-api-qbm'; +import { LoadedPlugin } from '@imx-modules/imx-api-qbm'; import { AppConfigService } from '../appConfig/appConfig.service'; import { SideNavigationComponent } from '../side-navigation-view/side-navigation-view-interfaces'; diff --git a/imxweb/projects/qbm/src/lib/admin/select-value.component.html b/imxweb/projects/qbm/src/lib/admin/select-value.component.html index 6864f7546..5a0a9c671 100644 --- a/imxweb/projects/qbm/src/lib/admin/select-value.component.html +++ b/imxweb/projects/qbm/src/lib/admin/select-value.component.html @@ -1,8 +1,8 @@ - {{'#LDS#Value' | translate}} + {{ '#LDS#Value' | translate }} - {{pr.Display}} + {{ pr.Display }} - \ No newline at end of file + diff --git a/imxweb/projects/qbm/src/lib/admin/select-value.component.ts b/imxweb/projects/qbm/src/lib/admin/select-value.component.ts index 2797c5ac4..d7970d803 100644 --- a/imxweb/projects/qbm/src/lib/admin/select-value.component.ts +++ b/imxweb/projects/qbm/src/lib/admin/select-value.component.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -24,20 +24,22 @@ * */ -import { Component, Input, OnInit } from "@angular/core"; -import { ConfigSettingValidValue } from "imx-api-qbm"; -import { imx_SessionService } from "../session/imx-session.service"; -import { KeyData } from "./config-section"; -import { ConfigService } from "./config.service"; +import { Component, Input, OnInit } from '@angular/core'; +import { ConfigSettingValidValue } from '@imx-modules/imx-api-qbm'; +import { imx_SessionService } from '../session/imx-session.service'; +import { KeyData } from './config-section'; +import { ConfigService } from './config.service'; @Component({ templateUrl: './select-value.component.html', styles: ['.wide-field {min-width:450px;}'], - selector: 'imx-config-select' + selector: 'imx-config-select', }) export class SelectValueComponent implements OnInit { - - constructor(private readonly session: imx_SessionService, public readonly configSvc: ConfigService) { } + constructor( + private readonly session: imx_SessionService, + public readonly configSvc: ConfigService, + ) {} async ngOnInit(): Promise { this.validvalues = await this.session.Client.admin_apiconfig_values_get(this.configSvc.appId, this.conf.Path); @@ -46,5 +48,4 @@ export class SelectValueComponent implements OnInit { @Input() conf: KeyData; public validvalues: ConfigSettingValidValue[] = []; - -} \ No newline at end of file +} diff --git a/imxweb/projects/qbm/src/lib/admin/shared.scss b/imxweb/projects/qbm/src/lib/admin/shared.scss index 0f6e8da39..75b1baa74 100644 --- a/imxweb/projects/qbm/src/lib/admin/shared.scss +++ b/imxweb/projects/qbm/src/lib/admin/shared.scss @@ -1,15 +1,16 @@ -:host -{ + +@import '../../../../../shared/scss/components/top-navigation.scss'; +:host { min-width: 800px; display: flex; flex: 1; flex-direction: column; - .content-container{ + .content-container { padding: 0.5em 0.5em 0 0; overflow: auto; - &.loading{ + &.loading { display: flex; justify-content: center; flex: 1; @@ -17,52 +18,35 @@ } } - table - { + table { table-layout: fixed; border-collapse: collapse; margin-bottom: 1em; } - h2 - { + h2 { margin-bottom: 1em; } - td - { - padding: .5em; + td { + padding: 0.5em; vertical-align: top; border: solid 1px lightgray; } - table.status-table td:nth-child(1) - { + table.status-table td:nth-child(1) { width: 40%; } - table.plugin-table td:nth-child(2) - { + table.plugin-table td:nth-child(2) { width: 30%; } - .mat-icon - { + .mat-icon { vertical-align: middle; } - pre - { + pre { margin: 0; } - - .button-bar { - display: flex; - gap: 0.5rem; - justify-content: flex-end; - - button:first-child { - margin-right: auto; - } - } } diff --git a/imxweb/projects/qbm/src/lib/admin/status.component.html b/imxweb/projects/qbm/src/lib/admin/status.component.html index e523f93a4..fc7cb2560 100644 --- a/imxweb/projects/qbm/src/lib/admin/status.component.html +++ b/imxweb/projects/qbm/src/lib/admin/status.component.html @@ -1,47 +1,57 @@ -

    {{ '#LDS#An error occurred while connecting to the database. Please try again. If the problem persists, contact your administrator.' | translate }}

    +

    + {{ + '#LDS#An error occurred while connecting to the database. Please try again. If the problem persists, contact your administrator.' + | translate + }} +

    -

    {{ '#LDS#Overview' | translate }}

    +

    {{ '#LDS#Overview' | translate }}

    - {{'#LDS#Sessions' | translate}} + {{ '#LDS#Sessions' | translate }} - + - diff --git a/imxweb/projects/qbm/src/lib/data-table/data-table-generic-column.component.scss b/imxweb/projects/qbm/src/lib/data-table/data-table-generic-column.component.scss deleted file mode 100644 index 1ca156755..000000000 --- a/imxweb/projects/qbm/src/lib/data-table/data-table-generic-column.component.scss +++ /dev/null @@ -1,4 +0,0 @@ -/* You can add styles to this file, and also import other style files */ -td.mat-cell { - margin-right: 10px; -} diff --git a/imxweb/projects/qbm/src/lib/data-table/data-table-generic-column.component.ts b/imxweb/projects/qbm/src/lib/data-table/data-table-generic-column.component.ts index e21d262c8..24cbf17f5 100644 --- a/imxweb/projects/qbm/src/lib/data-table/data-table-generic-column.component.ts +++ b/imxweb/projects/qbm/src/lib/data-table/data-table-generic-column.component.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -46,8 +46,7 @@ import { MatColumnDef } from '@angular/material/table'; */ @Component({ selector: 'imx-data-table-generic-column', - templateUrl: './data-table-generic-column.component.html', - styleUrls: ['./data-table-generic-column.component.scss'] + templateUrl: './data-table-generic-column.component.html' }) export class DataTableGenericColumnComponent implements OnInit { /** diff --git a/imxweb/projects/qbm/src/lib/data-table/data-table-groups.interface.ts b/imxweb/projects/qbm/src/lib/data-table/data-table-groups.interface.ts index d774d618f..388499266 100644 --- a/imxweb/projects/qbm/src/lib/data-table/data-table-groups.interface.ts +++ b/imxweb/projects/qbm/src/lib/data-table/data-table-groups.interface.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -24,7 +24,7 @@ * */ -import { CollectionLoadParameters, TypedEntity } from 'imx-qbm-dbts'; +import { CollectionLoadParameters, TypedEntity } from '@imx-modules/imx-qbm-dbts'; import { DataSourceToolbarSettings } from '../data-source-toolbar/data-source-toolbar-settings'; export function getParameterSubsetForGrouping(original: CollectionLoadParameters): CollectionLoadParameters { @@ -46,12 +46,12 @@ export interface DataTableGroupedData { /** * The DataSourceToolbarSettings for the grouped data */ - settings: DataSourceToolbarSettings; + settings?: DataSourceToolbarSettings; /** * The navigationState for the grouped data */ - navigationState: CollectionLoadParameters; + navigationState?: CollectionLoadParameters; /** * Keeps track if the nested group data is currently visible (expanded) or not diff --git a/imxweb/projects/qbm/src/lib/data-table/data-table-row-highlight.interface.ts b/imxweb/projects/qbm/src/lib/data-table/data-table-row-highlight.interface.ts index e2a460d3a..2d075f852 100644 --- a/imxweb/projects/qbm/src/lib/data-table/data-table-row-highlight.interface.ts +++ b/imxweb/projects/qbm/src/lib/data-table/data-table-row-highlight.interface.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -29,5 +29,3 @@ export interface RowHighlight { */ filter: (row: any) => boolean; } - - diff --git a/imxweb/projects/qbm/src/lib/data-table/data-table.component.html b/imxweb/projects/qbm/src/lib/data-table/data-table.component.html index b88c365b2..143d6ac72 100644 --- a/imxweb/projects/qbm/src/lib/data-table/data-table.component.html +++ b/imxweb/projects/qbm/src/lib/data-table/data-table.component.html @@ -6,20 +6,26 @@ #LDS#Group by: {{ dst?.settings?.groupData?.currentGrouping?.display }} - + + @@ -134,11 +144,20 @@ *matRowDef="let row; columns: getNamesOfDisplayedColumns()" (click)="debouncedHighlightRow(row, $event); $event.stopPropagation()" (keydown.enter)="debouncedHighlightRow(row, $event); $event.stopPropagation()" - [ngClass]="{ 'imx-data-table-row-highlighted': highlightedEntity === row, 'imx-data-table-row-conditional': isHighlight(row) && !(highlightedEntity === row) }" + [ngClass]="{ + 'imx-data-table-row-highlighted': highlightedEntity === row, + 'imx-data-table-row-conditional': isHighlight(row) && !(highlightedEntity === row), + }" >
    - +
    {{ '#LDS#API projects' | translate }} - + {{ p.AppId }} - +
    {{ '#LDS#Software update' | translate }}
    {{ '#LDS#Update is currently running.' | translate }}
    -
    {{ '#LDS#Software updates are not enabled for this server.' | translate }}
    +
    + {{ '#LDS#Software updates are not enabled for this server.' | translate }} +
    {{ '#LDS#Updates are available.' | translate }}

    - - {{option}} + {{ option }} - \ No newline at end of file + diff --git a/imxweb/projects/qbm/src/lib/auto-complete/auto-complete.component.scss b/imxweb/projects/qbm/src/lib/auto-complete/auto-complete.component.scss index 20c499adb..963eb99c8 100644 --- a/imxweb/projects/qbm/src/lib/auto-complete/auto-complete.component.scss +++ b/imxweb/projects/qbm/src/lib/auto-complete/auto-complete.component.scss @@ -6,24 +6,9 @@ padding: 0 0 0 10px; } -.mat-input-element { +.mat-mdc-input-element { flex: 1; - height: 100%; - border: 0px solid transparent; - background: transparent; padding-left: 5px; - outline: none; -} - -.mat-input-element:focus { - outline: none; - border: 0px solid transparent; -} - -.mat-icon-button { - width: 24px; - height: 24px; - line-height: 24px; } .imx-search-image { diff --git a/imxweb/projects/qbm/src/lib/auto-complete/auto-complete.component.ts b/imxweb/projects/qbm/src/lib/auto-complete/auto-complete.component.ts index 89e2de604..12811beed 100644 --- a/imxweb/projects/qbm/src/lib/auto-complete/auto-complete.component.ts +++ b/imxweb/projects/qbm/src/lib/auto-complete/auto-complete.component.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -30,10 +30,9 @@ import { MatAutocompleteTrigger } from '@angular/material/autocomplete'; @Component({ selector: 'imx-auto-complete', templateUrl: './auto-complete.component.html', - styleUrls: ['./auto-complete.component.scss'] + styleUrls: ['./auto-complete.component.scss'], }) export class AutoCompleteComponent { - public filterText = ''; public filteredOptions: string[]; @@ -49,8 +48,7 @@ export class AutoCompleteComponent { } public filterOptions(): void { - this.filteredOptions = this.availableOptions - .filter(app => app.toLocaleLowerCase().includes(this.filterText.toLocaleLowerCase())); + this.filteredOptions = this.availableOptions.filter((app) => app.toLocaleLowerCase().includes(this.filterText.toLocaleLowerCase())); } public clearText(): void { @@ -58,5 +56,4 @@ export class AutoCompleteComponent { this.filterOptions(); this.EmitValueChangedEvent(); } - } diff --git a/imxweb/projects/qbm/src/lib/auto-complete/auto-complete.module.ts b/imxweb/projects/qbm/src/lib/auto-complete/auto-complete.module.ts index ea49479e5..93d2d73b0 100644 --- a/imxweb/projects/qbm/src/lib/auto-complete/auto-complete.module.ts +++ b/imxweb/projects/qbm/src/lib/auto-complete/auto-complete.module.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -34,17 +34,9 @@ import { EuiCoreModule } from '@elemental-ui/core'; import { AutoCompleteComponent } from './auto-complete.component'; - @NgModule({ declarations: [AutoCompleteComponent], - imports: [ - CommonModule, - FormsModule, - EuiCoreModule, - MatAutocompleteModule, - MatInputModule, - MatButtonModule - ], - exports: [AutoCompleteComponent] + imports: [CommonModule, FormsModule, EuiCoreModule, MatAutocompleteModule, MatInputModule, MatButtonModule], + exports: [AutoCompleteComponent], }) -export class AutoCompleteModule { } +export class AutoCompleteModule {} diff --git a/imxweb/projects/qbm/src/lib/base/Guid.ts b/imxweb/projects/qbm/src/lib/base/Guid.ts index 554fd2722..0de2fade0 100644 --- a/imxweb/projects/qbm/src/lib/base/Guid.ts +++ b/imxweb/projects/qbm/src/lib/base/Guid.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR diff --git a/imxweb/projects/qbm/src/lib/base/busy.service.ts b/imxweb/projects/qbm/src/lib/base/busy.service.ts index 16559eef5..25ff25dd0 100644 --- a/imxweb/projects/qbm/src/lib/base/busy.service.ts +++ b/imxweb/projects/qbm/src/lib/base/busy.service.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -24,7 +24,7 @@ * */ -import { EventEmitter, Injectable } from "@angular/core"; +import { EventEmitter, Injectable } from '@angular/core'; export interface Busy { endBusy: (forceEnd?: boolean) => void; @@ -37,9 +37,10 @@ export interface Busy { providedIn: 'root', }) export class BusyService { - /** Returns false if and only if there are no active busy sections. */ - public get isBusy() { return this.busyCounter > 0; } + public get isBusy() { + return this.busyCounter > 0; + } private busyCounter = 0; @@ -48,19 +49,16 @@ export class BusyService { */ beginBusy(): Busy { this.busyCounter++; - if (this.busyCounter >= 1) - this.busyStateChanged.emit(true); + if (this.busyCounter >= 1) this.busyStateChanged.emit(true); var isEnded = false; return { endBusy: (forceEnd?: boolean) => { // section can only be ended once. - if (isEnded) - return; + if (isEnded) return; isEnded = true; - this.busyCounter = forceEnd ? 0 : this.busyCounter-1; - if (this.busyCounter <= 0) - this.busyStateChanged.emit(false); - } + this.busyCounter = forceEnd ? 0 : this.busyCounter - 1; + if (this.busyCounter <= 0) this.busyStateChanged.emit(false); + }, }; } diff --git a/imxweb/projects/qbm/src/lib/temp-billboard/temp-billboard.module.ts b/imxweb/projects/qbm/src/lib/base/elemental-defaults.ts similarity index 58% rename from imxweb/projects/qbm/src/lib/temp-billboard/temp-billboard.module.ts rename to imxweb/projects/qbm/src/lib/base/elemental-defaults.ts index b07ba08d5..9eaa0c60d 100644 --- a/imxweb/projects/qbm/src/lib/temp-billboard/temp-billboard.module.ts +++ b/imxweb/projects/qbm/src/lib/base/elemental-defaults.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -24,19 +24,22 @@ * */ -import { NgModule } from '@angular/core'; -import { CommonModule } from '@angular/common'; -import { TempBillboardComponent } from './temp-billboard.component'; -import { TempBillboardService } from './temp-billboard.service'; -import { EuiCoreModule } from '@elemental-ui/core'; +import { MomentDateAdapter } from '@angular/material-moment-adapter'; +import { DateAdapter, MAT_DATE_FORMATS, MAT_DATE_LOCALE } from '@angular/material/core'; -/** - * @deprecated This will be removed with A15 support - */ -@NgModule({ - declarations: [TempBillboardComponent], - providers: [TempBillboardService], - imports: [CommonModule, EuiCoreModule], - exports: [TempBillboardComponent], -}) -export class TempBillboardModule {} +export const EUI_DATE_FORMATS = { + parse: { + dateInput: ['LL', 'L'], + }, + display: { + dateInput: 'LL', + monthYearLabel: 'MMM YYYY', + dateA11yLabel: 'LL', + monthYearA11yLabel: 'MMMM YYYY', + }, +}; + +export const EuiDateProviders = [ + { provide: DateAdapter, useClass: MomentDateAdapter, deps: [MAT_DATE_LOCALE] }, + { provide: MAT_DATE_FORMATS, useValue: EUI_DATE_FORMATS }, +]; diff --git a/imxweb/projects/qbm/src/lib/base/error.service.ts b/imxweb/projects/qbm/src/lib/base/error.service.ts index a9d3aa852..fc20fc997 100644 --- a/imxweb/projects/qbm/src/lib/base/error.service.ts +++ b/imxweb/projects/qbm/src/lib/base/error.service.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -24,16 +24,18 @@ * */ -import { Injectable } from "@angular/core"; +import { Injectable } from '@angular/core'; @Injectable({ - providedIn: 'root' + providedIn: 'root', }) export class ErrorService { private _target: string; /** Returns the current target for generated error messages. */ - public get target() { return this._target; } + public get target() { + return this._target; + } /** Sets a new target and returns a callback function that resets * the target to its previous value. @@ -44,10 +46,9 @@ export class ErrorService { var disposed = false; return () => { // only call once - if (disposed) - return; + if (disposed) return; disposed = true; this._target = previousTarget; }; } -} \ No newline at end of file +} diff --git a/imxweb/projects/qbm/src/lib/base/global-error-handler.ts b/imxweb/projects/qbm/src/lib/base/global-error-handler.ts index 09bf9aa4a..48dd3ceab 100644 --- a/imxweb/projects/qbm/src/lib/base/global-error-handler.ts +++ b/imxweb/projects/qbm/src/lib/base/global-error-handler.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -24,19 +24,24 @@ * */ +import { HttpErrorResponse } from '@angular/common/http'; import { ErrorHandler, Injectable, Injector } from '@angular/core'; -import { UserMessageService } from '../user-message/user-message.service'; import { ClassloggerService } from '../classlogger/classlogger.service'; -import { HttpErrorResponse } from '@angular/common/http'; +import { ConfirmationService } from '../confirmation/confirmation.service'; +import { UserMessageService } from '../user-message/user-message.service'; import { ErrorService } from './error.service'; @Injectable() export class GlobalErrorHandler implements ErrorHandler { private messageService: UserMessageService; private logger: ClassloggerService; + private confirm: ConfirmationService; - constructor(private injector: Injector, private readonly errorService: ErrorService) {} + constructor( + private injector: Injector, + private readonly errorService: ErrorService, + ) {} private get target() { return this.errorService.target; @@ -46,8 +51,16 @@ export class GlobalErrorHandler implements ErrorHandler { this.checkInjectedServices(); if (error instanceof HttpErrorResponse) { - this.handleHttpErrorResponse(error); + if (error.status !== 419) { + this.handleHttpErrorResponse(error); + } + } else if (error.name === 'AbortError') { + return; } else if (error instanceof Error) { + if (error.message != null && error.message.indexOf('57002006') !== -1) { + this.handleSessionExpired(); + return; + } if (error.message != null && error.message.indexOf('\n') !== -1) { this.messageService.subject.next({ text: error.message.substring(0, error.message.indexOf('\n')).replace('Uncaught (in promise):', ''), @@ -111,5 +124,13 @@ export class GlobalErrorHandler implements ErrorHandler { if (this.logger == null) { this.logger = this.injector.get(ClassloggerService); } + + if (this.confirm == null) { + this.confirm = this.injector.get(ConfirmationService); + } + } + + private handleSessionExpired(): void { + this.confirm.handleExpiredSession(); } } diff --git a/imxweb/projects/qbm/src/lib/base/ie-warning.service.ts b/imxweb/projects/qbm/src/lib/base/ie-warning.service.ts index 8cf40534f..11c342d5f 100644 --- a/imxweb/projects/qbm/src/lib/base/ie-warning.service.ts +++ b/imxweb/projects/qbm/src/lib/base/ie-warning.service.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -41,7 +41,7 @@ export class IeWarningService { private readonly alertBanner: EuiAlertBannerService, private readonly translate: TranslateService, private readonly ldsReplace: LdsReplacePipe, - private readonly mastHeadService: MastHeadService + private readonly mastHeadService: MastHeadService, ) {} public async showIe11Banner(): Promise { @@ -58,10 +58,10 @@ export class IeWarningService { message: this.ldsReplace.transform( await this.translate .get( - '#LDS#Internet Explorer is no longer supported and the application may not work properly. Please use a browser from the following list: {0}.' + '#LDS#Internet Explorer is no longer supported and the application may not work properly. Please use a browser from the following list: {0}.', ) .toPromise(), - docLink + docLink, ), }); this.alertBanner.userDismissed.subscribe(() => this.storageService.storeHelperAlertDismissal(alertKey)); diff --git a/imxweb/projects/qbm/src/lib/base/metadata.service.ts b/imxweb/projects/qbm/src/lib/base/metadata.service.ts index 4e5cb4a93..dffeaa003 100644 --- a/imxweb/projects/qbm/src/lib/base/metadata.service.ts +++ b/imxweb/projects/qbm/src/lib/base/metadata.service.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -24,61 +24,85 @@ * */ -import { Injectable } from '@angular/core'; -import { TranslateService } from '@ngx-translate/core'; - -import { MetaTableData } from 'imx-api-qbm'; -import { imx_SessionService } from '../session/imx-session.service'; +import { Injectable, OnDestroy } from '@angular/core'; +import { MetaTableData } from '@imx-modules/imx-qbm-dbts'; +/** + * Abstract implementation for getting portal specific metadata. + */ @Injectable({ providedIn: 'root', }) -export class MetadataService { - public readonly tables: { [id: string]: MetaTableData } = {}; +export abstract class MetadataService implements OnDestroy { + public readonly tables: { [id: string]: MetaTableData | undefined } = {}; + protected abortController: AbortController; + + /** + * @deprecated use tables instead + */ + private tableMetadata: { [id: string]: MetaTableData | undefined } = {}; + + constructor() { + this.abortController = new AbortController(); + } + + ngOnDestroy(): void { + this.abortCall(); + } /** - * @deprecated Use tables instead. + * Fetches table metadata. Applications will provide authentication / methods to use. + * @param tableName The name of the table to fetch data for + * @param options Additional api options */ - private tableMetadata: { [id: string]: MetaTableData } = {}; + protected abstract getTable(tableName: string, options?: unknown): Promise; - constructor( - private sessionService: imx_SessionService, - private readonly translateService: TranslateService, - ) {} + /** + * Handles aborting any current requests managed by this service. + */ + public abortCall() { + this.abortController.abort(); + this.abortController = new AbortController(); + } /** - * Updates meta data for the tables of the provided table names that are not already present in the tables map - * @param tableName The names of the tables to update + * Fetches and updates metadata for the tables of the provided table names that are not already present in the tables map + * @param tableNames The names of the tables to update + * @param options Additional api options */ - public async updateNonExisting(tableNames: string[]): Promise { + public async updateNonExisting(tableNames: string[], options?: unknown): Promise { // Use a Set to obtain unique values const uniqueSet = Array.from(new Set(tableNames.filter((tableName) => this.tables[tableName] == null))); - return this.update(uniqueSet); + return this.update(uniqueSet, options); } /** - * Updates meta data for the tables of the provided table names - * @param tableName The names of the tables to update + * Fetches and updates metadata for the tables of the provided table names + * @param tableNames The names of the tables to update + * @param options Additional api options */ - public async update(tableNames: string[]): Promise { + public async update(tableNames: string[], options?: unknown): Promise { for (const tableName of tableNames) { - this.tables[tableName] = await this.sessionService.Client.imx_metadata_table_get(tableName, { - cultureName: this.translateService.currentLang, - }); + const metaTableData = await this.getTable(tableName, options); + if (metaTableData) { + this.tables[tableName] = metaTableData; + } } } /** * @deprecated Use use the method update and the property tables instead. Will be removed. - * @param table The name of the table to update and get metadata for + * @param tableName The name of the table to update and get metadata for + * @param options Additional api options */ - public async GetTableMetadata(table: string): Promise { - if (this.tableMetadata[table] == null) { - this.tableMetadata[table] = await this.sessionService.Client.imx_metadata_table_get(table, { - cultureName: this.translateService.currentLang, - }); + public async GetTableMetadata(tableName: string, options?: unknown): Promise { + if (this.tableMetadata[tableName] == null) { + const metaTableData = await this.getTable(tableName, options); + if (metaTableData) { + this.tableMetadata[tableName] = metaTableData; + } } - return this.tableMetadata[table]; + return this.tableMetadata[tableName]; } } diff --git a/imxweb/projects/qbm/src/lib/base/opsupport-db-object.service.ts b/imxweb/projects/qbm/src/lib/base/opsupport-db-object.service.ts index df0045a0f..b1bffad09 100644 --- a/imxweb/projects/qbm/src/lib/base/opsupport-db-object.service.ts +++ b/imxweb/projects/qbm/src/lib/base/opsupport-db-object.service.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -26,7 +26,7 @@ import { Injectable } from '@angular/core'; -import { EntityData } from 'imx-qbm-dbts'; +import { EntityData } from '@imx-modules/imx-qbm-dbts'; import { imx_SessionService } from '../session/imx-session.service'; export interface OpsupportDbObjectParameters { diff --git a/imxweb/projects/qbm/src/lib/base/paginator.spec.ts b/imxweb/projects/qbm/src/lib/base/paginator.spec.ts index 3be77a6ee..73c63b6c6 100644 --- a/imxweb/projects/qbm/src/lib/base/paginator.spec.ts +++ b/imxweb/projects/qbm/src/lib/base/paginator.spec.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -32,9 +32,9 @@ import { LdsReplacePipe } from '../lds-replace/lds-replace.pipe'; import { clearStylesFromDOM } from '../testing/clear-styles.spec'; export class TranslateServiceStub { - public get(key: any): any { - return of(key); - } + public get(key: any): any { + return of(key); + } } describe('Paginator', () => { @@ -51,38 +51,48 @@ describe('Paginator', () => { [ { - page: 0, pageSize: 0, length: 1, + page: 0, + pageSize: 0, + length: 1, expected: [ { index: 0, value: '0' }, - { index: 2, value: '1' } - ] + { index: 2, value: '1' }, + ], }, { - page: 0, pageSize: 1, length: 0, + page: 0, + pageSize: 1, + length: 0, expected: [ { index: 0, value: '0' }, - { index: 2, value: '0' } - ] + { index: 2, value: '0' }, + ], }, { - page: 0, pageSize: 1, length: 2, + page: 0, + pageSize: 1, + length: 2, expected: [ { index: 0, value: '1' }, { index: 2, value: '1' }, - { index: 4, value: '2' } - ] + { index: 4, value: '2' }, + ], }, { - page: 2, pageSize: 1, length: 2, + page: 2, + pageSize: 1, + length: 2, expected: [ { index: 0, value: '3' }, { index: 2, value: '3' }, - { index: 4, value: '2' } - ] - } - ].forEach(testcase => it('displays correct page info', () => { - const paginator = Paginator.Create(translationService, mockLdsReplacePipe); - const rangelabelTokens = paginator.getRangeLabel(testcase.page, testcase.pageSize, testcase.length).replace('#LDS#', '').split(' '); - testcase.expected.forEach(result => expect(rangelabelTokens[result.index]).toEqual(result.value)); - })); + { index: 4, value: '2' }, + ], + }, + ].forEach((testcase) => + it('displays correct page info', () => { + const paginator = Paginator.Create(translationService, mockLdsReplacePipe); + const rangelabelTokens = paginator.getRangeLabel(testcase.page, testcase.pageSize, testcase.length).replace('#LDS#', '').split(' '); + testcase.expected.forEach((result) => expect(rangelabelTokens[result.index]).toEqual(result.value)); + }), + ); }); diff --git a/imxweb/projects/qbm/src/lib/base/paginator.ts b/imxweb/projects/qbm/src/lib/base/paginator.ts index 8a0470726..92c055cd4 100644 --- a/imxweb/projects/qbm/src/lib/base/paginator.ts +++ b/imxweb/projects/qbm/src/lib/base/paginator.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -30,33 +30,36 @@ import { TranslateService } from '@ngx-translate/core'; import { LdsReplacePipe } from '../lds-replace/lds-replace.pipe'; export class Paginator extends MatPaginatorIntl { - private rangeText = ''; - private rangeTextFallback = ''; - - private constructor(private translateService: TranslateService, private readonly ldsReplace: LdsReplacePipe) { - super(); - this.translateService.get('#LDS#Entries per page').subscribe((text: string) => this.itemsPerPageLabel = text + ':'); - this.translateService.get('#LDS#First page').subscribe((text: string) => this.firstPageLabel = text); - this.translateService.get('#LDS#Previous page').subscribe((text: string) => this.previousPageLabel = text); - this.translateService.get('#LDS#Next page').subscribe((text: string) => this.nextPageLabel = text); - this.translateService.get('#LDS#Last page').subscribe((text: string) => this.lastPageLabel = text); - this.translateService.get('#LDS#{0} - {1} of {2}').subscribe((text: string) => this.rangeText = text); - this.translateService.get('#LDS#0 of {0}').subscribe((text: string) => this.rangeTextFallback = text); - this.getRangeLabel = (page: number, pageSize: number, length: number) => { - length = Math.max(length, 0); - - if (length === 0 || pageSize === 0) { - return this.ldsReplace.transform(this.rangeTextFallback, length); - } - - const startIndex = page * pageSize; - const endIndex = startIndex < length ? Math.min(startIndex + pageSize, length) : startIndex + pageSize; - - return this.ldsReplace.transform(this.rangeText, startIndex + 1, endIndex, length); - }; - } - - public static Create(translateService: TranslateService, ldsReplace: LdsReplacePipe): Paginator { - return new Paginator(translateService, ldsReplace); - } + private rangeText = ''; + private rangeTextFallback = ''; + + private constructor( + private translateService: TranslateService, + private readonly ldsReplace: LdsReplacePipe, + ) { + super(); + this.translateService.get('#LDS#Entries per page').subscribe((text: string) => (this.itemsPerPageLabel = text + ':')); + this.translateService.get('#LDS#First page').subscribe((text: string) => (this.firstPageLabel = text)); + this.translateService.get('#LDS#Previous page').subscribe((text: string) => (this.previousPageLabel = text)); + this.translateService.get('#LDS#Next page').subscribe((text: string) => (this.nextPageLabel = text)); + this.translateService.get('#LDS#Last page').subscribe((text: string) => (this.lastPageLabel = text)); + this.translateService.get('#LDS#{0} - {1} of {2}').subscribe((text: string) => (this.rangeText = text)); + this.translateService.get('#LDS#0 of {0}').subscribe((text: string) => (this.rangeTextFallback = text)); + this.getRangeLabel = (page: number, pageSize: number, length: number) => { + length = Math.max(length, 0); + + if (length === 0 || pageSize === 0) { + return this.ldsReplace.transform(this.rangeTextFallback, length); + } + + const startIndex = page * pageSize; + const endIndex = startIndex < length ? Math.min(startIndex + pageSize, length) : startIndex + pageSize; + + return this.ldsReplace.transform(this.rangeText, startIndex + 1, endIndex, length); + }; + } + + public static Create(translateService: TranslateService, ldsReplace: LdsReplacePipe): Paginator { + return new Paginator(translateService, ldsReplace); + } } diff --git a/imxweb/projects/qbm/src/lib/base/qbm-sqlwizard.service.ts b/imxweb/projects/qbm/src/lib/base/qbm-sqlwizard.service.ts index 6f8015d14..c85787f3f 100644 --- a/imxweb/projects/qbm/src/lib/base/qbm-sqlwizard.service.ts +++ b/imxweb/projects/qbm/src/lib/base/qbm-sqlwizard.service.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -25,7 +25,7 @@ */ import { Injectable } from '@angular/core'; -import { FilterProperty, CollectionLoadParameters, EntityCollectionData } from 'imx-qbm-dbts'; +import { FilterProperty, CollectionLoadParameters, EntityCollectionData } from '@imx-modules/imx-qbm-dbts'; import { SqlWizardApiService } from '../sqlwizard/sqlwizard-api.service'; @Injectable({ diff --git a/imxweb/projects/qbm/src/lib/base/query-parameters-handler.spec.ts b/imxweb/projects/qbm/src/lib/base/query-parameters-handler.spec.ts index a23b0343d..636bf6e9e 100644 --- a/imxweb/projects/qbm/src/lib/base/query-parameters-handler.spec.ts +++ b/imxweb/projects/qbm/src/lib/base/query-parameters-handler.spec.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -24,28 +24,16 @@ * */ +import { ActivatedRouteSnapshot } from '@angular/router'; -import { ActivatedRouteSnapshot, ParamMap } from '@angular/router'; -import * as TypeMoq from 'typemoq'; - -import { QueryParametersHandler } from './query-parameters-handler'; import { clearStylesFromDOM } from '../testing/clear-styles.spec'; +import { QueryParametersHandler } from './query-parameters-handler'; -function CreateActiveRouteSnapshot(queryParams: { [key: string]: any }): ActivatedRouteSnapshot { - const mock = TypeMoq.Mock.ofType(); - mock - .setup(item => item.queryParamMap) - .returns(() => { - const mockParamMap = TypeMoq.Mock.ofType(); - mockParamMap.setup(item => item.keys).returns(() => Object.keys(queryParams)); - mockParamMap.setup(item => item.get(TypeMoq.It.isAnyString())).returns((key: string) => queryParams[key]); - return mockParamMap.object; - }); - return mock.object; +function CreateActiveRouteSnapshot(queryParams: { [key: string]: string }): ActivatedRouteSnapshot { + return { queryParamMap: { keys: Object.keys(queryParams), get: (key: string) => queryParams[key] } } as unknown as ActivatedRouteSnapshot; } describe('QueryParametersHandler', () => { - afterAll(() => { clearStylesFromDOM(); }); @@ -53,39 +41,39 @@ describe('QueryParametersHandler', () => { [ { search: '', - expected: undefined + expected: undefined, }, { search: '?', - expected: undefined + expected: undefined, }, { search: '?a', - expected: { 'a': '' } + expected: { a: '' }, }, { search: '?a=1', - expected: { 'a': '1' } + expected: { a: '1' }, }, { search: '?a=1&b=2', - expected: { 'a': '1', 'b': '2' } + expected: { a: '1', b: '2' }, }, { search: '?a=1&b=2', - route: CreateActiveRouteSnapshot({ 'c': '3' }), - expected: { 'a': '1', 'b': '2', 'c': '3' } + route: CreateActiveRouteSnapshot({ c: '3' }), + expected: { a: '1', b: '2', c: '3' }, }, { search: '?a=1&b=2', - route: CreateActiveRouteSnapshot({ 'c': '3' }), + route: CreateActiveRouteSnapshot({ c: '3' }), filter: (key: string) => key === 'c', - expected: { 'c': '3' } - } - ].forEach(testcase => + expected: { c: '3' }, + }, + ].forEach((testcase) => it('can parse querystrings correctly', () => { const handler = new QueryParametersHandler(testcase.search, testcase.route); expect(handler.GetQueryParameters(testcase.filter)).toEqual(testcase.expected); - }) + }), ); }); diff --git a/imxweb/projects/qbm/src/lib/base/query-parameters-handler.ts b/imxweb/projects/qbm/src/lib/base/query-parameters-handler.ts index e8eb459ec..e3196a198 100644 --- a/imxweb/projects/qbm/src/lib/base/query-parameters-handler.ts +++ b/imxweb/projects/qbm/src/lib/base/query-parameters-handler.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -24,16 +24,22 @@ * */ -import { ActivatedRouteSnapshot, ParamMap, DefaultUrlSerializer } from '@angular/router'; +import { ActivatedRouteSnapshot, DefaultUrlSerializer, ParamMap } from '@angular/router'; export class QueryParametersHandler { - public get path(): string { return this.lastPath || this.route?.routeConfig?.path; } + public get path(): string { + return this.lastPath || (this.route?.routeConfig?.path ?? ''); + } private readonly urlSerializer = new DefaultUrlSerializer(); private readonly queryParametersCollection: ParamMap[] = []; private readonly lastPath: string; - constructor(search?: string, private readonly route?: ActivatedRouteSnapshot, lastUrl?: string) { + constructor( + search?: string, + private readonly route?: ActivatedRouteSnapshot, + lastUrl?: string, + ) { if (lastUrl) { const lastLocation = lastUrl.split('?'); @@ -50,12 +56,12 @@ export class QueryParametersHandler { } } - public GetQueryParameters(filter: (name: string) => boolean = null): { [key: string]: any } { + public GetQueryParameters(filter: (name: string) => boolean = null as any): { [key: string]: any } | undefined { const outparams: { [id: string]: any } = {}; - this.queryParametersCollection.forEach(params => { + this.queryParametersCollection.forEach((params) => { if (params.keys) { params.keys - .filter(name => filter == null || filter(name)) + .filter((name) => filter == null || filter(name)) .forEach((name: string) => { outparams[name] = params.get(name); }); diff --git a/imxweb/projects/qbm/src/lib/base/registry.service.ts b/imxweb/projects/qbm/src/lib/base/registry.service.ts index 4a4570e68..92709d2a8 100644 --- a/imxweb/projects/qbm/src/lib/base/registry.service.ts +++ b/imxweb/projects/qbm/src/lib/base/registry.service.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -28,10 +28,11 @@ import { Injectable } from '@angular/core'; @Injectable() export class RegistryService { + public get Registry(): { [id: string]: T[] } { + return this.registry; + } - public get Registry(): { [id: string]: T[]; } { return this.registry; } - - private registry: { [id: string]: T[]; } = {}; + private registry: { [id: string]: T[] } = {}; public register(key: string, obj: T): void { if (!this.registry[key]) { @@ -39,5 +40,4 @@ export class RegistryService { } this.registry[key].push(obj); } - } diff --git a/imxweb/projects/qbm/src/lib/base/server-error.ts b/imxweb/projects/qbm/src/lib/base/server-error.ts index 06b837e04..ce9c2d6ab 100644 --- a/imxweb/projects/qbm/src/lib/base/server-error.ts +++ b/imxweb/projects/qbm/src/lib/base/server-error.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -24,15 +24,15 @@ * */ -import { MethodDescriptor } from 'imx-qbm-dbts'; +import { MethodDescriptor } from '@imx-modules/imx-qbm-dbts'; export class ServerError extends Error { - protected messageUserFriendly: string; + protected messageUserFriendly: string; - constructor(message: string, endpoint?: MethodDescriptor) { - super(message + (endpoint ? '\n' + JSON.stringify(endpoint) : '')); - this.messageUserFriendly = message; - } + constructor(message: string, endpoint?: MethodDescriptor) { + super(message + (endpoint ? '\n' + JSON.stringify(endpoint) : '')); + this.messageUserFriendly = message; + } - public toString = (): string => this.messageUserFriendly; + public toString = (): string => this.messageUserFriendly; } diff --git a/imxweb/projects/qbm/src/lib/base/server-exception-error.ts b/imxweb/projects/qbm/src/lib/base/server-exception-error.ts index 7b17ea5b3..fb77b2b6b 100644 --- a/imxweb/projects/qbm/src/lib/base/server-exception-error.ts +++ b/imxweb/projects/qbm/src/lib/base/server-exception-error.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -24,25 +24,25 @@ * */ -import { ExceptionData } from 'imx-api-qbm'; +import { ExceptionData } from '@imx-modules/imx-api-qbm'; import { ServerError } from './server-error'; export class ServerExceptionError extends ServerError { - constructor(private readonly dataItems: ExceptionData[]) { - super(ServerExceptionError.parse(dataItems)); + constructor(private readonly dataItems: ExceptionData[]) { + super(ServerExceptionError.parse(dataItems)); - this.messageUserFriendly = ServerExceptionError.parse(this.dataItems, true); - } - - private static parse(dataItems: ExceptionData[], userFriendly: boolean = false): string { - if (dataItems && dataItems.length > 0) { - if (userFriendly) { - return dataItems.map(item => `${item.Message}${item.Number ? ` [${item.Number}]` : ''}`).join(', '); - } + this.messageUserFriendly = ServerExceptionError.parse(this.dataItems, true); + } - return JSON.stringify(dataItems); - } + private static parse(dataItems: ExceptionData[], userFriendly: boolean = false): string { + if (dataItems && dataItems.length > 0) { + if (userFriendly) { + return dataItems.map((item) => `${item.Message}${item.Number ? ` [${item.Number}]` : ''}`).join(', '); + } - return 'Unknown error'; + return JSON.stringify(dataItems); } + + return 'Unknown error'; + } } diff --git a/imxweb/projects/qbm/src/lib/menu/menu-item/group-menu-item.ts b/imxweb/projects/qbm/src/lib/base/sidesheet-helper.ts similarity index 59% rename from imxweb/projects/qbm/src/lib/menu/menu-item/group-menu-item.ts rename to imxweb/projects/qbm/src/lib/base/sidesheet-helper.ts index c55d6b6dc..cc32be51e 100644 --- a/imxweb/projects/qbm/src/lib/menu/menu-item/group-menu-item.ts +++ b/imxweb/projects/qbm/src/lib/base/sidesheet-helper.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -24,11 +24,20 @@ * */ -import { MenuItem } from './menu-item.interface'; +/** + * Calculates the sidesheet width. + * @param pixelWidth + * @param percentageWidth + * @returns The calculated sidesheet width in pixel. + */ +export function calculateSidesheetWidth(pixelWidth: number = 900, percentageWidth: number = 0.6): string { + const calculatedWidth = document.body.offsetWidth * percentageWidth; + return `${Math.max(pixelWidth, calculatedWidth)}px`; +} -/** Represents a menu item that acts as a container for its child items, - * without having any associated actions. +/** + * Checks the width of the document body is lower than 768px. */ -export class GroupMenuItem implements MenuItem { - constructor(public readonly id: string, public readonly title: string, public readonly items: MenuItem[]) {} +export function isMobile(): boolean { + return document.body.offsetWidth <= 768; } diff --git a/imxweb/projects/qbm/src/lib/base/timezone-info.spec.ts b/imxweb/projects/qbm/src/lib/base/timezone-info.spec.ts index 8634a96f6..79809903b 100644 --- a/imxweb/projects/qbm/src/lib/base/timezone-info.spec.ts +++ b/imxweb/projects/qbm/src/lib/base/timezone-info.spec.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -28,7 +28,6 @@ import { TimezoneInfo } from './timezone-info'; import { clearStylesFromDOM } from '../testing/clear-styles.spec'; describe('TimezoneInfo', () => { - afterAll(() => { clearStylesFromDOM(); }); @@ -40,10 +39,8 @@ describe('TimezoneInfo', () => { }); it('should be created', () => { - expect(() => { const timezoneInfo = TimezoneInfo.get(); }).not.toThrowError(); - }); }); diff --git a/imxweb/projects/qbm/src/lib/base/timezone-info.ts b/imxweb/projects/qbm/src/lib/base/timezone-info.ts index 277d54514..b0184fac4 100644 --- a/imxweb/projects/qbm/src/lib/base/timezone-info.ts +++ b/imxweb/projects/qbm/src/lib/base/timezone-info.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -25,49 +25,40 @@ */ export class TimezoneInfo { + public static get(): string { + const year = 2015; // Falls die Uhrzeit auf dem Client mal überhaupt nicht stimmt. + let lastDate = null; + let curTestDate: Date; + let lastUtcOffset = 0; + let curUtcOffset: number; + let dayLightChanges = ''; + let countDayLightChanges = 0; - public static get(): string { - const year = 2015; // Falls die Uhrzeit auf dem Client mal überhaupt nicht stimmt. - let lastDate = null; - let curTestDate: Date; - let lastUtcOffset = 0; - let curUtcOffset: number; - let dayLightChanges = ''; - let countDayLightChanges = 0; + // alle Tage des aktuellen Jahres prüfen, + for (let month = 0; month < 12 && countDayLightChanges < 2; month++) { + for (let day = 1; day <= 31 && countDayLightChanges < 2; day++) { + curTestDate = new Date(Date.UTC(year, month, day, 0, 0, 0, 0)); - // alle Tage des aktuellen Jahres prüfen, - for (let month = 0; month < 12 && countDayLightChanges < 2; month++) { - for (let day = 1; day <= 31 && countDayLightChanges < 2; day++) { - curTestDate = new Date(Date.UTC(year, month, day, 0, 0, 0, 0)); - - // man kann den 31 Februar definieren, dann kommt automatisch der 3 März heraus - // deshalb ignorieren, wenn der Monatstag abweicht - if (curTestDate.getUTCDate() !== day) { - continue; - } - - curUtcOffset = curTestDate.getTimezoneOffset() * -1; + // man kann den 31 Februar definieren, dann kommt automatisch der 3 März heraus + // deshalb ignorieren, wenn der Monatstag abweicht + if (curTestDate.getUTCDate() !== day) { + continue; + } - if (lastDate != null && curUtcOffset !== lastUtcOffset) { - dayLightChanges += year + - ',' + - (lastDate.getUTCMonth() + 1) + - ',' + - lastDate.getUTCDate() + - ',' + - lastUtcOffset + - ',' + - curUtcOffset + - ';'; - countDayLightChanges++; - } + curUtcOffset = curTestDate.getTimezoneOffset() * -1; - lastDate = curTestDate; - lastUtcOffset = curUtcOffset; - } + if (lastDate != null && curUtcOffset !== lastUtcOffset) { + dayLightChanges += + year + ',' + (lastDate.getUTCMonth() + 1) + ',' + lastDate.getUTCDate() + ',' + lastUtcOffset + ',' + curUtcOffset + ';'; + countDayLightChanges++; } - // wenn es keine Sommer-/ Winterzeit gibt, dann nur das UTC Offset merken - return dayLightChanges === '' ? lastUtcOffset + '' : dayLightChanges; + lastDate = curTestDate; + lastUtcOffset = curUtcOffset; + } } + + // wenn es keine Sommer-/ Winterzeit gibt, dann nur das UTC Offset merken + return dayLightChanges === '' ? lastUtcOffset + '' : dayLightChanges; + } } diff --git a/imxweb/projects/qbm/src/lib/base/user-action.service.ts b/imxweb/projects/qbm/src/lib/base/user-action.service.ts index e6814c778..a6ff93561 100644 --- a/imxweb/projects/qbm/src/lib/base/user-action.service.ts +++ b/imxweb/projects/qbm/src/lib/base/user-action.service.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR diff --git a/imxweb/projects/qbm/src/lib/base/user-agent-helper.ts b/imxweb/projects/qbm/src/lib/base/user-agent-helper.ts index 3fe810041..35eef9b93 100644 --- a/imxweb/projects/qbm/src/lib/base/user-agent-helper.ts +++ b/imxweb/projects/qbm/src/lib/base/user-agent-helper.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR diff --git a/imxweb/projects/qbm/src/lib/bulk-property-editor/bulk-item/bulk-item-icon.ts b/imxweb/projects/qbm/src/lib/bulk-property-editor/bulk-item/bulk-item-icon.ts index f9979200c..d402f38b7 100644 --- a/imxweb/projects/qbm/src/lib/bulk-property-editor/bulk-item/bulk-item-icon.ts +++ b/imxweb/projects/qbm/src/lib/bulk-property-editor/bulk-item/bulk-item-icon.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR diff --git a/imxweb/projects/qbm/src/lib/bulk-property-editor/bulk-item/bulk-item.component.html b/imxweb/projects/qbm/src/lib/bulk-property-editor/bulk-item/bulk-item.component.html index a9129f5f4..d4d027998 100644 --- a/imxweb/projects/qbm/src/lib/bulk-property-editor/bulk-item/bulk-item.component.html +++ b/imxweb/projects/qbm/src/lib/bulk-property-editor/bulk-item/bulk-item.component.html @@ -1,36 +1,53 @@ - + - - + + {{ bulkItem?.customTitle || bulkItem?.entity?.GetEntity()?.GetDisplay() }} - + {{ bulkItem?.additionalInfo }}

    {{ bulkItem?.description }}
    - + [attr.data-imx-identifier]="'bulk-item' + cdr.column.ColumnName + '_' + i" + > - + [attr.data-imx-identifier]="'bulk-item-custom-select-option-' + i" + >
    - - + +
    diff --git a/imxweb/projects/qbm/src/lib/bulk-property-editor/bulk-item/bulk-item.component.scss b/imxweb/projects/qbm/src/lib/bulk-property-editor/bulk-item/bulk-item.component.scss index 0c9f3f288..518edff47 100644 --- a/imxweb/projects/qbm/src/lib/bulk-property-editor/bulk-item/bulk-item.component.scss +++ b/imxweb/projects/qbm/src/lib/bulk-property-editor/bulk-item/bulk-item.component.scss @@ -1,36 +1,9 @@ @import '@elemental-ui/core/src/styles/_palette.scss'; -eui-icon { - color: $aspen-green; -} - button { margin-left: 10px; } -.mat-expansion-panel { - margin-bottom: 20px; - margin-top: 20px; -} - -.mat-expansion-panel-header-description { - justify-content: end; -} - -.mat-expansion-panel-header { - min-height: 24px; - height: auto; - padding: 12px 24px; -} - -.mat-expansion-panel-header-title { - flex-basis: auto; -} - -.mat-expansion-panel-header-description, .mat-expansion-panel-header-title { - align-items: center; -} - .imx-custom-property { margin-bottom: 20px; } @@ -44,10 +17,14 @@ button { margin-bottom: 10px; } -.imx-panel-icon { +.imx-icon-new { margin-right: 10px; } .imx-madatory-item { color: $corbin-orange; } + +.imx-bulk-item-description { + flex: initial; +} diff --git a/imxweb/projects/qbm/src/lib/bulk-property-editor/bulk-item/bulk-item.component.ts b/imxweb/projects/qbm/src/lib/bulk-property-editor/bulk-item/bulk-item.component.ts index 092185e0b..c569e9aa6 100644 --- a/imxweb/projects/qbm/src/lib/bulk-property-editor/bulk-item/bulk-item.component.ts +++ b/imxweb/projects/qbm/src/lib/bulk-property-editor/bulk-item/bulk-item.component.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -28,11 +28,11 @@ import { Component, EventEmitter, Input, OnInit, Output, QueryList, ViewChild, V import { AbstractControl, UntypedFormGroup } from '@angular/forms'; import { MatExpansionPanel } from '@angular/material/expansion'; +import { EntityWriteDataSingle } from '@imx-modules/imx-qbm-dbts'; +import { isEqual } from 'lodash'; +import { CdrEditorComponent } from '../../cdr/cdr-editor/cdr-editor.component'; import { BulkItem, BulkItemStatus } from './bulk-item'; import { BulkItemIcon } from './bulk-item-icon'; -import { CdrEditorComponent } from '../../cdr/cdr-editor/cdr-editor.component'; -import { isEqual } from 'lodash'; -import { EntityWriteDataSingle } from 'imx-qbm-dbts'; @Component({ selector: 'imx-bulk-item', diff --git a/imxweb/projects/qbm/src/lib/bulk-property-editor/bulk-item/bulk-item.ts b/imxweb/projects/qbm/src/lib/bulk-property-editor/bulk-item/bulk-item.ts index 5695d3551..905993b2c 100644 --- a/imxweb/projects/qbm/src/lib/bulk-property-editor/bulk-item/bulk-item.ts +++ b/imxweb/projects/qbm/src/lib/bulk-property-editor/bulk-item/bulk-item.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -24,7 +24,7 @@ * */ -import { TypedEntity } from 'imx-qbm-dbts'; +import { TypedEntity } from '@imx-modules/imx-qbm-dbts'; import { ColumnDependentReference } from '../../cdr/column-dependent-reference.interface'; import { EntitySelect } from '../../entity/entity-select/entity-select.interface'; @@ -33,7 +33,7 @@ export enum BulkItemStatus { saved, skipped, error, - valid + valid, } export interface BulkItem { diff --git a/imxweb/projects/qbm/src/lib/bulk-property-editor/bulk-property-editor.component.html b/imxweb/projects/qbm/src/lib/bulk-property-editor/bulk-property-editor.component.html index 57b8b982e..23ea4cdf3 100644 --- a/imxweb/projects/qbm/src/lib/bulk-property-editor/bulk-property-editor.component.html +++ b/imxweb/projects/qbm/src/lib/bulk-property-editor/bulk-property-editor.component.html @@ -1,13 +1,15 @@
    - + (controlCreated)="formGroup.addControl('bulk-item' + i, $event)" + >
    diff --git a/imxweb/projects/qbm/src/lib/bulk-property-editor/bulk-property-editor.component.scss b/imxweb/projects/qbm/src/lib/bulk-property-editor/bulk-property-editor.component.scss index dd3e7eb0a..90d4ee007 100644 --- a/imxweb/projects/qbm/src/lib/bulk-property-editor/bulk-property-editor.component.scss +++ b/imxweb/projects/qbm/src/lib/bulk-property-editor/bulk-property-editor.component.scss @@ -1,2 +1 @@ /* You can add global styles to this file, and also import other style files */ - diff --git a/imxweb/projects/qbm/src/lib/bulk-property-editor/bulk-property-editor.component.ts b/imxweb/projects/qbm/src/lib/bulk-property-editor/bulk-property-editor.component.ts index 64031b93f..e523ddcbd 100644 --- a/imxweb/projects/qbm/src/lib/bulk-property-editor/bulk-property-editor.component.ts +++ b/imxweb/projects/qbm/src/lib/bulk-property-editor/bulk-property-editor.component.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -33,7 +33,7 @@ import { BulkItemComponent } from './bulk-item/bulk-item.component'; @Component({ selector: 'imx-bulk-editor', templateUrl: './bulk-property-editor.component.html', - styleUrls: ['./bulk-property-editor.component.scss'] + styleUrls: ['./bulk-property-editor.component.scss'], }) export class BulkPropertyEditorComponent implements OnInit { public formGroup = new UntypedFormGroup({}); @@ -50,8 +50,8 @@ export class BulkPropertyEditorComponent implements OnInit { public ngOnInit(): void { this.entities.sort((a, b) => { - let typeA = a.properties.every(p => p.isReadOnly()); - let typeB = b.properties.every(p => p.isReadOnly()); + let typeA = a.properties.every((p) => p.isReadOnly()); + let typeB = b.properties.every((p) => p.isReadOnly()); if (typeA && typeB) { return 0; @@ -61,8 +61,8 @@ export class BulkPropertyEditorComponent implements OnInit { return 1; } - typeA = a.properties.some(p => p.column.GetMetadata().GetMinLength() > 0); - typeB = b.properties.some(p => p.column.GetMetadata().GetMinLength() > 0); + typeA = a.properties.some((p) => p.column.GetMetadata().GetMinLength() > 0); + typeB = b.properties.some((p) => p.column.GetMetadata().GetMinLength() > 0); if (typeA && typeB) { return 0; diff --git a/imxweb/projects/qbm/src/lib/bulk-property-editor/bulk-property-editor.module.ts b/imxweb/projects/qbm/src/lib/bulk-property-editor/bulk-property-editor.module.ts index 8ce22e233..aaace196b 100644 --- a/imxweb/projects/qbm/src/lib/bulk-property-editor/bulk-property-editor.module.ts +++ b/imxweb/projects/qbm/src/lib/bulk-property-editor/bulk-property-editor.module.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -56,8 +56,8 @@ import { BulkPropertyEditorComponent } from './bulk-property-editor.component'; MatCardModule, ReactiveFormsModule, TranslateModule, - EntityModule + EntityModule, ], - exports: [BulkPropertyEditorComponent] + exports: [BulkPropertyEditorComponent], }) -export class BulkPropertyEditorModule { } +export class BulkPropertyEditorModule {} diff --git a/imxweb/projects/qbm/src/lib/busy-indicator/busy-indicator.component.html b/imxweb/projects/qbm/src/lib/busy-indicator/busy-indicator.component.html index a7c8a3e09..5340bb296 100644 --- a/imxweb/projects/qbm/src/lib/busy-indicator/busy-indicator.component.html +++ b/imxweb/projects/qbm/src/lib/busy-indicator/busy-indicator.component.html @@ -1,4 +1,4 @@
    {{ '#LDS#Loading...' | translate }}
    -
    \ No newline at end of file +
    diff --git a/imxweb/projects/qbm/src/lib/busy-indicator/busy-indicator.component.scss b/imxweb/projects/qbm/src/lib/busy-indicator/busy-indicator.component.scss index 2d008bd32..100fefc0b 100644 --- a/imxweb/projects/qbm/src/lib/busy-indicator/busy-indicator.component.scss +++ b/imxweb/projects/qbm/src/lib/busy-indicator/busy-indicator.component.scss @@ -2,6 +2,7 @@ flex-grow: 1; display: flex; align-items: center; + justify-content: center; margin: 0 auto; > div { @@ -10,8 +11,7 @@ flex-direction: column; } - - .imx-loading-text{ + .imx-loading-text { margin-top: 40px; } -} \ No newline at end of file +} diff --git a/imxweb/projects/qbm/src/lib/busy-indicator/busy-indicator.component.ts b/imxweb/projects/qbm/src/lib/busy-indicator/busy-indicator.component.ts index 1a9d5c36c..70ebc8323 100644 --- a/imxweb/projects/qbm/src/lib/busy-indicator/busy-indicator.component.ts +++ b/imxweb/projects/qbm/src/lib/busy-indicator/busy-indicator.component.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -29,8 +29,6 @@ import { Component } from '@angular/core'; @Component({ selector: 'imx-busy-indicator', templateUrl: './busy-indicator.component.html', - styleUrls: ['./busy-indicator.component.scss'] + styleUrls: ['./busy-indicator.component.scss'], }) -export class BusyIndicatorComponent { - -} \ No newline at end of file +export class BusyIndicatorComponent {} diff --git a/imxweb/projects/qbm/src/lib/busy-indicator/busy-indicator.module.ts b/imxweb/projects/qbm/src/lib/busy-indicator/busy-indicator.module.ts index 01e22b893..8993ced3a 100644 --- a/imxweb/projects/qbm/src/lib/busy-indicator/busy-indicator.module.ts +++ b/imxweb/projects/qbm/src/lib/busy-indicator/busy-indicator.module.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -24,23 +24,14 @@ * */ -import { NgModule } from "@angular/core"; -import { MatProgressSpinnerModule } from "@angular/material/progress-spinner"; -import { TranslateModule } from "@ngx-translate/core"; -import { BusyIndicatorComponent } from "./busy-indicator.component"; +import { NgModule } from '@angular/core'; +import { MatProgressSpinnerModule } from '@angular/material/progress-spinner'; +import { TranslateModule } from '@ngx-translate/core'; +import { BusyIndicatorComponent } from './busy-indicator.component'; @NgModule({ - imports: [ - MatProgressSpinnerModule, - TranslateModule - ], - declarations: [ - BusyIndicatorComponent - ], - exports: [ - BusyIndicatorComponent - ] + imports: [MatProgressSpinnerModule, TranslateModule], + declarations: [BusyIndicatorComponent], + exports: [BusyIndicatorComponent], }) -export class BusyIndicatorModule { - -} \ No newline at end of file +export class BusyIndicatorModule {} diff --git a/imxweb/projects/qbm/src/lib/cache/cache.service.ts b/imxweb/projects/qbm/src/lib/cache/cache.service.ts index 09f26c2d6..b8562831c 100644 --- a/imxweb/projects/qbm/src/lib/cache/cache.service.ts +++ b/imxweb/projects/qbm/src/lib/cache/cache.service.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -24,22 +24,20 @@ * */ -import { Injectable } from "@angular/core"; -import { CachedPromise } from "imx-qbm-dbts"; -import { Subscription } from "rxjs"; -import { AuthenticationService } from "../authentication/authentication.service"; +import { Injectable } from '@angular/core'; +import { CachedPromise } from '@imx-modules/imx-qbm-dbts'; +import { Subscription } from 'rxjs'; +import { AuthenticationService } from '../authentication/authentication.service'; /** Provides caching for promises. */ @Injectable({ - providedIn: 'root' + providedIn: 'root', }) export class CacheService { - - constructor(private readonly authService: AuthenticationService) { - } + constructor(private readonly authService: AuthenticationService) {} private defaultOptions: CacheOptions = { - flushOnAuthentication: true + flushOnAuthentication: true, }; /** Returns a new cached promise. The cache options can be configured @@ -47,12 +45,13 @@ export class CacheService { * @param func Construction function for a new promise. */ public buildCache(func: () => Promise, opts?: CacheOptions): CachedPromise { - var o = { ...this.defaultOptions, opts }; var subscription: Subscription; - const cachedPromise = new CachedPromise(func, () => { subscription?.unsubscribe(); }); - + const cachedPromise = new CachedPromise(func, () => { + subscription?.unsubscribe(); + }); + if (o.flushOnAuthentication) { subscription = this.authService.onSessionResponse.subscribe(() => cachedPromise.reset()); } @@ -65,5 +64,5 @@ export interface CacheOptions { /** Sets whether the cache will be flushed on authentication events, i.e. * when the user logs on or off. */ - flushOnAuthentication?: boolean + flushOnAuthentication?: boolean; } diff --git a/imxweb/projects/qbm/src/lib/captcha/captcha.component.html b/imxweb/projects/qbm/src/lib/captcha/captcha.component.html index ef3627a4a..a4cc00d9a 100644 --- a/imxweb/projects/qbm/src/lib/captcha/captcha.component.html +++ b/imxweb/projects/qbm/src/lib/captcha/captcha.component.html @@ -1,3 +1,37 @@ - + + {{ LdsCaptchaInfo | translate }} + -

    The CAPTCHA configuration is unsupported.

    \ No newline at end of file +
    + +

    The CAPTCHA configuration is unsupported.

    + + + +
    + +
    + + + +
    diff --git a/imxweb/projects/qbm/src/lib/captcha/captcha.component.scss b/imxweb/projects/qbm/src/lib/captcha/captcha.component.scss new file mode 100644 index 000000000..9b048dfb3 --- /dev/null +++ b/imxweb/projects/qbm/src/lib/captcha/captcha.component.scss @@ -0,0 +1,18 @@ +@import 'common/captcha-login'; + +:host { + display: block; +} + +.captcha-container { + display: flex; + + .mat-mdc-form-field { + flex: 1 1 auto; + } + + img { + padding-right: 1em; + height: 34px; + } +} diff --git a/imxweb/projects/qbm/src/lib/captcha/captcha.component.ts b/imxweb/projects/qbm/src/lib/captcha/captcha.component.ts index fa142b00d..8fb1d6789 100644 --- a/imxweb/projects/qbm/src/lib/captcha/captcha.component.ts +++ b/imxweb/projects/qbm/src/lib/captcha/captcha.component.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -24,23 +24,62 @@ * */ -import { Component, Input } from '@angular/core'; +import { Component, EventEmitter, Input, Output } from '@angular/core'; import { AppConfigService } from '../appConfig/appConfig.service'; -import { CaptchaMode, CaptchaService } from './captcha.service'; +import { CaptchaService } from './captcha.service'; @Component({ - selector: 'imx-captcha', - templateUrl: './captcha.component.html', - styles: [`:host { display: block; } img { height: 100%; }`] + selector: 'imx-captcha', + templateUrl: './captcha.component.html', + styleUrls: ['./captcha.component.scss'], }) export class CaptchaComponent { + /** + * Disable next button. + */ + @Input() disableButton: boolean; - constructor(public readonly captchaSvc: CaptchaService, public readonly appConfig: AppConfigService) { - } + /** + * Show back button. + */ + @Input() showBackButton = false; - @Input() builtInCaptchaUrl: string = 'passwordreset/captchaimage'; + /** + * Show all buttons. + */ + @Input() showAllButtons = true; - isBuiltIn(): boolean { - return this.captchaSvc.Mode == CaptchaMode.BuiltIn; - } -} \ No newline at end of file + /** + * Event emitter for the next button, which should take the user to the next function. + */ + @Output() nextClick: EventEmitter = new EventEmitter(); + + @Output() onBackEvent: EventEmitter = new EventEmitter(); + + /** + * Url for One Identity's ReCaptcha image + */ + builtInCaptchaUrl: string; + public LdsCaptchaInfo: string = '#LDS#Enter the characters from the image.'; + + constructor( + public readonly captchaSvc: CaptchaService, + public readonly appConfig: AppConfigService, + ) { + this.builtInCaptchaUrl = this.captchaSvc.captchaImageUrl; + } + + /** + * Emits an event to the parent component, when the Next button was clicked. + */ + public onNext() { + this.nextClick.emit(true); + } + + /** + * Emits an event to the parent component, when the Back button was clicked. + */ + public onBack(): void { + this.onBackEvent.emit(); + } +} diff --git a/imxweb/projects/qbm/src/lib/captcha/captcha.module.ts b/imxweb/projects/qbm/src/lib/captcha/captcha.module.ts index 8ddcbf55b..11ab28e52 100644 --- a/imxweb/projects/qbm/src/lib/captcha/captcha.module.ts +++ b/imxweb/projects/qbm/src/lib/captcha/captcha.module.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -35,21 +35,8 @@ import { TranslateModule } from '@ngx-translate/core'; import { CaptchaComponent } from './captcha.component'; @NgModule({ - imports: [ - CommonModule, - FormsModule, - EuiCoreModule, - MatButtonModule, - MatFormFieldModule, - MatInputModule, - TranslateModule - ], - declarations: [ - CaptchaComponent - ], - exports: [ - CaptchaComponent - ] + imports: [CommonModule, FormsModule, EuiCoreModule, MatButtonModule, MatFormFieldModule, MatInputModule, TranslateModule], + declarations: [CaptchaComponent], + exports: [CaptchaComponent], }) -export class CaptchaModule { -} \ No newline at end of file +export class CaptchaModule {} diff --git a/imxweb/projects/qbm/src/lib/captcha/captcha.service.ts b/imxweb/projects/qbm/src/lib/captcha/captcha.service.ts index d5389b097..0806185ee 100644 --- a/imxweb/projects/qbm/src/lib/captcha/captcha.service.ts +++ b/imxweb/projects/qbm/src/lib/captcha/captcha.service.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -24,40 +24,72 @@ * */ -import { Injectable } from "@angular/core"; +import { Injectable } from '@angular/core'; @Injectable({ providedIn: 'root' }) export class CaptchaService { - - constructor() { - this.ReinitCaptcha(); - } - private _recaptchaPublicKey: string; - public get recaptchaPublicKey() { return this._recaptchaPublicKey; } - /** CAPTCHA response entered by the user. */ - public Response: string = ""; + public Response: string = ''; + /** + * Url parameter for One Identity's ReCaptcha + */ public builtInUrlParameter: string; - enableReCaptcha(publicKey: string) { - throw new Error("not supported"); - this._recaptchaPublicKey = publicKey; + /** + * Url parameter for captcha image. + */ + public captchaImageUrl: string; + + /** + * This variable holds the public key for ReCaptcha V3. + * The ReCaptchaPublicKey can be set in Password Reset Portal config. + */ + public get recaptchaPublicKey(): string { + return this._recaptchaPublicKey; } + /** + * Holds a CaptchaMode based on if the user has recaptchaPublicKey or not. + */ public get Mode(): CaptchaMode { - if (this._recaptchaPublicKey) - return CaptchaMode.RecaptchaV2; + if (this.recaptchaPublicKey) return CaptchaMode.RecaptchaV3; return CaptchaMode.BuiltIn; } + /** + * True if One Identity's ReCaptcha is enabled + */ + public get isBuiltIn(): boolean { + return this.Mode === CaptchaMode.BuiltIn; + } + + /** + * True if ReCaptchaV3 is enabled + */ + public get isReCaptchaV3(): boolean { + return this.Mode === CaptchaMode.RecaptchaV3; + } + + constructor() { + this.ReinitCaptcha(); + } + + /** + * Enables Google's ReCaptcha V3 function. + * @param publicKey Google ReCaptcha's public key, provided by Password Reset Portal's config. + */ + public enableReCaptcha(publicKey: string) { + this._recaptchaPublicKey = publicKey; + } + /** Reinitializes the image to help users who cannot read a particular CAPTCHA, or if an authentication * attempt has failed. */ - ReinitCaptcha() { - this.Response = ""; + public ReinitCaptcha() { + this.Response = ''; // Add a cache-busting parameter this.builtInUrlParameter = '?t=' + new Date().getTime(); @@ -66,5 +98,6 @@ export class CaptchaService { export enum CaptchaMode { BuiltIn, - RecaptchaV2 -} \ No newline at end of file + RecaptchaV2, + RecaptchaV3, +} diff --git a/imxweb/projects/qbm/src/lib/cdr/Readme.md b/imxweb/projects/qbm/src/lib/cdr/Readme.md index 9cdfffead..d960b7a12 100644 --- a/imxweb/projects/qbm/src/lib/cdr/Readme.md +++ b/imxweb/projects/qbm/src/lib/cdr/Readme.md @@ -1,19 +1,22 @@ # CDR: **C**olumn **D**ependent **R**eference + The classes and interfaces in the cdr module supply the possibility to dynamically include UI components that allow editing of entity properties. -The name *CDR* refers to the fact that those editor components are not included -directly in the code but instead *referenced* indirectly. +The name _CDR_ refers to the fact that those editor components are not included +directly in the code but instead _referenced_ indirectly. This indirect reference will be resolved to an editor at runtime. -What editor component this will be exactly in the end *depends* on the -*column* and its meta-data. +What editor component this will be exactly in the end _depends_ on the +_column_ and its meta-data. ## The registry: resolving CDRs to editors + Generally, when you want to include an editor for a column dependent reference, you make use of the [CdrEditorComponent](cdr-editor\cdr-editor.component.ts), which provides a convenient tag that you can include in a template: imx-cdr-editor. E.g. + ```html

    Resulting Editor

    @@ -31,11 +34,13 @@ If none of the registered plugins was able to supply an editor the registry resolves to a EditDefaultComponent. The registry askes the registered plugins in FILO fashion, so that the plugins registered first, -will be the last to be asked. This order was chosen assuming that the more appliation specific a module is -* the later it will be initialized and -* the more likely it can provide a specialized CDR editor. +will be the last to be asked. This order was chosen assuming that the more appliation specific a module is + +- the later it will be initialized and +- the more likely it can provide a specialized CDR editor. ## Out-of-the-box CDR editors + As mentioned above, the CdrRegistryService solely supplies a single fallback editor out of the box: [EditDefaultComponent](edit-default/edit-default.component.ts). All other editors have to be provided by plugins that register at the CdrRegistryService. @@ -43,17 +48,20 @@ All other editors have to be provided by plugins that register at the CdrRegistr Nevertheless within the CDR module there are two plugins that supply some general default editors. [DefaultCdrEditorProvider](default-cdr-editor-provider.ts) provided editors: -* [EditBooleanComponent](edit-boolean/edit-boolean.component.ts): for boolean properties -* [EditLimitedValueComponent](edit-limited-value/edit-limited-value.component.ts): for properties where the value can be one of a limited set of allowed values -* [EditMultiLimitedValueComponent](edit-multi-limited-value/edit-multi-limited-value.component.ts): for properties where the value can be one or many of a limited set of alowed values -* [EditMulitValueComponent](edit-multi-value/edit-multi-value.component.ts) -* [EditMultiLineComponent](edit-multiline/edit-multiline.component.ts): for text properties that allow multiple lines -* [EditNumberComponent](edit-number/edit-number.component.ts): for numeric properties + +- [EditBooleanComponent](edit-boolean/edit-boolean.component.ts): for boolean properties +- [EditLimitedValueComponent](edit-limited-value/edit-limited-value.component.ts): for properties where the value can be one of a limited set of allowed values +- [EditMultiLimitedValueComponent](edit-multi-limited-value/edit-multi-limited-value.component.ts): for properties where the value can be one or many of a limited set of alowed values +- [EditMulitValueComponent](edit-multi-value/edit-multi-value.component.ts) +- [EditMultiLineComponent](edit-multiline/edit-multiline.component.ts): for text properties that allow multiple lines +- [EditNumberComponent](edit-number/edit-number.component.ts): for numeric properties [FkCdrEditorProvider](fk-cdr-editor-provider.ts) provided editors: -* [EditFkComponent](edit-fk/edit-fk.component.ts): for foreign key properties, i.e. properties pointing to other entities, e.g. "primary department" property of a person + +- [EditFkComponent](edit-fk/edit-fk.component.ts): for foreign key properties, i.e. properties pointing to other entities, e.g. "primary department" property of a person If you want to make use of these two provider services you have to register them at the CdrRegistryService, e.g. during your app's initialization like this: + ```typescript export function initApp(registry: CdrRegistryService) { return () => @@ -66,27 +74,32 @@ export function initApp(registry: CdrRegistryService) { ``` ## Providing custom CDR editors + First thing you have to do is to create an editor component. Second thing is to create a provider class that must be registered at the CdrRegistryService. ### Creating a CDR editor component + A CDR editor is just a normal Angular UI component that implements a certain interface: [CdrEditor](cdr-editor.interface.ts) This interface defines a method that should be called by the provider to tell the editor which column dependent reference it should display/edit: + ```typescript bind(cdref: ColumnDependentReference) ``` ### Creating a CDR editor provider + A CDR editor provider is a class implementing the [CdrEditorProvider](cdr-editor-provider.interface.ts) interface. Although not necessary it is a good choice to make this class an Angular service. The interface allows to supply multiple different editor types -but if you want to supply instances of a single editor class only, +but if you want to supply instances of a single editor class only, there is a convenient abstract base class that you can inherit from: [BaseCdrEditorProvider](base-cdr-editor-provider.ts) When you inherit from BaseCdrEditorProvider the only method you have to implement is the one that 'accepts' a given column dependent reference, i.e. whether the provided editor fits for it. + ```typescript protected abstract accept(cdref: ColumnDependentReference): boolean; -``` \ No newline at end of file +``` diff --git a/imxweb/projects/qbm/src/lib/cdr/base-cdr-editor-provider.ts b/imxweb/projects/qbm/src/lib/cdr/base-cdr-editor-provider.ts index 8f8b41674..00ef74206 100644 --- a/imxweb/projects/qbm/src/lib/cdr/base-cdr-editor-provider.ts +++ b/imxweb/projects/qbm/src/lib/cdr/base-cdr-editor-provider.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -24,9 +24,9 @@ * */ -import { CdrEditor } from './cdr-editor.interface'; +import { ComponentFactoryResolver, ComponentRef, ViewContainerRef } from '@angular/core'; import { CdrEditorProvider } from './cdr-editor-provider.interface'; -import { ViewContainerRef, ComponentRef, ComponentFactoryResolver } from '@angular/core'; +import { CdrEditor } from './cdr-editor.interface'; import { ColumnDependentReference } from './column-dependent-reference.interface'; /** @@ -44,7 +44,7 @@ export abstract class BaseCdrEditorProvider implements CdrE * @param cdref A column dependent reference that contains the data for the editor. * @returns An instance of {@link CdrEditor}, that can be used for editing data. */ - public createEditor(parent: ViewContainerRef, cdref: ColumnDependentReference): ComponentRef { + public createEditor(parent: ViewContainerRef, cdref: ColumnDependentReference): ComponentRef | null { if (!this.accept(cdref)) { return null; } diff --git a/imxweb/projects/qbm/src/lib/cdr/base-cdr.spec.ts b/imxweb/projects/qbm/src/lib/cdr/base-cdr.spec.ts index ea77131aa..a5aca1acd 100644 --- a/imxweb/projects/qbm/src/lib/cdr/base-cdr.spec.ts +++ b/imxweb/projects/qbm/src/lib/cdr/base-cdr.spec.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -25,17 +25,18 @@ */ import { BaseCdr } from './base-cdr'; -import { IEntityColumn } from 'imx-qbm-dbts'; +import { IEntityColumn } from '@imx-modules/imx-qbm-dbts'; describe('BaseCdr', () => { - [ true, false ].forEach(canEdit => + [true, false].forEach((canEdit) => it('can create', () => { - const cdr = new BaseCdr({ - GetMetadata: () => ({ - CanEdit: () => canEdit - }) - } as IEntityColumn); - expect(cdr.column).toBeDefined(); - expect(cdr.isReadOnly()).toEqual(!canEdit); - })); + const cdr = new BaseCdr({ + GetMetadata: () => ({ + CanEdit: () => canEdit, + }), + } as IEntityColumn); + expect(cdr.column).toBeDefined(); + expect(cdr.isReadOnly()).toEqual(!canEdit); + }), + ); }); diff --git a/imxweb/projects/qbm/src/lib/cdr/base-cdr.ts b/imxweb/projects/qbm/src/lib/cdr/base-cdr.ts index bb7ca0153..464646adb 100644 --- a/imxweb/projects/qbm/src/lib/cdr/base-cdr.ts +++ b/imxweb/projects/qbm/src/lib/cdr/base-cdr.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -24,10 +24,10 @@ * */ -import { IEntityColumn } from 'imx-qbm-dbts'; +import { IEntityColumn } from '@imx-modules/imx-qbm-dbts'; -import { ColumnDependentReference } from './column-dependent-reference.interface'; import { Subject } from 'rxjs'; +import { ColumnDependentReference } from './column-dependent-reference.interface'; /** * Generic implementation of a {@link ColumnDependentReference | column dependent reference}. @@ -37,7 +37,6 @@ import { Subject } from 'rxjs'; * const value = new BaseCdr(columnToUse, undefined, renderedReadonlyOrNot ); // Build a CDR with a give readOnly state */ export class BaseCdr implements ColumnDependentReference { - /** * A small hint, that is displayed on a hint icon */ @@ -53,18 +52,17 @@ export class BaseCdr implements ColumnDependentReference { */ public minlengthSubject = new Subject(); - constructor(public readonly column: IEntityColumn, public readonly display?: string, public readonly isReadOnlyColumn?: boolean) {} + constructor( + public readonly column: IEntityColumn, + public readonly display?: string, + ) {} /** * Checks, whether a CDR should be rendered as read-only * @returns True, if the CDR needs to be show as 'read-only', otherwise false. */ public isReadOnly(): boolean { - if (this.isReadOnlyColumn !== undefined) { - return this.column == null || this.isReadOnlyColumn || !this.column.GetMetadata().CanEdit(); - } else { - return this.column == null || !this.column.GetMetadata().CanEdit(); - } + return this.column == null || !this.column.GetMetadata().CanEdit(); } /** diff --git a/imxweb/projects/qbm/src/lib/cdr/base-readonly-cdr.ts b/imxweb/projects/qbm/src/lib/cdr/base-readonly-cdr.ts index 83981a169..1bc6d04de 100644 --- a/imxweb/projects/qbm/src/lib/cdr/base-readonly-cdr.ts +++ b/imxweb/projects/qbm/src/lib/cdr/base-readonly-cdr.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -24,7 +24,6 @@ * */ - import { ColumnDependentReference } from './column-dependent-reference.interface'; import { BaseCdr } from './base-cdr'; diff --git a/imxweb/projects/qbm/src/lib/cdr/cdr-editor-provider-registry.interface.ts b/imxweb/projects/qbm/src/lib/cdr/cdr-editor-provider-registry.interface.ts index 16382bd15..bac51a110 100644 --- a/imxweb/projects/qbm/src/lib/cdr/cdr-editor-provider-registry.interface.ts +++ b/imxweb/projects/qbm/src/lib/cdr/cdr-editor-provider-registry.interface.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -35,10 +35,9 @@ import { CdrEditorProvider } from './cdr-editor-provider.interface'; * registered editor provider. */ export interface CdrEditorProviderRegistry extends CdrEditorProvider { - - /** - * Registers an editor provider for column dependent references. - * @param provider The editor provider to register. - */ - register(provider: CdrEditorProvider): void; + /** + * Registers an editor provider for column dependent references. + * @param provider The editor provider to register. + */ + register(provider: CdrEditorProvider): void; } diff --git a/imxweb/projects/qbm/src/lib/cdr/cdr-editor-provider.interface.ts b/imxweb/projects/qbm/src/lib/cdr/cdr-editor-provider.interface.ts index a2510e7e6..052a371ff 100644 --- a/imxweb/projects/qbm/src/lib/cdr/cdr-editor-provider.interface.ts +++ b/imxweb/projects/qbm/src/lib/cdr/cdr-editor-provider.interface.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -24,23 +24,22 @@ * */ -import { ColumnDependentReference } from './column-dependent-reference.interface'; +import { ComponentRef, ViewContainerRef } from '@angular/core'; import { CdrEditor } from './cdr-editor.interface'; -import { ViewContainerRef, ComponentRef } from '@angular/core'; +import { ColumnDependentReference } from './column-dependent-reference.interface'; /** * Defines an interface that can provide an UI component to display and/or edit a column dependent reference, * namely a CDR "editor". */ export interface CdrEditorProvider { - - /** - * Creates an editor for a given column dependent reference. - * - * If the column dependent reference does not suite any of the editors - * the provider can provide, it should return null. - * - * @param cdref The column dependent reference. - */ - createEditor(parent: ViewContainerRef, cdref: ColumnDependentReference): ComponentRef; + /** + * Creates an editor for a given column dependent reference. + * + * If the column dependent reference does not suite any of the editors + * the provider can provide, it should return null. + * + * @param cdref The column dependent reference. + */ + createEditor(parent: ViewContainerRef, cdref: ColumnDependentReference): ComponentRef | null; } diff --git a/imxweb/projects/qbm/src/lib/cdr/cdr-editor.interface.ts b/imxweb/projects/qbm/src/lib/cdr/cdr-editor.interface.ts index 20381aa4a..27b1fded6 100644 --- a/imxweb/projects/qbm/src/lib/cdr/cdr-editor.interface.ts +++ b/imxweb/projects/qbm/src/lib/cdr/cdr-editor.interface.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -33,16 +33,16 @@ import { ColumnDependentReference } from './column-dependent-reference.interface * Interface for the argument, that it emitted in the CDR editor. */ export interface ValueHasChangedEventArg { - /** - * The new value of the editor. - */ - value: any; + /** + * The new value of the editor. + */ + value: any; - /** - * A flag to show whether the emitting of a follow up event should be forced - * (evaluated by {@link CdrEditorComponent|CdrEditorComponent}). - */ - forceEmit?: boolean; + /** + * A flag to show whether the emitting of a follow up event should be forced + * (evaluated by {@link CdrEditorComponent|CdrEditorComponent}). + */ + forceEmit?: boolean; } /** @@ -54,6 +54,11 @@ export interface CdrEditor { */ control: AbstractControl; + /** + * Determines, if the control should only be validated after the value has been changed + */ + validateOnlyOnChange?: boolean; + /** * An event, that is emitted, if the value of the cdr has changed. */ diff --git a/imxweb/projects/qbm/src/lib/cdr/cdr-editor/cdr-editor.component.html b/imxweb/projects/qbm/src/lib/cdr/cdr-editor/cdr-editor.component.html index 56b101a3b..4fbad3415 100644 --- a/imxweb/projects/qbm/src/lib/cdr/cdr-editor/cdr-editor.component.html +++ b/imxweb/projects/qbm/src/lib/cdr/cdr-editor/cdr-editor.component.html @@ -4,6 +4,6 @@

    - {{description}} + {{ description }}

    diff --git a/imxweb/projects/qbm/src/lib/cdr/cdr-editor/cdr-editor.component.scss b/imxweb/projects/qbm/src/lib/cdr/cdr-editor/cdr-editor.component.scss index 075680508..25a05bfda 100644 --- a/imxweb/projects/qbm/src/lib/cdr/cdr-editor/cdr-editor.component.scss +++ b/imxweb/projects/qbm/src/lib/cdr/cdr-editor/cdr-editor.component.scss @@ -4,8 +4,8 @@ /* place for hints and other indicators */ > .hint-container { flex-grow: 0; - margin: 0 0.5em 2em; + margin: 0 0.5em 1.25em; align-items: center; display: flex; } -} \ No newline at end of file +} diff --git a/imxweb/projects/qbm/src/lib/cdr/cdr-editor/cdr-editor.component.ts b/imxweb/projects/qbm/src/lib/cdr/cdr-editor/cdr-editor.component.ts index f6979e0aa..7c13db180 100644 --- a/imxweb/projects/qbm/src/lib/cdr/cdr-editor/cdr-editor.component.ts +++ b/imxweb/projects/qbm/src/lib/cdr/cdr-editor/cdr-editor.component.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -24,13 +24,13 @@ * */ -import { Component, Input, ViewChild, ViewContainerRef, OnChanges, SimpleChanges, EventEmitter, Output, ElementRef } from '@angular/core'; +import { Component, ElementRef, EventEmitter, Input, OnChanges, Output, SimpleChanges, ViewChild, ViewContainerRef } from '@angular/core'; import { AbstractControl } from '@angular/forms'; -import { ColumnDependentReference } from '../column-dependent-reference.interface'; -import { CdrRegistryService } from '../cdr-registry.service'; import { ClassloggerService } from '../../classlogger/classlogger.service'; import { CdrEditor } from '../cdr-editor.interface'; +import { CdrRegistryService } from '../cdr-registry.service'; +import { ColumnDependentReference } from '../column-dependent-reference.interface'; /** * This component provides an {@link CdrEditor|editor} for a {@link ColumnDependentReference|column dependent reference}. @@ -42,11 +42,11 @@ import { CdrEditor } from '../cdr-editor.interface'; * In the *.ts file: * cdrForColumns: ColumnDependentReferences; * formGroup: FormGroup<{cdrArray: FormArray}>; - * In the *.html file: * + * In the *.html file: * * --> *
    - * { if (value?.forceEmit === true) { this.valueChange.emit(value.value); @@ -122,14 +131,17 @@ export class CdrEditorComponent implements OnChanges { } }); } - if (ref.instance.pendingChanged) { + if (ref?.instance.pendingChanged) { ref.instance.pendingChanged.subscribe((value) => { this.pendingChanged.emit(value); }); } - this.controlCreated.emit(ref.instance.control); + this.controlCreated.emit(ref?.instance.control); this.elementRef.nativeElement.setAttribute('data-imx-identifier', `cdr-editor-${this.cdr.column.ColumnName}`); - this.editor = ref.instance; + this.editor = ref?.instance; + if (this.editor) { + this.editor.validateOnlyOnChange = this.validateOnlyOnChange; + } } catch (e) { this.logger.error(this, 'Failed to create editor for column dependent reference.', e); } diff --git a/imxweb/projects/qbm/src/lib/cdr/cdr-factory.service.ts b/imxweb/projects/qbm/src/lib/cdr/cdr-factory.service.ts index 33a3c6b26..5f0933524 100644 --- a/imxweb/projects/qbm/src/lib/cdr/cdr-factory.service.ts +++ b/imxweb/projects/qbm/src/lib/cdr/cdr-factory.service.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -25,7 +25,7 @@ */ import { Injectable } from '@angular/core'; -import { IEntity, IEntityColumn } from 'imx-qbm-dbts'; +import { IEntity, IEntityColumn } from '@imx-modules/imx-qbm-dbts'; import { BaseCdr } from './base-cdr'; import { BaseReadonlyCdr } from './base-readonly-cdr'; import { ColumnDependentReference } from './column-dependent-reference.interface'; @@ -36,19 +36,19 @@ import { ColumnDependentReference } from './column-dependent-reference.interface export class CdrFactoryService { /** * Builds an array of column dependent references, depending on the columns provided. - * If the column does not exists, it is left out of the array. + * If the column does not exists, it is filtered out via the Boolean constructor. * @param entity The complete entity that provides the columns. * @param columnNames The list of columns, a CDR is needed for. * @param readOnly If true, readonly CDR will be build otherwise normal base CDR. * @returns A list of column dependent references. */ - public buildCdrFromColumnList(entity: IEntity, columnNames: string[], readOnly: boolean = false): ColumnDependentReference[] { - return columnNames.map((column) => this.buildCdr(entity, column, readOnly)).filter((cdr) => cdr != null); + public buildCdrFromColumnList(entity: IEntity | undefined, columnNames: string[], readOnly: boolean = false): ColumnDependentReference[] { + return columnNames.map((column) => this.buildCdr(entity, column, readOnly)).filter(Boolean) as ColumnDependentReference[]; } /** * Builds an array of column dependent references, depending on the columns provided. - * If the column does not exists, it is left out of the array. + * If the column does not exists, it is filtered out via the Boolean constructor. * You are able to add a list of column names, that should be readonly * @param entity The complete entity that provides the columns. * @param columnNames The list of columns, a CDR is needed for. @@ -58,9 +58,11 @@ export class CdrFactoryService { public buildCdrFromColumnListAdvanced( entity: IEntity, columnNames: string[], - readOnlyColumns: string[] = [] + readOnlyColumns: string[] = [], ): ColumnDependentReference[] { - return columnNames.map((column) => this.buildCdr(entity, column, readOnlyColumns.includes(column))).filter((cdr) => cdr != null); + return columnNames + .map((column) => this.buildCdr(entity, column, readOnlyColumns.includes(column))) + .filter(Boolean) as ColumnDependentReference[]; } /** @@ -70,10 +72,15 @@ export class CdrFactoryService { * @param readOnly If true, a read-only CDR will be build otherwise a normal base CDR. * @returns The column dependent reference or null, if the column is not defined in the entity. */ - public buildCdr(entity: IEntity, columnName: string, readOnly: boolean = false, columnDisplay?: string): ColumnDependentReference { + public buildCdr( + entity: IEntity | undefined, + columnName: string, + readOnly: boolean = false, + columnDisplay?: string, + ): ColumnDependentReference | undefined { const column = CdrFactoryService.tryGetColumn(entity, columnName); - return column == null ? null : readOnly ? new BaseReadonlyCdr(column, columnDisplay) : new BaseCdr(column, columnDisplay); + return column == null ? undefined : readOnly ? new BaseReadonlyCdr(column, columnDisplay) : new BaseCdr(column, columnDisplay); } /** @@ -82,7 +89,7 @@ export class CdrFactoryService { * @param columnName The name of the column, that should be provided. * @returns Null, if the entity doesn't have a column with the given name otherwise the column is returned. */ - public static tryGetColumn(entity: IEntity, columnName: string): IEntityColumn { + public static tryGetColumn(entity: IEntity | undefined, columnName: string): IEntityColumn | undefined { try { return entity?.GetColumn(columnName); } catch { diff --git a/imxweb/projects/qbm/src/lib/cdr/cdr-registry.service.ts b/imxweb/projects/qbm/src/lib/cdr/cdr-registry.service.ts index f48a54bf0..362cadeda 100644 --- a/imxweb/projects/qbm/src/lib/cdr/cdr-registry.service.ts +++ b/imxweb/projects/qbm/src/lib/cdr/cdr-registry.service.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -24,14 +24,14 @@ * */ -import { Injectable, ErrorHandler, ViewContainerRef, ComponentFactoryResolver, ComponentRef } from '@angular/core'; +import { ComponentFactoryResolver, ComponentRef, ErrorHandler, Injectable, ViewContainerRef } from '@angular/core'; +import { ClassloggerService } from '../classlogger/classlogger.service'; import { CdrEditorProviderRegistry } from './cdr-editor-provider-registry.interface'; import { CdrEditorProvider } from './cdr-editor-provider.interface'; -import { ColumnDependentReference } from './column-dependent-reference.interface'; import { CdrEditor } from './cdr-editor.interface'; +import { ColumnDependentReference } from './column-dependent-reference.interface'; import { EditDefaultComponent } from './edit-default/edit-default.component'; -import { ClassloggerService } from '../classlogger/classlogger.service'; /** * A service that is capable of {@link create|creating} an {@link CdrEditor|editor} @@ -45,10 +45,9 @@ import { ClassloggerService } from '../classlogger/classlogger.service'; * @see CdrEditorProvider */ @Injectable({ - providedIn: 'root' + providedIn: 'root', }) export class CdrRegistryService implements CdrEditorProviderRegistry { - /** * This array contains the registered (@see register) providers. */ @@ -61,8 +60,11 @@ export class CdrRegistryService implements CdrEditorProviderRegistry { * @param logger The logger used for logging messages. * @throws {Error} Throws an error if the given error handler is null or undefined. */ - constructor(private componentFactoryResolver: ComponentFactoryResolver, - private errorHandler: ErrorHandler, private logger: ClassloggerService) { } + constructor( + private componentFactoryResolver: ComponentFactoryResolver, + private errorHandler: ErrorHandler, + private logger: ClassloggerService, + ) {} /** * Registers an editor provider for column dependent references. @@ -76,12 +78,15 @@ export class CdrRegistryService implements CdrEditorProviderRegistry { throw new Error('The provider must not be null or undefined.'); } - if (this.registeredProviders.find(p => p === provider)) { + if (this.registeredProviders.find((p) => p === provider)) { throw new Error('This provider has already been registered.'); } - this.logger.debug(this, `Registering '${this.className(provider)}' as - column dependent reference editor provider #${this.registeredProviders.length + 1}.`); + this.logger.debug( + this, + `Registering '${this.className(provider)}' as + column dependent reference editor provider #${this.registeredProviders.length + 1}.`, + ); this.registeredProviders.push(provider); } @@ -100,7 +105,7 @@ export class CdrRegistryService implements CdrEditorProviderRegistry { * @param cdref The column dependent reference for which an editor shall be created * @throws {Error} Throws an error if the given column dependent reference is null or undefined. */ - public createEditor(parent: ViewContainerRef, cdref: ColumnDependentReference): ComponentRef { + public createEditor(parent: ViewContainerRef, cdref: ColumnDependentReference): ComponentRef | null { if (cdref == null) { throw new Error('The cdref must not be null or undefined.'); } @@ -113,16 +118,26 @@ export class CdrRegistryService implements CdrEditorProviderRegistry { const editor = provider.createEditor(parent, cdref); if (!editor) { - this.logger.debug(this, `Provider '${this.className(provider)}' returned '${this.className(editor)}' - for '${this.className(cdref)}' -> skipping it.'`); + this.logger.debug( + this, + `Provider '${this.className(provider)}' returned '${this.className(editor)}' + for '${this.className(cdref)}' -> skipping it.'`, + ); } else { - this.logger.debug(this, `Returning editor '${this.className(editor.instance)}' - for '${this.className(cdref)}' created by '${this.className(provider)}'.`); + this.logger.debug( + this, + `Returning editor '${this.className(editor.instance)}' + for '${this.className(cdref)}' created by '${this.className(provider)}'.`, + ); return editor; } } catch (e) { - this.logger.error(this, `Error during attempt to create editor through provider ${this.className(provider)} - -> skipping the provider this time.`, e); + this.logger.error( + this, + `Error during attempt to create editor through provider ${this.className(provider)} + -> skipping the provider this time.`, + e, + ); this.errorHandler.handleError(e); } } diff --git a/imxweb/projects/qbm/src/lib/cdr/cdr-sidesheet/cdr-sidesheet-config.ts b/imxweb/projects/qbm/src/lib/cdr/cdr-sidesheet/cdr-sidesheet-config.ts index 2d2bd2052..091b9807c 100644 --- a/imxweb/projects/qbm/src/lib/cdr/cdr-sidesheet/cdr-sidesheet-config.ts +++ b/imxweb/projects/qbm/src/lib/cdr/cdr-sidesheet/cdr-sidesheet-config.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR diff --git a/imxweb/projects/qbm/src/lib/cdr/cdr-sidesheet/cdr-sidesheet.component.html b/imxweb/projects/qbm/src/lib/cdr/cdr-sidesheet/cdr-sidesheet.component.html index 5b25aff80..6138ca778 100644 --- a/imxweb/projects/qbm/src/lib/cdr/cdr-sidesheet/cdr-sidesheet.component.html +++ b/imxweb/projects/qbm/src/lib/cdr/cdr-sidesheet/cdr-sidesheet.component.html @@ -1,12 +1,19 @@
    - + - +
    - +
    diff --git a/imxweb/projects/qbm/src/lib/cdr/cdr-sidesheet/cdr-sidesheet.component.ts b/imxweb/projects/qbm/src/lib/cdr/cdr-sidesheet/cdr-sidesheet.component.ts index 8c9ab6c3a..9004b50de 100644 --- a/imxweb/projects/qbm/src/lib/cdr/cdr-sidesheet/cdr-sidesheet.component.ts +++ b/imxweb/projects/qbm/src/lib/cdr/cdr-sidesheet/cdr-sidesheet.component.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -25,21 +25,20 @@ */ import { Component, Inject } from '@angular/core'; -import { UntypedFormControl, UntypedFormGroup } from '@angular/forms'; -import { EuiSidesheetRef, EUI_SIDESHEET_DATA } from '@elemental-ui/core'; +import { AbstractControl, UntypedFormGroup } from '@angular/forms'; +import { EUI_SIDESHEET_DATA, EuiSidesheetRef } from '@elemental-ui/core'; import { CdrSidesheetConfig } from './cdr-sidesheet-config'; /** * Provides a side sheet, that displays a form with {@link CdrEditor | cdr editors}. - * + * * Writeable properties can be edited. */ @Component({ - templateUrl: './cdr-sidesheet.component.html' + templateUrl: './cdr-sidesheet.component.html', }) export class CdrSidesheetComponent { - /** * The form, that stores the editors. */ @@ -52,7 +51,7 @@ export class CdrSidesheetComponent { */ constructor( @Inject(EUI_SIDESHEET_DATA) public readonly config: CdrSidesheetConfig, - public readonly sidesheetRef: EuiSidesheetRef + public readonly sidesheetRef: EuiSidesheetRef, ) {} /** @@ -60,7 +59,7 @@ export class CdrSidesheetComponent { * @param name The name of the control. * @param control The form control that should be added. */ - public addFormControl(name: string, control: UntypedFormControl): void { + public addFormControl(name: string, control: AbstractControl): void { this.cdrFormGroup.addControl(name, control); } } diff --git a/imxweb/projects/qbm/src/lib/cdr/cdr.module.ts b/imxweb/projects/qbm/src/lib/cdr/cdr.module.ts index 118515868..ae3f3c91b 100644 --- a/imxweb/projects/qbm/src/lib/cdr/cdr.module.ts +++ b/imxweb/projects/qbm/src/lib/cdr/cdr.module.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -24,9 +24,9 @@ * */ +import { CommonModule } from '@angular/common'; import { NgModule } from '@angular/core'; import { FormsModule, ReactiveFormsModule } from '@angular/forms'; -import { CommonModule } from '@angular/common'; import { MatAutocompleteModule } from '@angular/material/autocomplete'; import { MatButtonModule } from '@angular/material/button'; import { MatCheckboxModule } from '@angular/material/checkbox'; @@ -38,47 +38,47 @@ import { MatPaginatorModule } from '@angular/material/paginator'; import { MatProgressSpinnerModule } from '@angular/material/progress-spinner'; import { MatRadioModule } from '@angular/material/radio'; import { MatSelectModule } from '@angular/material/select'; -import { MatSliderModule } from '@angular/material/slider'; import { MatSlideToggleModule } from '@angular/material/slide-toggle'; +import { MatSliderModule } from '@angular/material/slider'; import { MatTableModule } from '@angular/material/table'; import { TranslateModule } from '@ngx-translate/core'; import { EuiCoreModule } from '@elemental-ui/core'; -import { CdrRegistryService } from './cdr-registry.service'; +import { ScrollingModule } from '@angular/cdk/scrolling'; +import { MatCardModule } from '@angular/material/card'; +import { MatTooltipModule } from '@angular/material/tooltip'; +import { DataSourceToolbarModule } from '../data-source-toolbar/data-source-toolbar.module'; +import { DataTableModule } from '../data-table/data-table.module'; +import { DateModule } from '../date/date.module'; +import { DisableControlModule } from '../disable-control/disable-control.module'; +import { FkAdvancedPickerModule } from '../fk-advanced-picker/fk-advanced-picker.module'; +import { FkHierarchicalDialogModule } from '../fk-hierarchical-dialog/fk-hierarchical-dialog.module'; +import { ImageModule } from '../image/image.module'; +import { InfoModalDialogModule } from '../info-modal-dialog/info-modal-dialog.module'; +import { LdsReplaceModule } from '../lds-replace/lds-replace.module'; import { CdrEditorComponent } from './cdr-editor/cdr-editor.component'; -import { EditBooleanComponent } from './edit-boolean/edit-boolean.component'; -import { EditDefaultComponent } from './edit-default/edit-default.component'; -import { EditMultilineComponent } from './edit-multiline/edit-multiline.component'; -import { EditNumberComponent } from './edit-number/edit-number.component'; -import { EditLimitedValueComponent } from './edit-limited-value/edit-limited-value.component'; -import { EditMultiValueComponent } from './edit-multi-value/edit-multi-value.component'; -import { EditMultiLimitedValueComponent } from './edit-multi-limited-value/edit-multi-limited-value.component'; +import { CdrSidesheetComponent } from './cdr-sidesheet/cdr-sidesheet.component'; +import { DateRangeComponent } from './date-range/date-range.component'; import { EditBinaryComponent } from './edit-binary/edit-binary.component'; +import { EditBitmaskComponent } from './edit-bitmask/edit-bitmask.component'; +import { EditBooleanComponent } from './edit-boolean/edit-boolean.component'; import { EditDateComponent } from './edit-date/edit-date.component'; -import { PropertyViewerComponent } from './property-viewer/property-viewer.component'; -import { DisableControlModule } from '../disable-control/disable-control.module'; -import { EditImageComponent } from './edit-image/edit-image.component'; -import { DataSourceToolbarModule } from '../data-source-toolbar/data-source-toolbar.module'; -import { DataTableModule } from '../data-table/data-table.module'; +import { EditDefaultComponent } from './edit-default/edit-default.component'; import { EditFkMultiComponent } from './edit-fk/edit-fk-multi.component'; import { EditFkComponent } from './edit-fk/edit-fk.component'; -import { LdsReplaceModule } from '../lds-replace/lds-replace.module'; -import { FkAdvancedPickerModule } from '../fk-advanced-picker/fk-advanced-picker.module'; +import { EditImageComponent } from './edit-image/edit-image.component'; +import { EditLimitedValueComponent } from './edit-limited-value/edit-limited-value.component'; +import { EditMultiLimitedValueComponent } from './edit-multi-limited-value/edit-multi-limited-value.component'; +import { EditMultiValueComponent } from './edit-multi-value/edit-multi-value.component'; +import { EditMultilineComponent } from './edit-multiline/edit-multiline.component'; +import { EditNumberComponent } from './edit-number/edit-number.component'; import { EditRiskIndexComponent } from './edit-risk-index/edit-risk-index.component'; +import { EditUrlComponent } from './edit-url/edit-url.component'; +import { EntityColumnEditorComponent } from './entity-column-editor/entity-column-editor.component'; +import { PropertyViewerComponent } from './property-viewer/property-viewer.component'; import { ViewPropertyDefaultComponent } from './view-property-default/view-property-default.component'; -import { ScrollingModule } from '@angular/cdk/scrolling'; -import { FkHierarchicalDialogModule } from '../fk-hierarchical-dialog/fk-hierarchical-dialog.module'; import { ViewPropertyComponent } from './view-property/view-property.component'; -import { DateModule } from '../date/date.module'; -import { DateRangeComponent } from './date-range/date-range.component'; -import { ImageModule } from '../image/image.module'; -import { EntityColumnEditorComponent } from './entity-column-editor/entity-column-editor.component'; -import { EditUrlComponent } from './edit-url/edit-url.component'; -import { CdrSidesheetComponent } from './cdr-sidesheet/cdr-sidesheet.component'; -import { MatCardModule } from '@angular/material/card'; -import { MatTooltipModule } from '@angular/material/tooltip'; -import { InfoModalDialogModule } from '../info-modal-dialog/info-modal-dialog.module'; @NgModule({ declarations: [ @@ -91,6 +91,7 @@ import { InfoModalDialogModule } from '../info-modal-dialog/info-modal-dialog.mo EditMultiValueComponent, EditMultiLimitedValueComponent, EditBinaryComponent, + EditBitmaskComponent, EditDateComponent, PropertyViewerComponent, EditImageComponent, diff --git a/imxweb/projects/qbm/src/lib/cdr/column-dependent-reference.interface.ts b/imxweb/projects/qbm/src/lib/cdr/column-dependent-reference.interface.ts index 9717f5e78..ac38d9f73 100644 --- a/imxweb/projects/qbm/src/lib/cdr/column-dependent-reference.interface.ts +++ b/imxweb/projects/qbm/src/lib/cdr/column-dependent-reference.interface.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -24,44 +24,43 @@ * */ - -import { IEntityColumn, ValueConstraint } from 'imx-qbm-dbts'; +import { IEntityColumn, ValueConstraint } from '@imx-modules/imx-qbm-dbts'; import { Subject } from 'rxjs'; /** * Defines a column dependent reference. */ export interface ColumnDependentReference { - /** - * The column of the entity. - */ - column: IEntityColumn; + /** + * The column of the entity. + */ + column: IEntityColumn; - /** - * Custom display - if it is set it will be used instead of column.GetMetadata().GetDisplay() - */ - display?: string; + /** + * Custom display - if it is set it will be used instead of column.GetMetadata().GetDisplay() + */ + display?: string; - /** - * Custom MinLength - is evaluated in addition to column.GetMetadata().GetMinLength() - */ - minLength?: number; + /** + * Custom MinLength - is evaluated in addition to column.GetMetadata().GetMinLength() + */ + minLength?: number; - minlengthSubject?: Subject + minlengthSubject?: Subject; - /** - * Custom valueConstraint - if it is set it will be used instead of column.GetMetadata().valueConstraint - */ - valueConstraint?: ValueConstraint; + /** + * Custom valueConstraint - if it is set it will be used instead of column.GetMetadata().valueConstraint + */ + valueConstraint?: ValueConstraint; - /** - * Optional hint - */ - hint?: string; + /** + * Optional hint + */ + hint?: string; - /** - * Returns whether the column should be only displayed (true) - * or also allow editing (false). - */ - isReadOnly(): boolean; + /** + * Returns whether the column should be only displayed (true) + * or also allow editing (false). + */ + isReadOnly(): boolean; } diff --git a/imxweb/projects/qbm/src/lib/cdr/date-range/date-range.component.html b/imxweb/projects/qbm/src/lib/cdr/date-range/date-range.component.html index 4fa842234..b81d2622d 100644 --- a/imxweb/projects/qbm/src/lib/cdr/date-range/date-range.component.html +++ b/imxweb/projects/qbm/src/lib/cdr/date-range/date-range.component.html @@ -1,28 +1,31 @@ - - {{ columnContainer?.display | translate }} - - {{'#LDS#Use dynamic time frame' | translate}} - + + {{ columnContainer.display | translate }} + + + {{ '#LDS#Use dynamic time frame' | translate }} + + - {{ '#LDS#Dynamic time frame' | translate }} + {{ '#LDS#Dynamic time frame' | translate }} {{ option.display }} -
    +
    -
    +
    + [imxIdentifierSuffix]="'-from-' + columnContainer?.name" + > + [imxIdentifierSuffix]="'-until-' + columnContainer?.name" + >
    - - + - - - diff --git a/imxweb/projects/qbm/src/lib/cdr/date-range/date-range.component.scss b/imxweb/projects/qbm/src/lib/cdr/date-range/date-range.component.scss index 80bb65375..7588c93b4 100644 --- a/imxweb/projects/qbm/src/lib/cdr/date-range/date-range.component.scss +++ b/imxweb/projects/qbm/src/lib/cdr/date-range/date-range.component.scss @@ -2,13 +2,6 @@ flex-grow: 1; } -.mat-form-field { - width: 100%; -} -.mat-checkbox{ +.mat-mdc-checkbox { padding-bottom: 1.25em; } -.hidden{ - display: none; -} - diff --git a/imxweb/projects/qbm/src/lib/cdr/date-range/date-range.component.ts b/imxweb/projects/qbm/src/lib/cdr/date-range/date-range.component.ts index a8abef75d..fbfbf0e91 100644 --- a/imxweb/projects/qbm/src/lib/cdr/date-range/date-range.component.ts +++ b/imxweb/projects/qbm/src/lib/cdr/date-range/date-range.component.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -26,19 +26,19 @@ import { Component, ErrorHandler, EventEmitter, OnDestroy } from '@angular/core'; import { UntypedFormControl, Validators } from '@angular/forms'; -import { Subscription } from 'rxjs'; import moment from 'moment-timezone'; +import { Subscription } from 'rxjs'; -import { DateRangeType, DateRangeTypeLabels, ValType, ValueRange } from 'imx-qbm-dbts'; +import { EuiSelectOption } from '@elemental-ui/core'; +import { DateRangeType, DateRangeTypeLabels, ValType, ValueRange } from '@imx-modules/imx-qbm-dbts'; +import { ImxTranslationProviderService } from '../../translation/imx-translation-provider.service'; import { CdrEditor, ValueHasChangedEventArg } from '../cdr-editor.interface'; import { ColumnDependentReference } from '../column-dependent-reference.interface'; import { EntityColumnContainer } from '../entity-column-container'; -import { EuiSelectOption } from '@elemental-ui/core'; -import { ImxTranslationProviderService } from '../../translation/imx-translation-provider.service'; /** * Provides a {@link CdrEditor | CDR editor} for editing / viewing date range columns. - * + * * The user can choose between these two options: * It displays either two {@link DateComponent | date components} or a dynamic time frame like 'two weeks ago'. * When set to read-only, it uses a {@link ViewPropertyComponent | view property component} to display the content. @@ -104,7 +104,10 @@ export class DateRangeComponent implements CdrEditor, OnDestroy { private required = false; - public constructor(private readonly errorHandler: ErrorHandler, private translateProviderService: ImxTranslationProviderService) { + public constructor( + private readonly errorHandler: ErrorHandler, + private translateProviderService: ImxTranslationProviderService, + ) { this.translateProviderService.GetCultures().then(() => this.updateOptions()); } @@ -138,7 +141,7 @@ export class DateRangeComponent implements CdrEditor, OnDestroy { this.dateFrom.setValidators(null); this.dateUntil.setValidators(null); } - }) + }), ); } @@ -147,7 +150,7 @@ export class DateRangeComponent implements CdrEditor, OnDestroy { if (!!value) { this.writeValue({ from: value?.toDate(), until: this.dateUntil.value?.toDate() }); } - }) + }), ); this.subscribers.push( @@ -155,7 +158,7 @@ export class DateRangeComponent implements CdrEditor, OnDestroy { if (!!value) { this.writeValue({ from: this.dateFrom.value?.toDate(), until: value?.toDate() }); } - }) + }), ); this.subscribers.push( @@ -167,7 +170,7 @@ export class DateRangeComponent implements CdrEditor, OnDestroy { this.updateControlValues(); } this.valueHasChanged.emit({ value: this.control.value }); - }) + }), ); this.subscribers.push( @@ -175,7 +178,7 @@ export class DateRangeComponent implements CdrEditor, OnDestroy { if (!!value) { this.writeValue(value); } - }) + }), ); } } @@ -238,8 +241,8 @@ export class DateRangeComponent implements CdrEditor, OnDestroy { } const valueRange = ValueRange.Parse(value); if (valueRange.success) { - const from = valueRange.result.Start ? moment(valueRange.result.Start) : null; - const until = valueRange.result.End ? moment(valueRange.result.End) : null; + const from = valueRange.result?.Start ? moment(valueRange.result.Start) : null; + const until = valueRange.result?.End ? moment(valueRange.result.End) : null; this.dateFrom.setValue(from, { emitEvent: true }); this.dateUntil.setValue(until, { emitEvent: true }); if (this.required) { diff --git a/imxweb/projects/qbm/src/lib/cdr/default-cdr-editor-provider.spec.ts b/imxweb/projects/qbm/src/lib/cdr/default-cdr-editor-provider.spec.ts index 6fa2dbf68..5cad2f0b8 100644 --- a/imxweb/projects/qbm/src/lib/cdr/default-cdr-editor-provider.spec.ts +++ b/imxweb/projects/qbm/src/lib/cdr/default-cdr-editor-provider.spec.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -24,27 +24,23 @@ * */ -import { ViewContainerRef, ComponentRef } from '@angular/core'; -import * as TypeMoq from 'typemoq'; - -import { DefaultCdrEditorProvider } from './default-cdr-editor-provider'; +import { ComponentRef, ViewContainerRef } from '@angular/core'; +import { IValueMetadata, LimitedValueData, ValType } from '@imx-modules/imx-qbm-dbts'; +import { clearStylesFromDOM } from '../testing/clear-styles.spec'; +import { CdrEditor } from './cdr-editor.interface'; import { ColumnDependentReference } from './column-dependent-reference.interface'; -import { IValueMetadata, ValType, LimitedValueData, IEntityColumn } from 'imx-qbm-dbts'; +import { DefaultCdrEditorProvider } from './default-cdr-editor-provider'; import { EditBooleanComponent } from './edit-boolean/edit-boolean.component'; -import { CdrEditor } from './cdr-editor.interface'; -import { EditNumberComponent } from './edit-number/edit-number.component'; import { EditLimitedValueComponent } from './edit-limited-value/edit-limited-value.component'; import { EditMultiLimitedValueComponent } from './edit-multi-limited-value/edit-multi-limited-value.component'; import { EditMultiValueComponent } from './edit-multi-value/edit-multi-value.component'; import { EditMultilineComponent } from './edit-multiline/edit-multiline.component'; +import { EditNumberComponent } from './edit-number/edit-number.component'; import { EditRiskIndexComponent } from './edit-risk-index/edit-risk-index.component'; import { ViewPropertyDefaultComponent } from './view-property-default/view-property-default.component'; -import { clearStylesFromDOM } from '../testing/clear-styles.spec'; describe('DefaultCdrEditorProvider', () => { - beforeEach(() => { - - }); + beforeEach(() => {}); afterAll(() => { clearStylesFromDOM(); @@ -147,62 +143,53 @@ describe('DefaultCdrEditorProvider', () => { it('should create ViewPropertyDefaultComponent for readonly RiskIndex cdr', () => { testCreateEditor(ViewPropertyDefaultComponent, ValType.Double, false, false, false, [], '', true); }); - }); -function testCreateEditor(TCtor: new (...args: any[]) => T, type: ValType, - multiLine: boolean = false, multiValue: boolean = false, range: boolean = false, - limitedValues: string[] = [], schemaKey: string = '', isReadOnly: boolean = false) { - // Arrange - const cdrMock = createCdr(multiLine, multiValue, range, type, limitedValues, schemaKey, isReadOnly); - const editorMock = TypeMoq.Mock.ofType(); - const parentMock = TypeMoq.Mock.ofType(); - const childMock = createComponentMock(editorMock.object); - - parentMock.setup( p => p.createComponent(TypeMoq.It.isAny(), TypeMoq.It.isAny())).returns(() => childMock.object); - - // Act - const provider = new DefaultCdrEditorProvider(); - const editor = provider.createEditor(parentMock.object, cdrMock.object); - - // Assert - expect(editor === childMock.object).toBeTruthy(); - editorMock.verify(e => e.bind(cdrMock.object), TypeMoq.Times.once()); - editorMock.verify(e => e.bind(TypeMoq.It.isAny()), TypeMoq.Times.once()); +function testCreateEditor( + TCtor: new (...args: any[]) => T, + type: ValType, + multiLine: boolean = false, + multiValue: boolean = false, + range: boolean = false, + limitedValues: string[] = [], + schemaKey: string = '', + isReadOnly: boolean = false, +) { + const cdrMock = createCdr(multiLine, multiValue, range, type, limitedValues, schemaKey, isReadOnly); + const childMock = createComponentMock({} as T); + const parentMock = { createComponent: () => childMock } as unknown as ViewContainerRef; + const provider = new DefaultCdrEditorProvider(); + + const editor = provider.createEditor(parentMock, cdrMock); + expect(editor === childMock).toBeTruthy(); } -export function createComponentMock(instance: T): TypeMoq.IMock> { - const mock = TypeMoq.Mock.ofType>(); - mock.setup(m => m.instance).returns(() => instance); - return mock; +function createCdr( + multiLine: boolean, + multiValue: boolean, + range: boolean, + type: ValType, + limitedValues?: string[], + schemaKey?: string, + isReadOnly?: boolean, +): ColumnDependentReference { + const limited: LimitedValueData[] = limitedValues.map((elem) => ({ Value: elem })); + + const metaData: IValueMetadata = { + IsMultiLine: () => multiLine, + IsMultiValue: () => multiValue, + IsRange: () => range, + GetType: () => type, + GetLimitedValues: () => limited as ReadonlyArray, + GetSchemaKey: () => schemaKey, + CanEdit: () => !isReadOnly, + GetBitMaskCaptions: () => [] as ReadonlyArray, + } as IValueMetadata; + + return { column: { GetMetadata: () => metaData }, isReadOnly: () => isReadOnly } as unknown as ColumnDependentReference; } -function createCdr(multiLine: boolean, multiValue: boolean, range: boolean, - type: ValType, limitedValues?: string[], schemaKey?: string, isReadOnly?: boolean) -: TypeMoq.IMock { - - const metaMock = TypeMoq.Mock.ofType(); - metaMock.setup(m => m.IsMultiLine()).returns(() => multiLine); - metaMock.setup(m => m.IsMultiValue()).returns(() => multiValue); - metaMock.setup(m => m.IsRange()).returns(() => range); - metaMock.setup(m => m.GetType()).returns(() => type); - - const lvArray: LimitedValueData[] = []; - if (limitedValues != null) { - for (const lv of limitedValues) { - const lvMock = TypeMoq.Mock.ofType(); - lvMock.setup(m => m.Value).returns(() => lv); - lvArray.push(lvMock.object); - } - } - - metaMock.setup(m => m.GetLimitedValues()).returns(() => lvArray); - metaMock.setup(m => m.GetSchemaKey()).returns(() => schemaKey) - metaMock.setup(m => m.CanEdit()).returns(() => !isReadOnly) - - const cdrMock = TypeMoq.Mock.ofType(); - cdrMock.setup(m => m.column).returns(() => ({ GetMetadata: () => metaMock.object } as IEntityColumn)); - cdrMock.setup(m => m.isReadOnly()).returns(() => isReadOnly); - - return cdrMock; +export function createComponentMock(instance: T): ComponentRef { + instance.bind = () => {}; + return { instance } as ComponentRef; } diff --git a/imxweb/projects/qbm/src/lib/cdr/default-cdr-editor-provider.ts b/imxweb/projects/qbm/src/lib/cdr/default-cdr-editor-provider.ts index 956f6d2e1..8fe8a6130 100644 --- a/imxweb/projects/qbm/src/lib/cdr/default-cdr-editor-provider.ts +++ b/imxweb/projects/qbm/src/lib/cdr/default-cdr-editor-provider.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -24,21 +24,22 @@ * */ +import { ComponentRef, Type, ViewContainerRef } from '@angular/core'; +import { IValueMetadata, ValType } from '@imx-modules/imx-qbm-dbts'; import { CdrEditorProvider } from './cdr-editor-provider.interface'; -import { ViewContainerRef, ComponentRef, Type } from '@angular/core'; -import { ColumnDependentReference } from './column-dependent-reference.interface'; import { CdrEditor } from './cdr-editor.interface'; -import { ValType, IValueMetadata } from 'imx-qbm-dbts'; +import { ColumnDependentReference } from './column-dependent-reference.interface'; +import { DateRangeComponent } from './date-range/date-range.component'; import { EditBooleanComponent } from './edit-boolean/edit-boolean.component'; -import { EditNumberComponent } from './edit-number/edit-number.component'; -import { EditMultiLimitedValueComponent } from './edit-multi-limited-value/edit-multi-limited-value.component'; +import { EditDateComponent } from './edit-date/edit-date.component'; +import { EditImageComponent } from './edit-image/edit-image.component'; import { EditLimitedValueComponent } from './edit-limited-value/edit-limited-value.component'; +import { EditMultiLimitedValueComponent } from './edit-multi-limited-value/edit-multi-limited-value.component'; import { EditMultiValueComponent } from './edit-multi-value/edit-multi-value.component'; import { EditMultilineComponent } from './edit-multiline/edit-multiline.component'; -import { EditImageComponent } from './edit-image/edit-image.component'; -import { EditDateComponent } from './edit-date/edit-date.component'; +import { EditNumberComponent } from './edit-number/edit-number.component'; +import { EditBitmaskComponent } from './edit-bitmask/edit-bitmask.component'; import { EditRiskIndexComponent } from './edit-risk-index/edit-risk-index.component'; -import { DateRangeComponent } from './date-range/date-range.component'; import { EditUrlComponent } from './edit-url/edit-url.component'; /** @@ -61,7 +62,7 @@ export class DefaultCdrEditorProvider implements CdrEditorProvider { * @param cdref A column dependent reference that contains the data for the editor. * @returns An instance of {@link CdrEditor}, that can be used or editing data. */ - public createEditor(parent: ViewContainerRef, cdref: ColumnDependentReference): ComponentRef { + public createEditor(parent: ViewContainerRef, cdref: ColumnDependentReference): ComponentRef | null { const meta = cdref.column.GetMetadata(); const multiLine = meta.IsMultiLine(); const multiValue = meta.IsMultiValue(); @@ -76,6 +77,10 @@ export class DefaultCdrEditorProvider implements CdrEditorProvider { return this.createBound(EditImageComponent, parent, cdref); } + if (type === ValType.Int && meta.GetBitMaskCaptions()?.length > 0) { + return this.createBound(EditBitmaskComponent, parent, cdref); + } + if (!multiLine && !multiValue && !range && !limitedValues && !isRiskIndexColumn) { switch (type) { case ValType.Bool: @@ -122,7 +127,7 @@ export class DefaultCdrEditorProvider implements CdrEditorProvider { private createBound( editor: Type, parent: ViewContainerRef, - cdref: ColumnDependentReference + cdref: ColumnDependentReference, ): ComponentRef { const result = parent.createComponent(editor); result.instance.bind(cdref); @@ -130,7 +135,7 @@ export class DefaultCdrEditorProvider implements CdrEditorProvider { } /** - * @ignore only ised internally + * @ignore only used internally * Checks, if there are limited values defined for the column. * @returns True, if there are limited values available, otherwise false. */ diff --git a/imxweb/projects/qbm/src/lib/cdr/edit-binary/edit-binary.component.html b/imxweb/projects/qbm/src/lib/cdr/edit-binary/edit-binary.component.html index da31437a4..64dadf8e1 100644 --- a/imxweb/projects/qbm/src/lib/cdr/edit-binary/edit-binary.component.html +++ b/imxweb/projects/qbm/src/lib/cdr/edit-binary/edit-binary.component.html @@ -1,13 +1,8 @@ - - {{ columnContainer?.display | translate }} - + + {{ columnContainer.display | translate }} + - - + - diff --git a/imxweb/projects/qbm/src/lib/cdr/edit-binary/edit-binary.component.scss b/imxweb/projects/qbm/src/lib/cdr/edit-binary/edit-binary.component.scss index b03a7d6a4..bfe7e877f 100644 --- a/imxweb/projects/qbm/src/lib/cdr/edit-binary/edit-binary.component.scss +++ b/imxweb/projects/qbm/src/lib/cdr/edit-binary/edit-binary.component.scss @@ -1,7 +1,3 @@ :host { flex-grow: 1; } - -.mat-form-field { - width: 100%; -} \ No newline at end of file diff --git a/imxweb/projects/qbm/src/lib/cdr/edit-binary/edit-binary.component.ts b/imxweb/projects/qbm/src/lib/cdr/edit-binary/edit-binary.component.ts index 4a33a8754..1e66290b0 100644 --- a/imxweb/projects/qbm/src/lib/cdr/edit-binary/edit-binary.component.ts +++ b/imxweb/projects/qbm/src/lib/cdr/edit-binary/edit-binary.component.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR diff --git a/imxweb/projects/qbm/src/lib/cdr/edit-bitmask/edit-bitmask.component.html b/imxweb/projects/qbm/src/lib/cdr/edit-bitmask/edit-bitmask.component.html new file mode 100644 index 000000000..61723f2ad --- /dev/null +++ b/imxweb/projects/qbm/src/lib/cdr/edit-bitmask/edit-bitmask.component.html @@ -0,0 +1,10 @@ + + + + + + + + \ No newline at end of file diff --git a/imxweb/projects/qbm/src/lib/cdr/edit-bitmask/edit-bitmask.component.scss b/imxweb/projects/qbm/src/lib/cdr/edit-bitmask/edit-bitmask.component.scss new file mode 100644 index 000000000..bcd8ac2d3 --- /dev/null +++ b/imxweb/projects/qbm/src/lib/cdr/edit-bitmask/edit-bitmask.component.scss @@ -0,0 +1,3 @@ +:host { + flex-grow: 1; +} \ No newline at end of file diff --git a/imxweb/projects/qbm/src/lib/cdr/edit-bitmask/edit-bitmask.component.ts b/imxweb/projects/qbm/src/lib/cdr/edit-bitmask/edit-bitmask.component.ts new file mode 100644 index 000000000..fd526d951 --- /dev/null +++ b/imxweb/projects/qbm/src/lib/cdr/edit-bitmask/edit-bitmask.component.ts @@ -0,0 +1,179 @@ +/* + * ONE IDENTITY LLC. PROPRIETARY INFORMATION + * + * This software is confidential. One Identity, LLC. or one of its affiliates or + * subsidiaries, has supplied this software to you under terms of a + * license agreement, nondisclosure agreement or both. + * + * You may not copy, disclose, or use this software except in accordance with + * those terms. + * + * + * Copyright 2024 One Identity LLC. + * ALL RIGHTS RESERVED. + * + * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR + * WARRANTIES ABOUT THE SUITABILITY OF THE SOFTWARE, + * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED + * TO THE IMPLIED WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE, OR + * NON-INFRINGEMENT. ONE IDENTITY LLC. SHALL NOT BE + * LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE + * AS A RESULT OF USING, MODIFYING OR DISTRIBUTING + * THIS SOFTWARE OR ITS DERIVATIVES. + * + */ + +import { Component, EventEmitter } from '@angular/core'; +import { UntypedFormControl, Validators } from '@angular/forms'; +import { EuiSelectOption } from '@elemental-ui/core'; +import { Subject, Subscription } from 'rxjs'; +import { ClassloggerService } from '../../classlogger/classlogger.service'; +import { CdrEditor, ValueHasChangedEventArg } from '../cdr-editor.interface'; +import { ColumnDependentReference } from '../column-dependent-reference.interface'; +import { EntityColumnContainer } from '../entity-column-container'; + +@Component({ + selector: 'imx-edit-bitmask', + templateUrl: './edit-bitmask.component.html', + styleUrls: ['./edit-bitmask.component.scss'], +}) +export class EditBitmaskComponent implements CdrEditor { + /** + * The form control associated with the editor. + */ + public readonly control = new UntypedFormControl(undefined, { updateOn: 'blur' }); + + /** + * The container that wraps the column functionality. + */ + public readonly columnContainer = new EntityColumnContainer(); + + /** + * Event that is emitted, after a value has been changed. + */ + public readonly valueHasChanged = new EventEmitter(); + + /** + * A subject for triggering an update of the editor. + */ + public readonly updateRequested = new Subject(); + + /** + * The list of selectable bitmask options. + */ + public options: EuiSelectOption[] = []; + + private readonly subscribers: Subscription[] = []; + private isWriting = false; + + constructor(private readonly logger: ClassloggerService) {} + + /** + * Binds a column dependent reference to the component. + * Subscribes to subjects from the column dependent reference and its container. + * @param cdref a column dependent reference + */ + public bind(cdref: ColumnDependentReference): void { + if (cdref && cdref.column) { + this.columnContainer.init(cdref); + const value = this.toArray(this.columnContainer.value); + this.control.setValue(value, { emitEvent: false }); + if (this.columnContainer.isValueRequired && this.columnContainer.canEdit) { + this.logger.debug(this, 'value is required'); + this.control.setValidators(Validators.required); + } + + if (cdref.minlengthSubject) { + this.subscribers.push( + cdref.minlengthSubject.subscribe(() => { + if (this.columnContainer.isValueRequired && this.columnContainer.canEdit) { + this.logger.debug(this, 'value is required'); + this.control.setValidators(Validators.required); + } else { + this.control.setValidators(null); + } + }), + ); + } + + this.subscribers.push( + this.columnContainer.subscribe(() => { + if (!this.isWriting) { + return; + } + if (this.control.value !== this.columnContainer.value) { + this.control.setValue(this.toArray(this.columnContainer.value)); + } + this.valueHasChanged.emit({ value: this.control.value }); + }), + ); + this.subscribers.push(this.control.valueChanges.subscribe(async (value) => this.writeValue(this.fromArray(value)))); + this.initOptions(); + this.logger.trace(this, 'Control initialized'); + } else { + this.logger.error(this, 'The Column Dependent Reference is undefined'); + } + } + + /** + * Updates the value for the CDR. + * @param values The values, that will be used as a new value. + */ + private async writeValue(value: Number): Promise { + this.logger.debug(this, 'writeValue called with value', value); + + if (!this.columnContainer.canEdit || this.columnContainer.value === value) { + return; + } + + try { + this.isWriting = true; + this.logger.debug(this, 'writeValue - PutValue...'); + await this.columnContainer.updateValue(value); + } catch (e) { + this.logger.error(this, e); + } finally { + this.isWriting = false; + const valueAfterWrite = this.toArray(this.columnContainer.value); + if (this.control.value !== valueAfterWrite) { + this.control.setValue(valueAfterWrite, { emitEvent: false }); + } + } + + this.valueHasChanged.emit({ value, forceEmit: true }); + } + + private toArray(value: Number): Number[] { + let array: number[] = []; + let binaryRepresentation = parseInt(value.toString(), 10).toString(2); + binaryRepresentation = binaryRepresentation.split('').reverse().join(''); + + // You need to reverse the string to get the power of 2 corresponding + for (let i = binaryRepresentation.length - 1; i >= 0; i--) { + if (Number(binaryRepresentation[i]) === 1) { + array.push(Math.pow(2, i)); + } + } + return array; + } + + private fromArray(values: number[]): Number { + let result = 0; + for (let idx = 0; idx < values.length; idx++) { + result += values[idx]; + } + return result; + } + + protected getBinaryNumber(idx: number): number { + return Math.pow(2, idx); + } + + private async initOptions(): Promise { + const bitMaskCaptions = this.columnContainer?.metaData?.GetBitMaskCaptions(); + const allOptions = bitMaskCaptions?.map((elem, idx): EuiSelectOption => ({ display: elem, value: this.getBinaryNumber(idx) })) || []; + // filter out deactivated captions, these are empty strings + this.options = allOptions?.filter((option: EuiSelectOption) => !!option?.display.length); + } +} diff --git a/imxweb/projects/qbm/src/lib/cdr/edit-boolean/edit-boolean.component.html b/imxweb/projects/qbm/src/lib/cdr/edit-boolean/edit-boolean.component.html index 9080b4daa..044835833 100644 --- a/imxweb/projects/qbm/src/lib/cdr/edit-boolean/edit-boolean.component.html +++ b/imxweb/projects/qbm/src/lib/cdr/edit-boolean/edit-boolean.component.html @@ -1,12 +1,12 @@ - - {{ columnContainer?.display | translate }} + + {{ columnContainer.display | translate }} - + - - + diff --git a/imxweb/projects/qbm/src/lib/cdr/edit-boolean/edit-boolean.component.scss b/imxweb/projects/qbm/src/lib/cdr/edit-boolean/edit-boolean.component.scss index d1d1a4480..2593e3e7a 100644 --- a/imxweb/projects/qbm/src/lib/cdr/edit-boolean/edit-boolean.component.scss +++ b/imxweb/projects/qbm/src/lib/cdr/edit-boolean/edit-boolean.component.scss @@ -7,14 +7,8 @@ } mat-checkbox { - display: inline-block; - span { white-space: normal; word-break: break-word; } } - -.imx-checkbox-spinner { - margin-left: 10px; -} diff --git a/imxweb/projects/qbm/src/lib/cdr/edit-boolean/edit-boolean.component.ts b/imxweb/projects/qbm/src/lib/cdr/edit-boolean/edit-boolean.component.ts index 1d6202d9c..69b888ac2 100644 --- a/imxweb/projects/qbm/src/lib/cdr/edit-boolean/edit-boolean.component.ts +++ b/imxweb/projects/qbm/src/lib/cdr/edit-boolean/edit-boolean.component.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR diff --git a/imxweb/projects/qbm/src/lib/cdr/edit-date/edit-date.component.html b/imxweb/projects/qbm/src/lib/cdr/edit-date/edit-date.component.html index 482c41131..41ea6de24 100644 --- a/imxweb/projects/qbm/src/lib/cdr/edit-date/edit-date.component.html +++ b/imxweb/projects/qbm/src/lib/cdr/edit-date/edit-date.component.html @@ -6,8 +6,10 @@ [max]="columnContainer?.valueConstraint?.MaxValue" [isValueRequired]="columnContainer?.isValueRequired" [withTime]="withTime" + [validateOnlyOnChange]="validateOnlyOnChange" [isLoading]="isBusy" - [imxIdentifierSuffix]="'-cdr-' + columnContainer?.name"> + [imxIdentifierSuffix]="'-cdr-' + columnContainer?.name" +> diff --git a/imxweb/projects/qbm/src/lib/cdr/edit-date/edit-date.component.scss b/imxweb/projects/qbm/src/lib/cdr/edit-date/edit-date.component.scss index bcd8ac2d3..bfe7e877f 100644 --- a/imxweb/projects/qbm/src/lib/cdr/edit-date/edit-date.component.scss +++ b/imxweb/projects/qbm/src/lib/cdr/edit-date/edit-date.component.scss @@ -1,3 +1,3 @@ :host { flex-grow: 1; -} \ No newline at end of file +} diff --git a/imxweb/projects/qbm/src/lib/cdr/edit-date/edit-date.component.ts b/imxweb/projects/qbm/src/lib/cdr/edit-date/edit-date.component.ts index 52fc4d146..7f41513ee 100644 --- a/imxweb/projects/qbm/src/lib/cdr/edit-date/edit-date.component.ts +++ b/imxweb/projects/qbm/src/lib/cdr/edit-date/edit-date.component.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -26,19 +26,18 @@ import { Component, ErrorHandler, EventEmitter, OnDestroy } from '@angular/core'; import { UntypedFormControl } from '@angular/forms'; +import moment, { Moment } from 'moment-timezone'; import { Subject, Subscription } from 'rxjs'; import { CdrEditor, ValueHasChangedEventArg } from '../cdr-editor.interface'; import { ColumnDependentReference } from '../column-dependent-reference.interface'; -import moment from 'moment-timezone'; -import { Moment } from 'moment-timezone'; -import { EntityColumnContainer } from '../entity-column-container'; +import { DateFormat } from '@imx-modules/imx-qbm-dbts'; import { ClassloggerService } from '../../classlogger/classlogger.service'; -import { DateFormat } from 'imx-qbm-dbts'; +import { EntityColumnContainer } from '../entity-column-container'; /** * Provides a {@link CdrEditor | CDR editor} for editing / viewing date value columns - * + * * It uses a {@link DateComponent | date component} for editing the value. * When set to read-only, it uses a {@link ViewPropertyComponent | view property component} to display the content. */ @@ -73,8 +72,11 @@ export class EditDateComponent implements CdrEditor, OnDestroy { */ public isBusy = false; + public validateOnlyOnChange: boolean = false; + private readonly subscribers: Subscription[] = []; private isWriting = false; + private previousValue: Moment | undefined; /** * Determines, if a time control should be added. @@ -86,7 +88,10 @@ export class EditDateComponent implements CdrEditor, OnDestroy { return dateFormat === DateFormat.DateTime || dateFormat === DateFormat.UtcDateTime; } - public constructor(private readonly errorHandler: ErrorHandler, private logger: ClassloggerService) {} + public constructor( + private readonly errorHandler: ErrorHandler, + private logger: ClassloggerService, + ) {} /** * Unsubscribes all events, after the 'OnDestroy' hook is triggered. @@ -110,7 +115,7 @@ export class EditDateComponent implements CdrEditor, OnDestroy { this.subscribers.push( cdref.minlengthSubject.subscribe(() => { this.resetControlValue(); - }) + }), ); } @@ -123,8 +128,9 @@ export class EditDateComponent implements CdrEditor, OnDestroy { this.logger.trace(this, 'Control set to new value'); this.resetControlValue(); this.valueHasChanged.emit({ value: this.control.value }); + this.control.updateValueAndValidity({ onlySelf: true, emitEvent: true }); } - }) + }), ); this.setValidators(); @@ -140,7 +146,7 @@ export class EditDateComponent implements CdrEditor, OnDestroy { } this.valueHasChanged.emit({ value: this.control.value }); }); - }) + }), ); } } @@ -162,8 +168,8 @@ export class EditDateComponent implements CdrEditor, OnDestroy { this.updateControlValue(value); } - private updateControlValue(value: Moment): void { - if (this.control.value !== value) { + private updateControlValue(value: Moment | undefined): void { + if (!this.control.value?.isSame(value)) { this.control.setValue(value, { emitEvent: false }); } } @@ -173,14 +179,15 @@ export class EditDateComponent implements CdrEditor, OnDestroy { * @param value The Moment object, that is used as the new value for the control. */ private async writeValue(value: Moment): Promise { - if (this.control.errors) { + if (this.control.errors || value?.isSame(this.previousValue)) { return; } - + this.previousValue = value; // Beware: the columnContainer used date while the date editor uses moment!! const date = value == null ? undefined : value.toDate(); + const resetValue = this.columnContainer.value; this.logger.debug(this, 'writeValue called with value', date); - if (!this.columnContainer.canEdit || this.columnContainer.value === date) { + if (!this.columnContainer.canEdit || moment(this.columnContainer.value).isSame(value)) { return; } @@ -192,6 +199,7 @@ export class EditDateComponent implements CdrEditor, OnDestroy { await this.columnContainer.updateValue(date); } catch (error) { this.errorHandler.handleError(error); + this.control?.setValue(resetValue ? moment(resetValue) : undefined); } finally { this.isBusy = false; this.isWriting = false; diff --git a/imxweb/projects/qbm/src/lib/cdr/edit-default/edit-default.component.html b/imxweb/projects/qbm/src/lib/cdr/edit-default/edit-default.component.html index b21f28bd8..8ce5a02b8 100644 --- a/imxweb/projects/qbm/src/lib/cdr/edit-default/edit-default.component.html +++ b/imxweb/projects/qbm/src/lib/cdr/edit-default/edit-default.component.html @@ -1,27 +1,28 @@ - - - {{ columnContainer?.display | translate }} - - -
    - -
    - - {{ '#LDS#This field is mandatory.' | translate }} - - - {{validationErrorMessage}} - + + + {{ columnContainer?.display ?? '' | translate }} + + +
    + +
    + + {{ '#LDS#This field is mandatory.' | translate }} + + + {{ validationErrorMessage }} +
    - - + - diff --git a/imxweb/projects/qbm/src/lib/cdr/edit-default/edit-default.component.scss b/imxweb/projects/qbm/src/lib/cdr/edit-default/edit-default.component.scss index 541e13d68..22baa9c3e 100644 --- a/imxweb/projects/qbm/src/lib/cdr/edit-default/edit-default.component.scss +++ b/imxweb/projects/qbm/src/lib/cdr/edit-default/edit-default.component.scss @@ -1,4 +1,4 @@ -@import "@elemental-ui/core/src/styles/_palette.scss"; +@import '@elemental-ui/core/src/styles/_palette.scss'; :host { display: flex; @@ -6,10 +6,6 @@ align-items: center; } -.mat-form-field { - flex-grow: 1; -} - .imx-spacer { height: 30px; } diff --git a/imxweb/projects/qbm/src/lib/cdr/edit-default/edit-default.component.ts b/imxweb/projects/qbm/src/lib/cdr/edit-default/edit-default.component.ts index 0e5e390d6..658865002 100644 --- a/imxweb/projects/qbm/src/lib/cdr/edit-default/edit-default.component.ts +++ b/imxweb/projects/qbm/src/lib/cdr/edit-default/edit-default.component.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -38,7 +38,7 @@ import { EditorBase } from '../editor-base'; @Component({ selector: 'imx-edit-default', templateUrl: './edit-default.component.html', - styleUrls: ['./edit-default.component.scss'] + styleUrls: ['./edit-default.component.scss'], }) export class EditDefaultComponent extends EditorBase { public readonly control = new UntypedFormControl(undefined, { updateOn: 'blur' }); diff --git a/imxweb/projects/qbm/src/lib/cdr/edit-fk/edit-fk-multi.component.html b/imxweb/projects/qbm/src/lib/cdr/edit-fk/edit-fk-multi.component.html index c4bdba47f..c3a52bf19 100644 --- a/imxweb/projects/qbm/src/lib/cdr/edit-fk/edit-fk-multi.component.html +++ b/imxweb/projects/qbm/src/lib/cdr/edit-fk/edit-fk-multi.component.html @@ -1,13 +1,24 @@ - - {{ columnContainer?.display | translate }} - + {{ columnContainer.display | translate }} + + [required]="columnContainer.isValueRequired" + />
    -
    @@ -16,11 +27,6 @@
    - - - + diff --git a/imxweb/projects/qbm/src/lib/cdr/edit-fk/edit-fk-multi.component.scss b/imxweb/projects/qbm/src/lib/cdr/edit-fk/edit-fk-multi.component.scss index ce02f3513..ed30bbbdc 100644 --- a/imxweb/projects/qbm/src/lib/cdr/edit-fk/edit-fk-multi.component.scss +++ b/imxweb/projects/qbm/src/lib/cdr/edit-fk/edit-fk-multi.component.scss @@ -1,41 +1,5 @@ +@import 'common/select'; + :host { - display: flex; flex-grow: 1; - flex-direction: column; - align-items: baseline; - - >* { - margin-right: 10px; - } -} - -input { - flex: 1; -} - -.mat-form-field { - width: 100%; -} - -.imx-spacer { - height: 30px; -} - -.mat-button { - min-width: initial; } - -.mat-error { - margin-top: 5px; - font-size: small; -} - -.imx-suffix-container { - display: flex; - margin-bottom: 5px; - - > *:not(:last-child) { - margin-right: 5px; - margin-top: 0; - } -} \ No newline at end of file diff --git a/imxweb/projects/qbm/src/lib/cdr/edit-fk/edit-fk-multi.component.spec.ts b/imxweb/projects/qbm/src/lib/cdr/edit-fk/edit-fk-multi.component.spec.ts index 7e3790e7a..6ca7e8d98 100644 --- a/imxweb/projects/qbm/src/lib/cdr/edit-fk/edit-fk-multi.component.spec.ts +++ b/imxweb/projects/qbm/src/lib/cdr/edit-fk/edit-fk-multi.component.spec.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -26,18 +26,18 @@ import { fakeAsync, tick } from '@angular/core/testing'; import { FormsModule, ReactiveFormsModule } from '@angular/forms'; -import { of } from 'rxjs'; import { EuiSidesheetService } from '@elemental-ui/core'; import { TranslateModule, TranslateService } from '@ngx-translate/core'; +import { of } from 'rxjs'; -import { IValueMetadata } from 'imx-qbm-dbts'; -import { EntityColumnStub } from '../../testing/entity-column-stub.spec'; -import { clearStylesFromDOM } from '../../testing/clear-styles.spec'; -import { EditFkMultiComponent } from './edit-fk-multi.component'; -import { MultiValueService } from '../../multi-value/multi-value.service'; +import { IValueMetadata } from '@imx-modules/imx-qbm-dbts'; import { MockBuilder, MockedComponentFixture, MockRender } from 'ng-mocks'; -import { CdrModule } from '../cdr.module'; import { QbmDefaultMocks } from '../../../default-mocks.spec'; +import { MultiValueService } from '../../multi-value/multi-value.service'; +import { clearStylesFromDOM } from '../../testing/clear-styles.spec'; +import { EntityColumnStub } from '../../testing/entity-column-stub.spec'; +import { CdrModule } from '../cdr.module'; +import { EditFkMultiComponent } from './edit-fk-multi.component'; describe('EditFkMultiComponent', () => { let component: EditFkMultiComponent; @@ -105,7 +105,7 @@ describe('EditFkMultiComponent', () => { valueStructs: [], expected: { value: undefined, - display: undefined, + display: '', controlValue: undefined, }, canEdit: true, @@ -114,7 +114,7 @@ describe('EditFkMultiComponent', () => { valueStructs: [], expected: { value: undefined, - display: undefined, + display: '', controlValue: undefined, }, canEdit: false, @@ -163,8 +163,8 @@ describe('EditFkMultiComponent', () => { expect(component.control.value).toEqual(start.display); expect(component.columnContainer.value).toEqual(start.value); } - }) - ) + }), + ), ); for (const testcase of [ @@ -194,7 +194,7 @@ describe('EditFkMultiComponent', () => { } else { expect(component.control.errors).toBeNull(); } - } + }, ); } }); diff --git a/imxweb/projects/qbm/src/lib/cdr/edit-fk/edit-fk-multi.component.ts b/imxweb/projects/qbm/src/lib/cdr/edit-fk/edit-fk-multi.component.ts index afc34ecfd..7d99f9b54 100644 --- a/imxweb/projects/qbm/src/lib/cdr/edit-fk/edit-fk-multi.component.ts +++ b/imxweb/projects/qbm/src/lib/cdr/edit-fk/edit-fk-multi.component.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -26,24 +26,25 @@ import { Component, EventEmitter, OnDestroy, OnInit } from '@angular/core'; import { UntypedFormControl } from '@angular/forms'; -import { TranslateService } from '@ngx-translate/core'; import { EuiSidesheetService } from '@elemental-ui/core'; -import { Subscription, Subject } from 'rxjs'; +import { TranslateService } from '@ngx-translate/core'; +import { Subject, Subscription } from 'rxjs'; -import { CdrEditor, ValueHasChangedEventArg } from '../cdr-editor.interface'; -import { EntityColumnContainer } from '../entity-column-container'; -import { ColumnDependentReference } from '../column-dependent-reference.interface'; +import { ValueStruct } from '@imx-modules/imx-qbm-dbts'; +import { calculateSidesheetWidth } from '../../base/sidesheet-helper'; import { ClassloggerService } from '../../classlogger/classlogger.service'; -import { FkAdvancedPickerComponent } from '../../fk-advanced-picker/fk-advanced-picker.component'; -import { ValueStruct } from 'imx-qbm-dbts'; import { ForeignKeySelection } from '../../fk-advanced-picker/./foreign-key-selection.interface'; +import { FkAdvancedPickerComponent } from '../../fk-advanced-picker/fk-advanced-picker.component'; +import { FkHierarchicalDialogComponent } from '../../fk-hierarchical-dialog/fk-hierarchical-dialog.component'; import { LdsReplacePipe } from '../../lds-replace/lds-replace.pipe'; import { MultiValueService } from '../../multi-value/multi-value.service'; -import { FkHierarchicalDialogComponent } from '../../fk-hierarchical-dialog/fk-hierarchical-dialog.component'; +import { CdrEditor, ValueHasChangedEventArg } from '../cdr-editor.interface'; +import { ColumnDependentReference } from '../column-dependent-reference.interface'; +import { EntityColumnContainer } from '../entity-column-container'; /** * Provides a {@link CdrEditor | CDR editor} for editing / viewing multi foreign key value columns. - * + * * Its value is changed by clicking on the 'select' / 'change' button. Then a side sheet is opened for selecting multiple values. * When set to read-only, it uses a {@link ViewPropertyComponent | view property component} to display the content. */ @@ -62,7 +63,7 @@ export class EditFkMultiComponent implements CdrEditor, OnInit, OnDestroy { public loading = false; private isWriting = false; - private currentValueStruct: ValueStruct; + private currentValueStruct: ValueStruct; private isHierarchical: boolean; private readonly subscribers: Subscription[] = []; @@ -71,13 +72,13 @@ export class EditFkMultiComponent implements CdrEditor, OnInit, OnDestroy { * Creates a new EditFkMultiComponent. * @param logger Log service. * @param sidesheet Side sheet, that opens the picker dialog for selecting objects. - */ + */ constructor( private readonly logger: ClassloggerService, private readonly sidesheet: EuiSidesheetService, private readonly translateService: TranslateService, private readonly ldsReplace: LdsReplacePipe, - private readonly multiValueProvider: MultiValueService + private readonly multiValueProvider: MultiValueService, ) {} public ngOnDestroy(): void { @@ -117,7 +118,7 @@ export class EditFkMultiComponent implements CdrEditor, OnInit, OnDestroy { this.subscribers.push( cdref.minlengthSubject.subscribe((elem) => { this.setValidators(); - }) + }), ); } @@ -131,7 +132,7 @@ export class EditFkMultiComponent implements CdrEditor, OnInit, OnDestroy { this, `Control (${this.columnContainer.name}) set to new value:`, this.columnContainer.value, - this.control.value + this.control.value, ); this.currentValueStruct = { DataValue: this.columnContainer.value, @@ -140,7 +141,7 @@ export class EditFkMultiComponent implements CdrEditor, OnInit, OnDestroy { this.control.setValue(await this.multiValueToDisplay(this.currentValueStruct), { emitEvent: false }); } this.valueHasChanged.emit({ value: this.currentValueStruct }); - }) + }), ); this.subscribers.push( @@ -152,7 +153,7 @@ export class EditFkMultiComponent implements CdrEditor, OnInit, OnDestroy { DataValue: this.columnContainer.value, DisplayValue: this.columnContainer.displayValue, }; - const candidateCollection = await this.columnContainer.fkRelations[0]?.Get({ PageSize: -1 }); + const candidateCollection = await this.columnContainer.fkRelations?.[0]?.Get({ PageSize: -1 }); this.isHierarchical = candidateCollection?.Hierarchy != null; this.setValidators(); this.control.setValue(await this.multiValueToDisplay(this.currentValueStruct), { emitEvent: false }); @@ -161,7 +162,7 @@ export class EditFkMultiComponent implements CdrEditor, OnInit, OnDestroy { this.loading = false; } }); - }) + }), ); this.logger.trace(this, 'Control initialized'); } else { @@ -191,7 +192,7 @@ export class EditFkMultiComponent implements CdrEditor, OnInit, OnDestroy { subTitle: await this.translateService.get(this.columnContainer?.display).toPromise(), padding: '0', disableClose: true, - width: 'max(600px,60%)', + width: calculateSidesheetWidth(), testId: this.isHierarchical ? 'edit-fk-multi-hierarchy-sidesheet' : 'edit-fk-multi-sidesheet', data: { idList: this.multiValueProvider.getValues(this.columnContainer.value), @@ -211,7 +212,7 @@ export class EditFkMultiComponent implements CdrEditor, OnInit, OnDestroy { selection.candidates && selection.candidates.length > 0 ? { DataValue: this.multiValueProvider.getMultiValue(selection.candidates.map((v) => v.DataValue)), - DisplayValue: this.multiValueProvider.getMultiValue(selection.candidates.map((v) => v.DisplayValue)), + DisplayValue: this.multiValueProvider.getMultiValue(selection.candidates.map((v) => v.DisplayValue ?? '')), } : { DataValue: undefined, @@ -232,7 +233,7 @@ export class EditFkMultiComponent implements CdrEditor, OnInit, OnDestroy { * Updates the value for the CDR. * @param value The new value struct, that is used for the new value of the component. */ - private async writeValue(value: ValueStruct): Promise { + private async writeValue(value: ValueStruct): Promise { this.logger.debug(this, 'writeValue - called with', value); if (!this.columnContainer.canEdit) { @@ -270,7 +271,7 @@ export class EditFkMultiComponent implements CdrEditor, OnInit, OnDestroy { this.valueHasChanged.emit({ value: this.currentValueStruct, forceEmit: true }); } - private async multiValueToDisplay(value: ValueStruct): Promise { + private async multiValueToDisplay(value: ValueStruct): Promise { const values = this.multiValueProvider.getValues(value.DataValue); if (values == null) { diff --git a/imxweb/projects/qbm/src/lib/cdr/edit-fk/edit-fk.component.html b/imxweb/projects/qbm/src/lib/cdr/edit-fk/edit-fk.component.html index 34dd8394a..c12daca68 100644 --- a/imxweb/projects/qbm/src/lib/cdr/edit-fk/edit-fk.component.html +++ b/imxweb/projects/qbm/src/lib/cdr/edit-fk/edit-fk.component.html @@ -1,25 +1,43 @@ - + - {{ columnContainer?.display | translate }} - - ({{ '#LDS#Table: {0}' | translate | ldsReplace : metadataProvider.tables[selectedTable.TableName]?.DisplaySingular - || selectedTable.TableName }}) + {{ columnContainer.display | translate }} + + ({{ + '#LDS#Table: {0}' + | translate + | ldsReplace: metadataProvider.tables[selectedTable.TableName]?.DisplaySingular || selectedTable.TableName + }}) - - + [required]="columnContainer.isValueRequired" + /> + - + [attr.data-imx-identifier]="'cdr-edit-fk-mat-option-assign-candidate-' + columnContainer?.name" + >
    {{ getDisplay(candidate) }}
    @@ -29,35 +47,47 @@
    -
    - {{ '#LDS#Loading...' | translate }} + + {{ '#LDS#Loading...' | translate }}
    - + [attr.data-imx-identifier]="'cdr-edit-fk-button-remove-assignment-' + columnContainer?.name" + >
    -
    - {{ '#LDS#The value entered in the {0} box could not be found. Please select a value from the list.' | translate | - ldsReplace : (columnContainer?.display | translate) }} + {{ + '#LDS#The value entered in the {0} box could not be found. Please select a value from the list.' + | translate + | ldsReplace: (columnContainer.display | translate) + }} {{ '#LDS#This field is mandatory.' | translate }}
    - - - - + + - \ No newline at end of file + diff --git a/imxweb/projects/qbm/src/lib/cdr/edit-fk/edit-fk.component.scss b/imxweb/projects/qbm/src/lib/cdr/edit-fk/edit-fk.component.scss index 761bc542e..a99329601 100644 --- a/imxweb/projects/qbm/src/lib/cdr/edit-fk/edit-fk.component.scss +++ b/imxweb/projects/qbm/src/lib/cdr/edit-fk/edit-fk.component.scss @@ -1,4 +1,4 @@ -@import "@elemental-ui/core/src/styles/_palette.scss"; +@import '@elemental-ui/core/src/styles/_palette.scss'; @import '@elemental-ui/core/src/styles/_eui_palette.scss'; :host { flex-grow: 1; @@ -6,60 +6,25 @@ align-items: center; } -.mat-form-field { - flex-grow: 1; -} - .imx-spacer { height: 30px; } -.imx-candidate-option { - line-height: 1.5em; - display: flex; - width: 100%; - height: 50px; - - .imx-candidate-item { - width: 100%; - - .imx-candidate-content { - width: 100%; - overflow: hidden; - - .imx-candidate-display { - font-size: 14px; - line-height: 14px; - text-overflow: ellipsis; - overflow: hidden; - width: 100vw; - } - - .imx-candidate-longdisplay { - font-size: 12px; - text-overflow: ellipsis; - overflow: hidden; - } - } - } -} - .imx-viewport { height: 200px; width: 100%; overflow-x: hidden; } -.mat-option { +.mat-mdc-option { height: 50px; } .imx-suffix-container { display: flex; - margin-bottom: 5px; > *:not(:last-child) { - margin-right: 5px; + margin-right: 8px; margin-top: 0; } } @@ -68,16 +33,16 @@ cursor: pointer; margin-top: 0; display: inline; - line-height: 35px; + line-height: 36px !important; } .eui-dark-theme { :host { color: $color-gray-2; - .imx-candidate-option{ - .imx-candidate-item{ - .imx-candidate-content{ - .imx-candidate-display{ + .imx-candidate-option { + .imx-candidate-item { + .imx-candidate-content { + .imx-candidate-display { color: $color-gray-5; } .imx-candidate-longdisplay { @@ -92,10 +57,10 @@ .eui-contrast-theme { :host { color: $color-gray-0; - .imx-candidate-option{ - .imx-candidate-item{ - .imx-candidate-content{ - .imx-candidate-display{ + .imx-candidate-option { + .imx-candidate-item { + .imx-candidate-content { + .imx-candidate-display { color: $color-gray-0; } .imx-candidate-longdisplay { diff --git a/imxweb/projects/qbm/src/lib/cdr/edit-fk/edit-fk.component.spec.ts b/imxweb/projects/qbm/src/lib/cdr/edit-fk/edit-fk.component.spec.ts index eca50406e..8de399133 100644 --- a/imxweb/projects/qbm/src/lib/cdr/edit-fk/edit-fk.component.spec.ts +++ b/imxweb/projects/qbm/src/lib/cdr/edit-fk/edit-fk.component.spec.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -25,22 +25,22 @@ */ import { discardPeriodicTasks, fakeAsync, tick } from '@angular/core/testing'; -import { MatAutocompleteSelectedEvent } from '@angular/material/autocomplete'; import { FormsModule, ReactiveFormsModule } from '@angular/forms'; +import { MatAutocompleteSelectedEvent } from '@angular/material/autocomplete'; import { EuiSidesheetService } from '@elemental-ui/core'; -import { EditFkComponent } from './edit-fk.component'; -import { IForeignKeyInfo, IValueMetadata, IEntityColumn, ValueStruct, EntityCollectionData } from 'imx-qbm-dbts'; -import { EntityColumnStub } from '../../testing/entity-column-stub.spec'; -import { clearStylesFromDOM } from '../../testing/clear-styles.spec'; -import { MetadataService } from '../../base/metadata.service'; -import { MockBuilder, MockedComponentFixture, MockRender } from 'ng-mocks'; -import { CdrModule } from '../cdr.module'; +import { ChangeDetectorRef } from '@angular/core'; +import { EntityCollectionData, IEntityColumn, IForeignKeyInfo, IValueMetadata, ValueStruct } from '@imx-modules/imx-qbm-dbts'; import { TranslateModule, TranslateService } from '@ngx-translate/core'; +import { MockBuilder, MockRender, MockedComponentFixture } from 'ng-mocks'; import { QbmDefaultMocks } from '../../../default-mocks.spec'; +import { MetadataService } from '../../base/metadata.service'; import { LdsReplacePipe } from '../../lds-replace/lds-replace.pipe'; +import { clearStylesFromDOM } from '../../testing/clear-styles.spec'; +import { EntityColumnStub } from '../../testing/entity-column-stub.spec'; +import { CdrModule } from '../cdr.module'; import { ViewPropertyComponent } from '../view-property/view-property.component'; -import { ChangeDetectorRef } from '@angular/core'; +import { EditFkComponent } from './edit-fk.component'; function createColumnStub( value: ValueStruct, @@ -108,6 +108,7 @@ describe('EditFkComponent', () => { const metadataMinLength = 5; const columnStub = new EntityColumnStub('value', 'display', { CanEdit: () => !testcase.input.isReadonly, + GetDisplay: () => 'display', GetMinLength: () => metadataMinLength, GetFkRelations: () => [{} as IForeignKeyInfo] as ReadonlyArray, GetLimitedValues: () => undefined, @@ -183,7 +184,7 @@ describe('EditFkComponent', () => { expect(component.control.value).toEqual(testcase.valueStructs[0]); expect(component.columnContainer.value).toEqual(testcase.valueStructs[0].DataValue); } else { - expect(component.columnContainer.displayValue).toBeUndefined(); + expect(component.columnContainer.displayValue).toEqual(''); expect(component.control.value).toBeUndefined(); expect(component.columnContainer.value).toBeUndefined(); } @@ -226,7 +227,7 @@ describe('EditFkComponent', () => { await component.removeAssignment(); - expect(component.columnContainer.displayValue).toBeUndefined(); + expect(component.columnContainer.displayValue).toEqual(''); expect(component.control.value).toBeUndefined(); expect(component.columnContainer.value).toBeUndefined(); }); @@ -296,7 +297,6 @@ describe('EditFkComponent', () => { expect(component.candidates[0].DataValue).toEqual(candidateCollection.Entities[0].Columns.XObjectKey.Value); expect(component.candidates[0].DisplayValue).toEqual(candidateCollection.Entities[0].Display); - expect(component.hasCandidatesOrIsLoading).toEqual(true); }); [ diff --git a/imxweb/projects/qbm/src/lib/cdr/edit-fk/edit-fk.component.ts b/imxweb/projects/qbm/src/lib/cdr/edit-fk/edit-fk.component.ts index 0a027be34..830da52dd 100644 --- a/imxweb/projects/qbm/src/lib/cdr/edit-fk/edit-fk.component.ts +++ b/imxweb/projects/qbm/src/lib/cdr/edit-fk/edit-fk.component.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -42,8 +42,16 @@ import { TranslateService } from '@ngx-translate/core'; import { Subject, Subscription } from 'rxjs'; import { debounceTime } from 'rxjs/operators'; -import { CollectionLoadParameters, DbObjectKey, IForeignKeyInfo, ValueStruct } from 'imx-qbm-dbts'; +import { + CollectionLoadParameters, + DbObjectKey, + EntityColumnData, + EntityData, + IForeignKeyInfo, + ValueStruct, +} from '@imx-modules/imx-qbm-dbts'; import { MetadataService } from '../../base/metadata.service'; +import { calculateSidesheetWidth } from '../../base/sidesheet-helper'; import { ClassloggerService } from '../../classlogger/classlogger.service'; import { Candidate } from '../../fk-advanced-picker/candidate.interface'; import { FkAdvancedPickerComponent } from '../../fk-advanced-picker/fk-advanced-picker.component'; @@ -78,21 +86,6 @@ export class EditFkComponent implements CdrEditor, AfterViewInit, OnDestroy, OnI */ public readonly updateRequested = new Subject(); - /** - * Indicator that the component is loading data from the server, or has a candidate list. - */ - public get hasCandidatesOrIsLoading(): boolean { - return ( - this.candidatesTotalCount > 0 || - // make sure the user can change selectedTable even if there are no available candidates - // in the first candidate table - this.columnContainer?.fkRelations?.length > 1 || - this.parameters?.search?.length > 0 || - this.parameters?.filter != null || - this.loading - ); - } - /** * The form control associated with the editor. */ @@ -111,14 +104,13 @@ export class EditFkComponent implements CdrEditor, AfterViewInit, OnDestroy, OnI /** * A list of possible candidates, that can be selected. */ + // public candidates: Candidate[] ; private _candidates: Candidate[]; - public get candidates(): Candidate[] { return this._candidates; } - - public set candidates(value: Candidate[]) { - this._candidates = value; + public set candidates(value: Candidate[] | undefined | null) { + this._candidates = value || []; } /** @@ -130,7 +122,7 @@ export class EditFkComponent implements CdrEditor, AfterViewInit, OnDestroy, OnI * The table, the user is currently selecting items from. * It is possible to choose elements from different tables at the same time. */ - public selectedTable: IForeignKeyInfo; + public selectedTable: IForeignKeyInfo | undefined; /** * Indicator, whether the candidate data is hierarchical or not. @@ -149,7 +141,7 @@ export class EditFkComponent implements CdrEditor, AfterViewInit, OnDestroy, OnI private parameters: CollectionLoadParameters = { PageSize: this.pageSize, StartIndex: 0 }; private savedParameters: CollectionLoadParameters; - private savedCandidates: Candidate[]; + private savedCandidates: Candidate[] | undefined | null; private readonly subscribers: Subscription[] = []; private isWriting = false; @@ -166,7 +158,7 @@ export class EditFkComponent implements CdrEditor, AfterViewInit, OnDestroy, OnI private readonly changeDetectorRef: ChangeDetectorRef, private readonly translator: TranslateService, public readonly metadataProvider: MetadataService, - private readonly errorHandler: ErrorHandler + private readonly errorHandler: ErrorHandler, ) { this.subscribers.push( this.control.valueChanges.pipe(debounceTime(500)).subscribe(async (keyword) => { @@ -176,7 +168,7 @@ export class EditFkComponent implements CdrEditor, AfterViewInit, OnDestroy, OnI } return this.search(keyword); - }) + }), ); } @@ -233,7 +225,7 @@ export class EditFkComponent implements CdrEditor, AfterViewInit, OnDestroy, OnI * @returns The display of the candidate object. */ public getDisplay(candidate: Candidate): string { - return candidate ? candidate.DisplayValue : undefined; + return candidate?.DisplayValue ?? ''; } /** @@ -300,11 +292,11 @@ export class EditFkComponent implements CdrEditor, AfterViewInit, OnDestroy, OnI subTitle: await this.translator.get(this.columnContainer?.display).toPromise(), padding: '0', disableClose: true, - width: 'max(600px,60%)', + width: calculateSidesheetWidth(), testId: this.isHierarchical ? 'edit-fk-hierarchy-sidesheet' : 'edit-fk-sidesheet', data: { fkRelations: this.columnContainer.fkRelations, - selectedTableName: this.selectedTable.TableName, + selectedTableName: this.selectedTable?.TableName, idList: this.columnContainer.value ? [this.columnContainer.value] : [], }, }); @@ -343,7 +335,7 @@ export class EditFkComponent implements CdrEditor, AfterViewInit, OnDestroy, OnI cdref.minlengthSubject.subscribe((elem) => { this.setControlValue(); this.changeDetectorRef.detectChanges(); - }) + }), ); } @@ -361,7 +353,7 @@ export class EditFkComponent implements CdrEditor, AfterViewInit, OnDestroy, OnI this, `Control (${this.columnContainer.name}) set to new value:`, this.columnContainer.value, - this.control.value + this.control.value, ); this.candidates = []; this.setControlValue(); @@ -371,7 +363,7 @@ export class EditFkComponent implements CdrEditor, AfterViewInit, OnDestroy, OnI } } this.valueHasChanged.emit({ value: this.control.value }); - }) + }), ); this.subscribers.push( @@ -387,7 +379,7 @@ export class EditFkComponent implements CdrEditor, AfterViewInit, OnDestroy, OnI } this.valueHasChanged.emit({ value: this.control.value }); }); - }) + }), ); this.logger.trace(this, 'Control initialized', this.control.value); } else { @@ -402,7 +394,7 @@ export class EditFkComponent implements CdrEditor, AfterViewInit, OnDestroy, OnI private setControlValue(): void { const fkRelations = this.columnContainer.fkRelations; if (fkRelations && fkRelations.length > 0) { - let table: IForeignKeyInfo; + let table: IForeignKeyInfo | undefined; if (fkRelations.length > 1 && this.columnContainer.value) { this.logger.trace(this, 'the column already has a value, and it is a dynamic foreign key'); const dbObjectKey = DbObjectKey.FromXml(this.columnContainer.value); @@ -415,7 +407,7 @@ export class EditFkComponent implements CdrEditor, AfterViewInit, OnDestroy, OnI this.control.setValue(this.getValueStruct(), { emitEvent: false }); const autoCompleteValidator = (control) => - control.value != null || this.parameters.search == null || this.candidates?.length > 0 ? null : { checkAutocomplete: true }; + control.value != null || this.parameters.search == null || !!this.candidates?.length ? null : { checkAutocomplete: true }; if (this.columnContainer.isValueRequired && this.columnContainer.canEdit) { this.control.setValidators([ (control) => (control.value == null || control.value.length === 0 ? { required: true } : null), @@ -445,7 +437,7 @@ export class EditFkComponent implements CdrEditor, AfterViewInit, OnDestroy, OnI * Updates the value for the CDR. * @param value The new value struct, that should be used as the new control value. */ - private async writeValue(value: ValueStruct): Promise { + private async writeValue(value: ValueStruct): Promise { this.logger.debug(this, 'writeValue called with value', value); if (!this.columnContainer.canEdit || this.equal(this.getValueStruct(), value)) { @@ -493,45 +485,50 @@ export class EditFkComponent implements CdrEditor, AfterViewInit, OnDestroy, OnI const multipleFkRelations = this.columnContainer.fkRelations && this.columnContainer.fkRelations.length > 1; const identityRelatedTable = this.selectedTable.TableName === 'Person'; - const newCandidates = candidateCollection.Entities?.map((entityData) => { - let key: string = ''; - let detailValue: string = entityData.LongDisplay ?? ''; - const defaultEmailColumn = entityData.Columns?.['DefaultEmailAddress']; - /** - * If the candidates data relate to identities (fkRelation Person table) - * then we want to use the email address for the detail line (displayLong) - */ - if (defaultEmailColumn && identityRelatedTable) { - detailValue = defaultEmailColumn.Value; - } - if (multipleFkRelations) { - this.logger.trace(this, 'dynamic foreign key'); - const xObjectKeyColumn = entityData.Columns?.['XObjectKey']; - key = xObjectKeyColumn ? xObjectKeyColumn.Value : undefined; - } else { - this.logger.trace(this, 'foreign key'); - - const parentColumn = entityData.Columns ? entityData.Columns[this.columnContainer.fkRelations[0].ColumnName] : undefined; - if (parentColumn != null) { - this.logger.trace(this, 'Use value from explicit parent column'); - key = parentColumn.Value; + const newCandidates: Candidate[] = + candidateCollection.Entities?.map((entityData) => { + let key: string | null | undefined = null; + let detailValue: string = entityData.LongDisplay ?? ''; + const defaultEmailColumn = entityData?.Columns?.['DefaultEmailAddress']; + /** + * If the candidates data relate to identities (fkRelation Person table) + * then we want to use the email address for the detail line (displayLong) + */ + if (defaultEmailColumn && identityRelatedTable) { + detailValue = defaultEmailColumn.Value; + } + if (multipleFkRelations) { + this.logger.trace(this, 'dynamic foreign key'); + const xObjectKeyColumn = entityData.Columns?.['XObjectKey']; + key = xObjectKeyColumn ? xObjectKeyColumn.Value : undefined; } else { - this.logger.trace(this, 'Use the primary key'); - const keys = entityData.Keys; - key = keys && keys.length ? keys[0] : ''; + this.logger.trace(this, 'foreign key'); + const parentColumn = entityData.Columns + ? this.getColumCaseInsensitive( + entityData, + this.columnContainer.fkRelations?.[0].fkColumnName || this.columnContainer.fkRelations?.[0].ColumnName || '', + ) + : undefined; + if (parentColumn != null) { + this.logger.trace(this, 'Use value from explicit parent column'); + key = parentColumn?.Value ?? ''; + } else { + this.logger.trace(this, 'Use the primary key'); + const keys = entityData.Keys; + key = keys && keys.length ? keys[0] : ''; + } } - } - return { - DataValue: key, - DisplayValue: entityData.Display, - displayLong: detailValue, - }; - }); + return { + DataValue: key ?? '', + DisplayValue: entityData.Display ?? '', + displayLong: detailValue, + }; + }) ?? []; if (concatCandidates) { - this.candidates.push(...(newCandidates || [])); + if (newCandidates) this.candidates?.push(...(newCandidates || [])); this.savedCandidates = this.candidates; } else { - this.candidates = newCandidates || []; + this.candidates = newCandidates; this.savedCandidates = this.candidates; } } finally { @@ -541,7 +538,7 @@ export class EditFkComponent implements CdrEditor, AfterViewInit, OnDestroy, OnI } } - private getValueStruct(): ValueStruct { + private getValueStruct(): ValueStruct | undefined { if (this.columnContainer.value) { return { DataValue: this.columnContainer.value, DisplayValue: this.columnContainer.displayValue || '' }; } @@ -549,9 +546,9 @@ export class EditFkComponent implements CdrEditor, AfterViewInit, OnDestroy, OnI return undefined; } - private equal(value: ValueStruct, value2: ValueStruct): boolean { + private equal(value: ValueStruct | undefined, value2: ValueStruct | undefined): boolean { if (value && value2) { - return value.DataValue === value2.DataValue && value.DisplayValue === value.DisplayValue; + return value.DataValue === value2.DataValue && value.DisplayValue === value2.DisplayValue; } return value == null && value2 == null; @@ -575,13 +572,25 @@ export class EditFkComponent implements CdrEditor, AfterViewInit, OnDestroy, OnI }, 0); } + private getColumCaseInsensitive(entityData: EntityData, columnname: string): EntityColumnData | undefined { + const index = Object.keys(entityData.Columns ?? []).find((key) => key.toLowerCase() === columnname.toLowerCase()); + if (index) { + return entityData.Columns?.[index]; + } + return undefined; + } + private async onScroll(event: any): Promise { if ( event.target.offsetHeight + event.target.scrollTop >= event.target.scrollHeight - 10 && !this.loading && - this.candidatesTotalCount > this.pageSize + this.parameters.StartIndex + this.candidatesTotalCount > this.pageSize + (this.parameters.StartIndex ?? 0) ) { this.changeDetectorRef.detectChanges(); + if (!this.parameters.StartIndex) { + this.parameters.StartIndex = 0; + } + this.parameters.StartIndex += this.pageSize; await this.updateCandidates(this.parameters, false, true); this.changeDetectorRef.detectChanges(); diff --git a/imxweb/projects/qbm/src/lib/cdr/edit-image/edit-image.component.html b/imxweb/projects/qbm/src/lib/cdr/edit-image/edit-image.component.html index cbbe32b1a..9c3d38be5 100644 --- a/imxweb/projects/qbm/src/lib/cdr/edit-image/edit-image.component.html +++ b/imxweb/projects/qbm/src/lib/cdr/edit-image/edit-image.component.html @@ -1,12 +1,14 @@ - + - + (change)="resetFileFormatErrorState(); file.click()" + (remove)="remove()" +> diff --git a/imxweb/projects/qbm/src/lib/cdr/edit-image/edit-image.component.scss b/imxweb/projects/qbm/src/lib/cdr/edit-image/edit-image.component.scss index bcd8ac2d3..bfe7e877f 100644 --- a/imxweb/projects/qbm/src/lib/cdr/edit-image/edit-image.component.scss +++ b/imxweb/projects/qbm/src/lib/cdr/edit-image/edit-image.component.scss @@ -1,3 +1,3 @@ :host { flex-grow: 1; -} \ No newline at end of file +} diff --git a/imxweb/projects/qbm/src/lib/cdr/edit-image/edit-image.component.ts b/imxweb/projects/qbm/src/lib/cdr/edit-image/edit-image.component.ts index 9d515ffa0..dede468f0 100644 --- a/imxweb/projects/qbm/src/lib/cdr/edit-image/edit-image.component.ts +++ b/imxweb/projects/qbm/src/lib/cdr/edit-image/edit-image.component.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -28,16 +28,16 @@ import { Component, ElementRef, EventEmitter, OnDestroy, ViewChild } from '@angu import { UntypedFormControl, Validators } from '@angular/forms'; import { Subject, Subscription } from 'rxjs'; -import { ColumnDependentReference } from '../column-dependent-reference.interface'; -import { CdrEditor, ValueHasChangedEventArg } from '../cdr-editor.interface'; -import { EntityColumnContainer } from '../entity-column-container'; import { ClassloggerService } from '../../classlogger/classlogger.service'; -import { Base64ImageService } from '../../images/base64-image.service'; import { FileSelectorService } from '../../file-selector/file-selector.service'; +import { Base64ImageService } from '../../images/base64-image.service'; +import { CdrEditor, ValueHasChangedEventArg } from '../cdr-editor.interface'; +import { ColumnDependentReference } from '../column-dependent-reference.interface'; +import { EntityColumnContainer } from '../entity-column-container'; /** * Provides a {@link CdrEditor | CDR editor} for editing / viewing image data columns. - * + * * To change its value, it uses an {@link ImageSelectComponent | image select component}. * When set to read-only, it uses an {@link ImageViewComponent | image view component} to display the content. */ @@ -55,7 +55,7 @@ export class EditImageComponent implements CdrEditor, OnDestroy { /** * Gets a small hint, if the file format is not supported. */ - public get fileFormatHint(): string { + public get fileFormatHint(): string | undefined { return this.fileFormatError ? '#LDS#Please select an image in PNG format.' : undefined; } @@ -92,11 +92,11 @@ export class EditImageComponent implements CdrEditor, OnDestroy { constructor( private readonly logger: ClassloggerService, private readonly imageProvider: Base64ImageService, - private readonly fileSelector: FileSelectorService + private readonly fileSelector: FileSelectorService, ) { this.subscriptions.push( this.fileSelector.fileFormatError.subscribe(() => (this.fileFormatError = true)), - this.fileSelector.fileSelected.subscribe((filepath) => this.writeValue(this.imageProvider.getImageData(filepath))) + this.fileSelector.fileSelected.subscribe((filepath) => this.writeValue(this.imageProvider.getImageData(filepath))), ); } @@ -124,7 +124,7 @@ export class EditImageComponent implements CdrEditor, OnDestroy { this.subscriptions.push( cdref.minlengthSubject.subscribe(() => { this.setValidators(); - }) + }), ); } this.subscriptions.push( @@ -137,7 +137,7 @@ export class EditImageComponent implements CdrEditor, OnDestroy { this.control.setValue(this.columnContainer.value, { emitEvent: false }); } this.valueHasChanged.emit({ value: this.control.value }); - }) + }), ); this.subscriptions.push( @@ -154,7 +154,7 @@ export class EditImageComponent implements CdrEditor, OnDestroy { } finally { } }); - }) + }), ); } } @@ -171,8 +171,8 @@ export class EditImageComponent implements CdrEditor, OnDestroy { * @param files A list of files to emit as *.png. */ // TODO: Check Upgrade - public emitFiles(files: FileList): void { - this.fileSelector.emitFiles(files, 'image/png'); + public emitFiles(files: EventTarget | null): void { + this.fileSelector.emitFiles((files as any).files, 'image/png'); } /** @@ -202,7 +202,7 @@ export class EditImageComponent implements CdrEditor, OnDestroy { * Updates the value for the CDR. * @param value The new image url, that will be used as the new value. */ - private async writeValue(value: string): Promise { + private async writeValue(value: string | undefined): Promise { this.logger.debug(this, 'writeValue called with value', value); if (!this.columnContainer.canEdit || this.columnContainer.value === value) { diff --git a/imxweb/projects/qbm/src/lib/cdr/edit-limited-value/edit-limited-value.component.html b/imxweb/projects/qbm/src/lib/cdr/edit-limited-value/edit-limited-value.component.html index 01fdcf038..87b5f34a6 100644 --- a/imxweb/projects/qbm/src/lib/cdr/edit-limited-value/edit-limited-value.component.html +++ b/imxweb/projects/qbm/src/lib/cdr/edit-limited-value/edit-limited-value.component.html @@ -1,15 +1,25 @@ - + - {{ columnContainer?.display | translate }} + {{ columnContainer.display | translate }} - - {{ columnContainer?.displayValue }} + + {{ + columnContainer?.displayValue + }} {{ limitedValue.Description }}
    - +
    diff --git a/imxweb/projects/qbm/src/lib/cdr/edit-limited-value/edit-limited-value.component.scss b/imxweb/projects/qbm/src/lib/cdr/edit-limited-value/edit-limited-value.component.scss index fa4f45863..0a4d9f197 100644 --- a/imxweb/projects/qbm/src/lib/cdr/edit-limited-value/edit-limited-value.component.scss +++ b/imxweb/projects/qbm/src/lib/cdr/edit-limited-value/edit-limited-value.component.scss @@ -5,23 +5,3 @@ display: flex; align-items: center; } - - -mat-form-field { - flex-grow: 1; - - [matsuffix] { - - margin-left: 10px; // set margin to infix - - eui-icon { - margin-top: unset; // correct margin-top: -16px from _material_fixes.scss - display: block; - } - - mat-spinner { - display: inline-flex; - margin-right: 10px; - } - } -} diff --git a/imxweb/projects/qbm/src/lib/cdr/edit-limited-value/edit-limited-value.component.ts b/imxweb/projects/qbm/src/lib/cdr/edit-limited-value/edit-limited-value.component.ts index f99f13e2e..92d59a014 100644 --- a/imxweb/projects/qbm/src/lib/cdr/edit-limited-value/edit-limited-value.component.ts +++ b/imxweb/projects/qbm/src/lib/cdr/edit-limited-value/edit-limited-value.component.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -27,14 +27,14 @@ import { Component } from '@angular/core'; import { UntypedFormControl } from '@angular/forms'; -import { EditorBase } from '../editor-base'; import { ClassloggerService } from '../../classlogger/classlogger.service'; +import { EditorBase } from '../editor-base'; /** * Provides a {@link CdrEditor | CDR editor} for editing / viewing limited value columns. - * + * * To change the value it uses an Angular Material select component. - * When set to read-only, it uses a {@link ViewPropertyComponent | view property component} to display the content. + * When set to read-only, it uses a {@link ViewPropertyComponent | view property component} to display the content. */ @Component({ selector: 'imx-edit-limited-value', diff --git a/imxweb/projects/qbm/src/lib/cdr/edit-multi-limited-value/edit-multi-limited-value.component.html b/imxweb/projects/qbm/src/lib/cdr/edit-multi-limited-value/edit-multi-limited-value.component.html index 8bd8aa2b7..92c47f49a 100644 --- a/imxweb/projects/qbm/src/lib/cdr/edit-multi-limited-value/edit-multi-limited-value.component.html +++ b/imxweb/projects/qbm/src/lib/cdr/edit-multi-limited-value/edit-multi-limited-value.component.html @@ -1,23 +1,32 @@ - - {{ columnContainer?.display | translate }} - -
    - - {{ item.Description }} - -
    -
    - -
    + + {{ columnContainer.display | translate }} + +
    + + + {{ item.Description }} + + +
    +
    + +
    - {{ '#LDS#This field is mandatory.' | translate }} + {{ '#LDS#This field is mandatory.' | translate }} - - + diff --git a/imxweb/projects/qbm/src/lib/cdr/edit-multi-limited-value/edit-multi-limited-value.component.scss b/imxweb/projects/qbm/src/lib/cdr/edit-multi-limited-value/edit-multi-limited-value.component.scss index 3b9b75c44..2683e6df1 100644 --- a/imxweb/projects/qbm/src/lib/cdr/edit-multi-limited-value/edit-multi-limited-value.component.scss +++ b/imxweb/projects/qbm/src/lib/cdr/edit-multi-limited-value/edit-multi-limited-value.component.scss @@ -1,13 +1,9 @@ -@import '@elemental-ui/core/src/styles/_palette.scss'; +@import '@elemental-ui/core/src/styles/_eui_palette.scss'; :host { flex-grow: 1; } -.mat-form-field { - width: 100%; -} - .imx-error-margin { margin-top: -15px; margin-left: 10px; @@ -18,12 +14,6 @@ flex-flow: column; } -.imx-red-checkbox { - ::ng-deep .mat-checkbox-frame { - border-color: $phoenix-red; - } -} - .imx-suffix-container { display: flex; margin-bottom: 5px; diff --git a/imxweb/projects/qbm/src/lib/cdr/edit-multi-limited-value/edit-multi-limited-value.component.ts b/imxweb/projects/qbm/src/lib/cdr/edit-multi-limited-value/edit-multi-limited-value.component.ts index 111716158..38881f9cf 100644 --- a/imxweb/projects/qbm/src/lib/cdr/edit-multi-limited-value/edit-multi-limited-value.component.ts +++ b/imxweb/projects/qbm/src/lib/cdr/edit-multi-limited-value/edit-multi-limited-value.component.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -25,20 +25,24 @@ */ import { ChangeDetectorRef, Component, EventEmitter, OnDestroy } from '@angular/core'; -import { UntypedFormArray, UntypedFormControl } from '@angular/forms'; +import { FormGroup, UntypedFormArray, UntypedFormControl } from '@angular/forms'; import { Subject, Subscription } from 'rxjs'; import { debounceTime, distinctUntilChanged, tap } from 'rxjs/operators'; -import { LimitedValueData } from 'imx-qbm-dbts'; -import { ColumnDependentReference } from '../column-dependent-reference.interface'; +import { LimitedValueData } from '@imx-modules/imx-qbm-dbts'; import { ClassloggerService } from '../../classlogger/classlogger.service'; +import { MultiValueService } from '../../multi-value/multi-value.service'; import { CdrEditor, ValueHasChangedEventArg } from '../cdr-editor.interface'; +import { ColumnDependentReference } from '../column-dependent-reference.interface'; import { EntityColumnContainer } from '../entity-column-container'; -import { MultiValueService } from '../../multi-value/multi-value.service'; + +interface LimitedForm { + array: UntypedFormArray; +} /** * Provides a {@link CdrEditor | CDR editor} for editing / viewing multi limited value columns - * + * * To change the value it uses a list of check boxes with one box per possible value. * When set to read-only, it uses a {@link ViewPropertyComponent | view property component} to display the content. */ @@ -54,7 +58,9 @@ export class EditMultiLimitedValueComponent implements CdrEditor, OnDestroy { * The form control associated with the editor. */ // TODO: Check Upgrade - public control = new UntypedFormArray([]); + public control = new FormGroup({ + array: new UntypedFormArray([]), + }); /** * The container that wraps the column functionality. @@ -68,12 +74,12 @@ export class EditMultiLimitedValueComponent implements CdrEditor, OnDestroy { public readonly pendingChanged = new EventEmitter(); private readonly subscriptions: Subscription[] = []; - private isWriting = false; + public isWriting = false; constructor( private readonly logger: ClassloggerService, private readonly changeDetectorRef: ChangeDetectorRef, - private readonly multiValueProvider: MultiValueService + private readonly multiValueProvider: MultiValueService, ) {} /** @@ -93,22 +99,20 @@ export class EditMultiLimitedValueComponent implements CdrEditor, OnDestroy { this.columnContainer.init(cdref); this.initValues(); this.subscriptions.push( - this.control.valueChanges - .pipe( - tap(() => this.pendingChanged.emit(true)), - debounceTime(1400), - distinctUntilChanged(), - ) - .subscribe( - async (values) => await this.writeValue(values) - ) + this.control.controls.array.valueChanges + .pipe( + tap(() => this.pendingChanged.emit(true)), + debounceTime(1400), + distinctUntilChanged(), + ) + .subscribe(async (values) => await this.writeValue(values)), ); this.subscriptions.push( this.columnContainer.subscribe(() => { if (this.isWriting) { return; } - if (this.getSelectedNamesMultiValue(this.control.value) !== this.columnContainer.value) { + if (this.getSelectedNamesMultiValue(this.control.controls.array.value) !== this.columnContainer.value) { this.initValues(); } @@ -116,7 +120,7 @@ export class EditMultiLimitedValueComponent implements CdrEditor, OnDestroy { this.subscriptions.push( cdref.minlengthSubject.subscribe(() => { this.initValues(); - }) + }), ); } @@ -124,12 +128,12 @@ export class EditMultiLimitedValueComponent implements CdrEditor, OnDestroy { this.updateRequested.subscribe(() => setTimeout(() => { this.initValues(); - this.control.updateValueAndValidity({ onlySelf: true, emitEvent: false }); - }) - ) + this.control.controls.array.updateValueAndValidity({ onlySelf: true, emitEvent: false }); + }), + ), ); this.valueHasChanged.emit({ value: this.columnContainer.value }); - }) + }), ); this.logger.trace(this, 'Control initialized'); } else { @@ -141,16 +145,16 @@ export class EditMultiLimitedValueComponent implements CdrEditor, OnDestroy { * Initializes possible values and marks all selected ones. */ public initValues(): void { - if (this.control.controls?.length > 0) { + if (this.control.controls.array.controls?.length > 0) { return; } const selectedValues = this.multiValueProvider.getValues(this.columnContainer.value); - this.columnContainer.limitedValuesContainer.values.forEach((limitedValueData) => - this.control.push(new UntypedFormControl(this.isSelected(limitedValueData, selectedValues))) + this.columnContainer.limitedValuesContainer?.values?.forEach((limitedValueData) => + this.control.controls.array.push(new UntypedFormControl(this.isSelected(limitedValueData, selectedValues))), ); if (this.columnContainer.isValueRequired && this.columnContainer.canEdit) { - this.control.setValidators((control: UntypedFormArray) => - control.controls.find((checkBox) => checkBox.value) ? null : { required: true } + this.control.controls.array.setValidators((control: UntypedFormArray) => + control.controls.find((checkBox) => checkBox.value) ? null : { required: true }, ); } } @@ -178,33 +182,32 @@ export class EditMultiLimitedValueComponent implements CdrEditor, OnDestroy { try { this.logger.debug(this, 'writeValue - updateCdrValue...'); this.isWriting = true; - this.control.disable({ emitEvent: false }); + this.control.controls.array.disable({ emitEvent: false }); this.changeDetectorRef.detectChanges(); await this.columnContainer.updateValue(value); } catch (e) { this.logger.error(this, e); } finally { this.isWriting = false; - this.control.enable({ emitEvent: false }); + this.control.controls.array.enable({ emitEvent: false }); this.pendingChanged.emit(false); this.changeDetectorRef.detectChanges(); - if (this.getSelectedNamesMultiValue(this.control.value) !== this.columnContainer.value) { + if (this.getSelectedNamesMultiValue(this.control.controls.array.value) !== this.columnContainer.value) { const selectedValues = this.multiValueProvider.getValues(this.columnContainer.value); - this.control.controls.forEach((checkBox, index) => - checkBox.setValue(this.isSelected(this.columnContainer.limitedValuesContainer.values[index], selectedValues), { + this.control.controls.array.controls.forEach((checkBox, index) => + checkBox.setValue(this.isSelected(this.columnContainer.limitedValuesContainer.values?.[index], selectedValues), { emitEvent: false, - }) + }), ); } } } - /** * Gets the MultiValue of the selected values. * @param values The array of booleans provided by the checkboxes */ - private getSelectedNamesMultiValue(values: boolean[]): string { + private getSelectedNamesMultiValue(values: boolean[]): string | undefined { return this.multiValueProvider.getMultiValue(this.getSelectedNames(values)); } @@ -216,13 +219,18 @@ export class EditMultiLimitedValueComponent implements CdrEditor, OnDestroy { const selectedValues: string[] = []; values.forEach((value, index) => { if (value) { - selectedValues.push(this.columnContainer.limitedValuesContainer.values[index]?.Value); + const newValue = this.columnContainer.limitedValuesContainer.values?.[index]?.Value; + if (newValue) { + selectedValues.push(this.columnContainer.limitedValuesContainer.values?.[index]?.Value); + } } }); return selectedValues; } - private isSelected(limitedValueData: LimitedValueData, selectedValues: string[]): boolean { - return selectedValues && selectedValues.indexOf(limitedValueData.Value + '') > -1; + private isSelected(limitedValueData: LimitedValueData | undefined, selectedValues: string[] | undefined): boolean { + if (!limitedValueData || !selectedValues) return false; + + return selectedValues && selectedValues.indexOf(limitedValueData.Value) > -1; } } diff --git a/imxweb/projects/qbm/src/lib/cdr/edit-multi-value/edit-multi-value.component.html b/imxweb/projects/qbm/src/lib/cdr/edit-multi-value/edit-multi-value.component.html index b3cb3e413..38b7c5361 100644 --- a/imxweb/projects/qbm/src/lib/cdr/edit-multi-value/edit-multi-value.component.html +++ b/imxweb/projects/qbm/src/lib/cdr/edit-multi-value/edit-multi-value.component.html @@ -1,16 +1,18 @@ - - {{ columnContainer?.display | translate }} - + + {{ columnContainer.display | translate }} + {{ '#LDS#This field is mandatory.' | translate }} - - + - diff --git a/imxweb/projects/qbm/src/lib/cdr/edit-multi-value/edit-multi-value.component.scss b/imxweb/projects/qbm/src/lib/cdr/edit-multi-value/edit-multi-value.component.scss index a2fcf0657..7bd3a17ca 100644 --- a/imxweb/projects/qbm/src/lib/cdr/edit-multi-value/edit-multi-value.component.scss +++ b/imxweb/projects/qbm/src/lib/cdr/edit-multi-value/edit-multi-value.component.scss @@ -2,11 +2,7 @@ flex-grow: 1; } -.mat-form-field { - width: 100%; -} - .imx-multi-value-container { display: flex; flex-flow: column; -} \ No newline at end of file +} diff --git a/imxweb/projects/qbm/src/lib/cdr/edit-multi-value/edit-multi-value.component.ts b/imxweb/projects/qbm/src/lib/cdr/edit-multi-value/edit-multi-value.component.ts index b9c967d42..a40792e0e 100644 --- a/imxweb/projects/qbm/src/lib/cdr/edit-multi-value/edit-multi-value.component.ts +++ b/imxweb/projects/qbm/src/lib/cdr/edit-multi-value/edit-multi-value.component.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -28,15 +28,15 @@ import { Component, EventEmitter, OnDestroy } from '@angular/core'; import { UntypedFormControl, Validators } from '@angular/forms'; import { Subscription } from 'rxjs'; -import { ColumnDependentReference } from '../column-dependent-reference.interface'; import { ClassloggerService } from '../../classlogger/classlogger.service'; -import { EntityColumnContainer } from '../entity-column-container'; -import { CdrEditor, ValueHasChangedEventArg } from '../cdr-editor.interface'; import { MultiValueService } from '../../multi-value/multi-value.service'; +import { CdrEditor, ValueHasChangedEventArg } from '../cdr-editor.interface'; +import { ColumnDependentReference } from '../column-dependent-reference.interface'; +import { EntityColumnContainer } from '../entity-column-container'; /** * Provides a {@link CdrEditor | CDR editor} for editing / viewing multi valued columns. - * + * * To change its value, it uses a text area. Each line represents a part of the multi value. * When set to read-only, it uses a {@link ViewPropertyComponent | view property component} to display the content. */ @@ -64,7 +64,10 @@ export class EditMultiValueComponent implements CdrEditor, OnDestroy { private readonly subscribers: Subscription[] = []; private isWriting = false; - constructor(private readonly logger: ClassloggerService, private readonly multiValueProvider: MultiValueService) {} + constructor( + private readonly logger: ClassloggerService, + private readonly multiValueProvider: MultiValueService, + ) {} /** * Unsubscribes all events, after the 'OnDestroy' hook is triggered. @@ -96,7 +99,7 @@ export class EditMultiValueComponent implements CdrEditor, OnDestroy { } else { this.control.setValidators(null); } - }) + }), ); } @@ -109,7 +112,7 @@ export class EditMultiValueComponent implements CdrEditor, OnDestroy { this.control.setValue(this.columnContainer.value); } this.valueHasChanged.emit({ value: this.control.value }); - }) + }), ); this.subscribers.push(this.control.valueChanges.subscribe(async (value) => this.writeValue(this.fromTextArea(value)))); this.logger.trace(this, 'Control initialized'); @@ -122,7 +125,7 @@ export class EditMultiValueComponent implements CdrEditor, OnDestroy { * Updates the value for the CDR. * @param values The values, that will be used as a new value. */ - private async writeValue(value: string): Promise { + private async writeValue(value: string | undefined): Promise { this.logger.debug(this, 'writeValue called with value', value); if (!this.columnContainer.canEdit || this.columnContainer.value === value) { @@ -146,12 +149,12 @@ export class EditMultiValueComponent implements CdrEditor, OnDestroy { this.valueHasChanged.emit({ value, forceEmit: true }); } - private toTextArea(value: string): string { + private toTextArea(value: string): string | undefined { const values = this.multiValueProvider.getValues(value); return values && values.length > 0 ? values.join('\r\n') : undefined; } - private fromTextArea(value: string): string { + private fromTextArea(value: string): string | undefined { return value ? this.multiValueProvider.getMultiValue(value.replace(/\r\n/g, '\n').split('\n')) : undefined; } } diff --git a/imxweb/projects/qbm/src/lib/cdr/edit-multiline/edit-multiline.component.html b/imxweb/projects/qbm/src/lib/cdr/edit-multiline/edit-multiline.component.html index 835321c87..bca9076d9 100644 --- a/imxweb/projects/qbm/src/lib/cdr/edit-multiline/edit-multiline.component.html +++ b/imxweb/projects/qbm/src/lib/cdr/edit-multiline/edit-multiline.component.html @@ -1,22 +1,24 @@ - - {{ columnContainer.display | translate }} - - -
    - -
    - - {{ '#LDS#This field is mandatory.' | translate }} - + + {{ columnContainer.display | translate }} + +
    + +
    + + {{ '#LDS#This field is mandatory.' | translate }} +
    - - + diff --git a/imxweb/projects/qbm/src/lib/cdr/edit-multiline/edit-multiline.component.scss b/imxweb/projects/qbm/src/lib/cdr/edit-multiline/edit-multiline.component.scss index 24645d267..3e9f20bb0 100644 --- a/imxweb/projects/qbm/src/lib/cdr/edit-multiline/edit-multiline.component.scss +++ b/imxweb/projects/qbm/src/lib/cdr/edit-multiline/edit-multiline.component.scss @@ -1,20 +1,7 @@ -textarea.mat-input-element.cdk-textarea-autosize { - box-sizing: content-box; - } - :host { flex-grow: 1; display: flex; align-items: center; - - ::ng-deep .mat-form-field-appearance-outline .mat-form-field-suffix { - align-self: flex-start; - margin-top: 15px; - } -} - -.mat-form-field { - flex-grow: 1; } .imx-spacer { @@ -24,10 +11,10 @@ textarea.mat-input-element.cdk-textarea-autosize { .imx-suffix-container { display: flex; margin-bottom: 5px; - - > *{ + + > * { justify-self: flex-start; margin-right: 5px; margin-top: 0; } -} \ No newline at end of file +} diff --git a/imxweb/projects/qbm/src/lib/cdr/edit-multiline/edit-multiline.component.ts b/imxweb/projects/qbm/src/lib/cdr/edit-multiline/edit-multiline.component.ts index e5b3d8157..e5d5103b3 100644 --- a/imxweb/projects/qbm/src/lib/cdr/edit-multiline/edit-multiline.component.ts +++ b/imxweb/projects/qbm/src/lib/cdr/edit-multiline/edit-multiline.component.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR diff --git a/imxweb/projects/qbm/src/lib/cdr/edit-number/edit-number.component.html b/imxweb/projects/qbm/src/lib/cdr/edit-number/edit-number.component.html index 66a3693fd..0dfb4a758 100644 --- a/imxweb/projects/qbm/src/lib/cdr/edit-number/edit-number.component.html +++ b/imxweb/projects/qbm/src/lib/cdr/edit-number/edit-number.component.html @@ -1,29 +1,38 @@ - - - {{ columnContainer?.display | translate }} - - -
    - -
    - - {{ '#LDS#WD_InputInvalidInteger' | translate | ldsReplace: control.value }} - - - {{ '#LDS#Please enter a number greater than or equal to {0}.' | translate | ldsReplace: columnContainer.valueConstraint.MinValue }} - - - {{ '#LDS#Please enter a number less than or equal to {0}.' | translate | ldsReplace: columnContainer.valueConstraint.MaxValue }} - + + + {{ columnContainer.display | translate }} + + +
    + +
    + + {{ '#LDS#The value you entered is invalid. Enter an integer number.' | translate }} + + + {{ + '#LDS#The value you entered is invalid. Enter a number greater than or equal to {0}.' + | translate + | ldsReplace: columnContainer.valueConstraint?.MinValue + }} + + + {{ + '#LDS#The value you entered is invalid. Enter a number less than or equal to {0}.' + | translate + | ldsReplace: columnContainer.valueConstraint?.MaxValue + }} +
    - - + diff --git a/imxweb/projects/qbm/src/lib/cdr/edit-number/edit-number.component.scss b/imxweb/projects/qbm/src/lib/cdr/edit-number/edit-number.component.scss index 1901f0a99..58e286ef8 100644 --- a/imxweb/projects/qbm/src/lib/cdr/edit-number/edit-number.component.scss +++ b/imxweb/projects/qbm/src/lib/cdr/edit-number/edit-number.component.scss @@ -1,4 +1,4 @@ -@import "@elemental-ui/core/src/styles/_palette.scss"; +@import '@elemental-ui/core/src/styles/_palette.scss'; :host { flex-grow: 1; @@ -6,10 +6,6 @@ align-items: center; } -.mat-form-field { - flex-grow: 1; -} - .imx-spacer { height: 30px; } @@ -18,8 +14,4 @@ display: flex; margin-bottom: 5px; - > .imx-suffix-spinner { - margin-right: 5px; - margin-top: 0; - } } diff --git a/imxweb/projects/qbm/src/lib/cdr/edit-number/edit-number.component.ts b/imxweb/projects/qbm/src/lib/cdr/edit-number/edit-number.component.ts index 728721d4d..0d9c1b2ab 100644 --- a/imxweb/projects/qbm/src/lib/cdr/edit-number/edit-number.component.ts +++ b/imxweb/projects/qbm/src/lib/cdr/edit-number/edit-number.component.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -27,7 +27,7 @@ import { AfterViewInit, Component } from '@angular/core'; import { AbstractControl, UntypedFormControl, ValidatorFn } from '@angular/forms'; -import { ValType } from 'imx-qbm-dbts'; +import { ValType } from '@imx-modules/imx-qbm-dbts'; import { ClassloggerService } from '../../classlogger/classlogger.service'; import { EditorBase } from '../editor-base'; import { NumberError } from './number-error.interface'; diff --git a/imxweb/projects/qbm/src/lib/cdr/edit-number/number-error.interface.ts b/imxweb/projects/qbm/src/lib/cdr/edit-number/number-error.interface.ts index 21494121d..8482a4070 100644 --- a/imxweb/projects/qbm/src/lib/cdr/edit-number/number-error.interface.ts +++ b/imxweb/projects/qbm/src/lib/cdr/edit-number/number-error.interface.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR diff --git a/imxweb/projects/qbm/src/lib/cdr/edit-number/number-validator.service.ts b/imxweb/projects/qbm/src/lib/cdr/edit-number/number-validator.service.ts index 0d1ef64d4..edfc43239 100644 --- a/imxweb/projects/qbm/src/lib/cdr/edit-number/number-validator.service.ts +++ b/imxweb/projects/qbm/src/lib/cdr/edit-number/number-validator.service.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -26,7 +26,7 @@ import { Injectable } from '@angular/core'; -import { ValueConstraint } from 'imx-qbm-dbts'; +import { ValueConstraint } from '@imx-modules/imx-qbm-dbts'; import { NumberError } from './number-error.interface'; /** @@ -48,7 +48,7 @@ export class NumberValidatorService { * @param range The {@link ValueConstraint}, that determines the bounds. * @returns */ - public validate(value: any, range: ValueConstraint): NumberError | null { + public validate(value: any, range: ValueConstraint | undefined): NumberError | null { if (value == null) { return null; } diff --git a/imxweb/projects/qbm/src/lib/cdr/edit-risk-index/edit-risk-index.component.html b/imxweb/projects/qbm/src/lib/cdr/edit-risk-index/edit-risk-index.component.html index 84f5765a0..d0b8af7ff 100644 --- a/imxweb/projects/qbm/src/lib/cdr/edit-risk-index/edit-risk-index.component.html +++ b/imxweb/projects/qbm/src/lib/cdr/edit-risk-index/edit-risk-index.component.html @@ -1,25 +1,28 @@ - - {{ columnContainer?.display | translate }} - -
    +
    +
    + +
    + +
    +
    +
    #LDS#No risk - + #LDS#Maximum risk
    -
    - -
    - - - +
    - - - \ No newline at end of file + + diff --git a/imxweb/projects/qbm/src/lib/cdr/edit-risk-index/edit-risk-index.component.scss b/imxweb/projects/qbm/src/lib/cdr/edit-risk-index/edit-risk-index.component.scss index 4f9c59b0a..2dc95f434 100644 --- a/imxweb/projects/qbm/src/lib/cdr/edit-risk-index/edit-risk-index.component.scss +++ b/imxweb/projects/qbm/src/lib/cdr/edit-risk-index/edit-risk-index.component.scss @@ -3,70 +3,27 @@ :host { flex-grow: 1; } - -.slider-container { +.imx-slider-label-container{ display: flex; align-items: center; - - .mat-slider { - width: 300px; - flex-grow: 2; - } - - .slider-label { - &__main { - display: block; - } - &__prefix { - font-size: 14px; - margin-right: 8px; - } - &__suffix { - font-size: 14px; - margin-left: 8px; - } - } - - ::ng-deep .mat-slider-thumb-container { - .mat-slider-thumb-label { - transform: rotate(45deg); - border-radius: 50% 50% 0; - } - .mat-slider-thumb { - transform: scale(0); - } - .mat-slider-thumb-label-text { - opacity: 1; + min-height: 24px; + .imx-suffix-container { + display: flex; + margin-left: 10px; + width: 24px; + height: 24px; + + > * { + margin-right: 5px; + margin-top: 0; } } } - -:host { +.imx-slider-container{ display: flex; align-items: center; -} - -.mat-form-field { - flex-grow: 1; -} - -.imx-suffix-container { - display: flex; - margin-bottom: 5px; - margin-left: 10px; - width: 30px; - height: 30px; - - > * { - margin-right: 5px; - margin-top: 0; - } -} - -@media only screen and (max-width: 320px) { - .slider-container { - .mat-slider-horizontal { - min-width: unset; - } + gap: 12px; + .mat-mdc-slider{ + flex-grow: 1; } } diff --git a/imxweb/projects/qbm/src/lib/cdr/edit-risk-index/edit-risk-index.component.ts b/imxweb/projects/qbm/src/lib/cdr/edit-risk-index/edit-risk-index.component.ts index a542e93ee..cd32ea92c 100644 --- a/imxweb/projects/qbm/src/lib/cdr/edit-risk-index/edit-risk-index.component.ts +++ b/imxweb/projects/qbm/src/lib/cdr/edit-risk-index/edit-risk-index.component.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -26,11 +26,12 @@ import { Component } from '@angular/core'; import { UntypedFormControl } from '@angular/forms'; +import { MatSliderDragEvent } from '@angular/material/slider'; import { EditorBase } from '../editor-base'; /** * Provides a {@link CdrEditor | CDR editor} for editing / viewing risk index columns. - * + * * To change the value, it uses an Angular Material slider, that ranges between 0 and 1. * When set to read-only, it uses a {@link ViewPropertyComponent | view property component} to display the content. */ @@ -43,12 +44,7 @@ export class EditRiskIndexComponent extends EditorBase { /** * The form control associated with the editor. */ - public readonly control = new UntypedFormControl(undefined, { updateOn: 'blur' }); - - /** - * @ignore Only used in template. - */ - public sliderFocused = false; + public readonly control = new UntypedFormControl(undefined, { updateOn: 'submit' }); /** * Converts a number value to a string in the current language. @@ -58,4 +54,9 @@ export class EditRiskIndexComponent extends EditorBase { public formatLabel(value: number): string { return value.toLocaleString(); } + + onDragEnd($event: MatSliderDragEvent): void { + this.control.setValue($event.value); + this.control.markAsDirty(); + } } diff --git a/imxweb/projects/qbm/src/lib/cdr/edit-url/edit-url.component.html b/imxweb/projects/qbm/src/lib/cdr/edit-url/edit-url.component.html index a8b949fbd..24ddbb38f 100644 --- a/imxweb/projects/qbm/src/lib/cdr/edit-url/edit-url.component.html +++ b/imxweb/projects/qbm/src/lib/cdr/edit-url/edit-url.component.html @@ -1,7 +1,13 @@ - - {{ columnContainer?.display | translate }} - + + {{ columnContainer.display | translate }} + {{ '#LDS#Please enter a valid URL in the format https://www.example.com or http://www.example.com respectively.' | translate }} @@ -12,10 +18,5 @@ - - + - diff --git a/imxweb/projects/qbm/src/lib/cdr/edit-url/edit-url.component.scss b/imxweb/projects/qbm/src/lib/cdr/edit-url/edit-url.component.scss index b03a7d6a4..bfe7e877f 100644 --- a/imxweb/projects/qbm/src/lib/cdr/edit-url/edit-url.component.scss +++ b/imxweb/projects/qbm/src/lib/cdr/edit-url/edit-url.component.scss @@ -1,7 +1,3 @@ :host { flex-grow: 1; } - -.mat-form-field { - width: 100%; -} \ No newline at end of file diff --git a/imxweb/projects/qbm/src/lib/cdr/edit-url/edit-url.component.spec.ts b/imxweb/projects/qbm/src/lib/cdr/edit-url/edit-url.component.spec.ts index cfb630225..24ecfc5a5 100644 --- a/imxweb/projects/qbm/src/lib/cdr/edit-url/edit-url.component.spec.ts +++ b/imxweb/projects/qbm/src/lib/cdr/edit-url/edit-url.component.spec.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -24,7 +24,7 @@ * */ -import { async, ComponentFixture, TestBed } from '@angular/core/testing'; +import { ComponentFixture, TestBed, waitForAsync } from '@angular/core/testing'; import { EditUrlComponent } from './edit-url.component'; @@ -32,11 +32,10 @@ describe('EditUrlComponent', () => { let component: EditUrlComponent; let fixture: ComponentFixture; - beforeEach(async(() => { + beforeEach(waitForAsync(() => { TestBed.configureTestingModule({ - declarations: [ EditUrlComponent ] - }) - .compileComponents(); + declarations: [EditUrlComponent], + }).compileComponents(); })); beforeEach(() => { diff --git a/imxweb/projects/qbm/src/lib/cdr/edit-url/edit-url.component.ts b/imxweb/projects/qbm/src/lib/cdr/edit-url/edit-url.component.ts index 7cecba97a..a381fbf4a 100644 --- a/imxweb/projects/qbm/src/lib/cdr/edit-url/edit-url.component.ts +++ b/imxweb/projects/qbm/src/lib/cdr/edit-url/edit-url.component.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -100,7 +100,7 @@ export class EditUrlComponent implements CdrEditor, OnDestroy { validators.push(Validators.required); } this.control.setValidators(validators); - }) + }), ); } @@ -113,7 +113,7 @@ export class EditUrlComponent implements CdrEditor, OnDestroy { this.control.setValue(this.columnContainer.value, { emitEvent: false }); } this.valueHasChanged.emit({ value: this.control.value }); - }) + }), ); this.control.setValidators(validators); diff --git a/imxweb/projects/qbm/src/lib/cdr/edit-url/url-validator.service.spec.ts b/imxweb/projects/qbm/src/lib/cdr/edit-url/url-validator.service.spec.ts index e110a941c..f9ac55795 100644 --- a/imxweb/projects/qbm/src/lib/cdr/edit-url/url-validator.service.spec.ts +++ b/imxweb/projects/qbm/src/lib/cdr/edit-url/url-validator.service.spec.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR diff --git a/imxweb/projects/qbm/src/lib/cdr/edit-url/url-validator.service.ts b/imxweb/projects/qbm/src/lib/cdr/edit-url/url-validator.service.ts index b57933f4f..5bc689dc2 100644 --- a/imxweb/projects/qbm/src/lib/cdr/edit-url/url-validator.service.ts +++ b/imxweb/projects/qbm/src/lib/cdr/edit-url/url-validator.service.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -31,7 +31,7 @@ import { ValidatorFn, Validators } from '@angular/forms'; * A service for providing an url validation. */ @Injectable({ - providedIn: 'root' + providedIn: 'root', }) export class UrlValidatorService { @@ -43,6 +43,6 @@ export class UrlValidatorService { * 'http://www.google.com' */ public readonly validators: ReadonlyArray = [ - Validators.pattern(new RegExp('^(http|https)\:\/\/[a-zA-Z0-9\-\.]+\.[a-zA-Z]{2,3}(\/\S*)?')) + Validators.pattern(new RegExp('^(http|https)://[a-zA-Z0-9-.]+.[a-zA-Z]{2,3}(/S*)?')), ]; } diff --git a/imxweb/projects/qbm/src/lib/cdr/editor-base.ts b/imxweb/projects/qbm/src/lib/cdr/editor-base.ts index 47e9483bc..1c2d51643 100644 --- a/imxweb/projects/qbm/src/lib/cdr/editor-base.ts +++ b/imxweb/projects/qbm/src/lib/cdr/editor-base.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -23,16 +23,16 @@ * THIS SOFTWARE OR ITS DERIVATIVES. * */ -import { OnDestroy, Component, EventEmitter, ErrorHandler } from '@angular/core'; +import { Component, ErrorHandler, EventEmitter, OnDestroy } from '@angular/core'; import { AbstractControl, ValidatorFn, Validators } from '@angular/forms'; import { Subject, Subscription } from 'rxjs'; +import { ValType } from '@imx-modules/imx-qbm-dbts'; +import { ServerError } from '../base/server-error'; +import { ClassloggerService } from '../classlogger/classlogger.service'; import { CdrEditor, ValueHasChangedEventArg } from './cdr-editor.interface'; import { ColumnDependentReference } from './column-dependent-reference.interface'; -import { ClassloggerService } from '../classlogger/classlogger.service'; import { EntityColumnContainer } from './entity-column-container'; -import { ServerError } from '../base/server-error'; -import { ValType } from 'imx-qbm-dbts'; /** * A base class for CDR editors, that handles simple dataTypes like string, boolean or integer. @@ -86,7 +86,10 @@ export abstract class EditorBase implements CdrEditor, OnDestroy { private readonly subscribers: Subscription[] = []; private isWriting = false; - public constructor(protected readonly logger: ClassloggerService, protected readonly errorHandler?: ErrorHandler) {} + public constructor( + protected readonly logger: ClassloggerService, + protected readonly errorHandler?: ErrorHandler, + ) {} /** * Unsubscribes all events, as soon as the component is destroyed. @@ -121,7 +124,7 @@ export abstract class EditorBase implements CdrEditor, OnDestroy { this.subscribers.push( cdref.minlengthSubject.subscribe((elem) => { this.setControlValue(); - }) + }), ); } @@ -132,38 +135,30 @@ export abstract class EditorBase implements CdrEditor, OnDestroy { return; } - if (!this.control.hasError('generalError') && this.control.value !== this.columnContainer.value) { + if (this.control.value !== this.columnContainer.value) { this.logger.trace( this, `Control (${this.columnContainer.name}) set to new value:`, this.columnContainer.value, - this.control.value + this.control.value, ); this.setControlValue(); } this.valueHasChanged.emit({ value: this.control.value }); - }) + }), ); this.subscribers.push( this.updateRequested.subscribe(() => { setTimeout(() => { try { - if (!this.control.hasError('generalError') && this.control.value !== this.columnContainer.value) { - this.logger.trace( - this, - `Control (${this.columnContainer.name}) set to new value:`, - this.columnContainer.value, - this.control.value - ); - this.setControlValue(); - this.control.updateValueAndValidity({ onlySelf: true, emitEvent: false }); - } + this.setControlValue(); + this.control.updateValueAndValidity({ onlySelf: true, emitEvent: false }); } finally { } this.valueHasChanged.emit({ value: this.control.value }); }); - }) + }), ); this.logger.trace(this, 'Control initialized'); @@ -213,14 +208,14 @@ export abstract class EditorBase implements CdrEditor, OnDestroy { } catch (e) { this.lastError = e; this.logger.error(this, e); - this.control.updateValueAndValidity({ emitEvent: true }); } finally { this.isBusy = false; this.isWriting = false; - if (!this.control.hasError('generalError') && this.control.value !== this.columnContainer.value) { + if (!this.lastError && this.control.value !== this.columnContainer.value) { this.control.setValue(this.columnContainer.value, { emitEvent: false }); this.logger.debug(this, 'form control value is set to', this.control.value); } + this.control.updateValueAndValidity({ emitEvent: false }); } this.valueHasChanged.emit({ value, forceEmit: true }); diff --git a/imxweb/projects/qbm/src/lib/cdr/entity-column-container.spec.ts b/imxweb/projects/qbm/src/lib/cdr/entity-column-container.spec.ts index 861738b69..7913d4c71 100644 --- a/imxweb/projects/qbm/src/lib/cdr/entity-column-container.spec.ts +++ b/imxweb/projects/qbm/src/lib/cdr/entity-column-container.spec.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -25,7 +25,7 @@ */ import { EntityColumnContainer } from './entity-column-container'; -import { IEntityColumn } from 'imx-qbm-dbts'; +import { IEntityColumn } from '@imx-modules/imx-qbm-dbts'; describe('EntityColumnContainer', () => { [ @@ -33,7 +33,7 @@ describe('EntityColumnContainer', () => { { flags: { isReadOnly: false, canEdit: true }, expectedEdit: true }, { flags: { isReadOnly: true, canEdit: false }, expectedEdit: false }, { flags: { isReadOnly: false, canEdit: false }, expectedEdit: false }, - ].forEach(testcase => { + ].forEach((testcase) => { it('determines canEdit', () => { const columnContainer = new EntityColumnContainer(); columnContainer.init({ @@ -42,15 +42,14 @@ describe('EntityColumnContainer', () => { GetValue: () => undefined, GetMetadata: () => ({ CanEdit: () => testcase.flags.canEdit, - GetLimitedValues: () => undefined - }) + GetLimitedValues: () => undefined, + }), } as IEntityColumn, - isReadOnly: () => testcase.flags.isReadOnly + isReadOnly: () => testcase.flags.isReadOnly, }); expect(columnContainer.canEdit).toEqual(testcase.expectedEdit); - } - ); + }); }); it('provides displayValue', () => { @@ -61,9 +60,9 @@ describe('EntityColumnContainer', () => { column: { GetValue: () => undefined, GetDisplayValue: () => displayValue, - GetMetadata: () => undefined + GetMetadata: () => undefined, } as IEntityColumn, - isReadOnly: () => false + isReadOnly: () => false, }); expect(columnContainer.displayValue).toEqual(displayValue); }); @@ -76,9 +75,9 @@ describe('EntityColumnContainer', () => { column: { GetValue: () => value, GetDisplayValue: () => undefined, - GetMetadata: () => undefined + GetMetadata: () => undefined, } as IEntityColumn, - isReadOnly: () => false + isReadOnly: () => false, }); expect(columnContainer.value).toEqual(value); }); diff --git a/imxweb/projects/qbm/src/lib/cdr/entity-column-container.ts b/imxweb/projects/qbm/src/lib/cdr/entity-column-container.ts index e279c5054..71911ab00 100644 --- a/imxweb/projects/qbm/src/lib/cdr/entity-column-container.ts +++ b/imxweb/projects/qbm/src/lib/cdr/entity-column-container.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -24,7 +24,7 @@ * */ -import { IForeignKeyInfo, IValueMetadata, ValType, ValueConstraint, ValueStruct } from 'imx-qbm-dbts'; +import { IForeignKeyInfo, IValueMetadata, ValType, ValueConstraint, ValueStruct } from '@imx-modules/imx-qbm-dbts'; import { Subscription } from 'rxjs'; import { ValueWrapper } from '../value-wrapper/value-wrapper'; import { ColumnDependentReference } from './column-dependent-reference.interface'; @@ -52,14 +52,14 @@ export class EntityColumnContainer implements ValueWrapper { /** * The display value of the column. */ - public get displayValue(): string { + public get displayValue(): string | undefined { return this.cdr && this.cdr.column ? this.cdr.column.GetDisplayValue() : undefined; } /** * A read-only list of {@link IForeignKeyInfo | FK informations} */ - public get fkRelations(): ReadonlyArray { + public get fkRelations(): ReadonlyArray | undefined { return this.cdr && this.cdr.column ? this.cdr.column.GetMetadata().GetFkRelations() : undefined; } @@ -68,51 +68,53 @@ export class EntityColumnContainer implements ValueWrapper { * If the CDR itself doesn't contain a display, the display given by the column is used. */ public get display(): string { - return this.cdr && (this.cdr.display || (this.cdr.column ? this.cdr.column.GetMetadata().GetDisplay() : undefined)); + return this.cdr && (this.cdr.display || (this.cdr.column ? this.cdr.column.GetMetadata().GetDisplay() : '')); } /** * The information, whether a value is mandatory or not. */ public get isValueRequired(): boolean { - return this.cdr && (this.cdr.minLength > 0 || (this.cdr.column && this.cdr.column.GetMetadata().GetMinLength() > 0)); + return this.cdr && ((this.cdr?.minLength ?? 0) > 0 || (this.cdr.column && this.cdr.column.GetMetadata().GetMinLength() > 0)); } /** * The name of the column. */ - public get name(): string { + public get name(): string | undefined { return this.cdr && this.cdr.column ? this.cdr.column.ColumnName : undefined; } - /** * The value type of the column, like bool, number, string, etc. */ - public get type(): ValType { + public get type(): ValType | undefined { return this.cdr && this.cdr.column ? this.cdr.column.GetType() : undefined; } /** * The information of a min value, a max value or limited values used by the given column. */ - public get valueConstraint(): ValueConstraint { + public get valueConstraint(): ValueConstraint | undefined { return this.cdr && (this.cdr.valueConstraint || (this.cdr.column ? this.cdr.column.GetMetadata().valueConstraint : undefined)); } /** * The meta data provided for the given column, like minLength, display, isMultiLine, etc. */ - public get metaData(): IValueMetadata { + public get metaData(): IValueMetadata | undefined { return this.cdr && this.cdr.column ? this.cdr.column.GetMetadata() : undefined; } /** * An additinal hint provided by the given CDR. */ - public get hint(): string { + public get hint(): string | undefined { return this.cdr?.hint; } + /** + * The visibility of the display value. + */ public get showDisplayValue(): boolean { return !!this.metaData?.CanSee(); } @@ -149,7 +151,7 @@ export class EntityColumnContainer implements ValueWrapper { * Updates the value and puts it into the column * @param value The new value for the column */ - public async updateValue(value: T): Promise { + public async updateValue(value: T | undefined): Promise { if (this.cdr && this.cdr.column) { return this.cdr.column.PutValue(value); } @@ -159,7 +161,7 @@ export class EntityColumnContainer implements ValueWrapper { * Updates column value and column display in one call * @param value The value struct, that should be used */ - public async updateValueStruct(value: ValueStruct): Promise { + public async updateValueStruct(value: ValueStruct): Promise { if (this.cdr && this.cdr.column) { return this.cdr.column.PutValueStruct(value); } diff --git a/imxweb/projects/qbm/src/lib/cdr/entity-column-editor/entity-column-editor.component.html b/imxweb/projects/qbm/src/lib/cdr/entity-column-editor/entity-column-editor.component.html index 7373d1ca8..422a3ab20 100644 --- a/imxweb/projects/qbm/src/lib/cdr/entity-column-editor/entity-column-editor.component.html +++ b/imxweb/projects/qbm/src/lib/cdr/entity-column-editor/entity-column-editor.component.html @@ -1,4 +1,2 @@ - + diff --git a/imxweb/projects/qbm/src/lib/cdr/entity-column-editor/entity-column-editor.component.scss b/imxweb/projects/qbm/src/lib/cdr/entity-column-editor/entity-column-editor.component.scss index bcd8ac2d3..bfe7e877f 100644 --- a/imxweb/projects/qbm/src/lib/cdr/entity-column-editor/entity-column-editor.component.scss +++ b/imxweb/projects/qbm/src/lib/cdr/entity-column-editor/entity-column-editor.component.scss @@ -1,3 +1,3 @@ :host { flex-grow: 1; -} \ No newline at end of file +} diff --git a/imxweb/projects/qbm/src/lib/cdr/entity-column-editor/entity-column-editor.component.ts b/imxweb/projects/qbm/src/lib/cdr/entity-column-editor/entity-column-editor.component.ts index c1c0bcafa..dd2282611 100644 --- a/imxweb/projects/qbm/src/lib/cdr/entity-column-editor/entity-column-editor.component.ts +++ b/imxweb/projects/qbm/src/lib/cdr/entity-column-editor/entity-column-editor.component.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -27,10 +27,9 @@ import { Component, EventEmitter, Input, OnChanges, Output, SimpleChanges, ViewChild } from '@angular/core'; import { AbstractControl } from '@angular/forms'; -import { IEntityColumn } from 'imx-qbm-dbts'; -import { ColumnDependentReference } from '../column-dependent-reference.interface'; +import { IEntityColumn } from '@imx-modules/imx-qbm-dbts'; import { CdrEditorComponent } from '../cdr-editor/cdr-editor.component'; - +import { ColumnDependentReference } from '../column-dependent-reference.interface'; /** * Provides a column editor component, that wraps around a {@link CdrEditor | column dependent reference editor}. @@ -45,7 +44,7 @@ export class EntityColumnEditorComponent implements OnChanges { * @ignore only used in template. * The column dependent reference used by the editor. */ - public cdr: ColumnDependentReference; + public cdr: ColumnDependentReference | undefined; /** * An entity column, that should be edited with a {@link CdrEditor | column dependent reference editor}. @@ -56,6 +55,7 @@ export class EntityColumnEditorComponent implements OnChanges { * Indicator, whether the control should be displayed as read-only. */ @Input() public readonly: boolean; + @Input() public display: string; /** * This is emitted, after the control is created properly. @@ -79,6 +79,7 @@ export class EntityColumnEditorComponent implements OnChanges { ? { column: this.column, isReadOnly: () => this.readonly || !this.column.GetMetadata().CanEdit(), + display: this.display, } : undefined; } diff --git a/imxweb/projects/qbm/src/lib/cdr/fk-cdr-editor-provider.spec.ts b/imxweb/projects/qbm/src/lib/cdr/fk-cdr-editor-provider.spec.ts index ddbbf63b0..2793be4a1 100644 --- a/imxweb/projects/qbm/src/lib/cdr/fk-cdr-editor-provider.spec.ts +++ b/imxweb/projects/qbm/src/lib/cdr/fk-cdr-editor-provider.spec.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -24,22 +24,19 @@ * */ -import { ViewContainerRef, ComponentRef } from '@angular/core'; -import * as TypeMoq from 'typemoq'; +import { ComponentRef, ViewContainerRef } from '@angular/core'; -import { IValueMetadata, IForeignKeyInfo, IEntityColumn } from 'imx-qbm-dbts'; -import { FkCdrEditorProvider } from './fk-cdr-editor-provider'; -import { ColumnDependentReference } from './column-dependent-reference.interface'; +import { IForeignKeyInfo } from '@imx-modules/imx-qbm-dbts'; +import { clearStylesFromDOM } from '../testing/clear-styles.spec'; import { CdrEditor } from './cdr-editor.interface'; +import { ColumnDependentReference } from './column-dependent-reference.interface'; import { createComponentMock } from './default-cdr-editor-provider.spec'; import { EditFkComponent } from './edit-fk/edit-fk.component'; -import { clearStylesFromDOM } from '../testing/clear-styles.spec'; +import { FkCdrEditorProvider } from './fk-cdr-editor-provider'; import { ViewPropertyDefaultComponent } from './view-property-default/view-property-default.component'; describe('FkCdrEditorProvider', () => { - - beforeEach(() => { - }); + beforeEach(() => {}); afterAll(() => { clearStylesFromDOM(); @@ -51,7 +48,7 @@ describe('FkCdrEditorProvider', () => { it('should return null, if non fk column', () => { const editor = testCreateEditor(null, null, true); - expect( editor ).toBeNull(); + expect(editor).toBeNull(); }); it('should create ViewPropertyDefaultComponent for a Fk property that is set as readonly', () => { @@ -63,55 +60,45 @@ describe('FkCdrEditorProvider', () => { }); it('should work with empty fk', () => { - expect(() => {testCreateEditor(EditFkComponent, [createMockForeignKey('', '')], true)}).not.toThrowError(); + expect(() => { + testCreateEditor(EditFkComponent, [createMockForeignKey('', '')], true); + }).not.toThrowError(); }); - }); -function testCreateEditor(TCtor: new (...args: any[]) => T, fkRelation?: IForeignKeyInfo[], - editorShouldBeNull: boolean = false, isReadOnly: boolean = false): ComponentRef { - const cdrMock = createCdr(fkRelation, isReadOnly); - const editorMock = TypeMoq.Mock.ofType(); - const parentMock = TypeMoq.Mock.ofType(); - const childMock = createComponentMock(editorMock.object); - - parentMock.setup( p => p.createComponent(TypeMoq.It.isAny(), TypeMoq.It.isAny())).returns(() => childMock.object); - - // Act - const provider = new FkCdrEditorProvider(); - const editor = provider.createEditor(parentMock.object, cdrMock.object); - - // Assert - if (editorShouldBeNull) { - expect(editor).toBeNull(); - } else { - expect(editor === childMock.object).toBeTruthy(); - } - editorMock.verify(e => e.bind(cdrMock.object), TypeMoq.Times.atMostOnce()); - editorMock.verify(e => e.bind(TypeMoq.It.isAny()), TypeMoq.Times.atMostOnce()); - - return editor; +function testCreateEditor( + TCtor: new (...args: any[]) => T, + fkRelation?: IForeignKeyInfo[], + editorShouldBeNull: boolean = false, + isReadOnly: boolean = false, +): ComponentRef { + const cdrMock = createCdr(fkRelation, isReadOnly); + const childMock = createComponentMock({} as T); + const parentMock = { createComponent: () => childMock } as unknown as ViewContainerRef; + // Act + const provider = new FkCdrEditorProvider(); + const editor = provider.createEditor(parentMock, cdrMock); + + // Assert + if (editorShouldBeNull) { + expect(editor).toBeNull(); + } else { + expect(editor === childMock).toBeTruthy(); + } + + return editor; } function createMockForeignKey(tablename: string, column: string): IForeignKeyInfo { - const mockKey = TypeMoq.Mock.ofType(); - mockKey.setup(m => m.TableName).returns(() => tablename); - mockKey.setup(m => m.ColumnName).returns(() => column); - - return mockKey.object; + const mockKey: IForeignKeyInfo = { TableName: tablename, ColumnName: column } as unknown as IForeignKeyInfo; + return mockKey; } - -function createCdr( fkRelation?: IForeignKeyInfo[], isReadOnly?: boolean) -: TypeMoq.IMock { - - const metaMock = TypeMoq.Mock.ofType(); - metaMock.setup(m => m.GetFkRelations()).returns(() => fkRelation); - metaMock.setup(m => m.CanEdit()).returns(() => !isReadOnly) - - const cdrMock = TypeMoq.Mock.ofType(); - cdrMock.setup(m => m.column).returns(() => ({ GetMetadata: () => metaMock.object } as IEntityColumn)); - cdrMock.setup(m => m.isReadOnly()).returns(() => isReadOnly); - - return cdrMock; +function createCdr(fkRelation?: IForeignKeyInfo[], isReadOnly?: boolean): ColumnDependentReference { + const metaData = { + GetFkRelations: () => fkRelation, + CanEdit: () => !isReadOnly, + IsMultiValue: () => false, + }; + return { column: { GetMetadata: () => metaData }, isReadOnly: () => isReadOnly } as unknown as ColumnDependentReference; } diff --git a/imxweb/projects/qbm/src/lib/cdr/fk-cdr-editor-provider.ts b/imxweb/projects/qbm/src/lib/cdr/fk-cdr-editor-provider.ts index 0d5659432..e58e10bc0 100644 --- a/imxweb/projects/qbm/src/lib/cdr/fk-cdr-editor-provider.ts +++ b/imxweb/projects/qbm/src/lib/cdr/fk-cdr-editor-provider.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -24,13 +24,13 @@ * */ -import { ViewContainerRef, ComponentRef, Type } from '@angular/core'; +import { ComponentRef, Type, ViewContainerRef } from '@angular/core'; import { CdrEditorProvider } from './cdr-editor-provider.interface'; -import { ColumnDependentReference } from './column-dependent-reference.interface'; import { CdrEditor } from './cdr-editor.interface'; -import { EditFkComponent } from './edit-fk/edit-fk.component'; +import { ColumnDependentReference } from './column-dependent-reference.interface'; import { EditFkMultiComponent } from './edit-fk/edit-fk-multi.component'; +import { EditFkComponent } from './edit-fk/edit-fk.component'; /** * A special provider for foreign key columns. @@ -47,7 +47,7 @@ export class FkCdrEditorProvider implements CdrEditorProvider { * @param cdref A column dependent reference that contains the data for the editor. * @returns An instance of {@link CdrEditor}, that can be used or editing data, or null, if no foreign key information is given. */ - public createEditor(parent: ViewContainerRef, cdref: ColumnDependentReference): ComponentRef { + public createEditor(parent: ViewContainerRef, cdref: ColumnDependentReference): ComponentRef | null { if (this.hasFkRelations(cdref)) { return cdref.column.GetMetadata().IsMultiValue() ? this.createBound(EditFkMultiComponent, parent, cdref) @@ -64,7 +64,7 @@ export class FkCdrEditorProvider implements CdrEditorProvider { private createBound( type: Type, parent: ViewContainerRef, - cdref: ColumnDependentReference + cdref: ColumnDependentReference, ): ComponentRef { const result = parent.createComponent(type); result.instance.bind(cdref); @@ -74,7 +74,7 @@ export class FkCdrEditorProvider implements CdrEditorProvider { /** * Determines, if there are fk relations present or not. * @param cdref The column dependent reference, that needs to be checked - * @returns + * @returns */ private hasFkRelations(cdref: ColumnDependentReference): boolean { const fkRelations = cdref.column.GetMetadata().GetFkRelations(); diff --git a/imxweb/projects/qbm/src/lib/cdr/limited-values-container.spec.ts b/imxweb/projects/qbm/src/lib/cdr/limited-values-container.spec.ts index 641645331..fe5baedf4 100644 --- a/imxweb/projects/qbm/src/lib/cdr/limited-values-container.spec.ts +++ b/imxweb/projects/qbm/src/lib/cdr/limited-values-container.spec.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -24,31 +24,34 @@ * */ - -import { ValType, IValueMetadata, LimitedValueData } from 'imx-qbm-dbts'; +import { ValType, IValueMetadata, LimitedValueData } from '@imx-modules/imx-qbm-dbts'; import { LimitedValuesContainer } from './limited-values-container'; describe('LimitedValuesContainer', () => { - function buildLimitedValues(limited: any[]): ReadonlyArray { - return limited.map(element => ({ Value: element, Description: `${element}` })); - } + function buildLimitedValues(limited: any[]): ReadonlyArray { + return limited.map((element) => ({ Value: element, Description: `${element}` })); + } [ { value: { limited: ['a', 'b', 'c'], minLength: 0, type: ValType.String }, description: 'with string allowing null', expected: true }, { value: { limited: [null, 'b', 'c'], minLength: 1, type: ValType.String }, description: 'with string allowing null', expected: false }, - { value: { limited: ['a', 'b', 'c'], minLength: 1, type: ValType.String }, description: 'with string not allowing null', expected: false }, + { + value: { limited: ['a', 'b', 'c'], minLength: 1, type: ValType.String }, + description: 'with string not allowing null', + expected: false, + }, { value: { limited: [1, 2, 3], minLength: 0, type: ValType.Int }, description: 'with number allowing null', expected: true }, { value: { limited: [0, 2, 3], minLength: 0, type: ValType.Int }, description: 'with number allowing null', expected: false }, { value: { limited: [1, 2, 3], minLength: 1, type: ValType.Int }, description: 'with number not allowing null', expected: false }, - ].forEach(testcase => { + ].forEach((testcase) => { it(`should have a "null" option ${testcase.description}`, () => { - const container = new LimitedValuesContainer({ - GetLimitedValues: () => buildLimitedValues(testcase.value.limited), - GetMinLength: () => testcase.value.minLength, - GetType: () => testcase.value.type - } as IValueMetadata); - - expect(container.hasNullOption()).toEqual(testcase.expected); + const container = new LimitedValuesContainer({ + GetLimitedValues: () => buildLimitedValues(testcase.value.limited), + GetMinLength: () => testcase.value.minLength, + GetType: () => testcase.value.type, + } as IValueMetadata); + + expect(container.hasNullOption()).toEqual(testcase.expected); }); }); @@ -57,45 +60,45 @@ describe('LimitedValuesContainer', () => { metadata: { limited: ['a', 'b', 'c'], type: ValType.String }, value: 'd', description: 'for string not in limited values', - expected: true + expected: true, }, { metadata: { limited: ['a', 'b', 'c'], type: ValType.String }, value: 'a', description: 'for string in limited values', - expected: false + expected: false, }, { metadata: { limited: ['a', 'b', 'c'], type: ValType.String }, description: 'for string null', - expected: false + expected: false, }, { - metadata: { limited: [1, 2, 3], type: ValType.Int }, + metadata: { limited: [1, 2, 3], type: ValType.Int }, description: 'for number not in limited values', value: 4, - expected: true + expected: true, }, { - metadata: { limited: [1, 2, 3], type: ValType.Int }, + metadata: { limited: [1, 2, 3], type: ValType.Int }, description: 'for number in limited value', value: 1, - expected: false + expected: false, }, { - metadata: { limited: [1, 2, 3], type: ValType.Int }, + metadata: { limited: [1, 2, 3], type: ValType.Int }, description: 'for number 0', value: 0, - expected: true + expected: true, }, - ].forEach(testcase => { + ].forEach((testcase) => { it(`isNotInLimitedValueRange ${testcase.description}`, () => { - const container = new LimitedValuesContainer({ - GetLimitedValues: () => buildLimitedValues(testcase.metadata.limited), - GetType: () => testcase.metadata.type - } as IValueMetadata); + const container = new LimitedValuesContainer({ + GetLimitedValues: () => buildLimitedValues(testcase.metadata.limited), + GetType: () => testcase.metadata.type, + } as IValueMetadata); - expect(container.isNotInLimitedValueRange(testcase.value)).toEqual(testcase.expected); + expect(container.isNotInLimitedValueRange(testcase.value)).toEqual(testcase.expected); }); }); }); diff --git a/imxweb/projects/qbm/src/lib/cdr/limited-values-container.ts b/imxweb/projects/qbm/src/lib/cdr/limited-values-container.ts index d15b22501..fdf749a45 100644 --- a/imxweb/projects/qbm/src/lib/cdr/limited-values-container.ts +++ b/imxweb/projects/qbm/src/lib/cdr/limited-values-container.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -24,7 +24,7 @@ * */ -import { LimitedValueData, IValueMetadata, ValType } from 'imx-qbm-dbts'; +import { IValueMetadata, LimitedValueData, ValType } from '@imx-modules/imx-qbm-dbts'; /** * A wrapper, that encapsules limited value property functions. @@ -33,7 +33,7 @@ export class LimitedValuesContainer { /** * A read-only list of a possible limited values. */ - public get values(): ReadonlyArray { + public get values(): ReadonlyArray | undefined { return this.metadata ? this.metadata.GetLimitedValues() : undefined; } @@ -42,12 +42,15 @@ export class LimitedValuesContainer { /** * Determines, whether the limited value collection allows a null option. */ + /** + * Determines, whether the limited value collection allows a null option + */ public hasNullOption(): boolean { return this.metadata.GetMinLength() === 0 && !this.contains(this.getNullValue()); } /** - * Determines, whether the value is part of the limited value range or not. + * Determines, whether the value is part of the limited value range or not */ public isNotInLimitedValueRange(value: string | number): boolean { return !((value || '') === (this.getNullValue() || '')) && !this.contains(value); @@ -57,7 +60,7 @@ export class LimitedValuesContainer { * Gets the value representing 'null'. * @returns the value that is used as 'null'. */ - private getNullValue(): string { + private getNullValue(): string | null { return this.metadata.GetType() === ValType.String ? null : '0'; } @@ -66,7 +69,7 @@ export class LimitedValuesContainer { * @param value The value to be checked. * @returns */ - private contains(value: string | number): boolean { - return this.values && this.values.filter((v) => `${v.Value}` === `${value}`).length > 0; + private contains(value: string | number | null): boolean { + return (this.values && this.values.filter((v) => `${v.Value}` === `${value}`).length > 0) ?? false; } } diff --git a/imxweb/projects/qbm/src/lib/cdr/property-viewer/property-viewer.component.ts b/imxweb/projects/qbm/src/lib/cdr/property-viewer/property-viewer.component.ts index aaa74b1fa..cf7d611f1 100644 --- a/imxweb/projects/qbm/src/lib/cdr/property-viewer/property-viewer.component.ts +++ b/imxweb/projects/qbm/src/lib/cdr/property-viewer/property-viewer.component.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -26,38 +26,32 @@ import { Component, Input, OnChanges } from '@angular/core'; -import { IEntityColumn } from 'imx-qbm-dbts'; +import { IEntityColumn } from '@imx-modules/imx-qbm-dbts'; import { BaseReadonlyCdr } from '../base-readonly-cdr'; import { ColumnDependentReference } from '../column-dependent-reference.interface'; @Component({ - selector: 'imx-property-viewer', - templateUrl: './property-viewer.component.html', - styleUrls: ['./property-viewer.component.scss'] + selector: 'imx-property-viewer', + templateUrl: './property-viewer.component.html', + styleUrls: ['./property-viewer.component.scss'], }) export class PropertyViewerComponent implements OnChanges { - public cdrList: ColumnDependentReference[]; - @Input() public showHiddenProperties = true; - @Input() public properties: IEntityColumn[] = []; + public cdrList: ColumnDependentReference[]; + @Input() public showHiddenProperties = true; + @Input() public properties: IEntityColumn[] = []; - public ngOnChanges(): void { - if (this.properties) { - this.cdrList = this.properties - .filter(column => this.showProperty(column)) - .map(column => new BaseReadonlyCdr(column)); - } + public ngOnChanges(): void { + if (this.properties) { + this.cdrList = this.properties.filter((column) => this.showProperty(column)).map((column) => new BaseReadonlyCdr(column)); } + } - private showProperty(column: IEntityColumn): boolean { - // show hidden properties? - return (column.GetMetadata().CanSee() || this.showHiddenProperties) - - && - - true; - /* TODO + private showProperty(column: IEntityColumn): boolean { + // show hidden properties? + return (column.GetMetadata().CanSee() || this.showHiddenProperties) && true; + /* TODO // show empty properties? (from edittable select current not(isnullorempty(currentcolumn)) or getconfig("VI_Common_DisplayEmptyProperties") = "true");*/ - } + } } diff --git a/imxweb/projects/qbm/src/lib/cdr/view-property-default/view-property-default.component.html b/imxweb/projects/qbm/src/lib/cdr/view-property-default/view-property-default.component.html index 8416faeb7..bbb9d7c58 100644 --- a/imxweb/projects/qbm/src/lib/cdr/view-property-default/view-property-default.component.html +++ b/imxweb/projects/qbm/src/lib/cdr/view-property-default/view-property-default.component.html @@ -1,5 +1,6 @@ + [attr.data-imx-identifier]="'cdr-readonly-' + columnContainer?.name" +> diff --git a/imxweb/projects/qbm/src/lib/cdr/view-property-default/view-property-default.component.scss b/imxweb/projects/qbm/src/lib/cdr/view-property-default/view-property-default.component.scss index bcd8ac2d3..bfe7e877f 100644 --- a/imxweb/projects/qbm/src/lib/cdr/view-property-default/view-property-default.component.scss +++ b/imxweb/projects/qbm/src/lib/cdr/view-property-default/view-property-default.component.scss @@ -1,3 +1,3 @@ :host { flex-grow: 1; -} \ No newline at end of file +} diff --git a/imxweb/projects/qbm/src/lib/cdr/view-property-default/view-property-default.component.ts b/imxweb/projects/qbm/src/lib/cdr/view-property-default/view-property-default.component.ts index b7cd76a99..1330c0dfb 100644 --- a/imxweb/projects/qbm/src/lib/cdr/view-property-default/view-property-default.component.ts +++ b/imxweb/projects/qbm/src/lib/cdr/view-property-default/view-property-default.component.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -31,7 +31,7 @@ import { EditorBase } from '../editor-base'; @Component({ selector: 'imx-view-property-default', templateUrl: './view-property-default.component.html', - styleUrls: ['./view-property-default.component.scss'] + styleUrls: ['./view-property-default.component.scss'], }) export class ViewPropertyDefaultComponent extends EditorBase { public readonly control = new UntypedFormControl(undefined); diff --git a/imxweb/projects/qbm/src/lib/cdr/view-property/view-property.component.html b/imxweb/projects/qbm/src/lib/cdr/view-property/view-property.component.html index c287e3d5a..ad6f75b98 100644 --- a/imxweb/projects/qbm/src/lib/cdr/view-property/view-property.component.html +++ b/imxweb/projects/qbm/src/lib/cdr/view-property/view-property.component.html @@ -1,4 +1,4 @@
    - {{ (columnContainer?.display | translate) + (columnContainer.isValueRequired ? '*' : '') }} + {{ (columnContainer.display | translate) + (columnContainer.isValueRequired ? '*' : '') }} {{ columnContainer.showDisplayValue ? (displayedValue | translate) : '' }}
    diff --git a/imxweb/projects/qbm/src/lib/cdr/view-property/view-property.component.ts b/imxweb/projects/qbm/src/lib/cdr/view-property/view-property.component.ts index 22a53673e..9e40eaa56 100644 --- a/imxweb/projects/qbm/src/lib/cdr/view-property/view-property.component.ts +++ b/imxweb/projects/qbm/src/lib/cdr/view-property/view-property.component.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -27,7 +27,7 @@ import { Component, Input } from '@angular/core'; import { TranslateService } from '@ngx-translate/core'; -import { ValType } from 'imx-qbm-dbts'; +import { ValType } from '@imx-modules/imx-qbm-dbts'; import { EntityColumnContainer } from '../entity-column-container'; import { ImxTranslationProviderService } from '../../translation/imx-translation-provider.service'; diff --git a/imxweb/projects/qbm/src/lib/chart-options/line-chart-options.spec.ts b/imxweb/projects/qbm/src/lib/chart-options/line-chart-options.spec.ts index f5d220643..a588adbd8 100644 --- a/imxweb/projects/qbm/src/lib/chart-options/line-chart-options.spec.ts +++ b/imxweb/projects/qbm/src/lib/chart-options/line-chart-options.spec.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -31,7 +31,6 @@ import { SeriesInformation } from './series-information'; import { clearStylesFromDOM } from '../testing/clear-styles.spec'; describe('LineChartOptions', () => { - afterAll(() => { clearStylesFromDOM(); }); @@ -44,8 +43,8 @@ describe('LineChartOptions', () => { { isSmooth: true, isArea: true, expect: 'area-spline' }, { isSmooth: true, isArea: false, expect: 'spline' }, { isSmooth: false, isArea: true, expect: 'area' }, - { isSmooth: false, isArea: false, expect: 'line' } - ].forEach(element => { + { isSmooth: false, isArea: false, expect: 'line' }, + ].forEach((element) => { it(`gets line type with smooth lines = ${element.isSmooth} and colored area = ${element.isArea}`, () => { const xAxisInformation = new XAxisInformation('number', [1, 2, 3]); const yAxisInformation = new YAxisInformation([new SeriesInformation('dummy', [1, 2, 3])]); @@ -54,7 +53,6 @@ describe('LineChartOptions', () => { chart.colorArea = element.isArea; expect(chart.options.data.type).toBe(element.expect); }); - }); it('should create an instance', () => { const xAxisInformation = new XAxisInformation('number', [1, 2, 3]); @@ -62,6 +60,4 @@ describe('LineChartOptions', () => { const chart = new LineChartOptions(xAxisInformation, yAxisInformation); expect(chart.options.data.type).toBe('area-spline'); }); - - }); diff --git a/imxweb/projects/qbm/src/lib/chart-options/line-chart-options.ts b/imxweb/projects/qbm/src/lib/chart-options/line-chart-options.ts index 908fa64e4..3512e3f09 100644 --- a/imxweb/projects/qbm/src/lib/chart-options/line-chart-options.ts +++ b/imxweb/projects/qbm/src/lib/chart-options/line-chart-options.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -72,17 +72,11 @@ export class LineChartOptions { */ public tooltip: (data: any) => string; // TODO: hier müsste noch eine bessere Lösung gefunden werden - /** - * Gets the {@link XAxisInformation|x axis informations} for the chart - */ - public readonly xAxisInformation: XAxisInformation; - - /** - * Gets the {@link YAxisInformation|y axis informations} for the chart - */ - public readonly yAxisInformation: YAxisInformation; - - public constructor(xAxisInformation: XAxisInformation, yAxisInformation: YAxisInformation) { + public constructor( + public readonly xAxisInformation: XAxisInformation, + public readonly yAxisInformation: YAxisInformation, + public readonly emptyText?: string, + ) { this.xAxisInformation = xAxisInformation; this.yAxisInformation = yAxisInformation; } @@ -103,6 +97,11 @@ export class LineChartOptions { columns: col, names: this.yAxisInformation.getNames(), type: this.getType(), + empty: { + label: { + text: this.emptyText ?? '', + }, + }, colors: this.yAxisInformation.getColors(), }, tooltip: { @@ -121,6 +120,7 @@ export class LineChartOptions { lines: this.additionalLines, }, }, + padding: this.padding, }; } diff --git a/imxweb/projects/qbm/src/lib/chart-options/series-information.spec.ts b/imxweb/projects/qbm/src/lib/chart-options/series-information.spec.ts index 5c5e8ccbc..5ba981e53 100644 --- a/imxweb/projects/qbm/src/lib/chart-options/series-information.spec.ts +++ b/imxweb/projects/qbm/src/lib/chart-options/series-information.spec.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -28,7 +28,6 @@ import { SeriesInformation } from './series-information'; import { clearStylesFromDOM } from '../testing/clear-styles.spec'; describe('YAxisInformation', () => { - afterAll(() => { clearStylesFromDOM(); }); diff --git a/imxweb/projects/qbm/src/lib/chart-options/series-information.ts b/imxweb/projects/qbm/src/lib/chart-options/series-information.ts index 11667ed40..c2479951f 100644 --- a/imxweb/projects/qbm/src/lib/chart-options/series-information.ts +++ b/imxweb/projects/qbm/src/lib/chart-options/series-information.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -25,7 +25,6 @@ */ export class SeriesInformation { - /** * Gets the name of the serie */ @@ -34,7 +33,7 @@ export class SeriesInformation { /** * Gets the color of the serie */ - public readonly color: string; + public readonly color?: string; /** * Gets the values of the serie @@ -51,6 +50,6 @@ export class SeriesInformation { * Combines the axis data with its title, so that it's useable by the billboard.js ChartOptions */ public getSerie(): any[] { - return ([this.name.replace(' ', '') as any]).concat(this.values); + return [this.name.replace(' ', '') as any].concat(this.values); } } diff --git a/imxweb/projects/qbm/src/lib/chart-options/x-axis-information.spec.ts b/imxweb/projects/qbm/src/lib/chart-options/x-axis-information.spec.ts index 16d87a122..c3a3825fa 100644 --- a/imxweb/projects/qbm/src/lib/chart-options/x-axis-information.spec.ts +++ b/imxweb/projects/qbm/src/lib/chart-options/x-axis-information.spec.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -28,7 +28,6 @@ import { XAxisInformation } from './x-axis-information'; import { clearStylesFromDOM } from '../testing/clear-styles.spec'; describe('XAxisInformation', () => { - afterAll(() => { clearStylesFromDOM(); }); @@ -47,5 +46,4 @@ describe('XAxisInformation', () => { const info = new XAxisInformation('number', [1, 2, 3], {}); expect(info.getAxisData()).toEqual(['x', 1, 2, 3]); }); - }); diff --git a/imxweb/projects/qbm/src/lib/chart-options/x-axis-information.ts b/imxweb/projects/qbm/src/lib/chart-options/x-axis-information.ts index c83d8ae86..9970aae8c 100644 --- a/imxweb/projects/qbm/src/lib/chart-options/x-axis-information.ts +++ b/imxweb/projects/qbm/src/lib/chart-options/x-axis-information.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -40,7 +40,7 @@ export class XAxisInformation { /** * Gets the tick configuration for the axis */ - public readonly tickConfiguration: XTickConfiguration; + public readonly tickConfiguration: XTickConfiguration | undefined; public constructor(dataType: 'number' | 'date' | 'string', values: (number | Date | string)[], xTickConfiguration?: XTickConfiguration) { this.dataType = dataType; diff --git a/imxweb/projects/qbm/src/lib/chart-options/y-axis-information.spec.ts b/imxweb/projects/qbm/src/lib/chart-options/y-axis-information.spec.ts index c68be4fd2..8bca5e883 100644 --- a/imxweb/projects/qbm/src/lib/chart-options/y-axis-information.spec.ts +++ b/imxweb/projects/qbm/src/lib/chart-options/y-axis-information.spec.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -28,7 +28,6 @@ import { YAxisInformation } from './y-axis-information'; import { clearStylesFromDOM } from '../testing/clear-styles.spec'; describe('YAxisInformationGroup', () => { - afterAll(() => { clearStylesFromDOM(); }); diff --git a/imxweb/projects/qbm/src/lib/chart-options/y-axis-information.ts b/imxweb/projects/qbm/src/lib/chart-options/y-axis-information.ts index b07824c06..23abe5ef9 100644 --- a/imxweb/projects/qbm/src/lib/chart-options/y-axis-information.ts +++ b/imxweb/projects/qbm/src/lib/chart-options/y-axis-information.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -24,11 +24,10 @@ * */ -import { SeriesInformation } from './series-information'; import { YTickConfiguration, yAxisConfiguration } from 'billboard.js'; +import { SeriesInformation } from './series-information'; export class YAxisInformation { - /** * Gets the series, that are displayed on the chart */ @@ -60,7 +59,7 @@ export class YAxisInformation { return { max: this.max, min: this.min, - tick: this.tickConfiguration + tick: this.tickConfiguration, }; } @@ -69,7 +68,7 @@ export class YAxisInformation { */ public getNames(): { [key: string]: string } { const names: { [id: string]: string } = {}; - this.series.forEach(element => { + this.series.forEach((element) => { names[element.name.replace(' ', '')] = element.name; }); @@ -81,8 +80,11 @@ export class YAxisInformation { */ public getColors(): { [key: string]: string } { const colors: { [id: string]: string } = {}; - this.series.forEach(element => { - colors[element.name.replace(' ', '')] = element.color; + this.series.forEach((element) => { + const index = element.name.replace(' ', ''); + if (index && element.color) { + colors[index] = element.color; + } }); return colors; diff --git a/imxweb/projects/qbm/src/lib/chart-tile/chart-tile.component.html b/imxweb/projects/qbm/src/lib/chart-tile/chart-tile.component.html index e9b936f77..1b74c861f 100644 --- a/imxweb/projects/qbm/src/lib/chart-tile/chart-tile.component.html +++ b/imxweb/projects/qbm/src/lib/chart-tile/chart-tile.component.html @@ -1,8 +1,14 @@ - - -
    - -
    -
    - + -->
    +
    diff --git a/imxweb/projects/qbm/src/lib/chart-tile/chart-tile.component.ts b/imxweb/projects/qbm/src/lib/chart-tile/chart-tile.component.ts index b033e0328..ef13f9be4 100644 --- a/imxweb/projects/qbm/src/lib/chart-tile/chart-tile.component.ts +++ b/imxweb/projects/qbm/src/lib/chart-tile/chart-tile.component.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -24,14 +24,13 @@ * */ -import { Component, EventEmitter, Input, Output } from '@angular/core'; +import { Component, EventEmitter, Input, Output } from '@angular/core'; @Component({ templateUrl: './chart-tile.component.html', - selector: 'imx-chart-tile' + selector: 'imx-chart-tile', }) export class ChartTileComponent { - @Input() public displayNameDialogDashboardDef: string; @Input() public chartType: string; @Input() public useHistogramStyle: boolean; diff --git a/imxweb/projects/qbm/src/lib/classlogger/classlogger.module.ts b/imxweb/projects/qbm/src/lib/classlogger/classlogger.module.ts index c7997d965..d96b03e16 100644 --- a/imxweb/projects/qbm/src/lib/classlogger/classlogger.module.ts +++ b/imxweb/projects/qbm/src/lib/classlogger/classlogger.module.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -32,12 +32,7 @@ import { LoggerModule } from 'ngx-logger'; @NgModule({ declarations: [], - imports: [ - CommonModule, - LoggerModule - ], - providers: [ - ClassloggerService - ] + imports: [CommonModule, LoggerModule], + providers: [ClassloggerService], }) -export class ClassloggerModule { } +export class ClassloggerModule {} diff --git a/imxweb/projects/qbm/src/lib/classlogger/classlogger.service.ts b/imxweb/projects/qbm/src/lib/classlogger/classlogger.service.ts index 7994e38e4..37d6e34ba 100644 --- a/imxweb/projects/qbm/src/lib/classlogger/classlogger.service.ts +++ b/imxweb/projects/qbm/src/lib/classlogger/classlogger.service.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -61,10 +61,9 @@ import { NGXLogger } from 'ngx-logger'; * */ @Injectable({ - providedIn: 'root' + providedIn: 'root', }) export class ClassloggerService { - constructor(private nativLogger: NGXLogger) {} /** diff --git a/imxweb/projects/qbm/src/lib/configuration/elemental-ui-config.interface.ts b/imxweb/projects/qbm/src/lib/configuration/elemental-ui-config.interface.ts index 38fa37463..c33b7379b 100644 --- a/imxweb/projects/qbm/src/lib/configuration/elemental-ui-config.interface.ts +++ b/imxweb/projects/qbm/src/lib/configuration/elemental-ui-config.interface.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -27,7 +27,5 @@ import { EuiDownloadOptions } from '@elemental-ui/core'; export interface ElementalUiConfig { - downloadOptions?: EuiDownloadOptions; - } diff --git a/imxweb/projects/qbm/src/lib/configuration/elemental-ui-config.service.ts b/imxweb/projects/qbm/src/lib/configuration/elemental-ui-config.service.ts index 40be47939..7fa2a0584 100644 --- a/imxweb/projects/qbm/src/lib/configuration/elemental-ui-config.service.ts +++ b/imxweb/projects/qbm/src/lib/configuration/elemental-ui-config.service.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -24,7 +24,6 @@ * */ - import { Injectable } from '@angular/core'; import { TranslateService } from '@ngx-translate/core'; import { AuthenticationService } from '../authentication/authentication.service'; @@ -35,10 +34,9 @@ import { ElementalUiConfig } from './elemental-ui-config.interface'; * A service that helps configure Element UI */ @Injectable({ - providedIn: 'root' + providedIn: 'root', }) export class ElementalUiConfigService { - private readonly config: ElementalUiConfig = { downloadOptions: { url: '', @@ -49,9 +47,9 @@ export class ElementalUiConfigService { loaderConfig: { helperText: '', buttonText: '', - spinnerAriaLabel: '' - } - } + spinnerAriaLabel: '', + }, + }, }; /** @@ -63,15 +61,24 @@ export class ElementalUiConfigService { constructor( private readonly translate: TranslateService, - authentication: AuthenticationService + authentication: AuthenticationService, ) { authentication.onSessionResponse.subscribe(() => { - this.translate.get('#LDS#File download in progress'). - subscribe((trans: string) => this.config.downloadOptions.loaderConfig.helperText = trans); - this.translate.get('#LDS#Cancel download'). - subscribe((trans: string) => this.config.downloadOptions.loaderConfig.buttonText = trans); - this.translate.get('#LDS#Loading...'). - subscribe((trans: string) => this.config.downloadOptions.loaderConfig.spinnerAriaLabel = trans); + this.translate.get('#LDS#File download in progress').subscribe((trans: string) => { + if (this.config?.downloadOptions?.loaderConfig) { + this.config.downloadOptions.loaderConfig.helperText = trans; + } + }); + this.translate.get('#LDS#Cancel download').subscribe((trans: string) => { + if (this.config?.downloadOptions?.loaderConfig) { + this.config.downloadOptions.loaderConfig.buttonText = trans; + } + }); + this.translate.get('#LDS#Loading...').subscribe((trans: string) => { + if (this.config?.downloadOptions?.loaderConfig) { + this.config.downloadOptions.loaderConfig.spinnerAriaLabel = trans; + } + }); }); } } diff --git a/imxweb/projects/qbm/src/lib/confirmation/confirmation.module.ts b/imxweb/projects/qbm/src/lib/confirmation/confirmation.module.ts index 94e595ce7..6a6e8ef40 100644 --- a/imxweb/projects/qbm/src/lib/confirmation/confirmation.module.ts +++ b/imxweb/projects/qbm/src/lib/confirmation/confirmation.module.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -31,8 +31,6 @@ import { ConfirmationService } from './confirmation.service'; @NgModule({ providers: [ConfirmationService], - imports: [ - CommonModule - ] + imports: [CommonModule], }) -export class ConfirmationModule { } +export class ConfirmationModule {} diff --git a/imxweb/projects/qbm/src/lib/confirmation/confirmation.service.ts b/imxweb/projects/qbm/src/lib/confirmation/confirmation.service.ts index 507219f75..8f7098c8e 100644 --- a/imxweb/projects/qbm/src/lib/confirmation/confirmation.service.ts +++ b/imxweb/projects/qbm/src/lib/confirmation/confirmation.service.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -26,13 +26,17 @@ import { Injectable, NgZone } from '@angular/core'; import { MatDialog } from '@angular/material/dialog'; +import { EuiLoadingService } from '@elemental-ui/core'; import { TranslateService } from '@ngx-translate/core'; import { MessageDialogResult } from '../message-dialog/message-dialog-result.enum'; import { MessageDialogComponent } from '../message-dialog/message-dialog.component'; +import { MessageDialogService } from '../message-dialog/message-dialog.service'; import { MessageParameter } from '../message-dialog/message-parameter.interface'; +import { AuthenticationService } from '../authentication/authentication.service'; import { LdsReplacePipe } from '../lds-replace/lds-replace.pipe'; +import { ISessionState } from '../session/session-state'; @Injectable({ providedIn: 'root', @@ -43,7 +47,15 @@ export class ConfirmationService { private readonly translate: TranslateService, private readonly pipe: LdsReplacePipe, private readonly zone: NgZone, - ) {} + private readonly messageDialogService: MessageDialogService, + private readonly authentication: AuthenticationService, + private readonly busyService: EuiLoadingService, + ) { + authentication.onSessionResponse.subscribe((session) => (this.currentSession = session)); + } + + private showErrorDialogState = true; + private currentSession: ISessionState; public async confirmLeaveWithUnsavedChanges(title?: string, message?: string, disableClose?: boolean): Promise { const dialogRef = this.dialogService.open(MessageDialogComponent, { @@ -93,7 +105,8 @@ export class ConfirmationService { }, panelClass: 'imx-messageDialog', }); - return (await dialogRef.afterClosed().toPromise()) === MessageDialogResult.YesResult; + const result =await dialogRef.afterClosed().toPromise(); + return result === MessageDialogResult.YesResult || result === MessageDialogResult.OkResult; } // Damit es bis "Pull Request 38432: 299557-imxweb-confirmdialogs-with-yes-no-buttons" funktioniert @@ -103,4 +116,53 @@ export class ConfirmationService { Message: message || '#LDS#Are you sure you want to delete the object?', }); } + + public async showErrorMessage(data: MessageParameter): Promise { + let message = data?.Message ? this.translate.instant(data.Message) : ''; + message = data?.Parameter ? this.pipe.transform(message, ...data.Parameter) : message; + const title = this.translate.instant('#LDS#Error'); + if (this.showErrorDialogState) { + this.showErrorDialogState = false; + this.messageDialogService.errorMessages$.next([message]); + await this.showMessageBox(title, message, 'error', async () => { + this.showErrorDialogState = true; + this.messageDialogService.errorMessages$.next([]); + }); + } else { + this.messageDialogService.errorMessages$.next([...this.messageDialogService.errorMessages$.value, message]); + } + } + + public async handleExpiredSession(): Promise { + await this.showMessageBox( + this.translate.instant('#LDS#Heading Session Expired'), + this.translate.instant('#LDS#Your session has expired. You will now be redirected to the login page where you can log in again.'), + 'clock', + async () => { + const ref = this.busyService.show(); + try { + await this.authentication.update(true); + } finally { + this.busyService.hide(ref); + } + }, + ); + } + + public async showMessageBox(translatedTitle: string, translatedText, icon: string, callback: () => Promise): Promise { + this.zone.run(() => { + this.dialogService + .open(MessageDialogComponent, { + data: { + Title: translatedTitle, + Message: translatedText, + ShowOk: true, + icon: icon, + }, + panelClass: 'imx-messageDialog-error', + }) + .afterClosed() + .subscribe(callback); + }); + } } diff --git a/imxweb/projects/qbm/src/lib/connection/connection.component.html b/imxweb/projects/qbm/src/lib/connection/connection.component.html index a50ff6044..15e75f41b 100644 --- a/imxweb/projects/qbm/src/lib/connection/connection.component.html +++ b/imxweb/projects/qbm/src/lib/connection/connection.component.html @@ -1,4 +1,4 @@ - +
    @@ -6,7 +6,7 @@
    @@ -20,21 +20,22 @@ class="permission-search" data-imx-identifier="permission-eui-search" width="100%" - [(searchControl)]="search" - [placeholder]="'#LDS#Search' | translate"> + [searchControl]="search" + [placeholder]="'#LDS#Search' | translate" + >
    - - + + - - + + - +
    {{'#LDS#Display name' | translate}}{{entity.Display}}{{ '#LDS#Display name' | translate }}{{ entity.Display }} {{'#LDS#Description' | translate}}{{entity.Description}}{{ '#LDS#Description' | translate }}{{ entity.Description }}
    {{ '#LDS#There is no data matching your search.' | translate }} @@ -51,22 +52,22 @@ - {{group.Display}} + {{ group.Display }}
    - - + + - - + + - +
    {{'#LDS#Display name' | translate}}{{entity.Display}}{{ '#LDS#Display name' | translate }}{{ entity.Display }} {{'#LDS#Description' | translate}}{{entity.Description}}{{ '#LDS#Description' | translate }}{{ entity.Description }}
    @@ -78,7 +79,7 @@
    -
    diff --git a/imxweb/projects/qbm/src/lib/connection/connection.component.scss b/imxweb/projects/qbm/src/lib/connection/connection.component.scss index 5d4182f39..8a504d236 100644 --- a/imxweb/projects/qbm/src/lib/connection/connection.component.scss +++ b/imxweb/projects/qbm/src/lib/connection/connection.component.scss @@ -1,37 +1,6 @@ -@import "@elemental-ui/core/src/styles/_palette.scss"; +@import '@elemental-ui/core/src/styles/_palette.scss'; :host { - .mat-tab-group, ::ng-deep .mat-tab-body-wrapper { - height: 100%; - overflow: auto; - } - - ::ng-deep .mat-tab-body-content { - display: flex; - flex-direction: column; - justify-content: space-between; - } - - .imx-mat-tab-container { - padding: 20px; - display: flex; - flex-direction: column; - overflow: auto; - } - - .imx-table-container { - margin-top: 1rem; - height: calc(100% - 57px); - - &.overflow-auto { - overflow: auto; - } - - th, td { - width: 50%; - } - } - .no-results { display: flex; flex-direction: column; @@ -47,15 +16,8 @@ mat-panel-title { font-weight: bold; } -} - -.eui-sidesheet-actions { - ::ng-deep .mat-button-wrapper { + .eui-sidesheet-content { display: flex; - gap: 0.25rem; - } - - .justify-start { - margin-right: auto; + flex-direction: column; } } diff --git a/imxweb/projects/qbm/src/lib/connection/connection.component.ts b/imxweb/projects/qbm/src/lib/connection/connection.component.ts index 672b8e233..ad36b7255 100644 --- a/imxweb/projects/qbm/src/lib/connection/connection.component.ts +++ b/imxweb/projects/qbm/src/lib/connection/connection.component.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -26,26 +26,26 @@ import { Clipboard } from '@angular/cdk/clipboard'; import { Component, Inject, OnDestroy, OnInit } from '@angular/core'; +import { FormControl } from '@angular/forms'; import { EUI_SIDESHEET_DATA } from '@elemental-ui/core'; -import { PermissionInfo, SessionInfoData } from 'imx-api-qbm'; -import { DataSourceToolbarSettings } from '../data-source-toolbar/data-source-toolbar-settings'; +import { PermissionInfo } from '@imx-modules/imx-api-qbm'; +import { ValType } from '@imx-modules/imx-qbm-dbts'; +import { TranslateService } from '@ngx-translate/core'; +import { Subscription } from 'rxjs'; +import { distinctUntilChanged } from 'rxjs/operators'; +import { AuthenticationService } from '../authentication/authentication.service'; import { BusyService } from '../base/busy.service'; -import { SnackBarService } from '../snackbar/snack-bar.service'; import { BaseReadonlyCdr } from '../cdr/base-readonly-cdr'; -import { FormControl } from '@angular/forms'; -import { distinctUntilChanged } from 'rxjs/operators'; import { ColumnDependentReference } from '../cdr/column-dependent-reference.interface'; +import { DataSourceToolbarSettings } from '../data-source-toolbar/data-source-toolbar-settings'; import { EntityService } from '../entity/entity.service'; -import { ValType } from 'imx-qbm-dbts'; import { ISessionState } from '../session/session-state'; -import { AuthenticationService } from '../authentication/authentication.service'; -import { Subscription } from 'rxjs'; +import { SnackBarService } from '../snackbar/snack-bar.service'; import { ConnectionSessionInfoData, SystemUsers } from './connection'; -import { TranslateService } from '@ngx-translate/core'; @Component({ templateUrl: './connection.component.html', - styleUrls: ['./connection.component.scss'] + styleUrls: ['./connection.component.scss'], }) /** Shows connection data and can copy data for support */ @@ -53,11 +53,11 @@ export class ConnectionComponent implements OnInit, OnDestroy { public busyService = new BusyService(); public systemUsers: SystemUsers; public dstSettings: DataSourceToolbarSettings; - public displayedColumns = ['Display','Description']; + public displayedColumns = ['Display', 'Description']; public search: FormControl = new FormControl(''); public searchValue: string; public permissionGroups: PermissionInfo[] = []; - public cdrList:ColumnDependentReference[] = []; + public cdrList: ColumnDependentReference[] = []; public sessionState: ISessionState; private readonly subscriptions: Subscription[] = []; @@ -68,24 +68,28 @@ export class ConnectionComponent implements OnInit, OnDestroy { private readonly snackbar: SnackBarService, private readonly entityService: EntityService, private readonly authentication: AuthenticationService, - private readonly translate: TranslateService + private readonly translate: TranslateService, ) { - this.subscriptions.push(this.authentication.onSessionResponse.subscribe((sessionState: ISessionState) => (this.sessionState = sessionState))); + this.subscriptions.push( + this.authentication.onSessionResponse.subscribe((sessionState: ISessionState) => (this.sessionState = sessionState)), + ); } ngOnInit() { - const { FeatureGroups, PermissionGroups, ...systemUsers} = this.data; - this.systemUsers = {...systemUsers}; - this.systemUsers.UserUid = this.data.UserUid = this.sessionState?.UserUid; + const { FeatureGroups, PermissionGroups, ...systemUsers } = this.data; + this.systemUsers = { ...systemUsers }; + this.systemUsers.UserUid = this.data.UserUid = this.sessionState?.UserUid ?? ''; this.cdrList = this.createCdrList(); - this.permissionGroups = this.data.PermissionGroups; - this.subscriptions.push(this.search.valueChanges.pipe(distinctUntilChanged()).subscribe(() => { - const searchValue = this.search.value.toLowerCase(); - this.permissionGroups = this.data.PermissionGroups.filter(permission => { - return permission.Display.toLowerCase().includes(searchValue) - || permission.Description.toLowerCase().includes(searchValue); - }); - })); + this.permissionGroups = this.data.PermissionGroups ?? []; + this.subscriptions.push( + this.search.valueChanges.pipe(distinctUntilChanged()).subscribe(() => { + const searchValue = this.search.value.toLowerCase(); + this.permissionGroups = + this.data.PermissionGroups?.filter((permission) => { + return permission.Display?.toLowerCase().includes(searchValue) || permission.Description?.toLowerCase().includes(searchValue); + }) ?? []; + }), + ); } /** @@ -96,23 +100,31 @@ export class ConnectionComponent implements OnInit, OnDestroy { const cdrList: BaseReadonlyCdr[] = []; const columnNames: string[] = Object.keys(this.systemUsers); const ldsKeys = { - AuthenticatedBy: "#LDS#Authentication used", - CultureFormat: "#LDS#Language for value formatting", - CultureUi: "#LDS#Language", - DialogUserUid: "#LDS#System user UID", - IsReadOnly: "#LDS#Read-only", - TimeZone: "#LDS#Time zone", - UserUid: "#LDS#User UID", - } + AuthenticatedBy: '#LDS#Authentication used', + CultureFormat: '#LDS#Language for value formatting', + CultureUi: '#LDS#Language', + DialogUserUid: '#LDS#System user UID', + IsReadOnly: '#LDS#Read-only', + TimeZone: '#LDS#Time zone', + UserUid: '#LDS#User UID', + }; columnNames?.forEach((name) => { try { - cdrList.push(new BaseReadonlyCdr(this.entityService.createLocalEntityColumn( - { Type: typeof(this.systemUsers[name]) === "boolean" ? ValType.Bool : ValType.String, ColumnName: name, Display: this.translate.instant(ldsKeys[name] ?? "") }, - undefined, - { Value: this.systemUsers[name] } - ))); - } catch(e) {} + cdrList.push( + new BaseReadonlyCdr( + this.entityService.createLocalEntityColumn( + { + Type: typeof this.systemUsers[name] === 'boolean' ? ValType.Bool : ValType.String, + ColumnName: name, + Display: this.translate.instant(ldsKeys[name] ?? ''), + }, + undefined, + { Value: this.systemUsers[name] }, + ), + ), + ); + } catch (e) {} }); //Sort cdrs in ascending order @@ -131,7 +143,7 @@ export class ConnectionComponent implements OnInit, OnDestroy { */ public copyConnectionData(): void { this.clipboard.copy(JSON.stringify(this.data)); - this.snackbar.open({ key: '#LDS#The connection information has been successfully copied to the clipboard.'}); + this.snackbar.open({ key: '#LDS#The connection information has been successfully copied to the clipboard.' }); } ngOnDestroy(): void { diff --git a/imxweb/projects/qbm/src/lib/connection/connection.ts b/imxweb/projects/qbm/src/lib/connection/connection.ts index dc831805b..3ed8eaeb1 100644 --- a/imxweb/projects/qbm/src/lib/connection/connection.ts +++ b/imxweb/projects/qbm/src/lib/connection/connection.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -24,7 +24,7 @@ * */ -import { SessionInfoData } from 'imx-api-qbm'; +import { SessionInfoData } from '@imx-modules/imx-api-qbm'; export interface SystemUsers { AuthenticatedBy?: string; diff --git a/imxweb/projects/qbm/src/lib/custom-theme/custom-theme.module.ts b/imxweb/projects/qbm/src/lib/custom-theme/custom-theme.module.ts index 2b5b8103f..7ca9b2772 100644 --- a/imxweb/projects/qbm/src/lib/custom-theme/custom-theme.module.ts +++ b/imxweb/projects/qbm/src/lib/custom-theme/custom-theme.module.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -31,12 +31,8 @@ import { CustomThemeService } from './custom-theme.service'; /** Loads and initializes custom themes provided by the API. */ @NgModule({ - imports: [ - CommonModule - ], - providers: [ - AppConfigService - ] + imports: [CommonModule], + providers: [AppConfigService], }) export class CustomThemeModule { constructor(config: CustomThemeService) { diff --git a/imxweb/projects/qbm/src/lib/custom-theme/custom-theme.service.ts b/imxweb/projects/qbm/src/lib/custom-theme/custom-theme.service.ts index 20380713c..6e38d9391 100644 --- a/imxweb/projects/qbm/src/lib/custom-theme/custom-theme.service.ts +++ b/imxweb/projects/qbm/src/lib/custom-theme/custom-theme.service.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -26,15 +26,14 @@ import { DOCUMENT } from '@angular/common'; import { Inject, Injectable } from '@angular/core'; -import { CustomThemeInfo } from 'imx-api-qbm'; import { AppConfigService } from '../appConfig/appConfig.service'; @Injectable({ providedIn: 'root' }) export class CustomThemeService { constructor( @Inject(DOCUMENT) private document: Document, - private readonly config: AppConfigService - ) { } + private readonly config: AppConfigService, + ) {} public initialize(): void { this.config.initializedSubject.subscribe(async () => { @@ -50,6 +49,9 @@ export class CustomThemeService { const head = this.document.getElementsByTagName('head')[0]; for (var theme of customThemes) { + if (!theme.Urls) { + continue; + } for (var url of theme.Urls) { const style = this.document.createElement('link'); style.rel = 'stylesheet'; @@ -58,16 +60,16 @@ export class CustomThemeService { } } - this._customThemes = customThemes.map(m => { + this._customThemes = customThemes.map((m) => { // map .NET types to the expected type for the theme switcher return { - name: m.DisplayName, - class: m.Class + name: m.DisplayName ?? '', + class: m.Class ?? '', }; }); } - private _customThemes: { name: string, class: string }[] = []; + private _customThemes: { name: string; class: string }[] = []; public get customThemes() { return this._customThemes; diff --git a/imxweb/projects/qbm/src/lib/data-export/data-export.component.html b/imxweb/projects/qbm/src/lib/data-export/data-export.component.html index cb37ca351..e2b348e3c 100644 --- a/imxweb/projects/qbm/src/lib/data-export/data-export.component.html +++ b/imxweb/projects/qbm/src/lib/data-export/data-export.component.html @@ -1,80 +1,89 @@
    -
    - {{'#LDS#Data to be exported' | translate}}: - - - {{'#LDS#Displayed data' | translate}} - {{'#LDS#{0} items' | translate | ldsReplace:currentDataCount}} + {{ '#LDS#Data to be exported' | translate }}: + + + {{ '#LDS#Displayed data' | translate }} + ({{ '#LDS#{0} items' | translate | ldsReplace: currentDataCount }}) - {{'#LDS#All data' | translate}} - {{'#LDS#{0} items' | translate | ldsReplace:allDataCount}} + {{ '#LDS#All data' | translate }} + ({{ '#LDS#{0} items' | translate | ldsReplace: allDataCount }})
    - - #LDS#Here you can export data. Select all columns whose contents you want to export. Additionally, you can change the order using drag and drop. Move the mouse pointer over the corresponding area on the left and drag the element to the desired location. + + {{ LdsKey }}
    -
    +
    - - {{'#LDS#Select a column to be exported.' | translate}} + {{ '#LDS#Select a column to be exported.' | translate }} -
    @@ -83,7 +92,14 @@
    -
    diff --git a/imxweb/projects/qbm/src/lib/data-export/data-export.component.scss b/imxweb/projects/qbm/src/lib/data-export/data-export.component.scss index a33312ef3..1a78f090f 100644 --- a/imxweb/projects/qbm/src/lib/data-export/data-export.component.scss +++ b/imxweb/projects/qbm/src/lib/data-export/data-export.component.scss @@ -1,4 +1,4 @@ -@import "@elemental-ui/core/src/styles/_eui_palette.scss"; +@import '@elemental-ui/core/src/styles/_eui_palette.scss'; :host { .tool-bar { @@ -12,30 +12,11 @@ align-items: center; gap: 15px; } - - .mat-radio-group { - display: inherit; - gap: 25px; - } - .eui-select{ - width: 110px; - } - - ::ng-deep .mat-radio-label { - padding: 0; - - .mat-radio-label-content { - display: flex; - flex-direction: column; - } + &-left { + align-items: baseline !important; } } - .eui-sidesheet-content { - display: flex; - flex-direction: column; - } - .card-container { margin-top: 15px; display: flex; @@ -63,12 +44,6 @@ justify-content: space-between; box-sizing: border-box; } - - - .export-column--field { - width: 100%; - margin: 0 10px; - } } // CDK drag styling @@ -94,7 +69,6 @@ transition: transform 250ms cubic-bezier(0, 0, 0.2, 1); } - // Theming .eui-light-theme { :host { diff --git a/imxweb/projects/qbm/src/lib/data-export/data-export.component.ts b/imxweb/projects/qbm/src/lib/data-export/data-export.component.ts index 553ffd261..bd4f1dcdf 100644 --- a/imxweb/projects/qbm/src/lib/data-export/data-export.component.ts +++ b/imxweb/projects/qbm/src/lib/data-export/data-export.component.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -24,15 +24,16 @@ * */ -import { Component, Inject, OnDestroy, OnInit } from '@angular/core'; import { CdkDragDrop, moveItemInArray } from '@angular/cdk/drag-drop'; +import { HttpHeaders } from '@angular/common/http'; +import { Component, Inject, OnDestroy, OnInit } from '@angular/core'; import { FormControl } from '@angular/forms'; -import { EuiDownloadOptions, EuiSelectOption, EuiTheme, EUI_SIDESHEET_DATA, EuiSelectFeedbackMessages } from '@elemental-ui/core'; -import { DataSourceToolbarSettings } from '../data-source-toolbar/data-source-toolbar-settings'; -import { ElementalUiConfigService } from '../configuration/elemental-ui-config.service'; +import { EUI_SIDESHEET_DATA, EuiDownloadOptions, EuiSelectFeedbackMessages, EuiSelectOption, EuiTheme } from '@elemental-ui/core'; +import { TranslateService } from '@ngx-translate/core'; import { AppConfigService } from '../appConfig/appConfig.service'; +import { ElementalUiConfigService } from '../configuration/elemental-ui-config.service'; +import { DataSourceToolbarSettings } from '../data-source-toolbar/data-source-toolbar-settings'; import { DSTExportState, ExportColumnsService, FilteredColumnOption } from './export-columns.service'; -import { TranslateService } from '@ngx-translate/core'; @Component({ selector: 'imx-data-export', @@ -50,44 +51,52 @@ export class DataExportComponent implements OnInit, OnDestroy { @Inject(EUI_SIDESHEET_DATA) public readonly settings: DataSourceToolbarSettings, private readonly config: AppConfigService, private readonly elementalUiConfigService: ElementalUiConfigService, - private readonly translateService: TranslateService - ) { - this.feedbackMessages = { - ...this.feedbackMessages, - clear: this.translateService.instant('#LDS#Clear'), - search :this.translateService.instant('#LDS#Search'), - } - } + private readonly translateService: TranslateService, + ) { + this.feedbackMessages = { + ...this.feedbackMessages, + clear: this.translateService.instant('#LDS#Clear'), + search: this.translateService.instant('#LDS#Search'), + }; + } public get controlsCount(): number { - return this.state?.columns.length; + return this.state?.columns?.length ?? 0; } public get uniqueControlsCount(): number { - return new Set(this.state?.columns.map(column => column.value)).size; + return new Set(this.state?.columns?.map((column) => column.value)).size; } public get canAddMore(): boolean { - return this.controlsCount < this.state?.columnOptions.length; + return this.controlsCount < (this.state?.columnOptions?.length ?? 0); } public get canExport(): boolean { - return this.controlsCount > 0 && - this.state?.columns.map(control => control.valid).every(value => value) && - this.uniqueControlsCount === this.controlsCount; + return ( + this.controlsCount > 0 && + (this.state?.columns?.map((control) => control.valid)?.every((value) => value) ?? false) && + this.uniqueControlsCount === this.controlsCount + ); } public get currentDataCount(): number { - return this.settings.dataSource.Data.length; + return this.settings.dataSource?.Data.length ?? 0; } public get allDataCount(): number { - return this.settings.dataSource.totalCount; + return this.settings.dataSource?.totalCount ?? 0; } public get theme(): string { const bodyClasses = document.body.classList; - return bodyClasses.contains(EuiTheme.LIGHT) ? EuiTheme.LIGHT : (bodyClasses.contains(EuiTheme.DARK) ? EuiTheme.DARK : (bodyClasses.contains(EuiTheme.CONTRAST) ? EuiTheme.CONTRAST : '')); + return bodyClasses.contains(EuiTheme.LIGHT) + ? EuiTheme.LIGHT + : bodyClasses.contains(EuiTheme.DARK) + ? EuiTheme.DARK + : bodyClasses.contains(EuiTheme.CONTRAST) + ? EuiTheme.CONTRAST + : ''; } public ngOnInit(): void { @@ -105,61 +114,65 @@ export class DataExportComponent implements OnInit, OnDestroy { public setDownloadOptions(): void { this.downloadOptions = { ...this.elementalUiConfigService.Config.downloadOptions, - fileMimeType: this.state.selectedExport.value, + fileMimeType: this.state?.selectedExport?.value, requestOptions: { - headers: { - 'Accept': this.state.selectedExport.value - }, - withCredentials: true + headers: new HttpHeaders({ Accept: this.state.selectedExport?.value }), + withCredentials: true, }, - } + url: '', + }; } // Update the request url public setUrl(): void { - const withProperties = '-' + this.state.columns.map(column => column.value).join(','); - const method = this.settings.exportMethod.getMethod(withProperties, this.state.isAllData ? this.allDataCount : null); + const withProperties = '-' + this.state.columns?.map((column) => column.value).join(','); + const method = this.settings?.exportMethod?.getMethod(withProperties, this.state.isAllData ? this.allDataCount : 0); this.downloadOptions = { ...this.downloadOptions, - url: this.config.BaseUrl + method.path + url: this.config.BaseUrl + (method?.path ?? ''), }; this.updateFilteredColumnOptions(); } // Calculate all valid options for all select (remove selected ones) - public updateFilteredColumnOptions():void{ - this.filteredColumnOptions = this.state.columns.map( - form => ( - { - value: form.value, - options: this.state.columnOptions.filter(option => !this.state.columns.filter(columnForm => columnForm.value !== form.value).map(columnForm => columnForm.value).includes(option.value)) - } - ) - ); + public updateFilteredColumnOptions(): void { + this.filteredColumnOptions = + this.state.columns?.map((form) => ({ + value: form.value, + options: + this.state.columnOptions?.filter( + (option) => + !this.state.columns + ?.filter((columnForm) => columnForm.value !== form.value) + .map((columnForm) => columnForm.value) + .includes(option.value), + ) ?? [], + })) ?? []; } // Return all available options - public getFilteredOptions(value:string): EuiSelectOption[]{ - return this.filteredColumnOptions.filter(columnOption => columnOption.value === value)[0]?.options; + public getFilteredOptions(value: string): EuiSelectOption[] { + return this.filteredColumnOptions.filter((columnOption) => columnOption.value === value)[0]?.options; } // Drag & drop order of columns public drop(event: CdkDragDrop): void { + if (!this.state.columns) { + return; + } moveItemInArray(this.state.columns, event.previousIndex, event.currentIndex); this.setUrl(); } // Remove a column from the export list public deleteColumn(ind: number): void { - this.state.columns.splice(ind, 1); + this.state.columns?.splice(ind, 1); this.setUrl(); } // Add a column to the export list public addNewColumn(value?: EuiSelectOption): void { - this.state.columns.push( - this.columnExportService.createColumn(value) - ); + this.state.columns?.push(this.columnExportService.createColumn(value)); this.updateFilteredColumnOptions(); } @@ -169,11 +182,12 @@ export class DataExportComponent implements OnInit, OnDestroy { ...this.downloadOptions, fileMimeType: type.value, requestOptions: { - headers: { - accept: type.value - }, - withCredentials: true - } + headers: new HttpHeaders({ Accept: type.value }), + withCredentials: true, + }, }; } + + public LdsKey = + '#LDS#Here you can export data. Select all columns whose contents you want to export. Additionally, you can change the order using drag and drop. Move the mouse pointer over the corresponding area on the left and drag the element to the desired location.'; } diff --git a/imxweb/projects/qbm/src/lib/data-export/data-export.module.ts b/imxweb/projects/qbm/src/lib/data-export/data-export.module.ts index 8e6c891e5..585f64cfa 100644 --- a/imxweb/projects/qbm/src/lib/data-export/data-export.module.ts +++ b/imxweb/projects/qbm/src/lib/data-export/data-export.module.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -38,7 +38,6 @@ import { DataExportComponent } from './data-export.component'; import { LdsReplaceModule } from '../lds-replace/lds-replace.module'; import { MatRadioModule } from '@angular/material/radio'; - @NgModule({ imports: [ CommonModule, @@ -53,7 +52,7 @@ import { MatRadioModule } from '@angular/material/radio'; DragDropModule, CdkScrollableModule, MatRadioModule, - FormsModule + FormsModule, ], declarations: [DataExportComponent], }) diff --git a/imxweb/projects/qbm/src/lib/data-export/export-columns.service.spec.ts b/imxweb/projects/qbm/src/lib/data-export/export-columns.service.spec.ts index 343d4aecb..ff2389755 100644 --- a/imxweb/projects/qbm/src/lib/data-export/export-columns.service.spec.ts +++ b/imxweb/projects/qbm/src/lib/data-export/export-columns.service.spec.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR diff --git a/imxweb/projects/qbm/src/lib/data-export/export-columns.service.ts b/imxweb/projects/qbm/src/lib/data-export/export-columns.service.ts index 7ea4d4c9f..486e05cc7 100644 --- a/imxweb/projects/qbm/src/lib/data-export/export-columns.service.ts +++ b/imxweb/projects/qbm/src/lib/data-export/export-columns.service.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -27,24 +27,25 @@ import { Injectable } from '@angular/core'; import { FormControl, Validators } from '@angular/forms'; import { EuiSelectOption } from '@elemental-ui/core'; -import { DataModel, DataModelProperty } from 'imx-qbm-dbts'; +import { DataModel, DataModelProperty } from '@imx-modules/imx-qbm-dbts'; import _ from 'lodash'; import { DataSourceToolbarSettings } from '../data-source-toolbar/data-source-toolbar-settings'; export interface DSTExportState { - dataModel?: DataModel, - selectedExport?: FormControl, - exportOptions?: EuiSelectOption[], - isAllData?: boolean, - columns?: FormControl[], - columnOptions?: EuiSelectOption[] + dataModel?: DataModel; + selectedExport?: FormControl; + exportOptions?: EuiSelectOption[]; + isAllData?: boolean; + columns?: FormControl[]; + columnOptions?: EuiSelectOption[]; } -export interface FilteredColumnOption{ - value: string; options: EuiSelectOption[]; +export interface FilteredColumnOption { + value: string; + options: EuiSelectOption[]; } @Injectable({ - providedIn: 'root' + providedIn: 'root', }) export class ExportColumnsService { public columnOptions: EuiSelectOption[]; @@ -63,18 +64,21 @@ export class ExportColumnsService { { display: 'PDF', value: 'application/pdf', - } + }, ]; - public exportOptionsFilter = (option: EuiSelectOption, searchInputValue: string) => option.display.toLowerCase().includes(searchInputValue.toLowerCase()); + public exportOptionsFilter = (option: EuiSelectOption, searchInputValue: string) => + option.display.toLowerCase().includes(searchInputValue.toLowerCase()); public columnOptionsFilter = (option: EuiSelectOption, searchInputValue: string) => { const sanitizedInput = searchInputValue.toLowerCase(); - return option.display.toLowerCase().includes(sanitizedInput) || option?.displayDetail?.toLowerCase().includes(sanitizedInput); - } + return ( + (option.display.toLowerCase().includes(sanitizedInput) || option?.displayDetail?.toLowerCase().includes(sanitizedInput)) ?? false + ); + }; // This function will check if the incoming data model is different from what exists. public setupExport(settings?: DataSourceToolbarSettings): void { - if (this.stashedState && this.checkDataModel(settings.dataModel)) { + if (this.stashedState && this.checkDataModel(settings?.dataModel)) { // This is the same data model, don't need to do anything return; } @@ -83,33 +87,33 @@ export class ExportColumnsService { this.createInitialState(settings); } - public checkDataModel(dataModel: DataModel): boolean { - const stashedProperties = this.stashedState.dataModel.Properties.map(column => column.Property.ColumnName); - const properties = dataModel.Properties.map(column => column.Property.ColumnName); + public checkDataModel(dataModel: DataModel | undefined): boolean { + const stashedProperties = this.stashedState.dataModel?.Properties?.map((column) => column?.Property?.ColumnName); + const properties = dataModel?.Properties?.map((column) => column?.Property?.ColumnName); return _.isEqual(stashedProperties, properties); } // Saves the column options internally - public createInitialState(settings: DataSourceToolbarSettings): void { + public createInitialState(settings: DataSourceToolbarSettings | undefined): void { // Column Options sorted alphebetically, not filtering by IsAdditional - this leads to empty exports - const columnOptions = settings.dataModel.Properties.map(prop => { + const columnOptions = settings?.dataModel?.Properties?.map((prop) => { return this.makeOption(prop); }); - columnOptions.sort((a, b) => a.display >= b.display ? 1: -1); + columnOptions?.sort((a, b) => (a.display >= b.display ? 1 : -1)); const selectedExport = new FormControl('text/csv'); // Check for initial columns, or try to use displayed columns const columns: FormControl[] = []; - if (settings.exportMethod?.initialColumns) { - settings.exportMethod.initialColumns.forEach(column => { - const option = columnOptions.find(prop => prop.value === column); + if (settings?.exportMethod?.initialColumns) { + settings.exportMethod.initialColumns.forEach((column) => { + const option = columnOptions?.find((prop) => prop.value === column); if (option) { columns.push(this.createColumn(option)); } - }) + }); } else if (settings?.displayedColumns) { - settings.displayedColumns.forEach(column => { - const option = columnOptions.find(prop => prop.value === column.ColumnName); + settings.displayedColumns.forEach((column) => { + const option = columnOptions?.find((prop) => prop.value === column.ColumnName); if (option) { columns.push(this.createColumn(option)); } @@ -122,23 +126,23 @@ export class ExportColumnsService { } this.stashedState = { - dataModel: settings.dataModel, + dataModel: settings?.dataModel, columnOptions, columns, isAllData: this.isAllData, selectedExport, - exportOptions: this.exportOptions - } + exportOptions: this.exportOptions, + }; } // Setup an option for column export public makeOption(property: DataModelProperty): EuiSelectOption { const display = property.Property?.Display ?? property.Property?.ColumnName; return { - display, - value: property.Property.ColumnName, - displayDetail: property.Property?.Description - } + display: display ?? '', + value: property?.Property?.ColumnName, + displayDetail: property.Property?.Description, + }; } // Create a new column for export @@ -149,10 +153,10 @@ export class ExportColumnsService { // Stash the state of the sidesheet for later use public stashState(): void { // Filter out all invalid columns, leave one if all are invalid - if (this.stashedState.columns.every(column => column.invalid)) { + if (this.stashedState?.columns?.every((column) => column.invalid)) { this.stashedState.columns = [this.createColumn()]; } else { - this.stashedState.columns = this.stashedState.columns.filter(column => column.valid); + this.stashedState.columns = this.stashedState?.columns?.filter((column) => column.valid); } } } diff --git a/imxweb/projects/qbm/src/lib/data-source-toolbar/additional-infos/additional-infos.component.html b/imxweb/projects/qbm/src/lib/data-source-toolbar/additional-infos/additional-infos.component.html index e7e23a773..c32d8131e 100644 --- a/imxweb/projects/qbm/src/lib/data-source-toolbar/additional-infos/additional-infos.component.html +++ b/imxweb/projects/qbm/src/lib/data-source-toolbar/additional-infos/additional-infos.component.html @@ -1,39 +1,47 @@ -

    {{(data.type === 'list' ? '#LDS#Heading Additional Information per Entry' : '#LDS#Heading Additional Columns') | translate}}

    +

    + {{ (data.type === 'list' ? '#LDS#Heading Additional Information per Entry' : '#LDS#Heading Additional Columns') | translate }} +

    - + - {{infoText}} + {{ infoText }} - {{infoTextLong}} + {{ infoTextLong }} - {{'#LDS#Columns that can be added' | translate}} + {{ '#LDS#Columns that can be added' | translate }} - - {{property?.Display ?? (property?.untranslatedDisplay | translate) ?? property?.ColumnName}} + *ngFor="let property of possibleProperties" + > + {{ property?.Display ?? (property?.untranslatedDisplay ?? '' | translate) ?? property?.ColumnName }} - {{'#LDS#Columns that are displayed' | translate}} + {{ '#LDS#Columns that are displayed' | translate }}
    - {{property?.Display ?? (property?.untranslatedDisplay | translate) ?? property?.ColumnName}} -
    - + @@ -44,10 +52,9 @@

    {{(data.type === 'list' ? '#LDS#Heading Additional Informat

    - - - - \ No newline at end of file + + + + diff --git a/imxweb/projects/qbm/src/lib/data-source-toolbar/additional-infos/additional-infos.component.scss b/imxweb/projects/qbm/src/lib/data-source-toolbar/additional-infos/additional-infos.component.scss index bbce90c22..5516d8dfc 100644 --- a/imxweb/projects/qbm/src/lib/data-source-toolbar/additional-infos/additional-infos.component.scss +++ b/imxweb/projects/qbm/src/lib/data-source-toolbar/additional-infos/additional-infos.component.scss @@ -2,19 +2,19 @@ @import '@elemental-ui/core/src/styles/_palette.scss'; @import '@elemental-ui/core/src/styles/_eui_palette.scss'; -:host{ - display:flex; +:host { + display: flex; flex-direction: column; - height: 100% + height: 100%; } -.imx-dialog-content{ +.imx-dialog-content { flex: 1 1 auto; display: grid; grid-template-columns: 1fr 1fr; } -.imx-element-chooser{ +.imx-element-chooser { margin-right: 15px; overflow: hidden; display: flex; @@ -27,17 +27,6 @@ } } -.imx-helper-alert { - grid-row: 1; - grid-column-start: 1; - grid-column-end: 3; - margin-bottom: 10px; - - .imx-info-content { - font-size: 14px; - } -} - .disabled-list { background: transparent; } @@ -48,7 +37,6 @@ flex-direction: column; background: $white; border-radius: 4px; - overflow: hidden; } .example-box { @@ -61,7 +49,7 @@ align-items: center; justify-content: space-between; box-sizing: border-box; - background: $white; + background: $white; flex-grow: 1; flex-basis: 0; @@ -70,7 +58,7 @@ } } -.dragDropContainer{ +.dragDropContainer { grid-column: 2; padding: 10px; overflow-y: auto; @@ -86,9 +74,9 @@ .cdk-drag-preview { box-sizing: border-box; border-radius: 4px; - box-shadow: 0 5px 5px -3px $black-c - 0 8px 10px 1px mat.get-color-from-palette($asher-gray-palette, 900), - 0 3px 14px 2px mat.get-color-from-palette($asher-gray-palette, 700); + box-shadow: + 0 5px 5px -3px $black-c 0 8px 10px 1px mat.m2-get-color-from-palette($asher-gray-palette, 900), + 0 3px 14px 2px mat.m2-get-color-from-palette($asher-gray-palette, 700); } .cdk-drag-placeholder { @@ -112,7 +100,7 @@ .example-box { border: solid 1px $color-gray-60; color: $color-gray-10; - background: $color-gray-70; + background: $color-gray-70; } } } @@ -126,7 +114,7 @@ .example-box { border: solid 1px $color-gray-0; color: $color-gray-10; - background: $color-gray-100; + background: $color-gray-100; } .imx-drag-handle { diff --git a/imxweb/projects/qbm/src/lib/data-source-toolbar/additional-infos/additional-infos.component.ts b/imxweb/projects/qbm/src/lib/data-source-toolbar/additional-infos/additional-infos.component.ts index e658f8673..0771f61a8 100644 --- a/imxweb/projects/qbm/src/lib/data-source-toolbar/additional-infos/additional-infos.component.ts +++ b/imxweb/projects/qbm/src/lib/data-source-toolbar/additional-infos/additional-infos.component.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -26,9 +26,9 @@ import { CdkDragDrop, moveItemInArray } from '@angular/cdk/drag-drop'; import { Component, Inject, OnInit } from '@angular/core'; -import { MatDialogRef, MAT_DIALOG_DATA } from '@angular/material/dialog'; +import { MAT_DIALOG_DATA, MatDialogRef } from '@angular/material/dialog'; import { MatSelectionListChange } from '@angular/material/list'; -import { DataModel, EntitySchema, IClientProperty } from 'imx-qbm-dbts'; +import { DataModel, EntitySchema, IClientProperty } from '@imx-modules/imx-qbm-dbts'; import { ClientPropertyForTableColumns } from '../client-property-for-table-columns'; @Component({ @@ -37,13 +37,13 @@ import { ClientPropertyForTableColumns } from '../client-property-for-table-colu styleUrls: ['./additional-infos.component.scss'], }) export class AdditionalInfosComponent implements OnInit { - public possibleProperties: IClientProperty[]; + public possibleProperties: ClientPropertyForTableColumns[]; public infoText = '#LDS#Select the columns you want to add.'; public infoTextLong = '#LDS#Here you can add additional columns to your table. Additionally, you can change the order using drag and drop. Move the mouse pointer over the shaded area and drag the element to the desired location.'; - public get result(): any { + public get result(): { all: IClientProperty[]; optionals: IClientProperty[] } { return { all: this.data.preselectedProperties, optionals: this.optionals }; } @@ -62,7 +62,7 @@ export class AdditionalInfosComponent implements OnInit { additionalColumns: ClientPropertyForTableColumns[]; type: 'list' | 'columns'; }, - public dialogRef: MatDialogRef + public dialogRef: MatDialogRef, ) {} public ngOnInit(): void { @@ -112,8 +112,8 @@ export class AdditionalInfosComponent implements OnInit { private static compareNames(column1: IClientProperty, column2: IClientProperty): number { if (column1.Display == null || column2?.Display == null) { - return column1.ColumnName?.localeCompare(column2.ColumnName); + return column1.ColumnName?.localeCompare(column2.ColumnName ?? '') ?? 0; } - return column1.ColumnName?.localeCompare(column2.ColumnName); + return column1.ColumnName?.localeCompare(column2.ColumnName ?? '') ?? 0; } } diff --git a/imxweb/projects/qbm/src/lib/data-source-toolbar/client-property-for-table-columns.ts b/imxweb/projects/qbm/src/lib/data-source-toolbar/client-property-for-table-columns.ts index ccb3fe2b1..737dd37cf 100644 --- a/imxweb/projects/qbm/src/lib/data-source-toolbar/client-property-for-table-columns.ts +++ b/imxweb/projects/qbm/src/lib/data-source-toolbar/client-property-for-table-columns.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -24,20 +24,18 @@ * */ -import { IClientProperty } from 'imx-qbm-dbts'; +import { IClientProperty } from '@imx-modules/imx-qbm-dbts'; /** * Extends the IClientProperty interface, by adding a property for marking columns, * that have to be displayed on the far right side */ -export interface ClientPropertyForTableColumns extends IClientProperty{ - +export interface ClientPropertyForTableColumns extends IClientProperty { /** * Marks, whether the property should be displayed on the far right side of a table or not */ afterAdditionals?: boolean; - /** * Gets/Sets an untranslated display, that can be displayed, if the property 'Display' is not set */ diff --git a/imxweb/projects/qbm/src/lib/data-source-toolbar/column-options.ts b/imxweb/projects/qbm/src/lib/data-source-toolbar/column-options.ts index 7d30c019a..961e69a66 100644 --- a/imxweb/projects/qbm/src/lib/data-source-toolbar/column-options.ts +++ b/imxweb/projects/qbm/src/lib/data-source-toolbar/column-options.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -26,13 +26,13 @@ import { EventEmitter, Injector } from '@angular/core'; import { MatDialog } from '@angular/material/dialog'; -import { DataModel, DataModelViewConfig, EntitySchema, IClientProperty, ValType } from 'imx-qbm-dbts'; +import { DataModel, DataModelViewConfig, EntitySchema, IClientProperty, ValType } from '@imx-modules/imx-qbm-dbts'; +import _ from 'lodash'; import { ClassloggerService } from '../classlogger/classlogger.service'; import { StorageService } from '../storage/storage.service'; import { AdditionalInfosComponent } from './additional-infos/additional-infos.component'; -import { DataSourceToolbarSettings } from './data-source-toolbar-settings'; import { ClientPropertyForTableColumns } from './client-property-for-table-columns'; -import _ from 'lodash'; +import { DataSourceToolbarSettings } from './data-source-toolbar-settings'; import { DSTViewConfig } from './data-source-toolbar-view-config.interface'; export interface ShownClientPropertiesArg { @@ -48,7 +48,7 @@ export class ColumnOptions { /** * List of possible addable columns */ - public optionalColumns: IClientProperty[] = []; + public optionalColumns: (IClientProperty | undefined)[] = []; /** * A list of client properties, that should be shown in the main column @@ -60,7 +60,7 @@ export class ColumnOptions { /** * currently used view settings */ - public currentViewSettings: DataModelViewConfig | DSTViewConfig; + public currentViewSettings: DataModelViewConfig | DSTViewConfig | undefined; /** * Event, that emits, when the shownClientProperies Property changes @@ -76,14 +76,14 @@ export class ColumnOptions { * Indicates whether there are optional columns or not */ public get hasOptionalColumns(): boolean { - return this.currentViewSettings && this.optionalColumns?.length > 0; + return (this.currentViewSettings && this.optionalColumns?.length > 0) ?? false; } // Additional columns are set to null if we are using a config so that we can still edit the columns public get additionalColumns(): IClientProperty[] { return ( this.currentViewSettings?.AdditionalTableColumns?.map((elem) => - ColumnOptions.getClientProperty(ColumnOptions.findKey(elem, this.entitySchema), this.dataModel, this.entitySchema) + ColumnOptions.getClientProperty(ColumnOptions.findKey(elem, this.entitySchema), this.dataModel, this.entitySchema), ) ?? [] ); } @@ -99,19 +99,23 @@ export class ColumnOptions { private logger: ClassloggerService; // getter for settings - private get dataModel(): DataModel { + private get dataModel(): DataModel | undefined { return this.settings.dataModel; } private entitySchema: EntitySchema; private get displayedColumns(): IClientProperty[] { - return this.settings.displayedColumns; + return this.settings?.displayedColumns ?? []; } private originalEntitySchema; - constructor(public settings: DataSourceToolbarSettings, injector: Injector, public viewConfig?: DSTViewConfig) { + constructor( + public settings: DataSourceToolbarSettings, + injector: Injector, + public viewConfig?: DSTViewConfig, + ) { // Use the injected viewConfig if available - this.currentViewSettings = viewConfig ?? this.dataModel.Configurations?.find((elem) => elem.Id === this.dataModel.DefaultConfigId); + this.currentViewSettings = viewConfig ?? this.dataModel?.Configurations?.find((elem) => elem.Id === this.dataModel?.DefaultConfigId); if (this.currentViewSettings) { // Clean up settings, if there are null or empty columnsnames attached @@ -120,7 +124,7 @@ export class ColumnOptions { this.currentViewSettings.AdditionalListColumns.some((elem) => elem == null || elem === '') ) { (this.currentViewSettings.AdditionalListColumns as any) = this.currentViewSettings.AdditionalListColumns.filter( - (elem) => elem != null && elem !== '' + (elem) => elem != null && elem !== '', ); } @@ -129,7 +133,7 @@ export class ColumnOptions { this.currentViewSettings.AdditionalTableColumns.some((elem) => elem == null || elem === '') ) { (this.currentViewSettings.AdditionalTableColumns as any) = this.currentViewSettings.AdditionalTableColumns.filter( - (elem) => elem != null && elem !== '' + (elem) => elem != null && elem !== '', ); } } @@ -145,7 +149,7 @@ export class ColumnOptions { public getPropertiesForNavigation(): string[] { return this.shownClientProperties .filter((elem) => this.displayedColumns.findIndex((disp) => disp.ColumnName === elem.ColumnName) === -1) - .map((elem) => elem.ColumnName); + .map((elem) => elem.ColumnName ?? ''); } /** @@ -199,9 +203,9 @@ export class ColumnOptions { } // We will reset by grabbing the default Id - this.currentViewSettings = this.dataModel.Configurations?.find((elem) => elem.Id === 'Default'); + this.currentViewSettings = this.dataModel?.Configurations?.find((elem) => elem.Id === 'Default'); - const addition = this.additionalColumns; + const addition: IClientProperty[] = this.additionalColumns ?? []; this.selectedOptionals = []; this.shownClientProperties = [...this.displayedColumns]; @@ -232,7 +236,9 @@ export class ColumnOptions { // hack for adding the new columns to to entitySchema elements.forEach((element) => { const key = ColumnOptions.findKey(element, this.entitySchema); - (this.entitySchema.Columns[key] as any) = ColumnOptions.getClientProperty(key, this.dataModel, this.entitySchema); + if (key) { + (this.entitySchema.Columns[key] as any) = ColumnOptions.getClientProperty(key, this.dataModel, this.entitySchema); + } }); } @@ -256,16 +262,17 @@ export class ColumnOptions { } private initOptionalColumns(): void { - const optional = this.dataModel.Properties?.filter((elem) => elem.IsAdditionalColumn).map((elem) => elem.Property); + const optional = this.dataModel?.Properties?.filter((elem) => elem.IsAdditionalColumn).map((elem) => elem.Property); // Check if this isAdditional or if its already in the additionalColumns, both are needed to not lose the option from config selection - this.optionalColumns = optional?.filter((value, index, categoryArray) => { - const isAdditional = - this.isAdditional(value.ColumnName) || - this.additionalColumns.find((ele) => ele.ColumnName.toLocaleLowerCase() == value.ColumnName.toLocaleLowerCase()) != null; - const indexMatch = categoryArray.indexOf(value) === index; - return isAdditional && indexMatch; - }); + this.optionalColumns = + optional?.filter((value, index, categoryArray) => { + const isAdditional = + this.isAdditional(value?.ColumnName) || + this.additionalColumns.find((ele) => ele.ColumnName?.toLocaleLowerCase() == value?.ColumnName?.toLocaleLowerCase()) != null; + const indexMatch = categoryArray.indexOf(value) === index; + return isAdditional && indexMatch; + }) ?? []; this.logger.trace(this, 'optional columns', this.optionalColumns); } @@ -273,7 +280,7 @@ export class ColumnOptions { private initShownClientProperties(): void { const current = this.currentViewSettings?.AdditionalTableColumns?.filter((element) => - this.displayedColumns.every((elem) => elem.ColumnName !== element) + this.displayedColumns.every((elem) => elem.ColumnName !== element), ).map((elem) => ColumnOptions.getClientProperty(elem, this.dataModel)) ?? []; this.shownClientProperties = [...this.displayedColumns]; const index = this.shownClientProperties.findIndex((elem) => elem.afterAdditionals); @@ -284,32 +291,37 @@ export class ColumnOptions { private initAdditionalListElements(): void { const lists = this.currentViewSettings?.AdditionalListColumns; - if (lists?.length > 0) { - this.additionalListElements = lists.map((elem) => - ColumnOptions.getClientProperty(ColumnOptions.findKey(elem, this.entitySchema), this.dataModel, this.entitySchema) - ); - this.additionalListElementsChanged.emit(this.additionalListElements); + if (!!lists?.length) { + this.additionalListElements = + lists?.map((elem) => + ColumnOptions.getClientProperty(ColumnOptions.findKey(elem, this.entitySchema), this.dataModel, this.entitySchema), + ) ?? []; + this.additionalListElementsChanged.emit(this.additionalListElements ?? []); this.logger.trace(this, 'additional list elements from viewSettings', this.additionalListElements); } } - private isAdditional(key: string): boolean { + private isAdditional(key: string | undefined): boolean { return ( - this.displayedColumns.find((elem) => elem.ColumnName.toLocaleLowerCase() === key.toLocaleLowerCase()) == null && - this.currentViewSettings?.AdditionalListColumns?.find((elem) => elem.toLocaleLowerCase() === key.toLocaleLowerCase()) == null && - this.currentViewSettings?.AdditionalTableColumns?.find((elem) => elem.toLocaleLowerCase() === key.toLocaleLowerCase()) == null + this.displayedColumns.find((elem) => elem.ColumnName?.toLocaleLowerCase() === key?.toLocaleLowerCase()) == null && + this.currentViewSettings?.AdditionalListColumns?.find((elem) => elem.toLocaleLowerCase() === key?.toLocaleLowerCase()) == null && + this.currentViewSettings?.AdditionalTableColumns?.find((elem) => elem.toLocaleLowerCase() === key?.toLocaleLowerCase()) == null ); } - public static getClientProperty(name: string, dataModel: DataModel, entitySchema?: EntitySchema): IClientProperty { - let property: IClientProperty; + public static getClientProperty( + name: string | undefined, + dataModel: DataModel | undefined, + entitySchema?: EntitySchema, + ): IClientProperty { + let property: IClientProperty | null | undefined = null; if (entitySchema) { const key = ColumnOptions.findKey(name, entitySchema); property = key != null ? entitySchema.Columns[key] : null; } if (property == null) { property = dataModel?.Properties?.find( - (elem) => elem?.Property?.ColumnName?.toLocaleLowerCase() === name?.toLocaleLowerCase() + (elem) => elem?.Property?.ColumnName?.toLocaleLowerCase() === name?.toLocaleLowerCase(), )?.Property; } if (property == null) { @@ -318,8 +330,8 @@ export class ColumnOptions { return property; } - public static findKey(key: string, schema: EntitySchema): string { - const keyVariant = Object.keys(schema.Columns).find((elem) => elem.toLocaleLowerCase() === key.toLocaleLowerCase()); + public static findKey(key: string | undefined, schema: EntitySchema): string | undefined { + const keyVariant = Object.keys(schema.Columns).find((elem) => elem.toLocaleLowerCase() === key?.toLocaleLowerCase()); return keyVariant ?? key; } } diff --git a/imxweb/projects/qbm/src/lib/data-source-toolbar/data-model/data-model-helper.spec.ts b/imxweb/projects/qbm/src/lib/data-source-toolbar/data-model/data-model-helper.spec.ts index 72106ba64..a48747cc7 100644 --- a/imxweb/projects/qbm/src/lib/data-source-toolbar/data-model/data-model-helper.spec.ts +++ b/imxweb/projects/qbm/src/lib/data-source-toolbar/data-model/data-model-helper.spec.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -24,15 +24,12 @@ * */ -import { DataModelFilterOption, DataModelProperty, ValType } from 'imx-qbm-dbts'; +import { DataModelFilterOption, DataModelProperty, ValType } from '@imx-modules/imx-qbm-dbts'; import { createGroupData } from './data-model-helper'; describe('DataModelHelper', () => { it('should createGroupData - undefined if no data', () => { - const groupData = createGroupData( - { }, - undefined - ); + const groupData = createGroupData({}, undefined); expect(groupData).toBeUndefined(); }); @@ -43,11 +40,11 @@ describe('DataModelHelper', () => { Properties: [ { IsGroupable: false, Property: { Type: ValType.String, ColumnName: 'some columnName not groupable' } }, { IsGroupable: true, Property: { Type: ValType.String, ColumnName: 'some columnName excluded' } }, - { IsGroupable: true, Property: { Type: ValType.String, ColumnName: 'some columnName' } } - ] as DataModelProperty[] + { IsGroupable: true, Property: { Type: ValType.String, ColumnName: 'some columnName' } }, + ] as DataModelProperty[], }, - __ => Promise.resolve({ TotalCount: 0 }), - ['some columnName excluded'] + (__) => Promise.resolve({ TotalCount: 0 }), + ['some columnName excluded'], ); expect(groupData.groups.length).toEqual(1); @@ -58,11 +55,9 @@ describe('DataModelHelper', () => { it('should createGroupData groups based on GroupInfo with length === 1', () => { const groupData = createGroupData( { - GroupInfo: [ - { Options: [{ Value: 'option1' }] } - ] + GroupInfo: [{ Options: [{ Value: 'option1' }] }], }, - __ => Promise.resolve({ TotalCount: 0 }) + (__) => Promise.resolve({ TotalCount: 0 }), ); expect(groupData.groups.length).toEqual(1); @@ -73,12 +68,9 @@ describe('DataModelHelper', () => { it('should createGroupData groupingCategories based on GroupInfo with length > 1', () => { const groupData = createGroupData( { - GroupInfo: [ - { Options: [{ Value: 'option1' }] }, - { Options: [{ Value: 'option2' }] } - ] + GroupInfo: [{ Options: [{ Value: 'option1' }] }, { Options: [{ Value: 'option2' }] }], }, - __ => Promise.resolve({ TotalCount: 0 }) + (__) => Promise.resolve({ TotalCount: 0 }), ); expect(groupData.groups.length).toEqual(0); @@ -92,14 +84,10 @@ describe('DataModelHelper', () => { it('should createGroupData groups based on Properties and GroupInfo length === 1', () => { const groupData = createGroupData( { - Properties: [ - { IsGroupable: true, Property: { Type: ValType.String, ColumnName: 'some columnName' } } - ] as DataModelProperty[], - GroupInfo: [ - { Options: [{ Value: 'option1' }] } - ] + Properties: [{ IsGroupable: true, Property: { Type: ValType.String, ColumnName: 'some columnName' } }] as DataModelProperty[], + GroupInfo: [{ Options: [{ Value: 'option1' }] }], }, - __ => Promise.resolve({ TotalCount: 0 }) + (__) => Promise.resolve({ TotalCount: 0 }), ); expect(groupData.groups.length).toEqual(2); @@ -111,15 +99,10 @@ describe('DataModelHelper', () => { it('should createGroupData groups and groupingCategories based on Properties and GroupInfo with length > 1', () => { const groupData = createGroupData( { - Properties: [ - { IsGroupable: true, Property: { Type: ValType.String, ColumnName: 'some columnName' } } - ] as DataModelProperty[], - GroupInfo: [ - { Options: [{ Value: 'option1' }] }, - { Options: [{ Value: 'option2' }] } - ] + Properties: [{ IsGroupable: true, Property: { Type: ValType.String, ColumnName: 'some columnName' } }] as DataModelProperty[], + GroupInfo: [{ Options: [{ Value: 'option1' }] }, { Options: [{ Value: 'option2' }] }], }, - __ => Promise.resolve({ TotalCount: 0 }) + (__) => Promise.resolve({ TotalCount: 0 }), ); expect(groupData.groups.length).toEqual(1); diff --git a/imxweb/projects/qbm/src/lib/data-source-toolbar/data-model/data-model-helper.ts b/imxweb/projects/qbm/src/lib/data-source-toolbar/data-model/data-model-helper.ts index fb38ca44f..e9a600c3e 100644 --- a/imxweb/projects/qbm/src/lib/data-source-toolbar/data-model/data-model-helper.ts +++ b/imxweb/projects/qbm/src/lib/data-source-toolbar/data-model/data-model-helper.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -24,38 +24,42 @@ * */ -import { CollectionLoadParameters, DataModel, DataModelFilterOption, GroupInfo, GroupInfoData } from 'imx-qbm-dbts'; -import { DataSourceToolBarGroup, DataSourceToolbarGroupData } from '../data-source-toolbar-groups.interface'; +import { CollectionLoadParameters, DataModel, DataModelFilterOption, GroupInfo, GroupInfoData } from '@imx-modules/imx-qbm-dbts'; +import { + DataSourceToolBarGroup, + DataSourceToolbarGroupData, + DataSourceToolBarGroupingCategory, +} from '../data-source-toolbar-groups.interface'; import { GroupInfoLoadParameters } from './group-info-load-parameters.interface'; export function createGroupData( dataModel: DataModel, - getGroupInfo: (parameters: GroupInfoLoadParameters) => Promise, - excludedColumns?: string[] -): DataSourceToolbarGroupData { - const groups = []; - const groupingCategories = []; + getGroupInfo: (parameters: GroupInfoLoadParameters) => Promise | undefined, + excludedColumns?: string[], +): DataSourceToolbarGroupData | undefined { + const groups: DataSourceToolBarGroup[] = []; + const groupingCategories: DataSourceToolBarGroupingCategory[] = []; if (dataModel.Properties) { - dataModel.Properties.filter((p) => p.IsGroupable && p.Property && !excludedColumns?.includes(p.Property.ColumnName)).forEach( + dataModel.Properties.filter((p) => p.IsGroupable && p.Property && !excludedColumns?.includes(p.Property.ColumnName ?? '')).forEach( (property) => groups.push({ property, getData: async (parameter: CollectionLoadParameters) => { - return getGroupInfo({ ...parameter, by: property.Property.ColumnName }); + return getGroupInfo({ ...parameter, by: property.Property?.ColumnName ?? '' }); }, - }) + }), ); } if (dataModel.GroupInfo?.length === 1) { - dataModel.GroupInfo[0].Options.forEach((option) => groups.push(getDataSourceToolBarGroup(option, getGroupInfo))); + dataModel.GroupInfo?.[0].Options?.forEach((option) => groups.push(getDataSourceToolBarGroup(option, getGroupInfo))); } else { dataModel.GroupInfo?.forEach((property) => groupingCategories.push({ property, - groups: property.Options.map((option) => getDataSourceToolBarGroup(option, getGroupInfo)), - }) + groups: property.Options?.map((option) => getDataSourceToolBarGroup(option, getGroupInfo)) ?? [], + }), ); } @@ -68,27 +72,29 @@ export function createGroupData( function getDataSourceToolBarGroup( option: DataModelFilterOption, - getGroupInfo: (parameters: GroupInfoLoadParameters) => Promise + getGroupInfo: (parameters: GroupInfoLoadParameters) => Promise | undefined, ): DataSourceToolBarGroup { return { property: option, getData: async (param: CollectionLoadParameters) => { const data = await getGroupInfo({ ...param, ...{ def: option.Value } }); - data.Groups = data.Groups?.map((item) => { - setFilterDisplay(item); - return item; - }); + if (data) { + data.Groups = data.Groups?.map((item) => { + setFilterDisplay(item); + return item; + }); + } return data; }, }; } -function setFilterDisplay(item: GroupInfo): void { - item.Display.forEach((display) => - item.Filters.forEach((filter) => { +export function setFilterDisplay(item: GroupInfo): void { + item.Display?.forEach((display) => + item.Filters?.forEach((filter) => { if (filter.Value1 != null) { - display.Display = display.Display.replace(`%${filter.ColumnName}%`, filter.Value1); + display.Display = display.Display?.replace(`%${filter.ColumnName}%`, filter.Value1); } - }) + }), ); } diff --git a/imxweb/projects/qbm/src/lib/data-source-toolbar/data-model/data-model-wrapper.interface.ts b/imxweb/projects/qbm/src/lib/data-source-toolbar/data-model/data-model-wrapper.interface.ts index db6545ef2..343fe3546 100644 --- a/imxweb/projects/qbm/src/lib/data-source-toolbar/data-model/data-model-wrapper.interface.ts +++ b/imxweb/projects/qbm/src/lib/data-source-toolbar/data-model/data-model-wrapper.interface.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -24,12 +24,12 @@ * */ -import { DataModel, GroupInfoData } from 'imx-qbm-dbts'; +import { DataModel, GroupInfoData } from '@imx-modules/imx-qbm-dbts'; import { GroupInfoLoadParameters } from './group-info-load-parameters.interface'; export interface DataModelWrapper { dataModel: DataModel; - getGroupInfo?: (parameters: GroupInfoLoadParameters) => Promise; + getGroupInfo?: (parameters: GroupInfoLoadParameters) => Promise; groupingFilterOptions?: string[]; groupingExcludedColumns?: string[]; } diff --git a/imxweb/projects/qbm/src/lib/data-source-toolbar/data-model/filter-tree-parameter.ts b/imxweb/projects/qbm/src/lib/data-source-toolbar/data-model/filter-tree-parameter.ts index 4f021b94a..93e23d099 100644 --- a/imxweb/projects/qbm/src/lib/data-source-toolbar/data-model/filter-tree-parameter.ts +++ b/imxweb/projects/qbm/src/lib/data-source-toolbar/data-model/filter-tree-parameter.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -24,7 +24,7 @@ * */ -import { FilterTreeData } from 'imx-qbm-dbts'; +import { FilterTreeData } from '@imx-modules/imx-qbm-dbts'; export interface FilterTreeParameter { filterMethode: (parentkey: string) => Promise; diff --git a/imxweb/projects/qbm/src/lib/data-source-toolbar/data-model/group-info-load-parameters.interface.ts b/imxweb/projects/qbm/src/lib/data-source-toolbar/data-model/group-info-load-parameters.interface.ts index 81fbd5d5e..27816210a 100644 --- a/imxweb/projects/qbm/src/lib/data-source-toolbar/data-model/group-info-load-parameters.interface.ts +++ b/imxweb/projects/qbm/src/lib/data-source-toolbar/data-model/group-info-load-parameters.interface.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -24,7 +24,7 @@ * */ -import { CollectionLoadParameters } from 'imx-qbm-dbts'; +import { CollectionLoadParameters } from '@imx-modules/imx-qbm-dbts'; export interface GroupInfoLoadParameters extends CollectionLoadParameters { by?: string; diff --git a/imxweb/projects/qbm/src/lib/data-source-toolbar/data-source-item-status.interface.ts b/imxweb/projects/qbm/src/lib/data-source-toolbar/data-source-item-status.interface.ts index cfadc3064..28e6a1694 100644 --- a/imxweb/projects/qbm/src/lib/data-source-toolbar/data-source-item-status.interface.ts +++ b/imxweb/projects/qbm/src/lib/data-source-toolbar/data-source-item-status.interface.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -24,11 +24,29 @@ * */ -import { TypedEntity } from 'imx-qbm-dbts'; +import { TypedEntity } from '@imx-modules/imx-qbm-dbts'; +import { QueuedActionState } from '../processing-queue/processing-queue.interface'; import { DataTileBadge } from './data-tile-badge.interface'; export interface DataSourceItemStatus { - enabled: (item: TypedEntity) => boolean; - getBadges?: (input: TypedEntity) => DataTileBadge[]; + /** + * Function of the row to determine if the checkbox is clickable. + * @param item row entity + * @returns if the checkbox is clickable + */ + enabled: (item?: TypedEntity) => boolean; + /** + * Function of the row to determine if the row action should be allowed. We may want to prevent an entity from being interacted with while it is being processed. + * @param item row entity + * @returns if the row should be clickable + */ + rowEnabled?: (item?: TypedEntity) => boolean; + /** + * Function to return the status of a entity in the queue. + * @param item row entity + * @returns the state of this item in the queue + */ + status?: (item: TypedEntity) => QueuedActionState; + getBadges?: (input: TypedEntity) => DataTileBadge[]; getImagePath?: (item: TypedEntity) => Promise; } diff --git a/imxweb/projects/qbm/src/lib/data-source-toolbar/data-source-paginator.component.html b/imxweb/projects/qbm/src/lib/data-source-toolbar/data-source-paginator.component.html index 2cd56911f..5ddd8aab2 100644 --- a/imxweb/projects/qbm/src/lib/data-source-toolbar/data-source-paginator.component.html +++ b/imxweb/projects/qbm/src/lib/data-source-toolbar/data-source-paginator.component.html @@ -1 +1,7 @@ - + diff --git a/imxweb/projects/qbm/src/lib/data-source-toolbar/data-source-paginator.component.scss b/imxweb/projects/qbm/src/lib/data-source-toolbar/data-source-paginator.component.scss deleted file mode 100644 index 23e57191f..000000000 --- a/imxweb/projects/qbm/src/lib/data-source-toolbar/data-source-paginator.component.scss +++ /dev/null @@ -1,8 +0,0 @@ -/* You can add styles to this file, and also import other style files */ -mat-paginator { - box-shadow: none; - - &.hide-paginator { - display: none; - } -} diff --git a/imxweb/projects/qbm/src/lib/data-source-toolbar/data-source-paginator.component.ts b/imxweb/projects/qbm/src/lib/data-source-toolbar/data-source-paginator.component.ts index 2aa892d84..e9703c7af 100644 --- a/imxweb/projects/qbm/src/lib/data-source-toolbar/data-source-paginator.component.ts +++ b/imxweb/projects/qbm/src/lib/data-source-toolbar/data-source-paginator.component.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -24,14 +24,13 @@ * */ -import { Component, Input, Output, EventEmitter, SimpleChanges, OnChanges, ViewChild, OnDestroy, ChangeDetectorRef } from '@angular/core'; -import { PageEvent, MatPaginator } from '@angular/material/paginator'; +import { ChangeDetectorRef, Component, EventEmitter, Input, OnChanges, OnDestroy, Output, SimpleChanges, ViewChild } from '@angular/core'; +import { MatPaginator, PageEvent } from '@angular/material/paginator'; import { Subscription } from 'rxjs'; -import { CollectionLoadParameters } from 'imx-qbm-dbts'; -import { DataSourceToolbarComponent } from './data-source-toolbar.component'; +import { CollectionLoadParameters } from '@imx-modules/imx-qbm-dbts'; import { DataSourceToolbarSettings } from './data-source-toolbar-settings'; - +import { DataSourceToolbarComponent } from './data-source-toolbar.component'; /** * Paginator for navigating the datasource of the {@link DataSourceToolbarComponent| datasource toolbar component}. @@ -47,7 +46,6 @@ import { DataSourceToolbarSettings } from './data-source-toolbar-settings'; @Component({ selector: 'imx-data-source-paginator', templateUrl: './data-source-paginator.component.html', - styleUrls: ['./data-source-paginator.component.scss'] }) export class DataSourcePaginatorComponent implements OnChanges, OnDestroy { /** @@ -58,11 +56,11 @@ export class DataSourcePaginatorComponent implements OnChanges, OnDestroy { /** * Add in first/last buttons */ - @Input() public showFirstLastButtons: boolean = false; + @Input() public showFirstLastButtons: boolean = true; /** - * List of options for the page size. - */ + * List of options for the page size. + */ @Input() public pageSizeOptions: number[] = [20, 50, 100]; /** @@ -81,11 +79,11 @@ export class DataSourcePaginatorComponent implements OnChanges, OnDestroy { * Hides the paginator, if there is not data, a group is applied or the control is loading new content */ public get hidePaginator() { - return !this.dst?.dataSourceHasData || this.dst.settings?.groupData?.currentGrouping != null || this.isLoading; + return !this.dst?.dataSourceHasData || this.dst.settings?.groupData?.currentGrouping != null || this.isLoading; } public isLoading = true; - constructor (private readonly changeDetector: ChangeDetectorRef){} + constructor(private readonly changeDetector: ChangeDetectorRef) {} /** * @ignore @@ -101,16 +99,18 @@ export class DataSourcePaginatorComponent implements OnChanges, OnDestroy { if (changes['dst'] && changes['dst'].currentValue) { this.setPaginator(); - this.subscriptions.push(this.dst.settingsChanged.subscribe((value: DataSourceToolbarSettings) => { - this.dst.settings = value; - this.setPaginator(); - })); + this.subscriptions.push( + this.dst.settingsChanged.subscribe((value: DataSourceToolbarSettings) => { + this.dst.settings = value; + this.setPaginator(); + }), + ); - if(this.dst.busyService){ - this.dst.busyService.busyStateChanged.subscribe((value:boolean) =>{ + if (this.dst.busyService) { + this.dst.busyService.busyStateChanged.subscribe((value: boolean) => { this.isLoading = value; this.changeDetector.detectChanges(); - }) + }); } else { this.isLoading = false; } @@ -122,7 +122,7 @@ export class DataSourcePaginatorComponent implements OnChanges, OnDestroy { * Unsubscribes all listeners. */ public ngOnDestroy(): void { - this.subscriptions.forEach(subscription => subscription.unsubscribe()); + this.subscriptions.forEach((subscription) => subscription.unsubscribe()); } /** @@ -146,8 +146,9 @@ export class DataSourcePaginatorComponent implements OnChanges, OnDestroy { } if (this.dst.settings.navigationState) { - this.paginator.pageSize = this.dst.settings.navigationState.PageSize; - this.paginator.pageIndex = this.dst.settings.navigationState.StartIndex / this.dst.settings.navigationState.PageSize; + this.paginator.pageSize = this.dst.settings.navigationState.PageSize ?? 0; + if (this.paginator.pageSize > 0) + this.paginator.pageIndex = (this.dst.settings.navigationState.StartIndex ?? 0) / this.paginator.pageSize; } } } diff --git a/imxweb/projects/qbm/src/lib/data-source-toolbar/data-source-toolbar-custom.component.html b/imxweb/projects/qbm/src/lib/data-source-toolbar/data-source-toolbar-custom.component.html index ec0cab1e5..7611b7c50 100644 --- a/imxweb/projects/qbm/src/lib/data-source-toolbar/data-source-toolbar-custom.component.html +++ b/imxweb/projects/qbm/src/lib/data-source-toolbar/data-source-toolbar-custom.component.html @@ -1,2 +1,2 @@ - + diff --git a/imxweb/projects/qbm/src/lib/data-source-toolbar/data-source-toolbar-custom.component.ts b/imxweb/projects/qbm/src/lib/data-source-toolbar/data-source-toolbar-custom.component.ts index c28712c34..f3dd5523e 100644 --- a/imxweb/projects/qbm/src/lib/data-source-toolbar/data-source-toolbar-custom.component.ts +++ b/imxweb/projects/qbm/src/lib/data-source-toolbar/data-source-toolbar-custom.component.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -45,10 +45,8 @@ import { Component, Input, TemplateRef } from '@angular/core'; @Component({ selector: 'imx-data-source-toolbar-custom', templateUrl: './data-source-toolbar-custom.component.html', - styleUrls: ['./data-source-toolbar-custom.component.scss'] + styleUrls: ['./data-source-toolbar-custom.component.scss'], }) - - export class DataSourceToolbarCustomComponent { /** * Reference to a custom template. diff --git a/imxweb/projects/qbm/src/lib/data-source-toolbar/data-source-toolbar-export-method.interface.ts b/imxweb/projects/qbm/src/lib/data-source-toolbar/data-source-toolbar-export-method.interface.ts index 61ba35573..4c5238b44 100644 --- a/imxweb/projects/qbm/src/lib/data-source-toolbar/data-source-toolbar-export-method.interface.ts +++ b/imxweb/projects/qbm/src/lib/data-source-toolbar/data-source-toolbar-export-method.interface.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -24,12 +24,11 @@ * */ -import { DataModelProperty, MethodDefinition } from 'imx-qbm-dbts'; - +import { DataModelProperty, MethodDefinition } from '@imx-modules/imx-qbm-dbts'; export interface DataSourceToolbarExportMethod { // This will define an api method that the dst can then call to make a download to the client getMethod: (withProperties: string, PageSize?: number) => MethodDefinition; // inititalColumns will set the initial export columns, if not present then we will try to figure it out from the displayed columns - initialColumns?: string[] + initialColumns?: string[]; } diff --git a/imxweb/projects/qbm/src/lib/data-source-toolbar/data-source-toolbar-filters.interface.ts b/imxweb/projects/qbm/src/lib/data-source-toolbar/data-source-toolbar-filters.interface.ts index ee9a9e03e..f51e41b6d 100644 --- a/imxweb/projects/qbm/src/lib/data-source-toolbar/data-source-toolbar-filters.interface.ts +++ b/imxweb/projects/qbm/src/lib/data-source-toolbar/data-source-toolbar-filters.interface.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -24,7 +24,7 @@ * */ -import { DataModelFilter, DataModelFilterOption } from 'imx-qbm-dbts'; +import { DataModelFilter, DataModelFilterOption } from '@imx-modules/imx-qbm-dbts'; export interface DataSourceToolbarFilter extends DataModelFilter { /** @@ -51,11 +51,11 @@ export interface DataSourceToolbarSelectedFilter { /** * The option that was selected */ - selectedOption: DataModelFilterOptionExtended; + selectedOption?: DataModelFilterOptionExtended; /** * The filter the value was selected for */ - filter: DataSourceToolbarFilter; + filter?: DataSourceToolbarFilter; /** * Indicates if the selected filter is not part of the standard datamodel filters diff --git a/imxweb/projects/qbm/src/lib/data-source-toolbar/data-source-toolbar-groups.interface.ts b/imxweb/projects/qbm/src/lib/data-source-toolbar/data-source-toolbar-groups.interface.ts index f842b125d..c1ac1de58 100644 --- a/imxweb/projects/qbm/src/lib/data-source-toolbar/data-source-toolbar-groups.interface.ts +++ b/imxweb/projects/qbm/src/lib/data-source-toolbar/data-source-toolbar-groups.interface.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -24,7 +24,13 @@ * */ -import { CollectionLoadParameters, DataModelFilterOption, DataModelGroupInfo, GroupInfoData, IClientProperty } from 'imx-qbm-dbts'; +import { + CollectionLoadParameters, + DataModelFilterOption, + DataModelGroupInfo, + GroupInfoData, + IClientProperty, +} from '@imx-modules/imx-qbm-dbts'; export interface DataSourceToolbarGroupData { /** @@ -42,7 +48,7 @@ export interface DataSourceToolbarGroupData { */ currentGrouping?: { display: string; - getData: (parameter?: CollectionLoadParameters) => Promise; + getData: (parameter?: CollectionLoadParameters) => Promise; navigationState?: CollectionLoadParameters; }; } @@ -56,7 +62,7 @@ export interface DataSourceToolBarGroup { /** * Callback for getting the corresponding GroupInfo data for the property */ - getData: (parameter?: CollectionLoadParameters) => Promise; + getData: (parameter?: CollectionLoadParameters) => Promise; /** * The navigation state used, when loading the group elements for a grouping type diff --git a/imxweb/projects/qbm/src/lib/data-source-toolbar/data-source-toolbar-menu-item.interface.ts b/imxweb/projects/qbm/src/lib/data-source-toolbar/data-source-toolbar-menu-item.interface.ts index a4c4cd2af..fd4bd0535 100644 --- a/imxweb/projects/qbm/src/lib/data-source-toolbar/data-source-toolbar-menu-item.interface.ts +++ b/imxweb/projects/qbm/src/lib/data-source-toolbar/data-source-toolbar-menu-item.interface.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -24,7 +24,7 @@ * */ -import { IClientProperty } from 'imx-qbm-dbts'; +import { IClientProperty } from '@imx-modules/imx-qbm-dbts'; /** * Internal repesentation of a menu item in a datasource toolbar menu. diff --git a/imxweb/projects/qbm/src/lib/data-source-toolbar/data-source-toolbar-settings.ts b/imxweb/projects/qbm/src/lib/data-source-toolbar/data-source-toolbar-settings.ts index 8e1367277..1eebba275 100644 --- a/imxweb/projects/qbm/src/lib/data-source-toolbar/data-source-toolbar-settings.ts +++ b/imxweb/projects/qbm/src/lib/data-source-toolbar/data-source-toolbar-settings.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -24,7 +24,7 @@ * */ -import { TypedEntity, TypedEntityCollectionData, CollectionLoadParameters, EntitySchema, DataModel } from 'imx-qbm-dbts'; +import { CollectionLoadParameters, DataModel, EntitySchema, TypedEntity, TypedEntityCollectionData } from '@imx-modules/imx-qbm-dbts'; import { ClientPropertyForTableColumns } from './client-property-for-table-columns'; import { FilterTreeParameter } from './data-model/filter-tree-parameter'; import { DataSourceToolbarExportMethod } from './data-source-toolbar-export-method.interface'; @@ -40,7 +40,7 @@ export interface DataSourceToolbarSettings { * The datasource of the toolbar. * Basically this is a collection of typed entities. */ - dataSource: TypedEntityCollectionData; + dataSource: TypedEntityCollectionData | undefined; /** * Describes which chunk of data is currently loaded. @@ -103,9 +103,4 @@ export interface DataSourceToolbarSettings { } */ exportMethod?: DataSourceToolbarExportMethod; - - /** - * List of filtered columns, that can not be edited in the UI. - */ - staticFilterColumns?: string[]; } diff --git a/imxweb/projects/qbm/src/lib/data-source-toolbar/data-source-toolbar-view-config-helper.ts b/imxweb/projects/qbm/src/lib/data-source-toolbar/data-source-toolbar-view-config-helper.ts index 26aefc859..83eb63281 100644 --- a/imxweb/projects/qbm/src/lib/data-source-toolbar/data-source-toolbar-view-config-helper.ts +++ b/imxweb/projects/qbm/src/lib/data-source-toolbar/data-source-toolbar-view-config-helper.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -24,7 +24,7 @@ * */ -import { DSTViewConfig } from "./data-source-toolbar-view-config.interface"; +import { DSTViewConfig } from './data-source-toolbar-view-config.interface'; /** * Looks up if the config is set to be default @@ -41,5 +41,5 @@ export function isConfigDefault(config: DSTViewConfig): boolean { * @returns whether the config should be used */ export function isDefaultId(config: DSTViewConfig): boolean { - return config?.Id == 'Default' + return config?.Id == 'Default'; } diff --git a/imxweb/projects/qbm/src/lib/data-source-toolbar/data-source-toolbar-view-config.interface.ts b/imxweb/projects/qbm/src/lib/data-source-toolbar/data-source-toolbar-view-config.interface.ts index 8e00ff92a..a90e1d473 100644 --- a/imxweb/projects/qbm/src/lib/data-source-toolbar/data-source-toolbar-view-config.interface.ts +++ b/imxweb/projects/qbm/src/lib/data-source-toolbar/data-source-toolbar-view-config.interface.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -24,7 +24,7 @@ * */ -import { DataModelViewConfig } from 'imx-qbm-dbts'; +import { DataModelViewConfig } from '@imx-modules/imx-qbm-dbts'; export interface DSTViewConfig extends DataModelViewConfig { /** @@ -51,7 +51,7 @@ export interface DSTViewConfig extends DataModelViewConfig { /** Storage for arbitrary URL filter parameter values. */ AdditionalParameters?: { - [key: string]: string; + [key: string]: string; }; } @@ -65,5 +65,4 @@ export interface DataSourceToolbarViewConfig { * The list of available configs */ viewId: string; - } diff --git a/imxweb/projects/qbm/src/lib/data-source-toolbar/data-source-toolbar.component.html b/imxweb/projects/qbm/src/lib/data-source-toolbar/data-source-toolbar.component.html index a4b343e77..d804413bd 100644 --- a/imxweb/projects/qbm/src/lib/data-source-toolbar/data-source-toolbar.component.html +++ b/imxweb/projects/qbm/src/lib/data-source-toolbar/data-source-toolbar.component.html @@ -10,7 +10,6 @@ data-imx-identifier="dst-eui-search" [placeholder]="searchTerms.length ? ('#LDS#Search' | translate) : searchBoxText ? searchBoxText : ('#LDS#Search' | translate)" [searchControl]="searchControl" - size="medium" (keydown.enter)="addSearchFilter()" > @@ -18,8 +17,7 @@
    - - + @@ -95,140 +86,106 @@
    - + {{ (isDescending ? '#LDS#Descending' : '#LDS#Ascending') | translate }}
    -
    - - - -
    - - {{ filter.Options[0].Display }} - -

    {{ filter.Description || filter.Name }}

    - - - {{ fopt.Display }} - - - - - {{ fopt.Display }} - - - - - {{ foption.Display }} - - - - - {{ foption.Display }} - - -
    -
    - - - - -
    - -
    +
    -
    +
    -
    +
    -
    -
    - - -
    - - {{'#LDS#Search by keywords' | translate}}: - + + {{ '#LDS#Search by keywords' | translate }}: + - {{ st.selectedOption.Display }} - - - - {{ st.selectedOption?.Display }} + + + + - #LDS#Filter on: - - {{ "#LDS#Custom filter" | translate }} ({{ filterWizardExpression?.Expression?.Expressions?.length}}) - - - {{ '#LDS#Filter on' | translate }}: + + {{ '#LDS#Custom filter' | translate }} ({{ filterWizardExpression?.Expression?.Expressions?.length }}) + + + - {{ sf.selectedOption.Display }} - - - - {{ filterType }}: {{ currentFilterData[0].display }} + {{ sf.selectedOption?.Display ?? '' }} + + + + + {{ filterType }}: {{ currentFilterData?.display }} - - + + - + #LDS#Sort by: - + {{ currentSortColumn }} - - - - +
    diff --git a/imxweb/projects/qbm/src/lib/data-source-toolbar/data-source-toolbar.component.scss b/imxweb/projects/qbm/src/lib/data-source-toolbar/data-source-toolbar.component.scss index 68c6e0af5..3367afd41 100644 --- a/imxweb/projects/qbm/src/lib/data-source-toolbar/data-source-toolbar.component.scss +++ b/imxweb/projects/qbm/src/lib/data-source-toolbar/data-source-toolbar.component.scss @@ -1,17 +1,18 @@ -@import "@elemental-ui/core/src/styles/_palette.scss"; +@import '@elemental-ui/core/src/styles/_palette.scss'; @import '@elemental-ui/core/src/styles/_eui_palette.scss'; +@import 'base/mixins'; .imx-data-source-toolbar-container { display: flex; flex-direction: column; - + .imx-data-source-toolbar { display: flex; - overflow: hidden; justify-content: space-between; &.no-toolbar-options-visible { height: 0; + visibility: hidden; } } @@ -34,10 +35,6 @@ .imx-data-source-toolbar-search { width: 100%; - - .eui-search { - width: 100%; - } } .imx-chip-container { @@ -48,47 +45,23 @@ .imx-data-source-selected-filters { display: block; - margin: 10px 5px; + margin: 10px 10px; - .mat-chip-list-wrapper > span { - margin-right: 5px; - } - - .mat-chip { + .mat-mdc-chip { cursor: pointer; - .eui-icon { - &.remove { - font-size: 18px; - margin-right: -10px; - } - } - span.tag-name { font-size: 13px; white-space: nowrap; } - - &.isRegex { - background-color: $color-blue-60; - - .eui-icon { - &.remove { - color: $color-gray-0; - } - } - span.tag-name { - color: $color-gray-0; - } - } } } } -.mat-menu-panel { - +.mat-mdc-menu-panel { &.imx-sort-menu { max-width: 40vw; + padding: 12px; .imx-sort-options { max-height: 30vh; @@ -102,6 +75,7 @@ padding: 0 5px; gap: 5px; } + .imx-sort-buttons { display: flex; justify-content: flex-end; @@ -109,7 +83,6 @@ } } - &.imx-filters-menu { padding: 0 8px; } @@ -121,73 +94,39 @@ } } - - -.imx-filter-tree-dialog -> .mat-dialog-container { - display: flex; - flex-direction: column; +.imx-filter-tree-dialog>.mat-mdc-dialog-container { + @include flex-column-container(); } -.mat-menu-content { +.mat-mdc-menu-content { max-width: none; - .imx-data-source-filter-menu { - margin: 2px 15px 20px; - - p { - font-weight: 600; - margin-bottom: 8px; - } - - .mat-checkbox { - display: block; - } - - .mat-radio-button { - display: block; - margin-right: 5px; - - label.mat-radio-label { - white-space: normal; - } - } - .mat-select .mat-select-trigger { - margin-top: 5px; - } - - .mat-select .mat-select-value { - max-width: none; - white-space: normal; - .mat-select-value-text { - white-space: normal; - } - } - - .mat-checkbox-layout { - white-space: normal; - } - } - - .link-button { - color: $iris-blue; - } - - .mat-menu-item:disabled > .link-button { + .mat-mdc-menu-item:disabled>.imx-info { color: inherit; } - button.mat-menu-item { + button.mat-mdc-menu-item { white-space: break-spaces; min-height: 48px; height: auto; + + .mat-mdc-menu-item-text { + display: flex; + align-items: center; + justify-content: space-between; + width: 100%; + } } } .dst-saved-config-menu { .dst-saved-config-menu-item { - display: flex; - justify-content: space-between; + .mdc-list-item__primary-text { + display: flex; + justify-content: space-between; + align-items: center; + width: 100%; + } } .dst-saved-config-menu-item-action-buttons { @@ -195,24 +134,6 @@ } } -.cdk-overlay-pane .mat-select-panel .mat-option { - line-height: normal; - height: 100%; - - .mat-option-text { - white-space: normal; - margin: 5px 16px; - } -} - -.imx-data-source-filter-select { - background-color: $asher-gray; -} - -.imx-warning-icon { - color: $corbin-orange; -} - // Theming imx-data-source-toolbar { .themed-style .imx-data-source-toolbar-middle { @@ -220,10 +141,6 @@ imx-data-source-toolbar { border-radius: 5px; } - .mat-form-field-outline-thick { - opacity: 0.2; - } - .eui-search-icon { color: $color-blue-60; } @@ -231,32 +148,6 @@ imx-data-source-toolbar { .imx-data-source-filter-select { background-color: $color-gray-10; } - - .imx-warning-icon { - color: $color-orange-60; - } - - .imx-data-source-selected-filters { - .mat-chip { - .eui-icon.remove { - color: $color-gray-60; - } - - span.tag-name { - color: $color-gray-80; - } - } - } -} - -.mat-menu-content { - .link-button { - color: $color-blue-60; - } - - .dst-saved-config-delete-button { - color: $color-red-60; - } } .eui-dark-theme { @@ -266,10 +157,6 @@ imx-data-source-toolbar { border-radius: 5px; } - .mat-form-field-outline-thick { - opacity: 0.2; - } - .eui-search-icon { color: $color-blue-40; } @@ -277,41 +164,6 @@ imx-data-source-toolbar { .imx-data-source-filter-select { background-color: $color-gray-10; } - - .imx-warning-icon { - color: $color-orange-40; - } - - .imx-data-source-selected-filters { - .mat-chip { - .eui-icon.remove { - opacity: unset; - color: $color-gray-0; - } - span.tag-name { - color: $color-gray-0; - } - &.isRegex { - background-color: $color-blue-40; - - .eui-icon { - &.remove { - color: $color-gray-10; - } - } - } - } - } - } - - .mat-menu-content { - .link-button { - color: $color-blue-40; - } - - .dst-saved-config-delete-button { - color: $color-red-40; - } } } @@ -322,10 +174,6 @@ imx-data-source-toolbar { border-radius: 4px; } - .mat-form-field-outline-thick { - opacity: 0.2; - } - .eui-search-icon { color: $color-blue-40; } @@ -333,44 +181,15 @@ imx-data-source-toolbar { .imx-data-source-filter-select { background-color: $color-gray-10; } - - .imx-warning-icon { - color: $color-orange-40; - } - - .mat-menu-content { - .link-button { - color: $color-blue-40; - } - - .dst-saved-config-delete-button { - color: $color-red-40; - } - } - - .imx-data-source-selected-filters { - .mat-chip { - border: 1px solid $color-gray-0; - - .eui-icon.remove { - opacity: unset; - color: $color-gray-0; - } - span.tag-name { - color: $color-gray-0; - } - } - } } } - @media only screen and (max-width: 768px) { .imx-data-source-toolbar-container { .imx-data-source-toolbar-middle { - .eui-search.mat-form-field.mat-form-field-appearance-outline { + .eui-search.mat-mdc-form-field.mat-form-field-appearance-outline { min-width: unset; } } } -} +} \ No newline at end of file diff --git a/imxweb/projects/qbm/src/lib/data-source-toolbar/data-source-toolbar.component.ts b/imxweb/projects/qbm/src/lib/data-source-toolbar/data-source-toolbar.component.ts index bb8c9f943..986ab210d 100644 --- a/imxweb/projects/qbm/src/lib/data-source-toolbar/data-source-toolbar.component.ts +++ b/imxweb/projects/qbm/src/lib/data-source-toolbar/data-source-toolbar.component.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -42,50 +42,47 @@ import { FormControl, FormGroup, Validators } from '@angular/forms'; import { MatButtonToggleChange } from '@angular/material/button-toggle'; import { MatCheckboxChange } from '@angular/material/checkbox'; import { MatDialog } from '@angular/material/dialog'; +import { MatMenuTrigger } from '@angular/material/menu'; import { MatSelectChange } from '@angular/material/select'; import { MatTableDataSource } from '@angular/material/table'; -import { EuiSelectOption } from '@elemental-ui/core'; -import { Observable, Subject, Subscription } from 'rxjs'; -import { debounceTime, distinctUntilChanged, switchMap } from 'rxjs/operators'; +import { EuiSelectFeedbackMessages, EuiSelectOption, EuiSidesheetService } from '@elemental-ui/core'; import { CollectionLoadParameters, - SqlWizardExpression, - CompareOperator, DataModelFilterOption, EntitySchema, FilterData, + FilterTreeData, FilterType, IClientProperty, - IEntity, + SqlWizardExpression, TypedEntity, TypedEntityCollectionData, ValType, - FilterTreeData, -} from 'imx-qbm-dbts'; -import { v4 as uuid } from 'uuid'; -import { DataSourceToolbarFilter, DataSourceToolbarSelectedFilter } from './data-source-toolbar-filters.interface'; -import { DataSourceToolBarGroup, DataSourceToolBarGroupingCategory } from './data-source-toolbar-groups.interface'; -import { SelectionModelWrapper } from './selection-model-wrapper'; -import { DataSourceItemStatus } from './data-source-item-status.interface'; -import { FilterTreeComponent } from './filter-tree/filter-tree.component'; -import { FilterTreeSelectionArg } from './filter-tree/filter-tree-selection-arg.interface'; -import { ColumnOptions } from './column-options'; -import { EuiSidesheetService } from '@elemental-ui/core'; -import { FilterWizardComponent } from './filter-wizard/filter-wizard.component'; -import { DataExportComponent } from '../data-export/data-export.component'; +} from '@imx-modules/imx-qbm-dbts'; import { TranslateService } from '@ngx-translate/core'; -import { MatMenuTrigger } from '@angular/material/menu'; -import { SaveConfigDialogComponent } from './save-config-dialog/save-config-dialog.component'; +import { Observable, Subject, Subscription } from 'rxjs'; +import { debounceTime, distinctUntilChanged, switchMap } from 'rxjs/operators'; +import { v4 as uuid } from 'uuid'; +import { AppConfigService } from '../appConfig/appConfig.service'; +import { BusyService } from '../base/busy.service'; +import { calculateSidesheetWidth } from '../base/sidesheet-helper'; import { ConfirmationService } from '../confirmation/confirmation.service'; -import { DSTViewConfig } from './data-source-toolbar-view-config.interface'; +import { DataExportComponent } from '../data-export/data-export.component'; import { SnackBarService } from '../snackbar/snack-bar.service'; -import { FilterWizardService, selectedFiltersParams } from './filter-wizard/filter-wizard.service'; -import { BusyService } from '../base/busy.service'; import { SystemInfoService } from '../system-info/system-info.service'; -import { AppConfigService } from '../appConfig/appConfig.service'; -import { FilterTypeIdentifier } from './filter-wizard/filter-wizard.interfaces'; +import { ColumnOptions } from './column-options'; +import { DataSourceItemStatus } from './data-source-item-status.interface'; +import { DataSourceToolbarFilter, DataSourceToolbarSelectedFilter } from './data-source-toolbar-filters.interface'; +import { DataSourceToolBarGroup, DataSourceToolBarGroupingCategory } from './data-source-toolbar-groups.interface'; import { DataSourceToolbarSettings } from './data-source-toolbar-settings'; import { isConfigDefault, isDefaultId } from './data-source-toolbar-view-config-helper'; +import { DSTViewConfig } from './data-source-toolbar-view-config.interface'; +import { FilterTreeSelectionParameter } from './filter-wizard/filter-tree-sidesheet/filter-tree-sidesheet.model'; +import { FilterWizardComponent } from './filter-wizard/filter-wizard.component'; +import { FilterTypeIdentifier, FilterWizardResult } from './filter-wizard/filter-wizard.interfaces'; +import { FilterWizardService, selectedFiltersParams } from './filter-wizard/filter-wizard.service'; +import { SaveConfigDialogComponent } from './save-config-dialog/save-config-dialog.component'; +import { SelectionModelWrapper } from './selection-model-wrapper'; /** * The Datasource toolbar (DST) consist internally of a datasource and a toolbar view, @@ -125,7 +122,7 @@ export class DataSourceToolbarComponent implements OnChanges, OnInit, OnDestroy public get additionalColumns(): IClientProperty[] { const additionalColumns = this.columnOptions?.additionalColumns.concat(this.columnOptions.selectedOptionals) ?? []; return additionalColumns.filter(function (column) { - const key = column.ColumnName.toLocaleLowerCase(); + const key = column.ColumnName?.toLocaleLowerCase(); return !this.has(key) && this.add(key); }, new Set()); } @@ -158,14 +155,12 @@ export class DataSourceToolbarComponent implements OnChanges, OnInit, OnDestroy public isDescending = false; public ascendingSortControl = new FormControl(this.isDescending); - public selectedSortControl = new FormControl(null, Validators.required); + public selectedSortControl = new FormControl('', { nonNullable: true, validators: Validators.required }); public sortControl = new FormGroup({ selectedSortControl: this.selectedSortControl, ascendingSortControl: this.ascendingSortControl, }); - public sortFeedbackMessages = { - search: this.translate.instant('#LDS#Search'), - }; + public sortFeedbackMessages: EuiSelectFeedbackMessages; public sortOptions: EuiSelectOption[] = []; public sortOptionsFilter = (option: EuiSelectOption, searchInputValue: string) => option.display.toLowerCase().includes(searchInputValue.toLowerCase()); @@ -187,15 +182,22 @@ export class DataSourceToolbarComponent implements OnChanges, OnInit, OnDestroy } public get isSortApplied(): boolean { - return this.hasSortFunction && this.settings?.navigationState?.OrderBy && this.settings.navigationState.OrderBy.length > 0; + return this.hasSortFunction && this.settings?.navigationState?.OrderBy != null && this.settings.navigationState.OrderBy.length > 0; } public get isSortDesc(): boolean { - return this.hasSortFunction && this.settings?.navigationState?.OrderBy && this.settings.navigationState.OrderBy.includes(this.descArg); + return ( + this.hasSortFunction && + this.settings?.navigationState?.OrderBy != null && + this.settings.navigationState.OrderBy.toLocaleLowerCase().includes(this.descArg) + ); } + /** + * @ignore Used internally to set the filter column name currently being used + */ public get currentSortColumn(): string { - return this.selectedSortControl.value?.Display ?? this.selectedSortControl.value?.ColumnName; + return this.sortOptions?.find((option) => option.value == this.settings.navigationState?.OrderBy?.split(' ')[0])?.display ?? ''; } /** @@ -293,7 +295,7 @@ export class DataSourceToolbarComponent implements OnChanges, OnInit, OnDestroy /** * an optional search api to handle search cancelling when necessary, results will be wihin the observable searchResults$ */ - @Input() searchApi?: () => Observable; + @Input() searchApi?: (keywords?: string) => Observable | undefined; /** * If 'true', it gives the div.imx-chip-container a min-height: 15px, otherwise this component's styling stays the same @@ -314,7 +316,7 @@ export class DataSourceToolbarComponent implements OnChanges, OnInit, OnDestroy /** * Emits a collection of typed entities when the datasource changes. */ - @Output() public dataSourceChanged = new EventEmitter>(); + @Output() public dataSourceChanged = new EventEmitter | undefined | null>(); /** * Occurs when user presses next/previous page button or changes the page size. @@ -379,13 +381,13 @@ export class DataSourceToolbarComponent implements OnChanges, OnInit, OnDestroy /** * the columnOptions used by the toolbar */ - public columnOptions: ColumnOptions; + public columnOptions: ColumnOptions | undefined; public get additionalListElements(): IClientProperty[] { return this.columnOptions?.additionalListElements ?? []; } - public get optionalColumns(): IClientProperty[] { + public get optionalColumns(): (IClientProperty | undefined)[] { return this.columnOptions?.optionalColumns ?? []; } @@ -411,7 +413,7 @@ export class DataSourceToolbarComponent implements OnChanges, OnInit, OnDestroy * Checks if we have any saved configs at all in settings.viewConfig.viewConfigs */ public get hasSavedConfigs(): boolean { - return this.settings?.viewConfig?.viewConfigs && this.settings.viewConfig.viewConfigs.length > 0; + return !!this.settings?.viewConfig?.viewConfigs?.length; } /** @@ -469,10 +471,7 @@ export class DataSourceToolbarComponent implements OnChanges, OnInit, OnDestroy // Handle sort if (config?.OrderBy) { - this.isDescending = config.OrderBy.endsWith(this.descArg); - this.ascendingSortControl.reset(this.isDescending); - const columnName = config.OrderBy.slice().replace(this.descArg, ''); - this.findAndSelectSortColumn(columnName); + this.applyOrderBy(config.OrderBy); } // Handle search terms from Filter @@ -500,14 +499,25 @@ export class DataSourceToolbarComponent implements OnChanges, OnInit, OnDestroy this.updateNavigateStateWithFilters(); } + /** + * Applys the sortby column along with its direction + * @param config the DSTViewConfig + */ + public applyOrderBy(orderBy: string): void { + // look for a space - if so then we have a direction + const [columnName, dir] = orderBy.split(' '); + this.findAndSelectSortColumn(columnName); + this.isDescending = dir?.trim()?.toLocaleLowerCase() == this.descArg.trim(); + this.ascendingSortControl.reset(this.isDescending); + this.ascendingSortControl.markAsPristine(); + } + /** * Finds and applies the group from the config via onGroupSelected * @param config the DSTViewConfig */ public applyGroupBy(config: DSTViewConfig): void { - const group = this.settings?.groupData?.groups?.find( - (group) => this.getGroupColumnDisplay(group) === config.GroupBy || group.property.Property.ColumnName === config.GroupBy - ); + const group = this.settings?.groupData?.groups?.find((group) => this.getGroupColumnDisplay(group) === config.GroupBy); if (group) { this.onGroupSelected(group); } @@ -519,6 +529,9 @@ export class DataSourceToolbarComponent implements OnChanges, OnInit, OnDestroy */ public applyDynamicPropsAsSelectedFilters(config: DSTViewConfig): void { // Handle filters from dynamic properties + if (!config.AdditionalParameters) { + return; + } Object.entries(config.AdditionalParameters).forEach(([filterName, value]) => { const filter = this.getSelectedFilterFromName(filterName, value); if (filter) { @@ -537,13 +550,16 @@ export class DataSourceToolbarComponent implements OnChanges, OnInit, OnDestroy const filter = this.settings.filters?.find((filter) => filter.Name === filterName); if (filter) { filter.CurrentValue = value; - return filter.Delimiter - ? filter.CurrentValue.split(filter.Delimiter).map((elem) => ({ - filter, - selectedOption: this.findFilterOptionFromValue(elem, filter), - })) - : [{ filter, selectedOption: this.findFilterOptionFromValue(value, filter) }]; + if (filter.Delimiter) { + return filter.CurrentValue.split(filter.Delimiter).map((elem) => ({ + filter, + selectedOption: this.findFilterOptionFromValue(elem, filter), + })); + } + + return [{ filter, selectedOption: this.findFilterOptionFromValue(value, filter) }]; } + return []; } /** @@ -554,34 +570,34 @@ export class DataSourceToolbarComponent implements OnChanges, OnInit, OnDestroy if (!displayName) { return; } - const existingConfig = this.settings.viewConfig.viewConfigs.find((config) => config.DisplayName === displayName); + const existingConfig = this.settings?.viewConfig?.viewConfigs?.find((config) => config.DisplayName === displayName); if ( existingConfig && !(await this.confirm.confirmDelete( '#LDS#Heading Overwrite View', - '#LDS#A view with the entered name already exists. Do you want to overwrite the already existing view with the new view?' + '#LDS#A view with the entered name already exists. Do you want to overwrite the already existing view with the new view?', )) ) { return; } const config: DSTViewConfig = { Id: existingConfig?.Id, - ViewId: this.settings.viewConfig.viewId, + ViewId: this.settings?.viewConfig?.viewId, DisplayName: displayName, Filter: this.settings?.navigationState?.filter, GroupBy: this.settings?.groupData?.currentGrouping?.display, OrderBy: this.settings?.navigationState?.OrderBy, - AdditionalListColumns: this.columnOptions?.additionalListElements?.map((ele) => ele.ColumnName), + AdditionalListColumns: this.columnOptions?.additionalListElements?.map((ele) => ele.ColumnName ?? '') ?? [], AdditionalTableColumns: this.columnOptions?.selectedOptionals - ?.map((column) => column.ColumnName) - .concat(this.columnOptions?.additionalColumns?.map((column) => column.ColumnName)), + ?.map((column) => column.ColumnName ?? '') + .concat(this.columnOptions?.additionalColumns?.map((column) => column.ColumnName ?? '')), UseAsDefault: false, }; if (this.filtersCurrentlyApplied) { config.AdditionalParameters = {}; this.settings?.filters?.forEach((filter) => { - if (filter.CurrentValue) { - config.AdditionalParameters[filter.Name] = filter.CurrentValue; + if (filter.CurrentValue && config.AdditionalParameters) { + config.AdditionalParameters[filter.Name ?? ''] = filter.CurrentValue; } }); } @@ -618,10 +634,10 @@ export class DataSourceToolbarComponent implements OnChanges, OnInit, OnDestroy if (!(await this.confirm.confirmDelete('#LDS#Heading Delete View', '#LDS#Are you sure you want to delete the view?'))) { return; } - if (this.settings.viewConfig.viewConfigs.length === 1) { + if (this.settings?.viewConfig?.viewConfigs?.length === 1) { this.savedConfigsTrigger.closeMenu(); } - this.settings.viewConfig.viewConfigs.splice(index, 1); + this.settings?.viewConfig?.viewConfigs?.splice(index, 1); this.deleteConfigById.emit(id); } @@ -629,7 +645,9 @@ export class DataSourceToolbarComponent implements OnChanges, OnInit, OnDestroy * Used internally to manage the current search term * This will be triggered by a value change listner that fires just after a user stops typing */ - public searchControl = new FormControl(''); + public searchControl: FormControl = new FormControl('', { + nonNullable: true, + }); /** * Internal subscription used to subscribe to and watch for changes on the `searchControl` @@ -678,11 +696,6 @@ export class DataSourceToolbarComponent implements OnChanges, OnInit, OnDestroy */ public isInitialLoad = true; - /** - * An indicator used to determine, if there are any filter tree informations available - */ - public hasFilterTree = false; - /** * An indicator used to determine, if viewSettings could be applied */ @@ -702,7 +715,12 @@ export class DataSourceToolbarComponent implements OnChanges, OnInit, OnDestroy /** * The currently selected filter data */ - public currentFilterData: FilterTreeSelectionArg[] = []; + public currentFilterData: FilterTreeSelectionParameter | undefined; + + /** + * The column, that is used for the filter tree. + */ + private columnForTree: string; /** * The filter tree data, that is provided by the settings filter method. @@ -712,7 +730,12 @@ export class DataSourceToolbarComponent implements OnChanges, OnInit, OnDestroy /** * Filter wizard SQL expressions */ - public filterWizardExpression: SqlWizardExpression; + public filterWizardExpression: SqlWizardExpression | undefined; + + /** + * An indicator used to determine, if there are any filter tree informations available + */ + private hasFilterTree = false; /** * @ignore Used internally. @@ -773,7 +796,7 @@ export class DataSourceToolbarComponent implements OnChanges, OnInit, OnDestroy private readonly config: AppConfigService, private readonly snackbar: SnackBarService, private readonly filterService: FilterWizardService, - private readonly systemInfoService: SystemInfoService + private readonly systemInfoService: SystemInfoService, ) { if (!this.id) this.id = uuid(); @@ -782,21 +805,33 @@ export class DataSourceToolbarComponent implements OnChanges, OnInit, OnDestroy if (!this.isUpdatingPreselection) { this.selectionChanged.next(event); } - }) + }), ); this.subscriptions.push( this.filterService.navigationStateChanged.subscribe((event: selectedFiltersParams) => { if (event.id !== this.id) return; this.selectedFilters = event.selectedFilters; - }) + }), ); this.subscriptions.push( this.filterService.filterTabChangedEvent.subscribe((filterType: FilterTypeIdentifier) => { this.selectedFilterType = filterType as FilterTypeIdentifier; - }) + }), ); + this.sortFeedbackMessages = { + search: this.translate.instant('#LDS#Search'), + selected: '', + clear: '', + plusOther: '', + plusOtherPlural: '', + unsupportedCharacter: '', + noResults: '', + clearAll: '', + ok: '', + keyboardOptionsListAria: '', + }; } /** @@ -812,19 +847,19 @@ export class DataSourceToolbarComponent implements OnChanges, OnInit, OnDestroy } public get dataSourceHasData(): boolean { - return this.settings?.dataSource?.totalCount > 0; + return (this.settings?.dataSource?.totalCount ?? 0) > 0; } public get dataSourceIsLimitReached(): boolean { - return this.settings?.dataSource?.IsLimitReached; + return this.settings?.dataSource?.IsLimitReached ?? false; } public get searchCurrenltyApplied(): boolean { - return this.settings?.navigationState?.search?.length > 0 || this.searchTerms.length > 0; + return !!this.settings?.navigationState?.search?.length || this.searchTerms.length > 0; } public get filtersCurrentlyApplied(): boolean { - return this.selectedFilters?.length > 0 || this.currentFilterData?.length > 0; + return this.selectedFilters?.length > 0 || this.currentFilterData != null; } /** @@ -864,10 +899,10 @@ export class DataSourceToolbarComponent implements OnChanges, OnInit, OnDestroy setTimeout(() => this.navigateLocalDataSource(this.settings)); } + // We only want to do this if this is the initial load... const defaultSavedConfig = this.settings?.viewConfig?.viewConfigs?.find( - (config) => this.isConfigDefault(config) && !this.isDefaultId(config) + (config) => this.isConfigDefault(config) && !this.isDefaultId(config), ); - if (this.isInitialLoad) { await this.setInitialSortOptions(); defaultSavedConfig ? this.applyConfig(defaultSavedConfig) : this.setInitialFilterValues(); @@ -877,18 +912,19 @@ export class DataSourceToolbarComponent implements OnChanges, OnInit, OnDestroy this.filterTreeItems = this.settings?.filterTree?.filterMethode ? await this.settings.filterTree?.filterMethode('') : { Elements: [] }; - this.hasFilterTree = this.settings.filterTree && this.filterTreeItems?.Elements?.length > 0; + this.hasFilterTree = this.settings.filterTree != null && !!this.filterTreeItems?.Elements?.length; if (this.settings?.dataModel) { this.initColumnOptions(defaultSavedConfig); - this.hasViewSettings = this.columnOptions?.hasOptionalColumns; + this.hasViewSettings = this.columnOptions?.hasOptionalColumns ?? false; this.updateEntitySchema(); this.settings.dataSource?.Data?.forEach((elem) => elem.GetEntity().ApplySchema(this.settings.entitySchema)); } else { this.hasViewSettings = false; } - this.filterType = this.filterTreeItems?.Description; + this.filterType = this.filterTreeItems?.Description ?? ''; + this.columnForTree = !!this.filterTreeItems?.Elements?.length ? this.filterTreeItems?.Elements?.[0]?.Filter?.ColumnName ?? '' : ''; this.internalDataSource = new MatTableDataSource(this.settings.dataSource?.Data); if (this.isDataSourceLocal && (this.searchCurrenltyApplied || this.filtersCurrentlyApplied)) { // We need to apply a filter still over the local data since it was skipped earlier. Do so now. @@ -904,6 +940,7 @@ export class DataSourceToolbarComponent implements OnChanges, OnInit, OnDestroy this.isUpdatingPreselection = true; setTimeout(() => { + this.selection.clear(); this.preSelection.forEach((item) => this.selection.checked(item)); this.isUpdatingPreselection = false; }); @@ -914,12 +951,12 @@ export class DataSourceToolbarComponent implements OnChanges, OnInit, OnDestroy this.searchResults$ = this.searchControl.valueChanges.pipe( distinctUntilChanged(), debounceTime(300), - switchMap(() => this.searchApi()) + switchMap((value) => (this.searchApi ? this.searchApi(value) : Observable.create(undefined))), ); } if (changes['disableSearch']) { - this.searchControl = new FormControl({ value: '', disabled: this.disableSearch }); + this.searchControl = new FormControl({ value: '', disabled: this.disableSearch }, { nonNullable: true }); } } @@ -1040,12 +1077,14 @@ export class DataSourceToolbarComponent implements OnChanges, OnInit, OnDestroy * Is called internally when a filter is removed from selected filters. * Updates and emits the new navigationState to include any filter query params. */ - public onSelectedFilterRemoved(selectedFilter: DataSourceToolbarSelectedFilter, optionValue: string): void { - let settingsFilter = this.settings.filters?.filter((f) => f.Name === selectedFilter.filter.Name)[0]; - if (selectedFilter && selectedFilter.isCustom) { + public onSelectedFilterRemoved(selectedFilter: DataSourceToolbarSelectedFilter, optionValue: string | undefined): void { + let settingsFilter = this.settings.filters?.filter((f) => f.Name === selectedFilter?.filter?.Name)[0]; + if (selectedFilter?.isCustom ?? false) { settingsFilter = selectedFilter.filter; } - this.removeSelectedFilter(settingsFilter, true, optionValue, selectedFilter); + if (settingsFilter) { + this.removeSelectedFilter(settingsFilter, true, optionValue, selectedFilter); + } } /** @@ -1057,7 +1096,7 @@ export class DataSourceToolbarComponent implements OnChanges, OnInit, OnDestroy let selectedFilterData: DataSourceToolbarSelectedFilter; filter.CurrentValue = option ? option.Value : undefined; selectedFilterData = { selectedOption: option, filter }; - const index = this.findSelectedFilterIndex(filter.Name); + const index = this.findSelectedFilterIndex(filter.Name ?? ''); if (index >= 0) { this.selectedFilters[index] = selectedFilterData; } else { @@ -1073,7 +1112,9 @@ export class DataSourceToolbarComponent implements OnChanges, OnInit, OnDestroy */ public selectFilterValueChanged(filter: DataSourceToolbarFilter, event: MatSelectChange): void { const option = this.findFilterOptionFromValue(event.value, filter); - this.onRadioFilterChanged(filter, option); + if (option) { + this.onRadioFilterChanged(filter, option); + } } /** @@ -1084,13 +1125,13 @@ export class DataSourceToolbarComponent implements OnChanges, OnInit, OnDestroy */ public multiSelectFilterValueChange(filter: DataSourceToolbarFilter, event: MatSelectChange): void { filter.CurrentValue = undefined; - const relevantSelectedItems = this.selectedFilters.filter((sfilter) => sfilter.filter.Name === filter.Name); + const relevantSelectedItems = this.selectedFilters.filter((sfilter) => sfilter.filter?.Name === filter.Name); relevantSelectedItems.forEach((rsi) => { - this.removeSelectedFilter(filter, false, rsi.selectedOption.Value); + this.removeSelectedFilter(filter, false, rsi.selectedOption?.Value); }); event.value.forEach((value) => { const option = this.findFilterOptionFromValue(value, filter); - this.selectedFilters.push({ selectedOption: option, filter }); + if (option) this.selectedFilters.push({ selectedOption: option, filter }); }); this.rebuildSelectedDelimitedValue(filter); this.updateNavigateStateWithFilters(); @@ -1102,9 +1143,9 @@ export class DataSourceToolbarComponent implements OnChanges, OnInit, OnDestroy * for the multi select list */ public getMultiSelectCurrentValue(filter: DataSourceToolbarFilter): string[] { - let display = []; + let display: string[] = []; if (filter.Delimiter && filter.CurrentValue) { - display = filter.CurrentValue.split(filter.Delimiter); + display = filter.CurrentValue?.split(filter.Delimiter) ?? []; } return display; } @@ -1115,7 +1156,10 @@ export class DataSourceToolbarComponent implements OnChanges, OnInit, OnDestroy */ public toggleSort(): void { this.ascendingSortControl.setValue(this.isDescending); - if (!this.settings.navigationState.OrderBy || this.settings.navigationState.OrderBy.includes(this.descArg) !== this.isDescending) { + if ( + this.settings.navigationState.OrderBy == null || + this.settings.navigationState.OrderBy?.toLocaleLowerCase()?.includes(this.descArg) !== this.isDescending + ) { this.ascendingSortControl.markAsDirty(); return; } @@ -1127,7 +1171,11 @@ export class DataSourceToolbarComponent implements OnChanges, OnInit, OnDestroy * @param columnName - IClientProperty.ColumnName */ public findAndSelectSortColumn(columnName: string): void { - const selected = this.sortOptions.find((option) => option.value.ColumnName === columnName); + const selected = this.sortOptions.find((option) => option.value === columnName); + if (!selected) { + // The column isn't in the data model, nothing we can do :( + return; + } this.selectSort(selected); } @@ -1137,8 +1185,11 @@ export class DataSourceToolbarComponent implements OnChanges, OnInit, OnDestroy */ public selectSort(option: EuiSelectOption): void { this.selectedSortControl.setValue(option.value); - const column = (option.value as IClientProperty).ColumnName; - if (!this.settings.navigationState.OrderBy || !this.settings.navigationState.OrderBy.includes(column)) { + if ( + this.settings.navigationState.OrderBy == null || + option.value == null || + !(this.settings.navigationState.OrderBy?.includes(option.value) ?? false) + ) { this.selectedSortControl.markAsDirty(); return; } @@ -1151,7 +1202,7 @@ export class DataSourceToolbarComponent implements OnChanges, OnInit, OnDestroy */ public clearSort(emit = true): void { this.isDescending = false; - this.selectedSortControl.reset(null); + this.selectedSortControl.reset(''); this.sortControl.markAsPristine(); // If the nav state has sort values, we will clear those out and emit if (this.settings.navigationState.OrderBy && emit) { @@ -1165,12 +1216,12 @@ export class DataSourceToolbarComponent implements OnChanges, OnInit, OnDestroy * Pops a warning for large data, otherwise applies the sort to the nav state and emits a navigationStateChanged signal */ public async applySort(toggleAndApply?: boolean): Promise { - const isBigData = this.settings.dataSource.totalCount > this.sortWarningThreshold; + const isBigData = (this.settings.dataSource?.totalCount ?? 0) > this.sortWarningThreshold; if ( isBigData && !(await this.confirm.confirmLeaveWithUnsavedChanges( '#LDS#Heading Sort Data', - '#LDS#Sorting the data may take some time. Are you sure you want to sort the data?' + '#LDS#Sorting the data may take some time. Are you sure you want to sort the data?', )) ) { // Exit early - user doesn't want to continue. @@ -1183,7 +1234,8 @@ export class DataSourceToolbarComponent implements OnChanges, OnInit, OnDestroy } // Add sort and ascending to nav state - this.settings.navigationState.OrderBy = this.selectedSortControl.value.ColumnName; + this.settings.navigationState.OrderBy = this.selectedSortControl?.value ?? ''; + if (this.isDescending) { this.settings.navigationState.OrderBy += this.descArg; } @@ -1217,13 +1269,16 @@ export class DataSourceToolbarComponent implements OnChanges, OnInit, OnDestroy * unless emitChange is false */ public removeSelectedFilter( - filter: DataSourceToolbarFilter, + filter: DataSourceToolbarFilter | undefined, emitChange: boolean = true, optionValue?: string, - selectedFilter?: DataSourceToolbarSelectedFilter + selectedFilter?: DataSourceToolbarSelectedFilter, ): void { + if (!filter) { + return; + } filter.CurrentValue = undefined; - const index = this.findSelectedFilterIndex(filter.Name, optionValue); + const index = this.findSelectedFilterIndex(filter.Name ?? '', optionValue); if (index >= 0) { this.selectedFilters.splice(index, 1); @@ -1247,35 +1302,6 @@ export class DataSourceToolbarComponent implements OnChanges, OnInit, OnDestroy } } - /** - * @ignore Used internally. - * Shows a filter tree dialog and updates the filter set - */ - public async showFilterTree(): Promise { - const filterdata = await this.dialog - .open(FilterTreeComponent, { - width: 'min(600px,60%)', - autoFocus: false, - height: 'min(600px,60%)', - data: { - filterTreeParameter: this.settings.filterTree, - preselection: this.currentFilterData.map((elem) => elem), - type: this.filterType, - }, - panelClass: 'imx-toolbar-dialog', - }) - .afterClosed() - .toPromise(); - if (filterdata) { - //Get all filter, that were not associaed with the tree filter - const otherFilter = (this.settings.navigationState.filter ?? []).filter( - (elem) => elem.ColumnName !== filterdata[0].filter.ColumnName && elem.ColumnName !== this.currentFilterData[0].filter.ColumnName - ); - this.currentFilterData = filterdata; - this.filterTreeSelectionChanged.emit(this.currentFilterData.map((filter) => filter.filter).concat(otherFilter)); // combine the two filter again - } - } - /** * @ignore Used internally. * Shows a dialog for adding/removing additional informations @@ -1292,8 +1318,6 @@ export class DataSourceToolbarComponent implements OnChanges, OnInit, OnDestroy if (await this.resetView()) { this.clearTreeFilter(); } - - this.applyConfig(this.settings?.viewConfig?.viewConfigs?.find((config) => this.isDefaultId(config))); } /** @@ -1305,7 +1329,7 @@ export class DataSourceToolbarComponent implements OnChanges, OnInit, OnDestroy emit && !(await this.confirm.confirmDelete( '#LDS#Heading Reset View', - '#LDS#If you reset the view, the search, sorting, filters and additional columns will be reset. Are you sure you want to reset the view?' + '#LDS#If you reset the view, the search, sorting, filters and additional columns will be reset. Are you sure you want to reset the view?', )) ) { return false; @@ -1313,23 +1337,23 @@ export class DataSourceToolbarComponent implements OnChanges, OnInit, OnDestroy this.columnOptions?.resetView(); this.searchTerms = []; - if (this.settings.navigationState?.search) { - this.searchControl.reset(null); + if (this.settings.navigationState.search) { + this.searchControl.reset(''); delete this.settings.navigationState.search; } - if (this.settings.navigationState?.OrderBy) { + if (this.settings.navigationState.OrderBy) { delete this.settings.navigationState.OrderBy; this.clearSort(false); } if (this.settings?.groupData?.currentGrouping) { this.clearGroupedBy(false); } - delete this.settings.navigationState?.filter; + delete this.settings.navigationState.filter; if (this.filtersCurrentlyApplied) { this.clearFilters(false); } - this.filterWizardExpression = null; + this.filterWizardExpression = undefined; if (emit) { this.navigationStateChanged.emit(this.settings.navigationState); } @@ -1340,11 +1364,11 @@ export class DataSourceToolbarComponent implements OnChanges, OnInit, OnDestroy * clears the tree filter and emits the filterTreeSelectionChanged event */ public clearTreeFilter(emit = true): void { - const currentTree: FilterData = this.currentFilterData[0]?.filter; - this.currentFilterData = []; + const currentTree: FilterData | undefined = this.currentFilterData?.filter; + this.currentFilterData = undefined; if (emit) { this.filterTreeSelectionChanged.emit( - this.settings.navigationState.filter?.filter((elem) => elem.ColumnName != currentTree.ColumnName) + this.settings.navigationState.filter?.filter((elem) => elem.ColumnName != currentTree?.ColumnName), ); } } @@ -1355,17 +1379,17 @@ export class DataSourceToolbarComponent implements OnChanges, OnInit, OnDestroy * * If isDataSourceLocal is true then a 'settingsChanged signal is emitted isntead of a search signal. */ - public onSearch(keywords: string): void { + public onSearch(keywords: string | null | undefined): void { if (this.settings && this.settings.navigationState) { this.settings.navigationState.StartIndex = 0; - this.settings.navigationState.search = keywords; + this.settings.navigationState.search = keywords ?? ''; } if (this.isDataSourceLocal) { // Do search locally - this.localFilterState.keywords = keywords; + this.localFilterState.keywords = keywords ?? ''; this.localFilter(); } else { - this.search.emit(keywords); + this.search.emit(keywords ?? ''); } } @@ -1374,6 +1398,9 @@ export class DataSourceToolbarComponent implements OnChanges, OnInit, OnDestroy * Will be called when a group by option is selected */ public onGroupSelected(group: DataSourceToolBarGroup, groupCategory?: DataSourceToolBarGroupingCategory): void { + if (!this.settings.groupData) { + return; + } this.settings.groupData.currentGrouping = { display: (groupCategory?.property.Display ? groupCategory.property.Display + ' - ' : '') + this.getGroupColumnDisplay(group), getData: group.getData, @@ -1388,6 +1415,9 @@ export class DataSourceToolbarComponent implements OnChanges, OnInit, OnDestroy * Removes any grouping currently applied and emits the settings changed event */ public clearGroupedBy(emit = true): void { + if (!this.settings.groupData) { + return; + } this.settings.groupData.currentGrouping = undefined; if (emit) { this.settingsChanged.emit(this.settings); @@ -1399,9 +1429,18 @@ export class DataSourceToolbarComponent implements OnChanges, OnInit, OnDestroy * Used to convert the groupBy column api value into a display friendly format */ public getGroupColumnDisplay(group: DataSourceToolBarGroup): string { - return ( - group.property.Display ?? this.entitySchema.Columns[group.property.Property.ColumnName]?.Display ?? group.property.Property.Display - ); + if (group.property.Display) { + return group.property.Display; + } + + if (group.property.Property?.ColumnName) { + return this.entitySchema.Columns[group.property.Property?.ColumnName]?.Display ?? ''; + } + + if (group.property.Property?.Display) { + return group.property.Property?.Display; + } + return group.property.Property?.ColumnName ?? ''; } public canShowFilterWizard(): boolean { @@ -1410,7 +1449,8 @@ export class DataSourceToolbarComponent implements OnChanges, OnInit, OnDestroy this.filterService.isSqlWizardImplemented && !this.isDataSourceLocal && !this.disableFilterWizard) || - this.settings?.filters?.length > 0; + !!this.settings?.filters?.length || + this.hasFilterTree; return result; } @@ -1418,7 +1458,7 @@ export class DataSourceToolbarComponent implements OnChanges, OnInit, OnDestroy const sidesheetRef = this.sidesheet.open(FilterWizardComponent, { title: await this.translate.get('#LDS#Heading Filter Data').toPromise(), icon: 'filter', - width: '800px', + width: calculateSidesheetWidth(800, 0.5), padding: '0px', testId: 'filter-wizard-sidesheet', disableClose: true, @@ -1427,28 +1467,51 @@ export class DataSourceToolbarComponent implements OnChanges, OnInit, OnDestroy settings: this.settings, filterExpression: this.filterWizardExpression, selectedFilters: this.selectedFilters, + filterTreeParameter: { + filterTreeParameter: this.settings.filterTree, + preSelection: this.currentFilterData, + type: this.filterType, + }, isDataSourceLocal: this.isDataSourceLocal, }, }); - sidesheetRef.afterClosed().subscribe((result: SqlWizardExpression) => { - if (!result && !this.filterWizardExpression) { - return; - } - if (result?.Expression?.Expressions.length === 0) { - this.removeFilterWizard(); + sidesheetRef.afterClosed().subscribe((result: FilterWizardResult) => { + if (!result) { return; } - this.settings.navigationState.filter = this.settings.navigationState.filter?.filter((x) => x.Type != FilterType.Expression); - if (result) { - this.filterWizardExpression = result; + this.clearTreeFilter(false); + this.removeFilterWizard(false); + this.currentFilterData = result?.treeFilter; + + const hasNoFilters = (result?.expression?.Expression?.Expressions?.length || 0) === 0; + const hasNewTree = !!result?.treeFilter && this.currentFilterData !== result?.treeFilter; + + if (!hasNoFilters) { + this.filterWizardExpression = result.expression; } - this.settings.navigationState.filter - ? this.settings.navigationState.filter.push({ Type: FilterType.Expression, Expression: this.filterWizardExpression.Expression }) - : (this.settings.navigationState.filter = [{ Type: FilterType.Expression, Expression: this.filterWizardExpression.Expression }]); - if (result?.Expression?.Expressions.length > 0) { + if (hasNewTree && hasNoFilters) { + // has new tree and no other filters, only emit tree state + const otherFilter = (this.settings.navigationState.filter ?? []).filter( + (elem) => elem.ColumnName !== result?.treeFilter?.filter?.ColumnName, + ); + this.filterTreeSelectionChanged.emit( + this.currentFilterData?.filter ? [this.currentFilterData.filter].concat(otherFilter) : otherFilter, + ); + } else { + // tree or filters, do both but only emit nav state + this.settings.navigationState.filter = this.settings.navigationState.filter?.filter((x) => x.Type != FilterType.Expression) ?? []; + if (this.filterWizardExpression?.Expression) { + this.settings.navigationState.filter.push({ + Type: FilterType.Expression, + Expression: this.filterWizardExpression?.Expression, + }); + } + if (result.treeFilter?.filter) { + this.settings.navigationState.filter.push(result.treeFilter.filter); + } this.updateNavigateStateWithFilters(); } }); @@ -1456,7 +1519,7 @@ export class DataSourceToolbarComponent implements OnChanges, OnInit, OnDestroy public removeFilterWizard(reload: boolean = true): void { this.settings.navigationState.filter = this.settings.navigationState.filter?.filter((x) => x.Expression == null); - this.filterWizardExpression = null; + this.filterWizardExpression = undefined; if (reload) { this.navigationStateChanged.next(this.settings.navigationState); } @@ -1481,7 +1544,7 @@ export class DataSourceToolbarComponent implements OnChanges, OnInit, OnDestroy this.columnSubscriptions.push( this.columnOptions.shownColumnsSelectionChanged.subscribe((elem) => { this.shownColumnsSelectionChanged.emit(elem.properties); - const optionals = this.columnOptions.getPropertiesForNavigation(); + const optionals = this.columnOptions?.getPropertiesForNavigation() ?? []; this.additionalPropertiesForNavigation.forEach((prop) => { if (!optionals.includes(prop)) { optionals.push(prop); @@ -1494,17 +1557,20 @@ export class DataSourceToolbarComponent implements OnChanges, OnInit, OnDestroy this.navigationStateChanged.emit(this.settings.navigationState); } } - }) + }), ); this.columnSubscriptions.push( - this.columnOptions.additionalListElementsChanged.subscribe((elem) => this.additionalListElementsChanged.emit(elem)) + this.columnOptions.additionalListElementsChanged.subscribe((elem) => this.additionalListElementsChanged.emit(elem)), ); this.columnOptions.initColumnsAndAdditionalInformation(); } private updateEntitySchema(): void { - const newSchema = this.columnOptions.updateEntitySchema(); + const newSchema = this.columnOptions?.updateEntitySchema(); + if (!newSchema) { + return; + } this.settings.entitySchema = newSchema; this.entitySchema = newSchema; if (this.isDataSourceLocal) { @@ -1521,7 +1587,7 @@ export class DataSourceToolbarComponent implements OnChanges, OnInit, OnDestroy } else { // Grab string-based columns to filter over const columns = this.entitySchema.Columns; - const stringColumns = []; + const stringColumns: string[] = []; for (const [key, value] of Object.entries(columns)) { if (value.Type === ValType.String) { stringColumns.push(key); @@ -1550,8 +1616,8 @@ export class DataSourceToolbarComponent implements OnChanges, OnInit, OnDestroy private rebuildSelectedDelimitedValue(filter: DataSourceToolbarFilter): void { let val = ''; this.selectedFilters.forEach((sfilter) => { - if (sfilter.filter.Name === filter.Name) { - val += `${sfilter.selectedOption.Value}${filter.Delimiter}`; + if (sfilter.filter?.Name === filter.Name) { + val += `${sfilter.selectedOption?.Value}${filter.Delimiter}`; } }); filter.CurrentValue = val.length ? val.slice(0, -1) : undefined; @@ -1573,19 +1639,20 @@ export class DataSourceToolbarComponent implements OnChanges, OnInit, OnDestroy */ private navigateLocalDataSource(settings: DataSourceToolbarSettings): void { const tmpDataSource = this.settings.dataSource; - if (this.internalDataSource.filter.length > 0) { - // This data has a search filter, so apply the pagination over the filtered data - tmpDataSource.Data = this.internalDataSource.filteredData.slice( - settings.navigationState.StartIndex, - settings.navigationState.StartIndex + settings.navigationState.PageSize - ); - } else { - tmpDataSource.Data = this.localDataSource.Data.slice( - settings.navigationState.StartIndex, - settings.navigationState.StartIndex + settings.navigationState.PageSize - ); + if (tmpDataSource) { + if (this.internalDataSource.filter.length > 0) { + // This data has a search filter, so apply the pagination over the filtered data + tmpDataSource.Data = this.internalDataSource.filteredData.slice( + settings.navigationState.StartIndex, + (settings.navigationState.StartIndex ?? 0) + (settings.navigationState.PageSize ?? 0), + ); + } else { + tmpDataSource.Data = this.localDataSource.Data.slice( + settings.navigationState.StartIndex, + (settings.navigationState.StartIndex ?? 0) + (settings.navigationState.PageSize ?? 0), + ); + } } - this.settings = { ...{ dataSource: tmpDataSource, @@ -1603,16 +1670,10 @@ export class DataSourceToolbarComponent implements OnChanges, OnInit, OnDestroy * @param config the configuration, that should be loaded. */ private addTreeFilterFromConfig(config: DSTViewConfig): void { - const treeIndex = config?.Filter?.findIndex( - (elem) => - elem.Type === FilterType.Compare && // filter is a compare filter - !this.settings.staticFilterColumns?.some((column) => column.toLocaleUpperCase() === elem.ColumnName.toLocaleUpperCase()) - ); // filter is not static - - if (treeIndex > -1) { - const tree = config.Filter[treeIndex]; - const display = config.FilterDescriptions[treeIndex].LongDisplay ?? tree.Value1; - this.currentFilterData = [{ display, filter: tree }]; + const tree = config?.Filter?.find((elem) => elem.ColumnName === this.columnForTree); + if (tree != null) { + const display = this.filterTreeItems?.Elements?.find((elem) => elem.Filter?.Value1 === tree.Value1)?.Display ?? ''; + this.currentFilterData = { display, filter: tree }; if (this.settings.navigationState.filter) { this.settings.navigationState.filter.push(tree); } else { @@ -1643,6 +1704,8 @@ export class DataSourceToolbarComponent implements OnChanges, OnInit, OnDestroy * @ignore Used internally * Sets any initial values for the supplied filters and makes a call to update the navigation state * + * Also marks the 'isInitialLoad' property to false to ensure this only happens on the initial load + * of the component */ private setInitialFilterValues(): void { // Here we prefer the saved default config over emiting the init @@ -1656,8 +1719,10 @@ export class DataSourceToolbarComponent implements OnChanges, OnInit, OnDestroy } } }); - - this.applyConfig(this.settings?.viewConfig?.viewConfigs?.find((config) => this.isDefaultId(config))); + // We only need to update the state if there were filters applied + if (this.selectedFilters.length > 0) { + this.updateNavigateStateWithFilters(); + } } private async setInitialSortOptions(): Promise { @@ -1665,30 +1730,15 @@ export class DataSourceToolbarComponent implements OnChanges, OnInit, OnDestroy return; } this.sortWarningThreshold = (await this.systemInfoService.getImxConfig()).ThresholdSlowSortingWarning; - this.sortOptions = this.settings.dataModel.Properties.filter((property) => property.IsSortable) + this.sortOptions = (this.settings?.dataModel?.Properties?.filter((property) => property.IsSortable) ?? []) .map((property) => { return { - display: property.Property?.Display ?? property.Property.ColumnName, - displayDetail: property.Property?.Description, - value: property.Property, + display: property.Property?.Display ?? property.Property?.ColumnName ?? '', + displayDetail: property.Property?.Description ?? '', + value: property.Property?.ColumnName ?? '', }; }) .sort((a, b) => (a?.display < b?.display ? -1 : 1)); - - if (this.isSortApplied) { - const [column, dir] = this.settings.navigationState.OrderBy.split(' '); - const option = this.sortOptions.find((opt) => opt.value.ColumnName == column); - if (!option) { - // The initial column isn't in the data model, nothing we can do :( - return; - } - this.selectedSortControl.reset(option.value); - if (dir) { - // There was a dir option, we will make sure to keep consistent here - this.isDescending = dir.trim().toLocaleLowerCase() === this.descArg.trim(); - this.ascendingSortControl.reset(this.isDescending); - } - } } /** @@ -1733,7 +1783,7 @@ export class DataSourceToolbarComponent implements OnChanges, OnInit, OnDestroy this.searchResults$ = this.searchControl.valueChanges.pipe( distinctUntilChanged(), debounceTime(300), - switchMap(() => this.searchApi()) + switchMap((value) => (this.searchApi ? this.searchApi(value) : Observable.create(undefined))), ); } @@ -1742,57 +1792,60 @@ export class DataSourceToolbarComponent implements OnChanges, OnInit, OnDestroy } } - public isRedundant(value: string): boolean { + public isRedundant(value: string | null | undefined): boolean { // Prevent redundant api call from adding search to searchterm list return ( - !value && - this.searchTerms.length && - this.settings.navigationState?.search === this.searchTerms[this.searchTerms.length - 1].selectedOption.Value + (!value && + this.searchTerms.length > 0 && + this.settings.navigationState?.search === this.searchTerms[this.searchTerms.length - 1].selectedOption?.Value) ?? + false ); } public addSearchFilter(filter?: FilterData): void { - if ( - this.isEnterDisabled || - filter?.Type !== FilterType.Search || - filter?.Expression != null || - (!filter && (!this.searchControl.value || (!!this.searchControl.value && this.searchControl.value?.length === 0))) - ) { - // Here we return early if there is nothing to search over - return; - } - - const searchFilter = filter ?? { - Type: FilterType.Search, - Value1: this.searchControl.value.slice(), - IsRegex: this.isRegex, - }; - this.searchControl.reset(null); + setTimeout(() => { + if ( + this.isEnterDisabled || + filter?.ColumnName === this.columnForTree || + filter?.Expression != null || + (!filter && (!this.searchControl.value || (!!this.searchControl.value && this.searchControl.value?.length === 0))) + ) { + // Here we return early if there is nothing to search over + return; + } - this.searchTerms.push({ - selectedOption: { - Display: searchFilter.Value1, - Value: searchFilter.Value1, + const searchFilter = filter ?? { + Type: FilterType.Search, + Value1: this.searchControl?.value?.slice(), IsRegex: this.isRegex, - }, - filter: { - CurrentValue: searchFilter.Value1, - }, - }); - if (this.isDataSourceLocal) { - this.localFilterState.keywords = ''; - return; - } + }; + this.searchControl.reset(''); + + this.searchTerms.push({ + selectedOption: { + Display: searchFilter.Value1, + Value: searchFilter.Value1, + IsRegex: this.isRegex, + }, + filter: { + CurrentValue: searchFilter.Value1, + }, + }); + if (this.isDataSourceLocal) { + this.localFilterState.keywords = ''; + return; + } - if (this.settings.navigationState.filter) { - this.settings.navigationState.filter.push(searchFilter); - } else { - this.settings.navigationState.filter = [searchFilter]; - } + if (this.settings.navigationState.filter) { + this.settings.navigationState.filter.push(searchFilter); + } else { + this.settings.navigationState.filter = [searchFilter]; + } + }); } public removeSearchTerm(searchTerm: DataSourceToolbarSelectedFilter): void { - let index = this.searchTerms.findIndex((st) => st.selectedOption.Display === searchTerm.selectedOption.Display); + let index = this.searchTerms.findIndex((st) => st.selectedOption?.Display === searchTerm.selectedOption?.Display); this.searchTerms.splice(index, 1); if (this.isDataSourceLocal) { this.localFilter(); @@ -1800,7 +1853,7 @@ export class DataSourceToolbarComponent implements OnChanges, OnInit, OnDestroy } if (!!this.settings.navigationState.filter && this.searchTerms.length - 1 !== this.settings.navigationState.filter.length) { // Here we have to check over the filters since the lengths didn't match, we subtract 1 to account for the splicing - index = this.settings.navigationState.filter.findIndex((filter) => filter.Value1 === searchTerm.selectedOption.Display); + index = this.settings.navigationState.filter.findIndex((filter) => filter.Value1 === searchTerm.selectedOption?.Display); } if (!!this.settings.navigationState.filter) { this.settings.navigationState.filter.splice(index, 1); @@ -1816,9 +1869,9 @@ export class DataSourceToolbarComponent implements OnChanges, OnInit, OnDestroy private findSelectedFilterIndex(filterName: string, optionValue?: string): number { let index: number; if (optionValue) { - index = this.selectedFilters.map((f) => f.filter.Name + f.selectedOption.Value).indexOf(filterName + optionValue); + index = this.selectedFilters.map((f) => (f.filter?.Name ?? '') + (f.selectedOption?.Value ?? '')).indexOf(filterName + optionValue); } else { - index = this.selectedFilters.map((f) => f.filter.Name).indexOf(filterName); + index = this.selectedFilters.map((f) => f.filter?.Name).indexOf(filterName); } return index; } @@ -1839,9 +1892,9 @@ export class DataSourceToolbarComponent implements OnChanges, OnInit, OnDestroy * @ignore Used internally * Finds the relevant DataModelFilterOption from the supplied option value and filter */ - private findFilterOptionFromValue(optionValue: string, filter: DataSourceToolbarFilter): DataModelFilterOption { - const index = filter.Options.map((opt) => opt.Value).indexOf(optionValue); - return filter.Options[index]; + private findFilterOptionFromValue(optionValue: string, filter: DataSourceToolbarFilter): DataModelFilterOption | undefined { + const index = filter.Options?.map((opt) => opt.Value).indexOf(optionValue) ?? -1; + return filter.Options && index > -1 ? filter.Options[index] : undefined; } /** @@ -1854,13 +1907,17 @@ export class DataSourceToolbarComponent implements OnChanges, OnInit, OnDestroy private updateNavigateStateWithFilters(emit = true): void { this.settings.filters?.forEach((filter) => { if (filter.CurrentValue) { - this.settings.navigationState[filter.Name] = filter.CurrentValue; + if (filter.Name) { + this.settings.navigationState[filter.Name] = filter.CurrentValue; + } if (filter?.Column) { // This is a local filter and we must filter over this column this.localFilterState.filterColumns[filter.Column] = filter.CurrentValue; } } else { - delete this.settings.navigationState[filter.Name]; + if (filter.Name) { + delete this.settings.navigationState[filter.Name]; + } if (filter?.Column) { delete this.localFilterState.filterColumns[filter.Column]; } @@ -1894,7 +1951,7 @@ export class DataSourceToolbarComponent implements OnChanges, OnInit, OnDestroy // First check keyword, '' is default and will return true searchResult = val.includes(this.localFilterState?.keywords?.toLocaleLowerCase()); // Second check terms, allow for short circuiting - searchResult &&= this.searchTerms.every((term) => val.includes(term.selectedOption.Display)); + searchResult &&= this.searchTerms.every((term) => val.includes(term.selectedOption?.Display ?? '')); if (searchResult) { // Exit for loop if we have a positive hit break; @@ -1932,7 +1989,7 @@ export class DataSourceToolbarComponent implements OnChanges, OnInit, OnDestroy this.sidesheet.open(DataExportComponent, { title: await this.translate.get('#LDS#Heading Export Data').toPromise(), padding: '0px', - width: 'max(730px,65%)', + width: calculateSidesheetWidth(1000), icon: 'export', data: this.settings, }); diff --git a/imxweb/projects/qbm/src/lib/data-source-toolbar/data-source-toolbar.module.ts b/imxweb/projects/qbm/src/lib/data-source-toolbar/data-source-toolbar.module.ts index 4cad9065f..ae5ab7528 100644 --- a/imxweb/projects/qbm/src/lib/data-source-toolbar/data-source-toolbar.module.ts +++ b/imxweb/projects/qbm/src/lib/data-source-toolbar/data-source-toolbar.module.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -24,71 +24,63 @@ * */ -import { NgModule } from '@angular/core'; import { CommonModule } from '@angular/common'; +import { NgModule } from '@angular/core'; import { MatButtonToggleModule } from '@angular/material/button-toggle'; import { MatFormFieldModule } from '@angular/material/form-field'; import { MatIconModule } from '@angular/material/icon'; +import { MatListModule } from '@angular/material/list'; import { MatMenuModule } from '@angular/material/menu'; import { MatPaginatorModule } from '@angular/material/paginator'; import { MatTooltipModule } from '@angular/material/tooltip'; import { EuiCoreModule, EuiMaterialModule } from '@elemental-ui/core'; import { TranslateModule } from '@ngx-translate/core'; -import { MatListModule } from '@angular/material/list'; -import { DataSourceToolbarComponent } from './data-source-toolbar.component'; -import { DataSourcePaginatorComponent } from './data-source-paginator.component'; -import { DataSourceToolbarCustomComponent } from './data-source-toolbar-custom.component'; -import { DataTreeModule } from '../data-tree/data-tree.module'; -import { FilterTreeComponent } from './filter-tree/filter-tree.component'; -import { LdsReplaceModule } from '../lds-replace/lds-replace.module'; -import { AdditionalInfosComponent } from './additional-infos/additional-infos.component'; import { DragDropModule } from '@angular/cdk/drag-drop'; +import { provideHttpClient, withInterceptorsFromDi } from '@angular/common/http'; +import { FormsModule, ReactiveFormsModule } from '@angular/forms'; +import { MatCardModule } from '@angular/material/card'; import { MatChipsModule } from '@angular/material/chips'; +import { MatDividerModule } from '@angular/material/divider'; +import { LoggerModule } from 'ngx-logger'; +import { AppConfigService } from '../appConfig/appConfig.service'; import { ClassloggerModule } from '../classlogger/classlogger.module'; -import { MatCardModule } from '@angular/material/card'; +import { DataTreeModule } from '../data-tree/data-tree.module'; +import { LdsReplaceModule } from '../lds-replace/lds-replace.module'; +import { AdditionalInfosComponent } from './additional-infos/additional-infos.component'; +import { DataSourcePaginatorComponent } from './data-source-paginator.component'; +import { DataSourceToolbarCustomComponent } from './data-source-toolbar-custom.component'; +import { DataSourceToolbarComponent } from './data-source-toolbar.component'; +import { FilterTreeComponent } from './filter-tree/filter-tree.component'; import { SaveConfigDialogComponent } from './save-config-dialog/save-config-dialog.component'; -import { ReactiveFormsModule } from '@angular/forms'; -import { FormsModule } from '@angular/forms'; -import { AppConfigService } from '../appConfig/appConfig.service'; -import { HttpClientModule } from '@angular/common/http'; -import { LoggerConfig, LoggerModule } from 'ngx-logger'; -import { MatDividerModule } from '@angular/material/divider'; -@NgModule({ - declarations: [ - DataSourceToolbarComponent, - DataSourcePaginatorComponent, - DataSourceToolbarCustomComponent, - FilterTreeComponent, - AdditionalInfosComponent, - SaveConfigDialogComponent, - ], - imports: [ - CommonModule, - EuiCoreModule, - EuiMaterialModule, - MatFormFieldModule, - MatMenuModule, - MatIconModule, - MatTooltipModule, - MatPaginatorModule, - MatButtonToggleModule, - MatChipsModule, - MatListModule, - MatCardModule, - MatDividerModule, - DragDropModule, - TranslateModule, - DataTreeModule, - LdsReplaceModule, - ClassloggerModule, - ReactiveFormsModule, - FormsModule, - HttpClientModule, - LoggerModule, - ], - providers: [AppConfigService, LoggerConfig], - exports: [DataSourceToolbarComponent, DataSourcePaginatorComponent, DataSourceToolbarCustomComponent, FilterTreeComponent], -}) +@NgModule({ declarations: [ + DataSourceToolbarComponent, + DataSourcePaginatorComponent, + DataSourceToolbarCustomComponent, + FilterTreeComponent, + AdditionalInfosComponent, + SaveConfigDialogComponent, + ], + exports: [DataSourceToolbarComponent, DataSourcePaginatorComponent, DataSourceToolbarCustomComponent, FilterTreeComponent], imports: [CommonModule, + EuiCoreModule, + EuiMaterialModule, + MatFormFieldModule, + MatMenuModule, + MatIconModule, + MatTooltipModule, + MatPaginatorModule, + MatButtonToggleModule, + MatChipsModule, + MatListModule, + MatCardModule, + MatDividerModule, + DragDropModule, + TranslateModule, + DataTreeModule, + LdsReplaceModule, + ClassloggerModule, + ReactiveFormsModule, + FormsModule, + LoggerModule], providers: [AppConfigService, provideHttpClient(withInterceptorsFromDi())] }) export class DataSourceToolbarModule {} diff --git a/imxweb/projects/qbm/src/lib/data-source-toolbar/data-source-wrapper.spec.ts b/imxweb/projects/qbm/src/lib/data-source-toolbar/data-source-wrapper.spec.ts index 7364444b9..a0f2dbd66 100644 --- a/imxweb/projects/qbm/src/lib/data-source-toolbar/data-source-wrapper.spec.ts +++ b/imxweb/projects/qbm/src/lib/data-source-toolbar/data-source-wrapper.spec.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -24,46 +24,36 @@ * */ -import { EntitySchema, IClientProperty, TypedEntity } from 'imx-qbm-dbts'; +import { EntitySchema, IClientProperty, TypedEntity } from '@imx-modules/imx-qbm-dbts'; import { DataSourceWrapper } from './data-source-wrapper'; describe('DataSourceWrapper', () => { it('propertyDisplay', () => { const propertyDisplay = { ColumnName: '__Display' } as IClientProperty; - const dstWrapper = new DataSourceWrapper( - undefined, - undefined, - { Columns: { __Display: propertyDisplay } } as EntitySchema - ); - + const dstWrapper = new DataSourceWrapper(undefined, undefined, { Columns: { __Display: propertyDisplay } } as EntitySchema); + expect(dstWrapper.propertyDisplay.ColumnName).toEqual(propertyDisplay.ColumnName); }); it('getDstSettings', async () => { - type SomeEntity = { someProperty: string; } & TypedEntity; + type SomeEntity = { someProperty: string } & TypedEntity; const data = [{ someProperty: 'some value' }] as SomeEntity[]; const collection = { totalCount: data.length, - Data: data + Data: data, }; const someColumn = { ColumnName: 'SomeColumnName' } as IClientProperty; const entitySchema = { Columns: { someColumn } } as EntitySchema; - const displayedColumns = [ - entitySchema.Columns.someColumn - ]; + const displayedColumns = [entitySchema.Columns.someColumn]; - const dstWrapper = new DataSourceWrapper( - __ => Promise.resolve(collection), - displayedColumns, - entitySchema - ); + const dstWrapper = new DataSourceWrapper((__) => Promise.resolve(collection), displayedColumns, entitySchema); const parameters = { StartIndex: 23 }; - + const dstSettings = await dstWrapper.getDstSettings(parameters); expect((dstSettings.dataSource.Data[0] as SomeEntity).someProperty).toEqual(data[0].someProperty); @@ -71,4 +61,4 @@ describe('DataSourceWrapper', () => { expect(dstSettings.entitySchema.Columns.someColumn.ColumnName).toEqual(someColumn.ColumnName); expect(dstSettings.navigationState.StartIndex).toEqual(parameters.StartIndex); }); -}); \ No newline at end of file +}); diff --git a/imxweb/projects/qbm/src/lib/data-source-toolbar/data-source-wrapper.ts b/imxweb/projects/qbm/src/lib/data-source-toolbar/data-source-wrapper.ts index b002032fd..b33cdb53a 100644 --- a/imxweb/projects/qbm/src/lib/data-source-toolbar/data-source-wrapper.ts +++ b/imxweb/projects/qbm/src/lib/data-source-toolbar/data-source-wrapper.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -26,45 +26,57 @@ import { ApiRequestOptions, - CollectionLoadParameters, DataModel, DisplayColumns, EntitySchema, ExtendedTypedEntityCollection, IClientProperty, TypedEntity -} from 'imx-qbm-dbts'; -import { DataModelWrapper } from './data-model/data-model-wrapper.interface'; + CollectionLoadParameters, + DataModel, + DisplayColumns, + EntitySchema, + ExtendedTypedEntityCollection, + IClientProperty, + TypedEntity, +} from '@imx-modules/imx-qbm-dbts'; +import { ClientPropertyForTableColumns } from './client-property-for-table-columns'; import { createGroupData } from './data-model/data-model-helper'; +import { DataModelWrapper } from './data-model/data-model-wrapper.interface'; import { DataSourceToolbarFilter } from './data-source-toolbar-filters.interface'; import { DataSourceToolbarGroupData } from './data-source-toolbar-groups.interface'; import { DataSourceToolbarSettings } from './data-source-toolbar-settings'; -import { ClientPropertyForTableColumns } from './client-property-for-table-columns'; export class DataSourceWrapper { public readonly propertyDisplay: IClientProperty; - public extendedData: TExtendedData; + public extendedData: TExtendedData | undefined; private parameters: CollectionLoadParameters; private readonly filterOptions: DataSourceToolbarFilter[]; private dataModel: DataModel; - private readonly groupData: DataSourceToolbarGroupData; + private readonly groupData: DataSourceToolbarGroupData | undefined; constructor( - private readonly getData: (parameters: CollectionLoadParameters, requestOpts?: ApiRequestOptions) => Promise>, + private readonly getData: ( + parameters: CollectionLoadParameters, + requestOpts?: ApiRequestOptions, + ) => Promise>, private readonly displayedColumns: ClientPropertyForTableColumns[], private readonly entitySchema: EntitySchema, dataModelWrapper?: DataModelWrapper, - private readonly identifier?: string + private readonly identifier?: string, ) { this.propertyDisplay = this.entitySchema.Columns[DisplayColumns.DISPLAY_PROPERTYNAME]; if (dataModelWrapper) { this.dataModel = dataModelWrapper.dataModel; - this.filterOptions = dataModelWrapper.dataModel.Filters; + this.filterOptions = dataModelWrapper.dataModel.Filters ?? []; this.groupData = this.createGroupData(dataModelWrapper); } } - public async getDstSettings(parameters?: CollectionLoadParameters, requestOpts?: ApiRequestOptions ): Promise { + public async getDstSettings( + parameters?: CollectionLoadParameters, + requestOpts?: ApiRequestOptions, + ): Promise { this.parameters = { ...this.parameters, - ...parameters + ...parameters, }; const dataSource = await this.getData(this.parameters, requestOpts); @@ -79,39 +91,48 @@ export class DataSourceWrapper { + public async getGroupDstSettings( + parameters: CollectionLoadParameters, + requestOpts?: ApiRequestOptions, + ): Promise { return { displayedColumns: this.displayedColumns, dataModel: this.dataModel, dataSource: await this.getData(parameters, requestOpts), entitySchema: this.entitySchema, - navigationState: parameters + navigationState: parameters, }; } - private createGroupData(dataModelWrapper: DataModelWrapper): DataSourceToolbarGroupData { + private createGroupData(dataModelWrapper: DataModelWrapper): DataSourceToolbarGroupData | undefined { return createGroupData( dataModelWrapper.dataModel, - parameters => dataModelWrapper.getGroupInfo({ - ...parameters, - ...this.getGroupingFilterOptionParameters(dataModelWrapper.groupingFilterOptions), - }), - dataModelWrapper.groupingExcludedColumns + (parameters) => { + if (dataModelWrapper.getGroupInfo) { + return dataModelWrapper.getGroupInfo({ + ...parameters, + ...this.getGroupingFilterOptionParameters(dataModelWrapper.groupingFilterOptions ?? []), + }); + } + return undefined; + }, + dataModelWrapper.groupingExcludedColumns, ); } private getGroupingFilterOptionParameters(groupingFilterOptions: string[]): { [parameterName: string]: string } { const parameters = {}; - groupingFilterOptions?.forEach(filterOptionName => - parameters[filterOptionName] = this.filterOptions.find(item => item.Name === filterOptionName)?.CurrentValue + groupingFilterOptions?.forEach( + (filterOptionName) => + (parameters[filterOptionName] = this.filterOptions.find((item) => item.Name === filterOptionName)?.CurrentValue), ); return parameters; diff --git a/imxweb/projects/qbm/src/lib/data-source-toolbar/data-tile-badge.interface.ts b/imxweb/projects/qbm/src/lib/data-source-toolbar/data-tile-badge.interface.ts index 6a2b27d53..df4a033d0 100644 --- a/imxweb/projects/qbm/src/lib/data-source-toolbar/data-tile-badge.interface.ts +++ b/imxweb/projects/qbm/src/lib/data-source-toolbar/data-tile-badge.interface.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -28,7 +28,6 @@ * Defines badge properties, that can be used to add a badge to a {@link DataTileComponent | data tile} */ export interface DataTileBadge { - /** * The text of a badge */ diff --git a/imxweb/projects/qbm/src/lib/data-source-toolbar/filter-tree/filter-tree-database.ts b/imxweb/projects/qbm/src/lib/data-source-toolbar/filter-tree/filter-tree-database.ts index 4d58c6a71..fe845421d 100644 --- a/imxweb/projects/qbm/src/lib/data-source-toolbar/filter-tree/filter-tree-database.ts +++ b/imxweb/projects/qbm/src/lib/data-source-toolbar/filter-tree/filter-tree-database.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -26,34 +26,32 @@ import { EuiLoadingService } from '@elemental-ui/core'; -import { CollectionLoadParameters, FilterTreeData, IEntity } from 'imx-qbm-dbts'; +import { CollectionLoadParameters, FilterTreeData, IEntity } from '@imx-modules/imx-qbm-dbts'; import { TreeDatabase } from '../../data-tree/tree-database'; import { TreeNode } from '../../data-tree/tree-node'; import { TreeNodeResultParameter } from '../../data-tree/tree-node-result-parameter.interface'; import { FilterTreeEntityWrapperService } from './filter-tree-entity-wrapper.service'; export class FilterTreeDatabase extends TreeDatabase { - - constructor( private readonly entityWrapper: FilterTreeEntityWrapperService, private readonly getFilterTree: (parentkey: string) => Promise, - private readonly busyLoadingService: EuiLoadingService + private readonly busyLoadingService: EuiLoadingService, ) { super(); } public async getData(showLoading: boolean, parameters: CollectionLoadParameters = {}): Promise { let entities: IEntity[]; - if (showLoading) { - setTimeout(() => this.busyLoadingService.show()); + if (showLoading && this.busyLoadingService.overlayRefs.length === 0) { + this.busyLoadingService.show(); } try { - entities = this.entityWrapper.convertToEntities(await this.getFilterTree(parameters.ParentKey), parameters['parentDisplay']); + entities = this.entityWrapper.convertToEntities(await this.getFilterTree(parameters.ParentKey ?? ''), parameters['parentDisplay']); } finally { if (showLoading) { - setTimeout(() => this.busyLoadingService.hide()); + this.busyLoadingService.hide(); } } @@ -61,19 +59,23 @@ export class FilterTreeDatabase extends TreeDatabase { } /** return children for a given tree node including the information, if more elements are available on the server */ - public async getChildren(node: TreeNode, startIndex: number) - : Promise<{ nodes: TreeNode[], canLoadMore: boolean }> { - - const entities = await this.getData(false, { ParentKey: node.name, StartIndex: startIndex, parentDisplay: node.item.GetColumn('LongDisplay').GetValue() }); + public async getChildren(node: TreeNode, startIndex: number): Promise<{ nodes: TreeNode[]; canLoadMore: boolean }> { + const entities = await this.getData(false, { + ParentKey: node.name, + StartIndex: startIndex, + parentDisplay: node.item?.GetColumn('LongDisplay').GetValue(), + }); const nodes = this.createSortedNodes(entities.entities, node.level + 1); return { - nodes: entities.entities.map(entity => nodes.find(x => this.getId(x.item) === this.getId(entity))), - canLoadMore: entities.canLoadMore + nodes: entities.entities + .map((entity) => nodes.find((x) => this.getId(x?.item) === this.getId(entity)) ?? new TreeNode()) + .filter((elem) => elem?.identifier != null), + canLoadMore: entities.canLoadMore, }; } - public getId(entity: IEntity): string { - return entity.GetColumn('ObjectKey').GetValue(); + public getId(entity: IEntity | undefined): string { + return entity?.GetColumn('ObjectKey')?.GetValue() ?? ''; } } diff --git a/imxweb/projects/qbm/src/lib/data-source-toolbar/filter-tree/filter-tree-entity-wrapper.service.ts b/imxweb/projects/qbm/src/lib/data-source-toolbar/filter-tree/filter-tree-entity-wrapper.service.ts index 1bda0be53..b716d8882 100644 --- a/imxweb/projects/qbm/src/lib/data-source-toolbar/filter-tree/filter-tree-entity-wrapper.service.ts +++ b/imxweb/projects/qbm/src/lib/data-source-toolbar/filter-tree/filter-tree-entity-wrapper.service.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -25,16 +25,26 @@ */ import { Injectable } from '@angular/core'; -import { DisplayBuilder, DisplayPattern, EntityColumnData, EntityData, EntitySchema, FilterTreeData, FilterTreeElement, IClientProperty, IEntity, ReadWriteEntity, ValType } from 'imx-qbm-dbts'; +import { + DisplayBuilder, + DisplayPattern, + EntityColumnData, + EntityData, + EntitySchema, + FilterTreeData, + FilterTreeElement, + IClientProperty, + IEntity, + ReadWriteEntity, + ValType, +} from '@imx-modules/imx-qbm-dbts'; import { ImxTranslationProviderService } from '../../translation/imx-translation-provider.service'; @Injectable({ - providedIn: 'root' + providedIn: 'root', }) export class FilterTreeEntityWrapperService { - constructor( - private readonly translate: ImxTranslationProviderService - ) { } + constructor(private readonly translate: ImxTranslationProviderService) {} /** * Converts a list of FilterTreeData objects into a list or correlating entities @@ -42,7 +52,7 @@ export class FilterTreeEntityWrapperService { * @returns a list of entity objects */ public convertToEntities(data: FilterTreeData, parentDisplay: string): IEntity[] { - return data.Elements.map(filter => this.buildTreeFilterDataEntity(filter, parentDisplay)); + return data?.Elements?.map((filter) => this.buildTreeFilterDataEntity(filter, parentDisplay)) ?? []; } private buildTreeFilterDataEntity(data: FilterTreeElement, parentDisplay: string): IEntity { @@ -51,7 +61,7 @@ export class FilterTreeEntityWrapperService { this.buildEntityData(data, parentDisplay), undefined, undefined, - new DisplayBuilder(this.translate) + new DisplayBuilder(this.translate), ); } @@ -60,32 +70,32 @@ export class FilterTreeEntityWrapperService { ret['Display'] = { Type: ValType.String, - ColumnName: 'Display' + ColumnName: 'Display', }; ret['Filter'] = { Type: ValType.String, - ColumnName: 'Filter' + ColumnName: 'Filter', }; ret['HasChildren'] = { Type: ValType.Bool, - ColumnName: 'HasChildren' + ColumnName: 'HasChildren', }; ret['ObjectKey'] = { Type: ValType.String, - ColumnName: 'ObjectKey' + ColumnName: 'ObjectKey', }; ret['LongDisplay'] = { Type: ValType.String, - ColumnName: 'LongDisplay' + ColumnName: 'LongDisplay', }; return { DisplayPattern: new DisplayPattern('%Display%'), - Columns: ret + Columns: ret, }; } @@ -102,10 +112,9 @@ export class FilterTreeEntityWrapperService { ret['LongDisplay'] = { Value: (parentDisplay || '') === '' ? data.Display : `${parentDisplay}\\${data.Display}`, - IsReadOnly: true + IsReadOnly: true, }; return { Columns: ret, Keys: [JSON.stringify(data.Filter)] }; } } - diff --git a/imxweb/projects/qbm/src/lib/data-source-toolbar/filter-tree/filter-tree-selection-arg.interface.ts b/imxweb/projects/qbm/src/lib/data-source-toolbar/filter-tree/filter-tree-selection-arg.interface.ts index 587151377..ef0bfca11 100644 --- a/imxweb/projects/qbm/src/lib/data-source-toolbar/filter-tree/filter-tree-selection-arg.interface.ts +++ b/imxweb/projects/qbm/src/lib/data-source-toolbar/filter-tree/filter-tree-selection-arg.interface.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -24,22 +24,14 @@ * */ -import { FilterData, IEntity } from 'imx-qbm-dbts'; +import { FilterData, IEntity } from '@imx-modules/imx-qbm-dbts'; +import { FilterTreeSelectionParameter } from '../filter-wizard/filter-tree-sidesheet/filter-tree-sidesheet.model'; /** * Provides information for the selection of a filter tree. * It is used to unify the information, that is provided by the tree and a loaded configuration */ -export interface FilterTreeSelectionArg { - /** - * The text, that is displayed on chips. - */ - display: string; - /** - * The real filter information. - */ - filter: FilterData; - +export interface FilterTreeSelectionArg extends FilterTreeSelectionParameter { /** * An optional entity, that is used for data */ diff --git a/imxweb/projects/qbm/src/lib/data-source-toolbar/filter-tree/filter-tree.component.html b/imxweb/projects/qbm/src/lib/data-source-toolbar/filter-tree/filter-tree.component.html index ebc6c4145..5e53055ff 100644 --- a/imxweb/projects/qbm/src/lib/data-source-toolbar/filter-tree/filter-tree.component.html +++ b/imxweb/projects/qbm/src/lib/data-source-toolbar/filter-tree/filter-tree.component.html @@ -1,38 +1,72 @@ -

    {{'#LDS#Narrow the selection further down by: {0}' | translate |ldsReplace:data.type}}

    +

    {{ '#LDS#Narrow the selection further down by: {0}' | translate | ldsReplace: data.type }}

    - + - -
    - {{'#LDS#Selected item' |translate}}: - {{currentlySelectedFilter[0].display}} + +
    + {{ '#LDS#Selected item' | translate }}: + {{ currentlySelectedFilter[0]?.display }}
    - -
    -
    - +
    - {{filterElement.display}} + {{ filterElement?.display }}
    diff --git a/imxweb/projects/qbm/src/lib/data-source-toolbar/filter-tree/filter-tree.component.scss b/imxweb/projects/qbm/src/lib/data-source-toolbar/filter-tree/filter-tree.component.scss index 3f0f1c3c7..5d9688d4a 100644 --- a/imxweb/projects/qbm/src/lib/data-source-toolbar/filter-tree/filter-tree.component.scss +++ b/imxweb/projects/qbm/src/lib/data-source-toolbar/filter-tree/filter-tree.component.scss @@ -1,29 +1,20 @@ -@import "@elemental-ui/core/src/styles/_palette.scss"; +@import '@elemental-ui/core/src/styles/_palette.scss'; @import '@elemental-ui/core/src/styles/_eui_palette.scss'; +@import 'base/mixins'; :host { - display: flex; - flex-direction: column; - flex: 1 1 auto; - overflow: hidden; + @include flex-column-container-fill; height: 100%; - ::ng-deep .mat-list-base { - .mat-list-item.imx-list-item { - height: auto; - } - } - - ::ng-deep .mat-menu-panel { + ::ng-deep .mat-mdc-menu-panel { padding: 10px; max-width: 500px; } } .imx-dialog-content { + @include flex-column-container(); flex: 1 1 auto; - display: flex; - flex-direction: column; } .imx-filtertree-buttons { @@ -38,7 +29,6 @@ } } - .imx-badge { background-color: $white; } @@ -50,7 +40,7 @@ .imx-selected-item-element { margin: 5px 0; } -.mat-dialog-actions{ +.mat-mdc-dialog-actions { padding-bottom: 16px; } diff --git a/imxweb/projects/qbm/src/lib/data-source-toolbar/filter-tree/filter-tree.component.ts b/imxweb/projects/qbm/src/lib/data-source-toolbar/filter-tree/filter-tree.component.ts index d8fdaa096..5b4acea51 100644 --- a/imxweb/projects/qbm/src/lib/data-source-toolbar/filter-tree/filter-tree.component.ts +++ b/imxweb/projects/qbm/src/lib/data-source-toolbar/filter-tree/filter-tree.component.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -25,10 +25,10 @@ */ import { ChangeDetectorRef, Component, Inject, OnInit, ViewChild } from '@angular/core'; -import { MatDialogRef, MAT_DIALOG_DATA } from '@angular/material/dialog'; +import { MAT_DIALOG_DATA, MatDialogRef } from '@angular/material/dialog'; import { EuiLoadingService } from '@elemental-ui/core'; -import { FilterTreeData, IEntity } from 'imx-qbm-dbts'; +import { IEntity } from '@imx-modules/imx-qbm-dbts'; import { DataTreeComponent } from '../../data-tree/data-tree.component'; import { TreeDatabase } from '../../data-tree/tree-database'; import { FilterTreeParameter } from '../data-model/filter-tree-parameter'; @@ -42,9 +42,9 @@ import { FilterTreeDialogResultArg, FilterTreeSelectionArg } from './filter-tree styleUrls: ['./filter-tree.component.scss'], }) export class FilterTreeComponent implements OnInit { - public database: TreeDatabase; - public currentlySelectedFilter: FilterTreeSelectionArg[]; - public currentlySelectedFilterEntities: IEntity[]; + public database: TreeDatabase | undefined; + public currentlySelectedFilter: (FilterTreeSelectionArg | undefined)[]; + public currentlySelectedFilterEntities: (IEntity | undefined)[]; @ViewChild('tree') private tree: DataTreeComponent; constructor( @@ -53,7 +53,7 @@ export class FilterTreeComponent implements OnInit { public readonly data: { filterTreeParameter: FilterTreeParameter; preselection: FilterTreeSelectionArg[]; type: string }, public dialogRef: MatDialogRef, public changeDetector: ChangeDetectorRef, - private readonly entityWrapper: FilterTreeEntityWrapperService + private readonly entityWrapper: FilterTreeEntityWrapperService, ) {} public async ngOnInit(): Promise { @@ -64,7 +64,7 @@ export class FilterTreeComponent implements OnInit { } if (this.data?.preselection) { this.currentlySelectedFilter = this.data.preselection; - this.currentlySelectedFilterEntities = this.currentlySelectedFilter.map(elem=> elem.entity).filter(elem=>elem != null); + this.currentlySelectedFilterEntities = this.currentlySelectedFilter.map((elem) => elem?.entity).filter((elem) => elem != null); this.changeDetector.detectChanges(); } } @@ -78,7 +78,7 @@ export class FilterTreeComponent implements OnInit { if (!this.data.filterTreeParameter.multiSelect) { return; } - this.currentlySelectedFilter = this.tree.selectedEntities.map((elem) => new FilterTreeDialogResultArg(elem)); + this.currentlySelectedFilter = this.tree.selectedEntities.map((elem) => (elem ? new FilterTreeDialogResultArg(elem) : undefined)); } public onNodeSelected(entity: IEntity): void { diff --git a/imxweb/projects/qbm/src/lib/data-source-toolbar/filter-wizard/filter-tree-sidesheet/filter-tree-sidesheet.component.html b/imxweb/projects/qbm/src/lib/data-source-toolbar/filter-wizard/filter-tree-sidesheet/filter-tree-sidesheet.component.html new file mode 100644 index 000000000..2597b6e66 --- /dev/null +++ b/imxweb/projects/qbm/src/lib/data-source-toolbar/filter-wizard/filter-tree-sidesheet/filter-tree-sidesheet.component.html @@ -0,0 +1,36 @@ +
    +
    +

    + {{ '#LDS#Selected item' | translate }}: + {{ currentlySelectedFilter?.display ?? '-' }} +

    + +
    + +
    + + +
    + + {{ node.nodeDisplay }} +
    +
    diff --git a/imxweb/projects/qbm/src/lib/data-source-toolbar/filter-wizard/filter-tree-sidesheet/filter-tree-sidesheet.component.scss b/imxweb/projects/qbm/src/lib/data-source-toolbar/filter-wizard/filter-tree-sidesheet/filter-tree-sidesheet.component.scss new file mode 100644 index 000000000..9514d2314 --- /dev/null +++ b/imxweb/projects/qbm/src/lib/data-source-toolbar/filter-wizard/filter-tree-sidesheet/filter-tree-sidesheet.component.scss @@ -0,0 +1,90 @@ +@import '@elemental-ui/core/src/styles/_palette.scss'; +@import '@elemental-ui/core/src/styles/_eui_palette.scss'; +@import 'base/mixins'; + +:host { + @include flex-column-container-fill(); + height: 100%; + + .imx-bold-text { + font-weight: 900; + vertical-align: sub; + } + + .imx-filter-sheet { + display: flex; + flex-direction: column; + overflow: hidden; + height: inherit; + } + + .imx-tree-control { + @include flex-row-container-fill(); + } + + .imx-top-line { + @include flex-row-container-fill(); + overflow: hidden; + align-items: center; + p { + flex: 1 1 auto; + overflow: hidden; + + @include flex-row-container-fill(); + span { + vertical-align: middle; + text-wrap: nowrap; + } + + span[boldtext] { + font-weight: 700; + margin-right: 10px; + } + + span[content] { + white-space: nowrap; + overflow: hidden; + text-overflow: ellipsis; + } + } + } +} + +:host { + .imx-filter-tree-node.imx-selected-text { + color: $color-orange-60; + .eui-icon { + color: $color-orange-60; + } + } +} + +.eui-dark-theme { + :host { + .imx-filter-tree-node { + color: $color-gray-0; + } + + .imx-filter-tree-node.imx-selected-text { + color: $color-orange-40; + .eui-icon { + color: $color-orange-40; + } + } + } +} + +.eui-contrast-theme { + :host { + .imx-filter-tree-node { + color: $color-gray-0; + } + + .imx-filter-tree-node.imx-selected-text { + color: $color-orange-80; + .eui-icon { + color: $color-orange-80; + } + } + } +} diff --git a/imxweb/projects/qbm/src/lib/data-source-toolbar/filter-wizard/filter-tree-sidesheet/filter-tree-sidesheet.component.ts b/imxweb/projects/qbm/src/lib/data-source-toolbar/filter-wizard/filter-tree-sidesheet/filter-tree-sidesheet.component.ts new file mode 100644 index 000000000..0a92a2a35 --- /dev/null +++ b/imxweb/projects/qbm/src/lib/data-source-toolbar/filter-wizard/filter-tree-sidesheet/filter-tree-sidesheet.component.ts @@ -0,0 +1,124 @@ +/* + * ONE IDENTITY LLC. PROPRIETARY INFORMATION + * + * This software is confidential. One Identity, LLC. or one of its affiliates or + * subsidiaries, has supplied this software to you under terms of a + * license agreement, nondisclosure agreement or both. + * + * You may not copy, disclose, or use this software except in accordance with + * those terms. + * + * + * Copyright 2024 One Identity LLC. + * ALL RIGHTS RESERVED. + * + * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR + * WARRANTIES ABOUT THE SUITABILITY OF THE SOFTWARE, + * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED + * TO THE IMPLIED WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE, OR + * NON-INFRINGEMENT. ONE IDENTITY LLC. SHALL NOT BE + * LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE + * AS A RESULT OF USING, MODIFYING OR DISTRIBUTING + * THIS SOFTWARE OR ITS DERIVATIVES. + * + */ + +import { Component, EventEmitter, Input, OnInit, Output } from '@angular/core'; + +import { FlatTreeControl } from '@angular/cdk/tree'; +import _ from 'lodash'; +import { DynamicDataApiControls, DynamicDataSource } from '../../../sidenav-tree/sidenav-tree-dynamic-extension'; +import { FilterTreeNode, FilterTreeParameterData, FilterTreeSelectionParameter } from './filter-tree-sidesheet.model'; +@Component({ + selector: 'imx-filter-tree-sidesheet', + templateUrl: './filter-tree-sidesheet.component.html', + styleUrls: ['./filter-tree-sidesheet.component.scss'], +}) +export class FilterTreeSidesheetComponent implements OnInit { + public currentlySelectedFilter: FilterTreeSelectionParameter; + @Input() public data: FilterTreeParameterData; + @Output() public filterTreeSelectionChanged = new EventEmitter(); + + public hasChild = (_: number, node: FilterTreeNode) => node.hasChildren; + private isInitial = true; + + public apiControls: DynamicDataApiControls; + public dynamicDataSource: DynamicDataSource; + public treeControl: FlatTreeControl; + public selectFn = (node: FilterTreeNode) => + node.isSelected || + (this.data?.preSelection?.display === node.nodeDisplay && + _.isEqual(this.data?.preSelection?.filter, node?.filterData) && + this.isInitial); + + public isLoading = (node: FilterTreeNode) => node.isLoading || false; + + constructor() { + this.treeControl = new FlatTreeControl( + (leaf) => leaf.level, + (leaf) => leaf.hasChildren, + ); + + this.apiControls = { + setup: async () => { + const items = await this.data.filterTreeParameter.filterMethode(''); + const rootNode: FilterTreeNode = { + level: 0, + nodeDisplay: items.Description ?? '', + hasChildren: true, + objectKey: '', + children: + items.Elements?.map((elem) => ({ + filterData: elem.Filter, + nodeDisplay: elem.Display ?? '', + hasChildren: elem.HasHierarchy ?? false, + objectKey: elem.ObjectKey, + level: 1, + })) ?? [], + }; + return { rootNode }; + }, + getChildren: async (node) => { + node.isLoading = true; + const items = await this.data.filterTreeParameter.filterMethode(node.objectKey ?? ''); + node.isLoading = false; + return ( + items.Elements?.map((elem) => ({ + filterData: elem.Filter, + nodeDisplay: elem.Display ?? '', + hasChildren: elem.HasHierarchy ?? false, + objectKey: elem.ObjectKey, + level: node.level + 1, + })) ?? [] + ); + }, + changeSelection: (data, selectedNode) => { + data.forEach((elem) => (elem.isSelected = false)); + selectedNode.isSelected = true; + this.isInitial = false; + return data; + }, + }; + + this.dynamicDataSource = new DynamicDataSource(this.treeControl, this.apiControls); + } + + public async ngOnInit(): Promise { + this.currentlySelectedFilter = this.data.preSelection; + await this.dynamicDataSource.setup(true); + const current = this.dynamicDataSource.data.find((node) => node.nodeDisplay === this.data.preSelection?.display); + if (current) { + this.dynamicDataSource.setSelection(current); + } + } + + public onSelectedNodeChanged(node: FilterTreeNode) { + this.currentlySelectedFilter = { display: node.nodeDisplay, filter: node.filterData }; + this.filterTreeSelectionChanged.emit({ display: node.nodeDisplay, filter: node.filterData }); + } + + public closeAllNodes(): void { + this.treeControl.collapseAll(); + } +} diff --git a/imxweb/projects/qbm/src/lib/data-source-toolbar/filter-wizard/filter-tree-sidesheet/filter-tree-sidesheet.model.ts b/imxweb/projects/qbm/src/lib/data-source-toolbar/filter-wizard/filter-tree-sidesheet/filter-tree-sidesheet.model.ts new file mode 100644 index 000000000..da0753e50 --- /dev/null +++ b/imxweb/projects/qbm/src/lib/data-source-toolbar/filter-wizard/filter-tree-sidesheet/filter-tree-sidesheet.model.ts @@ -0,0 +1,109 @@ +/* + * ONE IDENTITY LLC. PROPRIETARY INFORMATION + * + * This software is confidential. One Identity, LLC. or one of its affiliates or + * subsidiaries, has supplied this software to you under terms of a + * license agreement, nondisclosure agreement or both. + * + * You may not copy, disclose, or use this software except in accordance with + * those terms. + * + * + * Copyright 2024 One Identity LLC. + * ALL RIGHTS RESERVED. + * + * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR + * WARRANTIES ABOUT THE SUITABILITY OF THE SOFTWARE, + * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED + * TO THE IMPLIED WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE, OR + * NON-INFRINGEMENT. ONE IDENTITY LLC. SHALL NOT BE + * LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE + * AS A RESULT OF USING, MODIFYING OR DISTRIBUTING + * THIS SOFTWARE OR ITS DERIVATIVES. + * + */ + +import { FilterData } from '@imx-modules/imx-qbm-dbts'; +import { FilterTreeParameter } from '../../data-model/filter-tree-parameter'; + +/** + * Provides information for the selection of a filter tree. + * It is used to unify the information, that is provided by the tree and a loaded configuration + */ +export interface FilterTreeSelectionParameter { + /** + * The text, that is displayed on chips. + */ + display?: string; + /** + * The real filter information. + */ + filter?: FilterData; +} + +/** + * Provides the information, that are used to describe a tree node in a + * {@link FilterTreeSidesheetComponent | filter tree side sheet component } + */ +export interface FilterTreeNode { + /** + * the level of the node + */ + level: number; + + /** + * Represents, whether the node has children or not. + */ + hasChildren: boolean; + + /** + * Represents the display of the node + */ + nodeDisplay: string; + + /** + * Represents the filter data, associated with the node. + */ + filterData?: FilterData; + + /** + * Represents the children of the tree node + */ + children?: FilterTreeNode[]; + + /** + * Represents an object key, that can be used, to identify the node. + */ + objectKey?: string; + + /** + * Represents, whether the node is loading or not + */ + isLoading?: boolean; + + /** + * Represents, whether the node is shown as selected or not + */ + isSelected?: boolean; +} + +/** + * Provides information for the filter tree sidesheet component + */ +export interface FilterTreeParameterData { + /** + * The parameter, that contains the filter method and other options. + */ + filterTreeParameter: FilterTreeParameter; + + /** + * A list of preselected elements + */ + preSelection: FilterTreeSelectionParameter; + + /** + * the type of the tree filter + */ + type: string; +} diff --git a/imxweb/projects/qbm/src/lib/data-source-toolbar/filter-wizard/filter-wizard.component.html b/imxweb/projects/qbm/src/lib/data-source-toolbar/filter-wizard/filter-wizard.component.html index 5a46cf50f..fac7d844c 100644 --- a/imxweb/projects/qbm/src/lib/data-source-toolbar/filter-wizard/filter-wizard.component.html +++ b/imxweb/projects/qbm/src/lib/data-source-toolbar/filter-wizard/filter-wizard.component.html @@ -1,42 +1,77 @@
    - + - - + + +
    -
    - -
    - - - - - + + + + + + + + + +
    + + {{ '#LDS#You do not have permission to show filters.' | translate }} + +
    +
    + + +
    - + diff --git a/imxweb/projects/qbm/src/lib/data-source-toolbar/filter-wizard/filter-wizard.component.scss b/imxweb/projects/qbm/src/lib/data-source-toolbar/filter-wizard/filter-wizard.component.scss index a5eaa7cdd..3bf390496 100644 --- a/imxweb/projects/qbm/src/lib/data-source-toolbar/filter-wizard/filter-wizard.component.scss +++ b/imxweb/projects/qbm/src/lib/data-source-toolbar/filter-wizard/filter-wizard.component.scss @@ -1,6 +1,9 @@ :host { .imx-sidesheet-content { overflow: hidden; + padding: 0px; + display: flex; + flex-direction: column; .imx-content-container { display: flex; @@ -8,6 +11,8 @@ row-gap: 10px; overflow: hidden; height: 100%; + padding:20px; + margin: 20px; } } @@ -24,19 +29,21 @@ align-items: center; } - .mat-tab-group { - height: 100%; - } - - ::ng-deep .mat-tab-body-wrapper { - padding: 0 10px; - height: 100%; + .imx-no-items-container { + flex: 1 1 auto; } } + imx-sqlwizard { overflow: hidden; flex-grow: 1; display: flex; flex-direction: column; } + +imx-busy-indicator { + flex: 1 1 auto; + justify-content: center; + align-items: center; +} diff --git a/imxweb/projects/qbm/src/lib/data-source-toolbar/filter-wizard/filter-wizard.component.ts b/imxweb/projects/qbm/src/lib/data-source-toolbar/filter-wizard/filter-wizard.component.ts index 8882d6f2c..9deb18441 100644 --- a/imxweb/projects/qbm/src/lib/data-source-toolbar/filter-wizard/filter-wizard.component.ts +++ b/imxweb/projects/qbm/src/lib/data-source-toolbar/filter-wizard/filter-wizard.component.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -24,28 +24,30 @@ * */ -import { Component, Inject, OnDestroy } from '@angular/core'; -import { EuiSidesheetRef, EuiSidesheetService, EUI_SIDESHEET_DATA } from '@elemental-ui/core'; +import { Component, Inject, OnDestroy, OnInit } from '@angular/core'; +import { MatTabChangeEvent } from '@angular/material/tabs'; +import { EUI_SIDESHEET_DATA, EuiSidesheetRef, EuiSidesheetService } from '@elemental-ui/core'; +import { LogOp, SqlExpression, SqlWizardExpression, isExpressionInvalid } from '@imx-modules/imx-qbm-dbts'; import { TranslateService } from '@ngx-translate/core'; -import { isExpressionInvalid, LogOp, SqlExpression, SqlWizardExpression } from 'imx-qbm-dbts'; import _ from 'lodash'; import { Subscription } from 'rxjs/internal/Subscription'; +import { BusyService } from '../../base/busy.service'; import { ConfirmationService } from '../../confirmation/confirmation.service'; -import { FilterWizardService } from './filter-wizard.service'; -import { FilterFormState, FilterTypeIdentifier, FilterWizardSidesheetData } from './filter-wizard.interfaces'; -import { MatTabChangeEvent } from '@angular/material/tabs'; import { SqlWizardApiService } from '../../sqlwizard/sqlwizard-api.service'; - +import { FilterTreeSelectionParameter } from './filter-tree-sidesheet/filter-tree-sidesheet.model'; +import { FilterFormState, FilterTypeIdentifier, FilterWizardSidesheetData } from './filter-wizard.interfaces'; +import { FilterWizardService } from './filter-wizard.service'; @Component({ selector: 'imx-filter-wizard', templateUrl: './filter-wizard.component.html', styleUrls: ['./filter-wizard.component.scss'], }) -export class FilterWizardComponent implements OnDestroy { +export class FilterWizardComponent implements OnInit, OnDestroy { public sqlExpression: SqlWizardExpression; - public lastGoodExpression: SqlExpression; + public lastGoodExpression: SqlExpression | undefined; public expressionDirty = false; public expressionInvalid = true; + public treeFilterUpdated = false; public selectedTabIndex = 0; public formState: FilterFormState = { canClearFilters: false, dirty: false, filterIdentifier: FilterTypeIdentifier.Predefined }; public readonly FilterTypeIdentifier: FilterTypeIdentifier; @@ -53,18 +55,28 @@ export class FilterWizardComponent implements OnDestroy { public readonly FTICustom = FilterTypeIdentifier.Custom; public readonly FTITargetSystem = FilterTypeIdentifier.TargetSystem; + private busyService = new BusyService(); + private readonly subscriptions: Subscription[] = []; private confirmLeaveTitle = ''; private confirmLeaveMessage = ''; + private hasProperties: boolean = false; + public initialized = false; + public isLoading = false; + public hasTreeFilter = false; + private treeFilterArgs: FilterTreeSelectionParameter | undefined; + private readonly emptyExpression = { Expression: { Expressions: [ { Expressions: [], LogOperator: LogOp.AND, + Negate: false, }, ], LogOperator: LogOp.AND, + Negate: false, }, }; @@ -75,7 +87,7 @@ export class FilterWizardComponent implements OnDestroy { private readonly filterService: FilterWizardService, public readonly sqlWizardSvc: SqlWizardApiService, readonly translation: TranslateService, - @Inject(EUI_SIDESHEET_DATA) public data?: FilterWizardSidesheetData + @Inject(EUI_SIDESHEET_DATA) public data?: FilterWizardSidesheetData, ) { translation.get('#LDS#Heading Cancel Filtering').subscribe((value: string) => (this.confirmLeaveTitle = value)); translation @@ -88,32 +100,51 @@ export class FilterWizardComponent implements OnDestroy { this.lastGoodExpression = _.cloneDeep(this.sqlExpression?.Expression); this.sidesheetRef.closeClicked().subscribe(() => this.close()); - this.expressionInvalid = data?.filterExpression && isExpressionInvalid(this.sqlExpression); + this.expressionInvalid = (data?.filterExpression && isExpressionInvalid(this.sqlExpression)) == true; + + this.treeFilterArgs = data?.filterTreeParameter?.preSelection; this.subscriptions.push( this.filterService.filterFormStateEvent.subscribe((formState: FilterFormState) => { setTimeout(() => (this.formState = formState)); - }) + }), ); + + this.subscriptions.push(this.busyService.busyStateChanged.subscribe((state) => (this.isLoading = state))); + } + + public async ngOnInit(): Promise { + const busy = this.busyService.beginBusy(); + try { + const columns = await this.sqlWizardSvc.getFilterProperties(this.data?.settings?.entitySchema?.TypeName ?? ''); + this.hasProperties = columns?.length > 0; + this.initialized = true; + + this.hasTreeFilter = + this.data?.filterTreeParameter?.filterTreeParameter != null && + !!(await this.data.filterTreeParameter.filterTreeParameter.filterMethode(''))?.Elements?.length; + } finally { + busy.endBusy(); + } } public get hasPredefinedFilters(): boolean { - return this.data.settings?.filters?.length > 0; + return !!this.data?.settings?.filters?.length; } public get canUseCustomFilters(): boolean { - return !this.data.isDataSourceLocal && this.showSqlWizard; + return !this.data?.isDataSourceLocal && this.hasProperties && this.showSqlWizard; } /** * Counts if we have at least 2 tabs to show */ public get useTabs(): boolean { - return [this.hasPredefinedFilters, this.canUseCustomFilters].reduce((a, b) => a + (b ? 1 : 0), 0) > 1; + return [this.hasPredefinedFilters, this.canUseCustomFilters, this.hasTreeFilter].reduce((a, b) => a + (b ? 1 : 0), 0) > 1; } public ngOnDestroy(): void { - if (isExpressionInvalid(this.sqlExpression)) { + if (isExpressionInvalid(this.sqlExpression) && this.sqlExpression.Expression) { this.sqlExpression.Expression.Expressions = []; } @@ -128,35 +159,42 @@ export class FilterWizardComponent implements OnDestroy { public onApplyFilters(): void { this.filterService.applyFilters(); - this.sidesheetService.close(this.sqlExpression); + this.sidesheetService.close({ expression: this.sqlExpression, treeFilter: this.treeFilterArgs }); } public onClearFilters(): void { - this.lastGoodExpression = null; - this.sqlExpression.Expression.Expressions = []; + this.lastGoodExpression = undefined; + if (this.sqlExpression.Expression) { + this.sqlExpression.Expression.Expressions = []; + } this.filterService.clearFilters(); - this.sidesheetService.close(this.sqlExpression); + this.sidesheetService.close({ expression: this.sqlExpression, treeFilter: undefined }); } public onSelectedTabChange(event: MatTabChangeEvent): void { - this.filterService.filterTabChanged(event.tab.content.templateRef.elementRef.nativeElement.parentElement.id as FilterTypeIdentifier); + this.filterService.filterTabChanged(event.tab.content?.templateRef.elementRef.nativeElement.parentElement.id as FilterTypeIdentifier); + } + + public onFilterTreeSelectionChanged(event: FilterTreeSelectionParameter) { + this.treeFilterUpdated = true; + this.treeFilterArgs = event; } public canApplyCustomFilters(): boolean { - return (this.expressionDirty || this.formState?.dirty) && !this.expressionInvalid; + return (this.expressionDirty || this.formState?.dirty || this.treeFilterUpdated) && !this.expressionInvalid; } public canRemoveCustomFilter(): boolean { - return this.lastGoodExpression?.Expressions?.length > 0 || this.formState?.canClearFilters; + return !!this.lastGoodExpression?.Expressions?.length || this.formState?.canClearFilters; } public containsTargetSystemFilter(): boolean { let filters = this.data?.settings.filters; - return filters && filters.find((item) => item.Name === 'namespace') != null; + return (filters && filters.find((item) => item.Name === 'namespace') != null) ?? false; } public get showSqlWizard(): boolean { - return this.sqlWizardSvc.implemented; + return this.sqlWizardSvc.implemented ?? false; } private async close(): Promise { diff --git a/imxweb/projects/qbm/src/lib/data-source-toolbar/filter-wizard/filter-wizard.interfaces.ts b/imxweb/projects/qbm/src/lib/data-source-toolbar/filter-wizard/filter-wizard.interfaces.ts index 30029d387..2224163b7 100644 --- a/imxweb/projects/qbm/src/lib/data-source-toolbar/filter-wizard/filter-wizard.interfaces.ts +++ b/imxweb/projects/qbm/src/lib/data-source-toolbar/filter-wizard/filter-wizard.interfaces.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -24,9 +24,10 @@ * */ +import { SqlWizardExpression } from '@imx-modules/imx-qbm-dbts'; import { DataSourceToolbarSelectedFilter } from '../data-source-toolbar-filters.interface'; import { DataSourceToolbarSettings } from '../data-source-toolbar-settings'; -import { SqlWizardExpression } from 'imx-qbm-dbts'; +import { FilterTreeParameterData, FilterTreeSelectionParameter } from './filter-tree-sidesheet/filter-tree-sidesheet.model'; export interface FilterWizardSidesheetData { id: string; @@ -34,6 +35,7 @@ export interface FilterWizardSidesheetData { settings: DataSourceToolbarSettings; selectedFilters: DataSourceToolbarSelectedFilter[]; isDataSourceLocal: boolean; + filterTreeParameter: FilterTreeParameterData; } export interface FilterFormState { @@ -47,3 +49,8 @@ export enum FilterTypeIdentifier { Custom = 'Custom', TargetSystem = 'TargetSystem', } + +export interface FilterWizardResult { + expression: SqlWizardExpression; + treeFilter?: FilterTreeSelectionParameter; +} diff --git a/imxweb/projects/qbm/src/lib/data-source-toolbar/filter-wizard/filter-wizard.module.ts b/imxweb/projects/qbm/src/lib/data-source-toolbar/filter-wizard/filter-wizard.module.ts index ebb71bb5d..7e079d139 100644 --- a/imxweb/projects/qbm/src/lib/data-source-toolbar/filter-wizard/filter-wizard.module.ts +++ b/imxweb/projects/qbm/src/lib/data-source-toolbar/filter-wizard/filter-wizard.module.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -24,28 +24,30 @@ * */ -import { NgModule } from '@angular/core'; import { CommonModule } from '@angular/common'; +import { NgModule } from '@angular/core'; +import { FormsModule, ReactiveFormsModule } from '@angular/forms'; +import { MatCardModule } from '@angular/material/card'; import { MatFormFieldModule } from '@angular/material/form-field'; +import { MatListModule } from '@angular/material/list'; +import { MatMenuModule } from '@angular/material/menu'; +import { MatTabsModule } from '@angular/material/tabs'; +import { MatTooltipModule } from '@angular/material/tooltip'; import { EuiCoreModule, EuiMaterialModule } from '@elemental-ui/core'; import { TranslateModule } from '@ngx-translate/core'; +import { BusyIndicatorModule } from '../../busy-indicator/busy-indicator.module'; import { ClassloggerModule } from '../../classlogger/classlogger.module'; import { LdsReplaceModule } from '../../lds-replace/lds-replace.module'; -import { FilterWizardComponent } from './filter-wizard.component'; +import { CustomTreeControlComponent } from '../../sidenav-tree/custom-tree-control.component'; import { SqlWizardModule } from '../../sqlwizard/sqlwizard.module'; -import { MatCardModule } from '@angular/material/card'; -import { MatListModule } from '@angular/material/list'; -import { MatMenuModule } from '@angular/material/menu'; -import { MatTooltipModule } from '@angular/material/tooltip'; -import { MatTabsModule } from '@angular/material/tabs'; -import { PredefinedFilterComponent } from './predefined-filter/predefined-filter.component'; -import { PredefinedFilterTreeComponent } from './predefined-filter-tree/predefined-filter-tree.component'; -import { SidenavTreeModule } from '../../sidenav-tree/sidenav-tree.module'; -import { FormsModule, ReactiveFormsModule } from '@angular/forms'; import { DataSourceToolbarModule } from '../data-source-toolbar.module'; +import { FilterTreeSidesheetComponent } from './filter-tree-sidesheet/filter-tree-sidesheet.component'; +import { FilterWizardComponent } from './filter-wizard.component'; +import { PredefinedFilterTreeComponent } from './predefined-filter-tree/predefined-filter-tree.component'; +import { PredefinedFilterComponent } from './predefined-filter/predefined-filter.component'; @NgModule({ - declarations: [FilterWizardComponent, PredefinedFilterComponent, PredefinedFilterTreeComponent], + declarations: [FilterWizardComponent, PredefinedFilterComponent, PredefinedFilterTreeComponent, FilterTreeSidesheetComponent], imports: [ CommonModule, EuiCoreModule, @@ -62,8 +64,9 @@ import { DataSourceToolbarModule } from '../data-source-toolbar.module'; LdsReplaceModule, ClassloggerModule, SqlWizardModule, - SidenavTreeModule, - DataSourceToolbarModule + DataSourceToolbarModule, + BusyIndicatorModule, + CustomTreeControlComponent, ], exports: [FilterWizardComponent], }) diff --git a/imxweb/projects/qbm/src/lib/data-source-toolbar/filter-wizard/filter-wizard.service.ts b/imxweb/projects/qbm/src/lib/data-source-toolbar/filter-wizard/filter-wizard.service.ts index 91c92eb3a..8fa37b743 100644 --- a/imxweb/projects/qbm/src/lib/data-source-toolbar/filter-wizard/filter-wizard.service.ts +++ b/imxweb/projects/qbm/src/lib/data-source-toolbar/filter-wizard/filter-wizard.service.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -25,13 +25,13 @@ */ import { EventEmitter, Injectable } from '@angular/core'; -import { CollectionLoadParameters } from 'imx-qbm-dbts'; +import { CollectionLoadParameters } from '@imx-modules/imx-qbm-dbts'; +import { SqlWizardApiService } from '../../sqlwizard/sqlwizard-api.service'; import { DataSourceToolbarSelectedFilter } from '../data-source-toolbar-filters.interface'; import { FilterFormState, FilterTypeIdentifier } from './filter-wizard.interfaces'; -import { SqlWizardApiService } from '../../sqlwizard/sqlwizard-api.service'; @Injectable({ - providedIn: 'root' + providedIn: 'root', }) export class FilterWizardService { public navigationStateChanged = new EventEmitter(); @@ -40,10 +40,10 @@ export class FilterWizardService { public filterFormStateEvent = new EventEmitter(); public filterTabChangedEvent = new EventEmitter(); - constructor(public readonly sqlWizardSvc: SqlWizardApiService) { } + constructor(public readonly sqlWizardSvc: SqlWizardApiService) {} public get isSqlWizardImplemented(): boolean { - return this.sqlWizardSvc.implemented; + return this.sqlWizardSvc.implemented ?? false; } public updateNavigation(id: string, params: CollectionLoadParameters, selectedFilters: DataSourceToolbarSelectedFilter[]): void { @@ -68,7 +68,7 @@ export class FilterWizardService { } export interface selectedFiltersParams { - id: string; + id: string; params: CollectionLoadParameters; selectedFilters: DataSourceToolbarSelectedFilter[]; } diff --git a/imxweb/projects/qbm/src/lib/data-source-toolbar/filter-wizard/predefined-filter-tree/predefined-filter-tree.component.scss b/imxweb/projects/qbm/src/lib/data-source-toolbar/filter-wizard/predefined-filter-tree/predefined-filter-tree.component.scss index 7cf3dc515..53c91a73f 100644 --- a/imxweb/projects/qbm/src/lib/data-source-toolbar/filter-wizard/predefined-filter-tree/predefined-filter-tree.component.scss +++ b/imxweb/projects/qbm/src/lib/data-source-toolbar/filter-wizard/predefined-filter-tree/predefined-filter-tree.component.scss @@ -15,4 +15,3 @@ color: $color-orange-60; } } - diff --git a/imxweb/projects/qbm/src/lib/data-source-toolbar/filter-wizard/predefined-filter-tree/predefined-filter-tree.component.ts b/imxweb/projects/qbm/src/lib/data-source-toolbar/filter-wizard/predefined-filter-tree/predefined-filter-tree.component.ts index 84bf1a778..243cc850e 100644 --- a/imxweb/projects/qbm/src/lib/data-source-toolbar/filter-wizard/predefined-filter-tree/predefined-filter-tree.component.ts +++ b/imxweb/projects/qbm/src/lib/data-source-toolbar/filter-wizard/predefined-filter-tree/predefined-filter-tree.component.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -24,7 +24,7 @@ * */ -import { Component, Inject,OnInit } from '@angular/core'; +import { Component, Inject, OnInit } from '@angular/core'; import { FilterWizardSidesheetData } from '../filter-wizard.interfaces'; import { EUI_SIDESHEET_DATA } from '@elemental-ui/core'; @@ -34,10 +34,7 @@ import { EUI_SIDESHEET_DATA } from '@elemental-ui/core'; styleUrls: ['./predefined-filter-tree.component.scss'], }) export class PredefinedFilterTreeComponent implements OnInit { - constructor(@Inject(EUI_SIDESHEET_DATA) public data?: FilterWizardSidesheetData) {} - public async ngOnInit(): Promise { - } - + public async ngOnInit(): Promise {} } diff --git a/imxweb/projects/qbm/src/lib/data-source-toolbar/filter-wizard/predefined-filter/predefined-filter.component.html b/imxweb/projects/qbm/src/lib/data-source-toolbar/filter-wizard/predefined-filter/predefined-filter.component.html index 2f9606b86..f75dc2f62 100644 --- a/imxweb/projects/qbm/src/lib/data-source-toolbar/filter-wizard/predefined-filter/predefined-filter.component.html +++ b/imxweb/projects/qbm/src/lib/data-source-toolbar/filter-wizard/predefined-filter/predefined-filter.component.html @@ -1,35 +1,82 @@ - - - -

    {{ filter.Description || filter.Name }}

    - - {{ filter.Options[0].Display }} - - - + +
    + + + + {{ filter.Description || filter.Name }} - {{ fopt.Display }} - - - - - {{ foption.Display }} - - - - + + + +
    + + + + + + {{ filter.Options[0].Display }} + + + + {{ fopt.Display }} + + + + + + + {{ foption.Display }} + + + + diff --git a/imxweb/projects/qbm/src/lib/data-source-toolbar/filter-wizard/predefined-filter/predefined-filter.component.scss b/imxweb/projects/qbm/src/lib/data-source-toolbar/filter-wizard/predefined-filter/predefined-filter.component.scss index 82b5c7389..715211ba5 100644 --- a/imxweb/projects/qbm/src/lib/data-source-toolbar/filter-wizard/predefined-filter/predefined-filter.component.scss +++ b/imxweb/projects/qbm/src/lib/data-source-toolbar/filter-wizard/predefined-filter/predefined-filter.component.scss @@ -4,23 +4,27 @@ display: flex; flex-direction: column; row-gap: 10px; - padding: 10px 0 10px 0; + padding: 20px; + flex: 1 1 auto; - .mat-checkbox { + .mat-mdc-checkbox { display: block; } - .mat-radio-button { - display: block; - margin-right: 5px; + .imx-filter-title, + // Need to ng deep to overwrite elemental values, specificity wins still + .imx-filter-title ::ng-deep label.eui-label { + font-size: 16px; + font-weight: 600; + } - label.mat-radio-label { - white-space: normal; - } + .hidden { + display: none; } - .imx-filter-title { - font-size: 16px; - font-weight: 600; + imx-busy-indicator { + flex: 1 1 auto; + justify-content: center; + align-items: center; } } diff --git a/imxweb/projects/qbm/src/lib/data-source-toolbar/filter-wizard/predefined-filter/predefined-filter.component.ts b/imxweb/projects/qbm/src/lib/data-source-toolbar/filter-wizard/predefined-filter/predefined-filter.component.ts index db9b22506..33c6ed6b0 100644 --- a/imxweb/projects/qbm/src/lib/data-source-toolbar/filter-wizard/predefined-filter/predefined-filter.component.ts +++ b/imxweb/projects/qbm/src/lib/data-source-toolbar/filter-wizard/predefined-filter/predefined-filter.component.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -24,19 +24,28 @@ * */ -import { AfterViewInit, Component, EventEmitter, Inject, Input, NgZone, OnDestroy, OnInit, Output, QueryList, ViewChildren } from '@angular/core'; +import { AfterViewInit, Component, EventEmitter, Inject, Input, OnDestroy, OnInit, Output } from '@angular/core'; +import { FormControl } from '@angular/forms'; import { MatCheckboxChange } from '@angular/material/checkbox'; -import { MatSelectChange } from '@angular/material/select'; import { MatTableDataSource } from '@angular/material/table'; -import { EUI_SIDESHEET_DATA } from '@elemental-ui/core'; -import { CollectionLoadParameters, DataModelFilterOption, TypedEntity } from 'imx-qbm-dbts'; +import { EUI_SIDESHEET_DATA, EuiSelectFeedbackMessages, EuiSelectOption } from '@elemental-ui/core'; +import { CollectionLoadParameters, DataModelFilterOption, TypedEntity } from '@imx-modules/imx-qbm-dbts'; +import { TranslateService } from '@ngx-translate/core'; +import * as _ from 'lodash'; import { Subscription } from 'rxjs/internal/Subscription'; import { DataSourceToolbarFilter, DataSourceToolbarSelectedFilter } from '../../data-source-toolbar-filters.interface'; import { DataSourceToolbarSettings } from '../../data-source-toolbar-settings'; import { DSTViewConfig } from '../../data-source-toolbar-view-config.interface'; import { FilterFormState, FilterTypeIdentifier, FilterWizardSidesheetData } from '../filter-wizard.interfaces'; import { FilterWizardService } from '../filter-wizard.service'; -import * as _ from 'lodash'; + +enum FilterTypes { + SingleCheck, + MultiCheck, + SelectCheck, + MultiRadio, + SelectRadio, +} @Component({ selector: 'imx-predefined-filter', templateUrl: './predefined-filter.component.html', @@ -45,10 +54,10 @@ import * as _ from 'lodash'; export class PredefinedFilterComponent implements OnInit, AfterViewInit, OnDestroy { @Input() public settings: DataSourceToolbarSettings; - /** + /** * The DataSourceToolbar's ID generated in data-source-toolbar.component.ts */ - @Input() public id: string; + @Input() public id: string | undefined; /** * List of filter names that should be hidden @@ -103,6 +112,30 @@ export class PredefinedFilterComponent implements OnInit, AfterViewInit, OnDestr public filters: DataSourceToolbarFilter[] = []; + /** + * Holds a reference to the filter type enum for use in html + */ + public filterTypeEnum = FilterTypes; + + /** + * Mapping of the filters to their html element, currentValue control, and EUI options + */ + public filterTypes: { + type: FilterTypes | undefined; + currentValue: FormControl; + options: EuiSelectOption[]; + }[] = []; + + public feedbackMessages: EuiSelectFeedbackMessages; + + /** + * Method to handle searching over options + */ + public searchFunction = (option: EuiSelectOption, search: string): boolean => + option.display.toLocaleLowerCase().includes(search.toLocaleLowerCase()); + + public isLoading: boolean = true; + /** * This is the mat table datasource. */ @@ -112,6 +145,11 @@ export class PredefinedFilterComponent implements OnInit, AfterViewInit, OnDestr private formState: FilterFormState; private filterTypeIndentifier: FilterTypeIdentifier = FilterTypeIdentifier.Predefined; + /** + * Value to specify the cutoff between a multi-x to a select-x field + */ + private selectOptionThreshold = 5; + /** * @ignore Used internally. * Filters the data source with these arguments locally. @@ -127,29 +165,51 @@ export class PredefinedFilterComponent implements OnInit, AfterViewInit, OnDestr keywords: '', }; - constructor(private readonly filterService: FilterWizardService, @Inject(EUI_SIDESHEET_DATA) public data?: FilterWizardSidesheetData) { + constructor( + private readonly filterService: FilterWizardService, + private translateService: TranslateService, + @Inject(EUI_SIDESHEET_DATA) public data?: FilterWizardSidesheetData, + ) { // this.hiddenFilters = ['namespace']; - this.id = data.id; - this.settings = Object.create(data.settings); - this.selectedFilters = data.selectedFilters; - this.filters = _.cloneDeep(data.settings.filters); + this.id = data?.id; + this.settings = data?.settings ? Object.create(data.settings) : undefined; + this.selectedFilters = data?.selectedFilters ?? []; + this.filters = _.cloneDeep(data?.settings.filters) ?? []; + this.getFilterTypes(); this.internalSelectedFilters = Object.create(this.selectedFilters); this.formState = { canClearFilters: this.selectedFilters.length > 0, dirty: false, filterIdentifier: FilterTypeIdentifier.Predefined }; this.subscriptions.push( this.filterService.applyFiltersEvent.subscribe(() => { this.applyFilters(); - }) + }), ); this.subscriptions.push( this.filterService.clearFiltersEvent.subscribe(() => { this.clearFilters(); - }) + }), ); + + this.feedbackMessages = { + selected: this.translateService.instant('#LDS#{{value}} selected'), + clear: this.translateService.instant('#LDS#Clear selection'), + search: this.translateService.instant('#LDS#Search'), + plusOther: this.translateService.instant('#LDS#and 1 more'), + plusOtherPlural: this.translateService.instant('#LDS#and {{value}} more'), + unsupportedCharacter: this.translateService.instant('#LDS#You are using unsupported characters.'), + noResults: this.translateService.instant('#LDS#There is no data matching your search.'), + clearAll: this.translateService.instant('#LDS#Clear selection'), + ok: this.translateService.instant('#LDS#OK'), + keyboardOptionsListAria: this.translateService.instant('#LDS#Use the arrow keys to select items.'), + }; } public ngAfterViewInit(): void { + // workaround for UI problem -> panel is drawn as expanded before its got collapsed + setTimeout(() => { + this.isLoading = false; + }, 500); } public ngOnInit(): void { @@ -160,6 +220,44 @@ export class PredefinedFilterComponent implements OnInit, AfterViewInit, OnDestr this.subscriptions.forEach((s) => s.unsubscribe()); } + /** + * Creates a mapping of all the incoming filters, creates form controls and options for select-x fields + */ + public getFilterTypes(): void { + this.filterTypes = this.filters.map((filter) => ({ + type: this.determineFilterType(filter), + currentValue: filter?.Delimiter + ? new FormControl(filter?.CurrentValue?.split(filter.Delimiter) ?? []) + : new FormControl(filter?.CurrentValue), + options: + filter.Options?.map((option: DataModelFilterOption) => ({ + display: option.Display ?? '', + value: option.Value ?? '', + option: option, + })) ?? [], + })); + } + + /** + * Determines which field we want to show on screen + * @param filter current state of a filter + * @returns The specific enum to generate a html element + */ + public determineFilterType(filter: DataSourceToolbarFilter): FilterTypes | undefined { + switch (true) { + case filter?.Options?.length === 1: + return FilterTypes.SingleCheck; + case filter.Delimiter && (filter?.Options?.length ?? 0) <= this.selectOptionThreshold: + return FilterTypes.MultiCheck; + case filter.Delimiter && (filter?.Options?.length ?? 0) > this.selectOptionThreshold: + return FilterTypes.SelectCheck; + case !filter.Delimiter && (filter?.Options?.length ?? 0) <= this.selectOptionThreshold: + return FilterTypes.MultiRadio; + case !filter.Delimiter && (filter?.Options?.length ?? 0) > this.selectOptionThreshold: + return FilterTypes.SelectRadio; + } + } + public onCheckboxFilterChanged(filter: DataSourceToolbarFilter, option: DataModelFilterOption, event: MatCheckboxChange): void { let selectedFilterData: DataSourceToolbarSelectedFilter; if (event.checked) { @@ -169,7 +267,9 @@ export class PredefinedFilterComponent implements OnInit, AfterViewInit, OnDestr filter.CurrentValue = option.Value; } selectedFilterData = { selectedOption: option, filter }; - this.internalSelectedFilters.push(selectedFilterData); + if (this.internalSelectedFilters.every((filter) => filter.filter?.Name !== selectedFilterData.filter?.Name)) { + this.internalSelectedFilters.push(selectedFilterData); + } } else { this.removeSelectedFilter(filter, false, option.Value); } @@ -177,30 +277,39 @@ export class PredefinedFilterComponent implements OnInit, AfterViewInit, OnDestr this.filterService.formStatusChanged(this.formState); } - public getMultiSelectCurrentValue(filter: DataSourceToolbarFilter): string[] { - let display = []; - if (filter.Delimiter && filter.CurrentValue) { - display = filter.CurrentValue.split(filter.Delimiter); - } - return display; - } - - public multiSelectFilterValueChange(filter: DataSourceToolbarFilter, event: MatSelectChange): void { - filter.CurrentValue = undefined; - const relevantSelectedItems = this.internalSelectedFilters.filter((sfilter) => sfilter.filter.Name === filter.Name); - relevantSelectedItems.forEach((rsi) => { - this.removeSelectedFilter(filter, false, rsi.selectedOption.Value); + /** + * Handles the adding of new and removal of unselected filters. Also sets the current value using the delimiter + * @param filter current filter having options changed + * @param options option set to apply as filters + */ + public onMultiSelectFilterChanged(filter: DataSourceToolbarFilter, options: EuiSelectOption | EuiSelectOption[]): void { + // Add new options + let selectedFilterData: DataSourceToolbarSelectedFilter; + options.forEach((option) => { + selectedFilterData = { selectedOption: option.option, filter }; + if ( + !this.internalSelectedFilters.some( + (internalFilter) => internalFilter.filter?.Name === filter.Name && internalFilter.filter?.CurrentValue?.includes(option.value), + ) + ) { + // If this is a new selection + this.internalSelectedFilters.push(selectedFilterData); + } }); - event.value.forEach((value) => { - const option = this.findFilterOptionFromValue(value, filter); - this.internalSelectedFilters.push({ selectedOption: option, filter }); + // Check all selected filters for values not in the optionset, remove them + const optionValues = options.map((option) => option.value); + this.internalSelectedFilters.forEach((internalFilter) => { + if (internalFilter.filter?.Name === filter.Name && !optionValues.includes(internalFilter.selectedOption?.Value)) { + this.removeSelectedFilter(filter, false, internalFilter.selectedOption?.Value); + } }); - this.rebuildSelectedDelimitedValue(filter); + // Set current value, mark dirty + filter.CurrentValue = optionValues.join(filter.Delimiter); this.formState.dirty = true; this.filterService.formStatusChanged(this.formState); } - public onRadioFilterChanged(filter: DataSourceToolbarFilter, option: DataModelFilterOption): void { + public onRadioFilterChanged(filter: DataSourceToolbarFilter, option: any): void { let selectedFilterData: DataSourceToolbarSelectedFilter; filter.CurrentValue = option ? option.Value : undefined; selectedFilterData = { selectedOption: option, filter }; @@ -214,9 +323,27 @@ export class PredefinedFilterComponent implements OnInit, AfterViewInit, OnDestr this.filterService.formStatusChanged(this.formState); } - public selectFilterValueChanged(filter: DataSourceToolbarFilter, event: MatSelectChange): void { - const option = this.findFilterOptionFromValue(event.value, filter); - this.onRadioFilterChanged(filter, option); + public onSelectFilterChanged(filter: DataSourceToolbarFilter, option: EuiSelectOption | EuiSelectOption[]): void { + let selectedFilterData: DataSourceToolbarSelectedFilter; + const selectedOption: EuiSelectOption = Array.isArray(option) ? option[0] : option; + filter.CurrentValue = selectedOption ? selectedOption.value : undefined; + selectedFilterData = { selectedOption: { Value: selectedOption.value, Display: selectedOption.display }, filter }; + const index = this.findSelectedFilterIndex(filter.Name); + if (index >= 0) { + this.internalSelectedFilters[index] = selectedFilterData; + } else { + this.internalSelectedFilters.push(selectedFilterData); + } + this.formState.dirty = true; + this.filterService.formStatusChanged(this.formState); + } + + /** + * Use clear from select-x to remove any options applied to it + * @param filter current state of filter + */ + public onClearFilter(filter: DataSourceToolbarFilter): void { + this.removeSelectedFilter(filter, false); this.formState.dirty = true; this.filterService.formStatusChanged(this.formState); } @@ -227,6 +354,9 @@ export class PredefinedFilterComponent implements OnInit, AfterViewInit, OnDestr */ public applyDynamicPropsAsSelectedFilters(config: DSTViewConfig): void { // Handle filters from dynamic properties + if (!config.AdditionalParameters) { + return; + } Object.entries(config.AdditionalParameters).forEach(([filterName, value]) => { const filter = this.getSelectedFilterFromName(filterName, value); if (filter) { @@ -241,7 +371,7 @@ export class PredefinedFilterComponent implements OnInit, AfterViewInit, OnDestr * @param value value of the filter * @returns the filter with the selected option */ - public getSelectedFilterFromName(filterName: string, value: string): DataSourceToolbarSelectedFilter { + public getSelectedFilterFromName(filterName: string, value: string): DataSourceToolbarSelectedFilter | undefined { const filter = this.filters?.find((filter) => filter.Name === filterName); if (filter) { filter.CurrentValue = value; @@ -254,7 +384,7 @@ export class PredefinedFilterComponent implements OnInit, AfterViewInit, OnDestr filter: DataSourceToolbarFilter, emitChange: boolean = true, optionValue?: string, - selectedFilter?: DataSourceToolbarSelectedFilter + selectedFilter?: DataSourceToolbarSelectedFilter, ): void { filter.CurrentValue = undefined; const index = this.findSelectedFilterIndex(filter.Name, optionValue); @@ -324,15 +454,22 @@ export class PredefinedFilterComponent implements OnInit, AfterViewInit, OnDestr this.selectedFilters = Object.create(this.internalSelectedFilters); this.filters?.forEach((filter) => { if (filter.CurrentValue) { - this.settings.navigationState[filter.Name] = filter.CurrentValue; - this.settings.filters.find(elem=>elem.Name === filter.Name).CurrentValue = filter.CurrentValue; + if (filter.Name) { + this.settings.navigationState[filter.Name] = filter.CurrentValue; + } + if (this.settings.filters?.find((elem) => elem.Name === filter.Name)) { + const test = this.settings.filters?.find((elem) => elem.Name === filter.Name); + if (test) test.CurrentValue = filter.CurrentValue; + } if (filter?.Column) { // This is a local filter and we must filter over this column this.localFilterState.filterColumns[filter.Column] = filter.CurrentValue; } } else { - delete this.settings.navigationState[filter.Name]; - delete this.settings.filters.find((elem) => elem.Name === filter.Name).CurrentValue; + if (filter.Name) { + delete this.settings.navigationState[filter.Name]; + } + delete this.settings.filters?.find((elem) => elem.Name === filter.Name)?.CurrentValue; if (filter?.Column) { delete this.localFilterState.filterColumns[filter.Column]; } @@ -346,7 +483,9 @@ export class PredefinedFilterComponent implements OnInit, AfterViewInit, OnDestr // Do filter locally this.localFilter(); } else { - this.filterService.updateNavigation(this.id, this.settings.navigationState, this.selectedFilters); + if (this.id) { + this.filterService.updateNavigation(this.id, this.settings.navigationState, this.selectedFilters); + } } } @@ -366,9 +505,9 @@ export class PredefinedFilterComponent implements OnInit, AfterViewInit, OnDestr * @ignore Used internally * Finds the relevant DataModelFilterOption from the supplied option value and filter */ - private findFilterOptionFromValue(optionValue: string, filter: DataSourceToolbarFilter): DataModelFilterOption { - const index = filter.Options.map((opt) => opt.Value).indexOf(optionValue); - return filter.Options[index]; + private findFilterOptionFromValue(optionValue: string, filter: DataSourceToolbarFilter): DataModelFilterOption | undefined { + const index = filter.Options?.map((opt) => opt.Value).indexOf(optionValue); + return index ? filter.Options?.[index] : undefined; } /** @@ -376,12 +515,14 @@ export class PredefinedFilterComponent implements OnInit, AfterViewInit, OnDestr * Attempts to find an existing selected filter matching the given name. * Returns the index or -1 if no match was found */ - private findSelectedFilterIndex(filterName: string, optionValue?: string): number { + private findSelectedFilterIndex(filterName: string | undefined, optionValue?: string): number { let index: number; if (optionValue) { - index = this.internalSelectedFilters.map((f) => f.filter.Name + f.selectedOption.Value).indexOf(filterName + optionValue); + index = this.internalSelectedFilters + .map((f) => (f.filter?.Name ?? '') + (f.selectedOption?.Value ?? '')) + .indexOf(filterName + optionValue); } else { - index = this.internalSelectedFilters.map((f) => f.filter.Name).indexOf(filterName); + index = this.internalSelectedFilters.map((f) => f.filter?.Name).indexOf(filterName); } return index; } @@ -393,8 +534,8 @@ export class PredefinedFilterComponent implements OnInit, AfterViewInit, OnDestr private rebuildSelectedDelimitedValue(filter: DataSourceToolbarFilter): void { let val = ''; this.internalSelectedFilters.forEach((sfilter) => { - if (sfilter.filter.Name === filter.Name) { - val += `${sfilter.selectedOption.Value}${filter.Delimiter}`; + if (sfilter.filter?.Name === filter.Name) { + val += `${sfilter.selectedOption?.Value}${filter.Delimiter}`; } }); filter.CurrentValue = val.length ? val.slice(0, -1) : undefined; @@ -415,7 +556,7 @@ export class PredefinedFilterComponent implements OnInit, AfterViewInit, OnDestr const val = (entity.GetColumn(column).GetValue() as string).toLocaleLowerCase(); searchResult = this.localFilterState.keywords ? val.includes(this.localFilterState.keywords.toLocaleLowerCase()) : false; // Allow for short circuiting - searchResult &&= this.searchTerms.every((term) => val.includes(term.selectedOption.Display)); + searchResult &&= this.searchTerms.every((term) => val.includes(term.selectedOption?.Display ?? '')); if (searchResult) { // Exit for loop if we have a positive hit break; diff --git a/imxweb/projects/qbm/src/lib/data-source-toolbar/save-config-dialog/save-config-dialog.component.html b/imxweb/projects/qbm/src/lib/data-source-toolbar/save-config-dialog/save-config-dialog.component.html index 198d1cf0e..0ea9dfb92 100644 --- a/imxweb/projects/qbm/src/lib/data-source-toolbar/save-config-dialog/save-config-dialog.component.html +++ b/imxweb/projects/qbm/src/lib/data-source-toolbar/save-config-dialog/save-config-dialog.component.html @@ -1,13 +1,26 @@ -

    {{(this.data?.currentName ? '#LDS#Heading Edit Name of View' : '#LDS#Heading Save Current View') | translate}}

    +

    {{ (this.data?.currentName ? '#LDS#Heading Edit Name of View' : '#LDS#Heading Save Current View') | translate }}

    - + + +
    + {{ '#LDS#Note: The order of the columns is not saved.' | translate }} +
    +
    - {{'#LDS#Name of view' | translate}} - + {{ '#LDS#Name of view' | translate }} +
    - - - + + + diff --git a/imxweb/projects/qbm/src/lib/data-source-toolbar/save-config-dialog/save-config-dialog.component.scss b/imxweb/projects/qbm/src/lib/data-source-toolbar/save-config-dialog/save-config-dialog.component.scss index 644323825..89c9b6c56 100644 --- a/imxweb/projects/qbm/src/lib/data-source-toolbar/save-config-dialog/save-config-dialog.component.scss +++ b/imxweb/projects/qbm/src/lib/data-source-toolbar/save-config-dialog/save-config-dialog.component.scss @@ -1,5 +1,5 @@ :host { - .mat-dialog-content { + .mat-mdc-dialog-content { padding-top: 5px; padding-bottom: 5px; } diff --git a/imxweb/projects/qbm/src/lib/data-source-toolbar/save-config-dialog/save-config-dialog.component.ts b/imxweb/projects/qbm/src/lib/data-source-toolbar/save-config-dialog/save-config-dialog.component.ts index 5e5eb9746..12c73013f 100644 --- a/imxweb/projects/qbm/src/lib/data-source-toolbar/save-config-dialog/save-config-dialog.component.ts +++ b/imxweb/projects/qbm/src/lib/data-source-toolbar/save-config-dialog/save-config-dialog.component.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -25,28 +25,27 @@ */ import { Component, Inject } from '@angular/core'; -import {FormControl, Validators} from '@angular/forms'; -import { MatDialogRef, MAT_DIALOG_DATA } from '@angular/material/dialog'; - +import { FormControl, Validators } from '@angular/forms'; +import { MAT_DIALOG_DATA, MatDialogRef } from '@angular/material/dialog'; @Component({ selector: 'imx-save-config-dialog', templateUrl: './save-config-dialog.component.html', - styleUrls: ['./save-config-dialog.component.scss'] + styleUrls: ['./save-config-dialog.component.scss'], }) export class SaveConfigDialogComponent { - - public formControl = new FormControl('', Validators.required) + public formControl = new FormControl('', Validators.required); public get displayName(): string { - return this.formControl.value; + return this.formControl.value ?? ''; } constructor( private dialogRef: MatDialogRef, - @Inject(MAT_DIALOG_DATA) public data?: { - currentName: string - } + @Inject(MAT_DIALOG_DATA) + public data?: { + currentName: string; + }, ) { if (data?.currentName) { this.formControl.reset(data.currentName); @@ -58,7 +57,6 @@ export class SaveConfigDialogComponent { } public get isNew(): boolean { - return this.data?.currentName ? this.formControl.value !== this.data.currentName: true; + return this.data?.currentName ? this.formControl.value !== this.data.currentName : true; } - } diff --git a/imxweb/projects/qbm/src/lib/data-source-toolbar/selection-model-wrapper.spec.ts b/imxweb/projects/qbm/src/lib/data-source-toolbar/selection-model-wrapper.spec.ts index bbe21af39..12f159dfe 100644 --- a/imxweb/projects/qbm/src/lib/data-source-toolbar/selection-model-wrapper.spec.ts +++ b/imxweb/projects/qbm/src/lib/data-source-toolbar/selection-model-wrapper.spec.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -24,17 +24,18 @@ * */ -import { TypedEntity } from 'imx-qbm-dbts'; +import { TypedEntity } from '@imx-modules/imx-qbm-dbts'; import { SelectionModelWrapper } from './selection-model-wrapper'; describe('SelectionModelWrapper select-deselect', () => { - const createSomeTypedEntity = (keys = ['']) => ({ - GetEntity: () => ({ - GetKeys: () => keys - }) - }) as TypedEntity; + const createSomeTypedEntity = (keys = ['']) => + ({ + GetEntity: () => ({ + GetKeys: () => keys, + }), + }) as TypedEntity; - const getKey = entity => entity.GetEntity().GetKeys().join(); + const getKey = (entity) => entity.GetEntity().GetKeys().join(); it('should select an item', () => { const selection = new SelectionModelWrapper(); @@ -45,7 +46,7 @@ describe('SelectionModelWrapper select-deselect', () => { selection.checked(entity); - expect(selection.selected.map(e => getKey(e))).toContain(getKey(entity)); + expect(selection.selected.map((e) => getKey(e))).toContain(getKey(entity)); }); it('should deselect an item', () => { @@ -59,6 +60,6 @@ describe('SelectionModelWrapper select-deselect', () => { selection.unChecked(entity); - expect(selection.selected.map(e => getKey(e))).not.toContain(getKey(entity)); + expect(selection.selected.map((e) => getKey(e))).not.toContain(getKey(entity)); }); -}); \ No newline at end of file +}); diff --git a/imxweb/projects/qbm/src/lib/data-source-toolbar/selection-model-wrapper.ts b/imxweb/projects/qbm/src/lib/data-source-toolbar/selection-model-wrapper.ts index b9ce96777..6f2922f12 100644 --- a/imxweb/projects/qbm/src/lib/data-source-toolbar/selection-model-wrapper.ts +++ b/imxweb/projects/qbm/src/lib/data-source-toolbar/selection-model-wrapper.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -27,25 +27,25 @@ import { SelectionChange, SelectionModel } from '@angular/cdk/collections'; import { Subject } from 'rxjs'; -import { TypedEntity } from 'imx-qbm-dbts'; +import { TypedEntity } from '@imx-modules/imx-qbm-dbts'; -export class SelectionModelWrapper { - public get changed(): Subject> { +export class SelectionModelWrapper { + public get changed(): Subject> { return this.selection.changed; } - public get selected(): ReadonlyArray { + public get selected(): ReadonlyArray { return this.selection.selected; } public get numOfSelectableItems(): number { - return this.selectableItems.filter(v => v).length; + return this.selectableItems.filter((v) => v).length; } /** * Selection model that handles multiple selection in the data source view. */ - private selection = new SelectionModel(true, []); + private selection = new SelectionModel(true, []); /** * Selection cache dictionary used by the data source view to get the check/uncheck state of an item if mutiselect is enabled. @@ -72,14 +72,14 @@ export class SelectionModelWrapper { /** * Checks if an item is selected. */ - public isSelected(item: TypedEntity): boolean { + public isSelected(item: T): boolean { return this.selectionCache[this.getId(item)]; } /** * Toggles selection state. */ - public toggle(item: TypedEntity): void { + public toggle(item: T): void { if (this.isSelected(item)) { this.unChecked(item); } else { @@ -90,10 +90,10 @@ export class SelectionModelWrapper { /** * Selects an item. */ - public checked(item: TypedEntity): void { + public checked(item: T): void { this.selection.select(item); - const found = this.selection.selected.find(x => this.getId(x) === this.getId(item)); + const found = this.selection.selected.find((x) => this.getId(x) === this.getId(item)); if (found) { this.selectionCache[this.getId(item)] = true; } @@ -102,16 +102,26 @@ export class SelectionModelWrapper { /** * Deselects an item. */ - public unChecked(item: TypedEntity): void { - const found = this.selection.selected.find(x => this.getId(x) === this.getId(item)); - + public unChecked(item: T): void { + const found = this.selection.selected.find((x) => this.getId(x) === this.getId(item)); if (found) { this.selectionCache[this.getId(item)] = false; this.selection.deselect(found); } } - private getId(item: TypedEntity): string { + public select(items: T[]): void { + this.selection.select(...items); + items.forEach((item) => (this.selectionCache[this.getId(item)] = true)); + } + + public setSelection(items: any[]): void { + this.selection.setSelection(...(items as T[])); + this.selectionCache = {}; + items.forEach((item) => (this.selectionCache[this.getId(item as T)] = true)); + } + + private getId(item: T): string { return item.GetEntity().GetKeys().join(','); } } diff --git a/imxweb/projects/qbm/src/lib/data-table/data-table-additional-info.model.ts b/imxweb/projects/qbm/src/lib/data-table/data-table-additional-info.model.ts index be3fe92c6..b7874e18a 100644 --- a/imxweb/projects/qbm/src/lib/data-table/data-table-additional-info.model.ts +++ b/imxweb/projects/qbm/src/lib/data-table/data-table-additional-info.model.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -24,13 +24,13 @@ * */ -import { IClientProperty, IEntity } from 'imx-qbm-dbts'; +import { IClientProperty, IEntity } from '@imx-modules/imx-qbm-dbts'; export function buildAdditionalElementsString(entity: IEntity, additionals: IClientProperty[], separator: string = '; '): string { return additionals == null ? '' : additionals - .filter((elem) => entity.GetColumn(elem?.ColumnName)?.GetDisplayValue() !== '') - .map((elem) => `${elem?.Display || elem?.ColumnName}: ${entity.GetColumn(elem?.ColumnName)?.GetDisplayValue()}`) + .filter((elem) => entity.GetColumn(elem?.ColumnName ?? '')?.GetDisplayValue() !== '') + .map((elem) => `${elem?.Display || elem?.ColumnName}: ${entity.GetColumn(elem?.ColumnName ?? '')?.GetDisplayValue()}`) .join(separator); } diff --git a/imxweb/projects/qbm/src/lib/data-table/data-table-cell/data-table-cell.component.html b/imxweb/projects/qbm/src/lib/data-table/data-table-cell/data-table-cell.component.html index 5f8a69828..c7b1abdca 100644 --- a/imxweb/projects/qbm/src/lib/data-table/data-table-cell/data-table-cell.component.html +++ b/imxweb/projects/qbm/src/lib/data-table/data-table-cell/data-table-cell.component.html @@ -1,6 +1,3 @@ - {{ property?.Type === ValType.Date - ? (column?.GetValue() | shortDate ) - : column?.GetDisplayValue() - }} + {{ property?.Type === ValType.Date ? (column?.GetValue() | shortDate) : column?.GetDisplayValue() }} diff --git a/imxweb/projects/qbm/src/lib/data-table/data-table-cell/data-table-cell.component.scss b/imxweb/projects/qbm/src/lib/data-table/data-table-cell/data-table-cell.component.scss index c9b9348a2..7d74d47cd 100644 --- a/imxweb/projects/qbm/src/lib/data-table/data-table-cell/data-table-cell.component.scss +++ b/imxweb/projects/qbm/src/lib/data-table/data-table-cell/data-table-cell.component.scss @@ -1 +1 @@ -/* for some styles */ \ No newline at end of file +/* for some styles */ diff --git a/imxweb/projects/qbm/src/lib/data-table/data-table-cell/data-table-cell.component.ts b/imxweb/projects/qbm/src/lib/data-table/data-table-cell/data-table-cell.component.ts index 19f6bb133..953a5e13a 100644 --- a/imxweb/projects/qbm/src/lib/data-table/data-table-cell/data-table-cell.component.ts +++ b/imxweb/projects/qbm/src/lib/data-table/data-table-cell/data-table-cell.component.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -26,25 +26,23 @@ import { Component, Input } from '@angular/core'; -import { IClientProperty, IEntityColumn, TypedEntity, ValType } from 'imx-qbm-dbts'; +import { IClientProperty, IEntityColumn, TypedEntity, ValType } from '@imx-modules/imx-qbm-dbts'; @Component({ selector: 'imx-data-table-cell', templateUrl: './data-table-cell.component.html', - styleUrls: ['./data-table-cell.component.scss'] + styleUrls: ['./data-table-cell.component.scss'], }) export class DataTableCellComponent { - public readonly ValType = ValType; @Input() public entity: TypedEntity; @Input() public property: IClientProperty; - - public get column(): IEntityColumn{ - try{ - return this.entity?.GetEntity()?.GetColumn(this.property?.ColumnName); - }catch { + public get column(): IEntityColumn | undefined { + try { + return this.entity?.GetEntity()?.GetColumn(this.property?.ColumnName ?? ''); + } catch { return undefined; } } diff --git a/imxweb/projects/qbm/src/lib/data-table/data-table-column.component.html b/imxweb/projects/qbm/src/lib/data-table/data-table-column.component.html index 80c0a93a1..a70809b66 100644 --- a/imxweb/projects/qbm/src/lib/data-table/data-table-column.component.html +++ b/imxweb/projects/qbm/src/lib/data-table/data-table-column.component.html @@ -4,7 +4,7 @@ {{ columnLabel }}
    - {{ translateProvider.GetColumnDisplay(entityColumn?.ColumnName, entitySchema) }} + {{ translateProvider.GetColumnDisplay(entityColumn?.ColumnName ?? '', entitySchema) }}
    diff --git a/imxweb/projects/qbm/src/lib/data-table/data-table-column.component.scss b/imxweb/projects/qbm/src/lib/data-table/data-table-column.component.scss index 091367d96..fe132278e 100644 --- a/imxweb/projects/qbm/src/lib/data-table/data-table-column.component.scss +++ b/imxweb/projects/qbm/src/lib/data-table/data-table-column.component.scss @@ -1,43 +1,3 @@ -@import "@elemental-ui/core/src/styles/_palette.scss"; -@import "@elemental-ui/core/src/styles/_eui_palette.scss"; +@import '@elemental-ui/core/src/styles/_palette.scss'; +@import '@elemental-ui/core/src/styles/_eui_palette.scss'; -.imx-table-column { - padding-right: 15px; -} - -td.mat-cell ::ng-deep div[subtitle] { - font-size: smaller; - color: $black-9; - overflow: hidden; - text-overflow: ellipsis; - white-space: nowrap; - max-width: 500px; -} - -::ng-deep .eui-sidesheet__content td.mat-cell ::ng-deep div[subtitle] { - max-width: 250px; -} - -@media screen and (max-width: 768px) { - td.mat-cell ::ng-deep div[subtitle] { - max-width: 250px; - } -} - -.eui-dark-theme { - :host { - .mat-header-cell { - color: $color-gray-10; - border-bottom-color: $color-gray-60; - } - } -} - -.eui-contrast-theme { - :host { - .mat-header-cell { - color: $color-gray-0; - border-bottom-color: $color-gray-60; - } - } -} diff --git a/imxweb/projects/qbm/src/lib/data-table/data-table-column.component.ts b/imxweb/projects/qbm/src/lib/data-table/data-table-column.component.ts index 2f0098bd3..47b6c11f7 100644 --- a/imxweb/projects/qbm/src/lib/data-table/data-table-column.component.ts +++ b/imxweb/projects/qbm/src/lib/data-table/data-table-column.component.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -24,16 +24,9 @@ * */ -import { - Component, - Input, - ViewChild, - TemplateRef, - ContentChild, - OnInit -} from '@angular/core'; +import { Component, ContentChild, Input, OnInit, TemplateRef, ViewChild } from '@angular/core'; import { MatColumnDef } from '@angular/material/table'; -import { IClientProperty, EntitySchema } from 'imx-qbm-dbts'; +import { EntitySchema, IClientProperty } from '@imx-modules/imx-qbm-dbts'; import { ImxTranslationProviderService } from '../translation/imx-translation-provider.service'; /** @@ -64,10 +57,9 @@ import { ImxTranslationProviderService } from '../translation/imx-translation-pr @Component({ selector: 'imx-data-table-column', templateUrl: './data-table-column.component.html', - styleUrls: ['./data-table-column.component.scss'] + styleUrls: ['./data-table-column.component.scss'], }) export class DataTableColumnComponent implements OnInit { - /** * Set alignment of column header and content */ @@ -94,17 +86,16 @@ export class DataTableColumnComponent implements OnInit { */ @Input() public alignContent: 'left' | 'center' | 'right' = 'left'; - public columnIndex: number; /** * Describes a typed entity property. */ @Input() - public get entityColumn(): IClientProperty { + public get entityColumn(): IClientProperty | undefined { return this.entityColumnField; } - public set entityColumn(value: IClientProperty) { + public set entityColumn(value: IClientProperty | undefined) { this.entityColumnField = value; } @@ -119,24 +110,22 @@ export class DataTableColumnComponent implements OnInit { */ @ViewChild(MatColumnDef, { static: true }) public columnDef: MatColumnDef; - /** + /** * The schema of a typed entity */ - public entitySchema: EntitySchema; + public entitySchema: EntitySchema; /** * @ignore Used internally. */ - private entityColumnField: IClientProperty; + private entityColumnField: IClientProperty | undefined; /** * Inject the 'translateProvider' for use in the template. */ - constructor( - public readonly translateProvider: ImxTranslationProviderService - ) {} + constructor(public readonly translateProvider: ImxTranslationProviderService) {} public ngOnInit(): void { - this.columnDef.name = this.entityColumnField.ColumnName; + this.columnDef.name = this.entityColumnField?.ColumnName || ''; } } diff --git a/imxweb/projects/qbm/src/lib/data-table/data-table-display-cell/data-table-display-cell.component.html b/imxweb/projects/qbm/src/lib/data-table/data-table-display-cell/data-table-display-cell.component.html index b4566cb66..b6e8734e9 100644 --- a/imxweb/projects/qbm/src/lib/data-table/data-table-display-cell/data-table-display-cell.component.html +++ b/imxweb/projects/qbm/src/lib/data-table/data-table-display-cell/data-table-display-cell.component.html @@ -1,7 +1,14 @@
    - {{ property?.Type === ValType.Date - ? (entity?.GetEntity()?.GetColumn(property.ColumnName)?.GetValue() | shortDate ) - : entity?.GetEntity()?.GetColumn(property.ColumnName)?.GetDisplayValue() + {{ + property?.Type === ValType.Date + ? (entity + ?.GetEntity() + ?.GetColumn(property.ColumnName ?? '') + ?.GetValue() | shortDate) + : entity + ?.GetEntity() + ?.GetColumn(property.ColumnName ?? '') + ?.GetDisplayValue() }}
    -
    {{ getSubtitleText()}}
    +
    {{ getSubtitleText() }}
    diff --git a/imxweb/projects/qbm/src/lib/data-table/data-table-display-cell/data-table-display-cell.component.ts b/imxweb/projects/qbm/src/lib/data-table/data-table-display-cell/data-table-display-cell.component.ts index 541cb527c..dba53ded6 100644 --- a/imxweb/projects/qbm/src/lib/data-table/data-table-display-cell/data-table-display-cell.component.ts +++ b/imxweb/projects/qbm/src/lib/data-table/data-table-display-cell/data-table-display-cell.component.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -26,16 +26,15 @@ import { Component, Input } from '@angular/core'; -import { IClientProperty, TypedEntity, ValType } from 'imx-qbm-dbts'; +import { IClientProperty, TypedEntity, ValType } from '@imx-modules/imx-qbm-dbts'; import { buildAdditionalElementsString } from '../data-table-additional-info.model'; @Component({ selector: 'imx-data-table-display-cell', templateUrl: './data-table-display-cell.component.html', - styleUrls: ['./data-table-display-cell.component.scss'] + styleUrls: ['./data-table-display-cell.component.scss'], }) export class DataTableDisplayCellComponent { - public readonly ValType = ValType; @Input() public entity: TypedEntity; diff --git a/imxweb/projects/qbm/src/lib/data-table/data-table-generic-column.component.html b/imxweb/projects/qbm/src/lib/data-table/data-table-generic-column.component.html index 71d6a3534..ad5fbe8ca 100644 --- a/imxweb/projects/qbm/src/lib/data-table/data-table-generic-column.component.html +++ b/imxweb/projects/qbm/src/lib/data-table/data-table-generic-column.component.html @@ -1,8 +1,8 @@ - -
    - {{ columnLabel }} + + + {{ columnLabel }} + + {{ grouping?.Display[0].Display || '' }}
    @@ -33,12 +39,12 @@ (selectionChanged)="selectionInGroupChanged($event, grouping?.Display[0]?.Display)" [parentManualColumns]="manualColumns" [parentManualGenericColumns]="manualGenericColumns" - [parentAdditionals]="dst?.additionalColumns" + [parentAdditionals]="dst.additionalColumns" [noDataText]="noDataText" [noDataIcon]="noDataIcon" [noMatchingDataText]="noMatchingDataText" [noMatchingDataIcon]="noMatchingDataIcon" - [groupedTableHasFiltersApplied]="dst?.filtersCurrentlyApplied" + [groupedTableHasFiltersApplied]="dst.filtersCurrentlyApplied" > @@ -66,9 +72,9 @@ matSort data-imx-identifier="datatable-table" [ngClass]="{ - 'imx-data-table__hidden': isGroupingApplied || !dst?.dataSourceHasData || isLoading, + 'imx-data-table__hidden': isGroupingApplied || !dst.dataSourceHasData || isLoading, 'imx-data-table-highlightedActive': ishighlightedEntityChangedUsed, - hidden: isLoading + hidden: isLoading, }" role="grid" > @@ -103,13 +109,15 @@ -
    {{ column.Display }} + {{ translateProvider.GetColumnDisplay(column.ColumnName ?? '', entitySchema) }} + @@ -120,7 +128,9 @@ - {{ column.Display }} + {{ translateProvider.GetColumnDisplay(column.ColumnName ?? '', entitySchema) }} +
    -
    - -

    +
    + +

    diff --git a/imxweb/projects/qbm/src/lib/data-table/data-table.component.scss b/imxweb/projects/qbm/src/lib/data-table/data-table.component.scss index d3c633280..380a54a96 100644 --- a/imxweb/projects/qbm/src/lib/data-table/data-table.component.scss +++ b/imxweb/projects/qbm/src/lib/data-table/data-table.component.scss @@ -13,37 +13,9 @@ display: none; } - .imx-data-table-grouped { - flex: 1 1 auto; - display: flex; - flex-direction: column; - overflow: hidden; - - .spaced-left { - margin-left: 5px; - } - imx-data-table{ - overflow-y: unset; - } - td.mat-cell { - padding-top: 12px; - - div { - overflow: hidden; - - &.group-row-expanded { - margin-bottom: 15px; - } - } - } + - .imx-data-table-grouped-content { - flex: 1 1 auto; - overflow: auto; - } - } - - .imx-data-table-no-results { + .imx-no-results { text-align: center; margin: 20px 0; flex: 1 1 auto; @@ -51,11 +23,6 @@ flex-direction: column; justify-content: center; - .eui-icon { - font-size: 100px; - color: $color-gray-10; - } - p { margin: 0; font-size: 18px; @@ -63,64 +30,6 @@ } } - // Handle background row coloring - .imx-data-table-highlightedActive .mat-row:hover { - background-color: $color-blue-10; - } - - // Handle cursor icons, make sure divs are minimal so we don't have the text icon too much - .imx-data-table-highlightedActive ::ng-deep.mat-cell { - &:hover { - cursor: pointer; - } - - // Make sure to exclude checkboxes as they behave differently with content fitting - > *:not(.mat-checkbox) { - display: flex; - height: fit-content; - - &:hover { - cursor: text; - } - } - - > .mat-button, - .mat-stroked-button, - .mat-raised-button, - .mat-flat-button, - .mat-icon-button { - &:hover { - cursor: pointer; - } - } - } - - .imx-data-table-row-highlighted { - background-color: $color-gray-5; - } - - .imx-data-table-row-conditional { - background-color: $color-red-20; - } - - .mat-column-select { - overflow: initial; - max-width: 50px; - width: 15px; - } - - td.mat-cell { - padding-right: 10px; - } - - table.mat-table { - box-shadow: none; - padding: 1px; - } - .imx-table-column { - padding-right: 15px; - } - .hidden { display: none; } @@ -130,30 +39,8 @@ :host { background-color: $color-gray-70; - .mat-table { - background-color: $color-gray-70; - } - - .imx-data-table-row-highlighted { - background-color: $color-gray-60; - } - .imx-data-table-highlightedActive .mat-row:hover { - background-color: $color-gray-60; - } - - .imx-data-table-row-conditional { - background-color: $color-red-80; - } - - ::ng-deep .custom-row td { - border-bottom-color: $color-gray-60; - } - - .imx-data-table-no-results { - eui-icon { - color: $color-gray-20; - } + .imx-no-results { p { color: $color-gray-10; } @@ -165,57 +52,7 @@ :host { background-color: $color-gray-90; - .mat-table { - background-color: $color-gray-90; - } - - .imx-data-table-row-highlighted, - .imx-data-table-highlightedActive .mat-row:hover { - background-color: $color-gray-0; - - ::ng-deep td.mat-cell { - color: $color-gray-100; - } - - ::ng-deep .mat-checkbox-frame, - ::ng-deep .mat-radio-outer-circle { - border-color: $color-gray-100; - } - } - - table { - border-top: none; - } - - ::ng-deep th:after, - ::ng-deep th:before { - content: ''; - position: absolute; - left: 0; - width: 100%; - } - ::ng-deep th:before { - top: 0; - border-top: 1px solid white; - } - ::ng-deep th:after { - bottom: 0; - border-bottom: 1px solid white; - } - - .imx-data-table-row-conditional { - background-color: $color-red-80; - } - - .imx-data-table-selection-info { - color: $color-blue-40; - } - - .imx-data-table-no-results { - eui-icon { - color: $color-gray-10; - } - + .imx-no-results { p { color: $color-gray-0; } diff --git a/imxweb/projects/qbm/src/lib/data-table/data-table.component.ts b/imxweb/projects/qbm/src/lib/data-table/data-table.component.ts index 384333e04..4c507af80 100644 --- a/imxweb/projects/qbm/src/lib/data-table/data-table.component.ts +++ b/imxweb/projects/qbm/src/lib/data-table/data-table.component.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -27,37 +27,36 @@ import { animate, state, style, transition, trigger } from '@angular/animations'; import { SelectionChange } from '@angular/cdk/collections'; import { + AfterViewInit, + ChangeDetectorRef, Component, - ViewChild, + ContentChildren, + EventEmitter, Input, - Output, OnChanges, - SimpleChanges, - EventEmitter, - ContentChildren, - QueryList, OnDestroy, - AfterViewInit, OnInit, - ChangeDetectorRef, + Output, + QueryList, + SimpleChanges, + ViewChild, } from '@angular/core'; import { MatDialog } from '@angular/material/dialog'; -import { MatTable, MatColumnDef, MatTableDataSource } from '@angular/material/table'; +import { MatColumnDef, MatTable, MatTableDataSource } from '@angular/material/table'; import { Subscription } from 'rxjs'; -import { TypedEntity, IClientProperty, EntitySchema, CollectionLoadParameters, GroupInfo, GroupInfoData } from 'imx-qbm-dbts'; +import { EuiLoadingService } from '@elemental-ui/core'; +import { CollectionLoadParameters, EntitySchema, GroupInfo, GroupInfoData, IClientProperty, TypedEntity } from '@imx-modules/imx-qbm-dbts'; +import { debounce } from 'lodash'; +import { ColumnOptions } from '../data-source-toolbar/column-options'; +import { DataSourceToolbarSettings } from '../data-source-toolbar/data-source-toolbar-settings'; +import { DataSourceToolbarComponent } from '../data-source-toolbar/data-source-toolbar.component'; import { ImxTranslationProviderService } from '../translation/imx-translation-provider.service'; import { DataTableColumnComponent } from './data-table-column.component'; import { DataTableGenericColumnComponent } from './data-table-generic-column.component'; -import { DataSourceToolbarComponent } from '../data-source-toolbar/data-source-toolbar.component'; -import { DataSourceToolbarSettings } from '../data-source-toolbar/data-source-toolbar-settings'; import { DataTableGroupedData } from './data-table-groups.interface'; import { RowHighlight } from './data-table-row-highlight.interface'; import { GroupPaginatorInformation } from './group-paginator/group-paginator.component'; -import { EuiLoadingService } from '@elemental-ui/core'; -import { OverlayRef } from '@angular/cdk/overlay'; -import { debounce } from 'lodash'; -import { ColumnOptions } from '../data-source-toolbar/column-options'; /** * A data table component with a detail view specialized on typed entities. @@ -103,7 +102,7 @@ export class DataTableComponent implements OnInit, OnChanges, AfterViewInit, * Represents the typed entity that is selected when the users clicks on a row. * Not to be confused with the 'selection' property. */ - public highlightedEntity: TypedEntity; + public highlightedEntity: TypedEntity | null; /** * @ignore Used internally in components template. @@ -322,7 +321,7 @@ export class DataTableComponent implements OnInit, OnChanges, AfterViewInit, public translateProvider: ImxTranslationProviderService, public dialog: MatDialog, private readonly busyService: EuiLoadingService, - private readonly changeDetectorRef: ChangeDetectorRef + private readonly changeDetectorRef: ChangeDetectorRef, ) {} public get isGroupingApplied(): boolean { @@ -375,7 +374,7 @@ export class DataTableComponent implements OnInit, OnChanges, AfterViewInit, this.settings = value; await this.dstHasChanged(); } - }) + }), ); this.subscriptions.push( @@ -383,7 +382,7 @@ export class DataTableComponent implements OnInit, OnChanges, AfterViewInit, if (event && event.source) { this.selectionChanged.emit(event.source.selected); } - }) + }), ); this.subscriptions.push( @@ -391,7 +390,7 @@ export class DataTableComponent implements OnInit, OnChanges, AfterViewInit, if (!!this.settings) { await this.dstHasChanged(); } - }) + }), ); if (this.dst.busyService) { @@ -399,7 +398,7 @@ export class DataTableComponent implements OnInit, OnChanges, AfterViewInit, this.dst.busyService.busyStateChanged.subscribe((busy: boolean) => { this.isLoading = busy; this.changeDetectorRef.detectChanges(); - }) + }), ); } this.isLoading = this.dst?.busyService?.isBusy ?? false; @@ -450,10 +449,10 @@ export class DataTableComponent implements OnInit, OnChanges, AfterViewInit, * Gets the display values of displayed columns */ public getNamesOfDisplayedColumns(): string[] { - let displayedColumnNames = []; + let displayedColumnNames: string[] = []; if (this.displayedColumns && this.displayedColumns.length > 0) { - displayedColumnNames = this.displayedColumns.map((item) => item.ColumnName); + displayedColumnNames = this.displayedColumns.map((item) => item.ColumnName ?? ''); } if (this.selectable) { @@ -475,12 +474,12 @@ export class DataTableComponent implements OnInit, OnChanges, AfterViewInit, // Prevent emission for certain cases if (event) { // Make sure we aren't selecting text - if (event.view.getSelection().type === 'Range') { + if (event.view?.getSelection()?.type === 'Range') { return; } // Prevent button clicks from propogating as row clicks, Walk up node chain until we hit table looking if we are a button - let target = event.target as HTMLElement; + let target: HTMLElement | null = event.target as HTMLElement; while (target) { if (target.tagName === 'BUTTON') { return; @@ -509,7 +508,10 @@ export class DataTableComponent implements OnInit, OnChanges, AfterViewInit, * Gets the display value for a specific column. */ public getDisplayValue(entity: TypedEntity, column: IClientProperty): string { - return entity.GetEntity().GetColumn(column.ColumnName).GetDisplayValue(); + return entity + .GetEntity() + .GetColumn(column.ColumnName ?? '') + .GetDisplayValue(); } /** @@ -542,8 +544,11 @@ export class DataTableComponent implements OnInit, OnChanges, AfterViewInit, * Emits an event to allow data to be retrieved from calling code if no data is present */ public onGroupExpanded(group: GroupInfo): void { - if (group && group.Count > 0) { - const groupingDisplay = group.Display[0].Display; + if (group && (group.Count ?? 0) > 0) { + const groupingDisplay = group.Display?.[0].Display; + if (!groupingDisplay) { + return; + } if (!this.groupData[groupingDisplay]) { this.groupData[groupingDisplay] = { data: undefined, @@ -578,6 +583,10 @@ export class DataTableComponent implements OnInit, OnChanges, AfterViewInit, public selectionInGroupChanged(items: TypedEntity[], groupKey: string): void { const groupingData = this.groupData[groupKey]; + if (!groupingData) { + return; + } + setTimeout(() => { if (groupingData.selected) { groupingData.selected.forEach((selectedItem) => { @@ -590,7 +599,7 @@ export class DataTableComponent implements OnInit, OnChanges, AfterViewInit, groupingData.selected = []; items.forEach((item) => { - groupingData.selected.push(item); + groupingData.selected?.push(item); this.checked(item); }); }); @@ -623,8 +632,9 @@ export class DataTableComponent implements OnInit, OnChanges, AfterViewInit, * updated the navigation state for the current grouping and loads its content */ private async updateGroupingState(currentGrouping: any, newState?: CollectionLoadParameters): Promise { - let busyIndicator: OverlayRef; - setTimeout(() => (busyIndicator = this.busyService.show())); + if (this.busyService.overlayRefs.length === 0) { + this.busyService.show(); + } try { if (newState) { @@ -638,7 +648,7 @@ export class DataTableComponent implements OnInit, OnChanges, AfterViewInit, this.groupedDataSource = new MatTableDataSource(this.groupPaginatorInformation.currentData.Groups); } finally { - setTimeout(() => this.busyService.hide(busyIndicator)); + this.busyService.hide(); } } @@ -651,10 +661,13 @@ export class DataTableComponent implements OnInit, OnChanges, AfterViewInit, if (this.settings && this.settings.entitySchema) { this.entitySchema = this.settings.entitySchema; //update schema with additionals - this.parentAdditionals.concat(this.additional).forEach((element) => { + (this.parentAdditionals ?? []).concat(this.additional).forEach((element) => { const key = ColumnOptions.findKey(element.ColumnName, this.entitySchema); - (this.entitySchema.Columns[key] as any) = element; + if (key) { + (this.entitySchema.Columns[key] as any) = element; + } }); + this.settings.dataSource?.Data.forEach((elem) => elem.GetEntity().ApplySchema(this.entitySchema)); this.manualColumns?.forEach((item: DataTableColumnComponent) => { item.entitySchema = this.entitySchema; }); @@ -692,10 +705,11 @@ export class DataTableComponent implements OnInit, OnChanges, AfterViewInit, if (this.dst.dataSourceChanged || this.dst.shownColumnsSelectionChanged) { this.displayedColumns = []; - this.additional = this.dst == null || this.dst.additionalColumns?.length === 0 ? this.parentAdditionals : this.dst.additionalColumns; + this.additional = + (this.dst == null || this.dst.additionalColumns?.length === 0 ? this.parentAdditionals : this.dst.additionalColumns) ?? []; // filter additionals for columns, that are already set in the DataSourceToolbarSettings this.additional = this.additional.filter((elem) => - this.settings?.displayedColumns?.every((disp) => disp.ColumnName !== elem.ColumnName) + this.settings?.displayedColumns?.every((disp) => disp.ColumnName !== elem.ColumnName), ); if (this.manualColumns == null && this.manualGenericColumns == null) { return; @@ -767,8 +781,11 @@ export class DataTableComponent implements OnInit, OnChanges, AfterViewInit, } if (grouping.isExpanded || skipNavigationChange) { - const preservedGroupingFilter = grouping.navigationState.filter; + const preservedGroupingFilter = grouping?.navigationState?.filter; grouping.navigationState = JSON.parse(JSON.stringify(this.settings.navigationState)); + if (!grouping.navigationState) { + grouping.navigationState = {}; + } grouping.navigationState.filter = preservedGroupingFilter; grouping.navigationState.StartIndex = 0; grouping.navigationState.withProperties = this.settings.navigationState.withProperties; diff --git a/imxweb/projects/qbm/src/lib/data-table/data-table.module.ts b/imxweb/projects/qbm/src/lib/data-table/data-table.module.ts index 1632bd1a2..7a1d533c1 100644 --- a/imxweb/projects/qbm/src/lib/data-table/data-table.module.ts +++ b/imxweb/projects/qbm/src/lib/data-table/data-table.module.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -24,8 +24,8 @@ * */ -import { NgModule } from '@angular/core'; import { CommonModule } from '@angular/common'; +import { NgModule } from '@angular/core'; import { MatButtonModule } from '@angular/material/button'; import { MatCardModule } from '@angular/material/card'; import { MatDialogModule } from '@angular/material/dialog'; @@ -42,16 +42,16 @@ import { TranslateModule } from '@ngx-translate/core'; import { EuiCoreModule, EuiMaterialModule } from '@elemental-ui/core'; +import { BusyIndicatorModule } from '../busy-indicator/busy-indicator.module'; import { DataSourceToolbarModule } from '../data-source-toolbar/data-source-toolbar.module'; -import { DataTableComponent } from './data-table.component'; -import { DataTableColumnComponent } from './data-table-column.component'; -import { DataTableGenericColumnComponent } from './data-table-generic-column.component'; import { DateModule } from '../date/date.module'; import { DataTableCellComponent } from './data-table-cell/data-table-cell.component'; +import { DataTableColumnComponent } from './data-table-column.component'; import { DataTableDisplayCellComponent } from './data-table-display-cell/data-table-display-cell.component'; -import { GroupPaginatorComponent } from './group-paginator/group-paginator.component'; +import { DataTableGenericColumnComponent } from './data-table-generic-column.component'; +import { DataTableComponent } from './data-table.component'; import { ExcludedColumnsPipe } from './excluded-columns.pipe'; -import { BusyIndicatorModule } from '../busy-indicator/busy-indicator.module'; +import { GroupPaginatorComponent } from './group-paginator/group-paginator.component'; import { TableAccessiblilityDirective } from './table-accessibility.directive'; @NgModule({ @@ -63,7 +63,7 @@ import { TableAccessiblilityDirective } from './table-accessibility.directive'; DataTableGenericColumnComponent, GroupPaginatorComponent, ExcludedColumnsPipe, - TableAccessiblilityDirective + TableAccessiblilityDirective, ], imports: [ CommonModule, @@ -84,8 +84,14 @@ import { TableAccessiblilityDirective } from './table-accessibility.directive'; MatToolbarModule, MatDialogModule, BusyIndicatorModule, - TranslateModule + TranslateModule, + ], + exports: [ + DataTableComponent, + DataTableColumnComponent, + DataTableGenericColumnComponent, + ExcludedColumnsPipe, + TableAccessiblilityDirective, ], - exports: [DataTableComponent, DataTableColumnComponent, DataTableGenericColumnComponent, ExcludedColumnsPipe], }) export class DataTableModule {} diff --git a/imxweb/projects/qbm/src/lib/data-table/excluded-columns.pipe.ts b/imxweb/projects/qbm/src/lib/data-table/excluded-columns.pipe.ts index 7fa9387fb..af28fc35e 100644 --- a/imxweb/projects/qbm/src/lib/data-table/excluded-columns.pipe.ts +++ b/imxweb/projects/qbm/src/lib/data-table/excluded-columns.pipe.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -26,8 +26,7 @@ import { Pipe, PipeTransform } from '@angular/core'; -import { IClientProperty } from 'imx-qbm-dbts'; - +import { IClientProperty } from '@imx-modules/imx-qbm-dbts'; @Pipe({ name: 'excludedColumns', @@ -41,8 +40,6 @@ export class ExcludedColumnsPipe implements PipeTransform { // filter items array, items which match and return true will be // kept, false will be filtered out - return items.filter(elem=> !filter.includes(elem.ColumnName ?? '')); + return items.filter((elem) => !filter.includes(elem.ColumnName ?? '')); } - - } diff --git a/imxweb/projects/qbm/src/lib/data-table/group-paginator/group-paginator.component.html b/imxweb/projects/qbm/src/lib/data-table/group-paginator/group-paginator.component.html index 37a062841..1cb4a54d9 100644 --- a/imxweb/projects/qbm/src/lib/data-table/group-paginator/group-paginator.component.html +++ b/imxweb/projects/qbm/src/lib/data-table/group-paginator/group-paginator.component.html @@ -1 +1,7 @@ - + diff --git a/imxweb/projects/qbm/src/lib/data-table/group-paginator/group-paginator.component.ts b/imxweb/projects/qbm/src/lib/data-table/group-paginator/group-paginator.component.ts index 1012706e7..14f8b4fe4 100644 --- a/imxweb/projects/qbm/src/lib/data-table/group-paginator/group-paginator.component.ts +++ b/imxweb/projects/qbm/src/lib/data-table/group-paginator/group-paginator.component.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -24,11 +24,11 @@ * */ -import { Component, Input, Output, EventEmitter, OnChanges, ViewChild, OnDestroy } from '@angular/core'; -import { PageEvent, MatPaginator } from '@angular/material/paginator'; +import { Component, EventEmitter, Input, OnChanges, OnDestroy, Output, ViewChild } from '@angular/core'; +import { MatPaginator, PageEvent } from '@angular/material/paginator'; import { Subscription } from 'rxjs'; -import { CollectionLoadParameters, GroupInfoData } from 'imx-qbm-dbts'; +import { CollectionLoadParameters, GroupInfoData } from '@imx-modules/imx-qbm-dbts'; export interface GroupPaginatorInformation { currentData: GroupInfoData; @@ -49,7 +49,6 @@ export interface GroupPaginatorInformation { @Component({ selector: 'imx-group-paginator', templateUrl: './group-paginator.component.html', - styleUrls: ['../../data-source-toolbar/data-source-paginator.component.scss'], }) export class GroupPaginatorComponent implements OnChanges, OnDestroy { @Input() public groupPaginatorInformation: GroupPaginatorInformation; @@ -120,8 +119,9 @@ export class GroupPaginatorComponent implements OnChanges, OnDestroy { private setPaginator(): void { this.paginator.length = this.groupPaginatorInformation?.currentData?.TotalCount ?? 0; if (this.navigationState) { - this.paginator.pageSize = this.navigationState.PageSize; - this.paginator.pageIndex = this.navigationState.StartIndex / this.navigationState.PageSize; + this.paginator.pageSize = this.navigationState.PageSize ?? 0; + + this.paginator.pageIndex = this.paginator.pageSize ? (this.navigationState.StartIndex ?? 0) / this.paginator.pageSize : 0; } } } diff --git a/imxweb/projects/qbm/src/lib/data-table/table-accessibility.directive.ts b/imxweb/projects/qbm/src/lib/data-table/table-accessibility.directive.ts index 6493aeade..7a2dc525a 100644 --- a/imxweb/projects/qbm/src/lib/data-table/table-accessibility.directive.ts +++ b/imxweb/projects/qbm/src/lib/data-table/table-accessibility.directive.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -65,7 +65,7 @@ export class TableAccessiblilityDirective implements AfterViewChecked, AfterView }); } // Set tabindex for the first cell on the first row if there is not another tabindex set already - private setTabindex():void{ + private setTabindex(): void { const selectables = this.el.nativeElement.querySelectorAll('tbody td:not(.mat-column-select)'); const tabIndexes = this.el.nativeElement.querySelectorAll('tbody td[tabindex="0"]'); if (tabIndexes.length === 0) { @@ -107,7 +107,7 @@ export class TableAccessiblilityDirective implements AfterViewChecked, AfterView this.moveFocusTo(row - 1, col); break; case 'Home': { - this.moveHome(event, row) + this.moveHome(event, row); break; } case 'End': { @@ -126,19 +126,19 @@ export class TableAccessiblilityDirective implements AfterViewChecked, AfterView }); } // Focus the cell right to the current cell, if its the last selectable cell then move to the next rows last cell - private moveArrowRight(row:number, col: number):void{ + private moveArrowRight(row: number, col: number): void { const newRow = col === this.maxcol ? row + 1 : row; const newcol = col === this.maxcol ? 0 : col + 1; this.moveFocusTo(newRow, newcol); } // Focus the cell left to the current cell, if its the first selectable cell then move to the previous rows last cell - private moveArrowLeft(row:number, col: number):void{ + private moveArrowLeft(row: number, col: number): void { const newRow = col === 0 ? row - 1 : row; const newcol = col === 0 ? this.maxcol : col - 1; this.moveFocusTo(newRow, newcol); } // If you click CTRL + Home than focus the first cell of the first column, else first cell of the current column - private moveHome(event: KeyboardEvent, row:number):void{ + private moveHome(event: KeyboardEvent, row: number): void { if (event.ctrlKey) { let newRow = 0; let result; @@ -156,7 +156,7 @@ export class TableAccessiblilityDirective implements AfterViewChecked, AfterView event.preventDefault(); } // If you click CTRL + End than focus the last cell of the last column, else last cell of the current column - private moveEnd(event: KeyboardEvent, row:number):void{ + private moveEnd(event: KeyboardEvent, row: number): void { if (event.ctrlKey) { let newRow = this.maxrow; let result; @@ -169,15 +169,12 @@ export class TableAccessiblilityDirective implements AfterViewChecked, AfterView newRow--; } while (!result); } else { - this.moveFocusTo( - row, - this.maxcol - ); + this.moveFocusTo(row, this.maxcol); } event.preventDefault(); } // Focus the first cell of the current column - private movePageUp(col: number):void{ + private movePageUp(col: number): void { let newRow = 0; let result; do { @@ -186,7 +183,7 @@ export class TableAccessiblilityDirective implements AfterViewChecked, AfterView } while (!result); } // Focus the last cell of the current column - private movePageDown(col: number):void{ + private movePageDown(col: number): void { let newRow = this.maxrow; let result; do { diff --git a/imxweb/projects/qbm/src/lib/data-tiles/data-tile-menu-item.interface.ts b/imxweb/projects/qbm/src/lib/data-tiles/data-tile-menu-item.interface.ts index 1c3872f90..23a8e5a6f 100644 --- a/imxweb/projects/qbm/src/lib/data-tiles/data-tile-menu-item.interface.ts +++ b/imxweb/projects/qbm/src/lib/data-tiles/data-tile-menu-item.interface.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -24,7 +24,7 @@ * */ -import { TypedEntity } from 'imx-qbm-dbts'; +import { TypedEntity } from '@imx-modules/imx-qbm-dbts'; /** * Interface that represents a menu item and the typed entity attached to the correspondig tile. diff --git a/imxweb/projects/qbm/src/lib/data-tiles/data-tile.component.html b/imxweb/projects/qbm/src/lib/data-tiles/data-tile.component.html index ec52c0bcd..5d12296b1 100644 --- a/imxweb/projects/qbm/src/lib/data-tiles/data-tile.component.html +++ b/imxweb/projects/qbm/src/lib/data-tiles/data-tile.component.html @@ -2,42 +2,60 @@
    -
    - {{badge.content | translate}} +
    + {{ badge.content | translate }}
    - +
    - + -
    - +
    +
    -
    - {{getTitleDisplayValue(titleObject.ColumnName)}} +
    + {{ getTitleDisplayValue(titleObject.ColumnName) }}
    -
    -
    - {{getTitleDisplayValue(subtitleObject.ColumnName)}} +
    +
    + {{ getTitleDisplayValue(subtitleObject.ColumnName) }}
    -
    - {{getAdditionalColumnText()}} +
    + {{ getAdditionalColumnText() }}
    @@ -50,12 +68,17 @@ - diff --git a/imxweb/projects/qbm/src/lib/data-tiles/data-tile.component.scss b/imxweb/projects/qbm/src/lib/data-tiles/data-tile.component.scss index 8a7f6a12a..769f7ebab 100644 --- a/imxweb/projects/qbm/src/lib/data-tiles/data-tile.component.scss +++ b/imxweb/projects/qbm/src/lib/data-tiles/data-tile.component.scss @@ -1,10 +1,6 @@ @import '@elemental-ui/core/src/styles/_palette.scss'; @import '@elemental-ui/core/src/styles/_eui_palette.scss'; -@mixin imx-data-tile-title-mixin { - white-space: nowrap; - overflow: hidden; - text-overflow: ellipsis; -} +@import 'base/mixins'; :host { margin: 10px 20px 10px 10px; @@ -50,7 +46,7 @@ } } -.mat-card { +.mat-mdc-card { cursor: pointer; width: 340px; height: 140px; @@ -68,7 +64,7 @@ padding: 0 5px 0 5px; } -.mat-mini-fab[disabled] { +.mat-mdc-mini-fab[disabled] { cursor: pointer; } @@ -81,7 +77,7 @@ } .imx-data-tile-title { - @include imx-data-tile-title-mixin(); + @include text-overflow-ellipsis; font-weight: bold; margin: 0; grid-column-start: 2; @@ -91,7 +87,7 @@ } .imx-data-tile-subtitle { - @include imx-data-tile-title-mixin(); + @include text-overflow-ellipsis; font-size: small; color: $black-9; margin: 0 0 10px 0; @@ -100,7 +96,7 @@ grid-row-start: 2; grid-row-end: 3; align-self: end; - display:flex; + display: flex; flex-direction: column; } @@ -134,7 +130,7 @@ .eui-dark-theme { :host { - .imx-data-tile-container{ + .imx-data-tile-container { background-color: $color-gray-70; } } @@ -142,7 +138,7 @@ .eui-contrast-theme { :host { - .imx-data-tile-container{ + .imx-data-tile-container { background-color: $color-gray-90; } } diff --git a/imxweb/projects/qbm/src/lib/data-tiles/data-tile.component.ts b/imxweb/projects/qbm/src/lib/data-tiles/data-tile.component.ts index c17495b1a..fb6d36739 100644 --- a/imxweb/projects/qbm/src/lib/data-tiles/data-tile.component.ts +++ b/imxweb/projects/qbm/src/lib/data-tiles/data-tile.component.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -24,17 +24,17 @@ * */ -import { Component, Input, EventEmitter, Output, TemplateRef, ViewChild, OnInit } from '@angular/core'; +import { Component, EventEmitter, Input, OnInit, Output, TemplateRef, ViewChild } from '@angular/core'; import { MatButton } from '@angular/material/button'; import { MatMenuTrigger } from '@angular/material/menu'; -import { TypedEntity, IClientProperty } from 'imx-qbm-dbts'; +import { IClientProperty, TypedEntity } from '@imx-modules/imx-qbm-dbts'; -import { DataTileBadge } from '../data-source-toolbar/data-tile-badge.interface'; -import { DataTileMenuItem } from './data-tile-menu-item.interface'; -import { Base64ImageService } from '../images/base64-image.service'; import { SafeUrl } from '@angular/platform-browser'; import { DataSourceItemStatus } from '../data-source-toolbar/data-source-item-status.interface'; +import { DataTileBadge } from '../data-source-toolbar/data-tile-badge.interface'; +import { Base64ImageService } from '../images/base64-image.service'; +import { DataTileMenuItem } from './data-tile-menu-item.interface'; /** * A single tile component used internally by the tiles components. @@ -43,28 +43,26 @@ import { DataSourceItemStatus } from '../data-source-toolbar/data-source-item-st @Component({ selector: 'imx-data-tile', templateUrl: './data-tile.component.html', - styleUrls: ['./data-tile.component.scss'] + styleUrls: ['./data-tile.component.scss'], }) export class DataTileComponent implements OnInit { /** * If present the badges will be shown in the upper right corner. Can be used e.g. to show different states. */ - public get badges(): DataTileBadge[] { - return this.status?.getBadges ? - this.status.getBadges(this.typedEntity) : undefined; + public get badges(): DataTileBadge[] | undefined { + return this.status?.getBadges ? this.status.getBadges(this.typedEntity) : undefined; } public get enabled(): boolean { - return this.status?.enabled ? - this.status.enabled(this.typedEntity) : true; + return this.status?.enabled ? this.status.enabled(this.typedEntity) : true; } public get hasImage(): boolean { - return (this.image || this.status?.getImagePath || this.fallbackIcon) ? true : false; + return this.image || this.status?.getImagePath || this.fallbackIcon ? true : false; } public get filteredActions(): DataTileMenuItem[] { - return this.enabled ? this.actions : this.actions.filter(elem => elem.useOnDisabledTile); + return this.enabled ? this.actions : this.actions.filter((elem) => elem.useOnDisabledTile); } public isLoadingImage: boolean; @@ -101,7 +99,6 @@ export class DataTileComponent implements OnInit { */ @Input() public additionalSubtitleObjects: IClientProperty[] = []; - /** * The property of the typed entity that will be used as the subtitle of the tile. */ @@ -130,22 +127,22 @@ export class DataTileComponent implements OnInit { @Input() public actions: DataTileMenuItem[]; /** - * The width of the tile. - */ + * The width of the tile. + */ @Input() public width = '340px'; /** - * The height of the tile. - */ + * The height of the tile. + */ @Input() public height = '140px'; @Input() public useActionMenu = true; /** - * Status of this item. If the property enabled is true, the item is selectable. - */ + * Status of this item. If the property enabled is true, the item is selectable. + */ @Input() public status: DataSourceItemStatus = { - enabled: __ => true + enabled: (__) => true, }; /** @@ -163,7 +160,7 @@ export class DataTileComponent implements OnInit { @Output() public selected = new EventEmitter(); // TODO: Check Upgrade - @Output() public badgeClicked = new EventEmitter<{ entity: TypedEntity, badge: DataTileBadge }>(); + @Output() public badgeClicked = new EventEmitter<{ entity: TypedEntity; badge: DataTileBadge }>(); /** * A icon button that indicates if the tile is selected. @@ -177,17 +174,15 @@ export class DataTileComponent implements OnInit { */ @ViewChild(MatMenuTrigger) public menuTrigger: MatMenuTrigger; - constructor(private readonly base64ImageService: Base64ImageService) { } + constructor(private readonly base64ImageService: Base64ImageService) {} public async ngOnInit(): Promise { if (this.status?.getImagePath) { this.isLoadingImage = true; this.imageUrl = await this.status.getImagePath(this.typedEntity); - this.isLoadingImage = false; + this.isLoadingImage = false; } else if (this.image?.ColumnName) { - this.imageUrl = this.base64ImageService.addBase64Prefix( - this.typedEntity.GetEntity().GetColumn(this.image.ColumnName).GetValue() - ); + this.imageUrl = this.base64ImageService.addBase64Prefix(this.typedEntity.GetEntity().GetColumn(this.image.ColumnName).GetValue()); } } @@ -195,14 +190,19 @@ export class DataTileComponent implements OnInit { * Used by the template to show the title or subtitle. * @ignore Used internally in components template. */ - public getTitleDisplayValue(colName: string): string { - return this.typedEntity.GetEntity().GetColumn(colName).GetDisplayValue(); + public getTitleDisplayValue(colName: string | undefined): string { + return colName ? this.typedEntity.GetEntity().GetColumn(colName).GetDisplayValue() : ''; } - public getAdditionalColumnText(): string { - return this.additionalSubtitleObjects.map(elem => - this.typedEntity.GetEntity().GetColumn(elem.ColumnName).GetDisplayValue()).join('; '); + return this.additionalSubtitleObjects + .map((elem) => + this.typedEntity + .GetEntity() + .GetColumn(elem.ColumnName ?? '') + .GetDisplayValue(), + ) + .join('; '); } public getDefaultTypeNameImage() { @@ -222,7 +222,7 @@ export class DataTileComponent implements OnInit { this.isSelected = !this.isSelected; this.selectionChanged.emit(this.typedEntity); //tile selection - if(!this.isSelected){ + if (!this.isSelected) { this.selected.emit(this.isSelected); } } diff --git a/imxweb/projects/qbm/src/lib/data-tiles/data-tiles.component.html b/imxweb/projects/qbm/src/lib/data-tiles/data-tiles.component.html index 91ab89d19..feb11a73d 100644 --- a/imxweb/projects/qbm/src/lib/data-tiles/data-tiles.component.html +++ b/imxweb/projects/qbm/src/lib/data-tiles/data-tiles.component.html @@ -1,5 +1,4 @@ - -
    +
    - - -
    - -

    -
    + +
    + +

    +
    diff --git a/imxweb/projects/qbm/src/lib/data-tiles/data-tiles.component.scss b/imxweb/projects/qbm/src/lib/data-tiles/data-tiles.component.scss index 62ef1c7b4..b2b0e8430 100644 --- a/imxweb/projects/qbm/src/lib/data-tiles/data-tiles.component.scss +++ b/imxweb/projects/qbm/src/lib/data-tiles/data-tiles.component.scss @@ -8,7 +8,7 @@ flex: auto; } -.imx-data-container{ +.imx-data-container { display: flex; flex-wrap: wrap; overflow-y: auto; @@ -16,19 +16,14 @@ } .hidden { - display:none; + display: none; } -.imx-data-tiles-no-results { +.imx-no-results { text-align: center; margin: 20px 0; flex: auto; - .eui-icon { - font-size: 100px; - color: rgba($color-gray-20, 0.55); - } - p { margin: 0; font-size: 18px; diff --git a/imxweb/projects/qbm/src/lib/data-tiles/data-tiles.component.ts b/imxweb/projects/qbm/src/lib/data-tiles/data-tiles.component.ts index 5c3c9c2b5..279c844b2 100644 --- a/imxweb/projects/qbm/src/lib/data-tiles/data-tiles.component.ts +++ b/imxweb/projects/qbm/src/lib/data-tiles/data-tiles.component.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -24,14 +24,14 @@ * */ -import { Component, Input, EventEmitter, Output, TemplateRef, OnDestroy, OnChanges, SimpleChanges, ChangeDetectorRef } from '@angular/core'; import { SelectionChange } from '@angular/cdk/collections'; +import { ChangeDetectorRef, Component, EventEmitter, Input, OnChanges, OnDestroy, Output, SimpleChanges, TemplateRef } from '@angular/core'; import { Subscription } from 'rxjs'; +import { IClientProperty, TypedEntity } from '@imx-modules/imx-qbm-dbts'; import { DataSourceToolbarComponent } from '../data-source-toolbar/data-source-toolbar.component'; -import { TypedEntity, IClientProperty } from 'imx-qbm-dbts'; -import { DataTileMenuItem } from './data-tile-menu-item.interface'; import { DataTileBadge } from '../data-source-toolbar/data-tile-badge.interface'; +import { DataTileMenuItem } from './data-tile-menu-item.interface'; /** * A list component containing {@link SingleTileComponent| tiles}. @@ -130,7 +130,13 @@ export class DataTilesComponent implements OnChanges, OnDestroy { /** * The height of a tile. */ - @Input() public height: '140px'; + @Input() + get height(): string { + return this._height; + } + set height(value: string) { + this._height = value || '140px'; + } @Input() public useActionMenu = true; @@ -151,7 +157,7 @@ export class DataTilesComponent implements OnChanges, OnDestroy { /** * Event, that will fire when the user clicks on the badge. */ - @Output() public badgeClicked = new EventEmitter(); + @Output() public badgeClicked = new EventEmitter<{ entity: TypedEntity; badge: DataTileBadge }>(); /** * @ignore @@ -162,7 +168,7 @@ export class DataTilesComponent implements OnChanges, OnDestroy { /** * Keeps track of the selected item in single select mode */ - private selectedItem: TypedEntity; + private selectedItem: TypedEntity | undefined; /** * @ignore @@ -170,7 +176,9 @@ export class DataTilesComponent implements OnChanges, OnDestroy { */ private subscriptions: Subscription[] = []; - constructor(private readonly changeDetector: ChangeDetectorRef){} + private _height: string; + + constructor(private readonly changeDetector: ChangeDetectorRef) {} /** * @ignore Used internally. @@ -180,19 +188,20 @@ export class DataTilesComponent implements OnChanges, OnDestroy { public ngOnChanges(changes: SimpleChanges): void { if (changes['dst'] && changes['dst'].currentValue) { this.subscriptions.push( - this.dst.selectionChanged.subscribe((event: SelectionChange) => this.selectionChanged.emit(event.source.selected)) + this.dst.selectionChanged.subscribe((event: SelectionChange) => this.selectionChanged.emit(event.source.selected)), ); this.additionalSubtitleObjects = this.dst?.additionalListElements; if (this.dst.busyService) { - this.subscriptions.push(this.dst.busyService.busyStateChanged.subscribe((value:boolean)=>{ - this.isLoading = value; - this.changeDetector.detectChanges() - })); + this.subscriptions.push( + this.dst.busyService.busyStateChanged.subscribe((value: boolean) => { + this.isLoading = value; + this.changeDetector.detectChanges(); + }), + ); } this.isLoading = this.dst?.busyService?.isBusy ?? false; - } } @@ -213,7 +222,7 @@ export class DataTilesComponent implements OnChanges, OnDestroy { this.selectedItem = this.selectedEntity; } - return this.selectedItem && this.selectedItem.GetEntity().GetKeys().join() === item.GetEntity().GetKeys().join(); + return this.selectedItem?.GetEntity().GetKeys().join() === item.GetEntity().GetKeys().join(); } /** @@ -245,7 +254,7 @@ export class DataTilesComponent implements OnChanges, OnDestroy { this.dst.selectAllOnPage(); } - public onBadgeClicked(badge: DataTileBadge): void { + public onBadgeClicked(badge: { entity: TypedEntity; badge: DataTileBadge }): void { this.badgeClicked.emit(badge); } } diff --git a/imxweb/projects/qbm/src/lib/data-tiles/data-tiles.module.ts b/imxweb/projects/qbm/src/lib/data-tiles/data-tiles.module.ts index fd9ca858c..f91626019 100644 --- a/imxweb/projects/qbm/src/lib/data-tiles/data-tiles.module.ts +++ b/imxweb/projects/qbm/src/lib/data-tiles/data-tiles.module.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -40,10 +40,7 @@ import { DataTileComponent } from './data-tile.component'; import { BusyIndicatorModule } from '../busy-indicator/busy-indicator.module'; @NgModule({ - declarations: [ - DataTilesComponent, - DataTileComponent - ], + declarations: [DataTilesComponent, DataTileComponent], imports: [ CommonModule, EuiCoreModule, @@ -54,8 +51,8 @@ import { BusyIndicatorModule } from '../busy-indicator/busy-indicator.module'; MatMenuModule, MatBadgeModule, TranslateModule, - BusyIndicatorModule + BusyIndicatorModule, ], - exports: [ DataTilesComponent ], + exports: [DataTilesComponent], }) -export class DataTilesModule { } +export class DataTilesModule {} diff --git a/imxweb/projects/qbm/src/lib/data-tree-wrapper/data-tree-wrapper.component.html b/imxweb/projects/qbm/src/lib/data-tree-wrapper/data-tree-wrapper.component.html index a9f4698c9..05adbacda 100644 --- a/imxweb/projects/qbm/src/lib/data-tree-wrapper/data-tree-wrapper.component.html +++ b/imxweb/projects/qbm/src/lib/data-tree-wrapper/data-tree-wrapper.component.html @@ -1,5 +1,6 @@ + + + diff --git a/imxweb/projects/qbm/src/lib/data-tree-wrapper/data-tree-wrapper.component.scss b/imxweb/projects/qbm/src/lib/data-tree-wrapper/data-tree-wrapper.component.scss index 2b502e374..330412829 100644 --- a/imxweb/projects/qbm/src/lib/data-tree-wrapper/data-tree-wrapper.component.scss +++ b/imxweb/projects/qbm/src/lib/data-tree-wrapper/data-tree-wrapper.component.scss @@ -7,4 +7,4 @@ .imx-toolbar-margin { margin-bottom: 16px; } -} \ No newline at end of file +} diff --git a/imxweb/projects/qbm/src/lib/data-tree-wrapper/data-tree-wrapper.component.ts b/imxweb/projects/qbm/src/lib/data-tree-wrapper/data-tree-wrapper.component.ts index ebf979875..56e68cf54 100644 --- a/imxweb/projects/qbm/src/lib/data-tree-wrapper/data-tree-wrapper.component.ts +++ b/imxweb/projects/qbm/src/lib/data-tree-wrapper/data-tree-wrapper.component.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -26,7 +26,7 @@ import { Component, ContentChild, EventEmitter, Input, OnChanges, Output, TemplateRef, ViewChild } from '@angular/core'; -import { CollectionLoadParameters, EntitySchema, FilterData, IEntity } from 'imx-qbm-dbts'; +import { CollectionLoadParameters, EntitySchema, FilterData, IEntity } from '@imx-modules/imx-qbm-dbts'; import { FilterTreeParameter } from '../data-source-toolbar/data-model/filter-tree-parameter'; import { DataSourceToolbarFilter } from '../data-source-toolbar/data-source-toolbar-filters.interface'; import { DataSourceToolbarSettings } from '../data-source-toolbar/data-source-toolbar-settings'; @@ -58,6 +58,7 @@ export class DataTreeWrapperComponent implements OnChanges { @ViewChild('tree') public treeControl: DataTreeComponent; @ContentChild(TemplateRef, { static: true }) public templateRef: TemplateRef; + @ContentChild('customDisplay', { static: true }) public customDisplay: TemplateRef; @Output() public nodeSelected = new EventEmitter(); @Output() public checkedNodesChanged = new EventEmitter(); @@ -157,10 +158,10 @@ export class DataTreeWrapperComponent implements OnChanges { * @param entity entity, for identifying the node */ public deleteNode(entity: IEntity, withDescendants: boolean) { - this.treeControl.deleteNode(entity,withDescendants); + this.treeControl.deleteNode(entity, withDescendants); } - public getEntityById(id: string): IEntity { + public getEntityById(id: string): IEntity | undefined { return this.treeControl.getEntityById(id); } } diff --git a/imxweb/projects/qbm/src/lib/data-tree-wrapper/data-tree-wrapper.module.ts b/imxweb/projects/qbm/src/lib/data-tree-wrapper/data-tree-wrapper.module.ts index 20901d55e..d7bde71c1 100644 --- a/imxweb/projects/qbm/src/lib/data-tree-wrapper/data-tree-wrapper.module.ts +++ b/imxweb/projects/qbm/src/lib/data-tree-wrapper/data-tree-wrapper.module.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -32,20 +32,9 @@ import { DataTreeWrapperComponent } from './data-tree-wrapper.component'; import { DataSourceToolbarModule } from '../data-source-toolbar/data-source-toolbar.module'; import { DataTreeModule } from '../data-tree/data-tree.module'; - - @NgModule({ - declarations: [ - DataTreeWrapperComponent - ], - imports: [ - CommonModule, - DataSourceToolbarModule, - DataTreeModule, - TranslateModule - ], - exports: [ - DataTreeWrapperComponent - ] + declarations: [DataTreeWrapperComponent], + imports: [CommonModule, DataSourceToolbarModule, DataTreeModule, TranslateModule], + exports: [DataTreeWrapperComponent], }) -export class DataTreeWrapperModule { } +export class DataTreeWrapperModule {} diff --git a/imxweb/projects/qbm/src/lib/data-tree/checkable-tree/checkable-tree.component.html b/imxweb/projects/qbm/src/lib/data-tree/checkable-tree/checkable-tree.component.html index 9a6f69b5c..a27aaa49f 100644 --- a/imxweb/projects/qbm/src/lib/data-tree/checkable-tree/checkable-tree.component.html +++ b/imxweb/projects/qbm/src/lib/data-tree/checkable-tree/checkable-tree.component.html @@ -3,8 +3,13 @@ @@ -15,11 +20,15 @@ + + +

    + {{ node.display }} +

    +
    diff --git a/imxweb/projects/qbm/src/lib/data-tree/checkable-tree/checkable-tree.component.scss b/imxweb/projects/qbm/src/lib/data-tree/checkable-tree/checkable-tree.component.scss index 0fd21ea87..8bfeae86f 100644 --- a/imxweb/projects/qbm/src/lib/data-tree/checkable-tree/checkable-tree.component.scss +++ b/imxweb/projects/qbm/src/lib/data-tree/checkable-tree/checkable-tree.component.scss @@ -11,7 +11,7 @@ flex: 1 1 auto; text-align: left; min-width: 0; - > ::ng-deep .mat-button-wrapper { + > ::ng-deep .mdc-button__label { color: $color-gray-100; overflow: hidden; text-overflow: ellipsis; @@ -31,10 +31,6 @@ text-overflow: ellipsis; white-space: nowrap; } - mat-progress-bar { - flex-grow: 1; - width: auto; - } } .imx-tree-node:hover { @@ -71,7 +67,7 @@ } .imx-tree-node:hover { background-color: $color-gray-0; - color: $color-gray-100 + color: $color-gray-100; } } } diff --git a/imxweb/projects/qbm/src/lib/data-tree/checkable-tree/checkable-tree.component.ts b/imxweb/projects/qbm/src/lib/data-tree/checkable-tree/checkable-tree.component.ts index 6349cf3a8..589f5eb4d 100644 --- a/imxweb/projects/qbm/src/lib/data-tree/checkable-tree/checkable-tree.component.ts +++ b/imxweb/projects/qbm/src/lib/data-tree/checkable-tree/checkable-tree.component.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -41,7 +41,7 @@ import { import { MatCheckboxChange } from '@angular/material/checkbox'; import { Subscription } from 'rxjs'; -import { CollectionLoadParameters, IEntity } from 'imx-qbm-dbts'; +import { CollectionLoadParameters, IEntity } from '@imx-modules/imx-qbm-dbts'; import { ClassloggerService } from '../../classlogger/classlogger.service'; import { SnackBarService } from '../../snackbar/snack-bar.service'; import { TreeDatabase } from '../tree-database'; @@ -63,10 +63,12 @@ export class CheckableTreeComponent implements OnChanges, AfterViewInit, OnDestr /** the {@link FlatTreeControl| FlatTreeControl} of @angular/cdk */ public treeControl: FlatTreeControl; - @ContentChild(TemplateRef, { static: true }) public templateRef: TemplateRef; + //@ContentChild(TemplateRef, { static: true }) public templateRef: TemplateRef; + @ContentChild('customDisplayTemplate', { static: true }) public customDisplayTemplate: TemplateRef; + @ContentChild('additionalTemplate', { static: true }) public templateRef: TemplateRef; /** currently selected entities */ - @Input() public selectedEntities: IEntity[] = []; + @Input() public selectedEntities: (IEntity | undefined)[] = []; /** the service providing the data for the {@link TreeDatasource| TreeDatasource} */ @Input() public database: TreeDatabase; @@ -111,7 +113,10 @@ export class CheckableTreeComponent implements OnChanges, AfterViewInit, OnDestr private subscriptions: Subscription[] = []; - constructor(private readonly snackBar: SnackBarService, private readonly logger: ClassloggerService) { + constructor( + private readonly snackBar: SnackBarService, + private readonly logger: ClassloggerService, + ) { this.treeControl = new FlatTreeControl(this.getLevel, this.isExpandable); } @@ -129,7 +134,7 @@ export class CheckableTreeComponent implements OnChanges, AfterViewInit, OnDestr this.treeDataSource.dataChange.subscribe((elem) => { this.treeRendered.emit(); this.updateCheckedTreeNodes(elem); - }) + }), ); this.logger.debug(this, `toggle Node of the selected entity to load its children`); @@ -167,7 +172,7 @@ export class CheckableTreeComponent implements OnChanges, AfterViewInit, OnDestr if (data) { this.initializeTreeData(); } - }) + }), ); } } @@ -189,7 +194,9 @@ export class CheckableTreeComponent implements OnChanges, AfterViewInit, OnDestr */ public add(childEntity: IEntity, uidParent: string) { const node = this.treeDataSource.data.find((elem) => this.getId(elem.item) === uidParent); - this.treeDataSource.addChildNode(node, childEntity); + if (node) { + this.treeDataSource.addChildNode(node, childEntity); + } } /** @@ -199,7 +206,9 @@ export class CheckableTreeComponent implements OnChanges, AfterViewInit, OnDestr */ public updateNode(entity: IEntity, newNodeInfo: TreeNodeInfo) { const node = this.getNode(entity); - this.treeDataSource.updateNode(node, newNodeInfo); + if (node) { + this.treeDataSource.updateNode(node, newNodeInfo); + } } /** @@ -208,8 +217,15 @@ export class CheckableTreeComponent implements OnChanges, AfterViewInit, OnDestr */ public deleteNode(entity: IEntity, withChildren: boolean) { const node = this.getNode(entity); + if (!node) { + return; + } const parent = this.getParentNode(node); - this.treeDataSource.removeNode(node,withChildren); + this.treeDataSource.removeNode(node, withChildren); + + if (!parent) { + return; + } const des = this.treeControl.getDescendants(parent).filter((elem) => !elem.isLoadMoreNode); if (des.length === 0 || withChildren) { @@ -227,16 +243,17 @@ export class CheckableTreeComponent implements OnChanges, AfterViewInit, OnDestr public isExpanded(entity: IEntity): boolean { const node = this.getNode(entity); - return this.treeControl.isExpanded(node); + return node ? this.treeControl.isExpanded(node) : false; } - public getEntityById(id: string): IEntity { + public getEntityById(id: string): IEntity | undefined { const node = this.treeDataSource.data.find((elem) => this.getId(elem.item) === id); return node?.item; } public hasChildren(entity: IEntity): boolean { - return this.isExpandable(this.getNode(entity)); + const node = this.getNode(entity); + return node ? this.isExpandable(node) : false; } /** returns true, if the node has childnodes */ @@ -246,6 +263,10 @@ export class CheckableTreeComponent implements OnChanges, AfterViewInit, OnDestr /** Emits the selected treenode. */ public selectNode(node: TreeNode): void { + if (!node.isSelectable) { + // node is not selectable + return; + } if (this.withMultiSelect) { this.checklistSelection.toggle(node); this.emitNodeCheckedEvent(node, this.checklistSelection.isSelected(node)); @@ -317,11 +338,11 @@ export class CheckableTreeComponent implements OnChanges, AfterViewInit, OnDestr this.treeDataSource?.init(await this.database.initialize(this.navigationState)); } - private getSelectedItem(): string { + private getSelectedItem(): string | null | undefined { return this.selectedEntities.length > 0 && this.selectedEntities[0] != null ? this.getId(this.selectedEntities[0]) : null; } - private getNode(entity: IEntity): TreeNode { + private getNode(entity: IEntity): TreeNode | undefined { return this.treeDataSource?.data.find((elem) => this.getId(elem.item) === this.getId(entity)); } @@ -382,8 +403,8 @@ export class CheckableTreeComponent implements OnChanges, AfterViewInit, OnDestr } } - private updateSelectedEntities(current: IEntity, checked: boolean): void { - if (checked) { + private updateSelectedEntities(current: IEntity | undefined, checked: boolean): void { + if (checked && current) { this.selectedEntities.push(current); } else { const index = this.selectedEntities.findIndex((elem) => this.getId(elem) === this.getId(current)); @@ -391,7 +412,7 @@ export class CheckableTreeComponent implements OnChanges, AfterViewInit, OnDestr } } - private getId(entity: IEntity): string { - return this.database ? this.database.getId(entity) : entity.GetKeys()[0]; + private getId(entity: IEntity | undefined): string { + return this.database ? this.database.getId(entity) : entity?.GetKeys()[0] ?? ''; } } diff --git a/imxweb/projects/qbm/src/lib/data-tree/data-tree-no-results.scss b/imxweb/projects/qbm/src/lib/data-tree/data-tree-no-results.scss index 9e69be81a..a7b0f9d45 100644 --- a/imxweb/projects/qbm/src/lib/data-tree/data-tree-no-results.scss +++ b/imxweb/projects/qbm/src/lib/data-tree/data-tree-no-results.scss @@ -1,6 +1,6 @@ -@import "@elemental-ui/core/src/styles/_palette.scss"; +@import '@elemental-ui/core/src/styles/_palette.scss'; -.imx-data-tree-no-results { +.imx-no-results { text-align: center; display: flex; margin: 20px 0; @@ -8,11 +8,6 @@ justify-content: center; flex-direction: column; align-items: center; - - .eui-icon { - font-size: 100px; - color: rgba($black-c, 0.55); - } p { margin: 0; diff --git a/imxweb/projects/qbm/src/lib/data-tree/data-tree-search-results/data-tree-search-results.component.html b/imxweb/projects/qbm/src/lib/data-tree/data-tree-search-results/data-tree-search-results.component.html index 6cf093f2b..be7c04dd3 100644 --- a/imxweb/projects/qbm/src/lib/data-tree/data-tree-search-results/data-tree-search-results.component.html +++ b/imxweb/projects/qbm/src/lib/data-tree/data-tree-search-results/data-tree-search-results.component.html @@ -1,11 +1,20 @@ - - + +
    @@ -18,13 +27,18 @@ - + -
    +

    @@ -32,20 +46,22 @@ - -
    +
    -
    -

    - {{ result.GetDisplayLong() }} -

    -
    - - + (click)="resultClicked(result)" + > +
    +

    + {{ result.GetDisplayLong() }} +

    + +
    - \ No newline at end of file + diff --git a/imxweb/projects/qbm/src/lib/data-tree/data-tree-search-results/data-tree-search-results.component.scss b/imxweb/projects/qbm/src/lib/data-tree/data-tree-search-results/data-tree-search-results.component.scss index e101d8410..edc6de0e5 100644 --- a/imxweb/projects/qbm/src/lib/data-tree/data-tree-search-results/data-tree-search-results.component.scss +++ b/imxweb/projects/qbm/src/lib/data-tree/data-tree-search-results/data-tree-search-results.component.scss @@ -1,4 +1,4 @@ -@import "@elemental-ui/core/src/styles/_palette.scss"; +@import '@elemental-ui/core/src/styles/_palette.scss'; @import '@elemental-ui/core/src/styles/_eui_palette.scss'; :host { @@ -15,16 +15,10 @@ .imx-search-results { flex: 1 1 auto; overflow-y: auto; + ::ng-deep.mat-pseudo-checkbox { display: none !important; } - ::ng-deep.mat-list-option { - height: auto; - } - - ::ng-deep.mat-list-item { - height: auto; - } } .imx-selected-candidate { @@ -34,12 +28,6 @@ .imx-search-results-multi { flex: 1 1 auto; overflow-y: auto; - ::ng-deep.mat-list-option { - background-color: transparent; - } - ::ng-deep.mat-list-option:hover { - background-color: $asher-gray; - } } .imx-candidate-option { @@ -104,8 +92,7 @@ flex: 1 1 auto; text-align: left; min-width: 0; - - > ::ng-deep .mat-button-wrapper { + > ::ng-deep .mdc-button__label { color: $black; overflow: hidden; text-overflow: ellipsis; @@ -131,9 +118,8 @@ background-color: $asher-gray; } -.eui-dark-theme{ - :host{ - +.eui-dark-theme { + :host { .imx-background-highlight { background-color: $color-gray-60; } @@ -154,27 +140,20 @@ background-color: $color-gray-60; } - .imx-search-results-multi { - ::ng-deep.mat-list-option:hover { - background-color: $color-gray-60; - } - } - .imx-search-result-item { - > ::ng-deep .mat-button-wrapper { + > ::ng-deep .mdc-button__label { color: $color-gray-2; } } - .imx-search-result-item:hover{ + .imx-search-result-item:hover { background-color: $color-gray-60; } } } -.eui-contrast-theme{ - :host{ - +.eui-contrast-theme { + :host { .imx-background-highlight { background-color: $color-gray-80; } @@ -195,19 +174,13 @@ background-color: $color-gray-80; } - .imx-search-results-multi { - ::ng-deep.mat-list-option:hover { - background-color: $color-gray-80; - } - } - .imx-search-result-item { - > ::ng-deep .mat-button-wrapper { + > ::ng-deep .mdc-button__label { color: $color-gray-0; } } - .imx-search-result-item:hover{ + .imx-search-result-item:hover { background-color: $color-gray-80; } } diff --git a/imxweb/projects/qbm/src/lib/data-tree/data-tree-search-results/data-tree-search-results.component.ts b/imxweb/projects/qbm/src/lib/data-tree/data-tree-search-results/data-tree-search-results.component.ts index aa69e939a..9bb1bb74f 100644 --- a/imxweb/projects/qbm/src/lib/data-tree/data-tree-search-results/data-tree-search-results.component.ts +++ b/imxweb/projects/qbm/src/lib/data-tree/data-tree-search-results/data-tree-search-results.component.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -28,24 +28,23 @@ import { Component, ContentChild, EventEmitter, Input, OnChanges, Output, Simple import { MatSelectionListChange } from '@angular/material/list'; import { PageEvent } from '@angular/material/paginator'; -import { CollectionLoadParameters, IEntity } from 'imx-qbm-dbts'; +import { CollectionLoadParameters, IEntity } from '@imx-modules/imx-qbm-dbts'; import { ClassloggerService } from '../../classlogger/classlogger.service'; +import { SettingsService } from '../../settings/settings-service'; import { TreeDatabase } from '../tree-database'; -import { SettingsService} from '../../settings/settings-service'; @Component({ selector: 'imx-data-tree-search-results', templateUrl: './data-tree-search-results.component.html', - styleUrls: ['./data-tree-search-results.component.scss', '../data-tree-no-results.scss'] + styleUrls: ['./data-tree-search-results.component.scss', '../data-tree-no-results.scss'], }) /** A component, that can display the search result for a{@link DataTreeComponent|data tree} */ export class DataTreeSearchResultsComponent implements OnChanges { - /** determines whether the control allows multiselect or not */ @Input() public withMultiSelect: boolean; /** currently selected entities */ - @Input() public selectedEntities: IEntity[] = []; + @Input() public selectedEntities: (IEntity | undefined)[] = []; /** * This text will be displayed when a search or filter is applied but there is no data as a result @@ -93,7 +92,10 @@ export class DataTreeSearchResultsComponent implements OnChanges { /** event, that fires, after the checked nodes list has been updated */ @Output() public checkedNodesChanged = new EventEmitter(); - constructor(private readonly logger: ClassloggerService, private readonly settings: SettingsService) { + constructor( + private readonly logger: ClassloggerService, + private readonly settings: SettingsService, + ) { this.paginatorPageSize = this.settings?.DefaultPageSize ?? 25; } @@ -107,7 +109,7 @@ export class DataTreeSearchResultsComponent implements OnChanges { public compareFunction = (o1: any, o2: any) => { this.logger.log(this, 'compare', o1, o2); return this.getId(o1) === this.getId(o2); - } + }; /** * clears all selected nodes for the tree and listings @@ -118,14 +120,13 @@ export class DataTreeSearchResultsComponent implements OnChanges { public async reload(): Promise { this.loading = true; - const data = await this.database.getData(true, this.navigationState); + const data = await this.database?.getData(true, this.navigationState); this.loading = false; - this.paginatorLength = data.totalCount; - this.searchResults = data.entities; - this.selectedOptions = this.searchResults.filter(elem => this.entityIsChecked(elem)); + this.paginatorLength = data?.totalCount ?? 0; + this.searchResults = data?.entities ?? []; + this.selectedOptions = this.searchResults.filter((elem) => this.entityIsChecked(elem)); } - /** @ignore updates the selection list an emits the according events */ public onSelectionChanged(selection: MatSelectionListChange): void { this.updateSelectedEntities(selection.options[0].value, selection.options[0].selected); @@ -149,39 +150,44 @@ export class DataTreeSearchResultsComponent implements OnChanges { ...{ StartIndex: newState.pageIndex * newState.pageSize, PageSize: newState.pageSize, - } + }, }; - const data = await this.database.getData(true, state); + const data = await this.database?.getData(true, state); this.loading = false; - this.searchResults = data.entities; - this.selectedOptions = this.searchResults.filter(elem => this.entityIsChecked(elem)); - this.paginatorLength = data.totalCount; + this.searchResults = data?.entities ?? []; + this.selectedOptions = this.searchResults.filter((elem) => this.entityIsChecked(elem)); + this.paginatorLength = data?.totalCount ?? 0; } /** @ignore checks, if an element is selected or not */ public isSelected(value: IEntity): boolean { - if (this.withMultiSelect) { return false; } - return this.selectedEntities.some(elem => this.getId(elem) === this.getId(value)); + if (this.withMultiSelect) { + return false; + } + return this.selectedEntities.some((elem) => this.getId(elem) === this.getId(value)); } private updateSelectedEntities(current: IEntity, checked: boolean): void { if (checked) { this.selectedEntities.push(current); } else { - const index = this.selectedEntities.findIndex(elem => this.getId(elem) === this.getId(current)); + const index = this.selectedEntities.findIndex((elem) => this.getId(elem) === this.getId(current)); this.selectedEntities.splice(index, 1); } } private entityIsChecked(entity: IEntity): boolean { - this.logger.log(this, 'Keys', + this.logger.log( + this, + 'Keys', this.selectedEntities, - this.getId(entity), this.selectedEntities.some(elem => this.getId(entity) === this.getId(elem))); - return this.selectedEntities.some(elem => this.getId(entity) === this.getId(elem)); + this.getId(entity), + this.selectedEntities.some((elem) => this.getId(entity) === this.getId(elem)), + ); + return this.selectedEntities.some((elem) => this.getId(entity) === this.getId(elem)); } - private getId(entity: IEntity): string { + private getId(entity: IEntity | undefined): string { return TreeDatabase.getId(entity); - } - + } } diff --git a/imxweb/projects/qbm/src/lib/data-tree/data-tree-search-results/search-result-action.interface.ts b/imxweb/projects/qbm/src/lib/data-tree/data-tree-search-results/search-result-action.interface.ts index 6d92a35f8..0582e1c44 100644 --- a/imxweb/projects/qbm/src/lib/data-tree/data-tree-search-results/search-result-action.interface.ts +++ b/imxweb/projects/qbm/src/lib/data-tree/data-tree-search-results/search-result-action.interface.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -24,7 +24,7 @@ * */ -import { IEntity } from 'imx-qbm-dbts'; +import { IEntity } from '@imx-modules/imx-qbm-dbts'; export interface SearchResultAction { action: (entity: IEntity) => Promise; diff --git a/imxweb/projects/qbm/src/lib/data-tree/data-tree.component.html b/imxweb/projects/qbm/src/lib/data-tree/data-tree.component.html index 699c91b18..3a7964925 100644 --- a/imxweb/projects/qbm/src/lib/data-tree/data-tree.component.html +++ b/imxweb/projects/qbm/src/lib/data-tree/data-tree.component.html @@ -7,7 +7,6 @@ [disabled]="selectedEntities.length === 0" mat-flat-button class="imx-data-table-selection-info mat-caption" - (click)="onOpenSelectionDialog()" data-imx-identifier="datatree-button-show-selected" > {{ '#LDS#Selected items' | translate }} ({{ selectedEntities.length }}) @@ -30,6 +29,9 @@ + + +
    @@ -53,8 +55,12 @@ -
    +

    + + +

    {{data.display}}

    +
    diff --git a/imxweb/projects/qbm/src/lib/data-tree/data-tree.component.scss b/imxweb/projects/qbm/src/lib/data-tree/data-tree.component.scss index e3fd0e09a..441f57b0a 100644 --- a/imxweb/projects/qbm/src/lib/data-tree/data-tree.component.scss +++ b/imxweb/projects/qbm/src/lib/data-tree/data-tree.component.scss @@ -1,4 +1,4 @@ -@import "@elemental-ui/core/src/styles/_palette.scss"; +@import '@elemental-ui/core/src/styles/_palette.scss'; :host { display: flex; @@ -7,30 +7,12 @@ flex: 1 1 auto; } -.multi-select-formcontrol-eui-search { - width: 100%; - display: flex; - - .eui-search { - width: 100%; - } - - ::ng-deep .eui-search.mat-form-field.mat-form-field-appearance-outline { - min-width: 280px; - flex: 1; - margin-bottom: 10px; - } -} - -.mat-form-field { - flex: 1; -} - .imx-data-tree-content { flex: 1 1 auto; overflow-y: auto; display: flex; flex-direction: column; + padding-left: 10px; } .imx-search-selection { @@ -40,10 +22,6 @@ overflow-y: auto; } -.mat-tree-node .mat-icon-button.mat-button-base { - flex: 0 0 40px; -} - .imx-selected-items-button-containter { display: flex; flex-direction: row; @@ -58,4 +36,4 @@ .hidden { display: none; -} \ No newline at end of file +} diff --git a/imxweb/projects/qbm/src/lib/data-tree/data-tree.component.ts b/imxweb/projects/qbm/src/lib/data-tree/data-tree.component.ts index b011e1874..5387daea9 100644 --- a/imxweb/projects/qbm/src/lib/data-tree/data-tree.component.ts +++ b/imxweb/projects/qbm/src/lib/data-tree/data-tree.component.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -41,13 +41,14 @@ import { EuiSidesheetService } from '@elemental-ui/core'; import { TranslateService } from '@ngx-translate/core'; import { Subscription } from 'rxjs'; -import { CollectionLoadParameters, IEntity } from 'imx-qbm-dbts'; +import { CollectionLoadParameters, IEntity } from '@imx-modules/imx-qbm-dbts'; +import { calculateSidesheetWidth } from '../base/sidesheet-helper'; import { ClassloggerService } from '../classlogger/classlogger.service'; import { CheckableTreeComponent } from './checkable-tree/checkable-tree.component'; import { DataTreeSearchResultsComponent } from './data-tree-search-results/data-tree-search-results.component'; import { TreeDatabase } from './tree-database'; -import { TreeSelectionListComponent } from './tree-selection-list/tree-selection-list.component'; import { TreeNodeInfo } from './tree-node'; +import { TreeSelectionListComponent } from './tree-selection-list/tree-selection-list.component'; @Component({ selector: 'imx-data-tree', @@ -74,7 +75,7 @@ export class DataTreeComponent implements OnChanges, OnDestroy { @Input() public withSelectedNodeHighlight: boolean; /** currently selected entities */ - @Input() public selectedEntities: IEntity[] = []; + @Input() public selectedEntities: (IEntity | undefined)[] = []; /** the service providing the data for the {@link TreeDatasource| TreeDatasource} */ @Input() public database: TreeDatabase; @@ -119,6 +120,7 @@ export class DataTreeComponent implements OnChanges, OnDestroy { @ViewChild(DataTreeSearchResultsComponent) public searchResults: DataTreeSearchResultsComponent; @ContentChild(TemplateRef, { static: true }) public templateRef: TemplateRef; + @ContentChild('customDisplay') public customDisplay: TemplateRef; private subscriptions: Subscription[] = []; @@ -126,7 +128,7 @@ export class DataTreeComponent implements OnChanges, OnDestroy { public sidesheet: EuiSidesheetService, private readonly logger: ClassloggerService, private readonly translator: TranslateService, - private readonly changeDetector: ChangeDetectorRef + private readonly changeDetector: ChangeDetectorRef, ) {} public async ngOnChanges(changes: SimpleChanges): Promise { @@ -138,7 +140,7 @@ export class DataTreeComponent implements OnChanges, OnDestroy { this.database.busyService.busyStateChanged.subscribe((value: boolean) => { this.isLoading = value; this.changeDetector.detectChanges(); - }) + }), ); } this.isLoading = this.database?.busyService?.isBusy ?? false; @@ -182,7 +184,7 @@ export class DataTreeComponent implements OnChanges, OnDestroy { return this.simpleTree?.hasChildren(entity); } - public getEntityById(id: string): IEntity { + public getEntityById(id: string): IEntity | undefined { return this.simpleTree?.getEntityById(id); } @@ -217,7 +219,7 @@ export class DataTreeComponent implements OnChanges, OnDestroy { * @param entity entity, for identifying the node */ public deleteNode(entity: IEntity, withDescendants: boolean) { - this.simpleTree?.deleteNode(entity,withDescendants); + this.simpleTree?.deleteNode(entity, withDescendants); } /** @ignore opens a side sheet containing the {@link TreeSelectionListComponent|selected elements} */ @@ -226,19 +228,19 @@ export class DataTreeComponent implements OnChanges, OnDestroy { title: await this.translator.get('#LDS#Heading Selected Items').toPromise(), panelClass: 'imx-sidesheet', padding: '0', - width: '50%', + width: calculateSidesheetWidth(800, 0.5), testId: 'data-tree-selected-elements-sidesheet', data: this.selectedEntities, }); this.subscriptions.push( sidesheetRef.afterClosed().subscribe((result) => { - this.logger.log(this, 'The side sheet was closed', result); - }) + this.logger.log(this, 'The sidesheet was closed', result); + }), ); } public hasSearchResults(): boolean { - return this.navigationState?.search && this.navigationState?.search !== null && this.navigationState?.search !== ''; + return (this.navigationState?.search ?? '') !== ''; } } diff --git a/imxweb/projects/qbm/src/lib/data-tree/data-tree.module.ts b/imxweb/projects/qbm/src/lib/data-tree/data-tree.module.ts index 7739565c8..31f441cb9 100644 --- a/imxweb/projects/qbm/src/lib/data-tree/data-tree.module.ts +++ b/imxweb/projects/qbm/src/lib/data-tree/data-tree.module.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -47,14 +47,13 @@ import { CheckableTreeComponent } from './checkable-tree/checkable-tree.componen import { DataTreeSearchResultsComponent } from './data-tree-search-results/data-tree-search-results.component'; import { BusyIndicatorModule } from '../busy-indicator/busy-indicator.module'; - @NgModule({ declarations: [ DataTreeComponent, MatSelectionListMultipleDirective, TreeSelectionListComponent, CheckableTreeComponent, - DataTreeSearchResultsComponent + DataTreeSearchResultsComponent, ], imports: [ ClassloggerModule, @@ -71,10 +70,8 @@ import { BusyIndicatorModule } from '../busy-indicator/busy-indicator.module'; TranslateModule, MatPaginatorModule, MatCardModule, - BusyIndicatorModule + BusyIndicatorModule, ], - exports: [ - DataTreeComponent - ] + exports: [DataTreeComponent], }) -export class DataTreeModule { } +export class DataTreeModule {} diff --git a/imxweb/projects/qbm/src/lib/data-tree/entity-tree-database.ts b/imxweb/projects/qbm/src/lib/data-tree/entity-tree-database.ts index 4cd315dc2..6fbed1f89 100644 --- a/imxweb/projects/qbm/src/lib/data-tree/entity-tree-database.ts +++ b/imxweb/projects/qbm/src/lib/data-tree/entity-tree-database.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -24,19 +24,18 @@ * */ -import { CollectionLoadParameters, IEntity } from 'imx-qbm-dbts'; +import { CollectionLoadParameters, IEntity } from '@imx-modules/imx-qbm-dbts'; import { BusyService } from '../base/busy.service'; import { TreeDatabase } from './tree-database'; import { TreeNodeResultParameter } from './tree-node-result-parameter.interface'; export class EntityTreeDatabase extends TreeDatabase { - constructor( private readonly getEntities: (parameters: CollectionLoadParameters) => Promise, - busyService: BusyService + busyService: BusyService, ) { super(); - this.busyService = busyService + this.busyService = busyService; } public async getData(showLoading: boolean, parameters: CollectionLoadParameters = {}): Promise { @@ -46,7 +45,7 @@ export class EntityTreeDatabase extends TreeDatabase { try { entities = await this.getEntities(parameters); - } finally { + } finally { isBusy?.endBusy(); } diff --git a/imxweb/projects/qbm/src/lib/data-tree/mat-selection-list-multiple-directive.ts b/imxweb/projects/qbm/src/lib/data-tree/mat-selection-list-multiple-directive.ts index ef7ad90aa..ed08fe964 100644 --- a/imxweb/projects/qbm/src/lib/data-tree/mat-selection-list-multiple-directive.ts +++ b/imxweb/projects/qbm/src/lib/data-tree/mat-selection-list-multiple-directive.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -29,25 +29,24 @@ import { Directive, Host, Input, OnChanges } from '@angular/core'; import { MatListOption, MatSelectionList } from '@angular/material/list'; @Directive({ - // tslint:disable-next-line: directive-selector - selector: 'mat-selection-list[multiple]' + // eslint-disable-next-line @angular-eslint/directive-selector + selector: 'mat-selection-list[multiple]', }) // TODO Later: kann wieder weg, wenn wir mal auf einen neuere Material - Version migrieren export class MatSelectionListMultipleDirective implements OnChanges { + @Input() public multiple: boolean; + private matSelectionList: MatSelectionList; - @Input() public multiple: boolean; - private matSelectionList: MatSelectionList; + constructor(@Host() matSelectionList: MatSelectionList) { + this.matSelectionList = matSelectionList; + } - constructor(@Host() matSelectionList: MatSelectionList) { - this.matSelectionList = matSelectionList; + public ngOnChanges(): void { + if (this.multiple) { + this.matSelectionList.selectedOptions = new SelectionModel(true, this.matSelectionList.selectedOptions.selected); + } else { + const selected = this.matSelectionList.selectedOptions.selected.splice(0, 1); + this.matSelectionList.selectedOptions = new SelectionModel(false, selected); } - - public ngOnChanges(): void { - if (this.multiple) { - this.matSelectionList.selectedOptions = new SelectionModel(true, this.matSelectionList.selectedOptions.selected); - } else { - const selected = this.matSelectionList.selectedOptions.selected.splice(0, 1); - this.matSelectionList.selectedOptions = new SelectionModel(false, selected); - } - } -} \ No newline at end of file + } +} diff --git a/imxweb/projects/qbm/src/lib/data-tree/node-checked-change.interface.ts b/imxweb/projects/qbm/src/lib/data-tree/node-checked-change.interface.ts index f6a712537..031a87137 100644 --- a/imxweb/projects/qbm/src/lib/data-tree/node-checked-change.interface.ts +++ b/imxweb/projects/qbm/src/lib/data-tree/node-checked-change.interface.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -24,7 +24,7 @@ * */ -import { IEntity } from 'imx-qbm-dbts'; +import { IEntity } from '@imx-modules/imx-qbm-dbts'; export interface NodeCheckedChange { /** entities for the node including parents */ diff --git a/imxweb/projects/qbm/src/lib/data-tree/tree-database.ts b/imxweb/projects/qbm/src/lib/data-tree/tree-database.ts index 0e2f85360..9b43801aa 100644 --- a/imxweb/projects/qbm/src/lib/data-tree/tree-database.ts +++ b/imxweb/projects/qbm/src/lib/data-tree/tree-database.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -24,22 +24,22 @@ * */ -import { Subject, BehaviorSubject } from 'rxjs'; import { EventEmitter } from '@angular/core'; +import { BehaviorSubject, Subject } from 'rxjs'; -import { CollectionLoadParameters, IEntity } from 'imx-qbm-dbts'; +import { CollectionLoadParameters, IEntity } from '@imx-modules/imx-qbm-dbts'; +import { BusyService } from '../base/busy.service'; import { TreeNode } from './tree-node'; import { TreeNodeResultParameter } from './tree-node-result-parameter.interface'; -import { BusyService } from '../base/busy.service'; /** * Data-provider for the data-tree. * When expanding a node in the tree, the data source of the tree will need to fetch children by using this class. */ export abstract class TreeDatabase { - public readonly initialized = new Subject(); + public readonly initialized = new Subject(); public busyService: BusyService; - public dataReloaded$ = new BehaviorSubject(undefined); + public dataReloaded$: BehaviorSubject = new BehaviorSubject(undefined); /** set this parameter to true, if your implementation supports searching */ public canSearch = false; @@ -62,13 +62,13 @@ export abstract class TreeDatabase { protected hasChildrenColumnName = 'HasChildren'; protected rootData: IEntity[] = []; - protected rootNodes: TreeNode[]; + public rootNodes: TreeNode[]; /** Initial data from database */ public async initialize(navigationState: CollectionLoadParameters = {}): Promise { // load the root entities const isBusy = this.busyService?.beginBusy(); - let entities: TreeNodeResultParameter; + let entities: TreeNodeResultParameter | undefined; try { entities = await this.getData(true, { ...navigationState, ...{ ParentKey: '' } }); } finally { @@ -100,22 +100,20 @@ export abstract class TreeDatabase { /** return children for a given tree node including the information, if more elements are available on the server */ public async getChildren(node: TreeNode, startIndex: number): Promise<{ nodes: TreeNode[]; canLoadMore: boolean }> { - const isBusy = this.busyService?.beginBusy(); - let entities: TreeNodeResultParameter; + let entities: TreeNodeResultParameter | undefined; try { entities = await this.getData(false, { ParentKey: node.name, StartIndex: startIndex }); } finally { - isBusy?.endBusy(); } - const nodes = this.createSortedNodes(entities.entities, node.level + 1); + const nodes = this.createSortedNodes(entities?.entities ?? [], node.level + 1); return { - nodes: entities.entities.map((entity) => nodes.find((x) => this.getId(x.item) === this.getId(entity))), - canLoadMore: entities.canLoadMore, + nodes: entities?.entities.map((entity) => nodes.find((x) => this.getId(x.item) === this.getId(entity)) ?? new TreeNode()) ?? [], + canLoadMore: entities?.canLoadMore ?? false, }; } /** abstract function, which have to be implemented */ - public async getData(showLoading: boolean, parameter: CollectionLoadParameters = {}): Promise { + public async getData(showLoading: boolean, parameter: CollectionLoadParameters = {}): Promise { return undefined; } @@ -139,16 +137,16 @@ export abstract class TreeDatabase { this.identifierColumnName ? item.GetColumn(this.identifierColumnName).GetValue() : '', this.getId(item), levelNumber, - item.GetColumn(this.hasChildrenColumnName).GetValue() + item.GetColumn(this.hasChildrenColumnName).GetValue(), ); } /** gets an unique id by combining all id parts */ - public getId(entity: IEntity): string { + public getId(entity: IEntity | undefined): string { return TreeDatabase.getId(entity); } - public static getId(entity: IEntity): string { + public static getId(entity: IEntity | undefined): string { return entity?.GetKeys() ? entity.GetKeys().join(',') : ''; } } diff --git a/imxweb/projects/qbm/src/lib/data-tree/tree-datasource.spec.ts b/imxweb/projects/qbm/src/lib/data-tree/tree-datasource.spec.ts index a15ef026a..d99e04b64 100644 --- a/imxweb/projects/qbm/src/lib/data-tree/tree-datasource.spec.ts +++ b/imxweb/projects/qbm/src/lib/data-tree/tree-datasource.spec.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -30,38 +30,39 @@ import { CollectionViewer, SelectionChange } from '@angular/cdk/collections'; import { TreeDatabase } from './tree-database'; import { TreeNode } from './tree-node'; import { TreeDatasource } from './tree-datasource'; -import { CollectionLoadParameters, IEntity } from 'imx-qbm-dbts'; +import { CollectionLoadParameters, IEntity } from '@imx-modules/imx-qbm-dbts'; describe('TreeDatabase', () => { - const createEntity = (key, parent?) => ({ - GetColumn: __ => ({ GetDisplayValue: () => '' }), - GetDisplay: () => '', - GetKeys: () => [key], - parent - } as IEntity & { parent?: string; }); + const createEntity = (key, parent?) => + ({ + GetColumn: (__) => ({ GetDisplayValue: () => '' }), + GetDisplay: () => '', + GetKeys: () => [key], + parent, + }) as IEntity & { parent?: string }; let treeControl: FlatTreeControl; let dummyEntity: IEntity; beforeEach(() => { treeControl = new FlatTreeControl( - node => node.level, - node => node.item.GetColumn('HasChildren').GetValue() + (node) => node.level, + (node) => node.item.GetColumn('HasChildren').GetValue(), ); dummyEntity = createEntity('dummy'); }); it('should disconnect all subscriptions', () => { - const treeDatasource = new TreeDatasource(treeControl, new class extends TreeDatabase {}()); + const treeDatasource = new TreeDatasource(treeControl, new (class extends TreeDatabase {})()); treeDatasource.connect({ viewChange: {} } as CollectionViewer); - expect(treeDatasource['subscriptions'].length > 0 && treeDatasource['subscriptions'].every(s => s.closed)).toBeFalsy(); + expect(treeDatasource['subscriptions'].length > 0 && treeDatasource['subscriptions'].every((s) => s.closed)).toBeFalsy(); treeDatasource.disconnect(); - expect(treeDatasource['subscriptions'].length > 0 && treeDatasource['subscriptions'].every(s => s.closed)).toBeTruthy(); + expect(treeDatasource['subscriptions'].length > 0 && treeDatasource['subscriptions'].every((s) => s.closed)).toBeTruthy(); }); describe('toggle node', () => { @@ -74,38 +75,27 @@ describe('TreeDatabase', () => { let treeDatabase: TreeDatabase; beforeEach(() => { - treeDatabase = new class extends TreeDatabase { + treeDatabase = new (class extends TreeDatabase { private readonly justSomeParentEntity = createEntity('keyParent1'); private readonly justSomeEntity = createEntity('keyOfSomeEntity'); - + constructor() { super(); - - this['rootData'] = [ - this.justSomeParentEntity, - entityUnderTest, - this.justSomeEntity - ]; - this['rootNodes'] = [ - toNode(this.justSomeParentEntity), - nodeUnderTest, - toNode(this.justSomeEntity) - ]; + + this['rootData'] = [this.justSomeParentEntity, entityUnderTest, this.justSomeEntity]; + this['rootNodes'] = [toNode(this.justSomeParentEntity), nodeUnderTest, toNode(this.justSomeEntity)]; } - + readonly getChildren = jasmine.createSpy('getChildren').and.callFake((node, __) => ({ - nodes: this.children.filter(child => child.parent === node.name).map(child => toNode(child, 1)) + nodes: this.children.filter((child) => child.parent === node.name).map((child) => toNode(child, 1)), })); - - private readonly children = [ - child, - createEntity('keyAnotherChild', this.justSomeParentEntity.GetKeys().join()) - ]; - }(); + + private readonly children = [child, createEntity('keyAnotherChild', this.justSomeParentEntity.GetKeys().join())]; + })(); }); it('expands', async () => { - // Arrange + // Arrange const expectedNumOfNodesAfterExpand = 4; const treeDatasource = new TreeDatasource(treeControl, treeDatabase); @@ -117,7 +107,7 @@ describe('TreeDatabase', () => { // Check expect(treeDatabase.getChildren).toHaveBeenCalled(); - const childNode = treeDatasource.data.find(d => d.name === child.GetKeys().join()); + const childNode = treeDatasource.data.find((d) => d.name === child.GetKeys().join()); expect(childNode.isLoading).toEqual(false); @@ -135,7 +125,7 @@ describe('TreeDatabase', () => { const index = treeDatasource.data.indexOf(nodeUnderTest); treeDatasource.data.splice(index + 1, 0, childNode); // fake expand - + // Act await treeDatasource.handleTreeControl({ removed: [nodeUnderTest] } as SelectionChange); @@ -148,30 +138,30 @@ describe('TreeDatabase', () => { }); }); - for(const testcase of [ + for (const testcase of [ { description: 'add node', change: { added: [ new TreeNode(dummyEntity, 'uid-parent1', 'uid-parent1', 0, true), - new TreeNode(dummyEntity, 'uid-parent2', 'uid-parent2', 0, true) - ] + new TreeNode(dummyEntity, 'uid-parent2', 'uid-parent2', 0, true), + ], }, - expectGetChildren: 2 + expectGetChildren: 2, }, { description: 'remove node', change: { - removed: [new TreeNode(dummyEntity, 'uid-parent1', 'uid-parent1', 0, true)] + removed: [new TreeNode(dummyEntity, 'uid-parent1', 'uid-parent1', 0, true)], }, - expectGetChildren: 0 + expectGetChildren: 0, }, ]) { it(`can handle the tree control (${testcase.description})`, async () => { // Arrange - const treeDatabase = new class extends TreeDatabase { + const treeDatabase = new (class extends TreeDatabase { readonly getChildren = jasmine.createSpy('getChildren'); - }(); + })(); const treeDatasource = new TreeDatasource(treeControl, treeDatabase); @@ -187,25 +177,65 @@ describe('TreeDatabase', () => { } for (const testcase of [ - { desciption: 'for root', entities:[dummyEntity], node: new TreeNode(dummyEntity, 'uid-parent1', 'uid-parent1', 0), ParentKey: '', startIndex: 0, hasmore: true, expectedLenght: 2 }, - { desciption: 'for children', entities:[dummyEntity], node: new TreeNode(dummyEntity, 'uid-parent1', 'uid-parent1', 0), ParentKey: 'uid-parent1', startIndex: 0, hasmore: true, expectedLenght: 2 }, - { desciption: 'for root', entities:[dummyEntity], node: new TreeNode(dummyEntity, 'uid-parent1', 'uid-parent1', 0), ParentKey: '', startIndex: 0, hasmore: false, expectedLenght: 1 }, - { desciption: 'for children', entities:[dummyEntity], node: new TreeNode(dummyEntity, 'uid-parent1', 'uid-parent1', 0), ParentKey: 'uid-parent1', startIndex: 0, hasmore: false, expectedLenght: 1 }, - { desciption: 'without nodes', entities:[], node: new TreeNode(dummyEntity, 'uid-parent1', 'uid-parent1', 0), ParentKey: 'uid-parent1', startIndex: 0, hasmore: false, expectedLenght: 0 } + { + desciption: 'for root', + entities: [dummyEntity], + node: new TreeNode(dummyEntity, 'uid-parent1', 'uid-parent1', 0), + ParentKey: '', + startIndex: 0, + hasmore: true, + expectedLenght: 2, + }, + { + desciption: 'for children', + entities: [dummyEntity], + node: new TreeNode(dummyEntity, 'uid-parent1', 'uid-parent1', 0), + ParentKey: 'uid-parent1', + startIndex: 0, + hasmore: true, + expectedLenght: 2, + }, + { + desciption: 'for root', + entities: [dummyEntity], + node: new TreeNode(dummyEntity, 'uid-parent1', 'uid-parent1', 0), + ParentKey: '', + startIndex: 0, + hasmore: false, + expectedLenght: 1, + }, + { + desciption: 'for children', + entities: [dummyEntity], + node: new TreeNode(dummyEntity, 'uid-parent1', 'uid-parent1', 0), + ParentKey: 'uid-parent1', + startIndex: 0, + hasmore: false, + expectedLenght: 1, + }, + { + desciption: 'without nodes', + entities: [], + node: new TreeNode(dummyEntity, 'uid-parent1', 'uid-parent1', 0), + ParentKey: 'uid-parent1', + startIndex: 0, + hasmore: false, + expectedLenght: 0, + }, ]) { it(`can load more (${testcase.desciption})`, async () => { //Arrange - const treeDatabase = new class extends TreeDatabase { + const treeDatabase = new (class extends TreeDatabase { getData(showLoading: boolean, parameters: CollectionLoadParameters = {}): Promise { return Promise.resolve({ entities: testcase.entities, canLoadMore: testcase.hasmore, - totalCount: 999 + totalCount: 999, }); } - readonly createSortedNodes = (entities, __) => entities.map(ent => new TreeNode(ent, '', '')); - }(); + readonly createSortedNodes = (entities, __) => entities.map((ent) => new TreeNode(ent, '', '')); + })(); const source = new TreeDatasource(treeControl, treeDatabase); @@ -215,6 +245,6 @@ describe('TreeDatabase', () => { // check expect(source.data.length).toEqual(testcase.expectedLenght); - }) + }); } -}); \ No newline at end of file +}); diff --git a/imxweb/projects/qbm/src/lib/data-tree/tree-datasource.ts b/imxweb/projects/qbm/src/lib/data-tree/tree-datasource.ts index d20be208c..ce3b8c2a2 100644 --- a/imxweb/projects/qbm/src/lib/data-tree/tree-datasource.ts +++ b/imxweb/projects/qbm/src/lib/data-tree/tree-datasource.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -26,13 +26,12 @@ import { CollectionViewer, SelectionChange } from '@angular/cdk/collections'; import { FlatTreeControl } from '@angular/cdk/tree'; -import { BehaviorSubject, Observable, merge, Subscription } from 'rxjs'; +import { BehaviorSubject, merge, Observable, Subscription } from 'rxjs'; import { concatMap, map } from 'rxjs/operators'; -import { TreeNode, TreeNodeInfo } from './tree-node'; +import { IEntity } from '@imx-modules/imx-qbm-dbts'; import { TreeDatabase } from './tree-database'; -import { IEntity } from 'imx-qbm-dbts'; -import * as _ from 'lodash'; +import { TreeNode, TreeNodeInfo } from './tree-node'; /** Datasource for the data-tree */ export class TreeDatasource { @@ -49,7 +48,10 @@ export class TreeDatasource { */ private subscriptions: Subscription[] = []; - constructor(private treeControl: FlatTreeControl, private dataService: TreeDatabase) {} + constructor( + private treeControl: FlatTreeControl, + private dataService: TreeDatabase, + ) {} public init(value: TreeNode[]): void { this.treeControl.dataNodes = value; @@ -76,7 +78,7 @@ export class TreeDatasource { if (treeDataHasChanged) { this.dataChange.next(this.data); } - }) + }), ); return merge(collectionViewer.viewChange, this.dataChange).pipe(map(() => this.data)); @@ -86,7 +88,7 @@ export class TreeDatasource { public async handleTreeControl(change: SelectionChange): Promise { if (change.added && change.added.length > 0) { return (await Promise.all(change.added.filter((node) => node.expandable).map((node) => this.toggleNode(node, true)))).some( - (result) => result === true + (result) => result === true, ); } @@ -97,10 +99,12 @@ export class TreeDatasource { .filter((node) => node.expandable) .slice() .reverse() - .map((node) => this.toggleNode(node, false)) + .map((node) => this.toggleNode(node, false)), ) ).some((result) => result === true); } + + return false; } /** Loads more elements and adds them to the tree */ @@ -108,13 +112,13 @@ export class TreeDatasource { node.isLoading = true; try { const newData = await this.dataService.getData(false, { ParentKey, StartIndex: startIndex }); - const nodes = this.dataService.createSortedNodes(newData.entities, node.level); + const nodes = this.dataService.createSortedNodes(newData?.entities ?? [], node.level); if (nodes.length === 0) { return; } - if (newData.canLoadMore) { + if (newData?.canLoadMore) { nodes.push(new TreeNode(undefined, ParentKey + 'more', 'more', node.level, false, false, true)); } @@ -136,7 +140,7 @@ export class TreeDatasource { /** add an empty tree node at the top of the tree */ public addEmpyNodeToTop(): TreeNode { if (this.data?.length === 0 || this.data[0].identifier !== 'newObject') { - const emptyNode = new TreeNode(null, 'newObject', this.emptyNodeCaption, 0, false); + const emptyNode = new TreeNode(undefined, 'newObject', this.emptyNodeCaption, 0, false); this.data.splice(0, 0, ...[emptyNode]); this.dataChange.next(this.data); diff --git a/imxweb/projects/qbm/src/lib/data-tree/tree-node-result-parameter.interface.ts b/imxweb/projects/qbm/src/lib/data-tree/tree-node-result-parameter.interface.ts index 64d77ce42..82d7532d6 100644 --- a/imxweb/projects/qbm/src/lib/data-tree/tree-node-result-parameter.interface.ts +++ b/imxweb/projects/qbm/src/lib/data-tree/tree-node-result-parameter.interface.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -24,7 +24,7 @@ * */ -import { IEntity } from 'imx-qbm-dbts'; +import { IEntity } from '@imx-modules/imx-qbm-dbts'; export interface TreeNodeResultParameter { /** loaded entities */ diff --git a/imxweb/projects/qbm/src/lib/data-tree/tree-node.ts b/imxweb/projects/qbm/src/lib/data-tree/tree-node.ts index 805026f3f..82acf8d13 100644 --- a/imxweb/projects/qbm/src/lib/data-tree/tree-node.ts +++ b/imxweb/projects/qbm/src/lib/data-tree/tree-node.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -24,7 +24,7 @@ * */ -import { IEntity } from 'imx-qbm-dbts'; +import { IEntity } from '@imx-modules/imx-qbm-dbts'; export interface TreeNodeInfo { item?: IEntity; @@ -34,27 +34,41 @@ export interface TreeNodeInfo { expandable?: boolean; isLoading?: boolean; isLoadMoreNode?: boolean; + isSelectable?: boolean; display?: string; + nodes?: TreeNodeInfo[]; } /** Class representing a single node in the DataTree with expandable and level information */ export class TreeNode implements TreeNodeInfo { /** the display of the bounded item of the node */ public get display(): string { - return this.item != null ? this.item.GetDisplay() : this.name; + return (this.item != null ? this.item.GetDisplay() : this.name) ?? ''; } constructor( - public item: IEntity, - public readonly identifier: string, + public item?: IEntity, + public readonly identifier?: string, public readonly name?: string, public readonly level: number = 1, public expandable: boolean = false, public isLoading: boolean = false, - public isLoadMoreNode: boolean = false + public isLoadMoreNode: boolean = false, + public isSelectable: boolean = true, + public nodes: TreeNodeInfo[] = [], ) {} public static createNodeFromInfo(info: TreeNodeInfo) { - return new TreeNode(info.item, info.identifier,info.name,info.level,info.expandable,info.isLoading,info.isLoadMoreNode); + return new TreeNode( + info.item, + info.identifier, + info.name, + info.level, + info.expandable, + info.isLoading, + info.isLoadMoreNode, + info.isSelectable, + info.nodes, + ); } } diff --git a/imxweb/projects/qbm/src/lib/data-tree/tree-selection-list/tree-selection-list.component.scss b/imxweb/projects/qbm/src/lib/data-tree/tree-selection-list/tree-selection-list.component.scss index 1d316dd80..45903d7b9 100644 --- a/imxweb/projects/qbm/src/lib/data-tree/tree-selection-list/tree-selection-list.component.scss +++ b/imxweb/projects/qbm/src/lib/data-tree/tree-selection-list/tree-selection-list.component.scss @@ -1,4 +1,4 @@ -@import "@elemental-ui/core/src/styles/_palette.scss"; +@import '@elemental-ui/core/src/styles/_palette.scss'; @import '@elemental-ui/core/src/styles/_eui_palette.scss'; :host { @@ -23,7 +23,7 @@ h2 { overflow: auto; } -.mat-list { +.mat-mdc-list { height: 100%; overflow: auto; } diff --git a/imxweb/projects/qbm/src/lib/data-tree/tree-selection-list/tree-selection-list.component.ts b/imxweb/projects/qbm/src/lib/data-tree/tree-selection-list/tree-selection-list.component.ts index 46a23cb0c..ac3f2ca7f 100644 --- a/imxweb/projects/qbm/src/lib/data-tree/tree-selection-list/tree-selection-list.component.ts +++ b/imxweb/projects/qbm/src/lib/data-tree/tree-selection-list/tree-selection-list.component.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -27,31 +27,29 @@ import { Component, Inject, OnInit } from '@angular/core'; import { EUI_SIDESHEET_DATA } from '@elemental-ui/core'; -import { DbObjectKey, IEntity} from 'imx-qbm-dbts'; +import { DbObjectKey, IEntity } from '@imx-modules/imx-qbm-dbts'; import { MetadataService } from '../../base/metadata.service'; import { CdrFactoryService } from '../../cdr/cdr-factory.service'; @Component({ templateUrl: './tree-selection-list.component.html', - styleUrls: ['./tree-selection-list.component.scss'] + styleUrls: ['./tree-selection-list.component.scss'], }) export class TreeSelectionListComponent implements OnInit { - - public items: { entities: IEntity[], tableName: string }[]; + public items: { entities: IEntity[]; tableName: string }[]; constructor( @Inject(EUI_SIDESHEET_DATA) public readonly data: IEntity[], - private readonly metadataProvider: MetadataService) { - } + private readonly metadataProvider: MetadataService, + ) {} public ngOnInit(): void { const allItems = this.data.map((elem: IEntity) => ({ entity: elem, tableName: this.getTableName(elem) })); - const tables = allItems.map(elem => elem.tableName).filter((v, i, a) => a.indexOf(v) === i); + const tables = allItems.map((elem) => elem.tableName).filter((v, i, a) => a.indexOf(v) === i); - this.items = tables.map(elem => ({ - entities: allItems.filter(ent => ent.tableName === elem).map(ent => ent.entity), - tableName: elem + this.items = tables.map((elem) => ({ + entities: allItems.filter((ent) => ent.tableName === elem).map((ent) => ent.entity), + tableName: elem, })); - } private getTableName(entity: IEntity): string { @@ -63,5 +61,4 @@ export class TreeSelectionListComponent implements OnInit { const tableName = DbObjectKey.FromXml(column.GetValue()).TableName; return this.metadataProvider.tables[tableName]?.DisplaySingular || tableName; } - } diff --git a/imxweb/projects/qbm/src/lib/data-view/data-view-auto-table/data-view-auto-table.component.html b/imxweb/projects/qbm/src/lib/data-view/data-view-auto-table/data-view-auto-table.component.html new file mode 100644 index 000000000..8132b813c --- /dev/null +++ b/imxweb/projects/qbm/src/lib/data-view/data-view-auto-table/data-view-auto-table.component.html @@ -0,0 +1,182 @@ + + + + + + + + + + + + + + + + + + + + +
    + #LDS#Group by: + {{ dataSource.groupByColumn()?.Display }} + +
    + {{ group?.Display[0].Display || '' }} +
    +
      + + +
    + + + + +
    +
    +
    + + + + + + + + + + + + + + + + + + + + + + +
    + + + + + + + {{ dataSource.GetColumnDisplay(column.ColumnName || '', dataSource?.entitySchema()) }} + + {{ element?.GetEntity()?.GetColumn(column.ColumnName)?.GetDisplayValue() }} + + + + {{ dataSource.GetColumnDisplay(column.ColumnName || '', dataSource?.entitySchema()) }} + + {{ element?.GetEntity()?.GetColumn(column.ColumnName)?.GetDisplayValue() }} +
    +
    + +
    + + +
    {{ noDataText | translate }}
    +
    + +
    +
      +
        +
      • {{ '#LDS#Check the spelling of the search terms you entered.' | translate }}
      • +
      • {{ '#LDS#Clear or use less filters.' | translate }}
      • +
      • {{ '#LDS#Enter different, more generic search terms.' | translate }}
      • +
      • {{ '#LDS#Fewer search terms lead to more matches. Try to reduce the search terms until you get a result.' | translate }}
      • +
      +
    +
    +
    +
    diff --git a/imxweb/projects/qbm/src/lib/data-view/data-view-auto-table/data-view-auto-table.component.scss b/imxweb/projects/qbm/src/lib/data-view/data-view-auto-table/data-view-auto-table.component.scss new file mode 100644 index 000000000..1ca0cafea --- /dev/null +++ b/imxweb/projects/qbm/src/lib/data-view/data-view-auto-table/data-view-auto-table.component.scss @@ -0,0 +1,95 @@ +/* You can add styles to this file, and also import other style files */ +@import '@elemental-ui/core/src/styles/_eui_palette.scss'; + +:host { + height: 100%; + display: flex; + flex-direction: column; + overflow: auto; + + .imx-header-cell { + cursor: pointer; + padding-right: 20px; + } + + .imx-no-results { + text-align: center; + margin: 20px 0; + flex: 1 1 auto; + display: flex; + flex-direction: column; + justify-content: center; + &-title { + font-size: 64px; + font-weight: 700; + text-transform: uppercase; + } + li { + text-align: left; + list-style-type: unset; + font-weight: 600; + } + } + tr.expanded-detail-row { + height: 0; + &:hover { + background-color: unset; + } + } + + .expanded-group-row { + td { + border-bottom-width: 0; + } + } + .mat-mdc-cell { + .mat-mdc-icon-button { + justify-content: center; + } + } + .expanded-group-detail { + display: flex; + flex-direction: column; + width: 100%; + } + .mat-column-expand { + width: 40px; + } +} + +.imx-no-results { + &-title { + color: $color-gray-10; + } + li { + color: $color-gray-60; + } +} + +/* Dark theme */ +.eui-dark-theme { + :host { + .imx-no-results { + &-title { + color: $color-gray-20; + } + li { + color: $color-gray-10; + } + } + } +} + +/* High-contrast theme */ +.eui-contrast-theme { + :host { + .imx-no-results { + &-title { + color: $color-gray-0; + } + li { + color: $color-gray-0; + } + } + } +} diff --git a/imxweb/projects/qbm/src/lib/data-view/data-view-auto-table/data-view-auto-table.component.ts b/imxweb/projects/qbm/src/lib/data-view/data-view-auto-table/data-view-auto-table.component.ts new file mode 100644 index 000000000..142c82569 --- /dev/null +++ b/imxweb/projects/qbm/src/lib/data-view/data-view-auto-table/data-view-auto-table.component.ts @@ -0,0 +1,210 @@ +/* + * ONE IDENTITY LLC. PROPRIETARY INFORMATION + * + * This software is confidential. One Identity, LLC. or one of its affiliates or + * subsidiaries, has supplied this software to you under terms of a + * license agreement, nondisclosure agreement or both. + * + * You may not copy, disclose, or use this software except in accordance with + * those terms. + * + * + * Copyright 2024 One Identity LLC. + * ALL RIGHTS RESERVED. + * + * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR + * WARRANTIES ABOUT THE SUITABILITY OF THE SOFTWARE, + * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED + * TO THE IMPLIED WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE, OR + * NON-INFRINGEMENT. ONE IDENTITY LLC. SHALL NOT BE + * LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE + * AS A RESULT OF USING, MODIFYING OR DISTRIBUTING + * THIS SOFTWARE OR ITS DERIVATIVES. + * + */ + +import { animate, state, style, transition, trigger } from '@angular/animations'; +import { Component, ContentChildren, Input, QueryList, Signal, ViewChild, computed, effect } from '@angular/core'; +import { MatColumnDef, MatTable } from '@angular/material/table'; +import { isEqual } from 'lodash'; +import { QueuedActionState } from '../../processing-queue/processing-queue.interface'; +import { ImxTranslationProviderService } from '../../translation/imx-translation-provider.service'; +import { DataViewSource } from '../data-view-source'; +import { GroupInfoRow } from '../data-view.interface'; +/** + * + * @example + * Base example with default 'auto' mode. + * + * + * + * @example + * The fallowing exmaple show how to use the 'manual mode, set selection option and use sorting on manual column. + * To use sorting on manual column you need to add the 'matSort' directive to the imx-data-view-auto-table and add 'mat-sort-header' directive to the required th element. + * + * + * + * {{ identitySchema?.Columns[this.displayColumns.DISPLAY_PROPERTYNAME]?.Display }} + * + *
    {{ item.GetEntity().GetDisplay() }}
    + *
    {{ item.DefaultEmailAddress.Column.GetDisplayValue() }}
    + * + * + *
    + * + * {{ identitySchema?.Columns.IsSecurityIncident?.Display }} + * + *
    + * {{ '#LDS#Security risk' | translate }} + *
    + * + *
    + *
    + */ +@Component({ + selector: 'imx-data-view-auto-table', + templateUrl: './data-view-auto-table.component.html', + styleUrls: ['./data-view-auto-table.component.scss'], + animations: [ + trigger('detailExpand', [ + state('collapsed', style({ height: '0px', minHeight: '0' })), + state('expanded', style({ height: '*' })), + transition('expanded <=> collapsed', animate('225ms cubic-bezier(0.4, 0.0, 0.2, 1)')), + ]), + ], +}) +export class DataViewAutoTableComponent { + /** + * Input the dataViewSource service. It handles all the action and the data loading. This input property is required. + */ + @Input({ required: true }) public dataSource: DataViewSource; + + /** + * Set the no data title. + */ + @Input() public noDataText: string; + /** + * Set the icon type, which shown, when there is no data. + */ + @Input() public noDataIcon = 'content-alert'; + /** + * Indicates, if multiselect is enabled. + */ + @Input() public selectable = false; + /** + * If set to 'auto' (= default) the data table will check the 'displayedColumns' input field and build a visual presentation. + * If set to 'manual' the data table render all the material columns in the content of the data view auto table component. In manual mode the additional columns also available. + */ + @Input() public mode: 'auto' | 'manual' = 'auto'; + + /** + * TODO: Refine if needed + * If mode is 'auto', then specify the name of the column you want a queue status badge to appear under. If left blank, then no status badge will appear, even if item is in the processing queue. + * This input has no effect on 'manual', as the injected ng-container should contain the reference to the imx-data-view-status component + */ + // @Input() public queueStatusColumnName: string; + + @ContentChildren(MatColumnDef) columnDefs: QueryList; + @ViewChild(MatTable, { static: true }) table: MatTable; + /** + * Array of the display columns. + */ + public namesOfDisplayedColumns: string[] = []; + /** + * Array of the grouped display columns. + */ + public groupColumnsToDisplayWithExpand = ['Display', 'expand']; + /** + * Signal about grouping is applied. + */ + public isGroupingApplied: Signal = computed(() => !!this.dataSource.groupByColumn()); + + public stateOptions = QueuedActionState; + private cacheColumnDefs: string[] = []; + + constructor( + public readonly translateProvider: ImxTranslationProviderService, + public readonly groupedDataSource: DataViewSource, + ) { + effect(() => { + if (this.dataSource.columnsToDisplay() && this.columnDefs && this.table) { + this.columnDefs.forEach((columnDef) => { + if (this.cacheColumnDefs.indexOf(columnDef.name) === -1) { + this.table.addColumnDef(columnDef); + this.cacheColumnDefs.push(columnDef.name); + } + }); + if (this.selectable) { + this.namesOfDisplayedColumns = ['select', ...this.dataSource?.columnsToDisplay()?.map((column) => column.ColumnName || '')]; + } else { + this.namesOfDisplayedColumns = this.dataSource?.columnsToDisplay()?.map((column) => column.ColumnName || ''); + } + } + }); + } + + /** + * Select or clear all the currenlty visible rows. + */ + public toggleAllRows(): void { + if (this.dataSource.isAllSelected()) { + this.dataSource.selection.clear(); + this.dataSource.nestedSelection = new Map(); + return; + } + + this.dataSource.selection.select(this.dataSource.getAllSelectableEntities()); + } + + /** + * Expand the selected row in grouped data table. + * @param group the selected grouped row. + */ + public expandGroup(group: GroupInfoRow): void { + if (!!group.Count && group.Count > 0) { + group.expanded = !group.expanded; + } + } + + /** + * Calls from the template when a selection is changing in the nested tables. Updates the nested selection and calls DataViewSource SelectionModelWrapper setSelection function. + * @param selection The selected array. + * @param tableIndex The nested table index. + */ + public onNestedSelectionChange(selection: any[], tableIndex: number): void { + this.dataSource.nestedSelection.set(tableIndex, selection); + let nestedSelection: any[] = []; + this.dataSource.nestedSelection.forEach((tableSelection) => { + nestedSelection.push(...tableSelection); + }); + this.dataSource.selection.setSelection(nestedSelection); + } + + /** + * Returns the selected nested table selection. + * @param index The selected nested table index. + */ + public getNestedSelection(index: number): any[] { + return this.dataSource.nestedSelection.get(index) || []; + } + + /** + * Remove the selectedItem from the nested table selection. + * @param selectedItem The selected item to remove. + */ + public onRemoveSelection(selectedItem: any): void { + this.dataSource.nestedSelection.forEach((value, key) => { + const newValue = value.filter((item) => !isEqual(item, selectedItem)); + this.dataSource.nestedSelection.set(key, newValue); + }); + } +} diff --git a/imxweb/projects/qbm/src/lib/data-view/data-view-chipbar/data-view-chipbar.component.html b/imxweb/projects/qbm/src/lib/data-view/data-view-chipbar/data-view-chipbar.component.html new file mode 100644 index 000000000..384811e5f --- /dev/null +++ b/imxweb/projects/qbm/src/lib/data-view/data-view-chipbar/data-view-chipbar.component.html @@ -0,0 +1,67 @@ +
    + + {{ '#LDS#Keywords' | translate }}: + + + {{ item.value }} + + + + + {{ '#LDS#Filters' | translate }}: + + + + + {{ '#LDS#Custom filter' | translate }} ({{ item.value?.Expression?.Expressions?.length }}) + + + + + + + + + + {{ getPredefinedFilterDisplay(item) }} + + + + + + + + {{ !!dataSource.filterTreeData().Description ? dataSource.filterTreeData().Description + ': ' : '' + }}{{ dataSource.filterTreeSelection()?.display }} + + + + +
    diff --git a/imxweb/projects/qbm/src/lib/data-view/data-view-chipbar/data-view-chipbar.component.scss b/imxweb/projects/qbm/src/lib/data-view/data-view-chipbar/data-view-chipbar.component.scss new file mode 100644 index 000000000..86a97463f --- /dev/null +++ b/imxweb/projects/qbm/src/lib/data-view/data-view-chipbar/data-view-chipbar.component.scss @@ -0,0 +1,22 @@ +@import '@elemental-ui/core/src/styles/_palette.scss'; +@import '@elemental-ui/core/src/styles/_eui_palette.scss'; +@import 'base/mixins'; + +.imx-chipbar{ + display: flex; + gap: 8px; + flex-wrap: wrap; + justify-content: flex-end; + align-items: center; + margin-bottom: 16px; +} +.imx-chip-avatar { + width: 50px; +} + +.mat-mdc-chip { + height: 32px; +} +span{ + font-size: 14px; +} diff --git a/imxweb/projects/qbm/src/lib/data-view/data-view-chipbar/data-view-chipbar.component.ts b/imxweb/projects/qbm/src/lib/data-view/data-view-chipbar/data-view-chipbar.component.ts new file mode 100644 index 000000000..c084bfb53 --- /dev/null +++ b/imxweb/projects/qbm/src/lib/data-view/data-view-chipbar/data-view-chipbar.component.ts @@ -0,0 +1,187 @@ +/* + * ONE IDENTITY LLC. PROPRIETARY INFORMATION + * + * This software is confidential. One Identity, LLC. or one of its affiliates or + * subsidiaries, has supplied this software to you under terms of a + * license agreement, nondisclosure agreement or both. + * + * You may not copy, disclose, or use this software except in accordance with + * those terms. + * + * + * Copyright 2024 One Identity LLC. + * ALL RIGHTS RESERVED. + * + * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR + * WARRANTIES ABOUT THE SUITABILITY OF THE SOFTWARE, + * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED + * TO THE IMPLIED WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE, OR + * NON-INFRINGEMENT. ONE IDENTITY LLC. SHALL NOT BE + * LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE + * AS A RESULT OF USING, MODIFYING OR DISTRIBUTING + * THIS SOFTWARE OR ITS DERIVATIVES. + * + */ + +import { Component, Input, Signal, computed } from '@angular/core'; +import { FilterType } from '@imx-modules/imx-qbm-dbts'; +import { DataSourceToolbarFilter } from '../../data-source-toolbar/data-source-toolbar-filters.interface'; +import { DataViewSource } from '../data-view-source'; +import { ExpressionFilter, KeywordFilter, SelectedFilter, SelectedFilterType } from '../data-view.interface'; + +/** + * @example + * + */ +@Component({ + selector: 'imx-data-view-chipbar', + templateUrl: './data-view-chipbar.component.html', + styleUrls: ['./data-view-chipbar.component.scss'], +}) +export class DataViewChipbarComponent { + /** + * Input the dataViewSource service. It handles all the action and the data loading. This input property is required. + */ + @Input({ required: true }) public dataSource: DataViewSource; + /** + * Signal, that filtering the all the selected predefinedFilter. + */ + public predefinedFilters: Signal = computed(() => { + let filters: DataSourceToolbarFilter[] = []; + this.dataSource + .predefinedFilters() + .filter((filter) => !!filter?.CurrentValue) + .map((filter) => { + if (!!filter.Delimiter) { + filter.CurrentValue?.split(filter.Delimiter).map((splitedValue) => { + filters.push({ ...filter, CurrentValue: splitedValue }); + }); + } else { + filters.push(filter); + } + }); + return filters; + }); + /** + * Signal, that filters all the search type filters. + */ + public keywords: Signal = computed( + () => this.dataSource.selectedFilters().filter((filter) => filter.type === SelectedFilterType.Keyword) as KeywordFilter[], + ); + /** + * Signal, that filter all the custom filters. + */ + public customFilters: Signal = computed( + () => this.dataSource.selectedFilters().filter((filter) => filter.type === SelectedFilterType.Custom) as ExpressionFilter[], + ); + /** + * Signal, that calculates the chip bar existence. + */ + public showChipBar: Signal = computed( + () => this.dataSource.selectedFilters()?.length > 0 || this.predefinedFilters().length > 0 || !!this.dataSource.filterTreeSelection(), + ); + + public showResetButton: Signal = computed( + () => (this.keywords()?.length || 0) + (this.customFilters()?.length || 0) + (this.predefinedFilters()?.length || 0) > 1, + ); + + /** + * Return the predefined filter selected option display value. + * @param item selected predefined filter + * @returns The display of the predefined filter. + */ + public getPredefinedFilterDisplay(item: DataSourceToolbarFilter): string { + if (item.CurrentValue == null) { + return ''; + } + let found = item.Options?.find((element) => element.Value === item.CurrentValue); + return found?.Display || ''; + } + + /** + * Remove the selected filter from the DataViewSource selectedFilters signal and from the DataViewSource state signal + * @param item The selected filter. + */ + public removeItem(item: SelectedFilter): void { + this.dataSource.selectedFilters.update((filters) => filters.filter((filter) => filter.value != item.value)); + + switch (item.type) { + case SelectedFilterType.Custom: + this.dataSource.state.update((state) => ({ + ...state, + filter: state.filter?.filter((filter) => filter.Type !== FilterType.Expression), + })); + break; + case SelectedFilterType.Keyword: + this.dataSource.state.update((state) => ({ ...state, filter: state.filter?.filter((filter) => filter.Value1 !== item.value) })); + break; + } + this.dataSource.updateState(); + } + + /** + * Remove the selected predefined filter from the DataViewSource predefinedFilters signal and from the DataViewSource state signal. + * @param item The selected predefined filter. + */ + public removePredefinedItem(item: DataSourceToolbarFilter): void { + const updatedValue = !!item.Delimiter ? this.getUpdatedPredefinedFilterValue(item) : undefined; + this.dataSource.state.update((state) => { + if (item.Name) { + state[item.Name] = updatedValue; + } + return state; + }); + this.dataSource.predefinedFilters.update((predefinedFilters) => + predefinedFilters.map((predefinedFilter) => ({ + ...predefinedFilter, + CurrentValue: item.Name === predefinedFilter.Name ? updatedValue : predefinedFilter.CurrentValue, + })), + ); + this.dataSource.updateState(); + } + /** + * Remove the filter tree filter from the DataViewSource filterTreeSelection signal and from the DataViewSource state signal. + */ + public removeFilterTree(): void { + this.dataSource.state.update((state) => { + const filter = + state.filter?.filter((filter) => filter.ColumnName !== this.dataSource.filterTreeSelection()?.filter?.ColumnName) || []; + return { ...state, filter }; + }); + this.dataSource.filterTreeSelection.set(undefined); + this.dataSource.updateState(); + } + + /** + * Clear all the filters from the chipbar. + */ + public onClearAll(): void { + this.dataSource.selectedFilters.set([]); + this.dataSource.state.update((state) => ({ ...state, filter: undefined, search: undefined })); + this.dataSource.predefinedFilters.update((predefinedFilters) => + predefinedFilters.map((filter) => { + this.dataSource.state.update((state) => { + if (filter.Name) { + state[filter.Name] = undefined; + } + return state; + }); + return { ...filter, CurrentValue: undefined }; + }), + ); + this.dataSource.filterTreeSelection.set(undefined); + this.dataSource.updateState(); + } + + private getUpdatedPredefinedFilterValue(item: DataSourceToolbarFilter): string | undefined { + let updateValue: string | undefined; + const filter = this.dataSource.predefinedFilters().find((filter) => filter.Name === item.Name); + if (!!filter && !!filter.Delimiter) { + updateValue = filter?.CurrentValue?.split(filter.Delimiter) + .filter((value) => value !== item.CurrentValue) + .join(filter.Delimiter); + } + return updateValue; + } +} diff --git a/imxweb/projects/qbm/src/lib/data-view/data-view-filter/data-view-filter.component.html b/imxweb/projects/qbm/src/lib/data-view/data-view-filter/data-view-filter.component.html new file mode 100644 index 000000000..b14ee6288 --- /dev/null +++ b/imxweb/projects/qbm/src/lib/data-view/data-view-filter/data-view-filter.component.html @@ -0,0 +1,10 @@ + diff --git a/imxweb/projects/qbm/src/lib/data-view/data-view-filter/data-view-filter.component.scss b/imxweb/projects/qbm/src/lib/data-view/data-view-filter/data-view-filter.component.scss new file mode 100644 index 000000000..e69de29bb diff --git a/imxweb/projects/qbm/src/lib/data-view/data-view-filter/data-view-filter.component.ts b/imxweb/projects/qbm/src/lib/data-view/data-view-filter/data-view-filter.component.ts new file mode 100644 index 000000000..f308b9579 --- /dev/null +++ b/imxweb/projects/qbm/src/lib/data-view/data-view-filter/data-view-filter.component.ts @@ -0,0 +1,177 @@ +/* + * ONE IDENTITY LLC. PROPRIETARY INFORMATION + * + * This software is confidential. One Identity, LLC. or one of its affiliates or + * subsidiaries, has supplied this software to you under terms of a + * license agreement, nondisclosure agreement or both. + * + * You may not copy, disclose, or use this software except in accordance with + * those terms. + * + * + * Copyright 2024 One Identity LLC. + * ALL RIGHTS RESERVED. + * + * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR + * WARRANTIES ABOUT THE SUITABILITY OF THE SOFTWARE, + * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED + * TO THE IMPLIED WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE, OR + * NON-INFRINGEMENT. ONE IDENTITY LLC. SHALL NOT BE + * LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE + * AS A RESULT OF USING, MODIFYING OR DISTRIBUTING + * THIS SOFTWARE OR ITS DERIVATIVES. + * + */ + +import { Component, Input, Signal, computed } from '@angular/core'; +import { EuiSidesheetService } from '@elemental-ui/core'; +import { FilterType, SqlWizardExpression } from '@imx-modules/imx-qbm-dbts'; +import { TranslateService } from '@ngx-translate/core'; +import { calculateSidesheetWidth } from '../../base/sidesheet-helper'; +import { DataSourceToolbarSelectedFilter } from '../../data-source-toolbar/data-source-toolbar-filters.interface'; +import { FilterWizardComponent } from '../../data-source-toolbar/filter-wizard/filter-wizard.component'; +import { FilterWizardResult, FilterWizardSidesheetData } from '../../data-source-toolbar/filter-wizard/filter-wizard.interfaces'; +import { FilterWizardService } from '../../data-source-toolbar/filter-wizard/filter-wizard.service'; +import { DataViewSource } from '../data-view-source'; +import { ExpressionFilter, SelectedFilter, SelectedFilterType } from '../data-view.interface'; + +@Component({ + selector: 'imx-data-view-filter', + templateUrl: './data-view-filter.component.html', + styleUrls: ['./data-view-filter.component.scss'], +}) +export class DataViewFilterComponent { + /** + * Input the DataViewSource service. It handles all the action and the data loading. This input property is required. + */ + @Input({ required: true }) public dataSource: DataViewSource; + /** + * This unique id is required to use only the related navigationStateChanged events from FilterWizardService. + */ + private id: string = new Date().toString(); + /** + * Signal, that computes the SqlWizardExpression from the DataSourceToolbarCustomComponent.SelectedFilters signal. + */ + private filterExpressions: Signal = computed( + () => + this.dataSource + .selectedFilters() + .filter((item) => item.type === SelectedFilterType.Custom) + .map((filter: ExpressionFilter) => filter.value)[0], + ); + /** + * Signal, that computed the selected predefined filters from DataViewSource predefinedFilters signal. + */ + private getSelectedPredefinedFilters: Signal = computed(() => { + let selectedFilters: DataSourceToolbarSelectedFilter[] = []; + this.dataSource.predefinedFilters().forEach((item) => + selectedFilters.push({ + filter: item, + selectedOption: { Value: item.CurrentValue }, + }), + ); + + return selectedFilters; + }); + private filterType: Signal = computed(() => this.dataSource.filterTreeData().Description || ''); + + constructor( + public readonly filterService: FilterWizardService, + private readonly sidesheetService: EuiSidesheetService, + readonly translate: TranslateService, + ) { + // Updates the predefined filters from the filterWizardService + this.filterService.navigationStateChanged.subscribe((state) => { + if (state.id === this.id) { + this.dataSource.state.set(state.params); + this.dataSource.predefinedFilters.update((predefinedFilters) => + predefinedFilters.map((predefinedFilter) => ({ + ...predefinedFilter, + CurrentValue: state.selectedFilters?.find((filter) => filter.filter?.Name === predefinedFilter.Name)?.filter?.CurrentValue, + })), + ); + } + }); + } + + /** + * Show the filter wizard sidesheet component and update the state and the related signals in dataViewSource service. + */ + public async onShowFilterWizard(): Promise { + const componentData: FilterWizardSidesheetData = { + id: this.id, + settings: { + dataSource: this.dataSource.collectionData(), + navigationState: this.dataSource.state(), + entitySchema: this.dataSource.entitySchema(), + filters: this.dataSource.predefinedFilters(), + dataModel: this.dataSource.dataModel(), + }, + filterExpression: this.filterExpressions(), + selectedFilters: this.getSelectedPredefinedFilters(), + isDataSourceLocal: false, + filterTreeParameter: { + filterTreeParameter: this.dataSource.filterTree, + preSelection: this.dataSource.filterTreeSelection() || {}, + type: this.filterType(), + }, + }; + const sidesheetRef = this.sidesheetService.open(FilterWizardComponent, { + title: await this.translate.instant('#LDS#Heading Filter Data'), + icon: 'filter', + width: calculateSidesheetWidth(800, 0.5), + padding: '0px', + testId: 'filter-wizard-sidesheet', + disableClose: true, + data: componentData, + }); + + sidesheetRef.afterClosed().subscribe((result: FilterWizardResult) => { + if (!result) { + return; + } + if (!!result?.treeFilter && !!result?.treeFilter?.filter) { + const otherFilter = (this.dataSource.state().filter ?? []).filter( + (elem) => elem.ColumnName !== result.treeFilter?.filter?.ColumnName, + ); + this.dataSource.filterTreeSelection.set(result.treeFilter); + const filter = result.treeFilter.filter != null ? [result.treeFilter.filter].concat(otherFilter) : otherFilter; + this.dataSource.state.update((state) => ({ ...state, filter })); + } else { + this.dataSource.state.update((state) => { + const filter = + state.filter?.filter((filter) => filter.ColumnName !== this.dataSource.filterTreeSelection()?.filter?.ColumnName) || []; + return { ...state, filter }; + }); + this.dataSource.filterTreeSelection.set(undefined); + } + if (result?.expression?.Expression?.Expressions?.length === 0) { + this.removeFilterWizard(); + return; + } + this.dataSource.state.update((state) => { + const filter = state.filter?.filter((filter) => filter.Type !== FilterType.Expression) || []; + filter.push({ Type: FilterType.Expression, Expression: result?.expression.Expression }); + return { + ...state, + filter, + }; + }); + this.dataSource.selectedFilters.update((filters) => { + const updatedFilters: SelectedFilter[] = filters.filter((filter) => filter.type !== SelectedFilterType.Custom); + updatedFilters.push({ type: SelectedFilterType.Custom, value: result.expression }); + return updatedFilters; + }); + this.dataSource.updateState(); + }); + } + + /** + * Remove the filter wizard expression from the DataViewSource state signal and update calls DataViewSource updateState function. + */ + public removeFilterWizard(): void { + this.dataSource.state.update((state) => ({ ...state, filter: state.filter?.filter((x) => x.Expression == null) })); + this.dataSource.updateState(); + } +} diff --git a/imxweb/projects/qbm/src/lib/data-view/data-view-group/data-view-group.component.html b/imxweb/projects/qbm/src/lib/data-view/data-view-group/data-view-group.component.html new file mode 100644 index 000000000..50a5d3df6 --- /dev/null +++ b/imxweb/projects/qbm/src/lib/data-view/data-view-group/data-view-group.component.html @@ -0,0 +1,8 @@ + + diff --git a/imxweb/projects/qbm/src/lib/data-view/data-view-group/data-view-group.component.ts b/imxweb/projects/qbm/src/lib/data-view/data-view-group/data-view-group.component.ts new file mode 100644 index 000000000..f28d9fea3 --- /dev/null +++ b/imxweb/projects/qbm/src/lib/data-view/data-view-group/data-view-group.component.ts @@ -0,0 +1,69 @@ +/* + * ONE IDENTITY LLC. PROPRIETARY INFORMATION + * + * This software is confidential. One Identity, LLC. or one of its affiliates or + * subsidiaries, has supplied this software to you under terms of a + * license agreement, nondisclosure agreement or both. + * + * You may not copy, disclose, or use this software except in accordance with + * those terms. + * + * + * Copyright 2024 One Identity LLC. + * ALL RIGHTS RESERVED. + * + * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR + * WARRANTIES ABOUT THE SUITABILITY OF THE SOFTWARE, + * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED + * TO THE IMPLIED WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE, OR + * NON-INFRINGEMENT. ONE IDENTITY LLC. SHALL NOT BE + * LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE + * AS A RESULT OF USING, MODIFYING OR DISTRIBUTING + * THIS SOFTWARE OR ITS DERIVATIVES. + * + */ + +import { Component, effect, Input, OnInit } from '@angular/core'; +import { FormControl } from '@angular/forms'; +import { EuiSelectFeedbackMessages } from '@elemental-ui/core'; +import { TranslateService } from '@ngx-translate/core'; +import { DataViewSource } from '../data-view-source'; + +@Component({ + selector: 'imx-data-view-group', + templateUrl: './data-view-group.component.html', +}) +export class DataViewGroupComponent implements OnInit { + /** + * Input the DataViewSource service. It handles all the action and the data loading. This input property is required. + */ + @Input({ required: true }) public dataSource: DataViewSource; + formControl = new FormControl('', { nonNullable: true }); + feedbackMessages: EuiSelectFeedbackMessages; + + constructor(private readonly translateService: TranslateService) { + this.feedbackMessages = { + ...this.feedbackMessages, + search: this.translateService.instant('#LDS#Search'), + }; + effect(() => { + if (!!this.dataSource.groupByColumn() && this.dataSource.groupByColumn()?.ColumnName !== this.formControl.value) { + this.formControl.setValue(this.dataSource.groupByColumn()?.ColumnName || '', { emitEvent: false }); + } + }); + } + + ngOnInit(): void { + // Change the DataViewSource groupByColumn signal and rerender the table on template group option change event. + this.formControl.valueChanges.subscribe((column) => { + const selectedOption = this.dataSource.groupOptions.find((option) => option.value === column); + this.dataSource.groupByColumn.set(selectedOption?.clientProperty); + if (column !== null) { + this.dataSource.state.update((state) => ({ ...state, StartIndex: 0 })); + this.dataSource.selection.clear(); + this.dataSource.updateState(); + } + }); + } +} diff --git a/imxweb/projects/qbm/src/lib/data-view/data-view-nested-table/data-view-nested-table.component.html b/imxweb/projects/qbm/src/lib/data-view/data-view-nested-table/data-view-nested-table.component.html new file mode 100644 index 000000000..5e5edb2e3 --- /dev/null +++ b/imxweb/projects/qbm/src/lib/data-view/data-view-nested-table/data-view-nested-table.component.html @@ -0,0 +1,90 @@ + + + + + + + + + + + + + + + + + + + + + + + +
    + + + + + + + {{ dataSource.GetColumnDisplay(column.ColumnName || '', dataSource?.entitySchema()) }} + + {{ element?.GetEntity()?.GetColumn(column.ColumnName)?.GetDisplayValue() }} + + {{ dataSource.GetColumnDisplay(column.ColumnName || '', dataSource?.entitySchema()) }} + + {{ element?.GetEntity()?.GetColumn(column.ColumnName)?.GetDisplayValue() }} +
    +
    + +
    + +

    +
    +
    + diff --git a/imxweb/projects/qbm/src/lib/data-view/data-view-nested-table/data-view-nested-table.component.ts b/imxweb/projects/qbm/src/lib/data-view/data-view-nested-table/data-view-nested-table.component.ts new file mode 100644 index 000000000..f55f77819 --- /dev/null +++ b/imxweb/projects/qbm/src/lib/data-view/data-view-nested-table/data-view-nested-table.component.ts @@ -0,0 +1,210 @@ +/* + * ONE IDENTITY LLC. PROPRIETARY INFORMATION + * + * This software is confidential. One Identity, LLC. or one of its affiliates or + * subsidiaries, has supplied this software to you under terms of a + * license agreement, nondisclosure agreement or both. + * + * You may not copy, disclose, or use this software except in accordance with + * those terms. + * + * + * Copyright 2024 One Identity LLC. + * ALL RIGHTS RESERVED. + * + * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR + * WARRANTIES ABOUT THE SUITABILITY OF THE SOFTWARE, + * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED + * TO THE IMPLIED WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE, OR + * NON-INFRINGEMENT. ONE IDENTITY LLC. SHALL NOT BE + * LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE + * AS A RESULT OF USING, MODIFYING OR DISTRIBUTING + * THIS SOFTWARE OR ITS DERIVATIVES. + * + */ + +import { + ChangeDetectorRef, + Component, + computed, + effect, + EventEmitter, + Input, + OnInit, + Output, + QueryList, + Signal, + ViewChild, + WritableSignal, +} from '@angular/core'; +import { MatColumnDef, MatTable } from '@angular/material/table'; +import { CollectionLoadParameters, DataModel, EntitySchema, FilterData, IClientProperty } from '@imx-modules/imx-qbm-dbts'; +import { isEqual } from 'lodash'; +import { DataSourceItemStatus } from '../../data-source-toolbar/data-source-item-status.interface'; +import { DataViewSource } from '../data-view-source'; +import { ExecuteFunction, HightlightEntityFunction } from '../data-view.interface'; + +@Component({ + selector: 'imx-data-view-nested-table', + templateUrl: './data-view-nested-table.component.html', + providers: [DataViewSource], +}) +export class DataViewNestedTableComponent implements OnInit { + /** + * Required input property to use the same execute function as the parent component. + */ + @Input({ required: true }) execute: ExecuteFunction; + /** + * Required input property to use the same schema as the parent component. + */ + @Input({ required: true }) schema: EntitySchema; + /** + * Required input property to use the same table columns as the parent component. + */ + @Input({ required: true }) columnsToDisplay: IClientProperty[]; + /** + * Optional input property to use the same data model as the parent component. + */ + @Input() dataModel?: DataModel; + /** + * Table specific filters. + */ + @Input() filterData?: FilterData[]; + /** + * Filter and search params inherited from the parent component. + */ + @Input() params: CollectionLoadParameters; + /** + * Inherited table row selectable. + */ + @Input() selectable: boolean; + /** + * Use selection setter/getter to update the data source selection if the user uncheck some rows in the show selected only table. + */ + @Input() set selection(selection: any[]) { + this._selection = selection; + this.dataSource.selection.setSelection(selection); + } + get selection(): any[] { + return this._selection; + } + /** + * Inherited writableSignal to use on table row click action. + */ + @Input() highlightedEntity: WritableSignal; + + /** + * + */ + + @Input() public highlightedExecute: HightlightEntityFunction | undefined; + /** + * Set the no data title. + */ + @Input() public noDataText; + /** + * Set the icon type, which shown, when there is no data. + */ + @Input() public noDataIcon = 'content-alert'; + /** + * Inherited table mode from auto table component. + */ + @Input() public mode: 'auto' | 'manual'; + @Input() columnDefs: QueryList; + @Input() additionalColumns: IClientProperty[] = []; + /** + * Inherited data tabal item status; + */ + @Input() itemStatus: DataSourceItemStatus; + /** + * An event emitter on table selection change. + */ + @Output() selectionChange: EventEmitter = new EventEmitter(); + /** + * Array of the display columns. Add selectable column if selectable input property is true. + */ + public namesOfDisplayedColumns: Signal = computed(() => { + if (this.selectable) { + return ['select', ...this.dataSource?.columnsToDisplay()?.map((column) => column.ColumnName || '')]; + } + return this.dataSource?.columnsToDisplay()?.map((column) => column.ColumnName || ''); + }); + /** + * Signal hide paginator from the user when the DataViewSource total count is lower the the lowest page size option. + */ + public hidePaginator: Signal = computed(() => this.dataSource.totalCount() < this.dataSource.pageSizeOptions[0]); + + @ViewChild(MatTable, { static: true }) table: MatTable; + private _selection: any[] = []; + private cacheColumnDefs: string[] = []; + + constructor( + public readonly dataSource: DataViewSource, + public changeDetectionRef: ChangeDetectorRef, + ) { + // use effect to update the parent highlightedEntity with the current highlightedEntity. + effect( + () => { + if (this.dataSource.highlightedEntity() && !!this.highlightedEntity) { + this.highlightedEntity.set(this.dataSource.highlightedEntity()); + } + }, + { allowSignalWrites: true }, + ); + effect(() => { + if (this.dataSource.columnsToDisplay() && this.columnDefs && this.table) { + this.columnDefs.forEach((columnDef) => { + if (this.cacheColumnDefs.indexOf(columnDef.name) === -1) { + this.table.addColumnDef(columnDef); + this.cacheColumnDefs.push(columnDef.name); + } + }); + } + }); + } + + ngOnInit(): void { + // Update the DataViewSource state before call init. + this.dataSource.itemStatus = this.itemStatus; + this.dataSource.state.update((state) => ({ + ...this.params, + ...state, + filter: [...(this.filterData || []), ...(this.params.filter || [])], + search: this.params?.search, + })); + this.dataSource.additionalColumns.set(this.additionalColumns); + this.dataSource.init({ + execute: this.execute, + schema: this.schema, + columnsToDisplay: this.columnsToDisplay, + dataModel: this.dataModel, + selectionChange: (selection: any[]) => { + this.onSelectionChange(selection); + }, + highlightEntity: this.highlightedExecute, + }); + } + + /** + * Calls when a nested table selection is changed and emit the selectionChange Event. + * @param selection All the currently selected items. + */ + public onSelectionChange(selection: any[]): void { + if (!isEqual(this.selection, selection)) { + this.selectionChange.emit(selection); + } + } + + /** + * Select or clear all the currenlty visible rows. + */ + public toggleAllRows(): void { + if (this.dataSource.isAllSelected()) { + this.dataSource.selection.clear(); + return; + } + + this.dataSource.selection.select(this.dataSource.getAllSelectableEntities()); + } +} diff --git a/imxweb/projects/qbm/src/lib/data-view/data-view-paginator/data-view-paginator.component.html b/imxweb/projects/qbm/src/lib/data-view/data-view-paginator/data-view-paginator.component.html new file mode 100644 index 000000000..eeaa9726d --- /dev/null +++ b/imxweb/projects/qbm/src/lib/data-view/data-view-paginator/data-view-paginator.component.html @@ -0,0 +1,13 @@ + + + + diff --git a/imxweb/projects/qbm/src/lib/data-view/data-view-paginator/data-view-paginator.component.scss b/imxweb/projects/qbm/src/lib/data-view/data-view-paginator/data-view-paginator.component.scss new file mode 100644 index 000000000..61ac96f2c --- /dev/null +++ b/imxweb/projects/qbm/src/lib/data-view/data-view-paginator/data-view-paginator.component.scss @@ -0,0 +1,8 @@ +@import '@elemental-ui/core/src/styles/_eui_palette.scss'; + +:host{ + + .mat-mdc-paginator{ + border:none; + } +} diff --git a/imxweb/projects/qbm/src/lib/data-view/data-view-paginator/data-view-paginator.component.ts b/imxweb/projects/qbm/src/lib/data-view/data-view-paginator/data-view-paginator.component.ts new file mode 100644 index 000000000..fe2fc0b54 --- /dev/null +++ b/imxweb/projects/qbm/src/lib/data-view/data-view-paginator/data-view-paginator.component.ts @@ -0,0 +1,73 @@ +/* + * ONE IDENTITY LLC. PROPRIETARY INFORMATION + * + * This software is confidential. One Identity, LLC. or one of its affiliates or + * subsidiaries, has supplied this software to you under terms of a + * license agreement, nondisclosure agreement or both. + * + * You may not copy, disclose, or use this software except in accordance with + * those terms. + * + * + * Copyright 2024 One Identity LLC. + * ALL RIGHTS RESERVED. + * + * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR + * WARRANTIES ABOUT THE SUITABILITY OF THE SOFTWARE, + * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED + * TO THE IMPLIED WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE, OR + * NON-INFRINGEMENT. ONE IDENTITY LLC. SHALL NOT BE + * LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE + * AS A RESULT OF USING, MODIFYING OR DISTRIBUTING + * THIS SOFTWARE OR ITS DERIVATIVES. + * + */ + +import { Component, Input, Signal, computed } from '@angular/core'; +import { PageEvent } from '@angular/material/paginator'; +import { DataViewSource } from '../data-view-source'; + +@Component({ + selector: 'imx-data-view-paginator', + templateUrl: './data-view-paginator.component.html', + styleUrls: ['./data-view-paginator.component.scss'], +}) +export class DataViewPaginatorComponent { + /** + * Input the dataViewSource service. It handles all the action and the data loading. This input property is required. + */ + @Input({ required: true }) public dataSource: DataViewSource; + /** + * Signal get page size from DataViewSource state signal. + */ + public pageSize: Signal = computed(() => + this.dataSource.showOnlySelected() + ? this.dataSource.selection.selected.length + : this.dataSource.state().PageSize || this.dataSource.pageSizeOptions[0], + ); + /** + * Signal calculates the page index from DataViewSource state signal and pageSize. + */ + public pageIndex: Signal = computed(() => { + return this.dataSource.showOnlySelected() ? 0 : (this.dataSource.state().StartIndex || 0) / this.pageSize(); + }); + /** + * Signal hide page size selection UI from the user when the DataViewSource total count is lower the the lowest page size option. + */ + public hidePageSize: Signal = computed( + () => this.dataSource.totalCount() < this.dataSource.pageSizeOptions[0] || this.dataSource.showOnlySelected(), + ); + public totalCount: Signal = computed(() => + this.dataSource.showOnlySelected() ? this.dataSource.selection.selected.length : this.dataSource?.totalCount(), + ); + + /** + * Update the DataViewSource state and reload the table data on pagination change. + * @param event The current page state from the mat-paginator. + */ + public async onStateChanged(event: PageEvent): Promise { + this.dataSource.state.update((state) => ({ ...state, PageSize: event.pageSize, StartIndex: event.pageIndex * event.pageSize })); + await this.dataSource.updateState(); + } +} diff --git a/imxweb/projects/qbm/src/lib/data-view/data-view-search/data-view-search.component.html b/imxweb/projects/qbm/src/lib/data-view/data-view-search/data-view-search.component.html new file mode 100644 index 000000000..d6444a871 --- /dev/null +++ b/imxweb/projects/qbm/src/lib/data-view/data-view-search/data-view-search.component.html @@ -0,0 +1,2 @@ + + diff --git a/imxweb/projects/qbm/src/lib/data-view/data-view-search/data-view-search.component.scss b/imxweb/projects/qbm/src/lib/data-view/data-view-search/data-view-search.component.scss new file mode 100644 index 000000000..a07a4db69 --- /dev/null +++ b/imxweb/projects/qbm/src/lib/data-view/data-view-search/data-view-search.component.scss @@ -0,0 +1,3 @@ +:host{ + width: 400px; +} diff --git a/imxweb/projects/qbm/src/lib/data-view/data-view-search/data-view-search.component.ts b/imxweb/projects/qbm/src/lib/data-view/data-view-search/data-view-search.component.ts new file mode 100644 index 000000000..aab459642 --- /dev/null +++ b/imxweb/projects/qbm/src/lib/data-view/data-view-search/data-view-search.component.ts @@ -0,0 +1,125 @@ +/* + * ONE IDENTITY LLC. PROPRIETARY INFORMATION + * + * This software is confidential. One Identity, LLC. or one of its affiliates or + * subsidiaries, has supplied this software to you under terms of a + * license agreement, nondisclosure agreement or both. + * + * You may not copy, disclose, or use this software except in accordance with + * those terms. + * + * + * Copyright 2024 One Identity LLC. + * ALL RIGHTS RESERVED. + * + * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR + * WARRANTIES ABOUT THE SUITABILITY OF THE SOFTWARE, + * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED + * TO THE IMPLIED WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE, OR + * NON-INFRINGEMENT. ONE IDENTITY LLC. SHALL NOT BE + * LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE + * AS A RESULT OF USING, MODIFYING OR DISTRIBUTING + * THIS SOFTWARE OR ITS DERIVATIVES. + * + */ + +import { Component, effect, EventEmitter, Input, OnInit, Output } from '@angular/core'; +import { FormControl } from '@angular/forms'; +import { FilterType } from '@imx-modules/imx-qbm-dbts'; +import { debounceTime } from 'rxjs/operators'; +import { DataViewSource } from '../data-view-source'; +import { KeywordFilter, SelectedFilterType } from '../data-view.interface'; + +@Component({ + selector: 'imx-data-view-search', + templateUrl: './data-view-search.component.html', +}) +export class DataViewSearchComponent implements OnInit { + /** + * Input the dataViewSource service. It handles all the action and the data loading. This input property is required. + */ + @Input({ required: true }) public dataSource: DataViewSource; + /** + * Event to emit all the search params on change. + */ + @Output() public onSearchChange = new EventEmitter(); + /** + * FormControl to tracks the value and valueChange on eui-search component. + */ + public searchControl: FormControl = new FormControl('', { nonNullable: true }); + /** + * Private reset property to not call search accidentally. + */ + private reset = false; + private searchParams: string | undefined; + + constructor() { + effect(() => { + const newSearchParams = this.dataSource.state().search; + if (newSearchParams !== this.searchParams) { + this.searchParams = newSearchParams; + this.onSearchChange.emit(newSearchParams); + this.searchControl.setValue(newSearchParams || '', { emitEvent: false }); + } + }); + } + + public ngOnInit(): void { + // Call onSearch on searchControl valueChange after a 1000ms standby. + this.searchControl.valueChanges.pipe(debounceTime(1000)).subscribe((value) => this.onSearch(value)); + } + + /** + * Update DataViewSource setKeywords signal and reload data. + * @param keywords The value of the searchControl. + */ + public onSearch(keywords: string): void { + if (this.reset) { + this.reset = false; + return; + } + + this.dataSource.setKeywords(keywords); + } + + /** + * Add all keywords in searchControl value to the DataViewSource selectedfilters signal. + */ + public onAssignKeywords(): void { + setTimeout(() => { + if (this.isSearchEmpty) { + return; + } + this.reset = true; + let keywords = this.searchControl.value + .split(' ') + .map((item) => item.trim()) + .filter( + (item) => + item?.length > 0 && + !this.dataSource.selectedFilters().some((filter) => filter.type === SelectedFilterType.Keyword && filter.value === item), + ); + this.dataSource.selectedFilters.update((filters) => [ + ...filters, + ...keywords.map((keyword) => ({ type: SelectedFilterType.Keyword, value: keyword }) as KeywordFilter), + ]); + this.dataSource.state.update((state) => ({ + ...state, + filter: [...(state.filter || []), ...keywords.map((keyword) => ({ Type: FilterType.Search, Value1: keyword }))], + })); + this.searchControl.reset(''); + this.reset = false; + }); + } + + /** + * Calcuates the searchControls is really empty or not. + */ + private get isSearchEmpty(): boolean { + return this.searchControl.value == null || + (typeof this.searchControl.value === 'string' && this.searchControl.value.trim().length === 0) + ? true + : false; + } +} diff --git a/imxweb/projects/qbm/src/lib/data-view/data-view-selection/data-view-selection.component.html b/imxweb/projects/qbm/src/lib/data-view/data-view-selection/data-view-selection.component.html new file mode 100644 index 000000000..7f7dec396 --- /dev/null +++ b/imxweb/projects/qbm/src/lib/data-view/data-view-selection/data-view-selection.component.html @@ -0,0 +1,25 @@ +
    +
    + {{ '#LDS#Selected items' | translate }}: {{ totalSelected() > 0 ? totalSelected() : ('#LDS#None' | translate) }} +
    + + + {{ '#LDS#Show selected only' | translate }} + +
    diff --git a/imxweb/projects/qbm/src/lib/data-view/data-view-selection/data-view-selection.component.scss b/imxweb/projects/qbm/src/lib/data-view/data-view-selection/data-view-selection.component.scss new file mode 100644 index 000000000..200a7290e --- /dev/null +++ b/imxweb/projects/qbm/src/lib/data-view/data-view-selection/data-view-selection.component.scss @@ -0,0 +1,58 @@ +@import '@elemental-ui/core/src/styles/_eui_palette.scss'; + +:host{ + margin-right: auto; + .imx-selection{ + display: flex; + align-items: center; + &-info{ + font-size: 14px; + font-weight: 600; + margin-right: 8px; + &-title{ + font-weight: 400; + margin-right: 8px; + } + } + .mdc-icon-button{ + margin-right: 0; + } + } +} + + +:host{ + .imx-selection{ + &-info{ + &-itle{ + color: $color-gray-10; + } + } + } +} + +/* Dark theme */ +.eui-dark-theme { + :host{ + .imx-selection { + &-info { + &-title{ + color: $color-gray-20; + } + } + } + } +} + +/* High-contrast theme */ +.eui-contrast-theme { + :host{ + .imx-selection { + &-info{ + &-title{ + color: $color-gray-0; + } + } + } + } +} diff --git a/imxweb/projects/qbm/src/lib/data-view/data-view-selection/data-view-selection.component.ts b/imxweb/projects/qbm/src/lib/data-view/data-view-selection/data-view-selection.component.ts new file mode 100644 index 000000000..1e5c4761c --- /dev/null +++ b/imxweb/projects/qbm/src/lib/data-view/data-view-selection/data-view-selection.component.ts @@ -0,0 +1,76 @@ +/* + * ONE IDENTITY LLC. PROPRIETARY INFORMATION + * + * This software is confidential. One Identity, LLC. or one of its affiliates or + * subsidiaries, has supplied this software to you under terms of a + * license agreement, nondisclosure agreement or both. + * + * You may not copy, disclose, or use this software except in accordance with + * those terms. + * + * + * Copyright 2024 One Identity LLC. + * ALL RIGHTS RESERVED. + * + * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR + * WARRANTIES ABOUT THE SUITABILITY OF THE SOFTWARE, + * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED + * TO THE IMPLIED WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE, OR + * NON-INFRINGEMENT. ONE IDENTITY LLC. SHALL NOT BE + * LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE + * AS A RESULT OF USING, MODIFYING OR DISTRIBUTING + * THIS SOFTWARE OR ITS DERIVATIVES. + * + */ + +import { Component, Input, Signal, computed } from '@angular/core'; +import { MatSlideToggleChange } from '@angular/material/slide-toggle'; +import { DataViewSource } from '../data-view-source'; + +/** + * @example + * + */ + +@Component({ + selector: 'imx-data-view-selection', + templateUrl: './data-view-selection.component.html', + styleUrls: ['./data-view-selection.component.scss'], +}) +export class DataViewSelectionComponent { + /** + * Input the dataViewSource service. It handles all the action and the data loading. This input property is required. + */ + @Input({ required: true }) public dataSource: DataViewSource; + /** + * The value of the material slide toggle. + */ + public showSelected: boolean = false; + /** + * Get the total selected number and update the showSelected value in every selection change. + */ + public totalSelected: Signal = computed(() => { + this.dataSource.selectionChanged(); + if (this.dataSource.selection.selected.length == 0) { + this.showSelected = false; + } + return this.dataSource.selection.selected.length || 0; + }); + + /** + * Calls selection wrapper clear function. + */ + public onClearSelection(): void { + this.dataSource.nestedSelection = new Map(); + this.dataSource.selection.clear(); + } + + /** + * Update showOnlySelected signal in every slide toggle change event. + * @param $event The slide toggle change event object. + */ + public onShowSelectionChanged($event: MatSlideToggleChange) { + this.dataSource.showOnlySelected.set($event.checked); + } +} diff --git a/imxweb/projects/qbm/src/lib/data-view/data-view-settings/data-view-settings.component.html b/imxweb/projects/qbm/src/lib/data-view/data-view-settings/data-view-settings.component.html new file mode 100644 index 000000000..3088f58fa --- /dev/null +++ b/imxweb/projects/qbm/src/lib/data-view/data-view-settings/data-view-settings.component.html @@ -0,0 +1,85 @@ + + + + + + + + + + + + + +
    + + diff --git a/imxweb/projects/qbm/src/lib/data-view/data-view-settings/data-view-settings.component.ts b/imxweb/projects/qbm/src/lib/data-view/data-view-settings/data-view-settings.component.ts new file mode 100644 index 000000000..215892c27 --- /dev/null +++ b/imxweb/projects/qbm/src/lib/data-view/data-view-settings/data-view-settings.component.ts @@ -0,0 +1,262 @@ +/* + * ONE IDENTITY LLC. PROPRIETARY INFORMATION + * + * This software is confidential. One Identity, LLC. or one of its affiliates or + * subsidiaries, has supplied this software to you under terms of a + * license agreement, nondisclosure agreement or both. + * + * You may not copy, disclose, or use this software except in accordance with + * those terms. + * + * + * Copyright 2024 One Identity LLC. + * ALL RIGHTS RESERVED. + * + * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR + * WARRANTIES ABOUT THE SUITABILITY OF THE SOFTWARE, + * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED + * TO THE IMPLIED WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE, OR + * NON-INFRINGEMENT. ONE IDENTITY LLC. SHALL NOT BE + * LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE + * AS A RESULT OF USING, MODIFYING OR DISTRIBUTING + * THIS SOFTWARE OR ITS DERIVATIVES. + * + */ + +import { Component, EventEmitter, Input, Output, Signal, computed } from '@angular/core'; +import { MatDialog } from '@angular/material/dialog'; +import { EuiSidesheetService } from '@elemental-ui/core'; +import { FilterType, IClientProperty } from '@imx-modules/imx-qbm-dbts'; +import { TranslateService } from '@ngx-translate/core'; +import { firstValueFrom } from 'rxjs'; +import { calculateSidesheetWidth } from '../../base/sidesheet-helper'; +import { ConfirmationService } from '../../confirmation/confirmation.service'; +import { DataExportComponent } from '../../data-export/data-export.component'; +import { AdditionalInfosComponent } from '../../data-source-toolbar/additional-infos/additional-infos.component'; +import { DataSourceToolbarSettings } from '../../data-source-toolbar/data-source-toolbar-settings'; +import { DSTViewConfig } from '../../data-source-toolbar/data-source-toolbar-view-config.interface'; +import { SaveConfigDialogComponent } from '../../data-source-toolbar/save-config-dialog/save-config-dialog.component'; +import { SnackBarService } from '../../snackbar/snack-bar.service'; +import { DataViewSource } from '../data-view-source'; + +@Component({ + selector: 'imx-data-view-settings', + templateUrl: './data-view-settings.component.html', +}) +export class DataViewSettingsComponent { + /** + * Input the dataViewSource service. It handles all the action and the data loading. This input property is required. + */ + @Input({ required: true }) public dataSource: DataViewSource; + /** + * Event to emit a DSTViewConfig for post/put via the viewConfig.putViewConfig function. + */ + @Output() public updateConfig = new EventEmitter(); + /** + * Event to emit an DSTViewConfig.Id for delete via the viewConfig.deleteViewConfig function. + */ + @Output() public deleteConfigById = new EventEmitter(); + /** + * Checks if we have any saved configs at all in settings.viewConfig.viewConfigs. + */ + public hasSavedConfigs: Signal = computed( + () => !!this.dataSource.viewConfig()?.viewConfigs && !!this.dataSource.viewConfig()?.viewConfigs?.length, + ); + + constructor( + private readonly sidesheetService: EuiSidesheetService, + private readonly translateService: TranslateService, + private dialog: MatDialog, + private readonly confirm: ConfirmationService, + private readonly snackbar: SnackBarService, + ) {} + + /** + * Opens the dataExportSidesheet component with the required settings. + */ + public openExportSidesheet(): void { + const settings: DataSourceToolbarSettings = { + dataSource: this.dataSource.collectionData(), + navigationState: this.dataSource.state(), + entitySchema: this.dataSource.entitySchema(), + dataModel: this.dataSource.dataModel(), + exportMethod: this.dataSource.exportFunction, + displayedColumns: this.dataSource.columnsToDisplay(), + }; + this.sidesheetService.open(DataExportComponent, { + title: this.translateService.instant('#LDS#Heading Export Data'), + padding: '0px', + width: calculateSidesheetWidth(), + icon: 'export', + data: settings, + }); + } + + /** + * Call DataViewSource resetView on reset view button click. + */ + public onResetViewAndTree(): void { + this.dataSource.resetView(); + } + + /** + * Opens AdditionalInfosComponent dialog to add/remove columns and change column order. + */ + public async updateAdditionalColumns(): Promise { + this.dialog + .open(AdditionalInfosComponent, { + width: 'min(1200px,70%)', + autoFocus: false, + height: 'min(700px,70%)', + data: { + dataModel: this.dataSource.dataModel(), + entitySchema: this.dataSource.entitySchema(), + displayedColumns: this.dataSource.initialColumnsToDisplay, + additionalPropertyNames: this.dataSource.optionalColumns(), + additionalColumns: [], + preselectedProperties: [...this.dataSource.columnsToDisplay()], + }, + panelClass: 'imx-toolbar-dialog', + }) + .afterClosed() + .subscribe(async (result: { all: IClientProperty[]; optionals: IClientProperty[] }) => { + if (result) { + const needsReload = result.optionals.some( + (res) => this.dataSource.additionalColumns().find((sel) => sel.ColumnName === res.ColumnName) == null, + ); + if (needsReload) { + const additionalColumnNames = result.optionals.map((column) => column.ColumnName || ''); + this.dataSource.updateEntitySchema(additionalColumnNames); + this.dataSource.state.update((state) => ({ ...state, withProperties: additionalColumnNames.join(',') })); + await this.dataSource.updateState(true); + } + this.dataSource.additionalColumns.set(result.optionals); + this.dataSource.columnsToDisplay.set(result.all); + } + }); + } + + /** + * Opens the SaveConfigDialogComponent dialog and setup the a new config than emit that. + */ + public async saveConfig(): Promise { + const displayName = await firstValueFrom(this.dialog.open(SaveConfigDialogComponent).afterClosed()); + if (!displayName) { + return; + } + const existingConfig = this.dataSource.viewConfig()?.viewConfigs?.find((config) => config.DisplayName === displayName); + if (existingConfig && existingConfig.Id === 'Default') { + this.snackbar.open({ + key: '#LDS#You cannot overwrite the default view.', + }); + return; + } + if ( + existingConfig && + !(await this.confirm.confirmDelete( + '#LDS#Heading Overwrite View', + '#LDS#A view with the entered name already exists. Do you want to overwrite the already existing view with the new view?', + )) + ) { + return; + } + const config: DSTViewConfig = { + Id: existingConfig?.Id, + ViewId: this.dataSource.viewConfig()?.viewId, + DisplayName: displayName, + Filter: [ + ...(this.dataSource.state().filter || []), + ...(this.dataSource.state().search ? [{ Type: FilterType.Search, Value1: this.dataSource.state().search }] : []), + ], + GroupBy: this.dataSource.groupByColumn()?.ColumnName, + OrderBy: this.dataSource.state()?.OrderBy, + AdditionalTableColumns: this.dataSource.additionalColumns().map((column) => column.ColumnName || ''), + AdditionalParameters: this.dataSource + .predefinedFilters() + .filter((filter) => !!filter.CurrentValue) + .reduce( + (prevFilters: { [key: string]: string }, filter) => ({ ...prevFilters, [filter.Name || '']: filter.CurrentValue || '' }), + {}, + ), + UseAsDefault: false, + }; + this.snackbar.open({ + key: '#LDS#The view has been successfully saved.', + }); + this.updateConfig.emit(config); + } + + /** + * Checks the required config is dafault or not. + * @param config The selected DSTViewConfig. + * @returns Is config default. + */ + public isDefaultId(config: DSTViewConfig): boolean { + return config?.Id == 'Default'; + } + + /** + * Checks the required config is used as favourite or not. + * @param config The selected DSTViewConfig + * @returns Config is favourite. + */ + public isConfigDefault(config: DSTViewConfig): boolean { + return config.UseAsDefault; + } + + /** + * Changes the default icons on screen to reflect which config is default, emits a updateConfig signal to change the data on the server + * @param config the selected DSTViewConfig + */ + public toggleDefaultConfig(config: DSTViewConfig): void { + // Find the currently chosen default + const lastDefaultConfig = this.dataSource.viewConfig()?.viewConfigs?.find((config) => config.UseAsDefault); + if (!config.UseAsDefault) { + if (lastDefaultConfig && lastDefaultConfig.Id !== config.Id) { + // Set the previous config to false, as long as it isn't the same as the incoming config + lastDefaultConfig.UseAsDefault = false; + } + } + config.UseAsDefault = !config.UseAsDefault; + if (!config?.IsReadOnly) { + // We can safely update the chosen config as default, API will handle the others + this.updateConfig.emit(config); + } + if (config?.IsReadOnly && lastDefaultConfig) { + // We need to update the last config to be not-default, we cannot update the chosen as it is read-sonly + lastDefaultConfig?.IsReadOnly ? null : this.updateConfig.emit(lastDefaultConfig); + } + } + + /** + * Opens the SaveConfigDialogComponent dialog and update the selected config DisplayName. + * @param config the selected DSTViewConfig + */ + public async changeConfigName(config: DSTViewConfig): Promise { + await this.dialog + .open(SaveConfigDialogComponent, { + data: { + currentName: config.DisplayName, + }, + }) + .afterClosed() + .subscribe((displayName) => { + if (displayName) { + config.DisplayName = displayName; + this.updateConfig.emit(config); + } + }); + } + + /** + * Remove the selected config after show confirm dialog by the id of the config. + * @param id The id of the config. + */ + public async removeConfigIndex(id?: string): Promise { + if (id && !(await this.confirm.confirmDelete('#LDS#Heading Delete View', '#LDS#Are you sure you want to delete the view?'))) { + return; + } + this.deleteConfigById.emit(id); + } +} diff --git a/imxweb/projects/qbm/src/lib/data-view/data-view-source-factory.service.ts b/imxweb/projects/qbm/src/lib/data-view/data-view-source-factory.service.ts new file mode 100644 index 000000000..424b5740b --- /dev/null +++ b/imxweb/projects/qbm/src/lib/data-view/data-view-source-factory.service.ts @@ -0,0 +1,51 @@ +/* + * ONE IDENTITY LLC. PROPRIETARY INFORMATION + * + * This software is confidential. One Identity, LLC. or one of its affiliates or + * subsidiaries, has supplied this software to you under terms of a + * license agreement, nondisclosure agreement or both. + * + * You may not copy, disclose, or use this software except in accordance with + * those terms. + * + * + * Copyright 2024 One Identity LLC. + * ALL RIGHTS RESERVED. + * + * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR + * WARRANTIES ABOUT THE SUITABILITY OF THE SOFTWARE, + * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED + * TO THE IMPLIED WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE, OR + * NON-INFRINGEMENT. ONE IDENTITY LLC. SHALL NOT BE + * LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE + * AS A RESULT OF USING, MODIFYING OR DISTRIBUTING + * THIS SOFTWARE OR ITS DERIVATIVES. + * + */ + +import { Injectable } from '@angular/core'; +import { TypedEntity } from '@imx-modules/imx-qbm-dbts'; +import { ClassloggerService } from '../classlogger/classlogger.service'; +import { ConfirmationService } from '../confirmation/confirmation.service'; +import { ProcessingQueueService } from '../processing-queue/processing-queue.service'; +import { SettingsService } from '../settings/settings-service'; +import { SqlWizardApiService } from '../sqlwizard/sqlwizard-api.service'; +import { DataViewSource } from './data-view-source'; + +@Injectable({ + providedIn: 'root', +}) +export class DataViewSourceFactoryService { + constructor( + private readonly settings: SettingsService, + private readonly log: ClassloggerService, + private readonly confirmService: ConfirmationService, + private readonly sqlWizardApiService: SqlWizardApiService, + private readonly queueService: ProcessingQueueService, + ) {} + + public getDataSource(): DataViewSource { + return new DataViewSource(this.settings, this.log, this.confirmService, this.sqlWizardApiService, this.queueService); + } +} diff --git a/imxweb/projects/qbm/src/lib/data-view/data-view-source.spec.ts b/imxweb/projects/qbm/src/lib/data-view/data-view-source.spec.ts new file mode 100644 index 000000000..07128708c --- /dev/null +++ b/imxweb/projects/qbm/src/lib/data-view/data-view-source.spec.ts @@ -0,0 +1,138 @@ +/* + * ONE IDENTITY LLC. PROPRIETARY INFORMATION + * + * This software is confidential. One Identity, LLC. or one of its affiliates or + * subsidiaries, has supplied this software to you under terms of a + * license agreement, nondisclosure agreement or both. + * + * You may not copy, disclose, or use this software except in accordance with + * those terms. + * + * + * Copyright 2024 One Identity LLC. + * ALL RIGHTS RESERVED. + * + * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR + * WARRANTIES ABOUT THE SUITABILITY OF THE SOFTWARE, + * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED + * TO THE IMPLIED WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE, OR + * NON-INFRINGEMENT. ONE IDENTITY LLC. SHALL NOT BE + * LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE + * AS A RESULT OF USING, MODIFYING OR DISTRIBUTING + * THIS SOFTWARE OR ITS DERIVATIVES. + * + */ + +import { computed, signal } from '@angular/core'; +import { Sort } from '@angular/material/sort'; +import { MatTableDataSource } from '@angular/material/table'; +import { FilterTreeData, MethodDefinition, TypedEntity } from '@imx-modules/imx-qbm-dbts'; +import { debounce } from 'lodash'; +import { Observable, of } from 'rxjs'; +import { ClassloggerService } from '../classlogger/classlogger.service'; +import { ConfirmationService } from '../confirmation/confirmation.service'; +import { DSTViewConfig } from '../data-source-toolbar/data-source-toolbar-view-config.interface'; +import { SelectionModelWrapper } from '../data-source-toolbar/selection-model-wrapper'; +import { SettingsService } from '../settings/settings-service'; +import { SqlWizardApiService } from '../sqlwizard/sqlwizard-api.service'; +import { DataViewSource } from './data-view-source'; +import { DataViewInitParameters, GroupInfoRow, WritableEntitySchema } from './data-view.interface'; +export const FakeDataViewSource: Pick = { + collectionData: signal({ totalCount: 0, Data: [] }), + entitySchema: signal({ Columns: {}, LocalColumns: {} }), + dataModel: signal(undefined), + execute: () => Promise.resolve({ totalCount: 0, Data: [] }), + entitySubject: signal([]), + entitySubject$: of([]), + count: 0, + totalCount: signal(0), + getAllSelectableEntities: signal([]), + data: [], + loading: signal(false), + isLimitReached: signal(false), + selection: new SelectionModelWrapper(), + selectionChanged: signal(undefined), + selectionChangeFunction: undefined, + showOnlySelected: signal(false), + columnsToDisplay: signal([]), + initialColumnsToDisplay: [], + optionalColumns: signal([]), + additionalColumns: signal([]), + additionalListColumns: signal(undefined), + pageSizeOptions: [], + sortId: signal(undefined), + sortDirection: signal(''), + state: signal({ undefined }), + predefinedFilters: signal([]), + selectedFilters: signal([]), + exportFunction: { + getMethod: (withProperties: string, PageSize?: number) => ({}) as MethodDefinition, + }, + viewConfig: signal(undefined), + showFilters: signal(false), + currentSelectedEntityCount: signal(0), + isAllSelected: signal(false), + highlightedEntity: signal(undefined), + highlightedExecute: undefined, + itemStatus: { + enabled: () => true, + }, + groupOptions: [], + groupByColumn: signal(null), + groupData: signal(undefined), + groupedDataSource: computed(() => ({}) as MatTableDataSource), + nestedSelection: new Map(), + filterTree: { + filterMethode: (parentkey: string) => Promise.resolve({} as FilterTreeData), + }, + filterTreeData: signal({}), + filterTreeSelection: signal(undefined), + settings: new SettingsService(), + log: { + debug: () => {}, + info: () => {}, + } as unknown as ClassloggerService, + confirmService: {} as ConfirmationService, + sqlWizardApiService: {} as SqlWizardApiService, + ngOnDestroy: function (): void {}, + connect: function (): Observable { + return of([]); + }, + disconnect: function (): void {}, + init: async function (initParameters: DataViewInitParameters): Promise { + this.execute = initParameters.execute; + await this.updateState(); + return Promise.resolve(); + }, + updateState: async function (): Promise { + let collectionData = await this.execute(); + console.log(collectionData); + this.collectionData.set(collectionData); + return Promise.resolve(); + }, + sortChange: function (sortState: Sort): void {}, + abortCall: function (): void {}, + resetView: function (): Promise { + return Promise.resolve(); + }, + applyConfig: function (config: DSTViewConfig): Promise { + return Promise.resolve(); + }, + setKeywords: function (keywords: string): void {}, + updateEntitySchema: function (additionalColumnNames: string[]): void {}, + debouncedHighlightRow: debounce((entity: TypedEntity, event?) => {}, 250), + highlightRow: function (entity: TypedEntity, event?: MouseEvent): void {}, + isSortable: function (column: string | undefined): boolean { + return false; + }, + GetColumnDisplay: function (columnName: string, entitySchema?: WritableEntitySchema): string { + return ''; + }, + // initOptionalColumns: function (): void { + // + // }, + initFilters: function (initParameters: DataViewInitParameters): Promise { + return Promise.resolve(); + }, +}; diff --git a/imxweb/projects/qbm/src/lib/data-view/data-view-source.ts b/imxweb/projects/qbm/src/lib/data-view/data-view-source.ts new file mode 100644 index 000000000..2d390d8c3 --- /dev/null +++ b/imxweb/projects/qbm/src/lib/data-view/data-view-source.ts @@ -0,0 +1,622 @@ +/* + * ONE IDENTITY LLC. PROPRIETARY INFORMATION + * + * This software is confidential. One Identity, LLC. or one of its affiliates or + * subsidiaries, has supplied this software to you under terms of a + * license agreement, nondisclosure agreement or both. + * + * You may not copy, disclose, or use this software except in accordance with + * those terms. + * + * + * Copyright 2024 One Identity LLC. + * ALL RIGHTS RESERVED. + * + * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR + * WARRANTIES ABOUT THE SUITABILITY OF THE SOFTWARE, + * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED + * TO THE IMPLIED WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE, OR + * NON-INFRINGEMENT. ONE IDENTITY LLC. SHALL NOT BE + * LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE + * AS A RESULT OF USING, MODIFYING OR DISTRIBUTING + * THIS SOFTWARE OR ITS DERIVATIVES. + * + */ + +import { DataSource, SelectionChange } from '@angular/cdk/collections'; +import { Injectable, OnDestroy, Signal, WritableSignal, computed, effect, signal } from '@angular/core'; +import { toObservable } from '@angular/core/rxjs-interop'; +import { Sort, SortDirection } from '@angular/material/sort'; +import { MatTableDataSource } from '@angular/material/table'; +import { EuiSelectOption } from '@elemental-ui/core'; +import { + CollectionLoadParameters, + DataModel, + DataModelProperty, + ExtendedTypedEntityCollection, + FilterTreeData, + FilterType, + GroupInfoData, + IClientProperty, + TypedEntity, + ValType, +} from '@imx-modules/imx-qbm-dbts'; +import { debounce } from 'lodash'; +import { Observable, Subscription } from 'rxjs'; +import { ClassloggerService } from '../classlogger/classlogger.service'; +import { ConfirmationService } from '../confirmation/confirmation.service'; +import { FilterTreeParameter } from '../data-source-toolbar/data-model/filter-tree-parameter'; +import { DataSourceItemStatus } from '../data-source-toolbar/data-source-item-status.interface'; +import { DataSourceToolbarExportMethod } from '../data-source-toolbar/data-source-toolbar-export-method.interface'; +import { DataSourceToolbarFilter } from '../data-source-toolbar/data-source-toolbar-filters.interface'; +import { DSTViewConfig, DataSourceToolbarViewConfig } from '../data-source-toolbar/data-source-toolbar-view-config.interface'; +import { FilterTreeSelectionParameter } from '../data-source-toolbar/filter-wizard/filter-tree-sidesheet/filter-tree-sidesheet.model'; +import { SelectionModelWrapper } from '../data-source-toolbar/selection-model-wrapper'; +import { CompletedActionStates, QueuedActionState } from '../processing-queue/processing-queue.interface'; +import { ProcessingQueueService } from '../processing-queue/processing-queue.service'; +import { SettingsService } from '../settings/settings-service'; +import { SqlWizardApiService } from '../sqlwizard/sqlwizard-api.service'; +import { + DataViewInitParameters, + ExecuteFunction, + ExecuteGroupFunction, + GroupInfoRow, + HightlightEntityFunction, + SelectedFilter, + SelectedFilterType, + SelectionChangeFunction, + WritableEntitySchema, +} from './data-view.interface'; + +/** + * Set injectbale providedIn to null to have multiple instances of the DataViewSource service for every component. + */ +@Injectable({ + providedIn: null, +}) +export class DataViewSource implements DataSource, OnDestroy { + /** + * Collection of the generic type. + */ + public collectionData: WritableSignal> = signal({ totalCount: 0, Data: [] }); + public entitySchema: WritableSignal; + public dataModel: WritableSignal = signal(undefined); + public execute: ExecuteFunction; + public entitySubject: Signal = computed(() => { + this.selectionChanged(); + return this.showOnlySelected() ? this.selection.selected : this.collectionData().Data; + }); + public entitySubject$: Observable = toObservable(this.entitySubject); + public get count(): number { + return this.collectionData()?.Data.length | 0; + } + public totalCount: Signal = computed(() => { + return !!this.groupByColumn() ? this.groupData()?.TotalCount || 0 : this.collectionData()?.totalCount || 0; + }); + public getAllSelectableEntities: Signal = computed(() => this.entitySubject().filter((entity) => this.itemStatus.enabled(entity))); + + public get data(): T[] { + return this.collectionData()?.Data; + } + public loading: WritableSignal = signal(true); + public isLimitReached: Signal = computed(() => !!this.collectionData().IsLimitReached); + + // Selection + public readonly selection = new SelectionModelWrapper(); + public selectionChanged: WritableSignal | undefined> = signal(undefined); + public selectionChangeFunction: SelectionChangeFunction | undefined; + public showOnlySelected: WritableSignal = signal(false); + + // Table settings + public columnsToDisplay: WritableSignal = signal([]); + public initialColumnsToDisplay: IClientProperty[] = []; + public optionalColumns: WritableSignal<(IClientProperty | undefined)[]> = signal([]); + public additionalColumns: WritableSignal = signal([]); + public additionalListColumns: WritableSignal = signal(undefined); + public pageSizeOptions: number[] = []; + public sortId: WritableSignal = signal(undefined); + public sortDirection: WritableSignal = signal(''); + + // Filters & settings + public state: WritableSignal = signal({}); + public predefinedFilters: WritableSignal = signal([]); + public selectedFilters: WritableSignal = signal([]); + public exportFunction: DataSourceToolbarExportMethod; + public viewConfig: WritableSignal = signal(undefined); + public showFilters: WritableSignal = signal(false); + /** + * Signal, that calculates the number of the currently visible selected entities. + */ + public currentSelectedEntityCount: Signal = computed(() => { + this.selectionChanged(); + return this.entitySubject().filter((entity) => this.selection.isSelected(entity)).length; + }); + /** + * Signal, that calculates all the visible and selectable rows are selected. + */ + public isAllSelected: Signal = computed(() => this.currentSelectedEntityCount() == this.getAllSelectableEntities().length); + /** + * Row click event signal. + */ + public highlightedEntity: WritableSignal = signal(undefined, { equal: () => false }); + public highlightedExecute: HightlightEntityFunction | undefined; + + // If the item is defined, then use the queue to find if its in the queue or completed. Otherwise return true + private itemNotInQueueOrCompleted = (item?: TypedEntity) => + item + ? [...CompletedActionStates, QueuedActionState.NotInQueue].includes( + this.queueService.pollAction(item.GetEntity().GetKeys().join(',')), + ) + : true; + /** + * Row status functions - enabled if queue status is failed or not in queue + */ + public itemStatus: DataSourceItemStatus = { + status: (item?) => (item ? this.queueService.pollAction(item.GetEntity().GetKeys().join(',')) : QueuedActionState.NotInQueue), + enabled: this.itemNotInQueueOrCompleted, + // By default, enabled = rowEnabled + rowEnabled: this.itemNotInQueueOrCompleted, + }; + + // Group + public groupOptions: EuiSelectOption[] = []; + public groupByColumn: WritableSignal = signal(null); + public groupData: WritableSignal = signal(undefined); + public groupedDataSource: Signal> = computed( + () => new MatTableDataSource(this.groupData()?.Groups ?? []), + ); + /** + * Map of nested selection. + */ + public nestedSelection: Map = new Map(); + private groupExecute: ExecuteGroupFunction; + + // Filter tree + public filterTree: FilterTreeParameter; + public filterTreeData: WritableSignal = signal({}); + public filterTreeSelection: WritableSignal = signal(undefined); + + private abortController = new AbortController(); + private subscription: Subscription; + + constructor( + public readonly settings: SettingsService, + public readonly log: ClassloggerService, + public readonly confirmService: ConfirmationService, + public readonly sqlWizardApiService: SqlWizardApiService, + private readonly queueService: ProcessingQueueService, + ) { + this.pageSizeOptions = this.settings.DefaultPageOptions; + this.state.set({ PageSize: this.settings?.DefaultPageSize, StartIndex: 0 }); + this.log.debug(this, 'Creating data source'); + this.subscription = this.selection.changed.subscribe((change) => { + this.selectionChanged.set(change); + if (this.selectionChangeFunction) { + this.selectionChangeFunction(this.selection.selected); + } + if (this.selection.selected.length === 0) { + this.showOnlySelected.set(false); + } + }); + effect( + () => { + // Check when a new group is submitted whether a selected item is in the queue, deselect if so + this.queueService._groups(); + this.selection.selected.forEach((item) => { + if (!this.itemStatus.enabled(item)) { + this.selection.unChecked(item); + } + }); + }, + { allowSignalWrites: true }, + ); + effect( + () => { + if (this.highlightedEntity() && this.highlightedExecute) { + this.highlightedExecute(this.highlightedEntity()); + this.highlightedEntity.set(undefined); + } + }, + { allowSignalWrites: true }, + ); + } + + ngOnDestroy(): void { + this.log.debug(this, 'Destroying data source'); + this.subscription?.unsubscribe(); + } + + /** + * Connects the data table with the data source. + * @returns Observable that emits a new value when the data changes. + */ + public connect(): Observable { + this.log.debug(this, 'Connect'); + return this.entitySubject$; + } + + /** + * Disconnects the data table from this data source. + */ + public disconnect(): void { + this.log.debug(this, 'Disconnect'); + } + + /** + * Initialize the data source and call updateState function. + * @param initParameters The initParameters object contains all the required values to setup the data source properly. + */ + public async init(initParameters: DataViewInitParameters): Promise { + this.loading.set(true); + this.log.info(this, 'Initializing data source'); + this.execute = initParameters.execute; + this.collectionData.set({ totalCount: 0, Data: [] }); + this.entitySchema = signal({ ...initParameters.schema, LocalColumns: initParameters.schema.Columns }); + this.initialColumnsToDisplay = initParameters.columnsToDisplay; + if (initParameters.viewConfig) { + this.viewConfig.set(initParameters.viewConfig); + } + this.dataModel.set(initParameters.dataModel); + this.setupGroupOptions(); + if (initParameters.groupExecute) { + this.groupExecute = initParameters.groupExecute; + } + if (initParameters.exportFunction) { + this.exportFunction = initParameters.exportFunction; + } + if (!initParameters.localSource) { + await this.initFilters(initParameters); + } + this.selectionChangeFunction = initParameters.selectionChange; + this.highlightedExecute = initParameters.highlightEntity; + this.initOptionalColumns(); + if (initParameters.dataModel?.DefaultConfigId && !initParameters.uniqueConfig) { + const config = this.viewConfig()?.viewConfigs?.find((config) => config.Id == this.dataModel()?.DefaultConfigId); + if (config) { + await this.applyConfig(config); + return; + } + } + await this.updateState(); + this.columnsToDisplay.set(initParameters.columnsToDisplay); + this.loading.set(false); + } + + /** + * Calls the required execute function to reload the data. + */ + public async updateState(forceUpdate: boolean = false): Promise { + this.log.info(this, 'Updating data source'); + this.abortCall(); + if (!!this.groupByColumn() && !!this.groupExecute && !forceUpdate) { + this.loading.set(true); + const groupData = await this.groupExecute(this.groupByColumn()?.ColumnName || '', this.state(), this.abortController.signal); + this.groupData.set(groupData); + this.loading.set(false); + } else if (this.execute) { + this.loading.set(true); + let collectionData = await this.execute(this.state(), this.abortController.signal); + if (!!collectionData) { + collectionData.Data.map((elem) => { + if (elem.GetEntity) { + elem.GetEntity()?.ApplySchema(this.entitySchema()); + } + }); + this.collectionData.set(collectionData); + } else { + this.collectionData.set({ totalCount: 0, Data: [] }); + } + this.loading.set(false); + } + } + + /** + * Update the data state sorting. + * @param sortState The current sort state. + */ + public sortChange(sortState: Sort) { + if (sortState.direction) { + this.sortId.set(sortState.active); + this.sortDirection.set(sortState.direction); + this.state.update((state) => ({ ...state, OrderBy: `${sortState.active} ${sortState.direction}` })); + } else { + this.sortId.set(undefined); + this.sortDirection.set(''); + this.state.update((state) => ({ ...state, OrderBy: undefined })); + } + this.log.debug(this, 'Sort change', sortState.active, sortState.direction); + this.updateState(); + } + + /** + * Abort the previous data loading. + */ + public abortCall(): void { + this.log.info(this, 'Aborting call'); + this.abortController.abort(); + this.abortController = new AbortController(); + this.abortController.signal; + } + + /** + * Reset filters, columns and page index to default and than reload the data after a confirm dialog confirmation. + */ + public async resetView(): Promise { + if ( + await this.confirmService.confirmDelete( + '#LDS#Heading Reset View', + '#LDS#If you reset the view, the search, sorting, filters and additional columns will be reset. Are you sure you want to reset the view?', + ) + ) { + this.state.set({ PageSize: this.settings?.DefaultPageSize, StartIndex: 0 }); + this.columnsToDisplay.set(this.initialColumnsToDisplay); + this.selectedFilters.set([]); + this.predefinedFilters.update((predefinedFilters) => predefinedFilters.map((filter) => ({ ...filter, CurrentValue: undefined }))); + this.filterTreeSelection.set(undefined); + this.sortId.set(undefined); + this.sortDirection.set(''); + this.updateState(); + } + } + + /** + * Apply the selected to config and reload the data table. + * @param config The selected view config. + */ + public async applyConfig(config: DSTViewConfig): Promise { + let columnsToDisplay = this.initialColumnsToDisplay; + let additionalColumns: IClientProperty[] = []; + this.state.set({ PageSize: this.settings?.DefaultPageSize, StartIndex: 0 }); + this.predefinedFilters.update((predefinedFilters) => predefinedFilters.map((filter) => ({ ...filter, CurrentValue: undefined }))); + this.selection.clear(); + //Update additional columns + if (!!config.AdditionalTableColumns?.length) { + additionalColumns = + (this.dataModel() + ?.Properties?.filter((property) => config?.AdditionalTableColumns?.includes(property?.Property?.ColumnName || '')) + .filter((property) => !this.initialColumnsToDisplay.some((column) => column.ColumnName === property?.Property?.ColumnName)) + .map((property) => property?.Property) + .filter((property) => !!property) as IClientProperty[]) || []; + columnsToDisplay = [...this.initialColumnsToDisplay, ...additionalColumns]; + this.state.update((state) => ({ ...state, withProperties: config?.AdditionalTableColumns?.join(',') })); + this.updateEntitySchema(config?.AdditionalTableColumns || []); + } + // Update predefined filters + if (config.AdditionalParameters) { + this.state.update((state) => ({ ...state, ...config.AdditionalParameters })); + this.predefinedFilters.update((filters) => + filters.map((filter) => { + if (!!config?.AdditionalParameters?.[filter.Name || '']) { + return { ...filter, CurrentValue: config?.AdditionalParameters?.[filter.Name || ''] }; + } else { + return filter; + } + }), + ); + } else { + this.predefinedFilters.set([...(this.dataModel()?.Filters || [])]); + } + this.additionalListColumns.set( + config.AdditionalListColumns?.map( + (column) => this.dataModel()?.Properties?.find((property) => property.Property?.ColumnName === column)?.Property, + ).filter(Boolean) as IClientProperty[], + ); + // Update selected filters + if (!!config.Filter?.length) { + this.state.update((state) => ({ ...state, filter: config.Filter?.filter((filter) => filter.Type === FilterType.Expression) })); + this.selectedFilters.set( + config.Filter?.map((filter) => { + let selectedFilter: SelectedFilter; + if (filter.Type == FilterType.Search) { + selectedFilter = { type: SelectedFilterType.Keyword, value: filter.Value1 }; + } else { + selectedFilter = { type: SelectedFilterType.Custom, value: { Expression: filter.Expression } }; + } + return selectedFilter; + }) || [], + ); + this.setKeywords( + config.Filter?.filter((filter) => filter.Type === FilterType.Search) + .map((filter) => filter.Value1) + .join(' ') || '', + ); + } else { + this.selectedFilters.set([]); + } + // Update order + if (!!config.OrderBy) { + this.state.update((state) => ({ ...state, OrderBy: config.OrderBy })); + const order = config.OrderBy.split(' '); + this.sortId.set(order[0]); + this.sortDirection.set((order[1].toLowerCase() as SortDirection) || 'asc'); + } + // Update grouping + if (!!config.GroupBy) { + const selectedOption = this.groupOptions.find((option) => option.value === config.GroupBy); + this.groupByColumn.set(selectedOption?.clientProperty); + } + await this.updateState(); + this.columnsToDisplay.set(columnsToDisplay); + this.additionalColumns.set(additionalColumns); + } + + /** + * Updates the state signal search property with the selected keywords + * @param keywords All the searched keywords seperate with a space. + */ + public setKeywords(keywords: string): void { + const alreadySearched = this.state() + .search?.split(' ') + .map((item) => item.trim()) + .every((searchItem) => this.selectedFilters().find((filter) => filter.value === searchItem)); + + let exisitingKeywords: string[] = this.selectedFilters() + .filter((item) => item.type === SelectedFilterType.Keyword) + .map((item) => (item.value as string).trim()); + let newKeywords: string[] = keywords + .split(' ') + .map((item) => item.trim()) + .filter((item) => item?.length > 0 && !exisitingKeywords.includes(item)); + + this.state.update((state) => ({ ...state, search: newKeywords.join(' '), StartIndex: undefined })); + const noAction = alreadySearched && !keywords; + if (noAction) { + return; + } + this.updateState(); + } + + /** + * Updates the entitySchem with the required LocalColumns, because in entitySchema the column object is readonly. + * @param additionalColumnNames The array of the columns. + */ + public updateEntitySchema(additionalColumnNames: string[]): void { + this.entitySchema.update((entitySchema) => { + additionalColumnNames.map((column) => (entitySchema.LocalColumns[column] = this.getClientProperty(column))); + return entitySchema; + }); + } + + /** + * Used to prevent unintended multiple signal firing + */ + public debouncedHighlightRow = debounce((entity: T, event?) => this.highlightRow(entity, event), 250); + + /** + * Highlights (selects) the current row and emits an event. + * @param entity The selected row. + * @param event The mouse clicked event. + */ + public highlightRow(entity: T, event?: MouseEvent): void { + // Prevent emission for certain cases + if (event) { + // Make sure we aren't selecting text + if (event.view?.getSelection()?.type === 'Range') { + return; + } + + // Prevent button clicks from propogating as row clicks, Walk up node chain until we hit table looking if we are a button + let target: HTMLElement | null = event.target as HTMLElement; + while (target) { + if (target.tagName === 'BUTTON') { + return; + } + if (target.tagName === 'TABLE') { + break; + } + target = target.parentElement; + } + } + + // Emit a changed event (even if the same row was selected), to allow any listners to decide whether to act or not + // Signal is allowed if there is no rowEnabled function, or if the function is allowing it and the highlightedExecute function is initialized. + if (!!this.highlightedExecute && (!this.itemStatus.rowEnabled || this.itemStatus.rowEnabled(entity))) + this.highlightedEntity.set(entity); + } + + /** + * Checks a column sortable or not via the data model IsSortable property. + * @param column The selected column name. + * @returns Column is sortable. + */ + public isSortable(column: string | undefined): boolean { + if (!column || this?.dataModel() == null || !!this.groupByColumn()) { + return false; + } + const sortable = this?.dataModel()?.Properties?.find((prop: DataModelProperty) => prop.Property?.ColumnName === column); + return sortable == null ? false : sortable?.IsSortable; + } + + /** + * Returns the column display property or the column name to the table column header. + * @param columnName the selected column name. + * @param entitySchema the selected WritableEntitySchema + * @returns The displayed column header. + */ + public GetColumnDisplay(columnName: string, entitySchema?: WritableEntitySchema): string { + const column = entitySchema?.LocalColumns[columnName]; + if (column == null || column.Display == null) { + return columnName; + } + + return column.Display; + } + + /** + * Set option columns from the dataModel signal. + */ + private initOptionalColumns(): void { + this.optionalColumns.set( + this.dataModel() + ?.Properties?.filter((property) => property.IsAdditionalColumn) + .map((property) => property.Property) || [], + ); + } + + /** + * Initialize the filter properties. + * @param initParameters The initParameters object contains all the required values to setup the data source properly. + */ + async initFilters(initParameters: DataViewInitParameters): Promise { + if (!!initParameters.dataModel?.Filters?.length || initParameters.filterTree) { + this.showFilters.set(true); + } else { + const column = await this.sqlWizardApiService.getFilterProperties(this.entitySchema().TypeName ?? ''); + if (!!column.length && !!this.sqlWizardApiService.implemented) { + this.showFilters.set(true); + } + } + this.predefinedFilters.set([...(initParameters.dataModel?.Filters || [])]); + if (initParameters.filterTree) { + this.filterTree = initParameters.filterTree; + this.filterTreeData.set(await this.filterTree.filterMethode('')); + } + } + + /** + * Get IClientProperty from the entitySchema/dataModel or created it with string type. + * @param name column name + * @returns IClientProperty + */ + private getClientProperty(name: string): IClientProperty { + let property: IClientProperty | undefined; + if (this.entitySchema()) { + const key = + Object.keys(this.entitySchema().LocalColumns).find((elem) => elem.toLocaleLowerCase() === name.toLocaleLowerCase()) ?? name; + property = key != null ? this.entitySchema().LocalColumns[key] : undefined; + } + if (property == null) { + property = this.dataModel()?.Properties?.find( + (elem) => elem?.Property?.ColumnName?.toLocaleLowerCase() === name?.toLocaleLowerCase(), + )?.Property; + } + if (property == null) { + property = { ColumnName: name, Type: ValType.String }; + } + return property; + } + + /** + * Setup group options. Inherited from data model groupable properties. + */ + private setupGroupOptions(): void { + this.groupOptions = + this.dataModel() + ?.Properties?.filter((property) => property.IsGroupable) + .map((property) => ({ + display: property.Property?.Display || '', + value: property.Property?.ColumnName || '', + clientProperty: property.Property, + })) || []; + this.dataModel()?.GroupInfo?.map((groupInfo) => { + groupInfo.Options?.map((option) => { + const property: IClientProperty = { + Type: ValType.Text, + ColumnName: option.Value, + }; + this.groupOptions.push({ display: `${option.Display} - ${groupInfo.Display}`, value: option.Value, clientProperty: property }); + }); + }); + } +} diff --git a/imxweb/projects/qbm/src/lib/data-view/data-view-status/data-view-status.component.html b/imxweb/projects/qbm/src/lib/data-view/data-view-status/data-view-status.component.html new file mode 100644 index 000000000..df7c9ed61 --- /dev/null +++ b/imxweb/projects/qbm/src/lib/data-view/data-view-status/data-view-status.component.html @@ -0,0 +1,34 @@ +@switch (status) { + @case (stateOptions.Waiting) { + {{ '#LDS#Queued' | translate }} + } + @case (stateOptions.Processing) { + {{ '#LDS#Processing' | translate }} + } + @case (stateOptions.Success) { + {{ '#LDS#Success' | translate }} + } + @case (stateOptions.Failed) { + {{ '#LDS#Failed' | translate }} + } +} diff --git a/imxweb/projects/qbm/src/lib/data-view/data-view-status/data-view-status.component.scss b/imxweb/projects/qbm/src/lib/data-view/data-view-status/data-view-status.component.scss new file mode 100644 index 000000000..715217fac --- /dev/null +++ b/imxweb/projects/qbm/src/lib/data-view/data-view-status/data-view-status.component.scss @@ -0,0 +1,4 @@ +:host{ + display: flex; + margin-bottom: 5px; +} diff --git a/imxweb/projects/qbm/src/lib/menu/menu-item/navigation-menu-item.ts b/imxweb/projects/qbm/src/lib/data-view/data-view-status/data-view-status.component.ts similarity index 65% rename from imxweb/projects/qbm/src/lib/menu/menu-item/navigation-menu-item.ts rename to imxweb/projects/qbm/src/lib/data-view/data-view-status/data-view-status.component.ts index 70aaf4daa..8ba148650 100644 --- a/imxweb/projects/qbm/src/lib/menu/menu-item/navigation-menu-item.ts +++ b/imxweb/projects/qbm/src/lib/data-view/data-view-status/data-view-status.component.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -24,13 +24,15 @@ * */ -import { MenuItem } from './menu-item.interface'; +import { Component, Input } from '@angular/core'; +import { QueuedActionState } from '../../processing-queue/processing-queue.interface'; -/** Represents a menu item that activates a route when clicked. */ -export class NavigationMenuItem implements MenuItem { - constructor( - public readonly id: string, - public readonly route: string, - public readonly title: string, - public readonly description: string) {} +@Component({ + selector: 'imx-data-view-status', + templateUrl: './data-view-status.component.html', + styleUrl: './data-view-status.component.scss', +}) +export class DataViewStatusComponent { + public stateOptions = QueuedActionState; + @Input() status: QueuedActionState; } diff --git a/imxweb/projects/qbm/src/lib/data-view/data-view-toolbar/data-view-toolbar.component.html b/imxweb/projects/qbm/src/lib/data-view/data-view-toolbar/data-view-toolbar.component.html new file mode 100644 index 000000000..954a25f22 --- /dev/null +++ b/imxweb/projects/qbm/src/lib/data-view/data-view-toolbar/data-view-toolbar.component.html @@ -0,0 +1,19 @@ +
    + + + + + + +
    + diff --git a/imxweb/projects/qbm/src/lib/data-view/data-view-toolbar/data-view-toolbar.component.scss b/imxweb/projects/qbm/src/lib/data-view/data-view-toolbar/data-view-toolbar.component.scss new file mode 100644 index 000000000..4bccc30ec --- /dev/null +++ b/imxweb/projects/qbm/src/lib/data-view/data-view-toolbar/data-view-toolbar.component.scss @@ -0,0 +1,9 @@ +.imx-data-view-controls{ + display: flex; + flex-wrap: wrap; + align-items: center; + width: 100%; + justify-content: flex-end; + gap: 8px; + margin-bottom: 16px; +} diff --git a/imxweb/projects/qbm/src/lib/data-view/data-view-toolbar/data-view-toolbar.component.ts b/imxweb/projects/qbm/src/lib/data-view/data-view-toolbar/data-view-toolbar.component.ts new file mode 100644 index 000000000..f2361f446 --- /dev/null +++ b/imxweb/projects/qbm/src/lib/data-view/data-view-toolbar/data-view-toolbar.component.ts @@ -0,0 +1,67 @@ +/* + * ONE IDENTITY LLC. PROPRIETARY INFORMATION + * + * This software is confidential. One Identity, LLC. or one of its affiliates or + * subsidiaries, has supplied this software to you under terms of a + * license agreement, nondisclosure agreement or both. + * + * You may not copy, disclose, or use this software except in accordance with + * those terms. + * + * + * Copyright 2024 One Identity LLC. + * ALL RIGHTS RESERVED. + * + * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR + * WARRANTIES ABOUT THE SUITABILITY OF THE SOFTWARE, + * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED + * TO THE IMPLIED WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE, OR + * NON-INFRINGEMENT. ONE IDENTITY LLC. SHALL NOT BE + * LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE + * AS A RESULT OF USING, MODIFYING OR DISTRIBUTING + * THIS SOFTWARE OR ITS DERIVATIVES. + * + */ + +import { Component, EventEmitter, Input, Output } from '@angular/core'; +import { DSTViewConfig } from '../../data-source-toolbar/data-source-toolbar-view-config.interface'; +import { DataViewSource } from '../data-view-source'; + +/** + * @example + * The updateConfig and the deleteConfigById Output only needs when you want to use the dataViewSettings component. + * + */ +@Component({ + selector: 'imx-data-view-toolbar', + templateUrl: './data-view-toolbar.component.html', + styleUrls: ['./data-view-toolbar.component.scss'], +}) +export class DataViewToolbarComponent { + /** + * Input the dataViewSource service. It handles all the action and the data loading. This input property is required. + */ + @Input({ required: true }) public dataSource: DataViewSource; + @Input() showSettings = true; + @Input() showSearch = true; + @Input() showGrouping = true; + /** + * Event to emit a DSTViewConfig for post/put via the viewConfig.putViewConfig function. + */ + @Output() public updateConfig = new EventEmitter(); + /** + * Event to emit an DSTViewConfig.Id for delete via the viewConfig.deleteViewConfig function. + */ + @Output() public deleteConfigById = new EventEmitter(); + /** + * Event to emit all the search params on change. Only need this event emitter if you use only the toolbar component. + */ + @Output() public onSearchChange = new EventEmitter(); + + constructor() {} +} diff --git a/imxweb/projects/qbm/src/lib/data-view/data-view.interface.ts b/imxweb/projects/qbm/src/lib/data-view/data-view.interface.ts new file mode 100644 index 000000000..4f856b30e --- /dev/null +++ b/imxweb/projects/qbm/src/lib/data-view/data-view.interface.ts @@ -0,0 +1,100 @@ +/* + * ONE IDENTITY LLC. PROPRIETARY INFORMATION + * + * This software is confidential. One Identity, LLC. or one of its affiliates or + * subsidiaries, has supplied this software to you under terms of a + * license agreement, nondisclosure agreement or both. + * + * You may not copy, disclose, or use this software except in accordance with + * those terms. + * + * + * Copyright 2024 One Identity LLC. + * ALL RIGHTS RESERVED. + * + * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR + * WARRANTIES ABOUT THE SUITABILITY OF THE SOFTWARE, + * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED + * TO THE IMPLIED WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE, OR + * NON-INFRINGEMENT. ONE IDENTITY LLC. SHALL NOT BE + * LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE + * AS A RESULT OF USING, MODIFYING OR DISTRIBUTING + * THIS SOFTWARE OR ITS DERIVATIVES. + * + */ + +import { + CollectionLoadParameters, + DataModel, + EntitySchema, + GroupInfo, + GroupInfoData, + IClientProperty, + SqlWizardExpression, + TypedEntityCollectionData, +} from '@imx-modules/imx-qbm-dbts'; +import { FilterTreeParameter } from '../data-source-toolbar/data-model/filter-tree-parameter'; +import { DataSourceToolbarExportMethod } from '../data-source-toolbar/data-source-toolbar-export-method.interface'; +import { DataSourceToolbarViewConfig } from '../data-source-toolbar/data-source-toolbar-view-config.interface'; + +// Extends entity schema with a local column object to updates columns +export interface WritableEntitySchema extends EntitySchema { + LocalColumns: { + [id: string]: IClientProperty; + }; +} +// Type for execute function. +export type ExecuteFunction = { + (params: CollectionLoadParameters, signal: AbortSignal): Promise | undefined>; +}; +// Type for group execute function. +export type ExecuteGroupFunction = { + (columnName: string, params: CollectionLoadParameters, signal: AbortSignal): Promise; +}; +// Type for table selection change function. +export type SelectionChangeFunction = { + (selection: readonly T[]): void; +}; +// Type for table row highlight function. +export type HightlightEntityFunction = { + (entity: T): void; +}; +// Enum for the data table filter +export enum SelectedFilterType { + None, + Keyword, // search keyword + Custom, // expression filter +} + +export interface KeywordFilter { + type: SelectedFilterType.Keyword; + value: string; +} + +export interface ExpressionFilter { + type: SelectedFilterType.Custom; + value: SqlWizardExpression; +} +// Combined keyword and expression filter type. +export type SelectedFilter = KeywordFilter | ExpressionFilter; +// Group info interface with an expanded extension to handle group expanded actions. +export interface GroupInfoRow extends GroupInfo { + expanded?: boolean; +} + +// Interface for initialize data view. +export interface DataViewInitParameters { + execute: ExecuteFunction; + schema: EntitySchema; + columnsToDisplay: IClientProperty[]; + dataModel?: DataModel; + groupExecute?: ExecuteGroupFunction; + exportFunction?: DataSourceToolbarExportMethod; + viewConfig?: DataSourceToolbarViewConfig; + uniqueConfig?: boolean; + selectionChange?: SelectionChangeFunction; + filterTree?: FilterTreeParameter; + highlightEntity?: HightlightEntityFunction; + localSource?: boolean; +} diff --git a/imxweb/projects/qbm/src/lib/data-view/data-view.module.ts b/imxweb/projects/qbm/src/lib/data-view/data-view.module.ts new file mode 100644 index 000000000..2ba8faf4e --- /dev/null +++ b/imxweb/projects/qbm/src/lib/data-view/data-view.module.ts @@ -0,0 +1,109 @@ +/* + * ONE IDENTITY LLC. PROPRIETARY INFORMATION + * + * This software is confidential. One Identity, LLC. or one of its affiliates or + * subsidiaries, has supplied this software to you under terms of a + * license agreement, nondisclosure agreement or both. + * + * You may not copy, disclose, or use this software except in accordance with + * those terms. + * + * + * Copyright 2024 One Identity LLC. + * ALL RIGHTS RESERVED. + * + * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR + * WARRANTIES ABOUT THE SUITABILITY OF THE SOFTWARE, + * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED + * TO THE IMPLIED WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE, OR + * NON-INFRINGEMENT. ONE IDENTITY LLC. SHALL NOT BE + * LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE + * AS A RESULT OF USING, MODIFYING OR DISTRIBUTING + * THIS SOFTWARE OR ITS DERIVATIVES. + * + */ + +import { DragDropModule } from '@angular/cdk/drag-drop'; +import { CommonModule } from '@angular/common'; +import { NgModule } from '@angular/core'; +import { FormsModule, ReactiveFormsModule } from '@angular/forms'; +import { MatButtonModule } from '@angular/material/button'; +import { MatChipsModule } from '@angular/material/chips'; +import { MatRippleModule } from '@angular/material/core'; +import { MatFormFieldModule } from '@angular/material/form-field'; +import { MatIconModule } from '@angular/material/icon'; +import { MatInputModule } from '@angular/material/input'; +import { MatPaginatorModule } from '@angular/material/paginator'; +import { MatProgressBarModule } from '@angular/material/progress-bar'; +import { MatSelectModule } from '@angular/material/select'; +import { MatSortModule } from '@angular/material/sort'; +import { MatTableModule } from '@angular/material/table'; +import { MatTabsModule } from '@angular/material/tabs'; +import { EuiCoreModule, EuiMaterialModule } from '@elemental-ui/core'; +import { TranslateModule } from '@ngx-translate/core'; +import { DataTableModule } from '../data-table/data-table.module'; +import { BusyIndicatorModule } from './../busy-indicator/busy-indicator.module'; +import { DataViewAutoTableComponent } from './data-view-auto-table/data-view-auto-table.component'; +import { DataViewChipbarComponent } from './data-view-chipbar/data-view-chipbar.component'; +import { DataViewFilterComponent } from './data-view-filter/data-view-filter.component'; +import { DataViewGroupComponent } from './data-view-group/data-view-group.component'; +import { DataViewNestedTableComponent } from './data-view-nested-table/data-view-nested-table.component'; +import { DataViewPaginatorComponent } from './data-view-paginator/data-view-paginator.component'; +import { DataViewSearchComponent } from './data-view-search/data-view-search.component'; +import { DataViewSelectionComponent } from './data-view-selection/data-view-selection.component'; +import { DataViewSettingsComponent } from './data-view-settings/data-view-settings.component'; +import { DataViewStatusComponent } from './data-view-status/data-view-status.component'; +import { DataViewToolbarComponent } from './data-view-toolbar/data-view-toolbar.component'; +@NgModule({ + declarations: [ + DataViewAutoTableComponent, + DataViewPaginatorComponent, + DataViewSearchComponent, + DataViewToolbarComponent, + DataViewChipbarComponent, + DataViewGroupComponent, + DataViewNestedTableComponent, + DataViewSettingsComponent, + DataViewFilterComponent, + DataViewSelectionComponent, + DataViewStatusComponent, + ], + imports: [ + CommonModule, + CommonModule, + TranslateModule, + FormsModule, + ReactiveFormsModule, + EuiCoreModule, + EuiMaterialModule, + MatFormFieldModule, + MatIconModule, + MatInputModule, + MatButtonModule, + MatPaginatorModule, + MatTableModule, + MatChipsModule, + MatProgressBarModule, + DragDropModule, + MatSortModule, + MatTabsModule, + MatSelectModule, + MatRippleModule, + BusyIndicatorModule, + DataTableModule, + ], + exports: [ + DataViewAutoTableComponent, + DataViewPaginatorComponent, + DataViewSearchComponent, + DataViewToolbarComponent, + DataViewChipbarComponent, + DataViewGroupComponent, + DataViewSettingsComponent, + DataViewFilterComponent, + DataViewSelectionComponent, + DataViewStatusComponent, + ], +}) +export class DataViewModule {} diff --git a/imxweb/projects/qbm/src/lib/date/date.module.ts b/imxweb/projects/qbm/src/lib/date/date.module.ts index 005eb1204..539c14214 100644 --- a/imxweb/projects/qbm/src/lib/date/date.module.ts +++ b/imxweb/projects/qbm/src/lib/date/date.module.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -30,11 +30,11 @@ import { FormsModule, ReactiveFormsModule } from '@angular/forms'; import { MatMomentDateModule, MAT_MOMENT_DATE_FORMATS, MomentDateAdapter } from '@angular/material-moment-adapter'; import { A11yModule } from '@angular/cdk/a11y'; -import { OverlayModule} from '@angular/cdk/overlay'; +import { OverlayModule } from '@angular/cdk/overlay'; import { MatButtonModule } from '@angular/material/button'; -import { DateAdapter, MAT_DATE_FORMATS, MAT_DATE_LOCALE } from '@angular/material/core'; -import { MatDatepickerModule } from '@angular/material/datepicker'; +import { DateAdapter, MAT_DATE_FORMATS, MAT_DATE_LOCALE, MatNativeDateModule } from '@angular/material/core'; +import { MatDateSelectionModel, MatDatepickerModule } from '@angular/material/datepicker'; import { MatDividerModule } from '@angular/material/divider'; import { MatFormFieldModule } from '@angular/material/form-field'; import { MatIconModule } from '@angular/material/icon'; @@ -52,18 +52,8 @@ import { ShortDatePipe } from './short-date.pipe'; import { LocalizedDatePipe } from './localized-date.pipe'; @NgModule({ - declarations: [ - ShortDatePipe, - LocalizedDatePipe, - DateComponent, - CalendarComponent, - TimePickerComponent - ], - exports: [ - DateComponent, - ShortDatePipe, - LocalizedDatePipe - ], + declarations: [ShortDatePipe, LocalizedDatePipe, DateComponent, CalendarComponent, TimePickerComponent], + exports: [DateComponent, ShortDatePipe, LocalizedDatePipe], imports: [ A11yModule, CommonModule, @@ -79,11 +69,13 @@ import { LocalizedDatePipe } from './localized-date.pipe'; MatProgressSpinnerModule, OverlayModule, ReactiveFormsModule, - TranslateModule + TranslateModule, + MatNativeDateModule, + MatDatepickerModule, ], providers: [ { provide: DateAdapter, useClass: MomentDateAdapter, deps: [MAT_DATE_LOCALE] }, { provide: MAT_DATE_FORMATS, useValue: MAT_MOMENT_DATE_FORMATS }, - ] + ], }) -export class DateModule { } +export class DateModule {} diff --git a/imxweb/projects/qbm/src/lib/date/date/calendar/calendar.component.html b/imxweb/projects/qbm/src/lib/date/date/calendar/calendar.component.html index e1e770cc2..01ad71d99 100644 --- a/imxweb/projects/qbm/src/lib/date/date/calendar/calendar.component.html +++ b/imxweb/projects/qbm/src/lib/date/date/calendar/calendar.component.html @@ -1,9 +1,11 @@ -
    - + + [startAt]="datePickerDate" + > @@ -29,9 +41,14 @@ (overlayOutsideClick)="isDatePickerOpen = false" > + [control]="shadowDate" + [min]="min" + [max]="max" + (close)="isDatePickerOpen = false" + cdkTrapFocus + [cdkTrapFocus]="true" + [cdkTrapFocusAutoCapture]="true" + > @@ -44,12 +61,15 @@ [cdkConnectedOverlayBackdropClass]="'mat-overlay-transparent-backdrop'" (overlayOutsideClick)="handleTimePickerOutsideClick($event)" > - - + + -
    {{ validationErrorKey | translate }} diff --git a/imxweb/projects/qbm/src/lib/date/date/date.component.scss b/imxweb/projects/qbm/src/lib/date/date/date.component.scss index db249c530..4b374974e 100644 --- a/imxweb/projects/qbm/src/lib/date/date/date.component.scss +++ b/imxweb/projects/qbm/src/lib/date/date/date.component.scss @@ -2,22 +2,3 @@ display: flex; align-items: center; } - -mat-form-field { - flex-grow: 1; - - [matsuffix] { - - margin-left: 10px; // set margin to infix - - eui-icon { - margin-top: unset; // correct margin-top: -16px from _material_fixes.scss - display: block; - } - - mat-spinner { - display: inline-flex; - margin-right: 10px; - } - } -} diff --git a/imxweb/projects/qbm/src/lib/date/date/date.component.ts b/imxweb/projects/qbm/src/lib/date/date/date.component.ts index 415b8769f..84f6122b3 100644 --- a/imxweb/projects/qbm/src/lib/date/date/date.component.ts +++ b/imxweb/projects/qbm/src/lib/date/date/date.component.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -24,11 +24,10 @@ * */ -import { Component, Input, OnInit, OnDestroy } from '@angular/core'; +import { Component, Input, OnDestroy, OnInit } from '@angular/core'; import { AbstractControl, UntypedFormControl, ValidationErrors, ValidatorFn, Validators } from '@angular/forms'; -import moment from 'moment-timezone'; -import { Moment } from 'moment-timezone'; +import moment, { Moment } from 'moment-timezone'; import { Subscription } from 'rxjs'; import { ClassloggerService } from '../../classlogger/classlogger.service'; import { DateParser } from './date-parser'; @@ -44,7 +43,7 @@ import { DateParser } from './date-parser'; @Component({ selector: 'imx-date', templateUrl: './date.component.html', - styleUrls: ['./date.component.scss'] + styleUrls: ['./date.component.scss'], }) export class DateComponent implements OnInit, OnDestroy { // ###################################################################################################### @@ -114,6 +113,8 @@ export class DateComponent implements OnInit, OnDestroy { */ @Input() public withTime = true; + @Input() validateOnlyOnChange: boolean = false; + /** * @ignore only public because of databinding in template * @@ -154,7 +155,9 @@ export class DateComponent implements OnInit, OnDestroy { * the result of the internal shadow form control. * Useful to avoid unecessay update loop when writing back the value to the input control. */ - private result: Moment; + private result: Moment | undefined; + + private isUpdated: boolean = false; /** * @ignore @@ -168,15 +171,14 @@ export class DateComponent implements OnInit, OnDestroy { * * The text <-> moment date and time parser. */ - private parser !: DateParser; + private parser!: DateParser; /** * Creates a new date editor component. * * @param logger The logger service to be injected. */ - constructor(private logger: ClassloggerService) { - } + constructor(private logger: ClassloggerService) {} /** * @ignore only public because of databinding in template @@ -214,17 +216,25 @@ export class DateComponent implements OnInit, OnDestroy { this.setupValidators(); this.handleControlChanged(); - this.subscriptions.push(this.control.valueChanges.subscribe(x => this.handleControlChanged())); - this.subscriptions.push(this.shadowText.valueChanges.subscribe(x => this.handleShadowTextChanged())); - this.subscriptions.push(this.shadowTime.valueChanges.subscribe(x => this.handleShadowTimeChanged())); - this.subscriptions.push(this.shadowDate.valueChanges.subscribe(x => this.handleShadowDateChanged())); + this.subscriptions.push( + this.control.valueChanges.subscribe((x) => { + if (this.shadowText.untouched) { + this.shadowText.markAsTouched({ emitEvent: false }); + } + this.isUpdated = true; + this.handleControlChanged(); + }), + ); + this.subscriptions.push(this.shadowText.valueChanges.subscribe((x) => this.handleShadowTextChanged())); + this.subscriptions.push(this.shadowTime.valueChanges.subscribe((x) => this.handleShadowTimeChanged())); + this.subscriptions.push(this.shadowDate.valueChanges.subscribe((x) => this.handleShadowDateChanged())); } /** * @ignore OnDestroy lifecycle hook */ public ngOnDestroy(): void { - this.subscriptions.forEach(s => s.unsubscribe()); + this.subscriptions.forEach((s) => s.unsubscribe()); } /** @@ -320,7 +330,7 @@ export class DateComponent implements OnInit, OnDestroy { if (this.shadowDate.value) { const d = moment(this.shadowDate.value); - value = moment({year: d.year(), month: d.month(), day: d.date()}); + value = moment({ year: d.year(), month: d.month(), day: d.date() }); } if (this.shadowTime.value) { @@ -344,8 +354,7 @@ export class DateComponent implements OnInit, OnDestroy { */ private handleControlChanged(): void { const updatedValue = this.control.value as Moment; - - if (updatedValue !== this.result) { + if (!updatedValue?.isSame(this.result)) { this.result = updatedValue; this.updateShadowText(this.getDateTextFromControl()); this.updateShadowDate(this.control.value); @@ -455,18 +464,22 @@ export class DateComponent implements OnInit, OnDestroy { * * validation method: validates the moment representation of a date (and time) */ - private validateMomentInDateRange(date: Moment): ValidationErrors | null { + private validateMomentInDateRange(date: Moment | undefined): ValidationErrors | null { + if (!this.isUpdated && this.validateOnlyOnChange) { + return null; + } if (date && !date.isValid()) { return { matDatepickerParse: true }; } - if (this.min && date < moment(this.min)) { + if (this.min && date && date < moment(this.min)) { return { matDatepickerMin: true }; } - if (this.max && date > moment(this.max)) { + if (this.max && date && date > moment(this.max)) { return { matDatepickerMax: true }; } - } + return null; + } } diff --git a/imxweb/projects/qbm/src/lib/date/date/time-picker/time-picker.component.html b/imxweb/projects/qbm/src/lib/date/date/time-picker/time-picker.component.html index 5212783c9..b07486fc2 100644 --- a/imxweb/projects/qbm/src/lib/date/date/time-picker/time-picker.component.html +++ b/imxweb/projects/qbm/src/lib/date/date/time-picker/time-picker.component.html @@ -1,6 +1,6 @@ - - - - - - +
    + + + + +
    diff --git a/imxweb/projects/qbm/src/lib/date/date/time-picker/time-picker.component.ts b/imxweb/projects/qbm/src/lib/date/date/time-picker/time-picker.component.ts index c740d96b6..92b6f1e27 100644 --- a/imxweb/projects/qbm/src/lib/date/date/time-picker/time-picker.component.ts +++ b/imxweb/projects/qbm/src/lib/date/date/time-picker/time-picker.component.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -24,8 +24,8 @@ * */ -import { Component, Input, EventEmitter, Output, HostListener } from '@angular/core'; -import { AbstractControl, FormControl } from '@angular/forms'; +import { Component, EventEmitter, HostListener, Input, Output } from '@angular/core'; +import { FormControl } from '@angular/forms'; import { Moment } from 'moment-timezone'; /** @@ -34,10 +34,9 @@ import { Moment } from 'moment-timezone'; @Component({ selector: 'imx-time-picker', templateUrl: './time-picker.component.html', - styleUrls: ['./time-picker.component.scss'] + styleUrls: ['./time-picker.component.scss'], }) export class TimePickerComponent { - /** * The input control for the time. * @@ -45,7 +44,7 @@ export class TimePickerComponent { */ // TODO: Check Upgrade - @Input() public control: AbstractControl; + @Input() public control: FormControl; /** * This event will be emitted when the user clicks on the close button. @@ -71,5 +70,4 @@ export class TimePickerComponent { event.stopPropagation(); this.close.emit(); } - } diff --git a/imxweb/projects/qbm/src/lib/date/localized-date.pipe.ts b/imxweb/projects/qbm/src/lib/date/localized-date.pipe.ts index bef4466dc..68e0a41a5 100644 --- a/imxweb/projects/qbm/src/lib/date/localized-date.pipe.ts +++ b/imxweb/projects/qbm/src/lib/date/localized-date.pipe.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -28,18 +28,15 @@ import { Pipe, PipeTransform, Injectable } from '@angular/core'; import { ImxTranslationProviderService } from '../translation/imx-translation-provider.service'; @Injectable({ - providedIn: 'root' + providedIn: 'root', }) @Pipe({ name: 'localizedDate', }) export class LocalizedDatePipe implements PipeTransform { - private readonly currentCulture: string; - constructor( - private readonly translationProviderService: ImxTranslationProviderService, - ) { + constructor(private readonly translationProviderService: ImxTranslationProviderService) { this.currentCulture = this.translationProviderService.CultureFormat; } @@ -54,6 +51,5 @@ export class LocalizedDatePipe implements PipeTransform { } } return new Date(value).toLocaleString(this.currentCulture); - } } diff --git a/imxweb/projects/qbm/src/lib/date/short-date.pipe.ts b/imxweb/projects/qbm/src/lib/date/short-date.pipe.ts index adbc9445a..8c6db0691 100644 --- a/imxweb/projects/qbm/src/lib/date/short-date.pipe.ts +++ b/imxweb/projects/qbm/src/lib/date/short-date.pipe.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -28,18 +28,15 @@ import { Pipe, PipeTransform, Injectable } from '@angular/core'; import { ImxTranslationProviderService } from '../translation/imx-translation-provider.service'; @Injectable({ - providedIn: 'root' + providedIn: 'root', }) @Pipe({ name: 'shortDate', }) export class ShortDatePipe implements PipeTransform { - private readonly currentCulture: string; - constructor( - private readonly translationProviderService: ImxTranslationProviderService, - ) { + constructor(private readonly translationProviderService: ImxTranslationProviderService) { this.currentCulture = this.translationProviderService.CultureFormat; } @@ -52,6 +49,5 @@ export class ShortDatePipe implements PipeTransform { return value; } return new Date(value).toLocaleDateString(this.currentCulture); - } } diff --git a/imxweb/projects/qbm/src/lib/disable-control/disable-control.directive.ts b/imxweb/projects/qbm/src/lib/disable-control/disable-control.directive.ts index 42bcfd8f9..404e536aa 100644 --- a/imxweb/projects/qbm/src/lib/disable-control/disable-control.directive.ts +++ b/imxweb/projects/qbm/src/lib/disable-control/disable-control.directive.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -28,20 +28,18 @@ import { Directive, Input, OnInit } from '@angular/core'; import { NgControl } from '@angular/forms'; @Directive({ - selector: '[imxDisableControl]' + selector: '[imxDisableControl]', }) export class DisableControlDirective implements OnInit { - @Input() set imxDisableControl(condition: boolean) { this.action = condition ? 'disable' : 'enable'; } private action: string; - constructor(private ngControl: NgControl) { - } + constructor(private ngControl: NgControl) {} public ngOnInit(): void { - this.ngControl.control[this.action](); + this.ngControl.control?.[this.action](); } } diff --git a/imxweb/projects/qbm/src/lib/disable-control/disable-control.module.ts b/imxweb/projects/qbm/src/lib/disable-control/disable-control.module.ts index 2b8f04208..983ba8b47 100644 --- a/imxweb/projects/qbm/src/lib/disable-control/disable-control.module.ts +++ b/imxweb/projects/qbm/src/lib/disable-control/disable-control.module.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -29,14 +29,8 @@ import { CommonModule } from '@angular/common'; import { DisableControlDirective } from './disable-control.directive'; @NgModule({ - declarations: [ - DisableControlDirective - ], - imports: [ - CommonModule - ], - exports: [ - DisableControlDirective - ] + declarations: [DisableControlDirective], + imports: [CommonModule], + exports: [DisableControlDirective], }) -export class DisableControlModule { } +export class DisableControlModule {} diff --git a/imxweb/projects/qbm/src/lib/doc/doc-chapter.service.ts b/imxweb/projects/qbm/src/lib/doc/doc-chapter.service.ts deleted file mode 100644 index d8db83443..000000000 --- a/imxweb/projects/qbm/src/lib/doc/doc-chapter.service.ts +++ /dev/null @@ -1,52 +0,0 @@ -/* - * ONE IDENTITY LLC. PROPRIETARY INFORMATION - * - * This software is confidential. One Identity, LLC. or one of its affiliates or - * subsidiaries, has supplied this software to you under terms of a - * license agreement, nondisclosure agreement or both. - * - * You may not copy, disclose, or use this software except in accordance with - * those terms. - * - * - * Copyright 2023 One Identity LLC. - * ALL RIGHTS RESERVED. - * - * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR - * WARRANTIES ABOUT THE SUITABILITY OF THE SOFTWARE, - * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED - * TO THE IMPLIED WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE, OR - * NON-INFRINGEMENT. ONE IDENTITY LLC. SHALL NOT BE - * LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE - * AS A RESULT OF USING, MODIFYING OR DISTRIBUTING - * THIS SOFTWARE OR ITS DERIVATIVES. - * - */ - -import { Injectable } from "@angular/core"; - -@Injectable({ - providedIn: 'root' -}) -export class DocChapterService { - - /** Maps the Angular routes to the corresponding documentation chapter. */ - public readonly chapters: { [route: string]: DocChapter } = {}; - -} - -export interface DocChapter { - - /** Returns the document containing this chapter. */ - readonly document: DocDocument; - - /** Returns the chapter UID. */ - readonly chapterUid: string; -} - -export interface DocDocument { - - /** Maps languages to the document paths. */ - readonly paths: { [language: string]: string }; -} diff --git a/imxweb/projects/qbm/src/lib/dynamic-tabs/dynamic-tab-data-provider.directive.ts b/imxweb/projects/qbm/src/lib/dynamic-tabs/dynamic-tab-data-provider.directive.ts index 89102b3b6..fa271ec3e 100644 --- a/imxweb/projects/qbm/src/lib/dynamic-tabs/dynamic-tab-data-provider.directive.ts +++ b/imxweb/projects/qbm/src/lib/dynamic-tabs/dynamic-tab-data-provider.directive.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -27,8 +27,8 @@ import { Directive, Input } from '@angular/core'; @Directive({ - selector: '[imxDataProvider]' + selector: '[imxDataProvider]', }) export class DynamicTabDataProviderDirective { - @Input('imxDataProvider')public data: any; + @Input('imxDataProvider') public data: any; } diff --git a/imxweb/projects/qbm/src/lib/dynamic-tabs/dynamic-tabs.model.ts b/imxweb/projects/qbm/src/lib/dynamic-tabs/dynamic-tabs.model.ts index 2764fa1a5..909b68e90 100644 --- a/imxweb/projects/qbm/src/lib/dynamic-tabs/dynamic-tabs.model.ts +++ b/imxweb/projects/qbm/src/lib/dynamic-tabs/dynamic-tabs.model.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR diff --git a/imxweb/projects/qbm/src/lib/dynamic-tabs/dynamic-tabs.module.ts b/imxweb/projects/qbm/src/lib/dynamic-tabs/dynamic-tabs.module.ts index 7930018df..a8443bbaa 100644 --- a/imxweb/projects/qbm/src/lib/dynamic-tabs/dynamic-tabs.module.ts +++ b/imxweb/projects/qbm/src/lib/dynamic-tabs/dynamic-tabs.module.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -29,17 +29,9 @@ import { CommonModule } from '@angular/common'; import { DynamicTabDataProviderDirective } from './dynamic-tab-data-provider.directive'; - - @NgModule({ - declarations: [ - DynamicTabDataProviderDirective - ], - imports: [ - CommonModule - ], - exports: [ - DynamicTabDataProviderDirective - ] + declarations: [DynamicTabDataProviderDirective], + imports: [CommonModule], + exports: [DynamicTabDataProviderDirective], }) -export class DynamicTabsModule { } +export class DynamicTabsModule {} diff --git a/imxweb/projects/qbm/src/lib/entity/entity-select/entity-select.component.html b/imxweb/projects/qbm/src/lib/entity/entity-select/entity-select.component.html index 20996769c..37d9a7c42 100644 --- a/imxweb/projects/qbm/src/lib/entity/entity-select/entity-select.component.html +++ b/imxweb/projects/qbm/src/lib/entity/entity-select/entity-select.component.html @@ -1,4 +1,9 @@ {{ title | translate }} - + diff --git a/imxweb/projects/qbm/src/lib/entity/entity-select/entity-select.component.ts b/imxweb/projects/qbm/src/lib/entity/entity-select/entity-select.component.ts index 41a839eba..67cf55eb7 100644 --- a/imxweb/projects/qbm/src/lib/entity/entity-select/entity-select.component.ts +++ b/imxweb/projects/qbm/src/lib/entity/entity-select/entity-select.component.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -28,21 +28,21 @@ import { AfterContentInit, Component, EventEmitter, Input, OnChanges, Output, Si import { AbstractControl, UntypedFormControl, Validators } from '@angular/forms'; import { EuiSelectOption } from '@elemental-ui/core'; -import { IClientProperty, IEntity } from 'imx-qbm-dbts'; +import { IClientProperty, IEntity } from '@imx-modules/imx-qbm-dbts'; @Component({ selector: 'imx-entity-select', templateUrl: './entity-select.component.html', - styleUrls: ['./entity-select.component.scss'] + styleUrls: ['./entity-select.component.scss'], }) export class EntitySelectComponent implements OnChanges, AfterContentInit { public readonly control = new UntypedFormControl(undefined, Validators.required); - public options: EuiSelectOption[]; + public options: EuiSelectOption[] | undefined; @Input() public title: string; @Input() public placeholder: string; - @Input() public display: { primary?: IClientProperty, secondary?: IClientProperty }; + @Input() public display: { primary?: IClientProperty; secondary?: IClientProperty }; @Input() public entities: IEntity[]; @Output() public controlCreated = new EventEmitter(); @@ -56,12 +56,12 @@ export class EntitySelectComponent implements OnChanges, AfterContentInit { public ngOnChanges(changes: SimpleChanges): void { if (changes['entities'] || changes['display']) { if (this.entities) { - this.options = this.entities.map(entity => ({ - display: this.display?.primary ? - (entity.GetColumn(this.display.primary.ColumnName).GetDisplayValue() || entity.GetDisplay()) : entity.GetDisplay(), - displayDetail: this.display?.secondary ? - entity.GetColumn(this.display.secondary.ColumnName).GetDisplayValue() : undefined, - value: entity + this.options = this.entities.map((entity) => ({ + display: this.display?.primary + ? entity.GetColumn(this.display.primary.ColumnName ?? '').GetDisplayValue() || entity.GetDisplay() + : entity.GetDisplay(), + displayDetail: this.display?.secondary ? entity.GetColumn(this.display.secondary.ColumnName ?? '').GetDisplayValue() : undefined, + value: entity, })); } else { this.options = undefined; @@ -74,13 +74,19 @@ export class EntitySelectComponent implements OnChanges, AfterContentInit { } public filter(option: EuiSelectOption, searchInputValue: string): boolean { - return option.display.toString().toUpperCase().trim().includes(searchInputValue.toUpperCase().trim()) - || (option.displayDetail && option.displayDetail.toString().toUpperCase().trim().includes(searchInputValue.toUpperCase().trim())); + return ( + (option.display.toString().toUpperCase().trim().includes(searchInputValue.toUpperCase().trim()) || + option.displayDetail?.toString().toUpperCase().trim().includes(searchInputValue.toUpperCase().trim())) ?? + false + ); } - - // TODO: Check Upgrade - // public onChange(event: any): void { - // this.selectionChange.emit(event.value); - // } + public selectionUpdated(arg: EuiSelectOption | EuiSelectOption[]) { + if (Object.hasOwn(arg, 'value')) { + // is a EuiSelectOption + this.selectionChange.emit((arg as EuiSelectOption).value); + } else { + this.selectionChange.emit(arg[0].value); + } + } } diff --git a/imxweb/projects/qbm/src/lib/entity/entity-select/entity-select.interface.ts b/imxweb/projects/qbm/src/lib/entity/entity-select/entity-select.interface.ts index 7292bb062..0f0f69ca3 100644 --- a/imxweb/projects/qbm/src/lib/entity/entity-select/entity-select.interface.ts +++ b/imxweb/projects/qbm/src/lib/entity/entity-select/entity-select.interface.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -24,12 +24,12 @@ * */ -import { IClientProperty, IEntity } from 'imx-qbm-dbts'; +import { IClientProperty, IEntity } from '@imx-modules/imx-qbm-dbts'; export interface EntitySelect { entities: IEntity[]; placeholder: string; selectionChange: (entity: IEntity) => void; - display?: { primary?: IClientProperty, secondary?: IClientProperty }; + display?: { primary?: IClientProperty; secondary?: IClientProperty }; title?: string; } diff --git a/imxweb/projects/qbm/src/lib/entity/entity.module.ts b/imxweb/projects/qbm/src/lib/entity/entity.module.ts index d67af3497..95966b403 100644 --- a/imxweb/projects/qbm/src/lib/entity/entity.module.ts +++ b/imxweb/projects/qbm/src/lib/entity/entity.module.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -24,21 +24,22 @@ * */ -import { NgModule } from '@angular/core'; import { CommonModule } from '@angular/common'; +import { NgModule } from '@angular/core'; import { FormsModule, ReactiveFormsModule } from '@angular/forms'; import { EuiCoreModule, EuiMaterialModule } from '@elemental-ui/core'; import { TranslateModule } from '@ngx-translate/core'; -import { EntityService } from './entity.service'; -import { EntitySelectComponent } from './entity-select/entity-select.component'; -import { TypedEntitySelectComponent } from './typed-entity-select/typed-entity-select.component'; -import { TypedEntitySelectorComponent } from './typed-entity-select/typed-entity-selector/typed-entity-selector.component'; +import { DataSourceToolbarModule } from '../data-source-toolbar/data-source-toolbar.module'; +import { DataTableModule } from '../data-table/data-table.module'; import { FkAdvancedPickerModule } from '../fk-advanced-picker/fk-advanced-picker.module'; +import { EntitySelectComponent } from './entity-select/entity-select.component'; +import { EntityService } from './entity.service'; import { FkTableSelectComponent } from './fk-table-select/fk-table-select.component'; -import { DataTableModule } from '../data-table/data-table.module'; import { TypedEntityCandidateSidesheetComponent } from './typed-entity-candidate-sidesheet/typed-entity-candidate-sidesheet.component'; -import { DataSourceToolbarModule } from '../data-source-toolbar/data-source-toolbar.module'; +import { TypedEntitySelectComponent } from './typed-entity-select/typed-entity-select.component'; +import { TypedEntitySelectorComponent } from './typed-entity-select/typed-entity-selector/typed-entity-selector.component'; +import { SelectedElementsModule } from '../selected-elements/selected-elements.module'; @NgModule({ declarations: [ @@ -46,12 +47,9 @@ import { DataSourceToolbarModule } from '../data-source-toolbar/data-source-tool TypedEntitySelectComponent, TypedEntitySelectorComponent, FkTableSelectComponent, - TypedEntityCandidateSidesheetComponent - ], - exports: [ - EntitySelectComponent, - TypedEntitySelectComponent + TypedEntityCandidateSidesheetComponent, ], + exports: [EntitySelectComponent, TypedEntitySelectComponent], imports: [ CommonModule, EuiCoreModule, @@ -61,11 +59,9 @@ import { DataSourceToolbarModule } from '../data-source-toolbar/data-source-tool ReactiveFormsModule, TranslateModule, DataTableModule, - DataSourceToolbarModule - + DataSourceToolbarModule, + SelectedElementsModule ], - providers: [ - EntityService - ] + providers: [EntityService], }) -export class EntityModule { } +export class EntityModule {} diff --git a/imxweb/projects/qbm/src/lib/entity/entity.service.ts b/imxweb/projects/qbm/src/lib/entity/entity.service.ts index 521aad6c1..f895daa64 100644 --- a/imxweb/projects/qbm/src/lib/entity/entity.service.ts +++ b/imxweb/projects/qbm/src/lib/entity/entity.service.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -26,23 +26,29 @@ import { Injectable } from '@angular/core'; -import { EntityColumnData, IClientProperty, FkCandidateProvider, FkProviderItem, IEntityColumn, LocalEntityColumn } from 'imx-qbm-dbts'; +import { + EntityColumnData, + IClientProperty, + FkCandidateProvider, + FkProviderItem, + IEntityColumn, + LocalEntityColumn, +} from '@imx-modules/imx-qbm-dbts'; import { ImxTranslationProviderService } from '../translation/imx-translation-provider.service'; @Injectable({ - providedIn: 'root' + providedIn: 'root', }) export class EntityService { - constructor(private readonly translator: ImxTranslationProviderService) { } + constructor(private readonly translator: ImxTranslationProviderService) {} public createLocalEntityColumn( property: IClientProperty, fkProviderItems?: FkProviderItem[], data: EntityColumnData = {}, - putValueDelegate: (oldValue: any, newValue: any) => Promise = () => Promise.resolve() + putValueDelegate: (oldValue: any, newValue: any) => Promise = () => Promise.resolve(), ): IEntityColumn { - var fkProvider = fkProviderItems ? new FkCandidateProvider(fkProviderItems) : undefined; - return new LocalEntityColumn(property, this.translator, fkProvider, data, ((z, x, y) => putValueDelegate(x, y))); + return new LocalEntityColumn(property, this.translator, fkProvider, data, (z, x, y) => putValueDelegate(x, y)); } } diff --git a/imxweb/projects/qbm/src/lib/entity/fk-table-select/fk-table-select.component.html b/imxweb/projects/qbm/src/lib/entity/fk-table-select/fk-table-select.component.html index aa7e3bb6a..df92c504a 100644 --- a/imxweb/projects/qbm/src/lib/entity/fk-table-select/fk-table-select.component.html +++ b/imxweb/projects/qbm/src/lib/entity/fk-table-select/fk-table-select.component.html @@ -1,7 +1,13 @@ - + [filterFunction]="filter" + [options]="options" + [inputControl]="control" + [hideClearButton]="true" + data-imx-identifier="fk-table-select" +> diff --git a/imxweb/projects/qbm/src/lib/entity/fk-table-select/fk-table-select.component.scss b/imxweb/projects/qbm/src/lib/entity/fk-table-select/fk-table-select.component.scss index e110d11b2..248a268c5 100644 --- a/imxweb/projects/qbm/src/lib/entity/fk-table-select/fk-table-select.component.scss +++ b/imxweb/projects/qbm/src/lib/entity/fk-table-select/fk-table-select.component.scss @@ -1 +1 @@ -// add styles if necessary \ No newline at end of file +// add styles if necessary diff --git a/imxweb/projects/qbm/src/lib/entity/fk-table-select/fk-table-select.component.ts b/imxweb/projects/qbm/src/lib/entity/fk-table-select/fk-table-select.component.ts index cdf06af27..9d300eaa4 100644 --- a/imxweb/projects/qbm/src/lib/entity/fk-table-select/fk-table-select.component.ts +++ b/imxweb/projects/qbm/src/lib/entity/fk-table-select/fk-table-select.component.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -28,7 +28,7 @@ import { Component, EventEmitter, Input, OnInit, Output } from '@angular/core'; import { UntypedFormControl } from '@angular/forms'; import { EuiSelectOption } from '@elemental-ui/core'; -import { IForeignKeyInfo } from 'imx-qbm-dbts'; +import { IForeignKeyInfo } from '@imx-modules/imx-qbm-dbts'; import { MetadataService } from '../../base/metadata.service'; @Component({ @@ -66,8 +66,12 @@ export class FkTableSelectComponent implements OnInit { return option.display.toString().toUpperCase().trim().includes(searchInputValue.toUpperCase().trim()); } - // TODO: Check Upgrade - // public onChange(event: any): void { - // this.selectionChanged.emit(event.value); - // } + public selectionUpdated(event: EuiSelectOption | EuiSelectOption[]) { + if (Object.hasOwn(event, 'value')) { + // is a EuiSelectOption + this.selectionChanged.emit((event as EuiSelectOption).value); + } else { + this.selectionChanged.emit(event[0].option); + } + } } diff --git a/imxweb/projects/qbm/src/lib/entity/typed-entity-candidate-sidesheet/typed-entity-candidate-sidesheet-parameter.interface.ts b/imxweb/projects/qbm/src/lib/entity/typed-entity-candidate-sidesheet/typed-entity-candidate-sidesheet-parameter.interface.ts index 67aca146d..81c8427de 100644 --- a/imxweb/projects/qbm/src/lib/entity/typed-entity-candidate-sidesheet/typed-entity-candidate-sidesheet-parameter.interface.ts +++ b/imxweb/projects/qbm/src/lib/entity/typed-entity-candidate-sidesheet/typed-entity-candidate-sidesheet-parameter.interface.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -24,9 +24,9 @@ * */ -import { TypedEntity } from 'imx-qbm-dbts'; +import { TypedEntity } from '@imx-modules/imx-qbm-dbts'; export interface TypedEntityCandidateSidesheetParameter { - entities: TypedEntity []; + entities: TypedEntity[]; tables?: string[]; } diff --git a/imxweb/projects/qbm/src/lib/entity/typed-entity-candidate-sidesheet/typed-entity-candidate-sidesheet.component.html b/imxweb/projects/qbm/src/lib/entity/typed-entity-candidate-sidesheet/typed-entity-candidate-sidesheet.component.html index 737a41894..e66c77e7b 100644 --- a/imxweb/projects/qbm/src/lib/entity/typed-entity-candidate-sidesheet/typed-entity-candidate-sidesheet.component.html +++ b/imxweb/projects/qbm/src/lib/entity/typed-entity-candidate-sidesheet/typed-entity-candidate-sidesheet.component.html @@ -1,21 +1,30 @@ -
    - - +
    + +
    - - + +
    {{ item.GetEntity().GetDisplay() }}
    -
    {{ getTable(item) }}
    +
    {{ getTable(item) }}
    - - +
    diff --git a/imxweb/projects/qbm/src/lib/entity/typed-entity-candidate-sidesheet/typed-entity-candidate-sidesheet.component.scss b/imxweb/projects/qbm/src/lib/entity/typed-entity-candidate-sidesheet/typed-entity-candidate-sidesheet.component.scss index 5ae595d5d..6cebff944 100644 --- a/imxweb/projects/qbm/src/lib/entity/typed-entity-candidate-sidesheet/typed-entity-candidate-sidesheet.component.scss +++ b/imxweb/projects/qbm/src/lib/entity/typed-entity-candidate-sidesheet/typed-entity-candidate-sidesheet.component.scss @@ -1,4 +1,4 @@ -@import "@elemental-ui/core/src/styles/_palette.scss"; +@import '@elemental-ui/core/src/styles/_palette.scss'; :host { display: flex; @@ -7,27 +7,3 @@ height: 100%; } -.eui-sidesheet-content{ - display: flex; - flex-direction: column; - overflow: hidden; - height:100% -} - -.imx-sidesheet-content { - overflow: hidden; - display: flex; - flex-direction: column; - height:100% -} - - -.imx-table-container { - display: flex; - flex-direction: column; - overflow: hidden; - height: inherit; - max-width: 100%; - flex-direction: 1 1 auto; -} - diff --git a/imxweb/projects/qbm/src/lib/entity/typed-entity-candidate-sidesheet/typed-entity-candidate-sidesheet.component.ts b/imxweb/projects/qbm/src/lib/entity/typed-entity-candidate-sidesheet/typed-entity-candidate-sidesheet.component.ts index 7eba9ec06..6eb2d74c4 100644 --- a/imxweb/projects/qbm/src/lib/entity/typed-entity-candidate-sidesheet/typed-entity-candidate-sidesheet.component.ts +++ b/imxweb/projects/qbm/src/lib/entity/typed-entity-candidate-sidesheet/typed-entity-candidate-sidesheet.component.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -26,8 +26,8 @@ import { Component, Inject, OnInit } from '@angular/core'; import { EUI_SIDESHEET_DATA } from '@elemental-ui/core'; +import { DataModelFilterOption, DbObjectKey, DisplayColumns, EntitySchema, IClientProperty, TypedEntity } from '@imx-modules/imx-qbm-dbts'; import { TranslateService } from '@ngx-translate/core'; -import { DataModelFilterOption, DbObjectKey, DisplayColumns, EntitySchema, IClientProperty, TypedEntity } from 'imx-qbm-dbts'; import { MetadataService } from '../../base/metadata.service'; import { CdrFactoryService } from '../../cdr/cdr-factory.service'; import { DataSourceToolbarFilter } from '../../data-source-toolbar/data-source-toolbar-filters.interface'; @@ -95,12 +95,15 @@ export class TypedEntityCandidateSidesheetComponent implements OnInit { public navigate(source: TypedEntityTableFilter): void { this.navigationState = { ...this.navigationState, ...source }; const possible = source.table - ? this.searchedEntities.filter( - (elem) => CdrFactoryService.tryGetColumn(elem.GetEntity(), 'XObjectKey')?.GetValue()?.includes(source.table), + ? this.searchedEntities.filter((elem) => + CdrFactoryService.tryGetColumn(elem.GetEntity(), 'XObjectKey')?.GetValue()?.includes(source.table), ) : this.searchedEntities; - const data = possible.slice(this.navigationState.StartIndex, this.navigationState.StartIndex + this.navigationState.PageSize); + const data = possible.slice( + this.navigationState.StartIndex, + (this.navigationState.StartIndex ?? 0) + (this.navigationState.PageSize ?? 0), + ); this.dstSettings = { displayedColumns: this.displayedColumns, dataSource: { @@ -122,16 +125,18 @@ export class TypedEntityCandidateSidesheetComponent implements OnInit { return ''; } const tableName = DbObjectKey.FromXml(column.GetValue()).TableName; - return this.metaData.tables[tableName]?.DisplaySingular; + return this.metaData.tables[tableName]?.DisplaySingular ?? ''; } private getOptionsForFilter(): DataModelFilterOption[] { - return this.data.tables - .map((elem) => ({ Value: elem, Display: this.metaData.tables[elem]?.DisplaySingular })) - .filter((elem) => - this.data.entities.some( - (entity) => CdrFactoryService.tryGetColumn(entity.GetEntity(), 'XObjectKey')?.GetValue().includes(elem.Value), - ), - ); + return ( + this.data.tables + ?.map((elem) => ({ Value: elem, Display: this.metaData.tables[elem]?.DisplaySingular ?? '' })) + .filter((elem) => + this.data.entities.some((entity) => + CdrFactoryService.tryGetColumn(entity.GetEntity(), 'XObjectKey')?.GetValue().includes(elem.Value), + ), + ) ?? [] + ); } } diff --git a/imxweb/projects/qbm/src/lib/entity/typed-entity-candidate-sidesheet/typed-entity-table-filter.interface.ts b/imxweb/projects/qbm/src/lib/entity/typed-entity-candidate-sidesheet/typed-entity-table-filter.interface.ts index 7eeb702c0..6a3da4932 100644 --- a/imxweb/projects/qbm/src/lib/entity/typed-entity-candidate-sidesheet/typed-entity-table-filter.interface.ts +++ b/imxweb/projects/qbm/src/lib/entity/typed-entity-candidate-sidesheet/typed-entity-table-filter.interface.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -24,7 +24,7 @@ * */ -import { CollectionLoadParameters } from 'imx-qbm-dbts'; +import { CollectionLoadParameters } from '@imx-modules/imx-qbm-dbts'; export interface TypedEntityTableFilter extends CollectionLoadParameters { table?: string; diff --git a/imxweb/projects/qbm/src/lib/entity/typed-entity-select/typed-entity-fk-data.interface.ts b/imxweb/projects/qbm/src/lib/entity/typed-entity-select/typed-entity-fk-data.interface.ts index c0711987e..b4c22da07 100644 --- a/imxweb/projects/qbm/src/lib/entity/typed-entity-select/typed-entity-fk-data.interface.ts +++ b/imxweb/projects/qbm/src/lib/entity/typed-entity-select/typed-entity-fk-data.interface.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -24,12 +24,24 @@ * */ -import { CollectionLoadParameters, IForeignKeyInfo, TypedEntity, TypedEntityCollectionData } from 'imx-qbm-dbts'; +import { + ApiRequestOptions, + CollectionLoadParameters, + DataModel, + EntityCollectionData, + FilterTreeData, + IForeignKeyInfo, + TypedEntity, + TypedEntityCollectionData, +} from '@imx-modules/imx-qbm-dbts'; export interface TypedEntityFkData { - getTyped?: (parameters: CollectionLoadParameters) => Promise>; + getTyped?: (parameters: CollectionLoadParameters, opts?: ApiRequestOptions) => Promise>; isMultiValue: boolean; preselectedEntities?: TypedEntity[]; fkTables: ReadonlyArray; preselectedTableName: string; + GetFilterTree?: (parentKey: string, opts?: ApiRequestOptions) => Promise; + GetDataModel?: (opts?: ApiRequestOptions) => Promise; + Get?: (parameters: CollectionLoadParameters, opts?: ApiRequestOptions) => Promise; } diff --git a/imxweb/projects/qbm/src/lib/entity/typed-entity-select/typed-entity-select.component.html b/imxweb/projects/qbm/src/lib/entity/typed-entity-select/typed-entity-select.component.html index e98cbab22..c4e71cc23 100644 --- a/imxweb/projects/qbm/src/lib/entity/typed-entity-select/typed-entity-select.component.html +++ b/imxweb/projects/qbm/src/lib/entity/typed-entity-select/typed-entity-select.component.html @@ -1,13 +1,24 @@ - - {{ data?.valueWrapper?.display | translate }} - + {{ data?.valueWrapper?.display ?? '' | translate }} + + [required]="data?.valueWrapper?.isValueRequired" + />
    -
    diff --git a/imxweb/projects/qbm/src/lib/entity/typed-entity-select/typed-entity-select.component.scss b/imxweb/projects/qbm/src/lib/entity/typed-entity-select/typed-entity-select.component.scss index 61b9e0d07..69253c8fc 100644 --- a/imxweb/projects/qbm/src/lib/entity/typed-entity-select/typed-entity-select.component.scss +++ b/imxweb/projects/qbm/src/lib/entity/typed-entity-select/typed-entity-select.component.scss @@ -1,40 +1 @@ -:host { - display: flex; - flex-direction: column; - align-items: baseline; - - >* { - margin-right: 10px; - } -} - -input { - flex: 1; -} - -.mat-form-field { - width: 100%; -} - -.imx-spacer { - height: 30px; -} - -.mat-button { - min-width: initial; -} - -.mat-error { - margin-top: 5px; - font-size: small; -} - -.imx-suffix-container { - display: flex; - margin-bottom: 5px; - - > *:not(:last-child) { - margin-right: 5px; - margin-top: 0; - } -} +@import 'common/select'; diff --git a/imxweb/projects/qbm/src/lib/entity/typed-entity-select/typed-entity-select.component.ts b/imxweb/projects/qbm/src/lib/entity/typed-entity-select/typed-entity-select.component.ts index 9a341008f..5b56bb9d1 100644 --- a/imxweb/projects/qbm/src/lib/entity/typed-entity-select/typed-entity-select.component.ts +++ b/imxweb/projects/qbm/src/lib/entity/typed-entity-select/typed-entity-select.component.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -29,7 +29,8 @@ import { UntypedFormControl } from '@angular/forms'; import { EuiSidesheetService } from '@elemental-ui/core'; import { TranslateService } from '@ngx-translate/core'; -import { TypedEntity } from 'imx-qbm-dbts'; +import { TypedEntity } from '@imx-modules/imx-qbm-dbts'; +import { calculateSidesheetWidth } from '../../base/sidesheet-helper'; import { LdsReplacePipe } from '../../lds-replace/lds-replace.pipe'; import { TypedEntitySelectionData } from './typed-entity-selection-data.interface'; import { TypedEntitySelectorComponent } from './typed-entity-selector/typed-entity-selector.component'; @@ -37,7 +38,7 @@ import { TypedEntitySelectorComponent } from './typed-entity-selector/typed-enti @Component({ selector: 'imx-typed-entity-select', templateUrl: './typed-entity-select.component.html', - styleUrls: ['./typed-entity-select.component.scss'] + styleUrls: ['./typed-entity-select.component.scss'], }) export class TypedEntitySelectComponent implements OnInit { @Input() public data: TypedEntitySelectionData; @@ -54,8 +55,8 @@ export class TypedEntitySelectComponent implements OnInit { constructor( private readonly translate: TranslateService, private readonly ldsReplace: LdsReplacePipe, - private readonly sidesheet: EuiSidesheetService - ) { } + private readonly sidesheet: EuiSidesheetService, + ) {} public async ngOnInit(): Promise { if (this.data) { @@ -69,28 +70,29 @@ export class TypedEntitySelectComponent implements OnInit { } public async editAssignment(): Promise { - if (this.selected == null) { // beim erste Mal aus der Datenbank holen + if (this.selected == null) { + // beim erste Mal aus der Datenbank holen this.loading = true; this.selected = await this.data.getSelected(); this.loading = false; } - const selection = await this.sidesheet.open( - TypedEntitySelectorComponent, - { + const selection = await this.sidesheet + .open(TypedEntitySelectorComponent, { title: await this.translate.get(this.data.title || this.data.valueWrapper.display).toPromise(), padding: '0', - width: 'max(600px, 60%)', + width: calculateSidesheetWidth(), testId: `typed-entity-selector-${this.data.valueWrapper.name}`, data: { getTyped: this.data.dynamicFkRelation ? undefined : this.data.getTyped, isMultiValue: true, preselectedEntities: this.selected, fkTables: this.data.dynamicFkRelation?.tables, - preselectedTableName: this.data.dynamicFkRelation?.getSelectedTableName(this.selected) - } - } - ).afterClosed().toPromise(); + preselectedTableName: this.data.dynamicFkRelation?.getSelectedTableName(this.selected), + }, + }) + .afterClosed() + .toPromise(); if (selection) { if (!this.data.valueWrapper.canEdit) { @@ -109,17 +111,15 @@ export class TypedEntitySelectComponent implements OnInit { private async update(emitEvent: boolean): Promise { if (this.selected?.length > 0) { - const entities = this.selected.map(item => item.GetEntity()); + const entities = this.selected.map((item) => item.GetEntity()); this.control.setValue( - entities.length === 1 ? entities[0].GetDisplay() : - this.ldsReplace.transform(await this.translate.get('#LDS#{0} items selected').toPromise(), entities.length), - { emitEvent } + entities.length === 1 + ? entities[0].GetDisplay() + : this.ldsReplace.transform(await this.translate.get('#LDS#{0} items selected').toPromise(), entities.length), + { emitEvent }, ); } else { - this.control.setValue( - undefined, - { emitEvent } - ); + this.control.setValue(undefined, { emitEvent }); } } } diff --git a/imxweb/projects/qbm/src/lib/entity/typed-entity-select/typed-entity-selection-data.interface.ts b/imxweb/projects/qbm/src/lib/entity/typed-entity-select/typed-entity-selection-data.interface.ts index 66abb0fdc..f7635c3db 100644 --- a/imxweb/projects/qbm/src/lib/entity/typed-entity-select/typed-entity-selection-data.interface.ts +++ b/imxweb/projects/qbm/src/lib/entity/typed-entity-select/typed-entity-selection-data.interface.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -24,17 +24,17 @@ * */ -import { CollectionLoadParameters, IForeignKeyInfo, TypedEntity, TypedEntityCollectionData } from 'imx-qbm-dbts'; +import { CollectionLoadParameters, IForeignKeyInfo, TypedEntity, TypedEntityCollectionData } from '@imx-modules/imx-qbm-dbts'; import { ValueWrapper } from '../../value-wrapper/value-wrapper'; -export interface TypedEntitySelectionData { +export interface TypedEntitySelectionData { valueWrapper: ValueWrapper; title?: string; getInitialDisplay: () => Promise; - getSelected: () => Promise; - getTyped?: (parameters: CollectionLoadParameters) => Promise>; + getSelected: () => Promise; + getTyped?: (parameters: CollectionLoadParameters) => Promise | undefined>; dynamicFkRelation?: { tables: ReadonlyArray; - getSelectedTableName: (selected: TypedEntity[]) => string; + getSelectedTableName: (selected: T[]) => string; }; } diff --git a/imxweb/projects/qbm/src/lib/entity/typed-entity-select/typed-entity-selector/typed-entity-selector.component.html b/imxweb/projects/qbm/src/lib/entity/typed-entity-select/typed-entity-selector/typed-entity-selector.component.html index b76524af9..2d2500c77 100644 --- a/imxweb/projects/qbm/src/lib/entity/typed-entity-select/typed-entity-selector/typed-entity-selector.component.html +++ b/imxweb/projects/qbm/src/lib/entity/typed-entity-select/typed-entity-selector/typed-entity-selector.component.html @@ -1,30 +1,44 @@
    - + (selectionChanged)="tableSelectionChanged($event)" + > - +
    -
    -
    - - - -
    +
    +
    - -
    diff --git a/imxweb/projects/qbm/src/lib/entity/typed-entity-select/typed-entity-selector/typed-entity-selector.component.scss b/imxweb/projects/qbm/src/lib/entity/typed-entity-select/typed-entity-selector/typed-entity-selector.component.scss index d896c0bac..62415c052 100644 --- a/imxweb/projects/qbm/src/lib/entity/typed-entity-select/typed-entity-selector/typed-entity-selector.component.scss +++ b/imxweb/projects/qbm/src/lib/entity/typed-entity-select/typed-entity-selector/typed-entity-selector.component.scss @@ -18,38 +18,7 @@ max-height: calc(100% - 60px); } -.imx-button-bar { - display: flex; - justify-content: space-between; - margin-bottom: 0; - padding: 16px 32px; - border-top: 1px solid rgba(0, 0, 0, 0.12); - background-color: $white; - - button { - margin-left: 10px; - } - - .justify-start { - margin-right: auto; - } - - .imx-selected-items { - margin: 0; - line-height: 36px; - } - - ::ng-deep .eui-badge .eui-badge-content { - font-size: 14px; - line-height: 14px; - } - - .imx-badge { - background-color: unset; - } -} - -.imx-fk-selector{ +.imx-fk-selector { overflow: hidden; display: flex; flex-direction: column; @@ -58,17 +27,11 @@ .eui-dark-theme { :host { background-color: $color-gray-80; - .imx-button-bar { - background-color: $color-gray-70; - } } } .eui-contrast-theme { :host { background-color: $color-gray-100; - .imx-button-bar { - background-color: $color-gray-90; - } } } diff --git a/imxweb/projects/qbm/src/lib/entity/typed-entity-select/typed-entity-selector/typed-entity-selector.component.ts b/imxweb/projects/qbm/src/lib/entity/typed-entity-select/typed-entity-selector/typed-entity-selector.component.ts index c54a4f21b..12fcdf26b 100644 --- a/imxweb/projects/qbm/src/lib/entity/typed-entity-select/typed-entity-selector/typed-entity-selector.component.ts +++ b/imxweb/projects/qbm/src/lib/entity/typed-entity-select/typed-entity-selector/typed-entity-selector.component.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -25,21 +25,20 @@ */ import { Component, Inject } from '@angular/core'; -import { EuiSidesheetRef, EuiSidesheetService, EUI_SIDESHEET_DATA } from '@elemental-ui/core'; +import { EUI_SIDESHEET_DATA, EuiSidesheetRef, EuiSidesheetService } from '@elemental-ui/core'; import { TranslateService } from '@ngx-translate/core'; -import { IForeignKeyInfo, TypedEntity } from 'imx-qbm-dbts'; -import { TypedEntityCandidateSidesheetComponent } from '../../typed-entity-candidate-sidesheet/typed-entity-candidate-sidesheet.component'; +import { IForeignKeyInfo, TypedEntity } from '@imx-modules/imx-qbm-dbts'; import { TypedEntityFkData } from '../typed-entity-fk-data.interface'; @Component({ selector: 'imx-typed-entity-selector', templateUrl: './typed-entity-selector.component.html', - styleUrls: ['./typed-entity-selector.component.scss'] + styleUrls: ['./typed-entity-selector.component.scss'], }) export class TypedEntitySelectorComponent { public selectedItems: TypedEntity[]; - public selectedFkTable: IForeignKeyInfo; + public selectedFkTable: IForeignKeyInfo | undefined; // TODO: Check Upgrade public readonly fkRelationData: TypedEntityFkData; @@ -48,11 +47,11 @@ export class TypedEntitySelectorComponent { @Inject(EUI_SIDESHEET_DATA) data: TypedEntityFkData, private sidesheet: EuiSidesheetService, private readonly translate: TranslateService, - private readonly sideSheetRef: EuiSidesheetRef + private readonly sideSheetRef: EuiSidesheetRef, ) { this.fkRelationData = data; - this.selectedItems = data.preselectedEntities?.slice(); + this.selectedItems = data.preselectedEntities?.slice() ?? []; if (data.fkTables?.length > 0) { this.selectedFkTable = this.getTable(data.preselectedTableName) ?? data.fkTables[0]; @@ -75,19 +74,7 @@ export class TypedEntitySelectorComponent { this.selectedFkTable = this.getTable(tableName); } - - public async showSelected(): Promise { - this.sidesheet.open(TypedEntityCandidateSidesheetComponent, { - title: await this.translate.get('#LDS#Heading Selected Items').toPromise(), - padding: '0', - width: 'max(550px, 55%)', - testId: 'typed-entity-selector-candidates-sidesheet', - data: { entities: this.selectedItems, tables: this.fkRelationData.fkTables?.map(elem => elem.TableName) } - } - ); - } - - private getTable(tableName: string): IForeignKeyInfo { - return this.fkRelationData.fkTables.find(item => item.TableName === tableName); + private getTable(tableName: string): IForeignKeyInfo | undefined { + return this.fkRelationData.fkTables.find((item) => item.TableName === tableName); } } diff --git a/imxweb/projects/qbm/src/lib/ext/ext.component.ts b/imxweb/projects/qbm/src/lib/ext/ext.component.ts index c5cf855ef..9a94716c8 100644 --- a/imxweb/projects/qbm/src/lib/ext/ext.component.ts +++ b/imxweb/projects/qbm/src/lib/ext/ext.component.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -24,10 +24,10 @@ * */ -import { ComponentFactoryResolver, Component, ViewChild, OnInit, Input } from '@angular/core'; +import { Component, ComponentFactoryResolver, Input, OnInit, ViewChild } from '@angular/core'; -import { ExtService } from './ext.service'; import { ExtDirective } from './ext.directive'; +import { ExtService } from './ext.service'; @Component({ selector: 'imx-ext', @@ -42,7 +42,10 @@ export class ExtComponent implements OnInit { @Input() public properties: { [property: string]: any }; - constructor(private componentFactoryResolver: ComponentFactoryResolver, private extService: ExtService) {} + constructor( + private componentFactoryResolver: ComponentFactoryResolver, + private extService: ExtService, + ) {} public ngOnInit(): void { this.loadComponent(); @@ -60,13 +63,15 @@ export class ExtComponent implements OnInit { viewContainerRef.clear(); extensions.forEach((element) => { - const c = viewContainerRef.createComponent(this.componentFactoryResolver.resolveComponentFactory(element.instance)); - c.instance.referrer = this.referrer; - c.instance.inputData = element.inputData; + if (element.instance) { + const c = viewContainerRef.createComponent(this.componentFactoryResolver.resolveComponentFactory(element.instance)); + c.instance.referrer = this.referrer; + c.instance.inputData = element.inputData; - if (this.properties) { - for (let key in this.properties) { - Reflect.set(c.instance, key, this.properties[key]); + if (this.properties) { + for (let key in this.properties) { + Reflect.set(c.instance, key, this.properties[key]); + } } } }); diff --git a/imxweb/projects/qbm/src/lib/ext/ext.directive.ts b/imxweb/projects/qbm/src/lib/ext/ext.directive.ts index c273ec2c8..ce9312bdd 100644 --- a/imxweb/projects/qbm/src/lib/ext/ext.directive.ts +++ b/imxweb/projects/qbm/src/lib/ext/ext.directive.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -27,7 +27,7 @@ import { Directive, ViewContainerRef } from '@angular/core'; @Directive({ - selector: '[imxExtd]' + selector: '[imxExtd]', }) export class ExtDirective { constructor(public viewContainerRef: ViewContainerRef) {} diff --git a/imxweb/projects/qbm/src/lib/ext/ext.module.ts b/imxweb/projects/qbm/src/lib/ext/ext.module.ts index be7691710..e8001aba7 100644 --- a/imxweb/projects/qbm/src/lib/ext/ext.module.ts +++ b/imxweb/projects/qbm/src/lib/ext/ext.module.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -33,6 +33,6 @@ import { ExtDirective } from './ext.directive'; @NgModule({ providers: [ExtService], declarations: [ExtComponent, ExtDirective], - exports: [ExtComponent, ExtDirective] + exports: [ExtComponent, ExtDirective], }) export class ExtModule {} diff --git a/imxweb/projects/qbm/src/lib/ext/ext.service.ts b/imxweb/projects/qbm/src/lib/ext/ext.service.ts index 8b55efa26..d279c22a8 100644 --- a/imxweb/projects/qbm/src/lib/ext/ext.service.ts +++ b/imxweb/projects/qbm/src/lib/ext/ext.service.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -30,10 +30,11 @@ import { IExtension } from './extension'; @Injectable() export class ExtService { + public get Registry(): { [id: string]: IExtension[] } { + return this.registry; + } - public get Registry(): { [id: string]: IExtension[]; } { return this.registry; } - - private registry: { [id: string]: IExtension[]; } = {}; + private registry: { [id: string]: IExtension[] } = {}; public register(key: string, obj: IExtension): void { if (!this.registry[key]) { @@ -45,22 +46,22 @@ export class ExtService { public async getFittingComponents(key: string, filter: (ext: T) => Promise): Promise { const ret: T[] = []; const ext = this.registry[key]; - if (!ext) { return []; } + if (!ext) { + return []; + } for (const part of ext) { const t = part as T; - if (t && await filter(t)) { + if (t && (await filter(t))) { ret.push(t); } } return ret; } - public async getFittingComponent(key: string): Promise { + public async getFittingComponent(key: string): Promise { if (this.registry[key]) { return this.registry[key][0] as T; } else { - return null; + return undefined; } } - } - diff --git a/imxweb/projects/qbm/src/lib/ext/extension.ts b/imxweb/projects/qbm/src/lib/ext/extension.ts index 307136d4b..11de2b354 100644 --- a/imxweb/projects/qbm/src/lib/ext/extension.ts +++ b/imxweb/projects/qbm/src/lib/ext/extension.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR diff --git a/imxweb/projects/qbm/src/lib/file-selector/file-selector.service.spec.ts b/imxweb/projects/qbm/src/lib/file-selector/file-selector.service.spec.ts index 2df300ead..a81dd60cb 100644 --- a/imxweb/projects/qbm/src/lib/file-selector/file-selector.service.spec.ts +++ b/imxweb/projects/qbm/src/lib/file-selector/file-selector.service.spec.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -34,9 +34,7 @@ describe('FileSelectorService', () => { beforeEach(() => { TestBed.configureTestingModule({ - imports: [ - LoggerTestingModule - ] + imports: [LoggerTestingModule], }); service = TestBed.inject(FileSelectorService); }); @@ -48,7 +46,7 @@ describe('FileSelectorService', () => { it('emitFiles publishes file format error if file types mismatch', () => { // Arrange let fileFormatErrorIsSet; - const fs = service.fileFormatError.subscribe(() => fileFormatErrorIsSet = true); + const fs = service.fileFormatError.subscribe(() => (fileFormatErrorIsSet = true)); const files = [new Blob([], { type: 'some file type' }) as File]; @@ -57,9 +55,9 @@ describe('FileSelectorService', () => { { length: files.length, item: (index) => files[index], - 0: files[0] + 0: files[0], }, - 'some other file type' + 'some other file type', ); // Assert diff --git a/imxweb/projects/qbm/src/lib/file-selector/file-selector.service.ts b/imxweb/projects/qbm/src/lib/file-selector/file-selector.service.ts index c74d7a181..3b6a93260 100644 --- a/imxweb/projects/qbm/src/lib/file-selector/file-selector.service.ts +++ b/imxweb/projects/qbm/src/lib/file-selector/file-selector.service.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -30,15 +30,15 @@ import { Subject } from 'rxjs'; import { ClassloggerService } from '../classlogger/classlogger.service'; @Injectable({ - providedIn: 'root' + providedIn: 'root', }) export class FileSelectorService { - public readonly fileFormatError = new Subject(); + public readonly fileFormatError = new Subject(); public readonly fileSelected = new Subject(); - constructor(private logger: ClassloggerService) { } + constructor(private logger: ClassloggerService) {} - public emitFiles(files: FileList, acceptedFileFormat: string): void { + public emitFiles(files: FileList | null, acceptedFileFormat: string): void { if (files == null || files.length === 0) { this.logger.debug(this, 'No file selected.'); return; diff --git a/imxweb/projects/qbm/src/lib/filter-tile/filter-tile.component.html b/imxweb/projects/qbm/src/lib/filter-tile/filter-tile.component.html index 14cba0230..6255cdcd3 100644 --- a/imxweb/projects/qbm/src/lib/filter-tile/filter-tile.component.html +++ b/imxweb/projects/qbm/src/lib/filter-tile/filter-tile.component.html @@ -6,7 +6,7 @@
    - {{caption}} + {{ caption }}
    diff --git a/imxweb/projects/qbm/src/lib/filter-tile/filter-tile.component.scss b/imxweb/projects/qbm/src/lib/filter-tile/filter-tile.component.scss index 46a5c9813..a82b95bb0 100644 --- a/imxweb/projects/qbm/src/lib/filter-tile/filter-tile.component.scss +++ b/imxweb/projects/qbm/src/lib/filter-tile/filter-tile.component.scss @@ -1,4 +1,4 @@ -@import "@elemental-ui/core/src/styles/_palette.scss"; +@import '@elemental-ui/core/src/styles/_palette.scss'; @import '@elemental-ui/core/src/styles/_eui_palette.scss'; .FilterIcon, @@ -72,26 +72,24 @@ .eui-dark-theme { :host { + .FilterContentClassChecked { + color: $color-gray-60; + } - .FilterContentClassChecked { - color: $color-gray-60; - } - - .FilterMatCard { - background-color: $color-gray-70; - } + .FilterMatCard { + background-color: $color-gray-70; + } } } .eui-contrast-theme { :host { + .FilterContentClassChecked { + color: $color-gray-80; + } - .FilterContentClassChecked { - color: $color-gray-80; - } - - .FilterMatCard { - background-color: $color-gray-90; - } + .FilterMatCard { + background-color: $color-gray-90; + } } } diff --git a/imxweb/projects/qbm/src/lib/filter-tile/filter-tile.component.ts b/imxweb/projects/qbm/src/lib/filter-tile/filter-tile.component.ts index 63d015dcc..fa75718cf 100644 --- a/imxweb/projects/qbm/src/lib/filter-tile/filter-tile.component.ts +++ b/imxweb/projects/qbm/src/lib/filter-tile/filter-tile.component.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -31,9 +31,7 @@ import { MatCheckboxDefaultOptions, MAT_CHECKBOX_DEFAULT_OPTIONS } from '@angula selector: 'imx-filter-tile', templateUrl: './filter-tile.component.html', styleUrls: ['./filter-tile.component.scss'], - providers: [ - {provide: MAT_CHECKBOX_DEFAULT_OPTIONS, useValue: { clickAction: 'noop' } as MatCheckboxDefaultOptions} - ] + providers: [{ provide: MAT_CHECKBOX_DEFAULT_OPTIONS, useValue: { clickAction: 'noop' } as MatCheckboxDefaultOptions }], }) export class FilterTileComponent { @Input() public caption: string; diff --git a/imxweb/projects/qbm/src/lib/fk-advanced-picker/candidate-entity.ts b/imxweb/projects/qbm/src/lib/fk-advanced-picker/candidate-entity.ts index 7a949bdbd..f920bfee2 100644 --- a/imxweb/projects/qbm/src/lib/fk-advanced-picker/candidate-entity.ts +++ b/imxweb/projects/qbm/src/lib/fk-advanced-picker/candidate-entity.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -24,19 +24,26 @@ * */ -import { TypedEntity, EntitySchema, DisplayColumns, ValType } from 'imx-qbm-dbts'; +import { DisplayColumns, EntitySchema, TypedEntity, ValType } from '@imx-modules/imx-qbm-dbts'; export class CandidateEntity extends TypedEntity { - public static GetEntitySchema(): EntitySchema { - const columns = { - XObjectKey: { - Type: ValType.String, - ColumnName: 'XObjectKey' - } - }; + public static GetEntitySchema(parentColumnName?: string, tablename?: string): EntitySchema { + const columns = { + XObjectKey: { + Type: ValType.String, + ColumnName: 'XObjectKey', + }, + }; - columns[DisplayColumns.DISPLAY_PROPERTYNAME] = DisplayColumns.DISPLAY_PROPERTY; - - return { Columns: columns }; + if (parentColumnName) { + columns[parentColumnName] = { + Type: ValType.String, + ColumnName: parentColumnName, + }; } + + columns[DisplayColumns.DISPLAY_PROPERTYNAME] = DisplayColumns.DISPLAY_PROPERTY; + + return { Columns: columns, TypeName: tablename }; + } } diff --git a/imxweb/projects/qbm/src/lib/fk-advanced-picker/candidate.interface.ts b/imxweb/projects/qbm/src/lib/fk-advanced-picker/candidate.interface.ts index a975fa89a..cd76010c7 100644 --- a/imxweb/projects/qbm/src/lib/fk-advanced-picker/candidate.interface.ts +++ b/imxweb/projects/qbm/src/lib/fk-advanced-picker/candidate.interface.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -24,8 +24,8 @@ * */ -import { ValueStruct } from 'imx-qbm-dbts'; +import { ValueStruct } from '@imx-modules/imx-qbm-dbts'; export interface Candidate extends ValueStruct { - displayLong?: string; + displayLong?: string; } diff --git a/imxweb/projects/qbm/src/lib/fk-advanced-picker/fk-advanced-picker.component.html b/imxweb/projects/qbm/src/lib/fk-advanced-picker/fk-advanced-picker.component.html index a3fbef167..155f936e5 100644 --- a/imxweb/projects/qbm/src/lib/fk-advanced-picker/fk-advanced-picker.component.html +++ b/imxweb/projects/qbm/src/lib/fk-advanced-picker/fk-advanced-picker.component.html @@ -1,24 +1,25 @@
    + + {{ '#LDS#Select at least one item.' | translate }} +
    -
    -
    - -
    - - - -
    - - +
    \ No newline at end of file diff --git a/imxweb/projects/qbm/src/lib/fk-advanced-picker/fk-advanced-picker.component.scss b/imxweb/projects/qbm/src/lib/fk-advanced-picker/fk-advanced-picker.component.scss index bbac9a462..ce2c6d8f1 100644 --- a/imxweb/projects/qbm/src/lib/fk-advanced-picker/fk-advanced-picker.component.scss +++ b/imxweb/projects/qbm/src/lib/fk-advanced-picker/fk-advanced-picker.component.scss @@ -1,5 +1,7 @@ -@import "@elemental-ui/core/src/styles/_palette.scss"; +@import '@elemental-ui/core/src/styles/_palette.scss'; @import '@elemental-ui/core/src/styles/_eui_palette.scss'; +@import 'base/mixins'; + :host { overflow-y: auto; display: flex; @@ -8,13 +10,7 @@ } .imx-dialog-content { - display: flex; - flex-direction: column; - overflow-y: auto; - height: 100%; - eui-alert{ - margin-bottom: 20px; - } + @include flex-column-container($overflow: auto, $height: 100%); > imx-fk-selector { display: flex; @@ -23,46 +19,9 @@ } } -.eui-sidesheet-actions { - display: flex; - justify-content: flex-end; - margin-bottom: 0; - - button { - margin-left: 10px; - } - - .justify-start { - margin-right: auto; - } - - .imx-badge { - background-color: unset; - } -} - .imx-icon-large { background-repeat: no-repeat; padding-left: 35px; min-width: 32px; min-height: 32px; } -.eui-dark-theme { - :host { - background-color: $color-gray-80; - - .imx-dialog-actions { - background: $color-gray-70; - } - } -} - -.eui-contrast-theme { - :host { - background-color: $color-gray-100; - - .imx-dialog-actions { - background: $color-gray-90; - } - } -} diff --git a/imxweb/projects/qbm/src/lib/fk-advanced-picker/fk-advanced-picker.component.ts b/imxweb/projects/qbm/src/lib/fk-advanced-picker/fk-advanced-picker.component.ts index 1f03c4a47..405d4fc55 100644 --- a/imxweb/projects/qbm/src/lib/fk-advanced-picker/fk-advanced-picker.component.ts +++ b/imxweb/projects/qbm/src/lib/fk-advanced-picker/fk-advanced-picker.component.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -24,20 +24,16 @@ * */ -import { Component, Inject, ViewChild, OnInit, ElementRef, OnDestroy } from '@angular/core'; +import { Component, ElementRef, Inject, OnDestroy, OnInit, ViewChild } from '@angular/core'; +import { EUI_SIDESHEET_DATA, EuiSidesheetRef } from '@elemental-ui/core'; import { Subscription } from 'rxjs'; -import { EuiSidesheetRef, EUI_SIDESHEET_DATA } from '@elemental-ui/core'; -import { - TypedEntity, - IEntity, - IForeignKeyInfo, -} from 'imx-qbm-dbts'; -import { ClassloggerService } from '../classlogger/classlogger.service'; +import { IEntity, IForeignKeyInfo, TypedEntity } from '@imx-modules/imx-qbm-dbts'; import { MetadataService } from '../base/metadata.service'; -import { ForeignKeyPickerData } from './foreign-key-picker-data.interface'; -import { FkSelectorComponent } from './fk-selector.component'; +import { ClassloggerService } from '../classlogger/classlogger.service'; import { ConfirmationService } from '../confirmation/confirmation.service'; +import { FkSelectorComponent } from './fk-selector.component'; +import { ForeignKeyPickerData } from './foreign-key-picker-data.interface'; @Component({ templateUrl: './fk-advanced-picker.component.html', @@ -58,7 +54,7 @@ export class FkAdvancedPickerComponent implements OnInit, OnDestroy { public readonly metadataProvider: MetadataService, private readonly logger: ClassloggerService, private readonly confirmation: ConfirmationService, - private readonly elementRef: ElementRef + private readonly elementRef: ElementRef, ) { this.closeClickSubscription = this.sidesheetRef.closeClicked().subscribe(async () => { if (!this.isChanged || (await this.confirmation.confirmLeaveWithUnsavedChanges())) { @@ -103,8 +99,10 @@ export class FkAdvancedPickerComponent implements OnInit, OnDestroy { table: this.selector.selectedTable, candidates: entityList.map((typedEntity) => { const entity = typedEntity.GetEntity(); + const columnName = this.selectedTable.fkColumnName ?? this.selectedTable.ColumnName; + const data = entity.GetColumn(columnName)?.GetValue(); return { - DataValue: this.getKey(entity), + DataValue: data !== '' ? data : this.getKey(entity), DisplayValue: entity.GetDisplay(), displayLong: entity.GetDisplayLong(), }; @@ -113,10 +111,10 @@ export class FkAdvancedPickerComponent implements OnInit, OnDestroy { } public onSelectedCandidatesChanges(): void { - this.isChanged = this.data.isMultiValue; + this.isChanged = this.data.isMultiValue ?? false; } - private getKey(entity: IEntity): string { + private getKey(entity: IEntity): string | undefined { if (this.data.fkRelations && this.data.fkRelations.length > 1) { this.logger.trace(this, 'Dynamic foreign key'); const xObjectKeyColumn = entity.GetColumn('XObjectKey'); @@ -126,10 +124,10 @@ export class FkAdvancedPickerComponent implements OnInit, OnDestroy { this.logger.trace(this, 'Foreign key'); try { - const parentColumn = entity.GetColumn(this.data.fkRelations[0].ColumnName); - if (parentColumn) { + const parentColumnValue = entity.GetColumn(this.data.fkRelations[0].ColumnName)?.GetValue() ?? ''; + if (parentColumnValue !== '') { this.logger.trace(this, 'Use value from explicit parent column'); - return parentColumn.GetValue(); + return parentColumnValue; } } catch (error) { this.logger.trace(this, 'tried to get parent column but failed', error); diff --git a/imxweb/projects/qbm/src/lib/fk-advanced-picker/fk-advanced-picker.module.ts b/imxweb/projects/qbm/src/lib/fk-advanced-picker/fk-advanced-picker.module.ts index a5ab90306..cd1176c4f 100644 --- a/imxweb/projects/qbm/src/lib/fk-advanced-picker/fk-advanced-picker.module.ts +++ b/imxweb/projects/qbm/src/lib/fk-advanced-picker/fk-advanced-picker.module.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR diff --git a/imxweb/projects/qbm/src/lib/fk-advanced-picker/fk-candidates/fk-candidate-entity-builder.service.ts b/imxweb/projects/qbm/src/lib/fk-advanced-picker/fk-candidates/fk-candidate-entity-builder.service.ts index 9dd54c0a4..c17bfc244 100644 --- a/imxweb/projects/qbm/src/lib/fk-advanced-picker/fk-candidates/fk-candidate-entity-builder.service.ts +++ b/imxweb/projects/qbm/src/lib/fk-advanced-picker/fk-candidates/fk-candidate-entity-builder.service.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -26,18 +26,23 @@ import { Injectable } from '@angular/core'; -import { EntityCollectionData, TypedEntityBuilder, TypedEntityCollectionData } from 'imx-qbm-dbts'; +import { EntityCollectionData, EntitySchema, TypedEntityBuilder, TypedEntityCollectionData } from '@imx-modules/imx-qbm-dbts'; import { CandidateEntity } from '../candidate-entity'; @Injectable({ - providedIn: 'root' + providedIn: 'root', }) export class FkCandidateEntityBuilderService { - public readonly entitySchema = CandidateEntity.GetEntitySchema(); + public entitySchema: EntitySchema; private readonly builder = new TypedEntityBuilder(CandidateEntity); - public build(entityCollectionData: EntityCollectionData): TypedEntityCollectionData { + public build( + entityCollectionData: EntityCollectionData, + parentColumnName?: string, + tablename?: string, + ): TypedEntityCollectionData { + this.entitySchema = CandidateEntity.GetEntitySchema(parentColumnName, tablename); return this.builder.buildReadWriteEntities(entityCollectionData, this.entitySchema); } } diff --git a/imxweb/projects/qbm/src/lib/fk-advanced-picker/fk-candidates/fk-candidates-data.interface.ts b/imxweb/projects/qbm/src/lib/fk-advanced-picker/fk-candidates/fk-candidates-data.interface.ts index 8ea9a9e96..0b8337af6 100644 --- a/imxweb/projects/qbm/src/lib/fk-advanced-picker/fk-candidates/fk-candidates-data.interface.ts +++ b/imxweb/projects/qbm/src/lib/fk-advanced-picker/fk-candidates/fk-candidates-data.interface.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -24,12 +24,21 @@ * */ -import { CollectionLoadParameters, EntityCollectionData, FilterTreeData, TypedEntity, TypedEntityCollectionData } from 'imx-qbm-dbts'; +import { + ApiRequestOptions, + CollectionLoadParameters, + DataModel, + EntityCollectionData, + FilterTreeData, + TypedEntity, + TypedEntityCollectionData, +} from '@imx-modules/imx-qbm-dbts'; export interface FkCandidatesData { - get: (parameters: CollectionLoadParameters) => Promise; - GetFilterTree?: (parentKey: string) => Promise; - getTyped?: (parameters: CollectionLoadParameters) => Promise>; - isMultiValue: boolean; + Get?: (parameters: CollectionLoadParameters, opts?: ApiRequestOptions) => EntityCollectionData | Promise; + GetFilterTree?: (parentKey: string, opts?: ApiRequestOptions) => Promise; + GetDataModel?: (opts?: ApiRequestOptions) => Promise; + getTyped?: (parameters: CollectionLoadParameters, opts?: ApiRequestOptions) => Promise>; + isMultiValue?: boolean; preselectedEntities?: TypedEntity[]; } diff --git a/imxweb/projects/qbm/src/lib/fk-advanced-picker/fk-candidates/fk-candidates.component.html b/imxweb/projects/qbm/src/lib/fk-advanced-picker/fk-candidates/fk-candidates.component.html index a1fc2e032..cfcff53a9 100644 --- a/imxweb/projects/qbm/src/lib/fk-advanced-picker/fk-candidates/fk-candidates.component.html +++ b/imxweb/projects/qbm/src/lib/fk-advanced-picker/fk-candidates/fk-candidates.component.html @@ -6,7 +6,7 @@ [preSelection]="data?.preselectedEntities" [alwaysVisible]="showToolbar" [busyService]="busyService" - [options]="['search', 'filterTree']" + [options]="['search', 'filter']" (search)="search($event)" data-imx-identifier="fk-candidates-dst" > @@ -21,10 +21,10 @@ [showSelectedItemsMenu]="showSelectedItemsMenu" data-imx-identifier="fk-candidates-datatable" > - +
    {{ item.GetEntity().GetDisplay() }}
    -
    {{ item.GetEntity().GetDisplayLong() }}
    +
    {{ item.GetEntity().GetDisplayLong() }}
    diff --git a/imxweb/projects/qbm/src/lib/fk-advanced-picker/fk-candidates/fk-candidates.component.scss b/imxweb/projects/qbm/src/lib/fk-advanced-picker/fk-candidates/fk-candidates.component.scss index 7dd3faf31..900d79d7a 100644 --- a/imxweb/projects/qbm/src/lib/fk-advanced-picker/fk-candidates/fk-candidates.component.scss +++ b/imxweb/projects/qbm/src/lib/fk-advanced-picker/fk-candidates/fk-candidates.component.scss @@ -9,15 +9,6 @@ .imx-subtext { font-size: smaller; } - - .imx-table-container { - display: flex; - flex-direction: column; - overflow: hidden; - height: inherit; - max-width: 100%; - flex: 1 1 auto; - } } // Theming section diff --git a/imxweb/projects/qbm/src/lib/fk-advanced-picker/fk-candidates/fk-candidates.component.ts b/imxweb/projects/qbm/src/lib/fk-advanced-picker/fk-candidates/fk-candidates.component.ts index 2a9082adc..8a7ef493c 100644 --- a/imxweb/projects/qbm/src/lib/fk-advanced-picker/fk-candidates/fk-candidates.component.ts +++ b/imxweb/projects/qbm/src/lib/fk-advanced-picker/fk-candidates/fk-candidates.component.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -25,18 +25,29 @@ */ import { OverlayRef } from '@angular/cdk/overlay'; -import { Component, EventEmitter, Input, OnChanges, Output, SimpleChanges, ViewChild } from '@angular/core'; +import { Component, EventEmitter, Input, OnChanges, Output, ViewChild } from '@angular/core'; import { EuiLoadingService } from '@elemental-ui/core'; -import { CollectionLoadParameters, DisplayColumns, FilterData, IForeignKeyInfo, TypedEntity, ValType } from 'imx-qbm-dbts'; +import { + CollectionLoadParameters, + DataModel, + DisplayColumns, + EntitySchema, + FilterData, + IForeignKeyInfo, + TypedEntity, + ValType, +} from '@imx-modules/imx-qbm-dbts'; +import { BusyService } from '../../base/busy.service'; import { ClientPropertyForTableColumns } from '../../data-source-toolbar/client-property-for-table-columns'; import { DataSourceToolbarSettings } from '../../data-source-toolbar/data-source-toolbar-settings'; import { DataSourceToolbarComponent } from '../../data-source-toolbar/data-source-toolbar.component'; import { DataTableComponent } from '../../data-table/data-table.component'; +import { TypedEntityFkData } from '../../entity/typed-entity-select/typed-entity-fk-data.interface'; import { SettingsService } from '../../settings/settings-service'; +import { CandidateEntity } from '../candidate-entity'; import { FkCandidateEntityBuilderService } from './fk-candidate-entity-builder.service'; import { FkCandidatesData } from './fk-candidates-data.interface'; -import { BusyService } from '../../base/busy.service'; @Component({ selector: 'imx-fk-candidates', @@ -44,9 +55,9 @@ import { BusyService } from '../../base/busy.service'; styleUrls: ['./fk-candidates.component.scss'], }) export class FkCandidatesComponent implements OnChanges { - @Input() public data: FkCandidatesData; + @Input() public data: FkCandidatesData | TypedEntityFkData; @Input() public selectedFkTable: IForeignKeyInfo; - @Input() public showLongdisplay = false; + @Input() public showLongDisplay = false; @Input() public showSelectedItemsMenu = true; @Input() public noDataText: string; @Input() public busyService: BusyService; @@ -57,23 +68,23 @@ export class FkCandidatesComponent implements OnChanges { public readonly DisplayColumns = DisplayColumns; // Enables use of this static class in the Angular Template. public settings: DataSourceToolbarSettings; - public entitySchema = this.candidateBuilder.entitySchema; + public entitySchema: EntitySchema; + public dataModel: DataModel | undefined; @ViewChild(DataTableComponent) private readonly table: DataTableComponent; @ViewChild(DataSourceToolbarComponent) private readonly dst: DataSourceToolbarComponent; - private busyIndicator: OverlayRef; + private busyIndicator: OverlayRef | undefined; + private abortController: AbortController = new AbortController(); constructor( private readonly busyServiceElemental: EuiLoadingService, private readonly settingsService: SettingsService, - private readonly candidateBuilder: FkCandidateEntityBuilderService + private readonly candidateBuilder: FkCandidateEntityBuilderService, ) {} - public async ngOnChanges(changes: SimpleChanges): Promise { - if ((changes['data'] && this.data) || changes['selectedFkTable']) { - await this.getData({ StartIndex: 0, PageSize: this.settingsService.DefaultPageSize, filter: undefined, search: '' }); - } + public async ngOnChanges(): Promise { + await this.getData({ StartIndex: 0, PageSize: this.settingsService.DefaultPageSize }); } public async search(keywords: string): Promise { @@ -95,7 +106,7 @@ export class FkCandidatesComponent implements OnChanges { } public get showToolbar(): boolean { - return this.settings?.navigationState?.filter?.length > 0; + return !!this.settings?.navigationState?.filter?.length; } public async filterByTree(filters: FilterData[]): Promise { @@ -108,6 +119,10 @@ export class FkCandidatesComponent implements OnChanges { * @param newState the state of the data source */ public async getData(newState?: CollectionLoadParameters): Promise { + // Abort any previous calls + this.abortController.abort(); + this.abortController = new AbortController(); + let isBusy; if (this.busyService) { isBusy = this.busyService.beginBusy(); @@ -117,16 +132,20 @@ export class FkCandidatesComponent implements OnChanges { } } try { - let navigationState = this.settings?.navigationState || { PageSize: this.settingsService.DefaultPageSize, StartIndex: 0 }; - - if (newState) { - navigationState = { ...navigationState, ...newState }; - } + let navigationState = this.settings?.navigationState + ? { ...this.settings.navigationState, ...newState } + : { PageSize: this.settingsService.DefaultPageSize, StartIndex: 0 }; const dataSource = this.data.getTyped - ? await this.data.getTyped(navigationState) + ? await this.data.getTyped(navigationState, { signal: this.abortController.signal }) : this.candidateBuilder.build( - this.selectedFkTable ? await this.selectedFkTable.Get(navigationState) : await this.data.get(navigationState) + this.selectedFkTable + ? await this.selectedFkTable.Get(navigationState, { signal: this.abortController.signal }) + : this.data.Get + ? await this.data.Get(navigationState, { signal: this.abortController.signal }) + : { TotalCount: 0 }, + this.selectedFkTable?.fkColumnName, + this.selectedFkTable?.TableName, ); const displayedColumns: ClientPropertyForTableColumns[] = [DisplayColumns.DISPLAY_PROPERTY]; @@ -137,18 +156,23 @@ export class FkCandidatesComponent implements OnChanges { untranslatedDisplay: '#LDS#Selection', }); } + this.entitySchema = CandidateEntity.GetEntitySchema( + this.selectedFkTable?.fkColumnName ?? this.selectedFkTable?.ColumnName, + this.selectedFkTable?.TableName, + ); this.settings = { dataSource, displayedColumns, entitySchema: this.entitySchema, navigationState, + dataModel: this.data.GetDataModel ? await this.data.GetDataModel({ signal: this.abortController.signal }) : undefined, filterTree: { filterMethode: async (parentKey) => { return this.selectedFkTable - ? this.selectedFkTable.GetFilterTree(parentKey) + ? this.selectedFkTable.GetFilterTree(parentKey, { signal: this.abortController.signal }) : this.data.GetFilterTree - ? this.data.GetFilterTree(parentKey) - : { Elements: [] }; + ? this.data.GetFilterTree(parentKey, { signal: this.abortController.signal }) + : { Elements: [] }; }, multiSelect: false, }, diff --git a/imxweb/projects/qbm/src/lib/fk-advanced-picker/fk-selector.component.html b/imxweb/projects/qbm/src/lib/fk-advanced-picker/fk-selector.component.html index 8b6076d3d..5c1e81926 100644 --- a/imxweb/projects/qbm/src/lib/fk-advanced-picker/fk-selector.component.html +++ b/imxweb/projects/qbm/src/lib/fk-advanced-picker/fk-selector.component.html @@ -1,6 +1,11 @@
    - + {{ metadataProvider.tables[item.TableName]?.DisplaySingular || item.TableName }} @@ -21,7 +26,7 @@ - + - +
    {{ item?.GetEntity()?.GetDisplay() }}
    diff --git a/imxweb/projects/qbm/src/lib/fk-advanced-picker/fk-selector.component.scss b/imxweb/projects/qbm/src/lib/fk-advanced-picker/fk-selector.component.scss index 03d90773e..77062e511 100644 --- a/imxweb/projects/qbm/src/lib/fk-advanced-picker/fk-selector.component.scss +++ b/imxweb/projects/qbm/src/lib/fk-advanced-picker/fk-selector.component.scss @@ -14,42 +14,3 @@ overflow: hidden; } -.mat-radio-group { - display: flex; - - .mat-radio-button { - margin-right: 5px; - } -} - -.imx-table-container { - flex-grow: 1; - overflow: auto; - display: flex; - flex-direction: column; - - .imx-radio-button { - margin-right: 10px; - } - - .imx-main-display { - font-style: normal; - font-weight: 700; - font-size: 14px; - line-height: 48px; - } - - > imx-data-table { - display: flex; - flex-direction: column; - - .imx-selected-row { - color: $color-orange-60 - } - - ::ng-deep .mat-sidenav-container { - display: flex; - flex-direction: column; - } - } -} diff --git a/imxweb/projects/qbm/src/lib/fk-advanced-picker/fk-selector.component.ts b/imxweb/projects/qbm/src/lib/fk-advanced-picker/fk-selector.component.ts index c064a2e17..2b0b06933 100644 --- a/imxweb/projects/qbm/src/lib/fk-advanced-picker/fk-selector.component.ts +++ b/imxweb/projects/qbm/src/lib/fk-advanced-picker/fk-selector.component.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -24,31 +24,32 @@ * */ -import { Component, OnInit, ViewChild, Input, Output, EventEmitter } from '@angular/core'; +import { Component, EventEmitter, Input, OnInit, Output, ViewChild } from '@angular/core'; import { - TypedEntityBuilder, CollectionLoadParameters, - DisplayColumns, - ValType, - TypedEntity, - IForeignKeyInfo, - FilterType, CompareOperator, - DbObjectKey, + DataModel, DataModelFilter, + DbObjectKey, + DisplayColumns, + EntitySchema, FilterData, - DataModel, -} from 'imx-qbm-dbts'; -import { ClassloggerService } from '../classlogger/classlogger.service'; + FilterType, + IForeignKeyInfo, + TypedEntity, + TypedEntityBuilder, + ValType, +} from '@imx-modules/imx-qbm-dbts'; +import { BusyService } from '../base/busy.service'; import { MetadataService } from '../base/metadata.service'; +import { ClassloggerService } from '../classlogger/classlogger.service'; +import { ClientPropertyForTableColumns } from '../data-source-toolbar/client-property-for-table-columns'; import { DataSourceToolbarSettings } from '../data-source-toolbar/data-source-toolbar-settings'; -import { CandidateEntity } from './candidate-entity'; import { DataTableComponent } from '../data-table/data-table.component'; -import { ForeignKeyPickerData } from './foreign-key-picker-data.interface'; import { SettingsService } from '../settings/settings-service'; -import { ClientPropertyForTableColumns } from '../data-source-toolbar/client-property-for-table-columns'; -import { BusyService } from '../base/busy.service'; +import { CandidateEntity } from './candidate-entity'; +import { ForeignKeyPickerData } from './foreign-key-picker-data.interface'; @Component({ selector: 'imx-fk-selector', @@ -59,7 +60,7 @@ export class FkSelectorComponent implements OnInit { public settings: DataSourceToolbarSettings; public selectedTable: IForeignKeyInfo; public selectedCandidates: TypedEntity[] = []; - public preselectedEntities: TypedEntity[]; + public preselectedEntities: TypedEntity[] | null; public readonly DisplayColumns = DisplayColumns; // Enables use of this static class in Angular Templates. @@ -72,7 +73,7 @@ export class FkSelectorComponent implements OnInit { public busyService = new BusyService(); private readonly builder = new TypedEntityBuilder(CandidateEntity); - private readonly entitySchema = CandidateEntity.GetEntitySchema(); + public entitySchema: EntitySchema; private filters: DataModelFilter[]; private dataModel: DataModel; @@ -88,8 +89,9 @@ export class FkSelectorComponent implements OnInit { if (this.data.fkRelations && this.data.fkRelations.length > 0) { this.logger.trace(this, 'Pre-select the first candidate table'); this.selectedTable = this.data.fkRelations.find((fkr) => fkr.TableName === this.data.selectedTableName) || this.data.fkRelations[0]; + this.entitySchema = CandidateEntity.GetEntitySchema(this.selectedTable.ColumnName, this.selectedTable.TableName); this.dataModel = await this.selectedTable.GetDataModel(); - this.filters = this.dataModel.Filters; + this.filters = this.dataModel.Filters ?? []; } if (this.data.fkRelations && this.data.fkRelations.length > 0) { @@ -225,7 +227,7 @@ export class FkSelectorComponent implements OnInit { this.logger.debug(this, 'Getting preselected entities'); for (const key of this.data.idList) { - let table: IForeignKeyInfo; + let table: IForeignKeyInfo | undefined; if (this.data.fkRelations.length > 1) { const tableName = DbObjectKey.FromXml(key).TableName; table = this.data.fkRelations.find((fkr) => fkr.TableName === tableName); diff --git a/imxweb/projects/qbm/src/lib/fk-advanced-picker/foreign-key-picker-data.interface.ts b/imxweb/projects/qbm/src/lib/fk-advanced-picker/foreign-key-picker-data.interface.ts index d9d47bcc2..823169015 100644 --- a/imxweb/projects/qbm/src/lib/fk-advanced-picker/foreign-key-picker-data.interface.ts +++ b/imxweb/projects/qbm/src/lib/fk-advanced-picker/foreign-key-picker-data.interface.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -24,13 +24,13 @@ * */ -import { IForeignKeyInfo, IWriteValue } from 'imx-qbm-dbts'; +import { IForeignKeyInfo, IWriteValue } from '@imx-modules/imx-qbm-dbts'; export interface ForeignKeyPickerData { - fkRelations: IForeignKeyInfo[]; - selectedTableName?: string; - idList?: string[]; - isMultiValue?: boolean; - isRequired?: boolean; - disabledIds?: string[]; + fkRelations: IForeignKeyInfo[]; + selectedTableName?: string; + idList?: string[]; + isMultiValue?: boolean; + isRequired?: boolean; + disabledIds?: string[]; } diff --git a/imxweb/projects/qbm/src/lib/fk-advanced-picker/foreign-key-selection.interface.ts b/imxweb/projects/qbm/src/lib/fk-advanced-picker/foreign-key-selection.interface.ts index acf1ecb11..3d66e16be 100644 --- a/imxweb/projects/qbm/src/lib/fk-advanced-picker/foreign-key-selection.interface.ts +++ b/imxweb/projects/qbm/src/lib/fk-advanced-picker/foreign-key-selection.interface.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -24,10 +24,10 @@ * */ -import { IForeignKeyInfo } from 'imx-qbm-dbts'; +import { IForeignKeyInfo } from '@imx-modules/imx-qbm-dbts'; import { Candidate } from './candidate.interface'; export interface ForeignKeySelection { - table?: IForeignKeyInfo; - candidates?: Candidate[]; + table?: IForeignKeyInfo; + candidates?: Candidate[]; } diff --git a/imxweb/projects/qbm/src/lib/fk-container/dyn-fk-container.ts b/imxweb/projects/qbm/src/lib/fk-container/dyn-fk-container.ts index 0be40eeb7..1df0ad820 100644 --- a/imxweb/projects/qbm/src/lib/fk-container/dyn-fk-container.ts +++ b/imxweb/projects/qbm/src/lib/fk-container/dyn-fk-container.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -24,7 +24,7 @@ * */ -import { EntityData } from 'imx-qbm-dbts'; +import { EntityData } from '@imx-modules/imx-qbm-dbts'; import { FkContainer } from './fk-container'; export class DynFkContainer extends FkContainer { diff --git a/imxweb/projects/qbm/src/lib/fk-container/fk-container.ts b/imxweb/projects/qbm/src/lib/fk-container/fk-container.ts index 304619a1f..5e3316e59 100644 --- a/imxweb/projects/qbm/src/lib/fk-container/fk-container.ts +++ b/imxweb/projects/qbm/src/lib/fk-container/fk-container.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -26,14 +26,14 @@ import { ErrorHandler } from '@angular/core'; -import { EntityValue, EntityData, CollectionLoadParameters, EntityCollectionData } from 'imx-qbm-dbts'; +import { CollectionLoadParameters, EntityCollectionData, EntityData, EntityValue } from '@imx-modules/imx-qbm-dbts'; export class FkContainer { public property: EntityValue; - public candidateCollection: EntityCollectionData; - public value: EntityData; + public candidateCollection: EntityCollectionData | undefined; + public value: EntityData | null; - constructor(private getProperty: () => EntityValue) { } + constructor(private getProperty: () => EntityValue) {} public async init(errorHandler: ErrorHandler, parameters?: CollectionLoadParameters): Promise { this.property = this.getProperty(); @@ -42,13 +42,13 @@ export class FkContainer { if (this.property.value) { if (this.candidateCollection) { - this.value = this.candidateCollection.Entities.find(candidate => this.getEntityKey(candidate) === this.property.value); + this.value = this.candidateCollection.Entities?.find((candidate) => this.getEntityKey(candidate) === this.property.value) ?? null; } if (this.value == null) { this.value = { Display: this.property.Column.GetDisplayValue(), - Keys: [this.property.value] + Keys: [this.property.value], }; } } else { @@ -57,17 +57,18 @@ export class FkContainer { } public setKey(value: EntityData): void { - this.property.value = this.getEntityKey(value); + this.property.value = this.getEntityKey(value) ?? ''; } - protected getEntityKey(data: EntityData): string { + protected getEntityKey(data: EntityData): string | undefined { return data && data.Keys && data.Keys.length > 0 ? data.Keys[0] : undefined; } private async getCandidateCollection( property: EntityValue, errorHandler: ErrorHandler, - parameters?: CollectionLoadParameters): Promise { + parameters?: CollectionLoadParameters, + ): Promise { const fkRelations = property.GetMetadata().GetFkRelations(); if (fkRelations) { diff --git a/imxweb/projects/qbm/src/lib/fk-hierarchical-dialog/fk-hierarchical-dialog.component.html b/imxweb/projects/qbm/src/lib/fk-hierarchical-dialog/fk-hierarchical-dialog.component.html index f943a0f11..36ecc3497 100644 --- a/imxweb/projects/qbm/src/lib/fk-hierarchical-dialog/fk-hierarchical-dialog.component.html +++ b/imxweb/projects/qbm/src/lib/fk-hierarchical-dialog/fk-hierarchical-dialog.component.html @@ -1,9 +1,14 @@
    - - {{'#LDS#Object type' | translate}} - + + {{ '#LDS#Object type' | translate }} + {{ metadataProvider.tables[item.TableName]?.DisplaySingular || item.TableName }} @@ -11,33 +16,53 @@ - - + + {{ metadataProvider.tables[item.TableName]?.DisplaySingular || item.TableName }} - +
    -
    - -
    - -
    diff --git a/imxweb/projects/qbm/src/lib/fk-hierarchical-dialog/fk-hierarchical-dialog.component.scss b/imxweb/projects/qbm/src/lib/fk-hierarchical-dialog/fk-hierarchical-dialog.component.scss index e63578165..7faf83ea1 100644 --- a/imxweb/projects/qbm/src/lib/fk-hierarchical-dialog/fk-hierarchical-dialog.component.scss +++ b/imxweb/projects/qbm/src/lib/fk-hierarchical-dialog/fk-hierarchical-dialog.component.scss @@ -1,64 +1,31 @@ -@import "@elemental-ui/core/src/styles/_palette.scss"; @import '@elemental-ui/core/src/styles/_eui_palette.scss'; +@import 'base/mixins'; :host { - overflow-y: auto; - display: flex; - flex-direction: column; - height: 100%; + @include flex-column-container($overflow: auto, $height: 100%); } -.imx-fk-table-radio { - > *:not(:last-child) { - margin-right: 30px; - } -} - .imx-dialog-content { - display: flex; - flex-direction: column; - overflow-y: auto; - height: 100%; -} - -.eui-sidesheet-actions { - display: flex; - justify-content: flex-end; - margin-bottom: 0; - - button { - margin-left: 10px; - } - - .justify-start { - margin-right: auto; - } + @include flex-column-container($overflow: auto, $height: 100%); } -::ng-deep .imx-under { - margin-top: 30px; -} .eui-dark-theme { :host { background-color: $color-gray-80; - .imx-sidesheet-content{ + + .imx-sidesheet-content { background: $color-gray-80; } - .imx-dialog-actions { - background-color: $color-gray-70; - } } } .eui-contrast-theme { :host { background-color: $color-gray-100; - .imx-sidesheet-content{ + + .imx-sidesheet-content { background: $color-gray-100; } - .imx-dialog-actions { - background-color: $color-gray-90; - } } } diff --git a/imxweb/projects/qbm/src/lib/fk-hierarchical-dialog/fk-hierarchical-dialog.component.spec.ts b/imxweb/projects/qbm/src/lib/fk-hierarchical-dialog/fk-hierarchical-dialog.component.spec.ts index 2c91b8dc2..d08bd8e0c 100644 --- a/imxweb/projects/qbm/src/lib/fk-hierarchical-dialog/fk-hierarchical-dialog.component.spec.ts +++ b/imxweb/projects/qbm/src/lib/fk-hierarchical-dialog/fk-hierarchical-dialog.component.spec.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -35,8 +35,8 @@ import { FkHierarchicalDialogComponent } from './fk-hierarchical-dialog.componen import { FkHierarchicalDialogModule } from './fk-hierarchical-dialog.module'; const fkInfo = [ - { TableName: 'testtable1', ColumnName: 'testcolumn1', Get: (_) => undefined ,GetDataModel: () =>undefined}, - { TableName: 'testtable2', ColumnName: 'testcolumn2', Get: (_) => undefined, GetDataModel: () =>undefined }, + { TableName: 'testtable1', ColumnName: 'testcolumn1', Get: (_) => undefined, GetDataModel: () => undefined }, + { TableName: 'testtable2', ColumnName: 'testcolumn2', Get: (_) => undefined, GetDataModel: () => undefined }, ]; [ @@ -56,7 +56,8 @@ const fkInfo = [ beforeEach(() => { return MockBuilder([FkHierarchicalDialogComponent, TranslateModule.forRoot()]) .mock(FkHierarchicalDialogModule) - .mock(EuiSidesheetRef).mock(MetadataService,metadataServiceStub) + .mock(EuiSidesheetRef) + .mock(MetadataService, metadataServiceStub) .mock(ConfirmationService) .mock(EuiLoadingService) .mock(EUI_SIDESHEET_DATA, { @@ -77,5 +78,5 @@ const fkInfo = [ it('should create', () => { expect(component).toBeTruthy(); }); - }) + }), ); diff --git a/imxweb/projects/qbm/src/lib/fk-hierarchical-dialog/fk-hierarchical-dialog.component.ts b/imxweb/projects/qbm/src/lib/fk-hierarchical-dialog/fk-hierarchical-dialog.component.ts index d180286b4..04ee5f923 100644 --- a/imxweb/projects/qbm/src/lib/fk-hierarchical-dialog/fk-hierarchical-dialog.component.ts +++ b/imxweb/projects/qbm/src/lib/fk-hierarchical-dialog/fk-hierarchical-dialog.component.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -25,9 +25,8 @@ */ import { Component, Inject, OnDestroy, OnInit, ViewChild } from '@angular/core'; -import { EuiLoadingService, EuiSidesheetRef, EUI_SIDESHEET_DATA } from '@elemental-ui/core'; +import { EUI_SIDESHEET_DATA, EuiLoadingService, EuiSidesheetRef } from '@elemental-ui/core'; import { Subscription } from 'rxjs'; -import { OverlayRef } from '@angular/cdk/overlay'; import { CollectionLoadParameters, @@ -38,15 +37,15 @@ import { IEntity, IForeignKeyInfo, TypedEntity, -} from 'imx-qbm-dbts'; +} from '@imx-modules/imx-qbm-dbts'; import { MetadataService } from '../base/metadata.service'; import { ClassloggerService } from '../classlogger/classlogger.service'; import { ConfirmationService } from '../confirmation/confirmation.service'; +import { FilterTreeParameter } from '../data-source-toolbar/data-model/filter-tree-parameter'; +import { DataTreeWrapperComponent } from '../data-tree-wrapper/data-tree-wrapper.component'; import { ForeignKeyPickerData } from '../fk-advanced-picker/foreign-key-picker-data.interface'; -import { HierarchicalFkDatabase } from './hierarchical-fk-database'; import { HierarchicalCandidate } from './hierarchical-candidate'; -import { DataTreeWrapperComponent } from '../data-tree-wrapper/data-tree-wrapper.component'; -import { FilterTreeParameter } from '../data-source-toolbar/data-model/filter-tree-parameter'; +import { HierarchicalFkDatabase } from './hierarchical-fk-database'; @Component({ selector: 'imx-fk-hierarchical-dialog', @@ -74,7 +73,7 @@ export class FkHierarchicalDialogComponent implements OnInit, OnDestroy { private logger: ClassloggerService, private readonly confirmation: ConfirmationService, public readonly metadataProvider: MetadataService, - @Inject(EUI_SIDESHEET_DATA) public readonly data: ForeignKeyPickerData + @Inject(EUI_SIDESHEET_DATA) public readonly data: ForeignKeyPickerData, ) { this.closeClickSubscription = this.sidesheetRef.closeClicked().subscribe(async () => { if (!this.isChanged || (await this.confirmation.confirmLeaveWithUnsavedChanges())) { @@ -96,7 +95,7 @@ export class FkHierarchicalDialogComponent implements OnInit, OnDestroy { public async ngOnInit(): Promise { await this.getPreselectedEntities(); - this.filters = (await this.hierarchyService?.fkTable?.GetDataModel())?.Filters; + this.filters = (await this.hierarchyService?.fkTable?.GetDataModel())?.Filters ?? []; this.tableNames = this.data.fkRelations?.map((elem) => elem.TableName); } @@ -118,7 +117,7 @@ export class FkHierarchicalDialogComponent implements OnInit, OnDestroy { if (!this.data.isMultiValue) { this.selectedEntities = [entity]; this.applySelection(); - } + } } public selectedNodesChanged(): void { @@ -144,7 +143,7 @@ export class FkHierarchicalDialogComponent implements OnInit, OnDestroy { }); } - private getKey(entity: IEntity): string { + private getKey(entity: IEntity): string | undefined { if (this.data.fkRelations && this.data.fkRelations.length > 1) { const xObjectKeyColumn = entity.GetColumn('XObjectKey'); return xObjectKeyColumn ? xObjectKeyColumn.GetValue() : undefined; @@ -156,8 +155,9 @@ export class FkHierarchicalDialogComponent implements OnInit, OnDestroy { private async getPreselectedEntities(): Promise { if (this.data.fkRelations && this.data.fkRelations.length > 0 && this.data.idList && this.data.idList.length > 0) { - let over: OverlayRef; - setTimeout(() => (over = this.busyService.show())); + if (this.busyService.overlayRefs.length === 0) { + this.busyService.show(); + } try { const preselectedTemp: TypedEntity[] = []; @@ -166,7 +166,7 @@ export class FkHierarchicalDialogComponent implements OnInit, OnDestroy { this.logger.debug(this, 'Getting preselected entities'); for (const key of this.data.idList) { - let table: IForeignKeyInfo; + let table: IForeignKeyInfo | undefined; if (this.data.fkRelations.length > 1) { const tableName = DbObjectKey.FromXml(key).TableName; table = this.data.fkRelations.find((fkr) => fkr.TableName === tableName); @@ -187,7 +187,7 @@ export class FkHierarchicalDialogComponent implements OnInit, OnDestroy { this.logger.debug(this, 'Getting preselected entity with navigation state', navigationState); const elements = await table.Get(navigationState); - if (elements.Entities.length) { + if (elements.Entities?.length) { const entity = await this.hierarchyService.buildEntityWithHasChilderen(elements.Entities[0], elements.Hierarchy); preselectedTemp.push(entity); } @@ -197,7 +197,7 @@ export class FkHierarchicalDialogComponent implements OnInit, OnDestroy { this.selectedEntityCandidates = this.selectedEntities.map((elem) => new HierarchicalCandidate(elem)); this.logger.debug(this, `Retrieved ${this.selectedEntities.length} preselected entities`); } finally { - setTimeout(() => this.busyService.hide(over)); + this.busyService.hide(); } } } diff --git a/imxweb/projects/qbm/src/lib/fk-hierarchical-dialog/fk-hierarchical-dialog.module.ts b/imxweb/projects/qbm/src/lib/fk-hierarchical-dialog/fk-hierarchical-dialog.module.ts index e235bf506..e8b2d0ac8 100644 --- a/imxweb/projects/qbm/src/lib/fk-hierarchical-dialog/fk-hierarchical-dialog.module.ts +++ b/imxweb/projects/qbm/src/lib/fk-hierarchical-dialog/fk-hierarchical-dialog.module.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -38,12 +38,11 @@ import { MatSelectModule } from '@angular/material/select'; import { FkHierarchicalDialogComponent } from './fk-hierarchical-dialog.component'; import { ConfirmationModule } from '../confirmation/confirmation.module'; import { DataTreeWrapperModule } from '../data-tree-wrapper/data-tree-wrapper.module'; - -import {SelectedElementsModule} from '../selected-elements/selected-elements.module'; + +import { SelectedElementsModule } from '../selected-elements/selected-elements.module'; import { EuiCoreModule } from '@elemental-ui/core'; @NgModule({ - declarations: [FkHierarchicalDialogComponent], imports: [ EuiCoreModule, @@ -58,9 +57,8 @@ import { EuiCoreModule } from '@elemental-ui/core'; MatSelectModule, DataTreeWrapperModule, ConfirmationModule, - SelectedElementsModule + SelectedElementsModule, ], - exports: [FkHierarchicalDialogComponent] - + exports: [FkHierarchicalDialogComponent], }) -export class FkHierarchicalDialogModule { } +export class FkHierarchicalDialogModule {} diff --git a/imxweb/projects/qbm/src/lib/fk-hierarchical-dialog/hierarchical-candidate.ts b/imxweb/projects/qbm/src/lib/fk-hierarchical-dialog/hierarchical-candidate.ts index 63839a599..df6d26ee9 100644 --- a/imxweb/projects/qbm/src/lib/fk-hierarchical-dialog/hierarchical-candidate.ts +++ b/imxweb/projects/qbm/src/lib/fk-hierarchical-dialog/hierarchical-candidate.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -24,7 +24,7 @@ * */ -import { DisplayColumns, EntitySchema, ValType } from 'imx-qbm-dbts'; +import { DisplayColumns, EntitySchema, ValType } from '@imx-modules/imx-qbm-dbts'; import { CandidateEntity } from '../fk-advanced-picker/candidate-entity'; export class HierarchicalCandidate extends CandidateEntity { @@ -32,12 +32,12 @@ export class HierarchicalCandidate extends CandidateEntity { const columns = { XObjectKey: { Type: ValType.String, - ColumnName: 'XObjectKey' + ColumnName: 'XObjectKey', }, HasChildren: { Type: ValType.Bool, - ColumnName: 'HasChildren' - } + ColumnName: 'HasChildren', + }, }; columns[DisplayColumns.DISPLAY_PROPERTYNAME] = DisplayColumns.DISPLAY_PROPERTY; diff --git a/imxweb/projects/qbm/src/lib/fk-hierarchical-dialog/hierarchical-fk-database.ts b/imxweb/projects/qbm/src/lib/fk-hierarchical-dialog/hierarchical-fk-database.ts index 772448c36..35aad7fea 100644 --- a/imxweb/projects/qbm/src/lib/fk-hierarchical-dialog/hierarchical-fk-database.ts +++ b/imxweb/projects/qbm/src/lib/fk-hierarchical-dialog/hierarchical-fk-database.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -24,7 +24,6 @@ * */ -import { OverlayRef } from '@angular/cdk/overlay'; import { EuiLoadingService } from '@elemental-ui/core'; import { @@ -35,28 +34,27 @@ import { IEntity, IForeignKeyInfo, TypedEntityBuilder, - ValType -} from 'imx-qbm-dbts'; + ValType, +} from '@imx-modules/imx-qbm-dbts'; import { TreeDatabase } from '../data-tree/tree-database'; import { TreeNodeResultParameter } from '../data-tree/tree-node-result-parameter.interface'; import { HierarchicalCandidate } from './hierarchical-candidate'; export class HierarchicalFkDatabase extends TreeDatabase { - public fkTable: IForeignKeyInfo; private readonly builder = new TypedEntityBuilder(HierarchicalCandidate); - constructor( - private busyLoadingService: EuiLoadingService - ) { + constructor(private busyLoadingService: EuiLoadingService) { super(); this.canSearch = true; } /** implements the getData methode of TreeDataBase */ - public async getData(showLoading: boolean, parameters: CollectionLoadParameters = { ParentKey: '' /* first level */ }) - : Promise { + public async getData( + showLoading: boolean, + parameters: CollectionLoadParameters = { ParentKey: '' /* first level */ }, + ): Promise { if (!this.fkTable) { return { entities: [], canLoadMore: false, totalCount: 0 }; } @@ -64,12 +62,11 @@ export class HierarchicalFkDatabase extends TreeDatabase { const opts = { PageSize: 25, StartIndex: 0, - ...parameters + ...parameters, }; - let over: OverlayRef; - if (showLoading) { - setTimeout(() => over = this.busyLoadingService.show()); + if (showLoading && this.busyLoadingService.overlayRefs.length === 0) { + this.busyLoadingService.show(); } let data: EntityCollectionData; @@ -78,14 +75,16 @@ export class HierarchicalFkDatabase extends TreeDatabase { data = await this.fkTable.Get(opts); } finally { if (showLoading) { - setTimeout(() => this.busyLoadingService.hide(over)); + this.busyLoadingService.hide(); } } if (data) { - const nodeEntities = await Promise.all(data.Entities.map(async (elem): Promise => { - return (await this.buildEntityWithHasChilderen(elem, data.Hierarchy)).GetEntity(); - })); + const nodeEntities = await Promise.all( + data.Entities?.map(async (elem): Promise => { + return (await this.buildEntityWithHasChilderen(elem, data?.Hierarchy)).GetEntity(); + }) ?? [], + ); this.dataChanged.emit(nodeEntities); return { entities: nodeEntities, canLoadMore: opts.StartIndex + opts.PageSize < data.TotalCount, totalCount: data.TotalCount }; } @@ -93,20 +92,22 @@ export class HierarchicalFkDatabase extends TreeDatabase { } /** adds a hasChildren column to the entity */ - public async buildEntityWithHasChilderen(entityData: EntityData, data: HierarchyData): Promise { - + public async buildEntityWithHasChilderen(entityData: EntityData, data: HierarchyData | undefined): Promise { const entity = this.builder.buildReadWriteEntity({ entitySchema: HierarchicalCandidate.GetEntitySchema(), entityData }); - entity.GetEntity().AddColumns([{ - Type: ValType.Bool, - IsMultiValued: true, - ColumnName: 'HasChildren', - MinLen: 0, - Display: '' - }]); - await entity.GetEntity().GetColumn('HasChildren') - .PutValue(data ? data.EntitiesWithHierarchy.some(elem => entityData.Keys.some(key => key === elem)) : false); + entity.GetEntity().AddColumns([ + { + Type: ValType.Bool, + IsMultiValued: true, + ColumnName: 'HasChildren', + MinLen: 0, + Display: '', + }, + ]); + await entity + .GetEntity() + .GetColumn('HasChildren') + .PutValue(data ? data.EntitiesWithHierarchy?.some((elem) => entityData.Keys?.some((key) => key === elem)) : false); return entity; } - } diff --git a/imxweb/projects/qbm/src/lib/help-contextual/help-contextual-dialog/help-contextual-dialog.component.html b/imxweb/projects/qbm/src/lib/help-contextual/help-contextual-dialog/help-contextual-dialog.component.html index 03058aad4..731596155 100644 --- a/imxweb/projects/qbm/src/lib/help-contextual/help-contextual-dialog/help-contextual-dialog.component.html +++ b/imxweb/projects/qbm/src/lib/help-contextual/help-contextual-dialog/help-contextual-dialog.component.html @@ -1,12 +1,12 @@
    -

    +

    {{ dialogHeading }}

    -
    {{detail | translate}}
    +
    {{ detail }}
    diff --git a/imxweb/projects/qbm/src/lib/help-contextual/help-contextual-dialog/help-contextual-dialog.component.scss b/imxweb/projects/qbm/src/lib/help-contextual/help-contextual-dialog/help-contextual-dialog.component.scss index ee584edb3..d17f6a2d5 100644 --- a/imxweb/projects/qbm/src/lib/help-contextual/help-contextual-dialog/help-contextual-dialog.component.scss +++ b/imxweb/projects/qbm/src/lib/help-contextual/help-contextual-dialog/help-contextual-dialog.component.scss @@ -1,12 +1,10 @@ -.dialog-content__links{ +.dialog-content__links { margin-top: 20px; display: flex; flex-direction: column; gap: 10px; } -.mat-dialog-actions{ - justify-content: end; -} -.mat-dialog-content{ + +.mat-mdc-dialog-content{ max-width: 50vw; } diff --git a/imxweb/projects/qbm/src/lib/help-contextual/help-contextual-dialog/help-contextual-dialog.component.ts b/imxweb/projects/qbm/src/lib/help-contextual/help-contextual-dialog/help-contextual-dialog.component.ts index 15fe51dde..2cd33ef4b 100644 --- a/imxweb/projects/qbm/src/lib/help-contextual/help-contextual-dialog/help-contextual-dialog.component.ts +++ b/imxweb/projects/qbm/src/lib/help-contextual/help-contextual-dialog/help-contextual-dialog.component.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -24,9 +24,9 @@ * */ -import { Component, Inject, OnInit } from '@angular/core'; +import { Component, Inject } from '@angular/core'; import { MAT_DIALOG_DATA, MatDialogRef } from '@angular/material/dialog'; -import { ChapterLink, ContextualHelpItem } from 'imx-api-qbm'; +import { ChapterLink, ContextualHelpItem } from '@imx-modules/imx-api-qbm'; import { HelpContextualService } from '../help-contextual.service'; /** @@ -41,7 +41,7 @@ export class HelpContextualDialogComponent { constructor( private readonly helpContextService: HelpContextualService, public matDialogRef: MatDialogRef, - @Inject(MAT_DIALOG_DATA) public data: ContextualHelpItem + @Inject(MAT_DIALOG_DATA) public data: ContextualHelpItem, ) {} /** @@ -67,8 +67,8 @@ export class HelpContextualDialogComponent { */ getHelpLink(link: ChapterLink): string { if (link.IsExternal) { - return link.Url; + return link.Url ?? ''; } - return this.helpContextService.getHelpLink(link.Url); + return link.Url ? this.helpContextService.getHelpLink(link.Url) : ''; } } diff --git a/imxweb/projects/qbm/src/lib/help-contextual/help-contextual.component.html b/imxweb/projects/qbm/src/lib/help-contextual/help-contextual.component.html index e6bfdb3fb..614def370 100644 --- a/imxweb/projects/qbm/src/lib/help-contextual/help-contextual.component.html +++ b/imxweb/projects/qbm/src/lib/help-contextual/help-contextual.component.html @@ -1,4 +1,4 @@ -{{title | translate}} +{{ title | translate }} diff --git a/imxweb/projects/qbm/src/lib/help-contextual/help-contextual.component.scss b/imxweb/projects/qbm/src/lib/help-contextual/help-contextual.component.scss index e5bfd9150..a4db3b33e 100644 --- a/imxweb/projects/qbm/src/lib/help-contextual/help-contextual.component.scss +++ b/imxweb/projects/qbm/src/lib/help-contextual/help-contextual.component.scss @@ -1,36 +1,17 @@ @import '@elemental-ui/core/src/styles/_eui_palette.scss'; -:host{ +:host { display: flex; align-items: center; } -span{ +span { color: $color-gray-60; font-size: 14px; } -::ng-deep{ - eui-sidesheet{ - .eui-sidesheet{ - .mat-toolbar{ - justify-content: start; - .eui-sidesheet__heading-text{ - flex-basis: auto; - } - imx-help-contextual{ - .mat-icon-button{ - color: $color-gray-0; - } - } - .eui-sidesheet-close{ - margin-left: auto; - } - } - } - } -} + .eui-dark-theme { :host { - span{ + span { color: $color-gray-10; } } diff --git a/imxweb/projects/qbm/src/lib/help-contextual/help-contextual.component.ts b/imxweb/projects/qbm/src/lib/help-contextual/help-contextual.component.ts index 98865e775..5b98bd91f 100644 --- a/imxweb/projects/qbm/src/lib/help-contextual/help-contextual.component.ts +++ b/imxweb/projects/qbm/src/lib/help-contextual/help-contextual.component.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -25,10 +25,10 @@ */ import { Component, Input, OnDestroy } from '@angular/core'; -import { HelpContextualValues, HelpContextualService, HELP_CONTEXTUAL } from './help-contextual.service'; -import { ActivatedRoute } from '@angular/router'; import { MatDialog } from '@angular/material/dialog'; +import { ActivatedRoute } from '@angular/router'; import { HelpContextualDialogComponent } from './help-contextual-dialog/help-contextual-dialog.component'; +import { HELP_CONTEXTUAL, HelpContextualService, HelpContextualValues } from './help-contextual.service'; /** * Help contextual component * @example @@ -56,18 +56,18 @@ import { HelpContextualDialogComponent } from './help-contextual-dialog/help-con @Component({ selector: 'imx-help-contextual', templateUrl: './help-contextual.component.html', - styleUrls: ['./help-contextual.component.scss'] + styleUrls: ['./help-contextual.component.scss'], }) -export class HelpContextualComponent implements OnDestroy{ +export class HelpContextualComponent implements OnDestroy { @Input() contextId: HelpContextualValues; - @Input() size: 's'| 'm' | 'l' | 'xl' = 'm'; + @Input() size: 's' | 'm' | 'l' | 'xl' = 'm'; @Input() title: string; constructor( private router: ActivatedRoute, private helpContextualService: HelpContextualService, - private dialog: MatDialog - ) { } + private dialog: MatDialog, + ) {} ngOnDestroy(): void { this.helpContextualService.setHelpContextId(null); @@ -75,23 +75,26 @@ export class HelpContextualComponent implements OnDestroy{ /** * The call opens the dialog with the contextual help data. */ - public async onShowHelp(): Promise{ - const contextualHelpData = await this.helpContextualService.getHelpContext(this.getContextId()); - this.dialog - .open(HelpContextualDialogComponent, { - data: contextualHelpData - }) + public async onShowHelp(): Promise { + const id = this.getContextId(); + if (!id) { + return; + } + const contextualHelpData = await this.helpContextualService.getHelpContext(id); + this.dialog.open(HelpContextualDialogComponent, { + data: contextualHelpData, + }); } /** * The call returns the selected context ID. * @returns {HelpContextualValues} */ - private getContextId(): HelpContextualValues{ - if(!!this.contextId){ + private getContextId(): HelpContextualValues | null { + if (!!this.contextId) { return this.contextId; } - if(!!this.helpContextualService.GetHelpContextId()){ + if (!!this.helpContextualService.GetHelpContextId()) { return this.helpContextualService.GetHelpContextId(); } let contextId: HelpContextualValues; diff --git a/imxweb/projects/qbm/src/lib/help-contextual/help-contextual.module.ts b/imxweb/projects/qbm/src/lib/help-contextual/help-contextual.module.ts index 3b1760ae4..f07e22c13 100644 --- a/imxweb/projects/qbm/src/lib/help-contextual/help-contextual.module.ts +++ b/imxweb/projects/qbm/src/lib/help-contextual/help-contextual.module.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -33,20 +33,9 @@ import { TranslateModule } from '@ngx-translate/core'; import { EuiCoreModule } from '@elemental-ui/core'; import { MatButtonModule } from '@angular/material/button'; - - @NgModule({ - declarations: [ - HelpContextualComponent, - HelpContextualDialogComponent - ], - imports: [ - CommonModule, - MatDialogModule, - TranslateModule, - EuiCoreModule, - MatButtonModule - ], - exports: [HelpContextualComponent] + declarations: [HelpContextualComponent, HelpContextualDialogComponent], + imports: [CommonModule, MatDialogModule, TranslateModule, EuiCoreModule, MatButtonModule], + exports: [HelpContextualComponent], }) -export class HelpContextualModule { } +export class HelpContextualModule {} diff --git a/imxweb/projects/qbm/src/lib/help-contextual/help-contextual.service.ts b/imxweb/projects/qbm/src/lib/help-contextual/help-contextual.service.ts index 7627e157c..e474b7689 100644 --- a/imxweb/projects/qbm/src/lib/help-contextual/help-contextual.service.ts +++ b/imxweb/projects/qbm/src/lib/help-contextual/help-contextual.service.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -25,9 +25,9 @@ */ import { Injectable } from '@angular/core'; -import { AppConfigService } from '../appConfig/appConfig.service'; -import { ContextualHelpItem } from 'imx-api-qbm'; +import { ContextualHelpItem } from '@imx-modules/imx-api-qbm'; import { TranslateService } from '@ngx-translate/core'; +import { AppConfigService } from '../appConfig/appConfig.service'; /** * Contains all the methods for help context. @@ -36,7 +36,7 @@ import { TranslateService } from '@ngx-translate/core'; providedIn: 'root', }) export class HelpContextualService { - private helpContextId: HelpContextualValues; + private helpContextId: HelpContextualValues | null; constructor( private appConfigService: AppConfigService, private translateService: TranslateService, @@ -48,7 +48,7 @@ export class HelpContextualService { * @returns the selected ContextualHelpItem */ public async getHelpContext(contextId: HelpContextualValues): Promise { - const lang = this.translateService.currentLang; + const lang = this.translateService.currentLang === 'de' ? 'de-DE' : this.translateService.currentLang; let contextItem: ContextualHelpItem; try { contextItem = await this.appConfigService.client.imx_help_context_get(contextId, lang); @@ -71,7 +71,7 @@ export class HelpContextualService { * The call sets the stored help context ID. * @param {HelpContextualValues} */ - public setHelpContextId(contextId: HelpContextualValues): void { + public setHelpContextId(contextId: HelpContextualValues | null): void { this.helpContextId = contextId; } @@ -79,7 +79,7 @@ export class HelpContextualService { * The call returns the stored help context ID. * @returns {HelpContextualValues} */ - public GetHelpContextId(): HelpContextualValues { + public GetHelpContextId(): HelpContextualValues | null { return this.helpContextId; } } @@ -92,6 +92,7 @@ export class HelpContextualService { export const HELP_CONTEXTUAL = { Default: 'default', StatisticsPage: 'statistics-page', + StatisticsFavoritesOrdering: 'statistics-favorites-ordering', NewRequest: 'new-request', NewRequestRecommendedProduct: 'new-request-recommended-product', NewRequestReferenceUser: 'new-request-reference-user', @@ -130,32 +131,45 @@ export const HELP_CONTEXTUAL = { ClaimGroup: 'claim-group', MyResponsibilities: 'my-responsibilities', MyResponsibilitiesApplication: 'my-responsibilities-application', + MyResponsibilitiesApplicationRoleEntitlements: 'my-responsibilities-application-role-entitlements', MyResponsibilitiesIdentities: 'my-responsibilities-identities', MyResponsibilitiesQERResource: 'my-responsibilities-qer-resource', MyResponsibilitiesQERReuse: 'my-responsibilities-qer-reuse', MyResponsibilitiesQERAssign: 'my-responsibilities-qer-assign', MyResponsibilitiesQERReuseUS: 'my-responsibilities-qer-reuse-us', MyResponsibilitiesAERole: 'my-responsibilities-ae-role', + MyResponsibilitiesAERoleRoleEntitlements: 'my-responsibilities-ae-role-role-entitlements', MyResponsibilitiesDepartment: 'my-responsibilities-department', + MyResponsibilitiesDepartmentRoleEntitlements: 'my-responsibilities-department-role-entitlements', MyResponsibilitiesLocality: 'my-responsibilities-locality', + MyResponsibilitiesLocalityRoleEntitlements: 'my-responsibilities-locality-role-entitlements', MyResponsibilitiesProfitCenter: 'my-responsibilities-profit-center', + MyResponsibilitiesProfitCenterRoleEntitlements: 'my-responsibilities-profit-center-role-entitlements', MyResponsibilitiesBusinessRoles: 'my-responsibilities-business-roles', + MyResponsibilitiesBusinessRolesRoleEntitlements: 'my-responsibilities-business-roles-role-entitlements', MyResponsibilitiesSystemRoles: 'my-responsibilities-system-roles', + MyResponsibilitiesSystemRolesRoleEntitlements: 'my-responsibilities-system-roles-role-entitlements', MyResponsibilitiesGroups: 'my-responsibilities-groups', DataExplorer: 'data-explorer', DataExplorerIdentities: 'data-explorer-identities', DataExplorerAccounts: 'data-explorer-accounts', DataExplorerGroups: 'data-explorer-groups', DataExplorerDepartment: 'data-explorer-department', + DataExplorerDepartmentRoleEntitlements: 'data-explorer-department-role-entitlements', DataExplorerLocality: 'data-explorer-locality', + DataExplorerLocalityRoleEntitlements: 'data-explorer-locality-role-entitlements', DataExplorerProfitCenter: 'data-explorer-profit-center', + DataExplorerProfitCenterRoleEntitlements: 'data-explorer-profit-center-role-entitlements', DataExplorerBusinessRoles: 'data-explorer-business-roles', + DataExplorerBusinessRolesRoleEntitlements: 'data-explorer-business-roles-role-entitlements', DataExplorerSystemRoles: 'data-explorer-system-roles', + DataExplorerSystemRolesRoleEntitlements: 'data-explorer-system-roles-role-entitlements', DataExplorerQERResource: 'data-explorer-qer-resource', DataExplorerQERReuseUS: 'data-explorer-qer-reuse-us', DataExplorerQERReuse: 'data-explorer-qer-reuse', DataExplorerQERAssign: 'data-explorer-qer-assign', DataExplorerAERole: 'data-explorer-ae-role', + DataExplorerAERoleRoleEntitlements: 'data-explorer-ae-role-role-entitlements', Applications: 'applications', Statistics: 'statistics', PortalDevices: 'portal-devices', @@ -178,6 +192,7 @@ export const HELP_CONTEXTUAL = { ServiceItemsEdit: 'service-items-edit', ApprovalWorkflowManager: 'approval-workflow-manager', ApprovalWorkflowManagerCreate: 'approval-workflow-manager-create', + ApprovalWorkflowManagerEdit: 'approval-workflow-manager-edit', Reports: 'reports', ReportsCreate: 'reports-create', ReportsEdit: 'reports-edit', @@ -187,6 +202,7 @@ export const HELP_CONTEXTUAL = { Profile: 'profile', ProfileMultipleIdentities: 'profile-multiple-identities', Addressbook: 'addressbook', + ProcessingQueue: 'processing-queue', } as const; type ObjectValues = T[keyof T]; export type HelpContextualValues = ObjectValues; diff --git a/imxweb/projects/qbm/src/lib/hyperview/connector-provider.spec.ts b/imxweb/projects/qbm/src/lib/hyperview/connector-provider.spec.ts index 71392c96c..f646eb9a7 100644 --- a/imxweb/projects/qbm/src/lib/hyperview/connector-provider.spec.ts +++ b/imxweb/projects/qbm/src/lib/hyperview/connector-provider.spec.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -28,32 +28,27 @@ import { ConnectorProvider } from './connector-provider'; import { clearStylesFromDOM } from '../testing/clear-styles.spec'; describe('ConnectorProvider', () => { - afterAll(() => { clearStylesFromDOM(); }); it('should create an instance', () => { - expect(() => { const connector = new ConnectorProvider(true); - }).not.toThrowError(); }); [ { description: 'should return no connectors', nbOfElements: 1, expectedConnectors: 0 }, { description: 'should return one connectors', nbOfElements: 2, expectedConnectors: 1 }, - { description: 'should return three connectors', nbOfElements: 3, expectedConnectors: 2 } - ].forEach(testcase => { - + { description: 'should return three connectors', nbOfElements: 3, expectedConnectors: 2 }, + ].forEach((testcase) => { it('getConnectors ' + testcase.description, () => { - // Arrange const singleElement = { position: 'bla', - element: document.createElement('div') - } + element: document.createElement('div'), + }; const hvElements = []; for (let i = 0; i < testcase.nbOfElements; i++) { @@ -62,8 +57,8 @@ describe('ConnectorProvider', () => { const hvSettings = { enforceVerticalLayout: false, - elements: hvElements - } + elements: hvElements, + }; expect(() => { // Act @@ -78,25 +73,23 @@ describe('ConnectorProvider', () => { [ { description: 'should return no connectors', isHierarchical: false, expectedConnectors: 0 }, - { description: 'should return one connectors', isVertical: true, expectedConnectors: 1 } - ].forEach(testcase => { - + { description: 'should return one connectors', isVertical: true, expectedConnectors: 1 }, + ].forEach((testcase) => { it('getConnectors should create different connectors according to the layout ' + testcase.description, () => { - // Arrange const hvElements = []; for (let i = 0; i < 3; i++) { const singleElement = { position: i, - element: document.createElement('div' + i) - } + element: document.createElement('div' + i), + }; hvElements.push(singleElement); } const hvSettings = { enforceVerticalLayout: false, - elements: hvElements - } + elements: hvElements, + }; expect(() => { // Act @@ -114,10 +107,7 @@ describe('ConnectorProvider', () => { expect(conn.element1.tagName).toBe('DIV' + index); } }); - }).not.toThrowError(); }); }); - - }); diff --git a/imxweb/projects/qbm/src/lib/hyperview/connector-provider.ts b/imxweb/projects/qbm/src/lib/hyperview/connector-provider.ts index ed490f1ee..15bdccab8 100644 --- a/imxweb/projects/qbm/src/lib/hyperview/connector-provider.ts +++ b/imxweb/projects/qbm/src/lib/hyperview/connector-provider.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -28,24 +28,23 @@ import { HvSettings } from './hyperview-types'; import { Connector } from './connector'; export interface IConnectorProvider { - getConnectors(settings: HvSettings): Connector[]; + getConnectors(settings: HvSettings): Connector[]; } export class ConnectorProvider implements IConnectorProvider { + private hierarchical: boolean; - private hierarchical: boolean; + constructor(hierarchical: boolean) { + this.hierarchical = hierarchical; + } - constructor(hierarchical: boolean) { - this.hierarchical = hierarchical; - } - - public getConnectors(settings: HvSettings): Connector[] { - const es = settings.elements; - const res: Connector[] = []; - for (let i = 1; i < es.length; i++) { - const srcIndex = this.hierarchical ? 0 : i - 1; - res.push(new Connector(es[srcIndex].element, es[i].element)); - } - return res; + public getConnectors(settings: HvSettings): Connector[] { + const es = settings.elements; + const res: Connector[] = []; + for (let i = 1; i < es.length; i++) { + const srcIndex = this.hierarchical ? 0 : i - 1; + res.push(new Connector(es[srcIndex].element, es[i].element)); } + return res; + } } diff --git a/imxweb/projects/qbm/src/lib/hyperview/connector.spec.ts b/imxweb/projects/qbm/src/lib/hyperview/connector.spec.ts index aea562a6d..fa30150f9 100644 --- a/imxweb/projects/qbm/src/lib/hyperview/connector.spec.ts +++ b/imxweb/projects/qbm/src/lib/hyperview/connector.spec.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -28,15 +28,13 @@ import { Connector } from './connector'; import { clearStylesFromDOM } from '../testing/clear-styles.spec'; describe('Connector', () => { - afterAll(() => { clearStylesFromDOM(); }); it('should create an visible connector', () => { - const element = document.createElement('div'); - expect( () => { + expect(() => { const connector = new Connector(element, element); expect(connector.isHidden).toBeFalsy(); }).not.toThrowError(); diff --git a/imxweb/projects/qbm/src/lib/hyperview/connector.ts b/imxweb/projects/qbm/src/lib/hyperview/connector.ts index 3c2e68833..151c3814f 100644 --- a/imxweb/projects/qbm/src/lib/hyperview/connector.ts +++ b/imxweb/projects/qbm/src/lib/hyperview/connector.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -28,10 +28,13 @@ * The connector class */ export class Connector { - public isHidden: boolean; - public data: string; + public isHidden: boolean; + public data: string; - constructor(public readonly element1: HTMLElement, public readonly element2: HTMLElement) { - this.isHidden = false; - } + constructor( + public readonly element1: HTMLElement, + public readonly element2: HTMLElement, + ) { + this.isHidden = false; + } } diff --git a/imxweb/projects/qbm/src/lib/hyperview/connectors.spec.ts b/imxweb/projects/qbm/src/lib/hyperview/connectors.spec.ts index 6a1a4b340..a72e30222 100644 --- a/imxweb/projects/qbm/src/lib/hyperview/connectors.spec.ts +++ b/imxweb/projects/qbm/src/lib/hyperview/connectors.spec.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -24,42 +24,23 @@ * */ -import * as TypeMoq from 'typemoq'; - -import { Connectors } from './connectors'; -import { Connector } from './connector'; import { clearStylesFromDOM } from '../testing/clear-styles.spec'; +import { Connector } from './connector'; +import { Connectors } from './connectors'; describe('Connectors', () => { - afterAll(() => { clearStylesFromDOM(); }); it('should create connectors in each direction', () => { + const elem1 = { offsetLeft: 10, offsetWidth: 0, offsetTop: 0, offsetHeight: 0 }; + const elem2 = { offsetLeft: 50, offsetWidth: 0, offsetTop: 50, offsetHeight: 0 }; + const elem3 = { offsetLeft: 75, offsetWidth: 0, offsetTop: 25, offsetHeight: 0 }; - const elem1 = TypeMoq.Mock.ofType(); - elem1.setup(e => e.offsetLeft).returns(() => 10); - elem1.setup(e => e.offsetWidth).returns(() => 0); - elem1.setup(e => e.offsetTop).returns(() => 10); - elem1.setup(e => e.offsetHeight).returns(() => 0); - - const elem2 = TypeMoq.Mock.ofType(); - elem2.setup(e => e.offsetLeft).returns(() => 50); - elem2.setup(e => e.offsetWidth).returns(() => 0); - elem2.setup(e => e.offsetTop).returns(() => 50); - elem2.setup(e => e.offsetHeight).returns(() => 0); - - const elem3 = TypeMoq.Mock.ofType(); - elem3.setup(e => e.offsetLeft).returns(() => 75); - elem3.setup(e => e.offsetWidth).returns(() => 0); - elem3.setup(e => e.offsetTop).returns(() => 25); - elem3.setup(e => e.offsetHeight).returns(() => 0); - - - const html1 = elem1.object; - const html2 = elem2.object; - const html3 = elem3.object; + const html1 = elem1 as unknown as HTMLElement; + const html2 = elem2 as unknown as HTMLElement; + const html3 = elem3 as unknown as HTMLElement; const conn1 = new Connector(html1, html2); const conn2 = new Connector(html1, html1); @@ -75,5 +56,4 @@ describe('Connectors', () => { expect(connectors.maxValue.Y).toBe(50); }).not.toThrowError(); }); - }); diff --git a/imxweb/projects/qbm/src/lib/hyperview/connectors.ts b/imxweb/projects/qbm/src/lib/hyperview/connectors.ts index 95c4a857f..615effa1e 100644 --- a/imxweb/projects/qbm/src/lib/hyperview/connectors.ts +++ b/imxweb/projects/qbm/src/lib/hyperview/connectors.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -35,13 +35,11 @@ interface Coord { * Class managing the connectors for a hyperview control. */ export class Connectors { - public readonly connectorList: Connector[]; public readonly maxValue = { X: 0, Y: 0 }; constructor(connectors: Connector[]) { - // get connectors from xml this.connectorList = connectors; @@ -52,7 +50,6 @@ export class Connectors { * Repaints all connectors. */ private repaintAllConnectors(): void { - // reset maxValue this.maxValue.X = 0; this.maxValue.Y = 0; @@ -66,7 +63,6 @@ export class Connectors { * Draws a connector between two shapes. */ private drawConnector(connector: Connector): void { - // get centerpoints of both shapes const p1 = this.centerPoint(connector.element1); const p2 = this.centerPoint(connector.element2); @@ -82,10 +78,10 @@ export class Connectors { m = deltaY / deltaX; } if (m < 0) { - middle = (p1.X + (deltaX * 0.3)); + middle = p1.X + deltaX * 0.3; curveCoords += middle + ' ' + p1.Y + ' ' + middle + ' ' + p2.Y; } else { - middle = (p1.Y + (deltaY * 0.3)); + middle = p1.Y + deltaY * 0.3; curveCoords += p1.X + ' ' + middle + ' ' + p2.X + ' ' + middle; } curveCoords += ' ' + p2.X + ' ' + p2.Y; @@ -102,8 +98,8 @@ export class Connectors { */ private centerPoint(element: HTMLElement): Coord { return { - X: Math.round(element.offsetLeft + (element.offsetWidth / 2)), - Y: Math.round(element.offsetTop + (element.offsetHeight / 2)) + X: Math.round(element.offsetLeft + element.offsetWidth / 2), + Y: Math.round(element.offsetTop + element.offsetHeight / 2), }; } } diff --git a/imxweb/projects/qbm/src/lib/hyperview/hyperview-layout-hierarchical.ts b/imxweb/projects/qbm/src/lib/hyperview/hyperview-layout-hierarchical.ts index 41025c81c..591467fab 100644 --- a/imxweb/projects/qbm/src/lib/hyperview/hyperview-layout-hierarchical.ts +++ b/imxweb/projects/qbm/src/lib/hyperview/hyperview-layout-hierarchical.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -24,7 +24,6 @@ * */ - import { IConnectorProvider, ConnectorProvider } from './connector-provider'; import { toPixelString, HvElement, HvCell, Size, HyperViewLayout, LayoutResult } from './hyperview-types'; import { ClassloggerService } from '../classlogger/classlogger.service'; @@ -33,7 +32,6 @@ import { ClassloggerService } from '../classlogger/classlogger.service'; * Hyperview layouter that arranges the elements hierarchical. */ export class HyperviewLayoutHierarchical implements HyperViewLayout { - /** * Returns a list of all possible positions for a shape in a hyperview. */ @@ -46,21 +44,21 @@ export class HyperviewLayoutHierarchical implements HyperViewLayout { 'MiddleRight', 'BottomLeft', 'BottomCenter', - 'BottomRight' + 'BottomRight', ]; // waiting for https://github.com/Microsoft/TypeScript/issues/13042 private vLayoutElements: { - [id: string /* should be keyof Positions*/]: HvCell + [id: string /* should be keyof Positions*/]: HvCell; }; constructor( private readonly elements: HvElement[], - private logger: ClassloggerService + private logger: ClassloggerService, ) { this.elements = elements; const elems = this.elements; - const centerElement = elems.findIndex(e => e.position === 'MiddleCenter'); + const centerElement = elems.findIndex((e) => e.position === 'MiddleCenter'); if (centerElement === -1) { throw new Error('A shape with MiddleCenter position is required for hierarchical layout.'); } else if (centerElement !== 0) { @@ -70,7 +68,6 @@ export class HyperviewLayoutHierarchical implements HyperViewLayout { elems[centerElement] = elems[0]; elems[0] = swap; } - } /** @@ -108,9 +105,8 @@ export class HyperviewLayoutHierarchical implements HyperViewLayout { const finalSize = this.getSumSizeOfElements(this.elements); return { - size: finalSize + size: finalSize, }; - } /** @@ -120,14 +116,17 @@ export class HyperviewLayoutHierarchical implements HyperViewLayout { return new ConnectorProvider(true /* hierarchical layout */); } - private layoutTopShapes(sCenter: Size, elems: { [id: string]: HvCell; }): Size { + private layoutTopShapes(sCenter: Size, elems: { [id: string]: HvCell }): Size { // layout top left shapes sCenter = this.getMaxSize(elems['MiddleCenter'].size, elems['TopCenter'].size.width, elems['MiddleLeft'].size.height); this.layoutElements(elems['TopLeft'], sCenter, -2, -1, false, false); // layout top center shapes - sCenter = this.getMaxSize(elems['MiddleCenter'].size, elems['TopCenter'].size.width, - Math.max(elems['MiddleLeft'].size.height, elems['MiddleRight'].size.height)); + sCenter = this.getMaxSize( + elems['MiddleCenter'].size, + elems['TopCenter'].size.width, + Math.max(elems['MiddleLeft'].size.height, elems['MiddleRight'].size.height), + ); this.layoutElements(elems['TopCenter'], sCenter, 0, -1, true, false); // layout top right shapes @@ -136,14 +135,17 @@ export class HyperviewLayoutHierarchical implements HyperViewLayout { return sCenter; } - private layoutBottomShapes(sCenter: Size, elems: { [id: string]: HvCell; }): Size { + private layoutBottomShapes(sCenter: Size, elems: { [id: string]: HvCell }): Size { // layout bottom left shapes sCenter = this.getMaxSize(elems['MiddleCenter'].size, elems['BottomCenter'].size.width, elems['MiddleLeft'].size.height); this.layoutElements(elems['BottomLeft'], sCenter, -2, 1, false, false); // layout bottom center shapes - sCenter = this.getMaxSize(elems['MiddleCenter'].size, elems['BottomCenter'].size.width, - Math.max(elems['MiddleLeft'].size.height, elems['MiddleRight'].size.height)); + sCenter = this.getMaxSize( + elems['MiddleCenter'].size, + elems['BottomCenter'].size.width, + Math.max(elems['MiddleLeft'].size.height, elems['MiddleRight'].size.height), + ); this.layoutElements(elems['BottomCenter'], sCenter, 0, 1, true, false); // layout bottom right shapes @@ -152,7 +154,7 @@ export class HyperviewLayoutHierarchical implements HyperViewLayout { return sCenter; } - private layoutMiddleShapes(sCenter: Size, elems: { [id: string]: HvCell; }): Size { + private layoutMiddleShapes(sCenter: Size, elems: { [id: string]: HvCell }): Size { // layout middle left shapes sCenter = this.getMaxSize(elems['MiddleCenter'].size, 0, elems['MiddleLeft'].size.height); this.layoutElements(elems['MiddleLeft'], sCenter, -1, 0, false, true); @@ -168,7 +170,7 @@ export class HyperviewLayoutHierarchical implements HyperViewLayout { private clearVLayoutElements(): void { this.vLayoutElements = {}; - this.positions.forEach(p => { + this.positions.forEach((p) => { this.vLayoutElements[p] = { elements: [], size: { width: 0, height: 0 } }; }); } @@ -177,7 +179,6 @@ export class HyperviewLayoutHierarchical implements HyperViewLayout { * Normalizes the view by moving all components into the visible area. */ private normalize(): void { - // the control should now be placed in the edge const clientcenter = { X: 0, Y: 0 }; @@ -195,15 +196,15 @@ export class HyperviewLayoutHierarchical implements HyperViewLayout { miny = -miny; minx = Math.max(minx, clientcenter.X); - miny = Math.max(miny, clientcenter.Y * 3 / 5); + miny = Math.max(miny, (clientcenter.Y * 3) / 5); // move elements this.elements.forEach((node, index) => { const oldLeft = node.element.style.left; const oldTop = node.element.style.top; - const left = toPixelString((node.element.offsetLeft + minx)); - const top = toPixelString((node.element.offsetTop + miny)); + const left = toPixelString(node.element.offsetLeft + minx); + const top = toPixelString(node.element.offsetTop + miny); node.element.style.left = left; node.element.style.top = top; @@ -230,7 +231,7 @@ export class HyperviewLayoutHierarchical implements HyperViewLayout { * @param bY taken from the class */ private layoutElements(regElements: HvCell, centerSize: Size, dx: number, dy: number, bX: boolean, bY: boolean): void { - const padding = 50; + const padding = 20; const regSize = regElements.size; let cX = 0; let cY = 0; @@ -260,8 +261,8 @@ export class HyperviewLayoutHierarchical implements HyperViewLayout { cY -= regElement.element.offsetHeight + padding; } - regElement.element.style.left = toPixelString((cX - (bX ? regSize.width / 2 : 0))); - regElement.element.style.top = toPixelString((cY - (bY ? regSize.height / 2 : 0))); + regElement.element.style.left = toPixelString(cX - (bX ? regSize.width / 2 : 0)); + regElement.element.style.top = toPixelString(cY - (bY ? regSize.height / 2 : 0)); // AutoReset in Outer regions if (Math.abs(dx) > 1) { @@ -274,12 +275,14 @@ export class HyperviewLayoutHierarchical implements HyperViewLayout { cY = regElement.element.offsetTop; } + // translate the following shapes by this shape's width if (dx > 0) { - cX += regSize.width + padding; + cX += regElement.element.offsetWidth + padding; } + // translate the following shapes by this shape's height if (dy > 0) { - cY += regSize.height + padding; + cY += regElement.element.offsetHeight + padding; } } } @@ -290,14 +293,14 @@ export class HyperviewLayoutHierarchical implements HyperViewLayout { private getMaxSizeOfElements(vElements: HvElement[]): Size { let layoutSize: Size = { width: 0, - height: 0 + height: 0, }; for (const node of vElements) { const shape = node.element; layoutSize = { width: Math.max(layoutSize.width, shape.offsetWidth), - height: Math.max(layoutSize.height, shape.offsetHeight) + height: Math.max(layoutSize.height, shape.offsetHeight), }; } @@ -307,14 +310,14 @@ export class HyperviewLayoutHierarchical implements HyperViewLayout { private getSumSizeOfElements(vElements: HvElement[]): Size { let layoutSize: Size = { width: 0, - height: 0 + height: 0, }; for (const node of vElements) { const shape = node.element; layoutSize = { width: Math.max(layoutSize.width, shape.offsetLeft + shape.offsetWidth), - height: Math.max(layoutSize.height, shape.offsetTop + shape.offsetHeight) + height: Math.max(layoutSize.height, shape.offsetTop + shape.offsetHeight), }; } diff --git a/imxweb/projects/qbm/src/lib/hyperview/hyperview-layout-horizontal.spec.ts b/imxweb/projects/qbm/src/lib/hyperview/hyperview-layout-horizontal.spec.ts index 005ca79a6..02b58504e 100644 --- a/imxweb/projects/qbm/src/lib/hyperview/hyperview-layout-horizontal.spec.ts +++ b/imxweb/projects/qbm/src/lib/hyperview/hyperview-layout-horizontal.spec.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -28,7 +28,6 @@ import { HyperviewLayoutHorizontal } from './hyperview-layout-horizontal'; import { clearStylesFromDOM } from '../testing/clear-styles.spec'; describe('HyperviewLayoutHorizontal', () => { - const htmlElement = document.createElement('div'); afterAll(() => { @@ -39,8 +38,8 @@ describe('HyperviewLayoutHorizontal', () => { const elements = []; const middlecenter = { position: 'MiddleCenter', - element: htmlElement - } + element: htmlElement, + }; elements.push(middlecenter); expect(() => { diff --git a/imxweb/projects/qbm/src/lib/hyperview/hyperview-layout-horizontal.ts b/imxweb/projects/qbm/src/lib/hyperview/hyperview-layout-horizontal.ts index ccd5de94b..c0181aa90 100644 --- a/imxweb/projects/qbm/src/lib/hyperview/hyperview-layout-horizontal.ts +++ b/imxweb/projects/qbm/src/lib/hyperview/hyperview-layout-horizontal.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -24,14 +24,13 @@ * */ -import { IConnectorProvider, ConnectorProvider } from './connector-provider'; +import { ConnectorProvider, IConnectorProvider } from './connector-provider'; import { HvElement, HyperViewLayout, LayoutResult, toPixelString } from './hyperview-types'; /** * Hyperview layouter that arranges the elements in a horizontal line. */ export class HyperviewLayoutHorizontal implements HyperViewLayout { - private elements: HvElement[]; constructor(elements: HvElement[]) { @@ -55,7 +54,7 @@ export class HyperviewLayoutHorizontal implements HyperViewLayout { if (index > 0) { const previousElement = es[index - 1].element; - element.style.left = toPixelString((previousElement.offsetLeft + previousElement.offsetWidth + 10)); + element.style.left = toPixelString(previousElement.offsetLeft + previousElement.offsetWidth + 10); element.style.zIndex = '100'; } }); @@ -63,15 +62,16 @@ export class HyperviewLayoutHorizontal implements HyperViewLayout { // calculate the maximum height const maxw = this.getMaxHeight(); - firstElement.style.top = toPixelString(((maxw - firstElement.offsetHeight) / 2)); + firstElement.style.top = toPixelString((maxw - firstElement.offsetHeight) / 2); es.slice(1).forEach((node) => { const element = node.element; - element.style.top = toPixelString(((maxw - element.offsetHeight) / 2)); + element.style.top = toPixelString((maxw - element.offsetHeight) / 2); }); return { size: { width: 0, height: maxw } }; } + return { size: { width: 0, height: 0 } }; } /** diff --git a/imxweb/projects/qbm/src/lib/hyperview/hyperview-layout-vertical.spec.ts b/imxweb/projects/qbm/src/lib/hyperview/hyperview-layout-vertical.spec.ts index 145531e72..539e1404e 100644 --- a/imxweb/projects/qbm/src/lib/hyperview/hyperview-layout-vertical.spec.ts +++ b/imxweb/projects/qbm/src/lib/hyperview/hyperview-layout-vertical.spec.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -24,12 +24,10 @@ * */ - import { HyperviewLayoutVertical } from './hyperview-layout-vertical'; import { clearStylesFromDOM } from '../testing/clear-styles.spec'; describe('HyperviewLayoutVertical', () => { - afterAll(() => { clearStylesFromDOM(); }); @@ -40,8 +38,8 @@ describe('HyperviewLayoutVertical', () => { const elements = []; const middlecenter = { position: 'MiddleCenter', - element: htmlElement - } + element: htmlElement, + }; elements.push(middlecenter); expect(() => { @@ -62,4 +60,3 @@ describe('HyperviewLayoutVertical', () => { }).not.toThrowError(); }); }); - diff --git a/imxweb/projects/qbm/src/lib/hyperview/hyperview-layout-vertical.ts b/imxweb/projects/qbm/src/lib/hyperview/hyperview-layout-vertical.ts index 700cd681f..c0510739e 100644 --- a/imxweb/projects/qbm/src/lib/hyperview/hyperview-layout-vertical.ts +++ b/imxweb/projects/qbm/src/lib/hyperview/hyperview-layout-vertical.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -24,14 +24,13 @@ * */ -import { HyperViewLayout, toPixelString, HvElement, LayoutResult } from './hyperview-types'; -import { IConnectorProvider, ConnectorProvider } from './connector-provider'; +import { ConnectorProvider, IConnectorProvider } from './connector-provider'; +import { HvElement, HyperViewLayout, LayoutResult, toPixelString } from './hyperview-types'; /** * Layouter that aligns the elements vertically, with the root node at the top. */ export class HyperviewLayoutVertical implements HyperViewLayout { - private elements: HvElement[]; constructor(elements: HvElement[]) { @@ -44,19 +43,16 @@ export class HyperviewLayoutVertical implements HyperViewLayout { public layout(): LayoutResult { const es = this.elements; if (es.length > 0) { - // get the maximum width const maxw = this.getMaxWidth(); es.forEach((node, index) => { const element = node.element; element.style.position = 'absolute'; - element.style.left = toPixelString(((maxw - element.offsetWidth) / 2)); + element.style.left = toPixelString((maxw - element.offsetWidth) / 2); if (index > 0) { const previousElement = es[index - 1].element; - element.style.top = toPixelString((previousElement.offsetTop + - previousElement.offsetHeight + - 10)); + element.style.top = toPixelString(previousElement.offsetTop + previousElement.offsetHeight + 10); } else { element.style.top = '0px'; } @@ -64,6 +60,7 @@ export class HyperviewLayoutVertical implements HyperViewLayout { return { size: { width: maxw, height: 0 } }; } + return { size: { width: 0, height: 0 } }; } /** diff --git a/imxweb/projects/qbm/src/lib/hyperview/hyperview-types.ts b/imxweb/projects/qbm/src/lib/hyperview/hyperview-types.ts index f4f136e8d..f59b70f32 100644 --- a/imxweb/projects/qbm/src/lib/hyperview/hyperview-types.ts +++ b/imxweb/projects/qbm/src/lib/hyperview/hyperview-types.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR diff --git a/imxweb/projects/qbm/src/lib/hyperview/hyperview.component.html b/imxweb/projects/qbm/src/lib/hyperview/hyperview.component.html index e7c3d3db8..64cc94bdb 100644 --- a/imxweb/projects/qbm/src/lib/hyperview/hyperview.component.html +++ b/imxweb/projects/qbm/src/lib/hyperview/hyperview.component.html @@ -1,4 +1,12 @@ -
    +
    1. - - + + + +
    2. @@ -26,34 +41,31 @@
      diff --git a/imxweb/projects/qbm/src/lib/hyperview/hyperview.component.scss b/imxweb/projects/qbm/src/lib/hyperview/hyperview.component.scss index c0aa4469f..21dc4ea6a 100644 --- a/imxweb/projects/qbm/src/lib/hyperview/hyperview.component.scss +++ b/imxweb/projects/qbm/src/lib/hyperview/hyperview.component.scss @@ -12,9 +12,9 @@ height: calc(100% - 74px); overflow: hidden; position: relative; - transform-origin: center center; margin: 5px; - .imx-hyperview-container{ + transform-origin: center center; + .imx-hyperview-container { position: absolute; transform-origin: top left; > ol { @@ -90,12 +90,11 @@ path { stroke-linejoin: miter; stroke-miterlimit: 4; stroke-linecap: butt; - opacity: 1.0; + opacity: 1; } //theming -:host{ - +:host { .imx-hyperview > ol { background-color: $color-gray-80; } @@ -125,11 +124,10 @@ path { } } - .eui-dark-theme { - :host{ + :host { .connector { - stroke: $color-gray-30 + stroke: $color-gray-30; } .imx-hyperview > ol { @@ -140,9 +138,6 @@ path { .hyperviewelement:hover { box-shadow: 0 0 5px 3px rgba($color: $color-gray-0, $alpha: 0.7); } - button{ - background: $color-gray-70; - } .imx-hyperview-toolbar { background-color: $color-gray-70; } @@ -150,9 +145,9 @@ path { } .eui-contrast-theme { - :host{ + :host { .connector { - stroke: $color-gray-10 + stroke: $color-gray-10; } .imx-hyperview > ol { diff --git a/imxweb/projects/qbm/src/lib/hyperview/hyperview.component.ts b/imxweb/projects/qbm/src/lib/hyperview/hyperview.component.ts index 9fd8bb173..994af36f3 100644 --- a/imxweb/projects/qbm/src/lib/hyperview/hyperview.component.ts +++ b/imxweb/projects/qbm/src/lib/hyperview/hyperview.component.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -25,39 +25,39 @@ */ import { + AfterViewChecked, + AfterViewInit, + ChangeDetectorRef, Component, - ViewChild, ElementRef, - Input, - ChangeDetectorRef, EventEmitter, - Renderer2, - AfterViewInit, + Input, OnDestroy, - AfterViewChecked, + Output, QueryList, + Renderer2, + ViewChild, ViewChildren, - Output, } from '@angular/core'; -import { Connectors } from './connectors'; +import { ShapeData } from '@imx-modules/imx-api-qbm'; +import { Subscription } from 'rxjs'; +import { ClassloggerService } from '../classlogger/classlogger.service'; import { Connector } from './connector'; +import { Connectors } from './connectors'; import { HyperviewLayoutHierarchical } from './hyperview-layout-hierarchical'; -import { HyperviewLayoutVertical } from './hyperview-layout-vertical'; import { HyperviewLayoutHorizontal } from './hyperview-layout-horizontal'; +import { HyperviewLayoutVertical } from './hyperview-layout-vertical'; import { - HyperViewLayout, - HvSettings, HvElement, - ShapeClickArgs, - toPixelString, - LayoutResult, + HvSettings, + HyperViewLayout, HyperViewNavigation, HyperViewNavigationEnum, + LayoutResult, + ShapeClickArgs, + toPixelString, } from './hyperview-types'; -import { ShapeData } from 'imx-api-qbm'; -import { ClassloggerService } from '../classlogger/classlogger.service'; -import { Subscription } from 'rxjs'; export enum ShapeType { ListShape, @@ -115,11 +115,14 @@ export class HyperviewComponent implements AfterViewInit, OnDestroy, AfterViewCh /** * Creates a new hyperview component. */ - constructor(private changeDetectorRef: ChangeDetectorRef, private logger: ClassloggerService, private renderer: Renderer2) {} + constructor( + private changeDetectorRef: ChangeDetectorRef, + private logger: ClassloggerService, + private renderer: Renderer2, + ) {} ngAfterViewInit(): void { this.setupLayout(); - // register for element resize const observer = new ResizeObserver(() => { this.logger.trace(this, 'resize event detected, marking layout as dirty'); @@ -133,7 +136,7 @@ export class HyperviewComponent implements AfterViewInit, OnDestroy, AfterViewCh this.shapeList.changes.subscribe(() => { this.logger.trace(this, 'shape list changed, marking layout as dirty'); this.layoutDirty = true; - }) + }), ); } @@ -188,7 +191,7 @@ export class HyperviewComponent implements AfterViewInit, OnDestroy, AfterViewCh const layouter = this.buildLayouter(); const layoutResult = layouter.layout(); this.connectors = new Connectors(layouter.getConnectorProvider().getConnectors(this.settings)).connectorList.filter( - (connector) => !connector.isHidden + (connector) => !connector.isHidden, ); this.scrollToMiddleCenterShape(layoutResult); this.changeDetectorRef.detectChanges(); @@ -221,7 +224,7 @@ export class HyperviewComponent implements AfterViewInit, OnDestroy, AfterViewCh public get selectedHyperviewCaption(): string { const centerObj = this.shapes.filter((shape) => shape.LayoutType === 'MiddleCenter')?.[0]; - return !!centerObj?.HeaderText ? `${centerObj.HeaderText}: ${centerObj.Caption}` : centerObj?.Caption; + return !!centerObj?.HeaderText ? `${centerObj.HeaderText}: ${centerObj.Caption}` : centerObj?.Caption ?? ''; } private scrollToMiddleCenterShape(layoutResult: LayoutResult) { @@ -279,7 +282,9 @@ export class HyperviewComponent implements AfterViewInit, OnDestroy, AfterViewCh this.middleCenterShape = { position: this.middleCenterPosition, element }; res.push(this.middleCenterShape); } else { - res.push({ position, element }); + if (position) { + res.push({ position, element }); + } } } diff --git a/imxweb/projects/qbm/src/lib/hyperview/hyperview.module.ts b/imxweb/projects/qbm/src/lib/hyperview/hyperview.module.ts index 4087b0d08..06a37a6f3 100644 --- a/imxweb/projects/qbm/src/lib/hyperview/hyperview.module.ts +++ b/imxweb/projects/qbm/src/lib/hyperview/hyperview.module.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -28,7 +28,7 @@ import { NgModule } from '@angular/core'; import { CommonModule } from '@angular/common'; import { MatBadgeModule } from '@angular/material/badge'; import { MatTooltipModule } from '@angular/material/tooltip'; -import { EuiCoreModule } from '@elemental-ui/core'; +import { EuiCoreModule, EuiMaterialModule } from '@elemental-ui/core'; import { HyperviewComponent } from './hyperview.component'; import { PropertyShapeComponent } from './propertyshape.component'; @@ -36,29 +36,12 @@ import { ListShapeComponent } from './listshape.component'; import { SimpleShapeComponent } from './simpleshape.component'; import { ShapeComponent } from './shape.component'; import { ZoomPanDirective } from './zoom-pan.directive'; -import { MatIconModule } from '@angular/material/icon'; import { TranslateModule } from '@ngx-translate/core'; import { MatButtonModule } from '@angular/material/button'; @NgModule({ - declarations: [ - HyperviewComponent, - PropertyShapeComponent, - ListShapeComponent, - SimpleShapeComponent, - ShapeComponent, - ZoomPanDirective - ], - imports: [ - CommonModule, - EuiCoreModule, - MatTooltipModule, - MatBadgeModule, - TranslateModule, - MatButtonModule, - ], - exports: [ - HyperviewComponent - ], + declarations: [HyperviewComponent, PropertyShapeComponent, ListShapeComponent, SimpleShapeComponent, ShapeComponent, ZoomPanDirective], + imports: [CommonModule, EuiCoreModule, EuiMaterialModule, MatTooltipModule, MatBadgeModule, TranslateModule, MatButtonModule], + exports: [HyperviewComponent], }) export class HyperViewModule { } diff --git a/imxweb/projects/qbm/src/lib/hyperview/listshape.component.scss b/imxweb/projects/qbm/src/lib/hyperview/listshape.component.scss index d91472870..a8f19e825 100644 --- a/imxweb/projects/qbm/src/lib/hyperview/listshape.component.scss +++ b/imxweb/projects/qbm/src/lib/hyperview/listshape.component.scss @@ -14,7 +14,8 @@ a { padding-left: 1em; } -a:hover, a:focus { +a:hover, +a:focus { text-decoration: none; cursor: pointer; } @@ -22,11 +23,17 @@ a:hover, a:focus { // Theming li { - > a,a:active,a:focus,a:hover,a:link,visited { + > a, + a:active, + a:focus, + a:hover, + a:link, + visited { color: $color-gray-0; } } -a:hover, a:focus { +a:hover, +a:focus { background-color: rgba($color: $color-gray-100, $alpha: 0.2); } diff --git a/imxweb/projects/qbm/src/lib/hyperview/listshape.component.ts b/imxweb/projects/qbm/src/lib/hyperview/listshape.component.ts index 87dc77809..b09f63ad1 100644 --- a/imxweb/projects/qbm/src/lib/hyperview/listshape.component.ts +++ b/imxweb/projects/qbm/src/lib/hyperview/listshape.component.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -26,7 +26,7 @@ import { Component, EventEmitter, Input, Output } from '@angular/core'; -import { ShapeData, ShapeListEntry } from 'imx-api-qbm'; +import { ShapeData, ShapeListEntry } from '@imx-modules/imx-api-qbm'; import { ShapeClickArgs } from './hyperview-types'; /** @@ -39,6 +39,7 @@ import { ShapeClickArgs } from './hyperview-types'; }) export class ListShapeComponent { @Input() public shape: ShapeData; + @Input() public selected: EventEmitter = new EventEmitter(); @Output() public changeShapeSize = new EventEmitter(); @@ -51,7 +52,7 @@ export class ListShapeComponent { */ public click(elem: ShapeListEntry): void { if (this.isLinkEnabled(elem)) { - this.selected.emit({ objectKey: elem.ObjectKey, caption: this.shape.Caption }); + this.selected.emit({ objectKey: elem.ObjectKey ?? '', caption: this.shape.Caption ?? '' }); } } diff --git a/imxweb/projects/qbm/src/lib/hyperview/propertyshape.component.html b/imxweb/projects/qbm/src/lib/hyperview/propertyshape.component.html index 8ce8b553a..4e1c161af 100644 --- a/imxweb/projects/qbm/src/lib/hyperview/propertyshape.component.html +++ b/imxweb/projects/qbm/src/lib/hyperview/propertyshape.component.html @@ -1,7 +1,15 @@
      -
      +
      {{ property.Property }}
      diff --git a/imxweb/projects/qbm/src/lib/hyperview/propertyshape.component.scss b/imxweb/projects/qbm/src/lib/hyperview/propertyshape.component.scss index 4e54925b8..92433e221 100644 --- a/imxweb/projects/qbm/src/lib/hyperview/propertyshape.component.scss +++ b/imxweb/projects/qbm/src/lib/hyperview/propertyshape.component.scss @@ -1,4 +1,5 @@ -@import "variables.scss"; +@import 'base/variables'; +@import '@elemental-ui/core/src/styles/_eui_palette.scss'; table.LayoutpPropItems { cursor: pointer; @@ -7,17 +8,17 @@ table.LayoutpPropItems { .LayoutpPropRow { display: flex; - min-height: $propcellminheight; + min-height: $IMX_PropCell_MinHeight; } .LayoutpPropCol { - min-height: $propcellminheight; + min-height: $IMX_PropCell_MinHeight; padding: 2px 4px 3px 0; vertical-align: top; } .LayoutpPropCol:nth-child(1) { - width: $propertylabelwidth; + width: $IMX_PropertyLabel_Width; } .LayoutpPropCol0 { @@ -42,7 +43,15 @@ table.LayoutpPropItems { display: table-cell; } +.imx-hyperview-link { + &:focus, + &:hover { + cursor: pointer; + background-color: rgba($color: $color-gray-100, $alpha: 0.2); + } +} + .endsSection { border-bottom: solid 1px lightgray; - margin-bottom: .5em; -} \ No newline at end of file + margin-bottom: 0.5em; +} diff --git a/imxweb/projects/qbm/src/lib/hyperview/propertyshape.component.ts b/imxweb/projects/qbm/src/lib/hyperview/propertyshape.component.ts index ccbb59c85..4f17ea55f 100644 --- a/imxweb/projects/qbm/src/lib/hyperview/propertyshape.component.ts +++ b/imxweb/projects/qbm/src/lib/hyperview/propertyshape.component.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -24,11 +24,11 @@ * */ -import { Component, Input, EventEmitter } from '@angular/core'; +import { Component, EventEmitter, Input } from '@angular/core'; -import { ShapeData } from 'imx-api-qbm'; +import { ShapeData, ShapeProperty } from '@imx-modules/imx-api-qbm'; +import { EntityColumnData } from '@imx-modules/imx-qbm-dbts'; import { ShapeClickArgs } from './hyperview-types'; -import { EntityColumnData } from 'imx-qbm-dbts'; /** * A shape component that lists all {@link ShapeProperties|properties} of an object. @@ -43,7 +43,21 @@ export class PropertyShapeComponent { @Input() public selected: EventEmitter = new EventEmitter(); - public GetPropertyDisplayValue(property: EntityColumnData): string { - return property.DisplayValue != null ? property.DisplayValue : property.Value; + public GetPropertyDisplayValue(property: EntityColumnData | undefined): string { + return property?.DisplayValue != null ? property.DisplayValue : property?.Value ?? ''; + } + + /** + * Emit selection event for this {@link ShapeProperty|element}. + * @param shape the element the user clicked + */ + public onClick(shape: ShapeProperty): void { + if (this.isLinkEnabled() && !!shape.ObjectKey) { + this.selected.emit({ objectKey: shape.ObjectKey, caption: this.GetPropertyDisplayValue(shape.Value) }); + } + } + + public isLinkEnabled(): boolean { + return this.selected.observers.length > 0; } } diff --git a/imxweb/projects/qbm/src/lib/hyperview/shape.component.html b/imxweb/projects/qbm/src/lib/hyperview/shape.component.html index c8379ec0e..f3a5df149 100644 --- a/imxweb/projects/qbm/src/lib/hyperview/shape.component.html +++ b/imxweb/projects/qbm/src/lib/hyperview/shape.component.html @@ -1,11 +1,21 @@
      -

      +

      {{ shape.HeaderText }}
      -
      {{ shape.Caption }}
      -

      -
      +
      + {{ shape.Caption }} + ({{ ObjectCount }}) +
      +

    + -
    +
    diff --git a/imxweb/projects/qbm/src/lib/hyperview/shape.component.scss b/imxweb/projects/qbm/src/lib/hyperview/shape.component.scss index 522141435..c260ce63e 100644 --- a/imxweb/projects/qbm/src/lib/hyperview/shape.component.scss +++ b/imxweb/projects/qbm/src/lib/hyperview/shape.component.scss @@ -13,17 +13,16 @@ min-height: 32px; min-width: 32px; filter: grayscale(1) brightness(2); - -webkit-filter: grayscale(1) brightness(2); } .imx-shape-header-info { overflow: hidden; margin-right: 30px; - width:100%; + width: 100%; } .imx-hyperview-shape-content { - max-height: 300px; + max-height: 250px; overflow-x: hidden; overflow-y: auto; } @@ -31,11 +30,9 @@ .imx-hyperview-caption { text-overflow: ellipsis; overflow: hidden; - white-space: nowrap; font-weight: bold; - font-size: 14px; - text-align: left; - &--link{ + font-size: 16px; + &--link { cursor: pointer; } } @@ -49,9 +46,14 @@ font-weight: 400; } -// Theming +.objectcount { + font-style: italic; +} + +// theming -.imx-hyperview-caption--link:hover, .imx-hyperview-caption--link:focus { +.imx-hyperview-caption--link:hover, +.imx-hyperview-caption--link:focus { background-color: rgba($color: $color-gray-100, $alpha: 0.2); } diff --git a/imxweb/projects/qbm/src/lib/hyperview/shape.component.ts b/imxweb/projects/qbm/src/lib/hyperview/shape.component.ts index 85aefeb8e..271e41b9d 100644 --- a/imxweb/projects/qbm/src/lib/hyperview/shape.component.ts +++ b/imxweb/projects/qbm/src/lib/hyperview/shape.component.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -24,9 +24,9 @@ * */ -import { Component, EventEmitter, Input, OnInit } from '@angular/core'; +import { Component, EventEmitter, Input, OnInit, Output } from '@angular/core'; -import { ShapeData } from 'imx-api-qbm'; +import { ShapeData } from '@imx-modules/imx-api-qbm'; import { ModelCssService } from '../model-css/model-css.service'; import { TableImageService } from '../table-image/table-image.service'; import { ShapeClickArgs } from './hyperview-types'; @@ -41,11 +41,16 @@ import { ShapeClickArgs } from './hyperview-types'; }) export class ShapeComponent implements OnInit { @Input() public shape: ShapeData; - @Input() public navigate = false; @Input() public selected: EventEmitter = new EventEmitter(); + @Input() public navigate = false; + @Output() public changeContentSize = new EventEmitter(); public imageClass: string; + public isExpanded = false; - constructor(private readonly imageService: TableImageService, private readonly modelCssService: ModelCssService) {} + constructor( + private readonly imageService: TableImageService, + private readonly modelCssService: ModelCssService, + ) {} public ngOnInit(): void { this.modelCssService.loadModelCss(); @@ -53,9 +58,14 @@ export class ShapeComponent implements OnInit { this.imageClass = this.shape.ImageUid ? this.imageService.getCss(this.shape.ImageUid, true) : this.imageService.getDefaultCss(true); } + public setExpandable(): void { + this.isExpanded = !this.isExpanded; + this.changeContentSize.emit(); + } + public click(): void { - if (this.navigate && !this.isShapeLayoutMiddle) { - this.selected?.emit({ objectKey: this.shape.ObjectKey, caption: this.shape.Caption }); + if (this.navigate && !this.isShapeLayoutMiddle && this.shape.ObjectKey) { + this.selected?.emit({ objectKey: this.shape.ObjectKey ?? '', caption: this.shape.Caption ?? '' }); } } @@ -63,6 +73,14 @@ export class ShapeComponent implements OnInit { return this.shape && this.shape.Elements ? this.shape.Elements.length : -1; } + public get canExpand() { + return this.ObjectCount > 10; // windows implementation also uses > 10 as threshold + } + public get showContent() { + if (!this.canExpand) return true; + return this.isExpanded; + } + public get isShapeLayoutMiddle(): boolean { return this.shape?.LayoutType === 'MiddleCenter'; } diff --git a/imxweb/projects/qbm/src/lib/hyperview/simpleshape.component.html b/imxweb/projects/qbm/src/lib/hyperview/simpleshape.component.html index 536487341..389aa4a00 100644 --- a/imxweb/projects/qbm/src/lib/hyperview/simpleshape.component.html +++ b/imxweb/projects/qbm/src/lib/hyperview/simpleshape.component.html @@ -1,3 +1,3 @@ -
    {{shape.Description}}
    -
    \ No newline at end of file +
    {{ shape.Description }}
    + diff --git a/imxweb/projects/qbm/src/lib/hyperview/simpleshape.component.ts b/imxweb/projects/qbm/src/lib/hyperview/simpleshape.component.ts index 5aa3190c4..fc6d41d23 100644 --- a/imxweb/projects/qbm/src/lib/hyperview/simpleshape.component.ts +++ b/imxweb/projects/qbm/src/lib/hyperview/simpleshape.component.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -26,14 +26,14 @@ import { Component, Input } from '@angular/core'; -import { ShapeData } from 'imx-api-qbm'; +import { ShapeData } from '@imx-modules/imx-api-qbm'; /** * A shape component that only display the description of an {@link ShapeData|shape}. */ @Component({ selector: 'imx-hyperview-simpleshape', - templateUrl: './simpleshape.component.html' + templateUrl: './simpleshape.component.html', }) export class SimpleShapeComponent { @Input() public shape: ShapeData; diff --git a/imxweb/projects/qbm/src/lib/hyperview/zoom-pan.directive.ts b/imxweb/projects/qbm/src/lib/hyperview/zoom-pan.directive.ts index 09dd22bbb..30dc1d23c 100644 --- a/imxweb/projects/qbm/src/lib/hyperview/zoom-pan.directive.ts +++ b/imxweb/projects/qbm/src/lib/hyperview/zoom-pan.directive.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -36,7 +36,10 @@ export class ZoomPanDirective { private relativePosition = { x: 0, y: 0 }; //mousemove should work only after the element is clicked private mouseDown = false; - constructor(private elementRef: ElementRef, private renderer: Renderer2) {} + constructor( + private elementRef: ElementRef, + private renderer: Renderer2, + ) {} @HostListener('wheel', ['$event']) private scaling(event: WheelEvent) { diff --git a/imxweb/projects/qbm/src/lib/icon-stack/icon-stack.component.html b/imxweb/projects/qbm/src/lib/icon-stack/icon-stack.component.html index ab894daf6..0a8dd8985 100644 --- a/imxweb/projects/qbm/src/lib/icon-stack/icon-stack.component.html +++ b/imxweb/projects/qbm/src/lib/icon-stack/icon-stack.component.html @@ -3,4 +3,4 @@
    -{{ text }} \ No newline at end of file +{{ text }} diff --git a/imxweb/projects/qbm/src/lib/icon-stack/icon-stack.component.scss b/imxweb/projects/qbm/src/lib/icon-stack/icon-stack.component.scss index 826946135..e8b95dcdd 100644 --- a/imxweb/projects/qbm/src/lib/icon-stack/icon-stack.component.scss +++ b/imxweb/projects/qbm/src/lib/icon-stack/icon-stack.component.scss @@ -1,5 +1,4 @@ -@import "variables.scss"; - +@import '@elemental-ui/core/src/styles/_eui_palette.scss'; :host { display: flex; @@ -45,13 +44,13 @@ } .imx-iconStack eui-icon { - color: $black-6; + color: $color-gray-60; } .imx-ellipse { height: 13px; width: 90px; - background-color: $Imx_Ellipse_Gray; + background-color: $color-gray-10; border-radius: 50%; display: inline-block; } @@ -59,7 +58,7 @@ .imx-iconStack-text { width: 100%; font-size: 16px; - color: $black-6; + color: $color-gray-60; line-height: 4em; } } diff --git a/imxweb/projects/qbm/src/lib/icon-stack/icon-stack.component.ts b/imxweb/projects/qbm/src/lib/icon-stack/icon-stack.component.ts index 11bc8656a..3987d49ac 100644 --- a/imxweb/projects/qbm/src/lib/icon-stack/icon-stack.component.ts +++ b/imxweb/projects/qbm/src/lib/icon-stack/icon-stack.component.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -29,12 +29,10 @@ import { Component, Input } from '@angular/core'; @Component({ selector: 'imx-icon-stack', templateUrl: './icon-stack.component.html', - styleUrls: ['./icon-stack.component.scss'] + styleUrls: ['./icon-stack.component.scss'], }) -export class IconStackComponent { - +export class IconStackComponent { @Input() public icon1: string; @Input() public icon2: string; @Input() public text: string; - } diff --git a/imxweb/projects/qbm/src/lib/image/image-select/image-select.component.html b/imxweb/projects/qbm/src/lib/image/image-select/image-select.component.html index ba7290d2e..f4e07626f 100644 --- a/imxweb/projects/qbm/src/lib/image/image-select/image-select.component.html +++ b/imxweb/projects/qbm/src/lib/image/image-select/image-select.component.html @@ -1,33 +1,54 @@ - - {{ valueWrapper?.display | translate }} -
    - - -
    -
    - -
    - - -
    - - - + + {{ valueWrapper?.display ?? '' | translate }} + + +
    +
    + +
    + +
    + + +
    - {{ fileFormatHint || valueWrapper?.hint | translate }} + {{ (fileFormatHint || valueWrapper?.hint) ?? '' | translate }} {{ '#LDS#This field is mandatory.' | translate }} diff --git a/imxweb/projects/qbm/src/lib/image/image-select/image-select.component.scss b/imxweb/projects/qbm/src/lib/image/image-select/image-select.component.scss index 6f7e8cd45..c48c251b6 100644 --- a/imxweb/projects/qbm/src/lib/image/image-select/image-select.component.scss +++ b/imxweb/projects/qbm/src/lib/image/image-select/image-select.component.scss @@ -1,43 +1,3 @@ -:host { - ::ng-deep .mat-form-field-appearance-outline .mat-form-field-infix { - padding: 0; - margin-bottom: 10px; - } - - ::ng-deep .mat-form-field-infix input.mat-input-element { - margin-top: 0px; - } -} - -.mat-form-field { - width: 100%; -} - -.imx-form-input-container { - display: flex; - margin-top: 5px; - justify-content: space-between; - - .imx-suffix-container { - display: flex; - flex-direction: row; - } -} - -.imx-button-add { - margin-top: -5px; -} - -.imx-buttons-change-remove { - display: flex; - flex-direction: column; - margin-bottom: 10px; - - > * :not(:last-child) { - margin-bottom: 5px; - } -} - img { max-width: 200px; } diff --git a/imxweb/projects/qbm/src/lib/image/image-select/image-select.component.ts b/imxweb/projects/qbm/src/lib/image/image-select/image-select.component.ts index 71c39eed9..98db81192 100644 --- a/imxweb/projects/qbm/src/lib/image/image-select/image-select.component.ts +++ b/imxweb/projects/qbm/src/lib/image/image-select/image-select.component.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -25,7 +25,7 @@ */ import { Component, EventEmitter, Input, Output } from '@angular/core'; -import { AbstractControl, FormControl } from '@angular/forms'; +import { FormControl } from '@angular/forms'; import { Base64ImageService } from '../../images/base64-image.service'; import { ValueWrapper } from '../../value-wrapper/value-wrapper'; @@ -33,11 +33,11 @@ import { ValueWrapper } from '../../value-wrapper/value-wrapper'; @Component({ selector: 'imx-image-select', templateUrl: './image-select.component.html', - styleUrls: ['./image-select.component.scss'] + styleUrls: ['./image-select.component.scss'], }) export class ImageSelectComponent { // TODO: Check Upgrade - @Input() public control: AbstractControl; + @Input() public control: FormControl; @Input() public valueWrapper: ValueWrapper; @Input() public fileFormatHint: string; @Input() public hideRemoveButton: boolean; @@ -46,5 +46,5 @@ export class ImageSelectComponent { @Output() public change = new EventEmitter(); @Output() public remove = new EventEmitter(); - constructor(public readonly imageProvider: Base64ImageService) { } + constructor(public readonly imageProvider: Base64ImageService) {} } diff --git a/imxweb/projects/qbm/src/lib/image/image-view/image-view.component.html b/imxweb/projects/qbm/src/lib/image/image-view/image-view.component.html index b69cb7e41..0075826c8 100644 --- a/imxweb/projects/qbm/src/lib/image/image-view/image-view.component.html +++ b/imxweb/projects/qbm/src/lib/image/image-view/image-view.component.html @@ -1,5 +1,5 @@
    - {{ valueWrapper?.display | translate }} - - {{ defaultValue | translate }} -
    \ No newline at end of file + {{ valueWrapper.display | translate }} + + {{ defaultValue | translate }} +
    diff --git a/imxweb/projects/qbm/src/lib/image/image-view/image-view.component.scss b/imxweb/projects/qbm/src/lib/image/image-view/image-view.component.scss index a194cb6b8..434d7fa69 100644 --- a/imxweb/projects/qbm/src/lib/image/image-view/image-view.component.scss +++ b/imxweb/projects/qbm/src/lib/image/image-view/image-view.component.scss @@ -1,7 +1,6 @@ @import '@elemental-ui/core/src/styles/_palette.scss'; .imx-readonly-view { - margin-bottom: 20px; span { display: block; word-wrap: break-word; diff --git a/imxweb/projects/qbm/src/lib/image/image-view/image-view.component.ts b/imxweb/projects/qbm/src/lib/image/image-view/image-view.component.ts index dcd921c38..fd7740154 100644 --- a/imxweb/projects/qbm/src/lib/image/image-view/image-view.component.ts +++ b/imxweb/projects/qbm/src/lib/image/image-view/image-view.component.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -32,11 +32,11 @@ import { ValueWrapper } from '../../value-wrapper/value-wrapper'; @Component({ selector: 'imx-image-view', templateUrl: './image-view.component.html', - styleUrls: ['./image-view.component.scss'] + styleUrls: ['./image-view.component.scss'], }) export class ImageViewComponent { @Input() public valueWrapper: ValueWrapper; @Input() public defaultValue: string; - constructor(public readonly imageProvider: Base64ImageService) { } + constructor(public readonly imageProvider: Base64ImageService) {} } diff --git a/imxweb/projects/qbm/src/lib/image/image.module.ts b/imxweb/projects/qbm/src/lib/image/image.module.ts index f28851f91..753644cbe 100644 --- a/imxweb/projects/qbm/src/lib/image/image.module.ts +++ b/imxweb/projects/qbm/src/lib/image/image.module.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -38,14 +38,8 @@ import { ImageSelectComponent } from './image-select/image-select.component'; import { ImageViewComponent } from './image-view/image-view.component'; @NgModule({ - declarations: [ - ImageSelectComponent, - ImageViewComponent - ], - exports: [ - ImageSelectComponent, - ImageViewComponent - ], + declarations: [ImageSelectComponent, ImageViewComponent], + exports: [ImageSelectComponent, ImageViewComponent], imports: [ CommonModule, EuiCoreModule, @@ -55,7 +49,7 @@ import { ImageViewComponent } from './image-view/image-view.component'; MatInputModule, MatProgressSpinnerModule, ReactiveFormsModule, - TranslateModule - ] + TranslateModule, + ], }) -export class ImageModule { } +export class ImageModule {} diff --git a/imxweb/projects/qbm/src/lib/images/base64-image.service.spec.ts b/imxweb/projects/qbm/src/lib/images/base64-image.service.spec.ts index efed1abe7..8c8a95620 100644 --- a/imxweb/projects/qbm/src/lib/images/base64-image.service.spec.ts +++ b/imxweb/projects/qbm/src/lib/images/base64-image.service.spec.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -25,14 +25,11 @@ */ import { TestBed } from '@angular/core/testing'; -import * as TypeMoq from 'typemoq'; +import { IWriteValue } from '@imx-modules/imx-qbm-dbts'; import { Base64ImageService } from './base64-image.service'; -import { IWriteValue } from 'imx-qbm-dbts'; describe('Base64ImageService', () => { - - it('should be created', () => { const service: Base64ImageService = TestBed.get(Base64ImageService); expect(service).toBeTruthy(); @@ -42,30 +39,29 @@ describe('Base64ImageService', () => { { description: 'null image', image: null, expect: { hasImage: false, data: '' } }, { description: 'empty image', image: '', expect: { hasImage: false, data: '' } }, { description: 'image', image: '5642', expect: { hasImage: true, data: 'data:image/png;base64,5642' } }, - ].forEach(testcase => + ].forEach((testcase) => it(`can handle an image with ${testcase.description}`, () => { // Arrange const service: Base64ImageService = TestBed.get(Base64ImageService); - const writeValueMock = TypeMoq.Mock.ofType>(); - writeValueMock.setup(wm => wm.value).returns(() => testcase.image); - + const writeValueMock = { value: testcase.image } as IWriteValue; // Act & Assert - expect(service.getImageUrl(writeValueMock.object)).toBe(testcase.expect.data); - })); - + expect(service.getImageUrl(writeValueMock)).toBe(testcase.expect.data); + }), + ); [ { description: 'null url', image: null, expect: '' }, { description: 'empty url', image: '', expect: '' }, { description: 'url', image: '5642', expect: '5642' }, { description: 'url', image: 'data:image/png;base64,5642', expect: '5642' }, - ].forEach(testcase => + ].forEach((testcase) => it(`can handle an url with ${testcase.description}`, () => { // Arrange const service: Base64ImageService = TestBed.get(Base64ImageService); // Act & Assert expect(service.getImageData(testcase.image)).toBe(testcase.expect); - })); + }), + ); }); diff --git a/imxweb/projects/qbm/src/lib/images/base64-image.service.ts b/imxweb/projects/qbm/src/lib/images/base64-image.service.ts index 7a2fd6f32..01fac91c6 100644 --- a/imxweb/projects/qbm/src/lib/images/base64-image.service.ts +++ b/imxweb/projects/qbm/src/lib/images/base64-image.service.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -26,10 +26,10 @@ import { Injectable } from '@angular/core'; import { SafeUrl } from '@angular/platform-browser'; -import { IWriteValue } from 'imx-qbm-dbts'; +import { IWriteValue } from '@imx-modules/imx-qbm-dbts'; @Injectable({ - providedIn: 'root' + providedIn: 'root', }) export class Base64ImageService { private readonly base64DataUrl = 'data:image/png;base64,'; diff --git a/imxweb/projects/qbm/src/lib/indexbar/indexbar.component.html b/imxweb/projects/qbm/src/lib/indexbar/indexbar.component.html index 96aec2537..de1abec11 100644 --- a/imxweb/projects/qbm/src/lib/indexbar/indexbar.component.html +++ b/imxweb/projects/qbm/src/lib/indexbar/indexbar.component.html @@ -1,7 +1,6 @@
    -
    - - -
    - {{EffectiveLabel()}} -
    \ No newline at end of file +
    + +
    + {{ EffectiveLabel() }} +
    diff --git a/imxweb/projects/qbm/src/lib/indexbar/indexbar.component.ts b/imxweb/projects/qbm/src/lib/indexbar/indexbar.component.ts index c6f3e61b4..bd29aa9ac 100644 --- a/imxweb/projects/qbm/src/lib/indexbar/indexbar.component.ts +++ b/imxweb/projects/qbm/src/lib/indexbar/indexbar.component.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -27,107 +27,98 @@ import { Component, Input } from '@angular/core'; @Component({ - templateUrl: "./indexbar.component.html", - selector: "imx-indexbar" + templateUrl: './indexbar.component.html', + selector: 'imx-indexbar', }) export class IndexBarComponent { - // TODO replace VI_Common_Color_Gray, VI_Common_Color_Badge_Important,VI_Common_Color_Badge_Success,VI_Common_Color_Badge_Warning + // TODO replace VI_Common_Color_Gray, VI_Common_Color_Badge_Important,VI_Common_Color_Badge_Success,VI_Common_Color_Badge_Warning - ColorFilling(): string { - return (this.IsHigh() ? this.ColorHigh() : (this.IsLow() ? this.ColorLow() : this.ColorMedium())); - } + ColorFilling(): string { + return this.IsHigh() ? this.ColorHigh() : this.IsLow() ? this.ColorLow() : this.ColorMedium(); + } - Container1Style(): string { - return this.HasFlexibleProgressbar - ? '' - : `display: inline-block; min-width:${this.TotalWidth()}px;` - } + Container1Style(): string { + return this.HasFlexibleProgressbar ? '' : `display: inline-block; min-width:${this.TotalWidth()}px;`; + } - Container2Style(): string { - return `width: calc(100% - ${this.LabelWidth + 2}px); height: 14px; border: solid 1px %VI_Common_Color_Gray%; display:inline-block;`; - } + Container2Style(): string { + return `width: calc(100% - ${this.LabelWidth + 2}px); height: 14px; border: solid 1px %VI_Common_Color_Gray%; display:inline-block;`; + } - Container3Style(): string { - const f = this.ColorFilling(); - return `background-color: ${f}; color: ${f}; display: block; overflow: hidden; width: ${this.Percentage()}%; height: 14px;`; - } + Container3Style(): string { + const f = this.ColorFilling(); + return `background-color: ${f}; color: ${f}; display: block; overflow: hidden; width: ${this.Percentage()}%; height: 14px;`; + } - Label1Style(): string { - return `vertical-align: top; text-align:right; float:right; width:${this.LabelWidth}px;`; - } + Label1Style(): string { + return `vertical-align: top; text-align:right; float:right; width:${this.LabelWidth}px;`; + } - ColorHigh(): string { - return this.EffectiveWarningOnHighValues() - ? '%VI_Common_Color_Badge_Important%' - : '%VI_Common_Color_Badge_Success%'; - } + ColorHigh(): string { + return this.EffectiveWarningOnHighValues() ? '%VI_Common_Color_Badge_Important%' : '%VI_Common_Color_Badge_Success%'; + } - ColorLow(): string { - return this.EffectiveWarningOnHighValues() - ? '%VI_Common_Color_Badge_Success%' - : '%VI_Common_Color_Badge_Important%'; - } + ColorLow(): string { + return this.EffectiveWarningOnHighValues() ? '%VI_Common_Color_Badge_Success%' : '%VI_Common_Color_Badge_Important%'; + } - ColorMedium(): string { - return "%VI_Common_Color_Badge_Warning%"; - } + ColorMedium(): string { + return '%VI_Common_Color_Badge_Warning%'; + } - EffectiveLabel(): string { - return this.Label || this.Percentage() + " %"; - } + EffectiveLabel(): string { + return this.Label || this.Percentage() + ' %'; + } - EffectiveProgress(): number { - return this.Progress < 0.0 ? 0.0 : (this.Progress > 1.0 ? 1.0 : this.Progress); - } + EffectiveProgress(): number { + return this.Progress < 0.0 ? 0.0 : this.Progress > 1.0 ? 1.0 : this.Progress; + } - EffectiveWarningOnHighValues(): boolean { - return this.WarningOnHighValues; - } + EffectiveWarningOnHighValues(): boolean { + return this.WarningOnHighValues; + } - IsHigh(): boolean { - return this.EffectiveProgress() > this.UpperLimit; - } + IsHigh(): boolean { + return this.EffectiveProgress() > this.UpperLimit; + } - IsLow(): boolean { - return this.EffectiveProgress() <= this.LowerLimit; - } + IsLow(): boolean { + return this.EffectiveProgress() <= this.LowerLimit; + } - Percentage(): number { - return Math.floor(100.0 * this.EffectiveProgress()); - } + Percentage(): number { + return Math.floor(100.0 * this.EffectiveProgress()); + } - TotalWidth(): number { - return this.LabelWidth >= 0 - ? this.ProgressbarWidth + this.LabelWidth + 2 - : this.ProgressbarWidth; - } + TotalWidth(): number { + return this.LabelWidth >= 0 ? this.ProgressbarWidth + this.LabelWidth + 2 : this.ProgressbarWidth; + } - /** Optional value overriding the default label text that displays the progress percentage. */ - @Input() Label: string; + /** Optional value overriding the default label text that displays the progress percentage. */ + @Input() Label: string; - @Input() LabelWidth: number = 35; + @Input() LabelWidth: number = 35; - /** Optional. Specify a value if you want to override default lower limit of 0.25 - * Progress values that are less or equal to this value will be marked with the lower color. */ - @Input() LowerLimit: number = 0.25; + /** Optional. Specify a value if you want to override default lower limit of 0.25 + * Progress values that are less or equal to this value will be marked with the lower color. */ + @Input() LowerLimit: number = 0.25; - /** The progress as double value between 0.0 (0%) and 1.0 (100%) */ - @Input() Progress: number; + /** The progress as double value between 0.0 (0%) and 1.0 (100%) */ + @Input() Progress: number; - @Input() Tooltip: string; + @Input() Tooltip: string; - /** Optional. Specify a value if you want to override the default upper limit of 0.5 - * Progress values that are greater than this value will be marked with the high color. */ - @Input() UpperLimit: number; + /** Optional. Specify a value if you want to override the default upper limit of 0.5 + * Progress values that are greater than this value will be marked with the high color. */ + @Input() UpperLimit: number; - /** Default behaviour is to apply warning colors for low values (high values are good, low values are bad). - * You can (optionally) specify WarningOnHighValues = true, if you want to invert this behavior. */ - @Input() WarningOnHighValues: boolean; + /** Default behaviour is to apply warning colors for low values (high values are good, low values are bad). + * You can (optionally) specify WarningOnHighValues = true, if you want to invert this behavior. */ + @Input() WarningOnHighValues: boolean; - /** Default value is 50 (meaning 50 px). If HasFlexibleProgressbar()=true this width will be ignored and the remaining space will be used. */ - @Input() ProgressbarWidth: number = 50; + /** Default value is 50 (meaning 50 px). If HasFlexibleProgressbar()=true this width will be ignored and the remaining space will be used. */ + @Input() ProgressbarWidth: number = 50; - /** Default value is true (meaning the progress bar has a flexible width, if set to false it has a fixed width - see ProgressBarWidth()) */ - @Input() HasFlexibleProgressbar: boolean = true; - -} \ No newline at end of file + /** Default value is true (meaning the progress bar has a flexible width, if set to false it has a fixed width - see ProgressBarWidth()) */ + @Input() HasFlexibleProgressbar: boolean = true; +} diff --git a/imxweb/projects/qbm/src/lib/info-modal-dialog/info-badge/info-badge.component.html b/imxweb/projects/qbm/src/lib/info-modal-dialog/info-badge/info-badge.component.html index 01d22d46d..71709ce80 100644 --- a/imxweb/projects/qbm/src/lib/info-modal-dialog/info-badge/info-badge.component.html +++ b/imxweb/projects/qbm/src/lib/info-modal-dialog/info-badge/info-badge.component.html @@ -1,3 +1,4 @@ - + + {{ badgeText }} + + diff --git a/imxweb/projects/qbm/src/lib/info-modal-dialog/info-badge/info-badge.component.scss b/imxweb/projects/qbm/src/lib/info-modal-dialog/info-badge/info-badge.component.scss deleted file mode 100644 index 226ab9e9a..000000000 --- a/imxweb/projects/qbm/src/lib/info-modal-dialog/info-badge/info-badge.component.scss +++ /dev/null @@ -1,30 +0,0 @@ -@import "@elemental-ui/core/src/styles/_eui_palette.scss"; - -:host { - button { - transition: all .4s ease; - } -} - -// Theming -:host { - button { - color: $color-blue-60; - - &:hover { - color: $color-orange-60; - } - } -} - -.eui-dark-theme { - :host { - button { - color: $color-blue-40; - - &:hover { - color: $color-orange-40; - } - } - } -} diff --git a/imxweb/projects/qbm/src/lib/info-modal-dialog/info-badge/info-badge.component.ts b/imxweb/projects/qbm/src/lib/info-modal-dialog/info-badge/info-badge.component.ts index 7a1e30c89..37ab88e0c 100644 --- a/imxweb/projects/qbm/src/lib/info-modal-dialog/info-badge/info-badge.component.ts +++ b/imxweb/projects/qbm/src/lib/info-modal-dialog/info-badge/info-badge.component.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -30,8 +30,7 @@ import { InfoDialogComponent } from '../info-dialog/info-dialog.component'; @Component({ selector: 'imx-info-badge', - templateUrl: './info-badge.component.html', - styleUrls: ['./info-badge.component.scss'], + templateUrl: './info-badge.component.html' }) export class InfoBadgeComponent { // width string = '400px'. Sets the width of the appearing dialog. diff --git a/imxweb/projects/qbm/src/lib/info-modal-dialog/info-button/info-button.component.html b/imxweb/projects/qbm/src/lib/info-modal-dialog/info-button/info-button.component.html index f9f1c1575..904a6c404 100644 --- a/imxweb/projects/qbm/src/lib/info-modal-dialog/info-button/info-button.component.html +++ b/imxweb/projects/qbm/src/lib/info-modal-dialog/info-button/info-button.component.html @@ -1,3 +1,3 @@ - diff --git a/imxweb/projects/qbm/src/lib/info-modal-dialog/info-button/info-button.component.scss b/imxweb/projects/qbm/src/lib/info-modal-dialog/info-button/info-button.component.scss index 81d501e57..8f54c94fa 100644 --- a/imxweb/projects/qbm/src/lib/info-modal-dialog/info-button/info-button.component.scss +++ b/imxweb/projects/qbm/src/lib/info-modal-dialog/info-button/info-button.component.scss @@ -1,42 +1,5 @@ -@import "@elemental-ui/core/src/styles/_eui_palette.scss"; +@import 'components/button'; -:host { - button { - transition: all .4s ease; - } -} - -// Theming -:host { - button { - color: $color-blue-60; - - &:hover { - color: $color-orange-60; - } - } -} - -.eui-dark-theme { - :host { - button { - color: $color-blue-40; - - &:hover { - color: $color-orange-40; - } - } - } -} - -.eui-contrast-theme { - :host { - button { - color: $color-blue-40; - - &:hover { - color: $color-orange-40; - } - } - } +.imx-button-icon-hover-warning { + @extend .imx-button-icon-hover-warning; } diff --git a/imxweb/projects/qbm/src/lib/info-modal-dialog/info-button/info-button.component.ts b/imxweb/projects/qbm/src/lib/info-modal-dialog/info-button/info-button.component.ts index 199ad03a5..c227c6789 100644 --- a/imxweb/projects/qbm/src/lib/info-modal-dialog/info-button/info-button.component.ts +++ b/imxweb/projects/qbm/src/lib/info-modal-dialog/info-button/info-button.component.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -31,14 +31,14 @@ import { InfoDialogComponent } from '../info-dialog/info-dialog.component'; @Component({ selector: 'imx-info-button', templateUrl: './info-button.component.html', - styleUrls: ['./info-button.component.scss'] + styleUrls: ['./info-button.component.scss'], }) -export class InfoButtonComponent { +export class InfoButtonComponent { // width string = '400px'. Sets the width of the appearing dialog. @Input() public width = '400px'; // title: string Gives the dialog an h3 title if present - @Input() public title: string = null; + @Input() public title: string | null = null; // templateRef: TemplateRef. Provides the content within the the dialog @Input() public templateRef: TemplateRef; @@ -46,19 +46,19 @@ export class InfoButtonComponent { // panelClass: string | string[]. Allows for a class to be applied to the overlay and the above templateRef to be styled. @Input() public panelClass: string | string[]; - constructor( - private dialogService: MatDialog - ) { } + constructor(private dialogService: MatDialog) {} public async showInfo(): Promise { - await this.dialogService.open(InfoDialogComponent, { - width: this.width, - data: { - title: this.title, - content: this.templateRef - }, - panelClass: this.panelClass - }).afterClosed().toPromise(); + await this.dialogService + .open(InfoDialogComponent, { + width: this.width, + data: { + title: this.title, + content: this.templateRef, + }, + panelClass: this.panelClass, + }) + .afterClosed() + .toPromise(); } - } diff --git a/imxweb/projects/qbm/src/lib/info-modal-dialog/info-dialog/info-dialog.component.html b/imxweb/projects/qbm/src/lib/info-modal-dialog/info-dialog/info-dialog.component.html index e66b73ff0..45e9f1d1d 100644 --- a/imxweb/projects/qbm/src/lib/info-modal-dialog/info-dialog/info-dialog.component.html +++ b/imxweb/projects/qbm/src/lib/info-modal-dialog/info-dialog/info-dialog.component.html @@ -1,8 +1,8 @@ -

    {{data.title}}

    +

    {{ data.title }}

    - + diff --git a/imxweb/projects/qbm/src/lib/info-modal-dialog/info-dialog/info-dialog.component.scss b/imxweb/projects/qbm/src/lib/info-modal-dialog/info-dialog/info-dialog.component.scss index 9cfa9afc4..c6c9bd60c 100644 --- a/imxweb/projects/qbm/src/lib/info-modal-dialog/info-dialog/info-dialog.component.scss +++ b/imxweb/projects/qbm/src/lib/info-modal-dialog/info-dialog/info-dialog.component.scss @@ -1,10 +1,6 @@ :host { - .mat-dialog-title { + .mat-mdc-dialog-title { margin: 0; font-weight: bold; } - - .mat-dialog-actions { - justify-content: flex-end; - } } diff --git a/imxweb/projects/qbm/src/lib/info-modal-dialog/info-dialog/info-dialog.component.ts b/imxweb/projects/qbm/src/lib/info-modal-dialog/info-dialog/info-dialog.component.ts index c237c0829..a12d4b2a4 100644 --- a/imxweb/projects/qbm/src/lib/info-modal-dialog/info-dialog/info-dialog.component.ts +++ b/imxweb/projects/qbm/src/lib/info-modal-dialog/info-dialog/info-dialog.component.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -30,14 +30,14 @@ import { MAT_DIALOG_DATA } from '@angular/material/dialog'; @Component({ selector: 'imx-info-dialog', templateUrl: './info-dialog.component.html', - styleUrls: ['./info-dialog.component.scss'] + styleUrls: ['./info-dialog.component.scss'], }) export class InfoDialogComponent { - constructor( - @Inject(MAT_DIALOG_DATA) public data: { - content: TemplateRef, - title?: string - } - ) { } + @Inject(MAT_DIALOG_DATA) + public data: { + content: TemplateRef; + title?: string; + }, + ) {} } diff --git a/imxweb/projects/qbm/src/lib/info-modal-dialog/info-modal-dialog.module.ts b/imxweb/projects/qbm/src/lib/info-modal-dialog/info-modal-dialog.module.ts index f0d36bcee..64d5bba69 100644 --- a/imxweb/projects/qbm/src/lib/info-modal-dialog/info-modal-dialog.module.ts +++ b/imxweb/projects/qbm/src/lib/info-modal-dialog/info-modal-dialog.module.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR diff --git a/imxweb/projects/qbm/src/lib/jobqueue-overview/jobqueue-overview.component.html b/imxweb/projects/qbm/src/lib/jobqueue-overview/jobqueue-overview.component.html index 500a1f3d0..95dc1a9f0 100644 --- a/imxweb/projects/qbm/src/lib/jobqueue-overview/jobqueue-overview.component.html +++ b/imxweb/projects/qbm/src/lib/jobqueue-overview/jobqueue-overview.component.html @@ -9,13 +9,7 @@ - - - - -
    - -

    {{'#LDS#Currently, there is no data in any queues.' |translate}}

    -
    + +
    diff --git a/imxweb/projects/qbm/src/lib/jobqueue-overview/jobqueue-overview.component.scss b/imxweb/projects/qbm/src/lib/jobqueue-overview/jobqueue-overview.component.scss index 6826a21b6..030b08bca 100644 --- a/imxweb/projects/qbm/src/lib/jobqueue-overview/jobqueue-overview.component.scss +++ b/imxweb/projects/qbm/src/lib/jobqueue-overview/jobqueue-overview.component.scss @@ -1,6 +1,6 @@ @import '@elemental-ui/core/src/styles/_palette.scss'; -:host{ +:host { display: flex; flex-direction: column; align-items: flex-start; @@ -17,34 +17,19 @@ mat-form-field { display: flex; - - ::ng-deep .mat-form-field-wrapper { - padding-bottom: 0; - } } -mat-card { - flex: 1 1 auto; - display: flex; - flex-direction: column; -} - -.imx-billboard-card { +.imx-card-fill { align-self: normal; } -.imx-jobqueue-no-data { +.imx-no-results { height: 100%; display: flex; flex-direction: column; justify-content: center; align-items: center; - .eui-icon { - font-size: 100px; - color: rgba($black-c, 0.55); - } - p { margin: 0; font-size: 18px; diff --git a/imxweb/projects/qbm/src/lib/jobqueue-overview/jobqueue-overview.component.ts b/imxweb/projects/qbm/src/lib/jobqueue-overview/jobqueue-overview.component.ts index d451da3a1..460df9d7f 100644 --- a/imxweb/projects/qbm/src/lib/jobqueue-overview/jobqueue-overview.component.ts +++ b/imxweb/projects/qbm/src/lib/jobqueue-overview/jobqueue-overview.component.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -24,16 +24,16 @@ * */ -import { Component, Input, OnChanges, OnDestroy, OnInit, SimpleChanges} from '@angular/core'; +import { ChangeDetectorRef, Component, Input, OnChanges, OnDestroy, OnInit, SimpleChanges } from '@angular/core'; import { TranslateService } from '@ngx-translate/core'; -import { ChartOptions, XTickConfiguration } from 'billboard.js'; +import { Chart, ChartOptions, XTickConfiguration } from 'billboard.js'; import { interval, Subscription } from 'rxjs'; -import { JobQueueDataSlice, JobQueueOverviewService } from './jobqueue-overview.service'; -import { XAxisInformation } from '../chart-options/x-axis-information'; import { LineChartOptions } from '../chart-options/line-chart-options'; -import { YAxisInformation } from '../chart-options/y-axis-information'; import { SeriesInformation } from '../chart-options/series-information'; +import { XAxisInformation } from '../chart-options/x-axis-information'; +import { YAxisInformation } from '../chart-options/y-axis-information'; +import { JobQueueOverviewService } from './jobqueue-overview.service'; @Component({ selector: 'imx-jobqueue-overview', @@ -42,7 +42,7 @@ import { SeriesInformation } from '../chart-options/series-information'; }) export class JobQueueOverviewComponent implements OnInit, OnDestroy, OnChanges { @Input() public isShowGraph: boolean; - public chartOptions: ChartOptions = null; + public chartOptions: ChartOptions | null = null; public routineSubscription: Subscription; public queueNames: string[]; @@ -60,33 +60,42 @@ export class JobQueueOverviewComponent implements OnInit, OnDestroy, OnChanges { public ylabel: string; public title: string; + private chart: Chart; + private xAxisConfig: XTickConfiguration = { culling: { max: 5 }, format: '%H:%M:%S', }; - constructor(private readonly jobQueueOverviewService: JobQueueOverviewService, private translateService: TranslateService) { + constructor( + private readonly jobQueueOverviewService: JobQueueOverviewService, + private translateService: TranslateService, + private changeDetectorRef: ChangeDetectorRef, + ) { this.queueNames = this.jobQueueOverviewService.queueNames; - this.translateService.get('#LDS#All queues').subscribe((trans: string) => (this.queue = trans)); + this.queue = translateService.instant('#LDS#All queues'); // Translate chart labels - this.translateService.get('#LDS#Time').subscribe((trans: string) => (this.timeText = trans)); - this.translateService.get('#LDS#Error').subscribe((trans: string) => (this.errorText = trans)); - this.translateService.get('#LDS#Waiting').subscribe((trans: string) => (this.waitingText = trans)); - this.translateService.get('#LDS#Ready').subscribe((trans: string) => (this.readyText = trans)); - this.translateService.get('#LDS#Processing').subscribe((trans: string) => (this.processingText = trans)); - this.translateService.get('#LDS#Finished').subscribe((trans: string) => (this.finishedText = trans)); - - this.translateService.get('#LDS#Number of processes').subscribe((trans: string) => (this.ylabel = trans)); - this.translateService.get('#LDS#Processes over time').subscribe((trans: string) => (this.title = trans)); + + this.timeText = translateService.instant('#LDS#Time'); + this.errorText = translateService.instant('#LDS#Error'); + this.waitingText = translateService.instant('#LDS#Waiting'); + this.readyText = translateService.instant('#LDS#Ready'); + this.processingText = translateService.instant('#LDS#Processing'); + this.finishedText = translateService.instant('#LDS#Finished'); + + this.ylabel = translateService.instant('#LDS#Number of processes'); + this.title = translateService.instant('#LDS#Processes over time'); } public async ngOnInit(): Promise { + this.buildOptions(); // Setup service if it isn't already available if (!this.jobQueueOverviewService.isAvailable) { await this.jobQueueOverviewService.setUp(); await this.jobQueueOverviewService.isAvailablePromise; } + // Setup an interval and subscribe const routine = interval(this.jobQueueOverviewService.configParams.RefreshIntervalSeconds * 1000); this.routineSubscription = routine.subscribe(() => this.updatePlot()); @@ -94,10 +103,15 @@ export class JobQueueOverviewComponent implements OnInit, OnDestroy, OnChanges { public ngOnChanges(changes: SimpleChanges): void { if (changes['isShowGraph']) { - this.updatePlot(); + this.changeDetectorRef.detectChanges(); + this.chart?.resize(this.getSize()); } } + public onChart(chart: Chart) { + this.chart = chart; + } + public updatePlot(): void { if (!this.isShowGraph) { // Don't do anything that isn't visible @@ -105,51 +119,67 @@ export class JobQueueOverviewComponent implements OnInit, OnDestroy, OnChanges { } const data = this.jobQueueOverviewService.getSlice(this.queue); - - if (data.Time.length > 0) { - this.setData(data); - this.chartOptions.onresize = () => this.setData(data); + const dateArray: any[] = data.Time ? [...data.Time] : []; + const errorArray: any[] = data.Error ? [...data.Error] : []; + const waitingArray: any[] = data.Waiting ? [...data.Waiting] : []; + const readyArray: any[] = data.Ready ? [...data.Ready] : []; + const processingArray: any[] = data.Processing ? [...data.Processing] : []; + const finishArray: any[] = data.Finished ? [...data.Finished] : []; + + //add data ID as first element in arrays + dateArray.unshift('x'); + errorArray.unshift(this.errorText); + waitingArray.unshift(this.waitingText); + readyArray.unshift(this.readyText); + processingArray.unshift(this.processingText); + finishArray.unshift(this.finishedText); + + if (!!data.Time?.length) { + this.chart?.load({ + resizeAfter: true, + append: true, + columns: [dateArray, errorArray, waitingArray, readyArray, processingArray, finishArray], + }); } } - public setData(data: JobQueueDataSlice): void { + private buildOptions() { // If there is actually data, show it - const xAxis = new XAxisInformation('date', data.Time, this.xAxisConfig); + const xAxis = new XAxisInformation('date', [], this.xAxisConfig); const yAxis = new YAxisInformation([ - new SeriesInformation(this.errorText, data.Error, 'red'), - new SeriesInformation(this.waitingText, data.Waiting, 'orange'), - new SeriesInformation(this.readyText, data.Ready, 'blue'), - new SeriesInformation(this.processingText, data.Processing, 'yellow'), - new SeriesInformation(this.finishedText, data.Finished, 'green'), + new SeriesInformation(this.errorText, [], 'red'), + new SeriesInformation(this.waitingText, [], 'orange'), + new SeriesInformation(this.readyText, [], 'blue'), + new SeriesInformation(this.processingText, [], 'violet'), + new SeriesInformation(this.finishedText, [], 'green'), ]); yAxis.tickConfiguration = { format: (l) => (Number.isInteger(l) && l > -1 ? l.toString() : ''), }; - yAxis.min = 0; - const lineChartOptions = new LineChartOptions(xAxis, yAxis); + yAxis.min = -1; + const lineChartOptions = new LineChartOptions( + xAxis, + yAxis, + this.translateService.instant('#LDS#Currently, there is no data in any queues.'), + ); lineChartOptions.showPoints = true; lineChartOptions.hideLegend = false; lineChartOptions.colorArea = false; lineChartOptions.canZoom = true; lineChartOptions.padding = { left: 20, right: 20, unit: 'px' }; this.chartOptions = lineChartOptions.options; - this.chartOptions.size = this.getSize(); - } - - public removeOldSVG(): void { - const svgElement = document.getElementsByClassName('bb')[0].firstChild; - if (svgElement) { - svgElement.remove(); + if (this.chartOptions.data) { + this.chartOptions.data.labels = { format: (v, id, i, j) => `${v}` }; } + this.chartOptions.size = { width: 0, height: 0 }; } public getSize(): { height: number; width: number } { - const graphCard = document.querySelector('.imx-billboard-card'); + const graphCard = document.querySelector('.imx-card-fill'); const emptyCard = document.querySelector('.imx-empty-card'); let divForSize: HTMLDivElement; if (graphCard) { // The graph is already displayed, use the current graph, remove previous svg first for resize problem - this.removeOldSVG(); divForSize = graphCard as HTMLDivElement; } else { // We haven't yet rendered the graph, use the empty display instead diff --git a/imxweb/projects/qbm/src/lib/jobqueue-overview/jobqueue-overview.module.ts b/imxweb/projects/qbm/src/lib/jobqueue-overview/jobqueue-overview.module.ts index a80f7ada1..c2fd907da 100644 --- a/imxweb/projects/qbm/src/lib/jobqueue-overview/jobqueue-overview.module.ts +++ b/imxweb/projects/qbm/src/lib/jobqueue-overview/jobqueue-overview.module.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR diff --git a/imxweb/projects/qbm/src/lib/jobqueue-overview/jobqueue-overview.service.spec.ts b/imxweb/projects/qbm/src/lib/jobqueue-overview/jobqueue-overview.service.spec.ts index 4ddedb75c..d1731ff67 100644 --- a/imxweb/projects/qbm/src/lib/jobqueue-overview/jobqueue-overview.service.spec.ts +++ b/imxweb/projects/qbm/src/lib/jobqueue-overview/jobqueue-overview.service.spec.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -31,9 +31,9 @@ import { ClassloggerService } from '../classlogger/classlogger.service'; import { AppConfigService } from '../appConfig/appConfig.service'; import { imx_SessionService } from '../session/imx-session.service'; import { JobQueueOverviewService, JobQueueDataSlice, JobQueueGroups } from './jobqueue-overview.service'; -import { EntityColumnData, EntityData } from 'imx-qbm-dbts'; +import { EntityColumnData, EntityData } from '@imx-modules/imx-qbm-dbts'; import { of } from 'rxjs'; -import { EventStreamConfig } from 'imx-api-qbm'; +import { EventStreamConfig } from '@imx-modules/imx-api-qbm'; describe('JobQueueOverviewService', () => { let service: JobQueueOverviewService; diff --git a/imxweb/projects/qbm/src/lib/jobqueue-overview/jobqueue-overview.service.ts b/imxweb/projects/qbm/src/lib/jobqueue-overview/jobqueue-overview.service.ts index 2dd168b3b..49f8677e6 100644 --- a/imxweb/projects/qbm/src/lib/jobqueue-overview/jobqueue-overview.service.ts +++ b/imxweb/projects/qbm/src/lib/jobqueue-overview/jobqueue-overview.service.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -28,12 +28,12 @@ import { ErrorHandler, Injectable } from '@angular/core'; import { TranslateService } from '@ngx-translate/core'; import { interval, Subscription } from 'rxjs'; -import { ClassloggerService } from '../classlogger/classlogger.service'; +import { EventStreamConfig } from '@imx-modules/imx-api-qbm'; +import { EntityCollectionChangeData, EntityData } from '@imx-modules/imx-qbm-dbts'; +import _ from 'lodash'; import { AppConfigService } from '../appConfig/appConfig.service'; +import { ClassloggerService } from '../classlogger/classlogger.service'; import { imx_SessionService } from '../session/imx-session.service'; -import { EventStreamConfig } from 'imx-api-qbm'; -import { EntityCollectionChangeData, EntityData } from 'imx-qbm-dbts'; -import _ from 'lodash'; export interface JobQueueGroups { Error?: number; @@ -77,7 +77,7 @@ export class JobQueueOverviewService { public session: imx_SessionService, public translateService: TranslateService, private logger: ClassloggerService, - private errorHandler: ErrorHandler + private errorHandler: ErrorHandler, ) { this.translateService.get('#LDS#All queues').subscribe((trans: string) => (this.totalStreamName = trans)); this.isAvailablePromise = new Promise((resolve, reject) => { @@ -124,8 +124,8 @@ export class JobQueueOverviewService { if (changeData.New) { // Loop over each entity to add to the queues changeData.New.forEach((entity) => { - name = entity.Columns['QueueName'].Value; - uid = entity.Columns['UID_QBMJobqueueOverview'].Value; + name = entity.Columns?.['QueueName']?.Value; + uid = entity.Columns?.['UID_QBMJobqueueOverview']?.Value; this.addEntity(name, entity); this.uidToName[uid] = name; }); @@ -154,9 +154,11 @@ export class JobQueueOverviewService { public addEntity(name: string, entity: EntityData, isTotal: boolean = false): void { // Add this entity to the list this.entities[name] = {}; - for (const [key, value] of Object.entries(entity.Columns)) { - if (key.includes('Count')) { - this.entities[name][key] = isTotal ? 0 : value.Value; + if (entity.Columns) { + for (const [key, value] of Object.entries(entity.Columns)) { + if (key.includes('Count')) { + this.entities[name][key] = isTotal ? 0 : value.Value; + } } } // Check if name is already in queue list, prevents total queue from being duped @@ -211,7 +213,7 @@ export class JobQueueOverviewService { } public pushTable(): void { - const currentTable: object[] = this.table.pop(); + const currentTable: object[] | undefined = this.table.pop(); const incomingTable: object[] = []; // Replace popped table, if not empty (faster as easier to pop) if (currentTable) { @@ -269,12 +271,14 @@ export class JobQueueOverviewService { return slice; } this.axisTimes.forEach((e, timeIndex) => { - for (const [name, value] of Object.entries(this.table[timeIndex][queueIndex])) { - // Append to array or initialize - if (slice[name]) { - slice[name].push(value); - } else { - slice[name] = [value]; + if (this.table[timeIndex][queueIndex]) { + for (const [name, value] of Object.entries(this.table[timeIndex][queueIndex])) { + // Append to array or initialize + if (slice[name]) { + slice[name].push(value); + } else { + slice[name] = [value]; + } } } }); diff --git a/imxweb/projects/qbm/src/lib/lds-replace/lds-replace.module.ts b/imxweb/projects/qbm/src/lib/lds-replace/lds-replace.module.ts index aef2cc8c9..8684828d0 100644 --- a/imxweb/projects/qbm/src/lib/lds-replace/lds-replace.module.ts +++ b/imxweb/projects/qbm/src/lib/lds-replace/lds-replace.module.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -30,14 +30,8 @@ import { CommonModule } from '@angular/common'; import { LdsReplacePipe } from './lds-replace.pipe'; @NgModule({ - declarations: [ - LdsReplacePipe - ], - exports: [ - LdsReplacePipe - ], - imports: [ - CommonModule - ] + declarations: [LdsReplacePipe], + exports: [LdsReplacePipe], + imports: [CommonModule], }) -export class LdsReplaceModule { } +export class LdsReplaceModule {} diff --git a/imxweb/projects/qbm/src/lib/lds-replace/lds-replace.pipe.ts b/imxweb/projects/qbm/src/lib/lds-replace/lds-replace.pipe.ts index 37ca96436..d1667f0cd 100644 --- a/imxweb/projects/qbm/src/lib/lds-replace/lds-replace.pipe.ts +++ b/imxweb/projects/qbm/src/lib/lds-replace/lds-replace.pipe.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -27,7 +27,7 @@ import { Pipe, PipeTransform, Injectable } from '@angular/core'; @Injectable({ - providedIn: 'root' + providedIn: 'root', }) @Pipe({ name: 'ldsReplace', diff --git a/imxweb/projects/qbm/src/lib/login/login.component.html b/imxweb/projects/qbm/src/lib/login/login.component.html index 78c5d4e4f..9fa5fa9d4 100644 --- a/imxweb/projects/qbm/src/lib/login/login.component.html +++ b/imxweb/projects/qbm/src/lib/login/login.component.html @@ -13,19 +13,55 @@

    {{ title }}

    - +
    - +
    -
    - + + -
    @@ -35,28 +71,78 @@

    + {{ '#LDS#Authentication' | translate }} - + {{ authConfig.display | translate }}
    -
    - -
    + +
    + + + +
    +
    + +
    + + + +
    +
    + +
    + + + +
    + +
    diff --git a/imxweb/projects/qbm/src/lib/login/login.component.scss b/imxweb/projects/qbm/src/lib/login/login.component.scss index 9f6f8ef26..46d948013 100644 --- a/imxweb/projects/qbm/src/lib/login/login.component.scss +++ b/imxweb/projects/qbm/src/lib/login/login.component.scss @@ -1,7 +1,6 @@ -@import "variables.scss"; +@use '@angular/material' as mat; @import '@elemental-ui/core/src/styles/_eui_palette.scss'; - -$inputWidth: calc(40vw + 2px); +@import 'base/variables'; .imx-loginPage { display: flex; @@ -12,7 +11,7 @@ $inputWidth: calc(40vw + 2px); left: 0; right: 0; background-color: $iris-blue; - color: $white; + color: $color-gray-0; align-items: center; } @@ -23,7 +22,7 @@ $inputWidth: calc(40vw + 2px); left: 25px; right: 25px; bottom: 25px; - color: $white; + color: $color-gray-0; display: flex; flex-direction: column; align-items: center; @@ -31,8 +30,6 @@ $inputWidth: calc(40vw + 2px); h1 { text-align: center; } - - } .imx-loginMask { @@ -43,33 +40,24 @@ $inputWidth: calc(40vw + 2px); } .imx-loginInput { - margin: auto 12px; - ::ng-deep { - input { - width: $propertylabelwidth; - box-sizing: content-box; - margin-bottom: 9px; - height: 30px; - padding-left: 6px; - width: calc(40vw - 6px); - } - - .mat-form-field-infix { - color: $VI_Common_Color_Font; - } - - .mat-form-field-flex { - background-color: $white; - padding-left: 6px; - } - - .mat-form-field-appearance-legacy .mat-form-field-underline { - bottom: $ImxLoginControlsMargin; + .mat-mdc-form-field { + .mat-mdc-text-field-wrapper { + .mat-mdc-form-field-infix { + padding-top: 24px; + } + .mat-mdc-floating-label { + display: block; + top: 28px; + } + } } - - .mat-form-field-appearance-legacy .mat-form-field-wrapper { - padding-bottom: $ImxLoginControlsMargin; + } +} +.imx-loginData { + ::ng-deep { + .mat-mdc-form-field-subscript-wrapper { + min-height: 12px; } } } @@ -77,9 +65,6 @@ $inputWidth: calc(40vw + 2px); .imx-loginButtonpanel { text-align: center; padding: 30px 0; - margin: 0 auto; - width: 100%; - display: inline-block; button { margin: 0 10px; @@ -103,7 +88,7 @@ $inputWidth: calc(40vw + 2px); bottom: 10px; left: 0; right: 0; - color: $white; + color: $color-gray-0; } .imx-loginMessageContainer { @@ -119,11 +104,11 @@ $inputWidth: calc(40vw + 2px); .imx-loginTextBox { width: 224px; - color: $VI_Common_Color_Font !important; + color: $color-gray-80 !important; } a.imx-loginLink { - color: $white !important; + color: $color-gray-0 !important; } a.imx-loginLink:hover { @@ -150,11 +135,11 @@ a.imx-loginLink:hover { } mat-form-field { - width: $inputWidth; + width: $IMX_Login_Input_Width; } // on smaller screens -@media screen and (max-width : 600px) { +@media screen and (max-width: 600px) { .imx-loginInput { width: 95%; text-align: center; @@ -187,55 +172,31 @@ mat-form-field { } .eui-dark-theme { - :host{ - .imx-loginPage{ + :host { + .imx-loginPage { background-color: $color-gray-80; } - .imx-loginInput { + .imx-loginData { ::ng-deep { - input { - background-color: $color-gray-70; - border: none; - color: $color-gray-0; - } - - .mat-form-field-infix { - color: $color-gray-0 - } - - .mat-form-field-flex { - background-color:$color-gray-70; + .mat-mdc-text-field-wrapper { + background-color: $color-gray-70 !important; } - } } - } } .eui-contrast-theme { - :host{ - .imx-loginPage{ + :host { + .imx-loginPage { background-color: $color-gray-100; } - .imx-loginInput { + .imx-loginData { ::ng-deep { - input { - background-color: $color-gray-90; - border: none; - color: $color-gray-0; - } - - .mat-form-field-infix { - color: $color-gray-0 + .mat-mdc-text-field-wrapper { + background-color: $color-gray-90 !important; } - - .mat-form-field-flex { - background-color:$color-gray-90; - } - } } - } } diff --git a/imxweb/projects/qbm/src/lib/login/login.component.ts b/imxweb/projects/qbm/src/lib/login/login.component.ts index 81926c485..20f6380dc 100644 --- a/imxweb/projects/qbm/src/lib/login/login.component.ts +++ b/imxweb/projects/qbm/src/lib/login/login.component.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -24,30 +24,46 @@ * */ -import { OverlayRef } from '@angular/cdk/overlay'; -import { Component, OnInit, OnDestroy, ViewChild, ComponentFactoryResolver } from '@angular/core'; +import { + AfterViewChecked, + ChangeDetectorRef, + Component, + ComponentFactoryResolver, + OnDestroy, + OnInit, + QueryList, + ViewChild, + ViewChildren, +} from '@angular/core'; import { Router } from '@angular/router'; import { EuiLoadingService, EuiSplashScreenService, EuiTheme, EuiThemeService } from '@elemental-ui/core'; import { Subscription } from 'rxjs'; -import { Globals } from 'imx-qbm-dbts'; -import { ISessionState } from '../session/session-state'; -import { AuthenticationService } from '../authentication/authentication.service'; +import { HighContrastModeDetector } from '@angular/cdk/a11y'; +import { MatInput } from '@angular/material/input'; +import { Globals } from '@imx-modules/imx-qbm-dbts'; +import { ReCaptchaV3Service } from 'ng-recaptcha-2'; import { AppConfigService } from '../appConfig/appConfig.service'; -import { AuthConfigProvider } from '../authentication/auth-config-provider.interface'; +import { AuthConfigProvider, PreAuthStateType } from '../authentication/auth-config-provider.interface'; +import { AuthenticationService } from '../authentication/authentication.service'; +import { ErrorService } from '../base/error.service'; +import { CaptchaService } from '../captcha/captcha.service'; import { ClassloggerService } from '../classlogger/classlogger.service'; import { ExtDirective } from '../ext/ext.directive'; +import { ISessionState } from '../session/session-state'; import { SystemInfoService } from '../system-info/system-info.service'; -import { HighContrastModeDetector } from '@angular/cdk/a11y'; @Component({ selector: 'imx-login', templateUrl: './login.component.html', styleUrls: ['./login.component.scss'], }) -export class LoginComponent implements OnInit, OnDestroy { +export class LoginComponent implements OnInit, OnDestroy, AfterViewChecked { @ViewChild(ExtDirective, { static: true }) public directive: ExtDirective; + @ViewChildren('authPropertyInput') authPropertyInput: QueryList; + @ViewChildren('preAuthPropertyInput') preAuthPropertyInput: QueryList; + private firstTime: boolean = true; public title: string; public readonly product: { name: string; copyright: string } = { name: Globals.QIM_ProductNameFull, @@ -59,10 +75,12 @@ export class LoginComponent implements OnInit, OnDestroy { public configurationProviders: AuthConfigProvider[]; public logoUrl: string; public newUserConfigProvider: AuthConfigProvider; + public preAuthStateType = PreAuthStateType; private readonly newUserConfigProviderName = 'NewUser'; private readonly authProviderStorageKey = 'selectedAuthProvider'; private readonly subscriptions: Subscription[] = []; + private disposable: () => void; constructor( public readonly appConfigService: AppConfigService, @@ -74,24 +92,28 @@ export class LoginComponent implements OnInit, OnDestroy { private readonly splash: EuiSplashScreenService, private readonly busyService: EuiLoadingService, private readonly themeService: EuiThemeService, - private readonly detector: HighContrastModeDetector + private readonly detector: HighContrastModeDetector, + private readonly errorService: ErrorService, + private readonly captchaService: CaptchaService, + private readonly recaptchaV3Service: ReCaptchaV3Service, + private readonly changeDetection: ChangeDetectorRef, ) { this.title = this.appConfigService.Config.Title; this.subscriptions.push( this.appConfigService.onConfigTitleUpdated.subscribe(() => { this.title = this.appConfigService.Config.Title; - }) + }), ); this.subscriptions.push( - this.authentication.onSessionResponse.subscribe((sessionState: ISessionState) => { + this.authentication.onSessionResponse.subscribe(async (sessionState: ISessionState) => { this.logger.debug(this, 'LoginComponent - subscription - onSessionResponse'); this.logger.trace(this, 'sessionState', sessionState); const existingConfig = this.sessionState?.configurationProviders; this.sessionState = sessionState; if (this.sessionState.IsLoggedIn) { this.logger.debug(this, 'subscription - call navigate'); - this.router.navigate([this.appConfigService.Config.routeConfig.start], { queryParams: {} }); + await this.router.navigate([this.appConfigService.Config.routeConfig?.start], { queryParams: {} }); } else { // Cover the case where an error has occurred and the new sessionState does not contain the configurationProviders if (!this.sessionState.configurationProviders) { @@ -104,48 +126,33 @@ export class LoginComponent implements OnInit, OnDestroy { if (this.sessionState.configurationProviders && this.sessionState.configurationProviders.length > 0) { this.logger.debug(this, 'subscription - updating session config'); + this.sessionState.configurationProviders.map((configProvider) => { + configProvider.preAuthState = !!configProvider.preAuthState ? this.preAuthStateType.PreAuth : undefined; + }); this.selectedConfigProvider = this.sessionState.configurationProviders.find( - (authProvider) => authProvider.name === localStorage.getItem(this.authProviderStorageKey) + (authProvider) => authProvider.name === localStorage.getItem(this.authProviderStorageKey), ) || this.sessionState.configurationProviders[0]; this.onSelectAuthConfig(); } } - }) + }), ); + this.disposable = this.errorService.setTarget('login'); } - public async logoutOAuth(): Promise { - this.logger.debug(this, 'logoutOAuth'); - return this.authentication.logout(this.sessionState); - } - - public async login(): Promise { - this.logger.debug(this, 'LoginComponent - login'); - - if (this.selectedConfigProvider) { - if (this.selectedConfigProvider.isOAuth2) { - this.logger.debug(this, 'LoginComponent - login - oauth2'); - await this.authentication.oauthRedirect(this.selectedConfigProvider.name); - return; - } else if (this.selectedConfigProvider.customAuthFlow) { - throw new Error('Method not valid for a custom auth flow.'); - } - } + public ngAfterViewChecked(): void { + this.authPropertyInput.changes.subscribe(() => this.focusAuthProperty(false)); + this.preAuthPropertyInput.changes.subscribe(() => this.focusAuthProperty(true)); - let overlayRef: OverlayRef; - setTimeout(() => (overlayRef = this.busyService.show())); - try { - await this.authentication.login(this.loginData); - } finally { - this.logger.debug(this, 'LoginComponent - login - attempt completed'); - setTimeout(() => this.busyService.hide(overlayRef)); + if (this.firstTime) { + this.firstTime = false; + this.focusAuthProperty(true); } - - return Promise.resolve(); } public async ngOnInit(): Promise { + document.body.classList.add('recaptcha'); const config = await this.systemInfoService.getImxConfig(); if (config.DefaultHtmlTheme) { if (config.DefaultHtmlTheme === 'eui-auto-theme' && this.detector.getHighContrastMode() > 0) { @@ -170,16 +177,148 @@ export class LoginComponent implements OnInit, OnDestroy { } public ngOnDestroy(): void { + document.body.classList.remove('recaptcha'); + this.disposable(); this.subscriptions.forEach((subscription) => subscription.unsubscribe()); } + /** + * Calls authentication service logout function. + */ + public async logoutOAuth(): Promise { + this.logger.debug(this, 'logoutOAuth'); + return this.authentication.logout(this.sessionState); + } + + /** + * Calls the required login method. + */ + public async login(): Promise { + this.logger.debug(this, 'LoginComponent - login'); + + if (this.selectedConfigProvider) { + if (this.selectedConfigProvider.isOAuth2) { + this.logger.debug(this, 'LoginComponent - login - oauth2'); + await this.authentication.oauthRedirect(this.selectedConfigProvider.name); + return; + } else if (this.selectedConfigProvider.customAuthFlow) { + throw new Error('Method not valid for a custom auth flow.'); + } + } + + if (this.busyService.overlayRefs.length === 0) { + this.busyService.show(); + } + try { + await this.authentication.login(this.loginData); + } finally { + this.logger.debug(this, 'LoginComponent - login - attempt completed'); + this.busyService.hide(); + } + + return Promise.resolve(); + } + + /** + * Updates the localStorage and calls initCustAuthFlowView with the selected configuration provider. + */ public onSelectAuthConfig(): void { this.logger.debug(this, 'LoginComponent - onSelectAuthConfig', this.selectedConfigProvider.name); localStorage.setItem(this.authProviderStorageKey, this.selectedConfigProvider.name); this.loginData = { Module: this.selectedConfigProvider.name }; + this.configurationProviders.map((provider) => { + if (provider.preAuthState === this.preAuthStateType.Captcha || provider.preAuthState === this.preAuthStateType.Auth) { + provider.preAuthState = this.preAuthStateType.PreAuth; + } + }); this.initCustomAuthFlowView(this.selectedConfigProvider); } + public async createNewAccount(): Promise { + // Prevent the content from being cleared incase the sidesheet is closed unsuccessfully + this.initCustomAuthFlowView(this.newUserConfigProvider, false); + } + + /** + * Checks if the login proceess needs captcha verification. + */ + public async checkPreAuth(): Promise { + let overlayRef = this.busyService.show(); + try { + const response = await this.authentication.preAuth(this.loginData); + if (response) { + this.setupCaptcha(); + } else { + this.selectedConfigProvider.preAuthState = this.preAuthStateType.Auth; + this.focusAuthProperty(false); + } + } finally { + this.busyService.hide(overlayRef); + } + } + + /** + * Setup the selected configuration provider to preAuth state. + */ + public async backToPreAuth(): Promise { + this.selectedConfigProvider.preAuthState = this.preAuthStateType.PreAuth; + this.selectedConfigProvider.authProps + ?.filter((authProp) => !authProp.disabled) + .map((authProp) => { + if (this.loginData && authProp.name) delete this.loginData[authProp.name]; + }); + } + + /** + * Verify the captcha with the recaptcha image component. + */ + public async onVerifyCaptcha(): Promise { + await this.authentication.preAuthVerify(this.captchaService.Response); + this.selectedConfigProvider.preAuthState = this.preAuthStateType.Auth; + this.focusAuthProperty(false); + } + + /** + * Checks, weather the form should be hidden. + */ + public get isFormHidden(): boolean { + return this.selectedConfigProvider?.isOAuth2 || !!this.selectedConfigProvider.preAuthProps?.length; + } + + /** + * Returns the selected configuration providere preAuthState. + */ + public get selectedProviderPreAuthState(): null | PreAuthStateType { + return this.selectedConfigProvider?.preAuthState ?? null; + } + + /** + * Checks, weather the login button should be hidden. + */ + public get showLoginButton(): boolean { + return this.selectedProviderPreAuthState == this.preAuthStateType.Auth || !this.selectedProviderPreAuthState; + } + + /** + * Checks, weather the back button should be hidden. + */ + public get showBackButton(): boolean { + return ( + this.selectedProviderPreAuthState == this.preAuthStateType.Auth || this.selectedProviderPreAuthState == this.preAuthStateType.Captcha + ); + } + + public get showCreateAccountButton(): boolean { + return ( + this.newUserConfigProvider && + (this.selectedProviderPreAuthState === this.preAuthStateType.PreAuth || + (!this.selectedProviderPreAuthState && !!this.selectedConfigProvider?.authProps?.length)) + ); + } + + /** + * Builds the login options. + */ private buildConfigurationProviders(): void { const providers = this.sessionState?.configurationProviders ?? []; @@ -197,6 +336,9 @@ export class LoginComponent implements OnInit, OnDestroy { this.configurationProviders = providers; } + /** + * Initializes the custom authentication by creating the entry component. + */ private initCustomAuthFlowView(configProvider: AuthConfigProvider, shouldClear = true): void { if (this.directive) { if (shouldClear) { @@ -204,14 +346,42 @@ export class LoginComponent implements OnInit, OnDestroy { } if (configProvider?.customAuthFlow) { this.directive.viewContainerRef.createComponent( - this.componentFactoryResolver.resolveComponentFactory(configProvider.customAuthFlow.getEntryComponent()) + this.componentFactoryResolver.resolveComponentFactory(configProvider.customAuthFlow.getEntryComponent()), ); } } } - public async createNewAccount(): Promise { - // Prevent the content from being cleared incase the sidesheet is closed unsuccessfully - this.initCustomAuthFlowView(this.newUserConfigProvider, false); + /** + * Setup captcha verification. + */ + private async setupCaptcha(): Promise { + if (this.captchaService.isReCaptchaV3) { + let overlayRef = this.busyService.show(); + this.recaptchaV3Service.execute('login').subscribe(async (result) => { + try { + await this.authentication.preAuthVerify(result); + this.selectedConfigProvider.preAuthState = this.preAuthStateType.Auth; + } finally { + this.busyService.hide(overlayRef); + } + }); + } else { + this.selectedConfigProvider.preAuthState = this.preAuthStateType.Captcha; + } + } + + /** + * Focuses an authentication property + * + */ + private focusAuthProperty(preAuth: boolean) { + this.changeDetection.detectChanges(); + const index = preAuth ? 0 : 1; + const iterable = preAuth ? this.preAuthPropertyInput.toArray() : this.authPropertyInput.toArray(); + if (iterable.length > index) { + iterable[index]?.focus(); + } + this.changeDetection.detectChanges(); } } diff --git a/imxweb/projects/qbm/src/lib/mast-head/mast-head-menu-item.interface.ts b/imxweb/projects/qbm/src/lib/mast-head/mast-head-menu-item.interface.ts index 3b509a2be..9039b72e2 100644 --- a/imxweb/projects/qbm/src/lib/mast-head/mast-head-menu-item.interface.ts +++ b/imxweb/projects/qbm/src/lib/mast-head/mast-head-menu-item.interface.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR diff --git a/imxweb/projects/qbm/src/lib/mast-head/mast-head-menu.interface.ts b/imxweb/projects/qbm/src/lib/mast-head/mast-head-menu.interface.ts index 8ce3ec48a..e690d231e 100644 --- a/imxweb/projects/qbm/src/lib/mast-head/mast-head-menu.interface.ts +++ b/imxweb/projects/qbm/src/lib/mast-head/mast-head-menu.interface.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR diff --git a/imxweb/projects/qbm/src/lib/mast-head/mast-head.component.html b/imxweb/projects/qbm/src/lib/mast-head/mast-head.component.html index 80d77b9e1..cf5542937 100644 --- a/imxweb/projects/qbm/src/lib/mast-head/mast-head.component.html +++ b/imxweb/projects/qbm/src/lib/mast-head/mast-head.component.html @@ -1,12 +1,25 @@ - + - + -

    +

    {{ productName }} {{ appConfig?.Config?.Title }}

    @@ -17,15 +30,22 @@
    - +
    - @@ -35,8 +55,7 @@ #LDS#Log out - @@ -44,8 +63,7 @@ - diff --git a/imxweb/projects/qbm/src/lib/mast-head/mast-head.component.scss b/imxweb/projects/qbm/src/lib/mast-head/mast-head.component.scss index 030d96cee..72df502f3 100644 --- a/imxweb/projects/qbm/src/lib/mast-head/mast-head.component.scss +++ b/imxweb/projects/qbm/src/lib/mast-head/mast-head.component.scss @@ -1,6 +1,3 @@ -@import "@elemental-ui/core/src/styles/_palette.scss"; -@import '@elemental-ui/core/src/styles/_eui_palette.scss'; - :host { .imx-masthead-app-name { display: inline-block; @@ -13,6 +10,8 @@ } .imx-masthead--controls { + display: flex; + button[mat-button] { &:not(.imx-masthead-user-button) { padding: 0; @@ -31,68 +30,9 @@ } } -/* hide the logo inside the masthead if needed */ -::ng-deep eui-masthead.no-logo eui-logo { - display: none; -} - .custom-logo { margin-left: -16px; max-height: 50px; max-width: 300px; cursor: pointer; -} - -@media only screen and (max-width: 768px) { - :host { - eui-masthead { - .mat-toolbar { - .mat-toolbar-row { - width: unset !important; - justify-content: center; - } - - .imx-masthead-space, - .imx-masthead--controls { - display: none; - } - } - } - - .eui-top-navigation-mobile { - .eui-top-navigation-mobile-footer { - .mat-button { - &.imx-masthead--icon-button { - width: 100%; - - .mat-button-wrapper span { - display: inline-block; - } - } - } - } - } - } -} - -.eui-dark-theme { - :host { - .mat-toolbar.mat-primary { - background-color: $color-blue-80; - color: $color-gray-5; - } - } -} - -.eui-contrast-theme { - :host { - ::ng-deep .eui-masthead { - background-color: $color-blue-80; - } - - .mat-toolbar.mat-primary { - background-color: $color-blue-80; - color: $color-gray-0; - } - } -} +} \ No newline at end of file diff --git a/imxweb/projects/qbm/src/lib/mast-head/mast-head.component.ts b/imxweb/projects/qbm/src/lib/mast-head/mast-head.component.ts index a1d8f6db5..9c9e5f2c6 100644 --- a/imxweb/projects/qbm/src/lib/mast-head/mast-head.component.ts +++ b/imxweb/projects/qbm/src/lib/mast-head/mast-head.component.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -24,24 +24,25 @@ * */ -import { OverlayRef } from '@angular/cdk/overlay'; -import { Component, Input, OnDestroy } from '@angular/core'; +import { Component, effect, Input, OnDestroy } from '@angular/core'; import { MatDialog } from '@angular/material/dialog'; import { Router } from '@angular/router'; import { EuiLoadingService, EuiSidesheetService, EuiTopNavigationItem } from '@elemental-ui/core'; import { Subscription } from 'rxjs'; -import { AppConfigService } from '../appConfig/appConfig.service'; +import { TranslateService } from '@ngx-translate/core'; import { AboutComponent } from '../about/About.component'; +import { AppConfigService } from '../appConfig/appConfig.service'; import { AuthenticationService } from '../authentication/authentication.service'; -import { ISessionState } from '../session/session-state'; -import { MastHeadService } from './mast-head.service'; +import { calculateSidesheetWidth, isMobile } from '../base/sidesheet-helper'; import { ConfirmationService } from '../confirmation/confirmation.service'; -import { SystemInfoService } from '../system-info/system-info.service'; import { ConnectionComponent } from '../connection/connection.component'; -import { TranslateService } from '@ngx-translate/core'; import { ExtService } from '../ext/ext.service'; import { IExtension } from '../ext/extension'; +import { ProcessingQueueService } from '../processing-queue/processing-queue.service'; +import { ISessionState } from '../session/session-state'; +import { SystemInfoService } from '../system-info/system-info.service'; +import { MastHeadService } from './mast-head.service'; /** * Masthead of IMX web applications. It can contain dynamic menus or buttons, emitting menus/menu itmes when selected. @@ -104,10 +105,10 @@ import { IExtension } from '../ext/extension'; @Component({ selector: 'imx-mast-head', templateUrl: './mast-head.component.html', - styleUrls: ['./mast-head.component.scss'] + styleUrls: ['./mast-head.component.scss'], }) export class MastHeadComponent implements OnDestroy { - + public isQueueFinished: boolean; /** * When these {@link EuiTopNavigationItem|items} are set, the menu is displayed. */ @@ -118,17 +119,16 @@ export class MastHeadComponent implements OnDestroy { } public get isMobile(): boolean { - return document.body.offsetWidth <= 768; + return isMobile(); } public get isAuthenticated(): boolean { - return this.sessionState?.IsLoggedIn; + return this.sessionState?.IsLoggedIn ?? false; } public get isAppOverview(): boolean { return this.appConfig?.Config?.WebAppIndex === 'admin' && this.router.url === '/'; } - public get isAppAdminPortal(): boolean { return this.appConfig?.Config?.WebAppIndex === 'admin' && this.router.url === '/dashboard'; } @@ -146,6 +146,7 @@ export class MastHeadComponent implements OnDestroy { private readonly router: Router, private readonly dialog: MatDialog, private readonly confirmationService: ConfirmationService, + private queueService: ProcessingQueueService, private readonly busyService: EuiLoadingService, private readonly mastHeadService: MastHeadService, private readonly authentication: AuthenticationService, @@ -153,12 +154,13 @@ export class MastHeadComponent implements OnDestroy { private readonly translate: TranslateService, private readonly extService: ExtService, ) { - this.subscriptions.push(this.authentication.onSessionResponse.subscribe((sessionState: ISessionState) => - this.sessionState = sessionState - )); + effect(() => (this.isQueueFinished = this.queueService.isAllGroupsCompleted())); + this.subscriptions.push( + this.authentication.onSessionResponse.subscribe((sessionState: ISessionState) => (this.sessionState = sessionState)), + ); // apply custom logo from configuration - this.systemInfoService.getImxConfig().then(config => { + this.systemInfoService.getImxConfig().then((config) => { if (config.CompanyLogoUrl) { // make relative URL absolute if needed this.logoUrl = new URL(config.CompanyLogoUrl, this.appConfig.BaseUrl).href; @@ -167,15 +169,13 @@ export class MastHeadComponent implements OnDestroy { if (name) { this.productName = name; } - }); this.getDynamicExtensions(); } - public getDynamicExtensions(): void{ + public getDynamicExtensions(): void { this.extensions = this.extService.Registry['mastHead']; - } public showExtension(extension: IExtension): void { @@ -185,14 +185,14 @@ export class MastHeadComponent implements OnDestroy { } public ngOnDestroy(): void { - this.subscriptions.forEach(s => s.unsubscribe()); + this.subscriptions.forEach((s) => s.unsubscribe()); } /** * For navigating home, you know. */ public goHome(): void { - if (!this.isAppOverview) this.router.navigate([this.appConfig.Config.routeConfig.start], { queryParams: {} }); + if (!this.isAppOverview) this.router.navigate([this.appConfig.Config.routeConfig?.start], { queryParams: {} }); } /** @@ -208,30 +208,55 @@ export class MastHeadComponent implements OnDestroy { public async openConnection(): Promise { const data = await this.mastHeadService.getConnectionData(this.appConfig.Config.WebAppIndex); - await this.sideSheetService.open(ConnectionComponent, { - icon: 'rss', - title: this.translate.instant('#LDS#Heading Connection Information'), - padding: '0px', - width: 'max(700px, 60%)', - data: data - }).afterClosed().toPromise(); + await this.sideSheetService + .open(ConnectionComponent, { + icon: 'rss', + title: this.translate.instant('#LDS#Heading Connection Information'), + padding: '0px', + width: calculateSidesheetWidth(), + data: data, + }) + .afterClosed() + .toPromise(); } /** * Logs out and kills the session. */ public async logout(): Promise { - if (await this.confirmationService.confirm({ - Title: '#LDS#Heading Log Out', - Message: '#LDS#Are you sure you want to log out?', - identifier: 'confirm-logout-' - })) { - let overlayRef: OverlayRef; - setTimeout(() => (overlayRef = this.busyService.show())); + if ( + this.isQueueFinished && + (await this.confirmationService.confirm({ + Title: '#LDS#Heading Log Out', + Message: '#LDS#Are you sure you want to log out?', + identifier: 'confirm-logout-', + })) + ) { + if (this.busyService.overlayRefs.length === 0) { + this.busyService.show(); + } + try { + this.queueService.clearProcessing(); + await this.authentication.logout(); + } finally { + this.busyService.hide(); + } + } + + if ( + !this.isQueueFinished && + (await this.confirmationService.confirm({ + Title: '#LDS#Heading Unfinished Processes', + Message: '#LDS#There are still background processes that are not completed. Are you sure you want to log out?', + identifier: 'confirm-logout-busy-queue', + })) + ) { + this.busyService.show(); try { + this.queueService.clearProcessing(); await this.authentication.logout(); } finally { - setTimeout(() => this.busyService.hide(overlayRef)); + this.busyService.hide(); } } } diff --git a/imxweb/projects/qbm/src/lib/mast-head/mast-head.module.ts b/imxweb/projects/qbm/src/lib/mast-head/mast-head.module.ts index 475913018..3cb5457dd 100644 --- a/imxweb/projects/qbm/src/lib/mast-head/mast-head.module.ts +++ b/imxweb/projects/qbm/src/lib/mast-head/mast-head.module.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -27,11 +27,12 @@ import { CommonModule } from '@angular/common'; import { NgModule } from '@angular/core'; import { EuiCoreModule, EuiMaterialModule } from '@elemental-ui/core'; -import { TranslateModule, TranslateLoader, MissingTranslationHandler } from '@ngx-translate/core'; +import { MissingTranslationHandler, TranslateLoader, TranslateModule } from '@ngx-translate/core'; -import { MastHeadComponent } from './mast-head.component'; -import { ImxTranslateLoader } from '../translation/imx-translate-loader'; +import { ExtModule } from '../ext/ext.module'; import { ImxMissingTranslationHandler } from '../translation/imx-missing-translation-handler'; +import { ImxTranslateLoader } from '../translation/imx-translate-loader'; +import { MastHeadComponent } from './mast-head.component'; import { MastHeadService } from './mast-head.service'; @NgModule({ @@ -40,22 +41,19 @@ import { MastHeadService } from './mast-head.service'; CommonModule, EuiCoreModule, EuiMaterialModule, + ExtModule, TranslateModule.forRoot({ loader: { provide: TranslateLoader, - useClass: ImxTranslateLoader + useClass: ImxTranslateLoader, }, missingTranslationHandler: { provide: MissingTranslationHandler, - useClass: ImxMissingTranslationHandler - } + useClass: ImxMissingTranslationHandler, + }, }), ], - exports: [ - MastHeadComponent - ], - providers: [ - MastHeadService - ] + exports: [MastHeadComponent], + providers: [MastHeadService], }) -export class MastHeadModule { } +export class MastHeadModule {} diff --git a/imxweb/projects/qbm/src/lib/mast-head/mast-head.service.ts b/imxweb/projects/qbm/src/lib/mast-head/mast-head.service.ts index 4ba16e36a..48627da8d 100644 --- a/imxweb/projects/qbm/src/lib/mast-head/mast-head.service.ts +++ b/imxweb/projects/qbm/src/lib/mast-head/mast-head.service.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -25,23 +25,23 @@ */ import { Injectable } from '@angular/core'; +import { SessionInfoData } from '@imx-modules/imx-api-qbm'; +import { TranslateService } from '@ngx-translate/core'; import { Subject } from 'rxjs'; -import { MastHeadMenu } from './mast-head-menu.interface'; -import { MastHeadMenuItem } from './mast-head-menu-item.interface'; import { AppConfigService } from '../appConfig/appConfig.service'; -import { TranslateService } from '@ngx-translate/core'; -import { SessionInfoData } from 'imx-api-qbm'; +import { MastHeadMenuItem } from './mast-head-menu-item.interface'; +import { MastHeadMenu } from './mast-head-menu.interface'; @Injectable({ - providedIn: 'root' + providedIn: 'root', }) export class MastHeadService { public itemClickedSubject: Subject = new Subject(); constructor( private readonly appConfig: AppConfigService, - private readonly translate: TranslateService - ) { } + private readonly translate: TranslateService, + ) {} public itemClicked(menuItem: MastHeadMenu | MastHeadMenuItem): void { this.itemClickedSubject.next(menuItem); @@ -67,6 +67,9 @@ export class MastHeadService { private getLocaleDocumentationPath(): string { const docPaths = this.appConfig.Config.LocalDocPath; const currentLanguage = this.translate.currentLang; + if (!docPaths) { + return ''; + } const directLocaleMatch = docPaths[currentLanguage]; // If the browser culture directly matches a key for documentation paths, then use that if (directLocaleMatch) { @@ -77,6 +80,6 @@ export class MastHeadService { const docKeys = Object.keys(docPaths); const matchingKey = docKeys.find((element) => element.includes(currentLanguageShort)); // If still no match, fallback to the first documentation path entry - return docPaths[matchingKey] ?? docPaths[docKeys[0]]; + return (matchingKey ? docPaths[matchingKey] : docPaths[docKeys[0]]) ?? docPaths[docKeys[0]]; } } diff --git a/imxweb/projects/qbm/src/lib/master-detail/master-detail.component.html b/imxweb/projects/qbm/src/lib/master-detail/master-detail.component.html deleted file mode 100644 index ee206cbd4..000000000 --- a/imxweb/projects/qbm/src/lib/master-detail/master-detail.component.html +++ /dev/null @@ -1,15 +0,0 @@ -
    -
    - -
    -
    -
    - -
    -
    -
    - -
    -
    -
    -
    \ No newline at end of file diff --git a/imxweb/projects/qbm/src/lib/master-detail/master-detail.component.scss b/imxweb/projects/qbm/src/lib/master-detail/master-detail.component.scss index ae0d0e492..2a6304611 100644 --- a/imxweb/projects/qbm/src/lib/master-detail/master-detail.component.scss +++ b/imxweb/projects/qbm/src/lib/master-detail/master-detail.component.scss @@ -1,5 +1,6 @@ @use '@angular/material' as mat; -@import "variables.scss"; +@import '@elemental-ui/core/src/styles/_eui_palette.scss'; +@import 'base/variables'; $headerheight: 43; @@ -25,17 +26,17 @@ $headerheight: 43; } .imx-mdc-detail-opened .imx-mdc-master { - max-width: calc( 100% - 40em ); + max-width: calc(100% - 40em); width: 100%; } .imx-mdc-detail-close .imx-mdc-master { - max-width: calc( 100% - 30px ); + max-width: calc(100% - 30px); width: 100%; } .imx-mdc-detail { - background: none repeat scroll 0 0 mat.get-color-from-palette($asher-gray-palette, 900); + background: none repeat scroll 0 0 mat.m2-get-color-from-palette($asher-gray-palette, 900); border-width: 0; display: block; position: absolute; @@ -257,7 +258,7 @@ $headerheight: 43; /* #region VI_Styles_LayoutPanel_Default (Detail Pane CSS) */ .imx-mdc-detail .LayoutpPropRow { - border-bottom: 1px solid $VI_Common_Color_LightGray; + border-bottom: 1px solid $color-gray-30; line-height: 20px; min-height: 26px; } @@ -265,7 +266,7 @@ $headerheight: 43; .imx-mdc-detail .LayoutpPropCol0 { width: 146px; max-width: 146px; - color: $VI_Common_Color_Font; + color: $color-gray-80; } .imx-mdc-detail .LayoutpPropCol1 { @@ -273,8 +274,8 @@ $headerheight: 43; /* leave some space for scrollbars*/ max-width: 245px; /* #27180 */ - color: $VI_Common_Color_Font_Secondary; + color: $color-gray-80; font-weight: bold; } -/*#endregion*/ \ No newline at end of file +/*#endregion*/ diff --git a/imxweb/projects/qbm/src/lib/master-detail/master-detail.component.ts b/imxweb/projects/qbm/src/lib/master-detail/master-detail.component.ts deleted file mode 100644 index 00e43faa3..000000000 --- a/imxweb/projects/qbm/src/lib/master-detail/master-detail.component.ts +++ /dev/null @@ -1,139 +0,0 @@ -/* - * ONE IDENTITY LLC. PROPRIETARY INFORMATION - * - * This software is confidential. One Identity, LLC. or one of its affiliates or - * subsidiaries, has supplied this software to you under terms of a - * license agreement, nondisclosure agreement or both. - * - * You may not copy, disclose, or use this software except in accordance with - * those terms. - * - * - * Copyright 2023 One Identity LLC. - * ALL RIGHTS RESERVED. - * - * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR - * WARRANTIES ABOUT THE SUITABILITY OF THE SOFTWARE, - * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED - * TO THE IMPLIED WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE, OR - * NON-INFRINGEMENT. ONE IDENTITY LLC. SHALL NOT BE - * LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE - * AS A RESULT OF USING, MODIFYING OR DISTRIBUTING - * THIS SOFTWARE OR ITS DERIVATIVES. - * - */ - -import { Component, OnInit, ViewEncapsulation, HostBinding, ElementRef, ViewChild } from '@angular/core'; -import { DeviceStateService } from '../services/device-state.service'; -import * as elementResizeDetector from 'element-resize-detector'; - -/** @deprecated This component is deprecated and will be removed in a future release.*/ -@Component({ - selector: 'imx-master-detail', - templateUrl: './master-detail.component.html', - styleUrls: ['./master-detail.component.scss'], - encapsulation: ViewEncapsulation.None -}) -export class MasterDetailComponent implements OnInit { - public detailClosed: boolean; - public isSinglePanel: boolean; - public modalRoot: ElementRef; - - @HostBinding('class') public defaultHostClasses = 'imx-flex imx-flex-child'; - - @ViewChild('mdcContainer', { static: true }) public mdcContainer: ElementRef; - @ViewChild('mdcDetail', { static: true }) public mdcDetail: ElementRef; - - private detailContainerClass = 'imx-mdc-detailPopupContainer'; - - constructor(public deviceStateService: DeviceStateService) {} - - public ngOnInit() { - this.detailClosed = false; - this.isSinglePanel = false; - if (this.isPhoneDevice()) { - // initially close the detail panel on phone device - this.toggleDetailPane(false); - } - - const elementResizeDetectorMaker = elementResizeDetector; - - const erd = elementResizeDetectorMaker({ strategy: 'scroll' }); - erd.listenTo(this.mdcContainer.nativeElement, () => { - this.checkMode(); - }); - } - - // #region Css Classes - public masterDetailRootClasses() { - return { - 'imx-mdc-masterdetail imx-flex-child': true, - 'imx-mdc-detail-close': this.detailClosed, - 'imx-mdc-detail-opened': !this.detailClosed, - 'imx-mdc-singlePanel': this.isSinglePanel - }; - } - - public masterClasses() { - return 'imx-mdc-master imx-flex'; - } - - public detailClasses() { - return { - 'imx-mdc-detail imx-flex': true, - 'imx-mdc-detail-close': this.detailClosed - }; - } - - public detailHeaderClasses() { - return 'imx-mdc-detail-header'; - } - - public detailContentClasses() { - return { - 'imx-mdc-detail-content imx-flex': true, - 'imx-mdc-detail-closed': this.detailClosed - }; - } - - public detailContentWrapperClasses() { - return 'imx-mdc-detail-contentWrapper'; - } - // #endregion - - public getDeviceState(): string { - return this.deviceStateService.deviceState; - } - - public isPhoneDevice(): boolean { - return this.deviceStateService.isPhoneDevice(); - } - - public toggleDetailPane(state?: boolean) { - this.detailClosed = !this.detailClosed; - // force to open or to close the detail panel - state = typeof state === 'boolean' ? state : undefined; - if (state !== undefined) { - this.detailClosed = state; - } - } - - public openDetailPane() { - if (this.isPhoneDevice()) { - this.toggleDetailPane(false); - } - } - - public checkMode() { - const detailPopupContainer = this.mdcContainer; - if (this.isPhoneDevice()) { - this.isSinglePanel = true; - return; - } - // normal mode - // --> move detail panel next to the master panel - this.mdcContainer.nativeElement.appendChild(this.mdcDetail.nativeElement); - this.isSinglePanel = false; - } -} diff --git a/imxweb/projects/qbm/src/lib/menu/menu-item/menu-item.interface.ts b/imxweb/projects/qbm/src/lib/menu/menu-item/menu-item.interface.ts index 94cca45fc..13ed7a6f8 100644 --- a/imxweb/projects/qbm/src/lib/menu/menu-item/menu-item.interface.ts +++ b/imxweb/projects/qbm/src/lib/menu/menu-item/menu-item.interface.ts @@ -1,4 +1,4 @@ -import { ProjectConfig } from 'imx-api-qbm'; +import { ProjectConfig } from '@imx-modules/imx-api-qbm'; import { NavigationCommandsMenuItem } from './navigation-commands-menu-item.interface'; /* @@ -12,7 +12,7 @@ import { NavigationCommandsMenuItem } from './navigation-commands-menu-item.inte * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -33,7 +33,7 @@ export interface MenuItem { readonly id?: string; /** Display name. */ - readonly title: string; + readonly title?: string; /** Returns a descriptive text, intended for tooltips. */ readonly description?: string; @@ -52,7 +52,11 @@ export interface MenuItem { /** Submenu items. */ items?: MenuItem[]; - } -export type MenuFactory = (preProps: string[], features: string[], projectConfig?: ProjectConfig, groups?: string[]) => MenuItem; +export type MenuFactory = ( + preProps: string[], + features: string[], + projectConfig?: ProjectConfig, + groups?: string[], +) => MenuItem | undefined; diff --git a/imxweb/projects/qbm/src/lib/menu/menu-item/menu-item.spec.ts b/imxweb/projects/qbm/src/lib/menu/menu-item/menu-item.spec.ts index 88cd626e6..8e960f27b 100644 --- a/imxweb/projects/qbm/src/lib/menu/menu-item/menu-item.spec.ts +++ b/imxweb/projects/qbm/src/lib/menu/menu-item/menu-item.spec.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -24,87 +24,53 @@ * */ -import { GroupMenuItem } from './group-menu-item'; -import { NavigationMenuItem } from './navigation-menu-item'; import { RelatedApplicationMenuItem } from './related-application-menu-item'; -describe('GroupMenuItem', () => { - [ - { - menuItems: [], - expectedEnabled: false - }, - { - menuItems: [{ title: '' }], - expectedEnabled: false - }, - { - menuItems: [{ title: '' }], - expectedEnabled: false - }, - { - menuItems: [{ title: '' }], - expectedEnabled: true - } - ].forEach(testcase => - it('should be created with ' + (testcase.menuItems ? testcase.menuItems.length.toString() : 'undefined') + ' menuItems', () => { - const item = new GroupMenuItem('', '', testcase.menuItems); - expect(item.items.length).toEqual(testcase.menuItems.length); - }) - ); -}); - -describe('NavigationMenuItem', () => { - it('should be created', () => { - expect(new NavigationMenuItem('', '', '', '')).toBeDefined(); - }); -}); - describe('RelatedApplicationMenuItem', () => { [ { - appDisplayType: 'NR', - expectedTrigger: () => {} + appDisplayType: 'NR', + expectedTrigger: () => {}, }, { - appDisplayType: 'PP', - expectedTrigger: () => {} + appDisplayType: 'PP', + expectedTrigger: () => {}, }, { - appDisplayType: 'NV', - expectedTrigger: () => {} + appDisplayType: 'NV', + expectedTrigger: () => {}, }, { - appDisplayType: 'NT', - expectedTrigger: () => {} - } - ].forEach(testcase => + appDisplayType: 'NT', + expectedTrigger: () => {}, + }, + ].forEach((testcase) => it('should be created', () => { - const app = { - uid: '', - displayName: '', - description: '', - displayType: testcase.appDisplayType as 'NR' | 'PP' | 'NV' | 'NT', - uidParent: '' - }; + const app = { + uid: '', + displayName: '', + description: '', + displayType: testcase.appDisplayType as 'NR' | 'PP' | 'NV' | 'NT', + uidParent: '', + }; - const item = new RelatedApplicationMenuItem(app); + const item = new RelatedApplicationMenuItem(app); - expect(item.id).toEqual(app.uid); - expect(item.title).toEqual(app.displayName); - expect(item.description).toEqual(app.description); - expect(() => item.Trigger()).not.toThrow(); - }) + expect(item.id).toEqual(app.uid); + expect(item.title).toEqual(app.displayName); + expect(item.description).toEqual(app.description); + expect(() => item.Trigger()).not.toThrow(); + }), ); it('should be created', () => { const item = new RelatedApplicationMenuItem({ - uid: '', - displayName: '', - description: '', - displayType: undefined as 'NR' | 'PP' | 'NV' | 'NT', - uidParent: '' + uid: '', + displayName: '', + description: '', + displayType: undefined as any, + uidParent: '', }); expect(() => item.Trigger()).toThrow(); - }) -}); \ No newline at end of file + }); +}); diff --git a/imxweb/projects/qbm/src/lib/menu/menu-item/navigation-commands-menu-item.interface.ts b/imxweb/projects/qbm/src/lib/menu/menu-item/navigation-commands-menu-item.interface.ts index 126e17bd7..42bfa0a07 100644 --- a/imxweb/projects/qbm/src/lib/menu/menu-item/navigation-commands-menu-item.interface.ts +++ b/imxweb/projects/qbm/src/lib/menu/menu-item/navigation-commands-menu-item.interface.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR diff --git a/imxweb/projects/qbm/src/lib/menu/menu-item/related-application-menu-item.ts b/imxweb/projects/qbm/src/lib/menu/menu-item/related-application-menu-item.ts index 6441cde61..ad2a4e52c 100644 --- a/imxweb/projects/qbm/src/lib/menu/menu-item/related-application-menu-item.ts +++ b/imxweb/projects/qbm/src/lib/menu/menu-item/related-application-menu-item.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -29,34 +29,44 @@ import { RelatedApplication } from './related-application.interface'; /** Menu item for a link to an external web site */ export class RelatedApplicationMenuItem implements MenuItem { - public get id(): string { return this.app.uid; } - public get title(): string { return this.app.displayName; } - public get description(): string { return this.app.description; } + public get id(): string { + return this.app.uid; + } + public get title(): string { + return this.app.displayName; + } + public get description(): string { + return this.app.description; + } - constructor(private readonly app: RelatedApplication) { } + constructor(private readonly app: RelatedApplication) {} - public Trigger(): void { - // TODO (TFS number 805756): VI.WebRuntime.RuntimeUtil.CheckIsValidUrlForRedirect(url); + public Trigger(): void { + // TODO (TFS number 805756): VI.WebRuntime.RuntimeUtil.CheckIsValidUrlForRedirect(url); - if (this.app.displayType === 'NV') { // content and navigation - // TODO (TFS number 805756): show in VI_Common_ExternalFormHost - return; - } - - if (this.app.displayType === 'PP') { // Popup - // TODO (TFS number 805756): show in popup - return; - } + if (this.app.displayType === 'NV') { + // content and navigation + // TODO (TFS number 805756): show in VI_Common_ExternalFormHost + return; + } - if (this.app.displayType === 'NR') { // Content - return; - } + if (this.app.displayType === 'PP') { + // Popup + // TODO (TFS number 805756): show in popup + return; + } - if (this.app.displayType === 'NT') { // Content, navigation and header - // TODO (TFS number 805756): directly redirect to the URL - return; - } + if (this.app.displayType === 'NR') { + // Content + return; + } - throw new Error('MenuItem - the related application has an invalid displayType.'); + if (this.app.displayType === 'NT') { + // Content, navigation and header + // TODO (TFS number 805756): directly redirect to the URL + return; } + + throw new Error('MenuItem - the related application has an invalid displayType.'); + } } diff --git a/imxweb/projects/qbm/src/lib/menu/menu-item/related-application.interface.ts b/imxweb/projects/qbm/src/lib/menu/menu-item/related-application.interface.ts index 4556f147d..0c385ce8f 100644 --- a/imxweb/projects/qbm/src/lib/menu/menu-item/related-application.interface.ts +++ b/imxweb/projects/qbm/src/lib/menu/menu-item/related-application.interface.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -26,9 +26,9 @@ /** Represents a link to an external web site that should be displayed in the menu. */ export interface RelatedApplication { - displayType: 'NR' | 'PP' | 'NV' | 'NT'; - uid: string; - displayName: string; - description: string; - uidParent: string; + displayType: 'NR' | 'PP' | 'NV' | 'NT'; + uid: string; + displayName: string; + description: string; + uidParent: string; } diff --git a/imxweb/projects/qbm/src/lib/menu/menu.component.html b/imxweb/projects/qbm/src/lib/menu/menu.component.html deleted file mode 100644 index 8c0209df0..000000000 --- a/imxweb/projects/qbm/src/lib/menu/menu.component.html +++ /dev/null @@ -1,19 +0,0 @@ - diff --git a/imxweb/projects/qbm/src/lib/menu/menu.component.scss b/imxweb/projects/qbm/src/lib/menu/menu.component.scss deleted file mode 100644 index 69d6c73f0..000000000 --- a/imxweb/projects/qbm/src/lib/menu/menu.component.scss +++ /dev/null @@ -1,113 +0,0 @@ -@import "variables.scss"; -@import '@elemental-ui/core/src/styles/_eui_palette.scss'; - -:host { - background-color: $Imx_White-two; - - button.mat-menu-item, - div.mat-menu-content, - .mat-tab-link { - font-style: normal; - font-stretch: normal; - line-height: normal; - letter-spacing: normal; - color: $VI_Common_Color_Gray; - min-width: 10px !important; - } - - .mat-tab-link, - .mat-tab-link:focus, - .mat-tab-link:hover { - text-decoration: none; - } - - .mat-tab-link.mat-tab-label-active { - font-weight: bold; - } - - span { - display: inline-block !important; - } - - button.mat-menu-item { - box-sizing: border-box; - } - - button.mat-menu-item:hover, - button.mat-menu-item:focus { - background-color: $white !important; - } - - .mat-tab-nav-bar { - background-color: $white; - - .mat-tab-link { - font-size: 16px; - color: $black-6; - } - } - - .imx-mein-menu-item { - font-size: 16px; - padding: 10px 24px 10px 24px; - color: $black-7; - } -} - -.eui-dark-theme { - :host { - background-color: $color-gray-80; - - button.mat-menu-item, - div.mat-menu-content, - .mat-tab-link { - color: $color-gray-5; - } - - button.mat-menu-item:hover, - button.mat-menu-item:focus { - background-color: $color-gray-70; - } - - .mat-tab-nav-bar { - background-color: $color-gray-80; - - .mat-tab-link { - color: $color-gray-5; - } - } - - .imx-mein-menu-item { - color: $color-gray-5; - } - } -} - -.eui-contrast-theme { - :host { - background-color: $color-gray-100; - - button.mat-menu-item, - div.mat-menu-content, - .mat-tab-link { - color: $color-gray-0; - } - - button.mat-menu-item:hover, - button.mat-menu-item:focus { - background-color: $color-gray-90; - } - - .mat-tab-nav-bar { - background-color: $color-gray-100; - - .mat-tab-link { - color: $color-gray-0; - } - } - - .imx-mein-menu-item { - color: $color-gray-0; - } - } -} diff --git a/imxweb/projects/qbm/src/lib/menu/menu.component.ts b/imxweb/projects/qbm/src/lib/menu/menu.component.ts deleted file mode 100644 index b42e42a6b..000000000 --- a/imxweb/projects/qbm/src/lib/menu/menu.component.ts +++ /dev/null @@ -1,106 +0,0 @@ -/* - * ONE IDENTITY LLC. PROPRIETARY INFORMATION - * - * This software is confidential. One Identity, LLC. or one of its affiliates or - * subsidiaries, has supplied this software to you under terms of a - * license agreement, nondisclosure agreement or both. - * - * You may not copy, disclose, or use this software except in accordance with - * those terms. - * - * - * Copyright 2023 One Identity LLC. - * ALL RIGHTS RESERVED. - * - * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR - * WARRANTIES ABOUT THE SUITABILITY OF THE SOFTWARE, - * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED - * TO THE IMPLIED WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE, OR - * NON-INFRINGEMENT. ONE IDENTITY LLC. SHALL NOT BE - * LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE - * AS A RESULT OF USING, MODIFYING OR DISTRIBUTING - * THIS SOFTWARE OR ITS DERIVATIVES. - * - */ - -import { Component, ErrorHandler, Input } from '@angular/core'; -import { Router } from '@angular/router'; -import { TranslateService } from '@ngx-translate/core'; - -import { MenuItem } from './menu-item/menu-item.interface'; -import { ClassloggerService } from '../classlogger/classlogger.service'; - -/** - * Displays a menu and provides logic for navigation - */ -@Component({ - selector: 'imx-menu', - templateUrl: './menu.component.html', - styleUrls: ['./menu.component.scss'] -}) -export class MenuComponent { -/** - * The menu structure - */ - @Input() public menuItems: MenuItem[]; - - private errorMessageNonExistingRoute = ''; - - constructor( - private readonly router: Router, - private readonly logger: ClassloggerService, - private readonly errorHandler: ErrorHandler, - translator: TranslateService) { - translator.get('#LDS#the route does not exist').subscribe(value => this.errorMessageNonExistingRoute = value); - } - - public isActive(item: MenuItem): boolean { - if (!item) { - return false; - } - - if (item.items) { - for (const subitem of item.items) { - if (this.isActive(subitem)) { - return true; - } - } - } - - const itemIsActive = this.router.url === item.route; - - if (itemIsActive) { - this.logger.debug('currently active menu item:', item); - } - - return itemIsActive; - } - - public navigate(item: MenuItem): void { - if (item.trigger) { - this.logger.debug(this, 'call trigger'); - item.trigger(); - return; - } - - if (item.route) { - const route = this.router.config.find(configItem => configItem.path === item.route); - - if (route) { - this.logger.debug(this, 'navigate to route'); - this.router.navigate([`/${item.route}`]); - } else { - this.errorHandler.handleError(this.errorMessageNonExistingRoute); - } - - this.logger.trace(this, item.route); - } - - if (item.navigationCommands) { - this.logger.debug(this, 'navigate to route'); - this.router.navigate(item.navigationCommands.commands); - this.logger.trace(this, item.navigationCommands); - } - } -} diff --git a/imxweb/projects/qbm/src/lib/menu/menu.module.ts b/imxweb/projects/qbm/src/lib/menu/menu.module.ts deleted file mode 100644 index 88c66cad2..000000000 --- a/imxweb/projects/qbm/src/lib/menu/menu.module.ts +++ /dev/null @@ -1,43 +0,0 @@ -/* - * ONE IDENTITY LLC. PROPRIETARY INFORMATION - * - * This software is confidential. One Identity, LLC. or one of its affiliates or - * subsidiaries, has supplied this software to you under terms of a - * license agreement, nondisclosure agreement or both. - * - * You may not copy, disclose, or use this software except in accordance with - * those terms. - * - * - * Copyright 2023 One Identity LLC. - * ALL RIGHTS RESERVED. - * - * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR - * WARRANTIES ABOUT THE SUITABILITY OF THE SOFTWARE, - * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED - * TO THE IMPLIED WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE, OR - * NON-INFRINGEMENT. ONE IDENTITY LLC. SHALL NOT BE - * LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE - * AS A RESULT OF USING, MODIFYING OR DISTRIBUTING - * THIS SOFTWARE OR ITS DERIVATIVES. - * - */ - -import { NgModule } from '@angular/core'; -import { CommonModule } from '@angular/common'; -import { MatMenuModule } from '@angular/material/menu'; -import { MatTabsModule } from '@angular/material/tabs'; -import { TranslateModule } from '@ngx-translate/core'; -import { MatButtonModule } from '@angular/material/button'; - -import { MenuComponent } from './menu.component'; -import { MenuService } from './menu.service'; - -@NgModule({ - declarations: [MenuComponent], - imports: [CommonModule, MatMenuModule, MatTabsModule, MatButtonModule, TranslateModule], - exports: [MenuComponent], - providers: [MenuService], -}) -export class MenuModule {} diff --git a/imxweb/projects/qbm/src/lib/menu/menu.service.ts b/imxweb/projects/qbm/src/lib/menu/menu.service.ts index e48dfe538..c8a45a0b8 100644 --- a/imxweb/projects/qbm/src/lib/menu/menu.service.ts +++ b/imxweb/projects/qbm/src/lib/menu/menu.service.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -28,19 +28,17 @@ import { Injectable } from '@angular/core'; import { EuiTopNavigationItem, EuiTopNavigationItemType } from '@elemental-ui/core'; import { TranslateService } from '@ngx-translate/core'; -import { ProjectConfig } from 'imx-api-qbm'; +import { ProjectConfig } from '@imx-modules/imx-api-qbm'; import { MenuFactory, MenuItem } from './menu-item/menu-item.interface'; @Injectable({ - providedIn: 'root' + providedIn: 'root', }) export class MenuService { - private factories: MenuFactory[] = []; + private factories: (MenuFactory | undefined)[] = []; - constructor( - private readonly translate: TranslateService - ) { } + constructor(private readonly translate: TranslateService) {} public addMenuFactories(...factories: MenuFactory[]): void { this.factories.push(...factories); @@ -50,24 +48,32 @@ export class MenuService { this.factories = []; } - public async getMenuItems(preProps: string[], features: string[], allowEmpty: boolean = false, projectConfig?: ProjectConfig, groups?: string[]): Promise { + public async getMenuItems( + preProps: string[], + features: string[], + allowEmpty: boolean = false, + projectConfig?: ProjectConfig, + groups?: string[], + ): Promise { const menuItems: MenuItem[] = []; this.factories - .map(factory => factory(preProps, features, projectConfig, groups || [])) - .filter(menu => menu && (allowEmpty || (menu.items && menu.items.length > 0))) + .map((factory) => factory?.(preProps, features, projectConfig, groups)) + .filter((menu) => menu && (allowEmpty || (menu.items && menu.items.length > 0))) .sort((item1, item2) => this.compareMenuItems(item1, item2)) - .forEach(menu => { - const existing = menu.id != null && menuItems.find(item => item.id === menu.id); + .forEach((menu) => { + const existing = menu?.id != null && menuItems.find((item) => item.id === menu.id); if (existing) { if (existing.items) { // Here only splice it there are items, otherwise this is a flat home button and it already exists - existing.items.splice(-1, 0, ...menu.items); + existing.items.splice(-1, 0, ...(menu.items ?? [])); existing.items = this.sortMenuItems(existing.items); } } else { - menuItems.push(menu); - menu.items = this.sortMenuItems(menu.items); + if (menu?.id != null) { + menuItems.push(menu); + menu.items = this.sortMenuItems(menu.items ?? []); + } } }); @@ -79,7 +85,7 @@ export class MenuService { for (const menuItem of menuItems) { const hasSubItems = menuItem.items && menuItem.items.length > 0; - const caption = await this.translate.get(menuItem.title).toPromise(); + const caption = menuItem.title != null ? this.translate.instant(menuItem.title) : ''; const navItem: EuiTopNavigationItem = { type: hasSubItems ? EuiTopNavigationItemType.Menu : EuiTopNavigationItemType.RouterLink, text: caption, @@ -87,13 +93,13 @@ export class MenuService { matrixParams: 'exact', queryParams: 'exact', paths: 'subset', - fragment: 'exact' + fragment: 'exact', }, }; if (hasSubItems) { - navItem.items = await this.getNavigationItems(menuItem.items); + navItem.items = await this.getNavigationItems(menuItem.items ?? []); } else { - navItem.url = menuItem.route ? menuItem.route : menuItem.navigationCommands.commands; + navItem.url = menuItem.route ? menuItem.route : menuItem.navigationCommands?.commands; } navItems.push(navItem); } @@ -104,11 +110,12 @@ export class MenuService { if (!items) { return items; } - return items.sort((item1, item2) => this.compareMenuItems(item1, item2)) - .filter((item, index, array) => !item.id || index === array.findIndex(t => t.id === item.id)); + return items + .sort((item1, item2) => this.compareMenuItems(item1, item2)) + .filter((item, index, array) => !item.id || index === array.findIndex((t) => t.id === item.id)); } - private compareMenuItems(item1: MenuItem, item2: MenuItem): number { - return +!item1.sorting - +!item2.sorting || item1.sorting?.toString().localeCompare(item2.sorting?.toString()); + private compareMenuItems(item1: MenuItem | undefined, item2: MenuItem | undefined): number { + return (+!item1?.sorting - +!item2?.sorting || item1?.sorting?.toString().localeCompare(item2?.sorting?.toString() ?? '')) ?? 0; } } diff --git a/imxweb/projects/qbm/src/lib/message-dialog/message-dialog-result.enum.ts b/imxweb/projects/qbm/src/lib/message-dialog/message-dialog-result.enum.ts index a22930801..abacac1b5 100644 --- a/imxweb/projects/qbm/src/lib/message-dialog/message-dialog-result.enum.ts +++ b/imxweb/projects/qbm/src/lib/message-dialog/message-dialog-result.enum.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -28,5 +28,5 @@ export enum MessageDialogResult { OkResult, CancelResult, YesResult, - NoResult + NoResult, } diff --git a/imxweb/projects/qbm/src/lib/message-dialog/message-dialog.component.html b/imxweb/projects/qbm/src/lib/message-dialog/message-dialog.component.html index 4acc30ea5..059dc0087 100644 --- a/imxweb/projects/qbm/src/lib/message-dialog/message-dialog.component.html +++ b/imxweb/projects/qbm/src/lib/message-dialog/message-dialog.component.html @@ -1,15 +1,54 @@ -

    {{data.Title}}

    +
    + + +

    + {{ data.Title }} +

    +
    -
    {{ data.Message }}
    +
    + {{ message }} +
    - - - - - + + + + + diff --git a/imxweb/projects/qbm/src/lib/message-dialog/message-dialog.component.scss b/imxweb/projects/qbm/src/lib/message-dialog/message-dialog.component.scss index ad9d752d4..4d2113207 100644 --- a/imxweb/projects/qbm/src/lib/message-dialog/message-dialog.component.scss +++ b/imxweb/projects/qbm/src/lib/message-dialog/message-dialog.component.scss @@ -5,3 +5,10 @@ max-height: 400px; max-width: 600px; } +.mat-mdc-dialog-title { + align-items: end; + h2{ + font-weight: inherit; + font-size: inherit; + } +} diff --git a/imxweb/projects/qbm/src/lib/message-dialog/message-dialog.component.ts b/imxweb/projects/qbm/src/lib/message-dialog/message-dialog.component.ts index ffd33896b..1602e310b 100644 --- a/imxweb/projects/qbm/src/lib/message-dialog/message-dialog.component.ts +++ b/imxweb/projects/qbm/src/lib/message-dialog/message-dialog.component.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -25,24 +25,36 @@ */ import { Component, Inject } from '@angular/core'; -import { MatDialogRef, MAT_DIALOG_DATA } from '@angular/material/dialog'; +import { MAT_DIALOG_DATA, MatDialogRef } from '@angular/material/dialog'; -import { MessageParameter } from './message-parameter.interface'; import { MessageDialogResult } from './message-dialog-result.enum'; +import { MessageDialogService } from './message-dialog.service'; +import { MessageParameter } from './message-parameter.interface'; @Component({ selector: 'imx-message-dialog', templateUrl: './message-dialog.component.html', - styleUrls: ['./message-dialog.component.scss'] + styleUrls: ['./message-dialog.component.scss'], }) export class MessageDialogComponent { public readonly MessageDialogResult = MessageDialogResult; // Enables use of this Enum in Angular Templates. constructor( public dialogRef: MatDialogRef, - @Inject(MAT_DIALOG_DATA) public data: MessageParameter) { } + public messageDialogService: MessageDialogService, + @Inject(MAT_DIALOG_DATA) public data: MessageParameter, + ) {} public click(state: MessageDialogResult): void { this.dialogRef.close(state); } + + public get messages(): (string | undefined)[] { + let messages = this.messageDialogService.errorMessages$.value; + if (!!messages && messages.length > 0) { + return messages.filter((message, index) => index == messages.indexOf(message)); + } else { + return [this.data.Message]; + } + } } diff --git a/imxweb/projects/o3t/src/public_api.ts b/imxweb/projects/qbm/src/lib/message-dialog/message-dialog.service.ts similarity index 73% rename from imxweb/projects/o3t/src/public_api.ts rename to imxweb/projects/qbm/src/lib/message-dialog/message-dialog.service.ts index a50b468f8..30a9880f0 100644 --- a/imxweb/projects/o3t/src/public_api.ts +++ b/imxweb/projects/qbm/src/lib/message-dialog/message-dialog.service.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -24,11 +24,10 @@ * */ -/* - * Public API Surface of o3t - */ +import { Injectable } from '@angular/core'; +import { BehaviorSubject } from 'rxjs'; -export { O3TConfigModule } from './lib/o3t-config.module'; -export { ApiService } from './lib/api.service'; -export { TeamsComponent } from './lib/teams/teams.component'; -export { TeamsModule } from './lib/teams/teams.module'; +@Injectable() +export class MessageDialogService { + public errorMessages$: BehaviorSubject = new BehaviorSubject([]); +} diff --git a/imxweb/projects/qbm/src/lib/message-dialog/message-parameter.interface.ts b/imxweb/projects/qbm/src/lib/message-dialog/message-parameter.interface.ts index be2c84ee9..d0ac26d64 100644 --- a/imxweb/projects/qbm/src/lib/message-dialog/message-parameter.interface.ts +++ b/imxweb/projects/qbm/src/lib/message-dialog/message-parameter.interface.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -31,4 +31,5 @@ export interface MessageParameter { Message?: string; identifier?: string; Parameter?: any[]; + icon?: string; } diff --git a/imxweb/projects/qbm/src/lib/model-css/model-css.service.ts b/imxweb/projects/qbm/src/lib/model-css/model-css.service.ts index fb1b11dc9..fe16e4cec 100644 --- a/imxweb/projects/qbm/src/lib/model-css/model-css.service.ts +++ b/imxweb/projects/qbm/src/lib/model-css/model-css.service.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -24,36 +24,35 @@ * */ -import { DOCUMENT } from "@angular/common"; -import { Inject, Injectable } from "@angular/core"; -import { AppConfigService } from "../appConfig/appConfig.service"; +import { DOCUMENT } from '@angular/common'; +import { Inject, Injectable } from '@angular/core'; +import { AppConfigService } from '../appConfig/appConfig.service'; @Injectable({ - providedIn: "root" + providedIn: 'root', }) export class ModelCssService { - constructor(@Inject(DOCUMENT) private readonly document: Document, - private readonly appConfig: AppConfigService) { } + constructor( + @Inject(DOCUMENT) private readonly document: Document, + private readonly appConfig: AppConfigService, + ) {} /** Loads the model stylesheet into the document, unless it has already * been loaded. */ public loadModelCss() { - const id = 'imx-model-css'; const existing = this.document.getElementById(id); // already loaded? - if (existing) - return; + if (existing) return; const head = this.document.getElementsByTagName('head')[0]; const style = this.document.createElement('link'); style.id = id; style.rel = 'stylesheet'; - style.href = this.appConfig.BaseUrl + "/imx/modelcss"; + style.href = this.appConfig.BaseUrl + '/imx/modelcss'; head.appendChild(style); } - -} \ No newline at end of file +} diff --git a/imxweb/projects/qbm/src/lib/multi-select-formcontrol/multi-select-formcontrol.component.html b/imxweb/projects/qbm/src/lib/multi-select-formcontrol/multi-select-formcontrol.component.html index 92a80c985..c5c5d8206 100644 --- a/imxweb/projects/qbm/src/lib/multi-select-formcontrol/multi-select-formcontrol.component.html +++ b/imxweb/projects/qbm/src/lib/multi-select-formcontrol/multi-select-formcontrol.component.html @@ -1,48 +1,68 @@
    - + - - {{ entityColumn?.GetMetadata().GetDisplay() }} - + + {{ entityColumn?.GetMetadata()?.GetDisplay() }} + - +
    {{ candidate.Display }}
    -
    - +
    - + - {{ (selectedElementsCaption) + ' ('+ selectedCandidates?.length + ')' }} + {{ selectedElementsCaption + ' (' + selectedCandidates?.length + ')' }} - + - +
    {{ selectedCandidate.Display }}
    - +
    -
    diff --git a/imxweb/projects/qbm/src/lib/multi-select-formcontrol/multi-select-formcontrol.component.scss b/imxweb/projects/qbm/src/lib/multi-select-formcontrol/multi-select-formcontrol.component.scss index 3f239c567..9c7e6ca77 100644 --- a/imxweb/projects/qbm/src/lib/multi-select-formcontrol/multi-select-formcontrol.component.scss +++ b/imxweb/projects/qbm/src/lib/multi-select-formcontrol/multi-select-formcontrol.component.scss @@ -7,36 +7,17 @@ gap: 12px; } -.imx-selected-candidates{ +.imx-selected-candidates { height: 218px; overflow: auto; } -.mat-spinner { - margin-top: 15px; -} - -.multi-select-formcontrol-eui-search { - width: 100%; - display: flex; - - .eui-search { - width: 100%; - } - - ::ng-deep .eui-search.mat-form-field.mat-form-field-appearance-outline { - min-width: 280px; - flex: 1; - margin-bottom: 10px; - } -} - .imx-multi-select-formcontrol-container { display: flex; flex-direction: column; } -.mat-list { +.mat-mdc-list { flex: 1; } @@ -76,28 +57,10 @@ } } -.mat-form-field { - flex: 1; -} - -mat-list-item:hover { - background-color: $color-gray-2; -} - eui-icon { cursor: pointer; } -mat-form-field { - button { - eui-icon { - font-size: 14px; - margin-right: 4px; - } - } -} - - @media only screen and (max-width: 1024px) { :host > div { grid-column-start: 1; diff --git a/imxweb/projects/qbm/src/lib/multi-select-formcontrol/multi-select-formcontrol.component.ts b/imxweb/projects/qbm/src/lib/multi-select-formcontrol/multi-select-formcontrol.component.ts index 95a5df3e8..a395d1677 100644 --- a/imxweb/projects/qbm/src/lib/multi-select-formcontrol/multi-select-formcontrol.component.ts +++ b/imxweb/projects/qbm/src/lib/multi-select-formcontrol/multi-select-formcontrol.component.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -25,20 +25,15 @@ */ import { ListRange } from '@angular/cdk/collections'; -import { OverlayRef } from '@angular/cdk/overlay'; import { CdkVirtualScrollViewport } from '@angular/cdk/scrolling'; import { AfterViewInit, ChangeDetectorRef, Component, forwardRef, Input, OnChanges, OnDestroy, ViewChild } from '@angular/core'; -import { ControlValueAccessor, UntypedFormControl, NG_VALUE_ACCESSOR } from '@angular/forms'; +import { ControlValueAccessor, NG_VALUE_ACCESSOR, UntypedFormControl } from '@angular/forms'; import { MatSelectionListChange } from '@angular/material/list'; import { EuiLoadingService } from '@elemental-ui/core'; import { Subscription } from 'rxjs'; import { debounceTime, distinctUntilChanged } from 'rxjs/operators'; -import { - CollectionLoadParameters, - EntityData, - IEntityColumn -} from 'imx-qbm-dbts'; +import { CollectionLoadParameters, EntityData, IEntityColumn } from '@imx-modules/imx-qbm-dbts'; import { MultiValueService } from '../multi-value/multi-value.service'; import { SettingsService } from '../settings/settings-service'; @@ -51,11 +46,10 @@ import { SettingsService } from '../settings/settings-service'; provide: NG_VALUE_ACCESSOR, useExisting: forwardRef(() => MultiSelectFormcontrolComponent), multi: true, - } + }, ], }) export class MultiSelectFormcontrolComponent implements ControlValueAccessor, OnChanges, OnDestroy, AfterViewInit { - public candidatesTotalCount: number; public loading = false; public candidates: EntityData[]; @@ -79,7 +73,8 @@ export class MultiSelectFormcontrolComponent implements ControlValueAccessor, On private readonly multiValueProvider: MultiValueService, private readonly busyService: EuiLoadingService, private readonly settingsService: SettingsService, - private readonly changeDetectorRef: ChangeDetectorRef) { + private readonly changeDetectorRef: ChangeDetectorRef, + ) { this.initSearchControl(); } @@ -88,7 +83,7 @@ export class MultiSelectFormcontrolComponent implements ControlValueAccessor, On StartIndex: 0, PageSize: this.settingsService.DefaultPageSize, filter: undefined, - search: undefined + search: undefined, }); this.changeDetectorRef.detectChanges(); } @@ -109,29 +104,32 @@ export class MultiSelectFormcontrolComponent implements ControlValueAccessor, On public async ngAfterViewInit(): Promise { this.parameters = { PageSize: this.settingsService.DefaultPageSize, StartIndex: 0 }; - this.subscriptions.push(this.viewport.renderedRangeStream.subscribe(async (range: ListRange) => { - if (range.end === (this.settingsService.DefaultPageSize + this.parameters.StartIndex)) { - this.parameters.StartIndex += this.settingsService.DefaultPageSize; + this.subscriptions.push( + this.viewport.renderedRangeStream.subscribe(async (range: ListRange) => { + if (range.end === this.settingsService.DefaultPageSize + (this.parameters.StartIndex ?? 0)) { + if (!this.parameters.StartIndex) this.parameters.StartIndex = 0; + this.parameters.StartIndex += this.settingsService.DefaultPageSize; - const tmpCandidates = Object.assign([], this.candidates); - await this.loadData(this.parameters); + const tmpCandidates = Object.assign([], this.candidates); + await this.loadData(this.parameters); - this.candidates.unshift(...tmpCandidates); - this.changeDetectorRef.detectChanges(); - } - })); + this.candidates.unshift(...tmpCandidates); + this.changeDetectorRef.detectChanges(); + } + }), + ); } public ngOnDestroy(): void { - this.subscriptions.forEach(s => s.unsubscribe()); + this.subscriptions.forEach((s) => s.unsubscribe()); } public async updateSelected(selection: MatSelectionListChange): Promise { - const selectedChange: string[] = selection.options.map(option => option.value.Keys[0]); - if (this.selectedCandidates.findIndex(elem => selectedChange.includes(elem.Keys[0])) !== -1) { + const selectedChange: string[] = selection.options.map((option) => option.value.Keys[0]); + if (this.selectedCandidates.findIndex((elem) => selectedChange.includes(elem.Keys?.[0] ?? '')) !== -1) { return; } - this.selectedCandidates.push(...selection.options.map(option => option.value)); + this.selectedCandidates.push(...selection.options.map((option) => option.value)); if (this.pushMethod === 'auto') { await this.putNewValue(); } @@ -152,19 +150,21 @@ export class MultiSelectFormcontrolComponent implements ControlValueAccessor, On } public async pushValue(): Promise { - let overlayRef: OverlayRef; - setTimeout(() => overlayRef = this.busyService.show()); + if (this.busyService.overlayRefs.length === 0) { + this.busyService.show(); + } try { await this.putNewValue(); } finally { - setTimeout(() => this.busyService.hide(overlayRef)); + this.busyService.hide(); } } private async putNewValue(): Promise { - const value = this.selectedCandidates && this.selectedCandidates.length > 0 ? - this.multiValueProvider.getMultiValue(this.selectedCandidates.map(elem => elem.Keys[0])) - : ''; + const value = + this.selectedCandidates && this.selectedCandidates.length > 0 + ? this.multiValueProvider.getMultiValue(this.selectedCandidates.map((elem) => elem.Keys?.[0] ?? '')) + : ''; await this.entityColumn.PutValue(value); this.onChange(this.entityColumn); @@ -172,13 +172,13 @@ export class MultiSelectFormcontrolComponent implements ControlValueAccessor, On private initSearchControl(): void { this.searchControl.setValue(''); - this.subscriptions.push(this.searchControl.valueChanges - .pipe(distinctUntilChanged(), debounceTime(300)).subscribe(async (value) => { + this.subscriptions.push( + this.searchControl.valueChanges.pipe(distinctUntilChanged(), debounceTime(300)).subscribe(async (value) => { await this.loadData({ StartIndex: 0, PageSize: this.settingsService.DefaultPageSize, search: value }); this.viewport.scrollToIndex(0); this.changeDetectorRef.detectChanges(); - })); - + }), + ); } private async loadData(newState?: CollectionLoadParameters): Promise { @@ -187,12 +187,11 @@ export class MultiSelectFormcontrolComponent implements ControlValueAccessor, On return; } try { - setTimeout(() => this.loading = true); + this.loading = true; this.parameters = { ...this.parameters, ...newState }; - const data = await this.entityColumn.GetMetadata().GetFkRelations()[0].Get(this.parameters); - this.candidates = data.Entities; + this.candidates = data.Entities ?? []; } finally { this.loading = false; } diff --git a/imxweb/projects/qbm/src/lib/multi-select-formcontrol/multi-select-formcontrol.module.ts b/imxweb/projects/qbm/src/lib/multi-select-formcontrol/multi-select-formcontrol.module.ts index da0f642b6..bb5256e2e 100644 --- a/imxweb/projects/qbm/src/lib/multi-select-formcontrol/multi-select-formcontrol.module.ts +++ b/imxweb/projects/qbm/src/lib/multi-select-formcontrol/multi-select-formcontrol.module.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -52,8 +52,8 @@ import { MultiSelectFormcontrolComponent } from './multi-select-formcontrol.comp MatSelectModule, ReactiveFormsModule, ScrollingModule, - TranslateModule + TranslateModule, ], - exports: [MultiSelectFormcontrolComponent] + exports: [MultiSelectFormcontrolComponent], }) -export class MultiSelectFormcontrolModule { } +export class MultiSelectFormcontrolModule {} diff --git a/imxweb/projects/qbm/src/lib/multi-value/multi-value.module.ts b/imxweb/projects/qbm/src/lib/multi-value/multi-value.module.ts index 5ed6b70bc..d9287419e 100644 --- a/imxweb/projects/qbm/src/lib/multi-value/multi-value.module.ts +++ b/imxweb/projects/qbm/src/lib/multi-value/multi-value.module.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -31,11 +31,7 @@ import { MultiValueService } from './multi-value.service'; @NgModule({ declarations: [], - imports: [ - CommonModule - ], - providers: [ - MultiValueService - ] + imports: [CommonModule], + providers: [MultiValueService], }) -export class MultiValueModule { } +export class MultiValueModule {} diff --git a/imxweb/projects/qbm/src/lib/multi-value/multi-value.service.ts b/imxweb/projects/qbm/src/lib/multi-value/multi-value.service.ts index 0c9ce4562..ebe26a60c 100644 --- a/imxweb/projects/qbm/src/lib/multi-value/multi-value.service.ts +++ b/imxweb/projects/qbm/src/lib/multi-value/multi-value.service.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -26,20 +26,20 @@ import { Injectable } from '@angular/core'; -import { MultiValue } from 'imx-qbm-dbts'; +import { MultiValue } from '@imx-modules/imx-qbm-dbts'; /** * Service providing conversion to and from MultiValue with the default separator (MultiValueProperty.DefaultSeparator) */ @Injectable({ - providedIn: 'root' + providedIn: 'root', }) export class MultiValueService { - public getValues(value: string): string[] { - return value != null ? MultiValue.FromString(value).GetValues() : undefined; + public getValues(value: string | undefined): string[] | undefined { + return !!value ? MultiValue.FromString(value).GetValues() : undefined; } - public getMultiValue(values: string[]): string { - return values != null ? new MultiValue(values).GetStringValue() : undefined; + public getMultiValue(values: string[]): string | undefined { + return !!values ? new MultiValue(values).GetStringValue() : undefined; } } diff --git a/imxweb/projects/qbm/src/lib/object-history/object-history-api.service.ts b/imxweb/projects/qbm/src/lib/object-history/object-history-api.service.ts index ee7bd29f6..0bf6d48e5 100644 --- a/imxweb/projects/qbm/src/lib/object-history/object-history-api.service.ts +++ b/imxweb/projects/qbm/src/lib/object-history/object-history-api.service.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -24,11 +24,10 @@ * */ -import { HistoryData } from "imx-qbm-dbts"; -import { HistoryComparisonData } from "imx-api-qbm"; +import { HistoryData } from '@imx-modules/imx-qbm-dbts'; +import { HistoryComparisonData } from '@imx-modules/imx-api-qbm'; export abstract class ObjectHistoryApiService { - abstract getHistoryData(table: string, uid: string): Promise; - abstract getHistoryComparisonData(table: string, uid: string,options?: {CompareDate?: Date;}):Promise; -} \ No newline at end of file + abstract getHistoryComparisonData(table: string, uid: string, options?: { CompareDate?: Date }): Promise; +} diff --git a/imxweb/projects/qbm/src/lib/object-history/object-history-gridview/object-history-gridview.component.html b/imxweb/projects/qbm/src/lib/object-history/object-history-gridview/object-history-gridview.component.html index 68ba17a06..1ff7cd6fe 100644 --- a/imxweb/projects/qbm/src/lib/object-history/object-history-gridview/object-history-gridview.component.html +++ b/imxweb/projects/qbm/src/lib/object-history/object-history-gridview/object-history-gridview.component.html @@ -6,26 +6,34 @@
    - {{row.OldValue}} + {{ row.OldValue }} -
    -
    +
    +
    - {{columnDef.getValue(row)}} + {{ columnDef.getValue(row) }} - ({{'#LDS#No value'| translate}}) + ({{ '#LDS#No value' | translate }})
    {{ columnDef.getValue(row) }}
    - - + +
    - +

    diff --git a/imxweb/projects/qbm/src/lib/object-history/object-history-gridview/object-history-gridview.component.scss b/imxweb/projects/qbm/src/lib/object-history/object-history-gridview/object-history-gridview.component.scss index b200472da..9f3933930 100644 --- a/imxweb/projects/qbm/src/lib/object-history/object-history-gridview/object-history-gridview.component.scss +++ b/imxweb/projects/qbm/src/lib/object-history/object-history-gridview/object-history-gridview.component.scss @@ -2,8 +2,8 @@ display: flex; } -.imx-history-table-content{ +.imx-history-table-content { flex: 1 1 auto; display: flex; - flex-direction: column; -} \ No newline at end of file + flex-direction: column; +} diff --git a/imxweb/projects/qbm/src/lib/object-history/object-history-gridview/object-history-gridview.component.ts b/imxweb/projects/qbm/src/lib/object-history/object-history-gridview/object-history-gridview.component.ts index ba627bd2c..6474403bf 100644 --- a/imxweb/projects/qbm/src/lib/object-history/object-history-gridview/object-history-gridview.component.ts +++ b/imxweb/projects/qbm/src/lib/object-history/object-history-gridview/object-history-gridview.component.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -24,15 +24,15 @@ * */ +// eslint-disable-next-line max-classes-per-file import { Component, Input, OnChanges, OnInit, ViewChild } from '@angular/core'; +import { MatPaginator, PageEvent } from '@angular/material/paginator'; import { ActivatedRoute } from '@angular/router'; -import { PageEvent } from '@angular/material/paginator'; -import { MatPaginator } from '@angular/material/paginator'; import { TranslateService } from '@ngx-translate/core'; -import { ObjectHistoryEvent, TypedEntityCollectionData } from 'imx-qbm-dbts'; -import { ObjectHistoryParameters } from '../object-history.service'; +import { ObjectHistoryEvent, TypedEntityCollectionData } from '@imx-modules/imx-qbm-dbts'; import { SettingsService } from '../../settings/settings-service'; +import { ObjectHistoryParameters } from '../object-history.service'; interface IColumn { id: string; @@ -46,7 +46,7 @@ class Column implements IColumn { public title: string; } -function getLocalDataForPage(allData: T[], state: { page: number, pageSize: number, skip: number }): T[] { +function getLocalDataForPage(allData: T[], state: { page: number; pageSize: number; skip: number }): T[] { if (state) { const currentIndex = state.page * state.pageSize; return allData.slice(currentIndex, currentIndex + state.pageSize); @@ -56,18 +56,18 @@ function getLocalDataForPage(allData: T[], state: { page: number, pageSize: n } // TODO: One class per file. -// tslint:disable-next-line: max-classes-per-file +// eslint-disable-next-line max-classes-per-file @Component({ selector: 'imx-object-history-gridview', templateUrl: './object-history-gridview.component.html', - styleUrls: ['./object-history-gridview.component.scss'] + styleUrls: ['./object-history-gridview.component.scss'], }) export class ObjectHistoryGridviewComponent implements OnInit, OnChanges { @Input() public historyData: ObjectHistoryEvent[]; @ViewChild(MatPaginator) private paginator: MatPaginator; public get columns(): string[] { - return this.columnDefs.map(c => c.id); + return this.columnDefs.map((c) => c.id); } public dataCollection: TypedEntityCollectionData; @@ -77,11 +77,11 @@ export class ObjectHistoryGridviewComponent implements OnInit, OnChanges { size: 5, sizeOptions: [20, 50, 100], showFirstLastButtons: false, - hidden: false + hidden: false, }; private displayChangeTypePropertyChange = 'PropertyChange'; - private stateCached: { page: number, pageSize: number, skip: number }; + private stateCached: { page: number; pageSize: number; skip: number }; private parameters: ObjectHistoryParameters; constructor( @@ -96,31 +96,31 @@ export class ObjectHistoryGridviewComponent implements OnInit, OnChanges { await this.addColumnDef({ id: 'ChangeTime', title: '#LDS#Modified on', - getValue: (row: ObjectHistoryEvent) => new Date(row.ChangeTime).toLocaleString(this.translationProvider.currentLang) + getValue: (row: ObjectHistoryEvent) => new Date(row.ChangeTime).toLocaleString(this.translationProvider.currentLang), }); await this.addColumnDef({ id: 'ChangeType', title: '#LDS#Type of change', - getValue: (row: ObjectHistoryEvent) => row.ChangeType + getValue: (row: ObjectHistoryEvent) => row.ChangeType ?? '', }); await this.addColumnDef({ id: 'LongDisplay', title: '#LDS#Name', - getValue: (row: ObjectHistoryEvent) => row.LongDisplay + getValue: (row: ObjectHistoryEvent) => row.LongDisplay ?? '', }); await this.addColumnDef({ id: 'Property', title: '#LDS#Type', - getValue: (row: ObjectHistoryEvent) => row.Property + getValue: (row: ObjectHistoryEvent) => row.Property ?? '', }); await this.addColumnDef({ id: 'User', title: '#LDS#User', - getValue: (row: ObjectHistoryEvent) => row.User + getValue: (row: ObjectHistoryEvent) => row.User ?? '', }); this.parameters = { table: this.activatedRoute.snapshot.paramMap.get('table'), - uid: this.activatedRoute.snapshot.paramMap.get('uid') + uid: this.activatedRoute.snapshot.paramMap.get('uid'), }; this.displayChangeTypePropertyChange = await this.translationProvider.get('#LDS#PropertyChange').toPromise(); @@ -129,7 +129,7 @@ export class ObjectHistoryGridviewComponent implements OnInit, OnChanges { public ngOnChanges(): void { this.parameters = { table: this.activatedRoute.snapshot.paramMap.get('table'), - uid: this.activatedRoute.snapshot.paramMap.get('uid') + uid: this.activatedRoute.snapshot.paramMap.get('uid'), }; this.refresh(); } @@ -138,7 +138,7 @@ export class ObjectHistoryGridviewComponent implements OnInit, OnChanges { this.updateDataCollection({ skip: e.pageIndex * e.pageSize, page: e.pageIndex, - pageSize: e.pageSize + pageSize: e.pageSize, }); } @@ -166,7 +166,7 @@ export class ObjectHistoryGridviewComponent implements OnInit, OnChanges { this.columnDefs.push(column); } - private updateDataCollection(state?: { page: number, pageSize: number, skip: number }): void { + private updateDataCollection(state?: { page: number; pageSize: number; skip: number }): void { if (state) { this.stateCached = state; } @@ -174,14 +174,14 @@ export class ObjectHistoryGridviewComponent implements OnInit, OnChanges { this.stateCached = { skip: this.paginatorConfig.index * this.paginatorConfig.size, page: this.paginatorConfig.index, - pageSize: this.paginatorConfig.size + pageSize: this.paginatorConfig.size, }; } this.dataCollection = { - tableName: this.parameters.table, + tableName: this.parameters.table ?? '', totalCount: this.historyData.length, - Data: getLocalDataForPage(this.historyData, this.stateCached) + Data: getLocalDataForPage(this.historyData, this.stateCached), }; } } diff --git a/imxweb/projects/qbm/src/lib/object-history/object-history-state-comparison/object-history-state-comparison.component.html b/imxweb/projects/qbm/src/lib/object-history/object-history-state-comparison/object-history-state-comparison.component.html index 5ef7a8bac..1696877f7 100644 --- a/imxweb/projects/qbm/src/lib/object-history/object-history-state-comparison/object-history-state-comparison.component.html +++ b/imxweb/projects/qbm/src/lib/object-history/object-history-state-comparison/object-history-state-comparison.component.html @@ -1,19 +1,24 @@
    -
    - - - {{ columnDef.getTitle() }} - - {{ columnDef.getValue(row) }} - - - - - -
    - - +
    + + + {{ columnDef.getTitle() }} + + {{ columnDef.getValue(row) }} + + + + +
    - \ No newline at end of file + + +
    diff --git a/imxweb/projects/qbm/src/lib/object-history/object-history-state-comparison/object-history-state-comparison.component.scss b/imxweb/projects/qbm/src/lib/object-history/object-history-state-comparison/object-history-state-comparison.component.scss index 4d7c483dd..9f3933930 100644 --- a/imxweb/projects/qbm/src/lib/object-history/object-history-state-comparison/object-history-state-comparison.component.scss +++ b/imxweb/projects/qbm/src/lib/object-history/object-history-state-comparison/object-history-state-comparison.component.scss @@ -1,9 +1,9 @@ :host { - display: flex; - } - - .imx-history-table-content{ - flex: 1 1 auto; - display: flex; - flex-direction: column; - } \ No newline at end of file + display: flex; +} + +.imx-history-table-content { + flex: 1 1 auto; + display: flex; + flex-direction: column; +} diff --git a/imxweb/projects/qbm/src/lib/object-history/object-history-state-comparison/object-history-state-comparison.component.ts b/imxweb/projects/qbm/src/lib/object-history/object-history-state-comparison/object-history-state-comparison.component.ts index 0d473f9f9..bdaf8aa6c 100644 --- a/imxweb/projects/qbm/src/lib/object-history/object-history-state-comparison/object-history-state-comparison.component.ts +++ b/imxweb/projects/qbm/src/lib/object-history/object-history-state-comparison/object-history-state-comparison.component.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -25,14 +25,13 @@ */ import { Component, Input, OnChanges, OnInit, ViewChild } from '@angular/core'; +import { MatPaginator, PageEvent } from '@angular/material/paginator'; import { ActivatedRoute } from '@angular/router'; -import { PageEvent } from '@angular/material/paginator'; -import { MatPaginator } from '@angular/material/paginator'; import { TranslateService } from '@ngx-translate/core'; -import { TypedEntityCollectionData } from 'imx-qbm-dbts'; +import { HistoryComparisonData } from '@imx-modules/imx-api-qbm'; +import { TypedEntityCollectionData } from '@imx-modules/imx-qbm-dbts'; import { SettingsService } from '../../settings/settings-service'; -import { HistoryComparisonData } from 'imx-api-qbm'; interface IColumn { id: string; @@ -46,7 +45,7 @@ class Column implements IColumn { public title: string; } -function getLocalDataForPage(allData: T[], state: { page: number, pageSize: number, skip: number }): T[] { +function getLocalDataForPage(allData: T[], state: { page: number; pageSize: number; skip: number }): T[] { if (state) { const currentIndex = state.page * state.pageSize; return allData.slice(currentIndex, currentIndex + state.pageSize); @@ -58,11 +57,11 @@ function getLocalDataForPage(allData: T[], state: { page: number, pageSize: n @Component({ selector: 'imx-object-history-state-comparison', templateUrl: './object-history-state-comparison.component.html', - styleUrls: ['./object-history-state-comparison.component.scss'] + styleUrls: ['./object-history-state-comparison.component.scss'], }) export class ObjectHistoryStateComparisonComponent implements OnInit, OnChanges { public get columns(): string[] { - return this.columnDefs.map(c => c.id); + return this.columnDefs.map((c) => c.id); } public dataCollection: TypedEntityCollectionData; @@ -72,18 +71,18 @@ export class ObjectHistoryStateComparisonComponent implements OnInit, OnChanges size: 5, sizeOptions: [20, 50, 100], showFirstLastButtons: false, - hidden: false + hidden: false, }; - @Input() public historyComparisonData: HistoryComparisonData[] ; + @Input() public historyComparisonData: HistoryComparisonData[]; - private stateCached: { page: number, pageSize: number, skip: number }; + private stateCached: { page: number; pageSize: number; skip: number }; @ViewChild(MatPaginator) private paginator: MatPaginator; constructor( private activatedRoute: ActivatedRoute, private translationProvider: TranslateService, - settings: SettingsService + settings: SettingsService, ) { this.paginatorConfig.size = settings.DefaultPageSize; } @@ -92,27 +91,27 @@ export class ObjectHistoryStateComparisonComponent implements OnInit, OnChanges await this.addColumnDef({ id: 'TableName', title: '#LDS#Changed property', - getValue: (row: HistoryComparisonData) => row.TableName + getValue: (row: HistoryComparisonData) => row.TableName, }); await this.addColumnDef({ id: 'ChangeType', title: '#LDS#Type of changed property', - getValue: (row: HistoryComparisonData) => row.ChangeType + getValue: (row: HistoryComparisonData) => row.ChangeType, }); await this.addColumnDef({ id: 'Property', title: '#LDS#Changed property', - getValue: (row: HistoryComparisonData) => row.Property + getValue: (row: HistoryComparisonData) => row.Property, }); await this.addColumnDef({ id: 'HistoryValueDisplay', title: '#LDS#Old value', - getValue: (row: HistoryComparisonData) => row.HistoryValueDisplay + getValue: (row: HistoryComparisonData) => row.HistoryValueDisplay, }); await this.addColumnDef({ id: 'CurrentValueDisplay', title: '#LDS#Current value', - getValue: (row: HistoryComparisonData) => row.CurrentValueDisplay + getValue: (row: HistoryComparisonData) => row.CurrentValueDisplay, }); } @@ -124,7 +123,7 @@ export class ObjectHistoryStateComparisonComponent implements OnInit, OnChanges this.updateDataCollection({ skip: e.pageIndex * e.pageSize, page: e.pageIndex, - pageSize: e.pageSize + pageSize: e.pageSize, }); } @@ -144,7 +143,7 @@ export class ObjectHistoryStateComparisonComponent implements OnInit, OnChanges this.columnDefs.push(column); } - private updateDataCollection(state?: { page: number, pageSize: number, skip: number }): void { + private updateDataCollection(state?: { page: number; pageSize: number; skip: number }): void { if (state) { this.stateCached = state; } @@ -152,16 +151,15 @@ export class ObjectHistoryStateComparisonComponent implements OnInit, OnChanges this.stateCached = { skip: this.paginatorConfig.index * this.paginatorConfig.size, page: this.paginatorConfig.index, - pageSize: this.paginatorConfig.size + pageSize: this.paginatorConfig.size, }; } let table = this.activatedRoute.snapshot.paramMap.get('table'); this.dataCollection = { - tableName: table, + tableName: table ?? '', totalCount: this.historyComparisonData.length, - Data: getLocalDataForPage(this.historyComparisonData, this.stateCached) + Data: getLocalDataForPage(this.historyComparisonData, this.stateCached), }; } } - diff --git a/imxweb/projects/qbm/src/lib/object-history/object-history-state-overview/object-history-state-overview.component.html b/imxweb/projects/qbm/src/lib/object-history/object-history-state-overview/object-history-state-overview.component.html index 5ef7a8bac..1696877f7 100644 --- a/imxweb/projects/qbm/src/lib/object-history/object-history-state-overview/object-history-state-overview.component.html +++ b/imxweb/projects/qbm/src/lib/object-history/object-history-state-overview/object-history-state-overview.component.html @@ -1,19 +1,24 @@
    -
    - - - {{ columnDef.getTitle() }} - - {{ columnDef.getValue(row) }} - - - - - -
    - - +
    + + + {{ columnDef.getTitle() }} + + {{ columnDef.getValue(row) }} + + + + +
    - \ No newline at end of file + + +
    diff --git a/imxweb/projects/qbm/src/lib/object-history/object-history-state-overview/object-history-state-overview.component.scss b/imxweb/projects/qbm/src/lib/object-history/object-history-state-overview/object-history-state-overview.component.scss index 2ee4b031f..9f3933930 100644 --- a/imxweb/projects/qbm/src/lib/object-history/object-history-state-overview/object-history-state-overview.component.scss +++ b/imxweb/projects/qbm/src/lib/object-history/object-history-state-overview/object-history-state-overview.component.scss @@ -1,10 +1,9 @@ :host { - display: flex; - } - - .imx-history-table-content{ - flex: 1 1 auto; - display: flex; - flex-direction: column; - } - \ No newline at end of file + display: flex; +} + +.imx-history-table-content { + flex: 1 1 auto; + display: flex; + flex-direction: column; +} diff --git a/imxweb/projects/qbm/src/lib/object-history/object-history-state-overview/object-history-state-overview.component.ts b/imxweb/projects/qbm/src/lib/object-history/object-history-state-overview/object-history-state-overview.component.ts index 5aa299236..6412e0d83 100644 --- a/imxweb/projects/qbm/src/lib/object-history/object-history-state-overview/object-history-state-overview.component.ts +++ b/imxweb/projects/qbm/src/lib/object-history/object-history-state-overview/object-history-state-overview.component.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -24,13 +24,13 @@ * */ +// eslint-disable-next-line max-classes-per-file import { Component, Input, OnChanges, OnInit, ViewChild } from '@angular/core'; +import { MatPaginator, PageEvent } from '@angular/material/paginator'; import { ActivatedRoute } from '@angular/router'; -import { PageEvent } from '@angular/material/paginator'; -import { MatPaginator } from '@angular/material/paginator'; import { TranslateService } from '@ngx-translate/core'; -import { IStateOverviewItem, TypedEntityCollectionData } from 'imx-qbm-dbts'; +import { IStateOverviewItem, TypedEntityCollectionData } from '@imx-modules/imx-qbm-dbts'; import { SettingsService } from '../../settings/settings-service'; interface IColumn { @@ -45,7 +45,7 @@ class Column implements IColumn { public title: string; } -function getLocalDataForPage(allData: T[], state: { page: number, pageSize: number, skip: number }): T[] { +function getLocalDataForPage(allData: T[], state: { page: number; pageSize: number; skip: number }): T[] { if (state) { const currentIndex = state.page * state.pageSize; return allData.slice(currentIndex, currentIndex + state.pageSize); @@ -54,15 +54,15 @@ function getLocalDataForPage(allData: T[], state: { page: number, pageSize: n return allData; } -// tslint:disable-next-line: max-classes-per-file +// eslint-disable-next-line max-classes-per-file @Component({ selector: 'imx-object-history-state-overview', templateUrl: './object-history-state-overview.component.html', - styleUrls: ['./object-history-state-overview.component.scss'] + styleUrls: ['./object-history-state-overview.component.scss'], }) export class ObjectHistoryStateOverviewComponent implements OnInit, OnChanges { public get columns(): string[] { - return this.columnDefs.map(c => c.id); + return this.columnDefs.map((c) => c.id); } public dataCollection: TypedEntityCollectionData; @@ -72,18 +72,18 @@ export class ObjectHistoryStateOverviewComponent implements OnInit, OnChanges { size: 5, sizeOptions: [20, 50, 100], showFirstLastButtons: false, - hidden: false + hidden: false, }; @Input() public stateOverviewItems: IStateOverviewItem[]; - private stateCached: { page: number, pageSize: number, skip: number }; + private stateCached: { page: number; pageSize: number; skip: number }; @ViewChild(MatPaginator) private paginator: MatPaginator; constructor( private activatedRoute: ActivatedRoute, private translationProvider: TranslateService, - settings: SettingsService + settings: SettingsService, ) { this.paginatorConfig.size = settings.DefaultPageSize; } @@ -98,32 +98,32 @@ export class ObjectHistoryStateOverviewComponent implements OnInit, OnChanges { return textCurrent; } return new Date(date).toLocaleString(browserCulture); - } + }; await this.addColumnDef({ id: 'PropertyDisplay', title: '#LDS#Changed property', - getValue: (row: IStateOverviewItem) => row.PropertyDisplay + getValue: (row: IStateOverviewItem) => row.PropertyDisplay ?? '', }); await this.addColumnDef({ id: 'StateTypeDisplay', title: '#LDS#Type of changed property', - getValue: (row: IStateOverviewItem) => row.StateTypeDisplay + getValue: (row: IStateOverviewItem) => row.StateTypeDisplay ?? '', }); await this.addColumnDef({ id: 'ValueDisplay', title: '#LDS#Value', - getValue: (row: IStateOverviewItem) => row.ValueDisplay + getValue: (row: IStateOverviewItem) => row.ValueDisplay ?? '', }); await this.addColumnDef({ id: 'DateBegin', title: '#LDS#Value used since', - getValue: (row: IStateOverviewItem) => formatDate(row.DateBegin) + getValue: (row: IStateOverviewItem) => formatDate(row.DateBegin), }); await this.addColumnDef({ id: 'DateEnd', title: '#LDS#Value used until', - getValue: (row: IStateOverviewItem) => formatDate(row.DateEnd) + getValue: (row: IStateOverviewItem) => formatDate(row.DateEnd), }); } @@ -135,7 +135,7 @@ export class ObjectHistoryStateOverviewComponent implements OnInit, OnChanges { this.updateDataCollection({ skip: e.pageIndex * e.pageSize, page: e.pageIndex, - pageSize: e.pageSize + pageSize: e.pageSize, }); } @@ -155,7 +155,7 @@ export class ObjectHistoryStateOverviewComponent implements OnInit, OnChanges { this.columnDefs.push(column); } - private updateDataCollection(state?: { page: number, pageSize: number, skip: number }): void { + private updateDataCollection(state?: { page: number; pageSize: number; skip: number }): void { if (state) { this.stateCached = state; } @@ -163,15 +163,15 @@ export class ObjectHistoryStateOverviewComponent implements OnInit, OnChanges { this.stateCached = { skip: this.paginatorConfig.index * this.paginatorConfig.size, page: this.paginatorConfig.index, - pageSize: this.paginatorConfig.size + pageSize: this.paginatorConfig.size, }; } const table = this.activatedRoute.snapshot.paramMap.get('table'); this.dataCollection = { - tableName: table, + tableName: table ?? '', totalCount: this.stateOverviewItems.length, - Data: getLocalDataForPage(this.stateOverviewItems, this.stateCached) + Data: getLocalDataForPage(this.stateOverviewItems, this.stateCached), }; } } diff --git a/imxweb/projects/qbm/src/lib/object-history/object-history.component.html b/imxweb/projects/qbm/src/lib/object-history/object-history.component.html index 3639e8b5c..4e1d7ef9c 100644 --- a/imxweb/projects/qbm/src/lib/object-history/object-history.component.html +++ b/imxweb/projects/qbm/src/lib/object-history/object-history.component.html @@ -1,19 +1,30 @@
    -

    +

    {{ '#LDS#History' | translate }} -

    +

    - - - {{ mode.display }} - - - @@ -21,23 +32,39 @@

    mat-icon-button color="primary" [attr.data-imx-identifier]="'history-state-overview-mode-tooltip-button'" - matTooltip="{{ '#LDS#Here you can get an overview of all changes. Additionally, you can see how long the respective change was valid.' | translate }}" - matTooltipPosition="right" + matTooltip="{{ + '#LDS#Here you can get an overview of all changes. Additionally, you can see how long the respective change was valid.' + | translate + }}" > - + + {{ + '#LDS#Specify a date that lies in the past.' | translate + }} + {{ '#LDS#Specify a date.' | translate }} +
    @@ -46,7 +73,7 @@

    class="small" [dateControl]="timelineFromDateFormControl" [useClearIcon]="true" - [max]="timelineTo.date !== 'Invalid date' ? timelineTo.date : momentToday" + [max]="timelineToDateMoment" > size="s" >

    + + + + + +
    - + @@ -87,8 +144,14 @@

    - - + +
    diff --git a/imxweb/projects/qbm/src/lib/object-history/object-history.component.scss b/imxweb/projects/qbm/src/lib/object-history/object-history.component.scss index 6dff2fde7..f98e762e1 100644 --- a/imxweb/projects/qbm/src/lib/object-history/object-history.component.scss +++ b/imxweb/projects/qbm/src/lib/object-history/object-history.component.scss @@ -1,68 +1,30 @@ -@import "@elemental-ui/core/src/styles/_eui_palette.scss"; +@import '@elemental-ui/core/src/styles/_eui_palette.scss'; +@import 'base/mixins'; :host { - display: flex; - flex-direction: column; - overflow: hidden; - height: 100%; - - ::ng-deep eui-date-picker { - .mat-form-field-wrapper { - padding: 0; - - .mat-form-field-subscript-wrapper { - margin: 0; - } - - .mat-form-field-flex { - padding: 0 0 0 0.5rem; - - .mat-form-field-infix { - padding: 0.3rem 0 0.4rem 0; - width: 140px; - } - } - } - } - - ::ng-deep eui-time-picker { - .eui-time-picker-container { - display: flex; - align-items: center; - } - } + @include flex-column-container($overflow: hidden, $height: 100%); } - .imx-viewmode-content { + @include flex-column-container($overflow: auto); flex: 1 1 auto; - overflow: auto; - display: flex; - flex-direction: column; } .imx-viewmode-content-controls { margin-bottom: 1rem; + .eui-select{ + width: 180px; + } } -.imx-timeline-from, .imx-timeline-to, .imx-viewmode-content-controls { +.imx-timeline-from, +.imx-timeline-to, +.imx-viewmode-content-controls { display: flex; flex-direction: row; flex-wrap: wrap; - align-items: center; + align-items: baseline; gap: 6px; - ::ng-deep .mat-form-field-type-mat-select > .mat-form-field-wrapper { - padding: 0; - - .mat-form-field-infix { - border: none; - } - - .mat-form-field-subscript-wrapper { - margin: 0; - } - } - .timeline-to-text { margin-left: 1rem; } @@ -70,42 +32,21 @@ mat-button-toggle-group { margin-left: auto; - - ::ng-deep .mat-button-toggle-appearance-standard[ng-reflect-value='table'] .mat-button-toggle-label-content { - padding: 0 8px; - } } - -.eui-dark-theme { - :host { - mat-button-toggle-group { - .mat-button-toggle-checked { - background-color: $color-blue-40; - } - } - - .imx-viewmode-dropdown { - .mat-form-field-infix { - color: $color-gray-40; - } - - .mat-form-field-flex { - background-color: $color-gray-70; - } - } - } +.mdc-icon-button{ + line-height: 20px; } -.eui-contrast-theme { - :host { - .imx-viewmode-dropdown { - .mat-form-field-infix { - color: $color-gray-20; - } - - .mat-form-field-flex { - background-color: $color-gray-90; - } - } +.imx-filter-icon{ + font-size: 20px; + padding-right: 8px; + &-edit{ + color: $color-blue-60; + } + &-add{ + color: $color-green-60; + } + &-remove{ + color: $color-red-60; } } diff --git a/imxweb/projects/qbm/src/lib/object-history/object-history.component.ts b/imxweb/projects/qbm/src/lib/object-history/object-history.component.ts index b60d26dfd..d521dc547 100644 --- a/imxweb/projects/qbm/src/lib/object-history/object-history.component.ts +++ b/imxweb/projects/qbm/src/lib/object-history/object-history.component.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -24,29 +24,25 @@ * */ -import { OverlayRef } from '@angular/cdk/overlay'; +// eslint-disable-next-line max-classes-per-file import { Component, Input, OnDestroy, OnInit } from '@angular/core'; import { ActivatedRoute } from '@angular/router'; -import { EuiLoadingService } from '@elemental-ui/core'; +import { EuiLoadingService, EuiSelectOption } from '@elemental-ui/core'; import { TranslateService } from '@ngx-translate/core'; -import { UntypedFormControl } from '@angular/forms'; -import { HistoryComparisonData } from 'imx-api-qbm'; -import { IStateOverviewItem, ObjectHistoryEvent } from 'imx-qbm-dbts'; +import { FormControl, UntypedFormControl, Validators } from '@angular/forms'; +import { HistoryComparisonData } from '@imx-modules/imx-api-qbm'; +import { IStateOverviewItem, ObjectHistoryEvent } from '@imx-modules/imx-qbm-dbts'; import { ObjectHistoryParameters, ObjectHistoryService } from './object-history.service'; import { DateAdapter } from '@angular/material/core'; -import moment from 'moment-timezone'; +import moment, { Moment } from 'moment-timezone'; import { Subscription } from 'rxjs'; import { ExtendedObjectHistoryEvent, TimelineDateTimeFilter } from '../timeline/timeline'; - -class ViewMode { - public value: string; - public display: string; -} +import { EventChangeType, EventChangeTypes, HistoryEventChangeType } from '../timeline/timeline.model'; // TODO: One class per file. -// tslint:disable-next-line: max-classes-per-file +// eslint-disable-next-line max-classes-per-file @Component({ selector: 'imx-object-history', templateUrl: './object-history.component.html', @@ -80,19 +76,27 @@ export class ObjectHistoryComponent implements OnInit, OnDestroy { return this.timelineTo.date + ' ' + this.timelineTo.time; } + public get timelineToDateMoment(): moment.Moment { + return this.timelineTo.date !== 'Invalid date' ? moment(this.timelineTo.date) : this.momentToday; + } + public lookIcons: string[] = ['attributes', 'table']; public selectedLook: string = 'timeline'; public viewModeValue: string; - public historyData: ObjectHistoryEvent[] = []; - public filteredHistoryData: ObjectHistoryEvent[] | ExtendedObjectHistoryEvent[] = []; + public historyData: ExtendedObjectHistoryEvent[] = []; + public filteredHistoryData: ExtendedObjectHistoryEvent[] = []; public stateOverviewItems: IStateOverviewItem[] = []; public historyComparisonData: HistoryComparisonData[] = []; - public viewModes: ViewMode[] = []; - public compareDateFormControl = new UntypedFormControl(); - public timelineFromDateFormControl = new UntypedFormControl(); - public timelineFromTimeFormControl = new UntypedFormControl(); - public timelineToDateFormControl = new UntypedFormControl(); - public timelineToTimeFormControl = new UntypedFormControl(); + public viewModes: EuiSelectOption[] = []; + public momentToday = moment(); + public compareDateFormControl = new UntypedFormControl(new Date(new Date().setHours(23, 59, 59, 999)), { + nonNullable: true, + validators: Validators.required, + }); + public timelineFromDateFormControl: FormControl = new FormControl(); + public timelineFromTimeFormControl: FormControl = new FormControl(); + public timelineToDateFormControl: FormControl = new FormControl(); + public timelineToTimeFormControl: FormControl = new FormControl(); public timelineFrom: TimelineDateTimeFilter = { date: 'Invalid date', time: 'Invalid date', @@ -101,7 +105,9 @@ export class ObjectHistoryComponent implements OnInit, OnDestroy { date: 'Invalid date', time: 'Invalid date', }; - public momentToday = moment(); + public viewModeControl: FormControl = new FormControl(this.viewModeGrid, { nonNullable: true }); + public eventChangeTypes = EventChangeTypes; + public selectedEventChangeTypes: EventChangeType[] = []; private subscriptions: Subscription[] = []; @@ -110,7 +116,7 @@ export class ObjectHistoryComponent implements OnInit, OnDestroy { private activatedRoute: ActivatedRoute, private busyService: EuiLoadingService, private historyService: ObjectHistoryService, - private dateAdapter: DateAdapter + private dateAdapter: DateAdapter, ) {} public async ngOnInit(): Promise { @@ -122,7 +128,6 @@ export class ObjectHistoryComponent implements OnInit, OnDestroy { this.addViewMode(this.viewModeStateComparison, '#LDS#State comparison'); this.viewModeValue = this.viewModeGrid; - this.compareDateFormControl.setValue(new Date(new Date().setHours(23, 59, 59, 999))); await this.refresh(true); } @@ -139,7 +144,7 @@ export class ObjectHistoryComponent implements OnInit, OnDestroy { this.subscriptions.push( this.timelineFromDateFormControl.valueChanges.subscribe((date) => { this.timelineFrom.date = moment(date).format('YYYY-MM-DD'); - this.getFilteredHistoryData(); + this.timelineFromTimeFormControl.setValue(date || moment().startOf('day')); }), this.timelineFromTimeFormControl.valueChanges.subscribe((time) => { this.timelineFrom.time = moment(time).format('HH:mm:ss'); @@ -147,18 +152,17 @@ export class ObjectHistoryComponent implements OnInit, OnDestroy { }), this.timelineToDateFormControl.valueChanges.subscribe((date) => { this.timelineTo.date = moment(date).format('YYYY-MM-DD'); - this.getFilteredHistoryData(); + this.timelineToTimeFormControl.setValue(date || moment().startOf('day')); }), this.timelineToTimeFormControl.valueChanges.subscribe((time) => { this.timelineTo.time = moment(time).format('HH:mm:ss'); this.getFilteredHistoryData(); - }) + }), ); } private getFilteredHistoryData() { - if (this.historyData && this.viewModeValue === this.viewModeGrid) - this.filteredHistoryData = this.filterByTime(this.historyData); + if (this.historyData && this.viewModeValue === this.viewModeGrid) this.filteredHistoryData = this.filterByTime(this.historyData); } public async onViewModeChange(): Promise { @@ -172,23 +176,26 @@ export class ObjectHistoryComponent implements OnInit, OnDestroy { } public async refresh(fetchRemote: boolean): Promise { - let overlayRef: OverlayRef; - setTimeout(() => (overlayRef = this.busyService.show())); + if (this.busyService.overlayRefs.length === 0) { + this.busyService.show(); + } try { this.historyData = []; this.stateOverviewItems = []; this.historyComparisonData = []; - const table = this.objectType || this.activatedRoute.snapshot.paramMap.get('table'); - const uid = this.objectUid || this.activatedRoute.snapshot.paramMap.get('uid'); + const table = (this.objectType || this.activatedRoute.snapshot.paramMap.get('table')) ?? ''; + const uid = (this.objectUid || this.activatedRoute.snapshot.paramMap.get('uid')) ?? ''; if (this.viewModeValue === this.viewModeGrid) { const parameters: ObjectHistoryParameters = { table, uid, }; - this.filteredHistoryData = this.historyData = await this.historyService.get(parameters, fetchRemote); + const fetched = await this.historyService.get(parameters, fetchRemote); + this.historyData = fetched.map((elem) => ({ ...elem, Time: '00:00:00' })); + this.getFilteredHistoryData(); } else if (this.viewModeValue === this.viewModeStateOverview) { const stateOverviewItems = await this.historyService.getStateOverviewItems(table, uid); if (stateOverviewItems) { @@ -199,8 +206,6 @@ export class ObjectHistoryComponent implements OnInit, OnDestroy { if (date) { this.historyComparisonData = await this.historyService.getHistoryComparisonData(table, uid, { CompareDate: date }); - } else { - this.historyComparisonData = await this.historyService.getHistoryComparisonData(table, uid); } } } catch { @@ -208,15 +213,32 @@ export class ObjectHistoryComponent implements OnInit, OnDestroy { this.stateOverviewItems = []; this.historyComparisonData = []; } finally { - setTimeout(() => this.busyService.hide(overlayRef)); + this.busyService.hide(); } } + /** + * Updates the selected change types and call getFilterHistoryData() function on user checkbox change event. + * @param type Type of event change type. + */ + public onFilterTypeChanged(type: EventChangeType): void { + if (this.selectedEventChangeTypes.indexOf(type) === -1) { + this.selectedEventChangeTypes.push(type); + } else { + this.selectedEventChangeTypes = this.selectedEventChangeTypes.filter((selectedType) => selectedType !== type); + } + this.getFilteredHistoryData(); + } + + /** + * Checks the event change type is selected or not. + */ + public getFilterTypeValue(type: EventChangeType): boolean { + return this.selectedEventChangeTypes.indexOf(type) > -1; + } + private async addViewMode(value: string, displayKey: string): Promise { - const viewMode = new ViewMode(); - viewMode.value = value; - viewMode.display = await this.translate.get(displayKey).toPromise(); - this.viewModes.push(viewMode); + this.viewModes.push({ display: this.translate.instant(displayKey), value }); } private resetTimelineForm(): void { @@ -229,23 +251,34 @@ export class ObjectHistoryComponent implements OnInit, OnDestroy { /** * Handles from and to filtering and loads the result after filtering */ - private filterByTime(data: ObjectHistoryEvent[]): ObjectHistoryEvent[] | ExtendedObjectHistoryEvent[] { + private filterByTime(data: ObjectHistoryEvent[]): ExtendedObjectHistoryEvent[] { if (this.timelineFromString === 'Invalid date' && this.timelineToString === 'Invalid date') { - return data; + return this.filterByType(data).map((elem) => ({ ...elem, Time: '00:00:00' })); } - const isFromValid = this.timelineFromString !== 'Invalid date'; const isToValid = this.timelineToString !== 'Invalid date'; + return this.filterByType(data) + .filter((elem) => { + const momentElemTime = moment(elem.ChangeTime); + const fromValidation = momentElemTime.isAfter(moment(this.timelineFromString), 'second'); + const toValidation = momentElemTime.isBefore(moment(this.timelineToString), 'second'); + if (isFromValid && !isToValid) return fromValidation; + if (!isFromValid && isToValid) return toValidation; + return fromValidation && toValidation; + }) + .map((elem) => ({ ...elem, Time: '00:00:00' })); + } + /** + * Handles filtering events by change type. + */ + private filterByType(data: ObjectHistoryEvent[]): ObjectHistoryEvent[] { return data.filter((elem) => { - const momentElemTime = moment(elem.ChangeTime); - const fromValidation = momentElemTime.isAfter(moment(this.timelineFromString), 'second'); - const toValidation = momentElemTime.isBefore(moment(this.timelineToString), 'second'); - - if (isFromValid && !isToValid) return fromValidation; - if (!isFromValid && isToValid) return toValidation; - - return fromValidation && toValidation; + if (!!this.selectedEventChangeTypes.length) { + return this.selectedEventChangeTypes.indexOf(HistoryEventChangeType[elem.ChangeTypeId || '']) > -1; + } else { + return true; + } }); } } diff --git a/imxweb/projects/qbm/src/lib/object-history/object-history.module.ts b/imxweb/projects/qbm/src/lib/object-history/object-history.module.ts index d5088363c..22bde547d 100644 --- a/imxweb/projects/qbm/src/lib/object-history/object-history.module.ts +++ b/imxweb/projects/qbm/src/lib/object-history/object-history.module.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -40,34 +40,23 @@ import { TranslateModule } from '@ngx-translate/core'; import { DataSourceToolbarModule } from '../data-source-toolbar/data-source-toolbar.module'; import { DataTableModule } from '../data-table/data-table.module'; import { ObjectHistoryGridviewComponent } from './object-history-gridview/object-history-gridview.component'; -import { ObjectHistoryComponent } from './object-history.component'; import { ObjectHistoryStateComparisonComponent } from './object-history-state-comparison/object-history-state-comparison.component'; import { ObjectHistoryStateOverviewComponent } from './object-history-state-overview/object-history-state-overview.component'; +import { ObjectHistoryComponent } from './object-history.component'; -import {MomentDateAdapter} from '@angular/material-moment-adapter'; - import {DateAdapter, MAT_DATE_FORMATS, MAT_DATE_LOCALE} from '@angular/material/core'; import { MatButtonToggleModule } from '@angular/material/button-toggle'; +import { MatCheckboxModule } from '@angular/material/checkbox'; +import { MatMenuModule } from '@angular/material/menu'; +import { EuiDateProviders } from '../base/elemental-defaults'; import { TimelineComponent } from '../timeline/timeline.component'; - export const EUI_DATE_FORMATS = { - parse: { - dateInput: ['LL', 'L'], - }, - display: { - dateInput: 'LL', - monthYearLabel: 'MMM YYYY', - dateA11yLabel: 'LL', - monthYearA11yLabel: 'MMMM YYYY', - }, - }; - @NgModule({ declarations: [ ObjectHistoryGridviewComponent, ObjectHistoryComponent, ObjectHistoryStateComparisonComponent, ObjectHistoryStateOverviewComponent, - TimelineComponent + TimelineComponent, ], imports: [ CommonModule, @@ -85,16 +74,10 @@ import { TimelineComponent } from '../timeline/timeline.component'; MatTableModule, MatPaginatorModule, MatButtonToggleModule, + MatMenuModule, + MatCheckboxModule, ], - providers: [ - {provide: DateAdapter, useClass: MomentDateAdapter, deps: [MAT_DATE_LOCALE]}, - {provide: MAT_DATE_FORMATS, useValue: EUI_DATE_FORMATS} - ], - exports: [ - ObjectHistoryComponent, - ObjectHistoryGridviewComponent - ] + providers: [...EuiDateProviders], + exports: [ObjectHistoryComponent, ObjectHistoryGridviewComponent], }) -export class ObjectHistoryModule { - -} +export class ObjectHistoryModule {} diff --git a/imxweb/projects/qbm/src/lib/object-history/object-history.service.ts b/imxweb/projects/qbm/src/lib/object-history/object-history.service.ts index 233ad5522..4e7a514f3 100644 --- a/imxweb/projects/qbm/src/lib/object-history/object-history.service.ts +++ b/imxweb/projects/qbm/src/lib/object-history/object-history.service.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -25,14 +25,14 @@ */ import { Injectable } from '@angular/core'; -import { HistoryComparisonData } from 'imx-api-qbm'; -import { IStateOverviewItem, ObjectHistoryEvent } from 'imx-qbm-dbts'; -import { ObjectHistoryApiService } from './object-history-api.service'; +import { HistoryComparisonData } from '@imx-modules/imx-api-qbm'; +import { IStateOverviewItem, ObjectHistoryEvent } from '@imx-modules/imx-qbm-dbts'; import { MetadataService } from '../base/metadata.service'; +import { ObjectHistoryApiService } from './object-history-api.service'; export interface ObjectHistoryParameters { - table: string; - uid: string; + table?: string | null; + uid?: string | null; } @Injectable({ @@ -48,9 +48,12 @@ export class ObjectHistoryService { public async get(parameters: ObjectHistoryParameters, fetchRemote: boolean = true): Promise { if (fetchRemote || this.dataCached == null) { - this.dataCached = (await this.apiService.getHistoryData(parameters.table, parameters.uid)) - .map((x) => x.Events) - .reduce((a, b) => a.concat(b)); + this.dataCached = + parameters.table && parameters.uid + ? (await this.apiService.getHistoryData(parameters.table, parameters.uid)) + ?.map((x) => x.Events) + ?.reduce((a, b) => (a ?? []).concat(b ?? [])) ?? [] + : []; } return this.dataCached; @@ -59,7 +62,7 @@ export class ObjectHistoryService { public async getStateOverviewItems(table: string, uid: string): Promise { let stateOverviewItems = (await this.apiService.getHistoryData(table, uid)) .map((x) => x.StateOverviewItems) - .reduce((a, b) => a.concat(b)); + .reduce((a, b) => (a ?? []).concat(b ?? [])); return stateOverviewItems; } @@ -67,8 +70,8 @@ export class ObjectHistoryService { let historyComparisonData = await this.apiService.getHistoryComparisonData(table, uid, options); // Update tableName with translated display name for await (const item of historyComparisonData) { - await this.metadataService.updateNonExisting([item.TableName]); - item.TableName = this.metadataService.tables[item.TableName].Display; + await this.metadataService.updateNonExisting([item.TableName ?? '']); + item.TableName = this.metadataService.tables[item.TableName ?? '']?.Display; } return historyComparisonData; } diff --git a/imxweb/projects/qbm/src/lib/ordered-list/ordered-list.component.html b/imxweb/projects/qbm/src/lib/ordered-list/ordered-list.component.html index 758d7f96a..36775f191 100644 --- a/imxweb/projects/qbm/src/lib/ordered-list/ordered-list.component.html +++ b/imxweb/projects/qbm/src/lib/ordered-list/ordered-list.component.html @@ -1,20 +1,28 @@
    - {{placeholder}} + {{ placeholder }}
    - - - {{ pr.Display }} + + + {{ pr?.Display }}
    -
    -
    - +
    +
    diff --git a/imxweb/projects/qbm/src/lib/ordered-list/ordered-list.component.scss b/imxweb/projects/qbm/src/lib/ordered-list/ordered-list.component.scss index 9bebb5471..9845e0986 100644 --- a/imxweb/projects/qbm/src/lib/ordered-list/ordered-list.component.scss +++ b/imxweb/projects/qbm/src/lib/ordered-list/ordered-list.component.scss @@ -1,10 +1,6 @@ @import '@elemental-ui/core/src/styles/_eui_palette.scss'; :host { - .buttonbar { - margin: 1em 0; - } - .ordered-list { min-height: 45px; display: block; @@ -31,14 +27,17 @@ .cdk-drag-preview { box-sizing: border-box; border-radius: 4px; - box-shadow: 0 5px 5px -3px rgba(0, 0, 0, 0.2), 0 8px 10px 1px rgba(0, 0, 0, 0.14), 0 3px 14px 2px rgba(0, 0, 0, 0.12); + box-shadow: + 0 5px 5px -3px rgba(0, 0, 0, 0.2), + 0 8px 10px 1px rgba(0, 0, 0, 0.14), + 0 3px 14px 2px rgba(0, 0, 0, 0.12); } - .ordered-list--placeholder { - min-height: 75px; - border-radius: 4px; - transition: transform 250ms cubic-bezier(0, 0, 0.2, 1); - } +.ordered-list--placeholder { + min-height: 75px; + border-radius: 4px; + transition: transform 250ms cubic-bezier(0, 0, 0.2, 1); +} .cdk-drag-animating { transition: transform 250ms cubic-bezier(0, 0, 0.2, 1); @@ -78,7 +77,7 @@ background: $color-gray-0; } - .ordered-list--placeholder { + .ordered-list--placeholder { background-color: $color-gray-30; border: dotted 2px $color-gray-40; } @@ -102,7 +101,7 @@ background: $color-gray-70; } - .ordered-list--placeholder { + .ordered-list--placeholder { background-color: $color-gray-50; border: dotted 2px $color-gray-20; } @@ -114,8 +113,8 @@ } } -.eui-contrast-theme{ -:host { +.eui-contrast-theme { + :host { .ordered-list { border: solid 1px $color-gray-0; background: $color-gray-100; @@ -126,7 +125,7 @@ background: $color-gray-100; } - .ordered-list--placeholder { + .ordered-list--placeholder { background-color: $color-gray-50; border: dotted 2px $color-gray-0; } diff --git a/imxweb/projects/qbm/src/lib/ordered-list/ordered-list.component.ts b/imxweb/projects/qbm/src/lib/ordered-list/ordered-list.component.ts index d07ad4732..a19bb23f5 100644 --- a/imxweb/projects/qbm/src/lib/ordered-list/ordered-list.component.ts +++ b/imxweb/projects/qbm/src/lib/ordered-list/ordered-list.component.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -24,8 +24,8 @@ * */ -import { Component, EventEmitter, Input, Output } from '@angular/core'; import { CdkDragDrop, moveItemInArray } from '@angular/cdk/drag-drop'; +import { Component, EventEmitter, Input, Output } from '@angular/core'; import { EuiTheme } from '@elemental-ui/core'; @Component({ @@ -38,7 +38,7 @@ export class OrderedListComponent { @Input() deleteText: string; @Input() placeholder: string; @Input() testId: string = 'list'; - @Input() dataSource: { Name: string; Display: string }[] = []; + @Input() dataSource: { Name?: string; Display?: string }[] = []; @Input() data: string[] = []; @Input() isReadOnly: boolean = false; @@ -50,10 +50,10 @@ export class OrderedListComponent { return bodyClasses.contains(EuiTheme.LIGHT) ? EuiTheme.LIGHT : bodyClasses.contains(EuiTheme.DARK) - ? EuiTheme.DARK - : bodyClasses.contains(EuiTheme.CONTRAST) - ? EuiTheme.CONTRAST - : ''; + ? EuiTheme.DARK + : bodyClasses.contains(EuiTheme.CONTRAST) + ? EuiTheme.CONTRAST + : ''; } public drop(event: CdkDragDrop): void { @@ -67,7 +67,7 @@ export class OrderedListComponent { } public addNew(): void { - this.data.push(null); + this.data.push(''); this.notifyChange(); } diff --git a/imxweb/projects/qbm/src/lib/ordered-list/ordered-list.module.ts b/imxweb/projects/qbm/src/lib/ordered-list/ordered-list.module.ts index 19e8b5976..ead76ebe3 100644 --- a/imxweb/projects/qbm/src/lib/ordered-list/ordered-list.module.ts +++ b/imxweb/projects/qbm/src/lib/ordered-list/ordered-list.module.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -24,31 +24,18 @@ * */ -import { DragDropModule } from "@angular/cdk/drag-drop"; -import { CommonModule } from "@angular/common"; -import { NgModule } from "@angular/core"; -import { FormsModule } from "@angular/forms"; -import { MatSelectModule } from "@angular/material/select"; -import { EuiCoreModule, EuiMaterialModule } from "@elemental-ui/core"; -import { OrderedListComponent } from "./ordered-list.component"; +import { DragDropModule } from '@angular/cdk/drag-drop'; +import { CommonModule } from '@angular/common'; +import { NgModule } from '@angular/core'; +import { FormsModule } from '@angular/forms'; +import { MatSelectModule } from '@angular/material/select'; +import { EuiCoreModule, EuiMaterialModule } from '@elemental-ui/core'; +import { OrderedListComponent } from './ordered-list.component'; /** Provides an editor component to edit an ordered list of elements. */ @NgModule({ - imports: [ - CommonModule, - DragDropModule, - MatSelectModule, - FormsModule, - EuiCoreModule, - EuiMaterialModule, - ], - declarations: [ - OrderedListComponent - ], - exports: [ - OrderedListComponent - ] + imports: [CommonModule, DragDropModule, MatSelectModule, FormsModule, EuiCoreModule, EuiMaterialModule], + declarations: [OrderedListComponent], + exports: [OrderedListComponent], }) -export class OrderedListModule { - -} \ No newline at end of file +export class OrderedListModule {} diff --git a/imxweb/projects/qbm/src/lib/parameterized-text/parameter-replacement.interface.ts b/imxweb/projects/qbm/src/lib/parameterized-text/parameter-replacement.interface.ts index 5b356673d..02f9e5d0d 100644 --- a/imxweb/projects/qbm/src/lib/parameterized-text/parameter-replacement.interface.ts +++ b/imxweb/projects/qbm/src/lib/parameterized-text/parameter-replacement.interface.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR diff --git a/imxweb/projects/qbm/src/lib/parameterized-text/parameterized-text.component.html b/imxweb/projects/qbm/src/lib/parameterized-text/parameterized-text.component.html index 302634871..3859b7c1e 100644 --- a/imxweb/projects/qbm/src/lib/parameterized-text/parameterized-text.component.html +++ b/imxweb/projects/qbm/src/lib/parameterized-text/parameterized-text.component.html @@ -3,4 +3,6 @@ {{ textToken.value }} {{ textToken.value }} + + {{ '; ' + additionalText }}
    diff --git a/imxweb/projects/qbm/src/lib/parameterized-text/parameterized-text.component.scss b/imxweb/projects/qbm/src/lib/parameterized-text/parameterized-text.component.scss index df55d109f..7dcd90bdc 100644 --- a/imxweb/projects/qbm/src/lib/parameterized-text/parameterized-text.component.scss +++ b/imxweb/projects/qbm/src/lib/parameterized-text/parameterized-text.component.scss @@ -7,5 +7,5 @@ .imx-parameter-container { word-wrap: break-word; + display: block !important } - diff --git a/imxweb/projects/qbm/src/lib/parameterized-text/parameterized-text.component.ts b/imxweb/projects/qbm/src/lib/parameterized-text/parameterized-text.component.ts index 3795b082d..8ff1a39c2 100644 --- a/imxweb/projects/qbm/src/lib/parameterized-text/parameterized-text.component.ts +++ b/imxweb/projects/qbm/src/lib/parameterized-text/parameterized-text.component.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -33,15 +33,16 @@ import { TextToken } from './text-token.interface'; @Component({ selector: 'imx-parameterized-text', templateUrl: './parameterized-text.component.html', - styleUrls: ['./parameterized-text.component.scss'] + styleUrls: ['./parameterized-text.component.scss'], }) export class ParameterizedTextComponent implements OnInit { public textTokens: TextToken[]; @Input() parameterizedText: ParameterizedText; + @Input() additionalText: string = ''; @Output() textReady = new EventEmitter(); - constructor(private readonly service: ParameterizedTextService) { } + constructor(private readonly service: ParameterizedTextService) {} public ngOnInit(): void { this.textTokens = this.service.createTextTokens(this.parameterizedText); diff --git a/imxweb/projects/qbm/src/lib/parameterized-text/parameterized-text.interface.ts b/imxweb/projects/qbm/src/lib/parameterized-text/parameterized-text.interface.ts index 647219ce7..99b1b3f54 100644 --- a/imxweb/projects/qbm/src/lib/parameterized-text/parameterized-text.interface.ts +++ b/imxweb/projects/qbm/src/lib/parameterized-text/parameterized-text.interface.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -26,6 +26,6 @@ export interface ParameterizedText { value: string; - marker: { start: string; end: string; }; + marker: { start: string; end: string }; getParameterValue: (name: string) => string; } diff --git a/imxweb/projects/qbm/src/lib/parameterized-text/parameterized-text.module.ts b/imxweb/projects/qbm/src/lib/parameterized-text/parameterized-text.module.ts index 1f176e77b..2205b4e2e 100644 --- a/imxweb/projects/qbm/src/lib/parameterized-text/parameterized-text.module.ts +++ b/imxweb/projects/qbm/src/lib/parameterized-text/parameterized-text.module.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -30,14 +30,8 @@ import { CommonModule } from '@angular/common'; import { ParameterizedTextComponent } from './parameterized-text.component'; @NgModule({ - declarations: [ - ParameterizedTextComponent - ], - exports: [ - ParameterizedTextComponent - ], - imports: [ - CommonModule - ] + declarations: [ParameterizedTextComponent], + exports: [ParameterizedTextComponent], + imports: [CommonModule], }) -export class ParameterizedTextModule { } +export class ParameterizedTextModule {} diff --git a/imxweb/projects/qbm/src/lib/parameterized-text/parameterized-text.service.ts b/imxweb/projects/qbm/src/lib/parameterized-text/parameterized-text.service.ts index 7f9a7c722..78c91902b 100644 --- a/imxweb/projects/qbm/src/lib/parameterized-text/parameterized-text.service.ts +++ b/imxweb/projects/qbm/src/lib/parameterized-text/parameterized-text.service.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -31,16 +31,16 @@ import { ParameterizedText } from './parameterized-text.interface'; import { TextToken } from './text-token.interface'; @Injectable({ - providedIn: 'root' + providedIn: 'root', }) export class ParameterizedTextService { public createTextTokens(text: ParameterizedText): TextToken[] { const parameters = this.getParametersWithMatchingValue(text); - const output = []; + const output: TextToken[] = []; let part = text.value; - for (const parameter of parameters) { + for (const parameter of parameters) { const tokens = part.split(parameter.delimiter); const head = tokens[0]; @@ -65,10 +65,10 @@ export class ParameterizedTextService { private getParametersWithMatchingValue(text: ParameterizedText): ParameterReplacement[] { const re = new RegExp('(' + text.marker.start + '[^"]+' + text.marker.end + ')', 'g'); return (text.value.match(re) ?? []) - .map(parameter => ({ + .map((parameter) => ({ delimiter: parameter, - replacement: text.getParameterValue(parameter.split(text.marker.start).join('').split(text.marker.end).join('')) + replacement: text.getParameterValue(parameter.split(text.marker.start).join('').split(text.marker.end).join('')), })) - .filter(parameter => parameter.replacement != null); + .filter((parameter) => parameter.replacement != null); } } diff --git a/imxweb/projects/qbm/src/lib/parameterized-text/text-token.interface.ts b/imxweb/projects/qbm/src/lib/parameterized-text/text-token.interface.ts index b84ec1eeb..d8ef35f84 100644 --- a/imxweb/projects/qbm/src/lib/parameterized-text/text-token.interface.ts +++ b/imxweb/projects/qbm/src/lib/parameterized-text/text-token.interface.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR diff --git a/imxweb/projects/qbm/src/lib/plugins/plugin-loader.service.ts b/imxweb/projects/qbm/src/lib/plugins/plugin-loader.service.ts deleted file mode 100644 index 1f674a722..000000000 --- a/imxweb/projects/qbm/src/lib/plugins/plugin-loader.service.ts +++ /dev/null @@ -1,260 +0,0 @@ -/* - * ONE IDENTITY LLC. PROPRIETARY INFORMATION - * - * This software is confidential. One Identity, LLC. or one of its affiliates or - * subsidiaries, has supplied this software to you under terms of a - * license agreement, nondisclosure agreement or both. - * - * You may not copy, disclose, or use this software except in accordance with - * those terms. - * - * - * Copyright 2023 One Identity LLC. - * ALL RIGHTS RESERVED. - * - * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR - * WARRANTIES ABOUT THE SUITABILITY OF THE SOFTWARE, - * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED - * TO THE IMPLIED WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE, OR - * NON-INFRINGEMENT. ONE IDENTITY LLC. SHALL NOT BE - * LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE - * AS A RESULT OF USING, MODIFYING OR DISTRIBUTING - * THIS SOFTWARE OR ITS DERIVATIVES. - * - */ - -import { Injectable, Injector, isDevMode, createNgModuleRef } from '@angular/core'; -import { HttpClient, HttpHeaders } from '@angular/common/http'; - -import { NodeAppInfo, PlugInInfo } from 'imx-api-qbm'; - -import { imx_SessionService } from '../session/imx-session.service'; -import { ClassloggerService } from '../classlogger/classlogger.service'; -import { AppConfig } from '../appConfig/appconfig.interface'; - -import * as AngularCore from '@angular/core'; -import * as AngularCommon from '@angular/common'; -import * as AngularCommonHttp from '@angular/common/http'; -import * as AngularRouter from '@angular/router'; -import * as BrowserAnimations from '@angular/platform-browser/animations'; -import * as PlatformBrowser from '@angular/platform-browser'; -import * as AngularMaterialCore from '@angular/material/core'; -import * as CdkDragDropAngularMaterial from '@angular/cdk/drag-drop'; -import * as CdkPortalAngularMaterial from '@angular/cdk/portal'; -import * as CdkScrollingAngularMaterial from '@angular/cdk/scrolling'; -import * as CdkStepperModule from '@angular/cdk/stepper'; -import * as CdkTableModule from '@angular/cdk/table'; -import * as CdkTreeModule from '@angular/cdk/tree'; -import * as CdkPlatformModule from '@angular/cdk/platform'; -import * as CdkTextFieldModule from '@angular/cdk/text-field'; -import * as CdkKeycodesModule from '@angular/cdk/keycodes'; -import * as BadgeModule from '@angular/material/badge'; -import * as BottomSheetModule from '@angular/material/bottom-sheet'; -import * as ButtonModule from '@angular/material/button'; -import * as ButtonToggleModule from '@angular/material/button-toggle'; -import * as MatCardModule from '@angular/material/card'; -import * as MatCheckboxModule from '@angular/material/checkbox'; -import * as MatChipsModule from '@angular/material/chips'; -import * as MatStepperModule from '@angular/material/stepper'; -import * as MatDatepickerModule from '@angular/material/datepicker'; -import * as MatDialogModule from '@angular/material/dialog'; -import * as MatDividerModule from '@angular/material/divider'; -import * as MatExpansionModule from '@angular/material/expansion'; -import * as MatGridListModule from '@angular/material/grid-list'; -import * as MatIconModule from '@angular/material/icon'; -import * as MatInputModule from '@angular/material/input'; -import * as MatListModule from '@angular/material/list'; -import * as MatMenuModule from '@angular/material/menu'; -import * as MatPaginatorModule from '@angular/material/paginator'; -import * as MatProgressBarModule from '@angular/material/progress-bar'; -import * as MatProgressSpinnerModule from '@angular/material/progress-spinner'; -import * as MatRadioModule from '@angular/material/radio'; -import * as MatSelectModule from '@angular/material/select'; -import * as MatSidenavModule from '@angular/material/sidenav'; -import * as MatSliderModule from '@angular/material/slider'; -import * as MatSlideToggleModule from '@angular/material/slide-toggle'; -import * as MatSnackBarModule from '@angular/material/snack-bar'; -import * as MatSortModule from '@angular/material/sort'; -import * as MatTableModule from '@angular/material/table'; -import * as MatTabsModule from '@angular/material/tabs'; -import * as MatToolbarModule from '@angular/material/toolbar'; -import * as MatTooltipModule from '@angular/material/tooltip'; -import * as MatTreeModule from '@angular/material/tree'; -import * as OverlayModule from '@angular/cdk/overlay'; -import * as MatFormFieldModule from '@angular/material/form-field'; -import * as MatAutocompleteModule from '@angular/material/autocomplete'; -import * as FormsModule from '@angular/forms'; -import * as NgxTranslateModule from '@ngx-translate/core'; -import * as QBMDBTS from 'imx-qbm-dbts'; -import * as ElementUICore from '@elemental-ui/core'; -import * as Rxjs from 'rxjs'; -import * as RxjsOperators from 'rxjs/operators'; -import * as BillboardJs from 'billboard.js'; -import * as tslibModule from 'tslib'; -import * as MomentTimezone from 'moment-timezone'; -import * as lodash from 'lodash'; - -declare var SystemJS: any; - -@Injectable({ - providedIn: 'root', -}) -export class PluginLoaderService { - private appInfo: NodeAppInfo; - private plugins: PlugInInfo[] = []; - - constructor( - private readonly session: imx_SessionService, - private readonly logger: ClassloggerService, - private readonly httpClient: HttpClient, - private readonly injector: Injector - ) { - SystemJS.config({ - meta: { - '*.mjs': { - babelOptions: { - es2015: false - } - } - }, - map: { - 'plugin-babel': 'systemjs-plugin-babel/plugin-babel.js', - 'systemjs-babel-build': 'systemjs-plugin-babel/systemjs-babel-browser.js', - }, - transpiler: 'plugin-babel', - }); - } - - public async loadModules(appName: string): Promise { - const apps: NodeAppInfo[] = await this.session.Client.imx_applications_get(); - - this.appInfo = apps.filter((app) => app.Name === appName)[0]; - - this.logger.debug(this, `▶️ Found config section for ${this.appInfo.DisplayName}`); - - if (this.appInfo.PlugIns == null || this.appInfo.PlugIns.length === 0) { - this.logger.debug(this, `❌ No plugins found`); - return; - } - - this.logger.debug(this, `▶️ Found ${this.appInfo.PlugIns.length} plugin(s)`); - - const host = window.location.href.split('html')[0]; - this.logger.debug(this, `💻 Host: ${host} `); - - let config: AppConfig; - - if (!isDevMode()) { - config = (await this.httpClient.get('appconfig.json').toPromise()) as AppConfig; - this.importDependencies(); - this.logger.debug(this, '▶️ Config. PROD mode.', config); - } - - let moduleList = []; - - for (const plugin of this.appInfo.PlugIns) { - this.logger.debug(this, `⚙️ Plugin: ${plugin.Container}`); - - try { - if (isDevMode()) { - this.logger.debug(this, '▶️ Importing module. DEV mode.'); - moduleList.push(import(`html/${plugin.Container}/fesm2015/${plugin.Container}.mjs`)); - } else { - this.logger.debug(this, '▶️ Importing module. PROD mode.'); - moduleList.push(SystemJS.import(`${host}html/${plugin.Container}/fesm2015/${plugin.Container}.mjs`)); - } - - this.plugins.push(plugin); - } catch (e) { - this.logger.error(this, `💥 Loading of ${plugin.Name} (${plugin.Container}) failed with the following error: ${e.message}`); - } - } - - let modules = await Promise.allSettled(moduleList); - for (let i = 0; i < modules.length; i++) { - try { - let m = modules[i] as any; - let module = m.value[this.plugins[i].Name as any]; - createNgModuleRef(module, this.injector); - this.logger.debug(this, '▶️ Instance ready'); - } catch (e) { - this.logger.error( - this, - `💥 Loading of ${this.plugins[i].Name} (${this.plugins[i].Container}) failed with the following error: ${e.message}` - ); - } - } - } - - private importDependencies(): void { - // Angular Modules - SystemJS.set('@angular/core', SystemJS.newModule(AngularCore)); - SystemJS.set('@angular/common', SystemJS.newModule(AngularCommon)); - SystemJS.set('@angular/router', SystemJS.newModule(AngularRouter)); - SystemJS.set('@angular/platform-browser/animations', SystemJS.newModule(BrowserAnimations)); - SystemJS.set('@angular/common/http', SystemJS.newModule(AngularCommonHttp)); - - // Angular Material Modules - SystemJS.set('@angular/material/core', SystemJS.newModule(AngularMaterialCore)); - SystemJS.set('@angular/cdk/drag-drop', SystemJS.newModule(CdkDragDropAngularMaterial)); - SystemJS.set('@angular/cdk/portal', SystemJS.newModule(CdkPortalAngularMaterial)); - SystemJS.set('@angular/cdk/scrolling', SystemJS.newModule(CdkScrollingAngularMaterial)); - SystemJS.set('@angular/cdk/stepper', SystemJS.newModule(CdkStepperModule)); - SystemJS.set('@angular/cdk/table', SystemJS.newModule(CdkTableModule)); - SystemJS.set('@angular/cdk/platform', SystemJS.newModule(CdkPlatformModule)); - SystemJS.set('@angular/cdk/tree', SystemJS.newModule(CdkTreeModule)); - SystemJS.set('@angular/cdk/text-field', SystemJS.newModule(CdkTextFieldModule)); - SystemJS.set('@angular/cdk/keycodes', SystemJS.newModule(CdkKeycodesModule)); - SystemJS.set('@angular/material/badge', SystemJS.newModule(BadgeModule)); - SystemJS.set('@angular/material/bottom-sheet', SystemJS.newModule(BottomSheetModule)); - SystemJS.set('@angular/material/button', SystemJS.newModule(ButtonModule)); - SystemJS.set('@angular/material/button-toggle', SystemJS.newModule(ButtonToggleModule)); - SystemJS.set('@angular/material/card', SystemJS.newModule(MatCardModule)); - SystemJS.set('@angular/material/checkbox', SystemJS.newModule(MatCheckboxModule)); - SystemJS.set('@angular/material/chips', SystemJS.newModule(MatChipsModule)); - SystemJS.set('@angular/material/stepper', SystemJS.newModule(MatStepperModule)); - SystemJS.set('@angular/material/datepicker', SystemJS.newModule(MatDatepickerModule)); - SystemJS.set('@angular/material/dialog', SystemJS.newModule(MatDialogModule)); - SystemJS.set('@angular/material/divider', SystemJS.newModule(MatDividerModule)); - SystemJS.set('@angular/material/expansion', SystemJS.newModule(MatExpansionModule)); - SystemJS.set('@angular/material/grid-list', SystemJS.newModule(MatGridListModule)); - SystemJS.set('@angular/material/icon', SystemJS.newModule(MatIconModule)); - SystemJS.set('@angular/material/input', SystemJS.newModule(MatInputModule)); - SystemJS.set('@angular/material/list', SystemJS.newModule(MatListModule)); - SystemJS.set('@angular/material/menu', SystemJS.newModule(MatMenuModule)); - SystemJS.set('@angular/material/paginator', SystemJS.newModule(MatPaginatorModule)); - SystemJS.set('@angular/material/progress-bar', SystemJS.newModule(MatProgressBarModule)); - SystemJS.set('@angular/material/progress-spinner', SystemJS.newModule(MatProgressSpinnerModule)); - SystemJS.set('@angular/material/radio', SystemJS.newModule(MatRadioModule)); - SystemJS.set('@angular/material/select', SystemJS.newModule(MatSelectModule)); - SystemJS.set('@angular/material/sidenav', SystemJS.newModule(MatSidenavModule)); - SystemJS.set('@angular/material/slider', SystemJS.newModule(MatSliderModule)); - SystemJS.set('@angular/material/slide-toggle', SystemJS.newModule(MatSlideToggleModule)); - SystemJS.set('@angular/material/snack-bar', SystemJS.newModule(MatSnackBarModule)); - SystemJS.set('@angular/material/sort', SystemJS.newModule(MatSortModule)); - SystemJS.set('@angular/material/table', SystemJS.newModule(MatTableModule)); - SystemJS.set('@angular/material/tabs', SystemJS.newModule(MatTabsModule)); - SystemJS.set('@angular/material/toolbar', SystemJS.newModule(MatToolbarModule)); - SystemJS.set('@angular/material/tooltip', SystemJS.newModule(MatTooltipModule)); - SystemJS.set('@angular/material/tree', SystemJS.newModule(MatTreeModule)); - SystemJS.set('@angular/material/autocomplete', SystemJS.newModule(MatAutocompleteModule)); - SystemJS.set('@angular/cdk/overlay', SystemJS.newModule(OverlayModule)); - SystemJS.set('@angular/material/form-field', SystemJS.newModule(MatFormFieldModule)); - SystemJS.set('@angular/forms', SystemJS.newModule(FormsModule)); - SystemJS.set('@angular/platform-browser', SystemJS.newModule(PlatformBrowser)); - - // Other stuff - SystemJS.set('@ngx-translate/core', SystemJS.newModule(NgxTranslateModule)); - SystemJS.set('rxjs', SystemJS.newModule(Rxjs)); - SystemJS.set('rxjs/operators', SystemJS.newModule(RxjsOperators)); - SystemJS.set('billboard.js', SystemJS.newModule(BillboardJs)); - SystemJS.set('tslib', SystemJS.newModule(tslibModule)); - SystemJS.set('moment-timezone', SystemJS.newModule(MomentTimezone)); - SystemJS.set('lodash', SystemJS.newModule(lodash)); - - // Our stuff - SystemJS.set('imx-qbm-dbts', SystemJS.newModule(QBMDBTS)); - SystemJS.set('@elemental-ui/core', SystemJS.newModule(ElementUICore)); - } -} diff --git a/imxweb/projects/qbm/src/lib/processing-queue/processing-queue.interface.ts b/imxweb/projects/qbm/src/lib/processing-queue/processing-queue.interface.ts new file mode 100644 index 000000000..60ee29d5b --- /dev/null +++ b/imxweb/projects/qbm/src/lib/processing-queue/processing-queue.interface.ts @@ -0,0 +1,173 @@ +/* + * ONE IDENTITY LLC. PROPRIETARY INFORMATION + * + * This software is confidential. One Identity, LLC. or one of its affiliates or + * subsidiaries, has supplied this software to you under terms of a + * license agreement, nondisclosure agreement or both. + * + * You may not copy, disclose, or use this software except in accordance with + * those terms. + * + * + * Copyright 2024 One Identity LLC. + * ALL RIGHTS RESERVED. + * + * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR + * WARRANTIES ABOUT THE SUITABILITY OF THE SOFTWARE, + * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED + * TO THE IMPLIED WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE, OR + * NON-INFRINGEMENT. ONE IDENTITY LLC. SHALL NOT BE + * LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE + * AS A RESULT OF USING, MODIFYING OR DISTRIBUTING + * THIS SOFTWARE OR ITS DERIVATIVES. + * + */ + +import { computed, effect, Signal, signal, WritableSignal } from '@angular/core'; +import { v4 as uuid } from 'uuid'; + +export class ActionGroup implements QueuedActionGroup { + public uid: string; + public startDate: Date; + public actions: WritableSignal; + /** Action to take when group finishes */ + + /** + * Represents a collection of actions, state derived from the state of the actions + * @param display name of the group of actions, shows up on the accordion + * @param actions set of async tasks that will run in sequence + * @param groupAction optionally set a function to run once the group finishes + */ + constructor( + public display: string, + actions: Action[], + private groupAction?: () => Promise, + ) { + this.display = display; + this.uid = uuid(); + this.startDate = new Date(); + this.actions = signal(actions); + effect( + () => { + if (this.groupAction && CompletedActionStates.includes(this.state())) this.groupAction(); + }, + { allowSignalWrites: true }, + ); + } + + public finishedDate = computed(() => { + const allFinished = this.actions().every((action) => CompletedActionStates.includes(action.state())); + if (allFinished) { + if (this.groupAction) this.groupAction(); + return new Date(); + } else return undefined; + }); + + public taskCount = computed(() => this.actions().length); + public erroredActions = computed(() => this.actions().filter((action) => action.state() == QueuedActionState.Failed)); + public state = computed(() => { + const states = this.actions().map((action) => action.state()); + // If any subaction is processing, the group is in a processing state + if (states.some((state) => state == QueuedActionState.Processing)) return QueuedActionState.Processing; + // If any subaction failed, the group is in a failed state + else if (states.some((state) => state == QueuedActionState.Failed)) return QueuedActionState.Failed; + // If all subactions are success, the group is success. + else if (states.every((state) => state == QueuedActionState.Success)) return QueuedActionState.Success; + // If the above cases aren't met, then we are in waiting? + else return QueuedActionState.Waiting; + }); +} + +export class Action implements QueuedAction { + public uid: string; + public startDate: Date; + public state = signal(QueuedActionState.Waiting); + public error = signal(undefined); + + /** + * Represents a single chunk of work that will be sent off for processing. + * @param display header of task name + * @param display2 subtitle of task name, enter empty string for no display + * @param action async task to be run for this action, should return no values + */ + constructor( + public display: string, + public display2: string, + private action: () => Promise, + public objectKey: string = '', + ) { + this.startDate = new Date(); + this.uid = uuid(); + } + + public finishedDate = computed(() => (CompletedActionStates.includes(this.state()) ? new Date() : undefined)); + + /** + * Clear error state, try to process with the action function, and give a new finished datum + */ + public async execute(): Promise { + this.state.set(QueuedActionState.Processing); + try { + this.error.set(undefined); + await this.action(); + this.state.set(QueuedActionState.Success); + } catch (err) { + this.error.set(err); + this.state.set(QueuedActionState.Failed); + } + } +} + +export enum QueuedActionState { + Waiting, + Processing, + Success, + Failed, + NotInQueue, +} + +export const CompletedActionStates = [QueuedActionState.Failed, QueuedActionState.Success]; + +/** Public interface of a queued action group */ +export interface QueuedActionGroup { + readonly display: string; + + /** Returns the state of the group */ + readonly state: Signal; + + /** Unique id of this group */ + readonly uid: string; + + /** The set of all actions in the group */ + readonly actions: WritableSignal; + + /** The set of all actions that have an error state */ + readonly erroredActions: Signal; + + /** Date when the group was created */ + readonly startDate: Date; + + /** Date when the group had all actions reach a completed state */ + readonly finishedDate: Signal; +} + +/** Public interface of a queued action */ +export interface QueuedAction { + /** Bold header display for action */ + readonly display: string; + /** Sub header display for action */ + readonly display2: string; + /** Underlying object xml key */ + readonly objectKey: string; + /** Returns the state of this action. */ + readonly state: Signal; + /** Unique id for this action */ + readonly uid: string; + /** Returns the error if the state is Failed. */ + readonly error: WritableSignal; + /** Date when the action was queued. */ + readonly startDate: Date; + /** Date when the action reached a finished state */ + readonly finishedDate: Signal; +} diff --git a/imxweb/projects/qbm/src/lib/processing-queue/processing-queue.service.ts b/imxweb/projects/qbm/src/lib/processing-queue/processing-queue.service.ts new file mode 100644 index 000000000..4f7223e30 --- /dev/null +++ b/imxweb/projects/qbm/src/lib/processing-queue/processing-queue.service.ts @@ -0,0 +1,136 @@ +/* + * ONE IDENTITY LLC. PROPRIETARY INFORMATION + * + * This software is confidential. One Identity, LLC. or one of its affiliates or + * subsidiaries, has supplied this software to you under terms of a + * license agreement, nondisclosure agreement or both. + * + * You may not copy, disclose, or use this software except in accordance with + * those terms. + * + * + * Copyright 2024 One Identity LLC. + * ALL RIGHTS RESERVED. + * + * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR + * WARRANTIES ABOUT THE SUITABILITY OF THE SOFTWARE, + * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED + * TO THE IMPLIED WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE, OR + * NON-INFRINGEMENT. ONE IDENTITY LLC. SHALL NOT BE + * LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE + * AS A RESULT OF USING, MODIFYING OR DISTRIBUTING + * THIS SOFTWARE OR ITS DERIVATIVES. + * + */ + +import { computed, EnvironmentInjector, inject, Injectable, runInInjectionContext, signal, WritableSignal } from '@angular/core'; +import { TranslateService } from '@ngx-translate/core'; +import { SnackBarService } from '../snackbar/snack-bar.service'; +import { Action, ActionGroup, CompletedActionStates, QueuedActionState } from './processing-queue.interface'; + +/** Service to manage a queue of asynchronous actions. */ + +@Injectable({ providedIn: 'root' }) +export class ProcessingQueueService { + constructor( + private readonly snackbar: SnackBarService, + private readonly translate: TranslateService, + ) {} + /** Needed to ensure that group action effects can be run correctly */ + private environmentInjector = inject(EnvironmentInjector); + + /** Number of actions we check for before we use the queue service */ + public actionThreshold = 5; + + /** Array of all groups of actions */ + public _groups: WritableSignal = signal([]); + + /** Array of all actions, used for querying status in the pollAction function */ + private _actions = computed(() => this._groups().flatMap((group) => group.actions())); + + /** Internal flag for preventing all calls from happening simultaneously */ + private processing: boolean; + + /** Get the first action that is waiting to be processed */ + private firstWaitingAction = computed(() => this._actions().find((action) => action.state() == QueuedActionState.Waiting)); + + /** Boolean for if any GroupActions succeeded or failed */ + public hasCompletedGroups = computed(() => this._groups().some((group) => CompletedActionStates.includes(group.state()))); + + /** Boolean for if all GroupActions succeeded or failed */ + public isAllGroupsCompleted = computed(() => this._actions().every((action) => CompletedActionStates.includes(action.state()))); + + /** Total count of actions in the queue, regardless of state */ + public totalCount = computed(() => this._groups().reduce((acc, group) => acc + group.actions().length, 0)); + + /** Total count of actions in the queue that have errored */ + public errorCount = computed(() => this._groups().reduce((acc, group) => acc + group.erroredActions().length, 0)); + + /** + * Add a new group of actions to the queue for processing + * @param groupName display for the group of actions + * @param subactions list of actions to be processed as part of this group + * @param groupAction an action that will be run each time the group enters a finshed state from first or retries + */ + public submitGroupAction(groupName: string, actions: Action[], groupAction?: () => Promise): void { + let group: ActionGroup; + runInInjectionContext(this.environmentInjector, () => { + group = new ActionGroup(groupName, actions, groupAction); + }); + this._groups.update((currentGroups) => [...currentGroups, group]); + this.runNextActionIfAvailable(); + + this.snackbar.open({ key: this.translate.instant('#LDS#The actions are processed as background processes.') }); + } + + /** Clear out all groups in succeeded or failed states */ + public removeCompletedGroups(): void { + this._groups.update((currentGroups) => currentGroups.filter((group) => !CompletedActionStates.includes(group.state()))); + } + + /** + * Clear out all groups and set the processing flag to false. + */ + public clearProcessing(): void { + this._groups.update(() => []); + this.processing = false; + } + + /** + * Reprocess a single action that is already in the queue + * @param action that we want to put back into a waiting state and reprocess + */ + public onRetryAction(action: Action): void { + action.state.set(QueuedActionState.Waiting); + if (!this.processing) this.runNextActionIfAvailable(); + } + + /** + * Reprocess all failed actions in a group + * @param group that we want to put all failed actions into a waiting state and reprocess + */ + public onRetryGroup(group: ActionGroup): void { + group.erroredActions().forEach((action) => this.onRetryAction(action)); + } + + /** Runs all available action in sequence for as long as any actions are in the Waiting state. */ + private async runNextActionIfAvailable(): Promise { + if (!this.processing && this.firstWaitingAction()) { + this.processing = true; + await this.firstWaitingAction()!.execute(); + this.processing = false; + await this.runNextActionIfAvailable(); + } + } + + /** + * Check for specific action's state + * @param uid the unique id for this action to query state + */ + public pollAction(uid: string): QueuedActionState { + const action = this._actions().find((action) => action.objectKey == uid); + if (action) return action.state(); + else return QueuedActionState.NotInQueue; + } +} diff --git a/imxweb/projects/qbm/src/lib/processing-queue/processing-queue.spec.ts b/imxweb/projects/qbm/src/lib/processing-queue/processing-queue.spec.ts new file mode 100644 index 000000000..c1ce09287 --- /dev/null +++ b/imxweb/projects/qbm/src/lib/processing-queue/processing-queue.spec.ts @@ -0,0 +1,132 @@ +/* + * ONE IDENTITY LLC. PROPRIETARY INFORMATION + * + * This software is confidential. One Identity, LLC. or one of its affiliates or + * subsidiaries, has supplied this software to you under terms of a + * license agreement, nondisclosure agreement or both. + * + * You may not copy, disclose, or use this software except in accordance with + * those terms. + * + * + * Copyright 2024 One Identity LLC. + * ALL RIGHTS RESERVED. + * + * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR + * WARRANTIES ABOUT THE SUITABILITY OF THE SOFTWARE, + * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED + * TO THE IMPLIED WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE, OR + * NON-INFRINGEMENT. ONE IDENTITY LLC. SHALL NOT BE + * LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE + * AS A RESULT OF USING, MODIFYING OR DISTRIBUTING + * THIS SOFTWARE OR ITS DERIVATIVES. + * + */ + +import { fakeAsync, flush, TestBed, tick } from '@angular/core/testing'; +import { provideAnimations } from '@angular/platform-browser/animations'; +import { TranslateService } from '@ngx-translate/core'; +import { SnackBarService } from '../snackbar/snack-bar.service'; +import { Action } from './processing-queue.interface'; +import { ProcessingQueueService } from './processing-queue.service'; + +const lorem = + 'Omnis neque eius exercitationem omnis. Voluptatibus ut dignissimos commodi est. Praesentium hic cumque labore magnam qui accusantium. Cum et quos voluptatem provident adipisci blanditiis. Et est commodi eum eos iusto. Dolor ad nihil velit. Earum at eligendi et ullam numquam corporis accusamus. Error sint dolores sit dolores nobis. Aut nihil labore aliquam ullam reprehenderit dolorem id. Non placeat placeat ducimus omnis facilis et repellat vero. Vero velit id veniam ut asperiores. Tempora temporibus dolorem cumque voluptas nostrum cupiditate sint libero. Et et et perferendis numquam sint rerum beatae. Inventore omnis soluta vel harum beatae. Eius enim vel unde voluptatem molestias incidunt. Debitis quos eum delectus incidunt eos ut nesciunt. Tempora provident quo molestiae architecto officiis voluptatem accusamus. Dignissimos dolor qui illo hic ut est qui odit. Voluptatum dolores rem molestiae eligendi. Et et ut ab.'; + +const shortTime = 100; +const longTime = 1000; + +// One Fail, One complete -> Complete fail +const oneFailInTwo: Action[] = [ + new Action('Slow success', 'Runs for .1s', async () => {}), + new Action('Slow fail', 'Runs for .1s', async () => { + tick(shortTime); + throw lorem; + }), +]; + +// One Fail, One complete -> Complete fail +const longTasks: Action[] = [ + new Action('Fail', '', async () => { + tick(longTime); + }), + new Action('Complete', '', async () => {}), +]; + +describe('ProcessingQueueService', () => { + let service: ProcessingQueueService; + beforeEach(() => { + TestBed.configureTestingModule({ + providers: [ProcessingQueueService, SnackBarService, TranslateService, provideAnimations()], + }); + service = TestBed.inject(ProcessingQueueService); + }); + afterEach(() => service.clearProcessing()); + + it('should create', () => { + expect(service).toBeTruthy(); + }); + + it('should add a group, and after time have one error and one success, and then clear', fakeAsync(() => { + service.submitGroupAction(lorem, oneFailInTwo); + flush(); + + // Should have 1 error, number of actions length, and a completed group + expect([service.errorCount(), service.totalCount(), service.hasCompletedGroups()]).toEqual([1, oneFailInTwo.length, true]); + service.removeCompletedGroups(); + + // Should have no tasks left + expect(service.totalCount()).toEqual(0); + })); + + it('should add several groups, one long task, and removing completed groups should leave one group', fakeAsync(() => { + service.submitGroupAction(lorem, oneFailInTwo); + service.submitGroupAction(lorem, longTasks); + + // Should have two groups + expect(service._groups().length).toEqual([oneFailInTwo, longTasks].length); + flush(); + + // Should have a completed group + expect(service.hasCompletedGroups()).toBeTrue(); + + service.removeCompletedGroups(); + // Should have no completed groups + expect(service.hasCompletedGroups()).toBeFalse(); + + service.submitGroupAction(lorem, longTasks); + service.clearProcessing(); + // Should have no tasks even though a long running group was submitted + expect(service.totalCount()).toEqual(0); + })); + + it('should retry a failed action', fakeAsync(() => { + service.submitGroupAction(lorem, oneFailInTwo); + + flush(); + + service.onRetryAction(oneFailInTwo[1]); + // Should be retrying the only failed action, so no errors + expect([service.totalCount(), service.errorCount()]).toEqual([oneFailInTwo.length, 0]); + })); + + it('should retry a failed group, and increment the groupAction', fakeAsync(() => { + let count = 0; + const incCount = async () => { + count = count + 1; + return; + }; + + service.submitGroupAction(lorem, oneFailInTwo, incCount); + flush(); + + // Expect the group action to have been called once + expect(count).toEqual(1); + service.onRetryGroup(service._groups()[0]); + flush(); + + // Expect the group action to have been called twice + expect(count).toEqual(2); + })); +}); diff --git a/imxweb/projects/qbm/src/lib/progressbar/progressbar.component.html b/imxweb/projects/qbm/src/lib/progressbar/progressbar.component.html index 5e3ae84f2..52a71a054 100644 --- a/imxweb/projects/qbm/src/lib/progressbar/progressbar.component.html +++ b/imxweb/projects/qbm/src/lib/progressbar/progressbar.component.html @@ -1,7 +1,7 @@ -
    -
    {{caption}}
    -
    - -
    {{textVersion}}
    +
    +
    {{caption}}
    +
    + +
    {{textVersion}}
    -
    \ No newline at end of file +
    diff --git a/imxweb/projects/qbm/src/lib/progressbar/progressbar.component.scss b/imxweb/projects/qbm/src/lib/progressbar/progressbar.component.scss deleted file mode 100644 index 2cf1a87ed..000000000 --- a/imxweb/projects/qbm/src/lib/progressbar/progressbar.component.scss +++ /dev/null @@ -1,22 +0,0 @@ -.progressBar { - width: 150px; - justify-content: flex-start; - flex: 0 0 150px; - align-self: center; - margin-right: 10px; -} - -.progressBarTexts { - font-size: 12px; - text-align: center; -} - -.progressContainer { - display: flex; - flex-direction: column; -} - -.progressLine { - display: flex; - flex-direction: row; -} \ No newline at end of file diff --git a/imxweb/projects/qbm/src/lib/progressbar/progressbar.component.ts b/imxweb/projects/qbm/src/lib/progressbar/progressbar.component.ts index 5fdb2cc64..ee858da1e 100644 --- a/imxweb/projects/qbm/src/lib/progressbar/progressbar.component.ts +++ b/imxweb/projects/qbm/src/lib/progressbar/progressbar.component.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -29,10 +29,8 @@ import { Component, Input, OnInit } from '@angular/core'; @Component({ selector: 'imx-progressbar', templateUrl: './progressbar.component.html', - styleUrls: ['./progressbar.component.scss'] }) export class ImxProgressbarComponent implements OnInit { - @Input() public caption: string; @Input() public maxValue = 0; @Input() public value: number; @@ -41,11 +39,10 @@ export class ImxProgressbarComponent implements OnInit { public textVersion: string; public progressValue: number; - public ngOnInit(): void { - this.textVersion = this.maxValue === 0 ? '-' : - this.inPercent ? (this.value / this.maxValue) * 100 + '%' : this.value + '/' + this.maxValue; + this.textVersion = + this.maxValue === 0 ? '-' : this.inPercent ? (this.value / this.maxValue) * 100 + '%' : this.value + '/' + this.maxValue; - this.progressValue = this.inPercent ? this.value : this.maxValue === 0 ? 0 : (this.value * 100 / this.maxValue); + this.progressValue = this.inPercent ? this.value : this.maxValue === 0 ? 0 : (this.value * 100) / this.maxValue; } } diff --git a/imxweb/projects/qbm/src/lib/qbm.module.ts b/imxweb/projects/qbm/src/lib/qbm.module.ts index cf9adaa1f..83c89d778 100644 --- a/imxweb/projects/qbm/src/lib/qbm.module.ts +++ b/imxweb/projects/qbm/src/lib/qbm.module.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -45,24 +45,25 @@ import { MatSortModule } from '@angular/material/sort'; import { MatTableModule } from '@angular/material/table'; import { MatTabsModule } from '@angular/material/tabs'; import { MatToolbarModule } from '@angular/material/toolbar'; -import 'element-resize-detector'; import { NGXLogger } from 'ngx-logger'; -import { HttpClientModule } from '@angular/common/http'; +import { ClipboardModule } from '@angular/cdk/clipboard'; +import { provideHttpClient, withInterceptorsFromDi } from '@angular/common/http'; +import { MatProgressSpinnerModule } from '@angular/material/progress-spinner'; import { MatSnackBarModule } from '@angular/material/snack-bar'; import { EuiCoreModule } from '@elemental-ui/core'; import { TranslateModule } from '@ngx-translate/core'; +import { ReCaptchaV3Service, RecaptchaV3Module } from 'ng-recaptcha-2'; import { AboutComponent } from './about/About.component'; -import { AboutService } from './about/About.service'; import { ApiClientAngularService } from './api-client/api-client-angular.service'; import { AppConfigService } from './appConfig/appConfig.service'; import { AutoCompleteComponent } from './auto-complete/auto-complete.component'; import { AutoCompleteModule } from './auto-complete/auto-complete.module'; import { GlobalErrorHandler } from './base/global-error-handler'; -import { MetadataService } from './base/metadata.service'; import { OpsupportDbObjectService } from './base/opsupport-db-object.service'; import { RegistryService } from './base/registry.service'; import { UserActionService } from './base/user-action.service'; +import { CaptchaModule } from './captcha/captcha.module'; import { CdrEditorComponent } from './cdr/cdr-editor/cdr-editor.component'; import { CdrRegistryService } from './cdr/cdr-registry.service'; import { CdrModule } from './cdr/cdr.module'; @@ -70,15 +71,18 @@ import { DefaultCdrEditorProvider } from './cdr/default-cdr-editor-provider'; import { FkCdrEditorProvider } from './cdr/fk-cdr-editor-provider'; import { ClassloggerModule } from './classlogger/classlogger.module'; import { ClassloggerService } from './classlogger/classlogger.service'; +import { ConnectionComponent } from './connection/connection.component'; import { DataExportModule } from './data-export/data-export.module'; import { DataSourceToolbarModule } from './data-source-toolbar/data-source-toolbar.module'; import { DataTableModule } from './data-table/data-table.module'; +import { DataViewModule } from './data-view/data-view.module'; import { DisableControlModule } from './disable-control/disable-control.module'; import { ExtComponent } from './ext/ext.component'; import { ExtDirective } from './ext/ext.directive'; import { ExtModule } from './ext/ext.module'; import { ExtService } from './ext/ext.service'; import { FilterTileComponent } from './filter-tile/filter-tile.component'; +import { HelpContextualModule } from './help-contextual/help-contextual.module'; import { HyperViewModule } from './hyperview/hyperview.module'; import { IconStackComponent } from './icon-stack/icon-stack.component'; import { InfoModalDialogModule } from './info-modal-dialog/info-modal-dialog.module'; @@ -86,18 +90,14 @@ import { JobQueueOverviewModule } from './jobqueue-overview/jobqueue-overview.mo import { LdsReplaceModule } from './lds-replace/lds-replace.module'; import { LoginComponent } from './login/login.component'; import { MastHeadModule } from './mast-head/mast-head.module'; -import { MasterDetailComponent } from './master-detail/master-detail.component'; -import { MenuModule } from './menu/menu.module'; import { MessageDialogComponent } from './message-dialog/message-dialog.component'; -import { PluginLoaderService } from './plugins/plugin-loader.service'; +import { MessageDialogService } from './message-dialog/message-dialog.service'; import { ImxProgressbarComponent } from './progressbar/progressbar.component'; import { imx_QBM_SearchService } from './search/search.service'; import { SearchBarComponent } from './searchbar/searchbar.component'; -import { SelectModule } from './select/select.module'; -import { DeviceStateService } from './services/device-state.service'; import { imx_SessionService } from './session/imx-session.service'; import { SideNavigationViewModule } from './side-navigation-view/side-navigation-view.module'; -import { SidenavTreeModule } from './sidenav-tree/sidenav-tree.module'; +import { SidenavTreeComponent } from './sidenav-tree/sidenav-tree.component'; import { SnackBarService } from './snackbar/snack-bar.service'; import { TableImageService } from './table-image/table-image.service'; import { TestHelperModule } from './testing/TestHelperModule.spec'; @@ -110,11 +110,6 @@ import { ImxTreeTableComponent } from './treeTable/treeTable.component'; import { TwoFactorAuthenticationComponent } from './two-factor-authentication/two-factor-authentication.component'; import { TwoFactorAuthenticationService } from './two-factor-authentication/two-factor-authentication.service'; import { UserMessageModule } from './user-message/user-message.module'; -import { HelpContextualModule } from './help-contextual/help-contextual.module'; -import { TempBillboardModule } from './temp-billboard/temp-billboard.module'; -import { TempBillboardComponent } from './temp-billboard/temp-billboard.component'; -import { ConnectionComponent } from './connection/connection.component'; -import { ClipboardModule } from '@angular/cdk/clipboard'; export function initApp(registry: CdrRegistryService, logger: NGXLogger): () => Promise { logger.debug('init qbm'); @@ -133,7 +128,6 @@ export function initApp(registry: CdrRegistryService, logger: NGXLogger): () => IconStackComponent, LoginComponent, FilterTileComponent, - MasterDetailComponent, ImxProgressbarComponent, SearchBarComponent, ImxTreeTableComponent, @@ -142,9 +136,25 @@ export function initApp(registry: CdrRegistryService, logger: NGXLogger): () => TranslationEditorComponent, ConnectionComponent, ], + exports: [ + TwoFactorAuthenticationComponent, + AboutComponent, + ConnectionComponent, + IconStackComponent, + LoginComponent, + ExtComponent, + ExtDirective, + FilterTileComponent, + ImxProgressbarComponent, + SearchBarComponent, + ImxTreeTableComponent, + ImxMatColumnComponent, + CdrEditorComponent, + MessageDialogComponent, + AutoCompleteComponent, + ], imports: [ CommonModule, - HttpClientModule, TranslateModule, DisableControlModule, ExtModule, @@ -166,6 +176,7 @@ export function initApp(registry: CdrRegistryService, logger: NGXLogger): () => MatTabsModule, MatToolbarModule, MatProgressBarModule, + MatProgressSpinnerModule, ReactiveFormsModule, FormsModule, TestHelperModule, @@ -175,30 +186,28 @@ export function initApp(registry: CdrRegistryService, logger: NGXLogger): () => DataTableModule, AutoCompleteModule, DataSourceToolbarModule, - MenuModule, MastHeadModule, UserMessageModule, ClassloggerModule, - SelectModule, UserMessageModule, LdsReplaceModule, TileModule, JobQueueOverviewModule, - SidenavTreeModule, + SidenavTreeComponent, DataExportModule, InfoModalDialogModule, MatSnackBarModule, SideNavigationViewModule, HelpContextualModule, - TempBillboardModule, - ClipboardModule + ClipboardModule, + CaptchaModule, + RecaptchaV3Module, + DataViewModule, ], providers: [ GlobalErrorHandler, AppConfigService, - AboutService, imx_SessionService, - MetadataService, ImxTranslateLoader, ImxTranslationProviderService, RegistryService, @@ -207,31 +216,13 @@ export function initApp(registry: CdrRegistryService, logger: NGXLogger): () => imx_QBM_SearchService, SnackBarService, ExtService, - DeviceStateService, ImxTreeTableComponent, TwoFactorAuthenticationService, ApiClientAngularService, TableImageService, - PluginLoaderService, - ], - exports: [ - TwoFactorAuthenticationComponent, - AboutComponent, - ConnectionComponent, - IconStackComponent, - LoginComponent, - ExtComponent, - ExtDirective, - FilterTileComponent, - MasterDetailComponent, - ImxProgressbarComponent, - SearchBarComponent, - ImxTreeTableComponent, - ImxMatColumnComponent, - CdrEditorComponent, - MessageDialogComponent, - AutoCompleteComponent, - TempBillboardComponent, + MessageDialogService, + ReCaptchaV3Service, + provideHttpClient(withInterceptorsFromDi()), ], }) export class QbmModule { diff --git a/imxweb/projects/qbm/src/lib/route-guard/component-can-deactivate.interface.ts b/imxweb/projects/qbm/src/lib/route-guard/component-can-deactivate.interface.ts index 078916295..9094cc272 100644 --- a/imxweb/projects/qbm/src/lib/route-guard/component-can-deactivate.interface.ts +++ b/imxweb/projects/qbm/src/lib/route-guard/component-can-deactivate.interface.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR diff --git a/imxweb/projects/qbm/src/lib/route-guard/route-guard.module.ts b/imxweb/projects/qbm/src/lib/route-guard/route-guard.module.ts index 7ac8b0849..f90ed9874 100644 --- a/imxweb/projects/qbm/src/lib/route-guard/route-guard.module.ts +++ b/imxweb/projects/qbm/src/lib/route-guard/route-guard.module.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -30,11 +30,7 @@ import { CommonModule } from '@angular/common'; import { RouteGuardService } from './route-guard.service'; @NgModule({ - imports: [ - CommonModule - ], - providers: [ - RouteGuardService - ] + imports: [CommonModule], + providers: [RouteGuardService], }) -export class RouteGuardModule { } +export class RouteGuardModule {} diff --git a/imxweb/projects/qbm/src/lib/route-guard/route-guard.service.ts b/imxweb/projects/qbm/src/lib/route-guard/route-guard.service.ts index d8d784f83..6483430fa 100644 --- a/imxweb/projects/qbm/src/lib/route-guard/route-guard.service.ts +++ b/imxweb/projects/qbm/src/lib/route-guard/route-guard.service.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -24,28 +24,28 @@ * */ -import { Injectable, ErrorHandler } from '@angular/core'; -import { CanActivate, ActivatedRouteSnapshot, RouterStateSnapshot, Router, CanDeactivate } from '@angular/router'; +import { ErrorHandler, Injectable } from '@angular/core'; +import { ActivatedRouteSnapshot, Router, RouterStateSnapshot } from '@angular/router'; import { TranslateService } from '@ngx-translate/core'; -import { imx_SessionService } from '../session/imx-session.service'; import { AppConfigService } from '../appConfig/appConfig.service'; -import { ComponentCanDeactivate } from './component-can-deactivate.interface'; +import { AuthenticationService } from '../authentication/authentication.service'; import { OAuthService } from '../authentication/oauth.service'; import { QueryParametersHandler } from '../base/query-parameters-handler'; import { ClassloggerService } from '../classlogger/classlogger.service'; -import { AuthenticationService } from '../authentication/authentication.service'; -import { StorageService } from '../storage/storage.service'; import { ConfirmationService } from '../confirmation/confirmation.service'; +import { imx_SessionService } from '../session/imx-session.service'; +import { StorageService } from '../storage/storage.service'; +import { ComponentCanDeactivate } from './component-can-deactivate.interface'; @Injectable({ - providedIn: 'root' + providedIn: 'root', }) -export class RouteGuardService implements CanActivate, CanDeactivate { +export class RouteGuardService { private confirmLeaveTitle = ''; private confirmLeaveMessage = ''; private isLoggedIn: boolean; - private lastRoute: ActivatedRouteSnapshot; + private lastRoute: ActivatedRouteSnapshot | undefined; constructor( private readonly config: AppConfigService, @@ -57,15 +57,17 @@ export class RouteGuardService implements CanActivate, CanDeactivate this.confirmLeaveTitle = value); + translation.get('#LDS#Heading Cancel Editing').subscribe((value: string) => (this.confirmLeaveTitle = value)); - translation.get('#LDS#You have unsaved changes. Are you sure you want to cancel editing and discard your changes?') - .subscribe((value: string) => this.confirmLeaveMessage = value); + translation + .get('#LDS#You have unsaved changes. Are you sure you want to cancel editing and discard your changes?') + .subscribe((value: string) => (this.confirmLeaveMessage = value)); - this.authentication.onSessionResponse.subscribe(sessionState => this.isLoggedIn = sessionState && sessionState.IsLoggedIn); + this.authentication.onSessionResponse.subscribe( + (sessionState) => (this.isLoggedIn = (sessionState && sessionState.IsLoggedIn) ?? false), + ); } public async canActivate(route: ActivatedRouteSnapshot, state?: RouterStateSnapshot): Promise { @@ -91,9 +93,9 @@ export class RouteGuardService implements CanActivate, CanDeactivate !this.oauthService.IsOAuthParameter(name)) } - ); + this.router.navigate([queryParamsHandler.path || this.config.Config.routeConfig?.start], { + queryParams: queryParamsHandler.GetQueryParameters((name) => !this.oauthService.IsOAuthParameter(name)), + }); } } catch (error) { this.errorHandler.handleError(error); diff --git a/imxweb/projects/qbm/src/lib/search/db-object-info.ts b/imxweb/projects/qbm/src/lib/search/db-object-info.ts index b6f094943..1bd1f8b97 100644 --- a/imxweb/projects/qbm/src/lib/search/db-object-info.ts +++ b/imxweb/projects/qbm/src/lib/search/db-object-info.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -24,9 +24,9 @@ * */ -import { DbObjectKey } from 'imx-qbm-dbts'; +import { DbObjectKey } from '@imx-modules/imx-qbm-dbts'; export class DbObjectInfo { - public Display: string; - public Key: DbObjectKey; + public Display: string; + public Key?: DbObjectKey; } diff --git a/imxweb/projects/qbm/src/lib/search/search.service.ts b/imxweb/projects/qbm/src/lib/search/search.service.ts index d3caab8de..8f3c1bb3a 100644 --- a/imxweb/projects/qbm/src/lib/search/search.service.ts +++ b/imxweb/projects/qbm/src/lib/search/search.service.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -24,17 +24,15 @@ * */ -import { Injectable, ErrorHandler } from '@angular/core'; +import { ErrorHandler, Injectable } from '@angular/core'; import { Subject } from 'rxjs'; -import { OpsupportSearchIndexedtables, SearchResultObject } from 'imx-api-qbm'; -import { TypedEntityCollectionData, DbObjectKey } from 'imx-qbm-dbts'; -import { imx_SessionService } from '../session/imx-session.service'; +import { OpsupportSearchIndexedtables, SearchResultObject } from '@imx-modules/imx-api-qbm'; +import { DbObjectKey, TypedEntityCollectionData } from '@imx-modules/imx-qbm-dbts'; import { imx_ISearchService } from '../searchbar/iSearchService'; +import { imx_SessionService } from '../session/imx-session.service'; import { DbObjectInfo } from './db-object-info'; - - @Injectable() export class imx_QBM_SearchService implements imx_ISearchService { public readonly searchTermStream = new Subject(); @@ -43,19 +41,22 @@ export class imx_QBM_SearchService implements imx_ISearchService { constructor( private session: imx_SessionService, - private errorHandler: ErrorHandler) { - } + private errorHandler: ErrorHandler, + ) {} public async search(term: string, tables: string): Promise { - if (term === '') { return []; } + if (term === '') { + return []; + } try { const result = await this.session.Client.opsupport_search_get({ term: term, tables: tables }); if (result) { - return result.filter((sro: SearchResultObject) => sro.Key != null) - .map((sro: SearchResultObject) => ({ - Key: DbObjectKey.FromXml(sro.Key), - Display: sro.Display - })); + return result + .filter((sro: SearchResultObject) => sro.Key != null) + .map((sro: SearchResultObject) => ({ + Key: sro.Key ? DbObjectKey.FromXml(sro.Key) : undefined, + Display: sro.Display ?? '', + })); } } catch (error) { this.errorHandler.handleError(error); @@ -66,14 +67,15 @@ export class imx_QBM_SearchService implements imx_ISearchService { public async getIndexedTables(): Promise { return this.session.TypedClient.OpsupportSearchIndexedtables.Get(this.defaultOptions) - .then( - (response: TypedEntityCollectionData) => { - return response.Data.sort((t1, t2) => t1.DisplayNameSingular.value > t2.DisplayNameSingular.value ? 1 : -1 - ); - }).catch((error: any): OpsupportSearchIndexedtables[] => { - this.errorHandler.handleError(error); - return []; - }); + .then((response: TypedEntityCollectionData) => { + return response.Data.sort((t1, t2) => + t1.DisplayName.Column.GetDisplayValue().localeCompare(t2.DisplayName.Column.GetDisplayValue()), + ); + }) + .catch((error: any): OpsupportSearchIndexedtables[] => { + this.errorHandler.handleError(error); + return []; + }); } public GetTableDisplay(table: OpsupportSearchIndexedtables): string { diff --git a/imxweb/projects/qbm/src/lib/searchbar/iSearchService.ts b/imxweb/projects/qbm/src/lib/searchbar/iSearchService.ts index 52a4bc80b..e9d075a76 100644 --- a/imxweb/projects/qbm/src/lib/searchbar/iSearchService.ts +++ b/imxweb/projects/qbm/src/lib/searchbar/iSearchService.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -26,12 +26,12 @@ import { Subject } from 'rxjs'; -import { TypedEntity } from 'imx-qbm-dbts'; +import { TypedEntity } from '@imx-modules/imx-qbm-dbts'; export interface imx_ISearchService { - searchTermStream: Subject; - search(term: string, tables: string): Promise; - getIndexedTables(): Promise; - GetTableDisplay(table: TypedEntity): string; - GetTableValue(table: TypedEntity): string; + searchTermStream: Subject; + search(term: string, tables: string): Promise; + getIndexedTables(): Promise; + GetTableDisplay(table: TypedEntity): string; + GetTableValue(table: TypedEntity): string; } diff --git a/imxweb/projects/qbm/src/lib/searchbar/searchbar.component.html b/imxweb/projects/qbm/src/lib/searchbar/searchbar.component.html index 170f87018..73b3c976a 100644 --- a/imxweb/projects/qbm/src/lib/searchbar/searchbar.component.html +++ b/imxweb/projects/qbm/src/lib/searchbar/searchbar.component.html @@ -1,26 +1,47 @@ -
    +
    {{ ToJson(link) }} - \ No newline at end of file + diff --git a/imxweb/projects/qbm/src/lib/searchbar/searchbar.component.scss b/imxweb/projects/qbm/src/lib/searchbar/searchbar.component.scss index 1cc5559cb..5bc872916 100644 --- a/imxweb/projects/qbm/src/lib/searchbar/searchbar.component.scss +++ b/imxweb/projects/qbm/src/lib/searchbar/searchbar.component.scss @@ -1,14 +1,29 @@ -@import '@elemental-ui/core/src/styles/_palette.scss'; - -$SearchBarWidth: 535px; -$SearchBarHeight: 53px; - -$VI_Common_Color_Blue_1: #69CCE9; +@import '@elemental-ui/core/src/styles/_eui_palette.scss'; +@import 'base/variables'; +@import 'base/mixins'; .imx-searchbar-card { - max-width: $SearchBarWidth; - width: $SearchBarWidth; + max-width: $IMX_SearchBar_Width; + width: $IMX_SearchBar_Width; padding: 0; + .imx-searchbar-card-content { + padding: 0 !important; + } + margin-top: 4px; +} + +.imx-search-component { + @include flex-row-container(); +} + +.imx-display-card { + height: 37px; +} + +.imx-search-input { + display: flex; + align-items: center; + padding: 0px; } .imx-searchbar-resultcard { @@ -19,96 +34,53 @@ $VI_Common_Color_Blue_1: #69CCE9; } .imx-searchbar-noitems { - // color: $VI_Common_Color_Font; padding: 15px; - font-size: 1.2em; + background: $white; } .imx-searchbar-dropdown { - max-width: $SearchBarWidth; + max-width: $IMX_SearchBar_Width; margin-top: 2px; padding: 0; } .matlistItem:hover { - background-color: $VI_Common_Color_Blue_1; + background-color: $color-blue-40; } .matlistItem { white-space: pre-line; } -.mat-list-option { - height: auto !important; - padding-top: 10px !important; - padding-bottom: 10px !important; - - .mat-list-text { - padding-top: 10px !important; - padding-bottom: 10px !important; - // color: $VI_Common_Color_Font !important; - } -} - -.mat-card .imx-searchbar-input { - border: 0 solid transparent !important; - font-size: 1.2em; - margin-bottom: 0; - height: $SearchBarHeight; - box-sizing: border-box; - flex-grow: 0; - flex-shrink: 0; - /* use flex-basis, because of flex shorthand with calc()s doesn't work in IE */ - flex-basis: calc(100% - 52px); -} - -.mat-card .imx-searchbar-input::placeholder { - font-style: italic; -} - -.imx-searchbar-input::-ms-clear { - /* hide input-clear button (the 'X') in > IE 10 */ - display: none; - width: 0; - height: 0; -} - -.imx-searchbar-input::placeholder { - font-style: italic; -} - imx-searchbar { display: flex; } .imx-searchbar-tablefilter { margin-left: 15px; + width: 300px; + display: flex; - .mat-form-field-wrapper { - line-height: 20px; + .mat-mdc-form-field { + flex: 1 1 auto; } } .imx-searchbar-control { - height: $SearchBarHeight; + height: $IMX_SearchBar_Height; } .imx-searchbar-table { display: flex; - align-items: center; - flex-wrap: wrap; + flex-direction: column; width: 100%; - line-height: $SearchBarHeight; + line-height: $IMX_SearchBar_Height; + .imx-input-searchbar { + flex-grow: 1; + } } .imx-searchbar-select { margin-top: 30px; margin-left: 40px; } - -.mat-autocomplete-panel.mat-autocomplete-visible { - width: $SearchBarWidth; - margin-right: -13px; - margin-left: -40px; -} - diff --git a/imxweb/projects/qbm/src/lib/searchbar/searchbar.component.ts b/imxweb/projects/qbm/src/lib/searchbar/searchbar.component.ts index 00617a88c..ecbb008e2 100644 --- a/imxweb/projects/qbm/src/lib/searchbar/searchbar.component.ts +++ b/imxweb/projects/qbm/src/lib/searchbar/searchbar.component.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -24,28 +24,22 @@ * */ -import { OverlayRef } from '@angular/cdk/overlay'; -import { - Component, - OnInit, Input, ContentChild, TemplateRef, ElementRef, ViewChild, Output, EventEmitter, OnDestroy -} from '@angular/core'; +import { Component, ContentChild, EventEmitter, Input, OnDestroy, OnInit, Output, TemplateRef, ViewChild } from '@angular/core'; import { UntypedFormControl } from '@angular/forms'; import { MatAutocompleteSelectedEvent, MatAutocompleteTrigger } from '@angular/material/autocomplete'; import { MatSelect } from '@angular/material/select'; -import { EuiLoadingService } from '@elemental-ui/core'; -import { distinctUntilChanged, debounceTime } from 'rxjs/operators'; - -import { TypedEntity } from 'imx-qbm-dbts'; -import { imx_ISearchService } from './iSearchService'; +import { TypedEntity } from '@imx-modules/imx-qbm-dbts'; import { Subscription } from 'rxjs'; +import { debounceTime, distinctUntilChanged } from 'rxjs/operators'; +import { BusyService } from '../base/busy.service'; +import { imx_ISearchService } from './iSearchService'; @Component({ selector: 'imx-searchbar', templateUrl: './searchbar.component.html', - styleUrls: ['./searchbar.component.scss'] + styleUrls: ['./searchbar.component.scss'], }) export class SearchBarComponent implements OnInit, OnDestroy { - public get autoCompleteIsFocused(): boolean { return this.autocompleteFocus; } @@ -53,22 +47,22 @@ export class SearchBarComponent implements OnInit, OnDestroy { return this.filterFocus; } - public readonly filterComponentId = - Math.random().toString(36).substring(2, 15) + - Math.random().toString(36).substring(2, 15); + public readonly filterComponentId = Math.random().toString(36).substring(2, 15) + Math.random().toString(36).substring(2, 15); public noEntriesVisible = false; public tableList: TypedEntity[] = []; public tables = new UntypedFormControl(); public selectedTables: string[]; public searchResults: any[] = []; + private busyService: BusyService = new BusyService(); + @Input() public searchService: imx_ISearchService; @Input() public debounce = false; @Input() public debounceTime = 300; @Input() public watermark = '#LDS#Insert Text'; @Output() public selectionChange = new EventEmitter(); - @ContentChild('imxResultTemplate', /* TODO: add static flag */ {}) public resultTemplate: TemplateRef; + @ContentChild('imxResultTemplate', /* TODO: add static flag */ {}) public resultTemplate: TemplateRef; @ViewChild('tableSelect', { static: true }) public tableSelect: MatSelect; @ViewChild(MatAutocompleteTrigger, { static: true }) public autoCompleteTrigger: MatAutocompleteTrigger; @@ -76,36 +70,34 @@ export class SearchBarComponent implements OnInit, OnDestroy { private filterFocus = false; private term = ''; private readonly subscriptions: Subscription[] = []; + public isLoading: boolean = false; - constructor(private busyService: EuiLoadingService) { + constructor() { + this.subscriptions.push(this.busyService.busyStateChanged.subscribe((state) => (this.isLoading = state))); } public async ngOnInit(): Promise { let result: TypedEntity[]; - let overlayRef: OverlayRef; - setTimeout(() => overlayRef = this.busyService.show()); + + const isBusy = this.busyService.beginBusy(); try { result = await this.searchService.getIndexedTables(); } finally { - setTimeout(() => this.busyService.hide(overlayRef)); + isBusy.endBusy(); } this.tableList = result; - this.subscriptions.push(this.searchService.searchTermStream - .pipe( - debounceTime(this.debounceTime), - distinctUntilChanged() - ) - .subscribe(async (term: string) => { + this.subscriptions.push( + this.searchService.searchTermStream.pipe(debounceTime(this.debounceTime), distinctUntilChanged()).subscribe(async (term: string) => { this.term = term; await this.searchInternal(term); - }) + }), ); } public ngOnDestroy(): void { - this.subscriptions.forEach(subscription => subscription.unsubscribe()); + this.subscriptions.forEach((subscription) => subscription.unsubscribe()); } public search(term: string, evt?: KeyboardEvent): void { @@ -127,13 +119,13 @@ export class SearchBarComponent implements OnInit, OnDestroy { } json = ''; - Object.keys(link).forEach(key => (json += key + ': ' + link[key] + '\n')); + Object.keys(link).forEach((key) => (json += key + ': ' + link[key] + '\n')); return json.substring(0, json.length - 1); } - public displayItem(item?: any): string | undefined { - return item ? item.Display : undefined; + public displayItem(item?: any): string { + return item ? item.Display : ''; } /* *** Event handling *** */ @@ -142,13 +134,12 @@ export class SearchBarComponent implements OnInit, OnDestroy { const selectedtables = this.selectedTables !== undefined && this.selectedTables.length > 0 ? this.selectedTables.join(',') : ''; let result: TypedEntity[]; - let overlayRef: OverlayRef; - setTimeout(() => overlayRef = this.busyService.show()); + const isBusy = this.busyService.beginBusy(); try { result = await this.searchService.search(item, selectedtables); } finally { - setTimeout(() => this.busyService.hide(overlayRef)); + isBusy.endBusy(); } this.searchResults = result; this.setNoEntriesVisibility(); @@ -160,7 +151,7 @@ export class SearchBarComponent implements OnInit, OnDestroy { public onComponentLostFocus(_: FocusEvent): void { setTimeout(() => { - if (!this.autocompleteFocus && !this.filterFocus && document.activeElement.id !== this.filterComponentId) { + if (!this.autocompleteFocus && !this.filterFocus && document?.activeElement?.id !== this.filterComponentId) { this.noEntriesVisible = false; } }); @@ -169,7 +160,6 @@ export class SearchBarComponent implements OnInit, OnDestroy { public onInputFocus(): void { setTimeout(() => { this.autocompleteFocus = true; - this.setNoEntriesVisibility(); }); } diff --git a/imxweb/projects/qbm/src/lib/select/autocomplete.component.html b/imxweb/projects/qbm/src/lib/select/autocomplete.component.html deleted file mode 100644 index cdf940db0..000000000 --- a/imxweb/projects/qbm/src/lib/select/autocomplete.component.html +++ /dev/null @@ -1,64 +0,0 @@ - - {{ label }} - search - - - - - -
    -
    - -
    -
    -
    {{ contentProvider.display(item) }}
    -
    {{ contentProvider.displayLong(item) }}
    -
    -
    -
    -
    -
    - -
    -
    -
    {{ contentProvider.display(item) }}
    -
    {{ contentProvider.displayLong(item) }}
    -
    -
    -
    -
    - - - -
    -
    - -
    -
    -
    {{ contentProvider.display(item) }}
    -
    {{ contentProvider.displayLong(item) }}
    -
    -
    -
    -
    -
    - -
    -
    -
    {{ contentProvider.display(item) }}
    -
    {{ contentProvider.displayLong(item) }}
    -
    -
    -
    -
    - -
    - - {{ errorMessage }} - -
    diff --git a/imxweb/projects/qbm/src/lib/select/autocomplete.component.scss b/imxweb/projects/qbm/src/lib/select/autocomplete.component.scss deleted file mode 100644 index 260420460..000000000 --- a/imxweb/projects/qbm/src/lib/select/autocomplete.component.scss +++ /dev/null @@ -1,81 +0,0 @@ -@import '@elemental-ui/core/src/styles/_palette.scss'; - -:host { - width: 100%; -} - -.mat-form-field { - width: inherit; -} - -.imx-candidate-option { - line-height: 1.5em; - display: flex; - width: 100%; - - .imx-candidate-item { - display: flex; - align-items: center; - width: 100%; - - .imx-candidate-icon { - margin-right: 5px; - border-radius: 50%; - background: $asher-gray; - height: 20px; - width: 20px; - display: flex; - align-items: center; - flex: 0 0 20px; - - .eui-icon { - opacity: 0.6; - color: $black-9; - margin: auto; - } - } - - .imx-candidate-content { - flex: 1; - width: calc(100% - 25px); - overflow: hidden; - - .imx-candidate-display { - color: $black-6; - font-size: 14px; - text-overflow: ellipsis; - overflow: hidden; - width: 100vw; - } - - .imx-candidate-longdisplay { - color: $black-9; - font-size: 12px; - text-overflow: ellipsis; - overflow: hidden; - } - } - } -} - -.imx-input-button-container { - display: flex; -} - -::ng-deep span.mat-option-text { - display: flex; -} - -mat-checkbox { - margin-right: 10px; - width: 100%; - - ::ng-deep .mat-checkbox-layout { - width: 100%; - - .mat-checkbox-label { - width: 100%; - } - } - -} diff --git a/imxweb/projects/qbm/src/lib/select/autocomplete.component.ts b/imxweb/projects/qbm/src/lib/select/autocomplete.component.ts deleted file mode 100644 index 6fa19d20c..000000000 --- a/imxweb/projects/qbm/src/lib/select/autocomplete.component.ts +++ /dev/null @@ -1,264 +0,0 @@ -/* - * ONE IDENTITY LLC. PROPRIETARY INFORMATION - * - * This software is confidential. One Identity, LLC. or one of its affiliates or - * subsidiaries, has supplied this software to you under terms of a - * license agreement, nondisclosure agreement or both. - * - * You may not copy, disclose, or use this software except in accordance with - * those terms. - * - * - * Copyright 2023 One Identity LLC. - * ALL RIGHTS RESERVED. - * - * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR - * WARRANTIES ABOUT THE SUITABILITY OF THE SOFTWARE, - * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED - * TO THE IMPLIED WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE, OR - * NON-INFRINGEMENT. ONE IDENTITY LLC. SHALL NOT BE - * LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE - * AS A RESULT OF USING, MODIFYING OR DISTRIBUTING - * THIS SOFTWARE OR ITS DERIVATIVES. - * - */ - -import { - Component, - ViewChild, - AfterViewInit, - ElementRef, - Input, - Output, - EventEmitter, - OnChanges, - SimpleChanges, - ViewChildren, - QueryList -} from '@angular/core'; -import { MatAutocompleteTrigger, MatAutocompleteSelectedEvent, MatAutocomplete } from '@angular/material/autocomplete'; -import { MatCheckboxChange, MatCheckbox } from '@angular/material/checkbox'; -import { PageEvent } from '@angular/material/paginator'; -import { UntypedFormControl, AbstractControl, ValidatorFn } from '@angular/forms'; -import { Observable } from 'rxjs'; -import { startWith, map, debounceTime } from 'rxjs/operators'; - -import { ClassloggerService } from '../classlogger/classlogger.service'; -import { SelectDataSource } from './select-data-source'; -import { SelectContentProvider } from './select-content-provider.interface'; - -@Component({ - selector: 'imx-autocomplete', - templateUrl: './autocomplete.component.html', - styleUrls: ['./autocomplete.component.scss'] -}) -export class AutocompleteComponent implements AfterViewInit, OnChanges { - /** Reference to the autocomplete component. */ - public readonly autocompleteCtrl = new UntypedFormControl('', this.checkAutocompleteValidator()); - - /** Height of an item in the dropdown panel in px. Needed for virtual scrolling. */ - public readonly itemSize = 48; - - /** Needed fpr search if the component uses a local datasource */ - public filteredDatasource: Observable; - - /** The candidate list for the selection */ - @Input() public items: T[] = []; - - /** The datasource of the component */ - @Input() public dataSource: SelectDataSource; - - /** The name of icon for the items shown in the autocomplete control. */ - @Input() public itemIcon: string; - - /** The label of the input box */ - @Input() public label = ''; - - /** Flag for multi select mode */ - @Input() public multi = false; - - /** Selected items */ - @Input() public itemsSelected: T[] = []; - - /** Indicates if Datasource is remote or local. */ - @Input() public isLocalDatasource = false; - - /** Provides methods for displaying the item content */ - @Input() public contentProvider: SelectContentProvider; - - @Input() public pageSize = 50; - - @Input() public totalCount = 0; - - /** validation error message */ - @Input() public errorMessage: string; - - /** Fires when the form needs a refresh. */ - @Output() public refreshForm: EventEmitter = new EventEmitter(); - - /** Fires when the user types in the autocomplete input control. */ - @Output() public autocompleteValueChanged: EventEmitter = new EventEmitter(); - - /** Fires when the component needs a reset, e.g. user selects an entry. */ - @Output() public needReset: EventEmitter = new EventEmitter(); - - /** Indicates that the component wants to close */ - @Output() public closing: EventEmitter = new EventEmitter(); - - @ViewChild('auto', { static: true }) public autocomplete: MatAutocomplete; - - /** Reference to the {@link MatAutocompleteTrigger} */ - @ViewChild('trigger', { static: true }) public autocompleteTrigger: MatAutocompleteTrigger; - - /** Reference to the input control. */ - @ViewChild('inputCtrl', { static: true }) public inputCtrl: ElementRef; - - @ViewChildren(MatCheckbox) public checkboxCtrls: QueryList; - - private readonly debounceTime = 500; - - constructor(private logger: ClassloggerService) { - this.autocompleteCtrl.valueChanges.pipe(debounceTime(this.debounceTime)).subscribe(value => { - - if (!this.isLocalDatasource) { - this.dataSource.reset(); - } - - this.autocompleteValueChanged.emit(value); - }); - } - - public ngOnChanges(changes: SimpleChanges): void { - - if (changes['items'] && changes['items'].currentValue) { - this.dataSource.setData(this.items); - - if (this.isLocalDatasource) { - this.totalCount = this.dataSource.rawData.length; - this.filteredDatasource = this.autocompleteCtrl.valueChanges - .pipe( - startWith(''), - map(value => this.filter(value)) - ); - } - } - } - - public ngAfterViewInit(): void { - setTimeout(() => { - this.autocompleteTrigger.openPanel(); - this.inputCtrl.nativeElement.focus(); - }); - - } - - public onChecked(event: MatCheckboxChange, selectedItem: T): void { - this.applyMultiSelect(event.checked, selectedItem); - } - - public onCheckboxClicked(event: MouseEvent): void { - event.stopPropagation(); - } - - public onPage(event: PageEvent): void { - this.dataSource.getData(event.pageIndex * event.pageSize); - } - - public onCancel(): void { - this.close(); - } - - public onFocusout(event: FocusEvent): void { - if (!this.autocomplete.isOpen) { - this.close(); - return; - } - } - - /** - * Called when an item was selected, to push this item to the selection list. - * @param event the caller - */ - public selectSingleItem(event: MatAutocompleteSelectedEvent): void { - this.applySingleSelect(event.option.value); - } - - public panelClosing(): void { - this.close(); - } - - public itemSelected(selectedItem: T): boolean { - return this.itemsSelected.findIndex(item => this.contentProvider.key(item) === this.contentProvider.key(selectedItem)) >= 0; - } - - private close(): void { - this.closing.emit(true); - this.autocompleteValueChanged.emit(''); - this.inputCtrl.nativeElement.click(); - } - - private applySingleSelect(selectedItem: T): void { - if (selectedItem == null || typeof (selectedItem) === 'string' || this.multi) { - return; - } - - if (this.itemsSelected.findIndex(item => this.contentProvider.key(selectedItem) === this.contentProvider.key(item)) < 0) { - this.itemsSelected.splice(0); - this.itemsSelected.push(selectedItem); - this.refreshForm.emit(); - - if (!this.isLocalDatasource) { - this.dataSource.reset(); - } - } - - this.clearAutocompleteCtrl(); - } - - private applyMultiSelect(checked: boolean, selectedItem: T): void { - if (selectedItem == null || typeof (selectedItem) === 'string') { - return; - } - - const index = this.itemsSelected - .findIndex(item => this.contentProvider.key(selectedItem) === this.contentProvider.key(item)); - - if (index === -1 && checked) { - this.itemsSelected.push(selectedItem); - } else if (index >= 0 && !checked) { - this.itemsSelected.splice(index, 1); - } - this.inputCtrl.nativeElement.click(); - this.refreshForm.emit(); - } - - private clearAutocompleteCtrl(): void { - this.inputCtrl.nativeElement.value = ''; - this.autocompleteCtrl.setValue(undefined); - } - - private filter(value: string | T): T[] { - - if (typeof (value) !== 'string') { - return; - } - - return this.dataSource.rawData.filter(option => this.contentProvider.display(option).toLowerCase().includes(value.toLowerCase())); - } - - private checkAutocompleteValidator(): ValidatorFn { - return (control: AbstractControl): { [key: string]: boolean } | null => { - if (control == null || control.value == null || this.dataSource == null) { - return null; - } - - if (this.dataSource.rawData != null && this.dataSource.rawData.length > 0) { - return null; - } - - return { checkAutocomplete: true }; - }; - } - -} diff --git a/imxweb/projects/qbm/src/lib/select/data-navigation-parameters.interface.ts b/imxweb/projects/qbm/src/lib/select/data-navigation-parameters.interface.ts index d6fefcf1d..911739773 100644 --- a/imxweb/projects/qbm/src/lib/select/data-navigation-parameters.interface.ts +++ b/imxweb/projects/qbm/src/lib/select/data-navigation-parameters.interface.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -24,7 +24,7 @@ * */ -import { CollectionLoadParameters } from 'imx-qbm-dbts'; +import { CollectionLoadParameters } from '@imx-modules/imx-qbm-dbts'; export interface DataNavigationParameters { navigation: CollectionLoadParameters; diff --git a/imxweb/projects/qbm/src/lib/select/fk-selection-container.ts b/imxweb/projects/qbm/src/lib/select/fk-selection-container.ts index 0fd1deb88..16f04adb6 100644 --- a/imxweb/projects/qbm/src/lib/select/fk-selection-container.ts +++ b/imxweb/projects/qbm/src/lib/select/fk-selection-container.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -27,7 +27,7 @@ import { ErrorHandler } from '@angular/core'; import { AbstractControl } from '@angular/forms'; -import { EntityData, FilterType, CompareOperator, CollectionLoadParameters, EntityCollectionData } from 'imx-qbm-dbts'; +import { EntityData, FilterType, CompareOperator, CollectionLoadParameters, EntityCollectionData } from '@imx-modules/imx-qbm-dbts'; import { FkContainer } from '../fk-container/fk-container'; import { SelectContentProvider } from './select-content-provider.interface'; import { ClassloggerService } from '../classlogger/classlogger.service'; @@ -54,10 +54,10 @@ export class FkSelectionContainer { public placeholder?: string, public itemIcon?: string, public contentProvider: SelectContentProvider = { - display: item => item.Display, - key: item => item.Keys[0] - } - ) { + display: (item) => item.Display, + key: (item) => item.Keys[0], + }, + ) { this.navigation = { StartIndex: 0, PageSize: this.settingsService.DefaultPageSize }; } @@ -81,8 +81,11 @@ export class FkSelectionContainer { this.navigation.StartIndex = startIndex; try { this.loading = true; - this.logger.trace(this, `Load ${this.navigation.PageSize} new items of column - ${this.fkContainer.property.Column.ColumnName} from position ${this.navigation.StartIndex}`); + this.logger.trace( + this, + `Load ${this.navigation.PageSize} new items of column + ${this.fkContainer.property.Column.ColumnName} from position ${this.navigation.StartIndex}`, + ); await this.init(this.errorHandler); } finally { this.loading = false; @@ -90,14 +93,17 @@ export class FkSelectionContainer { } public async onAutocompleteValueChanged(keywords: string): Promise { - this.navigation.filter = keywords === '' - ? null - : [{ - ColumnName: this.filterColumn, - Type: FilterType.Compare, - CompareOp: CompareOperator.Like, - Value1: `%${keywords}%` - }]; + this.navigation.filter = + keywords === '' + ? null + : [ + { + ColumnName: this.filterColumn, + Type: FilterType.Compare, + CompareOp: CompareOperator.Like, + Value1: `%${keywords}%`, + }, + ]; this.getData(0); } diff --git a/imxweb/projects/qbm/src/lib/select/select-data-source.ts b/imxweb/projects/qbm/src/lib/select/select-data-source.ts deleted file mode 100644 index 8ad402c76..000000000 --- a/imxweb/projects/qbm/src/lib/select/select-data-source.ts +++ /dev/null @@ -1,63 +0,0 @@ -/* - * ONE IDENTITY LLC. PROPRIETARY INFORMATION - * - * This software is confidential. One Identity, LLC. or one of its affiliates or - * subsidiaries, has supplied this software to you under terms of a - * license agreement, nondisclosure agreement or both. - * - * You may not copy, disclose, or use this software except in accordance with - * those terms. - * - * - * Copyright 2023 One Identity LLC. - * ALL RIGHTS RESERVED. - * - * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR - * WARRANTIES ABOUT THE SUITABILITY OF THE SOFTWARE, - * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED - * TO THE IMPLIED WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE, OR - * NON-INFRINGEMENT. ONE IDENTITY LLC. SHALL NOT BE - * LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE - * AS A RESULT OF USING, MODIFYING OR DISTRIBUTING - * THIS SOFTWARE OR ITS DERIVATIVES. - * - */ - -import { EventEmitter } from '@angular/core'; - -import { ClassloggerService } from '../classlogger/classlogger.service'; - - -/** Datasource of select component */ -export class SelectDataSource { - - /** Fires when the datasource needs new data. */ - public needData: EventEmitter = new EventEmitter(); - - - /** Returns the list of items of the datasource */ - public get rawData(): any[] { - return this.cache; - } - - private cache = []; - - constructor(private logger: ClassloggerService) {} - - /** Resets the datasource */ - public reset(): void { - this.logger.debug(this, 'Resetting datasource'); - this.cache = []; - } - - public getData(startIndex: number): void { - this.needData.emit(startIndex); - } - - public setData(items: any[]): void { - this.logger.debug(this, `Setting cache with ${items.length}`); - this.cache = items; - } - -} diff --git a/imxweb/projects/qbm/src/lib/select/select.component.html b/imxweb/projects/qbm/src/lib/select/select.component.html deleted file mode 100644 index 9c1435128..000000000 --- a/imxweb/projects/qbm/src/lib/select/select.component.html +++ /dev/null @@ -1,40 +0,0 @@ -
    - - {{ label }} -
    - - - - {{ contentProvider.display(item) }} - cancel - - -
    -
    - - {{ label }} - - - - - - - - -
    diff --git a/imxweb/projects/qbm/src/lib/select/select.component.scss b/imxweb/projects/qbm/src/lib/select/select.component.scss deleted file mode 100644 index c9c4fc2e8..000000000 --- a/imxweb/projects/qbm/src/lib/select/select.component.scss +++ /dev/null @@ -1,40 +0,0 @@ -@import '@elemental-ui/core/src/styles/_palette.scss'; - -.mat-form-field { - width: 100%; -} - -.imx-main-container { - display: flex; - align-items: baseline; -} - -.mat-chip-list { - user-select: none; - outline: none; -} - -.imx-chip-value { - white-space: nowrap; - text-overflow: ellipsis; - overflow: hidden; -} - -.imx-chip-list-container { - min-height: 20px; - max-height: 120px; - overflow: auto; - padding: 4px; -} - -.imx-chip-icon { - flex: 0 0 30px; -} - -.mat-chip { - display: grid; - grid-template-columns: auto 1fr auto; - .eui-icon { - opacity: 0.6; - } -} diff --git a/imxweb/projects/qbm/src/lib/select/select.component.ts b/imxweb/projects/qbm/src/lib/select/select.component.ts deleted file mode 100644 index ee249db4d..000000000 --- a/imxweb/projects/qbm/src/lib/select/select.component.ts +++ /dev/null @@ -1,222 +0,0 @@ -/* - * ONE IDENTITY LLC. PROPRIETARY INFORMATION - * - * This software is confidential. One Identity, LLC. or one of its affiliates or - * subsidiaries, has supplied this software to you under terms of a - * license agreement, nondisclosure agreement or both. - * - * You may not copy, disclose, or use this software except in accordance with - * those terms. - * - * - * Copyright 2023 One Identity LLC. - * ALL RIGHTS RESERVED. - * - * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR - * WARRANTIES ABOUT THE SUITABILITY OF THE SOFTWARE, - * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED - * TO THE IMPLIED WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE, OR - * NON-INFRINGEMENT. ONE IDENTITY LLC. SHALL NOT BE - * LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE - * AS A RESULT OF USING, MODIFYING OR DISTRIBUTING - * THIS SOFTWARE OR ITS DERIVATIVES. - * - */ - -import { - Component, - Input, - EventEmitter, - Output, - AfterViewInit, - OnDestroy, - OnChanges, - SimpleChanges, - HostListener -} from '@angular/core'; -import { ENTER, COMMA } from '@angular/cdk/keycodes'; -import { AbstractControl, UntypedFormControl } from '@angular/forms'; -import { Subscription } from 'rxjs'; - -import { ClassloggerService } from '../classlogger/classlogger.service'; -import { SelectContentProvider } from './select-content-provider.interface'; -import { SelectDataSource } from './select-data-source'; -import { DataNavigationParameters } from './data-navigation-parameters.interface'; - -/** - * A component for selecting a single or multiple items from a candidate list using an autocomplete control. - * The selected object(s) is/are displayed as Mat-Chip(s) and can be removed using a remove icon. - */ -@Component({ - selector: 'imx-select', - templateUrl: './select.component.html', - styleUrls: ['./select.component.scss'], -}) -export class SelectComponent implements AfterViewInit, OnChanges, OnDestroy { - public readonly separatorKeysCodes: number[] = [ENTER, COMMA]; - public readonly chipListCtrl = new UntypedFormControl(''); - public dataSource: SelectDataSource; - public autocompleteVisible = false; - - /** Flag for multi select mode */ - @Input() public multi = false; - - /** The name of icon for the items shown in the autocomplete control. */ - @Input() public itemIcon: string; - - /** The candidate list for the selection */ - @Input() public items: T[] = []; - - /** The selected items */ - @Input() public itemsSelected: T[] = []; - - /** The text for the mat-label of the formcontrol */ - @Input() public label: string; - - /** The placeholder text of the autocomplete control */ - @Input() public placeholder: string; - - /** validation error message */ - @Input() public errorMessage: string; - - /** The form control of the component. */ - @Input() public formCtrl: AbstractControl; - - /** Provides methods for displaying the item content */ - @Input() public contentProvider: SelectContentProvider; - - /** Indicates if data is loading and shows/hides the spinner. */ - @Input() public loading = false; - - /** @deprecated Not in use. Will be removed. - * The virtual page size. - * Must be set for calculating the height of the virtual sroll container. - */ - @Input() public pageSize = 50; - - /** Indicates if Datasource is remote or local. */ - @Input() public isLocalDatasource = false; - - /** Indicates if the component is disabled = readonly */ - @Input() public disabled = false; - - @Input() public totalCount = 0; - - @Input() public labelAutoComplete: string; - - /** @deprecated Use needMoreData instead. Will be removed. - * Fires when the component need new data, e.g. user scrolls to the end of the container. - */ - @Output() public needData: EventEmitter = new EventEmitter(); - - /** Fires when the component need new data, e.g. user scrolls to the end of the container. */ - @Output() public needMoreData: EventEmitter = new EventEmitter(); - - /** @deprecated Will be removed. - * Fires when the user types in the autocomplete input control. - */ - @Output() public autocompleteValueChanged: EventEmitter = new EventEmitter(); - - private subscriptions: Subscription[] = []; - private parameters: DataNavigationParameters = { navigation: { StartIndex: 0, PageSize: this.pageSize}}; - private originalItemsSelected: T[] = []; - private canceling = false; - - constructor(private logger: ClassloggerService) { - this.dataSource = new SelectDataSource(this.logger); - } - - public ngAfterViewInit(): void { - this.subscriptions.push(this.dataSource.needData.subscribe((startIndex: number) => { - this.parameters.navigation.StartIndex = startIndex; - this.needMoreData.emit(this.parameters); - this.needData.emit(this.parameters.navigation.StartIndex); - })); - } - - public ngOnChanges(changes: SimpleChanges): void { - if (changes['itemsSelected'] && changes['itemsSelected'].currentValue && this.multi) { - this.originalItemsSelected = this.itemsSelected.slice(); - } - } - - public ngOnDestroy(): void { - this.subscriptions.forEach(subscription => subscription.unsubscribe()); - } - - /** - * Removes the specified item from the selection list. - * @param item the item to remove. - */ - public removeItem(item: T, event?: MouseEvent, ): void { - if (event) { - event.stopPropagation(); - } - - if (this.disabled) { - return; - } - - let index = -1; - - if (this.contentProvider && this.contentProvider.key) { - const itemKey = this.contentProvider.key(item); - index = this.itemsSelected.findIndex(itemSelected => this.contentProvider.key(itemSelected) === itemKey); - } else { - index = this.itemsSelected.indexOf(item); - } - - if (index >= 0) { - this.logger.debug(this, 'Selection list, remove', item); - this.itemsSelected.splice(index, 1); - this.refreshFormControl(); - } - } - - @HostListener('document:keydown.escape', ['$event']) - public onDocumentCancel(event: KeyboardEvent): void { - if (this.multi) { - this.itemsSelected = this.originalItemsSelected.slice(); - this.canceling = true; - } - } - - public showAutocomplete(): void { - if (!this.disabled) { - this.autocompleteVisible = true; - } - } - - public onAutocompleteValueChanged(event: string): void { - if (event == null) { - this.parameters.navigation.StartIndex = 0; - this.parameters.navigation.filter = undefined; - this.parameters.navigation.search = undefined; - } - - this.parameters.keyword = event; - this.needMoreData.emit(this.parameters); - this.autocompleteValueChanged.emit(this.parameters.keyword); - } - - public onAutocompleteClosing(): void { - this.autocompleteVisible = false; - this.dataSource.reset(); - this.parameters.keyword = ''; - this.parameters.navigation.StartIndex = 0; - this.parameters.navigation.filter = undefined; - this.parameters.navigation.search = undefined; - - if (this.multi && !this.canceling) { - this.originalItemsSelected = this.itemsSelected.slice(); - } - - this.canceling = false; - } - - public refreshFormControl(): void { - this.formCtrl.setValue(this.itemsSelected); - this.formCtrl.markAsDirty(); - } -} diff --git a/imxweb/projects/qbm/src/lib/selected-elements/selected-elements-dialog/selected-elements-dialog.component.html b/imxweb/projects/qbm/src/lib/selected-elements/selected-elements-dialog/selected-elements-dialog.component.html index 8ca680df6..fb50b7d88 100644 --- a/imxweb/projects/qbm/src/lib/selected-elements/selected-elements-dialog/selected-elements-dialog.component.html +++ b/imxweb/projects/qbm/src/lib/selected-elements/selected-elements-dialog/selected-elements-dialog.component.html @@ -1,6 +1,6 @@ -

    {{ data.header }}

    +

    {{ data.header }}

    - + {{ data.header }}

    >
    - - + +
    {{ item.GetEntity().GetDisplay() }}
    {{ getTable(item) }}
    diff --git a/imxweb/projects/qbm/src/lib/selected-elements/selected-elements-dialog/selected-elements-dialog.component.scss b/imxweb/projects/qbm/src/lib/selected-elements/selected-elements-dialog/selected-elements-dialog.component.scss index f4974f76d..da46eed08 100644 --- a/imxweb/projects/qbm/src/lib/selected-elements/selected-elements-dialog/selected-elements-dialog.component.scss +++ b/imxweb/projects/qbm/src/lib/selected-elements/selected-elements-dialog/selected-elements-dialog.component.scss @@ -1,41 +1,18 @@ -:host { - display: flex; - flex-direction: column; - overflow: hidden; - height: 100%; -} +@import 'base/mixins'; -.mat-dialog-content { +:host { display: flex; flex-direction: column; overflow: hidden; height: 100%; } -.mat-card { - display: flex; - flex-direction: column; - overflow: hidden; - flex: 1 1 auto; -} - -.imx-table-container { - display: flex; - flex-direction: column; - overflow: hidden; - height: inherit; - max-width: 100%; - flex: 1 1 auto; -} - -.mat-dialog-title { - margin: 10px 0 20px; +.mat-mdc-dialog-content { + @include flex-column-container($overflow: hidden, $height: 100%); } -.mat-dialog-actions { - justify-content: flex-end; - - > .mat-flat-button { +.mat-mdc-dialog-actions { + > .mat-mdc-unelevated-button { margin-bottom: 20px; } } diff --git a/imxweb/projects/qbm/src/lib/selected-elements/selected-elements-dialog/selected-elements-dialog.component.ts b/imxweb/projects/qbm/src/lib/selected-elements/selected-elements-dialog/selected-elements-dialog.component.ts index d22f4a4d1..ce7856d36 100644 --- a/imxweb/projects/qbm/src/lib/selected-elements/selected-elements-dialog/selected-elements-dialog.component.ts +++ b/imxweb/projects/qbm/src/lib/selected-elements/selected-elements-dialog/selected-elements-dialog.component.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -25,16 +25,15 @@ */ import { Component, Inject, OnInit } from '@angular/core'; +import { MAT_DIALOG_DATA } from '@angular/material/dialog'; +import { DataModelFilterOption, DbObjectKey, DisplayColumns, EntitySchema, IClientProperty, TypedEntity } from '@imx-modules/imx-qbm-dbts'; import { TranslateService } from '@ngx-translate/core'; -import { DataModelFilterOption, DbObjectKey, DisplayColumns, EntitySchema, IClientProperty, TypedEntity } from 'imx-qbm-dbts'; import { MetadataService } from '../../base/metadata.service'; import { CdrFactoryService } from '../../cdr/cdr-factory.service'; import { DataSourceToolbarFilter } from '../../data-source-toolbar/data-source-toolbar-filters.interface'; import { DataSourceToolbarSettings } from '../../data-source-toolbar/data-source-toolbar-settings'; import { CandidateEntity } from '../../fk-advanced-picker/candidate-entity'; -import { SelectedElementsDialogParameter } from './selected-elements-dialog.model'; -import { TypedEntityTableFilter } from './selected-elements-dialog.model'; -import { MAT_DIALOG_DATA } from '@angular/material/dialog'; +import { SelectedElementsDialogParameter, TypedEntityTableFilter } from './selected-elements-dialog.model'; /** * A component, that can be shown inside a MatDialogComponent. It contains a table of entities with their display value as a column @@ -68,13 +67,7 @@ export class SelectedElementsDialog implements OnInit { ) { this.entitySchemaCandidates = CandidateEntity.GetEntitySchema(); this.displayedColumns = [this.entitySchemaCandidates.Columns[DisplayColumns.DISPLAY_PROPERTYNAME]]; - this.sortedEntities = data.entities?.sort( - (a, b) => - a - .GetEntity() - .GetDisplay() - ?.localeCompare(b.GetEntity()?.GetDisplay()), - ); + this.sortedEntities = data.entities?.sort((a, b) => a.GetEntity().GetDisplay()?.localeCompare(b.GetEntity()?.GetDisplay())); } public async ngOnInit(): Promise { @@ -117,12 +110,15 @@ export class SelectedElementsDialog implements OnInit { public navigate(source: TypedEntityTableFilter): void { this.navigationState = { ...this.navigationState, ...source }; const possible = source.table - ? this.searchedEntities.filter( - (elem) => CdrFactoryService.tryGetColumn(elem.GetEntity(), 'XObjectKey')?.GetValue()?.includes(source.table), + ? this.searchedEntities.filter((elem) => + CdrFactoryService.tryGetColumn(elem.GetEntity(), 'XObjectKey')?.GetValue()?.includes(source.table), ) : this.searchedEntities; - const data = possible.slice(this.navigationState.StartIndex, this.navigationState.StartIndex + this.navigationState.PageSize); + const data = possible.slice( + this.navigationState.StartIndex, + (this.navigationState.StartIndex ?? 0) + (this.navigationState.PageSize ?? 0), + ); this.dstSettings = { displayedColumns: this.displayedColumns, dataSource: { @@ -149,16 +145,18 @@ export class SelectedElementsDialog implements OnInit { return ''; } const tableName = DbObjectKey.FromXml(column.GetValue()).TableName; - return this.metaData.tables[tableName]?.DisplaySingular; + return this.metaData.tables[tableName]?.DisplaySingular ?? ''; } private getOptionsForFilter(): DataModelFilterOption[] { - return this.data.tables - .map((elem) => ({ Value: elem, Display: this.metaData.tables[elem]?.DisplaySingular })) - .filter((elem) => - this.data.entities.some( - (entity) => CdrFactoryService.tryGetColumn(entity.GetEntity(), 'XObjectKey')?.GetValue().includes(elem.Value), - ), - ); + return ( + this.data.tables + ?.map((elem) => ({ Value: elem, Display: this.metaData.tables[elem]?.DisplaySingular })) + .filter((elem) => + this.data.entities.some((entity) => + CdrFactoryService.tryGetColumn(entity.GetEntity(), 'XObjectKey')?.GetValue().includes(elem.Value), + ), + ) ?? [] + ); } } diff --git a/imxweb/projects/qbm/src/lib/selected-elements/selected-elements-dialog/selected-elements-dialog.model.ts b/imxweb/projects/qbm/src/lib/selected-elements/selected-elements-dialog/selected-elements-dialog.model.ts index ebd4a0eb7..e1586f0a6 100644 --- a/imxweb/projects/qbm/src/lib/selected-elements/selected-elements-dialog/selected-elements-dialog.model.ts +++ b/imxweb/projects/qbm/src/lib/selected-elements/selected-elements-dialog/selected-elements-dialog.model.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -24,7 +24,7 @@ * */ -import { TypedEntity, CollectionLoadParameters } from 'imx-qbm-dbts'; +import { TypedEntity, CollectionLoadParameters } from '@imx-modules/imx-qbm-dbts'; export interface SelectedElementsDialogParameter { entities: TypedEntity[]; @@ -35,4 +35,3 @@ export interface SelectedElementsDialogParameter { export interface TypedEntityTableFilter extends CollectionLoadParameters { table?: string; } - diff --git a/imxweb/projects/qbm/src/lib/selected-elements/selected-elements.component.html b/imxweb/projects/qbm/src/lib/selected-elements/selected-elements.component.html index 93ac2c5f1..aafea3fcc 100644 --- a/imxweb/projects/qbm/src/lib/selected-elements/selected-elements.component.html +++ b/imxweb/projects/qbm/src/lib/selected-elements/selected-elements.component.html @@ -1,5 +1,15 @@ - + \ No newline at end of file diff --git a/imxweb/projects/qbm/src/lib/selected-elements/selected-elements.component.scss b/imxweb/projects/qbm/src/lib/selected-elements/selected-elements.component.scss index 848687f66..88d4bd17c 100644 --- a/imxweb/projects/qbm/src/lib/selected-elements/selected-elements.component.scss +++ b/imxweb/projects/qbm/src/lib/selected-elements/selected-elements.component.scss @@ -1,6 +1,5 @@ -@import '../../../../../shared/scss/common-table.scss'; +@import 'base/mixins'; - -.mat-stroked-button { - @include imx-icon-for-image-button(); +.mat-mdc-outlined-button { + @include image-button-icon(); } \ No newline at end of file diff --git a/imxweb/projects/qbm/src/lib/selected-elements/selected-elements.component.ts b/imxweb/projects/qbm/src/lib/selected-elements/selected-elements.component.ts index 641d54560..1f8e7340d 100644 --- a/imxweb/projects/qbm/src/lib/selected-elements/selected-elements.component.ts +++ b/imxweb/projects/qbm/src/lib/selected-elements/selected-elements.component.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -24,11 +24,11 @@ * */ -import { Component, Input } from '@angular/core'; +import { Component, EventEmitter, Input, Output } from '@angular/core'; import { MatDialog } from '@angular/material/dialog'; import { TranslateService } from '@ngx-translate/core'; -import { TypedEntity } from 'imx-qbm-dbts'; +import { TypedEntity } from '@imx-modules/imx-qbm-dbts'; import { SelectedElementsDialog } from './selected-elements-dialog/selected-elements-dialog.component'; @Component({ @@ -40,16 +40,46 @@ export class SelectedElementsComponent { @Input() public selectedElements: TypedEntity[] = []; @Input() public tables: string[]; @Input() public isLoading: boolean; - @Input() public caption = this.translate.instant('#LDS#Show selected'); - @Input() public dialogHeader = this.translate.instant('#LDS#Heading Selected Items'); + @Input() public caption: string; + @Input() public dialogHeader: string; + @Input() public showDeselectAll: boolean = false; + @Input() public deselectAllCaption: string; + + @Output() public openCustomSelectionDialog = new EventEmitter(); + @Output() public onDeselectAllClicked = new EventEmitter(); - constructor(public readonly dialog: MatDialog, public readonly translate: TranslateService) {} + constructor( + public readonly dialog: MatDialog, + public readonly translate: TranslateService, + ) { + if (!this.caption) { + this.caption = this.translate.instant('#LDS#Show selected'); + } + if (!this.deselectAllCaption) { + this.deselectAllCaption = this.translate.instant('#LDS#Deselect all'); + } + if (!this.dialogHeader) { + this.dialogHeader = this.translate.instant('#LDS#Heading Selected Items'); + } + } public onOpenSelectionDialog(): void { - this.dialog.open(SelectedElementsDialog, { - width: 'max(60%,600px)', - height: 'max(60%,600px)', - data: { entities: this.selectedElements, tables: this.tables ?? [], header: this.dialogHeader }, - }); + if (this.openCustomSelectionDialog.observed) { + this.openCustomSelectionDialog.emit(); + } else { + this.dialog.open(SelectedElementsDialog, { + width: 'max(60%,600px)', + height: 'max(60%,600px)', + data: { entities: this.selectedElements, tables: this.tables ?? [], header: this.dialogHeader }, + }); + } + } + + public deselectAll() { + if (this.onDeselectAllClicked.observed) { + this.onDeselectAllClicked.emit(); + } else { + this.selectedElements = []; + } } } diff --git a/imxweb/projects/qbm/src/lib/selected-elements/selected-elements.module.ts b/imxweb/projects/qbm/src/lib/selected-elements/selected-elements.module.ts index 442c47076..811536b73 100644 --- a/imxweb/projects/qbm/src/lib/selected-elements/selected-elements.module.ts +++ b/imxweb/projects/qbm/src/lib/selected-elements/selected-elements.module.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -39,7 +39,6 @@ import { SelectedElementsDialog } from './selected-elements-dialog/selected-elem import { DataTableModule } from '../data-table/data-table.module'; import { DataSourceToolbarModule } from '../data-source-toolbar/data-source-toolbar.module'; - @NgModule({ declarations: [SelectedElementsComponent, SelectedElementsDialog], imports: [ diff --git a/imxweb/projects/qbm/src/lib/services/device-state.service.ts b/imxweb/projects/qbm/src/lib/services/device-state.service.ts deleted file mode 100644 index 270f38425..000000000 --- a/imxweb/projects/qbm/src/lib/services/device-state.service.ts +++ /dev/null @@ -1,80 +0,0 @@ -/* - * ONE IDENTITY LLC. PROPRIETARY INFORMATION - * - * This software is confidential. One Identity, LLC. or one of its affiliates or - * subsidiaries, has supplied this software to you under terms of a - * license agreement, nondisclosure agreement or both. - * - * You may not copy, disclose, or use this software except in accordance with - * those terms. - * - * - * Copyright 2023 One Identity LLC. - * ALL RIGHTS RESERVED. - * - * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR - * WARRANTIES ABOUT THE SUITABILITY OF THE SOFTWARE, - * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED - * TO THE IMPLIED WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE, OR - * NON-INFRINGEMENT. ONE IDENTITY LLC. SHALL NOT BE - * LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE - * AS A RESULT OF USING, MODIFYING OR DISTRIBUTING - * THIS SOFTWARE OR ITS DERIVATIVES. - * - */ - -import { Injectable } from '@angular/core'; -import * as elementResizeDetector from 'element-resize-detector'; - -/** @deprecated This service is deprecated and will be removed in a future release.*/ -@Injectable() -export class DeviceStateService { - - get deviceState(): string { - this._deviceState = this.getCurrentDeviceState(); - return this._deviceState; - } - - private _deviceState = 'desktop'; - constructor() { - this.createDeviceStateIndicator(); - } - - public isPhoneDevice(): boolean { - return this.deviceState === 'mobile'; - } - - private createDeviceStateIndicator(): HTMLElement { - const indicatorNode = document.createElement('div'); - indicatorNode.className = 'state-indicator'; - document.body.appendChild(indicatorNode); - - // importing a commonjs module - // const elementResizeDetectorMaker = require('element-resize-detector'); - const elementResizeDetectorMaker = elementResizeDetector; - const erd = elementResizeDetectorMaker({ - strategy: 'scroll' - }); - erd.listenTo(document.body, () => this.deviceState); - return indicatorNode; - } - - private getCurrentDeviceState(): string { - const indicatorNode = this.getOrCreateIndicatorNode(); - return this.getDeviceStateFromNode(indicatorNode); - } - - private getOrCreateIndicatorNode() { - const indicatorNode = document.querySelector('.state-indicator'); - return indicatorNode || this.createDeviceStateIndicator(); - } - - private getDeviceStateFromNode(indicatorNode: Element) { - let state = window.getComputedStyle(indicatorNode, ':before').getPropertyValue('content'); - // delete quotes - state = state.replace(/['"]+/g, ''); - this._deviceState = state; - return state; - } -} diff --git a/imxweb/projects/qbm/src/lib/session/auth-prop-data-provider.interface.ts b/imxweb/projects/qbm/src/lib/session/auth-prop-data-provider.interface.ts index ec04bfaec..fcba06e75 100644 --- a/imxweb/projects/qbm/src/lib/session/auth-prop-data-provider.interface.ts +++ b/imxweb/projects/qbm/src/lib/session/auth-prop-data-provider.interface.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -28,4 +28,5 @@ export interface AuthPropDataProvider { name: string; inputType: string; display: string; + disabled?: boolean; } diff --git a/imxweb/projects/qbm/src/lib/session/imx-session.service.ts b/imxweb/projects/qbm/src/lib/session/imx-session.service.ts index 6f21152d1..b4a3293b6 100644 --- a/imxweb/projects/qbm/src/lib/session/imx-session.service.ts +++ b/imxweb/projects/qbm/src/lib/session/imx-session.service.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -26,10 +26,10 @@ import { Injectable } from '@angular/core'; -import { TypedClient, V2Client } from 'imx-api-qbm'; -import { ISessionState, SessionState } from './session-state'; +import { PreAuthResponseData, TypedClient, V2Client } from '@imx-modules/imx-api-qbm'; import { AppConfigService } from '../appConfig/appConfig.service'; import { ClassloggerService } from '../classlogger/classlogger.service'; +import { ISessionState, SessionState } from './session-state'; @Injectable() export class imx_SessionService { @@ -46,7 +46,8 @@ export class imx_SessionService { constructor( private appConfigService: AppConfigService, - private readonly logger: ClassloggerService) { } + private readonly logger: ClassloggerService, + ) {} public async getSessionState(): Promise { this.logger.debug(this, 'getSessionState'); @@ -57,7 +58,7 @@ export class imx_SessionService { public async login(loginData: { [key: string]: string }): Promise { this.logger.debug(this, 'login'); const sr = await this.appConfigService.client.imx_login_post(this.appConfigService.Config.WebAppIndex, loginData, { - noxsrf: false + noxsrf: false, }); return (this.sessionState = new SessionState(sr)); } @@ -67,4 +68,17 @@ export class imx_SessionService { const sr = await this.appConfigService.client.imx_logout_post(this.appConfigService.Config.WebAppIndex); return (this.sessionState = new SessionState(sr)); } + + public async preAuth(preAuthData: { [key: string]: string }): Promise { + return this.appConfigService.client.imx_login_preauth_post(this.appConfigService.Config.WebAppIndex, { AuthProps: preAuthData }); + } + + public async preAuthVerify(captchaCode: string): Promise { + return await this.appConfigService.client + .imx_login_preauth_verify_post(this.appConfigService.Config.WebAppIndex, { Code: captchaCode }) + .then(() => true) + .catch((error) => { + throw Error(error); + }); + } } diff --git a/imxweb/projects/qbm/src/lib/session/session-state.spec.ts b/imxweb/projects/qbm/src/lib/session/session-state.spec.ts index 1a6d6e9f6..1d7497da5 100644 --- a/imxweb/projects/qbm/src/lib/session/session-state.spec.ts +++ b/imxweb/projects/qbm/src/lib/session/session-state.spec.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -24,12 +24,11 @@ * */ -import { AuthPropType } from 'imx-api-qbm'; +import { AuthPropType } from '@imx-modules/imx-api-qbm'; import { SessionState } from './session-state'; import { clearStylesFromDOM } from '../testing/clear-styles.spec'; describe('SessionState ', () => { - afterAll(() => { clearStylesFromDOM(); }); @@ -41,14 +40,14 @@ describe('SessionState ', () => { IsAuthenticated: true, Display: 'display', Uid: 'uid', - AuthTime: undefined + AuthTime: undefined, }, SecondaryAuth: { IsAuthenticated: true, IsEnabled: false, - Name: 'Starling' - } - } + Name: 'Starling', + }, + }, }; const sessionState = new SessionState(sessionResponse); @@ -62,14 +61,14 @@ describe('SessionState ', () => { IsAuthenticated: true, Display: 'display', Uid: 'uid', - AuthTime: undefined + AuthTime: undefined, }, SecondaryAuth: { IsAuthenticated: true, IsEnabled: false, - Name: 'Starling' - } - } + Name: 'Starling', + }, + }, }; const sessionState = new SessionState(sessionResponse); @@ -79,45 +78,45 @@ describe('SessionState ', () => { [ { AuthProps: undefined, - expectedIsOAuth: undefined + expectedIsOAuth: undefined, }, { AuthProps: [], - expectedIsOAuth: undefined + expectedIsOAuth: undefined, }, { AuthProps: [ { Type: AuthPropType.Password, - IsMandatory: undefined - } + IsMandatory: undefined, + }, ], - expectedIsOAuth: undefined + expectedIsOAuth: undefined, }, { AuthProps: [ { Type: AuthPropType.OAuth2Code, - IsMandatory: undefined - } + IsMandatory: undefined, + }, ], - expectedIsOAuth: true - } - ].forEach(testcase => + expectedIsOAuth: true, + }, + ].forEach((testcase) => it('maps config', () => { const sessionResponse = { Config: [ { Name: 'config1', Display: 'display1', - AuthProps: testcase.AuthProps - } - ] + AuthProps: testcase.AuthProps, + }, + ], }; const sessionState = new SessionState(sessionResponse); expect(sessionState.configurationProviders.length).toEqual(sessionResponse.Config.length); expect(sessionState.configurationProviders[0].isOAuth2).toEqual(testcase.expectedIsOAuth); - }) + }), ); }); diff --git a/imxweb/projects/qbm/src/lib/session/session-state.ts b/imxweb/projects/qbm/src/lib/session/session-state.ts index 07acfe12d..cdd76d990 100644 --- a/imxweb/projects/qbm/src/lib/session/session-state.ts +++ b/imxweb/projects/qbm/src/lib/session/session-state.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -24,29 +24,29 @@ * */ -import { SessionResponse, AuthPropType } from 'imx-api-qbm'; -import { AuthConfigProvider } from '../authentication/auth-config-provider.interface'; +import { AuthPropType, SessionResponse } from '@imx-modules/imx-api-qbm'; +import { AuthConfigProvider, PreAuthStateType } from '../authentication/auth-config-provider.interface'; export enum AuthStepLevels { LoggedOut = 0, AwaitsSecondaryAuth = 1, - LoggedIn = 2 + LoggedIn = 2, } export interface ISessionState { IsLoggedOut?: boolean; IsAwaitingSecondaryAuth?: boolean; IsLoggedIn?: boolean; - Username?: string; + Username?: string | null; /** Returns the UID of the identity associated with the session. Note that this may * be `null` when the session has no associated identity. */ - UserUid?: string; - SecondaryAuthName?: string; - SecondaryErrorMessage?: string; + UserUid?: string | null; + SecondaryAuthName?: string | null; + SecondaryErrorMessage?: string | null; configurationProviders?: AuthConfigProvider[]; - externalLogoutUrl?: string; + externalLogoutUrl?: string | undefined; isOAuth?: boolean; hasErrorState?: boolean; culture?: string; @@ -57,82 +57,88 @@ export interface ISessionState { * Encapsulates SessionResponse and provides properties for determining the current state of the sessions */ export class SessionState implements ISessionState { - public get IsLoggedOut(): boolean { return this.currentAuthStep === AuthStepLevels.LoggedOut; } - public get IsAwaitingSecondaryAuth(): boolean { return this.currentAuthStep === AuthStepLevels.AwaitsSecondaryAuth; } - public get IsLoggedIn(): boolean { return this.currentAuthStep === AuthStepLevels.LoggedIn; } - public get Username(): string { return this.sessionResponse && this.IsLoggedIn ? this.sessionResponse.Status.PrimaryAuth.Display : null; } - public get UserUid(): string { return this.sessionResponse && this.IsLoggedIn ? this.sessionResponse.Status.PrimaryAuth.Uid : null; } - public get SecondaryAuthName(): string { - return this.sessionResponse && this.sessionResponse.Status && this.sessionResponse.Status.SecondaryAuth ? - this.sessionResponse.Status.SecondaryAuth.Name : - null; + public get IsLoggedOut(): boolean { + return this.currentAuthStep === AuthStepLevels.LoggedOut; + } + public get IsAwaitingSecondaryAuth(): boolean { + return this.currentAuthStep === AuthStepLevels.AwaitsSecondaryAuth; + } + public get IsLoggedIn(): boolean { + return this.currentAuthStep === AuthStepLevels.LoggedIn; + } + public get Username(): string | null { + return this.sessionResponse && this.IsLoggedIn ? this.sessionResponse?.Status?.PrimaryAuth?.Display ?? null : null; + } + public get UserUid(): string | null { + return this.sessionResponse && this.IsLoggedIn ? this.sessionResponse?.Status?.PrimaryAuth?.Uid ?? null : null; + } + public get SecondaryAuthName(): string | null { + return this.sessionResponse && this.sessionResponse.Status && this.sessionResponse.Status.SecondaryAuth + ? this.sessionResponse.Status.SecondaryAuth.Name ?? null + : null; } - public get SecondaryErrorMessage(): string { - return this.sessionResponse && this.sessionResponse.Status && this.sessionResponse.Status.SecondaryAuth ? - this.sessionResponse.Status.SecondaryAuth.ErrorMessage : - null; + public get SecondaryErrorMessage(): string | null { + return this.sessionResponse && this.sessionResponse.Status && this.sessionResponse.Status.SecondaryAuth + ? this.sessionResponse.Status.SecondaryAuth.ErrorMessage ?? null + : null; } public readonly configurationProviders: AuthConfigProvider[]; - public readonly externalLogoutUrl: string; - public readonly culture: string; - public readonly cultureFormat: string; - + public readonly externalLogoutUrl: string | undefined; + public readonly culture: string | undefined; + public readonly cultureFormat: string | undefined; private currentAuthStep: AuthStepLevels = AuthStepLevels.LoggedOut; constructor(private sessionResponse: SessionResponse) { this.currentAuthStep = this.GetCurrentAuthStep(); - this.configurationProviders = this.GetConfigurationProviders(); + this.configurationProviders = this.GetConfigurationProviders() ?? []; + if (this.sessionResponse && this.sessionResponse.Status) { this.externalLogoutUrl = this.sessionResponse.Status.ExternalLogoutUrl; } this.culture = this.sessionResponse?.Status?.Culture; - this.cultureFormat = this.sessionResponse?.Status?.CultureFormat ; + this.cultureFormat = this.sessionResponse?.Status?.CultureFormat; } private GetCurrentAuthStep(): AuthStepLevels { - if ( - !this.sessionResponse || - !this.sessionResponse.Status || - !this.sessionResponse.Status.PrimaryAuth.IsAuthenticated - ) { + if (!this.sessionResponse || !this.sessionResponse.Status || !this.sessionResponse?.Status?.PrimaryAuth?.IsAuthenticated) { return AuthStepLevels.LoggedOut; } - if ( - this.sessionResponse.Status.SecondaryAuth.IsEnabled && - !this.sessionResponse.Status.SecondaryAuth.IsAuthenticated - ) { + if (this.sessionResponse.Status.SecondaryAuth?.IsEnabled && !this.sessionResponse.Status.SecondaryAuth.IsAuthenticated) { return AuthStepLevels.AwaitsSecondaryAuth; } return AuthStepLevels.LoggedIn; } - private GetConfigurationProviders(): AuthConfigProvider[] { + private GetConfigurationProviders(): AuthConfigProvider[] | undefined { if (this.sessionResponse && this.sessionResponse.Config) { - return this.sessionResponse.Config.map(config => { + return this.sessionResponse.Config.map((config) => { const configProvider: AuthConfigProvider = { - name: config.Name, - display: config.Display, - externalLogoutUrl: config.ExternalLogoutUrl + name: config.Name ?? '', + display: config.Display ?? '', + externalLogoutUrl: config.ExternalLogoutUrl, }; - if (config.AuthProps) { configProvider.authProps = []; - config.AuthProps.forEach(authProp => { + config.AuthProps.forEach((authProp) => { if (authProp.Type === AuthPropType.OAuth2Code) { configProvider.isOAuth2 = true; } - - configProvider.authProps.push({ - name: authProp.Name, - inputType: authProp.Type === AuthPropType.Password ? 'Password' : 'Text', - display: authProp.Display + configProvider?.authProps?.push({ + name: authProp.Name ?? '', + inputType: authProp.Type === AuthPropType.Password ? 'password' : 'text', + display: authProp.Display ?? '', }); }); } + if (config?.PreAuthProperties?.length && config?.PreAuthProperties?.length > 0) { + configProvider.preAuthProps = configProvider?.authProps?.filter((authProp) => config?.PreAuthProperties?.includes(authProp.name)); + configProvider?.authProps?.map((authProp) => (authProp.disabled = config?.PreAuthProperties?.includes(authProp.name))); + configProvider.preAuthState = PreAuthStateType.PreAuth; + } return configProvider; }); diff --git a/imxweb/projects/qbm/src/lib/settings/settings-service.ts b/imxweb/projects/qbm/src/lib/settings/settings-service.ts index 2e0e3ef70..fb6014e14 100644 --- a/imxweb/projects/qbm/src/lib/settings/settings-service.ts +++ b/imxweb/projects/qbm/src/lib/settings/settings-service.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -24,18 +24,19 @@ * */ -import { Injectable } from "@angular/core"; +import { Injectable } from '@angular/core'; /** Wraps default settings for web applications. */ @Injectable({ - providedIn: 'root' + providedIn: 'root', }) export class SettingsService { + /** Optionset for the paginator by default. */ + DefaultPageOptions: number[] = [20, 50, 100]; /** Number of elements to load for a data page by default. */ DefaultPageSize: number = 20; /**Large number for getting all elements */ PageSizeForAllElements: number = 999999; - -} \ No newline at end of file +} diff --git a/imxweb/projects/qbm/src/lib/side-navigation-view/side-navigation-view-interfaces.ts b/imxweb/projects/qbm/src/lib/side-navigation-view/side-navigation-view-interfaces.ts index 3f3131688..ffe4daa15 100644 --- a/imxweb/projects/qbm/src/lib/side-navigation-view/side-navigation-view-interfaces.ts +++ b/imxweb/projects/qbm/src/lib/side-navigation-view/side-navigation-view-interfaces.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -25,9 +25,9 @@ */ import { Type } from '@angular/core'; +import { ProjectConfig } from '@imx-modules/imx-api-qbm'; import { AdminComponent } from '../admin/admin-component.interface'; import { IExtension } from '../ext/extension'; -import { ProjectConfig } from 'imx-api-qbm'; export interface SideNavigationItem { name: string; @@ -48,4 +48,9 @@ export interface SideNavigationExtension extends IExtension { contextId?: string; } -export type SideNavigationFactory = (preProps: string[], features: string[], projectConfig?: ProjectConfig, groups?: string[]) => SideNavigationExtension; +export type SideNavigationFactory = ( + preProps: string[], + features: string[], + projectConfig?: ProjectConfig, + groups?: string[], +) => SideNavigationExtension | undefined; diff --git a/imxweb/projects/qbm/src/lib/side-navigation-view/side-navigation-view.component.html b/imxweb/projects/qbm/src/lib/side-navigation-view/side-navigation-view.component.html index 150316974..b0fc38b16 100644 --- a/imxweb/projects/qbm/src/lib/side-navigation-view/side-navigation-view.component.html +++ b/imxweb/projects/qbm/src/lib/side-navigation-view/side-navigation-view.component.html @@ -1,8 +1,8 @@ -
    +
    - -
    -
    + +
    +
    -
    -
    - {{ componentTitle }} +
    +
    +

    {{ componentTitle }}

    @@ -27,11 +27,12 @@ [matTooltipPosition]="'after'" [matTooltipShowDelay]="500" [attr.data-imx-identifier]="'side-navigation-button-' + item.name" - [attr.aria-label]="'#LDS#Open page: {0}' | translate | ldsReplace : (item.translationKey | translate)" - class="snavigation-item" + [attr.aria-label]="'#LDS#Open page: {0}' | translate | ldsReplace: (item.translationKey | translate)" + class="imx-snavigation-item" (click)="selectPage(item.name)" - [ngClass]="{ 'snavigation-item--selected': selectedPage === item.name }" + [ngClass]="{ 'imx-snavigation-item--selected': selectedPage === item.name }" tabindex="0" + (keydown.enter)="selectPage(item.name)" > {{ item.translationKey }}
    @@ -39,8 +40,8 @@
    - -
    + +
    diff --git a/imxweb/projects/qbm/src/lib/side-navigation-view/side-navigation-view.component.scss b/imxweb/projects/qbm/src/lib/side-navigation-view/side-navigation-view.component.scss deleted file mode 100644 index 88e2a8397..000000000 --- a/imxweb/projects/qbm/src/lib/side-navigation-view/side-navigation-view.component.scss +++ /dev/null @@ -1 +0,0 @@ -@import '../../../../../shared/scss/side-navigation.scss'; diff --git a/imxweb/projects/qbm/src/lib/side-navigation-view/side-navigation-view.component.ts b/imxweb/projects/qbm/src/lib/side-navigation-view/side-navigation-view.component.ts index 53319287e..df6e870a3 100644 --- a/imxweb/projects/qbm/src/lib/side-navigation-view/side-navigation-view.component.ts +++ b/imxweb/projects/qbm/src/lib/side-navigation-view/side-navigation-view.component.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -27,45 +27,48 @@ import { ChangeDetectorRef, Component, HostListener, Input, OnDestroy, ViewChild, ViewContainerRef } from '@angular/core'; import { ActivatedRoute, NavigationEnd, Router } from '@angular/router'; import { Subscription } from 'rxjs'; +import { isMobile } from '../base/sidesheet-helper'; import { ClassloggerService } from '../classlogger/classlogger.service'; +import { HelpContextualValues } from '../help-contextual/help-contextual.service'; import { SideNavigationExtension, SideNavigationItem } from './side-navigation-view-interfaces'; @Component({ selector: 'imx-side-navigation-view', templateUrl: './side-navigation-view.component.html', - styleUrls: ['./side-navigation-view.component.scss'], }) export class SideNavigationViewComponent implements OnDestroy { @Input() public baseUrl = ''; @Input() public isAdmin = false; @Input() public componentName = ''; @Input() public componentTitle = ''; - @Input() public contextId:string; - _navItems: SideNavigationExtension[] = []; - get navItems(): SideNavigationExtension[] { + @Input() public contextId: HelpContextualValues; + _navItems: (SideNavigationExtension | undefined)[] = []; + get navItems(): (SideNavigationExtension | undefined)[] { return this._navItems; } - @Input() set navItems(value: SideNavigationExtension[]) { + @Input() set navItems(value: (SideNavigationExtension | undefined)[]) { this._navItems = value; if (value.length > 0) { this.setupNavItems(); this.handleRouteParam(); } } - get isMobile(): boolean { - return document.body.offsetWidth <= 768; - } public navigationItems: SideNavigationItem[] = []; public selectedPage: string = ''; public mobileSideNavExpanded = false; public showBackdrop = false; - public contentMargin = this.isMobile ? '58px' : '230px'; + public contentMargin = isMobile() ? '58px' : '230px'; @ViewChild('sideNavContent', { read: ViewContainerRef }) protected sideNavContentRef: ViewContainerRef; protected routerEvents$: Subscription; - constructor(private readonly logger: ClassloggerService, private readonly router: Router, private readonly route: ActivatedRoute, private cdref: ChangeDetectorRef) { + constructor( + private readonly logger: ClassloggerService, + private readonly router: Router, + private readonly route: ActivatedRoute, + private cdref: ChangeDetectorRef, + ) { this.routerEvents$ = this.router.events.subscribe(async (val) => { if (this.navItems.length > 0 && val instanceof NavigationEnd) { this.handleRouteParam(); @@ -75,7 +78,7 @@ export class SideNavigationViewComponent implements OnDestroy { @HostListener('window:resize') public onResize(): void { - this.showBackdrop = this.isMobile && this.mobileSideNavExpanded; + this.showBackdrop = isMobile() && this.mobileSideNavExpanded; setTimeout(() => this.setContentMargin(), 50); } @@ -87,12 +90,12 @@ export class SideNavigationViewComponent implements OnDestroy { public toggleMobileExpand(): void { this.mobileSideNavExpanded = !this.mobileSideNavExpanded; - const showBackdrop = this.isMobile && this.mobileSideNavExpanded; + const showBackdrop = isMobile() && this.mobileSideNavExpanded; setTimeout( () => { this.showBackdrop = showBackdrop; }, - showBackdrop ? 0 : 500 + showBackdrop ? 0 : 500, ); } @@ -103,7 +106,7 @@ export class SideNavigationViewComponent implements OnDestroy { return; } else { this.router.navigate([this.baseUrl, page]); - if (this.isMobile) { + if (isMobile()) { this.toggleMobileExpand(); } } @@ -112,21 +115,21 @@ export class SideNavigationViewComponent implements OnDestroy { private async setupNavItems(): Promise { this.navigationItems = []; for (const item of this.navItems) { - if (!item) { + if (item == null) { continue; } const navItem = { name: item.name, translationKey: item.caption, - icon: item.icon, + icon: item.icon ?? '', }; this.navigationItems.push(navItem); } } private setContentMargin(): void { - this.contentMargin = !this.isMobile ? '230px' : '58px'; + this.contentMargin = !isMobile() ? '230px' : '58px'; } private loadComponent(): void { @@ -151,31 +154,33 @@ export class SideNavigationViewComponent implements OnDestroy { this.cdref.detectChanges(); this.sideNavContentRef.clear(); const selectedPageItem = selectedItem; - const component = this.sideNavContentRef.createComponent(selectedPageItem.instance); - component.instance.data = selectedPageItem.data; - component.instance.isAdmin = this.isAdmin; - if(!!selectedPageItem.contextId){ - component.instance.contextId = selectedPageItem.contextId; + if (selectedPageItem.instance) { + const component = this.sideNavContentRef.createComponent(selectedPageItem.instance); + component.instance.data = selectedPageItem.data; + component.instance.isAdmin = this.isAdmin; + if (!!selectedPageItem.contextId) { + component.instance.contextId = selectedPageItem.contextId; + } } } private handleRouteParam(): void { const tab = this.route.snapshot.paramMap.get('tab'); if (!tab) { - this.router.navigate([this.navItems[0].name], { relativeTo: this.route }); + this.router.navigate([this.navItems[0]?.name], { relativeTo: this.route }); } else { - this.selectedPage = tab ? tab : this.navItems[0].name; + this.selectedPage = tab ? tab : this.navItems[0]?.name || ''; this.loadComponent(); } } - private getItem(name: string, list: SideNavigationExtension[]): SideNavigationExtension { + private getItem(name: string, list: (SideNavigationExtension | undefined)[]): SideNavigationExtension | null { if (list == null) { return null; } for (var item of list) { - if (item.name === name) { + if (item?.name === name) { return item; } } diff --git a/imxweb/projects/qbm/src/lib/side-navigation-view/side-navigation-view.module.ts b/imxweb/projects/qbm/src/lib/side-navigation-view/side-navigation-view.module.ts index 1a2b06562..4539ae499 100644 --- a/imxweb/projects/qbm/src/lib/side-navigation-view/side-navigation-view.module.ts +++ b/imxweb/projects/qbm/src/lib/side-navigation-view/side-navigation-view.module.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR diff --git a/imxweb/projects/qbm/src/lib/sidenav-tree/custom-tree-control.component.html b/imxweb/projects/qbm/src/lib/sidenav-tree/custom-tree-control.component.html new file mode 100644 index 000000000..0c7b1db0b --- /dev/null +++ b/imxweb/projects/qbm/src/lib/sidenav-tree/custom-tree-control.component.html @@ -0,0 +1,111 @@ + + + + + +
    + + +
    +
    + + +
    + + +
    +
    + +
    +
    +
    + + + + + +
    + + {{ noResultText | translate }} +
    + + +
    + + +
    +
    + + +
    + + + +
    +
    + +
    +
    +
    + + +
    +
    + + + + diff --git a/imxweb/projects/qbm/src/lib/sidenav-tree/custom-tree-control.component.scss b/imxweb/projects/qbm/src/lib/sidenav-tree/custom-tree-control.component.scss new file mode 100644 index 000000000..707c50f3d --- /dev/null +++ b/imxweb/projects/qbm/src/lib/sidenav-tree/custom-tree-control.component.scss @@ -0,0 +1,48 @@ +@import '@elemental-ui/core/src/styles/_eui_palette.scss'; + +:host { + height: 100%; + border-radius: 4px; + flex: 1 1 auto; + overflow: hidden; +} + +.imx-scroll-pad > .eui-scroll-container { + padding-left: 5px; +} +mat-tree-node[aria-level="1"]{ + .mdc-button{ + font-weight: 700; + } +} +mat-tree-node[aria-level="2"]{ + .mdc-button{ + font-weight: 600; + } +} +mat-tree-node{ + .mdc-button{ + font-weight: 400; + } +} +mat-nested-tree-node[aria-level="1"]{ + .mat-tree-node{ + .mdc-button{ + font-weight: 700; + } + } + mat-tree-node, mat-nested-tree-node[aria-level="2"]{ + .mat-tree-node{ + .mdc-button{ + font-weight: 600; + } + } + mat-tree-node, mat-nested-tree-node{ + .mat-tree-node{ + .mdc-button{ + font-weight: 400; + } + } + } + } +} diff --git a/imxweb/projects/qbm/src/lib/sidenav-tree/custom-tree-control.component.ts b/imxweb/projects/qbm/src/lib/sidenav-tree/custom-tree-control.component.ts new file mode 100644 index 000000000..9a31e8222 --- /dev/null +++ b/imxweb/projects/qbm/src/lib/sidenav-tree/custom-tree-control.component.ts @@ -0,0 +1,152 @@ +/* + * ONE IDENTITY LLC. PROPRIETARY INFORMATION + * + * This software is confidential. One Identity, LLC. or one of its affiliates or + * subsidiaries, has supplied this software to you under terms of a + * license agreement, nondisclosure agreement or both. + * + * You may not copy, disclose, or use this software except in accordance with + * those terms. + * + * + * Copyright 2024 One Identity LLC. + * ALL RIGHTS RESERVED. + * + * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR + * WARRANTIES ABOUT THE SUITABILITY OF THE SOFTWARE, + * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED + * TO THE IMPLIED WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE, OR + * NON-INFRINGEMENT. ONE IDENTITY LLC. SHALL NOT BE + * LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE + * AS A RESULT OF USING, MODIFYING OR DISTRIBUTING + * THIS SOFTWARE OR ITS DERIVATIVES. + * + */ + +import { FlatTreeControl, NestedTreeControl } from '@angular/cdk/tree'; +import { CommonModule } from '@angular/common'; +import { Component, EventEmitter, Input, OnChanges, Output, SimpleChanges, TemplateRef } from '@angular/core'; +import { MatTreeModule, MatTreeNestedDataSource } from '@angular/material/tree'; +import { EuiCoreModule, EuiMaterialModule } from '@elemental-ui/core'; +import { TranslateModule } from '@ngx-translate/core'; +import { DynamicDataSource } from './sidenav-tree-dynamic-extension'; + +/** + * Handles creating a responsive nested sidenav tree. + * + * + * Requires: + * @param {MatTreeNestedDataSource} dataSource: Static datasource with all data available at once, use dynamicDatasource otherwise. + * @param {DynamicDataSource} dynamicDataSource: Dynamic datasource for loading more data incrementally. + * @param {NestedTreeControl | FlatTreeControl} treeControl: Controls tree behavior. + * @param {string} headerText: Text that will appear on side and at top of sidenav. + * @param {TemplateRef} nodeContent: A template ref of how the node of the tree will look. + * + * Optional: + * @param {boolean} [sideNavExpanded=false] Sets whether the sidenav is open or closed initially, defaults to false. + * @param {boolean} [manageExpandedExternally=false] This prevents the internal sideNavExpanded management and requires the sideNavExpanded to be managed externally. This allows additional logic to be stuck in between. Defaults to false. + * @param {string} [expandWidth="600px"] Set the width of the expansion, according to material avoid percent based widths. Default is '600px' + + * @param {Function} [hasChild] Function to determine if a node has children or not. By default uses the children property. + * @param {Function} [isSelected] Function to determine if a node is currently selected. By default uses the isSelected property. + * @param {Function} [isLoading] Function to indicate if a node is currently getting children from the server. + * @param {boolean} [showSidenavHeader=true] Indicates if we should have the header and mat card present or not. Defaults to true. + * @param {string} [noResultText] The text shown in case of no search results + + + */ +@Component({ + selector: 'imx-custom-tree-control', + templateUrl: './custom-tree-control.component.html', + styleUrls: ['./custom-tree-control.component.scss'], + standalone: true, + imports: [CommonModule, MatTreeModule, EuiCoreModule, EuiMaterialModule, TranslateModule], +}) +export class CustomTreeControlComponent implements OnChanges { + public isLoadingMore: boolean; + private searchEnabled = false; + + // Required input + // Either dataSource as a MatTreeNestedDataSource + @Input() public dataSource: MatTreeNestedDataSource; + + // Or dynamicDataSource as a DynamicDataSource + @Input() public dynamicDataSource: DynamicDataSource; + + // treeControl as a NestedTreeControl + @Input() public treeControl: NestedTreeControl | FlatTreeControl; + + // nodeContent will a template rendered inside each node and it uses a node variable. + @Input() public nodeContent: TemplateRef; + + // Function used to determine if there are children under the node, defaults to look for a children property of length > 0. + @Input() public hasChild = (_: number, node: any) => node?.children && node.children.length > 0; + + // Function used to determine if the node is currently selected, this value is maintained outside this component + @Input() public isSelected = (node: any) => node.isSelected; + + // Function used to determine if the node is loading children, this value is maintained outside this component + @Input() public isLoading = (node: any) => false; + + // Text to show when search is empty + @Input() public noResultText = '#LDS#There are no items matching your search.'; + + // selectedNode outputs the node that was chosen + @Output() public selectedNode = new EventEmitter(); + + public async ngOnChanges(changes: SimpleChanges): Promise { + if (changes['database']) { + console.log('Need to refresh tree'); + } + } + + get initializingData(): boolean { + return this.dynamicDataSource?.initializingData; + } + + get hasData(): boolean { + return this.dynamicDataSource?.hasData; + } + + get canLoadMore(): boolean { + return this.dynamicDataSource?.canLoadMore; + } + + public get anyNodeOpen(): boolean { + return this.dynamicDataSource + ? this.dynamicDataSource.isRootNodeOpen || this.dynamicDataSource.isSearch + : this.treeControl.expansionModel.selected.length > 0; + } + + public closeAllNodes(): void { + this.treeControl.collapseAll(); + } + + public selectNode(node: any): void { + if (this.dynamicDataSource) { + this.dynamicDataSource.setSelection(node); + } + this.selectedNode.emit(node); + } + + public async onLoadMore(): Promise { + this.isLoadingMore = true; + try { + await this.dynamicDataSource.loadMore(); + } finally { + this.isLoadingMore = false; + } + } + + public enableSearch(): void { + this.searchEnabled = true; + } + public async onSearch(): Promise { + if (this.initializingData) { + return; + } + + await this.dynamicDataSource.onSearch(); + } +} diff --git a/imxweb/projects/qbm/src/lib/sidenav-tree/sidenav-tree-dynamic-extension.ts b/imxweb/projects/qbm/src/lib/sidenav-tree/sidenav-tree-dynamic-extension.ts index 1abd43006..19e2eb313 100644 --- a/imxweb/projects/qbm/src/lib/sidenav-tree/sidenav-tree-dynamic-extension.ts +++ b/imxweb/projects/qbm/src/lib/sidenav-tree/sidenav-tree-dynamic-extension.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -26,8 +26,8 @@ import { CollectionViewer, SelectionChange } from '@angular/cdk/collections'; import { FlatTreeControl } from '@angular/cdk/tree'; -import { CollectionLoadParameters } from 'imx-qbm-dbts'; -import { BehaviorSubject, merge, Observable, Subscription } from 'rxjs'; +import { CollectionLoadParameters } from '@imx-modules/imx-qbm-dbts'; +import { BehaviorSubject, Observable, Subscription, merge } from 'rxjs'; import { concatMap, map } from 'rxjs/operators'; import { DataSourceToolbarSettings } from '../data-source-toolbar/data-source-toolbar-settings'; @@ -44,7 +44,7 @@ export class DynamicDataApiControls { export class DynamicDataSource { public dataChange = new BehaviorSubject([]); public initializingData: boolean; - public dstSettings: DataSourceToolbarSettings; + public dstSettings: DataSourceToolbarSettings | undefined; public selectedNode: T; private totalCount: number; @@ -74,14 +74,19 @@ export class DynamicDataSource { } public get isSearch(): boolean { - return this.dstSettings?.navigationState.search?.length > 0; + return !!this.dstSettings?.navigationState?.search?.length; } + constructor( + private _treeControl: FlatTreeControl, + private _apiControls: DynamicDataApiControls, + ) {} + public async setup(expandRoot?: boolean): Promise { this.initializingData = true; try { const response = await this._apiControls.setup(); - this.totalCount = response?.totalCount; + this.totalCount = response?.totalCount ?? 0; this.rootNode = response.rootNode; this.dstSettings = response?.dstSettings; this.init(); @@ -101,15 +106,25 @@ export class DynamicDataSource { } public async loadMore(): Promise { - let nodes: T[]; + let nodes: T[] = []; if (this.isSearch) { - this.dstSettings.navigationState.StartIndex = this.data.length; - nodes = (await this._apiControls.search(this.dstSettings.navigationState)).searchNodes; - nodes = this._apiControls.changeSelection(nodes, this.selectedNode); + if (this.dstSettings) { + this.dstSettings.navigationState.StartIndex = this.data.length; + } + if (this._apiControls.search) { + nodes = (await this._apiControls.search(this.dstSettings?.navigationState ?? {})).searchNodes; + } + if (this._apiControls.changeSelection) { + nodes = this._apiControls.changeSelection(nodes, this.selectedNode); + } this.data.push(...nodes); } else { - nodes = await this._apiControls.loadMore(this.rootNode); - nodes = this._apiControls.changeSelection(nodes, this.selectedNode); + if (this._apiControls.loadMore) { + nodes = await this._apiControls.loadMore(this.rootNode); + } + if (this._apiControls.changeSelection) { + nodes = this._apiControls.changeSelection(nodes, this.selectedNode); + } const index = this.findEndOfChildren(this.rootNode); this.data.splice(index + 1, 0, ...nodes); @@ -122,9 +137,11 @@ export class DynamicDataSource { if (!this._apiControls.search || !this._apiControls.changeSelection) { throw Error('No remote search functionality has been defined.'); } - this.initializingData = true; - this.dstSettings.navigationState.StartIndex = 0; + this.initializingData = true; + if (this.dstSettings) { + this.dstSettings.navigationState.StartIndex = 0; + } // If we don't have cached data, and we are searching, cache if (!this.cachedData && this.isSearch) { this.cachedData = { @@ -143,16 +160,18 @@ export class DynamicDataSource { this.cachedData = null; } else { // Proceed with normal search - const response = await this._apiControls.search(this.dstSettings.navigationState); + const response = await this._apiControls.search(this.dstSettings?.navigationState ?? {}); if (!response) { // Here the search was aborted, so we return nothing return; } - this.totalCount = response?.totalCount; - const nodes = this._apiControls.changeSelection(response.searchNodes, this.selectedNode); + this.totalCount = response?.totalCount ?? 0; + const nodes = this._apiControls.changeSelection + ? this._apiControls.changeSelection(response?.searchNodes ?? [], this.selectedNode) + : []; this.currentCount = nodes.length; if (nodes.length > 0) { - this.rootNode = response.rootNode || this.rootNode; + this.rootNode = response?.rootNode || this.rootNode; this.nextData([this.rootNode, ...nodes]); this._treeControl.expand(this.rootNode); } else { @@ -160,6 +179,7 @@ export class DynamicDataSource { } } } + /** * Emits data and turns off the loading spinner * @param data that will be emitted as the next data state @@ -169,8 +189,6 @@ export class DynamicDataSource { this.initializingData = false; } - constructor(private _treeControl: FlatTreeControl, private _apiControls: DynamicDataApiControls) {} - public connect(collectionViewer: CollectionViewer): Observable { this.subscriptions$.push( this._treeControl.expansionModel.changed @@ -179,13 +197,13 @@ export class DynamicDataSource { if (treeDataHasChanged) { this.dataChange.next(this.data); } - }) + }), ); return merge(collectionViewer.viewChange, this.dataChange).pipe( map(() => { return this.data; - }) + }), ); } @@ -203,7 +221,7 @@ export class DynamicDataSource { change.removed .slice() .reverse() - .map((node) => this.toggleNode(node, false)) + .map((node) => this.toggleNode(node, false)), ) ).some((val) => val); } @@ -261,10 +279,10 @@ export class DynamicDataSource { } public setSelection(node: T): void { - const nodes = this._apiControls.changeSelection(this.data, node); + const nodes = this._apiControls.changeSelection ? this._apiControls.changeSelection(this.data, node) : []; this.dataChange.next(nodes); if (this.cachedData) { - this.cachedData.data = this._apiControls.changeSelection(this.cachedData.data, node); + this.cachedData.data = this._apiControls.changeSelection ? this._apiControls.changeSelection(this.cachedData.data, node) : []; } this.selectedNode = node; } diff --git a/imxweb/projects/qbm/src/lib/sidenav-tree/sidenav-tree.component.html b/imxweb/projects/qbm/src/lib/sidenav-tree/sidenav-tree.component.html index 0c7ae3a93..2958e7ee1 100644 --- a/imxweb/projects/qbm/src/lib/sidenav-tree/sidenav-tree.component.html +++ b/imxweb/projects/qbm/src/lib/sidenav-tree/sidenav-tree.component.html @@ -1,19 +1,18 @@ - -
    -
    -

    {{ headerText }}

    + +
    +
    +

    {{ headerText }}

    [searchBoxText]="'#LDS#Search' | translate" [useThemedStyle]="true" (search)="onSearch($event)" - (navigationStateChanged)="onSearch()" + (navigationStateChanged)="onSearch($event.search ?? '')" >

    - - - - -
    - - -
    -
    - - -
    - - -
    -
    - -
    -
    -
    -
    - - - - -
    - - {{ noResultText | translate }} -
    - - -
    - - -
    -
    - - -
    - - - -
    -
    - -
    -
    -
    - - -
    +
    diff --git a/imxweb/projects/qbm/src/lib/sidenav-tree/sidenav-tree.component.scss b/imxweb/projects/qbm/src/lib/sidenav-tree/sidenav-tree.component.scss index 97c4f821a..a9e49532d 100644 --- a/imxweb/projects/qbm/src/lib/sidenav-tree/sidenav-tree.component.scss +++ b/imxweb/projects/qbm/src/lib/sidenav-tree/sidenav-tree.component.scss @@ -1,284 +1,6 @@ -@import "@elemental-ui/core/src/styles/_eui_palette.scss"; +@import '@elemental-ui/core/src/styles/_eui_palette.scss'; :host { height: 100%; border-radius: 4px; - - ::ng-deep .mat-drawer-inner-container { - overflow: hidden; - } -} - -.snavigation { - height: 100%; - padding: 0; - - .mat-sidenav-container { - height: 100%; - border-radius: 4px; - - .mat-sidenav { - width: 100%; - overflow: hidden; - border-radius: 4px; - - .snavigation-side { - display: flex; - flex-direction: column; - height: 100%; - - .snavigation-side-toggle { - display: flex; - justify-content: flex-end; - margin: 5px 0; - - .snavigation-side-toggle-header { - margin: auto; - margin-left: 24px; - font-size: 16px; - line-height: 20px; - font-weight: 600; - } - - .toolbar--hidden { - width: 0; - } - - .expand-control-button { - ::ng-deep .mat-button-wrapper { - width: 100%; - height: 100%; - display: flex; - flex-direction: column; - justify-content: center; - } - - .rotate-90 { - margin: auto; - rotate: -90deg; - translate: 0 100%; - width: 1px; // prevent content from overflowing - -webkit-backface-visibility: hidden; // Handle the anti-aliasing from chrome on rotations - font-size: 16px; - } - } - } - - .snavigation-side-content--center { - justify-content: center; - display: flex; - align-items: center; - } - - .imx-no-data { - display: flex; - flex-direction: column; - align-items: center; - - eui-icon { - font-size: 100px; - line-height: 100px; - } - } - - .snavigation-side-content { - height: 100%; - overflow: auto; - margin: 0 24px 24px; - - mat-tree { - background-color: transparent; - } - - .mat-tree-node { - border-radius: 4px; - - .child-progress-bar { - margin-left: 10px; - max-width: 60%; - } - } - - /* - * This padding sets alignment of the nested nodes. - */ - .tree .mat-nested-tree-node div[role=group] { - margin-left: 20px; - } - - .tree-item-button { - width: 100%; - padding: 0; - color: unset; - text-overflow: ellipsis; - white-space: nowrap; - overflow: hidden; - - ::ng-deep .mat-button-wrapper { - display: flex; - align-items: center; - } - } - .tree-invisible { - display: none; - } - } - } - - &:not(.snavigation-side--expanded) { - .snavigation-side-toggle { - height: 100%; - } - .snavigation-side-toggle-header, .snavigation-side-content { - display: none; - } - .expand-control-button { - width: 48px; - padding: 0; - min-width: unset; - } - } - - &:is(.snavigation-side--expanded) { - .snavigation-side-toggle{ - align-items: center; - } - - .expand-control-button { - margin-right: 16px; - } - .rotate-90 { - display: none; - } - } - } - - .mat-sidenav-content { - padding: 32px; - position: relative; - display: flex; - flex-direction: column; - } - - // .mat-drawer-side seems to have a scss style - seems to leak from material - .mat-drawer-side { - border-right: none; - } - } - &.mat-card--hidden{ - .mat-sidenav-container{ - .mat-sidenav{ - .snavigation-side{ - .snavigation-side-content{ - margin: 0; - } - } - } - } - } -} - -// Theming -:host { - .snavigation-side-toggle-header { - color: $color-gray-60; - } - - .snavigation.snavigation--expanded { - border: 1px solid $color-gray-20; - &.mat-card--hidden{ - border:none; - box-shadow: none; - } - } - - .mat-sidenav:not(.snavigation-side--expanded) { - .expand-control-button { - background-color: $color-blue-10; - border: 1px solid $color-blue-20; - } - } - .snavigation-side-content { - background-color: $color-blue-10; - border: 1px solid $color-blue-20; - } - .mat-tree-node--selected { - background-color: $color-gray-0; - border: 1px solid $color-blue-40; - color: $color-orange-60; - } - - .imx-no-data { - eui-icon, span { - color: $color-gray-60; - } - } -} - -.eui-dark-theme { - :host { - .snavigation-side-toggle-header { - color: $color-gray-20; - } - - .snavigation.snavigation--expanded { - border: 1px solid $color-gray-60; - } - - .mat-sidenav:not(.snavigation-side--expanded) { - .expand-control-button { - background-color: $color-blue-90; - border: 1px solid $color-blue-80; - } - } - .snavigation-side-content { - background-color: $color-blue-90; - border: 1px solid $color-blue-80; - } - .mat-tree-node--selected { - background-color: $color-gray-80; - border: 1px solid $color-blue-40; - color: $color-orange-40; - } - - .imx-no-data { - eui-icon, span { - color: $color-gray-20; - } - } - } -} - -.eui-contrast-theme { - :host { - .snavigation-side-toggle-header { - color: $color-gray-0; - } - - .snavigation.snavigation--expanded { - border: 1px solid $color-gray-60; - } - - .mat-sidenav:not(.snavigation-side--expanded) { - .expand-control-button { - background-color: $color-gray-90; - border: 1px solid $color-gray-0; - } - } - .snavigation-side-content { - background-color: $color-gray-90; - border: 1px solid $color-gray-0; - } - .mat-tree-node--selected { - background-color: $color-gray-80; - border: 1px solid $color-gray-0; - color: $color-gray-0; - } - - .imx-no-data { - eui-icon, span { - color: $color-gray-0; - } - } - } } diff --git a/imxweb/projects/qbm/src/lib/sidenav-tree/sidenav-tree.component.ts b/imxweb/projects/qbm/src/lib/sidenav-tree/sidenav-tree.component.ts index 32a879a32..dfd1e6c5b 100644 --- a/imxweb/projects/qbm/src/lib/sidenav-tree/sidenav-tree.component.ts +++ b/imxweb/projects/qbm/src/lib/sidenav-tree/sidenav-tree.component.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -26,8 +26,14 @@ import { animate, animateChild, group, query, state, style, transition, trigger } from '@angular/animations'; import { FlatTreeControl, NestedTreeControl } from '@angular/cdk/tree'; -import { Component, Input, Output, EventEmitter, TemplateRef, SimpleChanges, OnChanges } from '@angular/core'; -import { MatTreeNestedDataSource } from '@angular/material/tree'; +import { CommonModule } from '@angular/common'; +import { Component, EventEmitter, Input, OnChanges, Output, SimpleChanges, TemplateRef } from '@angular/core'; +import { MatSidenavModule } from '@angular/material/sidenav'; +import { MatTreeModule, MatTreeNestedDataSource } from '@angular/material/tree'; +import { EuiCoreModule, EuiMaterialModule } from '@elemental-ui/core'; +import { TranslateModule } from '@ngx-translate/core'; +import { DataSourceToolbarModule } from '../data-source-toolbar/data-source-toolbar.module'; +import { CustomTreeControlComponent } from './custom-tree-control.component'; import { DynamicDataSource } from './sidenav-tree-dynamic-extension'; /** @@ -58,13 +64,24 @@ import { DynamicDataSource } from './sidenav-tree-dynamic-extension'; selector: 'imx-sidenav-tree', templateUrl: './sidenav-tree.component.html', styleUrls: ['./sidenav-tree.component.scss'], + standalone: true, + imports: [ + CommonModule, + MatTreeModule, + EuiCoreModule, + EuiMaterialModule, + MatSidenavModule, + TranslateModule, + DataSourceToolbarModule, + CustomTreeControlComponent, + ], animations: [ trigger('expandDiv', [ state( 'closed', style({ width: '48px', - }) + }), ), state('opened', style({ width: '{{ expandWidth }}' }), { params: { expandWidth: '*' } }), transition('* <=> *', [ @@ -83,13 +100,13 @@ import { DynamicDataSource } from './sidenav-tree-dynamic-extension'; 'closed', style({ rotate: '180deg', - }) + }), ), state( 'opened', style({ rotate: '0deg', - }) + }), ), transition('* <=> *', animate('400ms ease')), ]), @@ -99,7 +116,7 @@ import { DynamicDataSource } from './sidenav-tree-dynamic-extension'; style({ width: '0px', visibility: 'hidden', - }) + }), ), state( 'opened', @@ -107,14 +124,14 @@ import { DynamicDataSource } from './sidenav-tree-dynamic-extension'; width: '320px', visibility: 'visible', }), - { params: { expandWidth: '*' } } + { params: { expandWidth: '*' } }, ), state( 'hidden', style({ width: 0, visibility: 'hidden', - }) + }), ), transition('* <=> *', [group([query('@fadeIcon', animateChild(), { optional: true }), animate('400ms ease')])]), ]), @@ -125,7 +142,7 @@ import { DynamicDataSource } from './sidenav-tree-dynamic-extension'; opacity: '0', width: '0px', visibility: 'hidden', - }) + }), ), state( 'closed', @@ -133,14 +150,14 @@ import { DynamicDataSource } from './sidenav-tree-dynamic-extension'; opacity: '1', width: '40px', visibility: 'visible', - }) + }), ), state( 'hidden', style({ width: 0, visibility: 'hidden', - }) + }), ), transition('* <=> *', animate('400ms ease')), ]), @@ -183,7 +200,7 @@ export class SidenavTreeComponent implements OnChanges { @Input() public isSelected = (node: any) => node.isSelected; // Function used to determine if the node is loading children, this value is maintained outside this component - @Input() public isLoading = (node: any) => false; + @Input() public isLoading: (node: any) => boolean = (node: any) => false; // Remove the header and hide the mat-card style in false state @Input() public showSidenavHeader = true; @@ -191,6 +208,9 @@ export class SidenavTreeComponent implements OnChanges { // Text to show when search is empty @Input() public noResultText = '#LDS#There are no items matching your search.'; + // hides the expand icon + @Input() public hideExpandButton = false; + // Output // Emits when the sidenav state changed @Output() public sideNavExpandedChange = new EventEmitter(); diff --git a/imxweb/projects/qbm/src/lib/snackbar/snack-bar.service.ts b/imxweb/projects/qbm/src/lib/snackbar/snack-bar.service.ts index 3afea22e9..b1a28c92a 100644 --- a/imxweb/projects/qbm/src/lib/snackbar/snack-bar.service.ts +++ b/imxweb/projects/qbm/src/lib/snackbar/snack-bar.service.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -33,12 +33,12 @@ import { LdsReplacePipe } from '../lds-replace/lds-replace.pipe'; import { TextContainer } from '../translation/text-container'; @Injectable({ - providedIn: 'root' + providedIn: 'root', }) export class SnackBarService { private readonly defaultConfig: MatSnackBarConfig = { duration: 5000, - verticalPosition: 'top' + verticalPosition: 'top', }; private message = ''; private action = ''; @@ -47,16 +47,20 @@ export class SnackBarService { constructor( private readonly snackbar: MatSnackBar, private readonly translationProvider: TranslateService, - private readonly ldsReplace: LdsReplacePipe - ) { } + private readonly ldsReplace: LdsReplacePipe, + ) {} - public open(messageText: TextContainer, actionText: string = this.actionDismissCaption, config?: MatSnackBarConfig) - : MatSnackBarRef { - this.translationProvider.get(messageText.key) - .pipe(map((value: string) => messageText.parameters ? this.ldsReplace.transform(value, ...messageText.parameters) : value)) - .subscribe((value: string) => this.message = value); + public open( + messageText: TextContainer, + actionText: string = this.actionDismissCaption, + config?: MatSnackBarConfig, + ): MatSnackBarRef { + this.translationProvider + .get(messageText.key) + .pipe(map((value: string) => (messageText.parameters ? this.ldsReplace.transform(value, ...messageText.parameters) : value))) + .subscribe((value: string) => (this.message = value)); - this.translationProvider.get(actionText).subscribe((value: string) => this.action = value); + this.translationProvider.get(actionText).subscribe((value: string) => (this.action = value)); return this.snackbar.open(this.message, this.action, { ...this.defaultConfig, ...config }); } diff --git a/imxweb/projects/qbm/src/lib/splash/splash.service.ts b/imxweb/projects/qbm/src/lib/splash/splash.service.ts index 45ad0b619..66eb5be6d 100644 --- a/imxweb/projects/qbm/src/lib/splash/splash.service.ts +++ b/imxweb/projects/qbm/src/lib/splash/splash.service.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -24,32 +24,28 @@ * */ - import { Injectable } from '@angular/core'; import { EuiSplashScreenConfig, EuiSplashScreenOptions, EuiSplashScreenService } from '@elemental-ui/core'; @Injectable({ - providedIn: 'root' + providedIn: 'root', }) export class SplashService { - private defaultOptions: EuiSplashScreenConfig = { applicationName: 'One Identity Manager', icon: 'oi-horizontal', showSpinner: true, - message: 'Loading...' + message: 'Loading...', }; - constructor( - private readonly splash: EuiSplashScreenService, - ) { } + constructor(private readonly splash: EuiSplashScreenService) {} public init(options: EuiSplashScreenOptions): void { // open splash screen with fix values const config = { ...this.defaultOptions, - ...options - }; + ...options, + }; this.splash.open(config); } diff --git a/imxweb/projects/qbm/src/lib/sqlwizard/SqlNodeView.ts b/imxweb/projects/qbm/src/lib/sqlwizard/SqlNodeView.ts index 41b18372b..5b3a2f01e 100644 --- a/imxweb/projects/qbm/src/lib/sqlwizard/SqlNodeView.ts +++ b/imxweb/projects/qbm/src/lib/sqlwizard/SqlNodeView.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -25,129 +25,142 @@ */ import { EventEmitter } from '@angular/core'; -import { SqlExpression, LogOp, SqlColumnTypes, FilterProperty } from 'imx-qbm-dbts'; +import { FilterProperty, LogOp, SqlColumnTypes, SqlExpression } from '@imx-modules/imx-qbm-dbts'; import { SqlWizardApiService } from './sqlwizard-api.service'; export class SqlViewSettings { - - public root: SqlViewRoot; - constructor( - public readonly sqlWizardService: SqlWizardApiService, - tableName: string, - rootExpression?: SqlExpression) { - let expr = rootExpression; - if (!expr) { - expr = { - Expressions: [], - LogOperator: LogOp.AND - }; - } - - this.root = new SqlViewRoot(this, tableName, expr); + public root: SqlViewRoot; + constructor( + public readonly sqlWizardService: SqlWizardApiService, + tableName: string, + rootExpression?: SqlExpression, + ) { + let expr = rootExpression; + if (!expr) { + expr = { + Expressions: [], + LogOperator: LogOp.AND, + Negate: false, + }; } + + this.root = new SqlViewRoot(this, tableName, expr); + } } export interface ISqlNodeView { - readonly childViews: SqlNodeView[]; - Data: SqlExpression; - replaceChildNode(oldNode: SqlExpression, newData: SqlExpression): void; - addChildNode(): Promise; + readonly childViews: SqlNodeView[]; + Data: SqlExpression; + replaceChildNode(oldNode: SqlExpression, newData: SqlExpression): void; + addChildNode(): Promise; } abstract class SqlViewBase implements ISqlNodeView { - - get childViews(): SqlNodeView[] { - return this.views; + get childViews(): SqlNodeView[] { + return this.views; + } + + private views: SqlNodeView[] = []; + + constructor( + public readonly viewSettings: SqlViewSettings, + public tableName: string, + public Data: SqlExpression, + public Property: FilterProperty | undefined, + ) { + this.views = this.buildViews(); + } + + // how to listen to a change of Data.PropertyId without re-implementing the SqlExpression interface? + public readonly columnChanged: EventEmitter = new EventEmitter(); + + public async prepare(): Promise { + if (!this.Property && this.Data.PropertyId) { + // load property + const props = (await this.viewSettings.sqlWizardService.getFilterProperties(this.tableName)).filter( + (n) => n.PropertyId == this.Data.PropertyId, + ); + this.Property = props.length > 0 ? props[0] : undefined; } - - private views: SqlNodeView[] = []; - - constructor(public readonly viewSettings: SqlViewSettings, - public tableName: string, - public Data: SqlExpression, - public Property: FilterProperty) { - this.views = this.buildViews(); + // prepare recursively + for (let child of this.views) { + await child.prepare(); } - - // how to listen to a change of Data.PropertyId without re-implementing the SqlExpression interface? - public readonly columnChanged: EventEmitter = new EventEmitter(); - - public async prepare(): Promise { - if (!this.Property && this.Data.PropertyId) { - // load property - const props = (await this.viewSettings.sqlWizardService.getFilterProperties(this.tableName)) - .filter(n => n.PropertyId == this.Data.PropertyId); - this.Property = props.length > 0 ? props[0] : null; - } - // prepare recursively - for (let child of this.views) { - await child.prepare(); - } + } + + public async addChildNode(): Promise { + const e = { + LogOperator: LogOp.AND, + Expressions: [], + Negate: false, + }; + if (!this.Data.Expressions) { + this.Data.Expressions = []; } - - public async addChildNode(): Promise { - const e = { - LogOperator: LogOp.AND, - Expressions: [], - }; - this.Data.Expressions.push(e); - this.childViews.push(new SqlNodeView(this.viewSettings, this, this.tableName, e, null)); + this.Data.Expressions.push(e); + this.childViews.push(new SqlNodeView(this.viewSettings, this, this.tableName, e, undefined)); + } + + public replaceChildNode(oldNode: SqlExpression, newData: SqlExpression) { + const currentExprIndex = this.Data.Expressions?.indexOf(oldNode) ?? -1; + if (currentExprIndex < 0) { + throw Error('Expected to find child node in array.'); } - - public replaceChildNode(oldNode: SqlExpression, newData: SqlExpression) { - const currentExprIndex = this.Data.Expressions.indexOf(oldNode); - if (currentExprIndex < 0) { - throw Error('Expected to find child node in array.'); - } - - this.Data.Expressions[currentExprIndex] = newData; + if (this.Data.Expressions) { + this.Data.Expressions[currentExprIndex] = newData; } + } - private buildViews(): SqlNodeView[] { - let exp = this.Data.Expressions; - if (!exp) { - return []; - } + private buildViews(): SqlNodeView[] { + let exp = this.Data.Expressions; + if (!exp) { + return []; + } - const result = new Array(exp.length); + const result = new Array(exp.length); - exp.forEach((e, idx) => { - let view = new SqlNodeView(this.viewSettings, this, this.tableName, e, null); - result[idx] = view; - }); + exp.forEach((e, idx) => { + let view = new SqlNodeView(this.viewSettings, this, this.tableName, e, undefined); + result[idx] = view; + }); - return result; - } + return result; + } } export class SqlViewRoot extends SqlViewBase implements ISqlNodeView { - constructor(viewSettings: SqlViewSettings, tableName: string, Data: SqlExpression) { - super(viewSettings, tableName, Data, null); - } + constructor(viewSettings: SqlViewSettings, tableName: string, Data: SqlExpression) { + super(viewSettings, tableName, Data, undefined); + } } export class SqlNodeView extends SqlViewBase implements ISqlNodeView { - constructor(viewSettings: SqlViewSettings, - public Parent: ISqlNodeView, tableName: string, Data: SqlExpression, property: FilterProperty) { - super(viewSettings, tableName, Data, property); - } - - public isSimple(): boolean { - return !this.Property || this.Property.ColumnType == SqlColumnTypes.Normal; - } - - public canRemove(): boolean { - return true; - } - - public remove() { - const expressions = this.Parent.Data.Expressions; - const index = expressions.indexOf(this.Data); - - if (index < 0) { - throw new Error('Node not found'); - } - expressions.splice(index, 1); - this.Parent.childViews.splice(index, 1); + constructor( + viewSettings: SqlViewSettings, + public Parent: ISqlNodeView, + tableName: string, + Data: SqlExpression, + property: FilterProperty | undefined, + ) { + super(viewSettings, tableName, Data, property); + } + + public isSimple(): boolean { + return !this.Property || this.Property.ColumnType == SqlColumnTypes.Normal; + } + + public canRemove(): boolean { + return true; + } + + public remove() { + const expressions = this.Parent.Data.Expressions; + const index = expressions?.indexOf(this.Data) ?? -1; + + if (index < 0) { + throw new Error('Node not found'); } + expressions?.splice(index, 1); + this.Parent.childViews.splice(index, 1); + } } diff --git a/imxweb/projects/qbm/src/lib/sqlwizard/column-selection.component.html b/imxweb/projects/qbm/src/lib/sqlwizard/column-selection.component.html index eb810150f..bc6e5d96a 100644 --- a/imxweb/projects/qbm/src/lib/sqlwizard/column-selection.component.html +++ b/imxweb/projects/qbm/src/lib/sqlwizard/column-selection.component.html @@ -1,5 +1,11 @@
    - +
    diff --git a/imxweb/projects/qbm/src/lib/sqlwizard/column-selection.component.ts b/imxweb/projects/qbm/src/lib/sqlwizard/column-selection.component.ts index ce747851a..19c565da9 100644 --- a/imxweb/projects/qbm/src/lib/sqlwizard/column-selection.component.ts +++ b/imxweb/projects/qbm/src/lib/sqlwizard/column-selection.component.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -27,105 +27,106 @@ import { Component, EventEmitter, Input, OnChanges, OnInit, Output } from '@angular/core'; import { UntypedFormControl } from '@angular/forms'; import { EuiSelectOption } from '@elemental-ui/core'; -import { FilterProperty, LogOp, SqlExpression } from 'imx-qbm-dbts'; +import { FilterProperty, LogOp, SqlExpression } from '@imx-modules/imx-qbm-dbts'; import { SqlNodeView } from './SqlNodeView'; import { SqlWizardService } from './sqlwizard.service'; @Component({ - templateUrl: './column-selection.component.html', - selector: 'imx-sqlwizard-columnselection' + templateUrl: './column-selection.component.html', + selector: 'imx-sqlwizard-columnselection', }) - export class ColumnSelectionComponent implements OnInit, OnChanges { + @Input() public node: SqlNodeView; + @Output() public change = new EventEmitter(); - @Input() public node: SqlNodeView; - - @Output() public change = new EventEmitter(); - - public columns: FilterProperty[] = []; + public columns: FilterProperty[] = []; - public dataReady = false; - public options: EuiSelectOption[] = []; + public dataReady = false; + public options: EuiSelectOption[] = []; - public formControl = new UntypedFormControl(); + public formControl = new UntypedFormControl(); - private lastSelected; - - constructor(private readonly svc: SqlWizardService) { - } + private lastSelected; - public async ngOnInit(): Promise { - await this.reloadColumns(); - if (this.node.Property) { - this.formControl.setValue(this.node.Property.PropertyId); - } + constructor(private readonly svc: SqlWizardService) {} - this.formControl.valueChanges.subscribe(c => { - this.selectColumn(c); - }); + public async ngOnInit(): Promise { + await this.reloadColumns(); + if (this.node.Property) { + this.formControl.setValue(this.node.Property.PropertyId); } - // TODO: Check Upgrade - public selectionChange(value: any): void { - this.formControl.setValue(value); - this.node.columnChanged.emit(value); - this.change.emit(); + this.formControl.valueChanges.subscribe((c) => { + this.selectColumn(c); + }); + } + + public selectionChange(arg: EuiSelectOption | EuiSelectOption[]): void { + let value: string = Object.hasOwn(arg, 'value') ? (arg as EuiSelectOption).value : arg[0].option; + this.formControl.setValue(value); + this.node.columnChanged.emit(value); + this.change.emit(); + } + + public ngOnChanges(changes: any): void { + if (changes.node) { + this.reloadColumns(); } - - public ngOnChanges(changes: any): void { - if (changes.node) { - this.reloadColumns(); - } + } + public async selectColumn(propertyId: string): Promise { + if (this.lastSelected === propertyId) { + return; } - public async selectColumn(propertyId: string): Promise { - if (this.lastSelected === propertyId) { - return; - } - this.lastSelected = propertyId; - const found = this.columns.filter(c => c.PropertyId === propertyId); - if (found.length != 1) { - throw new Error('Property not found: ' + propertyId); - } - const filterProperty = found[0]; - - // If there is only one operator, pre-select it. - // this is important for boolean properties that do not show - // an operator selection. - let preselectedOperator: string = null; - if (found[0].Operators?.length === 1) { - preselectedOperator = found[0].Operators[0].Type; - } - - // create new empty node - const data: SqlExpression = { - PropertyId: propertyId, - Operator: preselectedOperator, - LogOperator: LogOp.AND - }; - this.node.Parent.replaceChildNode(this.node.Data, data); - this.node.Data = data; - this.node.Property = filterProperty; + this.lastSelected = propertyId; + const found = this.columns.filter((c) => c.PropertyId === propertyId); + if (found.length != 1) { + throw new Error('Property not found: ' + propertyId); } - public filter(option: EuiSelectOption, searchInputValue: string): boolean { - return option.display.toString().toUpperCase().trim().includes(searchInputValue.toUpperCase().trim()); + const filterProperty = found[0]; + + // If there is only one operator, pre-select it. + // this is important for boolean properties that do not show + // an operator selection. + let preselectedOperator: string | undefined; + if (found[0].Operators?.length === 1) { + preselectedOperator = found[0].Operators[0].Type; } - private async reloadColumns(): Promise { - const tableName = this.node.tableName; - - if (tableName) { - - this.columns = await this.svc.getColumns(this.node.viewSettings, tableName); - this.options = []; - for (const col of this.columns) { - this.options.push({ - display: col.Display, - value: col.PropertyId - }); - } + // create new empty node + const data: SqlExpression = { + PropertyId: propertyId, + Operator: preselectedOperator, + LogOperator: LogOp.AND, + Negate: false, + }; + this.node.Parent.replaceChildNode(this.node.Data, data); + this.node.Data = data; + this.node.Property = filterProperty; + } + public filter(option: EuiSelectOption, searchInputValue: string): boolean { + return ( + (option.display.toUpperCase().trim().includes(searchInputValue.toUpperCase().trim()) || + option.displayDetail?.toUpperCase().trim().includes(searchInputValue.toUpperCase().trim())) ?? + false + ); + } + + private async reloadColumns(): Promise { + const tableName = this.node.tableName; + + if (tableName) { + this.columns = await this.svc.getColumns(this.node.viewSettings, tableName); + this.options = []; + for (const col of this.columns) { + this.options.push({ + display: col.Display ?? '', + displayDetail: col.PropertyId, + value: col.PropertyId, + }); + } - this.dataReady = true; - } + this.dataReady = true; } + } } diff --git a/imxweb/projects/qbm/src/lib/sqlwizard/date-picker.component.html b/imxweb/projects/qbm/src/lib/sqlwizard/date-picker.component.html index 6866f3e9d..9283cc886 100644 --- a/imxweb/projects/qbm/src/lib/sqlwizard/date-picker.component.html +++ b/imxweb/projects/qbm/src/lib/sqlwizard/date-picker.component.html @@ -8,7 +8,15 @@ {{ '#LDS#Number' | translate }} - + {{ '#LDS#Time unit' | translate }} @@ -19,14 +27,14 @@ {{ - '#LDS#The value you entered is not a valid date.' | translate + '#LDS#The value you specified is not valid.' | translate }}
    {{ '#LDS#Date' | translate }} - + {{ '#LDS#The value you entered is not a valid date.' | translate }} diff --git a/imxweb/projects/qbm/src/lib/sqlwizard/date-picker.component.ts b/imxweb/projects/qbm/src/lib/sqlwizard/date-picker.component.ts index 155dfc619..ba52689a3 100644 --- a/imxweb/projects/qbm/src/lib/sqlwizard/date-picker.component.ts +++ b/imxweb/projects/qbm/src/lib/sqlwizard/date-picker.component.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -25,10 +25,10 @@ */ import { Component, EventEmitter, Input, OnInit, Output } from '@angular/core'; -import { DateDiffUnit } from 'imx-qbm-dbts'; +import { FormControl, FormGroup, ValidatorFn } from '@angular/forms'; +import { DateDiffUnit } from '@imx-modules/imx-qbm-dbts'; import { SqlNodeView } from './SqlNodeView'; import { DateDiffOption, SqlWizardService } from './sqlwizard.service'; -import { FormControl, FormGroup, ValidatorFn } from '@angular/forms'; @Component({ templateUrl: './date-picker.component.html', @@ -36,6 +36,8 @@ import { FormControl, FormGroup, ValidatorFn } from '@angular/forms'; selector: 'imx-sqlwizard-datepicker', }) export class DatePickerComponent implements OnInit { + public absoluteError = false; + @Input() public expr: SqlNodeView; @Output() public change = new EventEmitter(); @@ -46,12 +48,14 @@ export class DatePickerComponent implements OnInit { public diffUnits: DateDiffOption[]; + private _relative = false; + private datepickerValidator: ValidatorFn = (form: FormGroup) => { - if (form.get('relative').value) { + if (form.get('relative')?.value) { if ( !(!!form.get('timeUnit')?.value || form.get('timeUnit')?.value === 0) || - !form.get('difference').value || - Number(form.get('difference').value) < 1 + !form.get('difference')?.value || + Number(form.get('difference')?.value) < 1 ) { return { datepickerError: true }; } @@ -61,13 +65,14 @@ export class DatePickerComponent implements OnInit { public form = new FormGroup( { - relative: new FormControl(null), - difference: new FormControl(null), - timeUnit: new FormControl(null), - datepicker: new FormControl(null), + relative: new FormControl(null), + difference: new FormControl(null), + timeUnit: new FormControl(null), + datepicker: new FormControl(null), }, - [this.datepickerValidator] + [this.datepickerValidator], ); + constructor(svc: SqlWizardService) { this.diffUnits = svc.getDateDiffUnits(); } @@ -102,6 +107,6 @@ export class DatePickerComponent implements OnInit { } public get isRelative(): boolean { - return this.form.controls.relative.value; + return this.form.controls.relative.value ?? false; } } diff --git a/imxweb/projects/qbm/src/lib/sqlwizard/simple-expression.component.html b/imxweb/projects/qbm/src/lib/sqlwizard/simple-expression.component.html index da9f32018..0967d3dd6 100644 --- a/imxweb/projects/qbm/src/lib/sqlwizard/simple-expression.component.html +++ b/imxweb/projects/qbm/src/lib/sqlwizard/simple-expression.component.html @@ -15,12 +15,25 @@
    -
    - +
    diff --git a/imxweb/projects/qbm/src/lib/sqlwizard/simple-expression.component.scss b/imxweb/projects/qbm/src/lib/sqlwizard/simple-expression.component.scss index 728be68fa..93faed3e4 100644 --- a/imxweb/projects/qbm/src/lib/sqlwizard/simple-expression.component.scss +++ b/imxweb/projects/qbm/src/lib/sqlwizard/simple-expression.component.scss @@ -1,5 +1,3 @@ -@import '@elemental-ui/core/src/styles/_palette.scss'; - :host { display: flex; flex-direction: column; @@ -14,15 +12,8 @@ align-items: center; } -.imx-delete-btn { - color: $color-red-60; -} - -.imx-add-button { - color: $color-blue-60; -} - .imx-column-container { display: flex; + align-items: baseline; column-gap: 10px; } diff --git a/imxweb/projects/qbm/src/lib/sqlwizard/simple-expression.component.ts b/imxweb/projects/qbm/src/lib/sqlwizard/simple-expression.component.ts index 8875062c9..3e435d48e 100644 --- a/imxweb/projects/qbm/src/lib/sqlwizard/simple-expression.component.ts +++ b/imxweb/projects/qbm/src/lib/sqlwizard/simple-expression.component.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -26,57 +26,55 @@ import { Component, EventEmitter, Input, Output } from '@angular/core'; import { SqlNodeView } from './SqlNodeView'; -import { SqlColumnTypes, ValType as _valType } from 'imx-qbm-dbts'; +import { SqlColumnTypes, ValType as _valType } from '@imx-modules/imx-qbm-dbts'; @Component({ - selector: 'imx-sqlwizard-simpleexpression', - styleUrls: ['./sqlwizard.scss', './simple-expression.component.scss'], - templateUrl: './simple-expression.component.html' + selector: 'imx-sqlwizard-simpleexpression', + styleUrls: ['./sqlwizard.scss', './simple-expression.component.scss'], + templateUrl: './simple-expression.component.html', }) export class SimpleExpressionComponent { - @Input() public expr: SqlNodeView; - @Output() public change = new EventEmitter(); + @Input() public expr: SqlNodeView; + @Output() public change = new EventEmitter(); - public ValType = _valType; - public ColumnType = SqlColumnTypes; + public ValType = _valType; + public ColumnType = SqlColumnTypes; - public emitChanges(): void { - this.change.emit(); - } - - public delete(ind: number) { - this.expr.Data.Value.splice(ind, 1); - this.emitChanges(); - } + public emitChanges(): void { + this.change.emit(); + } - public addNew() { - this.expr.Data.Value.push(null); - this.emitChanges(); - } + public delete(ind: number) { + this.expr.Data.Value.splice(ind, 1); + this.emitChanges(); + } - // https://stackoverflow.com/questions/42322968/angular2-dynamic-input-field-lose-focus-when-input-changes - public trackByFn(index: any, item: any) { - return index; - } + public addNew() { + this.expr.Data.Value.push(null); + this.emitChanges(); + } - public operatorChanged() { - if (this.expr.Data.Operator == 'IN') { - if (!(this.expr.Data.Value instanceof Array)) { + // https://stackoverflow.com/questions/42322968/angular2-dynamic-input-field-lose-focus-when-input-changes + public trackByFn(index: any, item: any) { + return index; + } - // re-initialize with array with single null element - this.expr.Data.Value = [null]; - } - } - else { - // re-initialize with single null element - if (this.expr.Data.Value instanceof Array) { - this.expr.Data.Value = null; - } - } - this.emitChanges(); + public operatorChanged() { + if (this.expr.Data.Operator == 'IN') { + if (!(this.expr.Data.Value instanceof Array)) { + // re-initialize with array with single null element + this.expr.Data.Value = [null]; + } + } else { + // re-initialize with single null element + if (this.expr.Data.Value instanceof Array) { + this.expr.Data.Value = null; + } } + this.emitChanges(); + } - public isArray(x): boolean { - return x instanceof Array; - } + public isArray(x): boolean { + return x instanceof Array; + } } diff --git a/imxweb/projects/qbm/src/lib/sqlwizard/single-expression.component.html b/imxweb/projects/qbm/src/lib/sqlwizard/single-expression.component.html index 019b3d7a8..ed9e711a3 100644 --- a/imxweb/projects/qbm/src/lib/sqlwizard/single-expression.component.html +++ b/imxweb/projects/qbm/src/lib/sqlwizard/single-expression.component.html @@ -1,27 +1,32 @@
    - - - - -
    - -
    + + + + +
    + +
    - -
  • - - + +
  • + + -
    - -
    -
  • -
    +
    + +
    + +
    - diff --git a/imxweb/projects/qbm/src/lib/sqlwizard/single-expression.component.ts b/imxweb/projects/qbm/src/lib/sqlwizard/single-expression.component.ts index 372f62f75..6c8ed3e6b 100644 --- a/imxweb/projects/qbm/src/lib/sqlwizard/single-expression.component.ts +++ b/imxweb/projects/qbm/src/lib/sqlwizard/single-expression.component.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -26,45 +26,43 @@ import { Component, EventEmitter, Input, Output } from '@angular/core'; import { SqlNodeView, SqlViewSettings } from './SqlNodeView'; -import { LogOp as _logOp } from 'imx-qbm-dbts'; +import { LogOp as _logOp } from '@imx-modules/imx-qbm-dbts'; @Component({ - selector: 'imx-sqlwizard-singleexpression', - styleUrls: ['single-expression.component.scss', './sqlwizard.scss'], - templateUrl: './single-expression.component.html' + selector: 'imx-sqlwizard-singleexpression', + styleUrls: ['single-expression.component.scss', './sqlwizard.scss'], + templateUrl: './single-expression.component.html', }) export class SingleExpressionComponent { + @Input() public expr: SqlNodeView; + @Input() public first: boolean; + @Input() public last: boolean; + @Input() public viewSettings: SqlViewSettings; - @Input() public expr: SqlNodeView; - @Input() public first: boolean; - @Input() public last: boolean; - @Input() public viewSettings: SqlViewSettings; + @Output() public change = new EventEmitter(); - @Output() public change = new EventEmitter(); + public LogOp = _logOp; - public LogOp = _logOp; + public emitChanges(): void { + this.change.emit(); + } - public emitChanges(): void { - this.change.emit(); - } + public IsEmpty(): boolean { + return !this.expr.Data.PropertyId; + } - public IsEmpty(): boolean { - return !this.expr.Data.PropertyId; - } + public toggleLogOperator() { + this.expr.Parent.Data.LogOperator = this.expr.Parent.Data.LogOperator === _logOp.OR ? _logOp.AND : _logOp.OR; + this.change.emit(); + } - public toggleLogOperator() { - this.expr.Parent.Data.LogOperator = this.expr.Parent.Data.LogOperator === _logOp.OR ? _logOp.AND : _logOp.OR; - this.change.emit(); - } - - public async addExpression(): Promise { - await this.expr.Parent.addChildNode(); - this.emitChanges(); - } - - public removeExpression(): void { - this.expr.remove(); - this.emitChanges(); - } + public async addExpression(): Promise { + await this.expr.Parent.addChildNode(); + this.emitChanges(); + } + public removeExpression(): void { + this.expr.remove(); + this.emitChanges(); + } } diff --git a/imxweb/projects/qbm/src/lib/sqlwizard/single-value.component.html b/imxweb/projects/qbm/src/lib/sqlwizard/single-value.component.html index e228a9498..cfd52e6d3 100644 --- a/imxweb/projects/qbm/src/lib/sqlwizard/single-value.component.html +++ b/imxweb/projects/qbm/src/lib/sqlwizard/single-value.component.html @@ -1,20 +1,22 @@ - + {{ '#LDS#Value' | translate }} - + {{ lv.Description }} - + - +
    - {{ '#LDS#Property is activated' | translate }} + {{ '#LDS#Property is activated' | translate }} +
    @@ -22,15 +24,26 @@
    {{ '#LDS#Value' | translate }} - - {{ '#LDS#WD_InputInvalidInteger' | translate | ldsReplace : integerFormControl.value }} + + + {{ '#LDS#The value you entered is invalid. Enter an integer number.' | translate }} + +
    +
    + + {{ '#LDS#Value' | translate }} + + + {{ '#LDS#The value you entered is invalid. Enter an integer number.' | translate }}
    {{ '#LDS#Value' | translate }} - - {{ '#LDS#WD_InputInvalidFloat' | translate | ldsReplace : doubleFormControl.value }} + + {{ '#LDS#The value you entered is invalid. Enter a number.' | translate }}
    diff --git a/imxweb/projects/qbm/src/lib/sqlwizard/single-value.component.ts b/imxweb/projects/qbm/src/lib/sqlwizard/single-value.component.ts index 9cf470f36..7a40378eb 100644 --- a/imxweb/projects/qbm/src/lib/sqlwizard/single-value.component.ts +++ b/imxweb/projects/qbm/src/lib/sqlwizard/single-value.component.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -25,21 +25,21 @@ */ import { Component, EventEmitter, Input, OnDestroy, OnInit, Output } from '@angular/core'; +import { FormControl, Validators } from '@angular/forms'; import { FkProviderItem, IClientProperty, - MetaTableRelationData, + IEntityColumn, SqlColumnTypes, SqlTable, ValType, ValType as _valType, -} from 'imx-qbm-dbts'; +} from '@imx-modules/imx-qbm-dbts'; import { Subscription } from 'rxjs'; import { BaseCdr } from '../cdr/base-cdr'; import { EntityService } from '../entity/entity.service'; import { SqlNodeView } from './SqlNodeView'; import { SqlWizardApiService } from './sqlwizard-api.service'; -import { FormControl, Validators } from '@angular/forms'; @Component({ selector: 'imx-sqlwizard-singlevalue', @@ -47,19 +47,6 @@ import { FormControl, Validators } from '@angular/forms'; templateUrl: './single-value.component.html', }) export class SingleValueComponent implements OnInit, OnDestroy { - public get selectedTable() { - return this._selectedTable; - } - - public set selectedTable(val) { - this._selectedTable = val; - if (val) { - this._fkRelation.ParentTableName = val.Name; - this._fkRelation.ParentColumnName = val.ParentColumnName; - this._fkProviderItem.fkTableName = val.Name; - } - } - get value() { if (this.mode == 'array' && this.expr.Data.Value) { return this.expr.Data.Value[this.index]; @@ -77,20 +64,24 @@ export class SingleValueComponent implements OnInit, OnDestroy { } get displayValue() { - if (!this.expr.Data.DisplayValues) { + if (!this.expr.Data?.DisplayValues) { return null; } - return this.expr.Data.DisplayValues[this.mode === 'array' ? this.index : 0]; + if (this.mode == 'array') { + return this.expr.Data.DisplayValues[this.index]; + } else { + return this.expr.Data.DisplayValues ? this.expr.Data.DisplayValues[0] : null; + } } set displayValue(val) { - if (!this.expr.Data?.DisplayValues) { + if (!this.expr.Data) { return; } if (this.mode == 'array' && this.expr.Data.DisplayValues) { - this.expr.Data.DisplayValues[this.index] = val; + this.expr.Data.DisplayValues?.splice(this.index, 1, val ?? ''); } else { - this.expr.Data.DisplayValues = [val]; + this.expr.Data.DisplayValues = [val ?? '']; } } @@ -103,31 +94,21 @@ export class SingleValueComponent implements OnInit, OnDestroy { public ValType = _valType; public ColumnType = SqlColumnTypes; public cdr: BaseCdr; - public doubleFormControl = new FormControl(null, Validators.pattern(/^[+-]?\d+(\.\d+)?$/)); - public integerFormControl = new FormControl(null, Validators.pattern(/^[+-]?\d+$/)); - - private _selectedTable: SqlTable; - private _fkRelation: MetaTableRelationData = { - IsMemberRelation: false, - }; - private _fkProviderItem: FkProviderItem = { - columnName: 'dummycolumn', - fkTableName: 'not_set', - parameterNames: ['OrderBy', 'StartIndex', 'PageSize', 'filter', 'search'], - load: async (_, parameters = {}) => this.sqlWizardApi.getCandidates(this._fkRelation.ParentTableName, parameters), - getFilterTree: async () => ({ Elements: [] }), - getDataModel: async () => ({}), - }; + public doubleFormControl = new FormControl(null, [Validators.pattern(/^[+-]?\d+(\.\d+)?$/), Validators.required]); + public integerFormControl = new FormControl(null, [Validators.pattern(/^[+-]?\d+$/), Validators.required]); private subscriptions: Subscription[] = []; - constructor(private readonly entityService: EntityService, private readonly sqlWizardApi: SqlWizardApiService) {} + constructor( + private readonly entityService: EntityService, + private readonly sqlWizardApi: SqlWizardApiService, + ) {} public ngOnInit(): void { this.subscriptions.push( this.expr.columnChanged.subscribe((_) => { this.buildCdr(); - }) + }), ); this.buildCdr(); @@ -142,30 +123,33 @@ export class SingleValueComponent implements OnInit, OnDestroy { this.change.emit(); } + /** + * @ignore Builds a cdr for the expression. + */ private buildCdr() { - const tables = this.expr.Property.SelectionTables; - if (tables && tables.length > 0) { - this.selectedTable = tables[0]; - } else { - this.selectedTable = null; + const tables = this.expr.Property?.SelectionTables; + + if (this.expr.Property?.Type === ValType.Bool && this.expr.Data.Value === undefined) { + this.value = false; } - const property: IClientProperty = { - ColumnName: 'dummycolumn', - Type: ValType.String, - FkRelation: this._fkRelation, - }; + let column: IEntityColumn; - if (this.expr.Property.Type === ValType.Bool && this.expr.Data.Value === undefined ) this.value = false; + if ((tables?.length ?? 0) > 1) { + column = this.buildDynamicFk(tables ?? []); + } else { + if (!!tables?.length) { + column = this.buildFk(tables?.[0]); + } else { + column = this.buildSimple(); + } + } + if (!column) throw new Error('Column can not be build'); - const column = this.entityService.createLocalEntityColumn(property, [this._fkProviderItem], { - Value: this.value, - DisplayValue: this.displayValue, - }); - if (this.expr.Property.Type === ValType.Double) { + if (this.expr.Property?.Type === ValType.Double) { this.doubleFormControl.setValue(column.GetValue()); } - if (this.expr.Property.Type === ValType.Int) { + if (this.expr.Property?.Type === ValType.Int) { this.integerFormControl.setValue(column.GetValue()); } @@ -180,6 +164,86 @@ export class SingleValueComponent implements OnInit, OnDestroy { this.cdr = new BaseCdr(column, '#LDS#Value'); } + /** + * @ignore Builds a column, containing a dynamic fk definition, that uses multiple tables. + * @param tables a list containing the SQL tables, that are used for the column's fk relation + * @returns an entity column, that can be used by a cdr + */ + private buildDynamicFk(tables: SqlTable[]): IEntityColumn { + const property: IClientProperty = { + ColumnName: 'dummycolumn', + Type: ValType.String, + IsDynamicFk: true, + ValidReferencedTables: tables.map((elem) => ({ TableName: elem.Name })), + }; + + return this.buildColumn( + property, + tables.map((elem) => this.buildProviderItem(elem.Name, 'XObjectKey')), + ); + } + + /** + * @ignore Builds a column, containing a simple fk definition. + * @param table the SQL table, that is used for the column's fk relation + * @returns an entity column, that can be used by a cdr + */ + private buildFk(table: SqlTable | undefined): IEntityColumn { + const property: IClientProperty = { + ColumnName: 'dummycolumn', + Type: ValType.String, + FkRelation: { + IsMemberRelation: false, + ParentTableName: table?.Name ?? '', + ParentColumnName: table?.ParentColumnName, + }, + }; + + return this.buildColumn(property, [this.buildProviderItem(table?.Name, table?.ParentColumnName)]); + } + + /** + * @ignore Builds a simple entity column. + * @returns a simple entity column without fk providers + */ + private buildSimple(): IEntityColumn { + const property: IClientProperty = { + ColumnName: 'dummycolumn', + Type: this.expr.Property?.Type ?? ValType.String, + }; + return this.buildColumn(property, undefined); + } + + /** + * @ignore Builds a single FkProviderItem. + * @param tableName the name of the table + * @returns a fk provider item + */ + private buildProviderItem(tableName: string | undefined, fkColumnName?: string): FkProviderItem { + return { + columnName: 'dummycolumn', + fkColumnName, + fkTableName: tableName ?? '', + parameterNames: ['OrderBy', 'StartIndex', 'PageSize', 'filter', 'search'], + load: async (_, parameters = {}) => this.sqlWizardApi.getCandidates(tableName ?? '', parameters), + getFilterTree: async () => ({ Elements: [] }), + getDataModel: async () => ({}), + }; + } + + /** + * @ignore This is used to build the entity column in all helper methods. + * @param property the client property describing the column + * @param providerItems FkProviderItems, that are associated with the column. + * @returns an IEntityColumn, that can be used in the CDR + */ + private buildColumn(property: IClientProperty, providerItems: FkProviderItem[] | undefined): IEntityColumn { + return this.entityService.createLocalEntityColumn(property, providerItems, { + Value: this.value, + DisplayValue: this.displayValue ?? '', + }); + } + private onFormValueChanges(): void { this.subscriptions.push( this.doubleFormControl.valueChanges.subscribe((value) => { @@ -189,7 +253,7 @@ export class SingleValueComponent implements OnInit, OnDestroy { } else { this.value = {}; } - }) + }), ); this.subscriptions.push( this.integerFormControl.valueChanges.subscribe((value) => { @@ -199,8 +263,7 @@ export class SingleValueComponent implements OnInit, OnDestroy { } else { this.value = {}; } - }) + }), ); } } - diff --git a/imxweb/projects/qbm/src/lib/sqlwizard/sqlwizard-api.service.ts b/imxweb/projects/qbm/src/lib/sqlwizard/sqlwizard-api.service.ts index e0615dc92..a811b1676 100644 --- a/imxweb/projects/qbm/src/lib/sqlwizard/sqlwizard-api.service.ts +++ b/imxweb/projects/qbm/src/lib/sqlwizard/sqlwizard-api.service.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -24,10 +24,9 @@ * */ -import { CollectionLoadParameters, EntityCollectionData, FilterProperty } from 'imx-qbm-dbts'; +import { CollectionLoadParameters, EntityCollectionData, FilterProperty } from '@imx-modules/imx-qbm-dbts'; export abstract class SqlWizardApiService { - public abstract getFilterProperties(table: string): Promise; public abstract getCandidates(parentTable: string, options?: CollectionLoadParameters): Promise; diff --git a/imxweb/projects/qbm/src/lib/sqlwizard/sqlwizard.component.html b/imxweb/projects/qbm/src/lib/sqlwizard/sqlwizard.component.html index 830193cad..ec132d016 100644 --- a/imxweb/projects/qbm/src/lib/sqlwizard/sqlwizard.component.html +++ b/imxweb/projects/qbm/src/lib/sqlwizard/sqlwizard.component.html @@ -9,20 +9,25 @@ {{ '#LDS#Logical operator' | translate }} - - {{ andConditionLabel | translate }} - {{ orConditionLabel | translate }} + + {{ + andConditionLabel | translate + }} + {{ + orConditionLabel | translate + }}
    - {{logOpText() | translate}} + {{ logOpText() | translate }}
  • {{ i + 1 }}.
    - + +
  • diff --git a/imxweb/projects/qbm/src/lib/sqlwizard/sqlwizard.component.ts b/imxweb/projects/qbm/src/lib/sqlwizard/sqlwizard.component.ts index f65f2f930..3a558b8ad 100644 --- a/imxweb/projects/qbm/src/lib/sqlwizard/sqlwizard.component.ts +++ b/imxweb/projects/qbm/src/lib/sqlwizard/sqlwizard.component.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -24,11 +24,23 @@ * */ -import { AfterViewInit, Component, ElementRef, EventEmitter, Input, OnChanges, OnInit, Output, QueryList, SimpleChanges, ViewChildren } from '@angular/core'; +import { + AfterViewInit, + Component, + ElementRef, + EventEmitter, + Input, + OnChanges, + OnInit, + Output, + QueryList, + SimpleChanges, + ViewChildren, +} from '@angular/core'; +import { MatButtonToggleChange } from '@angular/material/button-toggle'; +import { SqlExpression, LogOp as _logOp } from '@imx-modules/imx-qbm-dbts'; import { SqlViewSettings } from './SqlNodeView'; -import { LogOp as _logOp, SqlExpression } from 'imx-qbm-dbts'; import { SqlWizardApiService } from './sqlwizard-api.service'; -import { MatButtonToggleChange } from '@angular/material/button-toggle'; @Component({ templateUrl: './sqlwizard.component.html', @@ -47,7 +59,7 @@ export class SqlWizardComponent implements OnInit, OnChanges, AfterViewInit { svc = this.apiSvc; } - return svc.implemented; + return svc.implemented ?? false; } @Input() public tableName: string; @@ -69,14 +81,14 @@ export class SqlWizardComponent implements OnInit, OnChanges, AfterViewInit { } public ngAfterViewInit(): void { - setTimeout( () => { + setTimeout(() => { this.expressionList.changes.subscribe(() => { if (this.newExpressionAdded) { this.expressionList?.last?.nativeElement.scrollIntoView(true); } this.newExpressionAdded = false; - }) + }); }); } @@ -108,7 +120,9 @@ export class SqlWizardComponent implements OnInit, OnChanges, AfterViewInit { } public onOperatorChanged(event: MatButtonToggleChange): void { - (event.value as string).toLowerCase() === 'and' ? (this.expression.LogOperator = this.LogOp.AND) : (this.expression.LogOperator = this.LogOp.OR); + (event.value as string).toLowerCase() === 'and' + ? (this.expression.LogOperator = this.LogOp.AND) + : (this.expression.LogOperator = this.LogOp.OR); this.change.emit(); } diff --git a/imxweb/projects/qbm/src/lib/sqlwizard/sqlwizard.module.ts b/imxweb/projects/qbm/src/lib/sqlwizard/sqlwizard.module.ts index 0c8d8bd13..654325cf8 100644 --- a/imxweb/projects/qbm/src/lib/sqlwizard/sqlwizard.module.ts +++ b/imxweb/projects/qbm/src/lib/sqlwizard/sqlwizard.module.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -24,33 +24,33 @@ * */ +import { CommonModule } from '@angular/common'; import { NgModule } from '@angular/core'; import { FormsModule, ReactiveFormsModule } from '@angular/forms'; -import { SqlWizardComponent } from './sqlwizard.component'; -import { SimpleExpressionComponent } from './simple-expression.component'; -import { CommonModule } from '@angular/common'; -import { ColumnSelectionComponent } from './column-selection.component'; -import { TableSelectionComponent } from './table-selection.component'; -import { SingleExpressionComponent } from './single-expression.component'; -import { WhereClauseExpressionComponent } from './where-clause-expression.component'; -import { TranslateModule } from '@ngx-translate/core'; -import { EuiCoreModule, EuiMaterialModule } from '@elemental-ui/core'; import { MatButtonModule } from '@angular/material/button'; -import { MatSelectModule } from '@angular/material/select'; +import { MatButtonToggleModule } from '@angular/material/button-toggle'; import { MatCheckboxModule } from '@angular/material/checkbox'; import { MatOptionModule } from '@angular/material/core'; +import { MatDatepickerModule } from '@angular/material/datepicker'; import { MatFormFieldModule } from '@angular/material/form-field'; import { MatInputModule } from '@angular/material/input'; -import { MatDatepickerModule } from '@angular/material/datepicker'; -import { MatSlideToggleModule } from '@angular/material/slide-toggle'; -import { MatButtonToggleModule } from '@angular/material/button-toggle'; -import { SqlWizardService } from './sqlwizard.service'; import { MatListModule } from '@angular/material/list'; -import { DatePickerComponent } from './date-picker.component'; import { MatRadioModule } from '@angular/material/radio'; -import { SingleValueComponent } from './single-value.component'; +import { MatSelectModule } from '@angular/material/select'; +import { MatSlideToggleModule } from '@angular/material/slide-toggle'; +import { EuiCoreModule, EuiMaterialModule } from '@elemental-ui/core'; +import { TranslateModule } from '@ngx-translate/core'; import { CdrModule } from '../cdr/cdr.module'; import { LdsReplaceModule } from '../lds-replace/lds-replace.module'; +import { ColumnSelectionComponent } from './column-selection.component'; +import { DatePickerComponent } from './date-picker.component'; +import { SimpleExpressionComponent } from './simple-expression.component'; +import { SingleExpressionComponent } from './single-expression.component'; +import { SingleValueComponent } from './single-value.component'; +import { SqlWizardComponent } from './sqlwizard.component'; +import { SqlWizardService } from './sqlwizard.service'; +import { TableSelectionComponent } from './table-selection.component'; +import { WhereClauseExpressionComponent } from './where-clause-expression.component'; @NgModule({ imports: [ diff --git a/imxweb/projects/qbm/src/lib/sqlwizard/sqlwizard.scss b/imxweb/projects/qbm/src/lib/sqlwizard/sqlwizard.scss index 4d12eea5c..3f2a499a2 100644 --- a/imxweb/projects/qbm/src/lib/sqlwizard/sqlwizard.scss +++ b/imxweb/projects/qbm/src/lib/sqlwizard/sqlwizard.scss @@ -1,5 +1,5 @@ @import '@elemental-ui/core/src/styles/_palette.scss'; - +@import 'base/mixins'; .column-selector { flex-grow: 1; @@ -24,10 +24,6 @@ li { flex-grow: 1; flex-shrink: 1; align-items: center; - - .mat-slide-toggle { - margin-top: 10px; - } } .expression { @@ -64,20 +60,21 @@ li { display: flex; flex-wrap: wrap; align-items: baseline; - .mat-error { + gap: 10px; + .mat-mdc-form-field-error { width: 100%; font-size: 75%; } } .expression-container { - transition: all .6s cubic-bezier(0.25, 0.8, 0.25, 1); + transition: all 0.6s cubic-bezier(0.25, 0.8, 0.25, 1); border: 1px $color-gray-20 solid; border-radius: 5px; display: flex; .expression-container-header { - transition: all .6s cubic-bezier(0.25, 0.8, 0.25, 1); + transition: all 0.6s cubic-bezier(0.25, 0.8, 0.25, 1); width: 30px; display: flex; justify-content: center; @@ -124,23 +121,18 @@ li { flex: 1 1 auto; } -mat-radio-button { - margin-right: 1em; +.imx-remove-all { + @include align-button-content($color-red-60); } -/* undo Elemental UI fix */ -::ng-deep .mat-form-field-wrapper, -::ng-deep mat-form-field.ng-untouched .mat-form-field-wrapper, -::ng-deep mat-form-field.ng-valid .mat-form-field-wrapper { - padding-bottom: 0; +.imx-btn-color-default { + @include align-button-content($color-blue-60); } -::ng-deep .mat-form-field-infix .mat-select-trigger { - vertical-align: middle; - - .mat-select-arrow-wrapper { - vertical-align: bottom; - } +/* undo Elemental UI fix */ +::ng-deep mat-form-field.ng-untouched .mat-mdc-form-field-wrapper, +::ng-deep mat-form-field.ng-valid .mat-mdc-form-field-wrapper { + padding-bottom: 0; } imx-sqlwizard-singlevalue { @@ -194,6 +186,14 @@ imx-sqlwizard-singlevalue { .selected-logical-op { color: $color-blue-40; } + + .imx-remove-all { + @include align-button-content($color-red-40); + } + + .imx-btn-color-default { + @include align-button-content($color-blue-40); + } } } @@ -215,5 +215,13 @@ imx-sqlwizard-singlevalue { .selected-logical-op { color: $color-blue-60; } + + .imx-remove-all { + @include align-button-content($color-red-40); + } + + .imx-btn-color-default { + @include align-button-content($color-blue-40); + } } } diff --git a/imxweb/projects/qbm/src/lib/sqlwizard/sqlwizard.service.ts b/imxweb/projects/qbm/src/lib/sqlwizard/sqlwizard.service.ts index 2c8f02e5f..80458babf 100644 --- a/imxweb/projects/qbm/src/lib/sqlwizard/sqlwizard.service.ts +++ b/imxweb/projects/qbm/src/lib/sqlwizard/sqlwizard.service.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -25,17 +25,15 @@ */ import { Injectable } from '@angular/core'; -import { FilterProperty } from 'imx-qbm-dbts'; -import { DateDiffUnit } from 'imx-qbm-dbts'; -import { SqlViewSettings } from './SqlNodeView'; +import { DateDiffUnit, FilterProperty } from '@imx-modules/imx-qbm-dbts'; import { AuthenticationService } from '../authentication/authentication.service'; +import { SqlViewSettings } from './SqlNodeView'; @Injectable() export class SqlWizardService { public constructor(authentication: AuthenticationService) { - authentication.onSessionResponse.subscribe(async (elem) => { - this.currentUser = elem.UserUid; + this.currentUser = elem.UserUid ?? ''; }); } @@ -50,10 +48,10 @@ export class SqlWizardService { { DisplayMl: '#LDS#SW_Hours', Value: DateDiffUnit.Hours }, ]; - public getColumns(viewSettings: SqlViewSettings, tableName: string): Promise { + public async getColumns(viewSettings: SqlViewSettings, tableName: string): Promise { const tableUser = tableName + this.currentUser; if (this._cache.has(tableUser)) { - return this._cache.get(tableUser); + return (await this._cache.get(tableUser)) ?? []; } const promise = this.getInternal(tableName, viewSettings); this._cache.set(tableUser, promise); diff --git a/imxweb/projects/qbm/src/lib/sqlwizard/table-selection.component.html b/imxweb/projects/qbm/src/lib/sqlwizard/table-selection.component.html index 0f879c778..8baa0f5ca 100644 --- a/imxweb/projects/qbm/src/lib/sqlwizard/table-selection.component.html +++ b/imxweb/projects/qbm/src/lib/sqlwizard/table-selection.component.html @@ -1,2 +1 @@ - - + diff --git a/imxweb/projects/qbm/src/lib/sqlwizard/table-selection.component.ts b/imxweb/projects/qbm/src/lib/sqlwizard/table-selection.component.ts index 0b4f8b5d8..5d1c98fcb 100644 --- a/imxweb/projects/qbm/src/lib/sqlwizard/table-selection.component.ts +++ b/imxweb/projects/qbm/src/lib/sqlwizard/table-selection.component.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -30,27 +30,24 @@ import { SqlNodeView } from './SqlNodeView'; import { SqlWizardApiService } from './sqlwizard-api.service'; @Component({ - selector: 'imx-sqlwizard-tableselection', - templateUrl: './table-selection.component.html', + selector: 'imx-sqlwizard-tableselection', + templateUrl: './table-selection.component.html', }) export class TableSelectionComponent implements OnInit { + @Input() public node: SqlNodeView; - @Input() public node: SqlNodeView; + public selectableTables: EuiSelectOption[] = []; - public selectableTables: EuiSelectOption[] = []; + public tableFilter: string; - public tableFilter: string; + constructor(private readonly sqlApiService: SqlWizardApiService) {} - constructor(private readonly sqlApiService: SqlWizardApiService) { - } - - public async ngOnInit() { - // TODO const tables = await this.sqlApiService.getSelectableTables(this.node.Data.); - // this.selectableTables = tables; - } - - public filter(option: EuiSelectOption, searchInputValue: string): boolean { - return option.display.toString().toUpperCase().trim().includes(searchInputValue.toUpperCase().trim()); - } + public async ngOnInit() { + // TODO const tables = await this.sqlApiService.getSelectableTables(this.node.Data.); + // this.selectableTables = tables; + } + public filter(option: EuiSelectOption, searchInputValue: string): boolean { + return option.display.toString().toUpperCase().trim().includes(searchInputValue.toUpperCase().trim()); + } } diff --git a/imxweb/projects/qbm/src/lib/sqlwizard/where-clause-expression.component.ts b/imxweb/projects/qbm/src/lib/sqlwizard/where-clause-expression.component.ts index 5a6fc563f..58d12a176 100644 --- a/imxweb/projects/qbm/src/lib/sqlwizard/where-clause-expression.component.ts +++ b/imxweb/projects/qbm/src/lib/sqlwizard/where-clause-expression.component.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -25,24 +25,23 @@ */ import { Component, EventEmitter, Input, Output } from '@angular/core'; -import { SqlColumnTypes, ValType } from 'imx-qbm-dbts'; +import { SqlColumnTypes, ValType } from '@imx-modules/imx-qbm-dbts'; import { SqlNodeView } from './SqlNodeView'; @Component({ - selector: 'imx-sqlwizard-whereclauseexpression', - styleUrls: ['./sqlwizard.scss'], - templateUrl: './where-clause-expression.component.html' + selector: 'imx-sqlwizard-whereclauseexpression', + styleUrls: ['./sqlwizard.scss'], + templateUrl: './where-clause-expression.component.html', }) export class WhereClauseExpressionComponent { + public ColumnType = SqlColumnTypes; + public ValType = ValType; - public ColumnType = SqlColumnTypes; - public ValType = ValType; + @Input() public expr: SqlNodeView; - @Input() public expr: SqlNodeView; + @Output() public change = new EventEmitter(); - @Output() public change = new EventEmitter(); - - public emitChanges(): void { - this.change.emit(); - } + public emitChanges(): void { + this.change.emit(); + } } diff --git a/imxweb/projects/qbm/src/lib/storage/storage.module.ts b/imxweb/projects/qbm/src/lib/storage/storage.module.ts index 2d1ff7c54..738dab39c 100644 --- a/imxweb/projects/qbm/src/lib/storage/storage.module.ts +++ b/imxweb/projects/qbm/src/lib/storage/storage.module.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -31,11 +31,7 @@ import { StorageService } from './storage.service'; @NgModule({ declarations: [], - imports: [ - CommonModule - ], - providers: [ - StorageService - ] + imports: [CommonModule], + providers: [StorageService], }) -export class StorageModule { } +export class StorageModule {} diff --git a/imxweb/projects/qbm/src/lib/storage/storage.service.spec.ts b/imxweb/projects/qbm/src/lib/storage/storage.service.spec.ts index 49cd06336..46fa0e041 100644 --- a/imxweb/projects/qbm/src/lib/storage/storage.service.spec.ts +++ b/imxweb/projects/qbm/src/lib/storage/storage.service.spec.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -71,5 +71,4 @@ describe('StorageService', () => { expect(sessionStorageSetItemSpy).toHaveBeenCalledWith(mockKey, 'true'); }); }); - }); diff --git a/imxweb/projects/qbm/src/lib/storage/storage.service.ts b/imxweb/projects/qbm/src/lib/storage/storage.service.ts index 3fd56a066..272558b1c 100644 --- a/imxweb/projects/qbm/src/lib/storage/storage.service.ts +++ b/imxweb/projects/qbm/src/lib/storage/storage.service.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -29,11 +29,13 @@ import { Injectable } from '@angular/core'; export const HELPER_ALERT_KEY_PREFIX = 'helperAlertDismissed'; @Injectable({ - providedIn: 'root' + providedIn: 'root', }) export class StorageService { - public get lastUrl(): string { return localStorage.getItem(this.lastUrlKey); } - public set lastUrl(value: string) { + public get lastUrl(): string { + return localStorage.getItem(this.lastUrlKey) ?? ''; + } + public set lastUrl(value: string | undefined) { if (value) { localStorage.setItem(this.lastUrlKey, value); } else { @@ -67,6 +69,6 @@ export class StorageService { } public removeKeys(...params: string[]): void { - params.forEach(key => sessionStorage.removeItem(key)); + params.forEach((key) => sessionStorage.removeItem(key)); } } diff --git a/imxweb/projects/qbm/src/lib/styles/data-explorer-common.scss b/imxweb/projects/qbm/src/lib/styles/data-explorer-common.scss index d87a92a1a..e5ea8c15d 100644 --- a/imxweb/projects/qbm/src/lib/styles/data-explorer-common.scss +++ b/imxweb/projects/qbm/src/lib/styles/data-explorer-common.scss @@ -1,167 +1,13 @@ -@import "@elemental-ui/core/src/styles/_palette.scss"; -@import "@elemental-ui/core/src/styles/_eui_palette.scss"; +@import '@elemental-ui/core/src/styles/_palette.scss'; +@import '@elemental-ui/core/src/styles/_eui_palette.scss'; .data-explorer { ::ng-deep .imx-data-table-selection-info { display: none; } - .sync-status-alert { - ::ng-deep .eui-alert.eui-alert-condensed { - margin-bottom: 10px; - } - } - imx-data-source-toolbar { flex: 0 0 auto; } - .data-explorer-card-header { - background-color: $white; - border-top-left-radius: 4px; - border-top-right-radius: 4px; - z-index: 100; - border: 1px solid rgba($color-blue-60, 0.6); - margin-bottom: 20px; - - .data-explorer-card-header-bg { - border-top-left-radius: 4px; - border-top-right-radius: 4px; - background-color: $color-blue-20; - padding: 10px 24px; - display: flex; - align-items: center; - justify-content: flex-start; - height: 45px; - - .eui-icon { - color: rgba($color-blue-60, 0.6); - margin-right: 10px; - } - .mat-icon-button{ - .eui-icon{ - margin-right: 0; - } - } - - & > span { - font-size: 20px; - } - } - } - - ::ng-deep .data-explorer-table { - .mat-sidenav-content { - overflow-y: hidden; - } - - .imx-data-table-row-highlighted { - background-color: inherit; - } - - .mat-row:hover { - cursor: pointer; - background-color: rgba($color-blue-20, 0.2) !important; - } - - .mat-checkbox-disabled { - cursor: not-allowed; - } - - .mat-table { - .mat-cell, - .mat-header-cell { - padding-right: 10px; - } - } - } - - &__action-buttons-wrapper { - background-color: $asher-gray; - padding: 10px 0; - position: sticky; - position: -webkit-sticky; - bottom: -35px; - left: 0; - z-index: 10; - } - - &__action-buttons { - display: flex; - justify-content: flex-end; - align-items: center; - background-color: $white; - padding: 16px 32px; - width: 100%; - - .mat-slide-toggle { - margin-right: 15px; - } - - .justify-start { - margin-right: auto; - } - } -} - -@media screen and (max-width: 480px) { - .data-explorer { - &__action-buttons-wrapper { - bottom: -15px; - } - - &__action-buttons { - display: block; - - .mat-slide-toggle { - display: block; - margin-bottom: 20px; - margin-top: 5px; - margin-right: 0; - - ::ng-deep .mat-slide-toggle-content { - white-space: normal; - } - } - - .mat-raised-button { - width: 100%; - } - } - } -} - -@media screen and (max-width: 320px) { - .data-explorer { - &__action-buttons { - .mat-slide-toggle { - margin-top: 15px; - margin-bottom: 25px; - } - } - } -} -.eui-dark-theme { - .data-explorer { - .data-explorer-card-header { - .data-explorer-card-header-bg { - background-color: $color-blue-80; - } - .eui-icon { - color: $color-gray-0; - } - } - } -} -.eui-contrast-theme { - .data-explorer { - .data-explorer-card-header { - .data-explorer-card-header-bg { - background-color: $color-blue-80; - } - .eui-icon { - color: $color-gray-0; - } - } - } } diff --git a/imxweb/projects/qbm/src/lib/styles/data-explorer-details-common.scss b/imxweb/projects/qbm/src/lib/styles/data-explorer-details-common.scss index cb3ff4336..3992fae24 100644 --- a/imxweb/projects/qbm/src/lib/styles/data-explorer-details-common.scss +++ b/imxweb/projects/qbm/src/lib/styles/data-explorer-details-common.scss @@ -1,7 +1,6 @@ @import '@elemental-ui/core/src/styles/_palette.scss'; @import '@elemental-ui/core/src/styles/_eui_palette.scss'; - .governance-sidesheet { background-color: $asher-gray; height: 100%; @@ -9,11 +8,6 @@ flex-direction: column; overflow: hidden; - ::ng-deep .mat-tab-group { - flex-grow: 1; - overflow: auto; - } - &__tab-content { display: flex; flex-direction: column; @@ -26,7 +20,7 @@ &__tab-content-body { flex: 1; - padding: 20px; + // padding: 20px; overflow: auto; display: flex; flex-direction: column; @@ -40,11 +34,6 @@ padding-left: 0; } } - - .mat-slide-toggle.custom-toggle { - display: flex; - margin-bottom: 20px; - } } .governance-sidesheet-action-buttons-container { diff --git a/imxweb/projects/qbm/src/lib/styles/imx-page-title.scss b/imxweb/projects/qbm/src/lib/styles/imx-page-title.scss index 8a3f3ca3c..88026ed2e 100644 --- a/imxweb/projects/qbm/src/lib/styles/imx-page-title.scss +++ b/imxweb/projects/qbm/src/lib/styles/imx-page-title.scss @@ -1,17 +1,29 @@ -@import 'variables.scss'; +@import 'base/variables'; -.pageContent h1.mat-headline { - margin: 0 0 40px; - font-size: 26px; - display: flex; - align-items: center; - span{ - white-space: nowrap; - } - @media #{$IMX_Mediaquery_Smartphone} { - margin: 0 0 10px; +.pageContent{ + h2.mat-headline-5 { + margin: 0 0 16px; + font-size: 26px; + display: flex; + align-items: center; + span { + white-space: nowrap; + } + + @media #{$IMX_Mediaquery_Smartphone} { + margin: 0 0 10px; + } + @media #{$IMX_Mediaquery_SmallDesktops} { + margin: 0 0 20px; + } } - @media #{$IMX_Mediaquery_SmallDesktops} { - margin: 0 0 20px; + .imx-header-toolbar{ + display: flex; + justify-content: space-between; + align-items: start; + &-container{ + display:flex; + flex-direction: column; + } } } diff --git a/imxweb/projects/qbm/src/lib/system-info/system-info.service.ts b/imxweb/projects/qbm/src/lib/system-info/system-info.service.ts index dad87cd17..d539d4a2e 100644 --- a/imxweb/projects/qbm/src/lib/system-info/system-info.service.ts +++ b/imxweb/projects/qbm/src/lib/system-info/system-info.service.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -27,21 +27,24 @@ import { Injectable } from '@angular/core'; import { imx_SessionService } from '../session/imx-session.service'; -import { ImxConfig, SystemInfo } from 'imx-api-qbm'; -import { CachedPromise } from 'imx-qbm-dbts'; +import { ImxConfig, SystemInfo } from '@imx-modules/imx-api-qbm'; +import { CachedPromise } from '@imx-modules/imx-qbm-dbts'; import { CacheService } from '../cache/cache.service'; /** Service that provides system info. * The service sends only one request per session, the retrieved data is cached. */ @Injectable({ - providedIn: 'root' + providedIn: 'root', }) export class SystemInfoService { private systemInfo: CachedPromise; private _imxConfig: CachedPromise; - constructor(private readonly session: imx_SessionService, cacheService: CacheService) { + constructor( + private readonly session: imx_SessionService, + cacheService: CacheService, + ) { this.systemInfo = cacheService.buildCache(() => this.session.Client.imx_system_get()); this._imxConfig = cacheService.buildCache(() => this.session.Client.imx_config_get()); } diff --git a/imxweb/projects/qbm/src/lib/table-image/table-image.service.ts b/imxweb/projects/qbm/src/lib/table-image/table-image.service.ts index ffad6c309..fcf65eefe 100644 --- a/imxweb/projects/qbm/src/lib/table-image/table-image.service.ts +++ b/imxweb/projects/qbm/src/lib/table-image/table-image.service.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -27,7 +27,7 @@ import { Injectable } from '@angular/core'; @Injectable({ - providedIn: 'root' + providedIn: 'root', }) export class TableImageService { private readonly cssPrefix = 'imx-table-'; @@ -41,12 +41,10 @@ export class TableImageService { const cssClass = `${this.cssPrefix}${imgId}`; - return (largeImg ? `${cssClass}${this.cssLargeSuffix}` : cssClass); + return largeImg ? `${cssClass}${this.cssLargeSuffix}` : cssClass; } public getDefaultCss(largeImg: boolean = false): string { - return (largeImg ? `${this.defaultCssPrefix}${this.cssLargeSuffix}` : this.defaultCssPrefix); + return largeImg ? `${this.defaultCssPrefix}${this.cssLargeSuffix}` : this.defaultCssPrefix; } - } - diff --git a/imxweb/projects/qbm/src/lib/temp-billboard/temp-billboard.component.ts b/imxweb/projects/qbm/src/lib/temp-billboard/temp-billboard.component.ts deleted file mode 100644 index d5df8c326..000000000 --- a/imxweb/projects/qbm/src/lib/temp-billboard/temp-billboard.component.ts +++ /dev/null @@ -1,139 +0,0 @@ -/* - * ONE IDENTITY LLC. PROPRIETARY INFORMATION - * - * This software is confidential. One Identity, LLC. or one of its affiliates or - * subsidiaries, has supplied this software to you under terms of a - * license agreement, nondisclosure agreement or both. - * - * You may not copy, disclose, or use this software except in accordance with - * those terms. - * - * - * Copyright 2023 One Identity LLC. - * ALL RIGHTS RESERVED. - * - * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR - * WARRANTIES ABOUT THE SUITABILITY OF THE SOFTWARE, - * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED - * TO THE IMPLIED WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE, OR - * NON-INFRINGEMENT. ONE IDENTITY LLC. SHALL NOT BE - * LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE - * AS A RESULT OF USING, MODIFYING OR DISTRIBUTING - * THIS SOFTWARE OR ITS DERIVATIVES. - * - */ - -/** - * @copyright One Identity 2023 - * @license All Rights Reserved - */ - -import { ChangeDetectionStrategy, Component, ElementRef, EventEmitter, Input, OnDestroy, OnInit, Output } from '@angular/core'; -import { Chart, ChartOptions } from 'billboard.js'; -import { debounceTime, tap } from 'rxjs/operators'; -import { EuiThemeService, EuiTheme } from '@elemental-ui/core'; -import { TempBillboardService } from './temp-billboard.service'; - -/** - * @deprecated This will be removed with A15 support. - */ -@Component({ - selector: 'imx-temp-billboard', - template: '
    ', - changeDetection: ChangeDetectionStrategy.OnPush, -}) -export class TempBillboardComponent implements OnDestroy, OnInit { - /** - * You can set billboard.js options with this input, more details see ChartOptions type - * - * @category Input - */ - @Input() - public set options(options: ChartOptions) { - if (!options) { - return; - } - - this._options = options; - } - - /** - * Emit the generated chart to use for advanced functionality - * - * @category Output - * @event - */ - @Output() - public chart = new EventEmitter(); - - /** - * Emit event before chart destroy - * - * @category Output - * @event - */ - @Output() - public beforeDestroy = new EventEmitter(); - - private _chart: Chart | null = null; - private _options: ChartOptions; - private _currentTheme: EuiTheme; - - constructor(private elementRef: ElementRef, private euiThemeService: EuiThemeService, private chartService: TempBillboardService) {} - - /** @internal */ - ngOnInit(): void { - this.euiThemeService - .getActualTheme() - .pipe( - debounceTime(0), - tap((theme: EuiTheme) => { - this._currentTheme = theme; - this.setupChart(); - }) - ) - .subscribe(); - } - - /** @internal */ - ngOnDestroy(): void { - this.beforeDestroy.emit(true); - if (this._chart?.$?.svg) { - this._chart.destroy(); - } - } - - private setupChart(): void { - if (!this._options) { - return; - } - - this.updateColors(); - - if (this._chart !== null) { - this._chart.destroy(); - } - - this._chart = this.chartService.generate({ - bindto: this.elementRef.nativeElement.firstChild, - ...this._options, - }); - - this.chart.emit(this._chart); - } - - private updateColors(): void { - let colors: string[] = ['#0a96d1', '#db2534', '#4ba803', '#ead200', '#b400e5', '#f800b6', '#616566']; - - if (this._currentTheme === EuiTheme.DARK || this._currentTheme === EuiTheme.CONTRAST) { - colors = ['#8acbe3', '#f29d99', '#99c478', '#f2e991', '#d98eed', '#fa96df', '#aab0b3']; - } - - if (!this._options.color) { - this._options.color = {}; - } - - this._options.color.pattern = colors; - } -} diff --git a/imxweb/projects/qbm/src/lib/testing/TestHelperModule.spec.ts b/imxweb/projects/qbm/src/lib/testing/TestHelperModule.spec.ts index 12e14b699..8cdf80e00 100644 --- a/imxweb/projects/qbm/src/lib/testing/TestHelperModule.spec.ts +++ b/imxweb/projects/qbm/src/lib/testing/TestHelperModule.spec.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -28,10 +28,9 @@ import { NgModule, NO_ERRORS_SCHEMA } from '@angular/core'; import { TranslateModule, TranslateLoader, TranslateParser, TranslateFakeLoader, TranslateDefaultParser } from '@ngx-translate/core'; @NgModule({ - exports: [TranslateModule], - imports: [TranslateModule.forRoot({ loader: { provide: TranslateLoader, useClass: TranslateFakeLoader } })], - providers: [{ provide: TranslateParser, useClass: TranslateDefaultParser }], - schemas: [NO_ERRORS_SCHEMA] + exports: [TranslateModule], + imports: [TranslateModule.forRoot({ loader: { provide: TranslateLoader, useClass: TranslateFakeLoader } })], + providers: [{ provide: TranslateParser, useClass: TranslateDefaultParser }], + schemas: [NO_ERRORS_SCHEMA], }) -export class TestHelperModule { -} +export class TestHelperModule {} diff --git a/imxweb/projects/qbm/src/lib/testing/base-imx-api-mock.spec.ts b/imxweb/projects/qbm/src/lib/testing/base-imx-api-mock.spec.ts index 1fdb85304..a9fc21557 100644 --- a/imxweb/projects/qbm/src/lib/testing/base-imx-api-mock.spec.ts +++ b/imxweb/projects/qbm/src/lib/testing/base-imx-api-mock.spec.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -24,65 +24,32 @@ * */ -import * as TypeMoq from 'typemoq'; +import { EntityColumnData, EntityData, IEntity, IEntityColumn, IReadValue } from '@imx-modules/imx-qbm-dbts'; -import { - EntityColumnData, - EntityData, - IEntityColumn, - IReadValue, - IEntity -} from 'imx-qbm-dbts'; - -export function CreateIReadValue(value: T, column: IEntityColumn = CreateIEntityColumn((value as unknown) as string)): IReadValue { - const readValueMock = TypeMoq.Mock.ofType>(); - readValueMock.setup((readValue: IReadValue) => readValue.value).returns(() => value); - readValueMock.setup((readValue: IReadValue) => readValue.Column).returns(() => column); - return readValueMock.object; +export function CreateIReadValue(value: T, column: IEntityColumn = CreateIEntityColumn(value as unknown as string)): IReadValue { + return { value, Column: column } as IReadValue; } -export function CreateIEntityColumn(displayValue: string): IEntityColumn { - const mock = TypeMoq.Mock.ofType(); - mock.setup((item: IEntityColumn) => item.GetDisplayValue).returns(() => () => displayValue); - return mock.object; +export function CreateIEntityColumn(displayValue: string | undefined): IEntityColumn { + return { GetDisplayValue: () => displayValue } as IEntityColumn; } export function CreateIEntity(getColumn: (name: string) => IEntityColumn, typeName?: string, keys?: string[]): IEntity { - const mock = TypeMoq.Mock.ofType(); - mock.setup((item: IEntity) => item.GetColumn).returns(() => (name: string) => getColumn(name)); - if (typeName) { - mock.setup(item => item.TypeName).returns(() => typeName); - } - if (keys && keys.length > 0) { - mock.setup(item => item.GetKeys()).returns(() => keys); - } - return mock.object; + return { getColumn: (name: string) => getColumn(name), TypeName: typeName, GetKeys: () => keys } as unknown as IEntity; } export class BaseImxApiDtoMock { public static CreateEntityDataCollection(dataCollection: EntityData[]): EntityData[] { - const result = dataCollection.map(data => { - if (data === null) { - return null; - } - - const mock = TypeMoq.Mock.ofType(); - mock.setup(property => property.Display).returns(() => data.Display); - mock.setup(property => property.LongDisplay).returns(() => data.LongDisplay); - mock.setup(property => property.Keys).returns(() => data.Keys); - mock.setup(property => property.Columns).returns(() => BaseImxApiDtoMock.CreateEntityDataColumnCollection(data.Columns)); - return mock.object; + const result = dataCollection.map((data) => { + return { ...data }; }); return result; } private static CreateEntityDataColumnCollection(columns: { [key: string]: EntityColumnData }): { [key: string]: EntityColumnData } { const entityDataColumns: { [key: string]: EntityColumnData } = {}; - Object.keys(columns).forEach(key => { - const mock = TypeMoq.Mock.ofType(); - mock.setup(property => property.DisplayValue).returns(() => columns[key].DisplayValue); - mock.setup(property => property.Value).returns(() => columns[key].Value); - entityDataColumns[key] = mock.object; + Object.keys(columns).forEach((key) => { + entityDataColumns[key] = { DisplayValue: columns[key].DisplayValue, Value: columns[key].Value }; }); return entityDataColumns; } @@ -90,7 +57,7 @@ export class BaseImxApiDtoMock { export class BaseImxApiDataMock { public static CreateEntityDataCollection(createEntity: (i: number) => TEntityCollection, numOfEntries: number) { - const dataCollection = []; + const dataCollection: TEntityCollection[] = []; for (let i = 1; i <= numOfEntries; i++) { dataCollection.push(createEntity(i)); } diff --git a/imxweb/projects/qbm/src/lib/testing/clear-styles.spec.ts b/imxweb/projects/qbm/src/lib/testing/clear-styles.spec.ts index dc7c4decd..7a8a7aa36 100644 --- a/imxweb/projects/qbm/src/lib/testing/clear-styles.spec.ts +++ b/imxweb/projects/qbm/src/lib/testing/clear-styles.spec.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -24,11 +24,11 @@ * */ -export function clearStylesFromDOM (): void { +export function clearStylesFromDOM(): void { const head: HTMLHeadElement = document.getElementsByTagName('head')[0]; - const styles : HTMLCollectionOf | [] = head.getElementsByTagName('style'); + const styles: HTMLCollectionOf | [] = head.getElementsByTagName('style'); - for (let i: number; i < styles.length; i++) { + for (let i: number = 0; i < styles.length; i++) { head.removeChild(styles[i]); } } diff --git a/imxweb/projects/qbm/src/lib/testing/dst-mock-help.spec.ts b/imxweb/projects/qbm/src/lib/testing/dst-mock-help.spec.ts index fe62be7d3..63b7a8d9c 100644 --- a/imxweb/projects/qbm/src/lib/testing/dst-mock-help.spec.ts +++ b/imxweb/projects/qbm/src/lib/testing/dst-mock-help.spec.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -24,7 +24,7 @@ * */ -import { ValType, IClientProperty } from "imx-qbm-dbts"; +import { ValType, IClientProperty } from '@imx-modules/imx-qbm-dbts'; export const mockDSTColumns: IClientProperty[] = [ { @@ -46,5 +46,5 @@ export const mockDSTColumns: IClientProperty[] = [ { Type: ValType.String, ColumnName: 'UID_DialogProduct', - } + }, ]; diff --git a/imxweb/projects/qbm/src/lib/testing/entity-column-stub.spec.ts b/imxweb/projects/qbm/src/lib/testing/entity-column-stub.spec.ts index b6f2be5f8..dffe1fe08 100644 --- a/imxweb/projects/qbm/src/lib/testing/entity-column-stub.spec.ts +++ b/imxweb/projects/qbm/src/lib/testing/entity-column-stub.spec.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -24,21 +24,30 @@ * */ -import { IEntityColumn, DataState, ValType, IValueMetadata, ValueStruct, IEntity, IColumnChangeArgs, IEvent } from 'imx-qbm-dbts'; +import { + DataState, + IColumnChangeArgs, + IEntity, + IEntityColumn, + IEvent, + IValueMetadata, + ValType, + ValueStruct, +} from '@imx-modules/imx-qbm-dbts'; export class EntityColumnStub implements IEntityColumn { GetEntity(): IEntity { - return null; + return {} as IEntity; } ColumnName = 'someColumnName'; - ExtendedProperties: { [id: string]: any; }; + ExtendedProperties: { [id: string]: any }; constructor( private value?: T, private displayValue?: string, - private metadata = { CanEdit: () => true } as IValueMetadata + private metadata = { CanEdit: () => true } as IValueMetadata, ) {} - + ColumnChanged: IEvent; GetDataState(): DataState { @@ -53,16 +62,16 @@ export class EntityColumnStub implements IEntityColumn { return this.metadata; } - GetValue(): T { + GetValue(): T | undefined { return this.value; } GetDisplayValue(): string { - return this.displayValue; + return this.displayValue ?? ''; } async PutValue(value: T): Promise { - await new Promise(resolve => setTimeout(resolve, 1000)); + await new Promise((resolve) => setTimeout(resolve, 1000)); this.value = value; } diff --git a/imxweb/projects/qbm/src/lib/testing/entity-schema-stub.spec.ts b/imxweb/projects/qbm/src/lib/testing/entity-schema-stub.spec.ts index 9986045c8..a91f9b98f 100644 --- a/imxweb/projects/qbm/src/lib/testing/entity-schema-stub.spec.ts +++ b/imxweb/projects/qbm/src/lib/testing/entity-schema-stub.spec.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -24,8 +24,7 @@ * */ -import { EntitySchema, IClientProperty, ValType } from "imx-qbm-dbts"; - +import { EntitySchema, IClientProperty, ValType } from '@imx-modules/imx-qbm-dbts'; export interface ClientPropertyMock { name: string; @@ -35,19 +34,15 @@ export interface ClientPropertyMock { } export class EntitySchemaStub implements EntitySchema { - - constructor( - properties: ClientPropertyMock[] - ) { + constructor(properties: ClientPropertyMock[]) { properties.forEach( - property => + (property) => (this.Columns[property.name] = { Type: property.type ? property.type : ValType.String, Display: property.Display, - }) + }), ); } public Columns: { [id: string]: IClientProperty } = {}; - } diff --git a/imxweb/projects/qbm/src/lib/tile/tile-variables.scss b/imxweb/projects/qbm/src/lib/tile/tile-variables.scss deleted file mode 100644 index 809739de6..000000000 --- a/imxweb/projects/qbm/src/lib/tile/tile-variables.scss +++ /dev/null @@ -1 +0,0 @@ -$tile-width: 395px; \ No newline at end of file diff --git a/imxweb/projects/qbm/src/lib/tile/tile.component.html b/imxweb/projects/qbm/src/lib/tile/tile.component.html index 55f8b997a..c39d05b7d 100644 --- a/imxweb/projects/qbm/src/lib/tile/tile.component.html +++ b/imxweb/projects/qbm/src/lib/tile/tile.component.html @@ -1,52 +1,60 @@
    - +
    - - - + +
    - - +
    - - - + +
    - - - + + - - - + +
    - +
    - - - - + +
    @@ -54,47 +62,64 @@
    - + -
    +
    -

    - {{caption}} -

    +

    + {{ caption }} +

    - {{subtitle}} + {{ subtitle }}

    -
    - +
    - - + [ngClass]="'imx-generic-tile-value' + (showImageAsValue() && showImageAsIconFont() ? ' imx-generic-tile-iconfont' : '')" + > - - - - {{showImageAsValue() ? ' ' : value}} + + + + {{ showImageAsValue() ? ' ' : value }} diff --git a/imxweb/projects/qbm/src/lib/tile/tile.component.scss b/imxweb/projects/qbm/src/lib/tile/tile.component.scss index d898664b7..f47d1dfa6 100644 --- a/imxweb/projects/qbm/src/lib/tile/tile.component.scss +++ b/imxweb/projects/qbm/src/lib/tile/tile.component.scss @@ -1,12 +1,9 @@ -@import "variables.scss"; -@import "./tile-variables.scss"; @import '@elemental-ui/core/src/styles/_eui_palette.scss'; - +@import 'base/variables'; // TODO: Cleanup. Do we need all classed? .imx-generic-tile { text-align: center; - color: $VI_Common_Color_Font; vertical-align: top; } @@ -22,7 +19,7 @@ font-size: 1.35em; } -.imx-generic-tile h1 { +.imx-generic-tile h3 { display: block; font-size: 0.975em; font-weight: normal; @@ -30,22 +27,22 @@ padding: 0px; } -.imx-generic-tile.square h1 { +.imx-generic-tile.square h3 { display: inline; font-size: 1.05em; } -.imx-generic-tile.overview h1 { +.imx-generic-tile.overview h3 { display: inline; font-size: 1.05em; } -.imx-generic-tile.large-overview h1 { +.imx-generic-tile.large-overview h3 { display: inline; font-size: 1.05em; } -.imx-generic-tile.dashboard h1 { +.imx-generic-tile.dashboard h3 { font-size: 1.15em; font-weight: 600; text-overflow: ellipsis; @@ -61,13 +58,13 @@ color: $black-b; } -section.imx-generic-tile.addon-tile > .mat-card > a { +section.imx-generic-tile.addon-tile > .mat-mdc-card > a { width: 100%; height: 100%; overflow: auto; } -.imx-generic-tile.addon-tile h1 { +.imx-generic-tile.addon-tile h3 { font-size: 1.05em; } @@ -131,53 +128,49 @@ section.imx-generic-tile.addon-tile > .mat-card > a { width: 100%; } -.mat-button { - text-transform: uppercase; -} - -.imx-mobile-nomobile > .mat-button { +.imx-mobile-nomobile > .mat-mdc-button { margin-right: -17px; } -.addon-tile .mat-card { +.addon-tile .mat-mdc-card { height: 120px; - width: $tile-width; + width: $IMX_Tile_Width; padding: 0; cursor: auto; } -.square .mat-card { +.square .mat-mdc-card { height: 7.5em; cursor: auto; } -.overview .mat-card { +.overview .mat-mdc-card { height: 175px; - width: $tile-width; + width: $IMX_Tile_Width; cursor: auto; overflow: auto; padding: 0; } -.dashboard .mat-card { +.dashboard .mat-mdc-card { height: 245px; display: flex; - width: $tile-width; + width: $IMX_Tile_Width; cursor: auto; overflow: auto; padding: 7px; flex-direction: column; } -.large-overview .mat-card { +.large-overview .mat-mdc-card { display: flex; min-height: 415px; - width: $tile-width; + width: $IMX_Tile_Width; cursor: auto; overflow: auto; padding: 0; } -section{ +section { position: relative; } section.imx-generic-tile { @@ -220,7 +213,7 @@ section.imx-generic-tile.large-overview { .imx-generic-tile-value { display: block; text-align: center; - color: $VI_Common_Color_Font; + color: $color-gray-80; font-size: 3em; } @@ -234,7 +227,7 @@ section.imx-generic-tile.large-overview { .overview .imx-generic-tile-value { display: block; text-align: left; - color: $VI_Common_Color_Font; + color: $color-gray-80; font-size: 0.9em; width: 280px; padding: 12px 0px 0px 0px; @@ -247,7 +240,7 @@ section.imx-generic-tile.large-overview { overflow: auto; } -section.imx-generic-tile.dashboard > .mat-card { +section.imx-generic-tile.dashboard > .mat-mdc-card { > div { padding: 6px 18px; } @@ -274,13 +267,13 @@ section.imx-generic-tile.dashboard > .mat-card { overflow: auto; } -.imx-generic-tile a[data-imx-identifier="tile-link"] { +.imx-generic-tile a[data-imx-identifier='tile-link'] { transition-property: all; transition-duration: 0.15s; height: 100%; } -.imx-generic-tile.large-overview a[data-imx-identifier="tile-link"] { +.imx-generic-tile.large-overview a[data-imx-identifier='tile-link'] { height: auto; } @@ -306,15 +299,9 @@ section.imx-generic-tile.dashboard > .mat-card { justify-content: center; background: rgba($color-gray-100, 0.32); border-radius: 4px; - .mat-spinner, - .mat-spinner svg { - max-height: 40px; - max-width: 40px; - } } } - /** TODO (TFS 805997) .highlighted .imx-generic-tile-iconfont { color: $VI_Common_Color_Badge_Warning; @@ -360,7 +347,7 @@ section.imx-generic-tile.dashboard > .mat-card { .IconImage a:link { text-decoration: none; - color: $VI_Common_Color_Font_Secondary; + color: $color-gray-80; outline: none; } diff --git a/imxweb/projects/qbm/src/lib/tile/tile.component.ts b/imxweb/projects/qbm/src/lib/tile/tile.component.ts index 9bb2d3f91..576519891 100644 --- a/imxweb/projects/qbm/src/lib/tile/tile.component.ts +++ b/imxweb/projects/qbm/src/lib/tile/tile.component.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -24,15 +24,14 @@ * */ -import { Component, EventEmitter, Input, Output, ContentChild, TemplateRef, ElementRef } from '@angular/core'; +import { Component, ContentChild, ElementRef, EventEmitter, Input, Output, TemplateRef } from '@angular/core'; @Component({ templateUrl: './tile.component.html', selector: 'imx-tile', - styleUrls: ['./tile.component.scss'] + styleUrls: ['./tile.component.scss'], }) export class TileComponent { - @Input() public caption: string; @Input() public subtitle: string; @Input() public actionText = '#LDS#View'; @@ -81,12 +80,11 @@ export class TileComponent { } public showImageInHeader(): boolean { - return this.image - && this.contentType !== 'Image'; + return this.image != null && this.contentType !== 'Image'; } public showImageAsValue(): boolean { - return this.image && this.contentType === 'Image'; + return this.image != null && this.contentType === 'Image'; } public showImageAsIconFont(): boolean { @@ -94,28 +92,26 @@ export class TileComponent { } public styleImage(): string { - let style: string; - if (this.showImageAsValue) { + let style: string = ''; + if (this.showImageAsValue()) { style = 'background-position: center; '; } return style + `background-repeat: no-repeat; background-image: url('${this.urlImage()}');`; } public urlImage(): string { - let firstPart: string; + let firstPart: string = ''; if (this.imageType === 'Url') { firstPart = this.image; } - let size: string; - if (this.showImageAsValue) { + let size: string = ''; + if (this.showImageAsValue()) { size = '&size=Large'; - } else if (this.showImageInHeader) { + } else if (this.showImageInHeader()) { size = '&size=big'; } - return firstPart + encodeURI(this.image) + size; } - } diff --git a/imxweb/projects/qbm/src/lib/tile/tile.module.ts b/imxweb/projects/qbm/src/lib/tile/tile.module.ts index f0abe7139..73e511131 100644 --- a/imxweb/projects/qbm/src/lib/tile/tile.module.ts +++ b/imxweb/projects/qbm/src/lib/tile/tile.module.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -33,23 +33,9 @@ import { EuiCoreModule, EuiMaterialModule } from '@elemental-ui/core'; import { MatButtonModule } from '@angular/material/button'; import { TranslateModule } from '@ngx-translate/core'; - @NgModule({ - declarations: [ - TileComponent, - ChartTileComponent - ], - imports: [ - CommonModule, - MatCardModule, - MatButtonModule, - EuiCoreModule, - TranslateModule, - EuiMaterialModule - ], - exports: [ - ChartTileComponent, - TileComponent - ] + declarations: [TileComponent, ChartTileComponent], + imports: [CommonModule, MatCardModule, MatButtonModule, EuiCoreModule, TranslateModule, EuiMaterialModule], + exports: [ChartTileComponent, TileComponent], }) -export class TileModule { } +export class TileModule {} diff --git a/imxweb/projects/qbm/src/lib/timeline/timeline.component.html b/imxweb/projects/qbm/src/lib/timeline/timeline.component.html index 1f5f67c0a..041265a5d 100644 --- a/imxweb/projects/qbm/src/lib/timeline/timeline.component.html +++ b/imxweb/projects/qbm/src/lib/timeline/timeline.component.html @@ -1,4 +1,4 @@ -
    +
    @@ -11,10 +11,28 @@
    - +
    {{ event.Time }} + + + {{ event.ChangeType }} ({{ event.User }}) - @@ -34,9 +52,9 @@
    - -

    - {{ '#LDS#No data' | translate }} -

    + +
    + {{ (data.length === 0 ? '#LDS#No data' : '#LDS#There were no changes during the selected period.') | translate }} +
    diff --git a/imxweb/projects/qbm/src/lib/timeline/timeline.component.scss b/imxweb/projects/qbm/src/lib/timeline/timeline.component.scss index bcaaf27b7..06a85efdb 100644 --- a/imxweb/projects/qbm/src/lib/timeline/timeline.component.scss +++ b/imxweb/projects/qbm/src/lib/timeline/timeline.component.scss @@ -15,9 +15,12 @@ display: flex; gap: 8px; min-height: 40px; - color: $color-blue-60; + color: $color-gray-80; font-weight: 700; pointer-events: none; + .mat-mdc-card-content{ + padding:0 !important; + } &:hover { .imx-timeline-date { @@ -41,6 +44,9 @@ } } + .imx-timeline-date{ + line-height: 16px; + } .imx-timeline-separator { flex: 0; display: flex; @@ -48,7 +54,7 @@ flex-direction: column; &-marker { - border: 2px solid $color-blue-60; + border: 2px solid $color-gray-80; border-radius: 50%; width: 1rem; height: 1rem; @@ -65,18 +71,21 @@ .imx-timeline-events { font-weight: 600; padding-bottom: 20px; - mat-card { padding: 0; pointer-events: none; &:hover { - box-shadow: 0px 5px 5px 0px rgba(0, 0, 0, 0.20); + box-shadow: 0px 5px 5px 0px rgba(0, 0, 0, 0.2); } .imx-timeline-event { - padding: 1rem; + padding: 0px 16px; pointer-events: auto; + font-size:14px; + display: flex; + align-items: center; + line-height: 38px; &:hover { background-color: $color-orange-10; @@ -92,34 +101,41 @@ } } - &:nth-child(n+2) { - background-image: linear-gradient(to right, $color-gray-10 33%, rgba(255,255,255,0) 0%); + &:nth-child(n + 2) { + background-image: linear-gradient(to right, $color-gray-10 33%, rgba(255, 255, 255, 0) 0%); background-position: top; background-size: 13px 1px; background-repeat: repeat-x; } &-time { - padding-right: 1rem; + padding-right: 8px; + font-weight: 700; } &-display { font-weight: 400; } + .imx-timeline-icon{ + font-size: 20px !important; + padding-right: 8px; + &-edit{ + color: $color-blue-60; + } + &-add{ + color: $color-green-60; + } + &-remove{ + color: $color-red-60; + } + } } } } } - .imx-no-results { - height: 100%; - display: flex; - flex-direction: column; - justify-content: center; - align-items: center; - - .eui-icon { - color: $color-gray-10; + div { + font-size: 18px; } } } @@ -132,7 +148,7 @@ background-color: $color-blue-80; .imx-timeline-events-group { - color: $color-blue-40; + color: $color-gray-2; &:hover { .imx-timeline-date { @@ -167,8 +183,8 @@ background-color: $color-gray-80; } - &:nth-child(n+2) { - background-image: linear-gradient(to right, $color-gray-60 33%, rgba(255,255,255,0) 0%); + &:nth-child(n + 2) { + background-image: linear-gradient(to right, $color-gray-60 33%, rgba(255, 255, 255, 0) 0%); background-position: top; background-size: 13px 1px; background-repeat: repeat-x; @@ -176,13 +192,6 @@ } } } - - .imx-no-results { - .eui-icon { - color: $color-gray-20; - } - } } } } - diff --git a/imxweb/projects/qbm/src/lib/timeline/timeline.component.ts b/imxweb/projects/qbm/src/lib/timeline/timeline.component.ts index 14a18ef70..d74ea7f13 100644 --- a/imxweb/projects/qbm/src/lib/timeline/timeline.component.ts +++ b/imxweb/projects/qbm/src/lib/timeline/timeline.component.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -24,22 +24,23 @@ * */ -import { Component, Input, OnChanges, OnInit, SimpleChanges } from '@angular/core'; -import { TimelineEventsGroupedByDate, ExtendedObjectHistoryEvent } from './timeline'; +import { Component, Input, OnChanges, OnInit } from '@angular/core'; import moment from 'moment-timezone'; -import { ObjectHistoryService } from '../object-history/object-history.service'; +import { ExtendedObjectHistoryEvent, TimelineEventsGroupedByDate } from './timeline'; +import { EventChangeTypes, HistoryEventChangeType } from './timeline.model'; @Component({ selector: 'imx-timeline', templateUrl: './timeline.component.html', - styleUrls: ['./timeline.component.scss'] + styleUrls: ['./timeline.component.scss'], }) export class TimelineComponent implements OnInit, OnChanges { - @Input() public data: ExtendedObjectHistoryEvent[]; + @Input() public data: ExtendedObjectHistoryEvent[] = []; public eventsGroupedByDate: TimelineEventsGroupedByDate[] = []; + public eventChangeTypes = EventChangeTypes; - constructor() { } + constructor() {} /** * Inits table @@ -62,19 +63,23 @@ export class TimelineComponent implements OnInit, OnChanges { this.eventsGroupedByDate = []; this.data.forEach((elem) => { - const date = moment(elem.ChangeTime).format("L"); + const date = moment(elem.ChangeTime).format('L'); - elem.Time = moment(elem.ChangeTime).format("HH:mm:ss"); + elem.Time = moment(elem.ChangeTime).format('HH:mm:ss'); if (this.eventsGroupedByDate.some((event) => event.date === date)) { - const dateEvents = this.eventsGroupedByDate.find((event) => event.date === date).events; + const dateEvents = this.eventsGroupedByDate?.find((event) => event.date === date)?.events ?? []; dateEvents.push(elem); dateEvents.sort((a, b) => b.Time.localeCompare(a.Time)); } else { this.eventsGroupedByDate.push({ date: date, - events: [elem] + events: [elem], }); } }); } + + public getEventChangeType(event: ExtendedObjectHistoryEvent): EventChangeTypes { + return HistoryEventChangeType[event.ChangeTypeId || '']; + } } diff --git a/imxweb/projects/qbm/src/lib/timeline/timeline.model.ts b/imxweb/projects/qbm/src/lib/timeline/timeline.model.ts new file mode 100644 index 000000000..bd4f91ca8 --- /dev/null +++ b/imxweb/projects/qbm/src/lib/timeline/timeline.model.ts @@ -0,0 +1,53 @@ +/* + * ONE IDENTITY LLC. PROPRIETARY INFORMATION + * + * This software is confidential. One Identity, LLC. or one of its affiliates or + * subsidiaries, has supplied this software to you under terms of a + * license agreement, nondisclosure agreement or both. + * + * You may not copy, disclose, or use this software except in accordance with + * those terms. + * + * + * Copyright 2024 One Identity LLC. + * ALL RIGHTS RESERVED. + * + * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR + * WARRANTIES ABOUT THE SUITABILITY OF THE SOFTWARE, + * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED + * TO THE IMPLIED WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE, OR + * NON-INFRINGEMENT. ONE IDENTITY LLC. SHALL NOT BE + * LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE + * AS A RESULT OF USING, MODIFYING OR DISTRIBUTING + * THIS SOFTWARE OR ITS DERIVATIVES. + * + */ + +export enum EventChangeTypes { + Edit, + Add, + Remove, +} +export type EventChangeType = EventChangeTypes.Add | EventChangeTypes.Edit | EventChangeTypes.Remove; + +export enum HistoryEventChangeType { + 'Object created' = EventChangeTypes.Edit, + 'PropertyChange' = EventChangeTypes.Edit, + 'AddResponsibility' = EventChangeTypes.Add, + 'AddMembership' = EventChangeTypes.Add, + 'Entitlement has been added' = EventChangeTypes.Add, + 'Rule violation resolved' = EventChangeTypes.Add, + 'Rule violation detected' = EventChangeTypes.Remove, + 'Entitlement removed' = EventChangeTypes.Remove, + 'Entitlement has been removed' = EventChangeTypes.Remove, + 'Membership removed' = EventChangeTypes.Remove, + 'Object deleted' = EventChangeTypes.Remove, + 'AddAccount' = EventChangeTypes.Add, + 'AddPermission' = EventChangeTypes.Add, + 'RemoveNonCompliance' = EventChangeTypes.Add, + 'AddNonCompliance' = EventChangeTypes.Remove, + 'RemoveResponsibility' = EventChangeTypes.Remove, + 'RemovePermission' = EventChangeTypes.Remove, + 'RemoveAccount' = EventChangeTypes.Remove, +} diff --git a/imxweb/projects/qbm/src/lib/timeline/timeline.ts b/imxweb/projects/qbm/src/lib/timeline/timeline.ts index b63128460..ccd5df53a 100644 --- a/imxweb/projects/qbm/src/lib/timeline/timeline.ts +++ b/imxweb/projects/qbm/src/lib/timeline/timeline.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -24,7 +24,7 @@ * */ -import { ObjectHistoryEvent } from 'imx-qbm-dbts'; +import { ObjectHistoryEvent } from '@imx-modules/imx-qbm-dbts'; export interface TimelineDateTimeFilter { date: string; diff --git a/imxweb/projects/qbm/src/lib/translation-editor/translation-editor.component.html b/imxweb/projects/qbm/src/lib/translation-editor/translation-editor.component.html index 3b6c9648c..765bdc58a 100644 --- a/imxweb/projects/qbm/src/lib/translation-editor/translation-editor.component.html +++ b/imxweb/projects/qbm/src/lib/translation-editor/translation-editor.component.html @@ -1,20 +1,17 @@ - -

    {{ '#LDS#Heading Edit Translations' | translate}}

    +

    {{ '#LDS#Heading Edit Translations' | translate }}

    - - - {{getDisplay(column)}} {{item.value}} - + + + {{ getDisplay(column) }} {{ item.value }} +
    -
    - - -
    \ No newline at end of file +
    diff --git a/imxweb/projects/qbm/src/lib/translation-editor/translation-editor.component.scss b/imxweb/projects/qbm/src/lib/translation-editor/translation-editor.component.scss index 4afbf24f5..ff8b92611 100644 --- a/imxweb/projects/qbm/src/lib/translation-editor/translation-editor.component.scss +++ b/imxweb/projects/qbm/src/lib/translation-editor/translation-editor.component.scss @@ -1,12 +1,10 @@ + +@import 'base/mixins'; :host { - display: flex; - flex-direction: column; - height: inherit; - } - - .mat-dialog-content { - flex: 1; - display: flex; - flex-direction: column; - height: inherit; - } \ No newline at end of file + @include flex-column-container($height: inherit); +} + +.mat-mdc-dialog-content { + @include flex-column-container($height: inherit); + flex: 1; +} diff --git a/imxweb/projects/qbm/src/lib/translation-editor/translation-editor.component.ts b/imxweb/projects/qbm/src/lib/translation-editor/translation-editor.component.ts index 891adba86..37c1c07a4 100644 --- a/imxweb/projects/qbm/src/lib/translation-editor/translation-editor.component.ts +++ b/imxweb/projects/qbm/src/lib/translation-editor/translation-editor.component.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -25,30 +25,28 @@ */ import { Component, ErrorHandler, Inject, OnInit } from '@angular/core'; -import { MatDialogRef, MAT_DIALOG_DATA } from '@angular/material/dialog'; +import { MAT_DIALOG_DATA, MatDialogRef } from '@angular/material/dialog'; import { EuiLoadingService } from '@elemental-ui/core'; -import { ReadWriteExtTypedEntity, TranslationDataRead, TranslationDataWrite, TranslationDataWriteElement } from 'imx-qbm-dbts'; +import { ReadWriteExtTypedEntity, TranslationDataRead, TranslationDataWrite, TranslationDataWriteElement } from '@imx-modules/imx-qbm-dbts'; import { SnackBarService } from '../snackbar/snack-bar.service'; @Component({ selector: 'imx-translation-editor', templateUrl: './translation-editor.component.html', - styleUrls: ['./translation-editor.component.scss'] + styleUrls: ['./translation-editor.component.scss'], }) export class TranslationEditorComponent implements OnInit { - - public translationData: TranslationDataRead; - public translationDataWrite: TranslationDataWrite={}; + public translationData: TranslationDataRead | undefined; + public translationDataWrite: TranslationDataWrite = {}; constructor( - @Inject(MAT_DIALOG_DATA) public data: ReadWriteExtTypedEntity<{ Translations?: TranslationDataRead}, TranslationDataWrite>, + @Inject(MAT_DIALOG_DATA) public data: ReadWriteExtTypedEntity<{ Translations?: TranslationDataRead }, TranslationDataWrite>, private readonly snackbar: SnackBarService, private readonly busyService: EuiLoadingService, private readonly errorHandler: ErrorHandler, public dialogRef: MatDialogRef, - ) { - } + ) {} public ngOnInit(): void { if (this.data && this.data.extendedDataRead) { @@ -56,62 +54,63 @@ export class TranslationEditorComponent implements OnInit { this.translationDataWrite.Translations = []; } - if (this.translationData.Translations[0]) { - Object.keys(this.translationData.Translations[0]).forEach( - key => { - this.translationData.Translations[0][key].forEach( - data=>{ - let translationDataWriteElement:TranslationDataWriteElement = {}; - translationDataWriteElement.ColumnName = key; - translationDataWriteElement.TranslationKey = this.data.GetEntity().GetColumn(key).GetValue(); - translationDataWriteElement.TranslationValue = data.Translation; - translationDataWriteElement.UidCulture = data.LanguageId; - this.translationDataWrite.Translations.push(translationDataWriteElement); - } - ); - } - ); + if (this.translationData?.Translations?.[0]) { + Object.keys(this.translationData?.Translations?.[0]).forEach((key) => { + this.translationData?.Translations?.[0][key].forEach((data) => { + let translationDataWriteElement: TranslationDataWriteElement = {}; + translationDataWriteElement.ColumnName = key; + translationDataWriteElement.TranslationKey = this.data.GetEntity().GetColumn(key).GetValue(); + translationDataWriteElement.TranslationValue = data.Translation; + translationDataWriteElement.UidCulture = data.LanguageId; + this.translationDataWrite?.Translations?.push(translationDataWriteElement); + }); + }); } } - public getDisplay(column:string) : string{ + public getDisplay(column: string): string { return this.data.GetEntity().GetColumn(column).GetMetadata().GetDisplay(); } - public getValue(columnName: string, uidCulture) : string { - let value = ""; - if (this.translationData.Translations[0]) { - let matchedData = this.translationData.Translations[0][columnName]; + public getValue(columnName: string, uidCulture): string { + let value = ''; + if (this.translationData?.Translations?.[0]) { + let matchedData = this.translationData?.Translations?.[0][columnName]; if (matchedData) { - value = matchedData.find(x => x.LanguageId == uidCulture) - ? matchedData.find(x=>x.LanguageId == uidCulture).Translation - : ""; + value = matchedData.find((x) => x.LanguageId == uidCulture)?.Translation ?? ''; } } return value; } - public onInput(translationValue: string, columnName: string, uidCulture: string): void { - if (this.translationDataWrite && this.translationDataWrite.Translations - && this.translationDataWrite.Translations.find(x => x.ColumnName === columnName && x.UidCulture === uidCulture)) { - let matchedElement = this.translationDataWrite.Translations.find(x => x.ColumnName === columnName && x.UidCulture === uidCulture); - matchedElement.TranslationValue = translationValue; - } - else { + public onInput(translationValueTarget: Event, columnName: string, uidCulture: string): void { + const translationValue = (translationValueTarget.target as any)?.value; + if ( + this.translationDataWrite && + this.translationDataWrite.Translations && + this.translationDataWrite.Translations.find((x) => x.ColumnName === columnName && x.UidCulture === uidCulture) + ) { + let matchedElement = this.translationDataWrite.Translations.find((x) => x.ColumnName === columnName && x.UidCulture === uidCulture); + if (matchedElement) { + matchedElement.TranslationValue = translationValue; + } + } else { let translationDataWriteElement: TranslationDataWriteElement = {}; translationDataWriteElement.ColumnName = columnName; translationDataWriteElement.TranslationKey = this.data.GetEntity().GetColumn(columnName).GetValue(); translationDataWriteElement.TranslationValue = translationValue; translationDataWriteElement.UidCulture = uidCulture; - this.translationDataWrite.Translations.push(translationDataWriteElement); + this.translationDataWrite?.Translations?.push(translationDataWriteElement); } } - public async save():Promise{ - const overlayRef = this.busyService.show(); + public async save(): Promise { + if (this.busyService.overlayRefs.length === 0) { + this.busyService.show(); + } try { await this.data.setExtendedData({ - Translations: this.translationDataWrite.Translations + Translations: this.translationDataWrite.Translations, }); await this.data.GetEntity().Commit(); @@ -119,9 +118,8 @@ export class TranslationEditorComponent implements OnInit { } catch (error) { this.errorHandler.handleError(error); } finally { - setTimeout(() => this.busyService.hide(overlayRef)); + this.busyService.hide(); this.dialogRef.close(); } } - } diff --git a/imxweb/projects/qbm/src/lib/translation/imx-missing-translation-handler.spec.ts b/imxweb/projects/qbm/src/lib/translation/imx-missing-translation-handler.spec.ts index 781581375..0810d7eeb 100644 --- a/imxweb/projects/qbm/src/lib/translation/imx-missing-translation-handler.spec.ts +++ b/imxweb/projects/qbm/src/lib/translation/imx-missing-translation-handler.spec.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -27,27 +27,31 @@ import { ImxMissingTranslationHandler } from './imx-missing-translation-handler'; describe('imx_MissingTranslationHandler', () => { - [ - { - text: 'text', - expected: 'text' - }, - { - text: '#LDS#text', - expected: 'text' - }, - { - text: '#LDS##LDS#text', - expected: '#LDS#text' - }, - { - text: 'text#LDS#', - expected: 'text#LDS#' - } - ].forEach(testcase => it('should provide a handle method', () => { - expect(new ImxMissingTranslationHandler().handle({ - key: testcase.text, - translateService: null - })).toEqual(testcase.expected); - })); + [ + { + text: 'text', + expected: 'text', + }, + { + text: '#LDS#text', + expected: 'text', + }, + { + text: '#LDS##LDS#text', + expected: '#LDS#text', + }, + { + text: 'text#LDS#', + expected: 'text#LDS#', + }, + ].forEach((testcase) => + it('should provide a handle method', () => { + expect( + new ImxMissingTranslationHandler().handle({ + key: testcase.text, + translateService: null, + }), + ).toEqual(testcase.expected); + }), + ); }); diff --git a/imxweb/projects/qbm/src/lib/translation/imx-missing-translation-handler.ts b/imxweb/projects/qbm/src/lib/translation/imx-missing-translation-handler.ts index b64ffb7dd..e12d05049 100644 --- a/imxweb/projects/qbm/src/lib/translation/imx-missing-translation-handler.ts +++ b/imxweb/projects/qbm/src/lib/translation/imx-missing-translation-handler.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -28,8 +28,6 @@ import { MissingTranslationHandler, MissingTranslationHandlerParams } from '@ngx export class ImxMissingTranslationHandler implements MissingTranslationHandler { public handle(params: MissingTranslationHandlerParams): string { - return params.key.startsWith('#LDS#') - ? params.key.substring('#LDS#'.length) - : params.key; + return params.key.startsWith('#LDS#') ? params.key.substring('#LDS#'.length) : params.key; } } diff --git a/imxweb/projects/qbm/src/lib/translation/imx-translate-loader.ts b/imxweb/projects/qbm/src/lib/translation/imx-translate-loader.ts index db42421e6..7599e4d97 100644 --- a/imxweb/projects/qbm/src/lib/translation/imx-translate-loader.ts +++ b/imxweb/projects/qbm/src/lib/translation/imx-translate-loader.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -26,7 +26,7 @@ import { Observable, from } from 'rxjs'; import { Injectable } from '@angular/core'; -import { TranslateLoader} from '@ngx-translate/core'; +import { TranslateLoader } from '@ngx-translate/core'; import { imx_SessionService } from '../session/imx-session.service'; @Injectable() @@ -40,7 +40,7 @@ export class ImxTranslateLoader implements TranslateLoader { private async getCaptionsLds(culture: string): Promise<{ [key: string]: string }> { const translations = await this.session.Client.imx_multilanguage_getcaptions_get({ cultureName: culture }); const translationsLds: { [key: string]: string } = {}; - Object.keys(translations).forEach((key: string) => translationsLds['#LDS#' + key] = translations[key]); + Object.keys(translations).forEach((key: string) => (translationsLds['#LDS#' + key] = translations[key])); return translationsLds; } } diff --git a/imxweb/projects/qbm/src/lib/translation/imx-translation-provider.service.ts b/imxweb/projects/qbm/src/lib/translation/imx-translation-provider.service.ts index a734a42f7..01969a229 100644 --- a/imxweb/projects/qbm/src/lib/translation/imx-translation-provider.service.ts +++ b/imxweb/projects/qbm/src/lib/translation/imx-translation-provider.service.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -26,18 +26,19 @@ import { Injectable } from '@angular/core'; import { DateAdapter } from '@angular/material/core'; +import { DefaultServiceResolver, EntitySchema, ITranslationProvider, MultiLanguageStringData } from '@imx-modules/imx-qbm-dbts'; import { TranslateService } from '@ngx-translate/core'; -import { ITranslationProvider, MultiLanguageStringData, EntitySchema, DefaultServiceResolver } from 'imx-qbm-dbts'; +import moment from 'moment-timezone'; import { Observable } from 'rxjs'; import { map } from 'rxjs/operators'; -import moment from 'moment-timezone'; -import { TextContainer } from './text-container'; -import { LdsReplacePipe } from '../lds-replace/lds-replace.pipe'; +import { Router } from '@angular/router'; import { AppConfigService } from '../appConfig/appConfig.service'; +import { LdsReplacePipe } from '../lds-replace/lds-replace.pipe'; +import { TextContainer } from './text-container'; @Injectable({ - providedIn: 'root' + providedIn: 'root', }) export class ImxTranslationProviderService implements ITranslationProvider { private multilanguageTranslationDict: { [key: string]: { [key: string]: string } } = {}; @@ -48,7 +49,7 @@ export class ImxTranslationProviderService implements ITranslationProvider { private appConfig: AppConfigService, private translateService: TranslateService, private readonly ldsReplace: LdsReplacePipe, - private readonly dateAdapter: DateAdapter + private readonly dateAdapter: DateAdapter, ) {} public get Culture(): string { @@ -59,26 +60,27 @@ export class ImxTranslationProviderService implements ITranslationProvider { return this.cultureFormat; } - public async init(culture: string = this.translateService.getBrowserCultureLang(), cultureFormat: string = this.translateService.getBrowserCultureLang()): Promise { - //Use more specific culture, if de is provided (used for help documents) - if(culture == 'de') { - culture = 'de-DE'; - } + public async init( + culture: string | undefined = this.translateService.getBrowserCultureLang(), + cultureFormat: string | undefined = this.translateService.getBrowserCultureLang(), + ): Promise { const defaultLang = this.translateService.getDefaultLang(); // Get filtered cultures that are available to frontends and set to english if culture (browser language) is not supported - const cultures = await this.appConfig.client.imx_multilanguage_uicultures_get({filter: [{ColumnName: 'Ident_DialogCulture', Value1: culture}]}); - if(cultures.TotalCount === 0){ + const cultures = await this.appConfig.client.imx_multilanguage_uicultures_get({ + filter: [{ ColumnName: 'Ident_DialogCulture', Value1: culture }], + }); + if (cultures.TotalCount === 0) { culture = 'en-US'; } - - if (defaultLang == null || defaultLang !== culture) { + + if (culture && defaultLang !== culture) { this.translateService.setDefaultLang(culture); } - if (this.translateService.currentLang == null || this.translateService.currentLang !== culture) { + if (culture && this.translateService.currentLang !== culture) { await this.translateService.use(culture).toPromise(); } - this.cultureFormat = cultureFormat; + this.cultureFormat = cultureFormat ?? ''; this.dateAdapter.setLocale(this.cultureFormat); moment.locale(this.cultureFormat); @@ -86,10 +88,10 @@ export class ImxTranslationProviderService implements ITranslationProvider { return; } - this.culture = culture; + this.culture = culture ?? 'en-US'; this.multilanguageTranslationDict = await this.appConfig.client.imx_multilanguage_translations_get('all', { - cultureName: this.culture + cultureName: this.culture, }); // use this translator as the default in dbts @@ -99,9 +101,33 @@ export class ImxTranslationProviderService implements ITranslationProvider { await this.appConfig.client.loadSchema(culture); } + /** + * Reinit when language is changed from the profile settings + * @param culture language to reinit with + * @param cultureFormat date formating to reinit with + */ + public async reinit(culture: string, cultureFormat: string, router: Router) { + this.culture = culture; + this.cultureFormat = cultureFormat; + await this.translateService.use(this.culture).toPromise(); + this.dateAdapter.setLocale(this.cultureFormat); + moment.locale(this.cultureFormat); + this.multilanguageTranslationDict = await this.appConfig.client.imx_multilanguage_translations_get('all', { + cultureName: this.culture, + }); + DefaultServiceResolver.UseTranslator(this); + await this.appConfig.client.loadSchema(this.culture); + + // We may have stale data or schemas from the current page, so we nav back to refresh existing components + let currentUrl = router.url; + router.navigateByUrl('/', { skipLocationChange: true }).then(() => { + router.navigate([currentUrl]); + }); + } + public GetTranslation(key: MultiLanguageStringData): string { - const uidColumn = this.multilanguageTranslationDict[key.UidColumn]; - return uidColumn ? uidColumn[key.Key] : key.Key; + const uidColumn = this.multilanguageTranslationDict[key.UidColumn ?? '']; + return (uidColumn ? uidColumn[key.Key ?? ''] : key.Key) ?? ''; } public Translate(text: TextContainer | string): Observable { @@ -112,7 +138,8 @@ export class ImxTranslationProviderService implements ITranslationProvider { const translation = this.translateService.get(text.key); if (text.parameters) { - return translation.pipe(map((translatedValue: any) => this.ldsReplace.transform(translatedValue, ...text.parameters))); + const params = text.parameters ?? []; + return translation.pipe(map((translatedValue: any) => this.ldsReplace.transform(translatedValue, ...params))); } return translation; @@ -130,10 +157,9 @@ export class ImxTranslationProviderService implements ITranslationProvider { return column.Display; } - public async GetCultures(): Promise{ - if(Object.keys(this.multilanguageTranslationDict).length === 0){ + public async GetCultures(): Promise { + if (Object.keys(this.multilanguageTranslationDict).length === 0) { await this.init(this.culture, this.cultureFormat); } } - } diff --git a/imxweb/projects/qbm/src/lib/translation/text-container.ts b/imxweb/projects/qbm/src/lib/translation/text-container.ts index b7dd02700..4565ed38c 100644 --- a/imxweb/projects/qbm/src/lib/translation/text-container.ts +++ b/imxweb/projects/qbm/src/lib/translation/text-container.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR diff --git a/imxweb/projects/qbm/src/lib/treeTable/MatColumn.html b/imxweb/projects/qbm/src/lib/treeTable/MatColumn.html index 8c28133f8..fc5961e88 100644 --- a/imxweb/projects/qbm/src/lib/treeTable/MatColumn.html +++ b/imxweb/projects/qbm/src/lib/treeTable/MatColumn.html @@ -1,18 +1,21 @@ - - - + + + - -
    {{title || field}}
    -
    - -
    - - - - - -
    {{getData(data,index)}}
    - - \ No newline at end of file + +
    {{title || field}}
    + + + + + + +
    {{getData(data,index)}}
    +
    + diff --git a/imxweb/projects/qbm/src/lib/treeTable/MatColumn.scss b/imxweb/projects/qbm/src/lib/treeTable/MatColumn.scss index 4eba72437..ec22173c1 100644 --- a/imxweb/projects/qbm/src/lib/treeTable/MatColumn.scss +++ b/imxweb/projects/qbm/src/lib/treeTable/MatColumn.scss @@ -1,3 +1,3 @@ .imx-small-right-margin { margin-right: 1em; -} \ No newline at end of file +} diff --git a/imxweb/projects/qbm/src/lib/treeTable/MatColumn.ts b/imxweb/projects/qbm/src/lib/treeTable/MatColumn.ts index fa9b66335..e123afcd1 100644 --- a/imxweb/projects/qbm/src/lib/treeTable/MatColumn.ts +++ b/imxweb/projects/qbm/src/lib/treeTable/MatColumn.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -24,10 +24,7 @@ * */ -import { - Component, Input, OnDestroy, OnInit, Optional, ViewChild, - ContentChild, TemplateRef, ElementRef, Output, EventEmitter -} from '@angular/core'; +import { Component, ContentChild, EventEmitter, Input, OnDestroy, OnInit, Optional, Output, TemplateRef, ViewChild } from '@angular/core'; import { MatSortHeader } from '@angular/material/sort'; import { MatColumnDef, MatTable } from '@angular/material/table'; import { DomSanitizer, SafeStyle } from '@angular/platform-browser'; @@ -36,17 +33,19 @@ import { ImxExpandableItem } from './imx-data-source'; @Component({ selector: 'imx-column', templateUrl: './MatColumn.html', - styleUrls: ['./MatColumn.scss'] + styleUrls: ['./MatColumn.scss'], }) export class ImxMatColumnComponent implements OnDestroy, OnInit { @Input() - get field(): string { return this.name; } + get field(): string { + return this.name; + } set field(name: string) { this.name = name; } @Input() public title: string; - @Input() public dataAccessor: ((data: T, index: number, name: string) => string); + @Input() public dataAccessor: (data: T, index: number, name: string) => string; @Input() public align: 'before' | 'after' = 'before'; @@ -54,30 +53,37 @@ export class ImxMatColumnComponent implements OnDestroy, OnInit { @ViewChild(MatSortHeader) public sortHeader: MatSortHeader; - @ContentChild('imxCellTemplate', { static: true }) public cellTemplate: TemplateRef; - @ContentChild('imxHeaderTemplate', { static: true }) public headerTemplate: TemplateRef; + @ContentChild('imxCellTemplate', { static: true }) public cellTemplate: TemplateRef; + @ContentChild('imxHeaderTemplate', { static: true }) public headerTemplate: TemplateRef; @Input() public class = 'imx-normalCell'; @Output() public itemExpanded = new EventEmitter>(); @Output() public itemCollapsed = new EventEmitter>(); @Input() public isFirstColumn = true; - public hasChildrenProvider: ((data: T) => boolean); + public hasChildrenProvider: (data: T) => boolean; private name: string; - constructor(private sanitizer: DomSanitizer, @Optional() public table: MatTable) { } + constructor( + private sanitizer: DomSanitizer, + @Optional() public table: MatTable, + ) {} public ButtonClass(data: ImxExpandableItem): string { - if (data.data == null) { return 'k-icon k-i-collapse'; } + if (data.data == null) { + return 'k-icon k-i-collapse'; + } const res = data.level === 0 || (this.hasChildrenProvider ? this.hasChildrenProvider(data.data) : false); - return !res ? 'imx-small-right-margin k-sprite' : data.isExpanded - ? 'imx-small-right-margin cux-icon cux-icon--caret-down' // TODO replace cux-icon (TFS 806274) - : 'imx-small-right-margin cux-icon cux-icon--caret-right'; // TODO replace cux-icon (TFS 806274) + return !res + ? 'imx-small-right-margin k-sprite' + : data.isExpanded + ? 'imx-small-right-margin cux-icon cux-icon--caret-down' // TODO replace cux-icon (TFS 806274) + : 'imx-small-right-margin cux-icon cux-icon--caret-right'; // TODO replace cux-icon (TFS 806274) } public getMargin(data: any): SafeStyle { - return this.sanitizer.bypassSecurityTrustStyle((data.level ? data.level : .0) * 20 + 'px'); + return this.sanitizer.bypassSecurityTrustStyle((data.level ? data.level : 0.0) * 20 + 'px'); } public ngOnInit(): void { @@ -97,7 +103,6 @@ export class ImxMatColumnComponent implements OnDestroy, OnInit { return this.dataAccessor ? this.dataAccessor(data.data, index, this.field) : (data.data as any)[this.field]; } - public buttonClicked(data: ImxExpandableItem): void { data.isExpanded = !data.isExpanded; if (data.isExpanded) { diff --git a/imxweb/projects/qbm/src/lib/treeTable/imx-data-source.ts b/imxweb/projects/qbm/src/lib/treeTable/imx-data-source.ts index 167b51602..2224a704d 100644 --- a/imxweb/projects/qbm/src/lib/treeTable/imx-data-source.ts +++ b/imxweb/projects/qbm/src/lib/treeTable/imx-data-source.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -32,10 +32,10 @@ export abstract class ImxDataSource extends DataSource { public data: T[]; public expandableData: ImxExpandableItem[]; - public hasChildrenProvider: ((data: T) => boolean); + public hasChildrenProvider: (data: T) => boolean; - public itemsProvider: (() => Promise); - public childItemsProvider: ((item: T) => Promise); + public itemsProvider: () => Promise; + public childItemsProvider: (item: T) => Promise; private rootItem: ImxExpandableItem; @@ -53,8 +53,8 @@ export abstract class ImxDataSource extends DataSource { throw new Error('The accessor "itemsProvider" is undefined '); } const items = this.itemsProvider(); - items.then(elements => { - const rows = this.getRows(elements, null, 1 ); + items.then((elements) => { + const rows = this.getRows(elements, null, 1); this.data = elements; this.expandableData = rows; this.itemCount = elements.length; @@ -71,15 +71,15 @@ export abstract class ImxDataSource extends DataSource { } const items = this.childItemsProvider(parent.data); - items.then(elements => { + items.then((elements) => { const newRows = this.getRows(elements, parent, parent.level + 1); const newRowSet: ImxExpandableItem[] = []; - this.shownItems.forEach(element => { + this.shownItems.forEach((element) => { if (element !== parent) { newRowSet.push(element); } else { newRowSet.push(element); - newRows.forEach(ele => { + newRows.forEach((ele) => { newRowSet.push(ele); if (expand) { ele.isExpanded = true; @@ -96,7 +96,7 @@ export abstract class ImxDataSource extends DataSource { public RemoveChildItems(parent: ImxExpandableItem) { const newRowSet: ImxExpandableItem[] = []; - this.shownItems.forEach(element => { + this.shownItems.forEach((element) => { if (!this.ElementHasParent(element, parent)) { newRowSet.push(element); } @@ -107,21 +107,27 @@ export abstract class ImxDataSource extends DataSource { } public ExpandRoot(): any { - const root = this.shownItems.find(el => el.isRoot); + const root = this.shownItems.find((el) => el.isRoot); + if (root == null) { + return; + } root.isExpanded = true; this.shownItems.push(new ImxExpandableItem(root.data, root, 1)); this._dataSubject.next(this.shownItems); } public CollapseRoot(): any { - const root = this.shownItems.find(el => el.isRoot); + const root = this.shownItems.find((el) => el.isRoot); + if (root == null) { + return; + } root.isExpanded = false; this.shownItems = [root]; this._dataSubject.next(this.shownItems); } public ExpandAll(): void { - this.shownItems.forEach(el => { + this.shownItems.forEach((el) => { if (!el.isExpanded) { el.isExpanded = true; this.LoadChildItems(el, true); @@ -130,48 +136,57 @@ export abstract class ImxDataSource extends DataSource { } public ElementHasParent(element: ImxExpandableItem, parent: ImxExpandableItem): boolean { - if (element.parent === parent) { return true; } + if (element.parent === parent) { + return true; + } const newElemen = element.parent; return newElemen && newElemen != null ? this.ElementHasParent(newElemen, parent) : false; } - public getRows(items: T[], parent: ImxExpandableItem, level: number): ImxExpandableItem[] { + public getRows(items: T[], parent: ImxExpandableItem | null, level: number): ImxExpandableItem[] { const ret: ImxExpandableItem[] = []; - items.forEach(element => { + items.forEach((element) => { ret.push(new ImxExpandableItem(element, parent, level)); }); return ret; } public disconnect(): void { - this.subscriptions.forEach(subscription => subscription.unsubscribe()); + this.subscriptions.forEach((subscription) => subscription.unsubscribe()); } public connect(): Observable { - this.subscriptions.push(this._dataSubject.subscribe( - (res: any) => { + this.subscriptions.push( + this._dataSubject.subscribe((res: any) => { this.data = res; - } - )); + }), + ); return this._dataSubject; } public SetRoot(specialElement: T) { - if (!specialElement) { return; } + if (!specialElement) { + return; + } this.shownItems = []; this.rootItem = new ImxExpandableItem(specialElement, null, 0); this.rootItem.isRoot = true; this.shownItems.push(this.rootItem); - const root = this.expandableData.find(el => el.data === specialElement); - this.shownItems.push(root); + const root = this.expandableData.find((el) => el.data === specialElement); + if (root != null) { + this.shownItems.push(root); + } this._dataSubject.next(this.shownItems); } } export class ImxExpandableItem { - public isExpanded = false; public isRoot = false; - constructor(public data: T, public parent: ImxExpandableItem, public level: number) { } + constructor( + public data: T, + public parent: ImxExpandableItem | null, + public level: number, + ) {} } diff --git a/imxweb/projects/qbm/src/lib/treeTable/tableTestClasses.spec.ts b/imxweb/projects/qbm/src/lib/treeTable/tableTestClasses.spec.ts index ea18497f7..c408bdceb 100644 --- a/imxweb/projects/qbm/src/lib/treeTable/tableTestClasses.spec.ts +++ b/imxweb/projects/qbm/src/lib/treeTable/tableTestClasses.spec.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -49,7 +49,7 @@ export class Test extends ImxDataSource { itemsProvider = () => { return this.buildTree(this.startUid); - } + }; childItemsProvider = (item: any) => { const val1 = this.buildTree(item.UID_JobError); @@ -59,14 +59,13 @@ export class Test extends ImxDataSource { return [].concat.apply([], arrayOfArrays); }); return ret; - } + }; hasChildrenProvider = (data: any) => { - return (data.UID_JobError !== null && data.UID_JobError !== '') - && (data.UID_JobSuccess != null && data.UID_JobSuccess !== ''); - } + return data.UID_JobError !== null && data.UID_JobError !== '' && data.UID_JobSuccess != null && data.UID_JobSuccess !== ''; + }; - private buildTree(uidstart: string): Promise<{ [key: string]: any; }[]> { + private buildTree(uidstart: string): Promise<{ [key: string]: any }[]> { return Promise.resolve(this.uids.map((uid: string) => Test.buildSingleObject(uid + uidstart))); } } diff --git a/imxweb/projects/qbm/src/lib/treeTable/treeTable.component.html b/imxweb/projects/qbm/src/lib/treeTable/treeTable.component.html index a3c87aff8..4fc8077c9 100644 --- a/imxweb/projects/qbm/src/lib/treeTable/treeTable.component.html +++ b/imxweb/projects/qbm/src/lib/treeTable/treeTable.component.html @@ -1,29 +1,29 @@ -
    - - - - - - - - - - - +
    + + + + + + + + + + - - - - - + + + + + - - - - {{rootText}} - - + + {{ rootText }} +
    diff --git a/imxweb/projects/qbm/src/lib/treeTable/treeTable.component.ts b/imxweb/projects/qbm/src/lib/treeTable/treeTable.component.ts index 7f664cfd6..4943716f0 100644 --- a/imxweb/projects/qbm/src/lib/treeTable/treeTable.component.ts +++ b/imxweb/projects/qbm/src/lib/treeTable/treeTable.component.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -36,7 +36,7 @@ import { ContentChild, TemplateRef, ElementRef, - OnDestroy + OnDestroy, } from '@angular/core'; import { MatTable, MatColumnDef } from '@angular/material/table'; import { Subscription } from 'rxjs'; @@ -50,11 +50,11 @@ import { ImxExpandableItem } from './imx-data-source'; templateUrl: './treeTable.component.html', styles: [ ` - .customWidthClass { - flex: 0 0 50px; - } - ` - ] + .customWidthClass { + flex: 0 0 50px; + } + `, + ], }) /* @@ -68,7 +68,6 @@ import { ImxExpandableItem } from './imx-data-source'; | child 1 2 value */ export class ImxTreeTableComponent implements AfterContentInit, OnDestroy { - get columnsToDisplay(): string[] { return this.columnsToDisplayInternal; } @@ -107,7 +106,7 @@ export class ImxTreeTableComponent implements AfterContentInit, OnDestroy { public isExpansionDetailRow = (i: number, ob: ImxExpandableItem) => { return ob.isRoot && this.rootType !== 'ColumnTemplate'; - } + }; public async ngAfterContentInit(): Promise { if (!this.dataSource.hasChildrenProvider) { @@ -127,23 +126,27 @@ export class ImxTreeTableComponent implements AfterContentInit, OnDestroy { this.columnsToDisplayInternal.push(simpleColumn.field); - this.subscriptions.push(simpleColumn.itemExpanded.subscribe({ - next: (event: ImxExpandableItem) => { - this.handleExpandEvent(event, true); - } - })); - - this.subscriptions.push(simpleColumn.itemCollapsed.subscribe({ - next: (event: ImxExpandableItem) => { - this.handleExpandEvent(event, false); - } - })); + this.subscriptions.push( + simpleColumn.itemExpanded.subscribe({ + next: (event: ImxExpandableItem) => { + this.handleExpandEvent(event, true); + }, + }), + ); + + this.subscriptions.push( + simpleColumn.itemCollapsed.subscribe({ + next: (event: ImxExpandableItem) => { + this.handleExpandEvent(event, false); + }, + }), + ); this.table.addColumnDef(simpleColumn.columnDef); }); } public ngOnDestroy(): void { - this.subscriptions.forEach(subscription => subscription.unsubscribe()); + this.subscriptions.forEach((subscription) => subscription.unsubscribe()); } public handleExpandEvent(data: ImxExpandableItem, expand: boolean): void { diff --git a/imxweb/projects/qbm/src/lib/two-factor-authentication/two-factor-authentication.component.ts b/imxweb/projects/qbm/src/lib/two-factor-authentication/two-factor-authentication.component.ts index c1e784cd8..8c9fbb744 100644 --- a/imxweb/projects/qbm/src/lib/two-factor-authentication/two-factor-authentication.component.ts +++ b/imxweb/projects/qbm/src/lib/two-factor-authentication/two-factor-authentication.component.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -24,36 +24,40 @@ * */ -import { ComponentFactoryResolver, Component, ViewChild, OnInit } from '@angular/core'; +import { Component, ComponentFactoryResolver, OnInit, ViewChild } from '@angular/core'; -import { TwoFactorAuthenticationService } from './two-factor-authentication.service'; +import { ClassloggerService } from '../classlogger/classlogger.service'; import { ExtDirective } from '../ext/ext.directive'; import { imx_SessionService } from '../session/imx-session.service'; import { ISessionState } from '../session/session-state'; +import { TwoFactorAuthenticationService } from './two-factor-authentication.service'; @Component({ selector: 'imx-2fahost', - template: ` - - ` + template: ` `, }) export class TwoFactorAuthenticationComponent implements OnInit { @ViewChild(ExtDirective, { static: true }) public directive: ExtDirective; constructor( private componentFactoryResolver: ComponentFactoryResolver, + private classlogger: ClassloggerService, private twoFactorAuthService: TwoFactorAuthenticationService, - private sessionService: imx_SessionService + private sessionService: imx_SessionService, ) {} public ngOnInit(): void { this.sessionService.getSessionState().then((sessionState: ISessionState) => { - const selectedProvider = this.twoFactorAuthService.Registry[sessionState.SecondaryAuthName]; - if (selectedProvider) { - this.directive.viewContainerRef.clear(); - this.directive.viewContainerRef.createComponent(this.componentFactoryResolver.resolveComponentFactory(selectedProvider)); + if (sessionState.SecondaryAuthName) { + const selectedProvider = this.twoFactorAuthService.Registry[sessionState.SecondaryAuthName]; + if (selectedProvider) { + this.directive.viewContainerRef.clear(); + this.directive.viewContainerRef.createComponent(this.componentFactoryResolver.resolveComponentFactory(selectedProvider)); + } else { + this.classlogger.warn(this, 'No provider selected'); + } } else { - // TODO log + this.classlogger.warn(this, 'No secondary auth name found'); } }); } diff --git a/imxweb/projects/qbm/src/lib/two-factor-authentication/two-factor-authentication.service.ts b/imxweb/projects/qbm/src/lib/two-factor-authentication/two-factor-authentication.service.ts index 431fe36e1..e23349fb9 100644 --- a/imxweb/projects/qbm/src/lib/two-factor-authentication/two-factor-authentication.service.ts +++ b/imxweb/projects/qbm/src/lib/two-factor-authentication/two-factor-authentication.service.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -28,9 +28,11 @@ import { Injectable, Type } from '@angular/core'; @Injectable() export class TwoFactorAuthenticationService { - public get Registry(): { [id: string]: Type; } { return this.registry; } + public get Registry(): { [id: string]: Type } { + return this.registry; + } - private registry: { [id: string]: Type; } = {}; + private registry: { [id: string]: Type } = {}; public register(key: string, svc: Type): void { this.registry[key] = svc; diff --git a/imxweb/projects/qbm/src/lib/user-message/message.interface.ts b/imxweb/projects/qbm/src/lib/user-message/message.interface.ts index e5b5312a5..f911caf07 100644 --- a/imxweb/projects/qbm/src/lib/user-message/message.interface.ts +++ b/imxweb/projects/qbm/src/lib/user-message/message.interface.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR diff --git a/imxweb/projects/qbm/src/lib/user-message/user-message.component.html b/imxweb/projects/qbm/src/lib/user-message/user-message.component.html index 91a9d9ec7..5efbae060 100644 --- a/imxweb/projects/qbm/src/lib/user-message/user-message.component.html +++ b/imxweb/projects/qbm/src/lib/user-message/user-message.component.html @@ -1,3 +1,10 @@ - - {{ (message?.text || '') | translate }} + + {{ message?.text || '' | translate }} diff --git a/imxweb/projects/qbm/src/lib/user-message/user-message.component.scss b/imxweb/projects/qbm/src/lib/user-message/user-message.component.scss index 58ada4d48..04e6b1cdf 100644 --- a/imxweb/projects/qbm/src/lib/user-message/user-message.component.scss +++ b/imxweb/projects/qbm/src/lib/user-message/user-message.component.scss @@ -19,12 +19,12 @@ } .imx-small-message { - color : $black; + color: $black; display: block; } .eui-dark-theme { - :host{ + :host { .imx-message { color: $color-gray-0; } @@ -35,7 +35,7 @@ } .eui-contrast-theme { - :host{ + :host { .imx-message { color: $color-gray-2; } diff --git a/imxweb/projects/qbm/src/lib/user-message/user-message.component.ts b/imxweb/projects/qbm/src/lib/user-message/user-message.component.ts index c3f646c63..7aeadb86c 100644 --- a/imxweb/projects/qbm/src/lib/user-message/user-message.component.ts +++ b/imxweb/projects/qbm/src/lib/user-message/user-message.component.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -24,13 +24,13 @@ * */ -import { Component, OnDestroy, ViewChild, AfterContentInit, Input, ChangeDetectorRef } from '@angular/core'; +import { AfterContentInit, ChangeDetectorRef, Component, Input, OnDestroy, ViewChild } from '@angular/core'; import { Subscription } from 'rxjs'; -import { UserMessageService } from './user-message.service'; -import { Message } from './message.interface'; -import { ClassloggerService } from '../classlogger/classlogger.service'; import { EuiAlertComponent } from '@elemental-ui/core'; +import { ClassloggerService } from '../classlogger/classlogger.service'; +import { Message } from './message.interface'; +import { UserMessageService } from './user-message.service'; /** * A component that displays a message inside an ElementalUI alert control @@ -38,7 +38,7 @@ import { EuiAlertComponent } from '@elemental-ui/core'; @Component({ selector: 'imx-usermessage', templateUrl: './user-message.component.html', - styleUrls: ['./user-message.component.scss'] + styleUrls: ['./user-message.component.scss'], }) export class UserMessageComponent implements AfterContentInit, OnDestroy { /** @@ -56,32 +56,35 @@ export class UserMessageComponent implements AfterContentInit, OnDestroy { * @ignore * The message, displayed as header of the ElementalUI alert component */ - public message: Message; + public message: Message | undefined; private readonly subscriptions: Subscription[] = []; - constructor(private readonly messageService: UserMessageService, private readonly logger: ClassloggerService, - private cdref: ChangeDetectorRef + constructor( + private readonly messageService: UserMessageService, + private readonly logger: ClassloggerService, + private cdref: ChangeDetectorRef, ) { this.logger.debug(this, 'init user message component'); - this.subscriptions.push(this.messageService.subject.subscribe(message => { - - this.logger.debug(this, 'message received:', message); - this.message = message; - if (this.alert) { - this.alert.isDismissed = !this.isForMe(); - this.cdref.detectChanges(); - } - })); + this.subscriptions.push( + this.messageService.subject.subscribe((message) => { + this.logger.debug(this, 'message received:', message); + this.message = message; + if (this.alert) { + this.alert.isDismissed = !this.isForMe(); + this.cdref.detectChanges(); + } + }), + ); } - public dismissClick(){ + public dismissClick() { this.cdref.detectChanges(); } private isForMe() { // is there a message, and is the message for this target? - return this.message != null && this.target == this.message.target; + return this.message != null && !!this.message.target && this.target == this.message.target; } /** @@ -99,6 +102,6 @@ export class UserMessageComponent implements AfterContentInit, OnDestroy { */ public ngOnDestroy(): void { this.logger.debug(this, 'unsubscribe observables'); - this.subscriptions.forEach(subscription => subscription.unsubscribe()); + this.subscriptions.forEach((subscription) => subscription.unsubscribe()); } } diff --git a/imxweb/projects/qbm/src/lib/user-message/user-message.module.ts b/imxweb/projects/qbm/src/lib/user-message/user-message.module.ts index 6e0cddb79..543135fdf 100644 --- a/imxweb/projects/qbm/src/lib/user-message/user-message.module.ts +++ b/imxweb/projects/qbm/src/lib/user-message/user-message.module.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -34,12 +34,8 @@ import { UserMessageService } from './user-message.service'; @NgModule({ declarations: [UserMessageComponent], - imports: [ - CommonModule, - EuiCoreModule, - TranslateModule - ], + imports: [CommonModule, EuiCoreModule, TranslateModule], providers: [UserMessageService], exports: [UserMessageComponent], }) -export class UserMessageModule { } +export class UserMessageModule {} diff --git a/imxweb/projects/qbm/src/lib/user-message/user-message.service.ts b/imxweb/projects/qbm/src/lib/user-message/user-message.service.ts index 82636936c..cff4f2385 100644 --- a/imxweb/projects/qbm/src/lib/user-message/user-message.service.ts +++ b/imxweb/projects/qbm/src/lib/user-message/user-message.service.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -31,5 +31,5 @@ import { Message } from './message.interface'; @Injectable() export class UserMessageService { - public readonly subject = new ReplaySubject(); + public readonly subject = new ReplaySubject(); } diff --git a/imxweb/projects/qbm/src/lib/value-wrapper/value-wrapper.ts b/imxweb/projects/qbm/src/lib/value-wrapper/value-wrapper.ts index 4ff9264f3..592bd3ab1 100644 --- a/imxweb/projects/qbm/src/lib/value-wrapper/value-wrapper.ts +++ b/imxweb/projects/qbm/src/lib/value-wrapper/value-wrapper.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR diff --git a/imxweb/projects/qbm/src/public_api.ts b/imxweb/projects/qbm/src/public_api.ts index a615141dc..62eb9ae72 100644 --- a/imxweb/projects/qbm/src/public_api.ts +++ b/imxweb/projects/qbm/src/public_api.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -29,37 +29,47 @@ */ export { AboutComponent } from './lib/about/About.component'; +export { AboutService } from './lib/about/About.service'; export { AdminComponent } from './lib/admin/admin-component.interface'; export { AdminRoutes } from './lib/admin/admin-routes'; -export { CacheService } from './lib/cache/cache.service'; export { AdminModule } from './lib/admin/admin.module'; export { LogDetailsSidesheetComponent } from './lib/admin/log-details-sidesheet.component'; export { ApiClientAngularService, BASE_URL } from './lib/api-client/api-client-angular.service'; export { ApiClientFetch } from './lib/api-client/api-client-fetch'; export { ApiClientService } from './lib/api-client/api-client.service'; export { DynamicMethod, GenericTypedEntity } from './lib/api-client/dynamic-method'; +export { DynamicCollectionLoadParameters } from './lib/api-client/dynamic-method/dynamic-collection-load-parameters.interface'; +export { DynamicMethodService } from './lib/api-client/dynamic-method/dynamic-method.service'; +export { InteractiveParameter } from './lib/api-client/dynamic-method/interactive-parameter.interface'; export { AppConfig } from './lib/appConfig/appconfig.interface'; export { AppConfigService } from './lib/appConfig/appConfig.service'; +export { TranslationConfiguration } from './lib/appConfig/translationConfiguration.interface'; export { AuthConfigProvider } from './lib/authentication/auth-config-provider.interface'; export { AuthenticationGuardService } from './lib/authentication/authentication-guard.service'; export { AuthenticationModule } from './lib/authentication/authentication.module'; export { AuthenticationService } from './lib/authentication/authentication.service'; +export { CustomAuthFlow } from './lib/authentication/custom-auth-flow.interface'; export { OAuthService } from './lib/authentication/oauth.service'; export { AutoCompleteComponent } from './lib/auto-complete/auto-complete.component'; export { AutoCompleteModule } from './lib/auto-complete/auto-complete.module'; -export { BusyService } from './lib/base/busy.service'; -export { Busy } from './lib/base/busy.service'; +export { Busy, BusyService } from './lib/base/busy.service'; export { ErrorService } from './lib/base/error.service'; export { GlobalErrorHandler } from './lib/base/global-error-handler'; export { Guid } from './lib/base/Guid'; +export { IeWarningService } from './lib/base/ie-warning.service'; export { MetadataService } from './lib/base/metadata.service'; export { OpsupportDbObjectParameters, OpsupportDbObjectService } from './lib/base/opsupport-db-object.service'; export { Paginator } from './lib/base/paginator'; export { QueryParametersHandler } from './lib/base/query-parameters-handler'; export { RegistryService } from './lib/base/registry.service'; +export { UserActionService } from './lib/base/user-action.service'; export { isIE } from './lib/base/user-agent-helper'; +export { BulkItem, BulkItemStatus } from './lib/bulk-property-editor/bulk-item/bulk-item'; +export { BulkPropertyEditorComponent } from './lib/bulk-property-editor/bulk-property-editor.component'; +export { BulkPropertyEditorModule } from './lib/bulk-property-editor/bulk-property-editor.module'; export { BusyIndicatorComponent } from './lib/busy-indicator/busy-indicator.component'; export { BusyIndicatorModule } from './lib/busy-indicator/busy-indicator.module'; +export { CacheService } from './lib/cache/cache.service'; export { CaptchaComponent } from './lib/captcha/captcha.component'; export { CaptchaModule } from './lib/captcha/captcha.module'; export { CaptchaMode, CaptchaService } from './lib/captcha/captcha.service'; @@ -76,41 +86,6 @@ export { CdrSidesheetConfig } from './lib/cdr/cdr-sidesheet/cdr-sidesheet-config export { CdrSidesheetComponent } from './lib/cdr/cdr-sidesheet/cdr-sidesheet.component'; export { CdrModule } from './lib/cdr/cdr.module'; export { ColumnDependentReference } from './lib/cdr/column-dependent-reference.interface'; -export { CustomAuthFlow } from './lib/authentication/custom-auth-flow.interface'; -export { CustomThemeModule } from './lib/custom-theme/custom-theme.module'; -export { CustomThemeService } from './lib/custom-theme/custom-theme.service'; -export { Connectors } from './lib/hyperview/connectors'; -export { ConnectionComponent } from './lib/connection/connection.component'; -export { DataNavigationParameters } from './lib/select/data-navigation-parameters.interface'; -export { DataSourcePaginatorComponent } from './lib/data-source-toolbar/data-source-paginator.component'; -export { DataSourceToolbarComponent } from './lib/data-source-toolbar/data-source-toolbar.component'; -export { DataSourceToolbarCustomComponent } from './lib/data-source-toolbar/data-source-toolbar-custom.component'; -export { DataSourceToolbarModule } from './lib/data-source-toolbar/data-source-toolbar.module'; -export { DataSourceToolbarSettings } from './lib/data-source-toolbar/data-source-toolbar-settings'; -export { ClientPropertyForTableColumns } from './lib/data-source-toolbar/client-property-for-table-columns'; -export { DataSourceToolbarFilter, DataSourceToolbarSelectedFilter } from './lib/data-source-toolbar/data-source-toolbar-filters.interface'; -export { - DataSourceToolbarGroupData, - DataSourceToolBarGroup, - DataSourceToolBarGroupingCategory, -} from './lib/data-source-toolbar/data-source-toolbar-groups.interface'; -export { DataSourceToolbarExportMethod } from './lib/data-source-toolbar/data-source-toolbar-export-method.interface'; -export { DataSourceToolbarViewConfig, DSTViewConfig } from './lib/data-source-toolbar/data-source-toolbar-view-config.interface'; -export { isConfigDefault, isDefaultId } from './lib/data-source-toolbar/data-source-toolbar-view-config-helper'; -export { DataModelWrapper } from './lib/data-source-toolbar/data-model/data-model-wrapper.interface'; -export { DataSourceItemStatus } from './lib/data-source-toolbar/data-source-item-status.interface'; -export { DataSourceWrapper } from './lib/data-source-toolbar/data-source-wrapper'; -export { DocChapterService, DocDocument, DocChapter } from './lib/doc/doc-chapter.service'; -export { FilterTreeParameter } from './lib/data-source-toolbar/data-model/filter-tree-parameter'; -export { FilterTreeDatabase } from './lib/data-source-toolbar/filter-tree/filter-tree-database'; -export { FilterTreeEntityWrapperService } from './lib/data-source-toolbar/filter-tree/filter-tree-entity-wrapper.service'; -export { DataTableColumnComponent } from './lib/data-table/data-table-column.component'; -export { DataTableComponent } from './lib/data-table/data-table.component'; -export { DataTableGenericColumnComponent } from './lib/data-table/data-table-generic-column.component'; -export { DataTableGroupedData } from './lib/data-table/data-table-groups.interface'; -export { DataTableModule } from './lib/data-table/data-table.module'; -export { getParameterSubsetForGrouping } from './lib/data-table/data-table-groups.interface'; -export { ExcludedColumnsPipe } from './lib/data-table/excluded-columns.pipe'; export { DefaultCdrEditorProvider } from './lib/cdr/default-cdr-editor-provider'; export { EditBinaryComponent } from './lib/cdr/edit-binary/edit-binary.component'; export { EditBooleanComponent } from './lib/cdr/edit-boolean/edit-boolean.component'; @@ -122,19 +97,57 @@ export { EditMultiLimitedValueComponent } from './lib/cdr/edit-multi-limited-val export { EditMultiValueComponent } from './lib/cdr/edit-multi-value/edit-multi-value.component'; export { EditMultilineComponent } from './lib/cdr/edit-multiline/edit-multiline.component'; export { EditNumberComponent } from './lib/cdr/edit-number/edit-number.component'; +export { EntityColumnContainer } from './lib/cdr/entity-column-container'; +export { EntityColumnEditorComponent } from './lib/cdr/entity-column-editor/entity-column-editor.component'; export { FkCdrEditorProvider } from './lib/cdr/fk-cdr-editor-provider'; export { PropertyViewerComponent } from './lib/cdr/property-viewer/property-viewer.component'; export { LineChartOptions } from './lib/chart-options/line-chart-options'; export { SeriesInformation } from './lib/chart-options/series-information'; +export { XAxisInformation } from './lib/chart-options/x-axis-information'; +export { YAxisInformation } from './lib/chart-options/y-axis-information'; export { ChartTileComponent } from './lib/chart-tile/chart-tile.component'; export { ClassloggerModule } from './lib/classlogger/classlogger.module'; export { ClassloggerService } from './lib/classlogger/classlogger.service'; export { ElementalUiConfigService } from './lib/configuration/elemental-ui-config.service'; +export { ConfirmationModule } from './lib/confirmation/confirmation.module'; +export { ConfirmationService } from './lib/confirmation/confirmation.service'; +export { ConnectionComponent } from './lib/connection/connection.component'; +export { CustomThemeModule } from './lib/custom-theme/custom-theme.module'; +export { CustomThemeService } from './lib/custom-theme/custom-theme.service'; +export { ClientPropertyForTableColumns } from './lib/data-source-toolbar/client-property-for-table-columns'; export { ColumnOptions } from './lib/data-source-toolbar/column-options'; export { createGroupData } from './lib/data-source-toolbar/data-model/data-model-helper'; +export { DataModelWrapper } from './lib/data-source-toolbar/data-model/data-model-wrapper.interface'; +export { FilterTreeParameter } from './lib/data-source-toolbar/data-model/filter-tree-parameter'; +export { DataSourceItemStatus } from './lib/data-source-toolbar/data-source-item-status.interface'; +export { DataSourcePaginatorComponent } from './lib/data-source-toolbar/data-source-paginator.component'; +export { DataSourceToolbarCustomComponent } from './lib/data-source-toolbar/data-source-toolbar-custom.component'; +export { DataSourceToolbarExportMethod } from './lib/data-source-toolbar/data-source-toolbar-export-method.interface'; +export { DataSourceToolbarFilter, DataSourceToolbarSelectedFilter } from './lib/data-source-toolbar/data-source-toolbar-filters.interface'; +export { + DataSourceToolBarGroup, + DataSourceToolBarGroupingCategory, + DataSourceToolbarGroupData, +} from './lib/data-source-toolbar/data-source-toolbar-groups.interface'; +export { DataSourceToolbarSettings } from './lib/data-source-toolbar/data-source-toolbar-settings'; +export { isConfigDefault, isDefaultId } from './lib/data-source-toolbar/data-source-toolbar-view-config-helper'; +export { DSTViewConfig, DataSourceToolbarViewConfig } from './lib/data-source-toolbar/data-source-toolbar-view-config.interface'; +export { DataSourceToolbarComponent } from './lib/data-source-toolbar/data-source-toolbar.component'; +export { DataSourceToolbarModule } from './lib/data-source-toolbar/data-source-toolbar.module'; +export { DataSourceWrapper } from './lib/data-source-toolbar/data-source-wrapper'; export { DataTileBadge } from './lib/data-source-toolbar/data-tile-badge.interface'; +export { FilterTreeDatabase } from './lib/data-source-toolbar/filter-tree/filter-tree-database'; +export { FilterTreeEntityWrapperService } from './lib/data-source-toolbar/filter-tree/filter-tree-entity-wrapper.service'; +export { FilterWizardComponent } from './lib/data-source-toolbar/filter-wizard/filter-wizard.component'; +export { FilterWizardModule } from './lib/data-source-toolbar/filter-wizard/filter-wizard.module'; export { buildAdditionalElementsString } from './lib/data-table/data-table-additional-info.model'; +export { DataTableColumnComponent } from './lib/data-table/data-table-column.component'; +export { DataTableGenericColumnComponent } from './lib/data-table/data-table-generic-column.component'; +export { DataTableGroupedData, getParameterSubsetForGrouping } from './lib/data-table/data-table-groups.interface'; export { RowHighlight } from './lib/data-table/data-table-row-highlight.interface'; +export { DataTableComponent } from './lib/data-table/data-table.component'; +export { DataTableModule } from './lib/data-table/data-table.module'; +export { ExcludedColumnsPipe } from './lib/data-table/excluded-columns.pipe'; export { DataTileMenuItem } from './lib/data-tiles/data-tile-menu-item.interface'; export { DataTileComponent } from './lib/data-tiles/data-tile.component'; export { DataTilesComponent } from './lib/data-tiles/data-tiles.component'; @@ -144,7 +157,10 @@ export { DataTreeWrapperModule } from './lib/data-tree-wrapper/data-tree-wrapper export { SearchResultAction } from './lib/data-tree/data-tree-search-results/search-result-action.interface'; export { DataTreeComponent } from './lib/data-tree/data-tree.component'; export { DataTreeModule } from './lib/data-tree/data-tree.module'; -export { TreeNodeInfo } from './lib/data-tree/tree-node'; +export { EntityTreeDatabase } from './lib/data-tree/entity-tree-database'; +export { TreeDatabase } from './lib/data-tree/tree-database'; +export { TreeNode, TreeNodeInfo } from './lib/data-tree/tree-node'; +export { TreeNodeResultParameter } from './lib/data-tree/tree-node-result-parameter.interface'; export { DateModule } from './lib/date/date.module'; export { DateComponent } from './lib/date/date/date.component'; export { LocalizedDatePipe } from './lib/date/localized-date.pipe'; @@ -157,22 +173,34 @@ export { DynamicTabsModule } from './lib/dynamic-tabs/dynamic-tabs.module'; export { EntitySelectComponent } from './lib/entity/entity-select/entity-select.component'; export { EntityModule } from './lib/entity/entity.module'; export { EntityService } from './lib/entity/entity.service'; +export { TypedEntityCandidateSidesheetComponent } from './lib/entity/typed-entity-candidate-sidesheet/typed-entity-candidate-sidesheet.component'; +export { TypedEntitySelectComponent } from './lib/entity/typed-entity-select/typed-entity-select.component'; +export { TypedEntitySelectionData } from './lib/entity/typed-entity-select/typed-entity-selection-data.interface'; export { ExtComponent } from './lib/ext/ext.component'; export { ExtDirective } from './lib/ext/ext.directive'; export { ExtModule } from './lib/ext/ext.module'; export { ExtService } from './lib/ext/ext.service'; export { IExtension } from './lib/ext/extension'; +export { FileSelectorService } from './lib/file-selector/file-selector.service'; export { FilterTileComponent } from './lib/filter-tile/filter-tile.component'; +export { FkAdvancedPickerComponent } from './lib/fk-advanced-picker/fk-advanced-picker.component'; +export { FkAdvancedPickerModule } from './lib/fk-advanced-picker/fk-advanced-picker.module'; export { FkCandidatesComponent } from './lib/fk-advanced-picker/fk-candidates/fk-candidates.component'; +export { FkSelectorComponent } from './lib/fk-advanced-picker/fk-selector.component'; +export { ForeignKeySelection } from './lib/fk-advanced-picker/foreign-key-selection.interface'; export { DynFkContainer } from './lib/fk-container/dyn-fk-container'; export { FkContainer } from './lib/fk-container/fk-container'; +export { Connectors } from './lib/hyperview/connectors'; export { HvCell, HvElement, ShapeClickArgs } from './lib/hyperview/hyperview-types'; export { HyperviewComponent } from './lib/hyperview/hyperview.component'; export { HyperViewModule } from './lib/hyperview/hyperview.module'; export { IconStackComponent } from './lib/icon-stack/icon-stack.component'; +export { ImageSelectComponent } from './lib/image/image-select/image-select.component'; +export { ImageViewComponent } from './lib/image/image-view/image-view.component'; +export { ImageModule } from './lib/image/image.module'; export { Base64ImageService } from './lib/images/base64-image.service'; -export { InfoButtonComponent } from './lib/info-modal-dialog/info-button/info-button.component'; export { InfoBadgeComponent } from './lib/info-modal-dialog/info-badge/info-badge.component'; +export { InfoButtonComponent } from './lib/info-modal-dialog/info-button/info-button.component'; export { InfoModalDialogModule } from './lib/info-modal-dialog/info-modal-dialog.module'; export { JobQueueOverviewComponent } from './lib/jobqueue-overview/jobqueue-overview.component'; export { JobQueueOverviewModule } from './lib/jobqueue-overview/jobqueue-overview.module'; @@ -183,28 +211,32 @@ export { MastHeadMenuItem } from './lib/mast-head/mast-head-menu-item.interface' export { MastHeadMenu } from './lib/mast-head/mast-head-menu.interface'; export { MastHeadComponent } from './lib/mast-head/mast-head.component'; export { MastHeadModule } from './lib/mast-head/mast-head.module'; -export { MasterDetailComponent } from './lib/master-detail/master-detail.component'; -export { GroupMenuItem } from './lib/menu/menu-item/group-menu-item'; +export { MastHeadService } from './lib/mast-head/mast-head.service'; export { MenuFactory, MenuItem } from './lib/menu/menu-item/menu-item.interface'; export { NavigationCommandsMenuItem } from './lib/menu/menu-item/navigation-commands-menu-item.interface'; -export { NavigationMenuItem } from './lib/menu/menu-item/navigation-menu-item'; export { RelatedApplicationMenuItem } from './lib/menu/menu-item/related-application-menu-item'; export { RelatedApplication } from './lib/menu/menu-item/related-application.interface'; -export { MenuComponent } from './lib/menu/menu.component'; -export { MenuModule } from './lib/menu/menu.module'; export { MenuService } from './lib/menu/menu.service'; export { MessageDialogResult } from './lib/message-dialog/message-dialog-result.enum'; export { MessageDialogComponent } from './lib/message-dialog/message-dialog.component'; export { MessageParameter } from './lib/message-dialog/message-parameter.interface'; +export { MultiSelectFormcontrolComponent } from './lib/multi-select-formcontrol/multi-select-formcontrol.component'; +export { MultiSelectFormcontrolModule } from './lib/multi-select-formcontrol/multi-select-formcontrol.module'; export { MultiValueService } from './lib/multi-value/multi-value.service'; export { ObjectHistoryApiService } from './lib/object-history/object-history-api.service'; export { ObjectHistoryGridviewComponent } from './lib/object-history/object-history-gridview/object-history-gridview.component'; export { ObjectHistoryComponent } from './lib/object-history/object-history.component'; export { ObjectHistoryModule } from './lib/object-history/object-history.module'; -export { NavigationService } from './lib/object-sheet/navigation.service'; export { OrderedListComponent } from './lib/ordered-list/ordered-list.component'; export { OrderedListModule } from './lib/ordered-list/ordered-list.module'; -export { PluginLoaderService } from './lib/plugins/plugin-loader.service'; +export { ParameterizedTextComponent } from './lib/parameterized-text/parameterized-text.component'; +export { ParameterizedText } from './lib/parameterized-text/parameterized-text.interface'; +export { ParameterizedTextModule } from './lib/parameterized-text/parameterized-text.module'; +export { ParameterizedTextService } from './lib/parameterized-text/parameterized-text.service'; +export { TextToken } from './lib/parameterized-text/text-token.interface'; +export { Action, ActionGroup, QueuedAction, QueuedActionGroup, QueuedActionState } from './lib/processing-queue/processing-queue.interface'; +export { ProcessingQueueService } from './lib/processing-queue/processing-queue.service'; + export { ImxProgressbarComponent } from './lib/progressbar/progressbar.component'; export { QbmModule } from './lib/qbm.module'; export { ComponentCanDeactivate } from './lib/route-guard/component-can-deactivate.interface'; @@ -213,11 +245,6 @@ export { DbObjectInfo } from './lib/search/db-object-info'; export { imx_QBM_SearchService } from './lib/search/search.service'; export { imx_ISearchService } from './lib/searchbar/iSearchService'; export { SearchBarComponent } from './lib/searchbar/searchbar.component'; -export { FkSelectionContainer } from './lib/select/fk-selection-container'; -export { SelectContentProvider } from './lib/select/select-content-provider.interface'; -export { SelectComponent } from './lib/select/select.component'; -export { SelectModule } from './lib/select/select.module'; -export { DeviceStateService } from './lib/services/device-state.service'; export { imx_SessionService } from './lib/session/imx-session.service'; export { AuthStepLevels, ISessionState, SessionState } from './lib/session/session-state'; export { SettingsService } from './lib/settings/settings-service'; @@ -237,50 +264,23 @@ export { StorageModule } from './lib/storage/storage.module'; export { HELPER_ALERT_KEY_PREFIX, StorageService } from './lib/storage/storage.service'; export { SystemInfoService } from './lib/system-info/system-info.service'; export { TableImageService } from './lib/table-image/table-image.service'; -export { TranslationConfiguration } from './lib/appConfig/translationConfiguration.interface'; -export { TreeDatabase } from './lib/data-tree/tree-database'; -export { UserActionService } from './lib/base/user-action.service'; -export { XAxisInformation } from './lib/chart-options/x-axis-information'; -export { YAxisInformation } from './lib/chart-options/y-axis-information'; -export { FkAdvancedPickerModule } from './lib/fk-advanced-picker/fk-advanced-picker.module'; -export { FkAdvancedPickerComponent } from './lib/fk-advanced-picker/fk-advanced-picker.component'; -export { FkSelectorComponent } from './lib/fk-advanced-picker/fk-selector.component'; -export { MastHeadService } from './lib/mast-head/mast-head.service'; -export { EntityColumnContainer } from './lib/cdr/entity-column-container'; -export { ForeignKeySelection } from './lib/fk-advanced-picker/foreign-key-selection.interface'; -export { BulkPropertyEditorModule } from './lib/bulk-property-editor/bulk-property-editor.module'; -export { BulkPropertyEditorComponent } from './lib/bulk-property-editor/bulk-property-editor.component'; -export { BulkItem } from './lib/bulk-property-editor/bulk-item/bulk-item'; -export { BulkItemStatus } from './lib/bulk-property-editor/bulk-item/bulk-item'; -export { ConfirmationModule } from './lib/confirmation/confirmation.module'; -export { ConfirmationService } from './lib/confirmation/confirmation.service'; -export { MultiSelectFormcontrolModule } from './lib/multi-select-formcontrol/multi-select-formcontrol.module'; -export { MultiSelectFormcontrolComponent } from './lib/multi-select-formcontrol/multi-select-formcontrol.component'; -export { TreeNodeResultParameter } from './lib/data-tree/tree-node-result-parameter.interface'; -export { TypedEntitySelectComponent } from './lib/entity/typed-entity-select/typed-entity-select.component'; -export { TypedEntitySelectionData } from './lib/entity/typed-entity-select/typed-entity-selection-data.interface'; -export { TypedEntityCandidateSidesheetComponent } from './lib/entity/typed-entity-candidate-sidesheet/typed-entity-candidate-sidesheet.component'; -export { ImageModule } from './lib/image/image.module'; -export { ImageSelectComponent } from './lib/image/image-select/image-select.component'; -export { ImageViewComponent } from './lib/image/image-view/image-view.component'; -export { FileSelectorService } from './lib/file-selector/file-selector.service'; -export { EntityColumnEditorComponent } from './lib/cdr/entity-column-editor/entity-column-editor.component'; -export { ParameterizedTextModule } from './lib/parameterized-text/parameterized-text.module'; -export { ParameterizedTextComponent } from './lib/parameterized-text/parameterized-text.component'; -export { ParameterizedTextService } from './lib/parameterized-text/parameterized-text.service'; -export { ParameterizedText } from './lib/parameterized-text/parameterized-text.interface'; -export { TextToken } from './lib/parameterized-text/text-token.interface'; -export { IeWarningService } from './lib/base/ie-warning.service'; -export { EntityTreeDatabase } from './lib/data-tree/entity-tree-database'; -export { DynamicMethodService } from './lib/api-client/dynamic-method/dynamic-method.service'; -export { DynamicCollectionLoadParameters } from './lib/api-client/dynamic-method/dynamic-collection-load-parameters.interface'; -export { InteractiveParameter } from './lib/api-client/dynamic-method/interactive-parameter.interface'; -export { FilterWizardModule } from './lib/data-source-toolbar/filter-wizard/filter-wizard.module'; -export { FilterWizardComponent } from './lib/data-source-toolbar/filter-wizard/filter-wizard.component'; -export { SidenavTreeModule } from './lib/sidenav-tree/sidenav-tree.module'; +export { EuiDateProviders } from './lib/base/elemental-defaults'; +export { calculateSidesheetWidth, isMobile } from './lib/base/sidesheet-helper'; +export { setFilterDisplay } from './lib/data-source-toolbar/data-model/data-model-helper'; +export { FilterTreeComponent } from './lib/data-source-toolbar/filter-tree/filter-tree.component'; +export { TableAccessiblilityDirective } from './lib/data-table/table-accessibility.directive'; +export { TypedEntityFkData } from './lib/entity/typed-entity-select/typed-entity-fk-data.interface'; +export { FkCandidatesData } from './lib/fk-advanced-picker/fk-candidates/fk-candidates-data.interface'; +export { HelpContextualComponent } from './lib/help-contextual/help-contextual.component'; +export { HelpContextualModule } from './lib/help-contextual/help-contextual.module'; +export { HELP_CONTEXTUAL, HelpContextualService, HelpContextualValues } from './lib/help-contextual/help-contextual.service'; +export { HyperViewNavigation, HyperViewNavigationEnum } from './lib/hyperview/hyperview-types'; +export { MessageDialogService } from './lib/message-dialog/message-dialog.service'; +export { SelectedElementsComponent } from './lib/selected-elements/selected-elements.component'; +export { SelectedElementsModule } from './lib/selected-elements/selected-elements.module'; +export { DynamicDataApiControls, DynamicDataSource } from './lib/sidenav-tree/sidenav-tree-dynamic-extension'; export { SidenavTreeComponent } from './lib/sidenav-tree/sidenav-tree.component'; -export { DynamicDataSource, DynamicDataApiControls } from './lib/sidenav-tree/sidenav-tree-dynamic-extension'; export { BaseImxApiDataMock, BaseImxApiDtoMock, @@ -308,13 +308,21 @@ export { Message } from './lib/user-message/message.interface'; export { UserMessageComponent } from './lib/user-message/user-message.component'; export { UserMessageModule } from './lib/user-message/user-message.module'; export { UserMessageService } from './lib/user-message/user-message.service'; -export { HelpContextualModule } from './lib/help-contextual/help-contextual.module'; -export { HelpContextualComponent } from './lib/help-contextual/help-contextual.component'; -export { HelpContextualService, HELP_CONTEXTUAL, HelpContextualValues } from './lib/help-contextual/help-contextual.service'; -export { HyperViewNavigation, HyperViewNavigationEnum } from './lib/hyperview/hyperview-types'; -export { SelectedElementsModule } from './lib/selected-elements/selected-elements.module'; -export { SelectedElementsComponent } from './lib/selected-elements/selected-elements.component'; -export { FilterTreeComponent } from './lib/data-source-toolbar/filter-tree/filter-tree.component'; -export { TempBillboardModule } from './lib/temp-billboard/temp-billboard.module'; -export { TempBillboardComponent } from './lib/temp-billboard/temp-billboard.component'; +// DataView +export { DataViewAutoTableComponent } from './lib/data-view/data-view-auto-table/data-view-auto-table.component'; +export { DataViewChipbarComponent } from './lib/data-view/data-view-chipbar/data-view-chipbar.component'; +export { DataViewFilterComponent } from './lib/data-view/data-view-filter/data-view-filter.component'; +export { DataViewGroupComponent } from './lib/data-view/data-view-group/data-view-group.component'; +export { DataViewPaginatorComponent } from './lib/data-view/data-view-paginator/data-view-paginator.component'; +export { DataViewSearchComponent } from './lib/data-view/data-view-search/data-view-search.component'; +export { DataViewSelectionComponent } from './lib/data-view/data-view-selection/data-view-selection.component'; +export { DataViewStatusComponent } from './lib/data-view/data-view-status/data-view-status.component'; + +export { DataViewSettingsComponent } from './lib/data-view/data-view-settings/data-view-settings.component'; +export { DataViewSource } from './lib/data-view/data-view-source'; +export { DataViewSourceFactoryService } from './lib/data-view/data-view-source-factory.service'; +export { FakeDataViewSource } from './lib/data-view/data-view-source.spec'; +export { DataViewToolbarComponent } from './lib/data-view/data-view-toolbar/data-view-toolbar.component'; +export { DataViewInitParameters } from './lib/data-view/data-view.interface'; +export { DataViewModule } from './lib/data-view/data-view.module'; diff --git a/imxweb/projects/qbm/src/test.ts b/imxweb/projects/qbm/src/test.ts index 38e0ab845..df55524d0 100644 --- a/imxweb/projects/qbm/src/test.ts +++ b/imxweb/projects/qbm/src/test.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -26,15 +26,15 @@ // This file is required by karma.conf.js and loads recursively all the .spec and framework files -import 'core-js/es7/reflect'; -import 'zone.js/dist/zone'; -import 'zone.js/dist/zone-testing'; +// Zone must be imported first. Be careful with prettier import organizing +import 'zone.js'; +import 'zone.js/testing'; + import { getTestBed } from '@angular/core/testing'; import { BrowserDynamicTestingModule, platformBrowserDynamicTesting } from '@angular/platform-browser-dynamic/testing'; +import 'core-js/es/reflect'; +import { QbmDefaultMocks } from './default-mocks.spec'; import { TestHelperModule } from './lib/testing/TestHelperModule.spec'; -import { QbmDefaultMocks} from './default-mocks.spec'; - -declare const require: any; // First, initialize the Angular testing environment. getTestBed().initTestEnvironment([BrowserDynamicTestingModule, TestHelperModule], platformBrowserDynamicTesting(), { @@ -42,9 +42,5 @@ getTestBed().initTestEnvironment([BrowserDynamicTestingModule, TestHelperModule] destroyAfterEach: false, }, }); -// Then we find all the tests. -const context = require.context('./', true, /\.spec\.ts$/); -// And load the modules. -context.keys().map(context); QbmDefaultMocks.registerDefaultMocks(); diff --git a/imxweb/projects/qbm/tsconfig.lib.json b/imxweb/projects/qbm/tsconfig.lib.json index 6bc419f84..f863d8bff 100644 --- a/imxweb/projects/qbm/tsconfig.lib.json +++ b/imxweb/projects/qbm/tsconfig.lib.json @@ -7,10 +7,11 @@ "declarationMap": true, "sourceMap": true, "inlineSources": true, + "strictNullChecks": true, "types": [] }, - "exclude": [ - "src/test.ts", - "**/*.spec.ts" - ] + "angularCompilerOptions": { + "strictTemplates": true + }, + "exclude": ["src/test.ts", "**/*.spec.ts"] } diff --git a/imxweb/projects/qbm/tsconfig.spec.json b/imxweb/projects/qbm/tsconfig.spec.json index 16da33db0..6bd74e1f7 100644 --- a/imxweb/projects/qbm/tsconfig.spec.json +++ b/imxweb/projects/qbm/tsconfig.spec.json @@ -1,17 +1,10 @@ { "extends": "../../tsconfig.json", "compilerOptions": { + "strictNullChecks": false, "outDir": "../../out-tsc/spec", - "types": [ - "jasmine", - "node" - ] + "types": ["jasmine", "node"] }, - "files": [ - "src/test.ts" - ], - "include": [ - "**/*.spec.ts", - "**/*.d.ts" - ] + "files": ["src/test.ts"], + "include": ["**/*.spec.ts", "**/*.d.ts"] } diff --git a/imxweb/projects/qbm/tslint.json b/imxweb/projects/qbm/tslint.json deleted file mode 100644 index 8bab15f53..000000000 --- a/imxweb/projects/qbm/tslint.json +++ /dev/null @@ -1,17 +0,0 @@ -{ - "extends": "../../tslint.json", - "rules": { - "directive-selector": [ - true, - "attribute", - "imx", - "camelCase" - ], - "component-selector": [ - true, - "element", - "imx", - "kebab-case" - ] - } -} diff --git a/imxweb/projects/qer-app-operationssupport/.compodocrc.json b/imxweb/projects/qer-app-operationssupport/.compodocrc.json index 4c9cd3fc1..59ae1dd26 100644 --- a/imxweb/projects/qer-app-operationssupport/.compodocrc.json +++ b/imxweb/projects/qer-app-operationssupport/.compodocrc.json @@ -1,6 +1,6 @@ { "name": "IMX Web - QER Operations Support", - "output": "../../documentation/v92/qer-app-operationssupport", + "output": "../../documentation/v93/qer-app-operationssupport", "theme": "material", "assetsFolder": "../../compodoc/assets", "customLogo": "../../compodoc/assets/images/oneidentity-logo.png", diff --git a/imxweb/projects/qer-app-operationssupport/.eslintrc.json b/imxweb/projects/qer-app-operationssupport/.eslintrc.json new file mode 100644 index 000000000..6cc4fb0bb --- /dev/null +++ b/imxweb/projects/qer-app-operationssupport/.eslintrc.json @@ -0,0 +1,38 @@ +{ + "extends": "../../.eslintrc.json", + "ignorePatterns": ["!**/*", "**/*.spec.ts"], + "overrides": [ + { + "files": ["*.ts"], + "parserOptions": { + "project": [ + "imxweb/projects/qer-app-operationssupport/tsconfig.app.json", + "imxweb/projects/qer-app-operationssupport/tsconfig.spec.json" + ], + "createDefaultProgram": true + }, + "rules": { + "@angular-eslint/directive-selector": [ + "error", + { + "type": "attribute", + "prefix": "imx", + "style": "camelCase" + } + ], + "@angular-eslint/component-selector": [ + "error", + { + "type": "element", + "prefix": "imx", + "style": "kebab-case" + } + ] + } + }, + { + "files": ["*.html"], + "rules": {} + } + ] +} diff --git a/imxweb/projects/qer-app-operationssupport/README.md b/imxweb/projects/qer-app-operationssupport/README.md index 740fc70ea..06148717e 100644 --- a/imxweb/projects/qer-app-operationssupport/README.md +++ b/imxweb/projects/qer-app-operationssupport/README.md @@ -1,4 +1,3 @@ # Operations Support Portal -The _Operations Support Portal_ is a web application to monitor the Identity Manager system state and troubleshoot queue processing. - +With the _Operations Support Portal_ users can perform typical operations support tasks. You can, among other things, monitor Job queue processing, DBQueue processing, and create passcodes to allow identities to log in to the Password Reset Portal. \ No newline at end of file diff --git a/imxweb/projects/qer-app-operationssupport/dpr-api-client.service.ts b/imxweb/projects/qer-app-operationssupport/dpr-api-client.service.ts index 77bf2b4c0..3768b63a6 100644 --- a/imxweb/projects/qer-app-operationssupport/dpr-api-client.service.ts +++ b/imxweb/projects/qer-app-operationssupport/dpr-api-client.service.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -25,12 +25,12 @@ */ import { Injectable } from '@angular/core'; -import { V2Client, TypedClient } from 'imx-api-dpr'; -import { ApiClient } from 'imx-qbm-dbts'; +import { V2Client, TypedClient } from '@imx-modules/imx-api-dpr'; +import { ApiClient } from '@imx-modules/imx-qbm-dbts'; import { AppConfigService, ClassloggerService, ImxTranslationProviderService } from 'qbm'; @Injectable({ - providedIn: 'root' + providedIn: 'root', }) export class DprApiService { private tc: TypedClient; @@ -50,7 +50,8 @@ export class DprApiService { constructor( private readonly config: AppConfigService, private readonly logger: ClassloggerService, - private readonly translationProvider: ImxTranslationProviderService) { + private readonly translationProvider: ImxTranslationProviderService, + ) { try { this.logger.debug(this, 'Initializing DPR API service'); diff --git a/imxweb/projects/qer-app-operationssupport/karma.conf.js b/imxweb/projects/qer-app-operationssupport/karma.conf.js index 5ac3b03d8..43effb2c5 100644 --- a/imxweb/projects/qer-app-operationssupport/karma.conf.js +++ b/imxweb/projects/qer-app-operationssupport/karma.conf.js @@ -12,10 +12,10 @@ module.exports = function (config) { require('karma-jasmine-html-reporter'), require('karma-coverage-istanbul-reporter'), require('@angular-devkit/build-angular/plugins/karma'), - require('karma-junit-reporter') + require('karma-junit-reporter'), ], client: { - clearContext: false // leave Jasmine Spec Runner output visible in browser + clearContext: false, // leave Jasmine Spec Runner output visible in browser }, coverageIstanbulReporter: { dir: require('path').join(__dirname, 'results'), @@ -23,7 +23,7 @@ module.exports = function (config) { fixWebpackSourcePaths: true, 'report-config': { html: { - subdir: 'coverage-html' + subdir: 'coverage-html', }, }, thresholds: { @@ -31,7 +31,7 @@ module.exports = function (config) { branches: 0, functions: 0, lines: 0, - } + }, }, junitReporter: { outputDir: require('path').join(__dirname, 'results'), @@ -40,13 +40,14 @@ module.exports = function (config) { port: 9876, captureTimeout: 210000, browserDisconnectTolerance: 3, - browserDisconnectTimeout : 210000, - browserNoActivityTimeout : 210000, + browserDisconnectTimeout: 210000, + browserNoActivityTimeout: 210000, colors: true, logLevel: config.LOG_INFO, autoWatch: true, restartOnFileChange: true, singleRun: false, - browsers: ['Chrome'] + failOnEmptyTestSuite: false, + browsers: ['Chrome'], }); }; diff --git a/imxweb/projects/qer-app-operationssupport/package.json b/imxweb/projects/qer-app-operationssupport/package.json index 4cfb5b054..8e635b684 100644 --- a/imxweb/projects/qer-app-operationssupport/package.json +++ b/imxweb/projects/qer-app-operationssupport/package.json @@ -1,9 +1,7 @@ { "name": "qer-app-operationssupport", - "version": "9.2.1", + "version": "9.3.0", "private": true, "description": "One Identity Manager Operations Support Web Portal", - "peerDependencies": { - - } + "peerDependencies": {} } diff --git a/imxweb/projects/qer-app-operationssupport/prebuild.js b/imxweb/projects/qer-app-operationssupport/prebuild.js new file mode 100644 index 000000000..ba107f717 --- /dev/null +++ b/imxweb/projects/qer-app-operationssupport/prebuild.js @@ -0,0 +1,6 @@ +const fs = require('fs'); +const src = 'dist/uci'; +const dest = 'html/qer-app-operationssupport/uci'; + +console.log(`Copy uci from ${src} folder to ${dest}`); +fs.cpSync(src, dest, { recursive: true }); diff --git a/imxweb/projects/qer-app-operationssupport/project.json b/imxweb/projects/qer-app-operationssupport/project.json new file mode 100644 index 000000000..5fef79b68 --- /dev/null +++ b/imxweb/projects/qer-app-operationssupport/project.json @@ -0,0 +1,221 @@ +{ + "$schema": "../../node_modules/nx/schemas/project-schema.json", + "name": "qer-app-operationssupport", + "sourceRoot": "projects/qer-app-operationssupport/src", + "projectType": "application", + "prefix": "imx", + "generators": { + "@schematics/angular:component": { + "style": "scss" + } + }, + "targets": { + "build": { + "executor": "@angular-devkit/build-angular:browser", + "options": { + "aot": true, + "allowedCommonJsDependencies": [ + "lodash", + "highlight.js", + "file-saver", + "billboard.js", + "moment-timezone", + "core-js/fn/map", + "core-js/fn/set", + "core-js/fn/weak-map", + "core-js/fn/array/from", + "core-js/fn/object/assign", + "core-js/es/array/from", + "core-js/es/object/assign", + "core-js/es/map", + "core-js/es/set", + "core-js/es/weak-map", + "lodash.debounce", + "lodash.clamp", + "moment", + "@elemental-ui/cadence-icon/codepoints" + ], + "outputPath": "dist/qer-app-operationssupport", + "index": "projects/qer-app-operationssupport/src/index.html", + "main": "projects/qer-app-operationssupport/src/main.ts", + "polyfills": ["projects/qer-app-operationssupport/src/polyfills.ts"], + "tsConfig": "projects/qer-app-operationssupport/tsconfig.app.json", + "assets": [ + "projects/qer-app-operationssupport/src/assets", + "projects/qer-app-operationssupport/src/appconfig.json", + { + "glob": "**/*", + "input": "./shared/assets/", + "output": "./assets" + }, + { + "glob": "**/*", + "input": "./node_modules/@elemental-ui/core/assets", + "output": "./assets" + } + ], + "styles": [ + "shared/scss/styles.scss", + "projects/qer-app-operationssupport/src/styles.scss", + "projects/qbm/src/lib/styles/imx-page-title.scss" + ], + "stylePreprocessorOptions": { + "includePaths": [ + "./shared/scss", + "./node_modules", + "./node_modules/@elemental-ui/cadence-icon", + "./node_modules/@elemental-ui/core" + ] + } + }, + "configurations": { + "production": { + "fileReplacements": [ + { + "replace": "projects/qer-app-operationssupport/src/environments/environment.ts", + "with": "projects/qer-app-operationssupport/src/environments/environment.prod.ts" + } + ], + "optimization": true, + "outputHashing": "all", + "sourceMap": false, + "namedChunks": false, + "aot": true, + "extractLicenses": true, + "vendorChunk": false, + "buildOptimizer": true, + "budgets": [ + { + "type": "initial", + "maximumWarning": "20mb", + "maximumError": "40mb" + }, + { + "type": "anyComponentStyle", + "maximumWarning": "6kb" + } + ] + }, + "development": { + "buildOptimizer": false, + "optimization": false, + "vendorChunk": true, + "extractLicenses": false, + "sourceMap": true, + "namedChunks": true + }, + "remote-dev": { + "fileReplacements": [ + { + "replace": "projects/qer-app-operationssupport/src/environments/environment.ts", + "with": "../imxweb_envs/qer-app-operationssupport/environments/environment.remote-dev.ts" + } + ], + "buildOptimizer": false, + "optimization": false, + "vendorChunk": true, + "extractLicenses": false, + "sourceMap": true, + "namedChunks": true + }, + "remote-qs": { + "fileReplacements": [ + { + "replace": "projects/qer-app-operationssupport/src/environments/environment.ts", + "with": "../imxweb_envs/qer-app-operationssupport/environments/environment.remote-qs.ts" + } + ], + "buildOptimizer": false, + "optimization": false, + "vendorChunk": true, + "extractLicenses": false, + "sourceMap": true, + "namedChunks": true + }, + "es5": { + "tsConfig": "./projects/qer-app-operationssupport/tsconfig-es5.app.json" + } + }, + "outputs": ["{options.outputPath}"], + "dependsOn": ["^build", "prebuild"] + }, + "prebuild": { + "executor": "nx:run-commands", + "options": { + "commands": ["node prebuild.js qer-app-operationssupport"] + }, + "dependsOn": [ + { + "projects": ["dpr", "uci"], + "target": "build" + } + ], + "cache": false + }, + "serve": { + "executor": "@angular-devkit/build-angular:dev-server", + "options": { + "browserTarget": "qer-app-operationssupport:build", + "disableHostCheck": true + }, + "configurations": { + "production": { + "browserTarget": "qer-app-operationssupport:build:production" + }, + "development": { + "browserTarget": "qer-app-operationssupport:build:development" + }, + "remote-dev": { + "browserTarget": "qer-app-operationssupport:build:remote-dev" + }, + "remote-qs": { + "browserTarget": "qer-app-operationssupport:build:remote-dev" + }, + "es5": { + "browserTarget": "qer-app-operationssupport:build:es5" + } + } + }, + "extract-i18n": { + "executor": "@angular-devkit/build-angular:extract-i18n", + "options": { + "browserTarget": "qer-app-operationssupport:build" + } + }, + "test": { + "executor": "@angular-devkit/build-angular:karma", + "options": { + "main": "projects/qer-app-operationssupport/src/test.ts", + "polyfills": "projects/qer-app-operationssupport/src/polyfills.ts", + "tsConfig": "projects/qer-app-operationssupport/tsconfig.spec.json", + "karmaConfig": "projects/qer-app-operationssupport/karma.conf.js", + "styles": ["projects/qer-app-operationssupport/src/styles.scss", "shared/scss/styles.scss"], + "stylePreprocessorOptions": { + "includePaths": [ + "./shared/assets", + "./shared/scss", + "./node_modules", + "./node_modules/@elemental-ui/cadence-icon", + "./node_modules/@elemental-ui/core" + ] + }, + "assets": [ + "projects/qer-app-operationssupport/src/assets", + "projects/qer-app-operationssupport/src/appconfig.json", + { + "glob": "**/*", + "input": "./shared/assets/", + "output": "./assets" + } + ] + } + }, + "lint": { + "executor": "@angular-devkit/build-angular:tslint", + "options": { + "tsConfig": ["projects/qer-app-operationssupport/tsconfig.app.json", "projects/qer-app-operationssupport/tsconfig.spec.json"], + "exclude": ["**/node_modules/**", "**/*.spec.ts", "**/*.json"] + } + } + } +} diff --git a/imxweb/projects/qer-app-operationssupport/src/app/app-routing.module.ts b/imxweb/projects/qer-app-operationssupport/src/app/app-routing.module.ts index 53736d677..f13da3e4f 100644 --- a/imxweb/projects/qer-app-operationssupport/src/app/app-routing.module.ts +++ b/imxweb/projects/qer-app-operationssupport/src/app/app-routing.module.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -25,37 +25,37 @@ */ import { NgModule } from '@angular/core'; -import { Routes, RouterModule } from '@angular/router'; +import { RouterModule, Routes } from '@angular/router'; +import { OutstandingComponent } from 'dpr'; import { AuthenticationGuardService, LoginComponent, RouteGuardService } from 'qbm'; -import { ObjectOverviewComponent } from './object-overview/object-overview.component'; -import { JobsComponent } from './processes/jobs/jobs.component'; -import { JournalComponent } from './journal/journal.component'; -import { UnresolvedRefsComponent } from './unresolved-refs/unresolved-refs.component'; +import { DashboardComponent } from './dashboard/dashboard.component'; +import { DataChangesComponent } from './data-changes/data-changes.component'; +import { DbQueueComponent } from './db-queue/db-queue.component'; +import { OutstandingManagerGuardService } from './guards/outstanding-manager-guard.service'; +import { SystemStatusRouteGuardService } from './guards/system-status-route-guard.service'; import { SystemStatusComponent } from './information/system-status/system-status.component'; -import { WebApplicationsComponent } from './web-applications/web-applications.component'; -import { ServiceAvailabilityComponent } from './service-report/service-availability.component'; -import { ServicesInactiveComponent } from './service-report/services-inactive.component'; +import { JournalComponent } from './journal/journal.component'; +import { ObjectOverviewComponent } from './object-overview/object-overview.component'; import { FrozenJobsComponent } from './processes/frozen-jobs/frozen-jobs.component'; import { JobChainsComponent } from './processes/job-chains/job-chains.component'; import { JobHistoryComponent } from './processes/job-history/job-history.component'; import { JobPerformanceComponent } from './processes/job-performance/job-performance.component'; -import { DashboardComponent } from './dashboard/dashboard.component'; +import { JobsComponent } from './processes/jobs/jobs.component'; +import { ObjectsByIdComponent } from './processes/objects-by-id/objects-by-id.component'; +import { ServiceAvailabilityComponent } from './service-report/service-availability.component'; +import { ServicesInactiveComponent } from './service-report/services-inactive.component'; import { SyncInformationComponent } from './sync/sync-information/sync-information.component'; import { SyncJournalComponent } from './sync/sync-journal/sync-journal.component'; -import { OutstandingComponent } from 'dpr'; -import { SystemStatusRouteGuardService } from './guards/system-status-route-guard.service'; -import { OutstandingManagerGuardService } from './guards/outstanding-manager-guard.service'; -import { ObjectsByIdComponent } from './processes/objects-by-id/objects-by-id.component'; -import { DataChangesComponent } from './data-changes/data-changes.component'; -import { DbQueueComponent } from './db-queue/db-queue.component'; +import { UnresolvedRefsComponent } from './unresolved-refs/unresolved-refs.component'; +import { WebApplicationsComponent } from './web-applications/web-applications.component'; const routes: Routes = [ { path: '', component: LoginComponent, canActivate: [AuthenticationGuardService], - resolve: [RouteGuardService] + resolve: [RouteGuardService], }, { path: 'start', @@ -182,7 +182,7 @@ const routes: Routes = [ path: 'DataChanges', component: DataChangesComponent, canActivate: [RouteGuardService], - resolve: [RouteGuardService] + resolve: [RouteGuardService], }, { path: 'DbQueue', @@ -190,11 +190,11 @@ const routes: Routes = [ canActivate: [RouteGuardService], resolve: [RouteGuardService], }, - { path: '**', redirectTo: 'start' } + { path: '**', redirectTo: 'start' }, ]; @NgModule({ - imports: [RouterModule.forRoot(routes, { useHash: true, relativeLinkResolution: 'legacy' })], + imports: [RouterModule.forRoot(routes, { useHash: true })], exports: [RouterModule], }) export class AppRoutingModule {} diff --git a/imxweb/projects/qer-app-operationssupport/src/app/app.component.html b/imxweb/projects/qer-app-operationssupport/src/app/app.component.html index 5bb4e9beb..46ce38a81 100644 --- a/imxweb/projects/qer-app-operationssupport/src/app/app.component.html +++ b/imxweb/projects/qer-app-operationssupport/src/app/app.component.html @@ -1,7 +1,7 @@
    - + @@ -9,7 +9,6 @@
    -
    -
    \ No newline at end of file +
    diff --git a/imxweb/projects/qer-app-operationssupport/src/app/app.component.scss b/imxweb/projects/qer-app-operationssupport/src/app/app.component.scss index f2f2404b6..8caa5f7be 100644 --- a/imxweb/projects/qer-app-operationssupport/src/app/app.component.scss +++ b/imxweb/projects/qer-app-operationssupport/src/app/app.component.scss @@ -1,5 +1,5 @@ -@import "variables.scss"; - +@import 'base/variables'; +@import '../../../../shared/scss/components/top-navigation.scss'; .page { display: flex; flex-direction: column; @@ -7,7 +7,7 @@ height: 100vh; } -.page .mat-tab-links { +.page .mat-mdc-tab-links { margin-left: 31px; } @@ -16,7 +16,7 @@ flex-direction: column; overflow: hidden; height: inherit; - margin: 40px 60px; + margin: 24px; &--full-page { margin: 0; @@ -38,20 +38,3 @@ } } } - -@media only screen and (max-width: 768px) { - - .eui-top-navigation-mobile { - .eui-top-navigation-mobile-footer { - .mat-button { - &.imx-masthead--icon-button { - width: 100%; - - .mat-button-wrapper span { - display: inline-block; - } - } - } - } - } -} \ No newline at end of file diff --git a/imxweb/projects/qer-app-operationssupport/src/app/app.component.ts b/imxweb/projects/qer-app-operationssupport/src/app/app.component.ts index 8a49b6ba1..33799dac3 100644 --- a/imxweb/projects/qer-app-operationssupport/src/app/app.component.ts +++ b/imxweb/projects/qer-app-operationssupport/src/app/app.component.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -25,26 +25,29 @@ */ import { OverlayRef } from '@angular/cdk/overlay'; -import { Component, OnInit, OnDestroy, ErrorHandler } from '@angular/core'; -import { Router, RouterEvent, NavigationStart, NavigationEnd, NavigationError, NavigationCancel, EventType } from '@angular/router'; +import { Component, ErrorHandler, OnDestroy, OnInit } from '@angular/core'; +import { Event, EventType, NavigationCancel, NavigationEnd, NavigationError, NavigationStart, Router, RouterEvent } from '@angular/router'; import { EuiLoadingService, EuiTheme, EuiThemeService, EuiTopNavigationItem } from '@elemental-ui/core'; import { Subscription } from 'rxjs'; +import { MatDialog } from '@angular/material/dialog'; +import { FeatureConfig, ProfileSettings } from '@imx-modules/imx-api-qer'; import { - MenuItem, AuthenticationService, + ClassloggerService, + ConfirmationService, ISessionState, + ImxTranslationProviderService, MenuService, + Message, SettingsService, - imx_SessionService, SplashService, - ImxTranslationProviderService, + UserMessageService, + imx_SessionService, } from 'qbm'; import { FeatureConfigService, OpSupportUserService, QerApiService, SettingsComponent } from 'qer'; -import { FeatureConfig, ProfileSettings } from 'imx-api-qer'; + import { isOutstandingManager } from './permissions/permissions-helper'; -import { MatDialog } from '@angular/material/dialog'; -import { TranslateService } from '@ngx-translate/core'; @Component({ selector: 'imx-root', @@ -55,12 +58,13 @@ export class AppComponent implements OnInit, OnDestroy { public menuItems: EuiTopNavigationItem[]; public isLoggedIn = false; public hideMenu = false; - public hideUserMessage = false; public showPageContent = true; + public message: Message | undefined; private routerStatus: EventType; private readonly subscriptions: Subscription[] = []; constructor( + private readonly logger: ClassloggerService, private readonly authentication: AuthenticationService, private readonly busyService: EuiLoadingService, private readonly router: Router, @@ -75,7 +79,8 @@ export class AppComponent implements OnInit, OnDestroy { private readonly themeService: EuiThemeService, private readonly errorHandler: ErrorHandler, private readonly translationProvider: ImxTranslationProviderService, - private readonly translateService: TranslateService + private readonly confirmationService: ConfirmationService, + private readonly userMessageService: UserMessageService, ) { this.subscriptions.push( this.authentication.onSessionResponse.subscribe(async (sessionState: ISessionState) => { @@ -88,15 +93,20 @@ export class AppComponent implements OnInit, OnDestroy { } } - this.isLoggedIn = sessionState.IsLoggedIn; + this.isLoggedIn = sessionState.IsLoggedIn ?? false; if (this.isLoggedIn) { - const isUseProfileLangChecked = (await this.qerClient.v2Client.opsupport_profile_get()).UseProfileLanguage ?? false; - // Set session culture if isUseProfileLangChecked is true, set browser culture otherwise + const isUseProfileLangChecked = (await this.qerClient.client.opsupport_profile_get()).UseProfileLanguage ?? false; + // Set session culture if isUseProfileLangChecked is true if (isUseProfileLangChecked) { - await this.translationProvider.init(sessionState.culture, sessionState.cultureFormat); - } else { - const browserCulture = this.translateService.getBrowserCultureLang(); - await this.translationProvider.init(browserCulture); + // Use culture if available, if not fetch + const culture = sessionState.culture + ? sessionState.culture + : (await this.qerClient.client.opsupport_profile_person_get())?.ProfileLanguage; + // If culture is found, use it, otherwise fallback to the app default + if (culture) { + this.logger.debug(this, `ProfileLangChecked is true, culture available: Setting ${culture} as profile language`); + await this.translationProvider.reinit(culture, sessionState.cultureFormat ?? culture, this.router); + } } // Close the splash screen that opened in app service initialisation @@ -110,19 +120,30 @@ export class AppComponent implements OnInit, OnDestroy { const groupInfo = await userModelService.getGroups(); this.menuItems = await this.menuService.getMenuItems( [], - groupInfo.map((group) => group.Name), - true + groupInfo.filter((group) => !!group.Name).map((group) => group.Name) as string[], + true, ); - this.applyProfileSettings(); + await this.applyProfileSettings(); } - }) + }), ); this.subscriptions.push( this.authentication.onSessionResponse.subscribe(async (sessionState: ISessionState) => { - this.isLoggedIn = sessionState.IsLoggedIn; - }) + this.isLoggedIn = sessionState.IsLoggedIn ?? false; + }), + ); + + this.subscriptions.push( + this.userMessageService.subject.subscribe((message) => { + this.message = message; + if (!!this.message && this.message.type === 'error' && !this.message.target) { + this.confirmationService.showErrorMessage({ + Message: this.message?.text, + }); + } + }), ); this.setupRouter(); @@ -143,17 +164,15 @@ export class AppComponent implements OnInit, OnDestroy { private setupRouter(): void { let overlayRef: OverlayRef; - this.router.events.subscribe((event: RouterEvent) => { + this.router.events.subscribe((event: Event & RouterEvent) => { if (event instanceof NavigationStart) { this.routerStatus = event.type; - this.hideUserMessage = true; if (this.isLoggedIn && event.url === '/') { // show the splash screen, when the user logs out! this.splash.init({ applicationName: 'Operations Support Web Portal' }); } } if (event instanceof NavigationEnd || event instanceof NavigationCancel || event instanceof NavigationError) { - this.hideUserMessage = false; this.routerStatus = event.type; this.hideMenu = event.url === '/'; this.showPageContent = true; @@ -181,7 +200,7 @@ export class AppComponent implements OnInit, OnDestroy { }, (__: string[], groups: string[]) => { if (!groups.includes('QER_4_OperationsSupport')) { - return null; + return undefined; } const menu = { @@ -220,7 +239,7 @@ export class AppComponent implements OnInit, OnDestroy { }, (__: string[], groups: string[]) => { if (!groups.includes('QER_4_OperationsSupport')) { - return null; + return undefined; } const menu = { @@ -239,7 +258,7 @@ export class AppComponent implements OnInit, OnDestroy { }, (__: string[], groups: string[]) => { if (!groups.includes('QER_4_OperationsSupport')) { - return null; + return undefined; } const menu = { id: 'OpsWeb_ROOT_Synchronization', @@ -274,7 +293,7 @@ export class AppComponent implements OnInit, OnDestroy { }, (__: string[], groups: string[]) => { if (!groups.includes('QER_4_OperationsSupport')) { - return null; + return undefined; } const menu = { id: 'OpsWeb_ROOT_System', @@ -307,10 +326,10 @@ export class AppComponent implements OnInit, OnDestroy { }); } return menu; - } + }, ); - return null; + return undefined; } private async applyProfileSettings() { diff --git a/imxweb/projects/qer-app-operationssupport/src/app/app.module.ts b/imxweb/projects/qer-app-operationssupport/src/app/app.module.ts index a24036ff5..24dfb6745 100644 --- a/imxweb/projects/qer-app-operationssupport/src/app/app.module.ts +++ b/imxweb/projects/qer-app-operationssupport/src/app/app.module.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -24,54 +24,55 @@ * */ +import { APP_INITIALIZER, ErrorHandler, NgModule } from '@angular/core'; import { BrowserModule } from '@angular/platform-browser'; -import { NgModule, APP_INITIALIZER, ErrorHandler } from '@angular/core'; -import { HttpClientModule } from '@angular/common/http'; -import { TranslateModule, TranslateLoader, MissingTranslationHandler, TranslateService } from '@ngx-translate/core'; +import { provideHttpClient, withInterceptorsFromDi } from '@angular/common/http'; import { MatPaginatorIntl } from '@angular/material/paginator'; import { BrowserAnimationsModule } from '@angular/platform-browser/animations'; import { EuiCoreModule, EuiMaterialModule } from '@elemental-ui/core'; +import { MissingTranslationHandler, TranslateLoader, TranslateModule, TranslateService } from '@ngx-translate/core'; import { LoggerModule, NgxLoggerLevel } from 'ngx-logger'; +import { OutstandingModule } from 'dpr'; +import { RECAPTCHA_V3_SITE_KEY } from 'ng-recaptcha-2'; import { - ImxTranslateLoader, - ImxMissingTranslationHandler, + AuthenticationModule, + CustomThemeModule, GlobalErrorHandler, - Paginator, - OpsupportDbObjectService, + ImxMissingTranslationHandler, + ImxTranslateLoader, LdsReplacePipe, - MenuModule, MastHeadModule, - UserMessageModule, - AuthenticationModule, + OpsupportDbObjectService, + Paginator, RouteGuardService, - CustomThemeModule, SqlWizardApiService, SqlWizardModule, + UserMessageModule, } from 'qbm'; -import { OutstandingModule } from 'dpr'; +import { OpsModule } from 'qer'; +import appConfigJson from '../appconfig.json'; +import { environment } from '../environments/environment'; import { AppRoutingModule } from './app-routing.module'; -import { SyncModule } from './sync/sync.module'; -import { ObjectOverviewModule } from './object-overview/object-overview.module'; -import { WebApplicationsModule } from './web-applications/web-applications.module'; -import { JournalModule } from './journal/journal.module'; -import { UnresolvedRefsModule } from './unresolved-refs/unresolved-refs.module'; -import { DashboardModule } from './dashboard/dashboard.module'; -import { SystemOverviewModule } from './information/system-overview/system-overview.module'; -import { SystemStatusModule } from './information/system-status/system-status.module'; -import { ProcessesModule } from './processes/processes.module'; import { AppComponent } from './app.component'; import { AppService } from './app.service'; -import { environment } from '../environments/environment'; -import appConfigJson from '../appconfig.json'; +import { OpsSqlWizardApiService } from './base/ops-sql-wizard-api.service'; +import { DashboardModule } from './dashboard/dashboard.module'; import { DataChangesModule } from './data-changes/data-changes.module'; import { DbQueueModule } from './db-queue/db-queue.module'; -import { OpsSqlWizardApiService } from './base/ops-sql-wizard-api.service'; -import { QerModule } from 'qer'; +import { SystemOverviewModule } from './information/system-overview/system-overview.module'; +import { SystemStatusModule } from './information/system-status/system-status.module'; +import { JournalModule } from './journal/journal.module'; +import { ObjectOverviewModule } from './object-overview/object-overview.module'; +import { ProcessesModule } from './processes/processes.module'; +import { SyncModule } from './sync/sync.module'; +import { UnresolvedRefsModule } from './unresolved-refs/unresolved-refs.module'; +import { WebApplicationsModule } from './web-applications/web-applications.module'; @NgModule({ declarations: [AppComponent], + bootstrap: [AppComponent], imports: [ AppRoutingModule, AuthenticationModule, @@ -79,10 +80,8 @@ import { QerModule } from 'qer'; BrowserModule, EuiCoreModule, EuiMaterialModule, - HttpClientModule, LoggerModule.forRoot({ level: NgxLoggerLevel.DEBUG, serverLogLevel: NgxLoggerLevel.OFF }), MastHeadModule, - MenuModule, DbQueueModule, TranslateModule.forRoot({ loader: { @@ -107,8 +106,8 @@ import { QerModule } from 'qer'; ProcessesModule, OutstandingModule, DataChangesModule, - QerModule, - SqlWizardModule + OpsModule, + SqlWizardModule, ], providers: [ { provide: 'environment', useValue: environment }, @@ -134,7 +133,14 @@ import { QerModule } from 'qer'; provide: SqlWizardApiService, useClass: OpsSqlWizardApiService, }, + { + provide: RECAPTCHA_V3_SITE_KEY, + useFactory: (config: AppService) => { + return config.recaptchaSiteKeyV3; + }, + deps: [AppService], + }, + provideHttpClient(withInterceptorsFromDi()), ], - bootstrap: [AppComponent], }) export class AppModule {} diff --git a/imxweb/projects/qer-app-operationssupport/src/app/app.service.ts b/imxweb/projects/qer-app-operationssupport/src/app/app.service.ts index 173de81a8..9bc642452 100644 --- a/imxweb/projects/qer-app-operationssupport/src/app/app.service.ts +++ b/imxweb/projects/qer-app-operationssupport/src/app/app.service.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -24,36 +24,33 @@ * */ -import { Injectable } from '@angular/core'; +import { Injectable, Injector, createNgModule } from '@angular/core'; import { Title } from '@angular/platform-browser'; import { TranslateService } from '@ngx-translate/core'; -import { Globals } from 'imx-qbm-dbts'; +import { ImxConfig, TypedClient } from '@imx-modules/imx-api-qbm'; +import { Globals } from '@imx-modules/imx-qbm-dbts'; import { AppConfigService, - ExtService, - ClassloggerService, + AuthenticationService, + CaptchaService, CdrRegistryService, + ClassloggerService, + ExtService, ImxTranslationProviderService, - imx_SessionService, - AuthenticationService, - PluginLoaderService, SplashService, - SystemInfoService + SystemInfoService, + imx_SessionService, } from 'qbm'; -import { SystemOverviewComponent } from './information/system-overview/system-overview.component'; import { environment } from '../environments/environment'; -import { TypedClient } from 'imx-api-qbm'; - -import * as QBM from 'qbm'; -import * as QER from 'qer'; - -declare var SystemJS: any; +import { SystemOverviewComponent } from './information/system-overview/system-overview.component'; @Injectable({ - providedIn: 'root' + providedIn: 'root', }) export class AppService { + public recaptchaSiteKeyV3: string | null = null; + private imxConfig: ImxConfig; constructor( public readonly registry: CdrRegistryService, private readonly logger: ClassloggerService, @@ -64,21 +61,22 @@ export class AppService { private readonly translationProvider: ImxTranslationProviderService, private readonly title: Title, private readonly extService: ExtService, - private readonly pluginLoader: PluginLoaderService, private readonly authentication: AuthenticationService, private readonly splash: SplashService, - ) { } - + private readonly injector: Injector, + private readonly captchaService: CaptchaService, + ) {} public async init(): Promise { this.showSplash(); await this.config.init(environment.clientUrl); - this.translateService.addLangs(this.config.Config.Translation.Langs); - const browserCulture = this.translateService.getBrowserCultureLang(); - this.logger.debug(this, `Set ${browserCulture} as default language`); - this.translateService.setDefaultLang(browserCulture); - await this.translateService.use(browserCulture).toPromise(); + if (this.config.Config.Translation?.Langs) { + this.translateService.addLangs(this.config.Config.Translation.Langs); + } + await this.translationProvider.init(); + + this.imxConfig = await this.systemInfoService.getImxConfig(); this.translateService.onLangChange.subscribe(() => { this.setTitle(); @@ -87,20 +85,21 @@ export class AppService { this.setTitle(); this.extService.register('SystemOverview', { - instance: SystemOverviewComponent + instance: SystemOverviewComponent, }); this.session.TypedClient = new TypedClient(this.config.v2client, this.translationProvider); - SystemJS.set('qbm', SystemJS.newModule(QBM)); - SystemJS.set('qer', SystemJS.newModule(QER)); - - await this.pluginLoader.loadModules(environment.appName); + await this.loadModules(environment.appName); + if (this.imxConfig.RecaptchaPublicKey) { + this.captchaService.enableReCaptcha(this.imxConfig.RecaptchaPublicKey); + this.recaptchaSiteKeyV3 = this.imxConfig.RecaptchaPublicKey; + } + this.captchaService.captchaImageUrl = 'opsupport/captchaimage'; } private async setTitle(): Promise { - const imxConfig = await this.systemInfoService.getImxConfig(); - const name = imxConfig.ProductName || Globals.QIM_ProductNameFull; + const name = this.imxConfig.ProductName || Globals.QIM_ProductNameFull; this.config.Config.Title = await this.translateService.get('#LDS#Heading Operations Support Web Portal').toPromise(); const title = `${name} ${this.config.Config.Title}`; this.title.setTitle(title); @@ -126,4 +125,42 @@ export class AppService { const loadingMsg = await this.translateService.get('#LDS#Loading...').toPromise(); this.splash.update({ applicationName: title, message: loadingMsg }); } + + private async loadModules(appName: string): Promise { + const apps = await this.session.Client.imx_applications_get(); + + const appInfo = apps.filter((app) => app.Name === appName)[0]; + + this.logger.debug(this, `▶️ Found config section for ${appInfo.DisplayName}`); + + if (appInfo.PlugIns == null || appInfo.PlugIns.length === 0) { + this.logger.debug(this, `❌ No plugins found`); + return; + } + + this.logger.debug(this, `▶️ Found ${appInfo.PlugIns.length} plugin(s)`); + + for (const plugin of appInfo.PlugIns) { + if (!plugin.Name || !plugin.Container) { + this.logger.debug(this, `❌ Malformed plugin: ${plugin.Container}`); + continue; + } + this.logger.debug(this, `⚙️ Plugin: ${plugin.Container}`); + + try { + this.logger.debug(this, '▶️ Importing module. DEV mode.'); + await import(`html/qer-app-operationssupport/${plugin.Container}/fesm2022/${plugin.Container}.mjs`) + .then((m) => { + if (plugin.Name) { + createNgModule(m[plugin.Name], this.injector); + } + }) + .catch((error) => + this.logger.error(this, `💥 Loading of ${plugin.Name} (${plugin.Container}) failed with the following error: ${error.message}`), + ); + } catch (e) { + this.logger.error(this, `💥 Loading of ${plugin.Name} (${plugin.Container}) failed with the following error: ${e.message}`); + } + } + } } diff --git a/imxweb/projects/qer-app-operationssupport/src/app/base/ops-sql-wizard-api.service.ts b/imxweb/projects/qer-app-operationssupport/src/app/base/ops-sql-wizard-api.service.ts index 9b21fd67c..e27a2f11b 100644 --- a/imxweb/projects/qer-app-operationssupport/src/app/base/ops-sql-wizard-api.service.ts +++ b/imxweb/projects/qer-app-operationssupport/src/app/base/ops-sql-wizard-api.service.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -25,11 +25,11 @@ */ import { Injectable } from '@angular/core'; -import { FilterProperty, CollectionLoadParameters, EntityCollectionData } from 'imx-qbm-dbts'; +import { FilterProperty, CollectionLoadParameters, EntityCollectionData } from '@imx-modules/imx-qbm-dbts'; import { SqlWizardApiService } from 'qbm'; @Injectable({ - providedIn: 'root' + providedIn: 'root', }) export class OpsSqlWizardApiService extends SqlWizardApiService { public implemented: boolean = false; @@ -38,7 +38,7 @@ export class OpsSqlWizardApiService extends SqlWizardApiService { return new Promise((resolve) => resolve([])); } getCandidates(parentTable: string, options?: CollectionLoadParameters): Promise { - return new Promise((resolve) => resolve({TotalCount: 0})); + return new Promise((resolve) => resolve({ TotalCount: 0 })); } constructor() { diff --git a/imxweb/projects/qer-app-operationssupport/src/app/base/subscription.service.ts b/imxweb/projects/qer-app-operationssupport/src/app/base/subscription.service.ts index 7d47905a1..8bb4d9dec 100644 --- a/imxweb/projects/qer-app-operationssupport/src/app/base/subscription.service.ts +++ b/imxweb/projects/qer-app-operationssupport/src/app/base/subscription.service.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -39,9 +39,7 @@ export abstract class SubscriptionService { public subscribe(updateInterval: number = 30000): void { this.updateItems(); - this.refreshTimer = interval(updateInterval).subscribe(_ => - this.updateItems() - ); + this.refreshTimer = interval(updateInterval).subscribe((_) => this.updateItems()); } public unsubscribe(): void { diff --git a/imxweb/projects/qer-app-operationssupport/src/app/dashboard/dashboard.component.html b/imxweb/projects/qer-app-operationssupport/src/app/dashboard/dashboard.component.html index 825c922ce..027faff45 100644 --- a/imxweb/projects/qer-app-operationssupport/src/app/dashboard/dashboard.component.html +++ b/imxweb/projects/qer-app-operationssupport/src/app/dashboard/dashboard.component.html @@ -1,11 +1,11 @@ -

    - {{'#LDS#Welcome' | translate}} -

    +

    + {{ '#LDS#Welcome' | translate }} +

    - - - - - - -
    \ No newline at end of file + + + + + + +
    diff --git a/imxweb/projects/qer-app-operationssupport/src/app/dashboard/dashboard.component.scss b/imxweb/projects/qer-app-operationssupport/src/app/dashboard/dashboard.component.scss index 77c9fa272..d11236459 100644 --- a/imxweb/projects/qer-app-operationssupport/src/app/dashboard/dashboard.component.scss +++ b/imxweb/projects/qer-app-operationssupport/src/app/dashboard/dashboard.component.scss @@ -1,3 +1,3 @@ :host { overflow: auto; -} \ No newline at end of file +} diff --git a/imxweb/projects/qer-app-operationssupport/src/app/dashboard/dashboard.component.ts b/imxweb/projects/qer-app-operationssupport/src/app/dashboard/dashboard.component.ts index 8b0e07c3d..4af9e04be 100644 --- a/imxweb/projects/qer-app-operationssupport/src/app/dashboard/dashboard.component.ts +++ b/imxweb/projects/qer-app-operationssupport/src/app/dashboard/dashboard.component.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -29,16 +29,14 @@ import { OpSupportUserService } from 'qer'; @Component({ templateUrl: './dashboard.component.html', - styleUrls: ['./dashboard.component.scss'] + styleUrls: ['./dashboard.component.scss'], }) export class DashboardComponent implements OnInit { - public isOperationsSupporter: boolean; - constructor(private readonly userService: OpSupportUserService) { - } + constructor(private readonly userService: OpSupportUserService) {} public async ngOnInit() { - this.isOperationsSupporter = (await this.userService.getGroups()).map(g => g.Name).includes("QER_4_OperationsSupport"); + this.isOperationsSupporter = (await this.userService.getGroups()).map((g) => g.Name).includes('QER_4_OperationsSupport'); } } diff --git a/imxweb/projects/qer-app-operationssupport/src/app/dashboard/dashboard.module.ts b/imxweb/projects/qer-app-operationssupport/src/app/dashboard/dashboard.module.ts index eec6f2d89..844aee136 100644 --- a/imxweb/projects/qer-app-operationssupport/src/app/dashboard/dashboard.module.ts +++ b/imxweb/projects/qer-app-operationssupport/src/app/dashboard/dashboard.module.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -36,13 +36,6 @@ import { ServiceReportModule } from '../service-report/service-report.module'; @NgModule({ declarations: [DashboardComponent], - imports: [ - CommonModule, - ObjectSearchModule, - NotificationsModule, - ServiceIssuesModule, - ServiceReportModule, - TranslateModule - ] + imports: [CommonModule, ObjectSearchModule, NotificationsModule, ServiceIssuesModule, ServiceReportModule, TranslateModule], }) -export class DashboardModule { } +export class DashboardModule {} diff --git a/imxweb/projects/qer-app-operationssupport/src/app/data-changes/data-changes-sidesheet/data-changes-sidesheet.component.html b/imxweb/projects/qer-app-operationssupport/src/app/data-changes/data-changes-sidesheet/data-changes-sidesheet.component.html index 1d30c8d31..fc491582d 100644 --- a/imxweb/projects/qer-app-operationssupport/src/app/data-changes/data-changes-sidesheet/data-changes-sidesheet.component.html +++ b/imxweb/projects/qer-app-operationssupport/src/app/data-changes/data-changes-sidesheet/data-changes-sidesheet.component.html @@ -1,15 +1,15 @@
    -
    +
    - +
    -
    +
    @@ -17,17 +17,17 @@ - {{column.ColumnDisplay}} + {{ column.ColumnDisplay }} - + - + diff --git a/imxweb/projects/qer-app-operationssupport/src/app/data-changes/data-changes-sidesheet/data-changes-sidesheet.component.scss b/imxweb/projects/qer-app-operationssupport/src/app/data-changes/data-changes-sidesheet/data-changes-sidesheet.component.scss index 781140e5e..51cd954b5 100644 --- a/imxweb/projects/qer-app-operationssupport/src/app/data-changes/data-changes-sidesheet/data-changes-sidesheet.component.scss +++ b/imxweb/projects/qer-app-operationssupport/src/app/data-changes/data-changes-sidesheet/data-changes-sidesheet.component.scss @@ -1,4 +1,3 @@ - :host { .wrapper { height: 100%; diff --git a/imxweb/projects/qer-app-operationssupport/src/app/data-changes/data-changes-sidesheet/data-changes-sidesheet.component.ts b/imxweb/projects/qer-app-operationssupport/src/app/data-changes/data-changes-sidesheet/data-changes-sidesheet.component.ts index ccdcb7645..8f4ee6198 100644 --- a/imxweb/projects/qer-app-operationssupport/src/app/data-changes/data-changes-sidesheet/data-changes-sidesheet.component.ts +++ b/imxweb/projects/qer-app-operationssupport/src/app/data-changes/data-changes-sidesheet/data-changes-sidesheet.component.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -26,9 +26,9 @@ import { Component, Inject, OnInit } from '@angular/core'; import { EUI_SIDESHEET_DATA, EuiSidesheetRef } from '@elemental-ui/core'; +import { HistoryOperation, HistoryOperationColumn } from '@imx-modules/imx-api-qbm'; +import { IEntityColumn, ValType } from '@imx-modules/imx-qbm-dbts'; import { TranslateService } from '@ngx-translate/core'; -import { HistoryOperation, HistoryOperationColumn } from 'imx-api-qbm'; -import { IEntityColumn, ValType } from 'imx-qbm-dbts'; import { BaseReadonlyCdr, ColumnDependentReference, EntityService } from 'qbm'; import { Subscription } from 'rxjs'; @@ -39,6 +39,7 @@ import { Subscription } from 'rxjs'; }) export class DataChangesSidesheetComponent implements OnInit { public isOpening = true; + public isMulti: boolean; private openSub$: Subscription; public cdrList: ColumnDependentReference[] = []; @@ -46,17 +47,16 @@ export class DataChangesSidesheetComponent implements OnInit { @Inject(EUI_SIDESHEET_DATA) public data: HistoryOperation, private sidesheetRef: EuiSidesheetRef, private entityService: EntityService, - private translate: TranslateService + private translate: TranslateService, ) {} - public get isMulti(): boolean { - return this.data?.Columns && this.data.Columns.length > 1; - } - public ngOnInit(): void { - this.openSub$ = this.sidesheetRef.componentInstance.onOpen().subscribe((_) => { - this.isOpening = false; - }); + this.isMulti = (this.data?.Columns && this.data.Columns.length > 1) ?? false; + if (this.sidesheetRef.componentInstance) { + this.openSub$ = this.sidesheetRef.componentInstance.onOpen().subscribe((_) => { + this.isOpening = false; + }); + } } public ngOnDestroy(): void { @@ -65,9 +65,9 @@ export class DataChangesSidesheetComponent implements OnInit { public getCdrList(column: HistoryOperationColumn): ColumnDependentReference[] { return [ - this.buildEntiyColumn('name', this.translate.instant('#LDS#Column name'), column.ColumnDisplay), - this.buildEntiyColumn('old', this.translate.instant('#LDS#Old value'), column.OldValueDisplay), - this.buildEntiyColumn('new', this.translate.instant('#LDS#New value'), column.NewValueDisplay), + this.buildEntiyColumn('name', this.translate.instant('#LDS#Column name'), column.ColumnDisplay ?? ''), + this.buildEntiyColumn('old', this.translate.instant('#LDS#Old value'), column.OldValueDisplay ?? ''), + this.buildEntiyColumn('new', this.translate.instant('#LDS#New value'), column.NewValueDisplay ?? ''), ].map((col) => new BaseReadonlyCdr(col)); } diff --git a/imxweb/projects/qer-app-operationssupport/src/app/data-changes/data-changes.component.html b/imxweb/projects/qer-app-operationssupport/src/app/data-changes/data-changes.component.html index 49e92584d..b4c620767 100644 --- a/imxweb/projects/qer-app-operationssupport/src/app/data-changes/data-changes.component.html +++ b/imxweb/projects/qer-app-operationssupport/src/app/data-changes/data-changes.component.html @@ -1,70 +1,131 @@ -

    {{ '#LDS#Heading Operation History' | translate }}

    +

    {{ '#LDS#Heading Operation History' | translate }}

    - - + + {{ '#LDS#User' | translate }} - + [value]="'ChangeType'" + > {{ '#LDS#Type of operation' | translate }}
    - - {{ '#LDS#User name' | translate }} - - - - - {{ '#LDS#Type of operation' | translate }} - - {{changeType.title}} - - - - - {{ '#LDS#From' | translate }} - - - - - - - {{ '#LDS#To' | translate }} - - - - - - + @if (isEnabledUsername) { + + {{ '#LDS#User name' | translate }} + + + } + @if (isEnabledChangeType) { + + + } + + @if (fromDateControl.getErrors()['matDatepickerMin'] || fromDateControl.getErrors()['matDatepickerMax']) { + {{ '#LDS#Specify a "From" date that lies before the "To" date.' | translate }} + } + + @if (isEnabledChangeType) { + + @if (toDateControl.getErrors()['matDatepickerMin'] || toDateControl.getErrors()['matDatepickerMax']) { + {{ '#LDS#Specify a "To" date that lies after the "From" date.' | translate }} + } + + } +
    - - - - - - - -
    {{ column.title | translate }} - - {{ column.value(row) }} - - - - {{ column.value(row) }} - {{ column.value(row) }} - {{ column.value(row) }} - - -
    - + @if (busyService.isBusy) { + + } @else { + @if (columns && !!dataSource && !!dataSource.data.length) { +
    + + @for (column of columns; track column.name) { + + + + + } + + +
    {{ column.title | translate }} + @switch (column.name) { + @case ('ChangeType') { + @switch (row.ChangeType) { + @case (changeTypeEnum.Insert) { + {{ column.value(row) }} + } + @case (changeTypeEnum.Update) { + {{ column.value(row) }} + } + @case (changeTypeEnum.Delete) { + {{ column.value(row) }} + } + } + } + @default { + {{ column.value(row) }} + } + } +
    +
    + } @else { +
    + +

    {{ '#LDS#No matching data' | translate }}

    +
    + } + } +
    diff --git a/imxweb/projects/qer-app-operationssupport/src/app/data-changes/data-changes.component.scss b/imxweb/projects/qer-app-operationssupport/src/app/data-changes/data-changes.component.scss index 6e8539274..03af9cb1b 100644 --- a/imxweb/projects/qer-app-operationssupport/src/app/data-changes/data-changes.component.scss +++ b/imxweb/projects/qer-app-operationssupport/src/app/data-changes/data-changes.component.scss @@ -1,72 +1,76 @@ @import '@elemental-ui/core/src/styles/_eui_palette.scss'; :host { - display: flex; - flex-direction: column; - overflow: hidden; - flex-grow: 1; + display: flex; + flex-direction: column; + overflow: hidden; + flex-grow: 1; } .search-type { - display: flex; - - >label { - align-self: center - } - - .search-type-radio-group { - display: flex; - margin: 15px 0; - align-items: flex-start; - } + display: flex; - .search-type-radio-button { - margin: 5px; - } + > label { + align-self: center; + } } .search-type-option-controls { - display: flex; - flex-direction: row; + display: flex; + flex-direction: row; + align-items: center; + gap: 8px; + .eui-form-field { + width: auto; + } + .eui-select { + min-width: 250px; + } +} - .mat-form-field { - margin: 5px; - } +eui-date-picker { + .mat-mdc-form-field { + width: 300px; + } +} - button { - align-self: center; - margin: 10px; - } +.hidden { + display: none; } .search-result-table-container { - flex: 1 1 auto; + flex: 1 1 auto; + display: flex; + flex-direction: column; + height: 100%; + overflow: hidden; + .search-result-table { + height: 100%; display: flex; flex-direction: column; overflow: auto; - margin-bottom: -20px; - - tr:hover { - background: $color-gray-5; - } + } + tr:hover { + background: $color-gray-5; + } } .eui-dark-theme { - :host { - .search-result-table-container { - tr:hover { - background: $color-gray-60; - } - } + :host { + .search-result-table-container { + tr:hover { + background: $color-gray-60; + } } + } } .eui-contrast-theme { :host { - .search-result-table-container { - tr:hover { - background: $color-gray-80; - } + .search-result-table-container { + tr:hover { + background: $color-gray-80; } + } } } diff --git a/imxweb/projects/qer-app-operationssupport/src/app/data-changes/data-changes.component.ts b/imxweb/projects/qer-app-operationssupport/src/app/data-changes/data-changes.component.ts index 2d9ed38df..69c39d1a0 100644 --- a/imxweb/projects/qer-app-operationssupport/src/app/data-changes/data-changes.component.ts +++ b/imxweb/projects/qer-app-operationssupport/src/app/data-changes/data-changes.component.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -24,23 +24,29 @@ * */ -import { Component, OnInit, ViewChild } from '@angular/core'; -import { UntypedFormControl, UntypedFormGroup, ValidatorFn, Validators } from '@angular/forms'; +import { ChangeDetectorRef, Component, OnInit, ViewChild } from '@angular/core'; +import { FormGroup, UntypedFormControl, Validators } from '@angular/forms'; import { MatPaginator } from '@angular/material/paginator'; import { MatTableDataSource } from '@angular/material/table'; -import { EuiBadgeComponent, EuiLoadingService, EuiSidesheetService } from '@elemental-ui/core'; +import { + EuiDatePickerComponent, + EuiLoadingService, + EuiSelectFeedbackMessages, + EuiSelectOption, + EuiSidesheetService, +} from '@elemental-ui/core'; import { TranslateService } from '@ngx-translate/core'; -import { OverlayRef } from '@angular/cdk/overlay'; import moment from 'moment'; -import { ChangeType as ChangeTypeEnum, HistoryOperation } from 'imx-api-qbm'; +import { ChangeType as ChangeTypeEnum, HistoryOperation } from '@imx-modules/imx-api-qbm'; +import { BusyService, calculateSidesheetWidth, SettingsService } from 'qbm'; import { DataChangesSidesheetComponent } from './data-changes-sidesheet/data-changes-sidesheet.component'; import { DataChangesService } from './data-changes.service'; export interface Column { name: string; title: string; - value: (row: HistoryOperation) => string; + value: (row: HistoryOperation) => string | undefined; } export interface SearchType { @@ -48,25 +54,6 @@ export interface SearchType { value: string; } -export interface ChangeType { - name: string; - title: string; - value: number; -} - -const searchFormValidator: ValidatorFn = (searchForm: UntypedFormGroup) => { - if (searchForm.get('backToDateFormControl').enabled && searchForm.get('backFromDateFormControl').enabled) { - if (searchForm.get('backToDateFormControl').value && searchForm.get('backFromDateFormControl').value) { - let backToDate: Date = searchForm.get('backToDateFormControl').value; - let backFromDate: Date = searchForm.get('backFromDateFormControl').value; - - if (backToDate >= backFromDate) return { isValid: false }; - } - } - - return null; -}; - @Component({ selector: 'imx-data-changes', templateUrl: './data-changes.component.html', @@ -74,134 +61,144 @@ const searchFormValidator: ValidatorFn = (searchForm: UntypedFormGroup) => { }) export class DataChangesComponent implements OnInit { @ViewChild(MatPaginator) paginator: MatPaginator; + @ViewChild('fromDateControl') fromDateControl: EuiDatePickerComponent; + @ViewChild('toDateControl') toDateControl: EuiDatePickerComponent; - public paginatorConfigurations = { - size: 20, - sizeOptions: [20, 50, 100], - showFirstLastButtons: false, - }; + public paginatorConfigurations: { size: number; sizeOptions: number[]; showFirstLastButtons: boolean }; public dataSource: MatTableDataSource; public columns: Column[]; public displayedColumns: string[]; - - public searchForm = new UntypedFormGroup( - { - usernameFormControl: new UntypedFormControl('', [Validators.required]), - backToDateFormControl: new UntypedFormControl('', [Validators.required]), - backFromDateFormControl: new UntypedFormControl('', [Validators.required]), - changeTypeFormControl: new UntypedFormControl('', [Validators.required]), - }, - { validators: searchFormValidator }, - ); + public feedbackMessages: EuiSelectFeedbackMessages; + + public searchForm = new FormGroup({ + usernameFormControl: new UntypedFormControl('', Validators.required), + changeTypeFormControl: new UntypedFormControl(['']), + fromDateFormControl: new UntypedFormControl('', { updateOn: 'blur', validators: Validators.required }), + toDateFormControl: new UntypedFormControl('', { updateOn: 'blur' }), + }); public selectedSearchType: string; - public changeTypes: ChangeType[]; + public busyService: BusyService; + + public changeTypes: EuiSelectOption[]; public badgeColor = { Insert: 'green', Update: 'orange', Delete: 'red', }; + public today: moment.Moment; + public yesterday: moment.Moment; + public get changeTypeEnum(): typeof ChangeTypeEnum { return ChangeTypeEnum; } public get isEnabledUsername(): boolean { - return this.searchForm.get('usernameFormControl').enabled; + return this.selectedSearchType === 'UserName'; } public get isEnabledChangeType(): boolean { - return this.searchForm.get('changeTypeFormControl').enabled; - } - - public get isEnabledBackTo(): boolean { - return this.searchForm.get('backToDateFormControl').enabled; + return this.selectedSearchType === 'ChangeType'; } - public get isEnabledBackFrom(): boolean { - return this.searchForm.get('backFromDateFormControl').enabled - } - - constructor( private translateService: TranslateService, private euiLoadingService: EuiLoadingService, private sidesheet: EuiSidesheetService, - private dataChangesService: DataChangesService - ) {} + private dataChangesService: DataChangesService, + public readonly settings: SettingsService, + private readonly changeDetector: ChangeDetectorRef, + ) { + this.paginatorConfigurations = { + size: this.settings.DefaultPageSize, + sizeOptions: this.settings.DefaultPageOptions, + showFirstLastButtons: true, + }; + this.today = moment(); + this.yesterday = moment().subtract(1, 'days'); + this.busyService = new BusyService(); + } public async ngOnInit(): Promise { this.selectedSearchType = 'UserName'; - this.changeTypes = this.dataChangesService.changeTypes; + this.changeTypes = this.dataChangesService.loadChangeTypes(); let culture = this.translateService.getBrowserCultureLang(); this.columns = [ { name: 'ChangeTime', title: '#LDS#Operation performed on', - value: (row: HistoryOperation) => row.ChangeTime?.toLocaleString(culture), + value: (row: HistoryOperation) => new Date(row.ChangeTime)?.toLocaleString(culture), + }, + { + name: 'ChangeType', + title: '#LDS#Type of operation', + value: (row: HistoryOperation) => this.dataChangesService.changeTypeString(row.ChangeType), }, - { name: 'ChangeType', title: '#LDS#Type of operation', value: (row: HistoryOperation) => this.dataChangesService.changeTypeString(row.ChangeType) }, { name: 'DisplayType', title: '#LDS#Object type', value: (row: HistoryOperation) => row.DisplayType }, { name: 'ObjectDisplay', title: '#LDS#Object name', value: (row: HistoryOperation) => row.ObjectDisplay }, { name: 'ProcessId', title: '#LDS#Process ID', value: (row: HistoryOperation) => row.ProcessId }, { name: 'User', title: '#LDS#Operation performed by', value: (row: HistoryOperation) => row.User }, ]; this.displayedColumns = this.columns.map((c) => c.name); + this.translateService.onLangChange.subscribe(() => { + this.loadFeedbackMessages(); + this.changeTypes = this.dataChangesService.loadChangeTypes(); + }); + + this.initSearchForm(); this.manageSearchState(); + this.updateUserNameControls(); + this.loadFeedbackMessages(); } public searchTypeChange(): void { this.dataSource = new MatTableDataSource(); this.dataSource.paginator = this.paginator; + // update validators when changing search type, because only visible elements can be mandatory + this.searchForm.controls.usernameFormControl?.setValidators( + this.selectedSearchType.toUpperCase() === 'ChangeType'.toUpperCase() ? null : Validators.required, + ); + this.searchForm.controls.toDateFormControl?.setValidators( + this.selectedSearchType.toUpperCase() === 'ChangeType'.toUpperCase() ? Validators.required : null, + ); + this.searchForm.controls.changeTypeFormControl?.setValidators( + this.selectedSearchType.toUpperCase() === 'UserName'.toUpperCase() ? null : Validators.required, + ); this.manageSearchState(); } public manageSearchState(): void { - this.searchForm.get('usernameFormControl').reset(); - this.searchForm.get('backFromDateFormControl').reset(); - this.searchForm.get('backToDateFormControl').reset(); - this.searchForm.get('changeTypeFormControl').reset(); - - let now = new Date(); - now.setHours(0, 0, 0, 0); - - if (this.selectedSearchType.toUpperCase() === 'UserName'.toUpperCase()) { - this.searchForm.get('usernameFormControl').enable(); - this.searchForm.get('backToDateFormControl').enable(); - this.searchForm.get('backFromDateFormControl').disable(); - this.searchForm.get('changeTypeFormControl').disable(); - - this.searchForm.get('backToDateFormControl').setValue(moment(new Date(now.getTime() - 24 * 60 * 60 * 1000))); // 24 hours back from now - } else if (this.selectedSearchType.toUpperCase() === 'ChangeType'.toUpperCase()) { - this.searchForm.get('usernameFormControl').disable(); - this.searchForm.get('backToDateFormControl').enable(); - this.searchForm.get('backFromDateFormControl').enable(); - this.searchForm.get('changeTypeFormControl').enable(); - - this.searchForm.get('backToDateFormControl').setValue(moment(new Date(now.getTime() - 24 * 60 * 60 * 1000))); - this.searchForm.get('backFromDateFormControl').setValue(moment(now)); + this.searchForm.controls.usernameFormControl.reset(); + this.searchForm.controls.changeTypeFormControl.reset(); + switch (this.selectedSearchType) { + case 'UserName': + this.updateUserNameControls(); + break; + case 'ChangeType': + this.updateChangeTypeControls(); + break; } } public async loadHistoryOperationsData(): Promise { - if (this.selectedSearchType.toUpperCase() === 'UserName'.toUpperCase()) await this.loadHistoryOperationsDataByUserName(); - else if (this.selectedSearchType.toUpperCase() === 'ChangeType'.toUpperCase()) await this.loadHistoryOperationsDataByChangeType(); + if (this.selectedSearchType === 'UserName') await this.loadHistoryOperationsDataByUserName(); + else if (this.selectedSearchType === 'ChangeType') await this.loadHistoryOperationsDataByChangeType(); } public async loadHistoryOperationsDataByUserName(): Promise { - let overlayRef: OverlayRef; - setTimeout(() => (overlayRef = this.euiLoadingService.show())); + const isBusy = this.busyService.beginBusy(); try { this.dataSource = new MatTableDataSource(); this.dataSource.paginator = this.paginator; - if (!this.searchForm.get('usernameFormControl').value) { + if (!this.searchForm.controls.usernameFormControl.value) { return; } const historyOperationsData = await this.dataChangesService.getHistoryOperationsDataByUserName( - this.searchForm.get('usernameFormControl').value, - { backto: this.searchForm.get('backToDateFormControl').value } + this.searchForm.controls.usernameFormControl.value, + { backto: this.searchForm.controls.fromDateFormControl.value }, ); if (historyOperationsData) { @@ -209,29 +206,27 @@ export class DataChangesComponent implements OnInit { this.dataSource.paginator = this.paginator; } } finally { - setTimeout(() => this.euiLoadingService.hide(overlayRef)); + isBusy.endBusy(); } } public async loadHistoryOperationsDataByChangeType(): Promise { - let overlayRef: OverlayRef; - setTimeout(() => (overlayRef = this.euiLoadingService.show())); - + const isBusy = this.busyService.beginBusy(); try { this.dataSource = new MatTableDataSource(); this.dataSource.paginator = this.paginator; if ( - !this.searchForm.get('backFromDateFormControl').value || - !this.searchForm.get('backToDateFormControl').value || - !this.searchForm.get('changeTypeFormControl').value + !this.searchForm.controls.changeTypeFormControl.value || + !this.searchForm.controls.fromDateFormControl.value || + !this.searchForm.controls.toDateFormControl.value ) { return; } await this.loadHistoryDataByChangeType(); } finally { - setTimeout(() => this.euiLoadingService.hide(overlayRef)); + isBusy.endBusy(); } } @@ -239,35 +234,54 @@ export class DataChangesComponent implements OnInit { if (row.Columns && row.Columns.length > 0) { let changeType = this.dataChangesService.changeTypeString(row.ChangeType); let title = this.translateService.instant('#LDS#Heading View Operation Details') + ' (' + changeType + ')'; - let headerColour = this.badgeColor[ChangeTypeEnum[row.ChangeType]]; - - this.sidesheet.open(DataChangesSidesheetComponent, - { - title: title, - subTitle: row.ObjectDisplay, - width: 'max(400px, 40%)', - data: row, - testId: 'data-change-details-sidesheet', - headerColour: headerColour - } - ); + let headerColour = this.badgeColor[ChangeTypeEnum[row.ChangeType]] ?? 'primary'; + + this.sidesheet.open(DataChangesSidesheetComponent, { + title: title, + subTitle: row.ObjectDisplay, + width: calculateSidesheetWidth(700, 0.4), + data: row, + testId: 'data-change-details-sidesheet', + headerColour, + }); } } - private async loadHistoryDataByChangeType(): Promise { - const backFrom = this.searchForm.get('backFromDateFormControl').value.toDate() as Date; + private initSearchForm(): void { + this.searchForm.controls.fromDateFormControl.valueChanges.subscribe((val: moment.Moment) => { + //if a valid date is set, update min and max date for the other picker + if (this.toDateControl && val <= this.searchForm.controls.toDateFormControl.value) { + this.toDateControl.min = val; + this.toDateControl.max = this.today; + } + this.changeDetector.detectChanges(); + }); - backFrom.setHours(23); - backFrom.setMinutes(59); - backFrom.setSeconds(59); + this.searchForm.controls.toDateFormControl.valueChanges.subscribe((val: moment.Moment) => { + //if a valid date is set, update min and max date for the other picker + if (this.fromDateControl && val >= this.searchForm.controls.fromDateFormControl.value) { + this.fromDateControl.max = val; + this.fromDateControl.min = moment(new Date('1970-01-01Z00:00:00:000')); + this.changeDetector.detectChanges(); + } + }); + } - const sum = this.searchForm.get('changeTypeFormControl').value.reduce((aggregate, currentValue) => aggregate + currentValue, 0); + private async loadHistoryDataByChangeType(): Promise { + const backFrom = moment(this.searchForm.controls.toDateFormControl.value) + .set('hours', 23) + .set('minutes', 59) + .set('seconds', 59) + .toDate(); + const backTo = moment(this.searchForm.controls.fromDateFormControl.value).toDate(); + + const sum = this.searchForm.controls.changeTypeFormControl.value.reduce((aggregate, currentValue) => aggregate + currentValue, 0); if (sum === 0) { return; } const historyOperationsData = await this.dataChangesService.getHistoryOperationsDataByChangeType({ - backto: this.searchForm.get('backToDateFormControl').value, + backto: backTo, backfrom: backFrom, types: sum, }); @@ -277,4 +291,39 @@ export class DataChangesComponent implements OnInit { this.dataSource.paginator = this.paginator; } } + + private loadFeedbackMessages(): void { + this.feedbackMessages = { + selected: this.translateService.instant('#LDS#{{value}} selected'), + clear: this.translateService.instant('#LDS#Clear selection'), + search: this.translateService.instant('#LDS#Search'), + plusOther: this.translateService.instant('#LDS#and 1 more'), + plusOtherPlural: this.translateService.instant('#LDS#and {{value}} more'), + unsupportedCharacter: this.translateService.instant('#LDS#You are using unsupported characters.'), + noResults: this.translateService.instant('#LDS#There is no data matching your search.'), + clearAll: this.translateService.instant('#LDS#Clear selection'), + ok: this.translateService.instant('#LDS#OK'), + keyboardOptionsListAria: this.translateService.instant('#LDS#Use the arrow keys to select items.'), + }; + } + + /** + * Updates the form, so it fits the requirements for a search by user name, by initializing the values of the date picker and assuring, that the toDateControl will be valid (because it is not used). + */ + private updateUserNameControls() { + this.searchForm.controls.toDateFormControl.setValue(this.today); + this.searchForm.controls.fromDateFormControl.setValue(this.today); + if (this.toDateControl) { + this.toDateControl.min = this.today; + this.toDateControl.max = this.today; + } + } + + /** + * Updates the form, so it fits the requirements for a search by change type, by initializing the values of the date picker. + */ + private updateChangeTypeControls() { + this.searchForm.controls.toDateFormControl.setValue(this.today); + this.searchForm.controls.fromDateFormControl.setValue(this.yesterday); + } } diff --git a/imxweb/projects/qer-app-operationssupport/src/app/data-changes/data-changes.module.ts b/imxweb/projects/qer-app-operationssupport/src/app/data-changes/data-changes.module.ts index 394086264..1afee0070 100644 --- a/imxweb/projects/qer-app-operationssupport/src/app/data-changes/data-changes.module.ts +++ b/imxweb/projects/qer-app-operationssupport/src/app/data-changes/data-changes.module.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -24,50 +24,33 @@ * */ -import { NgModule } from '@angular/core'; import { CommonModule } from '@angular/common'; -import { DataChangesComponent } from './data-changes.component'; -import { TranslateModule } from '@ngx-translate/core'; +import { NgModule } from '@angular/core'; +import { FormsModule, ReactiveFormsModule } from '@angular/forms'; +import { MatButtonModule } from '@angular/material/button'; +import { MatCardModule } from '@angular/material/card'; +import { MatDatepickerModule } from '@angular/material/datepicker'; +import { MatDividerModule } from '@angular/material/divider'; +import { MatExpansionModule } from '@angular/material/expansion'; +import { MatFormFieldModule } from '@angular/material/form-field'; import { MatIconModule } from '@angular/material/icon'; import { MatInputModule } from '@angular/material/input'; +import { MatListModule } from '@angular/material/list'; +import { MatPaginatorModule } from '@angular/material/paginator'; +import { MatProgressSpinnerModule } from '@angular/material/progress-spinner'; import { MatRadioModule } from '@angular/material/radio'; -import { MatFormFieldModule } from '@angular/material/form-field'; -import { MatButtonModule } from '@angular/material/button'; -import { FormsModule, ReactiveFormsModule } from '@angular/forms'; -import { MatDatepickerModule } from '@angular/material/datepicker'; import { MatSelectModule } from '@angular/material/select'; -import { MatDividerModule } from '@angular/material/divider'; import { MatTableModule } from '@angular/material/table'; -import {MatPaginatorModule} from '@angular/material/paginator'; -import { DataChangesService } from './data-changes.service'; +import { TranslateModule } from '@ngx-translate/core'; import { DataChangesSidesheetComponent } from './data-changes-sidesheet/data-changes-sidesheet.component'; -import {MatListModule} from '@angular/material/list'; -import {MatExpansionModule} from '@angular/material/expansion'; -import {MatCardModule} from '@angular/material/card'; -import { MatProgressSpinnerModule } from '@angular/material/progress-spinner'; +import { DataChangesComponent } from './data-changes.component'; +import { DataChangesService } from './data-changes.service'; -import {MomentDateAdapter} from '@angular/material-moment-adapter'; - import {DateAdapter, MAT_DATE_FORMATS, MAT_DATE_LOCALE} from '@angular/material/core'; -import { CdrModule } from 'qbm'; import { EuiCoreModule } from '@elemental-ui/core'; - -export const EUI_DATE_FORMATS = { - parse: { - dateInput: ['LL', 'L'], - }, - display: { - dateInput: 'LL', - monthYearLabel: 'MMM YYYY', - dateA11yLabel: 'LL', - monthYearA11yLabel: 'MMMM YYYY', - }, -}; +import { BusyIndicatorModule, CdrModule, EuiDateProviders } from 'qbm'; @NgModule({ - declarations: [ - DataChangesComponent, - DataChangesSidesheetComponent - ], + declarations: [DataChangesComponent, DataChangesSidesheetComponent], imports: [ CommonModule, TranslateModule, @@ -88,12 +71,9 @@ export const EUI_DATE_FORMATS = { MatExpansionModule, MatCardModule, MatProgressSpinnerModule, - CdrModule - ], - providers: [ - DataChangesService, - {provide: DateAdapter, useClass: MomentDateAdapter, deps: [MAT_DATE_LOCALE]}, - {provide: MAT_DATE_FORMATS, useValue: EUI_DATE_FORMATS} + BusyIndicatorModule, + CdrModule, ], + providers: [DataChangesService, ...EuiDateProviders], }) -export class DataChangesModule { } +export class DataChangesModule {} diff --git a/imxweb/projects/qer-app-operationssupport/src/app/data-changes/data-changes.service.ts b/imxweb/projects/qer-app-operationssupport/src/app/data-changes/data-changes.service.ts index e9b969eca..ec5ba173f 100644 --- a/imxweb/projects/qer-app-operationssupport/src/app/data-changes/data-changes.service.ts +++ b/imxweb/projects/qer-app-operationssupport/src/app/data-changes/data-changes.service.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -25,29 +25,31 @@ */ import { Injectable } from '@angular/core'; -import { imx_SessionService } from 'qbm'; -import { ChangeType as ChangeTypeEnum, HistoryOperationsData } from 'imx-api-qbm'; +import { EuiSelectOption } from '@elemental-ui/core'; +import { ChangeType as ChangeTypeEnum, HistoryOperationsData } from '@imx-modules/imx-api-qbm'; import { TranslateService } from '@ngx-translate/core'; -import { ChangeType } from './data-changes.component'; +import { imx_SessionService } from 'qbm'; @Injectable() export class DataChangesService { - public changeTypes: ChangeType[] = [ - { name: 'Insert', title: this.translateService.instant('#LDS#Event Insert'), value: 0 }, - { name: 'Update', title: this.translateService.instant('#LDS#Event Update'), value: 1 }, - { name: 'Delete', title: this.translateService.instant('#LDS#Event Delete'), value: 2 }, - ]; + public changeTypes: EuiSelectOption[]; constructor( private session: imx_SessionService, - private translateService: TranslateService - ) {} + private translateService: TranslateService, + ) { + this.changeTypes = this.loadChangeTypes(); + } - public async getHistoryOperationsDataByUserName(username: string,options?: { backto: Date} ): Promise { - return await this.session.Client.opsupport_changeoperations_user_get(username,options); + public async getHistoryOperationsDataByUserName(username: string, options?: { backto: Date }): Promise { + return await this.session.Client.opsupport_changeoperations_user_get(username, options); } - public async getHistoryOperationsDataByChangeType(options?: { backto: Date, backfrom: Date, types: number }): Promise { + public async getHistoryOperationsDataByChangeType(options?: { + backto: Date; + backfrom: Date; + types: number; + }): Promise { return await this.session.Client.opsupport_changeoperations_time_get(options); } @@ -55,16 +57,24 @@ export class DataChangesService { switch (changeType) { case ChangeTypeEnum.Insert: return this.changeTypes.find((obj) => { - return obj.value === 0; - })?.title; + return obj.value === 1; + })?.display; case ChangeTypeEnum.Update: return this.changeTypes.find((obj) => { - return obj.value === 1; - })?.title; + return obj.value === 2; + })?.display; case ChangeTypeEnum.Delete: return this.changeTypes.find((obj) => { - return obj.value === 2; - })?.title; + return obj.value === 4; + })?.display; } } + + public loadChangeTypes(): EuiSelectOption[] { + return [ + { name: 'Insert', display: this.translateService.instant('#LDS#Event Insert'), value: 1 }, + { name: 'Update', display: this.translateService.instant('#LDS#Event Update'), value: 2 }, + { name: 'Delete', display: this.translateService.instant('#LDS#Event Delete'), value: 4 }, + ]; + } } diff --git a/imxweb/projects/qer-app-operationssupport/src/app/db-queue/db-queue.component.html b/imxweb/projects/qer-app-operationssupport/src/app/db-queue/db-queue.component.html index 4ca6df561..8e954d805 100644 --- a/imxweb/projects/qer-app-operationssupport/src/app/db-queue/db-queue.component.html +++ b/imxweb/projects/qer-app-operationssupport/src/app/db-queue/db-queue.component.html @@ -1,6 +1,6 @@ -

    +

    {{ '#LDS#Heading DBQueue' | translate }} -

    +

    [options]="['search']" (navigationStateChanged)="getData($event)" > - - + - - - - - + + + + + + + +
    - - diff --git a/imxweb/projects/qer-app-operationssupport/src/app/db-queue/db-queue.component.scss b/imxweb/projects/qer-app-operationssupport/src/app/db-queue/db-queue.component.scss index da7f03430..171a2ee12 100644 --- a/imxweb/projects/qer-app-operationssupport/src/app/db-queue/db-queue.component.scss +++ b/imxweb/projects/qer-app-operationssupport/src/app/db-queue/db-queue.component.scss @@ -4,20 +4,3 @@ overflow: hidden; flex-grow: 1; } - -.imx-table-container { - flex: 1 1 auto; - display: flex; - flex-direction: column; - overflow: auto; - margin-bottom: -20px; - - > :nth-child(2) { - flex: 1 1 auto; - } -} - -.imx-refresh-button { - margin-right: 5px; - height: 50px; -} \ No newline at end of file diff --git a/imxweb/projects/qer-app-operationssupport/src/app/db-queue/db-queue.component.ts b/imxweb/projects/qer-app-operationssupport/src/app/db-queue/db-queue.component.ts index 842049844..1a95463d5 100644 --- a/imxweb/projects/qer-app-operationssupport/src/app/db-queue/db-queue.component.ts +++ b/imxweb/projects/qer-app-operationssupport/src/app/db-queue/db-queue.component.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -28,7 +28,7 @@ import { OverlayRef } from '@angular/cdk/overlay'; import { Component, OnInit } from '@angular/core'; import { EuiLoadingService } from '@elemental-ui/core'; -import { CollectionLoadParameters, EntitySchema, IClientProperty, DisplayColumns } from 'imx-qbm-dbts'; +import { CollectionLoadParameters, DisplayColumns, EntitySchema, IClientProperty } from '@imx-modules/imx-qbm-dbts'; import { DataSourceToolbarSettings } from 'qbm'; import { DbQueueService } from './db-queue.service'; @@ -38,7 +38,6 @@ import { DbQueueService } from './db-queue.service'; styleUrls: ['./db-queue.component.scss'], }) export class DbQueueComponent implements OnInit { - public dstSettings: DataSourceToolbarSettings; public readonly entitySchema: EntitySchema; public readonly DisplayColumns = DisplayColumns; @@ -46,12 +45,15 @@ export class DbQueueComponent implements OnInit { private navigationState: CollectionLoadParameters; private readonly displayedColumns: IClientProperty[]; - constructor(private readonly dbService: DbQueueService, private readonly busyService: EuiLoadingService) { + constructor( + private readonly dbService: DbQueueService, + private readonly busyService: EuiLoadingService, + ) { this.entitySchema = dbService.DbSchema; this.displayedColumns = [ this.entitySchema.Columns.UID_Task, this.entitySchema.Columns.CountProcessing, - this.entitySchema.Columns.CountWaiting + this.entitySchema.Columns.CountWaiting, ]; } @@ -59,7 +61,6 @@ export class DbQueueComponent implements OnInit { await this.getData({}); } - public onSearch(keywords: string): Promise { return this.getData({ StartIndex: 0, search: keywords }); } @@ -75,9 +76,11 @@ export class DbQueueComponent implements OnInit { dbQueue.Data = dbQueue.Data.filter((row) => { for (const column of this.displayedColumns) { - const cellValue = row.GetEntity().GetColumn(column.ColumnName).GetDisplayValue().toLowerCase(); - if (cellValue.includes(searchKeyword.toLowerCase())) { - return true; + if (column.ColumnName) { + const cellValue = row.GetEntity().GetColumn(column.ColumnName).GetDisplayValue().toLowerCase(); + if (cellValue.includes(searchKeyword.toLowerCase())) { + return true; + } } } return false; diff --git a/imxweb/projects/qer-app-operationssupport/src/app/db-queue/db-queue.module.ts b/imxweb/projects/qer-app-operationssupport/src/app/db-queue/db-queue.module.ts index 96519df96..b3eda06ec 100644 --- a/imxweb/projects/qer-app-operationssupport/src/app/db-queue/db-queue.module.ts +++ b/imxweb/projects/qer-app-operationssupport/src/app/db-queue/db-queue.module.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -32,17 +32,8 @@ import { EuiCoreModule } from '@elemental-ui/core'; import { TranslateModule } from '@ngx-translate/core'; import { MatButtonModule } from '@angular/material/button'; - - @NgModule({ declarations: [DbQueueComponent], - imports: [ - CommonModule, - DataSourceToolbarModule, - DataTableModule, - EuiCoreModule, - TranslateModule, - MatButtonModule - ] + imports: [CommonModule, DataSourceToolbarModule, DataTableModule, EuiCoreModule, TranslateModule, MatButtonModule], }) -export class DbQueueModule { } +export class DbQueueModule {} diff --git a/imxweb/projects/qer-app-operationssupport/src/app/db-queue/db-queue.service.ts b/imxweb/projects/qer-app-operationssupport/src/app/db-queue/db-queue.service.ts index c28da9f9d..90f922ae4 100644 --- a/imxweb/projects/qer-app-operationssupport/src/app/db-queue/db-queue.service.ts +++ b/imxweb/projects/qer-app-operationssupport/src/app/db-queue/db-queue.service.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -25,8 +25,8 @@ */ import { Injectable } from '@angular/core'; -import { OpsupportQueueDbqueue } from 'imx-api-qbm'; -import { CollectionLoadParameters, ExtendedTypedEntityCollection } from 'imx-qbm-dbts'; +import { OpsupportQueueDbqueue } from '@imx-modules/imx-api-qbm'; +import { CollectionLoadParameters, ExtendedTypedEntityCollection } from '@imx-modules/imx-qbm-dbts'; import { imx_SessionService } from 'qbm'; @Injectable({ @@ -35,7 +35,7 @@ import { imx_SessionService } from 'qbm'; export class DbQueueService { constructor(private session: imx_SessionService) {} - public get DbSchema () { + public get DbSchema() { return this.session.TypedClient.OpsupportQueueDbqueue.GetSchema(); } diff --git a/imxweb/projects/qer-app-operationssupport/src/app/guards/outstanding-manager-guard.service.ts b/imxweb/projects/qer-app-operationssupport/src/app/guards/outstanding-manager-guard.service.ts index 92cec76b9..38f03e7ee 100644 --- a/imxweb/projects/qer-app-operationssupport/src/app/guards/outstanding-manager-guard.service.ts +++ b/imxweb/projects/qer-app-operationssupport/src/app/guards/outstanding-manager-guard.service.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -25,7 +25,7 @@ */ import { Injectable, OnDestroy } from '@angular/core'; -import { CanActivate, ActivatedRouteSnapshot, RouterStateSnapshot, Router } from '@angular/router'; +import { Router } from '@angular/router'; import { Observable, Subscription } from 'rxjs'; import { AppConfigService, AuthenticationService, ISessionState } from 'qbm'; @@ -34,14 +34,14 @@ import { PermissionsService } from '../permissions/permissions.service'; @Injectable({ providedIn: 'root', }) -export class OutstandingManagerGuardService implements CanActivate, OnDestroy { +export class OutstandingManagerGuardService implements OnDestroy { private onSessionResponse: Subscription; constructor( private readonly permissionService: PermissionsService, private readonly authentication: AuthenticationService, private readonly appConfig: AppConfigService, - private readonly router: Router + private readonly router: Router, ) {} public canActivate(): Observable { @@ -49,8 +49,8 @@ export class OutstandingManagerGuardService implements CanActivate, OnDestroy { this.onSessionResponse = this.authentication.onSessionResponse.subscribe(async (sessionState: ISessionState) => { if (sessionState.IsLoggedIn) { const userIsOutstandingManager = await this.permissionService.isOutstandingManager(); - if (!userIsOutstandingManager) { - this.router.navigate([this.appConfig.Config.routeConfig.start], { queryParams: {} } ); + if (!userIsOutstandingManager) { + this.router.navigate([this.appConfig.Config?.routeConfig?.start], { queryParams: {} }); } observer.next(userIsOutstandingManager ? true : false); observer.complete(); diff --git a/imxweb/projects/qer-app-operationssupport/src/app/guards/system-status-route-guard.service.ts b/imxweb/projects/qer-app-operationssupport/src/app/guards/system-status-route-guard.service.ts index 21d754d98..ebbd93e9b 100644 --- a/imxweb/projects/qer-app-operationssupport/src/app/guards/system-status-route-guard.service.ts +++ b/imxweb/projects/qer-app-operationssupport/src/app/guards/system-status-route-guard.service.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -25,23 +25,23 @@ */ import { Injectable, OnDestroy } from '@angular/core'; -import { CanActivate, Router } from '@angular/router'; +import { Router } from '@angular/router'; import { AppConfigService, AuthenticationService, ISessionState } from 'qbm'; -import { Observable, Subscription } from 'rxjs'; import { FeatureConfigService } from 'qer'; +import { Observable, Subscription } from 'rxjs'; @Injectable({ - providedIn: 'root' + providedIn: 'root', }) -export class SystemStatusRouteGuardService implements CanActivate, OnDestroy { +export class SystemStatusRouteGuardService implements OnDestroy { private onSessionResponse: Subscription; constructor( private readonly authentication: AuthenticationService, private readonly appConfig: AppConfigService, private readonly router: Router, - private readonly featureService: FeatureConfigService - ) { } + private readonly featureService: FeatureConfigService, + ) {} public canActivate(): Observable { return new Observable((observer) => { @@ -49,7 +49,7 @@ export class SystemStatusRouteGuardService implements CanActivate, OnDestroy { if (sessionState.IsLoggedIn) { const conf = await this.featureService.getFeatureConfig(); if (!conf.EnableSystemStatus) { - this.router.navigate([this.appConfig.Config.routeConfig.start], { queryParams: {} }); + this.router.navigate([this.appConfig.Config?.routeConfig?.start], { queryParams: {} }); } observer.next(conf.EnableSystemStatus); observer.complete(); @@ -64,4 +64,3 @@ export class SystemStatusRouteGuardService implements CanActivate, OnDestroy { } } } - diff --git a/imxweb/projects/qer-app-operationssupport/src/app/hyperview/ops-hyperview.service.ts b/imxweb/projects/qer-app-operationssupport/src/app/hyperview/ops-hyperview.service.ts index c3ea3ba66..53aba9656 100644 --- a/imxweb/projects/qer-app-operationssupport/src/app/hyperview/ops-hyperview.service.ts +++ b/imxweb/projects/qer-app-operationssupport/src/app/hyperview/ops-hyperview.service.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -26,22 +26,20 @@ import { Injectable } from '@angular/core'; -import { ShapeData } from 'imx-api-qbm'; +import { ShapeData } from '@imx-modules/imx-api-qbm'; import { imx_SessionService } from 'qbm'; import { ObjectHyperviewService } from 'qer'; @Injectable({ - providedIn: 'root' + providedIn: 'root', }) export class OpsHyperviewService implements ObjectHyperviewService { - constructor(private session: imx_SessionService) { } + constructor(private session: imx_SessionService) {} public async get(tableName: string, uid: string, nodeName?: string): Promise { return this.session.Client.opsupport_hyperview_get(tableName, uid, { node: nodeName }); } - public getNavigationPermission(): Promise { return new Promise((resolve) => resolve(false)); } } - diff --git a/imxweb/projects/qer-app-operationssupport/src/app/information/issue-tiles.scss b/imxweb/projects/qer-app-operationssupport/src/app/information/issue-tiles.scss index 3b802fbf4..5fc6f3c52 100644 --- a/imxweb/projects/qer-app-operationssupport/src/app/information/issue-tiles.scss +++ b/imxweb/projects/qer-app-operationssupport/src/app/information/issue-tiles.scss @@ -1,4 +1,4 @@ -@import "@elemental-ui/core/src/styles/_palette.scss"; +@import '@elemental-ui/core/src/styles/_palette.scss'; .issueIconLine { position: relative; @@ -66,7 +66,7 @@ } .warningBubble { - background-color: $corbin-orange + background-color: $corbin-orange; } .errorBubble { diff --git a/imxweb/projects/qer-app-operationssupport/src/app/information/notifications/notification-issue-item.ts b/imxweb/projects/qer-app-operationssupport/src/app/information/notifications/notification-issue-item.ts index 043b136c3..d3be3b40a 100644 --- a/imxweb/projects/qer-app-operationssupport/src/app/information/notifications/notification-issue-item.ts +++ b/imxweb/projects/qer-app-operationssupport/src/app/information/notifications/notification-issue-item.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -30,7 +30,7 @@ export enum NotificationIssueType { Undefined, FrozenJobsToday, FrozenJobsSinceYesterday, - SystemJournalSinceYesterday + SystemJournalSinceYesterday, } export class NotificationIssueItem implements IssueItem { diff --git a/imxweb/projects/qer-app-operationssupport/src/app/information/notifications/notifications.component.html b/imxweb/projects/qer-app-operationssupport/src/app/information/notifications/notifications.component.html index 2ac3e07e9..7cce2db77 100644 --- a/imxweb/projects/qer-app-operationssupport/src/app/information/notifications/notifications.component.html +++ b/imxweb/projects/qer-app-operationssupport/src/app/information/notifications/notifications.component.html @@ -1,10 +1,10 @@
    -

    {{'#LDS#Notifications' | translate}} - +

    + {{ '#LDS#Notifications' | translate }} +

    - +
    @@ -12,14 +12,14 @@

    {{'#LDS#Notifications' | translate}}
    - + {{ item.title }} {{ item.text }} - +

    -
    \ No newline at end of file +
    diff --git a/imxweb/projects/qer-app-operationssupport/src/app/information/notifications/notifications.component.scss b/imxweb/projects/qer-app-operationssupport/src/app/information/notifications/notifications.component.scss index 04336951d..758332d8e 100644 --- a/imxweb/projects/qer-app-operationssupport/src/app/information/notifications/notifications.component.scss +++ b/imxweb/projects/qer-app-operationssupport/src/app/information/notifications/notifications.component.scss @@ -1,4 +1,4 @@ -@import "@elemental-ui/core/src/styles/_palette.scss"; +@import '@elemental-ui/core/src/styles/_palette.scss'; @import '@elemental-ui/core/src/styles/_eui_palette.scss'; .startSubTitle { @@ -40,23 +40,12 @@ imx-iconstack { line-height: 3em; } -.mat-button { - height: 100%; - color: $iris-blue; - font-weight: 600; -} - -.imx-spinner{ - display: inline-block; -} - - .imx-notification-container { display: flex; flex-wrap: wrap; margin-bottom: -10px; - >.imx-notification-card{ + > .imx-notification-card { margin-right: 10px; margin-bottom: 10px; } @@ -69,7 +58,6 @@ imx-iconstack { eui-icon { margin: 12px 15px; - color: $corbin-orange; } > * { @@ -110,12 +98,12 @@ imx-iconstack { } .eui-dark-theme { - :host{ - .notificationContentPane{ - .notificationTitle{ + :host { + .notificationContentPane { + .notificationTitle { color: $color-gray-5; } - .notificationContent{ + .notificationContent { color: $color-gray-5; } } @@ -123,12 +111,12 @@ imx-iconstack { } .eui-contrast-theme { - :host{ - .notificationContentPane{ - .notificationTitle{ + :host { + .notificationContentPane { + .notificationTitle { color: $color-gray-0; } - .notificationContent{ + .notificationContent { color: $color-gray-0; } } diff --git a/imxweb/projects/qer-app-operationssupport/src/app/information/notifications/notifications.component.ts b/imxweb/projects/qer-app-operationssupport/src/app/information/notifications/notifications.component.ts index 4d3ae5812..4171ee948 100644 --- a/imxweb/projects/qer-app-operationssupport/src/app/information/notifications/notifications.component.ts +++ b/imxweb/projects/qer-app-operationssupport/src/app/information/notifications/notifications.component.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -34,7 +34,7 @@ import { IssueItem } from '../service-issues/service-issues.models'; @Component({ selector: 'imx-notifications', templateUrl: './notifications.component.html', - styleUrls: ['./notifications.component.scss', '../issue-tiles.scss'] + styleUrls: ['./notifications.component.scss', '../issue-tiles.scss'], }) export class NotificationsComponent implements OnInit, OnDestroy { public get Notifications(): IssueItem[] { @@ -47,7 +47,8 @@ export class NotificationsComponent implements OnInit, OnDestroy { constructor( private domSanitizer: DomSanitizer, public notifications: NotificationsService, - private appConfigService: AppConfigService) { } + private appConfigService: AppConfigService, + ) {} public ngOnInit(): void { this.notifications.subscribe(this.appConfigService.Config.NotificationUpdateInterval); diff --git a/imxweb/projects/qer-app-operationssupport/src/app/information/notifications/notifications.module.ts b/imxweb/projects/qer-app-operationssupport/src/app/information/notifications/notifications.module.ts index d342997c4..0f311ea55 100644 --- a/imxweb/projects/qer-app-operationssupport/src/app/information/notifications/notifications.module.ts +++ b/imxweb/projects/qer-app-operationssupport/src/app/information/notifications/notifications.module.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -46,9 +46,9 @@ import { MatProgressSpinnerModule } from '@angular/material/progress-spinner'; QbmModule, LdsReplaceModule, EuiCoreModule, - TranslateModule + TranslateModule, ], providers: [NotificationsService], - exports: [NotificationsComponent] + exports: [NotificationsComponent], }) -export class NotificationsModule { } +export class NotificationsModule {} diff --git a/imxweb/projects/qer-app-operationssupport/src/app/information/notifications/notifications.service.spec.ts b/imxweb/projects/qer-app-operationssupport/src/app/information/notifications/notifications.service.spec.ts index 84790605c..f9351d70d 100644 --- a/imxweb/projects/qer-app-operationssupport/src/app/information/notifications/notifications.service.spec.ts +++ b/imxweb/projects/qer-app-operationssupport/src/app/information/notifications/notifications.service.spec.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -29,9 +29,10 @@ import { Router } from '@angular/router'; import { of } from 'rxjs'; import { NotificationsService } from './notifications.service'; -import { TypedEntityCollectionData } from 'imx-qbm-dbts'; +import { TypedEntityCollectionData } from '@imx-modules/imx-qbm-dbts'; import { NotificationIssueType } from './notification-issue-item'; import { imx_SessionService, ImxTranslationProviderService } from 'qbm'; +import { TranslateService } from '@ngx-translate/core'; interface JournalStatCounter { Errors?: number; @@ -63,15 +64,18 @@ interface SpyMethod { } function CreateSpyObj(name: string, methods: SpyMethod[]): any { - const spyobj = jasmine.createSpyObj(name, methods.map(method => method.name)); - methods.forEach(method => spyobj[method.name].and.callFake(() => Promise.resolve(method.getValue()))); + const spyobj = jasmine.createSpyObj( + name, + methods.map((method) => method.name), + ); + methods.forEach((method) => spyobj[method.name].and.callFake(() => Promise.resolve(method.getValue()))); return spyobj; } describe('NotificationsService', () => { function prepareTestBed(testCase: TestCase = { TestInput: [{}] }) { - const frozenjobs = generator(testCase.TestInput.map(item => item.Frozenjobs)); - const journalStat = generator(testCase.TestInput.map(item => item.JournalStat)); + const frozenjobs = generator(testCase.TestInput.map((item) => item.Frozenjobs)); + const journalStat = generator(testCase.TestInput.map((item) => item.JournalStat)); TestBed.configureTestingModule({ providers: [ NotificationsService, @@ -81,26 +85,32 @@ describe('NotificationsService', () => { Client = CreateSpyObj('Client', [ { name: 'opsupport_journal_stat_get', - getValue: () => journalStat.next().value - } + getValue: () => journalStat.next().value, + }, ]); TypedClient = { OpsupportQueueFrozenjobs: CreateSpyObj('OpsupportQueueFrozenjobs', [ { name: 'Get', - getValue: () => frozenjobs.next().value - } - ]) + getValue: () => frozenjobs.next().value, + }, + ]), }; - } + }, }, { provide: Router, useClass: class { navigate = jasmine.createSpy('navigate'); - } - } - ] + }, + }, + { + provide: TranslateService, + useValue: { + get: jasmine.createSpy('get').and.callFake(() => of('')), + }, + }, + ], }); } @@ -114,29 +124,29 @@ describe('NotificationsService', () => { { Description: 'with a non-empty frozenjobs collection and without errors/warnings in the journal', TestInput: [{ Frozenjobs: { totalCount: 1 } }], - ExpectedNotificationItems: [NotificationIssueType.FrozenJobsSinceYesterday] + ExpectedNotificationItems: [NotificationIssueType.FrozenJobsSinceYesterday], } as TestCase, { Description: 'with an empty frozenjobs collection and without errors/warnings in the journal', TestInput: [{}], - ExpectedNotificationItems: [] + ExpectedNotificationItems: [], } as TestCase, { Description: 'with a non-empty frozenjobs collection and with errors/warnings in the journal', TestInput: [{ Frozenjobs: { totalCount: 1 }, JournalStat: { Errors: 1, Warnings: 0 } }], - ExpectedNotificationItems: [NotificationIssueType.FrozenJobsSinceYesterday, NotificationIssueType.SystemJournalSinceYesterday] + ExpectedNotificationItems: [NotificationIssueType.FrozenJobsSinceYesterday, NotificationIssueType.SystemJournalSinceYesterday], } as TestCase, { Description: 'with an empty frozenjobs collection and with errors in the journal', TestInput: [{ JournalStat: { Errors: 1, Warnings: 0 } }], - ExpectedNotificationItems: [NotificationIssueType.SystemJournalSinceYesterday] + ExpectedNotificationItems: [NotificationIssueType.SystemJournalSinceYesterday], } as TestCase, { Description: 'with an empty frozenjobs collection and with warnings in the journal', TestInput: [{ JournalStat: { Errors: 0, Warnings: 1 } }], - ExpectedNotificationItems: [NotificationIssueType.SystemJournalSinceYesterday] - } as TestCase - ].forEach(testcase => { + ExpectedNotificationItems: [NotificationIssueType.SystemJournalSinceYesterday], + } as TestCase, + ].forEach((testcase) => { describe('should update all items', () => { beforeEach(() => prepareTestBed(testcase)); @@ -145,14 +155,14 @@ describe('NotificationsService', () => { inject( [NotificationsService], fakeAsync((service: NotificationsService) => { - service.updateItems().then(_ => { - expect(service.items.map(item => item.type)).toEqual(testcase.ExpectedNotificationItems); + service.updateItems().then((_) => { + expect(service.items.map((item) => item.type)).toEqual(testcase.ExpectedNotificationItems); }); tick(); discardPeriodicTasks(); - }) - ) + }), + ), ); }); }); @@ -161,19 +171,19 @@ describe('NotificationsService', () => { { Description: 'with a non-empty frozenjobs collection - then empty', TestInput: [{ Frozenjobs: { totalCount: 1 } }, {}], - ExpectedNotificationItems: [] + ExpectedNotificationItems: [], } as TestCase, { Description: 'with errors/warnings in the journal - then empty', TestInput: [{ JournalStat: { Errors: 1, Warnings: 0 } }, {}], - ExpectedNotificationItems: [] + ExpectedNotificationItems: [], } as TestCase, { Description: 'with a non-empty frozenjobs collection and with errors/warnings in the journal - then no emtpy frozenjobs collection', TestInput: [{ Frozenjobs: { totalCount: 1 }, JournalStat: { Errors: 1, Warnings: 0 } }, { JournalStat: { Errors: 1, Warnings: 0 } }], - ExpectedNotificationItems: [NotificationIssueType.SystemJournalSinceYesterday] - } as TestCase - ].forEach(testcase => { + ExpectedNotificationItems: [NotificationIssueType.SystemJournalSinceYesterday], + } as TestCase, + ].forEach((testcase) => { describe('should remove items', () => { beforeEach(() => prepareTestBed(testcase)); @@ -182,17 +192,17 @@ describe('NotificationsService', () => { inject( [NotificationsService], fakeAsync((service: NotificationsService) => { - service.updateItems().then(_ => { + service.updateItems().then((_) => { expect(service.items.length).toBeGreaterThan(0); - service.updateItems().then(_0 => { - expect(service.items.map(item => item.type)).toEqual(testcase.ExpectedNotificationItems); + service.updateItems().then((_0) => { + expect(service.items.map((item) => item.type)).toEqual(testcase.ExpectedNotificationItems); }); }); tick(); discardPeriodicTasks(); - }) - ) + }), + ), ); }); }); diff --git a/imxweb/projects/qer-app-operationssupport/src/app/information/notifications/notifications.service.ts b/imxweb/projects/qer-app-operationssupport/src/app/information/notifications/notifications.service.ts index 017ba90ee..5d2da188f 100644 --- a/imxweb/projects/qer-app-operationssupport/src/app/information/notifications/notifications.service.ts +++ b/imxweb/projects/qer-app-operationssupport/src/app/information/notifications/notifications.service.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -26,12 +26,11 @@ import { Injectable } from '@angular/core'; import { Router } from '@angular/router'; -import { FilterType, CompareOperator } from 'imx-qbm-dbts'; +import { TranslateService } from '@ngx-translate/core'; +import { LdsReplacePipe, TextContainer, imx_SessionService } from 'qbm'; import { SubscriptionService } from '../../base/subscription.service'; -import { NotificationIssueItem, NotificationIssueType } from './notification-issue-item'; import { IssueAction } from '../service-issues/service-issues.models'; -import { imx_SessionService, TextContainer, LdsReplacePipe } from 'qbm'; -import { TranslateService } from '@ngx-translate/core'; +import { NotificationIssueItem, NotificationIssueType } from './notification-issue-item'; @Injectable() export class NotificationsService extends SubscriptionService { @@ -40,7 +39,7 @@ export class NotificationsService extends SubscriptionService this.router.navigate(['/Jobs'], { queryParams: { failed: true } }), - } + }, ); } else { this.remove(type); @@ -90,7 +89,7 @@ export class NotificationsService extends SubscriptionService this.router.navigate(['/journal']), - } + }, ); } else { this.remove(type); @@ -102,9 +101,9 @@ export class NotificationsService extends SubscriptionService { - let issueItem: NotificationIssueItem = this.itemsInternal.find((item) => item.type === notificationType); + let issueItem = this.itemsInternal.find((item) => item.type === notificationType); if (issueItem == null) { issueItem = new NotificationIssueItem(); @@ -115,14 +114,18 @@ export class NotificationsService extends SubscriptionService 0 ? text.parameters[0] : '', - text.parameters?.length > 1 ? text.parameters[1] : '' - ); + if (text.parameters) { + issueItem.text = this.ldsreplace.transform( + tranlatedKey, + text.parameters.length > 0 ? text.parameters[0] : '', + text.parameters.length > 1 ? text.parameters[1] : '', + ); + } } private remove(type: NotificationIssueType): void { diff --git a/imxweb/projects/qer-app-operationssupport/src/app/information/service-issues/service-issue-item.ts b/imxweb/projects/qer-app-operationssupport/src/app/information/service-issues/service-issue-item.ts index 95ee004cd..3f044bb05 100644 --- a/imxweb/projects/qer-app-operationssupport/src/app/information/service-issues/service-issue-item.ts +++ b/imxweb/projects/qer-app-operationssupport/src/app/information/service-issues/service-issue-item.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -24,8 +24,7 @@ * */ -import { IssueItem, IssueAction } from './service-issues.models'; - +import { IssueAction, IssueItem } from './service-issues.models'; export enum ServiceIssueType { Undefined, @@ -36,7 +35,8 @@ export enum ServiceIssueType { FrozenJobs, InactiveServers, UnresolvedRefs, - SyncIssues + SyncIssues, + SystemThresholdExceeded, } export class ServiceIssueItem implements IssueItem { @@ -52,4 +52,3 @@ export class ServiceIssueItem implements IssueItem { this.type = ServiceIssueType.Undefined; } } - diff --git a/imxweb/projects/qer-app-operationssupport/src/app/information/service-issues/service-issue.component.html b/imxweb/projects/qer-app-operationssupport/src/app/information/service-issues/service-issue.component.html index 315a243fa..fc72b1f7d 100644 --- a/imxweb/projects/qer-app-operationssupport/src/app/information/service-issues/service-issue.component.html +++ b/imxweb/projects/qer-app-operationssupport/src/app/information/service-issues/service-issue.component.html @@ -3,18 +3,17 @@
    - - +
    {{ issueItem.title }}
    {{ issueItem.text }}
    -
    - \ No newline at end of file + diff --git a/imxweb/projects/qer-app-operationssupport/src/app/information/service-issues/service-issue.component.scss b/imxweb/projects/qer-app-operationssupport/src/app/information/service-issues/service-issue.component.scss index 37817e234..acf5164f2 100644 --- a/imxweb/projects/qer-app-operationssupport/src/app/information/service-issues/service-issue.component.scss +++ b/imxweb/projects/qer-app-operationssupport/src/app/information/service-issues/service-issue.component.scss @@ -1,4 +1,4 @@ -@import "@elemental-ui/core/src/styles/_palette.scss"; +@import '@elemental-ui/core/src/styles/_palette.scss'; @import '@elemental-ui/core/src/styles/_eui_palette.scss'; mat-card { @@ -40,9 +40,9 @@ mat-card { .issueIconLine { position: relative; width: 88px; - height:156px; + height: 156px; font-size: 72px; - line-height:156px; + line-height: 156px; float: left; background-color: $asher-gray; color: $black-3; @@ -64,8 +64,7 @@ mat-card { color: $color-gray-5; } - eui-icon - { + eui-icon { color: $color-gray-2; background-color: $color-gray-60; } @@ -82,8 +81,7 @@ mat-card { color: $color-gray-0; } - eui-icon - { + eui-icon { color: $color-gray-0; background-color: $color-gray-80; } diff --git a/imxweb/projects/qer-app-operationssupport/src/app/information/service-issues/service-issue.component.ts b/imxweb/projects/qer-app-operationssupport/src/app/information/service-issues/service-issue.component.ts index ac5cb881b..95ce42691 100644 --- a/imxweb/projects/qer-app-operationssupport/src/app/information/service-issues/service-issue.component.ts +++ b/imxweb/projects/qer-app-operationssupport/src/app/information/service-issues/service-issue.component.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -30,7 +30,7 @@ import { IssueItem } from './service-issues.models'; @Component({ selector: 'imx-service-issue', templateUrl: './service-issue.component.html', - styleUrls: ['./service-issue.component.scss', '../system-status/system-status.component.scss', '../issue-tiles.scss'] + styleUrls: ['./service-issue.component.scss', '../system-status/system-status.component.scss', '../issue-tiles.scss'], }) export class ServiceIssueComponent { @Input() public issueItem: IssueItem; diff --git a/imxweb/projects/qer-app-operationssupport/src/app/information/service-issues/service-issues.component.html b/imxweb/projects/qer-app-operationssupport/src/app/information/service-issues/service-issues.component.html index 929574769..8a846c2d3 100644 --- a/imxweb/projects/qer-app-operationssupport/src/app/information/service-issues/service-issues.component.html +++ b/imxweb/projects/qer-app-operationssupport/src/app/information/service-issues/service-issues.component.html @@ -1,12 +1,16 @@

    {{'#LDS#Service issues' | translate}} - +

    -
    - +
    +
    -
    +
    -
    \ No newline at end of file +
    diff --git a/imxweb/projects/qer-app-operationssupport/src/app/information/service-issues/service-issues.component.scss b/imxweb/projects/qer-app-operationssupport/src/app/information/service-issues/service-issues.component.scss index bed5e362f..130916110 100644 --- a/imxweb/projects/qer-app-operationssupport/src/app/information/service-issues/service-issues.component.scss +++ b/imxweb/projects/qer-app-operationssupport/src/app/information/service-issues/service-issues.component.scss @@ -1,4 +1,4 @@ -@import "@elemental-ui/core/src/styles/_palette.scss"; +@import '@elemental-ui/core/src/styles/_palette.scss'; :host { max-width: 1200px; } @@ -32,13 +32,3 @@ .no-issue-detected { max-width: 350px; } - -.imx-spinner{ - display: inline-block; -} - -.mat-button { - color: $iris-blue; - font-weight: 600; -} - diff --git a/imxweb/projects/qer-app-operationssupport/src/app/information/service-issues/service-issues.component.ts b/imxweb/projects/qer-app-operationssupport/src/app/information/service-issues/service-issues.component.ts index b49fbbba9..d6211cbae 100644 --- a/imxweb/projects/qer-app-operationssupport/src/app/information/service-issues/service-issues.component.ts +++ b/imxweb/projects/qer-app-operationssupport/src/app/information/service-issues/service-issues.component.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -33,11 +33,13 @@ import { IssueItem } from './service-issues.models'; @Component({ selector: 'imx-service-issues', templateUrl: './service-issues.component.html', - styleUrls: ['./service-issues.component.scss', '../issue-tiles.scss'] + styleUrls: ['./service-issues.component.scss', '../issue-tiles.scss'], }) export class ServiceIssuesComponent implements OnInit, OnDestroy { - - constructor( public service: ServiceIssuesService, private appConfigService: AppConfigService) {} + constructor( + public service: ServiceIssuesService, + private appConfigService: AppConfigService, + ) {} public ngOnInit(): void { this.service.subscribe(this.appConfigService.Config.NotificationUpdateInterval); diff --git a/imxweb/projects/qer-app-operationssupport/src/app/information/service-issues/service-issues.models.ts b/imxweb/projects/qer-app-operationssupport/src/app/information/service-issues/service-issues.models.ts index c9fe6a958..dd423f3fe 100644 --- a/imxweb/projects/qer-app-operationssupport/src/app/information/service-issues/service-issues.models.ts +++ b/imxweb/projects/qer-app-operationssupport/src/app/information/service-issues/service-issues.models.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR diff --git a/imxweb/projects/qer-app-operationssupport/src/app/information/service-issues/service-issues.module.ts b/imxweb/projects/qer-app-operationssupport/src/app/information/service-issues/service-issues.module.ts index 52a817bc3..8891ca354 100644 --- a/imxweb/projects/qer-app-operationssupport/src/app/information/service-issues/service-issues.module.ts +++ b/imxweb/projects/qer-app-operationssupport/src/app/information/service-issues/service-issues.module.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -24,21 +24,20 @@ * */ -import { NgModule } from '@angular/core'; import { CommonModule } from '@angular/common'; -import { EuiCoreModule } from '@elemental-ui/core'; +import { NgModule } from '@angular/core'; import { MatButtonModule } from '@angular/material/button'; import { MatCardModule } from '@angular/material/card'; import { MatGridListModule } from '@angular/material/grid-list'; +import { EuiCoreModule } from '@elemental-ui/core'; import { TranslateModule } from '@ngx-translate/core'; +import { MatProgressSpinnerModule } from '@angular/material/progress-spinner'; import { QbmModule } from 'qbm'; +import { SystemOverviewModule } from '../system-overview/system-overview.module'; import { ServiceIssueComponent } from './service-issue.component'; import { ServiceIssuesComponent } from './service-issues.component'; import { ServiceIssuesService } from './service-issues.service'; -import { MatProgressSpinnerModule } from '@angular/material/progress-spinner'; - - @NgModule({ declarations: [ServiceIssueComponent, ServiceIssuesComponent], @@ -50,9 +49,10 @@ import { MatProgressSpinnerModule } from '@angular/material/progress-spinner'; MatProgressSpinnerModule, QbmModule, EuiCoreModule, - TranslateModule + TranslateModule, + SystemOverviewModule, ], providers: [ServiceIssuesService], - exports: [ServiceIssuesComponent] + exports: [ServiceIssuesComponent], }) -export class ServiceIssuesModule { } +export class ServiceIssuesModule {} diff --git a/imxweb/projects/qer-app-operationssupport/src/app/information/service-issues/service-issues.service.spec.ts b/imxweb/projects/qer-app-operationssupport/src/app/information/service-issues/service-issues.service.spec.ts index e685fe6d1..0365e16c6 100644 --- a/imxweb/projects/qer-app-operationssupport/src/app/information/service-issues/service-issues.service.spec.ts +++ b/imxweb/projects/qer-app-operationssupport/src/app/information/service-issues/service-issues.service.spec.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -28,15 +28,19 @@ import { TestBed, inject } from '@angular/core/testing'; import { Router } from '@angular/router'; import { of } from 'rxjs'; -import { OpsupportSyncJournal, OpsupportSyncShell } from 'imx-api-dpr'; -import { TypedEntityCollectionData } from 'imx-qbm-dbts'; +import { OpsupportSyncJournal, OpsupportSyncShell } from '@imx-modules/imx-api-dpr'; +import { OpsupportSystemoverview } from '@imx-modules/imx-api-qbm'; +import { TypedEntityCollectionData } from '@imx-modules/imx-qbm-dbts'; +import { TranslateService } from '@ngx-translate/core'; import { AppConfigService, ImxTranslationProviderService, imx_SessionService } from 'qbm'; -import { ServiceIssueType, ServiceIssueItem } from './service-issue-item'; -import { ServiceIssuesService } from './service-issues.service'; -import { SystemStatusService } from '../system-status/system-status.service'; -import { UnresolvedRefsService } from '../../unresolved-refs/unresolved-refs.service'; import { SyncService } from '../../sync/sync.service'; +import { UnresolvedRefsService } from '../../unresolved-refs/unresolved-refs.service'; +import { SystemOverviewService } from '../system-overview/system-overview.service'; +import { SystemTreeDatabase } from '../system-overview/system-tree/system-tree-database'; import { SystemStatusInformation } from '../system-status/system-status-information.interface'; +import { SystemStatusService } from '../system-status/system-status.service'; +import { ServiceIssueItem } from './service-issue-item'; +import { ServiceIssuesService } from './service-issues.service'; interface TestInput { SystemStatus?: SystemStatusInformation[]; @@ -66,8 +70,11 @@ interface SpyMethod { } function CreateSpyObj(name: string, methods: SpyMethod[]): any { - const spyobj = jasmine.createSpyObj(name, methods.map(method => method.name)); - methods.forEach(method => spyobj[method.name].and.callFake(() => Promise.resolve(method.callContainer.ReturnValue))); + const spyobj = jasmine.createSpyObj( + name, + methods.map((method) => method.name), + ); + methods.forEach((method) => spyobj[method.name].and.callFake(() => Promise.resolve(method.callContainer.ReturnValue))); return spyobj; } @@ -84,62 +91,81 @@ function prepareTestBed(testinput: TestInput = {}) { useClass: class { Config = { NotificationUpdateInterval: 9999, - DatastoreIssueTreshold: testinput.SyncDatastoreIssueThreshold + DatastoreIssueTreshold: testinput.SyncDatastoreIssueThreshold, }; - } + }, }, { provide: ImxTranslationProviderService, useClass: class { multilanguageTranslationDict: {}; Translate = jasmine.createSpy('Translate').and.returnValue(of('')); - } + }, }, { provide: Router, useClass: class { navigate = jasmine.createSpy('navigate'); - } + }, }, { provide: imx_SessionService, useClass: class { TypedClient = { OpsupportQueueFrozenjobsbyqueue: CreateSpyObj('OpsupportQueueFrozenjobsbyqueue', [ - { name: 'Get', callContainer: new CallContainer(testinput.Frozenjobsbyqueue) } + { name: 'Get', callContainer: new CallContainer(testinput.Frozenjobsbyqueue) }, ]), OpsupportJobservers: CreateSpyObj('OpsupportJobservers', [ - { name: 'Get', callContainer: new CallContainer(testinput.InactiveJobServers) } - ]) - } - } + { name: 'Get', callContainer: new CallContainer(testinput.InactiveJobServers) }, + ]), + }; + }, }, { provide: SystemStatusService, useClass: class { get = jasmine.createSpy('get').and.callFake(() => Promise.resolve(systemStatusGetResult.ReturnValue)); set = jasmine.createSpy('set').and.returnValue(Promise.resolve({})); - } + }, }, { provide: UnresolvedRefsService, useClass: class { get = jasmine.createSpy('get').and.callFake(() => Promise.resolve(syncDatastoreGetResult.ReturnValue)); - } + }, }, { provide: SyncService, useValue: { getSyncShell: jasmine.createSpy('getSyncShell').and.returnValue(Promise.resolve({ Data: [], TotalCount: 0 })), - getSyncJournal:jasmine.createSpy('getSyncJournal').and.callFake(() => Promise.resolve(syncJournalGetResult.ReturnValue)), + getSyncJournal: jasmine.createSpy('getSyncJournal').and.callFake(() => Promise.resolve(syncJournalGetResult.ReturnValue)), syncShellSchema: OpsupportSyncShell.GetEntitySchema(), syncJournalSchema: OpsupportSyncJournal.GetEntitySchema(), - GetDisplayName: jasmine.createSpy('GetDisplayName').and.returnValue(Promise.resolve('theDisplay')) - } - } - ] + GetDisplayName: jasmine.createSpy('GetDisplayName').and.returnValue(Promise.resolve('theDisplay')), + }, + }, + { + provide: SystemOverviewService, + useValue: { + ItemsProvider: jasmine + .createSpy('ItemsProvider') + .and.returnValue(Promise.resolve({} as Promise>)), + }, + }, + { + provide: SystemTreeDatabase, + useValue: { + initialize: jasmine.createSpy('initialize').and.callFake(() => Promise.resolve([])), + }, + }, + { + provide: TranslateService, + useValue: { + get: jasmine.createSpy('get').and.callFake(() => of('')), + }, + }, + ], }); - } describe('ImxServerIssuesService init', () => { @@ -160,163 +186,162 @@ interface TestCase { Input: TestInput; Test: (items: ServiceIssueItem[]) => boolean; } +// TODO: 460775 fix tests +// for (const testcase of [ +// { +// Description: 'dbqueue is stopped - creates', +// Input: { SystemStatus: [{ IsDbSchedulerDisabled: true }] }, +// Test: (items) => items.filter((item) => item.type === ServiceIssueType.DbSchedulerDisabled).length === 1, +// } as TestCase, +// { +// Description: 'jobqueue is stopped - creates', +// Input: { SystemStatus: [{ IsJobServiceDisabled: true }] }, +// Test: (items) => items.filter((item) => item.type === ServiceIssueType.JobServiceDisabled).length === 1, +// } as TestCase, +// { +// Description: 'compilation is required - creates', +// Input: { SystemStatus: [{ IsCompilationRequired: true }] }, +// Test: (items) => items.filter((item) => item.type === ServiceIssueType.CompilationRequired).length === 1, +// } as TestCase, +// { +// Description: 'is in maintenance mode - creates', +// Input: { SystemStatus: [{ IsInMaintenanceMode: true }] }, +// Test: (items) => items.filter((item) => item.type === ServiceIssueType.MaintenanceMode).length === 1, +// } as TestCase, +// { +// Description: 'at least one job service is inactive - creates', +// Input: { InactiveJobServers: [{ totalCount: 1 }] }, +// Test: (items) => items.filter((item) => item.type === ServiceIssueType.InactiveServers).length === 1, +// } as TestCase, +// { +// Description: 'at least one frozen job exists - creates', +// Input: { Frozenjobsbyqueue: [{ Data: [frozenJobQueueEntry1] }] }, +// Test: (items) => items.filter((item) => item.id === frozenJobQueueEntry1.QueueName.value).length === 1, +// } as TestCase, +// { +// Description: 'at least one sync issue exists - creates', +// Input: { SyncJournal: [{ totalCount: 1 }] }, +// Test: (items) => items.filter((item) => item.type === ServiceIssueType.SyncIssues).length === 1, +// } as TestCase, +// { +// Description: 'number of unresolved references higher than threshold - creates', +// Input: { SyncDatastore: [{ totalCount: 1, Data: [0] }], SyncDatastoreIssueThreshold: 0 }, +// Test: (items) => items.filter((item) => item.type === ServiceIssueType.UnresolvedRefs).length === 1, +// } as TestCase, +// ]) { +// describe('ImxServerIssuesService items - create', () => { +// it(testcase.Description, () => { +// prepareTestBed(testcase.Input); +// inject([ServiceIssuesService], async (service: ServiceIssuesService) => { +// expect(service.items.length).toEqual(0); +// await service.updateItems(); +// expect(testcase.Test(service.items)).toEqual(true); +// })(); +// }); +// }); +// } -for (const testcase of [ - { - Description: 'dbqueue is stopped - creates', - Input: { SystemStatus: [{ IsDbSchedulerDisabled: true }] }, - Test: items => items.filter(item => item.type === ServiceIssueType.DbSchedulerDisabled).length === 1 - } as TestCase, - { - Description: 'jobqueue is stopped - creates', - Input: { SystemStatus: [{ IsJobServiceDisabled: true }] }, - Test: items => items.filter(item => item.type === ServiceIssueType.JobServiceDisabled).length === 1 - } as TestCase, - { - Description: 'compilation is required - creates', - Input: { SystemStatus: [{ IsCompilationRequired: true }] }, - Test: items => items.filter(item => item.type === ServiceIssueType.CompilationRequired).length === 1 - } as TestCase, - { - Description: 'is in maintenance mode - creates', - Input: { SystemStatus: [{ IsInMaintenanceMode: true }] }, - Test: items => items.filter(item => item.type === ServiceIssueType.MaintenanceMode).length === 1 - } as TestCase, - { - Description: 'at least one job service is inactive - creates', - Input: { InactiveJobServers: [{ totalCount: 1 }] }, - Test: items => items.filter(item => item.type === ServiceIssueType.InactiveServers).length === 1 - } as TestCase, - { - Description: 'at least one frozen job exists - creates', - Input: { Frozenjobsbyqueue: [{ Data: [frozenJobQueueEntry1] }] }, - Test: items => items.filter(item => item.id === frozenJobQueueEntry1.QueueName.value).length === 1 - } as TestCase, - { - Description: 'at least one sync issue exists - creates', - Input: { SyncJournal: [{ totalCount: 1 }] }, - Test: items => items.filter(item => item.type === ServiceIssueType.SyncIssues).length === 1 - } as TestCase, - { - Description: 'number of unresolved references higher than threshold - creates', - Input: { SyncDatastore: [{ totalCount: 1, Data: [0] }], SyncDatastoreIssueThreshold: 0 }, - Test: items => items.filter(item => item.type === ServiceIssueType.UnresolvedRefs).length === 1 - } as TestCase -]) { - describe('ImxServerIssuesService items - create', () => { - it(testcase.Description, () => { - prepareTestBed(testcase.Input); - inject([ServiceIssuesService], async (service: ServiceIssuesService) => { - expect(service.items.length).toEqual(0); - await service.updateItems(); - expect(testcase.Test(service.items)).toEqual(true); - })(); - }); - }); -} - -for (const testcase of [ - { - Description: 'dbqueue is stopped - state remains - updates', - Input: { SystemStatus: [{ IsDbSchedulerDisabled: true }, { IsDbSchedulerDisabled: true }] }, - Test: items => items.filter(item => item.type === ServiceIssueType.DbSchedulerDisabled).length === 1 - } as TestCase, - { - Description: 'dbqueue is started - then stopped - removes', - Input: { SystemStatus: [{ IsDbSchedulerDisabled: true }, { IsDbSchedulerDisabled: false }] }, - Test: items => items.filter(item => item.type === ServiceIssueType.DbSchedulerDisabled).length === 0 - } as TestCase, - { - Description: 'jobqueue is stopped - state remains - updates', - Input: { SystemStatus: [{ IsJobServiceDisabled: true }, { IsJobServiceDisabled: true }] }, - Test: items => items.filter(item => item.type === ServiceIssueType.JobServiceDisabled).length === 1 - } as TestCase, - { - Description: 'jobqueue is started - then stopped - removes', - Input: { SystemStatus: [{ IsJobServiceDisabled: true }, { IsJobServiceDisabled: false }] }, - Test: items => items.filter(item => item.type === ServiceIssueType.JobServiceDisabled).length === 0 - } as TestCase, - { - Description: 'compilation is required - state remains - updates', - Input: { SystemStatus: [{ IsCompilationRequired: true }, { IsCompilationRequired: true }] }, - Test: items => items.filter(item => item.type === ServiceIssueType.CompilationRequired).length === 1 - } as TestCase, - { - Description: 'compilation is required - then not anymore - removes', - Input: { SystemStatus: [{ IsCompilationRequired: true }, { IsCompilationRequired: false }] }, - Test: items => items.filter(item => item.type === ServiceIssueType.CompilationRequired).length === 0 - } as TestCase, - { - Description: 'is in maintenance mode - state remains - updates', - Input: { SystemStatus: [{ IsInMaintenanceMode: true }, { IsInMaintenanceMode: true }] }, - Test: items => items.filter(item => item.type === ServiceIssueType.MaintenanceMode).length === 1 - } as TestCase, - { - Description: 'is in maintenance mode - then not anymore - removes', - Input: { SystemStatus: [{ IsInMaintenanceMode: true }, { IsInMaintenanceMode: false }] }, - Test: items => items.filter(item => item.type === ServiceIssueType.MaintenanceMode).length === 0 - } as TestCase, - { - Description: 'at least one job service is inactive - state remains - updates', - Input: { InactiveJobServers: [{ totalCount: 1 }, { totalCount: 1 }] }, - Test: items => items.filter(item => item.type === ServiceIssueType.InactiveServers).length === 1 - } as TestCase, - { - Description: 'at least one job service is inactive - then not anymore - removes', - Input: { InactiveJobServers: [{ totalCount: 1 }, { totalCount: 0 }] }, - Test: items => items.filter(item => item.type === ServiceIssueType.InactiveServers).length === 0 - } as TestCase, - { - Description: 'at least one frozen job exists - state remains - updates', - Input: { Frozenjobsbyqueue: [{ Data: [frozenJobQueueEntry1] }, { Data: [frozenJobQueueEntry1] }] }, - Test: items => items.filter(item => item.id === frozenJobQueueEntry1.QueueName.value).length === 1 - } as TestCase, - { - Description: 'at least one frozen job exists - then not anymore - removes', - Input: { Frozenjobsbyqueue: [{ Data: [frozenJobQueueEntry1] }, { Data: [] }] }, - Test: items => items.filter(item => item.id === frozenJobQueueEntry1.QueueName.value).length === 0 - } as TestCase, - { - Description: 'at least one frozen job exists in a specific queue - then not anymore - removes only for this queue', - Input: { Frozenjobsbyqueue: [{ Data: [frozenJobQueueEntry1, frozenJobQueueEntry2] }, { Data: [frozenJobQueueEntry2] }] }, - Test: items => - items.filter(item => item.id === frozenJobQueueEntry1.QueueName.value).length === 0 && - items.filter(item => item.id === frozenJobQueueEntry2.QueueName.value).length === 1 - } as TestCase, - { - Description: 'at least one sync issue exists - state remains - updates', - Input: { SyncJournal: [{ totalCount: 1 }, { totalCount: 1 }] }, - Test: items => items.filter(item => item.type === ServiceIssueType.SyncIssues).length === 1 - } as TestCase, - { - Description: 'at least one sync issue exists - then not anymore - removes', - Input: { SyncJournal: [{ totalCount: 1 }, { totalCount: 0 }] }, - Test: items => items.filter(item => item.type === ServiceIssueType.SyncIssues).length === 0 - } as TestCase, - { - Description: 'number of unresolved references higher than threshold - state remains - updates', - Input: { SyncDatastore: [{ totalCount: 1 }, { totalCount: 1 }], SyncDatastoreIssueThreshold: 0 }, - Test: items => items.filter(item => item.type === ServiceIssueType.UnresolvedRefs).length === 1 - } as TestCase, - { - Description: 'number of unresolved references higher than threshold - then not anymore - removes', - Input: { SyncDatastore: [{ totalCount: 1 }, { totalCount: 0 }], SyncDatastoreIssueThreshold: 0 }, - Test: items => items.filter(item => item.type === ServiceIssueType.UnresolvedRefs).length === 0 - } as TestCase -]) { - describe('ImxServerIssuesService items - update or remove', () => { - beforeEach(() => { - prepareTestBed(testcase.Input); - }); - - it(testcase.Description, () => { - inject([ServiceIssuesService], async (service: ServiceIssuesService) => { - expect(service.items.length).toEqual(0); - await service.updateItems(); - expect(service.items.length).toBeGreaterThan(0); - await service.updateItems(); - expect(testcase.Test(service.items)).toEqual(true); - })(); - }); - }); - } +// for (const testcase of [ +// { +// Description: 'dbqueue is stopped - state remains - updates', +// Input: { SystemStatus: [{ IsDbSchedulerDisabled: true }, { IsDbSchedulerDisabled: true }] }, +// Test: (items) => items.filter((item) => item.type === ServiceIssueType.DbSchedulerDisabled).length === 1, +// } as TestCase, +// { +// Description: 'dbqueue is started - then stopped - removes', +// Input: { SystemStatus: [{ IsDbSchedulerDisabled: true }, { IsDbSchedulerDisabled: false }] }, +// Test: (items) => items.filter((item) => item.type === ServiceIssueType.DbSchedulerDisabled).length === 0, +// } as TestCase, +// { +// Description: 'jobqueue is stopped - state remains - updates', +// Input: { SystemStatus: [{ IsJobServiceDisabled: true }, { IsJobServiceDisabled: true }] }, +// Test: (items) => items.filter((item) => item.type === ServiceIssueType.JobServiceDisabled).length === 1, +// } as TestCase, +// { +// Description: 'jobqueue is started - then stopped - removes', +// Input: { SystemStatus: [{ IsJobServiceDisabled: true }, { IsJobServiceDisabled: false }] }, +// Test: (items) => items.filter((item) => item.type === ServiceIssueType.JobServiceDisabled).length === 0, +// } as TestCase, +// { +// Description: 'compilation is required - state remains - updates', +// Input: { SystemStatus: [{ IsCompilationRequired: true }, { IsCompilationRequired: true }] }, +// Test: (items) => items.filter((item) => item.type === ServiceIssueType.CompilationRequired).length === 1, +// } as TestCase, +// { +// Description: 'compilation is required - then not anymore - removes', +// Input: { SystemStatus: [{ IsCompilationRequired: true }, { IsCompilationRequired: false }] }, +// Test: (items) => items.filter((item) => item.type === ServiceIssueType.CompilationRequired).length === 0, +// } as TestCase, +// { +// Description: 'is in maintenance mode - state remains - updates', +// Input: { SystemStatus: [{ IsInMaintenanceMode: true }, { IsInMaintenanceMode: true }] }, +// Test: (items) => items.filter((item) => item.type === ServiceIssueType.MaintenanceMode).length === 1, +// } as TestCase, +// { +// Description: 'is in maintenance mode - then not anymore - removes', +// Input: { SystemStatus: [{ IsInMaintenanceMode: true }, { IsInMaintenanceMode: false }] }, +// Test: (items) => items.filter((item) => item.type === ServiceIssueType.MaintenanceMode).length === 0, +// } as TestCase, +// { +// Description: 'at least one job service is inactive - state remains - updates', +// Input: { InactiveJobServers: [{ totalCount: 1 }, { totalCount: 1 }] }, +// Test: (items) => items.filter((item) => item.type === ServiceIssueType.InactiveServers).length === 1, +// } as TestCase, +// { +// Description: 'at least one job service is inactive - then not anymore - removes', +// Input: { InactiveJobServers: [{ totalCount: 1 }, { totalCount: 0 }] }, +// Test: (items) => items.filter((item) => item.type === ServiceIssueType.InactiveServers).length === 0, +// } as TestCase, +// { +// Description: 'at least one frozen job exists - state remains - updates', +// Input: { Frozenjobsbyqueue: [{ Data: [frozenJobQueueEntry1] }, { Data: [frozenJobQueueEntry1] }] }, +// Test: (items) => items.filter((item) => item.id === frozenJobQueueEntry1.QueueName.value).length === 1, +// } as TestCase, +// { +// Description: 'at least one frozen job exists - then not anymore - removes', +// Input: { Frozenjobsbyqueue: [{ Data: [frozenJobQueueEntry1] }, { Data: [] }] }, +// Test: (items) => items.filter((item) => item.id === frozenJobQueueEntry1.QueueName.value).length === 0, +// } as TestCase, +// { +// Description: 'at least one frozen job exists in a specific queue - then not anymore - removes only for this queue', +// Input: { Frozenjobsbyqueue: [{ Data: [frozenJobQueueEntry1, frozenJobQueueEntry2] }, { Data: [frozenJobQueueEntry2] }] }, +// Test: (items) => +// items.filter((item) => item.id === frozenJobQueueEntry1.QueueName.value).length === 0 && +// items.filter((item) => item.id === frozenJobQueueEntry2.QueueName.value).length === 1, +// } as TestCase, +// { +// Description: 'at least one sync issue exists - state remains - updates', +// Input: { SyncJournal: [{ totalCount: 1 }, { totalCount: 1 }] }, +// Test: (items) => items.filter((item) => item.type === ServiceIssueType.SyncIssues).length === 1, +// } as TestCase, +// { +// Description: 'at least one sync issue exists - then not anymore - removes', +// Input: { SyncJournal: [{ totalCount: 1 }, { totalCount: 0 }] }, +// Test: (items) => items.filter((item) => item.type === ServiceIssueType.SyncIssues).length === 0, +// } as TestCase, +// { +// Description: 'number of unresolved references higher than threshold - state remains - updates', +// Input: { SyncDatastore: [{ totalCount: 1 }, { totalCount: 1 }], SyncDatastoreIssueThreshold: 0 }, +// Test: (items) => items.filter((item) => item.type === ServiceIssueType.UnresolvedRefs).length === 1, +// } as TestCase, +// { +// Description: 'number of unresolved references higher than threshold - then not anymore - removes', +// Input: { SyncDatastore: [{ totalCount: 1 }, { totalCount: 0 }], SyncDatastoreIssueThreshold: 0 }, +// Test: (items) => items.filter((item) => item.type === ServiceIssueType.UnresolvedRefs).length === 0, +// } as TestCase, +// ]) { +// describe('ImxServerIssuesService items - update or remove', () => { +// beforeEach(() => { +// prepareTestBed(testcase.Input); +// }); +// it(testcase.Description, () => { +// inject([ServiceIssuesService], async (service: ServiceIssuesService) => { +// expect(service.items.length).toEqual(0); +// await service.updateItems(); +// expect(service.items.length).toBeGreaterThan(0); +// await service.updateItems(); +// expect(testcase.Test(service.items)).toEqual(true); +// })(); +// }); +// }); +// } diff --git a/imxweb/projects/qer-app-operationssupport/src/app/information/service-issues/service-issues.service.ts b/imxweb/projects/qer-app-operationssupport/src/app/information/service-issues/service-issues.service.ts index dd11d97c4..a8ab68f2e 100644 --- a/imxweb/projects/qer-app-operationssupport/src/app/information/service-issues/service-issues.service.ts +++ b/imxweb/projects/qer-app-operationssupport/src/app/information/service-issues/service-issues.service.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -27,20 +27,22 @@ import { Injectable } from '@angular/core'; import { Router } from '@angular/router'; import { TranslateService } from '@ngx-translate/core'; -import { FilterType, CompareOperator } from 'imx-qbm-dbts'; -import { imx_SessionService, AppConfigService, TextContainer, LdsReplacePipe } from 'qbm'; -import { IssueAction } from './service-issues.models'; +import { CompareOperator, FilterType } from '@imx-modules/imx-qbm-dbts'; +import { AppConfigService, LdsReplacePipe, TextContainer, imx_SessionService } from 'qbm'; import { SubscriptionService } from '../../base/subscription.service'; -import { ServiceIssueType, ServiceIssueItem } from './service-issue-item'; -import { SystemStatusService } from '../system-status/system-status.service'; -import { UnresolvedRefsService } from '../../unresolved-refs/unresolved-refs.service'; import { SyncService } from '../../sync/sync.service'; +import { UnresolvedRefsService } from '../../unresolved-refs/unresolved-refs.service'; +import { SystemOverviewService } from '../system-overview/system-overview.service'; +import { SystemTreeDatabase } from '../system-overview/system-tree/system-tree-database'; +import { SystemStatusService } from '../system-status/system-status.service'; +import { ServiceIssueItem, ServiceIssueType } from './service-issue-item'; +import { IssueAction } from './service-issues.models'; @Injectable() export class ServiceIssuesService extends SubscriptionService { public isLoading = false; - private jobDisabled = false; - private dbDisabled = false; + private jobDisabled: boolean | undefined = false; + private dbDisabled: boolean | undefined = false; constructor( private router: Router, @@ -50,7 +52,9 @@ export class ServiceIssuesService extends SubscriptionService this.goToQueue(queue.QueueName.value), }, - queue.QueueName.value + queue.QueueName.value, ); this.remove(ServiceIssueType.FrozenJobs, queuesWithFrozenJobs); @@ -121,7 +126,7 @@ export class ServiceIssuesService extends SubscriptionService this.changeStatus(false, this.dbDisabled), - } + action: async () => this.changeStatus(false, this.dbDisabled!), + }, ); } else { this.remove(ServiceIssueType.JobServiceDisabled); @@ -150,8 +155,8 @@ export class ServiceIssuesService extends SubscriptionService this.changeStatus(this.jobDisabled, false), - } + action: async () => this.changeStatus(this.jobDisabled!, false), + }, ); } else { this.remove(ServiceIssueType.DbSchedulerDisabled); @@ -162,7 +167,7 @@ export class ServiceIssuesService extends SubscriptionService this.router.navigate(['/ServicesInactive']), - } + }, ); } @@ -229,7 +234,7 @@ export class ServiceIssuesService extends SubscriptionService { - if (totalCount <= this.configService.Config.DatastoreIssueTreshold) { + if (!!this.configService.Config.DatastoreIssueTreshold && totalCount <= this.configService.Config.DatastoreIssueTreshold) { this.remove(ServiceIssueType.UnresolvedRefs); return; } @@ -260,10 +265,29 @@ export class ServiceIssuesService extends SubscriptionService this.router.navigate(['/unresolvedRefs']), - } + }, ); } + private async checkSystemOverview(): Promise { + const entity = await this.systemOverviewService.ItemsProvider(); + this.database.initialize(entity); + const thresholdCount = this.database.ExceededThresholdsCounter; + const type = ServiceIssueType.SystemThresholdExceeded; + + if (thresholdCount > 0) { + await this.update( + type, + '#LDS#System information', + { key: '#LDS#{0} thresholds exceeded', parameters: [thresholdCount] }, + 'warning', + '', + ); + } else { + this.remove(type); + } + } + private async changeStatus(jobService: boolean, dbService: boolean): Promise { await this.statusService.set(jobService, dbService); await this.updateItems(); @@ -280,17 +304,14 @@ export class ServiceIssuesService extends SubscriptionService { - let issueItem: ServiceIssueItem; + let issueItem = + serviceType === ServiceIssueType.FrozenJobs + ? this.itemsInternal.find((item) => item.id === id) + : this.itemsInternal.find((item) => item.type === serviceType); - if (serviceType === ServiceIssueType.FrozenJobs) { - issueItem = this.itemsInternal.find((item) => item.id === id); - } else { - issueItem = this.itemsInternal.find((item) => item.type === serviceType); - } - - if (issueItem == null) { + if (!issueItem) { issueItem = new ServiceIssueItem(); issueItem.type = serviceType; issueItem.action = action; @@ -303,12 +324,14 @@ export class ServiceIssuesService extends SubscriptionService 0 ? text.parameters[0] : '', - text.parameters?.length > 1 ? text.parameters[1] : '' - ); - if (action) { + if (text.parameters) { + issueItem.text = this.ldsPipe.transform( + tranlatedKey, + text.parameters?.length > 0 ? text.parameters[0] : '', + text.parameters?.length > 1 ? text.parameters[1] : '', + ); + } + if (issueItem.action && action) { issueItem.action.caption = await this.translater.get(action.caption).toPromise(); } } diff --git a/imxweb/projects/qer-app-operationssupport/src/app/information/system-overview/system-overview.component.html b/imxweb/projects/qer-app-operationssupport/src/app/information/system-overview/system-overview.component.html index a7bbd33ae..9f70d1fff 100644 --- a/imxweb/projects/qer-app-operationssupport/src/app/information/system-overview/system-overview.component.html +++ b/imxweb/projects/qer-app-operationssupport/src/app/information/system-overview/system-overview.component.html @@ -1,28 +1,33 @@
    -
    {{systemName}}
    +
    {{ systemName }}
    - - + +
    -
    {{systemEmail}}
    -
    - - {{'#LDS#{0} thresholds exceeded' | translate | ldsReplace:exceededTresholdsCounter}} +
    {{ systemEmail }}
    +
    + + {{ '#LDS#{0} thresholds exceeded' | translate | ldsReplace: exceededThresholdsCounter }}
    {{ node.item.Element.value }}
    {{ node.item.Value.value }}
    -  ({{ '#LDS#Recommended: {0}' | translate | ldsReplace:node.item.RecommendedValue.value }}) +  ({{ '#LDS#Recommended: {0}' | translate | ldsReplace: node.item.RecommendedValue.value }})
    - + - {{node.display}} + {{ node.display }}
    diff --git a/imxweb/projects/qer-app-operationssupport/src/app/information/system-overview/system-overview.component.ts b/imxweb/projects/qer-app-operationssupport/src/app/information/system-overview/system-overview.component.ts index 1b97dbd89..be2571d95 100644 --- a/imxweb/projects/qer-app-operationssupport/src/app/information/system-overview/system-overview.component.ts +++ b/imxweb/projects/qer-app-operationssupport/src/app/information/system-overview/system-overview.component.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -24,24 +24,24 @@ * */ +import { OverlayRef } from '@angular/cdk/overlay'; import { FlatTreeControl } from '@angular/cdk/tree'; import { Component, OnInit } from '@angular/core'; -import { OverlayRef } from '@angular/cdk/overlay'; import { EuiLoadingService } from '@elemental-ui/core'; +import { OpsupportSystemoverview } from '@imx-modules/imx-api-qbm'; import { UserActionService } from 'qbm'; -import { OpsupportSystemoverview } from 'imx-api-qbm'; import { SystemOverviewService } from './system-overview.service'; -import { SystemTreeNode } from './system-tree/system-tree-node'; import { SystemTreeDatabase } from './system-tree/system-tree-database'; import { SystemTreeDataSource } from './system-tree/system-tree-datasource'; +import { SystemTreeNode } from './system-tree/system-tree-node'; const recommendValClass = 'imx-recommendedValue-exceeded'; -const tresholdExceededClass = 'imx-treshold-exceeded'; +const thresholdExceededClass = 'imx-threshold-exceeded'; @Component({ selector: 'imx-system-overview', - templateUrl: './system-overview.component.html' + templateUrl: './system-overview.component.html', }) export class SystemOverviewComponent implements OnInit { public treeControl: FlatTreeControl; @@ -55,14 +55,14 @@ export class SystemOverviewComponent implements OnInit { private systemOverviewService: SystemOverviewService, private userActionService: UserActionService, private busyService: EuiLoadingService, - private database: SystemTreeDatabase) { + private database: SystemTreeDatabase, + ) { this.treeControl = new FlatTreeControl(this.getLevel, this.isExpandable); this.dataSource = new SystemTreeDataSource(this.treeControl, database); - } public async ngOnInit(): Promise { let overlayRef: OverlayRef; - setTimeout(() => overlayRef = this.busyService.show()); + setTimeout(() => (overlayRef = this.busyService.show())); try { const entity = await this.systemOverviewService.ItemsProvider(); this.dataSource.data = this.database.initialize(entity); @@ -78,13 +78,13 @@ export class SystemOverviewComponent implements OnInit { public isExpandable = (node: SystemTreeNode): boolean => node.expandable; public hasChild = (index: number, nodeData: SystemTreeNode): boolean => nodeData.expandable; - get exceededTresholdsCounter(): number { - return this.database.ExceededTresholdsCounter; + get exceededThresholdsCounter(): number { + return this.database.ExceededThresholdsCounter; } public qualityOfValueClass(node: OpsupportSystemoverview): string { const qualityValue = node.QualityOfValue.value; - return qualityValue <= 0.2 ? tresholdExceededClass : qualityValue <= 0.5 ? recommendValClass : ''; + return qualityValue <= 0.2 ? thresholdExceededClass : qualityValue <= 0.5 ? recommendValClass : ''; } public disableTooltip(node: OpsupportSystemoverview): boolean { diff --git a/imxweb/projects/qer-app-operationssupport/src/app/information/system-overview/system-overview.module.ts b/imxweb/projects/qer-app-operationssupport/src/app/information/system-overview/system-overview.module.ts index 9ae217a3c..27d8ff469 100644 --- a/imxweb/projects/qer-app-operationssupport/src/app/information/system-overview/system-overview.module.ts +++ b/imxweb/projects/qer-app-operationssupport/src/app/information/system-overview/system-overview.module.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -39,14 +39,7 @@ import { SystemTreeDataSource } from './system-tree/system-tree-datasource'; @NgModule({ declarations: [SystemOverviewComponent], - imports: [ - CommonModule, - MatTreeModule, - MatButtonModule, - EuiCoreModule, - TranslateModule, - LdsReplaceModule - ], - providers: [SystemTreeDatabase, SystemTreeDataSource, SystemOverviewService] + imports: [CommonModule, MatTreeModule, MatButtonModule, EuiCoreModule, TranslateModule, LdsReplaceModule], + providers: [SystemTreeDatabase, SystemTreeDataSource, SystemOverviewService], }) -export class SystemOverviewModule { } +export class SystemOverviewModule {} diff --git a/imxweb/projects/qer-app-operationssupport/src/app/information/system-overview/system-overview.service.ts b/imxweb/projects/qer-app-operationssupport/src/app/information/system-overview/system-overview.service.ts index d8235ec0a..d9fc74feb 100644 --- a/imxweb/projects/qer-app-operationssupport/src/app/information/system-overview/system-overview.service.ts +++ b/imxweb/projects/qer-app-operationssupport/src/app/information/system-overview/system-overview.service.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -25,9 +25,9 @@ */ import { Injectable } from '@angular/core'; -import { OpsupportSystemoverview } from 'imx-api-qbm'; +import { OpsupportSystemoverview } from '@imx-modules/imx-api-qbm'; import { imx_SessionService } from 'qbm'; -import { TypedEntityCollectionData } from 'imx-qbm-dbts'; +import { TypedEntityCollectionData } from '@imx-modules/imx-qbm-dbts'; @Injectable() export class SystemOverviewService { diff --git a/imxweb/projects/qer-app-operationssupport/src/app/information/system-overview/system-tree/system-tree-database.spec.ts b/imxweb/projects/qer-app-operationssupport/src/app/information/system-overview/system-tree/system-tree-database.spec.ts index fffb7c91b..b9c9bd8c7 100644 --- a/imxweb/projects/qer-app-operationssupport/src/app/information/system-overview/system-tree/system-tree-database.spec.ts +++ b/imxweb/projects/qer-app-operationssupport/src/app/information/system-overview/system-tree/system-tree-database.spec.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -24,25 +24,23 @@ * */ -import * as TypeMoq from 'typemoq'; - -import { OpsupportSystemoverview } from "imx-api-qbm"; -import { SystemTreeDatabase } from "./system-tree-database"; +import { OpsupportSystemoverview } from '@imx-modules/imx-api-qbm'; +import { TypedEntityCollectionData } from '@imx-modules/imx-qbm-dbts'; import { CreateIReadValue } from 'qbm'; -import { TypedEntityCollectionData } from 'imx-qbm-dbts'; +import { SystemTreeDatabase } from './system-tree-database'; describe('SystemTreeDatabase', () => { let node: SystemTreeDatabase; function getSysOverviewMock(cat?: string, el?: string, val?: string, qov?: number): OpsupportSystemoverview { - const mock = TypeMoq.Mock.ofType(); - mock.setup(d => d.Category).returns(() => CreateIReadValue(cat)); - mock.setup(d => d.Element).returns(() => CreateIReadValue(el)); - mock.setup(d => d.Value).returns(() => CreateIReadValue(val)); - mock.setup(d => d.QualityOfValue).returns(() => CreateIReadValue(qov)); - mock.setup(d => d.RecommendedValue).returns(() => CreateIReadValue('Recommmended')); - mock.setup(d => d.UID_QBMVSystemOverview).returns(() => CreateIReadValue('14AA3338-8EEF-2ECE-9C85-D12E0E4CE3ED')); - return mock.object; + return { + Category: CreateIReadValue(cat), + Element: CreateIReadValue(el), + Value: CreateIReadValue(val), + QualityOfValue: CreateIReadValue(qov), + RecommendedValue: CreateIReadValue('Recommmended'), + UID_QBMVSystemOverview: CreateIReadValue('14AA3338-8EEF-2ECE-9C85-D12E0E4CE3ED'), + } as OpsupportSystemoverview; } function getMockedTypedEntityCollection( @@ -53,14 +51,14 @@ describe('SystemTreeDatabase', () => { cat2?: string, el2?: string, val2?: string, - qov2?: number + qov2?: number, ): TypedEntityCollectionData { const mock1 = getSysOverviewMock(cat1, el1, val1, qov1); const mock2 = getSysOverviewMock(cat2, el2, val2, qov2); return { tableName: 'dummyTable', totalCount: 10, - Data: [mock1, mock2] + Data: [mock1, mock2], }; } @@ -85,14 +83,14 @@ describe('SystemTreeDatabase', () => { it('should run initialization completely', () => { node.initialize(getMockedTypedEntityCollection('DB', 'DB Name', 'Val1', 0.1, 'DB', 'DB Queue', 'Val1', 0.1)); - expect(node.ExceededTresholdsCounter).toBe(2); + expect(node.ExceededThresholdsCounter).toBe(2); }); it('should export as csv-data', () => { node.initialize(getMockedTypedEntityCollection('Customer', 'Customer Name', 'Val1', 0.1, 'Customer', 'Customer Email', 'Val2', 0.7)); expect(node.export().length).toBeGreaterThan(0); expect(node.export()).toBe( - 'Category, Element, Value, QualityOfValue, RecommendedValue\r\nCustomer,Customer Name,Val1,0.1,Recommmended\r\nCustomer,Customer Email,Val2,0.7,Recommmended\r\n' + 'Category, Element, Value, QualityOfValue, RecommendedValue\r\nCustomer,Customer Name,Val1,0.1,Recommmended\r\nCustomer,Customer Email,Val2,0.7,Recommmended\r\n', ); }); -}); \ No newline at end of file +}); diff --git a/imxweb/projects/qer-app-operationssupport/src/app/information/system-overview/system-tree/system-tree-database.ts b/imxweb/projects/qer-app-operationssupport/src/app/information/system-overview/system-tree/system-tree-database.ts index 3788f7bee..27776eef4 100644 --- a/imxweb/projects/qer-app-operationssupport/src/app/information/system-overview/system-tree/system-tree-database.ts +++ b/imxweb/projects/qer-app-operationssupport/src/app/information/system-overview/system-tree/system-tree-database.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -24,17 +24,15 @@ * */ - import { Injectable } from '@angular/core'; -import { OpsupportSystemoverview } from 'imx-api-qbm'; -import { TypedEntityCollectionData } from 'imx-qbm-dbts'; +import { OpsupportSystemoverview } from '@imx-modules/imx-api-qbm'; +import { TypedEntityCollectionData } from '@imx-modules/imx-qbm-dbts'; import { RegistryService } from 'qbm'; import { SystemTreeNode } from './system-tree-node'; @Injectable() export class SystemTreeDatabase { - get CustomerName(): string { return this.customerName; } @@ -43,13 +41,13 @@ export class SystemTreeDatabase { return this.customerEmail; } - get ExceededTresholdsCounter(): number { - return this.tresholdsCounter; + get ExceededThresholdsCounter(): number { + return this.thresholdCount; } private dataMap: Map; private categoryRegistry: RegistryService; private exceededTresholdsRegistry: { [id: string]: number }; - private tresholdsCounter: number; + private thresholdCount: number; private customerName = ''; private customerEmail = ''; @@ -82,8 +80,8 @@ export class SystemTreeDatabase { const arr = Array.from(this.dataMap.entries()); arr.forEach((item: [string, OpsupportSystemoverview[]]) => { item[1].forEach((d: OpsupportSystemoverview) => { - const line = d.Category.value + ',' + d.Element.value + ',' + d.Value.value + ',' - + d.QualityOfValue.value + ',' + d.RecommendedValue.value; + const line = + d.Category.value + ',' + d.Element.value + ',' + d.Value.value + ',' + d.QualityOfValue.value + ',' + d.RecommendedValue.value; exp += line + '\r\n'; }); }); @@ -108,9 +106,9 @@ export class SystemTreeDatabase { private createNodes(): SystemTreeNode[] { const categories = Object.keys(this.categoryRegistry.Registry).sort(); - return categories.map(c => { + return categories.map((c) => { this.dataMap.set(c, this.categoryRegistry.Registry[c]); - return new SystemTreeNode(null, c, 0, true, this.exceededTresholdsRegistry[c]); + return new SystemTreeNode(undefined, c, 0, true, this.exceededTresholdsRegistry[c]); }); } @@ -119,13 +117,13 @@ export class SystemTreeDatabase { this.exceededTresholdsRegistry[category] = 0; } this.exceededTresholdsRegistry[category] += inc; - this.tresholdsCounter += inc; + this.thresholdCount += inc; } private initalize(): void { this.dataMap = new Map(); this.categoryRegistry = new RegistryService(); this.exceededTresholdsRegistry = {}; - this.tresholdsCounter = 0; + this.thresholdCount = 0; } } diff --git a/imxweb/projects/qer-app-operationssupport/src/app/information/system-overview/system-tree/system-tree-datasource.spec.ts b/imxweb/projects/qer-app-operationssupport/src/app/information/system-overview/system-tree/system-tree-datasource.spec.ts index 0ef8b9349..4c2fc3895 100644 --- a/imxweb/projects/qer-app-operationssupport/src/app/information/system-overview/system-tree/system-tree-datasource.spec.ts +++ b/imxweb/projects/qer-app-operationssupport/src/app/information/system-overview/system-tree/system-tree-datasource.spec.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -27,119 +27,66 @@ import { CollectionViewer, SelectionChange, SelectionModel } from '@angular/cdk/collections'; import { FlatTreeControl } from '@angular/cdk/tree'; import { Subject } from 'rxjs'; -import * as TypeMoq from 'typemoq'; -import { OpsupportSystemoverview } from 'imx-api-qbm'; -import { CreateIReadValue } from 'qbm'; import { SystemTreeDatabase } from './system-tree-database'; import { SystemTreeDataSource } from './system-tree-datasource'; import { SystemTreeNode } from './system-tree-node'; - -describe('SystemTreeDataSource', () => { +-describe('SystemTreeDataSource', () => { let dataSource: SystemTreeDataSource; - let flatTreeMock: TypeMoq.IMock>; - let database: TypeMoq.IMock; + let flatTreeMock: FlatTreeControl; + let database: SystemTreeDatabase; beforeEach(() => { - flatTreeMock = TypeMoq.Mock.ofType>(); - database = TypeMoq.Mock.ofType(); - dataSource = new SystemTreeDataSource(flatTreeMock.object, database.object); + flatTreeMock = {} as FlatTreeControl; + database = {} as SystemTreeDatabase; + dataSource = new SystemTreeDataSource(flatTreeMock, database); }); it('should be create with defaults', () => { expect(dataSource).toBeTruthy(); }); - // TODO #227277 fix unittests after update on Angular V9 - xit('should set data correctly', () => { - const data = dataSource.data; - expect(data).toBeDefined(); - - spyOn(dataSource, 'dataChange' as any); - - const node = TypeMoq.Mock.ofType(); - const nodes = new Array(); - nodes.push(node.object); - dataSource.data = nodes; - }); - it('should handle the connect', () => { - const selModelMock = TypeMoq.Mock.ofType>(); - flatTreeMock.setup(f => f.expansionModel).returns(() => selModelMock.object); - - const selChgMock = TypeMoq.Mock.ofType>>(); - selModelMock.setup(s => s.changed).returns(() => selChgMock.object); + const selChgMock = new Subject>(); + const selModelMock = { changed: selChgMock } as unknown as SelectionModel; + flatTreeMock.expansionModel = selModelMock; - const colViewerMock = TypeMoq.Mock.ofType(); - dataSource.connect(colViewerMock.object); + const colViewerMock = {} as CollectionViewer; + dataSource.connect(colViewerMock); }); it('should handle the treecontrol', () => { - const node = TypeMoq.Mock.ofType(); + const node = {} as SystemTreeNode; const nodes = new Array(); - nodes.push(node.object); + nodes.push(node); const toggleNodeSpy = spyOn(dataSource, 'toggleNode'); const emptyArray = new Array(); - const selChangeMock = TypeMoq.Mock.ofType>(); + let selChangeMock = { added: nodes, removed: nodes } as SelectionChange; - selChangeMock.setup(m => m.added).returns(() => nodes); - selChangeMock.setup(m => m.removed).returns(() => nodes); - dataSource.handleTreeControl(selChangeMock.object); + dataSource.handleTreeControl(selChangeMock); expect(toggleNodeSpy).toHaveBeenCalled(); toggleNodeSpy.calls.reset(); - selChangeMock.setup(m => m.added).returns(() => emptyArray); - selChangeMock.setup(m => m.removed).returns(() => emptyArray); - dataSource.handleTreeControl(selChangeMock.object); + selChangeMock = { added: emptyArray, removed: emptyArray } as SelectionChange; + dataSource.handleTreeControl(selChangeMock); expect(toggleNodeSpy).not.toHaveBeenCalled(); }); - - // TODO #227277 fix unittests after update on Angular V9 - xit('should handle toggleNode', () => { - const sysOverviewObjMock = TypeMoq.Mock.ofType(); - sysOverviewObjMock.setup(d => d.Category).returns(() => CreateIReadValue('Cat')); - sysOverviewObjMock.setup(d => d.Element).returns(() => CreateIReadValue('Elem')); - sysOverviewObjMock.setup(d => d.Value).returns(() => CreateIReadValue('Val')); - sysOverviewObjMock.setup(d => d.QualityOfValue).returns(() => CreateIReadValue(0.1)); - sysOverviewObjMock.setup(d => d.RecommendedValue).returns(() => CreateIReadValue('Recommmended')); - sysOverviewObjMock.setup(d => d.UID_QBMVSystemOverview).returns(() => CreateIReadValue('14AA3338-8EEF-2ECE-9C85-D12E0E4CE3ED')); - - const children = new Array(); - children.push(sysOverviewObjMock.object); - - database.setup(d => d.getChildren(TypeMoq.It.isAnyString())).returns(() => children); - - dataSource = new SystemTreeDataSource(flatTreeMock.object, database.object); - - const nodeMock = TypeMoq.Mock.ofType(); - const nodes = new Array(); - nodes.push(nodeMock.object); - dataSource.data = nodes; - - const dataChangeSpy = spyOn(dataSource, 'dataChange' as any); - - spyOn(dataSource.data, 'indexOf').and.returnValue(1); - - dataSource.toggleNode(nodeMock.object, true); - - expect(dataChangeSpy).not.toHaveBeenCalled(); - }); }); describe('SystemTreeDataSource', () => { it('unsubscribes on disconnect', () => { const flatTreeControlStub = { expansionModel: { - changed: new Subject() - } + changed: new Subject(), + }, } as FlatTreeControl; - const dataSource = new SystemTreeDataSource(flatTreeControlStub, TypeMoq.Mock.ofType().object); + const dataSource = new SystemTreeDataSource(flatTreeControlStub, {} as SystemTreeDatabase); dataSource.connect({} as CollectionViewer); expect(flatTreeControlStub.expansionModel.changed.observers.length).toEqual(1); diff --git a/imxweb/projects/qer-app-operationssupport/src/app/information/system-overview/system-tree/system-tree-datasource.ts b/imxweb/projects/qer-app-operationssupport/src/app/information/system-overview/system-tree/system-tree-datasource.ts index e52f8182c..dd47eeacd 100644 --- a/imxweb/projects/qer-app-operationssupport/src/app/information/system-overview/system-tree/system-tree-datasource.ts +++ b/imxweb/projects/qer-app-operationssupport/src/app/information/system-overview/system-tree/system-tree-datasource.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -27,7 +27,7 @@ import { CollectionViewer, SelectionChange } from '@angular/cdk/collections'; import { FlatTreeControl } from '@angular/cdk/tree'; import { Injectable } from '@angular/core'; -import { BehaviorSubject, merge, Observable, Subscription } from 'rxjs'; +import { BehaviorSubject, Observable, Subscription, merge } from 'rxjs'; import { map } from 'rxjs/operators'; import { SystemTreeDatabase } from './system-tree-database'; @@ -51,22 +51,27 @@ export class SystemTreeDataSource { */ private subscriptions: Subscription[] = []; - constructor(private treeControl: FlatTreeControl, private database: SystemTreeDatabase) { } + constructor( + private treeControl: FlatTreeControl, + private database: SystemTreeDatabase, + ) {} /** * @ignore Used internally. * Unsubscribes all listeners. */ public disconnect(): void { - this.subscriptions.forEach(subscription => subscription.unsubscribe()); + this.subscriptions.forEach((subscription) => subscription.unsubscribe()); } public connect(collectionViewer: CollectionViewer): Observable { - this.subscriptions.push(this.treeControl.expansionModel.changed.subscribe(change => { - if ((change as SelectionChange).added || (change as SelectionChange).removed) { - this.handleTreeControl(change as SelectionChange); - } - })); + this.subscriptions.push( + this.treeControl.expansionModel.changed.subscribe((change) => { + if ((change as SelectionChange).added || (change as SelectionChange).removed) { + this.handleTreeControl(change as SelectionChange); + } + }), + ); return merge(collectionViewer.viewChange, this.dataChange).pipe(map(() => this.data)); } @@ -74,13 +79,13 @@ export class SystemTreeDataSource { /** Handle expand/collapse behaviors */ public handleTreeControl(change: SelectionChange): void { if (change.added && change.added.length > 0) { - change.added.forEach(node => this.toggleNode(node, true)); + change.added.forEach((node) => this.toggleNode(node, true)); } if (change.removed && change.removed.length > 0) { change.removed .slice() .reverse() - .forEach(node => this.toggleNode(node, false)); + .forEach((node) => this.toggleNode(node, false)); } } @@ -96,12 +101,13 @@ export class SystemTreeDataSource { } if (expand) { - const nodes = children.map(name => new SystemTreeNode(name, null, node.level + 1, this.database.isExpandable(name.Element.value))); + const nodes = children.map( + (name) => new SystemTreeNode(name, undefined, node.level + 1, this.database.isExpandable(name.Element.value)), + ); this.data.splice(index + 1, 0, ...nodes); } else { let count = 0; - // tslint:disable-next-line: no-empty - for (let i = index + 1; i < this.data.length && this.data[i].level > node.level; i++, count++) { } + for (let i = index + 1; i < this.data.length && this.data[i].level > node.level; i++, count++) {} this.data.splice(index + 1, count); } diff --git a/imxweb/projects/qer-app-operationssupport/src/app/information/system-overview/system-tree/system-tree-node.spec.ts b/imxweb/projects/qer-app-operationssupport/src/app/information/system-overview/system-tree/system-tree-node.spec.ts index 03571ba20..1363d1294 100644 --- a/imxweb/projects/qer-app-operationssupport/src/app/information/system-overview/system-tree/system-tree-node.spec.ts +++ b/imxweb/projects/qer-app-operationssupport/src/app/information/system-overview/system-tree/system-tree-node.spec.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -23,19 +23,14 @@ * THIS SOFTWARE OR ITS DERIVATIVES. * */ -import * as TypeMoq from 'typemoq'; -import { SystemTreeNode } from './system-tree-node'; -import { OpsupportSystemoverview } from 'imx-api-qbm'; +import { OpsupportSystemoverview } from '@imx-modules/imx-api-qbm'; import { CreateIReadValue } from 'qbm'; +import { SystemTreeNode } from './system-tree-node'; describe('SystemTreeNode', () => { const dummyName = 'name'; - let sysOverviewObjMock: TypeMoq.IMock; - - beforeEach(() => { - sysOverviewObjMock = TypeMoq.Mock.ofType(); - }); + beforeEach(() => {}); it('should be use name as Display', () => { const node = new SystemTreeNode(null, dummyName, 0, true, 1); @@ -55,12 +50,9 @@ describe('SystemTreeNode', () => { it('should be use item.Element as Display', () => { const dummyDisplay = 'Person'; - sysOverviewObjMock.setup(d => d.Element).returns(() => CreateIReadValue(dummyDisplay)); - const node = new SystemTreeNode(sysOverviewObjMock.object, dummyName); + + const sysOverviewObjMock = { Element: CreateIReadValue(dummyDisplay) } as OpsupportSystemoverview; + const node = new SystemTreeNode(sysOverviewObjMock, dummyName); expect(node.display).toBe(dummyDisplay); }); }); - - - - diff --git a/imxweb/projects/qer-app-operationssupport/src/app/information/system-overview/system-tree/system-tree-node.ts b/imxweb/projects/qer-app-operationssupport/src/app/information/system-overview/system-tree/system-tree-node.ts index 78e946ae8..d6342747c 100644 --- a/imxweb/projects/qer-app-operationssupport/src/app/information/system-overview/system-tree/system-tree-node.ts +++ b/imxweb/projects/qer-app-operationssupport/src/app/information/system-overview/system-tree/system-tree-node.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -24,7 +24,7 @@ * */ -import { OpsupportSystemoverview } from 'imx-api-qbm'; +import { OpsupportSystemoverview } from '@imx-modules/imx-api-qbm'; export class SystemTreeNode { public display: string; @@ -33,8 +33,8 @@ export class SystemTreeNode { public name?: string, public level: number = 1, public expandable: boolean = false, - public hasExceeededTresholds: number = 0 + public hasExceeededTresholds: number = 0, ) { - this.display = item !== null ? item.Element.value : name; + this.display = (item ? item.Element.value : name) ?? ''; } } diff --git a/imxweb/projects/qer-app-operationssupport/src/app/information/system-status/system-status-information.interface.ts b/imxweb/projects/qer-app-operationssupport/src/app/information/system-status/system-status-information.interface.ts index b1e72f280..9d723a528 100644 --- a/imxweb/projects/qer-app-operationssupport/src/app/information/system-status/system-status-information.interface.ts +++ b/imxweb/projects/qer-app-operationssupport/src/app/information/system-status/system-status-information.interface.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR diff --git a/imxweb/projects/qer-app-operationssupport/src/app/information/system-status/system-status.component.html b/imxweb/projects/qer-app-operationssupport/src/app/information/system-status/system-status.component.html index 5e28d3b13..72e0dcc51 100644 --- a/imxweb/projects/qer-app-operationssupport/src/app/information/system-status/system-status.component.html +++ b/imxweb/projects/qer-app-operationssupport/src/app/information/system-status/system-status.component.html @@ -1,6 +1,6 @@ -

    - {{'#LDS#Heading System Status' | translate}} -

    +

    + {{ '#LDS#Heading System Status' | translate }} +

    @@ -11,19 +11,15 @@

    -
    {{'#LDS#DBQueue' | translate}}
    +
    {{ '#LDS#DBQueue' | translate }}
    - - {{'#LDS#DBQueue is paused' | translate}} - - {{'#LDS#DBQueue is running' | translate}} + {{ '#LDS#DBQueue is paused' | translate }} + {{ '#LDS#DBQueue is running' | translate }}
    -
    @@ -38,19 +34,15 @@

    -
    {{'#LDS#JobQueue' | translate}}
    +
    {{ '#LDS#JobQueue' | translate }}
    - - {{'#LDS#Job queue is paused' | translate}} - - {{'#LDS#Job queue is running' | translate}} + {{ '#LDS#Job queue is paused' | translate }} + {{ '#LDS#Job queue is running' | translate }}
    -
    @@ -63,22 +55,23 @@

    -
    {{'#LDS#Database' | translate}}
    +
    {{ '#LDS#Database' | translate }}
    - {{'#LDS#Database runs in maintenance mode' | - translate}} + {{ '#LDS#Database runs in maintenance mode' | translate }} - {{'#LDS#Database is up and running' | translate}} + {{ '#LDS#Database is up and running' | translate }}
    - {{'#LDS#Database must be compiled' | translate}} - - {{'#LDS#Database is up to date' | translate}} + {{ '#LDS#Database must be compiled' | translate }} + {{ '#LDS#Database is up to date' | translate }}
    @@ -86,4 +79,4 @@

    -

    \ No newline at end of file +
    diff --git a/imxweb/projects/qer-app-operationssupport/src/app/information/system-status/system-status.component.scss b/imxweb/projects/qer-app-operationssupport/src/app/information/system-status/system-status.component.scss index 103a2a2a1..ec94da641 100644 --- a/imxweb/projects/qer-app-operationssupport/src/app/information/system-status/system-status.component.scss +++ b/imxweb/projects/qer-app-operationssupport/src/app/information/system-status/system-status.component.scss @@ -1,24 +1,13 @@ -@import "@elemental-ui/core/src/styles/_palette.scss"; +@import '@elemental-ui/core/src/styles/_palette.scss'; @import '@elemental-ui/core/src/styles/_eui_palette.scss'; -.imx-db-icon { - padding-top: 45px; -} - -.mat-button { - color: $iris-blue; - font-weight: 600; -} - -eui-icon { - text-align: center; -} .eui-icon { + text-align: center; vertical-align: bottom; } -.mat-card { +.mat-mdc-card { padding: 0; margin: 5px; } diff --git a/imxweb/projects/qer-app-operationssupport/src/app/information/system-status/system-status.component.ts b/imxweb/projects/qer-app-operationssupport/src/app/information/system-status/system-status.component.ts index 11dc5c550..b6df2af2c 100644 --- a/imxweb/projects/qer-app-operationssupport/src/app/information/system-status/system-status.component.ts +++ b/imxweb/projects/qer-app-operationssupport/src/app/information/system-status/system-status.component.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -24,14 +24,14 @@ * */ -import { Component, OnInit, OnDestroy } from '@angular/core'; +import { Component, OnDestroy, OnInit } from '@angular/core'; import { DomSanitizer, SafeStyle } from '@angular/platform-browser'; import { Observable, Subject, Subscription, interval } from 'rxjs'; import { switchMap } from 'rxjs/operators'; -import { SystemStatusService } from './system-status.service'; -import { SystemStatusInformation } from './system-status-information.interface'; import { ConfirmationService } from 'qbm'; +import { SystemStatusInformation } from './system-status-information.interface'; +import { SystemStatusService } from './system-status.service'; @Component({ templateUrl: './system-status.component.html', @@ -44,17 +44,16 @@ export class SystemStatusComponent implements OnInit, OnDestroy { public isAdmin = false; - public get iconClassDb(): string { - return this.status == null ? this.cssClassError : this.status.IsDbSchedulerDisabled ? this.cssClassWarning : this.cssClassOk; + return !this.status ? this.cssClassError : this.status.IsDbSchedulerDisabled ? this.cssClassWarning : this.cssClassOk; } public get iconClassJob(): string { - return this.status == null ? this.cssClassError : this.status.IsJobServiceDisabled ? this.cssClassWarning : this.cssClassOk; + return !this.status ? this.cssClassError : this.status.IsJobServiceDisabled ? this.cssClassWarning : this.cssClassOk; } public get iconClassDbStatus(): string { - return this.status == null + return !this.status ? this.cssClassError : this.status.IsInMaintenanceMode || this.status.IsCompilationRequired ? this.cssClassWarning @@ -62,11 +61,11 @@ export class SystemStatusComponent implements OnInit, OnDestroy { } public get iconClassMaintenance(): string { - return this.status == null ? this.cssClassDbError : this.status.IsInMaintenanceMode ? this.cssClassDbWarning : this.cssClassDbOk; + return !this.status ? this.cssClassDbError : this.status.IsInMaintenanceMode ? this.cssClassDbWarning : this.cssClassDbOk; } public get iconClassUpdateStatus(): string { - return this.status == null ? this.cssClassDbError : this.status.IsCompilationRequired ? this.cssClassDbWarning : this.cssClassDbOk; + return !this.status ? this.cssClassDbError : this.status.IsCompilationRequired ? this.cssClassDbWarning : this.cssClassDbOk; } public get columns(): number { @@ -96,8 +95,8 @@ export class SystemStatusComponent implements OnInit, OnDestroy { constructor( private readonly sanitizer: DomSanitizer, private readonly statusService: SystemStatusService, - private readonly confirmationService: ConfirmationService - ) { } + private readonly confirmationService: ConfirmationService, + ) {} public async ngOnInit(): Promise { this.isAdmin = await this.statusService.isSystemAdmin(); @@ -106,7 +105,7 @@ export class SystemStatusComponent implements OnInit, OnDestroy { public ngOnDestroy(): void { this.refreshTimer.unsubscribe(); - this.subscriptions.forEach(subscription => subscription.unsubscribe()); + this.subscriptions.forEach((subscription) => subscription.unsubscribe()); } public async toggleDbQueue(): Promise { @@ -115,11 +114,13 @@ export class SystemStatusComponent implements OnInit, OnDestroy { return; } - if (await this.confirmationService.confirm({ - Title: '#LDS#Heading Start DBQueue', - Message: '#LDS#Are you sure you want to start the DBQueue?', - identifier: 'system-status-confirm-start-dbqueue' - })) { + if ( + await this.confirmationService.confirm({ + Title: '#LDS#Heading Start DBQueue', + Message: '#LDS#Are you sure you want to start the DBQueue?', + identifier: 'system-status-confirm-start-dbqueue', + }) + ) { this.changeIsDbServiceDisabled(); } } @@ -130,37 +131,45 @@ export class SystemStatusComponent implements OnInit, OnDestroy { return; } - if (await this.confirmationService.confirm({ - Title: '#LDS#Heading Start Job Queue', - Message: '#LDS#Are you sure you want to start the Job queue?', - identifier: 'system-status-confirm-start-jobqueue' - })) { + if ( + await this.confirmationService.confirm({ + Title: '#LDS#Heading Start Job Queue', + Message: '#LDS#Are you sure you want to start the Job queue?', + identifier: 'system-status-confirm-start-jobqueue', + }) + ) { this.changeIsJobServiceDisabled(); } } private changeIsJobServiceDisabled(): void { - const observer = this.statusService.setStatus(!this.status.IsJobServiceDisabled, this.status.IsDbSchedulerDisabled); - this.subscriptions.push(observer.subscribe(res => { - this.sub.next('foo'); - })); + const observer = this.statusService.setStatus(!!!this.status.IsJobServiceDisabled, !!this.status.IsDbSchedulerDisabled); + this.subscriptions.push( + observer.subscribe((res) => { + this.sub.next('foo'); + }), + ); } private initServerObserver(): void { let statusObserver: Observable; statusObserver = this.sub.pipe(switchMap((term: any) => this.statusService.getStatus())); - this.subscriptions.push(statusObserver.subscribe(res => { - this.status = res as SystemStatusInformation; - })); + this.subscriptions.push( + statusObserver.subscribe((res) => { + this.status = res as SystemStatusInformation; + }), + ); this.sub.next('foo'); - this.refreshTimer = interval(30000).subscribe(x => this.sub.next('foo')); + this.refreshTimer = interval(30000).subscribe((x) => this.sub.next('foo')); } private changeIsDbServiceDisabled(): void { - const observer = this.statusService.setStatus(this.status.IsJobServiceDisabled, !this.status.IsDbSchedulerDisabled); - this.subscriptions.push(observer.subscribe(res => { - this.sub.next('foo'); - })); + const observer = this.statusService.setStatus(!!this.status.IsJobServiceDisabled, !!!this.status.IsDbSchedulerDisabled); + this.subscriptions.push( + observer.subscribe((res) => { + this.sub.next('foo'); + }), + ); } } diff --git a/imxweb/projects/qer-app-operationssupport/src/app/information/system-status/system-status.module.ts b/imxweb/projects/qer-app-operationssupport/src/app/information/system-status/system-status.module.ts index 195471750..c93dd340e 100644 --- a/imxweb/projects/qer-app-operationssupport/src/app/information/system-status/system-status.module.ts +++ b/imxweb/projects/qer-app-operationssupport/src/app/information/system-status/system-status.module.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -34,16 +34,9 @@ import { EuiCoreModule } from '@elemental-ui/core'; import { SystemStatusComponent } from './system-status.component'; import { SystemStatusService } from './system-status.service'; - @NgModule({ declarations: [SystemStatusComponent], - imports: [ - CommonModule, - TranslateModule, - MatButtonModule, - MatCardModule, - EuiCoreModule - ], - providers: [SystemStatusService] + imports: [CommonModule, TranslateModule, MatButtonModule, MatCardModule, EuiCoreModule], + providers: [SystemStatusService], }) -export class SystemStatusModule { } +export class SystemStatusModule {} diff --git a/imxweb/projects/qer-app-operationssupport/src/app/information/system-status/system-status.service.ts b/imxweb/projects/qer-app-operationssupport/src/app/information/system-status/system-status.service.ts index a4135d287..cc09aad4e 100644 --- a/imxweb/projects/qer-app-operationssupport/src/app/information/system-status/system-status.service.ts +++ b/imxweb/projects/qer-app-operationssupport/src/app/information/system-status/system-status.service.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -24,16 +24,19 @@ * */ -import { Observable, from } from 'rxjs'; import { Injectable } from '@angular/core'; +import { Observable, from } from 'rxjs'; import { imx_SessionService } from 'qbm'; -import { SystemStatusInformation } from './system-status-information.interface'; import { OpSupportUserService } from 'qer'; +import { SystemStatusInformation } from './system-status-information.interface'; @Injectable() export class SystemStatusService { - constructor(private session: imx_SessionService, private readonly userService: OpSupportUserService) { } + constructor( + private session: imx_SessionService, + private readonly userService: OpSupportUserService, + ) {} public getStatus(): Observable { return from(this.get()); @@ -50,11 +53,11 @@ export class SystemStatusService { public set(isJobServiceDisabled: boolean, isDbSchedulerDisabled: boolean): Promise { return this.session.Client.opsupport_systemstatus_post('', { IsDbSchedulerDisabled: isDbSchedulerDisabled, - IsJobServiceDisabled: isJobServiceDisabled + IsJobServiceDisabled: isJobServiceDisabled, }); } public async isSystemAdmin(): Promise { - return (await this.userService.getGroups()).some(role => role.Name === 'VID_BaseData_SystemStop_EditRights'); + return (await this.userService.getGroups()).some((role) => role.Name === 'VID_BaseData_SystemStop_EditRights'); } } diff --git a/imxweb/projects/qer-app-operationssupport/src/app/journal/filter-tile-params.ts b/imxweb/projects/qer-app-operationssupport/src/app/journal/filter-tile-params.ts index 65f04c12a..86ea71487 100644 --- a/imxweb/projects/qer-app-operationssupport/src/app/journal/filter-tile-params.ts +++ b/imxweb/projects/qer-app-operationssupport/src/app/journal/filter-tile-params.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -24,7 +24,7 @@ * */ -import { FilterData } from 'imx-qbm-dbts'; +import { FilterData } from '@imx-modules/imx-qbm-dbts'; export class FilterTileParams { public caption: string; diff --git a/imxweb/projects/qer-app-operationssupport/src/app/journal/journal.component.html b/imxweb/projects/qer-app-operationssupport/src/app/journal/journal.component.html index fe9d9e919..3b9dc6198 100644 --- a/imxweb/projects/qer-app-operationssupport/src/app/journal/journal.component.html +++ b/imxweb/projects/qer-app-operationssupport/src/app/journal/journal.component.html @@ -1,34 +1,42 @@
    -

    +

    {{ '#LDS#Heading Database Log' | translate }} -

    +
    - + - - - - - - + + + +
    - + - +
    - - - + + -
    {{data.HostName.Column.GetDisplayValue()}}
    -
    {{data.LogonUser.Column.GetDisplayValue()}}
    +
    {{ data.HostName.Column.GetDisplayValue() }}
    +
    {{ data.LogonUser.Column.GetDisplayValue() }}
    @@ -36,7 +44,7 @@

    - diff --git a/imxweb/projects/qer-app-operationssupport/src/app/journal/journal.component.scss b/imxweb/projects/qer-app-operationssupport/src/app/journal/journal.component.scss index 64dd5ce64..fc29e01ee 100644 --- a/imxweb/projects/qer-app-operationssupport/src/app/journal/journal.component.scss +++ b/imxweb/projects/qer-app-operationssupport/src/app/journal/journal.component.scss @@ -1,4 +1,4 @@ -@import "@elemental-ui/core/src/styles/_palette.scss"; +@import '@elemental-ui/core/src/styles/_palette.scss'; :host { display: flex; @@ -7,18 +7,6 @@ flex-grow: 1; } -.imx-table-container { - flex: 1 1 auto; - display: flex; - flex-direction: column; - overflow: auto; - margin-bottom: -20px; - - > :nth-child(2) { - flex: 1 1 auto; - } -} - .imx-journal-textbox { max-height: 100px; overflow: auto; @@ -42,12 +30,6 @@ .imx-icon-column { margin-right: 20px; - .imx-warning-icon { - color: $corbin-orange; - } - .imx-error-icon { - color: $phoenix-red; - } } div[subtitle] { @@ -76,8 +58,3 @@ div[subtitle] { .mat-column-HostName { max-width: 300px; } - -.imx-refresh-button { - margin-right: 5px; - height: 50px; -} diff --git a/imxweb/projects/qer-app-operationssupport/src/app/journal/journal.component.ts b/imxweb/projects/qer-app-operationssupport/src/app/journal/journal.component.ts index 3eff98259..1f4e2c10b 100644 --- a/imxweb/projects/qer-app-operationssupport/src/app/journal/journal.component.ts +++ b/imxweb/projects/qer-app-operationssupport/src/app/journal/journal.component.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -24,17 +24,17 @@ * */ -import { Component, ViewChildren, QueryList, OnInit } from '@angular/core'; -import { EuiLoadingService } from '@elemental-ui/core'; import { OverlayRef } from '@angular/cdk/overlay'; +import { Component, OnInit, QueryList, ViewChildren } from '@angular/core'; +import { EuiLoadingService } from '@elemental-ui/core'; -import { CollectionLoadParameters, DataModel, DisplayColumns, EntitySchema, IClientProperty } from 'imx-qbm-dbts'; -import { FilterTileComponent, DataSourceToolbarSettings, DataSourceToolbarFilter, SettingsService } from 'qbm'; +import { CollectionLoadParameters, DataModel, DisplayColumns, EntitySchema, IClientProperty } from '@imx-modules/imx-qbm-dbts'; +import { DataSourceToolbarFilter, DataSourceToolbarSettings, FilterTileComponent, SettingsService } from 'qbm'; import { JournalService } from './journal.service'; @Component({ templateUrl: './journal.component.html', - styleUrls: ['./journal.component.scss'] + styleUrls: ['./journal.component.scss'], }) export class JournalComponent implements OnInit { @ViewChildren(FilterTileComponent) public filterTiles: QueryList; @@ -50,14 +50,15 @@ export class JournalComponent implements OnInit { constructor( public journalService: JournalService, private readonly settingsService: SettingsService, - private busyService: EuiLoadingService) { + private busyService: EuiLoadingService, + ) { this.entitySchemaJournal = journalService.OpsupportJournalEntitySchema; this.displayedColumns = [ this.entitySchemaJournal.Columns.MessageDate, this.entitySchemaJournal.Columns.ApplicationName, this.entitySchemaJournal.Columns.MessageString, this.entitySchemaJournal.Columns.MessageType, - this.entitySchemaJournal.Columns.HostName + this.entitySchemaJournal.Columns.HostName, ]; } @@ -78,7 +79,7 @@ export class JournalComponent implements OnInit { this.navigationState = navigationState; let overlayRef: OverlayRef; - setTimeout(() => overlayRef = this.busyService.show()); + setTimeout(() => (overlayRef = this.busyService.show())); try { const journalEntries = await this.journalService.getItems(navigationState); @@ -90,19 +91,17 @@ export class JournalComponent implements OnInit { navigationState: this.navigationState, dataModel: this.dataModel, }; - } finally { setTimeout(() => this.busyService.hide(overlayRef)); } } private async initFilters(): Promise { - let overlayRef: OverlayRef; - setTimeout(() => overlayRef = this.busyService.show()); + setTimeout(() => (overlayRef = this.busyService.show())); try { this.dataModel = await this.journalService.getDataModel(); - this.filterOptions = this.dataModel.Filters; + this.filterOptions = this.dataModel.Filters ?? []; } finally { setTimeout(() => this.busyService.hide(overlayRef)); } diff --git a/imxweb/projects/qer-app-operationssupport/src/app/journal/journal.module.ts b/imxweb/projects/qer-app-operationssupport/src/app/journal/journal.module.ts index beb76b666..a1a2bbc46 100644 --- a/imxweb/projects/qer-app-operationssupport/src/app/journal/journal.module.ts +++ b/imxweb/projects/qer-app-operationssupport/src/app/journal/journal.module.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -45,8 +45,8 @@ import { JournalService } from './journal.service'; EuiCoreModule, MatTooltipModule, MatButtonModule, - TranslateModule + TranslateModule, ], - providers: [JournalService] + providers: [JournalService], }) -export class JournalModule { } +export class JournalModule {} diff --git a/imxweb/projects/qer-app-operationssupport/src/app/journal/journal.service.ts b/imxweb/projects/qer-app-operationssupport/src/app/journal/journal.service.ts index d6a9c7e97..4e48ac553 100644 --- a/imxweb/projects/qer-app-operationssupport/src/app/journal/journal.service.ts +++ b/imxweb/projects/qer-app-operationssupport/src/app/journal/journal.service.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -27,23 +27,20 @@ import { Injectable } from '@angular/core'; import { imx_SessionService } from 'qbm'; -import { OpsupportJournal } from 'imx-api-qbm'; -import { CollectionLoadParameters, DataModel, EntitySchema, ExtendedTypedEntityCollection } from 'imx-qbm-dbts'; +import { OpsupportJournal } from '@imx-modules/imx-api-qbm'; +import { CollectionLoadParameters, DataModel, EntitySchema, ExtendedTypedEntityCollection } from '@imx-modules/imx-qbm-dbts'; @Injectable({ - providedIn: 'root' + providedIn: 'root', }) export class JournalService { - public get OpsupportJournalEntitySchema(): EntitySchema { return this.session.TypedClient.OpsupportJournal.GetSchema(); } - constructor(private session: imx_SessionService) { - } + constructor(private session: imx_SessionService) {} - public async getItems(parameter: CollectionLoadParameters): - Promise> { + public async getItems(parameter: CollectionLoadParameters): Promise> { return this.session.TypedClient.OpsupportJournal.Get(parameter); } diff --git a/imxweb/projects/qer-app-operationssupport/src/app/object-overview/object-overview.component.html b/imxweb/projects/qer-app-operationssupport/src/app/object-overview/object-overview.component.html index 56f497d29..501263815 100644 --- a/imxweb/projects/qer-app-operationssupport/src/app/object-overview/object-overview.component.html +++ b/imxweb/projects/qer-app-operationssupport/src/app/object-overview/object-overview.component.html @@ -1,87 +1,93 @@ - +
    -

    - {{display}} -

    +

    + {{ display }} +

    - {{tableDisplay}} + {{ tableDisplay }}
    - + -
    + + {{ '#LDS#There are currently no tasks for this object in any queues.' | translate }} + +
    + +
    +
    -

    {{ '#LDS#JobQueue' | translate }} -

    +

    {{ '#LDS#JobQueue' | translate }}

    +
    - - - + - - + + - {{dataItem.GetEntity().GetDisplay()}} + {{ dataItem.GetEntity().GetDisplay() }} - + {{ dataItem.Queue.Column.GetDisplayValue() }} - + {{ dataItem.TaskName.Column.GetDisplayValue() }} - - + +
    -
    - {{'#LDS#The queue cannot be displayed for this object type.' | translate}} +
    + {{ '#LDS#The queue cannot be displayed for this object type.' | translate }}
    -
    +
    -

    {{ '#LDS#DBQueue' | translate }}

    +

    {{ '#LDS#DBQueue' | translate }}

    - - - + - - + + - {{dataItem.GetEntity().GetDisplay()}} + {{ dataItem.GetEntity().GetDisplay() }} - + {{ dataItem.Object.Column.GetDisplayValue() }} - + {{ dataItem.SubObject.Column.GetDisplayValue() }} - + {{ dataItem.SortOrder.Column.GetDisplayValue() }} @@ -90,7 +96,7 @@

    {{ '#LDS#DBQueue' | translate }}

    - {{'#LDS#The queue cannot be displayed for this object type.' | translate}} + {{ '#LDS#The queue cannot be displayed for this object type.' | translate }}
    @@ -101,28 +107,14 @@

    {{ '#LDS#DBQueue' | translate }}

    - + + + - + - +
    - - - - - - - - - \ No newline at end of file diff --git a/imxweb/projects/qer-app-operationssupport/src/app/object-overview/object-overview.component.scss b/imxweb/projects/qer-app-operationssupport/src/app/object-overview/object-overview.component.scss index fa45d5136..020f00c1c 100644 --- a/imxweb/projects/qer-app-operationssupport/src/app/object-overview/object-overview.component.scss +++ b/imxweb/projects/qer-app-operationssupport/src/app/object-overview/object-overview.component.scss @@ -1,18 +1,20 @@ -@import "@elemental-ui/core/src/styles/_palette.scss"; -@import "../../../shared/assets/variables.scss"; +@import '@elemental-ui/core/src/styles/_palette.scss'; +@import 'base/variables'; +@import 'base/mixins'; :host { - display: flex; - flex-direction: column; - overflow: hidden; - height: 100%; + @include flex-column-container-fill(); +} +.imx-flex{ + .mat-headline-5{ + margin: 0; + } } .sub-headline { font-style: italic; font-weight: lighter; - margin-top: -2em; - margin-bottom: .5em; + margin-bottom: 0.5em; @media #{$IMX_Mediaquery_Smartphone} { margin-top: -0.5em; @@ -22,19 +24,8 @@ } } -:host ::ng-deep .mat-tab-body { - margin: 30px 0px; - - .mat-tab-body-content { - display: flex; - flex-direction: column; - } -} - .imx-job-queue-div { border-bottom: 1px solid $black-3; - padding-bottom: 30px; - margin-bottom: 30px; } .imx-object-overview-tab-text { @@ -49,31 +40,6 @@ .imx-object-overview-tab-text { font-size: medium; } - -:host ::ng-deep .mat-tab-body-wrapper { - position: relative; - overflow: hidden; - display: flex; - flex: 1; -} - -:host ::ng-deep .mat-tab-body { - margin: 30px 0px 0px 0px; -} - -:host ::ng-deep .mat-tab-body.mat-tab-body-active { - overflow-x: auto; +.imx-content-header, eui-alert{ + margin-top: 24px; } - -.imx-table-container { - margin-right: 30px; - max-height: 500px; - overflow: hidden; - display: flex; - flex-direction: column; -} - -.imx-refresh-button { - margin-right: 5px; - height: 50px; -} \ No newline at end of file diff --git a/imxweb/projects/qer-app-operationssupport/src/app/object-overview/object-overview.component.ts b/imxweb/projects/qer-app-operationssupport/src/app/object-overview/object-overview.component.ts index 26162af6d..3efd4f7d8 100644 --- a/imxweb/projects/qer-app-operationssupport/src/app/object-overview/object-overview.component.ts +++ b/imxweb/projects/qer-app-operationssupport/src/app/object-overview/object-overview.component.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -24,35 +24,35 @@ * */ -import { Component, OnInit, ErrorHandler, AfterViewInit } from '@angular/core'; +import { AfterViewInit, Component, ErrorHandler, OnInit } from '@angular/core'; import { ActivatedRoute, Router } from '@angular/router'; import { TranslateService } from '@ngx-translate/core'; -import { DbObjectKey, DisplayColumns, EntitySchema, IClientProperty, ReadOnlyEntity, ValType } from 'imx-qbm-dbts'; -import { QueueEntriesData, ShapeData } from 'imx-api-qbm'; +import { EuiSidesheetService } from '@elemental-ui/core'; +import { QueueEntriesData, ShapeData } from '@imx-modules/imx-api-qbm'; +import { DbObjectKey, DisplayColumns, EntitySchema, IClientProperty, ReadOnlyEntity, ValType } from '@imx-modules/imx-qbm-dbts'; import { + AuthenticationService, + ClassloggerService, + ClientPropertyForTableColumns, + DataSourceToolbarSettings, MetadataService, OpsupportDbObjectService, ShapeClickArgs, - ClassloggerService, - DataSourceToolbarSettings, - AuthenticationService, - ClientPropertyForTableColumns + calculateSidesheetWidth, } from 'qbm'; +import { FeatureConfigService, ObjectOverviewContainer } from 'qer'; +import { ErrorMessageSidesheetComponent } from '../processes/error-message-sidesheet/error-message-sidesheet.component'; import { QueueJobsService } from '../processes/jobs/queue-jobs.service'; -import { ObjectOverviewContainer, FeatureConfigService } from 'qer'; import { ObjectOverviewService } from './object-overview.service'; import { PersonDbQueueInfo } from './person-db-queue-info'; import { PersonJobQueueInfo } from './person-job-queue-info'; -import { ErrorMessageSidesheetComponent } from '../processes/error-message-sidesheet/error-message-sidesheet.component'; -import { EuiSidesheetService } from '@elemental-ui/core'; @Component({ templateUrl: './object-overview.component.html', - styleUrls: ['./object-overview.component.scss'] + styleUrls: ['./object-overview.component.scss'], }) export class ObjectOverviewComponent implements OnInit, AfterViewInit, ObjectOverviewContainer { - public hyperviewShapes: ShapeData[] = []; public DisplayColumns = DisplayColumns; @@ -94,7 +94,6 @@ export class ObjectOverviewComponent implements OnInit, AfterViewInit, ObjectOve private featureService: FeatureConfigService, authentication: AuthenticationService, ) { - this.entitySchemaDbs = PersonDbQueueInfo.GetEntitySchema(); this.entitySchemaJobs = PersonJobQueueInfo.GetEntitySchema(); @@ -105,8 +104,8 @@ export class ObjectOverviewComponent implements OnInit, AfterViewInit, ObjectOve { ColumnName: 'actions', Type: ValType.String, - afterAdditionals: true - } + afterAdditionals: true, + }, ]; this.displayedColumnsDbs = [ @@ -116,7 +115,7 @@ export class ObjectOverviewComponent implements OnInit, AfterViewInit, ObjectOve this.entitySchemaDbs.Columns.SortOrder, ]; - authentication.onSessionResponse.subscribe(session => this.uidUser = session.UserUid); + authentication.onSessionResponse.subscribe((session) => (this.uidUser = session.UserUid ?? '')); } public busy = true; @@ -127,18 +126,17 @@ export class ObjectOverviewComponent implements OnInit, AfterViewInit, ObjectOve public tabIndex = 0; public async ngOnInit(): Promise { - - this.route.params.subscribe(res => { - // reinitialize if params changes - if (this.objectUID !== res.uid) { + this.route.params.subscribe((res) => { + // reinitialize if params changes + if (this.objectUID !== res.uid) { this.init(); if (this.hasHyperviewParam(res.tab)) { this.tabIndex = 3; } - } - }) + } + }); - this.init(); + this.init(); } public async ngAfterViewInit(): Promise { @@ -148,16 +146,16 @@ export class ObjectOverviewComponent implements OnInit, AfterViewInit, ObjectOve } } - /** + /** * Handles the event, when a shape was clicked. * @param args the {@link ShapeClickArgs|arguments of the clicked shape} */ - public async onShapeClick(args: ShapeClickArgs): Promise { - const objKey = DbObjectKey.FromXml(args.objectKey); - if (await this.objectIsSupported(objKey)) { - this.router.navigate(['object', objKey.TableName, objKey.Keys[0], 'hyperview']); - } + public async onShapeClick(args: ShapeClickArgs): Promise { + const objKey = DbObjectKey.FromXml(args.objectKey); + if (await this.objectIsSupported(objKey)) { + this.router.navigate(['object', objKey.TableName, objKey.Keys[0], 'hyperview']); } + } // Checks if the item has an ErrorMessage or not public hasContent(item: PersonJobQueueInfo): boolean { @@ -173,19 +171,18 @@ export class ObjectOverviewComponent implements OnInit, AfterViewInit, ObjectOve public reactivate(item: PersonJobQueueInfo): void { this.jobService .Post([item.UID_Job.value]) - .then((_: any) => this.loadQueue('jobQueue')) + .then((_: any) => this.loadQueue()) .catch((err: any) => this.errorHandler.handleError(err)); } // Shows the error message for a JobQueueInfo object public async showMessage(item: PersonJobQueueInfo): Promise { - - await this.sidesheet + await this.sidesheet .open(ErrorMessageSidesheetComponent, { title: await this.translationProvider.get('#LDS#Heading View Error Message').toPromise(), subTitle: item.GetEntity().GetDisplay(), padding: '0', - width: 'max(60%,600px)', + width: calculateSidesheetWidth(), testId: 'error-message-sidesheet', data: item.ErrorMessages.Column.GetDisplayValue(), }) @@ -202,50 +199,55 @@ export class ObjectOverviewComponent implements OnInit, AfterViewInit, ObjectOve this.logger.error(this, 'selection trigged for: ' + ev.objectKey); } - public async loadQueue(updateType: 'both' | 'jobQueue' | 'dbQueue' = 'both'): Promise { + public async loadQueue(): Promise { const cached = await this.objectIsSupported(this.objectKey); - if (this.queuesUnsupported) { + if (this.queuesUnsupported || !cached) { return; } - if (updateType === 'both' || updateType === 'jobQueue') { - const job = cached.JobQueue.map(entityData => - new PersonJobQueueInfo((new ReadOnlyEntity(PersonJobQueueInfo.GetEntitySchema(), entityData)))); + if (cached.JobQueue) { + const job = cached.JobQueue.map( + (entityData) => new PersonJobQueueInfo(new ReadOnlyEntity(PersonJobQueueInfo.GetEntitySchema(), entityData)), + ); this.jobTotal = job.length; this.dstSettingsJobs = { displayedColumns: this.displayedColumnsJobs, - dataSource: { Data: job, totalCount: job.length }, + dataSource: { Data: job, totalCount: this.jobTotal }, entitySchema: this.entitySchemaJobs, - navigationState: {} + navigationState: {}, }; } - if (updateType === 'both' || updateType === 'dbQueue') { - const db = cached.DbQueue.map(entityData => - new PersonDbQueueInfo((new ReadOnlyEntity(PersonDbQueueInfo.GetEntitySchema(), entityData)))); + if (cached.DbQueue) { + const db = cached.DbQueue.map( + (entityData) => new PersonDbQueueInfo(new ReadOnlyEntity(PersonDbQueueInfo.GetEntitySchema(), entityData)), + ); this.dbTotal = db.length; this.dstSettingsDb = { displayedColumns: this.displayedColumnsDbs, - dataSource: { Data: db, totalCount: db.length }, + dataSource: { Data: db, totalCount: this.dbTotal }, entitySchema: this.entitySchemaDbs, - navigationState: {} + navigationState: {}, }; } } + public get hideQueueTables(): boolean { + return this.jobTotal === 0 && this.dbTotal === 0; + } + private async init(): Promise { this.hyperviewShapes = []; this.busy = true; try { await this.initDataFromPath(this.route); const featureConfig = await this.featureService.getFeatureConfig(); - this.showPassCodeTab = featureConfig.EnableSetPasswords - && this.objectKey.TableName.toLowerCase() === this.tablePerson - && this.uidUser !== this.objectUID; + this.showPassCodeTab = + featureConfig.EnableSetPasswords && this.objectKey.TableName.toLowerCase() === this.tablePerson && this.uidUser !== this.objectUID; await this.loadQueue(); } finally { this.busy = false; @@ -255,9 +257,9 @@ export class ObjectOverviewComponent implements OnInit, AfterViewInit, ObjectOve /** * Check if the given object is supported. * @param objKey {@link DbObjectKey} that needs to check. - * @returns + * @returns */ - private async objectIsSupported(objKey: DbObjectKey): Promise { + private async objectIsSupported(objKey: DbObjectKey): Promise { const cached = await this.overviewService.get(objKey); this.queuesUnsupported = cached.Unsupported; @@ -273,24 +275,22 @@ export class ObjectOverviewComponent implements OnInit, AfterViewInit, ObjectOve * @param param route param to check * @returns true, if it's the hyperview-param */ - private hasHyperviewParam(param: string): boolean { + private hasHyperviewParam(param: string | null): boolean { return param === 'hyperview'; } - // initializes the variables provided by the route private async initDataFromPath(route: ActivatedRoute): Promise { const snapShotMap = route.snapshot.paramMap; - this.tablename = snapShotMap.get('table'); - this.objectUID = snapShotMap.get('uid'); + this.tablename = snapShotMap.get('table') ?? ''; + this.objectUID = snapShotMap.get('uid') ?? ''; this.objectKey = new DbObjectKey(this.tablename, this.objectUID); const metadata = await this.metadataService.GetTableMetadata(this.tablename); this.tableDisplay = metadata.DisplaySingular; const entity = await this.dbObjectService.Get({ tableName: this.tablename, uid: this.objectUID }); - this.display = entity.Display; + this.display = entity.Display ?? ''; } - } diff --git a/imxweb/projects/qer-app-operationssupport/src/app/object-overview/object-overview.module.ts b/imxweb/projects/qer-app-operationssupport/src/app/object-overview/object-overview.module.ts index b3f36c2aa..fdb2763da 100644 --- a/imxweb/projects/qer-app-operationssupport/src/app/object-overview/object-overview.module.ts +++ b/imxweb/projects/qer-app-operationssupport/src/app/object-overview/object-overview.module.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -44,30 +44,27 @@ import { ObjectHistoryModule, ObjectHistoryApiService, QbmModule, + BusyIndicatorModule, } from 'qbm'; import { ObjectHyperviewModule, ObjectHyperviewService, OpsModule } from 'qer'; import { ObjectOverviewComponent } from './object-overview.component'; import { ObjectOverviewService } from './object-overview.service'; import { OpSupportHistoryApiService } from './opsupport-history-api.service'; -import { MatProgressSpinnerModule } from '@angular/material/progress-spinner'; import { OpsHyperviewService } from '../hyperview/ops-hyperview.service'; - @NgModule({ - declarations: [ - ObjectOverviewComponent, - ], + declarations: [ObjectOverviewComponent], imports: [ CommonModule, ObjectHistoryModule, DataTableModule, DataSourceToolbarModule, + BusyIndicatorModule, EuiCoreModule, FormsModule, MatTabsModule, MatButtonModule, MatCardModule, - MatProgressSpinnerModule, MatTooltipModule, MatFormFieldModule, MatSelectModule, @@ -77,18 +74,18 @@ import { OpsHyperviewService } from '../hyperview/ops-hyperview.service'; MatTableModule, MatPaginatorModule, OpsModule, - QbmModule + QbmModule, ], providers: [ { provide: ObjectHistoryApiService, - useClass: OpSupportHistoryApiService - }, + useClass: OpSupportHistoryApiService, + }, { provide: ObjectHyperviewService, - useClass: OpsHyperviewService - }, - ObjectOverviewService - ] + useClass: OpsHyperviewService, + }, + ObjectOverviewService, + ], }) -export class ObjectOverviewModule { } +export class ObjectOverviewModule {} diff --git a/imxweb/projects/qer-app-operationssupport/src/app/object-overview/object-overview.service.ts b/imxweb/projects/qer-app-operationssupport/src/app/object-overview/object-overview.service.ts index abf37dd04..023f1891e 100644 --- a/imxweb/projects/qer-app-operationssupport/src/app/object-overview/object-overview.service.ts +++ b/imxweb/projects/qer-app-operationssupport/src/app/object-overview/object-overview.service.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -25,8 +25,8 @@ */ import { Injectable } from '@angular/core'; -import { QueueEntriesData } from 'imx-api-qbm'; -import { DbObjectKey, EntitySchema } from 'imx-qbm-dbts'; +import { QueueEntriesData } from '@imx-modules/imx-api-qbm'; +import { DbObjectKey, EntitySchema } from '@imx-modules/imx-qbm-dbts'; import { imx_SessionService } from 'qbm'; @Injectable() @@ -35,10 +35,9 @@ export class ObjectOverviewService { return this.session.TypedClient.OpsupportQueueJobs.GetSchema(); } - constructor(private session: imx_SessionService) { } + constructor(private session: imx_SessionService) {} public get(objectKey: DbObjectKey): Promise { return this.session.Client.opsupport_queue_object_get(objectKey.TableName, objectKey.Keys[0]); } - } diff --git a/imxweb/projects/qer-app-operationssupport/src/app/object-overview/opsupport-history-api.service.ts b/imxweb/projects/qer-app-operationssupport/src/app/object-overview/opsupport-history-api.service.ts index 49727d884..8cd1129c5 100644 --- a/imxweb/projects/qer-app-operationssupport/src/app/object-overview/opsupport-history-api.service.ts +++ b/imxweb/projects/qer-app-operationssupport/src/app/object-overview/opsupport-history-api.service.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -25,20 +25,19 @@ */ import { Injectable } from '@angular/core'; -import { HistoryData } from 'imx-qbm-dbts'; -import { HistoryComparisonData } from 'imx-api-qbm'; +import { HistoryData } from '@imx-modules/imx-qbm-dbts'; +import { HistoryComparisonData } from '@imx-modules/imx-api-qbm'; import { ObjectHistoryApiService, imx_SessionService } from 'qbm'; @Injectable() export class OpSupportHistoryApiService implements ObjectHistoryApiService { - - constructor(private readonly session: imx_SessionService) { } + constructor(private readonly session: imx_SessionService) {} getHistoryData(table: string, uid: string): Promise { return this.session.Client.opsupport_history_get(table, uid); } - getHistoryComparisonData(table: string, uid: string,options?: {CompareDate?: Date;}): Promise { + getHistoryComparisonData(table: string, uid: string, options?: { CompareDate?: Date }): Promise { return this.session.Client.opsupport_history_comparison_get(table, uid, options); } -} \ No newline at end of file +} diff --git a/imxweb/projects/qer-app-operationssupport/src/app/object-overview/person-db-queue-info.ts b/imxweb/projects/qer-app-operationssupport/src/app/object-overview/person-db-queue-info.ts index af606bb8b..9f6be2728 100644 --- a/imxweb/projects/qer-app-operationssupport/src/app/object-overview/person-db-queue-info.ts +++ b/imxweb/projects/qer-app-operationssupport/src/app/object-overview/person-db-queue-info.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -24,7 +24,7 @@ * */ -import { DisplayColumns, EntitySchema, IReadValue, TypedEntity, ValType } from 'imx-qbm-dbts'; +import { DisplayColumns, EntitySchema, IReadValue, TypedEntity, ValType } from '@imx-modules/imx-qbm-dbts'; export class PersonDbQueueInfo extends TypedEntity { public readonly Object: IReadValue = this.GetEntityValue('Object'); @@ -42,11 +42,11 @@ export class PersonDbQueueInfo extends TypedEntity { Type: ValType.String, IsReadOnly: true, }, - SortOrder: { + SortOrder: { ColumnName: 'SortOrder', Type: ValType.String, IsReadOnly: true, - } + }, }; columns[DisplayColumns.DISPLAY_PROPERTYNAME] = DisplayColumns.DISPLAY_PROPERTY; columns[DisplayColumns.DISPLAY_LONG_PROPERTYNAME] = DisplayColumns.DISPLAY_PROPERTY_LONG; diff --git a/imxweb/projects/qer-app-operationssupport/src/app/object-overview/person-job-queue-info.ts b/imxweb/projects/qer-app-operationssupport/src/app/object-overview/person-job-queue-info.ts index 509a8e590..40922a6d8 100644 --- a/imxweb/projects/qer-app-operationssupport/src/app/object-overview/person-job-queue-info.ts +++ b/imxweb/projects/qer-app-operationssupport/src/app/object-overview/person-job-queue-info.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -24,7 +24,7 @@ * */ -import { DisplayColumns, EntitySchema, IReadValue, TypedEntity, ValType } from 'imx-qbm-dbts'; +import { DisplayColumns, EntitySchema, IReadValue, TypedEntity, ValType } from '@imx-modules/imx-qbm-dbts'; export class PersonJobQueueInfo extends TypedEntity { public readonly Queue: IReadValue = this.GetEntityValue('Queue'); @@ -58,8 +58,7 @@ export class PersonJobQueueInfo extends TypedEntity { ColumnName: 'ErrorMessages', Type: ValType.String, IsReadOnly: true, - } - + }, }; columns[DisplayColumns.DISPLAY_PROPERTYNAME] = DisplayColumns.DISPLAY_PROPERTY; columns[DisplayColumns.DISPLAY_LONG_PROPERTYNAME] = DisplayColumns.DISPLAY_PROPERTY_LONG; diff --git a/imxweb/projects/qer-app-operationssupport/src/app/object-search/object-search.component.ts b/imxweb/projects/qer-app-operationssupport/src/app/object-search/object-search.component.ts index d5de3c63c..c487c154d 100644 --- a/imxweb/projects/qer-app-operationssupport/src/app/object-search/object-search.component.ts +++ b/imxweb/projects/qer-app-operationssupport/src/app/object-search/object-search.component.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -26,12 +26,12 @@ import { Component } from '@angular/core'; import { Router } from '@angular/router'; -import { imx_QBM_SearchService, MetadataService, DbObjectInfo } from 'qbm'; +import { DbObjectInfo, imx_QBM_SearchService, MetadataService } from 'qbm'; @Component({ selector: 'imx-object-search', templateUrl: './object-search.component.html', - styleUrls: ['./object-search.component.scss'] + styleUrls: ['./object-search.component.scss'], }) export class ObjectSearchComponent { public get SearchService(): imx_QBM_SearchService { @@ -45,14 +45,21 @@ export class ObjectSearchComponent { constructor( private objectSearchService: imx_QBM_SearchService, private router: Router, - private metadataService: MetadataService) { } + private metadataService: MetadataService, + ) {} public itemSelected(event: any): void { const dataItem = event as DbObjectInfo; - this.router.navigate([`/object/${dataItem.Key.TableName}/${dataItem.Key.Keys[0]}`]); + if (dataItem.Key?.TableName && dataItem.Key?.Keys?.[0]) { + this.router.navigate([`/object/${dataItem.Key.TableName}/${dataItem.Key.Keys[0]}`]); + } else { + throw Error('DataItem has missing properties - cannot navigate.'); + } } public async setCurrentItem(dataItem: DbObjectInfo): Promise { - this.currentMetadataItem = await this.MetadataService.GetTableMetadata(dataItem.Key.TableName); + if (dataItem.Key?.TableName) { + this.currentMetadataItem = await this.MetadataService.GetTableMetadata(dataItem.Key.TableName); + } } } diff --git a/imxweb/projects/qer-app-operationssupport/src/app/object-search/object-search.module.ts b/imxweb/projects/qer-app-operationssupport/src/app/object-search/object-search.module.ts index d0714ced7..8b6ae4356 100644 --- a/imxweb/projects/qer-app-operationssupport/src/app/object-search/object-search.module.ts +++ b/imxweb/projects/qer-app-operationssupport/src/app/object-search/object-search.module.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -32,15 +32,9 @@ import { TranslateModule } from '@ngx-translate/core'; import { QbmModule } from 'qbm'; import { ObjectSearchComponent } from './object-search.component'; - @NgModule({ declarations: [ObjectSearchComponent], - imports: [ - CommonModule, - QbmModule, - MatTooltipModule, - TranslateModule - ], - exports: [ObjectSearchComponent] + imports: [CommonModule, QbmModule, MatTooltipModule, TranslateModule], + exports: [ObjectSearchComponent], }) -export class ObjectSearchModule { } +export class ObjectSearchModule {} diff --git a/imxweb/projects/qer-app-operationssupport/src/app/permissions/permissions-helper.ts b/imxweb/projects/qer-app-operationssupport/src/app/permissions/permissions-helper.ts index ffc69651f..ca2ee71fd 100644 --- a/imxweb/projects/qer-app-operationssupport/src/app/permissions/permissions-helper.ts +++ b/imxweb/projects/qer-app-operationssupport/src/app/permissions/permissions-helper.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -24,6 +24,6 @@ * */ -export function isOutstandingManager(groups: string[]): boolean { - return groups.find(item => item === 'QER_4_ManageOutstanding') != null; +export function isOutstandingManager(groups: (string | undefined)[]): boolean { + return groups.find((item) => item === 'QER_4_ManageOutstanding') != null; } diff --git a/imxweb/projects/qer-app-operationssupport/src/app/permissions/permissions.service.spec.ts b/imxweb/projects/qer-app-operationssupport/src/app/permissions/permissions.service.spec.ts index 2a55dae6e..0a9fd2317 100644 --- a/imxweb/projects/qer-app-operationssupport/src/app/permissions/permissions.service.spec.ts +++ b/imxweb/projects/qer-app-operationssupport/src/app/permissions/permissions.service.spec.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -43,9 +43,9 @@ describe('PermissionsService', () => { .mock(OpSupportUserService, { getGroups: jasmine.createSpy('userGroups').and.callFake(() => userGroups), }) - .beforeCompileComponents(testBed => { + .beforeCompileComponents((testBed) => { testBed.configureTestingModule({ - schemas: [CUSTOM_ELEMENTS_SCHEMA] + schemas: [CUSTOM_ELEMENTS_SCHEMA], }); }); }); @@ -66,5 +66,5 @@ describe('PermissionsService', () => { expect(await service.isOutstandingManager()).toEqual(testcase.canSee); }); - }; + } }); diff --git a/imxweb/projects/qer-app-operationssupport/src/app/permissions/permissions.service.ts b/imxweb/projects/qer-app-operationssupport/src/app/permissions/permissions.service.ts index b373db69d..7ddf783b7 100644 --- a/imxweb/projects/qer-app-operationssupport/src/app/permissions/permissions.service.ts +++ b/imxweb/projects/qer-app-operationssupport/src/app/permissions/permissions.service.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -30,12 +30,12 @@ import { OpSupportUserService } from 'qer'; import { isOutstandingManager } from './permissions-helper'; @Injectable({ - providedIn: 'root' + providedIn: 'root', }) export class PermissionsService { - constructor(private readonly userService: OpSupportUserService) { } + constructor(private readonly userService: OpSupportUserService) {} public async isOutstandingManager(): Promise { - return isOutstandingManager((await this.userService.getGroups()).map(group => group.Name)); + return isOutstandingManager((await this.userService.getGroups()).map((group) => group.Name)); } } diff --git a/imxweb/projects/qer-app-operationssupport/src/app/processes/error-message-sidesheet/error-message-sidesheet.component.html b/imxweb/projects/qer-app-operationssupport/src/app/processes/error-message-sidesheet/error-message-sidesheet.component.html index 7da1f9b6e..f9261d618 100644 --- a/imxweb/projects/qer-app-operationssupport/src/app/processes/error-message-sidesheet/error-message-sidesheet.component.html +++ b/imxweb/projects/qer-app-operationssupport/src/app/processes/error-message-sidesheet/error-message-sidesheet.component.html @@ -6,12 +6,7 @@
    -
    diff --git a/imxweb/projects/qer-app-operationssupport/src/app/processes/error-message-sidesheet/error-message-sidesheet.component.scss b/imxweb/projects/qer-app-operationssupport/src/app/processes/error-message-sidesheet/error-message-sidesheet.component.scss index 669fb287f..dbb33d096 100644 --- a/imxweb/projects/qer-app-operationssupport/src/app/processes/error-message-sidesheet/error-message-sidesheet.component.scss +++ b/imxweb/projects/qer-app-operationssupport/src/app/processes/error-message-sidesheet/error-message-sidesheet.component.scss @@ -1,7 +1,4 @@ -.eui-sidesheet-content { - flex-direction: column; - display: flex; -} +@import 'base/mixins'; .imx-text-container { overflow: auto; @@ -9,13 +6,11 @@ margin-bottom: 10px; } -.mat-card{ - display: flex; - flex-direction: column; +.mat-mdc-card { + @include flex-column-container($max-height: 100%); flex: 1 1 auto; - max-height: 100%; - .mat-card-content{ - overflow: auto; + .mat-mdc-card-content { + overflow: auto; } } diff --git a/imxweb/projects/qer-app-operationssupport/src/app/processes/error-message-sidesheet/error-message-sidesheet.component.ts b/imxweb/projects/qer-app-operationssupport/src/app/processes/error-message-sidesheet/error-message-sidesheet.component.ts index d2559c173..fff5b215d 100644 --- a/imxweb/projects/qer-app-operationssupport/src/app/processes/error-message-sidesheet/error-message-sidesheet.component.ts +++ b/imxweb/projects/qer-app-operationssupport/src/app/processes/error-message-sidesheet/error-message-sidesheet.component.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -40,14 +40,14 @@ export class ErrorMessageSidesheetComponent implements OnInit { @Inject(EUI_SIDESHEET_DATA) public readonly data: string, private sidesheetRef: EuiSidesheetRef, private clipboard: Clipboard, - private readonly snackbar: SnackBarService + private readonly snackbar: SnackBarService, ) {} public ngOnInit(): void {} public copyToClipboard(): void { this.clipboard.copy(this.data); - this.snackbar.open({ key: '#LDS#The error message has been successfully copied to the clipboard.'}); + this.snackbar.open({ key: '#LDS#The error message has been successfully copied to the clipboard.' }); this.sidesheetRef.close(); } } diff --git a/imxweb/projects/qer-app-operationssupport/src/app/processes/frozen-jobs/frozen-jobs.component.html b/imxweb/projects/qer-app-operationssupport/src/app/processes/frozen-jobs/frozen-jobs.component.html index 21f0b1cc8..40de002e9 100644 --- a/imxweb/projects/qer-app-operationssupport/src/app/processes/frozen-jobs/frozen-jobs.component.html +++ b/imxweb/projects/qer-app-operationssupport/src/app/processes/frozen-jobs/frozen-jobs.component.html @@ -1,45 +1,46 @@ -

    - {{'#LDS#Frozen process steps' | translate}} "{{queueName}}" ({{jobCount}}) -

    +

    {{ '#LDS#Frozen process steps' | translate }} "{{ queueName }}" ({{ jobCount }})

    - + - - + +
    {{ dataItem.JobChainName.Column.GetDisplayValue() }}
    - + {{ dataItem.TaskName.Column.GetDisplayValue() }} - - + +
    -
    +
    - + -
    - - diff --git a/imxweb/projects/qer-app-operationssupport/src/app/processes/frozen-jobs/frozen-jobs.component.scss b/imxweb/projects/qer-app-operationssupport/src/app/processes/frozen-jobs/frozen-jobs.component.scss index 71c8c43e8..171a2ee12 100644 --- a/imxweb/projects/qer-app-operationssupport/src/app/processes/frozen-jobs/frozen-jobs.component.scss +++ b/imxweb/projects/qer-app-operationssupport/src/app/processes/frozen-jobs/frozen-jobs.component.scss @@ -1,45 +1,6 @@ -@import "@elemental-ui/core/src/styles/_palette.scss"; - :host { display: flex; flex-direction: column; overflow: hidden; flex-grow: 1; } - -.imx-table-container { - flex: 1 1 auto; - height: calc(100% - 50px); - display: flex; - flex-direction: column; - - > :nth-child(2) { - flex: 1 1 auto; - } -} - -.imx-button-bar { - display: flex; - justify-content: flex-end; - margin-top: -10px; - - > * { - margin-left: 5px; - } -} - -.imx-refresh-button { - margin-right: 5px; - height: 50px; -} - -.mat-raised-button.rightButtonFloat { - clear: both; - width: auto; - float: right; - position: absolute; - right: 0; - padding: 0 20px; - background-color: $iris-blue; - color: $white; -} diff --git a/imxweb/projects/qer-app-operationssupport/src/app/processes/frozen-jobs/frozen-jobs.component.ts b/imxweb/projects/qer-app-operationssupport/src/app/processes/frozen-jobs/frozen-jobs.component.ts index d9bbfac9f..13b6e2bf2 100644 --- a/imxweb/projects/qer-app-operationssupport/src/app/processes/frozen-jobs/frozen-jobs.component.ts +++ b/imxweb/projects/qer-app-operationssupport/src/app/processes/frozen-jobs/frozen-jobs.component.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -24,23 +24,23 @@ * */ +import { OverlayRef } from '@angular/cdk/overlay'; import { Component, OnInit } from '@angular/core'; -import { ActivatedRoute } from '@angular/router'; import { MatDialog } from '@angular/material/dialog'; -import { OverlayRef } from '@angular/cdk/overlay'; +import { ActivatedRoute } from '@angular/router'; import { EuiLoadingService, EuiSidesheetConfig, EuiSidesheetService } from '@elemental-ui/core'; import { TranslateService } from '@ngx-translate/core'; -import { OpsupportQueueFrozenjobs } from 'imx-api-qbm'; +import { OpsupportQueueFrozenjobs } from '@imx-modules/imx-api-qbm'; +import { CollectionLoadParameters, DisplayColumns, EntitySchema, IClientProperty, TypedEntity, ValType } from '@imx-modules/imx-qbm-dbts'; +import { calculateSidesheetWidth, DataSourceToolbarSettings, MessageDialogComponent, SettingsService, SnackBarService } from 'qbm'; import { QueueJobsService } from '../jobs/queue-jobs.service'; -import { FrozenJobsService, JobQueueParameters } from './frozen-jobs.service'; -import { SnackBarService, MessageDialogComponent, DataSourceToolbarSettings, SettingsService } from 'qbm'; -import { CollectionLoadParameters, DisplayColumns, EntitySchema, IClientProperty, ValType } from 'imx-qbm-dbts'; +import { FrozenJobsService } from './frozen-jobs.service'; import { SingleFrozenJobComponent } from './single-frozen-job.component'; @Component({ templateUrl: './frozen-jobs.component.html', - styleUrls: ['./frozen-jobs.component.scss'] + styleUrls: ['./frozen-jobs.component.scss'], }) export class FrozenJobsComponent implements OnInit { public queueName = ''; @@ -64,7 +64,7 @@ export class FrozenJobsComponent implements OnInit { private busyService: EuiLoadingService, private frozenJobs: FrozenJobsService, private settingsService: SettingsService, - private translator: TranslateService + private translator: TranslateService, ) { this.entitySchemaFrozenJobs = frozenJobs.EntitySchema; this.displayedColumns = [ @@ -72,13 +72,13 @@ export class FrozenJobsComponent implements OnInit { this.entitySchemaFrozenJobs.Columns.TaskName, { ColumnName: 'actions', - Type: ValType.String - } + Type: ValType.String, + }, ]; } public async ngOnInit(): Promise { - this.queueName = this.route.snapshot.paramMap.get('queueName'); + this.queueName = this.route.snapshot.paramMap.get('queueName') ?? ''; await this.getData({ StartIndex: 0, PageSize: this.settingsService.DefaultPageSize, queueName: this.queueName }); } @@ -86,10 +86,9 @@ export class FrozenJobsComponent implements OnInit { return this.getData({ StartIndex: 0, search: keywords, queueName: this.queueName }); } - public async reactivate(item: OpsupportQueueFrozenjobs): Promise { let overlayRef: OverlayRef; - setTimeout(() => overlayRef = this.busyService.show()); + setTimeout(() => (overlayRef = this.busyService.show())); try { await this.jobService.Post([item.UID_Job.value]); this.snackbarService.open({ key: '#LDS#Process "{0}" is retrying.', parameters: [item.JobChainName.value] }); @@ -99,8 +98,8 @@ export class FrozenJobsComponent implements OnInit { } } - public onSelectionChanged(jobs: OpsupportQueueFrozenjobs[]): void { - this.selectedJobs = jobs; + public onSelectionChanged(jobs: TypedEntity[]): void { + this.selectedJobs = jobs as OpsupportQueueFrozenjobs[]; } public async viewDetails(job: OpsupportQueueFrozenjobs): Promise { @@ -108,17 +107,21 @@ export class FrozenJobsComponent implements OnInit { const opts: EuiSidesheetConfig = { title: await this.translator.get('#LDS#Heading View Process Details').toPromise(), subTitle: job.JobChainName.Column.GetDisplayValue(), - width: 'max(1000px, 80%)', + width: calculateSidesheetWidth(1100, 0.7), icon: 'reboot', testId: 'frozen-jobs-process-details-sidesheet', data: { UID_Tree: job.UID_Tree.value, - load: (startId:string) => {return this.jobService.getTreeData(startId)} + load: (startId: string) => { + return this.jobService.getTreeData(startId); + }, }, }; - this.sideSheet.open(SingleFrozenJobComponent, opts) + this.sideSheet + .open(SingleFrozenJobComponent, opts) // After the sidesheet closes, reload the current data to refresh any changes that might have been made - .afterClosed().subscribe(() => this.refresh()); + .afterClosed() + .subscribe(() => this.refresh()); } public async showMessage(item: OpsupportQueueFrozenjobs): Promise { @@ -126,9 +129,9 @@ export class FrozenJobsComponent implements OnInit { data: { ShowOk: true, Title: await this.translator.get('#LDS#Error message').toPromise(), - Message: item.ErrorMessages.Column.GetDisplayValue() + Message: item.ErrorMessages.Column.GetDisplayValue(), }, - panelClass: 'imx-messageDialog' + panelClass: 'imx-messageDialog', }); } @@ -139,7 +142,7 @@ export class FrozenJobsComponent implements OnInit { public async reactivateSelected(): Promise { if (this.selectedJobs.length > 0) { let overlayRef: OverlayRef; - setTimeout(() => overlayRef = this.busyService.show()); + setTimeout(() => (overlayRef = this.busyService.show())); try { await this.jobService.Post(this.selectedJobs.map((job: OpsupportQueueFrozenjobs) => job.UID_Job.value)); this.snackbarService.open({ key: '#LDS#{0} processes are retrying.', parameters: [this.selectedJobs.length] }); @@ -155,23 +158,21 @@ export class FrozenJobsComponent implements OnInit { await this.getData({ StartIndex: 0, PageSize: this.settingsService.DefaultPageSize, queueName: this.queueName }); } - public async getData(navigationState: JobQueueParameters): Promise { + public async getData(navigationState: CollectionLoadParameters): Promise { this.navigationState = navigationState; let overlayRef: OverlayRef; - setTimeout(() => overlayRef = this.busyService.show()); + setTimeout(() => (overlayRef = this.busyService.show())); try { - - const journalEntries = await this.frozenJobs.Get(navigationState); + const journalEntries = await this.frozenJobs.Get({ ...navigationState, queueName: this.queueName }); this.jobCount = journalEntries.totalCount; this.dstSettings = { displayedColumns: this.displayedColumns, dataSource: journalEntries, entitySchema: this.entitySchemaFrozenJobs, - navigationState: this.navigationState + navigationState: this.navigationState, }; - } finally { setTimeout(() => this.busyService.hide(overlayRef)); } diff --git a/imxweb/projects/qer-app-operationssupport/src/app/processes/frozen-jobs/frozen-jobs.service.spec.ts b/imxweb/projects/qer-app-operationssupport/src/app/processes/frozen-jobs/frozen-jobs.service.spec.ts index 20bd94560..105d6e9d4 100644 --- a/imxweb/projects/qer-app-operationssupport/src/app/processes/frozen-jobs/frozen-jobs.service.spec.ts +++ b/imxweb/projects/qer-app-operationssupport/src/app/processes/frozen-jobs/frozen-jobs.service.spec.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -25,7 +25,7 @@ */ import { FrozenJobsService } from './frozen-jobs.service'; -import { OpsupportQueueFrozenjobs } from 'imx-api-qbm'; +import { OpsupportQueueFrozenjobs } from '@imx-modules/imx-api-qbm'; import { testTypedEntityReadOnlyProvider } from '../../test-utilities/typed-entity-provider.spec'; import { ImxApiDtoMock } from '../../test-utilities/imx-api-mock.spec'; @@ -39,8 +39,8 @@ describe('FrozenJobsService', () => { typedClient: { OpsupportQueueFrozenjobs: jasmine.createSpyObj('OpsupportQueueFrozenjobs', { GetSchema: () => OpsupportQueueFrozenjobs.GetEntitySchema(), - Get: Promise.resolve({ Data: data, totalCount: data.length }) - }) - } + Get: Promise.resolve({ Data: data, totalCount: data.length }), + }), + }, }); }); diff --git a/imxweb/projects/qer-app-operationssupport/src/app/processes/frozen-jobs/frozen-jobs.service.ts b/imxweb/projects/qer-app-operationssupport/src/app/processes/frozen-jobs/frozen-jobs.service.ts index 8932a2830..99321bc6b 100644 --- a/imxweb/projects/qer-app-operationssupport/src/app/processes/frozen-jobs/frozen-jobs.service.ts +++ b/imxweb/projects/qer-app-operationssupport/src/app/processes/frozen-jobs/frozen-jobs.service.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -26,16 +26,16 @@ import { Injectable } from '@angular/core'; -import { TypedEntityCollectionData, EntitySchema, CollectionLoadParameters, TypedEntity } from 'imx-qbm-dbts'; +import { TypedEntityCollectionData, EntitySchema, CollectionLoadParameters, TypedEntity } from '@imx-modules/imx-qbm-dbts'; import { imx_SessionService } from 'qbm'; -import { OpsupportQueueFrozenjobs } from 'imx-api-qbm'; +import { OpsupportQueueFrozenjobs } from '@imx-modules/imx-api-qbm'; export interface JobQueueParameters extends CollectionLoadParameters { queueName: string; } @Injectable({ - providedIn: 'root' + providedIn: 'root', }) export class FrozenJobsService { public get EntitySchema(): EntitySchema { diff --git a/imxweb/projects/qer-app-operationssupport/src/app/processes/frozen-jobs/queue-tree.service.ts b/imxweb/projects/qer-app-operationssupport/src/app/processes/frozen-jobs/queue-tree.service.ts index 884f686da..a0acdfdbb 100644 --- a/imxweb/projects/qer-app-operationssupport/src/app/processes/frozen-jobs/queue-tree.service.ts +++ b/imxweb/projects/qer-app-operationssupport/src/app/processes/frozen-jobs/queue-tree.service.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -26,18 +26,25 @@ import { Injectable } from '@angular/core'; +import { HistoryOperationsData, OpsupportQueueJobaffects, ReactivateJobMode } from '@imx-modules/imx-api-qbm'; +import { + EntityCollectionData, + EntityData, + EntitySchema, + ExtendedTypedEntityCollection, + IEntityColumn, + TypedEntity, + TypedEntityCollectionData, +} from '@imx-modules/imx-qbm-dbts'; import { CdrFactoryService, ImxDataSource, imx_SessionService } from 'qbm'; -import { EntityCollectionData, EntityData, EntitySchema, ExtendedTypedEntityCollection, IEntityColumn, TypedEntity, TypedEntityCollectionData } from 'imx-qbm-dbts'; -import { HistoryOperationsData, OpsupportQueueJobaffects, ReactivateJobMode } from 'imx-api-qbm'; import { QueueJobsService } from '../jobs/queue-jobs.service'; @Injectable() export class QueueTreeService extends ImxDataSource { - public startUid: string; public items: TypedEntity[]; - public load: (startId: string) => Promise> + public load: (startId: string) => Promise>; constructor( private session: imx_SessionService, @@ -53,26 +60,39 @@ export class QueueTreeService extends ImxDataSource { public itemsProvider = async () => { let result: ExtendedTypedEntityCollection; - result = await this.load(this.startUid);//await this.session.TypedClient.OpsupportQueueTree.Get({ uidtree: this.startUid }); - return this.data = this.items = result?.Data; - } - - public childItemsProvider = (item: TypedEntity) => { + result = await this.load(this.startUid); //await this.session.TypedClient.OpsupportQueueTree.Get({ uidtree: this.startUid }); - const child1 = this.items ? this.items.find(el => this.getColumn(el, 'UID_Job').GetValue() === this.getColumn(item, 'UID_JobError').GetValue()) : null; - const child2 = this.items ? this.items.find(el => this.getColumn(el, 'UID_Job').GetValue() === this.getColumn(item, 'UID_JobSuccess').GetValue()) : null; + this.items = result?.Data; + return this.items; + }; - const res = []; - if (child1) { res.push(child1); } - if (child2) { res.push(child2); } + public childItemsProvider = (item: TypedEntity) => { + const child1 = this.items + ? this.items.find((el) => this.getColumn(el, 'UID_Job')?.GetValue() === this.getColumn(item, 'UID_JobError')?.GetValue()) + : undefined; + const child2 = this.items + ? this.items.find((el) => this.getColumn(el, 'UID_Job')?.GetValue() === this.getColumn(item, 'UID_JobSuccess')?.GetValue()) + : undefined; + + const res: TypedEntity[] = []; + if (child1) { + res.push(child1); + } + if (child2) { + res.push(child2); + } return Promise.resolve(res); - } + }; public hasChildrenProvider = (data: TypedEntity) => { - return (this.getColumn(data, 'UID_JobError').GetValue() != null && this.getColumn(data, 'UID_JobError').GetValue() !== '') - || (this.getColumn(data, 'UID_JobSuccess').GetValue() != null && this.getColumn(data, 'UID_JobSuccess').GetValue() !== ''); - } + const error = this.getColumn(data, 'UID_JobError')?.GetValue(); + const success = this.getColumn(data, 'UID_JobSuccess')?.GetValue() + return ( + ( error && success) || + ( error !== '' && success !== '') + ); + }; public async GetAffectedObjects(uidJob: string): Promise { return (await this.session.TypedClient.OpsupportQueueJobaffects.Get(uidJob)).Data; @@ -84,11 +104,13 @@ export class QueueTreeService extends ImxDataSource { public GetTotalSteps(): number { let count = 1; - this.items.forEach(el => { - if (this.getColumn(el, 'UID_JobError').GetValue() !== '') { + this.items.forEach((el) => { + const error = this.getColumn(el, 'UID_JobError')?.GetValue(); + if (error && error !== '') { count++; } - if (this.getColumn(el, 'UID_JobSuccess').GetValue() !== '') { + const success = this.getColumn(el, 'UID_JobSuccess')?.GetValue(); + if (success && success !== '') { count++; } }); @@ -96,13 +118,13 @@ export class QueueTreeService extends ImxDataSource { } public GetCompleteSteps(): number { - const root = this.items.find(el => this.getColumn(el, 'IsRootJob').GetValue()); - return this.GetCompleteSubSteps(this.getColumn(root, 'UID_Job').GetValue()); + const root = this.items.find((el) => this.getColumn(el, 'IsRootJob')?.GetValue()); + return root ? this.GetCompleteSubSteps(this.getColumn(root, 'UID_Job')?.GetValue()) : 0; } public RemoveEmpty(ent: EntityData[]): EntityData[] { const ret: EntityData[] = []; - ent.forEach(el => { + ent.forEach((el) => { if (el !== null) { ret.push(el); } @@ -111,34 +133,43 @@ export class QueueTreeService extends ImxDataSource { } public CanBeReactivated(): boolean { - if (!this.items) { return false; } - return this.getFrozenItem() !== undefined; + if (!this.items) { + return false; + } + return !!this.getFrozenItem(); } - public async Reactivate(mode: ReactivateJobMode): Promise { + public async Reactivate(mode: ReactivateJobMode): Promise { const frozen = this.getFrozenItem(); - if (frozen) { - return this.jobService.Retry(mode, [this.getColumn(frozen, 'UID_Job').GetValue()]); + const uidJob = frozen ? this.getColumn(frozen, 'UID_Job')?.GetValue() : undefined; + if (frozen && uidJob) { + return this.jobService.Retry(mode, [uidJob]); } - return Promise.resolve(null); } - private GetCompleteSubSteps(uidJob: string): number { - - if (uidJob === '') { return 0; } - const current = this.items.find(el => this.getColumn(el, 'UID_Job').GetValue() === uidJob); + private GetCompleteSubSteps(uidJob?: string): number { + if (!uidJob || uidJob === '') { + return 0; + } + const current = this.items.find((el) => this.getColumn(el, 'UID_Job')?.GetValue() === uidJob); const count = current && (this.getColumn(current, 'Ready2EXE')?.GetValue() ?? 'FINISHED') === 'FINISHED' ? 1 : 0; - - return count + this.GetCompleteSubSteps(this.getColumn(current, 'UID_JobSuccess').GetValue()) + this.GetCompleteSubSteps(this.getColumn(current, 'UID_JobError').GetValue()); + return current + ? count + + this.GetCompleteSubSteps(this.getColumn(current, 'UID_JobSuccess')?.GetValue()) + + this.GetCompleteSubSteps(this.getColumn(current, 'UID_JobError')?.GetValue()) + : count; } - public getFrozenItem(): TypedEntity { - return this.items.find(el => this.getColumn(el, 'Ready2EXE')?.GetValue()?.toUpperCase() === 'FROZEN' || - this.getColumn(el, 'Ready2EXE')?.GetValue()?.toUpperCase() === 'OVERLIMIT'); + public getFrozenItem(): TypedEntity | undefined { + return this.items.find( + (el) => + this.getColumn(el, 'Ready2EXE')?.GetValue()?.toUpperCase() === 'FROZEN' || + this.getColumn(el, 'Ready2EXE')?.GetValue()?.toUpperCase() === 'OVERLIMIT', + ); } - private getColumn(entity: TypedEntity, name: string): IEntityColumn { + private getColumn(entity: TypedEntity, name: string): IEntityColumn | undefined { return CdrFactoryService.tryGetColumn(entity.GetEntity(), name); } } diff --git a/imxweb/projects/qer-app-operationssupport/src/app/processes/frozen-jobs/single-frozen-job.component.html b/imxweb/projects/qer-app-operationssupport/src/app/processes/frozen-jobs/single-frozen-job.component.html index 2e8b055c4..3a0326a7b 100644 --- a/imxweb/projects/qer-app-operationssupport/src/app/processes/frozen-jobs/single-frozen-job.component.html +++ b/imxweb/projects/qer-app-operationssupport/src/app/processes/frozen-jobs/single-frozen-job.component.html @@ -1,53 +1,59 @@ -
    +
    - - +
    {{ '#LDS#The process does not exist or it has already been completed.' | translate }}
    -
    - - - -
    {{ displayAccessor(dataItem, rowIndex) }}
    -
    {{ timeAccessor(dataItem, rowIndex) }}
    -
    -
    - - -
    - -
    - {{ getColumn(dataItem, 'Ready2EXE')?.GetDisplayValue() }} - - - -
    -
    -
    +
    + + + + +
    {{ displayAccessor(data, rowIndex) }}
    +
    {{ timeAccessor(data, rowIndex) }}
    +
    +
    + + +
    + +
    + {{ getColumn(data, 'Ready2EXE')?.GetDisplayValue() }} + + + +
    +
    +
    +
    - +
    {{ '#LDS#Heading Affected Objects' | translate }}
    • -
      {{aff.ObjectKeyAffected.Column.GetDisplayValue()}}
      -
      {{aff.ObjectTypeDisplay.Column.GetDisplayValue()}}
      +
      {{ aff.ObjectKeyAffected.Column.GetDisplayValue() }}
      +
      {{ aff.ObjectTypeDisplay.Column.GetDisplayValue() }}
    @@ -66,20 +72,28 @@

    #LDS#Select how to proceed with the process.

    - + {{ '#LDS#Retry the frozen process step' | translate }} - - {{ '#LDS#End with success' | translate }} - {{ '#LDS#Continue with the success process step' | translate }} + + {{ + '#LDS#End with success' | translate + }} + {{ + '#LDS#Continue with the success process step' | translate + }} - - {{ '#LDS#End with error' | translate }} - {{ '#LDS#Continue with the error process step' | translate }} + + {{ '#LDS#End with error' | translate }} + + {{ + '#LDS#Continue with the error process step' | translate + }}
    - + diff --git a/imxweb/projects/qer-app-operationssupport/src/app/processes/frozen-jobs/single-frozen-job.component.scss b/imxweb/projects/qer-app-operationssupport/src/app/processes/frozen-jobs/single-frozen-job.component.scss index d39b0bdbf..6f38955e7 100644 --- a/imxweb/projects/qer-app-operationssupport/src/app/processes/frozen-jobs/single-frozen-job.component.scss +++ b/imxweb/projects/qer-app-operationssupport/src/app/processes/frozen-jobs/single-frozen-job.component.scss @@ -3,40 +3,20 @@ flex-direction: column; flex-grow: 1; - .imx-flex-container{ - display: flex; - flex-direction: column; - flex: 1 1 auto; - padding-bottom: 20px; - } - - imx-busy-indicator{ + imx-busy-indicator { justify-self: center; align-self: center; } } -.imx-table-container { - flex: 1 1 auto; - - > :nth-child(2) { - flex: 1 1 auto; - } -} - .imx-refresh-line { margin-bottom: 10px; display: flex; flex-direction: row; } -.reactivate-radio { - display: block; -} - .inner-card { - margin-top: 1em; - + margin-bottom: 1em; mat-card-content { padding: 0 1em; } @@ -55,8 +35,10 @@ list-style-type: initial; } -.small-busy { - margin-left: 1em; - align-self: center; - flex: 1 1 auto; +.imx-single-frozen.imx-flex-container { + margin: 0; + + ::ng-deep .mat-mdc-table { + box-shadow: none; + } } diff --git a/imxweb/projects/qer-app-operationssupport/src/app/processes/frozen-jobs/single-frozen-job.component.ts b/imxweb/projects/qer-app-operationssupport/src/app/processes/frozen-jobs/single-frozen-job.component.ts index b9383e104..b3bec4fc7 100644 --- a/imxweb/projects/qer-app-operationssupport/src/app/processes/frozen-jobs/single-frozen-job.component.ts +++ b/imxweb/projects/qer-app-operationssupport/src/app/processes/frozen-jobs/single-frozen-job.component.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -24,16 +24,16 @@ * */ +import { OverlayRef } from '@angular/cdk/overlay'; import { Component, Inject, OnInit } from '@angular/core'; +import { EUI_SIDESHEET_DATA, EuiLoadingService, EuiSidesheetService } from '@elemental-ui/core'; import { TranslateService } from '@ngx-translate/core'; -import { EuiLoadingService, EuiSidesheetService, EUI_SIDESHEET_DATA } from '@elemental-ui/core'; -import { OverlayRef } from '@angular/cdk/overlay'; -import { IEntityColumn, TypedEntity, TypedEntityCollectionData } from 'imx-qbm-dbts'; -import { HistoryOperationsData, OpsupportQueueJobaffects, ReactivateJobMode } from 'imx-api-qbm'; -import { CdrFactoryService, ImxTranslationProviderService, SnackBarService } from 'qbm'; -import { QueueTreeService } from './queue-tree.service'; +import { HistoryOperationsData, OpsupportQueueJobaffects, ReactivateJobMode } from '@imx-modules/imx-api-qbm'; +import { IEntityColumn, TypedEntity, TypedEntityCollectionData } from '@imx-modules/imx-qbm-dbts'; +import { calculateSidesheetWidth, CdrFactoryService, ImxTranslationProviderService, SnackBarService } from 'qbm'; import { ErrorMessageSidesheetComponent } from '../error-message-sidesheet/error-message-sidesheet.component'; +import { QueueTreeService } from './queue-tree.service'; @Component({ templateUrl: './single-frozen-job.component.html', @@ -51,23 +51,24 @@ export class SingleFrozenJobComponent implements OnInit { private backTitle = ''; public affectedObjects: OpsupportQueueJobaffects[] = []; - public operations: HistoryOperationsData; - public genprocid: string; + public operations: HistoryOperationsData | undefined; + public genprocid: string | undefined; public busy = false; public busyReload = false; constructor( - @Inject(EUI_SIDESHEET_DATA) public readonly data: { - UID_Tree: string, - disableRefresh: boolean, - load: (startId: string) => Promise> + @Inject(EUI_SIDESHEET_DATA) + public readonly data: { + UID_Tree: string; + disableRefresh: boolean; + load: (startId: string) => Promise>; }, public queueService: QueueTreeService, private sidesheet: EuiSidesheetService, private translate: TranslateService, private busyService: EuiLoadingService, private translationProvider: ImxTranslationProviderService, - private snackbarService: SnackBarService + private snackbarService: SnackBarService, ) { // TODO (TFS 805984): Use ngx-translate get and ldsReplace direct this.translationProvider @@ -75,21 +76,20 @@ export class SingleFrozenJobComponent implements OnInit { .subscribe((value: string) => this.translationProvider .Translate({ key: '#LDS#Go back to {0}', parameters: [`"${value}"`] }) - .subscribe((composedValue: string) => (this.backTitle = composedValue)) + .subscribe((composedValue: string) => (this.backTitle = composedValue)), ); this.queueService.load = data.load; } public ReactivateJobMode = ReactivateJobMode; - public mode: ReactivateJobMode = -1; + public mode: ReactivateJobMode; public async ngOnInit(): Promise { try { this.busy = true; await this.loadView(this.data.UID_Tree); - } - finally { + } finally { this.busy = false; } } @@ -124,21 +124,20 @@ export class SingleFrozenJobComponent implements OnInit { } const processTree = await this.queueService.LoadItems(); - const root = processTree.find((el: TypedEntity) => this.getColumn(el, 'IsRootJob').GetValue); + const root = processTree.find((el: TypedEntity) => this.getColumn(el, 'IsRootJob')?.GetValue()); if (root) { this.queueService.SetRoot(root); - this.jobDisplay = this.getColumn(root, 'JobChainName').GetDisplayValue(); + this.jobDisplay = this.getColumn(root, 'JobChainName')?.GetDisplayValue() ?? ''; this.queueService.ExpandAll(); // load affected objects - this.affectedObjects = await this.queueService.GetAffectedObjects(root.GetEntity().GetColumn("UID_Job").GetValue()); - this.genprocid = root.GetEntity().GetColumn("GenProcID").GetValue(); - this.operations = await this.queueService.GetChangeOperations(this.genprocid); - } - else { + this.affectedObjects = await this.queueService.GetAffectedObjects(root.GetEntity().GetColumn('UID_Job').GetValue()); + this.genprocid = root.GetEntity().GetColumn('GenProcID').GetValue(); + this.operations = this.genprocid ? await this.queueService.GetChangeOperations(this.genprocid) : undefined; + } else { this.affectedObjects = []; - this.operations = null; - this.genprocid = null; + this.operations = undefined; + this.genprocid = undefined; } } @@ -152,11 +151,11 @@ export class SingleFrozenJobComponent implements OnInit { public displayAccessor(data: TypedEntity, index: number): string { return index === 0 ? this.Display - : this.getColumn(data, 'JobName')?.GetDisplayValue() ?? this.getColumn(data, 'UID_JobOrigin')?.GetDisplayValue(); + : this.getColumn(data, 'JobName')?.GetDisplayValue() ?? this.getColumn(data, 'UID_JobOrigin')?.GetDisplayValue() ?? ''; } public hasProgress(item: TypedEntity): boolean { - return this.getColumn(item, 'IsRootJob').GetValue(); + return this.getColumn(item, 'IsRootJob')?.GetValue() ?? false; } public getTotalSteps(): number { @@ -168,7 +167,11 @@ export class SingleFrozenJobComponent implements OnInit { } public isFrozen(dataItem: TypedEntity): boolean { - return this.getColumn(dataItem, 'Ready2EXE')?.GetValue().toUpperCase() === 'FROZEN' || this.getColumn(dataItem, 'Ready2EXE')?.GetValue().toUpperCase() === 'OVERLIMIT' || this.getColumn(dataItem, 'WasError')?.GetValue(); + return ( + this.getColumn(dataItem, 'Ready2EXE')?.GetValue().toUpperCase() === 'FROZEN' || + this.getColumn(dataItem, 'Ready2EXE')?.GetValue().toUpperCase() === 'OVERLIMIT' || + this.getColumn(dataItem, 'WasError')?.GetValue() + ); } public async showMessage(dataItem: TypedEntity): Promise { @@ -176,23 +179,23 @@ export class SingleFrozenJobComponent implements OnInit { .open(ErrorMessageSidesheetComponent, { title: await this.translate.get('#LDS#Heading View Error Message').toPromise(), padding: '0', - width: 'max(50%,500px)', + width: calculateSidesheetWidth(800, 0.5), testId: 'error-message-sidesheet', - data: this.getColumn(dataItem, 'ErrorMessages').GetDisplayValue(), + data: this.getColumn(dataItem, 'ErrorMessages')?.GetDisplayValue(), }) .afterClosed() .toPromise(); } public getColumnDisplay(name: string): string { - return this.queueService.QueueTreeEntitySchema.Columns[name].Display; + return this.queueService.QueueTreeEntitySchema.Columns[name].Display ?? ''; } - public getValue(entity: TypedEntity, name: string): any { - return this.getColumn(entity, name).GetValue() ?? ''; + public getValue(entity: TypedEntity | undefined, name: string): any { + return this.getColumn(entity, name)?.GetValue() ?? ''; } - public getColumn(entity: TypedEntity, name: string): IEntityColumn { - return CdrFactoryService.tryGetColumn(entity.GetEntity(), name); + public getColumn(entity: TypedEntity | undefined, name: string): IEntityColumn | undefined { + return entity ? CdrFactoryService.tryGetColumn(entity?.GetEntity(), name) : undefined; } } diff --git a/imxweb/projects/qer-app-operationssupport/src/app/processes/job-chains/job-chains.component.html b/imxweb/projects/qer-app-operationssupport/src/app/processes/job-chains/job-chains.component.html index 73ad9967b..8d6b02310 100644 --- a/imxweb/projects/qer-app-operationssupport/src/app/processes/job-chains/job-chains.component.html +++ b/imxweb/projects/qer-app-operationssupport/src/app/processes/job-chains/job-chains.component.html @@ -1,26 +1,30 @@ -

    - {{'#LDS#Heading Process Steps per Process' | translate}} -

    +

    + {{ '#LDS#Heading Process Steps per Process' | translate }} +

    - - + + {{ data.JobChainName.Column.GetDisplayValue() }} - - - {{ data.Count.Column.GetDisplayValue() }} - - + + + {{ data.Count.Column.GetDisplayValue() }} + +
    - diff --git a/imxweb/projects/qer-app-operationssupport/src/app/processes/job-chains/job-chains.component.scss b/imxweb/projects/qer-app-operationssupport/src/app/processes/job-chains/job-chains.component.scss index 3f894fce0..57a7affa1 100644 --- a/imxweb/projects/qer-app-operationssupport/src/app/processes/job-chains/job-chains.component.scss +++ b/imxweb/projects/qer-app-operationssupport/src/app/processes/job-chains/job-chains.component.scss @@ -5,18 +5,3 @@ flex-grow: 1; } -.imx-table-container { - flex: 1 1 auto; - display: flex; - flex-direction: column; - overflow: auto; - - > :nth-child(2) { - flex: 1 1 auto; - } -} - -.imx-refresh-button { - margin-right: 5px; - height: 50px; -} diff --git a/imxweb/projects/qer-app-operationssupport/src/app/processes/job-chains/job-chains.component.ts b/imxweb/projects/qer-app-operationssupport/src/app/processes/job-chains/job-chains.component.ts index 78ebf3a57..90416c738 100644 --- a/imxweb/projects/qer-app-operationssupport/src/app/processes/job-chains/job-chains.component.ts +++ b/imxweb/projects/qer-app-operationssupport/src/app/processes/job-chains/job-chains.component.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -28,16 +28,15 @@ import { OverlayRef } from '@angular/cdk/overlay'; import { Component, OnInit } from '@angular/core'; import { EuiLoadingService } from '@elemental-ui/core'; -import { DisplayColumns, EntitySchema, IClientProperty } from 'imx-qbm-dbts'; +import { DisplayColumns, EntitySchema, IClientProperty } from '@imx-modules/imx-qbm-dbts'; import { DataSourceToolbarSettings } from 'qbm'; import { JobChainsService } from './job-chains.service'; @Component({ templateUrl: './job-chains.component.html', - styleUrls: ['./job-chains.component.scss'] + styleUrls: ['./job-chains.component.scss'], }) export class JobChainsComponent implements OnInit { - public dstSettings: DataSourceToolbarSettings; public readonly entitySchemaJobChains: EntitySchema; public readonly DisplayColumns = DisplayColumns; @@ -45,12 +44,10 @@ export class JobChainsComponent implements OnInit { constructor( private jobChains: JobChainsService, - private busyService: EuiLoadingService) { + private busyService: EuiLoadingService, + ) { this.entitySchemaJobChains = jobChains.EntitySchema; - this.displayedColumns = [ - this.entitySchemaJobChains.Columns.JobChainName, - this.entitySchemaJobChains.Columns.Count - ]; + this.displayedColumns = [this.entitySchemaJobChains.Columns.JobChainName, this.entitySchemaJobChains.Columns.Count]; } public async ngOnInit(): Promise { @@ -62,19 +59,16 @@ export class JobChainsComponent implements OnInit { } public async getData(): Promise { - let overlayRef: OverlayRef; - setTimeout(() => overlayRef = this.busyService.show()); + setTimeout(() => (overlayRef = this.busyService.show())); try { - const jobChainList = await this.jobChains.Get(); this.dstSettings = { displayedColumns: this.displayedColumns, dataSource: jobChainList, entitySchema: this.entitySchemaJobChains, - navigationState: {} + navigationState: {}, }; - } finally { setTimeout(() => this.busyService.hide(overlayRef)); } diff --git a/imxweb/projects/qer-app-operationssupport/src/app/processes/job-chains/job-chains.service.spec.ts b/imxweb/projects/qer-app-operationssupport/src/app/processes/job-chains/job-chains.service.spec.ts index de87c66cf..b13b4708a 100644 --- a/imxweb/projects/qer-app-operationssupport/src/app/processes/job-chains/job-chains.service.spec.ts +++ b/imxweb/projects/qer-app-operationssupport/src/app/processes/job-chains/job-chains.service.spec.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -25,7 +25,7 @@ */ import { JobChainsService } from './job-chains.service'; -import { OpsupportQueueJobchains } from 'imx-api-qbm'; +import { OpsupportQueueJobchains } from '@imx-modules/imx-api-qbm'; import { testTypedEntityReadOnlyProvider } from '../../test-utilities/typed-entity-provider.spec'; import { ImxApiDtoMock } from '../../test-utilities/imx-api-mock.spec'; @@ -36,11 +36,11 @@ describe('JobChainsService', () => { entityType: OpsupportQueueJobchains, data: data, parameters: {}, - typedClient: { + typedClient: { OpsupportQueueJobchains: jasmine.createSpyObj('OpsupportQueueJobchains', { GetSchema: () => OpsupportQueueJobchains.GetEntitySchema(), - Get: Promise.resolve({ Data: data, totalCount: data.length }) - }) - } + Get: Promise.resolve({ Data: data, totalCount: data.length }), + }), + }, }); }); diff --git a/imxweb/projects/qer-app-operationssupport/src/app/processes/job-chains/job-chains.service.ts b/imxweb/projects/qer-app-operationssupport/src/app/processes/job-chains/job-chains.service.ts index 1ed91df82..9a290b8b5 100644 --- a/imxweb/projects/qer-app-operationssupport/src/app/processes/job-chains/job-chains.service.ts +++ b/imxweb/projects/qer-app-operationssupport/src/app/processes/job-chains/job-chains.service.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -26,19 +26,19 @@ import { Injectable } from '@angular/core'; -import { TypedEntityCollectionData, EntitySchema } from 'imx-qbm-dbts'; +import { TypedEntityCollectionData, EntitySchema } from '@imx-modules/imx-qbm-dbts'; import { imx_SessionService } from 'qbm'; -import { OpsupportQueueJobchains } from 'imx-api-qbm'; +import { OpsupportQueueJobchains } from '@imx-modules/imx-api-qbm'; @Injectable({ - providedIn: 'root' + providedIn: 'root', }) export class JobChainsService { public get EntitySchema(): EntitySchema { return this.session.TypedClient.OpsupportQueueJobchains.GetSchema(); } - constructor(private session: imx_SessionService) { } + constructor(private session: imx_SessionService) {} public Get(): Promise> { return this.session.TypedClient.OpsupportQueueJobchains.Get(); diff --git a/imxweb/projects/qer-app-operationssupport/src/app/processes/job-history/job-history.component.html b/imxweb/projects/qer-app-operationssupport/src/app/processes/job-history/job-history.component.html index 175110abe..cfe202dc9 100644 --- a/imxweb/projects/qer-app-operationssupport/src/app/processes/job-history/job-history.component.html +++ b/imxweb/projects/qer-app-operationssupport/src/app/processes/job-history/job-history.component.html @@ -1,6 +1,6 @@ -

    +

    {{ '#LDS#Heading Process History' | translate }} -

    +
    (navigationStateChanged)="getData($event)" > - - + +
    - + #LDS#Error
    - + - {{getDateTimeString(dataItem.XDateInserted.value)}} + {{ getDateTimeString(dataItem.XDateInserted.value) }} - - + + - diff --git a/imxweb/projects/qer-app-operationssupport/src/app/processes/job-history/job-history.component.scss b/imxweb/projects/qer-app-operationssupport/src/app/processes/job-history/job-history.component.scss index 238d26945..28b7a0104 100644 --- a/imxweb/projects/qer-app-operationssupport/src/app/processes/job-history/job-history.component.scss +++ b/imxweb/projects/qer-app-operationssupport/src/app/processes/job-history/job-history.component.scss @@ -1,4 +1,4 @@ -@import "@elemental-ui/core/src/styles/_eui_palette.scss"; +@import '@elemental-ui/core/src/styles/_eui_palette.scss'; :host { display: flex; @@ -6,23 +6,6 @@ overflow: hidden; flex-grow: 1; - .imx-table-container { - flex: 1 1 auto; - display: flex; - flex-direction: column; - overflow: auto; - margin-bottom: -20px; - - > :nth-child(2) { - flex: 1 1 auto; - } - } - - .imx-refresh-button { - margin-right: 5px; - height: 50px; - } - .imx-icon-container { display: flex; padding: 0 16px; @@ -32,11 +15,3 @@ } } } - -:host { - .imx-icon-container { - .imx-bug-icon { - color: $color-red-60; - } - } -} diff --git a/imxweb/projects/qer-app-operationssupport/src/app/processes/job-history/job-history.component.ts b/imxweb/projects/qer-app-operationssupport/src/app/processes/job-history/job-history.component.ts index f636c6b8c..f8fb0ef1e 100644 --- a/imxweb/projects/qer-app-operationssupport/src/app/processes/job-history/job-history.component.ts +++ b/imxweb/projects/qer-app-operationssupport/src/app/processes/job-history/job-history.component.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -27,13 +27,21 @@ import { OverlayRef } from '@angular/cdk/overlay'; import { Component, OnInit } from '@angular/core'; import { EuiLoadingService, EuiSidesheetConfig, EuiSidesheetService } from '@elemental-ui/core'; +import { OpsupportQueueJobhistory } from '@imx-modules/imx-api-qbm'; +import { + CollectionLoadParameters, + DataModel, + DisplayColumns, + EntitySchema, + IClientProperty, + TypedEntity, + ValType, +} from '@imx-modules/imx-qbm-dbts'; import { TranslateService } from '@ngx-translate/core'; -import { OpsupportQueueJobhistory } from 'imx-api-qbm'; -import { CollectionLoadParameters, DataModel, DisplayColumns, EntitySchema, IClientProperty, ValType } from 'imx-qbm-dbts'; -import { DataSourceToolbarSettings, SettingsService } from 'qbm'; -import { JobHistoryService } from './job-history.service'; +import { DataSourceToolbarSettings, SettingsService, calculateSidesheetWidth } from 'qbm'; import { ErrorMessageSidesheetComponent } from '../error-message-sidesheet/error-message-sidesheet.component'; import { SingleFrozenJobComponent } from '../frozen-jobs/single-frozen-job.component'; +import { JobHistoryService } from './job-history.service'; @Component({ selector: 'imx-job-history', @@ -54,7 +62,7 @@ export class JobHistoryComponent implements OnInit { private readonly settingsService: SettingsService, private busyService: EuiLoadingService, private readonly translate: TranslateService, - private readonly sidesheet: EuiSidesheetService + private readonly sidesheet: EuiSidesheetService, ) { this.entitySchema = jobHistory.EntitySchema; this.displayedColumns = [ @@ -111,7 +119,7 @@ export class JobHistoryComponent implements OnInit { title: await this.translate.get('#LDS#Heading View Message').toPromise(), subTitle: item.GetEntity().GetDisplay(), padding: '0', - width: 'max(60%,600px)', + width: calculateSidesheetWidth(), testId: 'error-message-sidesheet', data: item.ErrorMessages.value, }) @@ -119,14 +127,15 @@ export class JobHistoryComponent implements OnInit { .toPromise(); } - public async viewDetails(job: OpsupportQueueJobhistory): Promise { + public async viewDetails(job: TypedEntity): Promise { const opts: EuiSidesheetConfig = { title: await this.translate.get('#LDS#Heading View Process Details').toPromise(), + subTitle: job.GetEntity().GetDisplay(), padding: '1em', - width: 'max(800px,80%)', + width: calculateSidesheetWidth(1100, 0.7), icon: 'reboot', data: { - UID_Tree: job.UID_Tree.value, + UID_Tree: job.GetEntity().GetColumn('UID_Tree').GetValue(), disableRefresh: true, load: (startId: string) => { return this.jobHistory.get({ filter: [{ ColumnName: 'UID_Tree', Value1: startId }] }); diff --git a/imxweb/projects/qer-app-operationssupport/src/app/processes/job-history/job-history.service.ts b/imxweb/projects/qer-app-operationssupport/src/app/processes/job-history/job-history.service.ts index 108ad1e65..80591aa55 100644 --- a/imxweb/projects/qer-app-operationssupport/src/app/processes/job-history/job-history.service.ts +++ b/imxweb/projects/qer-app-operationssupport/src/app/processes/job-history/job-history.service.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -25,8 +25,8 @@ */ import { Injectable } from '@angular/core'; -import { OpsupportQueueJobhistory } from 'imx-api-qbm'; -import { CollectionLoadParameters, DataModel, EntitySchema, ExtendedTypedEntityCollection } from 'imx-qbm-dbts'; +import { OpsupportQueueJobhistory } from '@imx-modules/imx-api-qbm'; +import { CollectionLoadParameters, DataModel, EntitySchema, ExtendedTypedEntityCollection } from '@imx-modules/imx-qbm-dbts'; import { imx_SessionService } from 'qbm'; @@ -40,8 +40,8 @@ export class JobHistoryService { return this.session.TypedClient.OpsupportQueueJobhistory.GetSchema(); } - public async get(parameters: CollectionLoadParameters):Promise> { - return this.session.TypedClient.OpsupportQueueJobhistory.Get(parameters); + public async get(parameters: CollectionLoadParameters): Promise> { + return this.session.TypedClient.OpsupportQueueJobhistory.Get(parameters); } public async getDataModel(): Promise { diff --git a/imxweb/projects/qer-app-operationssupport/src/app/processes/job-performance/job-performance-queues.service.ts b/imxweb/projects/qer-app-operationssupport/src/app/processes/job-performance/job-performance-queues.service.ts index 7371acb71..91d9fdd3a 100644 --- a/imxweb/projects/qer-app-operationssupport/src/app/processes/job-performance/job-performance-queues.service.ts +++ b/imxweb/projects/qer-app-operationssupport/src/app/processes/job-performance/job-performance-queues.service.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR diff --git a/imxweb/projects/qer-app-operationssupport/src/app/processes/job-performance/job-performance.component.html b/imxweb/projects/qer-app-operationssupport/src/app/processes/job-performance/job-performance.component.html index 89e80a736..e532460c2 100644 --- a/imxweb/projects/qer-app-operationssupport/src/app/processes/job-performance/job-performance.component.html +++ b/imxweb/projects/qer-app-operationssupport/src/app/processes/job-performance/job-performance.component.html @@ -1,32 +1,38 @@ -

    - {{'#LDS#Heading Processing Performance' | translate}} -

    +

    + {{ '#LDS#Heading Processing Performance' | translate }} +

    - {{queue}} + {{ queue }}
    - + - - + + {{ data.TaskName.Column.GetDisplayValue() }} - + {{ data.ComponentClass.Column.GetDisplayValue() }} - + {{ data.CountPerMinute.Column.GetDisplayValue() }} @@ -36,7 +42,7 @@

    - diff --git a/imxweb/projects/qer-app-operationssupport/src/app/processes/job-performance/job-performance.component.scss b/imxweb/projects/qer-app-operationssupport/src/app/processes/job-performance/job-performance.component.scss index 363260945..6fcf20988 100644 --- a/imxweb/projects/qer-app-operationssupport/src/app/processes/job-performance/job-performance.component.scss +++ b/imxweb/projects/qer-app-operationssupport/src/app/processes/job-performance/job-performance.component.scss @@ -3,21 +3,4 @@ flex-direction: column; overflow: hidden; flex-grow: 1; -} - -.imx-table-container { - flex: 1 1 auto; - display: flex; - flex-direction: column; - overflow: auto; - margin-bottom: -20px; - - > :nth-child(2) { - flex: 1 1 auto; - } -} - -.imx-refresh-button { - margin-right: 5px; - height: 50px; -} +} \ No newline at end of file diff --git a/imxweb/projects/qer-app-operationssupport/src/app/processes/job-performance/job-performance.component.ts b/imxweb/projects/qer-app-operationssupport/src/app/processes/job-performance/job-performance.component.ts index 4cc27e75f..399fee1ba 100644 --- a/imxweb/projects/qer-app-operationssupport/src/app/processes/job-performance/job-performance.component.ts +++ b/imxweb/projects/qer-app-operationssupport/src/app/processes/job-performance/job-performance.component.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -24,20 +24,19 @@ * */ -import { Component, OnInit } from '@angular/core'; import { OverlayRef } from '@angular/cdk/overlay'; -import { EuiLoadingService } from '@elemental-ui/core'; +import { Component, OnInit } from '@angular/core'; import { MatSelectChange } from '@angular/material/select'; +import { EuiLoadingService } from '@elemental-ui/core'; -import { JobPerformanceQueuesService } from './job-performance-queues.service'; +import { CollectionLoadParameters, EntitySchema, IClientProperty } from '@imx-modules/imx-qbm-dbts'; import { ClassloggerService, DataSourceToolbarSettings, SettingsService } from 'qbm'; -import { JobPerformanceService, JobPerformanceParameters } from './job-performance.service'; -import { CollectionLoadParameters, EntitySchema, IClientProperty } from 'imx-qbm-dbts'; - +import { JobPerformanceQueuesService } from './job-performance-queues.service'; +import { JobPerformanceService } from './job-performance.service'; @Component({ templateUrl: './job-performance.component.html', - styleUrls: ['./job-performance.component.scss'] + styleUrls: ['./job-performance.component.scss'], }) export class JobPerformanceComponent implements OnInit { public get Queues(): string[] { @@ -58,7 +57,7 @@ export class JobPerformanceComponent implements OnInit { private jobPerformance: JobPerformanceService, private logger: ClassloggerService, private readonly settingsService: SettingsService, - private busyService: EuiLoadingService + private busyService: EuiLoadingService, ) { this.entitySchemaJobPerformance = jobPerformance.EntitySchema; this.displayedColumns = [ @@ -87,31 +86,27 @@ export class JobPerformanceComponent implements OnInit { await this.getData({ StartIndex: 0, PageSize: this.settingsService.DefaultPageSize, queue: this.queueName }); } - public async getData(navigationState: JobPerformanceParameters): Promise { - + public async getData(navigationState: CollectionLoadParameters): Promise { this.navigationState = navigationState; let overlayRef: OverlayRef; - setTimeout(() => overlayRef = this.busyService.show()); + setTimeout(() => (overlayRef = this.busyService.show())); try { - - const jobPeformances = await this.jobPerformance.Get(navigationState); + const jobPeformances = await this.jobPerformance.Get({ ...navigationState, queue: this.queueName }); this.dstSettings = { displayedColumns: this.displayedColumns, dataSource: jobPeformances, entitySchema: this.entitySchemaJobPerformance, - navigationState: this.navigationState + navigationState: this.navigationState, }; - } finally { setTimeout(() => this.busyService.hide(overlayRef)); } } - private async UpdateQueueNames(): Promise { let overlayRef: OverlayRef; - setTimeout(() => overlayRef = this.busyService.show()); + setTimeout(() => (overlayRef = this.busyService.show())); try { this.queues = await this.jobPerformanceQueues.GetItems(); if (!this.queueName && this.queues.length > 0) { diff --git a/imxweb/projects/qer-app-operationssupport/src/app/processes/job-performance/job-performance.service.spec.ts b/imxweb/projects/qer-app-operationssupport/src/app/processes/job-performance/job-performance.service.spec.ts index 4dfcac4c5..f03422a00 100644 --- a/imxweb/projects/qer-app-operationssupport/src/app/processes/job-performance/job-performance.service.spec.ts +++ b/imxweb/projects/qer-app-operationssupport/src/app/processes/job-performance/job-performance.service.spec.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -24,7 +24,7 @@ * */ -import { OpsupportQueueJobperformance } from 'imx-api-qbm'; +import { OpsupportQueueJobperformance } from '@imx-modules/imx-api-qbm'; import { JobPerformanceService } from './job-performance.service'; import { testTypedEntityReadOnlyProvider } from '../../test-utilities/typed-entity-provider.spec'; import { ImxApiDtoMock } from '../../test-utilities/imx-api-mock.spec'; @@ -39,8 +39,8 @@ describe('QueueJobPerformanceService', () => { typedClient: { OpsupportQueueJobperformance: jasmine.createSpyObj('OpsupportQueueJobperformance', { GetSchema: () => OpsupportQueueJobperformance.GetEntitySchema(), - Get: Promise.resolve({ Data: data, totalCount: data.length }) - }) - } + Get: Promise.resolve({ Data: data, totalCount: data.length }), + }), + }, }); }); diff --git a/imxweb/projects/qer-app-operationssupport/src/app/processes/job-performance/job-performance.service.ts b/imxweb/projects/qer-app-operationssupport/src/app/processes/job-performance/job-performance.service.ts index 93d909e8e..c0487c225 100644 --- a/imxweb/projects/qer-app-operationssupport/src/app/processes/job-performance/job-performance.service.ts +++ b/imxweb/projects/qer-app-operationssupport/src/app/processes/job-performance/job-performance.service.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -26,8 +26,8 @@ import { Injectable } from '@angular/core'; -import { TypedEntityCollectionData, EntitySchema, CollectionLoadParameters } from 'imx-qbm-dbts'; -import { OpsupportQueueJobperformance } from 'imx-api-qbm'; +import { TypedEntityCollectionData, EntitySchema, CollectionLoadParameters } from '@imx-modules/imx-qbm-dbts'; +import { OpsupportQueueJobperformance } from '@imx-modules/imx-api-qbm'; import { imx_SessionService } from 'qbm'; export interface JobPerformanceParameters extends CollectionLoadParameters { @@ -35,9 +35,9 @@ export interface JobPerformanceParameters extends CollectionLoadParameters { } @Injectable({ - providedIn: 'root' + providedIn: 'root', }) -export class JobPerformanceService { +export class JobPerformanceService { public get EntitySchema(): EntitySchema { return this.session.TypedClient.OpsupportQueueJobperformance.GetSchema(); } diff --git a/imxweb/projects/qer-app-operationssupport/src/app/processes/jobs/jobs-gridview/jobs-gridview.component.html b/imxweb/projects/qer-app-operationssupport/src/app/processes/jobs/jobs-gridview/jobs-gridview.component.html index ecbda74c7..c77c46f80 100644 --- a/imxweb/projects/qer-app-operationssupport/src/app/processes/jobs/jobs-gridview/jobs-gridview.component.html +++ b/imxweb/projects/qer-app-operationssupport/src/app/processes/jobs/jobs-gridview/jobs-gridview.component.html @@ -10,25 +10,35 @@ > - - + +
    {{ dataItem.JobChainName.Column.GetDisplayValue() }}
    {{ dataItem.TaskName.Column.GetDisplayValue() }}
    - - + + - +
    -
    - @@ -45,7 +55,7 @@
    - diff --git a/imxweb/projects/qer-app-operationssupport/src/app/processes/jobs/jobs-gridview/jobs-gridview.component.scss b/imxweb/projects/qer-app-operationssupport/src/app/processes/jobs/jobs-gridview/jobs-gridview.component.scss index fd9a85618..80b454b8e 100644 --- a/imxweb/projects/qer-app-operationssupport/src/app/processes/jobs/jobs-gridview/jobs-gridview.component.scss +++ b/imxweb/projects/qer-app-operationssupport/src/app/processes/jobs/jobs-gridview/jobs-gridview.component.scss @@ -1,50 +1,7 @@ -@import "@elemental-ui/core/src/styles/_palette.scss"; +@import '@elemental-ui/core/src/styles/_palette.scss'; :host { display: flex; flex-direction: column; flex-grow: 1; overflow: hidden; } - -.imx-table-container { - flex: 1 1 auto; - display: flex; - flex-direction: column; - overflow: auto; - - > :nth-child(2) { - flex: 1 1 auto; - } - - ::ng-deep .mat-paginator { - margin-bottom: 0; - } -} - -div[subtitle] { - font-size: smaller; - color: $black-9; -} - - -.imx-button-bar { - display: flex; - justify-content: flex-end; - margin-top: 10px; - - > * { - margin-left: 5px; - } -} - -.imx-refresh-button { - margin-right: 5px; - height: 50px; -} - -.mat-raised-button.rightButtonFloat { - clear: both; - width: auto; - float: right; - padding: 0 20px; -} diff --git a/imxweb/projects/qer-app-operationssupport/src/app/processes/jobs/jobs-gridview/jobs-gridview.component.ts b/imxweb/projects/qer-app-operationssupport/src/app/processes/jobs/jobs-gridview/jobs-gridview.component.ts index 0a563e7f3..f9a8bb532 100644 --- a/imxweb/projects/qer-app-operationssupport/src/app/processes/jobs/jobs-gridview/jobs-gridview.component.ts +++ b/imxweb/projects/qer-app-operationssupport/src/app/processes/jobs/jobs-gridview/jobs-gridview.component.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -24,17 +24,32 @@ * */ -import { Component, Input, OnInit } from '@angular/core'; import { OverlayRef } from '@angular/cdk/overlay'; +import { Component, Input, OnInit } from '@angular/core'; import { EuiLoadingService, EuiSidesheetConfig, EuiSidesheetService } from '@elemental-ui/core'; -import { OpsupportQueueJobs, ReactivateJobMode } from 'imx-api-qbm'; -import { OpsupportQueueJobsParameters, QueueJobsService } from '../queue-jobs.service'; -import { SnackBarService, TextContainer, DataSourceToolbarSettings, DataSourceToolbarFilter, SettingsService, ClientPropertyForTableColumns } from 'qbm'; -import { CollectionLoadParameters, CompareOperator, DataModel, EntitySchema, FilterType, ValType } from 'imx-qbm-dbts'; -import { SingleFrozenJobComponent } from '../../frozen-jobs/single-frozen-job.component'; +import { OpsupportQueueJobs, ReactivateJobMode } from '@imx-modules/imx-api-qbm'; +import { + CollectionLoadParameters, + CompareOperator, + DataModel, + EntitySchema, + FilterType, + TypedEntity, + ValType, +} from '@imx-modules/imx-qbm-dbts'; import { TranslateService } from '@ngx-translate/core'; - +import { + calculateSidesheetWidth, + ClientPropertyForTableColumns, + DataSourceToolbarFilter, + DataSourceToolbarSettings, + SettingsService, + SnackBarService, + TextContainer, +} from 'qbm'; +import { SingleFrozenJobComponent } from '../../frozen-jobs/single-frozen-job.component'; +import { OpsupportQueueJobsParameters, QueueJobsService } from '../queue-jobs.service'; @Component({ selector: 'imx-jobs-gridview', @@ -68,7 +83,7 @@ export class JobsGridviewComponent implements OnInit { private busyService: EuiLoadingService, private readonly translator: TranslateService, private jobService: QueueJobsService, - settings: SettingsService + settings: SettingsService, ) { this.entitySchemaJobs = jobService.EntitySchema; this.displayedColumns = [ @@ -140,15 +155,16 @@ export class JobsGridviewComponent implements OnInit { return this.selectedJobs.length > 0; } - public async viewDetails(job: OpsupportQueueJobs): Promise { + public async viewDetails(job: TypedEntity): Promise { const opts: EuiSidesheetConfig = { title: await this.translator.get('#LDS#Heading Process Overview').toPromise(), - subTitle: job.JobChainName.Column.GetDisplayValue() + ' ' + job.XDateInserted.Column.GetDisplayValue(), - width: 'max(1000px, 80%)', + subTitle: + job.GetEntity().GetColumn('JobChainName').GetDisplayValue() + ' ' + job.GetEntity().GetColumn('XDateInserted').GetDisplayValue(), + width: calculateSidesheetWidth(1200, 0.7), icon: 'reboot', testId: 'job-details-sidesheet', data: { - UID_Tree: job.UID_Tree.value, + UID_Tree: job.GetEntity().GetColumn('UID_Tree').GetValue(), load: (startId: string) => { return this.jobService.getTreeData(startId); }, @@ -180,8 +196,8 @@ export class JobsGridviewComponent implements OnInit { this.retryJobs(this.selectedJobs, mode, { key: '#LDS#Your changes are being processed.', parameters: [this.selectedJobs.length] }); } - public onSelectionChanged(jobs: OpsupportQueueJobs[]): void { - this.selectedJobs = jobs; + public onSelectionChanged(jobs: TypedEntity[]): void { + this.selectedJobs = jobs as OpsupportQueueJobs[]; } public refresh(): void { @@ -232,7 +248,7 @@ export class JobsGridviewComponent implements OnInit { try { await this.jobService.Retry( mode, - jobs.map((job: OpsupportQueueJobs) => job.UID_Job.value) + jobs.map((job: OpsupportQueueJobs) => job.UID_Job.value), ); success = true; } finally { diff --git a/imxweb/projects/qer-app-operationssupport/src/app/processes/jobs/jobs.component.html b/imxweb/projects/qer-app-operationssupport/src/app/processes/jobs/jobs.component.html index 9323645b7..a46774067 100644 --- a/imxweb/projects/qer-app-operationssupport/src/app/processes/jobs/jobs.component.html +++ b/imxweb/projects/qer-app-operationssupport/src/app/processes/jobs/jobs.component.html @@ -1,15 +1,18 @@
    -

    #LDS#Processes

    - - {{infoText | translate}} +

    #LDS#Processes

    + + {{ infoText | translate }}
    - - {{(isShowGraph ? '#LDS#Chart view' : '#LDS#Table view') | translate}} + + {{ (isShowGraph ? '#LDS#Chart view' : '#LDS#Table view') | translate }} - - + diff --git a/imxweb/projects/qer-app-operationssupport/src/app/processes/jobs/jobs.component.scss b/imxweb/projects/qer-app-operationssupport/src/app/processes/jobs/jobs.component.scss index ee92c4df9..3798d2400 100644 --- a/imxweb/projects/qer-app-operationssupport/src/app/processes/jobs/jobs.component.scss +++ b/imxweb/projects/qer-app-operationssupport/src/app/processes/jobs/jobs.component.scss @@ -2,7 +2,7 @@ display: contents; max-height: 100%; flex: 1 1 auto; - + ::ng-deep .imx-table-container .imx-data-table-no-results { height: 100%; display: flex; @@ -14,16 +14,6 @@ .imx-heading-wrapper { display: flex; - - .imx-helper-alert { - display: flex; - margin: 0 0 20px auto; - align-self: flex-end; - width: 70%; - } -} -.jobs-toggle-showGraph { - margin-bottom: 10px; } .imx-filter-title { @@ -37,7 +27,6 @@ flex-direction: column; } - imx-jobqueue-overview { display: flex; flex: 1 1 auto; @@ -48,4 +37,4 @@ imx-jobqueue-overview { .imx-job-line { display: flex; flex-direction: row; -} \ No newline at end of file +} diff --git a/imxweb/projects/qer-app-operationssupport/src/app/processes/jobs/jobs.component.ts b/imxweb/projects/qer-app-operationssupport/src/app/processes/jobs/jobs.component.ts index 68a53d3be..684117423 100644 --- a/imxweb/projects/qer-app-operationssupport/src/app/processes/jobs/jobs.component.ts +++ b/imxweb/projects/qer-app-operationssupport/src/app/processes/jobs/jobs.component.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -28,16 +28,16 @@ import { Component, OnInit } from '@angular/core'; import { ActivatedRoute } from '@angular/router'; @Component({ templateUrl: './jobs.component.html', - styleUrls: ['./jobs.component.scss'] + styleUrls: ['./jobs.component.scss'], }) export class JobsComponent implements OnInit { - public failed = false; public isShowGraph = false; - public infoText = '#LDS#Here you can get an overview of all processes of the JobQueue. You can view them individually in a table or grouped by status in a chart. Additionally, you can handle failed processes.'; + public infoText = + '#LDS#Here you can get an overview of all processes of the JobQueue. You can view them individually in a table or grouped by status in a chart. Additionally, you can handle failed processes.'; - constructor(private activeRoute: ActivatedRoute) { } + constructor(private activeRoute: ActivatedRoute) {} public ngOnInit(): void { const failed = this.activeRoute.snapshot.queryParamMap.get('failed'); @@ -46,5 +46,4 @@ export class JobsComponent implements OnInit { this.failed = failed === 'true'; } } - } diff --git a/imxweb/projects/qer-app-operationssupport/src/app/processes/jobs/queue-jobs.service.ts b/imxweb/projects/qer-app-operationssupport/src/app/processes/jobs/queue-jobs.service.ts index af426c7e2..1eea8fe7a 100644 --- a/imxweb/projects/qer-app-operationssupport/src/app/processes/jobs/queue-jobs.service.ts +++ b/imxweb/projects/qer-app-operationssupport/src/app/processes/jobs/queue-jobs.service.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -26,9 +26,17 @@ import { Injectable } from '@angular/core'; -import { EntityCollectionData, EntitySchema, TypedEntityCollectionData, FilterData, CollectionLoadParameters, DataModel, TypedEntity } from 'imx-qbm-dbts'; +import { OpsupportQueueJobs, ReactivateJobMode } from '@imx-modules/imx-api-qbm'; +import { + CollectionLoadParameters, + DataModel, + EntityCollectionData, + EntitySchema, + FilterData, + TypedEntity, + TypedEntityCollectionData, +} from '@imx-modules/imx-qbm-dbts'; import { DataSourceToolbarFilter, imx_SessionService } from 'qbm'; -import { OpsupportQueueJobs, ReactivateJobMode } from 'imx-api-qbm'; export interface OpsupportQueueJobsParameters extends CollectionLoadParameters { frozen?: boolean; @@ -42,18 +50,18 @@ export class QueueJobsService { return this.session.TypedClient.OpsupportQueueJobs.GetSchema(); } - constructor(private session: imx_SessionService) { } + constructor(private session: imx_SessionService) {} public Get(parameters: OpsupportQueueJobsParameters): Promise> { return this.session.TypedClient.OpsupportQueueJobs.Get(parameters); } public async getFilters(): Promise { - return (await this.getDataModel()).Filters; + return (await this.getDataModel()).Filters ?? []; } public async getDataModel(): Promise { - return this.session.Client.opsupport_queue_jobs_datamodel_get(undefined); + return this.session.Client.opsupport_queue_jobs_datamodel_get(); } public Post(jobs: string[]): Promise { @@ -64,8 +72,7 @@ export class QueueJobsService { return this.session.Client.opsupport_queue_reactivatejob_post({ Mode: mode, UidJobs: jobs }); } - - public getTreeData(startUid: string): Promise>{ + public getTreeData(startUid: string): Promise> { return this.session.TypedClient.OpsupportQueueTree.Get({ uidtree: startUid }); } } diff --git a/imxweb/projects/qer-app-operationssupport/src/app/processes/objects-by-id/change-operation-sidesheet/change-operation-sidesheet.component.html b/imxweb/projects/qer-app-operationssupport/src/app/processes/objects-by-id/change-operation-sidesheet/change-operation-sidesheet.component.html index cc18c5fbd..8facd62a4 100644 --- a/imxweb/projects/qer-app-operationssupport/src/app/processes/objects-by-id/change-operation-sidesheet/change-operation-sidesheet.component.html +++ b/imxweb/projects/qer-app-operationssupport/src/app/processes/objects-by-id/change-operation-sidesheet/change-operation-sidesheet.component.html @@ -1,15 +1,15 @@
    -
    +
    - +
    -
    +
    @@ -17,33 +17,33 @@ - {{column.ColumnDisplay}} + {{ column.ColumnDisplay }} - + - +
    - {{'#LDS#Column name' | translate}} - + {{ '#LDS#Column name' | translate }} + - {{'#LDS#New value' | translate}} - + {{ '#LDS#New value' | translate }} + - {{'#LDS#Old value' | translate}} - + {{ '#LDS#Old value' | translate }} +
    diff --git a/imxweb/projects/qer-app-operationssupport/src/app/processes/objects-by-id/change-operation-sidesheet/change-operation-sidesheet.component.scss b/imxweb/projects/qer-app-operationssupport/src/app/processes/objects-by-id/change-operation-sidesheet/change-operation-sidesheet.component.scss index 781140e5e..75ab9ad9c 100644 --- a/imxweb/projects/qer-app-operationssupport/src/app/processes/objects-by-id/change-operation-sidesheet/change-operation-sidesheet.component.scss +++ b/imxweb/projects/qer-app-operationssupport/src/app/processes/objects-by-id/change-operation-sidesheet/change-operation-sidesheet.component.scss @@ -1,4 +1,3 @@ - :host { .wrapper { height: 100%; @@ -17,5 +16,6 @@ height: 100%; align-items: center; justify-content: center; + } } diff --git a/imxweb/projects/qer-app-operationssupport/src/app/processes/objects-by-id/change-operation-sidesheet/change-operation-sidesheet.component.ts b/imxweb/projects/qer-app-operationssupport/src/app/processes/objects-by-id/change-operation-sidesheet/change-operation-sidesheet.component.ts index 9bb85ba30..2ceab1312 100644 --- a/imxweb/projects/qer-app-operationssupport/src/app/processes/objects-by-id/change-operation-sidesheet/change-operation-sidesheet.component.ts +++ b/imxweb/projects/qer-app-operationssupport/src/app/processes/objects-by-id/change-operation-sidesheet/change-operation-sidesheet.component.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -26,31 +26,31 @@ import { Component, Inject, OnDestroy, OnInit } from '@angular/core'; import { EUI_SIDESHEET_DATA, EuiSidesheetRef } from '@elemental-ui/core'; -import { HistoryOperation } from 'imx-api-qbm'; +import { HistoryOperation } from '@imx-modules/imx-api-qbm'; import { Subscription } from 'rxjs'; @Component({ selector: 'imx-change-operation-sidesheet', templateUrl: './change-operation-sidesheet.component.html', - styleUrls: ['./change-operation-sidesheet.component.scss'] + styleUrls: ['./change-operation-sidesheet.component.scss'], }) export class ChangeOperationSidesheetComponent implements OnInit, OnDestroy { + public isMulti: boolean; public isOpening = true; private openSub$: Subscription; constructor( @Inject(EUI_SIDESHEET_DATA) public data: HistoryOperation, - private sidesheetRef: EuiSidesheetRef + private sidesheetRef: EuiSidesheetRef, ) {} - public get isMulti(): boolean { - return this.data?.Columns && this.data.Columns.length > 1; - } - public ngOnInit(): void { - this.openSub$ = this.sidesheetRef.componentInstance.onOpen().subscribe(_ => { - this.isOpening = false; - }); + this.isMulti = this.data.Columns ? this.data.Columns.length > 1 : false; + if (this.sidesheetRef.componentInstance) { + this.openSub$ = this.sidesheetRef.componentInstance.onOpen().subscribe((_) => { + this.isOpening = false; + }); + } } public ngOnDestroy(): void { diff --git a/imxweb/projects/qer-app-operationssupport/src/app/processes/objects-by-id/change-operation-table.component.html b/imxweb/projects/qer-app-operationssupport/src/app/processes/objects-by-id/change-operation-table.component.html index 141159bbf..d66267cd5 100644 --- a/imxweb/projects/qer-app-operationssupport/src/app/processes/objects-by-id/change-operation-table.component.html +++ b/imxweb/projects/qer-app-operationssupport/src/app/processes/objects-by-id/change-operation-table.component.html @@ -1,9 +1,8 @@ {{ columnDef.getTitle() }} - {{ columnDef.getValue(row) }} - + {{ columnDef.getValue(row) }} - - + + diff --git a/imxweb/projects/qer-app-operationssupport/src/app/processes/objects-by-id/change-operation-table.component.scss b/imxweb/projects/qer-app-operationssupport/src/app/processes/objects-by-id/change-operation-table.component.scss index 4bcd5af05..7ed9716d9 100644 --- a/imxweb/projects/qer-app-operationssupport/src/app/processes/objects-by-id/change-operation-table.component.scss +++ b/imxweb/projects/qer-app-operationssupport/src/app/processes/objects-by-id/change-operation-table.component.scss @@ -1,5 +1,4 @@ - -.flex-property{ +.flex-property { flex: 1 1 auto; display: flex; flex-direction: column; diff --git a/imxweb/projects/qer-app-operationssupport/src/app/processes/objects-by-id/change-operation-table.component.ts b/imxweb/projects/qer-app-operationssupport/src/app/processes/objects-by-id/change-operation-table.component.ts index 7ad686f4d..914707878 100644 --- a/imxweb/projects/qer-app-operationssupport/src/app/processes/objects-by-id/change-operation-table.component.ts +++ b/imxweb/projects/qer-app-operationssupport/src/app/processes/objects-by-id/change-operation-table.component.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -24,42 +24,42 @@ * */ -import { Component, OnInit, Input } from "@angular/core"; -import { EuiSidesheetService } from "@elemental-ui/core"; -import { TranslateService } from "@ngx-translate/core"; -import { HistoryOperation, ChangeType } from "imx-api-qbm"; -import { ChangeOperationSidesheetComponent } from "./change-operation-sidesheet/change-operation-sidesheet.component"; +import { Component, Input, OnInit } from '@angular/core'; +import { EuiSidesheetService } from '@elemental-ui/core'; +import { ChangeType, HistoryOperation } from '@imx-modules/imx-api-qbm'; +import { TranslateService } from '@ngx-translate/core'; +import { calculateSidesheetWidth } from 'qbm'; +import { ChangeOperationSidesheetComponent } from './change-operation-sidesheet/change-operation-sidesheet.component'; interface IColumn { id: string; title: string; - getValue: (row: HistoryOperation) => string; + getValue: (row: HistoryOperation) => string | undefined; } class Column implements IColumn { public id: string; public getTitle: () => string; - public getValue: (row: HistoryOperation) => string; + public getValue: (row: HistoryOperation) => string | undefined; public title: string; } @Component({ templateUrl: './change-operation-table.component.html', selector: 'imx-change-operation-table', - styleUrls: ['./change-operation-table.component.scss'] + styleUrls: ['./change-operation-table.component.scss'], }) export class ChangeOperationTableComponent implements OnInit { - - constructor(private translationProvider: TranslateService, + constructor( + private translationProvider: TranslateService, private sidesheet: EuiSidesheetService, - ) { - } + ) {} @Input() public data: HistoryOperation[] = []; public columnDefs: Column[] = []; public get columns(): string[] { - return this.columnDefs.map(c => c.id); + return this.columnDefs.map((c) => c.id); } ngOnInit(): void { @@ -75,51 +75,49 @@ export class ChangeOperationTableComponent implements OnInit { this.columnDefs.push(column); } - private async changeTypeTableColumn(){ + private async changeTypeTableColumn() { await this.addColumnDef({ id: 'ChangeTime', title: '#LDS#Operation performed on', - getValue: (row: HistoryOperation) => new Date(row.ChangeTime).toLocaleString(this.translationProvider.currentLang) + getValue: (row: HistoryOperation) => new Date(row.ChangeTime).toLocaleString(this.translationProvider.currentLang), }); await this.addColumnDef({ id: 'ChangeType', title: '#LDS#Type of operation', - getValue: (row: HistoryOperation) => Object.values(ChangeType)[row.ChangeType].toString() + getValue: (row: HistoryOperation) => Object.values(ChangeType)[row.ChangeType].toString(), }); await this.addColumnDef({ id: 'ObjectDisplay', title: '#LDS#Object name', - getValue: (row: HistoryOperation) => row.ObjectDisplay + getValue: (row: HistoryOperation) => row.ObjectDisplay, }); await this.addColumnDef({ id: 'DisplayType', title: '#LDS#Object type', - getValue: (row: HistoryOperation) => row.DisplayType + getValue: (row: HistoryOperation) => row.DisplayType, }); await this.addColumnDef({ id: 'User', title: '#LDS#Operation performed by', - getValue: (row: HistoryOperation) => row.User + getValue: (row: HistoryOperation) => row.User, }); } public async displayChangedPropertyListSidesheet(row: HistoryOperation) { if (row.Columns && row.Columns.length > 0) { let title = await this.translationProvider.get('#LDS#Heading View Operation Details').toPromise(); - let subtitle = await this.translationProvider.get('#LDS#Type of operation').toPromise() + Object.values(ChangeType)[row.ChangeType].toString(); + let subtitle = + (await this.translationProvider.get('#LDS#Type of operation').toPromise()) + Object.values(ChangeType)[row.ChangeType].toString(); - if( row.ObjectDisplay) - subtitle += await this.translationProvider.get('#LDS#Object').toPromise() + row.ObjectDisplay + if (row.ObjectDisplay) subtitle += (await this.translationProvider.get('#LDS#Object').toPromise()) + row.ObjectDisplay; - this.sidesheet.open(ChangeOperationSidesheetComponent, - { - title: title, - subTitle: subtitle , - width: 'max(400px, 40%)', - data: row, - testId: 'data-change-details-sidesheet' - } - ); + this.sidesheet.open(ChangeOperationSidesheetComponent, { + title: title, + subTitle: subtitle, + width: calculateSidesheetWidth(700, 0.4), + data: row, + testId: 'data-change-details-sidesheet', + }); } } } diff --git a/imxweb/projects/qer-app-operationssupport/src/app/processes/objects-by-id/object-by-id.service.ts b/imxweb/projects/qer-app-operationssupport/src/app/processes/objects-by-id/object-by-id.service.ts index e9ab9b228..65d5089b3 100644 --- a/imxweb/projects/qer-app-operationssupport/src/app/processes/objects-by-id/object-by-id.service.ts +++ b/imxweb/projects/qer-app-operationssupport/src/app/processes/objects-by-id/object-by-id.service.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -26,12 +26,12 @@ import { Injectable } from '@angular/core'; -import { EntitySchema, CollectionLoadParameters } from 'imx-qbm-dbts'; +import { EntitySchema, CollectionLoadParameters } from '@imx-modules/imx-qbm-dbts'; import { imx_SessionService } from 'qbm'; -import { HistoryOperationsData} from 'imx-api-qbm'; +import { HistoryOperationsData } from '@imx-modules/imx-api-qbm'; export interface OpsupportQueueJobsParameters extends CollectionLoadParameters { - processId:string; + processId: string; } @Injectable() @@ -40,7 +40,7 @@ export class ObjectByIdService { return this.session.TypedClient.OpsupportQueueJobs.GetSchema(); } - constructor(private session: imx_SessionService) { } + constructor(private session: imx_SessionService) {} public async getChangeOperation(parameters: string): Promise { return this.session.Client.opsupport_changeoperations_process_get(parameters); diff --git a/imxweb/projects/qer-app-operationssupport/src/app/processes/objects-by-id/objects-by-id.component.html b/imxweb/projects/qer-app-operationssupport/src/app/processes/objects-by-id/objects-by-id.component.html index a3946b500..d15fb2559 100644 --- a/imxweb/projects/qer-app-operationssupport/src/app/processes/objects-by-id/objects-by-id.component.html +++ b/imxweb/projects/qer-app-operationssupport/src/app/processes/objects-by-id/objects-by-id.component.html @@ -1,12 +1,12 @@ -

    +

    {{ '#LDS#Heading Processes and Operations by Process ID' | translate }} -

    + - +
    - + - + >
    -
    +

    {{ noDataText | translate }}

    - +
    -
    +

    diff --git a/imxweb/projects/qer-app-operationssupport/src/app/processes/objects-by-id/objects-by-id.component.scss b/imxweb/projects/qer-app-operationssupport/src/app/processes/objects-by-id/objects-by-id.component.scss index 61be1948f..e743db4a8 100644 --- a/imxweb/projects/qer-app-operationssupport/src/app/processes/objects-by-id/objects-by-id.component.scss +++ b/imxweb/projects/qer-app-operationssupport/src/app/processes/objects-by-id/objects-by-id.component.scss @@ -1,77 +1,42 @@ @import '@elemental-ui/core/src/styles/_palette.scss'; +@import 'base/variables'; +@import 'base/mixins'; -$SearchBarWidth: 535px; -$SearchBarHeight: 45px; :host { - display: flex; - flex-direction: column; - flex-grow: 1; - height: 100%; - mat-card { - display: flex; - flex-direction: column; - flex: 1 1 auto; - overflow:hidden; - } + @include flex-column-container-fill(); } .imx-searchbar-card { - max-width: $SearchBarWidth; - width: $SearchBarWidth; + max-width: $IMX_SearchBar_Width; + width: $IMX_SearchBar_Width; padding: 0px 10px; display: inline-block; } -.mat-paginator { - box-shadow: none; - margin-bottom: 6px; -} - .imx-procces-action{ display: flex; align-items: center; margin-bottom: 20px; } -.mat-card .imx-searchbar-input { - border: 0 solid transparent; - font-size: 1.2em; - margin-bottom: 0; - width: 450px; - height: $SearchBarHeight; - box-sizing: border-box; - flex-grow: 0; - flex-shrink: 0; - /* use flex-basis, because of flex shorthand with calc()s doesn't work in IE */ - flex-basis: calc(100% - 52px); -} -.mat-card .imx-searchbar-input::placeholder { - font-style: italic; -} -.imx-searchbar-input::-ms-clear { - /* hide input-clear button (the 'X') in > IE 10 */ - display: none; - width: 0; - height: 0; -} -.mat-radio-button{ +.mat-mdc-radio-button { margin-left: 15px; } -.flex-property{ +.flex-property { flex: 1 1 auto; display: flex; flex-direction: column; overflow: auto; } -.imx_MatTableRow{ +.imx_MatTableRow { cursor: pointer; } -.imx_MatTableHeaderRow{ +.imx_MatTableHeaderRow { padding-top: 20px; padding-bottom: 20px; } -.imx-change-table-no-results { +.imx-no-results { text-align: center; margin: 20px 0; flex: 1 1 auto; @@ -79,10 +44,7 @@ $SearchBarHeight: 45px; flex-direction: column; justify-content: center; background-color: $color-gray-0; - .eui-icon { - font-size: 100px; - color: $color-gray-10; - } + p { margin: 0; font-size: 18px; @@ -91,12 +53,10 @@ $SearchBarHeight: 45px; } .eui-dark-theme { - :host{ - .imx-change-table-no-results { + :host { + .imx-no-results { background-color: $color-gray-70; - eui-icon { - color: $color-gray-20; - } + p { color: $color-gray-10; } diff --git a/imxweb/projects/qer-app-operationssupport/src/app/processes/objects-by-id/objects-by-id.component.ts b/imxweb/projects/qer-app-operationssupport/src/app/processes/objects-by-id/objects-by-id.component.ts index 639696309..250dea5df 100644 --- a/imxweb/projects/qer-app-operationssupport/src/app/processes/objects-by-id/objects-by-id.component.ts +++ b/imxweb/projects/qer-app-operationssupport/src/app/processes/objects-by-id/objects-by-id.component.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -25,15 +25,15 @@ */ import { OverlayRef } from '@angular/cdk/overlay'; -import { Component, ViewChild } from '@angular/core'; -import { MatPaginator, PageEvent } from '@angular/material/paginator'; +import { Component } from '@angular/core'; +import { FormControl } from '@angular/forms'; +import { PageEvent } from '@angular/material/paginator'; import { MatRadioChange } from '@angular/material/radio'; import { EuiLoadingService } from '@elemental-ui/core'; import { debounceTime, distinctUntilChanged } from 'rxjs/operators'; -import { FormControl } from '@angular/forms'; -import { HistoryOperation } from 'imx-api-qbm'; -import { TypedEntityCollectionData } from 'imx-qbm-dbts'; +import { HistoryOperation } from '@imx-modules/imx-api-qbm'; +import { TypedEntityCollectionData } from '@imx-modules/imx-qbm-dbts'; import { SettingsService } from 'qbm'; import { ObjectByIdService } from './object-by-id.service'; @@ -58,7 +58,7 @@ export class ObjectsByIdComponent { ]; public selectedType = this.filterOptions[0].value; public processId: string; - public searchControl = new FormControl(''); + public searchControl = new FormControl('', { nonNullable: true }); public isShowGraph = false; public historyData: HistoryOperation[] = []; @@ -66,7 +66,6 @@ export class ObjectsByIdComponent { public dataCollection: TypedEntityCollectionData; private stateCached: { page: number; pageSize: number; skip: number }; - @ViewChild(MatPaginator) private paginator: MatPaginator; public paginatorConfig = { index: 0, size: 5, @@ -75,11 +74,15 @@ export class ObjectsByIdComponent { hidden: false, }; - constructor(private busyService: EuiLoadingService, private objectByIdService: ObjectByIdService, private settings: SettingsService) { + constructor( + private busyService: EuiLoadingService, + private objectByIdService: ObjectByIdService, + private settings: SettingsService, + ) { this.paginatorConfig.size = this.settings.DefaultPageSize; this.searchControl.valueChanges .pipe(distinctUntilChanged(), debounceTime(300)) - .subscribe(async () => await this.search(this.searchControl.value)); + .subscribe(async () => await this.onSearch(this.searchControl.value)); } public async typeChanged(evt: MatRadioChange) { @@ -93,7 +96,7 @@ export class ObjectsByIdComponent { let overlayRef: OverlayRef; setTimeout(() => (overlayRef = this.busyService.show())); try { - this.historyData = (await this.objectByIdService.getChangeOperation(this.processId)).Events; + this.historyData = (await this.objectByIdService.getChangeOperation(this.processId)).Events ?? []; } catch { this.historyData = []; } finally { @@ -103,7 +106,7 @@ export class ObjectsByIdComponent { } } - private async search(term: string): Promise { + private async onSearch(term: string): Promise { this.processId = term; await this.getChangeOperation(); } diff --git a/imxweb/projects/qer-app-operationssupport/src/app/processes/processes.module.ts b/imxweb/projects/qer-app-operationssupport/src/app/processes/processes.module.ts index 5b2d23d12..99fddbb9b 100644 --- a/imxweb/projects/qer-app-operationssupport/src/app/processes/processes.module.ts +++ b/imxweb/projects/qer-app-operationssupport/src/app/processes/processes.module.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -39,8 +39,15 @@ import { MatMenuModule } from '@angular/material/menu'; import { FormsModule } from '@angular/forms'; import { MatSlideToggleModule } from '@angular/material/slide-toggle'; - -import { BusyIndicatorModule, DataSourceToolbarModule, DataTableModule, JobQueueOverviewModule, LdsReplaceModule, ObjectHistoryModule, QbmModule } from 'qbm'; +import { + BusyIndicatorModule, + DataSourceToolbarModule, + DataTableModule, + JobQueueOverviewModule, + LdsReplaceModule, + ObjectHistoryModule, + QbmModule, +} from 'qbm'; import { FrozenJobsComponent } from './frozen-jobs/frozen-jobs.component'; import { SingleFrozenJobComponent } from './frozen-jobs/single-frozen-job.component'; import { JobChainsComponent } from './job-chains/job-chains.component'; @@ -63,7 +70,6 @@ import { ChangeOperationTableComponent } from './objects-by-id/change-operation- import { MatProgressSpinnerModule } from '@angular/material/progress-spinner'; import { MatProgressBarModule } from '@angular/material/progress-bar'; - @NgModule({ declarations: [ FrozenJobsComponent, @@ -103,7 +109,7 @@ import { MatProgressBarModule } from '@angular/material/progress-bar'; MatSlideToggleModule, JobQueueOverviewModule, ObjectHistoryModule, - BusyIndicatorModule + BusyIndicatorModule, ], providers: [ QueueTreeService, @@ -112,7 +118,7 @@ import { MatProgressBarModule } from '@angular/material/progress-bar'; JobPerformanceQueuesService, JobPerformanceService, FrozenJobsService, - ObjectByIdService - ] + ObjectByIdService, + ], }) -export class ProcessesModule { } +export class ProcessesModule {} diff --git a/imxweb/projects/qer-app-operationssupport/src/app/service-report/job-servers-details/job-servers-details.component.html b/imxweb/projects/qer-app-operationssupport/src/app/service-report/job-servers-details/job-servers-details.component.html index ccdca5b53..79c85380f 100644 --- a/imxweb/projects/qer-app-operationssupport/src/app/service-report/job-servers-details/job-servers-details.component.html +++ b/imxweb/projects/qer-app-operationssupport/src/app/service-report/job-servers-details/job-servers-details.component.html @@ -1,17 +1,17 @@ - + -
    +
    - {{roles.Display}} + {{ roles.Display }}
    -
    +
    -
    {{tag.Display}}
    - {{tag.Description}} +
    {{ tag.Display }}
    + {{ tag.Description }}
    - \ No newline at end of file + diff --git a/imxweb/projects/qer-app-operationssupport/src/app/service-report/job-servers-details/job-servers-details.component.scss b/imxweb/projects/qer-app-operationssupport/src/app/service-report/job-servers-details/job-servers-details.component.scss index f01ec035c..a1cf04d75 100644 --- a/imxweb/projects/qer-app-operationssupport/src/app/service-report/job-servers-details/job-servers-details.component.scss +++ b/imxweb/projects/qer-app-operationssupport/src/app/service-report/job-servers-details/job-servers-details.component.scss @@ -1,11 +1,4 @@ -::ng-deep .mat-tab-body { - margin: 20px; -} - -.imx-server-details-machine-roles, .imx-server-details-tags { +.imx-server-details-machine-roles, +.imx-server-details-tags { margin-bottom: 20px; } - -.mat-tab-group { - overflow-y: auto; -} \ No newline at end of file diff --git a/imxweb/projects/qer-app-operationssupport/src/app/service-report/job-servers-details/job-servers-details.component.spec.ts b/imxweb/projects/qer-app-operationssupport/src/app/service-report/job-servers-details/job-servers-details.component.spec.ts index 80d576c65..3f643800f 100644 --- a/imxweb/projects/qer-app-operationssupport/src/app/service-report/job-servers-details/job-servers-details.component.spec.ts +++ b/imxweb/projects/qer-app-operationssupport/src/app/service-report/job-servers-details/job-servers-details.component.spec.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -28,24 +28,25 @@ import { ComponentFixture, TestBed } from '@angular/core/testing'; import { JobServersDetailsComponent } from './job-servers-details.component'; import { EUI_SIDESHEET_DATA } from '@elemental-ui/core'; +import { TranslateModule } from '@ngx-translate/core'; describe('JobServersDetailsComponent', () => { let component: JobServersDetailsComponent; let fixture: ComponentFixture; const sidesheetData = { - Tags:[], - MachineRoles:[] + Tags: [], + MachineRoles: [], }; beforeEach(async () => { await TestBed.configureTestingModule({ - declarations: [ JobServersDetailsComponent ], - providers:[ + declarations: [JobServersDetailsComponent], + imports: [TranslateModule.forRoot()], + providers: [ { provide: EUI_SIDESHEET_DATA, - useValue: sidesheetData - } - ] - }) - .compileComponents(); + useValue: sidesheetData, + }, + ], + }).compileComponents(); }); beforeEach(() => { diff --git a/imxweb/projects/qer-app-operationssupport/src/app/service-report/job-servers-details/job-servers-details.component.ts b/imxweb/projects/qer-app-operationssupport/src/app/service-report/job-servers-details/job-servers-details.component.ts index a3733b8bc..0517035d4 100644 --- a/imxweb/projects/qer-app-operationssupport/src/app/service-report/job-servers-details/job-servers-details.component.ts +++ b/imxweb/projects/qer-app-operationssupport/src/app/service-report/job-servers-details/job-servers-details.component.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -27,20 +27,21 @@ import { Component, Inject, OnInit } from '@angular/core'; import { EUI_SIDESHEET_DATA } from '@elemental-ui/core'; import { TranslateService } from '@ngx-translate/core'; -import { OpsupportJobservers, ServerExtendedDataItem } from 'imx-api-qbm'; +import { OpsupportJobservers, ServerExtendedDataItem } from '@imx-modules/imx-api-qbm'; @Component({ selector: 'imx-job-servers-details', templateUrl: './job-servers-details.component.html', - styleUrls: ['./job-servers-details.component.scss'] + styleUrls: ['./job-servers-details.component.scss'], }) export class JobServersDetailsComponent { - - public tags:ServerExtendedDataItem[]; - public machineRoles:ServerExtendedDataItem[]; - constructor(@Inject(EUI_SIDESHEET_DATA) public serverDetails: OpsupportJobservers, - private translate : TranslateService) { - this.tags = serverDetails['Tags']; - this.machineRoles = serverDetails['MachineRoles']; - } + public tags: ServerExtendedDataItem[]; + public machineRoles: ServerExtendedDataItem[]; + constructor( + @Inject(EUI_SIDESHEET_DATA) public serverDetails: OpsupportJobservers, + private translate: TranslateService, + ) { + this.tags = serverDetails['Tags']; + this.machineRoles = serverDetails['MachineRoles']; + } } diff --git a/imxweb/projects/qer-app-operationssupport/src/app/service-report/job-servers-edit/job-servers-edit.component.html b/imxweb/projects/qer-app-operationssupport/src/app/service-report/job-servers-edit/job-servers-edit.component.html index 80a98a2e2..4700fd198 100644 --- a/imxweb/projects/qer-app-operationssupport/src/app/service-report/job-servers-edit/job-servers-edit.component.html +++ b/imxweb/projects/qer-app-operationssupport/src/app/service-report/job-servers-edit/job-servers-edit.component.html @@ -2,13 +2,23 @@
    - +
    -
    - +
    +
    diff --git a/imxweb/projects/qer-app-operationssupport/src/app/service-report/job-servers-edit/job-servers-edit.component.scss b/imxweb/projects/qer-app-operationssupport/src/app/service-report/job-servers-edit/job-servers-edit.component.scss index 265f55c89..4d903483d 100644 --- a/imxweb/projects/qer-app-operationssupport/src/app/service-report/job-servers-edit/job-servers-edit.component.scss +++ b/imxweb/projects/qer-app-operationssupport/src/app/service-report/job-servers-edit/job-servers-edit.component.scss @@ -1 +1 @@ -//Job Servers Edit Component Styles \ No newline at end of file +//Job Servers Edit Component Styles diff --git a/imxweb/projects/qer-app-operationssupport/src/app/service-report/job-servers-edit/job-servers-edit.component.spec.ts b/imxweb/projects/qer-app-operationssupport/src/app/service-report/job-servers-edit/job-servers-edit.component.spec.ts index 5f81ba00b..954888a15 100644 --- a/imxweb/projects/qer-app-operationssupport/src/app/service-report/job-servers-edit/job-servers-edit.component.spec.ts +++ b/imxweb/projects/qer-app-operationssupport/src/app/service-report/job-servers-edit/job-servers-edit.component.spec.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -29,11 +29,12 @@ import { ComponentFixture, TestBed } from '@angular/core/testing'; import { JobServersEditComponent } from './job-servers-edit.component'; import { EuiLoadingService, EuiSidesheetService, EUI_SIDESHEET_DATA, EuiSidesheetRef } from '@elemental-ui/core'; import { of } from 'rxjs'; -import { OpsupportJobservers } from 'imx-api-qbm'; +import { OpsupportJobservers } from '@imx-modules/imx-api-qbm'; import { JobServersService } from '../job-servers.service'; import { MatSnackBar, MatSnackBarModule } from '@angular/material/snack-bar'; import { SnackBarService } from '../../../../../qbm/src/lib/snackbar/snack-bar.service'; import { ConfirmationService } from 'qbm'; +import { TranslateModule } from '@ngx-translate/core'; describe('JobServersEditComponent', () => { let component: JobServersEditComponent; let fixture: ComponentFixture; @@ -48,14 +49,14 @@ describe('JobServersEditComponent', () => { open: jasmine.createSpy('open'), dismiss: jasmine.createSpy('dismiss'), }; - let confirm = true; - const mockConfirmationService = { - confirm: jasmine.createSpy('confirm').and.callFake(() => Promise.resolve(confirm)), - }; + let confirm = true; + const mockConfirmationService = { + confirm: jasmine.createSpy('confirm').and.callFake(() => Promise.resolve(confirm)), + }; beforeEach(async () => { await TestBed.configureTestingModule({ declarations: [JobServersEditComponent], - imports: [MatSnackBarModule], + imports: [MatSnackBarModule, TranslateModule.forRoot()], providers: [ { provide: MatSnackBar, diff --git a/imxweb/projects/qer-app-operationssupport/src/app/service-report/job-servers-edit/job-servers-edit.component.ts b/imxweb/projects/qer-app-operationssupport/src/app/service-report/job-servers-edit/job-servers-edit.component.ts index 1161dc531..f4f2bae7a 100644 --- a/imxweb/projects/qer-app-operationssupport/src/app/service-report/job-servers-edit/job-servers-edit.component.ts +++ b/imxweb/projects/qer-app-operationssupport/src/app/service-report/job-servers-edit/job-servers-edit.component.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -28,7 +28,7 @@ import { Component, Inject, OnInit } from '@angular/core'; import { EuiLoadingService, EuiSidesheetService, EUI_SIDESHEET_DATA, EuiSidesheetRef } from '@elemental-ui/core'; import { FormGroup, FormArray } from '@angular/forms'; import { BaseCdr, ColumnDependentReference, ConfirmationService, SnackBarService } from 'qbm'; -import { OpsupportJobservers } from 'imx-api-qbm'; +import { OpsupportJobservers } from '@imx-modules/imx-api-qbm'; @Component({ selector: 'imx-job-servers-edit', @@ -39,12 +39,12 @@ export class JobServersEditComponent implements OnInit { public readonly serverDetailsFormGroup: FormGroup; public cdrList: ColumnDependentReference[] = []; constructor( - @Inject(EUI_SIDESHEET_DATA) public serverDetails:{data: OpsupportJobservers, properties: string[]}, + @Inject(EUI_SIDESHEET_DATA) public serverDetails: { data: OpsupportJobservers; properties: string[] }, private readonly sidesheet: EuiSidesheetService, private readonly sidesheetRef: EuiSidesheetRef, private readonly snackBarService: SnackBarService, private readonly euiLoadingService: EuiLoadingService, - private readonly confirmation: ConfirmationService + private readonly confirmation: ConfirmationService, ) { this.serverDetailsFormGroup = new FormGroup({ formArray: new FormArray([]), diff --git a/imxweb/projects/qer-app-operationssupport/src/app/service-report/job-servers-gridview.component.html b/imxweb/projects/qer-app-operationssupport/src/app/service-report/job-servers-gridview.component.html index 9e9c057ed..3719f3e96 100644 --- a/imxweb/projects/qer-app-operationssupport/src/app/service-report/job-servers-gridview.component.html +++ b/imxweb/projects/qer-app-operationssupport/src/app/service-report/job-servers-gridview.component.html @@ -9,7 +9,7 @@ > - + @@ -55,9 +55,14 @@
    -
    @@ -68,7 +73,7 @@
    - diff --git a/imxweb/projects/qer-app-operationssupport/src/app/service-report/job-servers-gridview.component.scss b/imxweb/projects/qer-app-operationssupport/src/app/service-report/job-servers-gridview.component.scss index dfa0b6ba9..171a2ee12 100644 --- a/imxweb/projects/qer-app-operationssupport/src/app/service-report/job-servers-gridview.component.scss +++ b/imxweb/projects/qer-app-operationssupport/src/app/service-report/job-servers-gridview.component.scss @@ -4,26 +4,3 @@ overflow: hidden; flex-grow: 1; } - -.imx-table-container { - flex: 1 1 auto; - height: calc(100% - 50px); - display: flex; - flex-direction: column; - margin-bottom: -20px; - - > :nth-child(2) { - flex: 1 1 auto; - } -} - -.imx-refresh-button { - margin-right: 5px; - height: 50px; -} - -.imx-button-column{ - display: flex; - flex-direction: row; -} - diff --git a/imxweb/projects/qer-app-operationssupport/src/app/service-report/job-servers-gridview.component.ts b/imxweb/projects/qer-app-operationssupport/src/app/service-report/job-servers-gridview.component.ts index 7c18304e4..e373407b8 100644 --- a/imxweb/projects/qer-app-operationssupport/src/app/service-report/job-servers-gridview.component.ts +++ b/imxweb/projects/qer-app-operationssupport/src/app/service-report/job-servers-gridview.component.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -24,16 +24,17 @@ * */ -import { Component, EventEmitter, Input, OnInit, Output } from '@angular/core'; import { OverlayRef } from '@angular/cdk/overlay'; +import { Component, EventEmitter, Input, OnInit, Output } from '@angular/core'; import { EuiLoadingService, EuiSidesheetService } from '@elemental-ui/core'; import { TranslateService } from '@ngx-translate/core'; -import { OpsupportJobservers, ServerExtendedData } from 'imx-api-qbm'; -import { JobServersParameters, JobServersService } from './job-servers.service'; -import { DataSourceToolbarSettings, SettingsService, SnackBarService } from 'qbm'; -import { JobServersEditComponent } from './job-servers-edit/job-servers-edit.component'; +import { OpsupportJobservers } from '@imx-modules/imx-api-qbm'; +import { IClientProperty, TypedEntity } from '@imx-modules/imx-qbm-dbts'; +import { calculateSidesheetWidth, DataSourceToolbarSettings, SettingsService, SnackBarService } from 'qbm'; import { JobServersDetailsComponent } from './job-servers-details/job-servers-details.component'; +import { JobServersEditComponent } from './job-servers-edit/job-servers-edit.component'; +import { JobServersParameters, JobServersService } from './job-servers.service'; @Component({ selector: 'imx-job-servers-gridview', templateUrl: './job-servers-gridview.component.html', @@ -55,14 +56,14 @@ export class JobServersGridviewComponent implements OnInit { private readonly settingsService: SettingsService, private readonly sidesheet: EuiSidesheetService, private readonly snackBarService: SnackBarService, - private readonly translateService: TranslateService + private readonly translateService: TranslateService, ) {} public async ngOnInit(): Promise { let overlayRef = this.busyService.show(); try { await this.refresh(); - this.editableFields = (await this.gridDataService.getProjectConfig()).EditableFields.QBMServer; + this.editableFields = (await this.gridDataService.getProjectConfig()).EditableFields?.QBMServer; } finally { this.busyService.hide(overlayRef); } @@ -100,7 +101,7 @@ export class JobServersGridviewComponent implements OnInit { }, }; Object.assign(entitySchema.Columns, extraColumns); - const displayedColumns = []; + const displayedColumns: IClientProperty[] = []; displayedColumns.push(entitySchema.Columns.Ident_Server); if (this.navigationState.withconnection) { displayedColumns.push(entitySchema.Columns.Connection); @@ -120,7 +121,7 @@ export class JobServersGridviewComponent implements OnInit { dataSource: data, entitySchema, navigationState: this.navigationState, - extendedData: data.extendedData[0], + extendedData: data.extendedData?.[0] as any[], }; this.jobServersChecked.emit(this.navigationState.withconnection); @@ -128,7 +129,7 @@ export class JobServersGridviewComponent implements OnInit { setTimeout(() => this.busyService.hide(overlayRef)); } } - public async checkServer(data: any, event: Event) { + public async checkServer(data: TypedEntity, event: Event) { event.stopPropagation(); let overlayRef = this.busyService.show(); let uid = data.GetEntity().GetKeys()[0], @@ -136,7 +137,7 @@ export class JobServersGridviewComponent implements OnInit { connectionTime = await this.gridDataService.checkServerConnection(uid); this.busyService.hide(overlayRef); if (connectionTime.Value === -1) { - let textContainer = { key: '#LDS#The server does not respond.' }; + let textContainer = { key: '#LDS#The job server does not respond.' }; this.snackBarService.open(textContainer, '#LDS#Close', { duration: 6000 }); } else { data.GetEntity().Commit(true); @@ -151,27 +152,29 @@ export class JobServersGridviewComponent implements OnInit { return diff > 10; } - public edit(data: OpsupportJobservers): void { + public edit(data: TypedEntity): void { this.sidesheet.open(JobServersEditComponent, { - title: this.translateService.instant('#LDS#Heading Edit Server Settings'), + title: this.translateService.instant('#LDS#Heading Edit Job Server Settings'), + subTitle: data.GetEntity().GetDisplay(), disableClose: true, padding: '0', - width: 'max(50%,500px)', + width: calculateSidesheetWidth(800, 0.5), testId: 'job-servers-edit-sidesheet', data: { data, properties: this.editableFields }, }); } - public getServerDetails(data: ServerExtendedData[], event: Event): void { + public getServerDetails(data: OpsupportJobservers, event: Event): void { event.stopPropagation(); let overlayRef = this.busyService.show(); try { this.sidesheet.open(JobServersDetailsComponent, { - title: this.translateService.instant('#LDS#Heading View Server Details'), - width: 'max(50%,500px)', + title: this.translateService.instant('#LDS#Heading View Job Server Details'), + subTitle: data.GetEntity().GetDisplay(), + width: calculateSidesheetWidth(800, 0.5), padding: '0', - testId: 'job-servers-deatils-sidesheet', - data: data, + testId: 'job-servers-details-sidesheet', + data: this.dstSettings.extendedData, }); } finally { this.busyService.hide(overlayRef); diff --git a/imxweb/projects/qer-app-operationssupport/src/app/service-report/job-servers.service.ts b/imxweb/projects/qer-app-operationssupport/src/app/service-report/job-servers.service.ts index ac22d295b..a581045a0 100644 --- a/imxweb/projects/qer-app-operationssupport/src/app/service-report/job-servers.service.ts +++ b/imxweb/projects/qer-app-operationssupport/src/app/service-report/job-servers.service.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -26,9 +26,9 @@ import { Injectable } from '@angular/core'; -import { CollectionLoadParameters, EntitySchema, ExtendedTypedEntityCollection } from 'imx-qbm-dbts'; +import { CollectionLoadParameters, EntitySchema, ExtendedTypedEntityCollection } from '@imx-modules/imx-qbm-dbts'; import { imx_SessionService } from 'qbm'; -import { OpsupportJobservers } from 'imx-api-qbm'; +import { OpsupportJobservers } from '@imx-modules/imx-api-qbm'; export interface JobServersParameters extends CollectionLoadParameters { withconnection?: boolean; @@ -37,24 +37,21 @@ export interface JobServersParameters extends CollectionLoadParameters { @Injectable() export class JobServersService { - public get OpsupportJobserversSchema(): EntitySchema { return this.session.TypedClient.OpsupportJobservers.GetSchema(); } - constructor(private readonly session: imx_SessionService) { - } + constructor(private readonly session: imx_SessionService) {} public async get(parameters?: JobServersParameters): Promise> { return this.session.TypedClient.OpsupportJobservers.Get(parameters); } - public async checkServerConnection(uid){ + public async checkServerConnection(uid) { return this.session.Client.opsupport_jobservers_check_post(uid); } - public async getProjectConfig(){ + public async getProjectConfig() { return this.session.Client.opsupport_projectconfig_get(); } - } diff --git a/imxweb/projects/qer-app-operationssupport/src/app/service-report/service-availability.component.html b/imxweb/projects/qer-app-operationssupport/src/app/service-report/service-availability.component.html index 06d1abc9c..ad2f2a212 100644 --- a/imxweb/projects/qer-app-operationssupport/src/app/service-report/service-availability.component.html +++ b/imxweb/projects/qer-app-operationssupport/src/app/service-report/service-availability.component.html @@ -1,11 +1,11 @@ -

    - {{'#LDS#Heading Service Availability Check' | translate}} -

    - +

    + {{ '#LDS#Heading Job Server Overview' | translate }} +

    + - -
    - {{'#LDS#Last check' | translate}} + +
    + {{ '#LDS#Last check' | translate }} {{ lastUpdate }}
    diff --git a/imxweb/projects/qer-app-operationssupport/src/app/service-report/service-availability.component.scss b/imxweb/projects/qer-app-operationssupport/src/app/service-report/service-availability.component.scss index d4eeb9fd0..760447f0a 100644 --- a/imxweb/projects/qer-app-operationssupport/src/app/service-report/service-availability.component.scss +++ b/imxweb/projects/qer-app-operationssupport/src/app/service-report/service-availability.component.scss @@ -6,6 +6,6 @@ } .imx-job-grid { - display:flex; + display: flex; flex-direction: column; -} \ No newline at end of file +} diff --git a/imxweb/projects/qer-app-operationssupport/src/app/service-report/service-availability.component.ts b/imxweb/projects/qer-app-operationssupport/src/app/service-report/service-availability.component.ts index cbb033f64..6afb2229a 100644 --- a/imxweb/projects/qer-app-operationssupport/src/app/service-report/service-availability.component.ts +++ b/imxweb/projects/qer-app-operationssupport/src/app/service-report/service-availability.component.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -39,7 +39,7 @@ export class ServiceAvailabilityComponent { @ViewChild(JobServersGridviewComponent) private readonly jobGrid: JobServersGridviewComponent; - constructor(private translate: TranslateService){ } + constructor(private translate: TranslateService) {} public async Update(): Promise { await this.jobGrid.refresh(true); diff --git a/imxweb/projects/qer-app-operationssupport/src/app/service-report/service-report.component.html b/imxweb/projects/qer-app-operationssupport/src/app/service-report/service-report.component.html index 8073b03c8..29f99455b 100644 --- a/imxweb/projects/qer-app-operationssupport/src/app/service-report/service-report.component.html +++ b/imxweb/projects/qer-app-operationssupport/src/app/service-report/service-report.component.html @@ -1,16 +1,17 @@
    -

    {{'#LDS#Status reports' | translate}}

    +

    {{ '#LDS#Status reports' | translate }}

    - + + + - {{'#LDS#Service availability check' | translate}} - {{'#LDS#Check the availability of services.' | translate}} + {{ '#LDS#Heading Job Server Overview' | translate }} + {{ '#LDS#Check and manage your job servers.' | translate }} - +
    - diff --git a/imxweb/projects/qer-app-operationssupport/src/app/service-report/service-report.component.scss b/imxweb/projects/qer-app-operationssupport/src/app/service-report/service-report.component.scss index 2d0011e34..c0037c602 100644 --- a/imxweb/projects/qer-app-operationssupport/src/app/service-report/service-report.component.scss +++ b/imxweb/projects/qer-app-operationssupport/src/app/service-report/service-report.component.scss @@ -4,33 +4,25 @@ margin-bottom: 10px; } - -.mat-card { +.mat-mdc-card { width: 350px; - .mat-card-content { + .mat-mdc-card-content { padding: 19px; } - .mat-card-header { + .mat-mdc-card-header { height: 124px; display: flex; justify-content: center; - - .mat-card-header-text { - margin: 0; - height: 0; - } - - eui-icon { - line-height: 124px; - } + align-items: center; } - .mat-card-actions { + + .mat-mdc-card-actions { padding-bottom: 20px; padding-right: 20px; display: flex; flex-direction: column; align-items: flex-end; } -} \ No newline at end of file +} diff --git a/imxweb/projects/qer-app-operationssupport/src/app/service-report/service-report.component.ts b/imxweb/projects/qer-app-operationssupport/src/app/service-report/service-report.component.ts index 7ebe02838..9898f3e6e 100644 --- a/imxweb/projects/qer-app-operationssupport/src/app/service-report/service-report.component.ts +++ b/imxweb/projects/qer-app-operationssupport/src/app/service-report/service-report.component.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -32,9 +32,8 @@ import { Router } from '@angular/router'; templateUrl: './service-report.component.html', styleUrls: ['./service-report.component.scss'], }) -export class ServiceReportComponent { - - constructor(private router: Router) { } +export class ServiceReportComponent { + constructor(private router: Router) {} public CheckServiceAvailability(): void { this.router.navigate(['ServiceAvailability']); diff --git a/imxweb/projects/qer-app-operationssupport/src/app/service-report/service-report.module.ts b/imxweb/projects/qer-app-operationssupport/src/app/service-report/service-report.module.ts index a73e6c5bf..b411f5126 100644 --- a/imxweb/projects/qer-app-operationssupport/src/app/service-report/service-report.module.ts +++ b/imxweb/projects/qer-app-operationssupport/src/app/service-report/service-report.module.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -61,11 +61,11 @@ import { JobServersDetailsComponent } from './job-servers-details/job-servers-de MatCardModule, MatButtonModule, MatTooltipModule, - FormsModule, + FormsModule, ReactiveFormsModule, - MatTabsModule + MatTabsModule, ], providers: [JobServersService], - exports: [ServiceReportComponent] + exports: [ServiceReportComponent], }) -export class ServiceReportModule { } +export class ServiceReportModule {} diff --git a/imxweb/projects/qer-app-operationssupport/src/app/service-report/services-inactive.component.html b/imxweb/projects/qer-app-operationssupport/src/app/service-report/services-inactive.component.html index db19efdec..c548543aa 100644 --- a/imxweb/projects/qer-app-operationssupport/src/app/service-report/services-inactive.component.html +++ b/imxweb/projects/qer-app-operationssupport/src/app/service-report/services-inactive.component.html @@ -1,4 +1,4 @@ -

    - {{'#LDS#Inactive services' | translate}} -

    +

    + {{ '#LDS#Inactive services' | translate }} +

    diff --git a/imxweb/projects/qer-app-operationssupport/src/app/service-report/services-inactive.component.ts b/imxweb/projects/qer-app-operationssupport/src/app/service-report/services-inactive.component.ts index 6ec09ba5a..f5d7d5bf3 100644 --- a/imxweb/projects/qer-app-operationssupport/src/app/service-report/services-inactive.component.ts +++ b/imxweb/projects/qer-app-operationssupport/src/app/service-report/services-inactive.component.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -29,8 +29,6 @@ import { Component } from '@angular/core'; @Component({ selector: 'imx-services-inactive', templateUrl: './services-inactive.component.html', - styles: [] + styles: [], }) -export class ServicesInactiveComponent { - -} +export class ServicesInactiveComponent {} diff --git a/imxweb/projects/qer-app-operationssupport/src/app/sync/sync-information/sync-information.component.html b/imxweb/projects/qer-app-operationssupport/src/app/sync/sync-information/sync-information.component.html index 6a391f968..caf38b965 100644 --- a/imxweb/projects/qer-app-operationssupport/src/app/sync/sync-information/sync-information.component.html +++ b/imxweb/projects/qer-app-operationssupport/src/app/sync/sync-information/sync-information.component.html @@ -1,42 +1,48 @@
    -

    - {{'#LDS#Synchronization' | translate}} -

    +

    + {{ '#LDS#Synchronization' | translate }} +

    - + - - + + {{ data.DisplayName.Column.GetDisplayValue() }} - + {{ data.Description.Column.GetDisplayValue() }} - + {{ data.NextSyncDate.Column.GetDisplayValue() }} - + {{ data.CountJournalFailure.Column.GetDisplayValue() }} - + {{ data.LastSyncCountObjects.Column.GetDisplayValue() }} - + @@ -44,7 +50,7 @@

    - diff --git a/imxweb/projects/qer-app-operationssupport/src/app/sync/sync-information/sync-information.component.scss b/imxweb/projects/qer-app-operationssupport/src/app/sync/sync-information/sync-information.component.scss index 14ab8ce52..024835feb 100644 --- a/imxweb/projects/qer-app-operationssupport/src/app/sync/sync-information/sync-information.component.scss +++ b/imxweb/projects/qer-app-operationssupport/src/app/sync/sync-information/sync-information.component.scss @@ -4,20 +4,3 @@ overflow: hidden; height: 100%; } - - -.imx-table-container { - display: flex; - flex-direction: column; - overflow: hidden; - height: inherit; - - > :nth-child(2) { - flex: 1 1 auto; - } -} - -.imx-refresh-button { - margin-right: 5px; - height: 50px; -} diff --git a/imxweb/projects/qer-app-operationssupport/src/app/sync/sync-information/sync-information.component.ts b/imxweb/projects/qer-app-operationssupport/src/app/sync/sync-information/sync-information.component.ts index 00d19443f..58125e077 100644 --- a/imxweb/projects/qer-app-operationssupport/src/app/sync/sync-information/sync-information.component.ts +++ b/imxweb/projects/qer-app-operationssupport/src/app/sync/sync-information/sync-information.component.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -29,18 +29,17 @@ import { Component, OnInit } from '@angular/core'; import { Router } from '@angular/router'; import { EuiLoadingService } from '@elemental-ui/core'; -import { OpsupportSyncShell } from 'imx-api-dpr'; -import { EntitySchema, IClientProperty, ValType } from 'imx-qbm-dbts'; +import { OpsupportSyncShell } from '@imx-modules/imx-api-dpr'; +import { EntitySchema, IClientProperty, ValType } from '@imx-modules/imx-qbm-dbts'; import { DataSourceToolbarSettings, ClientPropertyForTableColumns, SettingsService } from 'qbm'; import { OpsupportSyncShellParameters, SyncService } from '../sync.service'; @Component({ selector: 'imx-sync-information', templateUrl: './sync-information.component.html', - styleUrls: ['./sync-information.component.scss'] + styleUrls: ['./sync-information.component.scss'], }) export class SyncInformationComponent implements OnInit { - public dstSettings: DataSourceToolbarSettings; public readonly entitySchemaSyncInfo: EntitySchema; private navigationState: OpsupportSyncShellParameters; @@ -50,7 +49,7 @@ export class SyncInformationComponent implements OnInit { private dataSource: SyncService, private router: Router, private busyService: EuiLoadingService, - private readonly settings: SettingsService + private readonly settings: SettingsService, ) { this.navigationState = { StartIndex: 0, PageSize: settings.DefaultPageSize }; this.entitySchemaSyncInfo = dataSource.syncShellSchema; @@ -64,8 +63,8 @@ export class SyncInformationComponent implements OnInit { ColumnName: 'actions', Type: ValType.String, afterAdditionals: true, - untranslatedDisplay: '#LDS#Actions' - } + untranslatedDisplay: '#LDS#Actions', + }, ]; } @@ -85,17 +84,15 @@ export class SyncInformationComponent implements OnInit { this.navigationState = { ...this.navigationState, ...navigationState }; let overlayRef: OverlayRef; - setTimeout(() => overlayRef = this.busyService.show()); + setTimeout(() => (overlayRef = this.busyService.show())); try { - const applications = await this.dataSource.getSyncShell(navigationState); this.dstSettings = { displayedColumns: this.displayedColumns, dataSource: applications, entitySchema: this.entitySchemaSyncInfo, - navigationState: this.navigationState + navigationState: this.navigationState, }; - } finally { setTimeout(() => this.busyService.hide(overlayRef)); } @@ -104,5 +101,4 @@ export class SyncInformationComponent implements OnInit { public viewDetails(syncShell: OpsupportSyncShell): void { this.router.navigate(['/SyncJournal/' + syncShell.UID_DPRShell.value]); } - } diff --git a/imxweb/projects/qer-app-operationssupport/src/app/sync/sync-journal/sync-journal.component.html b/imxweb/projects/qer-app-operationssupport/src/app/sync/sync-journal/sync-journal.component.html index 81a22b2fe..7eb439fdc 100644 --- a/imxweb/projects/qer-app-operationssupport/src/app/sync/sync-journal/sync-journal.component.html +++ b/imxweb/projects/qer-app-operationssupport/src/app/sync/sync-journal/sync-journal.component.html @@ -1,38 +1,49 @@
    -

    - {{'#LDS#Synchronization log' | translate}} {{ caption }} -

    +

    {{ '#LDS#Synchronization log' | translate }} {{ caption }}

    - -
    - + + +
    + - - + + {{ data.CreationTime.Column.GetDisplayValue() }} - + {{ data.ProjectionConfigDisplay.Column.GetDisplayValue() }} - + {{ data.ProjectionState.Column.GetDisplayValue() }} - + {{ data.ProjectionStartInfoDisplay.Column.GetDisplayValue() }} - + @@ -40,7 +51,7 @@

    - diff --git a/imxweb/projects/qer-app-operationssupport/src/app/sync/sync-journal/sync-journal.component.scss b/imxweb/projects/qer-app-operationssupport/src/app/sync/sync-journal/sync-journal.component.scss index e772dfef1..171a2ee12 100644 --- a/imxweb/projects/qer-app-operationssupport/src/app/sync/sync-journal/sync-journal.component.scss +++ b/imxweb/projects/qer-app-operationssupport/src/app/sync/sync-journal/sync-journal.component.scss @@ -4,19 +4,3 @@ overflow: hidden; flex-grow: 1; } - -.imx-table-container { - flex: 1 1 auto; - display: flex; - flex-direction: column; - overflow: auto; - - > :nth-child(2) { - flex: 1 1 auto; - } -} - -.imx-refresh-button { - margin-right: 5px; - height: 50px; -} diff --git a/imxweb/projects/qer-app-operationssupport/src/app/sync/sync-journal/sync-journal.component.ts b/imxweb/projects/qer-app-operationssupport/src/app/sync/sync-journal/sync-journal.component.ts index 690ec80f3..5becd1b75 100644 --- a/imxweb/projects/qer-app-operationssupport/src/app/sync/sync-journal/sync-journal.component.ts +++ b/imxweb/projects/qer-app-operationssupport/src/app/sync/sync-journal/sync-journal.component.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -24,24 +24,22 @@ * */ +import { OverlayRef } from '@angular/cdk/overlay'; import { Component, OnInit, ViewChild } from '@angular/core'; import { ActivatedRoute } from '@angular/router'; -import { OverlayRef } from '@angular/cdk/overlay'; import { EuiDownloadDirective, EuiLoadingService } from '@elemental-ui/core'; -import { OpsupportSyncJournal } from 'imx-api-dpr'; -import { EntitySchema, IClientProperty, ValType } from 'imx-qbm-dbts'; -import { DataSourceToolbarSettings, ElementalUiConfigService, ClientPropertyForTableColumns, SettingsService } from 'qbm'; +import { OpsupportSyncJournal, V2ApiClientMethodFactory } from '@imx-modules/imx-api-dpr'; +import { EntitySchema, MethodDefinition, ValType } from '@imx-modules/imx-qbm-dbts'; +import { AppConfigService, ClientPropertyForTableColumns, DataSourceToolbarSettings, ElementalUiConfigService, SettingsService } from 'qbm'; import { OpsSyncJournalParameters, SyncService } from '../sync.service'; -import { SyncSummaryService } from './sync-summary.service'; @Component({ selector: 'imx-sync-journal', templateUrl: './sync-journal.component.html', - styleUrls: ['./sync-journal.component.scss'] + styleUrls: ['./sync-journal.component.scss'], }) export class SyncJournalComponent implements OnInit { - public caption = ''; public dstSettings: DataSourceToolbarSettings; @@ -50,15 +48,16 @@ export class SyncJournalComponent implements OnInit { private navigationState: OpsSyncJournalParameters; private readonly displayedColumns: ClientPropertyForTableColumns[]; + private factory = new V2ApiClientMethodFactory(); constructor( + private readonly config: AppConfigService, private activeRoute: ActivatedRoute, private syncShellService: SyncService, - private syncSummaryService: SyncSummaryService, private readonly elementalUiConfigService: ElementalUiConfigService, private readonly settings: SettingsService, - private busyService: EuiLoadingService) { - + private busyService: EuiLoadingService, + ) { this.entitySchemaSyncInfo = syncShellService.syncJournalSchema; this.displayedColumns = [ this.entitySchemaSyncInfo.Columns.CreationTime, @@ -69,8 +68,8 @@ export class SyncJournalComponent implements OnInit { ColumnName: 'actions', Type: ValType.String, afterAdditionals: true, - untranslatedDisplay: '#LDS#Actions' - } + untranslatedDisplay: '#LDS#Actions', + }, ]; } @@ -78,11 +77,11 @@ export class SyncJournalComponent implements OnInit { const filter = this.activeRoute.snapshot.queryParamMap.get('filter'); const parameters = { shell: '', - filter: filter ? JSON.parse(filter) : null + filter: filter ? JSON.parse(filter) : null, }; let overlayRef: OverlayRef; - setTimeout(() => overlayRef = this.busyService.show()); + setTimeout(() => (overlayRef = this.busyService.show())); try { const uidSyncShell = this.activeRoute.snapshot.paramMap.get('uidSyncShell'); if (uidSyncShell) { @@ -95,8 +94,10 @@ export class SyncJournalComponent implements OnInit { setTimeout(() => this.busyService.hide(overlayRef)); } await this.getData({ - StartIndex: 0, PageSize: this.settings.DefaultPageSize, - shell: parameters.shell, filter: parameters.filter + StartIndex: 0, + PageSize: this.settings.DefaultPageSize, + shell: parameters.shell, + filter: parameters.filter, }); } @@ -104,17 +105,15 @@ export class SyncJournalComponent implements OnInit { this.navigationState = navigationState; let overlayRef: OverlayRef; - setTimeout(() => overlayRef = this.busyService.show()); + setTimeout(() => (overlayRef = this.busyService.show())); try { - const applications = await this.syncShellService.getSyncJournal(navigationState); this.dstSettings = { displayedColumns: this.displayedColumns, dataSource: applications, entitySchema: this.entitySchemaSyncInfo, - navigationState: this.navigationState + navigationState: this.navigationState, }; - } finally { setTimeout(() => this.busyService.hide(overlayRef)); } @@ -122,28 +121,22 @@ export class SyncJournalComponent implements OnInit { public async showReport(journalItem: OpsupportSyncJournal): Promise { let overlayRef: OverlayRef; - setTimeout(() => overlayRef = this.busyService.show()); + setTimeout(() => (overlayRef = this.busyService.show())); try { - const blob = await this.syncSummaryService - .Get({ journal: journalItem.UID_DPRJournal.value }); + const def = new MethodDefinition(this.factory.opsupport_sync_summary_get({ journal: journalItem.UID_DPRJournal.value })); + const url = this.config.BaseUrl + def.path; let fileName = journalItem.UID_DPRJournal.Column.GetDisplayValue(); - if (blob.type.startsWith('application/pdf')) { - fileName = `${fileName}.pdf`; - } - const csvUrl = URL.createObjectURL(blob); - - console.log(fileName); + fileName = `${fileName}.pdf`; if (this.directive) { this.directive.downloadOptions = { - ... this.elementalUiConfigService.Config.downloadOptions, - url: csvUrl, - fileName + ...this.elementalUiConfigService.Config.downloadOptions, + url: url, + fileName, }; this.directive.onClick(); } - } finally { setTimeout(() => this.busyService.hide(overlayRef)); } diff --git a/imxweb/projects/qer-app-operationssupport/src/app/sync/sync.module.ts b/imxweb/projects/qer-app-operationssupport/src/app/sync/sync.module.ts index e000ec327..bede766d3 100644 --- a/imxweb/projects/qer-app-operationssupport/src/app/sync/sync.module.ts +++ b/imxweb/projects/qer-app-operationssupport/src/app/sync/sync.module.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -24,37 +24,21 @@ * */ -import { NgModule } from '@angular/core'; import { CommonModule } from '@angular/common'; -import { EuiCoreModule } from '@elemental-ui/core'; +import { NgModule } from '@angular/core'; import { MatButtonModule } from '@angular/material/button'; import { MatTooltipModule } from '@angular/material/tooltip'; +import { EuiCoreModule } from '@elemental-ui/core'; import { TranslateModule } from '@ngx-translate/core'; import { DataSourceToolbarModule, DataTableModule } from 'qbm'; import { SyncInformationComponent } from './sync-information/sync-information.component'; import { SyncJournalComponent } from './sync-journal/sync-journal.component'; import { SyncService } from './sync.service'; -import { SyncSummaryService } from './sync-journal/sync-summary.service'; - @NgModule({ - declarations: [ - SyncInformationComponent, - SyncJournalComponent, - ], - imports: [ - CommonModule, - EuiCoreModule, - DataTableModule, - DataSourceToolbarModule, - MatButtonModule, - MatTooltipModule, - TranslateModule - ], - providers: [ - SyncService, - SyncSummaryService, - ] + declarations: [SyncInformationComponent, SyncJournalComponent], + imports: [CommonModule, EuiCoreModule, DataTableModule, DataSourceToolbarModule, MatButtonModule, MatTooltipModule, TranslateModule], + providers: [SyncService], }) -export class SyncModule { } +export class SyncModule {} diff --git a/imxweb/projects/qer-app-operationssupport/src/app/sync/sync.service.ts b/imxweb/projects/qer-app-operationssupport/src/app/sync/sync.service.ts index ae3eae844..3e3cd529e 100644 --- a/imxweb/projects/qer-app-operationssupport/src/app/sync/sync.service.ts +++ b/imxweb/projects/qer-app-operationssupport/src/app/sync/sync.service.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -26,8 +26,8 @@ import { Injectable } from '@angular/core'; -import { CollectionLoadParameters, EntitySchema, FilterData, TypedEntityCollectionData } from 'imx-qbm-dbts'; -import { OpsupportSyncJournal, OpsupportSyncShell } from 'imx-api-dpr'; +import { OpsupportSyncJournal, OpsupportSyncShell } from '@imx-modules/imx-api-dpr'; +import { CollectionLoadParameters, EntitySchema, FilterData, TypedEntityCollectionData } from '@imx-modules/imx-qbm-dbts'; import { DprApiService } from '../../../dpr-api-client.service'; export interface OpsupportSyncShellParameters extends CollectionLoadParameters { @@ -49,7 +49,7 @@ export class SyncService { return this.dprClient.typedClient.OpsupportSyncJournal.GetSchema(); } - constructor(private readonly dprClient: DprApiService) { } + constructor(private readonly dprClient: DprApiService) {} public getSyncShell(parameters: OpsupportSyncShellParameters): Promise> { return this.dprClient.typedClient.OpsupportSyncShell.Get(parameters); @@ -59,9 +59,8 @@ export class SyncService { return this.dprClient.typedClient.OpsupportSyncJournal.Get(parameters); } - public async GetDisplayName(uidShell: string, withfrozenjobs: boolean = false): Promise { - const syncShellItem = (await this.getSyncShell({ withfrozenjobs })).Data.find(a => a.UID_DPRShell.value === uidShell); + public async GetDisplayName(uidShell: string, withfrozenjobs: boolean = false): Promise { + const syncShellItem = (await this.getSyncShell({ withfrozenjobs })).Data.find((a) => a.UID_DPRShell.value === uidShell); return syncShellItem ? syncShellItem.DisplayName.value : null; } - } diff --git a/imxweb/projects/qer-app-operationssupport/src/app/test-utilities/imx-api-mock.spec.ts b/imxweb/projects/qer-app-operationssupport/src/app/test-utilities/imx-api-mock.spec.ts index 2619ab6fe..b8b80d0c9 100644 --- a/imxweb/projects/qer-app-operationssupport/src/app/test-utilities/imx-api-mock.spec.ts +++ b/imxweb/projects/qer-app-operationssupport/src/app/test-utilities/imx-api-mock.spec.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -24,18 +24,15 @@ * */ -import * as TypeMoq from 'typemoq'; - -import { EntityData, IEntity, IEntityColumn, IReadValue, TypedEntity } from 'imx-qbm-dbts'; -import { OpsupportSyncJournal, OpsupportSyncShell } from 'imx-api-dpr'; +import { OpsupportSyncJournal, OpsupportSyncShell } from '@imx-modules/imx-api-dpr'; import { - OpsupportQueueJobchains, - OpsupportQueueTree, OpsupportQueueFrozenjobs, - OpsupportQueueJobs, + OpsupportQueueJobchains, OpsupportQueueJobperformance, -} from 'imx-api-qbm'; -import { BaseImxApiDtoMock, BaseImxApiDataMock, CreateIEntityColumn, CreateIReadValue, CreateIEntity } from 'qbm'; + OpsupportQueueJobs, +} from '@imx-modules/imx-api-qbm'; +import { EntityData, IEntity, IEntityColumn } from '@imx-modules/imx-qbm-dbts'; +import { BaseImxApiDataMock, BaseImxApiDtoMock, CreateIEntity, CreateIEntityColumn, CreateIReadValue } from 'qbm'; export interface JobChainsMock { JobChainName: string; @@ -117,38 +114,32 @@ export class ImxApiDtoMock extends BaseImxApiDtoMock { const jobChainName = CreateIEntityColumn(properties.JobChainName); const count = CreateIEntityColumn(properties.Count.toString()); - const mock = TypeMoq.Mock.ofType(); - mock.setup((property) => property.JobChainName).returns(() => CreateIReadValue(properties.JobChainName, jobChainName)); - mock.setup((property) => property.Count).returns(() => CreateIReadValue(properties.Count, count)); - - mock - .setup((property) => property.GetEntity()) - .returns(() => + return { + JobChainName: CreateIReadValue(properties.JobChainName, jobChainName), + Count: CreateIReadValue(properties.Count, count), + GetEntity: () => CreateIEntity((name: string) => { if (name === 'JobChainName') { return jobChainName; } return count; - }) - ); - - return mock.object; + }), + } as OpsupportQueueJobchains; } public static CreateOpsupportSyncJournalCollection(propertiesCollection: OpsupportSyncJournalMock[]): OpsupportSyncJournal[] { - return propertiesCollection.map((properties) => { - const mock = TypeMoq.Mock.ofType(); - mock - .setup((property) => property.CreationTime) - .returns(() => CreateIReadValue(properties.CreationTime, CreateIEntityColumn(properties.CreationTime.toLocaleString()))); - mock.setup((property) => property.ProjectionConfigDisplay).returns(() => CreateIReadValue(properties.ProjectionConfigDisplay)); - mock.setup((property) => property.ProjectionStartInfoDisplay).returns(() => CreateIReadValue(properties.ProjectionStartInfoDisplay)); - mock.setup((property) => property.ProjectionState).returns(() => CreateIReadValue(properties.ProjectionState)); - mock.setup((property) => property.UID_DPRJournal).returns(() => CreateIReadValue(properties.UID_DPRJournal)); - mock.setup((property) => property.UID_DPRProjectionConfig).returns(() => CreateIReadValue(properties.UID_DPRProjectionConfig)); - return mock.object; - }); + return propertiesCollection.map( + (properties) => + ({ + CreationTime: CreateIReadValue(properties.CreationTime, CreateIEntityColumn(properties.CreationTime.toLocaleString())), + ProjectionConfigDisplay: CreateIReadValue(properties.ProjectionConfigDisplay), + ProjectionStartInfoDisplay: CreateIReadValue(properties.ProjectionStartInfoDisplay), + ProjectionState: CreateIReadValue(properties.ProjectionState), + UID_DPRJournal: CreateIReadValue(properties.UID_DPRJournal), + UID_DPRProjectionConfig: CreateIReadValue(properties.UID_DPRProjectionConfig), + }) as OpsupportSyncJournal, + ); } public static CreateSingleOpsupportQueueTreeBranch(properties: OpsupportQueueTreeParams): IEntity { @@ -159,31 +150,6 @@ export class ImxApiDtoMock extends BaseImxApiDtoMock { } } return this.createEntity(columns); - // const mock = TypeMoq.Mock.ofType(); - // mock.setup(obj => obj.UID_Job).returns(() => CreateIReadValue(properties.UID_Job ? properties.UID_Job : '')); - // mock.setup(obj => obj.BasisObjectKey).returns(() => CreateIReadValue(properties.BasisObjectKey ? properties.BasisObjectKey : '')); - // mock.setup(obj => obj.DeferOnError).returns(() => CreateIReadValue(properties.DeferOnError ? properties.DeferOnError : false)); - // mock.setup(obj => obj.ErrorMessages).returns(() => CreateIReadValue(properties.ErrorMessages ? properties.ErrorMessages : '')); - // mock.setup(obj => obj.GenProcID).returns(() => CreateIReadValue(properties.GenProcID ? properties.GenProcID : '')); - // mock.setup(obj => obj.IsRootJob).returns(() => CreateIReadValue(properties.IsRootJob ? properties.IsRootJob : false)); - // mock.setup(obj => obj.JobChainName).returns(() => CreateIReadValue(properties.JobChainName ? properties.JobChainName : '')); - // mock.setup(obj => obj.LimitationCount).returns(() => CreateIReadValue(properties.LimitationCount ? properties.LimitationCount : 0)); - // mock.setup(obj => obj.Queue).returns(() => CreateIReadValue(properties.Queue ? properties.Queue : '')); - // mock.setup(obj => obj.Ready2EXE).returns(() => CreateIReadValue(properties.Ready2EXE ? properties.Ready2EXE : '')); - // mock.setup(obj => obj.TaskName).returns(() => CreateIReadValue(properties.TaskName ? properties.TaskName : '')); - // mock.setup(obj => obj.UID_JobError).returns(() => CreateIReadValue(properties.UID_JobError ? properties.UID_JobError : '')); - // mock.setup(obj => obj.UID_JobOrigin).returns(() => CreateIReadValue(properties.UID_JobOrigin ? properties.UID_JobOrigin : '')); - // mock.setup(obj => obj.UID_JobSameServer) - // .returns(() => CreateIReadValue(properties.UID_JobSameServer ? properties.UID_JobSameServer : '')); - // mock.setup(obj => obj.UID_JobSuccess).returns(() => CreateIReadValue(properties.UID_JobSuccess ? properties.UID_JobSuccess : '')); - // mock.setup(obj => obj.UID_Tree).returns(() => CreateIReadValue(properties.UID_Tree ? properties.UID_Tree : '')); - // mock.setup(obj => obj.XDateInserted) - // .returns(() => CreateIReadValue(properties.XDateInserted ? properties.XDateInserted : new Date(2001, 1, 1))); - // mock.setup(obj => obj.XDateUpdated) - // .returns(() => CreateIReadValue(properties.XDateUpdated ? properties.XDateUpdated : new Date(2001, 1, 1))); - // mock.setup(obj => obj.XUserInserted).returns(() => CreateIReadValue(properties.XUserInserted ? properties.XUserInserted : '')); - // mock.setup(obj => obj.XUserUpdated).returns(() => CreateIReadValue(properties.XUserUpdated ? properties.XUserUpdated : '')); - // return mock.object; } public static createColumn(value?) { @@ -213,81 +179,72 @@ export class ImxApiDtoMock extends BaseImxApiDtoMock { } public static CreateOpsupportQueueFrozenjobs(properties: IJobQueueParams): OpsupportQueueFrozenjobs { - const mock = TypeMoq.Mock.ofType(); - mock - .setup((property) => property.TaskName) - .returns(() => CreateIReadValue(properties.TaskName, CreateIEntityColumn(properties.TaskName))); - mock - .setup((property) => property.JobChainName) - .returns(() => CreateIReadValue(properties.JobChainName, CreateIEntityColumn(properties.JobChainName))); - mock.setup((property) => property.UID_Tree).returns(() => CreateIReadValue(properties.Uid_Tree)); - mock.setup((property) => property.UID_Job).returns(() => CreateIReadValue(properties.Uid_Job)); - mock.setup((property) => property.UID_JobSuccess).returns(() => CreateIReadValue(properties.Uid_JobSuccess)); - mock.setup((property) => property.UID_JobError).returns(() => CreateIReadValue(properties.Uid_JobError)); - mock - .setup((property) => property.ErrorMessages) - .returns(() => CreateIReadValue(properties.ErrorMessages ? properties.ErrorMessages : '')); - mock.setup((property) => property.Queue).returns(() => CreateIReadValue(properties.Queue)); - mock.setup((property) => property.Retries).returns(() => CreateIReadValue(properties.Retries)); - mock.setup((property) => property.Ready2EXE).returns(() => CreateIReadValue(properties.ReadyToExe)); - mock.setup((property) => property.IsRootJob).returns(() => CreateIReadValue(properties.IsRootJob)); - mock.setup((property) => property.XDateInserted).returns(() => CreateIReadValue(properties.XDateInserted)); - return mock.object; + return { + TaskName: CreateIReadValue(properties.TaskName, CreateIEntityColumn(properties.TaskName)), + JobChainName: CreateIReadValue(properties.JobChainName, CreateIEntityColumn(properties.JobChainName)), + UID_Tree: CreateIReadValue(properties.Uid_Tree), + UID_Job: CreateIReadValue(properties.Uid_Job), + UID_JobSuccess: CreateIReadValue(properties.Uid_JobSuccess), + UID_JobError: CreateIReadValue(properties.Uid_JobError), + ErrorMessages: CreateIReadValue(properties.ErrorMessages ? properties.ErrorMessages : ''), + Retries: CreateIReadValue(properties.Retries), + Queue: CreateIReadValue(properties.Queue), + Ready2EXE: CreateIReadValue(properties.ReadyToExe), + IsRootJob: CreateIReadValue(properties.IsRootJob), + XDateInserted: CreateIReadValue(properties.XDateInserted), + } as OpsupportQueueFrozenjobs; } public static CreateOpsupportSyncShellCollection(propertiesCollection: IOpsupportSyncShell[]): OpsupportSyncShell[] { - return propertiesCollection.map((properties) => { - const mock = TypeMoq.Mock.ofType(); - mock - .setup((property) => property.CountJournalFailure) - .returns(() => CreateIReadValue(properties.CountJournalFailure, CreateIEntityColumn(properties.CountJournalFailure.toString()))); - mock - .setup((property) => property.Description) - .returns(() => CreateIReadValue(properties.Description, CreateIEntityColumn(properties.Description))); - mock - .setup((property) => property.DisplayName) - .returns(() => CreateIReadValue(properties.DisplayName, CreateIEntityColumn(properties.DisplayName))); - mock - .setup((property) => property.LastSyncCountObjects) - .returns(() => CreateIReadValue(properties.LastSyncCountObjects, CreateIEntityColumn(properties.LastSyncCountObjects.toString()))); - mock - .setup((property) => property.NextSyncDate) - .returns(() => CreateIReadValue(properties.NextSyncDate, CreateIEntityColumn(properties.NextSyncDate.toLocaleString()))); - mock - .setup((property) => property.UID_DPRShell) - .returns(() => CreateIReadValue(properties.UID_DPRShell, CreateIEntityColumn(properties.UID_DPRShell))); - return mock.object; - }); + return propertiesCollection.map( + (properties) => + ({ + CountJournalFailure: CreateIReadValue( + properties.CountJournalFailure, + CreateIEntityColumn(properties.CountJournalFailure.toString()), + ), + Description: CreateIReadValue(properties.Description, CreateIEntityColumn(properties.Description)), + DisplayName: CreateIReadValue(properties.DisplayName, CreateIEntityColumn(properties.DisplayName)), + LastSyncCountObjects: CreateIReadValue( + properties.LastSyncCountObjects, + CreateIEntityColumn(properties.LastSyncCountObjects.toString()), + ), + NextSyncDate: CreateIReadValue(properties.NextSyncDate, CreateIEntityColumn(properties.NextSyncDate.toLocaleString())), + UID_DPRShell: CreateIReadValue(properties.UID_DPRShell, CreateIEntityColumn(properties.UID_DPRShell)), + }) as OpsupportSyncShell, + ); } public static CreateOpsupportQueueJobsCollection(propertiesCollection: IJobQueueParams[]): OpsupportQueueJobs[] { - return propertiesCollection.map((properties) => { - const mock = TypeMoq.Mock.ofType(); - mock.setup((property) => property.TaskName).returns(() => CreateIReadValue(properties.TaskName)); - mock.setup((property) => property.JobChainName).returns(() => CreateIReadValue(properties.JobChainName)); - mock.setup((property) => property.UID_Tree).returns(() => CreateIReadValue(properties.Uid_Tree)); - mock.setup((property) => property.UID_Job).returns(() => CreateIReadValue(properties.Uid_Job)); - mock.setup((property) => property.UID_JobSuccess).returns(() => CreateIReadValue(properties.Uid_JobSuccess)); - mock.setup((property) => property.UID_JobError).returns(() => CreateIReadValue(properties.Uid_JobError)); - mock.setup((property) => property.Queue).returns(() => CreateIReadValue(properties.Queue)); - mock.setup((property) => property.Retries).returns(() => CreateIReadValue(properties.Retries)); - mock.setup((property) => property.Ready2EXE).returns(() => CreateIReadValue(properties.ReadyToExe)); - mock.setup((property) => property.IsRootJob).returns(() => CreateIReadValue(properties.IsRootJob)); - mock.setup((property) => property.XDateInserted).returns(() => CreateIReadValue(properties.XDateInserted)); - mock.setup((property) => property.CombinedStatus).returns(() => CreateIReadValue(properties.CombinedStatus)); - return mock.object; - }); + return propertiesCollection.map( + (properties) => + ({ + TaskName: CreateIReadValue(properties.TaskName), + JobChainName: CreateIReadValue(properties.JobChainName), + UID_Tree: CreateIReadValue(properties.Uid_Tree), + UID_Job: CreateIReadValue(properties.Uid_Job), + UID_JobSuccess: CreateIReadValue(properties.Uid_JobSuccess), + UID_JobError: CreateIReadValue(properties.Uid_JobError), + Queue: CreateIReadValue(properties.Queue), + Retries: CreateIReadValue(properties.Retries), + Ready2EXE: CreateIReadValue(properties.ReadyToExe), + IsRootJob: CreateIReadValue(properties.IsRootJob), + XDateInserted: CreateIReadValue(properties.XDateInserted), + CombinedStatus: CreateIReadValue(properties.CombinedStatus), + }) as OpsupportQueueJobs, + ); } public static CreateOpsupportQueueJobperformanceCollection(propertiesCollection: IJobQueueParams[]): OpsupportQueueJobperformance[] { - return propertiesCollection.map((properties) => { - const mock = TypeMoq.Mock.ofType(); - mock.setup((property) => property.TaskName).returns(() => CreateIReadValue(properties.TaskName)); - mock.setup((property) => property.Queue).returns(() => CreateIReadValue(properties.Queue)); - mock.setup((property) => property.ComponentClass).returns(() => CreateIReadValue('componentClassDummy')); - mock.setup((property) => property.CountPerMinute).returns(() => CreateIReadValue(23)); - return mock.object; - }); + return propertiesCollection.map( + (properties) => + ({ + TaskName: CreateIReadValue(properties.TaskName), + Queue: CreateIReadValue(properties.Queue), + ComponentClass: CreateIReadValue('componentClassDummy'), + CountPerMinute: CreateIReadValue(23), + }) as OpsupportQueueJobperformance, + ); } } @@ -300,8 +257,8 @@ export class ImxApiDataMock extends BaseImxApiDataMock { TaskName: `TaskName${i}`, JobChainName: `JobChainName${i}`, }), - numOfEntries - ) + numOfEntries, + ), ); } @@ -322,7 +279,7 @@ export class ImxApiDataMock extends BaseImxApiDataMock { }, }, }), - numOfEntries + numOfEntries, ); } @@ -346,51 +303,38 @@ export class ImxApiDataMock extends BaseImxApiDataMock { }, }, }), - numOfEntries + numOfEntries, ); } } export class DummyJobData { static getItem(params: IJobQueueParams): OpsupportQueueJobs { - const dummyTaskName = TypeMoq.Mock.ofType>(); - const dummyJobChainName = TypeMoq.Mock.ofType>(); - const dummyUidTree = TypeMoq.Mock.ofType>(); - const dummyUidJob = TypeMoq.Mock.ofType>(); - const dummyUidJobSuccess = TypeMoq.Mock.ofType>(); - const dummyUidJobError = TypeMoq.Mock.ofType>(); - const dummyQueue = TypeMoq.Mock.ofType>(); - const dummyRetries = TypeMoq.Mock.ofType>(); - const dummyIsRootJob = TypeMoq.Mock.ofType>(); - const dummyXDataInserted = TypeMoq.Mock.ofType>(); - const dummyReadyToExe = TypeMoq.Mock.ofType>(); + const dummyTaskName = { value: params.TaskName ? params.TaskName : '' }; + const dummyJobChainName = { value: params.JobChainName ? params.JobChainName : '' }; + const dummyUidTree = { value: params.Uid_Tree }; + const dummyUidJob = { value: params.Uid_Job }; + const dummyUidJobSuccess = { value: params.Uid_JobSuccess ? params.Uid_JobSuccess : '' }; + const dummyUidJobError = { value: params.Uid_JobError ? params.Uid_JobError : '' }; + const dummyQueue = { value: params.Queue ? params.Queue : '' }; + const dummyRetries = { value: params.Retries ? params.Retries : 0 }; + const dummyIsRootJob = { value: params.IsRootJob ? params.IsRootJob : false }; + const dummyXDataInserted = { value: params.XDateInserted ? params.XDateInserted : new Date(2001, 1, 1) }; + const dummyReadyToExe = { value: params.ReadyToExe ? params.ReadyToExe : 'TRUE' }; - dummyTaskName.setup((el) => el.value).returns(() => (params.TaskName ? params.TaskName : '')); - dummyJobChainName.setup((el) => el.value).returns(() => (params.JobChainName ? params.JobChainName : '')); - dummyUidTree.setup((el) => el.value).returns(() => params.Uid_Tree); - dummyUidJob.setup((el) => el.value).returns(() => params.Uid_Job); - dummyUidJobSuccess.setup((el) => el.value).returns(() => (params.Uid_JobSuccess ? params.Uid_JobSuccess : '')); - dummyUidJobError.setup((el) => el.value).returns(() => (params.Uid_JobError ? params.Uid_JobError : '')); - dummyQueue.setup((el) => el.value).returns(() => (params.Queue ? params.Queue : '')); - dummyRetries.setup((el) => el.value).returns(() => (params.Retries ? params.Retries : 0)); - dummyIsRootJob.setup((el) => el.value).returns(() => (params.IsRootJob ? params.IsRootJob : false)); - dummyXDataInserted.setup((el) => el.value).returns(() => (params.XDateInserted ? params.XDateInserted : new Date(2001, 1, 1))); - dummyReadyToExe.setup((el) => el.value).returns(() => (params.ReadyToExe ? params.ReadyToExe : 'TRUE')); - - const dummy = TypeMoq.Mock.ofType(); - dummy.setup((obj) => obj.TaskName).returns(() => dummyTaskName.object); - dummy.setup((obj) => obj.JobChainName).returns(() => dummyJobChainName.object); - dummy.setup((obj) => obj.UID_Tree).returns(() => dummyUidTree.object); - dummy.setup((obj) => obj.UID_Job).returns(() => dummyUidJob.object); - dummy.setup((obj) => obj.UID_JobSuccess).returns(() => dummyUidJobSuccess.object); - dummy.setup((obj) => obj.UID_JobError).returns(() => dummyUidJobError.object); - dummy.setup((obj) => obj.Queue).returns(() => dummyQueue.object); - dummy.setup((obj) => obj.Retries).returns(() => dummyRetries.object); - dummy.setup((obj) => obj.IsRootJob).returns(() => dummyIsRootJob.object); - dummy.setup((obj) => obj.XDateInserted).returns(() => dummyXDataInserted.object); - dummy.setup((obj) => obj.Ready2EXE).returns(() => dummyReadyToExe.object); - dummy.setup((obj) => obj.CombinedStatus).returns(() => CreateIReadValue(params.CombinedStatus)); - - return dummy.object; + return { + TaskName: dummyTaskName, + JobChainName: dummyJobChainName, + UID_Tree: dummyUidTree, + UID_Job: dummyUidJob, + UID_JobSuccess: dummyUidJobSuccess, + UID_JobError: dummyUidJobError, + Queue: dummyQueue, + Retries: dummyRetries, + IsRootJob: dummyIsRootJob, + XDateInserted: dummyXDataInserted, + Ready2EXE: dummyReadyToExe, + CombinedStatus: CreateIReadValue(params.CombinedStatus), + } as OpsupportQueueJobs; } } diff --git a/imxweb/projects/qer-app-operationssupport/src/app/test-utilities/imx-session.service.spy.spec.ts b/imxweb/projects/qer-app-operationssupport/src/app/test-utilities/imx-session.service.spy.spec.ts index 3e71c9e1e..e1b2da7d2 100644 --- a/imxweb/projects/qer-app-operationssupport/src/app/test-utilities/imx-session.service.spy.spec.ts +++ b/imxweb/projects/qer-app-operationssupport/src/app/test-utilities/imx-session.service.spy.spec.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -24,8 +24,8 @@ * */ -import { Client } from 'imx-api-qbm'; -import { DbObjectKey } from 'imx-qbm-dbts'; +import { Client } from '@imx-modules/imx-api-qbm'; +import { DbObjectKey } from '@imx-modules/imx-qbm-dbts'; import { ISessionState, DbObjectInfo } from 'qbm'; import { ImxApiDataMock, ImxApiDtoMock } from '../test-utilities/imx-api-mock.spec'; @@ -49,19 +49,19 @@ export class SessionServiceSpy { private dummySearchGetResponse: Promise = Promise.resolve([ { Key: new DbObjectKey('testtable', 'aKey'), Display: 'theDisplay' }, { Key: new DbObjectKey('testtable', 'anotherKey'), Display: 'anotherDisplay' }, - { Key: new DbObjectKey('testtable', 'aThirdKey'), Display: 'aThirdDisplay' } + { Key: new DbObjectKey('testtable', 'aThirdKey'), Display: 'aThirdDisplay' }, ]); private dummyEntityCollectionData = Promise.resolve({ Display: 'dummyDisplay', LongDisplay: 'dummyLongDisplay', Keys: ['', '', '', '', '', '', '', '', '', ''], - Columns: {} + Columns: {}, }); private historyEvents = [ { ChangeTime: new Date(2019, 1, 1), IsRemoveEvent: true }, - { ChangeTime: new Date(2019, 1, 2), IsRemoveEvent: true } + { ChangeTime: new Date(2019, 1, 2), IsRemoveEvent: true }, ]; public dummyTranslationDict: { @@ -79,11 +79,11 @@ export class SessionServiceSpy { public dummyProviderUrl = 'dummyProviderUrl'; public dummyCaptions = { text1_key: 'text1_value', - text2_key: 'text2_value' + text2_key: 'text2_value', } as { [key: string]: string }; public dummyTypedEntityCollection = { - totalCount: 10 + totalCount: 10, } as TypedEntityCollectionMock; public dbQueue = ImxApiDataMock.CreateDbQueue(); @@ -117,14 +117,14 @@ export class SessionServiceSpy { call: false, push: {}, sms: false, - verify: {} + verify: {}, }, systemStatusInformation: { IsDbSchedulerDisabled: true, IsJobServiceDisabled: false, IsCompilationRequired: true, - IsInMaintenanceMode: true - } + IsInMaintenanceMode: true, + }, }; return jasmine.createSpyObj('Client', { imx_metadata_table_get: Promise.resolve({ Display: this.dummyMetaTableDisplay }), @@ -138,7 +138,7 @@ export class SessionServiceSpy { opsupport_queue_object_get: Promise.resolve({ DbQueue: ImxApiDtoMock.CreateEntityDataCollection(this.dbQueue), JobQueue: ImxApiDtoMock.CreateEntityDataCollection(this.jobQueue), - Unsupported: false + Unsupported: false, }), opsupport_queue_reactivatejob_post: this.dummyEntityCollectionData, opsupport_search_get: this.dummySearchGetResponse, @@ -148,30 +148,32 @@ export class SessionServiceSpy { opsupport_starling_verify_get: Promise.resolve(config.starlingApi.verify), opsupport_sync_summary_get: Promise.resolve(), opsupport_systemstatus_get: Promise.resolve(config.systemStatusInformation), - opsupport_systemstatus_post: Promise.resolve(config.systemStatusInformation) + opsupport_systemstatus_post: Promise.resolve(config.systemStatusInformation), }); } private getSessionStateSpy(): jasmine.Spy { - return jasmine.createSpy('getSessionState').and.returnValue(Promise.resolve({ - IsLoggedOut: true, - IsLoggedIn: this.currentState.isLoggedIn, - Config: this.sessionResponseConfig, - SecondaryAuthName: this.dummySecondaryAuthName, - UserUid: this.dummyUserUid, - Status: { - PrimaryAuth: { - IsAuthenticated: this.currentState.isLoggedIn - } - } - })); + return jasmine.createSpy('getSessionState').and.returnValue( + Promise.resolve({ + IsLoggedOut: true, + IsLoggedIn: this.currentState.isLoggedIn, + Config: this.sessionResponseConfig, + SecondaryAuthName: this.dummySecondaryAuthName, + UserUid: this.dummyUserUid, + Status: { + PrimaryAuth: { + IsAuthenticated: this.currentState.isLoggedIn, + }, + }, + }), + ); } private getLogoutSpy(): jasmine.Spy { return jasmine.createSpy('logout').and.returnValue( Promise.resolve({ - IsLoggedOut: true - }) + IsLoggedOut: true, + }), ); } @@ -180,8 +182,8 @@ export class SessionServiceSpy { Promise.resolve({ IsLoggedIn: true, Config: this.sessionResponseConfig, - Username: this.dummyUserName - } as ISessionState) + Username: this.dummyUserName, + } as ISessionState), ); } } diff --git a/imxweb/projects/qer-app-operationssupport/src/app/test-utilities/imx-translation-provider.service.spy.spec.ts b/imxweb/projects/qer-app-operationssupport/src/app/test-utilities/imx-translation-provider.service.spy.spec.ts index 680945f38..81b270eee 100644 --- a/imxweb/projects/qer-app-operationssupport/src/app/test-utilities/imx-translation-provider.service.spy.spec.ts +++ b/imxweb/projects/qer-app-operationssupport/src/app/test-utilities/imx-translation-provider.service.spy.spec.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -29,8 +29,8 @@ import { of } from 'rxjs'; import { TextContainer } from 'qbm'; export class TranslationProviderServiceSpy { - public multilanguageTranslationDict = {}; - public Translate = jasmine.createSpy('Translate').and.callFake((text: TextContainer) => of(text.key + '_übersetzt')); - public GetColumnDisplay = jasmine.createSpy('GetColumnDisplay').and.callThrough(); - public currentLang = 'en-us'; + public multilanguageTranslationDict = {}; + public Translate = jasmine.createSpy('Translate').and.callFake((text: TextContainer) => of(text.key + '_übersetzt')); + public GetColumnDisplay = jasmine.createSpy('GetColumnDisplay').and.callThrough(); + public currentLang = 'en-us'; } diff --git a/imxweb/projects/qer-app-operationssupport/src/app/test-utilities/router-mock.spec.ts b/imxweb/projects/qer-app-operationssupport/src/app/test-utilities/router-mock.spec.ts index 104d17ca8..c7addec45 100644 --- a/imxweb/projects/qer-app-operationssupport/src/app/test-utilities/router-mock.spec.ts +++ b/imxweb/projects/qer-app-operationssupport/src/app/test-utilities/router-mock.spec.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -35,14 +35,16 @@ export class RoutingMock { return { snapshot: { paramMap: { - get: spyResult != null ? jasmine.createSpy('get').and - .returnValue(spyResult) : jasmine.createSpy('get').and.callFake((key: string) => key) + get: + spyResult != null + ? jasmine.createSpy('get').and.returnValue(spyResult) + : jasmine.createSpy('get').and.callFake((key: string) => key), }, queryParamMap: { - get: jasmine.createSpy('get').and.returnValue(queryParamsMap) - } + get: jasmine.createSpy('get').and.returnValue(queryParamsMap), + }, }, - queryParams + queryParams, }; } diff --git a/imxweb/projects/qer-app-operationssupport/src/app/test-utilities/test-helper.module.spec.ts b/imxweb/projects/qer-app-operationssupport/src/app/test-utilities/test-helper.module.spec.ts index e2c2f4a9f..8cdf80e00 100644 --- a/imxweb/projects/qer-app-operationssupport/src/app/test-utilities/test-helper.module.spec.ts +++ b/imxweb/projects/qer-app-operationssupport/src/app/test-utilities/test-helper.module.spec.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -28,9 +28,9 @@ import { NgModule, NO_ERRORS_SCHEMA } from '@angular/core'; import { TranslateModule, TranslateLoader, TranslateParser, TranslateFakeLoader, TranslateDefaultParser } from '@ngx-translate/core'; @NgModule({ - exports: [TranslateModule], - imports: [TranslateModule.forRoot({ loader: { provide: TranslateLoader, useClass: TranslateFakeLoader } })], - providers: [{ provide: TranslateParser, useClass: TranslateDefaultParser }], - schemas: [NO_ERRORS_SCHEMA] + exports: [TranslateModule], + imports: [TranslateModule.forRoot({ loader: { provide: TranslateLoader, useClass: TranslateFakeLoader } })], + providers: [{ provide: TranslateParser, useClass: TranslateDefaultParser }], + schemas: [NO_ERRORS_SCHEMA], }) -export class TestHelperModule { } +export class TestHelperModule {} diff --git a/imxweb/projects/qer-app-operationssupport/src/app/test-utilities/typed-entity-provider.spec.ts b/imxweb/projects/qer-app-operationssupport/src/app/test-utilities/typed-entity-provider.spec.ts index 0443620a0..22953e5de 100644 --- a/imxweb/projects/qer-app-operationssupport/src/app/test-utilities/typed-entity-provider.spec.ts +++ b/imxweb/projects/qer-app-operationssupport/src/app/test-utilities/typed-entity-provider.spec.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -26,7 +26,7 @@ import { TestBed } from '@angular/core/testing'; -import { ValType, EntitySchema, IClientProperty } from 'imx-qbm-dbts'; +import { ValType, EntitySchema, IClientProperty } from '@imx-modules/imx-qbm-dbts'; import { imx_SessionService } from 'qbm'; export interface ClientPropertyMock { @@ -39,11 +39,11 @@ export interface ClientPropertyMock { export function CreateEntitySchema(properties: ClientPropertyMock[]): EntitySchema { const columns: { [id: string]: IClientProperty } = {}; properties.forEach( - property => + (property) => (columns[property.name] = { Type: property.type ? property.type : ValType.String, Display: property.Display, - }) + }), ); return { Columns: columns }; } @@ -56,16 +56,20 @@ export interface TypedEntityReadOnlyProviderTestConfig { typedClient?: any; } -export function testTypedEntityReadOnlyProvider(testconfig: TypedEntityReadOnlyProviderTestConfig): void { - beforeEach(() => TestBed.configureTestingModule({ - providers: [ - testconfig.type, - { - provide: imx_SessionService, - useValue: { TypedClient: testconfig.typedClient } - } - ] - })); +export function testTypedEntityReadOnlyProvider( + testconfig: TypedEntityReadOnlyProviderTestConfig, +): void { + beforeEach(() => + TestBed.configureTestingModule({ + providers: [ + testconfig.type, + { + provide: imx_SessionService, + useValue: { TypedClient: testconfig.typedClient }, + }, + ], + }), + ); it('should be created', () => { expect(TestBed.get(testconfig.type)).toBeTruthy(); diff --git a/imxweb/projects/qer-app-operationssupport/src/app/unresolved-refs/unresolved-refs.component.html b/imxweb/projects/qer-app-operationssupport/src/app/unresolved-refs/unresolved-refs.component.html index c4c942e6a..ea61acf16 100644 --- a/imxweb/projects/qer-app-operationssupport/src/app/unresolved-refs/unresolved-refs.component.html +++ b/imxweb/projects/qer-app-operationssupport/src/app/unresolved-refs/unresolved-refs.component.html @@ -1,34 +1,34 @@
    -

    +

    {{ '#LDS#Heading Unresolved References' | translate }} -

    +
    - - + +
    {{ data?.DisplayName?.Column.GetDisplayValue() }}
    - +
    {{ data?.OwnerObject?.Column.GetDisplayValue() }}
    - +
    {{ data?.ShellDisplay?.Column.GetDisplayValue() }}
    - +
    {{ data?.SystemDisplay?.Column.GetDisplayValue() }}
    - +
    {{ data?.Data?.Column.GetDisplayValue() }}
    @@ -37,7 +37,7 @@

    - diff --git a/imxweb/projects/qer-app-operationssupport/src/app/unresolved-refs/unresolved-refs.component.scss b/imxweb/projects/qer-app-operationssupport/src/app/unresolved-refs/unresolved-refs.component.scss index 044b6f74b..a84ea5995 100644 --- a/imxweb/projects/qer-app-operationssupport/src/app/unresolved-refs/unresolved-refs.component.scss +++ b/imxweb/projects/qer-app-operationssupport/src/app/unresolved-refs/unresolved-refs.component.scss @@ -5,23 +5,7 @@ flex-grow: 1; } -.imx-table-container { - flex: 1 1 auto; - display: flex; - flex-direction: column; - overflow: auto; - - > :nth-child(2) { - flex: 1 1 auto; - } -} - .imx-unresolved-refs-data { max-height: 100px; overflow: auto; } - -.imx-refresh-button { - margin-right: 5px; - height: 50px; -} diff --git a/imxweb/projects/qer-app-operationssupport/src/app/unresolved-refs/unresolved-refs.component.ts b/imxweb/projects/qer-app-operationssupport/src/app/unresolved-refs/unresolved-refs.component.ts index 192aa9ac1..f3a034771 100644 --- a/imxweb/projects/qer-app-operationssupport/src/app/unresolved-refs/unresolved-refs.component.ts +++ b/imxweb/projects/qer-app-operationssupport/src/app/unresolved-refs/unresolved-refs.component.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -29,16 +29,15 @@ import { OverlayRef } from '@angular/cdk/overlay'; import { EuiLoadingService } from '@elemental-ui/core'; import { DataSourceToolbarSettings } from 'qbm'; -import { DisplayColumns, EntitySchema, IClientProperty } from 'imx-qbm-dbts'; +import { DisplayColumns, EntitySchema, IClientProperty } from '@imx-modules/imx-qbm-dbts'; import { UnresolvedRefsService } from './unresolved-refs.service'; @Component({ selector: 'imx-unresolved-refs-gridview', templateUrl: './unresolved-refs.component.html', - styleUrls: ['./unresolved-refs.component.scss'] + styleUrls: ['./unresolved-refs.component.scss'], }) export class UnresolvedRefsComponent implements OnInit { - public dstSettings: DataSourceToolbarSettings; public readonly entitySchemaRefs: EntitySchema; public readonly DisplayColumns = DisplayColumns; @@ -54,7 +53,7 @@ export class UnresolvedRefsComponent implements OnInit { this.entitySchemaRefs.Columns.OwnerObject, this.entitySchemaRefs.Columns.ShellDisplay, this.entitySchemaRefs.Columns.SystemDisplay, - this.entitySchemaRefs.Columns.Data + this.entitySchemaRefs.Columns.Data, ]; } @@ -67,19 +66,16 @@ export class UnresolvedRefsComponent implements OnInit { } public async getData(): Promise { - let overlayRef: OverlayRef; - setTimeout(() => overlayRef = this.busyService.show()); + setTimeout(() => (overlayRef = this.busyService.show())); try { - const journalEntries = await this.unresolvedRefsService.get(); this.dstSettings = { displayedColumns: this.displayedColumns, dataSource: journalEntries, entitySchema: this.entitySchemaRefs, - navigationState: {} + navigationState: {}, }; - } finally { setTimeout(() => this.busyService.hide(overlayRef)); } diff --git a/imxweb/projects/qer-app-operationssupport/src/app/unresolved-refs/unresolved-refs.module.ts b/imxweb/projects/qer-app-operationssupport/src/app/unresolved-refs/unresolved-refs.module.ts index da39edec0..7836073b0 100644 --- a/imxweb/projects/qer-app-operationssupport/src/app/unresolved-refs/unresolved-refs.module.ts +++ b/imxweb/projects/qer-app-operationssupport/src/app/unresolved-refs/unresolved-refs.module.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -35,20 +35,9 @@ import { DataSourceToolbarModule, DataTableModule } from 'qbm'; import { UnresolvedRefsComponent } from './unresolved-refs.component'; import { UnresolvedRefsService } from './unresolved-refs.service'; - - - @NgModule({ declarations: [UnresolvedRefsComponent], - imports: [ - CommonModule, - TranslateModule, - DataSourceToolbarModule, - DataTableModule, - EuiCoreModule, - MatTooltipModule, - MatButtonModule - ], - providers: [UnresolvedRefsService] + imports: [CommonModule, TranslateModule, DataSourceToolbarModule, DataTableModule, EuiCoreModule, MatTooltipModule, MatButtonModule], + providers: [UnresolvedRefsService], }) -export class UnresolvedRefsModule { } +export class UnresolvedRefsModule {} diff --git a/imxweb/projects/qer-app-operationssupport/src/app/unresolved-refs/unresolved-refs.service.ts b/imxweb/projects/qer-app-operationssupport/src/app/unresolved-refs/unresolved-refs.service.ts index 77e77b4e8..9e0a931cd 100644 --- a/imxweb/projects/qer-app-operationssupport/src/app/unresolved-refs/unresolved-refs.service.ts +++ b/imxweb/projects/qer-app-operationssupport/src/app/unresolved-refs/unresolved-refs.service.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -26,12 +26,12 @@ import { Injectable } from '@angular/core'; -import { OpsupportSyncDatastore } from 'imx-api-dpr'; -import { EntitySchema, TypedEntityCollectionData } from 'imx-qbm-dbts'; +import { OpsupportSyncDatastore } from '@imx-modules/imx-api-dpr'; +import { EntitySchema, TypedEntityCollectionData } from '@imx-modules/imx-qbm-dbts'; import { DprApiService } from '../../../dpr-api-client.service'; @Injectable({ - providedIn: 'root' + providedIn: 'root', }) export class UnresolvedRefsService { public schema: EntitySchema; diff --git a/imxweb/projects/qer-app-operationssupport/src/app/web-applications/web-applications.component.html b/imxweb/projects/qer-app-operationssupport/src/app/web-applications/web-applications.component.html index e15b2398b..d1a7848df 100644 --- a/imxweb/projects/qer-app-operationssupport/src/app/web-applications/web-applications.component.html +++ b/imxweb/projects/qer-app-operationssupport/src/app/web-applications/web-applications.component.html @@ -1,35 +1,41 @@
    -

    - {{'#LDS#Heading Web Applications' | translate}} -

    +

    + {{ '#LDS#Heading Web Applications' | translate }} +

    - + - - + + {{ data.BaseURL.Column.GetDisplayValue() }} - + {{ data.UID_DialogProduct.Column.GetDisplayValue() }} - + {{ data.IsDebug.Column.GetDisplayValue() }} - + {{ data.IsPrivate.Column.GetDisplayValue() }} - + {{ data.AutoUpdateLevel.Column.GetDisplayValue() }} @@ -39,7 +45,7 @@

    - diff --git a/imxweb/projects/qer-app-operationssupport/src/app/web-applications/web-applications.component.scss b/imxweb/projects/qer-app-operationssupport/src/app/web-applications/web-applications.component.scss index 09dc25eb1..f1c455826 100644 --- a/imxweb/projects/qer-app-operationssupport/src/app/web-applications/web-applications.component.scss +++ b/imxweb/projects/qer-app-operationssupport/src/app/web-applications/web-applications.component.scss @@ -5,27 +5,11 @@ flex-grow: 1; } - .mat-column-IsDebug, - .mat-column-IsPrivate { - max-width: 240px; - } - - .mat-column-BaseURL { - min-width: 440px; - } - -.imx-table-container { - flex: 1 1 auto; - display: flex; - flex-direction: column; - max-height: calc(100% - 45px); - - > :nth-child(2) { - flex: 1 1 auto; - } +.mat-column-IsDebug, +.mat-column-IsPrivate { + max-width: 240px; } -.imx-refresh-button { - margin-right: 5px; - height: 50px; +.mat-column-BaseURL { + min-width: 440px; } diff --git a/imxweb/projects/qer-app-operationssupport/src/app/web-applications/web-applications.component.ts b/imxweb/projects/qer-app-operationssupport/src/app/web-applications/web-applications.component.ts index d6016d6a6..bbea2f66e 100644 --- a/imxweb/projects/qer-app-operationssupport/src/app/web-applications/web-applications.component.ts +++ b/imxweb/projects/qer-app-operationssupport/src/app/web-applications/web-applications.component.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -27,7 +27,7 @@ import { OverlayRef } from '@angular/cdk/overlay'; import { Component, OnInit } from '@angular/core'; import { EuiLoadingService } from '@elemental-ui/core'; -import { CollectionLoadParameters, EntitySchema, IClientProperty } from 'imx-qbm-dbts'; +import { CollectionLoadParameters, EntitySchema, IClientProperty } from '@imx-modules/imx-qbm-dbts'; import { DataSourceToolbarSettings, SettingsService } from 'qbm'; import { WebApplicationsService } from './web-applications.service'; @@ -37,17 +37,15 @@ import { WebApplicationsService } from './web-applications.service'; styleUrls: ['./web-applications.component.scss'], }) export class WebApplicationsComponent implements OnInit { - public dstSettings: DataSourceToolbarSettings; public readonly entitySchemaWebApplications: EntitySchema; private navigationState: CollectionLoadParameters; private readonly displayedColumns: IClientProperty[]; - constructor( private webApplicationsService: WebApplicationsService, private busyService: EuiLoadingService, - private readonly settings: SettingsService + private readonly settings: SettingsService, ) { this.entitySchemaWebApplications = webApplicationsService.schema; this.displayedColumns = [ @@ -75,17 +73,15 @@ export class WebApplicationsComponent implements OnInit { this.navigationState = navigationState; let overlayRef: OverlayRef; - setTimeout(() => overlayRef = this.busyService.show()); + setTimeout(() => (overlayRef = this.busyService.show())); try { - const applications = await this.webApplicationsService.get(navigationState); this.dstSettings = { displayedColumns: this.displayedColumns, dataSource: applications, entitySchema: this.entitySchemaWebApplications, - navigationState: this.navigationState + navigationState: this.navigationState, }; - } finally { setTimeout(() => this.busyService.hide(overlayRef)); } diff --git a/imxweb/projects/qer-app-operationssupport/src/app/web-applications/web-applications.module.ts b/imxweb/projects/qer-app-operationssupport/src/app/web-applications/web-applications.module.ts index 1def5cc6c..c69a02dbe 100644 --- a/imxweb/projects/qer-app-operationssupport/src/app/web-applications/web-applications.module.ts +++ b/imxweb/projects/qer-app-operationssupport/src/app/web-applications/web-applications.module.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -35,21 +35,9 @@ import { DataSourceToolbarModule, DataTableModule } from 'qbm'; import { WebApplicationsComponent } from './web-applications.component'; import { WebApplicationsService } from './web-applications.service'; - - @NgModule({ - declarations: [ - WebApplicationsComponent - ], - imports: [ - CommonModule, - DataTableModule, - DataSourceToolbarModule, - EuiCoreModule, - MatTooltipModule, - MatButtonModule, - TranslateModule - ], - providers: [WebApplicationsService] + declarations: [WebApplicationsComponent], + imports: [CommonModule, DataTableModule, DataSourceToolbarModule, EuiCoreModule, MatTooltipModule, MatButtonModule, TranslateModule], + providers: [WebApplicationsService], }) -export class WebApplicationsModule { } +export class WebApplicationsModule {} diff --git a/imxweb/projects/qer-app-operationssupport/src/app/web-applications/web-applications.service.ts b/imxweb/projects/qer-app-operationssupport/src/app/web-applications/web-applications.service.ts index 2771526c8..f913c48ea 100644 --- a/imxweb/projects/qer-app-operationssupport/src/app/web-applications/web-applications.service.ts +++ b/imxweb/projects/qer-app-operationssupport/src/app/web-applications/web-applications.service.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -27,8 +27,8 @@ import { Injectable } from '@angular/core'; import { imx_SessionService } from 'qbm'; -import { OpsupportWebapplications } from 'imx-api-qbm'; -import { CollectionLoadParameters, EntitySchema, ExtendedTypedEntityCollection } from 'imx-qbm-dbts'; +import { OpsupportWebapplications } from '@imx-modules/imx-api-qbm'; +import { CollectionLoadParameters, EntitySchema, ExtendedTypedEntityCollection } from '@imx-modules/imx-qbm-dbts'; @Injectable() export class WebApplicationsService { @@ -36,7 +36,7 @@ export class WebApplicationsService { return this.session.TypedClient.OpsupportWebapplications.GetSchema(); } - constructor(private session: imx_SessionService) { } + constructor(private session: imx_SessionService) {} public async get(parameter: CollectionLoadParameters): Promise> { return this.session.TypedClient.OpsupportWebapplications.Get(parameter); diff --git a/imxweb/projects/qer-app-operationssupport/src/environments/environment.prod.ts b/imxweb/projects/qer-app-operationssupport/src/environments/environment.prod.ts index 7fe5e91b2..2ac427ed2 100644 --- a/imxweb/projects/qer-app-operationssupport/src/environments/environment.prod.ts +++ b/imxweb/projects/qer-app-operationssupport/src/environments/environment.prod.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -30,5 +30,5 @@ export const environment = { production: true, clientUrl: '', appName: packageJson.name, - appVersion: packageJson.version + appVersion: packageJson.version, }; diff --git a/imxweb/projects/qer-app-operationssupport/src/environments/environment.ts b/imxweb/projects/qer-app-operationssupport/src/environments/environment.ts index de9c0390d..1321fa2e3 100644 --- a/imxweb/projects/qer-app-operationssupport/src/environments/environment.ts +++ b/imxweb/projects/qer-app-operationssupport/src/environments/environment.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -35,5 +35,5 @@ export const environment = { production: false, clientUrl: 'http://localhost:8182', appName: packageJson.name, - appVersion: packageJson.version + appVersion: packageJson.version, }; diff --git a/imxweb/projects/qer-app-operationssupport/src/index.html b/imxweb/projects/qer-app-operationssupport/src/index.html index 4b785ba4e..f08db67fd 100644 --- a/imxweb/projects/qer-app-operationssupport/src/index.html +++ b/imxweb/projects/qer-app-operationssupport/src/index.html @@ -1,15 +1,13 @@ + + + + + + - - - - - - - - - - - + + + diff --git a/imxweb/projects/qer-app-operationssupport/src/main.ts b/imxweb/projects/qer-app-operationssupport/src/main.ts index 68f7fed01..aa265c318 100644 --- a/imxweb/projects/qer-app-operationssupport/src/main.ts +++ b/imxweb/projects/qer-app-operationssupport/src/main.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -36,4 +36,4 @@ if (environment.production) { platformBrowserDynamic() .bootstrapModule(AppModule) - .catch(err => console.log(err)); + .catch((err) => console.log(err)); diff --git a/imxweb/projects/qer-app-operationssupport/src/polyfills.ts b/imxweb/projects/qer-app-operationssupport/src/polyfills.ts index 48573d378..027c82242 100644 --- a/imxweb/projects/qer-app-operationssupport/src/polyfills.ts +++ b/imxweb/projects/qer-app-operationssupport/src/polyfills.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -41,9 +41,8 @@ */ /*************************************************************************************************** -* BROWSER POLYFILLS -*/ - + * BROWSER POLYFILLS + */ /** IE10 and IE11 requires the following for NgClass support on SVG elements */ // import 'classlist.js'; // Run `npm install --save classlist.js`. @@ -51,31 +50,25 @@ /** IE10 and IE11 requires the following for the Reflect API. */ // import 'core-js/es6/reflect'; - /** Evergreen browsers require these. */ // Used for reflect-metadata in JIT. If you use AOT (and only Angular decorators), you can remove. -import 'core-js/es7/reflect'; - +import 'core-js/es/reflect'; // Used for support array.includes -import 'core-js/es7/array'; +import 'core-js/es/array'; /** * Required to support Web Animations `@angular/platform-browser/animations`. * Needed for: All but Chrome, Firefox and Opera. http://caniuse.com/#feat=web-animation */ import 'web-animations-js'; - - /*************************************************************************************************** * Zone JS is required by default for Angular itself. */ -import 'zone.js/dist/zone'; // Included with Angular CLI. - - +import 'zone.js'; // Included with Angular CLI. /*************************************************************************************************** * APPLICATION IMPORTS */ -import 'whatwg-fetch'; import 'url-polyfill'; +import 'whatwg-fetch'; diff --git a/imxweb/projects/qer-app-operationssupport/src/styles.scss b/imxweb/projects/qer-app-operationssupport/src/styles.scss index ba6c0d14a..4df681e05 100644 --- a/imxweb/projects/qer-app-operationssupport/src/styles.scss +++ b/imxweb/projects/qer-app-operationssupport/src/styles.scss @@ -1,13 +1,22 @@ /* You can add global styles to this file, and also import other style files */ -@use '@angular/material' as mat; - -$material_icons_font_path: "~node_modules/@elemental-ui/core/assets/MaterialIcons"; -$cadence_font_path: "~node_modules/@elemental-ui/core/assets/Cadence"; -$source_sans_pro_font_path: "~node_modules/@elemental-ui/core/assets/Source_Sans_Pro"; - @import '@elemental-ui/core/src/styles/core.scss'; +@import '@elemental-ui/core/src/styles/_eui_palette.scss'; +@import 'base/variables'; +@import 'base/margins-paddings'; + +@import 'components/paginator'; +@import 'components/progress-bar'; +@import 'components/spinner'; +@import 'components/ripple'; +@import 'components/table'; +@import 'components/tabs'; +@import 'components/toolbar'; +@import 'components/tree'; -@import "variables"; +/* overall used styles */ +.imx-hidden { + display: none; +} /* #region Grid styles*/ @@ -16,67 +25,13 @@ $source_sans_pro_font_path: "~node_modules/@elemental-ui/core/assets/Source_Sans font-weight: bold; } -.mat-row.imx_MatTableRow { - min-height: 60px; -} - -.mat-header-row.imx_MatTableHeaderRow { - margin-top: 3px; - margin-bottom: 0; - padding-bottom: 12px; - padding-top: 12px; - min-height: 0; -} - -.imx-ListViewItem, -.mat-cell.imx_ColumnCell { +.imx-ListViewItem { font-size: 15px; text-overflow: ellipsis; - color: $VI_Common_Color_Gray; + color: $color-gray-60; margin: 0 10px; } -.imx_ColumnHeader { - font-size: 13px; - color: $VI_Common_Color_Gray; - margin: -8px 10px; - padding: 10px 0; - line-height: 24px; - display: block; - overflow: hidden; - text-overflow: ellipsis; -} - -.mat-header-cell.imx_CheckableCell { - flex: 0 0 45px; -} - -.mat-cell.imx_CheckableCell { - flex: 0 0 45px; -} - -.mat-sort-header-button:disabled { - background-color: Transparent !important; - color: $VI_Common_Color_Gray !important; - cursor: default; -} - -.mat-table .mat-checkbox-checked.mat-accent .mat-checkbox-background, -.mat-table .mat-checkbox-indeterminate.mat-accent .mat-checkbox-background { - background-color: $color-orange-60; -} - -.mat-ripple-element { - background: transparent !important; -} - -.mat-paginator-navigation-next.mat-icon-button, -.mat-paginator-navigation-previous.mat-icon-button { - background: transparent !important; - width: 16px !important; - margin-right: 10px !important; -} - .imx-ListViewItem { margin-top: 10px; margin-bottom: 10px; @@ -86,41 +41,20 @@ $source_sans_pro_font_path: "~node_modules/@elemental-ui/core/assets/Source_Sans /* #region MatCard styles */ -.mat-card { - - .mat-card-title { +.mat-mdc-card { + .mat-mdc-card-title { font-weight: 600; - font-size: 24px; - color: $gunmetal; - text-overflow: ellipsis; white-space: nowrap; - overflow: hidden; } - - mat-card-subtitle { - margin-top: 10px; - height: 50px; - font-weight: 400 !important; - font-size: 14px; - color: $black-6; - } - mat-card-actions { - text-transform: uppercase; - font-size: 14px; - letter-spacing: .5px; - color: $iris-blue; margin: 0 !important; - .mat-button { - text-align: center; - font-weight: 600 !important; + .mat-mdc-button { text-transform: uppercase; } } } - /* #endregion */ /* #region OpsWeb styles */ @@ -150,7 +84,7 @@ $source_sans_pro_font_path: "~node_modules/@elemental-ui/core/assets/Source_Sans margin-right: 2em; width: 500px; height: 400px; - border: solid 1px $VI_Common_Color_LightGray; + border: solid 1px $color-gray-30; margin-bottom: 1em; vertical-align: top; display: inline-flex; @@ -165,7 +99,7 @@ $source_sans_pro_font_path: "~node_modules/@elemental-ui/core/assets/Source_Sans width: auto; z-index: 50; height: auto; - border: solid 1px $VI_Common_Color_LightGray; + border: solid 1px $color-gray-30; display: block; position: fixed; flex-direction: none; @@ -177,7 +111,7 @@ $source_sans_pro_font_path: "~node_modules/@elemental-ui/core/assets/Source_Sans margin-right: 2em; width: 700px; height: 400px; - border: solid 1px $VI_Common_Color_LightGray; + border: solid 1px $color-gray-30; margin-bottom: 1em; vertical-align: top; display: inline-flex; @@ -188,7 +122,7 @@ $source_sans_pro_font_path: "~node_modules/@elemental-ui/core/assets/Source_Sans margin-right: 2em; width: 700px; height: 600px; - border: solid 1px $VI_Common_Color_LightGray; + border: solid 1px $color-gray-30; margin-bottom: 1em; vertical-align: top; } @@ -197,7 +131,7 @@ $source_sans_pro_font_path: "~node_modules/@elemental-ui/core/assets/Source_Sans font-size: 2em; background-color: #efefef; margin: 0; - padding: .5rem; + padding: 0.5rem; color: $black; } @@ -205,7 +139,7 @@ $source_sans_pro_font_path: "~node_modules/@elemental-ui/core/assets/Source_Sans font-size: 2em; background-color: $white; margin: 0; - padding: .5rem; + padding: 0.5rem; color: $iris-blue; } @@ -213,16 +147,16 @@ $source_sans_pro_font_path: "~node_modules/@elemental-ui/core/assets/Source_Sans font-size: 2em; background-color: $white; margin: 0; - padding: .5rem; + padding: 0.5rem; color: $iris-blue; } .imx-ops-tile:hover { - border-color: $VI_Common_Color_Gray; + border-color: $color-gray-60; } .imx-ops-tile-inner { - padding: 0 .5rem; + padding: 0 0.5rem; flex: 1 1 auto; overflow: auto; } @@ -232,7 +166,7 @@ $source_sans_pro_font_path: "~node_modules/@elemental-ui/core/assets/Source_Sans } .imx-ops-tile-innerBottom { - padding: 0 .5rem; + padding: 0 0.5rem; flex-direction: row; } @@ -255,7 +189,7 @@ $source_sans_pro_font_path: "~node_modules/@elemental-ui/core/assets/Source_Sans max-height: 400px; } -@media screen and (max-height:650px) { +@media screen and (max-height: 650px) { .contentBounds { max-height: 200px; } @@ -284,7 +218,7 @@ $source_sans_pro_font_path: "~node_modules/@elemental-ui/core/assets/Source_Sans font-weight: normal; font-style: normal; font-stretch: normal; - line-height: .83; + line-height: 0.83; letter-spacing: normal; } @@ -298,33 +232,28 @@ $source_sans_pro_font_path: "~node_modules/@elemental-ui/core/assets/Source_Sans padding-right: 5px; } - - -imx-service-availability .mat-card { +imx-service-availability .mat-mdc-card { width: 411px; margin-bottom: 56px; - .mat-card-content { + .mat-mdc-card-content { display: flex; padding: 24px; button { flex: 0 0 auto; align-self: center; - font-size: 15px; margin-right: 26px; } span:first-child { text-transform: uppercase; color: $black-7; - font-size: 14px; margin-bottom: 5px; } span { display: block; - font-size: 20px; } } } @@ -332,7 +261,7 @@ imx-service-availability .mat-card { /*#endregion*/ /* #region SystemOverview styles */ -$tresholdExceededColor: $corbin-orange; +$thresholdExceededColor: $color-orange-60; imx-system-overview { display: block; @@ -350,15 +279,6 @@ imx-system-overview { left: -2px; } - .mat-tree { - margin-left: -15px; - } - - .mat-tree-node { - min-height: 23px; - margin-left: 5px; - } - .imx-system-overview-name { min-width: 360px; padding-left: 10px; @@ -403,24 +323,23 @@ imx-system-overview { } } - .imx-treshold-exceeded { - color: $phoenix-red; + .imx-threshold-exceeded { + color: $color-red-60; font-weight: 600; font-size: 14px; } - .imx-treshold-exceeded-label { + .imx-threshold-exceeded-label { font-weight: 600; font-size: 15px; .eui-icon { - color: $corbin-orange; padding-right: 10px; } } .imx-recommendedValue-exceeded { - color: $tresholdExceededColor; + color: $thresholdExceededColor; } .example-tooltip-red { @@ -450,32 +369,10 @@ imx-object-history { font-size: 14px; } - .imx-viewmode-dropdown { - margin: auto 6px; - - .mat-form-field-infix { - width: 98px; - color: $VI_Common_Color_Font; - border: 0; - } - - .mat-form-field-flex { - background-color: $white; - padding-left: 6px; - } - } - .imx-loader-hidden { visibility: hidden; } } - -.mat-option.mat-option-object-history { - height: unset !important; - padding: 4px 6px !important; - margin: 0 !important; -} - .grid-title-inline, .grid-title-inline > h1 { display: inline; @@ -486,9 +383,6 @@ imx-object-history { margin-top: 1.22em; } -.mat-paginator { - margin-bottom: 20px; -} /*#endregion ObjectHistory styles*/ /* #region ObjectOverview styles*/ @@ -499,116 +393,38 @@ imx-object-history { /*#endregion ObjectOverview styles*/ -/* #region SystemStatus*/ - -.greenCheck { - margin-right: .5em; - line-height: 20px; - color: $aspen-green; -} - -.warningSign { - line-height: 20px; - margin-right: .5em; - color: $QBM_Primary_Orange; -} - -.errorSign { - line-height: 20px; - margin-right: .5em; - color: $phoenix-red; -} - -/*#endregion*/ .eui-dark-theme { .page { - color: $color-gray-5; - background-color: $color-gray-80; - } - .pageContent { - color: $color-gray-5; - background-color: $color-gray-80; - } - .mat-card .mat-card-title{ - color: $color-gray-5; - } - .imx-service-availability .mat-card{ color: $color-gray-5; + background-color: $color-gray-80; } - .mat-cell, .mat-footer-cell{ + .pageContent { color: $color-gray-5; + background-color: $color-gray-80; } - .imx-normalCell ,.imx-title{ + .imx-service-availability .mat-mdc-card { color: $color-gray-5; } - .eui-sidesheet { - .mat-toolbar{ - background-color: $color-blue-80; - } - } - - imx-object-history { - .imx-viewmode-dropdown { - .mat-form-field-flex { - background-color: $color-gray-80; - } - } - } imx-object-history-timeline { background-color: $color-gray-80; } - - .mat-table .mat-checkbox-checked.mat-accent .mat-checkbox-background, - .mat-table .mat-checkbox-indeterminate.mat-accent .mat-checkbox-background { - background-color: $color-orange-40; - } } .eui-contrast-theme { .page { - color: $color-gray-0; - background-color: $color-gray-100; - } - .pageContent { - color: $color-gray-0; - background-color: $color-gray-100; - } - .mat-card .mat-card-title{ color: $color-gray-0; + background-color: $color-gray-100; } - .imx-service-availability .mat-card{ - color: $color-gray-0; - } - .mat-tab-label{ - background-color: $color-gray-90; - } - .mat-cell, .mat-footer-cell{ + .pageContent { color: $color-gray-0; + background-color: $color-gray-100; } - .imx-normalCell ,.imx-title{ + .imx-service-availability .mat-mdc-card { color: $color-gray-0; } - .eui-sidesheet { - .mat-toolbar{ - background-color: $color-blue-80; - } - } - - imx-object-history { - .imx-viewmode-dropdown { - .mat-form-field-flex { - background-color: $color-gray-100; - } - } - } imx-object-history-timeline { background-color: $color-gray-80; } - - .mat-table .mat-checkbox-checked.mat-accent .mat-checkbox-background, - .mat-table .mat-checkbox-indeterminate.mat-accent .mat-checkbox-background { - background-color: $color-orange-40; - } } diff --git a/imxweb/projects/qer-app-operationssupport/src/test.ts b/imxweb/projects/qer-app-operationssupport/src/test.ts index b80edded4..0eacdebc4 100644 --- a/imxweb/projects/qer-app-operationssupport/src/test.ts +++ b/imxweb/projects/qer-app-operationssupport/src/test.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -26,30 +26,12 @@ // This file is required by karma.conf.js and loads recursively all the .spec and framework files -import 'zone.js/dist/long-stack-trace-zone'; -import 'zone.js/dist/proxy.js'; -import 'zone.js/dist/sync-test'; -import 'zone.js/dist/jasmine-patch'; -import 'zone.js/dist/async-test'; -import 'zone.js/dist/fake-async-test'; +// Zone must be imported first. Be careful with prettier import organizing +import 'zone.js'; +import 'zone.js/testing'; + import { getTestBed } from '@angular/core/testing'; import { BrowserDynamicTestingModule, platformBrowserDynamicTesting } from '@angular/platform-browser-dynamic/testing'; -import { TestHelperModule } from './app/test-utilities/test-helper.module.spec'; - -// Unfortunately there's no typing for the `__karma__` variable. Just declare it as any. -declare const __karma__: any; -declare const require: any; - -// Prevent Karma from running prematurely. -__karma__.loaded = function() {}; - // First, initialize the Angular testing environment. -getTestBed().initTestEnvironment([BrowserDynamicTestingModule, TestHelperModule], platformBrowserDynamicTesting()); -// Then we find all the tests. -const context = require.context('./', true, /\.spec\.ts$/); -// And load the modules. -context.keys().map(context); - -// Finally, start Karma to run the tests. -__karma__.start(); +getTestBed().initTestEnvironment(BrowserDynamicTestingModule, platformBrowserDynamicTesting()); diff --git a/imxweb/projects/qer-app-operationssupport/tsconfig-es5.app.json b/imxweb/projects/qer-app-operationssupport/tsconfig-es5.app.json index e1d0d6abd..036b8797e 100644 --- a/imxweb/projects/qer-app-operationssupport/tsconfig-es5.app.json +++ b/imxweb/projects/qer-app-operationssupport/tsconfig-es5.app.json @@ -1,6 +1,6 @@ { - "extends": "./tsconfig.app.json", - "compilerOptions": { - "target": "es2020" + "extends": "./tsconfig.app.json", + "compilerOptions": { + "target": "es2020" } -} \ No newline at end of file +} diff --git a/imxweb/projects/qer-app-operationssupport/tsconfig.app.json b/imxweb/projects/qer-app-operationssupport/tsconfig.app.json index 6f4758564..df14e7d10 100644 --- a/imxweb/projects/qer-app-operationssupport/tsconfig.app.json +++ b/imxweb/projects/qer-app-operationssupport/tsconfig.app.json @@ -1,18 +1,14 @@ { "extends": "../../tsconfig.json", "compilerOptions": { + "strictNullChecks": true, "outDir": "../../out-tsc/app", "types": [] }, "angularCompilerOptions": { - "fullTemplateTypeCheck": true, - "strictInjectionParameters": true, + "strictTemplates": true, + "strictInjectionParameters": true }, - "files": [ - "src/main.ts", - "src/polyfills.ts" - ], - "include": [ - "projects/qer-app-operationssupport/src/**/*.d.ts" - ] + "files": ["src/main.ts", "src/polyfills.ts"], + "include": ["projects/qer-app-operationssupport/src/**/*.d.ts"] } diff --git a/imxweb/projects/qer-app-operationssupport/tsconfig.spec.json b/imxweb/projects/qer-app-operationssupport/tsconfig.spec.json index a809b0a66..6f92d1611 100644 --- a/imxweb/projects/qer-app-operationssupport/tsconfig.spec.json +++ b/imxweb/projects/qer-app-operationssupport/tsconfig.spec.json @@ -1,18 +1,10 @@ { "extends": "../../tsconfig.json", "compilerOptions": { + "strictNullChecks": false, "outDir": "../../out-tsc/spec", - "types": [ - "jasmine", - "node" - ] + "types": ["jasmine", "node"] }, - "files": [ - "src/test.ts", - "src/polyfills.ts" - ], - "include": [ - "**/*.spec.ts", - "**/*.d.ts" - ] + "files": ["src/test.ts", "src/polyfills.ts"], + "include": ["**/*.spec.ts", "**/*.d.ts"] } diff --git a/imxweb/projects/qer-app-operationssupport/tslint.json b/imxweb/projects/qer-app-operationssupport/tslint.json deleted file mode 100644 index ef4889cbe..000000000 --- a/imxweb/projects/qer-app-operationssupport/tslint.json +++ /dev/null @@ -1,17 +0,0 @@ -{ - "extends": "../../tslint.json", - "rules": { - "directive-selector": [ - true, - "attribute", - "imx", - "camelCase" - ], - "component-selector": [ - true, - "element", - "imx", - "kebab-case" - ] - } -} diff --git a/imxweb/projects/qer-app-portal/.compodocrc.json b/imxweb/projects/qer-app-portal/.compodocrc.json index f06b44253..c9604d495 100644 --- a/imxweb/projects/qer-app-portal/.compodocrc.json +++ b/imxweb/projects/qer-app-portal/.compodocrc.json @@ -1,6 +1,6 @@ { "name": "IMX Web - QER Portal", - "output": "../../documentation/v92/qer-app-portal", + "output": "../../documentation/v93/qer-app-portal", "theme": "material", "assetsFolder": "../../compodoc/assets", "customLogo": "../../compodoc/assets/images/oneidentity-logo.png", diff --git a/imxweb/projects/qer-app-portal/.eslintrc.json b/imxweb/projects/qer-app-portal/.eslintrc.json new file mode 100644 index 000000000..e5e911b09 --- /dev/null +++ b/imxweb/projects/qer-app-portal/.eslintrc.json @@ -0,0 +1,35 @@ +{ + "extends": "../../.eslintrc.json", + "ignorePatterns": ["!**/*", "**/*.spec.ts"], + "overrides": [ + { + "files": ["*.ts"], + "parserOptions": { + "project": ["imxweb/projects/qer-app-portal//tsconfig.app.json", "imxweb/projects/qer-app-portal//tsconfig.spec.json"], + "createDefaultProgram": true + }, + "rules": { + "@angular-eslint/directive-selector": [ + "error", + { + "type": "attribute", + "prefix": "imx", + "style": "camelCase" + } + ], + "@angular-eslint/component-selector": [ + "error", + { + "type": "element", + "prefix": "imx", + "style": "kebab-case" + } + ] + } + }, + { + "files": ["*.html"], + "rules": {} + } + ] +} diff --git a/imxweb/projects/qer-app-portal/README.md b/imxweb/projects/qer-app-portal/README.md index 5e027eea0..271577a2a 100644 --- a/imxweb/projects/qer-app-portal/README.md +++ b/imxweb/projects/qer-app-portal/README.md @@ -1,37 +1,40 @@ -# One Identity Manager Web portal +# Web Portal -This is the main application of the product. It contains features for managers, auditors, normal users and so on. It can be categorized into the following parts. +With the _Web Portal_ users can request and unsubscribe products, and renew products with limited lifetimes. Users can also approve requests and unsubscriptions, perform attestations, view rule violations, and approve or deny exception approvals. Furthermore, users can manage various company resources. +The Web Portal can be categorized into the following parts. -For a more detailed description, please read the Web Portal Documentation. +For more information, refer to the corresponding technical documentation. -## 1. IT-Shop -The IT-Shop allows the user to request products. This requests will be decided through configurable workflows, that can be combinations of automated processes and user approvals. +## Requests (IT Shop) +The Web Portal allows users to request products. This requests are approved through configurable workflows, that can be combinations of automated processes and user approvals. -## 2. Data Management -The main part of data management is handled through the _Data Explorer_ and the _My Responsibilities_ view, which look quite similar. The _Data Explorer_ is used by administrators or auditors, the _My Responsibilities_ by managers. The objects that can be handled are determined by the dynamic One Identity Manager modules the company has installed. -Under the menu item _Statistics_ managers and administrators can look into the statistics. +## Data management +The main part of data management is handled through the _Data Explorer_ and the _My Responsibilities_ page. The Data Explorer is used by administrators or auditors, the My Responsibilities view is used by managers. The objects that can be handled are determined by the installed dynamic One Identity Manager modules. -## 3. Attestation -This concerns everything attestation related. Users can manage attestation policies, handle attestation runs and decide the attestation of objects. Attestation is a dynamic library, which needs the corresponding One Identity Manager module to be installed. +## Statistics +Using the _Statistics_ page managers and administrators can look into the statistics. + +## Attestation +Users can manage attestation policies, handle attestation runs and approve the attestation of objects. Attestation is a dynamic library which needs the corresponding One Identity Manager module to be installed. ## 4. Setup -Under the menu item _Setup_ users can manage shops, service items, service categories or reports. +Users can manage shops, service items, service categories, reports and more through the _Setup_ menu. -The following libraries are available. Which libraries will be used, depends on the configuration of the installation. +The following libraries are available. Which libraries are used depends on the configuration of the installation. |Library name | Description| |---|---| -| qbm | This is the base library. It contains all the base components, like the data table and the column dependent references. | -| qer | This is the Identity Management base library. It contains the basic components for identity management, like the Data Explorer.| -| aob | This is the applications library. It contains the components, that are needed to assign entitlements to application bundles. | -| apc | This is a library, that is linked into the Data Explorer. It is used to manage software, that is assigned to users.| -| att | This is the attestation library. It contains everything, that is attestation related, like attesting objects, manage attestation runs, etc.| -| cpl | This is the compliance library. It is used to handle compliance violations and manage compliance rules. | -| hds | This is the help desk library. It contains components to resolve help desk tickets or create new ones.| -| olg | This is the One Login library. It handles the one login multi factor authentication process.| -| pol | This is the policy library. It is used to handle policy violations and manage company policies.| +| qbm | This is the base library. It contains all base components such as the data table and the column-dependent references. | +| qer | This is the identity management base library. It contains the basic components for identity management such as the Data Explorer.| +| aob | This is the Application Governance library. It contains the components that are needed to manage applications. | +| apc | This is a library that is linked into the Data Explorer. It is used to manage software, that is assigned to users.| +| att | This is the attestation library. It contains everything related to attestation such as attesting objects, manage attestation runs, and so on.| +| cpl | This is the compliance library. It is used to handle rule violations and manage compliance rules. | +| hds | This is the help desk library. It contains components to manage help desk tickets.| +| olg | This is the One Login library. It handles the One Login multi-factor authentication process.| +| pol | This is the company policy library. It is used to handle policy violations and manage company policies.| | rmb | This is the business role library. It is linked into the Data Explorer and is used to manage business roles. | | rms | This is the system role library. It is linked into the Data Explorer and is used to manage system roles.| -| rps | This is the report library. It contains components to manage reports and assign them to other users. It handles report subscriptions as well.| -| sac | This is the SAP R/3 Compliance Add-on Module. It adds some SAP features to the request process. | +| rps | This is the report library. It contains components to manage reports. It handles report subscriptions as well.| +| sac | This is the SAP R/3 Compliance add-on module. It adds some SAP features to the request process. | | tsb | This is the target system library. It is linked into the Data Explorer and is used to manage system entitlements and user accounts from different target systems. | diff --git a/imxweb/projects/qer-app-portal/karma.conf.js b/imxweb/projects/qer-app-portal/karma.conf.js index 5b7e2c040..19124f6ed 100644 --- a/imxweb/projects/qer-app-portal/karma.conf.js +++ b/imxweb/projects/qer-app-portal/karma.conf.js @@ -12,10 +12,10 @@ module.exports = function (config) { require('karma-jasmine-html-reporter'), require('karma-coverage-istanbul-reporter'), require('@angular-devkit/build-angular/plugins/karma'), - require('karma-junit-reporter') + require('karma-junit-reporter'), ], client: { - clearContext: false // leave Jasmine Spec Runner output visible in browser + clearContext: false, // leave Jasmine Spec Runner output visible in browser }, coverageIstanbulReporter: { dir: require('path').join(__dirname, 'results'), @@ -26,7 +26,7 @@ module.exports = function (config) { branches: 0, functions: 0, lines: 0, - } + }, }, junitReporter: { outputDir: require('path').join(__dirname, 'results'), @@ -34,14 +34,15 @@ module.exports = function (config) { reporters: ['progress', 'coverage-istanbul', 'junit'], captureTimeout: 210000, browserDisconnectTolerance: 3, - browserDisconnectTimeout : 210000, - browserNoActivityTimeout : 210000, + browserDisconnectTimeout: 210000, + browserNoActivityTimeout: 210000, port: 9876, colors: true, logLevel: config.LOG_INFO, autoWatch: true, browsers: ['Chrome'], singleRun: false, - restartOnFileChange: true + failOnEmptyTestSuite: false, + restartOnFileChange: true, }); }; diff --git a/imxweb/projects/qer-app-portal/package.json b/imxweb/projects/qer-app-portal/package.json index cd2818945..d2f6d2c86 100644 --- a/imxweb/projects/qer-app-portal/package.json +++ b/imxweb/projects/qer-app-portal/package.json @@ -1,7 +1,6 @@ { "name": "qer-app-portal", - "version": "9.2.1", + "version": "9.3.0", "private": true, - "peerDependencies": { - } + "peerDependencies": {} } diff --git a/imxweb/projects/qer-app-portal/project.json b/imxweb/projects/qer-app-portal/project.json new file mode 100644 index 000000000..09da3754a --- /dev/null +++ b/imxweb/projects/qer-app-portal/project.json @@ -0,0 +1,214 @@ +{ + "$schema": "../../node_modules/nx/schemas/project-schema.json", + "name": "qer-app-portal", + "sourceRoot": "projects/qer-app-portal/src", + "projectType": "application", + "prefix": "imx", + "generators": { + "@schematics/angular:component": { + "style": "scss" + } + }, + "targets": { + "build": { + "executor": "@angular-devkit/build-angular:browser", + "options": { + "aot": true, + "allowedCommonJsDependencies": [ + "lodash", + "highlight.js", + "file-saver", + "billboard.js", + "moment-timezone", + "core-js/fn/map", + "core-js/fn/set", + "core-js/fn/weak-map", + "core-js/fn/array/from", + "core-js/fn/object/assign", + "core-js/es/array/from", + "core-js/es/object/assign", + "core-js/es/map", + "core-js/es/set", + "core-js/es/weak-map", + "lodash.debounce", + "lodash.clamp", + "moment", + "@elemental-ui/cadence-icon/codepoints" + ], + "outputPath": "dist/qer-app-portal", + "index": "projects/qer-app-portal/src/index.html", + "main": "projects/qer-app-portal/src/main.ts", + "polyfills": ["projects/qer-app-portal/src/polyfills.ts"], + "tsConfig": "projects/qer-app-portal/tsconfig.app.json", + "assets": [ + "projects/qer-app-portal/src/assets", + "projects/qer-app-portal/src/appconfig.json", + { + "glob": "**/*", + "input": "./shared/assets/", + "output": "./assets" + }, + { + "glob": "**/*", + "input": "./node_modules/@elemental-ui/core/assets", + "output": "./assets" + } + ], + "styles": [ + "shared/scss/styles.scss", + "projects/qer-app-portal/src/styles.scss", + "projects/qbm/src/lib/styles/imx-page-title.scss", + "projects/qbm/src/lib/styles/data-explorer-common.scss", + "projects/qbm/src/lib/styles/data-explorer-details-common.scss" + ], + "stylePreprocessorOptions": { + "includePaths": [ + "./shared/scss", + "./node_modules", + "./node_modules/@elemental-ui/cadence-icon", + "./node_modules/@elemental-ui/core" + ] + } + }, + "configurations": { + "production": { + "fileReplacements": [ + { + "replace": "projects/qer-app-portal/src/environments/environment.ts", + "with": "projects/qer-app-portal/src/environments/environment.prod.ts" + } + ], + "optimization": true, + "outputHashing": "all", + "sourceMap": false, + "namedChunks": false, + "aot": true, + "extractLicenses": true, + "vendorChunk": false, + "buildOptimizer": true, + "budgets": [ + { + "type": "initial", + "maximumWarning": "20mb", + "maximumError": "40mb" + }, + { + "type": "anyComponentStyle", + "maximumWarning": "6kb" + } + ] + }, + "development": { + "buildOptimizer": false, + "optimization": false, + "vendorChunk": true, + "extractLicenses": false, + "sourceMap": true, + "namedChunks": true + }, + "remote-dev": { + "fileReplacements": [ + { + "replace": "projects/qer-app-portal/src/environments/environment.ts", + "with": "../imxweb_envs/qer-app-portal/environments/environment.remote-dev.ts" + } + ], + "buildOptimizer": false, + "optimization": false, + "vendorChunk": true, + "extractLicenses": false, + "sourceMap": true, + "namedChunks": true + }, + "remote-qs": { + "fileReplacements": [ + { + "replace": "projects/qer-app-portal/src/environments/environment.ts", + "with": "../imxweb_envs/qer-app-portal/environments/environment.remote-qs.ts" + } + ], + "buildOptimizer": false, + "optimization": false, + "vendorChunk": true, + "extractLicenses": false, + "sourceMap": true, + "namedChunks": true + }, + "es5": { + "tsConfig": "./projects/qer-app-portal/tsconfig-es5.app.json" + } + }, + "outputs": ["{options.outputPath}"], + "dependsOn": ["^build", "prebuild"] + }, + "prebuild": { + "executor": "nx:run-commands", + "options": { + "commands": ["node prebuild.js qer-app-portal"] + }, + "dependsOn": [ + { + "projects": ["qer", "aad", "aob", "apc", "att", "cpl", "hds", "olg", "pol", "qam", "rmb", "rms", "rps", "sac", "tsb"], + "target": "build" + } + ], + "cache": false + }, + "serve": { + "executor": "@angular-devkit/build-angular:dev-server", + "options": { + "browserTarget": "qer-app-portal:build" + }, + "configurations": { + "production": { + "browserTarget": "qer-app-portal:build:production" + }, + "development": { + "browserTarget": "qer-app-portal:build:development" + }, + "remote-dev": { + "browserTarget": "qer-app-portal:build:remote-dev" + }, + "remote-qs": { + "browserTarget": "qer-app-portal:build:remote-qs" + }, + "es5": { + "browserTarget": "qer-app-portal:build:es5" + } + } + }, + "extract-i18n": { + "executor": "@angular-devkit/build-angular:extract-i18n", + "options": { + "browserTarget": "qer-app-portal:build" + } + }, + "test": { + "executor": "@angular-devkit/build-angular:karma", + "options": { + "main": "projects/qer-app-portal/src/test.ts", + "polyfills": "projects/qer-app-portal/src/polyfills.ts", + "tsConfig": "projects/qer-app-portal/tsconfig.spec.json", + "karmaConfig": "projects/qer-app-portal/karma.conf.js", + "styles": ["projects/qer-app-portal/src/styles.scss"], + "stylePreprocessorOptions": { + "includePaths": [ + "./shared/assets", + "./shared/scss", + "./node_modules", + "./node_modules/@elemental-ui/cadence-icon", + "./node_modules/@elemental-ui/core" + ] + }, + "assets": ["projects/qer-app-portal/src/appconfig.json", "projects/qer-app-portal/src/assets"] + } + }, + "lint": { + "executor": "@angular-devkit/build-angular:tslint", + "options": { + "tsConfig": ["projects/qer-app-portal/tsconfig.app.json", "projects/qer-app-portal/tsconfig.spec.json"], + "exclude": ["**/node_modules/**", "**/*.spec.ts", "**/*.json"] + } + } + } +} diff --git a/imxweb/projects/qer-app-portal/src/app/app-routing.module.ts b/imxweb/projects/qer-app-portal/src/app/app-routing.module.ts index 6ab1af599..9532ecc4f 100644 --- a/imxweb/projects/qer-app-portal/src/app/app-routing.module.ts +++ b/imxweb/projects/qer-app-portal/src/app/app-routing.module.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -24,14 +24,11 @@ * */ -import { NgModule, InjectionToken } from '@angular/core'; -import { Routes, RouterModule, ActivatedRouteSnapshot, Router } from '@angular/router'; +import { InjectionToken, NgModule } from '@angular/core'; +import { ActivatedRouteSnapshot, Router, RouterModule, Routes } from '@angular/router'; import { AuthenticationGuardService, LoginComponent, RouteGuardService } from 'qbm'; -import { - PasswordQueryComponent, - StartComponent -} from 'qer'; +import { PasswordQueryComponent, StartComponent } from 'qer'; const externalUrlProvider = new InjectionToken('externalUrlRedirectResolver'); @@ -55,19 +52,19 @@ const routes: Routes = [ canActivate: [RouteGuardService], resolve: { url: externalUrlProvider, - } + }, }, { path: 'passwordquestions', component: PasswordQueryComponent, canActivate: [RouteGuardService], - resolve: [RouteGuardService] + resolve: [RouteGuardService], }, - { path: '**', redirectTo: 'dashboard' } + { path: '**', redirectTo: 'dashboard' }, ]; @NgModule({ - imports: [RouterModule.forRoot([], { useHash: true, relativeLinkResolution: 'legacy' })], + imports: [RouterModule.forRoot([], { useHash: true })], exports: [RouterModule], providers: [ { @@ -77,17 +74,14 @@ const routes: Routes = [ if (externalUrl && externalUrl.toLocaleLowerCase() !== 'undefined') { window.open(externalUrl, '_self'); } - } + }, }, ], - }) export class AppRoutingModule { - constructor( - private readonly router: Router) { - + constructor(private readonly router: Router) { const config = this.router.config; - routes.forEach(route => { + routes.forEach((route) => { config.push(route); }); this.router.resetConfig(config); diff --git a/imxweb/projects/qer-app-portal/src/app/app.component.html b/imxweb/projects/qer-app-portal/src/app/app.component.html index b202569c6..9eb3ed928 100644 --- a/imxweb/projects/qer-app-portal/src/app/app.component.html +++ b/imxweb/projects/qer-app-portal/src/app/app.component.html @@ -18,7 +18,6 @@
    -
    diff --git a/imxweb/projects/qer-app-portal/src/app/app.component.scss b/imxweb/projects/qer-app-portal/src/app/app.component.scss index 353f07c22..25822db1c 100644 --- a/imxweb/projects/qer-app-portal/src/app/app.component.scss +++ b/imxweb/projects/qer-app-portal/src/app/app.component.scss @@ -1,5 +1,5 @@ -@import "variables.scss"; @import '@elemental-ui/core/src/styles/_eui_palette.scss'; +@import 'base/variables'; .page { display: flex; @@ -13,7 +13,7 @@ flex-direction: column; overflow: hidden; height: inherit; - margin: 40px 60px; + margin: 24px; &--full-page { margin: 0; @@ -36,22 +36,6 @@ } } -@media only screen and (max-width: 768px) { - - .eui-top-navigation-mobile { - .eui-top-navigation-mobile-footer { - .mat-button { - &.imx-masthead--icon-button { - width: 100%; - - .mat-button-wrapper span { - display: inline-block; - } - } - } - } - } -} .eui-dark-theme { .page { diff --git a/imxweb/projects/qer-app-portal/src/app/app.component.ts b/imxweb/projects/qer-app-portal/src/app/app.component.ts index 6e5a18f4f..2cb7fd4c0 100644 --- a/imxweb/projects/qer-app-portal/src/app/app.component.ts +++ b/imxweb/projects/qer-app-portal/src/app/app.component.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -23,28 +23,30 @@ * THIS SOFTWARE OR ITS DERIVATIVES. * */ -import { Component, Inject, ErrorHandler, OnDestroy, OnInit } from '@angular/core'; -import { EventType, NavigationCancel, NavigationEnd, NavigationError, NavigationStart, Router, RouterEvent } from '@angular/router'; +import { Component, ErrorHandler, Inject, OnDestroy, OnInit } from '@angular/core'; +import { Event, EventType, NavigationEnd, NavigationStart, Router } from '@angular/router'; import { Subscription } from 'rxjs'; import { AuthenticationService, + ClassloggerService, + ConfirmationService, IeWarningService, ImxTranslationProviderService, ISessionState, MenuService, + Message, SplashService, SystemInfoService, + UserMessageService, } from 'qbm'; -import { ProjectConfigurationService, UserModelService, SettingsComponent, QerApiService } from 'qer'; +import { ProjectConfigurationService, QerApiService, SettingsComponent, UserModelService } from 'qer'; -import { ProfileSettings, QerProjectConfig } from 'imx-api-qer'; -import { ProjectConfig } from 'imx-api-qbm'; import { MatDialog } from '@angular/material/dialog'; -import { EuiLoadingService, EuiTheme, EuiThemeService, EuiTopNavigationItem } from '@elemental-ui/core'; -import { TranslateService } from '@ngx-translate/core'; -import { APP_BASE_HREF } from '@angular/common'; +import { EuiTheme, EuiThemeService, EuiTopNavigationItem } from '@elemental-ui/core'; +import { ProjectConfig } from '@imx-modules/imx-api-qbm'; +import { ProfileSettings, QerProjectConfig } from '@imx-modules/imx-api-qer'; import { getBaseHref, HEADLESS_BASEHREF } from './app.module'; @Component({ @@ -56,12 +58,13 @@ export class AppComponent implements OnInit, OnDestroy { public menuItems: EuiTopNavigationItem[]; public isLoggedIn = false; public hideMenu = false; - public hideUserMessage = false; public showPageContent = true; + public message: Message | undefined; private routerStatus: EventType; private readonly subscriptions: Subscription[] = []; constructor( + private readonly logger: ClassloggerService, private readonly authentication: AuthenticationService, private readonly router: Router, private readonly splash: SplashService, @@ -75,8 +78,8 @@ export class AppComponent implements OnInit, OnDestroy { private readonly themeService: EuiThemeService, private readonly errorHandler: ErrorHandler, private readonly translationProvider: ImxTranslationProviderService, - private readonly translateService: TranslateService, - @Inject(APP_BASE_HREF) private baseHref: string + private readonly confirmationService: ConfirmationService, + private readonly userMessageService: UserMessageService, ) { this.subscriptions.push( this.authentication.onSessionResponse.subscribe(async (sessionState: ISessionState) => { @@ -89,33 +92,49 @@ export class AppComponent implements OnInit, OnDestroy { } } - this.isLoggedIn = sessionState.IsLoggedIn; + this.isLoggedIn = sessionState.IsLoggedIn ?? false; if (this.isLoggedIn) { - // Close the splash screen that opened in app service initialisation - // Needs to close here when running in containers (auth skipped) - splash.close(); + const isUseProfileLangChecked = (await this.qerClient.client.portal_profile_get()).UseProfileLanguage ?? false; + // Set session culture if isUseProfileLangChecked is true + if (isUseProfileLangChecked) { + // Use culture if available, if not fetch + const culture = sessionState.culture + ? sessionState.culture + : (await this.qerClient.client.portal_profile_person_get())?.ProfileLanguage; + // If culture is found, use it, otherwise fallback to the app default + if (culture) { + this.logger.debug(this, `ProfileLangChecked is true, culture available: Setting ${culture} as profile language`); + await this.translationProvider.reinit(culture, sessionState.cultureFormat ?? culture, this.router); + } + } const config: QerProjectConfig & ProjectConfig = await projectConfig.getConfig(); - const features = (await userModelService.getFeatures()).Features; + const features = (await userModelService.getFeatures()).Features ?? []; const systemInfo = await systemInfoService.get(); const groups = (await userModelService.getGroups()).map((group) => group.Name || ''); - const isUseProfileLangChecked = (await this.qerClient.v2Client.portal_profile_get()).UseProfileLanguage ?? false; - // Set session culture if isUseProfileLangChecked is true, set browser culture otherwise - if (isUseProfileLangChecked) { - await this.translationProvider.init(sessionState.culture, sessionState.cultureFormat); - } else { - const browserCulture = this.translateService.getBrowserCultureLang(); - await this.translationProvider.init(browserCulture); - } - - this.menuItems = await menuService.getMenuItems(systemInfo.PreProps, features, true, config, groups); ieWarningService.showIe11Banner(); - this.applyProfileSettings(); + await this.applyProfileSettings(); + this.menuItems = await menuService.getMenuItems(systemInfo.PreProps ?? [], features, true, config, groups); + // Close the splash screen that opened in app service initialisation + // Needs to close here when running in containers (auth skipped) + splash.close(); } - }) + }), ); + + this.subscriptions.push( + this.userMessageService.subject.subscribe((message) => { + this.message = message; + if (!!this.message && this.message.type === 'error' && !this.message.target) { + this.confirmationService.showErrorMessage({ + Message: this.message?.text, + }); + } + }), + ); + this.setupRouter(); } @@ -139,7 +158,7 @@ export class AppComponent implements OnInit, OnDestroy { } public async ngOnInit(): Promise { - this.authentication.update(); + await this.authentication.update(); } public ngOnDestroy(): void { @@ -167,31 +186,18 @@ export class AppComponent implements OnInit, OnDestroy { } private setupRouter(): void { - this.router.events.subscribe((event: RouterEvent) => { + this.router.events.subscribe((event: Event) => { if (event instanceof NavigationStart) { - this.hideUserMessage = true; this.routerStatus = event.type; if (this.isLoggedIn && event.url === '/') { // show the splash screen, when the user logs out! this.splash.init({ applicationName: 'One Identity Manager Portal' }); } } - - if (event instanceof NavigationCancel) { - this.hideUserMessage = false; - this.routerStatus = event.type; - } - if (event instanceof NavigationEnd) { - this.hideUserMessage = false; + this.routerStatus = event.type; this.hideMenu = event.url === '/'; this.showPageContent = true; - this.routerStatus = event.type; - } - - if (event instanceof NavigationError) { - this.hideUserMessage = false; - this.routerStatus = event.type; } }); } diff --git a/imxweb/projects/qer-app-portal/src/app/app.module.ts b/imxweb/projects/qer-app-portal/src/app/app.module.ts index fb692c57f..5afacef7e 100644 --- a/imxweb/projects/qer-app-portal/src/app/app.module.ts +++ b/imxweb/projects/qer-app-portal/src/app/app.module.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -24,7 +24,7 @@ * */ -import { HttpClientModule } from '@angular/common/http'; +import { provideHttpClient, withInterceptorsFromDi } from '@angular/common/http'; import { APP_INITIALIZER, ErrorHandler, NgModule } from '@angular/core'; import { MatDialogModule } from '@angular/material/dialog'; import { MatPaginatorIntl } from '@angular/material/paginator'; @@ -44,7 +44,6 @@ import { ImxTranslateLoader, LdsReplacePipe, MastHeadModule, - MenuModule, ObjectHistoryApiService, ObjectHistoryModule, Paginator, @@ -52,38 +51,40 @@ import { } from 'qbm'; import { AddressbookModule, + ApprovalWorkFlowModule, ApprovalsModule, ArchivedRequestsModule, + DataExplorerViewModule, DelegationModule, IdentitiesModule, ItshopPatternModule, + MyResponsibilitiesViewModule, NewRequestModule, ObjectHyperviewService, ProductSelectionModule, ProfileModule, QerModule, QpmIntegrationModule, + QueueStatusComponent, RelatedApplicationsModule, RequestConfigModule, RequestHistoryModule, ResourcesModule, RiskConfigModule, RoleManangementModule, + RoleMembershipsModule, ServiceCategoriesModule, ServiceItemsEditModule, ShoppingCartModule, + SourceDetectiveModule, StatisticsModule, - ViewDevicesModule, - MyResponsibilitiesViewModule, - ApprovalWorkFlowModule, - DataExplorerViewModule, + TeamResponsibilitiesModule, UserProcessModule, - SourceDetectiveModule, - RoleMembershipsModule, - TeamResponsibilitiesModule + ViewDevicesModule, } from 'qer'; import { APP_BASE_HREF } from '@angular/common'; +import { RECAPTCHA_V3_SITE_KEY } from 'ng-recaptcha-2'; import appConfigJson from '../appconfig.json'; import { environment } from '../environments/environment'; import { AppRoutingModule } from './app-routing.module'; @@ -98,6 +99,7 @@ export function getBaseHref(): string { } @NgModule({ declarations: [AppComponent], + bootstrap: [AppComponent], imports: [ AppRoutingModule, AuthenticationModule, @@ -105,14 +107,12 @@ export function getBaseHref(): string { BrowserModule, EuiCoreModule, EuiMaterialModule, - HttpClientModule, IdentitiesModule, ResourcesModule, LoggerModule.forRoot({ level: NgxLoggerLevel.DEBUG, serverLogLevel: NgxLoggerLevel.OFF }), MatDialogModule, MatTabsModule, MastHeadModule, - MenuModule, AddressbookModule, QerModule, ProfileModule, @@ -148,11 +148,13 @@ export function getBaseHref(): string { ViewDevicesModule, MyResponsibilitiesViewModule, ApprovalWorkFlowModule, + UserProcessModule, + TeamResponsibilitiesModule, DataExplorerViewModule, - UserProcessModule, + UserProcessModule, SourceDetectiveModule, RoleMembershipsModule, - TeamResponsibilitiesModule + QueueStatusComponent, ], providers: [ { provide: 'environment', useValue: environment }, @@ -173,7 +175,7 @@ export function getBaseHref(): string { }, { provide: ObjectHyperviewService, - useClass: PortalHyperviewService + useClass: PortalHyperviewService, }, { provide: MatPaginatorIntl, @@ -185,7 +187,14 @@ export function getBaseHref(): string { useValue: getBaseHref(), }, CdrRegistryService, + { + provide: RECAPTCHA_V3_SITE_KEY, + useFactory: (config: AppService) => { + return config.recaptchaSiteKeyV3; + }, + deps: [AppService], + }, + provideHttpClient(withInterceptorsFromDi()), ], - bootstrap: [AppComponent], }) export class AppModule {} diff --git a/imxweb/projects/qer-app-portal/src/app/app.service.ts b/imxweb/projects/qer-app-portal/src/app/app.service.ts index a8846abeb..2c75619c1 100644 --- a/imxweb/projects/qer-app-portal/src/app/app.service.ts +++ b/imxweb/projects/qer-app-portal/src/app/app.service.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -24,38 +24,32 @@ * */ -import { Injectable } from '@angular/core'; import { Title } from '@angular/platform-browser'; import { TranslateService } from '@ngx-translate/core'; -import { Globals } from 'imx-qbm-dbts'; +import { Injectable, Injector, createNgModule } from '@angular/core'; +import { ImxConfig, TypedClient } from '@imx-modules/imx-api-qbm'; +import { Globals } from '@imx-modules/imx-qbm-dbts'; import { AppConfigService, - imx_SessionService, + AuthenticationService, + CaptchaService, CdrRegistryService, - ImxTranslationProviderService, ClassloggerService, - AuthenticationService, - PluginLoaderService, + ImxTranslationProviderService, SplashService, - SystemInfoService + SystemInfoService, + imx_SessionService, } from 'qbm'; -import { - NotificationStreamService -} from 'qer'; +import { NotificationStreamService } from 'qer'; import { environment } from '../environments/environment'; -import { TypedClient } from 'imx-api-qbm'; -import { PortalDocConfigurationService } from './portal-doc-configuration.service'; - -import * as QBM from 'qbm'; -import * as QER from 'qer'; - -declare var SystemJS: any; @Injectable({ - providedIn: 'root' + providedIn: 'root', }) export class AppService { + public recaptchaSiteKeyV3: string | null = null; + private imxConfig: ImxConfig; constructor( public readonly registry: CdrRegistryService, private readonly logger: ClassloggerService, @@ -65,22 +59,24 @@ export class AppService { private readonly session: imx_SessionService, private readonly translationProvider: ImxTranslationProviderService, private readonly title: Title, - private readonly pluginLoader: PluginLoaderService, private readonly authentication: AuthenticationService, private readonly notificationService: NotificationStreamService, private readonly splash: SplashService, - private readonly docSvc: PortalDocConfigurationService, - ) { } + private readonly injector: Injector, + private readonly captchaService: CaptchaService, + ) {} public async init(): Promise { this.showSplash(); await this.config.init(environment.clientUrl); - this.translateService.addLangs(this.config.Config.Translation.Langs); - const browserCulture = this.translateService.getBrowserCultureLang(); - this.logger.debug(this, `Set ${browserCulture} as default language`); - this.translateService.setDefaultLang(browserCulture); - await this.translateService.use(browserCulture).toPromise(); + if (this.config.Config.Translation?.Langs) { + this.translateService.addLangs(this.config.Config.Translation.Langs); + } + + await this.translationProvider.init(); + + this.imxConfig = await this.systemInfoService.getImxConfig(); this.translateService.onLangChange.subscribe(() => { this.setTitle(); @@ -88,8 +84,8 @@ export class AppService { this.setTitle(); - this.authentication.onSessionResponse.subscribe(sessionState => { - if(sessionState && sessionState.IsLoggedIn) { + this.authentication.onSessionResponse.subscribe((sessionState) => { + if (sessionState && sessionState.IsLoggedIn) { // when the user logs in, start listening to notifications this.notificationService.openStream(); } @@ -97,17 +93,17 @@ export class AppService { this.session.TypedClient = new TypedClient(this.config.v2client, this.translationProvider); - this.docSvc.setupPaths(); - - SystemJS.set('qbm', SystemJS.newModule(QBM)); - SystemJS.set('qer', SystemJS.newModule(QER)); + await this.loadModules(environment.appName); - await this.pluginLoader.loadModules(environment.appName); + if (this.imxConfig.RecaptchaPublicKey) { + this.captchaService.enableReCaptcha(this.imxConfig.RecaptchaPublicKey); + this.recaptchaSiteKeyV3 = this.imxConfig.RecaptchaPublicKey; + } + this.captchaService.captchaImageUrl = 'portal/captchaimage'; } private async setTitle(): Promise { - const imxConfig = await this.systemInfoService.getImxConfig(); - const name = imxConfig.ProductName || Globals.QIM_ProductNameFull; + const name = this.imxConfig.ProductName || Globals.QIM_ProductNameFull; this.config.Config.Title = await this.translateService.get('#LDS#Heading Web Portal').toPromise(); const title = `${name} ${this.config.Config.Title}`; this.title.setTitle(title); @@ -134,4 +130,37 @@ export class AppService { this.splash.update({ applicationName: title, message: loadingMsg }); } + public async loadModules(appName: string): Promise { + const apps = await this.session.Client.imx_applications_get(); + + const appInfo = apps.filter((app) => app.Name === appName)[0]; + + this.logger.debug(this, `▶️ Found config section for ${appInfo.DisplayName}`); + + if (appInfo.PlugIns == null || appInfo.PlugIns.length === 0) { + this.logger.debug(this, `❌ No plugins found`); + return; + } + + this.logger.debug(this, `▶️ Found ${appInfo.PlugIns.length} plugin(s)`); + + for (const plugin of appInfo.PlugIns) { + this.logger.debug(this, `⚙️ Plugin: ${plugin.Container}`); + + try { + this.logger.debug(this, '▶️ Importing module. DEV mode.'); + await import(`html/qer-app-portal/${plugin.Container}/fesm2022/${plugin.Container}.mjs`) + .then((m) => { + if (plugin.Name) { + createNgModule(m[plugin.Name], this.injector); + } + }) + .catch((error) => + this.logger.error(this, `💥 Loading of ${plugin.Name} (${plugin.Container}) failed with the following error: ${error.message}`), + ); + } catch (e) { + this.logger.error(this, `💥 Loading of ${plugin.Name} (${plugin.Container}) failed with the following error: ${e.message}`); + } + } + } } diff --git a/imxweb/projects/qer-app-portal/src/app/hyperview/portal-hyperview.service.ts b/imxweb/projects/qer-app-portal/src/app/hyperview/portal-hyperview.service.ts index e1fdb716a..5960dc8c7 100644 --- a/imxweb/projects/qer-app-portal/src/app/hyperview/portal-hyperview.service.ts +++ b/imxweb/projects/qer-app-portal/src/app/hyperview/portal-hyperview.service.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -26,10 +26,10 @@ import { Injectable } from '@angular/core'; -import { ShapeData } from 'imx-api-qer'; +import { ShapeData } from '@imx-modules/imx-api-qer'; import { ApiClientService } from 'qbm'; -import { ObjectHyperviewService, ProjectConfigurationService, QerApiService } from 'qer'; +import { ObjectHyperviewService, ProjectConfigurationService, QerApiService, QerPermissionsService } from 'qer'; @Injectable({ providedIn: 'root', @@ -38,15 +38,15 @@ export class PortalHyperviewService implements ObjectHyperviewService { constructor( private readonly apiClient: QerApiService, private readonly apiProvider: ApiClientService, - private readonly configService: ProjectConfigurationService + private readonly configService: ProjectConfigurationService, + private readonly qerPermissionsService: QerPermissionsService, ) {} - public async get(tableName: string, uid: string, nodeName?: string): Promise { - return this.apiProvider.request(() => this.apiClient.client.portal_hyperview_get(tableName, uid, { node: nodeName })); + public async get(tableName: string, uid: string, node?: string): Promise { + return this.apiProvider.request(() => this.apiClient.client.portal_hyperview_get(tableName, uid, { node })) as Promise; } - public async getNavigationPermission(): Promise { const projectConfig = await this.configService.getConfig(); - return !projectConfig?.DisableHyperViewNavigation; + return projectConfig.EnableHyperViewNavigation && this.qerPermissionsService.isHyperviewNavigation(); } } diff --git a/imxweb/projects/qer-app-portal/src/app/portal-doc-configuration.service.ts b/imxweb/projects/qer-app-portal/src/app/portal-doc-configuration.service.ts deleted file mode 100644 index 6d7a7974d..000000000 --- a/imxweb/projects/qer-app-portal/src/app/portal-doc-configuration.service.ts +++ /dev/null @@ -1,54 +0,0 @@ -/* - * ONE IDENTITY LLC. PROPRIETARY INFORMATION - * - * This software is confidential. One Identity, LLC. or one of its affiliates or - * subsidiaries, has supplied this software to you under terms of a - * license agreement, nondisclosure agreement or both. - * - * You may not copy, disclose, or use this software except in accordance with - * those terms. - * - * - * Copyright 2023 One Identity LLC. - * ALL RIGHTS RESERVED. - * - * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR - * WARRANTIES ABOUT THE SUITABILITY OF THE SOFTWARE, - * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED - * TO THE IMPLIED WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE, OR - * NON-INFRINGEMENT. ONE IDENTITY LLC. SHALL NOT BE - * LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE - * AS A RESULT OF USING, MODIFYING OR DISTRIBUTING - * THIS SOFTWARE OR ITS DERIVATIVES. - * - */ - -import { Injectable } from "@angular/core"; -import { DocDocument, DocChapterService } from "qbm"; - -@Injectable({ - providedIn: 'root' -}) -export class PortalDocConfigurationService { - - constructor(private readonly docSvc: DocChapterService) { } - - setupPaths() { - // Web Portal User Guide - var portalDoc: DocDocument = { - paths: { - "en-US": "imx/doc/OneIM_QER_WebPortal_en-us.html5/OneIM_QER_WebPortal.html", - "de-DE": "imx/doc/OneIM_QER_WebPortal_de-de.html5/OneIM_QER_WebPortal.html", - "de-CH": "imx/doc/OneIM_QER_WebPortal_de-de.html5/OneIM_QER_WebPortal.html", - "de-AT": "imx/doc/OneIM_QER_WebPortal_de-de.html5/OneIM_QER_WebPortal.html" - } - }; - - // Declare the route/chapter mapping. Extend this section as new routes get added. - this.docSvc.chapters["addressbook"] = { - chapterUid: "443F4A50-2D9E-4886-9805-E780645F2B3B", - document: portalDoc - }; - } -} \ No newline at end of file diff --git a/imxweb/projects/qer-app-portal/src/app/portal-history.service.ts b/imxweb/projects/qer-app-portal/src/app/portal-history.service.ts index 33e8b9bb3..814cfa429 100644 --- a/imxweb/projects/qer-app-portal/src/app/portal-history.service.ts +++ b/imxweb/projects/qer-app-portal/src/app/portal-history.service.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -25,21 +25,20 @@ */ import { Injectable } from '@angular/core'; -import { HistoryData } from 'imx-qbm-dbts'; +import { HistoryData } from '@imx-modules/imx-qbm-dbts'; import { QerApiService } from 'qer'; import { ObjectHistoryApiService } from 'qbm'; -import { HistoryComparisonData } from 'imx-api-qer'; +import { HistoryComparisonData } from '@imx-modules/imx-api-qer'; @Injectable() export class PortalHistoryService implements ObjectHistoryApiService { - - constructor(private readonly apiService: QerApiService) { } + constructor(private readonly apiService: QerApiService) {} getHistoryData(table: string, uid: string): Promise { return this.apiService.client.portal_history_get(table, uid); } - getHistoryComparisonData(table: string, uid: string,options?: {CompareDate?: Date;}): Promise { + getHistoryComparisonData(table: string, uid: string, options?: { CompareDate?: Date }): Promise { return this.apiService.client.portal_history_comparison_get(table, uid, options); } -} \ No newline at end of file +} diff --git a/imxweb/projects/qer-app-portal/src/environments/environment.prod.ts b/imxweb/projects/qer-app-portal/src/environments/environment.prod.ts index a3125ce37..bb4762cd2 100644 --- a/imxweb/projects/qer-app-portal/src/environments/environment.prod.ts +++ b/imxweb/projects/qer-app-portal/src/environments/environment.prod.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -28,5 +28,5 @@ export const environment = { production: true, clientUrl: '', appName: 'qer-app-portal', - appVersion: '1.0.0' + appVersion: '1.0.0', }; diff --git a/imxweb/projects/qer-app-portal/src/environments/environment.ts b/imxweb/projects/qer-app-portal/src/environments/environment.ts index 5ebebe3ce..3bc9bea0c 100644 --- a/imxweb/projects/qer-app-portal/src/environments/environment.ts +++ b/imxweb/projects/qer-app-portal/src/environments/environment.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -32,10 +32,9 @@ export const environment = { production: false, clientUrl: 'http://localhost:8182', appName: 'qer-app-portal', - appVersion: '1.0.0' + appVersion: '1.0.0', }; - /* * For easier debugging in development mode, you can import the following file * to ignore zone related error stack frames such as `zone.run`, `zoneDelegate.invokeTask`. @@ -43,4 +42,4 @@ export const environment = { * This import should be commented out in production mode because it will have a negative impact * on performance if an error is thrown. */ -// import 'zone.js/dist/zone-error'; // Included with Angular CLI. +// import 'zone.js'; // Included with Angular CLI. diff --git a/imxweb/projects/qer-app-portal/src/index.html b/imxweb/projects/qer-app-portal/src/index.html index 4b785ba4e..f08db67fd 100644 --- a/imxweb/projects/qer-app-portal/src/index.html +++ b/imxweb/projects/qer-app-portal/src/index.html @@ -1,15 +1,13 @@ + + + + + + - - - - - - - - - - - + + + diff --git a/imxweb/projects/qer-app-portal/src/main.ts b/imxweb/projects/qer-app-portal/src/main.ts index 5b7a3816d..8cb3e4f09 100644 --- a/imxweb/projects/qer-app-portal/src/main.ts +++ b/imxweb/projects/qer-app-portal/src/main.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -34,5 +34,6 @@ if (environment.production) { enableProdMode(); } -platformBrowserDynamic().bootstrapModule(AppModule) - .catch(err => console.error(err)); +platformBrowserDynamic() + .bootstrapModule(AppModule) + .catch((err) => console.error(err)); diff --git a/imxweb/projects/qer-app-portal/src/polyfills.ts b/imxweb/projects/qer-app-portal/src/polyfills.ts index f87c86a13..e38109681 100644 --- a/imxweb/projects/qer-app-portal/src/polyfills.ts +++ b/imxweb/projects/qer-app-portal/src/polyfills.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -41,9 +41,8 @@ */ /*************************************************************************************************** -* BROWSER POLYFILLS -*/ - + * BROWSER POLYFILLS + */ /** IE10 and IE11 requires the following for NgClass support on SVG elements */ // import 'classlist.js'; // Run `npm install --save classlist.js`. @@ -51,16 +50,15 @@ /** IE10 and IE11 requires the following for the Reflect API. */ // import 'core-js/es6/reflect'; - /** Evergreen browsers require these. */ // Used for reflect-metadata in JIT. If you use AOT (and only Angular decorators), you can remove. -import 'core-js/es7/reflect'; +import 'core-js/es/reflect'; // Used for support array.includes -import 'core-js/es7/array'; +import 'core-js/es/array'; // Used for support object.values -import 'core-js/es7/object'; +import 'core-js/es/object'; /** * Required to support Web Animations `@angular/platform-browser/animations`. @@ -68,17 +66,13 @@ import 'core-js/es7/object'; */ import 'web-animations-js'; - - /*************************************************************************************************** * Zone JS is required by default for Angular itself. */ -import 'zone.js/dist/zone'; // Included with Angular CLI. - - +import 'zone.js'; // Included with Angular CLI. /*************************************************************************************************** * APPLICATION IMPORTS */ +import 'url-polyfill'; import 'whatwg-fetch'; -import 'url-polyfill'; \ No newline at end of file diff --git a/imxweb/projects/qer-app-portal/src/styles.scss b/imxweb/projects/qer-app-portal/src/styles.scss index 52a903849..436a3fb21 100644 --- a/imxweb/projects/qer-app-portal/src/styles.scss +++ b/imxweb/projects/qer-app-portal/src/styles.scss @@ -1,20 +1,14 @@ /* You can add global styles to this file, and also import other style files */ @use '@angular/material' as mat; - -$material_icons_font_path: "~node_modules/@elemental-ui/core/assets/MaterialIcons"; -$cadence_font_path: "~node_modules/@elemental-ui/core/assets/Cadence"; -$source_sans_pro_font_path: "~node_modules/@elemental-ui/core/assets/Source_Sans_Pro"; - @import '@elemental-ui/core/src/styles/core.scss'; - -.imx-dialog-panel-class > .mat-dialog-container { - background-color: mat.get-color-from-palette($asher-gray-palette, 200); +.imx-dialog-panel-class > .mat-mdc-dialog-container { + background-color: mat.m2-get-color-from-palette($asher-gray-palette, 200); } -.mat-snack-bar-container.mat-snack-bar-center.eui-alert-banner-panel { - position: fixed; - left: 0; +.mat-mdc-snack-bar-container.mat-snack-bar-center.eui-alert-banner-panel { + position: fixed; + left: 0; } // ToDo (als Teil von 254128): später wieder einbinden, wenn wir den Styleguide soweit haben // .pageContent > :last-child > h1 { @@ -26,93 +20,76 @@ $source_sans_pro_font_path: "~node_modules/@elemental-ui/core/assets/Source_Sans imx-data-explorer-groups, imx-data-explorer-identities, imx-data-explorer-accounts { + flex: 1 1 auto; + display: flex; + flex-direction: column; + overflow: hidden; + > .data-explorer--groups, + .data-explorer--accounts { flex: 1 1 auto; + overflow: hidden; display: flex; flex-direction: column; - overflow: hidden; - > .data-explorer--groups, - .data-explorer--accounts { - flex: 1 1 auto; - overflow: hidden; - display: flex; - flex-direction: column; - > :nth-child(2) { - flex: 1 1 auto; - display: flex; - flex-direction: column; - } + > :nth-child(2) { + flex: 1 1 auto; + display: flex; + flex-direction: column; } + } - .data-explorer--accounts { - > :nth-child(2) { - overflow: hidden; - } + .data-explorer--accounts { + > :nth-child(2) { + overflow: hidden; } + } - .data-explorer-table { - flex: 1 1 auto; - overflow: hidden; - display: flex; - flex-direction: column; - } + .data-explorer-table { + flex: 1 1 auto; + overflow: hidden; + display: flex; + flex-direction: column; + } - .data-explorer-table .mat-sidenav-content { - overflow-y: auto !important; - } } -.data-explorer.data-explorer--identities.identities--fullscreen -{ - display: flex !important; // TODO: Task 268556 : Styling direkt in der Komponente umsetzen - flex-direction: column; +.data-explorer.data-explorer--identities.identities--fullscreen { + display: flex !important; // TODO: Task 268556 : Styling direkt in der Komponente umsetzen + flex-direction: column; } .governance-sidesheet__tab-content { - height: calc(100% - 120px); + height: calc(100% - 120px); } .eui-dark-theme { - .loading-progress{ - background-color: $color-gray-70; - } - .mat-tab-group .mat-tab-header{ - background-color:$color-gray-80; - } - .eui-sidesheet - { - background-color:$color-gray-80; - .mat-toolbar{ - background-color: $color-blue-80; - } - .background--asher-gray{ - background-color: $color-gray-80; - } - } - .eui-sidesheet-actions.mat-card.eui-sidesheet-actions--white{ - background-color: $color-gray-70; + .loading-progress { + background-color: $color-gray-70; + } + + .eui-sidesheet { + background-color: $color-gray-80; + .background--asher-gray { + background-color: $color-gray-80; } + } + .eui-sidesheet-actions.mat-mdc-card.eui-sidesheet-actions--white { + background-color: $color-gray-70; + } } .eui-contrast-theme { - .loading-progress{ - background-color: $color-gray-90; - } - .mat-tab-group .mat-tab-header{ - background-color:$color-gray-100; + .loading-progress { + background-color: $color-gray-90; } - .eui-sidesheet - { - background-color:$color-gray-100; - .mat-toolbar{ - background-color: $color-blue-90; - } - .background--asher-gray{ - background-color: $color-gray-90; - } - } - .eui-sidesheet-actions.mat-card.eui-sidesheet-actions--white{ + + .eui-sidesheet { + background-color: $color-gray-100; + .background--asher-gray { background-color: $color-gray-90; + } + } + .eui-sidesheet-actions.mat-mdc-card.eui-sidesheet-actions--white { + background-color: $color-gray-90; } } - diff --git a/imxweb/projects/qer-app-portal/src/test.ts b/imxweb/projects/qer-app-portal/src/test.ts index 9f9f4fc1f..0eacdebc4 100644 --- a/imxweb/projects/qer-app-portal/src/test.ts +++ b/imxweb/projects/qer-app-portal/src/test.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -26,21 +26,12 @@ // This file is required by karma.conf.js and loads recursively all the .spec and framework files -import 'zone.js/dist/zone-testing'; -import { getTestBed } from '@angular/core/testing'; -import { - BrowserDynamicTestingModule, - platformBrowserDynamicTesting -} from '@angular/platform-browser-dynamic/testing'; +// Zone must be imported first. Be careful with prettier import organizing +import 'zone.js'; +import 'zone.js/testing'; -declare const require: any; +import { getTestBed } from '@angular/core/testing'; +import { BrowserDynamicTestingModule, platformBrowserDynamicTesting } from '@angular/platform-browser-dynamic/testing'; // First, initialize the Angular testing environment. -getTestBed().initTestEnvironment( - BrowserDynamicTestingModule, - platformBrowserDynamicTesting() -); -// Then we find all the tests. -const context = require.context('./', true, /\.spec\.ts$/); -// And load the modules. -context.keys().map(context); +getTestBed().initTestEnvironment(BrowserDynamicTestingModule, platformBrowserDynamicTesting()); diff --git a/imxweb/projects/qer-app-portal/tsconfig-es5.app.json b/imxweb/projects/qer-app-portal/tsconfig-es5.app.json index e1d0d6abd..036b8797e 100644 --- a/imxweb/projects/qer-app-portal/tsconfig-es5.app.json +++ b/imxweb/projects/qer-app-portal/tsconfig-es5.app.json @@ -1,6 +1,6 @@ { - "extends": "./tsconfig.app.json", - "compilerOptions": { - "target": "es2020" + "extends": "./tsconfig.app.json", + "compilerOptions": { + "target": "es2020" } -} \ No newline at end of file +} diff --git a/imxweb/projects/qer-app-portal/tsconfig.app.json b/imxweb/projects/qer-app-portal/tsconfig.app.json index ba711311b..d5376ba56 100644 --- a/imxweb/projects/qer-app-portal/tsconfig.app.json +++ b/imxweb/projects/qer-app-portal/tsconfig.app.json @@ -1,14 +1,13 @@ { "extends": "../../tsconfig.json", "compilerOptions": { + "strictNullChecks": true, "outDir": "../../out-tsc/app", "types": [] }, - "files": [ - "src/main.ts", - "src/polyfills.ts" - ], - "include": [ - "projects/qer-app-portal/src/**/*.d.ts" - ] + "angularCompilerOptions": { + "strictTemplates": true + }, + "files": ["src/main.ts", "src/polyfills.ts"], + "include": ["projects/qer-app-portal/src/**/*.d.ts"] } diff --git a/imxweb/projects/qer-app-portal/tsconfig.spec.json b/imxweb/projects/qer-app-portal/tsconfig.spec.json index a809b0a66..6f92d1611 100644 --- a/imxweb/projects/qer-app-portal/tsconfig.spec.json +++ b/imxweb/projects/qer-app-portal/tsconfig.spec.json @@ -1,18 +1,10 @@ { "extends": "../../tsconfig.json", "compilerOptions": { + "strictNullChecks": false, "outDir": "../../out-tsc/spec", - "types": [ - "jasmine", - "node" - ] + "types": ["jasmine", "node"] }, - "files": [ - "src/test.ts", - "src/polyfills.ts" - ], - "include": [ - "**/*.spec.ts", - "**/*.d.ts" - ] + "files": ["src/test.ts", "src/polyfills.ts"], + "include": ["**/*.spec.ts", "**/*.d.ts"] } diff --git a/imxweb/projects/qer-app-portal/tslint.json b/imxweb/projects/qer-app-portal/tslint.json deleted file mode 100644 index 8bab15f53..000000000 --- a/imxweb/projects/qer-app-portal/tslint.json +++ /dev/null @@ -1,17 +0,0 @@ -{ - "extends": "../../tslint.json", - "rules": { - "directive-selector": [ - true, - "attribute", - "imx", - "camelCase" - ], - "component-selector": [ - true, - "element", - "imx", - "kebab-case" - ] - } -} diff --git a/imxweb/projects/qer-app-pwdportal/.compodocrc.json b/imxweb/projects/qer-app-pwdportal/.compodocrc.json index b3353f21d..1f0abb84b 100644 --- a/imxweb/projects/qer-app-pwdportal/.compodocrc.json +++ b/imxweb/projects/qer-app-pwdportal/.compodocrc.json @@ -1,6 +1,6 @@ { "name": "IMX Web - Password Reset Portal", - "output": "../../documentation/v92/qer-app-pwdportal", + "output": "../../documentation/v93/qer-app-pwdportal", "theme": "material", "assetsFolder": "../../compodoc/assets", "customLogo": "../../compodoc/assets/images/oneidentity-logo.png", diff --git a/imxweb/projects/qer-app-pwdportal/.eslintrc.json b/imxweb/projects/qer-app-pwdportal/.eslintrc.json new file mode 100644 index 000000000..9b3d9538c --- /dev/null +++ b/imxweb/projects/qer-app-pwdportal/.eslintrc.json @@ -0,0 +1,35 @@ +{ + "extends": "../../.eslintrc.json", + "ignorePatterns": ["!**/*", "**/*.spec.ts"], + "overrides": [ + { + "files": ["*.ts"], + "parserOptions": { + "project": ["imxweb/projects/qer-app-pwdportal/tsconfig.app.json", "imxweb/projects/qer-app-pwdportal/tsconfig.spec.json"], + "createDefaultProgram": true + }, + "rules": { + "@angular-eslint/directive-selector": [ + "error", + { + "type": "attribute", + "prefix": "imx", + "style": "camelCase" + } + ], + "@angular-eslint/component-selector": [ + "error", + { + "type": "element", + "prefix": "imx", + "style": "kebab-case" + } + ] + } + }, + { + "files": ["*.html"], + "rules": {} + } + ] +} diff --git a/imxweb/projects/qer-app-pwdportal/karma.conf.js b/imxweb/projects/qer-app-pwdportal/karma.conf.js index b454fa9d7..80eeaba08 100644 --- a/imxweb/projects/qer-app-pwdportal/karma.conf.js +++ b/imxweb/projects/qer-app-pwdportal/karma.conf.js @@ -12,10 +12,10 @@ module.exports = function (config) { require('karma-jasmine-html-reporter'), require('karma-coverage-istanbul-reporter'), require('@angular-devkit/build-angular/plugins/karma'), - require('karma-junit-reporter') + require('karma-junit-reporter'), ], client: { - clearContext: false // leave Jasmine Spec Runner output visible in browser + clearContext: false, // leave Jasmine Spec Runner output visible in browser }, coverageIstanbulReporter: { dir: require('path').join(__dirname, 'results'), @@ -26,7 +26,7 @@ module.exports = function (config) { functions: 0, lines: 0, }, - fixWebpackSourcePaths: true + fixWebpackSourcePaths: true, }, junitReporter: { outputDir: require('path').join(__dirname, 'results'), @@ -35,13 +35,14 @@ module.exports = function (config) { port: 9876, captureTimeout: 210000, browserDisconnectTolerance: 3, - browserDisconnectTimeout : 210000, - browserNoActivityTimeout : 210000, + browserDisconnectTimeout: 210000, + browserNoActivityTimeout: 210000, colors: true, logLevel: config.LOG_INFO, autoWatch: true, browsers: ['Chrome'], singleRun: false, - restartOnFileChange: true + failOnEmptyTestSuite: false, + restartOnFileChange: true, }); }; diff --git a/imxweb/projects/qer-app-pwdportal/package.json b/imxweb/projects/qer-app-pwdportal/package.json index e98f32e1e..6cbd74a95 100644 --- a/imxweb/projects/qer-app-pwdportal/package.json +++ b/imxweb/projects/qer-app-pwdportal/package.json @@ -1,5 +1,5 @@ { "name": "qer-app-pwdportal", - "version": "9.2.1", + "version": "9.3.0", "private": true -} \ No newline at end of file +} diff --git a/imxweb/projects/qer-app-pwdportal/project.json b/imxweb/projects/qer-app-pwdportal/project.json new file mode 100644 index 000000000..11e8fa5f8 --- /dev/null +++ b/imxweb/projects/qer-app-pwdportal/project.json @@ -0,0 +1,211 @@ +{ + "$schema": "../../node_modules/nx/schemas/project-schema.json", + "name": "qer-app-pwdportal", + "projectType": "application", + "sourceRoot": "projects/qer-app-pwdportal/src", + "prefix": "imx", + "generators": { + "@schematics/angular:component": { + "style": "scss" + } + }, + "targets": { + "build": { + "executor": "@angular-devkit/build-angular:browser", + "options": { + "allowedCommonJsDependencies": [ + "lodash", + "highlight.js", + "file-saver", + "billboard.js", + "moment-timezone", + "core-js/fn/map", + "core-js/fn/set", + "core-js/fn/weak-map", + "core-js/fn/array/from", + "core-js/fn/object/assign", + "core-js/es/array/from", + "core-js/es/object/assign", + "core-js/es/map", + "core-js/es/set", + "core-js/es/weak-map", + "lodash.debounce", + "lodash.clamp", + "moment", + "@elemental-ui/cadence-icon/codepoints" + ], + "outputPath": "dist/qer-app-pwdportal", + "index": "projects/qer-app-pwdportal/src/index.html", + "main": "projects/qer-app-pwdportal/src/main.ts", + "polyfills": ["projects/qer-app-pwdportal/src/polyfills.ts"], + "tsConfig": "projects/qer-app-pwdportal/tsconfig.app.json", + "aot": true, + "assets": [ + "projects/qer-app-pwdportal/src/appconfig.json", + "projects/qer-app-pwdportal/src/assets", + { + "glob": "**/*", + "input": "./shared/assets/", + "output": "./assets" + }, + { + "glob": "**/*", + "input": "./node_modules/@elemental-ui/core/assets", + "output": "./assets" + } + ], + "styles": [ + "shared/scss/styles.scss", + "projects/qer-app-pwdportal/src/styles.scss", + "projects/qbm/src/lib/styles/imx-page-title.scss" + ], + "stylePreprocessorOptions": { + "includePaths": [ + "./shared/scss", + "./node_modules", + "./node_modules/@elemental-ui/cadence-icon", + "./node_modules/@elemental-ui/core" + ] + } + }, + "configurations": { + "production": { + "fileReplacements": [ + { + "replace": "projects/qer-app-pwdportal/src/environments/environment.ts", + "with": "projects/qer-app-pwdportal/src/environments/environment.prod.ts" + } + ], + "optimization": true, + "outputHashing": "all", + "sourceMap": false, + "namedChunks": false, + "extractLicenses": true, + "vendorChunk": false, + "buildOptimizer": true, + "budgets": [ + { + "type": "initial", + "maximumWarning": "20mb", + "maximumError": "40mb" + }, + { + "type": "anyComponentStyle", + "maximumWarning": "6kb" + } + ] + }, + "development": { + "buildOptimizer": false, + "optimization": false, + "vendorChunk": true, + "extractLicenses": false, + "sourceMap": true, + "namedChunks": true + }, + "remote-dev": { + "fileReplacements": [ + { + "replace": "projects/qer-app-pwdportal/src/environments/environment.ts", + "with": "../imxweb_envs/qer-app-pwdportal/environments/environment.remote-dev.ts" + } + ], + "buildOptimizer": false, + "optimization": false, + "vendorChunk": true, + "extractLicenses": false, + "sourceMap": true, + "namedChunks": true + }, + "remote-qs": { + "fileReplacements": [ + { + "replace": "projects/qer-app-pwdportal/src/environments/environment.ts", + "with": "../imxweb_envs/qer-app-pwdportal/environments/environment.remote-qs.ts" + } + ], + "buildOptimizer": false, + "optimization": false, + "vendorChunk": true, + "extractLicenses": false, + "sourceMap": true, + "namedChunks": true + }, + "es5": { + "tsConfig": "./projects/qer-app-pwdportal/tsconfig-es5.app.json" + } + }, + "outputs": ["{options.outputPath}"], + "dependsOn": ["^build", "prebuild"] + }, + "prebuild": { + "executor": "nx:run-commands", + "options": { + "commands": ["node prebuild.js qer-app-pwdportal"] + }, + "dependsOn": [ + { + "projects": ["att"], + "target": "build" + } + ], + "cache": false + }, + "serve": { + "executor": "@angular-devkit/build-angular:dev-server", + "options": { + "browserTarget": "qer-app-pwdportal:build" + }, + "configurations": { + "production": { + "browserTarget": "qer-app-pwdportal:build:production" + }, + "development": { + "browserTarget": "qer-app-pwdportal:build:development" + }, + "remote-dev": { + "browserTarget": "qer-app-pwdportal:build:remote-dev" + }, + "remote-qs": { + "browserTarget": "qer-app-pwdportal:build:remote-qs" + }, + "es5": { + "browserTarget": "qer-app-pwdportal:build:es5" + } + } + }, + "extract-i18n": { + "executor": "@angular-devkit/build-angular:extract-i18n", + "options": { + "browserTarget": "qer-app-pwdportal:build" + } + }, + "test": { + "executor": "@angular-devkit/build-angular:karma", + "options": { + "main": "projects/qer-app-pwdportal/src/test.ts", + "polyfills": "projects/qer-app-pwdportal/src/polyfills.ts", + "tsConfig": "projects/qer-app-pwdportal/tsconfig.spec.json", + "karmaConfig": "projects/qer-app-pwdportal/karma.conf.js", + "assets": ["projects/qer-app-pwdportal/src/appconfig.json", "projects/qer-app-pwdportal/src/assets"], + "styles": ["projects/qer-app-pwdportal/src/styles.scss"], + "stylePreprocessorOptions": { + "includePaths": [ + "./shared/assets", + "./shared/scss", + "./node_modules", + "./node_modules/@elemental-ui/cadence-icon", + "./node_modules/@elemental-ui/core" + ] + } + } + }, + "lint": { + "executor": "@angular-devkit/build-angular:tslint", + "options": { + "tsConfig": ["projects/qer-app-pwdportal/tsconfig.app.json", "projects/qer-app-pwdportal/tsconfig.spec.json"], + "exclude": ["**/node_modules/**"] + } + } + } +} diff --git a/imxweb/projects/qer-app-pwdportal/src/app/app-routing.module.ts b/imxweb/projects/qer-app-pwdportal/src/app/app-routing.module.ts index cc07e1b98..4d94ea670 100644 --- a/imxweb/projects/qer-app-pwdportal/src/app/app-routing.module.ts +++ b/imxweb/projects/qer-app-pwdportal/src/app/app-routing.module.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -25,9 +25,9 @@ */ import { InjectionToken, NgModule } from '@angular/core'; -import { Routes, RouterModule, ActivatedRouteSnapshot } from '@angular/router'; +import { ActivatedRouteSnapshot, RouterModule, Routes } from '@angular/router'; import { AuthenticationGuardService, LoginComponent, RouteGuardService } from 'qbm'; -import { PasswordDashboardComponent, PasswordResetComponent, PasswordQuestionsComponent } from 'qer'; +import { PasswordDashboardComponent, PasswordQuestionsModule, PasswordResetComponent } from 'qer'; const externalUrlProvider = new InjectionToken('externalUrlRedirectResolver'); @@ -36,31 +36,25 @@ const routes: Routes = [ path: '', component: LoginComponent, canActivate: [AuthenticationGuardService], - resolve: [RouteGuardService] + resolve: [RouteGuardService], }, { path: 'dashboard', component: PasswordDashboardComponent, canActivate: [RouteGuardService], - resolve: [RouteGuardService] + resolve: [RouteGuardService], }, { path: 'resetpassword', component: PasswordResetComponent, canActivate: [RouteGuardService], - resolve: [RouteGuardService] + resolve: [RouteGuardService], }, - { - path: 'password-questions', - component: PasswordQuestionsComponent, - canActivate: [RouteGuardService], - resolve: [RouteGuardService] - }, - { path: '**', redirectTo: 'dashboard' } + { path: '**', redirectTo: 'dashboard' }, ]; @NgModule({ - imports: [RouterModule.forRoot(routes, { useHash: true, relativeLinkResolution: 'legacy' })], + imports: [RouterModule.forRoot(routes, { useHash: true }), PasswordQuestionsModule], exports: [RouterModule], providers: [ { @@ -70,9 +64,8 @@ const routes: Routes = [ if (externalUrl && externalUrl.toLocaleLowerCase() !== 'undefined') { window.open(externalUrl, '_self'); } - } + }, }, ], }) - -export class AppRoutingModule { } +export class AppRoutingModule {} diff --git a/imxweb/projects/qer-app-pwdportal/src/app/app.component.html b/imxweb/projects/qer-app-pwdportal/src/app/app.component.html index 73aaaf49e..a2e4c8d4a 100644 --- a/imxweb/projects/qer-app-pwdportal/src/app/app.component.html +++ b/imxweb/projects/qer-app-pwdportal/src/app/app.component.html @@ -1,15 +1,14 @@
    - - - - - - - -
    - - -
    + + + + + + + +
    + +
    diff --git a/imxweb/projects/qer-app-pwdportal/src/app/app.component.scss b/imxweb/projects/qer-app-pwdportal/src/app/app.component.scss index c2f8a644d..86c7a5516 100644 --- a/imxweb/projects/qer-app-pwdportal/src/app/app.component.scss +++ b/imxweb/projects/qer-app-pwdportal/src/app/app.component.scss @@ -6,9 +6,21 @@ } .pageContent { - margin: 20px 30px; + margin: 24px; display: flex; flex-direction: column; overflow: hidden; height: inherit; + ::ng-deep { + imx-icon-tile { + imx-tile { + .mat-mdc-card { + height: 150px; + .mat-mdc-card-subtitle { + overflow: hidden; + } + } + } + } + } } diff --git a/imxweb/projects/qer-app-pwdportal/src/app/app.component.ts b/imxweb/projects/qer-app-pwdportal/src/app/app.component.ts index 1b1a537b4..83b0b1c72 100644 --- a/imxweb/projects/qer-app-pwdportal/src/app/app.component.ts +++ b/imxweb/projects/qer-app-pwdportal/src/app/app.component.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -25,16 +25,25 @@ */ import { Component, ErrorHandler, OnDestroy, OnInit } from '@angular/core'; -import { EventType, NavigationCancel, NavigationEnd, NavigationError, NavigationStart, Router, RouterEvent } from '@angular/router'; +import { Event, EventType, NavigationEnd, NavigationStart, Router, RouterEvent } from '@angular/router'; import { Subscription } from 'rxjs'; -import { AppConfigService, AuthenticationService, ISessionState, ImxTranslationProviderService, SplashService } from 'qbm'; import { MatDialog } from '@angular/material/dialog'; +import { EuiTheme, EuiThemeService } from '@elemental-ui/core'; +import { ProfileSettings } from '@imx-modules/imx-api-qer'; +import { + AppConfigService, + AuthenticationService, + ClassloggerService, + ConfirmationService, + ImxTranslationProviderService, + ISessionState, + Message, + SplashService, + UserMessageService, +} from 'qbm'; import { QerApiService, SettingsComponent } from 'qer'; -import { EuiLoadingService, EuiTheme, EuiThemeService } from '@elemental-ui/core'; -import { ProfileSettings } from 'imx-api-qer'; import { getBaseHref, HEADLESS_BASEHREF } from './app.module'; -import { TranslateService } from '@ngx-translate/core'; @Component({ selector: 'imx-root', @@ -43,12 +52,13 @@ import { TranslateService } from '@ngx-translate/core'; }) export class AppComponent implements OnInit, OnDestroy { public isLoggedIn = false; - public hideUserMessage = false; public showPageContent = true; + public message: Message | undefined; private routerStatus: EventType; private readonly subscriptions: Subscription[] = []; constructor( + private readonly logger: ClassloggerService, private readonly authentication: AuthenticationService, private readonly router: Router, private readonly splash: SplashService, @@ -58,7 +68,8 @@ export class AppComponent implements OnInit, OnDestroy { private readonly themeService: EuiThemeService, private readonly errorHandler: ErrorHandler, private readonly translationProvider: ImxTranslationProviderService, - private readonly translateService: TranslateService + private readonly confirmationService: ConfirmationService, + private readonly userMessageService: UserMessageService, ) { this.subscriptions.push( this.authentication.onSessionResponse.subscribe(async (sessionState: ISessionState) => { @@ -71,15 +82,20 @@ export class AppComponent implements OnInit, OnDestroy { } } - this.isLoggedIn = sessionState.IsLoggedIn; + this.isLoggedIn = sessionState.IsLoggedIn ?? false; if (this.isLoggedIn) { - const isUseProfileLangChecked = (await this.qerClient.v2Client.passwordreset_profile_get()).UseProfileLanguage ?? false; - // Set session culture if isUseProfileLangChecked is true, set browser culture otherwise + const isUseProfileLangChecked = (await this.qerClient.client.passwordreset_profile_get()).UseProfileLanguage ?? false; + // Set session culture if isUseProfileLangChecked is true if (isUseProfileLangChecked) { - await this.translationProvider.init(sessionState.culture, sessionState.cultureFormat); - } else { - const browserCulture = this.translateService.getBrowserCultureLang(); - await this.translationProvider.init(browserCulture); + // Use culture if available, if not fetch + const culture = sessionState.culture + ? sessionState.culture + : (await this.qerClient.client.passwordreset_profile_person_get())?.ProfileLanguage; + // If culture is found, use it, otherwise fallback to the app default + if (culture) { + this.logger.debug(this, `ProfileLangChecked is true, culture available: Setting ${culture} as profile language`); + await this.translationProvider.reinit(culture, sessionState.cultureFormat ?? culture, this.router); + } } // Close the splash screen that opened in app service initialisation @@ -87,14 +103,25 @@ export class AppComponent implements OnInit, OnDestroy { this.splash.close(); this.applyProfileSettings(); } - }) + }), + ); + + this.subscriptions.push( + this.userMessageService.subject.subscribe((message) => { + this.message = message; + if (!!this.message && this.message.type === 'error' && !this.message.target) { + this.confirmationService.showErrorMessage({ + Message: this.message?.text, + }); + } + }), ); this.setupRouter(); } public async ngOnInit(): Promise { - this.authentication.update(); + await this.authentication.update(); } public ngOnDestroy(): void { @@ -114,35 +141,23 @@ export class AppComponent implements OnInit, OnDestroy { } private setupRouter(): void { - this.router.events.subscribe((event: RouterEvent) => { + this.router.events.subscribe((event: Event & RouterEvent) => { if (event instanceof NavigationStart) { - this.hideUserMessage = true; this.routerStatus = event.type; if (this.isLoggedIn) { if (event.url === '/') { // show the splash screen, when the user logs out! this.splash.init({ applicationName: 'Password Reset Portal' }); - } else if (event.url === `/${this.config.Config.routeConfig.start}`) { + } else if (event.url === `/${this.config.Config.routeConfig?.start}`) { // closes the splash-screen, if its displayed between Login and Dashboard this.splash.close(); } } } - if (event instanceof NavigationCancel) { - this.hideUserMessage = false; - this.routerStatus = event.type; - } - if (event instanceof NavigationEnd) { - this.hideUserMessage = false; - this.showPageContent = true; - this.routerStatus = event.type; - } - - if (event instanceof NavigationError) { - this.hideUserMessage = false; this.routerStatus = event.type; + this.showPageContent = true; } }); } diff --git a/imxweb/projects/qer-app-pwdportal/src/app/app.module.ts b/imxweb/projects/qer-app-pwdportal/src/app/app.module.ts index 75a8b0d47..f45cff2d6 100644 --- a/imxweb/projects/qer-app-pwdportal/src/app/app.module.ts +++ b/imxweb/projects/qer-app-pwdportal/src/app/app.module.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -24,7 +24,7 @@ * */ -import { HttpClientModule } from '@angular/common/http'; +import { provideHttpClient, withInterceptorsFromDi } from '@angular/common/http'; import { APP_INITIALIZER, ErrorHandler, NgModule } from '@angular/core'; import { BrowserModule } from '@angular/platform-browser'; import { BrowserAnimationsModule } from '@angular/platform-browser/animations'; @@ -33,6 +33,8 @@ import { MissingTranslationHandler, TranslateLoader, TranslateModule, TranslateS import { LoggerModule, NgxLoggerLevel } from 'ngx-logger'; import { APP_BASE_HREF } from '@angular/common'; +import { MatPaginatorIntl } from '@angular/material/paginator'; +import { RECAPTCHA_V3_SITE_KEY } from 'ng-recaptcha-2'; import { AuthenticationModule, CustomThemeModule, @@ -41,18 +43,16 @@ import { ImxTranslateLoader, LdsReplacePipe, MastHeadModule, - MenuModule, Paginator, SqlWizardApiService, UserMessageModule, } from 'qbm'; +import { PasscodeLoginModule, PasswordModule, QaLoginModule, QerModule } from 'qer'; +import appConfigJson from '../appconfig.json'; import { environment } from '../environments/environment'; import { AppRoutingModule } from './app-routing.module'; import { AppComponent } from './app.component'; import { AppService } from './app.service'; -import { MatPaginatorIntl } from '@angular/material/paginator'; -import { PasswordModule, QaLoginModule, PasscodeLoginModule, ProfileModule, QerModule } from 'qer'; -import appConfigJson from '../appconfig.json'; import { PwdSqlWizardApiService } from './pwd-sql-wizard-api.service'; export const HEADLESS_BASEHREF = '/headless'; @@ -61,6 +61,7 @@ export function getBaseHref(): string { } @NgModule({ declarations: [AppComponent], + bootstrap: [AppComponent], imports: [ AppRoutingModule, AuthenticationModule, @@ -68,10 +69,8 @@ export function getBaseHref(): string { BrowserModule, EuiCoreModule, EuiMaterialModule, - HttpClientModule, LoggerModule.forRoot({ level: NgxLoggerLevel.DEBUG, serverLogLevel: NgxLoggerLevel.OFF }), MastHeadModule, - MenuModule, QaLoginModule, QerModule, PasscodeLoginModule, @@ -88,7 +87,6 @@ export function getBaseHref(): string { }, }), UserMessageModule, - ProfileModule, ], providers: [ { provide: 'environment', useValue: environment }, @@ -116,7 +114,14 @@ export function getBaseHref(): string { provide: SqlWizardApiService, useClass: PwdSqlWizardApiService, }, + { + provide: RECAPTCHA_V3_SITE_KEY, + useFactory: (config: AppService) => { + return config.recaptchaSiteKeyV3; + }, + deps: [AppService], + }, + provideHttpClient(withInterceptorsFromDi()), ], - bootstrap: [AppComponent], }) export class AppModule {} diff --git a/imxweb/projects/qer-app-pwdportal/src/app/app.service.ts b/imxweb/projects/qer-app-pwdportal/src/app/app.service.ts index 744248e97..6a354846f 100644 --- a/imxweb/projects/qer-app-pwdportal/src/app/app.service.ts +++ b/imxweb/projects/qer-app-pwdportal/src/app/app.service.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -24,35 +24,30 @@ * */ -import { Injectable } from '@angular/core'; +import { Injectable, Injector, createNgModule } from '@angular/core'; import { Title } from '@angular/platform-browser'; import { TranslateService } from '@ngx-translate/core'; -import { Globals } from 'imx-qbm-dbts'; +import { TypedClient } from '@imx-modules/imx-api-qbm'; +import { Globals } from '@imx-modules/imx-qbm-dbts'; import { AppConfigService, - AuthenticationService, - imx_SessionService, + CaptchaService, CdrRegistryService, - ImxTranslationProviderService, ClassloggerService, - PluginLoaderService, + ImxTranslationProviderService, SplashService, - SystemInfoService + SystemInfoService, + imx_SessionService, } from 'qbm'; +import { PasswordService, QerApiService } from 'qer'; import { environment } from '../environments/environment'; -import { TypedClient } from 'imx-api-qbm'; - -import * as QBM from 'qbm'; -import * as QER from 'qer'; - -declare var SystemJS: any; - @Injectable({ - providedIn: 'root' + providedIn: 'root', }) export class AppService { + public recaptchaSiteKeyV3: string | null = null; constructor( public readonly registry: CdrRegistryService, private readonly logger: ClassloggerService, @@ -62,20 +57,21 @@ export class AppService { private readonly session: imx_SessionService, private readonly translationProvider: ImxTranslationProviderService, private readonly title: Title, - private readonly pluginLoader: PluginLoaderService, - private readonly authentication: AuthenticationService, + private readonly qerApi: QerApiService, + private readonly passwordService: PasswordService, private readonly splash: SplashService, - ) { } + private readonly captchaService: CaptchaService, + private readonly injector: Injector, + ) {} public async init(): Promise { this.showSplash(); await this.config.init(environment.clientUrl); - this.translateService.addLangs(this.config.Config.Translation.Langs); - const browserCulture = this.translateService.getBrowserCultureLang(); - this.logger.debug(this, `Set ${browserCulture} as default language`); - this.translateService.setDefaultLang(browserCulture); - await this.translateService.use(browserCulture).toPromise(); + if (this.config.Config.Translation?.Langs) { + this.translateService.addLangs(this.config.Config.Translation.Langs); + } + await this.translationProvider.init(); this.translateService.onLangChange.subscribe(() => { this.setTitle(); @@ -84,10 +80,18 @@ export class AppService { this.setTitle(); this.session.TypedClient = new TypedClient(this.config.v2client, this.translationProvider); - SystemJS.set('qbm', SystemJS.newModule(QBM)); - SystemJS.set('qer', SystemJS.newModule(QER)); - await this.pluginLoader.loadModules(environment.appName); + await this.loadModules(environment.appName); + + const featureConfig = await this.qerApi.v2Client.passwordreset_authconfig_get(); + + this.captchaService.captchaImageUrl = 'passwordreset/captchaimage'; + if (featureConfig.RecaptchaPublicKey) { + this.captchaService.enableReCaptcha(featureConfig.RecaptchaPublicKey); + this.recaptchaSiteKeyV3 = featureConfig.RecaptchaPublicKey; + } + + await this.passwordService.registerCustomAuthFlows(featureConfig); } private async setTitle(): Promise { @@ -118,4 +122,38 @@ export class AppService { const loadingMsg = await this.translateService.get('#LDS#Loading...').toPromise(); this.splash.update({ applicationName: title, message: loadingMsg }); } + + private async loadModules(appName: string): Promise { + const apps = await this.session.Client.imx_applications_get(); + + const appInfo = apps.filter((app) => app.Name === appName)[0]; + + this.logger.debug(this, `▶️ Found config section for ${appInfo.DisplayName}`); + + if (appInfo.PlugIns == null || appInfo.PlugIns.length === 0) { + this.logger.debug(this, `❌ No plugins found`); + return; + } + + this.logger.debug(this, `▶️ Found ${appInfo.PlugIns.length} plugin(s)`); + + for (const plugin of appInfo.PlugIns) { + this.logger.debug(this, `⚙️ Plugin: ${plugin.Container}`); + + try { + this.logger.debug(this, '▶️ Importing module. DEV mode.'); + await import(`html/qer-app-pwdportal/${plugin.Container}/fesm2022/${plugin.Container}.mjs`) + .then((m) => { + if (plugin.Name) { + createNgModule(m[plugin.Name], this.injector); + } + }) + .catch((error) => + this.logger.error(this, `💥 Loading of ${plugin.Name} (${plugin.Container}) failed with the following error: ${error.message}`), + ); + } catch (e) { + this.logger.error(this, `💥 Loading of ${plugin.Name} (${plugin.Container}) failed with the following error: ${e.message}`); + } + } + } } diff --git a/imxweb/projects/qer-app-pwdportal/src/app/pwd-sql-wizard-api.service.ts b/imxweb/projects/qer-app-pwdportal/src/app/pwd-sql-wizard-api.service.ts index 7cf64b37e..e86c914a6 100644 --- a/imxweb/projects/qer-app-pwdportal/src/app/pwd-sql-wizard-api.service.ts +++ b/imxweb/projects/qer-app-pwdportal/src/app/pwd-sql-wizard-api.service.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -25,7 +25,7 @@ */ import { Injectable } from '@angular/core'; -import { FilterProperty, CollectionLoadParameters, EntityCollectionData } from 'imx-qbm-dbts'; +import { CollectionLoadParameters, EntityCollectionData, FilterProperty } from '@imx-modules/imx-qbm-dbts'; import { SqlWizardApiService } from 'qbm'; @Injectable({ @@ -37,7 +37,7 @@ export class PwdSqlWizardApiService extends SqlWizardApiService { getFilterProperties(table: string): Promise { return new Promise((resolve) => resolve([])); } - + getCandidates(parentTable: string, options?: CollectionLoadParameters): Promise { return new Promise((resolve) => resolve({ TotalCount: 0 })); } diff --git a/imxweb/projects/qer-app-pwdportal/src/environments/environment.prod.ts b/imxweb/projects/qer-app-pwdportal/src/environments/environment.prod.ts index ec3b6404f..eb3f27de9 100644 --- a/imxweb/projects/qer-app-pwdportal/src/environments/environment.prod.ts +++ b/imxweb/projects/qer-app-pwdportal/src/environments/environment.prod.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -28,5 +28,5 @@ export const environment = { production: true, clientUrl: '', appName: 'qer-app-pwdportal', - appVersion: '1.0.0' + appVersion: '1.0.0', }; diff --git a/imxweb/projects/qer-app-pwdportal/src/environments/environment.ts b/imxweb/projects/qer-app-pwdportal/src/environments/environment.ts index d49e085b6..7478e82ff 100644 --- a/imxweb/projects/qer-app-pwdportal/src/environments/environment.ts +++ b/imxweb/projects/qer-app-pwdportal/src/environments/environment.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -32,7 +32,7 @@ export const environment = { production: false, clientUrl: 'http://localhost:8182', appName: 'qer-app-pwdportal', - appVersion: '1.0.0' + appVersion: '1.0.0', }; /* @@ -42,4 +42,4 @@ export const environment = { * This import should be commented out in production mode because it will have a negative impact * on performance if an error is thrown. */ -// import 'zone.js/dist/zone-error'; // Included with Angular CLI. +// import 'zone.js'; // Included with Angular CLI. diff --git a/imxweb/projects/qer-app-pwdportal/src/index.html b/imxweb/projects/qer-app-pwdportal/src/index.html index 702cf2308..53a0e20ab 100644 --- a/imxweb/projects/qer-app-pwdportal/src/index.html +++ b/imxweb/projects/qer-app-pwdportal/src/index.html @@ -1,19 +1,17 @@ + + + + + + - - - - - - + + + +
    - - - -
    - - - - - \ No newline at end of file + + + diff --git a/imxweb/projects/qer-app-pwdportal/src/main.ts b/imxweb/projects/qer-app-pwdportal/src/main.ts index 5b7a3816d..8cb3e4f09 100644 --- a/imxweb/projects/qer-app-pwdportal/src/main.ts +++ b/imxweb/projects/qer-app-pwdportal/src/main.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -34,5 +34,6 @@ if (environment.production) { enableProdMode(); } -platformBrowserDynamic().bootstrapModule(AppModule) - .catch(err => console.error(err)); +platformBrowserDynamic() + .bootstrapModule(AppModule) + .catch((err) => console.error(err)); diff --git a/imxweb/projects/qer-app-pwdportal/src/polyfills.ts b/imxweb/projects/qer-app-pwdportal/src/polyfills.ts index 31ad3d496..9c1e09bff 100644 --- a/imxweb/projects/qer-app-pwdportal/src/polyfills.ts +++ b/imxweb/projects/qer-app-pwdportal/src/polyfills.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -41,9 +41,8 @@ */ /*************************************************************************************************** -* BROWSER POLYFILLS -*/ - + * BROWSER POLYFILLS + */ /** IE10 and IE11 requires the following for NgClass support on SVG elements */ // import 'classlist.js'; // Run `npm install --save classlist.js`. @@ -51,13 +50,12 @@ /** IE10 and IE11 requires the following for the Reflect API. */ // import 'core-js/es6/reflect'; - /** Evergreen browsers require these. */ // Used for reflect-metadata in JIT. If you use AOT (and only Angular decorators), you can remove. -import 'core-js/es7/reflect'; +import 'core-js/es/reflect'; // Used for support array.includes -import 'core-js/es7/array'; +import 'core-js/es/array'; /** * Required to support Web Animations `@angular/platform-browser/animations`. @@ -65,17 +63,13 @@ import 'core-js/es7/array'; */ import 'web-animations-js'; - - /*************************************************************************************************** * Zone JS is required by default for Angular itself. */ -import 'zone.js/dist/zone'; // Included with Angular CLI. - - +import 'zone.js'; // Included with Angular CLI. /*************************************************************************************************** * APPLICATION IMPORTS */ -import 'whatwg-fetch'; import 'url-polyfill'; +import 'whatwg-fetch'; diff --git a/imxweb/projects/qer-app-pwdportal/src/styles.scss b/imxweb/projects/qer-app-pwdportal/src/styles.scss index c4916f42e..c04561172 100644 --- a/imxweb/projects/qer-app-pwdportal/src/styles.scss +++ b/imxweb/projects/qer-app-pwdportal/src/styles.scss @@ -1,12 +1,7 @@ /* You can add global styles to this file, and also import other style files */ -@use '@angular/material' as mat; - -$material_icons_font_path: "~node_modules/@elemental-ui/core/assets/MaterialIcons"; -$cadence_font_path: "~node_modules/@elemental-ui/core/assets/Cadence"; -$source_sans_pro_font_path: "~node_modules/@elemental-ui/core/assets/Source_Sans_Pro"; - @import '@elemental-ui/core/src/styles/core.scss'; +@import 'components/toolbar'; .eui-dark-theme { .page { @@ -17,11 +12,6 @@ $source_sans_pro_font_path: "~node_modules/@elemental-ui/core/assets/Source_Sans color: $color-gray-5; background-color: $color-gray-80; } - .eui-sidesheet { - .mat-toolbar{ - background-color: $color-blue-80; - } - } } .eui-contrast-theme { @@ -33,9 +23,4 @@ $source_sans_pro_font_path: "~node_modules/@elemental-ui/core/assets/Source_Sans color: $color-gray-0; background-color: $color-gray-100; } - .eui-sidesheet { - .mat-toolbar{ - background-color: $color-blue-80; - } - } } diff --git a/imxweb/projects/qer-app-pwdportal/src/test.ts b/imxweb/projects/qer-app-pwdportal/src/test.ts index 46112a57e..f5b670cb3 100644 --- a/imxweb/projects/qer-app-pwdportal/src/test.ts +++ b/imxweb/projects/qer-app-pwdportal/src/test.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -26,26 +26,23 @@ // This file is required by karma.conf.js and loads recursively all the .spec and framework files -import 'zone.js/dist/zone-testing'; +// Zone must be imported first. Be careful with prettier import organizing +import 'zone.js'; +import 'zone.js/testing'; + import { getTestBed } from '@angular/core/testing'; -import { - BrowserDynamicTestingModule, - platformBrowserDynamicTesting -} from '@angular/platform-browser-dynamic/testing'; +import { BrowserDynamicTestingModule, platformBrowserDynamicTesting } from '@angular/platform-browser-dynamic/testing'; declare const require: { - context(path: string, deep?: boolean, filter?: RegExp): { + context( + path: string, + deep?: boolean, + filter?: RegExp, + ): { keys(): string[]; (id: string): T; }; }; // First, initialize the Angular testing environment. -getTestBed().initTestEnvironment( - BrowserDynamicTestingModule, - platformBrowserDynamicTesting() -); -// Then we find all the tests. -const context = require.context('./', true, /\.spec\.ts$/); -// And load the modules. -context.keys().map(context); +getTestBed().initTestEnvironment(BrowserDynamicTestingModule, platformBrowserDynamicTesting()); diff --git a/imxweb/projects/qer-app-pwdportal/tsconfig-es5.app.json b/imxweb/projects/qer-app-pwdportal/tsconfig-es5.app.json index e1d0d6abd..036b8797e 100644 --- a/imxweb/projects/qer-app-pwdportal/tsconfig-es5.app.json +++ b/imxweb/projects/qer-app-pwdportal/tsconfig-es5.app.json @@ -1,6 +1,6 @@ { - "extends": "./tsconfig.app.json", - "compilerOptions": { - "target": "es2020" + "extends": "./tsconfig.app.json", + "compilerOptions": { + "target": "es2020" } -} \ No newline at end of file +} diff --git a/imxweb/projects/qer-app-pwdportal/tsconfig.app.json b/imxweb/projects/qer-app-pwdportal/tsconfig.app.json index d99eeed8a..640419855 100644 --- a/imxweb/projects/qer-app-pwdportal/tsconfig.app.json +++ b/imxweb/projects/qer-app-pwdportal/tsconfig.app.json @@ -1,14 +1,13 @@ { "extends": "../../tsconfig.json", "compilerOptions": { + "strictNullChecks": true, "outDir": "../../out-tsc/app", "types": [] }, - "files": [ - "src/main.ts", - "src/polyfills.ts" - ], - "include": [ - "projects/qer-app-pwdportal/src/**/*.d.ts" - ] + "angularCompilerOptions": { + "strictTemplates": true + }, + "files": ["src/main.ts", "src/polyfills.ts"], + "include": ["projects/qer-app-pwdportal/src/**/*.d.ts"] } diff --git a/imxweb/projects/qer-app-pwdportal/tsconfig.spec.json b/imxweb/projects/qer-app-pwdportal/tsconfig.spec.json index a809b0a66..143838d98 100644 --- a/imxweb/projects/qer-app-pwdportal/tsconfig.spec.json +++ b/imxweb/projects/qer-app-pwdportal/tsconfig.spec.json @@ -2,17 +2,8 @@ "extends": "../../tsconfig.json", "compilerOptions": { "outDir": "../../out-tsc/spec", - "types": [ - "jasmine", - "node" - ] + "types": ["jasmine", "node"] }, - "files": [ - "src/test.ts", - "src/polyfills.ts" - ], - "include": [ - "**/*.spec.ts", - "**/*.d.ts" - ] + "files": ["src/test.ts", "src/polyfills.ts"], + "include": ["**/*.spec.ts", "**/*.d.ts"] } diff --git a/imxweb/projects/qer-app-pwdportal/tslint.json b/imxweb/projects/qer-app-pwdportal/tslint.json deleted file mode 100644 index 8bab15f53..000000000 --- a/imxweb/projects/qer-app-pwdportal/tslint.json +++ /dev/null @@ -1,17 +0,0 @@ -{ - "extends": "../../tslint.json", - "rules": { - "directive-selector": [ - true, - "attribute", - "imx", - "camelCase" - ], - "component-selector": [ - true, - "element", - "imx", - "kebab-case" - ] - } -} diff --git a/imxweb/projects/qer/.compodocrc.json b/imxweb/projects/qer/.compodocrc.json index bc4741cb2..25da3e915 100644 --- a/imxweb/projects/qer/.compodocrc.json +++ b/imxweb/projects/qer/.compodocrc.json @@ -1,6 +1,6 @@ { "name": "IMX Web - QER Library", - "output": "../../documentation/v92/qer", + "output": "../../documentation/v93/qer", "theme": "material", "assetsFolder": "../../compodoc/assets", "customLogo": "../../compodoc/assets/images/oneidentity-logo.png", diff --git a/imxweb/projects/qer/.eslintrc.json b/imxweb/projects/qer/.eslintrc.json new file mode 100644 index 000000000..07dc1c3d2 --- /dev/null +++ b/imxweb/projects/qer/.eslintrc.json @@ -0,0 +1,35 @@ +{ + "extends": "../../.eslintrc.json", + "ignorePatterns": ["!**/*", "**/*.spec.ts"], + "overrides": [ + { + "files": ["*.ts"], + "parserOptions": { + "project": ["imxweb/projects/qer/tsconfig.lib.json", "imxweb/projects/qer/tsconfig.spec.json"], + "createDefaultProgram": true + }, + "rules": { + "@angular-eslint/directive-selector": [ + "error", + { + "type": "attribute", + "prefix": "imx", + "style": "camelCase" + } + ], + "@angular-eslint/component-selector": [ + "error", + { + "type": "element", + "prefix": "imx", + "style": "kebab-case" + } + ] + } + }, + { + "files": ["*.html"], + "rules": {} + } + ] +} diff --git a/imxweb/projects/qer/README.md b/imxweb/projects/qer/README.md index b480bf293..33804c7a1 100644 --- a/imxweb/projects/qer/README.md +++ b/imxweb/projects/qer/README.md @@ -1,6 +1,6 @@ # Identity management base module -This library contains the basic components for identity management. +The `qer` library contains the basic components for identity management. That includes, but is not limited to, role management, the IT shop and identity administration. See the following pages for more details on the code structure. diff --git a/imxweb/projects/qer/additionalDocumentation/identity.md b/imxweb/projects/qer/additionalDocumentation/identity.md index a60f30552..cdfb8806d 100644 --- a/imxweb/projects/qer/additionalDocumentation/identity.md +++ b/imxweb/projects/qer/additionalDocumentation/identity.md @@ -1,35 +1,34 @@ -# Identity Management +# Identity management -This section lists components that support identity management use-cases. +In this section you can find information about components that support identity management use cases. -## 1. Data Explorer 'Identities' section +## 1. Identity management -The identities section of the data explorer is defined in the [`DataExplorerIdentitiesComponent`](../components/DataExplorerIdentitiesComponent.html) and can be used in two different contexts: -1. as an identity administrator -2. as a manager +The identity management is defined in the [`DataExplorerIdentitiesComponent`](../components/DataExplorerIdentitiesComponent.html) and can be used in different contexts: +- as a manager ("My Responsibilities" page) +- as an identity administrator (Data Explorer) -The manager view is filtered by identities, that are reporting to the user, while the admin view shows all identities in the system. +The manager view only shows identities, that the user is responsible for, while the admin view shows all identities in the system. -Clicking on an identity opens a side sheet that displays more information about the identity. +Clicking an identity opens a side sheet that displays more information about the identity. This library defines the following sub components that are part of this side sheet: - a tab control with the following sub components: - - [`ObjectHyperviewComponent`](../components/ObjectHyperviewComponent.html): displays a hyper view for the identity. - - [`OrgChartComponent`](../components/OrgChartComponent.html): displays an organizational chart for the identity. - - [`ObjectHistoryComponent`](../../qbm/components/ObjectHistoryComponent.html): displays the history of the identity object. This is defined in QBM. -- [`AssignmentsComponent`](../components/AssignmentsComponent.html): A component, that shows the memberships of the selected entity. The component looks quite similar to the data explorer control. The registration of membership tabs is quite similar, too. - + - [`ObjectHyperviewComponent`](../components/ObjectHyperviewComponent.html): Displays a hyperview for the identity. + - [`OrgChartComponent`](../components/OrgChartComponent.html): Displays an organizational chart for the identity. + - [`ObjectHistoryComponent`](../../qbm/components/ObjectHistoryComponent.html): Displays the history of the identity object. This is defined in QBM. + - [`AssignmentsComponent`](../components/AssignmentsComponent.html): Displays the memberships of the selected entity. - Additionally, it is possible to register other tabs using the [`ExtService`](../../qbm/injectables/ExtService.html), which is part of the QBM library. -## 2. Address Book -The [`AddressbookComponent`](../components/AddressbookComponent.html) lists all identities from the `Person` database table. It is a read-only view that opens a read-only sidesheet as well. +## 2. Address book +The [`AddressbookComponent`](../components/AddressbookComponent.html) lists all identities from the `Person` database table. It is a read-only view that opens a read-only side sheet. ## 3. Profile -The [`ProfileComponent`](../components/ProfileComponent.html) provides access to the current user's main data. Additionally the user can configure e-mail subscriptions ([`MailSubscriptionsComponent`](../components/MailSubscriptionsComponent.html)), manage -security keys ([`SecurityKeysComponent`](../components/SecurityKeysComponent.html)) and edit the Q&A profile ([`PasswordQueryComponent`](../components/PasswordQueryComponent.html)). +The [`ProfileComponent`](../components/ProfileComponent.html) provides access to the current user's main data. Additionally users can configure email subscriptions ([`MailSubscriptionsComponent`](../components/MailSubscriptionsComponent.html)), manage +security keys ([`SecurityKeysComponent`](../components/SecurityKeysComponent.html)) and manage their password questions ([`PasswordQueryComponent`](../components/PasswordQueryComponent.html)). -To extend the profile with more tab pages, register them with the [`ExtService`](../../qbm/injectables/ExtService.html), which is part of the QBM library. +To extend the profile with more tabs, register them with the [`ExtService`](../../qbm/injectables/ExtService.html), which is part of the QBM library. -## 4. User Model -The user model is defined in the [`UserModelService`](../injectables/UserModelService.html). It contains functions to fetch the current session's configuration, including information on available program features, pending items and direct reports. +## 4. User model +The user model is defined in the [`UserModelService`](../injectables/UserModelService.html). It contains functions to fetch the current session's configuration, including information on available program features, pending requests, and direct reports. diff --git a/imxweb/projects/qer/additionalDocumentation/it-shop.md b/imxweb/projects/qer/additionalDocumentation/it-shop.md index dc0e24674..5a6d01870 100644 --- a/imxweb/projects/qer/additionalDocumentation/it-shop.md +++ b/imxweb/projects/qer/additionalDocumentation/it-shop.md @@ -1,53 +1,53 @@ # IT Shop -## 1. New Request -The starting point of the request life cycle is defined by the [`NewRequestComponent`](../components/NewRequestComponent.html). This component consists of several tab page:. +## New request +The starting point of the request lifecycle is defined by the [`NewRequestComponent`](../components/NewRequestComponent.html). This component consists of several tabs: -1. [`NewRequestProductComponent`](../components/NewRequestProductComponent.html): The main page shows the service items organized by service category. -2. [`NewRequestPeerGroupComponent`](../components/NewRequestPeerGroupComponent.html): In this tab, the user can select recommended service items and organizational structures. -3. [`NewRequestReferenceUserComponent`](../components/NewRequestReferenceUserComponent.html): The user can select service items and organizational structures by reference user here. -4. [`NewRequestProductBundleComponent`](../components/NewRequestProductBundleComponent.html): The user can create requests based on a product bundle. +1. [`NewRequestProductComponent`](../components/NewRequestProductComponent.html): Shows the products by service category. +2. [`NewRequestPeerGroupComponent`](../components/NewRequestPeerGroupComponent.html): Shows recommended products and organizational structures. +3. [`NewRequestReferenceUserComponent`](../components/NewRequestReferenceUserComponent.html): Shows service items and organizational structures of a specific reference user. +4. [`NewRequestProductBundleComponent`](../components/NewRequestProductBundleComponent.html): Shows product bundles and their products. Users can request individual products from product bundles or whole product bundles. -## 2. Parameter Editor +## Parameter editor Service items can define request properties. These are handled using the [`ParameterDataService`](../injectables/ParameterDataService.html), which converts the data given by the server to editable parameter columns, that can be edited using the [`CartItemEditComponent`](../components/CartItemEditComponent.html). -## 3. Shopping Cart -The entry point into the shopping cart is defined by the [`ShoppingCartComponent`](../components/ShoppingCartComponent.html). It contains a table that lists the cart items in the cart. The items can be edited, deleted and checked for validity. All sub components and services are part of the [`ShoppingCartModule`](../modules/ShoppingCartModule.html). -Items in the cart can be moved to the Saved-for-later list and vice versa, this is handled by the [`ShoppingCartForLaterComponent`](../components/ShoppingCartForLaterComponent.html). +## Shopping cart +The entry point into the shopping cart is defined by the [`ShoppingCartComponent`](../components/ShoppingCartComponent.html). It contains a table that lists the products in the shopping cart. The products can be edited, removed and checked for validity. All sub components and services are part of the [`ShoppingCartModule`](../modules/ShoppingCartModule.html). +Products in the shopping cart can be moved to the Saved for Later list and vice versa. This is handled by the [`ShoppingCartForLaterComponent`](../components/ShoppingCartForLaterComponent.html). -## 4. Pending Requests +## Pending requests -The next step in the workflow is the approval of items. The entry point for this is the [`ApprovalsComponent`](../components/ApprovalsComponent.html), which lists all the requests currently approvable by the user. +The next step in the workflow is the approval of requests. The entry point for this is the [`ApprovalsComponent`](../components/ApprovalsComponent.html), which lists all requests that can currently be approved by the user. -This also contains a sub component [`InquiriesComponent`](../components/InquiriesComponent.html) which lists inquiries for the user. +This also contains a sub component [`InquiriesComponent`](../components/InquiriesComponent.html) which lists request inquiries for the user. All the sub components are part of the [`ApprovalsModule`](../modules/ApprovalsModule.html) which includes the components on the corresponding side sheet. -## 5. Request History +## Request history -All requests visible for the current user are displayed by the [`RequestHistoryComponent`](../components/RequestHistoryComponent.html). The actions that the user can perform on these requests are implemented in the [`RequestActionService`](../injectables/RequestActionService.html). +All requests visible for the current user are displayed by the [`RequestHistoryComponent`](../components/RequestHistoryComponent.html). The actions that the user can perform for these requests are implemented in the [`RequestActionService`](../injectables/RequestActionService.html). -## 6. Archived Requests +## Archived requests -Archived requests are requests that have been offloaded to the history database. These can be viewed using the [`ArchivedRequestsComponent`](../components/ArchivedRequestsComponent.html). +Archived requests are requests that have been moved to the history database. These can be viewed using the [`ArchivedRequestsComponent`](../components/ArchivedRequestsComponent.html). -## 7. Editors for Items +## Editors for items -### 7.1. Product Bundles +### Product bundles Product bundles can be edited using the [`ItshopPatternComponent`](../components/ItshopPatternComponent.html), defined in the [`ItshopPatternModule`](../modules/ItshopPatternModule.html). -### 7.2. Service Categories +### Service categories -The [`ServiceCategoriesModule`](../modules/ServiceCategoriesModule.html) contains the [`ServiceCategoriesComponent`](../components/ServiceCategoriesComponent.html). This component uses a [`DataTreeWrapperComponent`](../../qbm/components/DataTreeWrapperComponent.html) to show the service category structure of the IT shop. +The [`ServiceCategoriesModule`](../modules/ServiceCategoriesModule.html) contains the [`ServiceCategoriesComponent`](../components/ServiceCategoriesComponent.html). This component uses a [`DataTreeWrapperComponent`](../../qbm/components/DataTreeWrapperComponent.html) to show the service category structure of the IT Shop. -### 7.3. Service Items +### Service items -The service item functionality is part of the [`ServiceItemsEditModule`](../modules/ServiceItemsEditModule.html). The entry point for this component is the ['ServiceItemsEditComponent'](../components/ServiceItemsEditComponent.html) which lists all available service items. Clicking on an item opens a [`ServiceItemsEditSidesheetComponent`](../components/ServiceItemsEditSidesheetComponent.html). +The service item functionality is part of the [`ServiceItemsEditModule`](../modules/ServiceItemsEditModule.html). The entry point for this component is the [`ServiceItemsEditComponent`](../components/ServiceItemsEditComponent.html) which lists all available service items. Clicking on an item opens a [`ServiceItemsEditSidesheetComponent`](../components/ServiceItemsEditSidesheetComponent.html). -### 7.4. Workflow Editor +### Approval workflow editor -The workflow editor is part of the [`ApprovalWorkFlowModule`](../modules/ApprovalWorkFlowModule.html). The entry point is the [`ApprovalWorkflowHomeComponent`](../components/ApprovalWorkflowHomeComponent.html). +The approval workflow editor is part of the [`ApprovalWorkFlowModule`](../modules/ApprovalWorkFlowModule.html). The entry point is the [`ApprovalWorkflowHomeComponent`](../components/ApprovalWorkflowHomeComponent.html). The editing functionality is implemented in the [`ApprovalWorkflowEditComponent`](../components/ApprovalWorkflowEditComponent.html), \ No newline at end of file diff --git a/imxweb/projects/qer/additionalDocumentation/other.md b/imxweb/projects/qer/additionalDocumentation/other.md index 73d3cdc80..4dc91b754 100644 --- a/imxweb/projects/qer/additionalDocumentation/other.md +++ b/imxweb/projects/qer/additionalDocumentation/other.md @@ -1,33 +1,33 @@ # Other components and services -This page describes the most important components in the `qer` library. +In this section you can find information about the most important components in the `qer` library. -## 1. Data Explorer \ My Responsibilities +## Data Explorer\My responsibilities -The [`DataExplorerViewComponent`](../components/DataExplorerViewComponent.html) and the [`MyResponsibilitiesViewComponent`](../components/MyResponsibilitiesViewComponent.html) are used to display the main component for the _Data administration > _Data Explorer_ and the _Responsibilities_ > _My Responsibilities_ pages. It shows a menu item for each type registered in the [`DataExplorerRegistryService`](../injectables/DataExplorerRegistryService.html) or the [`MyResponsibilitiesRegistryService`](../injectables/MyResponsibilitiesRegistryService.html) respectively. +The [`DataExplorerViewComponent`](../components/DataExplorerViewComponent.html) and the [`MyResponsibilitiesViewComponent`](../components/MyResponsibilitiesViewComponent.html) are used to display the main component for the _Data administration_ > _Data Explorer_ and the _Responsibilities_ > _My Responsibilities_ pages. It shows a menu item for each object type registered in the [`DataExplorerRegistryService`](../injectables/DataExplorerRegistryService.html) or the [`MyResponsibilitiesRegistryService`](../injectables/MyResponsibilitiesRegistryService.html) respectively. -## 2. Delegation +## Delegation The [`DelegationComponent`](../components/DelegationComponent.html) implements the delegation functionality. The component uses a `MatStepper` to navigate through the steps. -## 3. Related Applications +## Related applications -The [`RelatedApplicationsComponent`](../components/RelatedApplicationsComponent.html) adds links to other sites to the navigation. These links are configured in the database table `RelatedApplication`. +The [`RelatedApplicationsComponent`](../components/RelatedApplicationsComponent.html) adds links to other websites to the navigation. These links are configured in the database table `RelatedApplication`. -## 4. Risk Index +## Risk index The [`RiskConfigComponent`](../components/RiskConfigComponent.html) displays a table of all risk index functions. They can be edited by using the [`RiskConfigSidesheetComponent`](../components/RiskConfigSidesheetComponent.html). -## 5. Source Detective +## Source detective The [`SourceDetectiveComponent`](../components/SourceDetectiveComponent.html) shows the assignment analysis of an object. It contains a tree with branches for every assignment. -## 6. Statistics -The [`StatisticsModule`](../modules/StatisticsModule.html) contains the components for the Statistics view. The entry point is the [`StatisticsHomePageComponent`](../components/StatisticsHomePageComponent.html). Statistics are organized into *areas* which are displayed in a navigation tree. The user can view the statistics for each area. Clicking on a statistic opens a [`ChartsSidesheetComponent`](../components/ChartsSidesheetComponent.html) or a [`HeatmapSidesheetComponent`](../components/HeatmapSidesheetComponent.html) for a heatmap statistic. +## Statistics +The [`StatisticsModule`](../modules/StatisticsModule.html) contains the components for the _Statistics_ page. The entry point is the [`StatisticsHomePageComponent`](../components/StatisticsHomePageComponent.html). Statistics are organized into *areas* which are displayed in a navigation tree. The user can view the statistics for each area. Clicking on a statistic opens a [`ChartsSidesheetComponent`](../components/ChartsSidesheetComponent.html) or a [`HeatmapSidesheetComponent`](../components/HeatmapSidesheetComponent.html) for a heatmap statistic. -## 7. Terms of Use +## Terms of use -The [`TermsOfUseListComponent`](../components/TermsOfUseListComponent.html) handles the user flow to accept the terms of use for a service item. It also includes step-up 2FA if configured. +The [`TermsOfUseListComponent`](../components/TermsOfUseListComponent.html) handles the user flow to accept the terms of use for a product. It also includes step-up 2FA if configured. -## 8. User Process +## User process The [`UserProcessComponent`](../components/UserProcessComponent.html) displays a list of all the processes associated with the current user. diff --git a/imxweb/projects/qer/additionalDocumentation/roles.md b/imxweb/projects/qer/additionalDocumentation/roles.md index 25633ef1b..3c9583927 100644 --- a/imxweb/projects/qer/additionalDocumentation/roles.md +++ b/imxweb/projects/qer/additionalDocumentation/roles.md @@ -1,14 +1,14 @@ -# Role Management +# Role management -The [role management module](../modules/RoleManangementModule.html) extends the Data Explorer with components for the following object types. +The [role management module](../modules/RoleManangementModule.html) extends the Data Explorer with components for the following object types: - departments - cost centers - locations - application roles - resources -- multi requestable / unsubscribeable resources -- multi request resources +- multi requestable/unsubscribable resources +- multi-request resources - assignment resources The UI uses the [`RolesOverviewComponent`](../components/RolesOverviewComponent.html) for roles and the [`ResourcesComponent`](../components/ResourcesComponent.html) for resources. diff --git a/imxweb/projects/qer/karma.conf.js b/imxweb/projects/qer/karma.conf.js index 211193c9d..3e53a3ac8 100644 --- a/imxweb/projects/qer/karma.conf.js +++ b/imxweb/projects/qer/karma.conf.js @@ -15,7 +15,7 @@ module.exports = function (config) { require('karma-junit-reporter'), ], client: { - clearContext: false // leave Jasmine Spec Runner output visible in browser + clearContext: false, // leave Jasmine Spec Runner output visible in browser }, coverageIstanbulReporter: { dir: require('path').join(__dirname, 'results'), @@ -23,7 +23,7 @@ module.exports = function (config) { fixWebpackSourcePaths: true, 'report-config': { html: { - subdir: 'coverage-html' + subdir: 'coverage-html', }, }, thresholds: { @@ -40,13 +40,14 @@ module.exports = function (config) { port: 9876, captureTimeout: 210000, browserDisconnectTolerance: 3, - browserDisconnectTimeout : 210000, - browserNoActivityTimeout : 210000, + browserDisconnectTimeout: 210000, + browserNoActivityTimeout: 210000, colors: true, logLevel: config.LOG_INFO, autoWatch: true, browsers: ['Chrome'], singleRun: false, - restartOnFileChange: true + failOnEmptyTestSuite: false, + restartOnFileChange: true, }); }; diff --git a/imxweb/projects/qer/ng-package.json b/imxweb/projects/qer/ng-package.json index 63a6e5dbc..06284498a 100644 --- a/imxweb/projects/qer/ng-package.json +++ b/imxweb/projects/qer/ng-package.json @@ -3,7 +3,7 @@ "dest": "../../dist/qer", "lib": { "entryFile": "src/public_api.ts", - "styleIncludePaths": ["../../shared/assets"] + "styleIncludePaths": ["../../shared/scss"] }, "deleteDestPath": false } diff --git a/imxweb/projects/qer/package.json b/imxweb/projects/qer/package.json index 831c0fbdb..86129c1c9 100644 --- a/imxweb/projects/qer/package.json +++ b/imxweb/projects/qer/package.json @@ -1,12 +1,9 @@ { "name": "qer", - "version": "9.2.1", + "version": "9.3.0", "private": true, - "dependencies": { - - }, - "peerDependencies": { - }, + "dependencies": {}, + "peerDependencies": {}, "bundledDependencies": [ "imx-api-qer" ] diff --git a/imxweb/projects/qer/project.json b/imxweb/projects/qer/project.json new file mode 100644 index 000000000..cbc81a10c --- /dev/null +++ b/imxweb/projects/qer/project.json @@ -0,0 +1,61 @@ +{ + "$schema": "../../node_modules/nx/schemas/project-schema.json", + "name": "qer", + "sourceRoot": "projects/qer/src", + "implicitDependencies": ["qbm"], + "projectType": "library", + "prefix": "imx", + "generators": { + "@schematics/angular:component": { + "style": "scss" + } + }, + "targets": { + "build": { + "executor": "@angular-devkit/build-angular:ng-packagr", + "options": { + "tsConfig": "projects/qer/tsconfig.lib.json", + "project": "projects/qer/ng-package.json" + }, + "configurations": { + "production": { + "tsConfig": "projects/qer/tsconfig.lib.prod.json" + }, + "development": { + "tsConfig": "projects/qer/tsconfig.lib.json" + }, + "remote-dev": { + "tsConfig": "projects/qer/tsconfig.lib.json" + }, + "remote-qs": { + "tsConfig": "projects/qer/tsconfig.lib.json" + } + }, + "outputs": ["{workspaceRoot}/dist/qer"] + }, + "test": { + "executor": "@angular-devkit/build-angular:karma", + "options": { + "stylePreprocessorOptions": { + "includePaths": [ + "./shared/assets", + "./shared/scss", + "./node_modules", + "./node_modules/@elemental-ui/cadence-icon", + "./node_modules/@elemental-ui/core" + ] + }, + "main": "projects/qer/src/test.ts", + "tsConfig": "projects/qer/tsconfig.spec.json", + "karmaConfig": "projects/qer/karma.conf.js" + } + }, + "lint": { + "executor": "@angular-devkit/build-angular:eslint", + "options": { + "tsConfig": ["projects/qer/tsconfig.lib.json", "projects/qer/tsconfig.spec.json"], + "exclude": ["**/node_modules/**", "**/*.spec.ts", "**/*.json"] + } + } + } +} diff --git a/imxweb/projects/qer/src/default-mocks.spec.ts b/imxweb/projects/qer/src/default-mocks.spec.ts index 6d2d0e5f1..fbcbe85bb 100644 --- a/imxweb/projects/qer/src/default-mocks.spec.ts +++ b/imxweb/projects/qer/src/default-mocks.spec.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -28,7 +28,7 @@ import { of, Subject } from 'rxjs'; import { ngMocks } from 'ng-mocks'; import { EuiSidesheetService } from '@elemental-ui/core'; import { TranslateService } from '@ngx-translate/core'; -import { ISessionState,AuthenticationService,RouteGuardService } from 'qbm'; +import { ISessionState, AuthenticationService, RouteGuardService } from 'qbm'; export class QerDefaultMocks { public static readonly afterClosedSubject = new Subject(); diff --git a/imxweb/projects/qer/src/lib/about/portal-about.service.ts b/imxweb/projects/qer/src/lib/about/portal-about.service.ts new file mode 100644 index 000000000..d8de2d2e6 --- /dev/null +++ b/imxweb/projects/qer/src/lib/about/portal-about.service.ts @@ -0,0 +1,55 @@ +/* + * ONE IDENTITY LLC. PROPRIETARY INFORMATION + * + * This software is confidential. One Identity, LLC. or one of its affiliates or + * subsidiaries, has supplied this software to you under terms of a + * license agreement, nondisclosure agreement or both. + * + * You may not copy, disclose, or use this software except in accordance with + * those terms. + * + * + * Copyright 2024 One Identity LLC. + * ALL RIGHTS RESERVED. + * + * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR + * WARRANTIES ABOUT THE SUITABILITY OF THE SOFTWARE, + * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED + * TO THE IMPLIED WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE, OR + * NON-INFRINGEMENT. ONE IDENTITY LLC. SHALL NOT BE + * LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE + * AS A RESULT OF USING, MODIFYING OR DISTRIBUTING + * THIS SOFTWARE OR ITS DERIVATIVES. + * + */ + +import { Injectable } from '@angular/core'; +import { PortalSysteminfoThirdparty } from '@imx-modules/imx-api-qer'; +import { CollectionLoadParameters, EntitySchema, TypedEntityCollectionData } from '@imx-modules/imx-qbm-dbts'; +import { AboutService, ApiClientService } from 'qbm'; +import { QerApiService } from '../qer-api-client.service'; + +@Injectable({ + providedIn: 'root', +}) +export class PortalAboutService extends AboutService { + constructor( + private readonly apiClient: QerApiService, + private apiProvider: ApiClientService, + ) { + super(); + } + + get EntitySchema(): EntitySchema { + return this.apiClient.typedClient.PortalSysteminfoThirdparty.GetSchema(); + } + + async get(parameters?: CollectionLoadParameters): Promise | undefined> { + return this.apiProvider.request(() => + this.apiClient.typedClient.PortalSysteminfoThirdparty.Get(parameters, { + signal: this.abortController.signal, + }), + ); + } +} diff --git a/imxweb/projects/qer/src/lib/addressbook/addressbook-detail/addressbook-detail.component.html b/imxweb/projects/qer/src/lib/addressbook/addressbook-detail/addressbook-detail.component.html index dded405e8..068ad0955 100644 --- a/imxweb/projects/qer/src/lib/addressbook/addressbook-detail/addressbook-detail.component.html +++ b/imxweb/projects/qer/src/lib/addressbook/addressbook-detail/addressbook-detail.component.html @@ -14,4 +14,3 @@
    - diff --git a/imxweb/projects/qer/src/lib/addressbook/addressbook-detail/addressbook-detail.component.scss b/imxweb/projects/qer/src/lib/addressbook/addressbook-detail/addressbook-detail.component.scss deleted file mode 100644 index 19f31db09..000000000 --- a/imxweb/projects/qer/src/lib/addressbook/addressbook-detail/addressbook-detail.component.scss +++ /dev/null @@ -1,8 +0,0 @@ -@import '@elemental-ui/core/src/styles/_palette.scss'; - -:host { - .eui-sidesheet-content { - display: flex; - flex-direction: column; - } -} diff --git a/imxweb/projects/qer/src/lib/addressbook/addressbook-detail/addressbook-detail.component.ts b/imxweb/projects/qer/src/lib/addressbook/addressbook-detail/addressbook-detail.component.ts index 53f11d5f4..e8a3a50db 100644 --- a/imxweb/projects/qer/src/lib/addressbook/addressbook-detail/addressbook-detail.component.ts +++ b/imxweb/projects/qer/src/lib/addressbook/addressbook-detail/addressbook-detail.component.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -26,7 +26,7 @@ import { Component, Inject, OnInit } from '@angular/core'; import { Router } from '@angular/router'; -import { EuiSidesheetRef, EUI_SIDESHEET_DATA } from '@elemental-ui/core'; +import { EUI_SIDESHEET_DATA, EuiSidesheetRef } from '@elemental-ui/core'; import { ProjectConfigurationService } from '../../project-configuration/project-configuration.service'; import { AddressbookDetail } from './addressbook-detail.interface'; @@ -34,19 +34,18 @@ import { AddressbookDetail } from './addressbook-detail.interface'; @Component({ selector: 'imx-addressbook-detail', templateUrl: './addressbook-detail.component.html', - styleUrls: ['./addressbook-detail.component.scss'] }) export class AddressbookDetailComponent implements OnInit { constructor( @Inject(EUI_SIDESHEET_DATA) public readonly data: AddressbookDetail, private readonly qerConfig: ProjectConfigurationService, public readonly sidesheetRef: EuiSidesheetRef, - public readonly router: Router - ) { } + public readonly router: Router, + ) {} public isShowOrgChart: boolean; ngOnInit(): void { - this.qerConfig.getConfig().then(config => this.isShowOrgChart = config.PersonConfig.ShowOrgChart); + this.qerConfig.getConfig().then((config) => (this.isShowOrgChart = config.PersonConfig?.ShowOrgChart ?? false)); } } diff --git a/imxweb/projects/qer/src/lib/addressbook/addressbook-detail/addressbook-detail.interface.ts b/imxweb/projects/qer/src/lib/addressbook/addressbook-detail/addressbook-detail.interface.ts index 969f46c63..15f2a70f7 100644 --- a/imxweb/projects/qer/src/lib/addressbook/addressbook-detail/addressbook-detail.interface.ts +++ b/imxweb/projects/qer/src/lib/addressbook/addressbook-detail/addressbook-detail.interface.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -24,7 +24,7 @@ * */ -import { IEntityColumn } from 'imx-qbm-dbts'; +import { IEntityColumn } from '@imx-modules/imx-qbm-dbts'; export interface AddressbookDetail { columns: IEntityColumn[]; diff --git a/imxweb/projects/qer/src/lib/addressbook/addressbook.component.html b/imxweb/projects/qer/src/lib/addressbook/addressbook.component.html index 4d3819ac9..3db28186c 100644 --- a/imxweb/projects/qer/src/lib/addressbook/addressbook.component.html +++ b/imxweb/projects/qer/src/lib/addressbook/addressbook.component.html @@ -1,31 +1,15 @@ -

    - {{ '#LDS#Heading Address Book' | translate }} - -

    - - - - -
    - - -
    - +
    +

    + {{ '#LDS#Heading Address Book' | translate }} + +

    + +
    + + + diff --git a/imxweb/projects/qer/src/lib/addressbook/addressbook.component.scss b/imxweb/projects/qer/src/lib/addressbook/addressbook.component.scss index 9f9a7d75f..5e346edf2 100644 --- a/imxweb/projects/qer/src/lib/addressbook/addressbook.component.scss +++ b/imxweb/projects/qer/src/lib/addressbook/addressbook.component.scss @@ -1,13 +1,8 @@ -@import '../../../../../shared/scss/common-table.scss'; +@import 'base/mixins'; + :host { - @include imx-flex-fill-control-hidden-overflow(); + @include flex-column-container-fill(); height: 100%; - - .mat-card { - @include imx-flex-fill-control-hidden-overflow(); - margin-right: 3px; - margin-bottom: 3px; - } } .imx-addressbook-table { diff --git a/imxweb/projects/qer/src/lib/addressbook/addressbook.component.ts b/imxweb/projects/qer/src/lib/addressbook/addressbook.component.ts index c94b32d0f..56f0447b4 100644 --- a/imxweb/projects/qer/src/lib/addressbook/addressbook.component.ts +++ b/imxweb/projects/qer/src/lib/addressbook/addressbook.component.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -25,15 +25,31 @@ */ import { Component, OnInit } from '@angular/core'; -import { OverlayRef } from '@angular/cdk/overlay'; import { EuiLoadingService, EuiSidesheetConfig, EuiSidesheetService } from '@elemental-ui/core'; import { TranslateService } from '@ngx-translate/core'; -import { DataSourceToolbarSettings, ClassloggerService, SettingsService, DataSourceWrapper, DataTableGroupedData, BusyService } from 'qbm'; -import { CollectionLoadParameters } from 'imx-qbm-dbts'; -import { PersonConfig, PortalPersonAll } from 'imx-api-qer'; - +import { PersonConfig, PortalPersonAll, ViewConfigData } from '@imx-modules/imx-api-qer'; +import { + CollectionLoadParameters, + DataModel, + DisplayColumns, + EntitySchema, + IClientProperty, + TypedEntityCollectionData, +} from '@imx-modules/imx-qbm-dbts'; +import { + BusyService, + ClassloggerService, + DataSourceToolbarViewConfig, + DataViewInitParameters, + DataViewSource, + SettingsService, + calculateSidesheetWidth, +} from 'qbm'; + +import { PersonService } from '../person/person.service'; import { ProjectConfigurationService } from '../project-configuration/project-configuration.service'; +import { ViewConfigService } from '../view-config/view-config.service'; import { AddressbookDetailComponent } from './addressbook-detail/addressbook-detail.component'; import { AddressbookService } from './addressbook.service'; @@ -44,18 +60,17 @@ import { AddressbookService } from './addressbook.service'; selector: 'imx-addressbook', templateUrl: './addressbook.component.html', styleUrls: ['./addressbook.component.scss'], + providers: [DataViewSource], }) export class AddressbookComponent implements OnInit { - /** - * Settings needed by the DataSourceToolbarComponent - */ - public dstSettings: DataSourceToolbarSettings; - - public groupData: { [key: string]: DataTableGroupedData } = {}; + public displayedColumns: IClientProperty[]; + public dataModel: DataModel; + public entitySchema: EntitySchema; public busyService = new BusyService(); - private personConfig: PersonConfig; - private dstWrapper: DataSourceWrapper; + private viewConfig: DataSourceToolbarViewConfig; + private personConfig: PersonConfig | undefined; + private viewConfigPath = 'person/all'; constructor( private readonly euiBusyService: EuiLoadingService, @@ -64,7 +79,10 @@ export class AddressbookComponent implements OnInit { private readonly settingsService: SettingsService, private readonly addressbookService: AddressbookService, private readonly sidesheet: EuiSidesheetService, - private readonly translateService: TranslateService + private readonly translateService: TranslateService, + private readonly personService: PersonService, + private readonly viewConfigService: ViewConfigService, + public dataSource: DataViewSource, ) {} public async ngOnInit(): Promise { @@ -72,41 +90,29 @@ export class AddressbookComponent implements OnInit { try { this.personConfig = (await this.configService.getConfig()).PersonConfig; - - this.dstWrapper = await this.addressbookService.createDataSourceWrapper( - this.personConfig.VI_MyData_WhitePages_ResultAttributes, - 'address-book' - ); - - this.dstSettings = await this.dstWrapper.getDstSettings({ PageSize: this.settingsService.DefaultPageSize, StartIndex: 0 }); - } finally { - isBusy.endBusy(); - } - } - - /** - * Occurs when the navigation state has changed - e.g. users clicks on the next page button. - * - */ - public async onNavigationStateChanged(newState: CollectionLoadParameters): Promise { - const isBusy = this.busyService.beginBusy(); - - try { - this.dstSettings = await this.dstWrapper.getDstSettings(newState); - } finally { - isBusy.endBusy(); - } - } - - public async onGroupingChange(groupKey: string): Promise { - const isBusy = this.busyService.beginBusy(); - - try { - const groupData = this.groupData[groupKey]; - groupData.settings = await this.dstWrapper.getGroupDstSettings(groupData.navigationState); - groupData.settings.dataModel = this.dstSettings.dataModel; - groupData.settings.entitySchema = this.dstSettings.entitySchema; - groupData.data = groupData.settings.dataSource; + this.dataModel = await this.personService.getDataModel(); + this.entitySchema = this.personService.schemaPersonAll; + this.displayedColumns = [ + this.entitySchema.Columns[DisplayColumns.DISPLAY_PROPERTYNAME], + ...(this.personConfig?.VI_MyData_WhitePages_ResultAttributes ?? []) + .filter((columnName) => this.entitySchema.Columns[columnName]) + .map((columnName) => this.entitySchema.Columns[columnName]), + ]; + this.viewConfig = await this.viewConfigService.getInitialDSTExtension(this.dataModel, this.viewConfigPath); + const dataViewInitParameters: DataViewInitParameters = { + execute: (params: CollectionLoadParameters, signal: AbortSignal): Promise> => + this.personService.getAll(params, signal), + schema: this.entitySchema, + columnsToDisplay: this.displayedColumns, + dataModel: this.dataModel, + highlightEntity: (entity: PortalPersonAll) => { + this.onHighlightedEntityChanged(entity); + }, + groupExecute: (columnName: string, parameters: CollectionLoadParameters, signal: AbortSignal) => + this.personService.getGroupInfo({ ...parameters, by: columnName }), + viewConfig: this.viewConfig, + }; + this.dataSource.init(dataViewInitParameters); } finally { isBusy.endBusy(); } @@ -121,34 +127,37 @@ export class AddressbookComponent implements OnInit { this.logger.debug(this, `Selected person changed`); this.logger.trace(this, 'New selected person', personAll); - let overlayRef: OverlayRef; - setTimeout(() => (overlayRef = this.euiBusyService.show())); + if (this.euiBusyService.overlayRefs.length === 0) { + this.euiBusyService.show(); + } let config: EuiSidesheetConfig; try { config = { - title: await this.translateService.get('#LDS#Heading View Identity Details').toPromise(), + title: this.translateService.instant('#LDS#Heading View Identity Details'), subTitle: personAll.GetEntity().GetDisplay(), padding: '0', - width: 'max(600px, 60%)', + width: calculateSidesheetWidth(), testId: 'addressbook-view-identity-details', - data: await this.addressbookService.getDetail(personAll, this.personConfig.VI_MyData_WhitePages_DetailAttributes), + data: await this.addressbookService.getDetail(personAll, this.personConfig?.VI_MyData_WhitePages_DetailAttributes ?? []), }; } finally { - setTimeout(() => this.euiBusyService.hide(overlayRef)); + this.euiBusyService.hide(); } this.sidesheet.open(AddressbookDetailComponent, config); } - public async onSearch(search: string): Promise { - const isBusy = this.busyService.beginBusy(); + public async updateConfig(config: ViewConfigData): Promise { + await this.viewConfigService.putViewConfig(config); + this.viewConfig = await this.viewConfigService.getDSTExtensionChanges(this.viewConfigPath); + this.dataSource.viewConfig.set(this.viewConfig); + } - try { - this.dstSettings = await this.dstWrapper.getDstSettings({ StartIndex: 0, search }); - } finally { - isBusy.endBusy(); - } + public async deleteConfigById(id: string): Promise { + await this.viewConfigService.deleteViewConfig(id); + this.viewConfig = await this.viewConfigService.getDSTExtensionChanges(this.viewConfigPath); + this.dataSource.viewConfig.set(this.viewConfig); } } diff --git a/imxweb/projects/qer/src/lib/addressbook/addressbook.module.ts b/imxweb/projects/qer/src/lib/addressbook/addressbook.module.ts index 2d146203a..9637c7bba 100644 --- a/imxweb/projects/qer/src/lib/addressbook/addressbook.module.ts +++ b/imxweb/projects/qer/src/lib/addressbook/addressbook.module.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -24,21 +24,30 @@ * */ -import { NgModule } from '@angular/core'; import { CommonModule } from '@angular/common'; +import { NgModule } from '@angular/core'; import { FormsModule, ReactiveFormsModule } from '@angular/forms'; import { MatButtonModule } from '@angular/material/button'; import { MatCardModule } from '@angular/material/card'; +import { MatExpansionModule } from '@angular/material/expansion'; import { RouterModule, Routes } from '@angular/router'; import { EuiCoreModule } from '@elemental-ui/core'; -import { MatExpansionModule } from '@angular/material/expansion'; import { TranslateModule } from '@ngx-translate/core'; -import { DataSourceToolbarModule, DataTableModule, CdrModule, RouteGuardService, HELP_CONTEXTUAL, HelpContextualModule } from 'qbm'; +import { + CdrModule, + DataSourceToolbarModule, + DataTableModule, + DataViewModule, + HELP_CONTEXTUAL, + HelpContextualModule, + RouteGuardService, +} from 'qbm'; -import { AddressbookComponent } from './addressbook.component'; -import { AddressbookDetailComponent } from './addressbook-detail/addressbook-detail.component'; +import { MatTableModule } from '@angular/material/table'; import { OrgChartModule } from '../org-chart/org-chart.module'; +import { AddressbookDetailComponent } from './addressbook-detail/addressbook-detail.component'; +import { AddressbookComponent } from './addressbook.component'; const routes: Routes = [ { @@ -46,9 +55,9 @@ const routes: Routes = [ component: AddressbookComponent, canActivate: [RouteGuardService], resolve: [RouteGuardService], - data:{ - contextId: HELP_CONTEXTUAL.Addressbook - } + data: { + contextId: HELP_CONTEXTUAL.Addressbook, + }, }, ]; @@ -69,6 +78,8 @@ const routes: Routes = [ OrgChartModule, ReactiveFormsModule, HelpContextualModule, + DataViewModule, + MatTableModule, ], exports: [AddressbookComponent], }) diff --git a/imxweb/projects/qer/src/lib/addressbook/addressbook.service.ts b/imxweb/projects/qer/src/lib/addressbook/addressbook.service.ts index f506a97ed..c9cd9eb64 100644 --- a/imxweb/projects/qer/src/lib/addressbook/addressbook.service.ts +++ b/imxweb/projects/qer/src/lib/addressbook/addressbook.service.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -26,41 +26,17 @@ import { Injectable } from '@angular/core'; -import { PortalPersonAll } from 'imx-api-qer'; -import { DisplayColumns } from 'imx-qbm-dbts'; -import { DataSourceWrapper } from 'qbm'; +import { TypedEntity } from '@imx-modules/imx-qbm-dbts'; import { PersonService } from '../person/person.service'; import { AddressbookDetail } from './addressbook-detail/addressbook-detail.interface'; @Injectable({ - providedIn: 'root' + providedIn: 'root', }) export class AddressbookService { - constructor(private readonly personService: PersonService) { } + constructor(private readonly personService: PersonService) {} - public async createDataSourceWrapper(columnNames: string[], identifier?: string): Promise { - - const entitySchema = this.personService.schemaPersonAll; - - const displayedColumns = columnNames - .filter(columnName => entitySchema.Columns[columnName]) - .map(columnName => entitySchema.Columns[columnName]); - displayedColumns.unshift(entitySchema.Columns[DisplayColumns.DISPLAY_PROPERTYNAME]); - - return new DataSourceWrapper( - state => this.personService.getAll(state), - displayedColumns, - entitySchema, - { - dataModel: await this.personService.getDataModel(), - getGroupInfo: parameters => this.personService.getGroupInfo(parameters), - groupingFilterOptions: ['withmanager', 'orphaned'] - }, - identifier - ); - } - - public async getDetail(personAll: PortalPersonAll, columnNames: string[]): Promise { + public async getDetail(personAll: TypedEntity, columnNames: string[]): Promise { const personUid = personAll.GetEntity().GetKeys()[0]; const personDetailEntity = (await this.personService.get(personUid)).Data[0].GetEntity(); @@ -69,9 +45,9 @@ export class AddressbookService { return { columns: columnNames - .filter(columnName => entitySchema.Columns[columnName]) - .map(columnName => personDetailEntity.GetColumn(columnName)), - personUid + .filter((columnName) => entitySchema.Columns[columnName]) + .map((columnName) => personDetailEntity.GetColumn(columnName)), + personUid, }; } } diff --git a/imxweb/projects/qer/src/lib/admin/authentication-factors.interface.ts b/imxweb/projects/qer/src/lib/admin/authentication-factors.interface.ts index 08cd58bee..8884e7005 100644 --- a/imxweb/projects/qer/src/lib/admin/authentication-factors.interface.ts +++ b/imxweb/projects/qer/src/lib/admin/authentication-factors.interface.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR diff --git a/imxweb/projects/qer/src/lib/admin/feature-config.service.ts b/imxweb/projects/qer/src/lib/admin/feature-config.service.ts index 83ac81276..14d4eca40 100644 --- a/imxweb/projects/qer/src/lib/admin/feature-config.service.ts +++ b/imxweb/projects/qer/src/lib/admin/feature-config.service.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -25,17 +25,15 @@ */ import { Injectable } from '@angular/core'; -import { FeatureConfig } from 'imx-api-qer'; -import { MethodDescriptor, TimeZoneInfo } from 'imx-qbm-dbts'; +import { FeatureConfig } from '@imx-modules/imx-api-qer'; +import { MethodDescriptor, TimeZoneInfo } from '@imx-modules/imx-qbm-dbts'; import { AppConfigService } from 'qbm'; @Injectable({ - providedIn: 'root' + providedIn: 'root', }) export class FeatureConfigService { - - constructor(private readonly config: AppConfigService) { } - + constructor(private readonly config: AppConfigService) {} public async getFeatureConfig(): Promise { const data = await this.config.apiClient.processRequest(this.getFeatureConfigDescriptor()); @@ -49,7 +47,7 @@ export class FeatureConfigService { parameters, method: 'GET', headers: { - 'imx-timezone': TimeZoneInfo.get() + 'imx-timezone': TimeZoneInfo.get(), }, credentials: 'include', observe: 'response', diff --git a/imxweb/projects/qer/src/lib/admin/qer-permissions-helper.ts b/imxweb/projects/qer/src/lib/admin/qer-permissions-helper.ts index 3950d2a97..67d42b6dc 100644 --- a/imxweb/projects/qer/src/lib/admin/qer-permissions-helper.ts +++ b/imxweb/projects/qer/src/lib/admin/qer-permissions-helper.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -64,15 +64,38 @@ export function isStructStatistics(features: string[]): boolean { export function isCancelPwO(features: string[]): boolean { return features.find((item) => item === 'QER_CancelPwO') != null; } -export function isPasswordHelpdesk(features: string[]): boolean { - return features.find((item) => item === 'Portal_UI_PasswordHelpdesk') != null; +export function isPolicyStatistics(features: string[]): boolean { + return features.find((item) => item === 'Portal_UI_PolicyStatistics') != null; } -export function isStatistics(features: string[]): boolean { +export function isPAGStatistics(features: string[]): boolean { + return features.find((item) => item === 'Portal_UI_PAGStatistics') != null; +} +export function isQERPolicyStatistics(features: string[]): boolean { + return features.find((item) => item === 'Portal_UI_QERPolicyStatistics') != null; +} +export function isPersonStatistics(features: string[]): boolean { + return features.find((item) => item === 'Portal_UI_PersonStatistics') != null; +} + +export function isTSBStatistics(features: string[]): boolean { return features.find((item) => item === 'Portal_UI_TSBStatistics') != null; } +export function isStatistics(features: string[]): boolean { + return ( + isRoleStatistics(features) || + isRuleAdmin(features) || + isShopStatistics(features) || + isStructStatistics(features) || + isPolicyStatistics(features) || + isPAGStatistics(features) || + isQERPolicyStatistics(features) || + isPersonStatistics(features) || + isTSBStatistics(features) + ); +} +export function isHyperviewNavigation(features: string[]): boolean { + return features.find((item) => item === 'Portal_HyperView_Navigation') != null; +} export function isAuditor(groups: string[]): boolean { return groups.find((item) => item.toUpperCase() === 'VI_4_AUDITING_AUDITOR') != null; } -export function isTsbNameSpaceAdminBase(groups: string[]): boolean { - return groups.find((item) => item.toUpperCase() === 'TSB_4_NAMESPACEADMIN_BASE') != null; -} diff --git a/imxweb/projects/qer/src/lib/admin/qer-permissions.service.ts b/imxweb/projects/qer/src/lib/admin/qer-permissions.service.ts index 5df25ee12..6243d881e 100644 --- a/imxweb/projects/qer/src/lib/admin/qer-permissions.service.ts +++ b/imxweb/projects/qer/src/lib/admin/qer-permissions.service.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -28,8 +28,10 @@ import { Injectable } from '@angular/core'; import { UserModelService } from '../user/user-model.service'; import { + hasFeatures, + isAuditor, isCancelPwO, - isPasswordHelpdesk, + isHyperviewNavigation, isPersonAdmin, isPersonManager, isResourceAdmin, @@ -38,12 +40,9 @@ import { isRuleAdmin, isShopAdmin, isShopStatistics, + isStatistics, isStructAdmin, isStructStatistics, - hasFeatures, - isAuditor, - isStatistics, - isTsbNameSpaceAdminBase, } from './qer-permissions-helper'; @Injectable({ @@ -53,51 +52,48 @@ export class QerPermissionsService { constructor(private readonly userService: UserModelService) {} public async isPersonAdmin(): Promise { - return isPersonAdmin((await this.userService.getFeatures()).Features); + return isPersonAdmin((await this.userService.getFeatures()).Features || []); } public async isPersonManager(): Promise { - return isPersonManager((await this.userService.getFeatures()).Features); + return isPersonManager((await this.userService.getFeatures()).Features || []); } public async isStructAdmin(): Promise { - return isStructAdmin((await this.userService.getFeatures()).Features); + return isStructAdmin((await this.userService.getFeatures()).Features || []); } public async isShopAdmin(): Promise { - return isShopAdmin((await this.userService.getFeatures()).Features); + return isShopAdmin((await this.userService.getFeatures()).Features || []); } public async isRuleAdmin(): Promise { - return isRuleAdmin((await this.userService.getFeatures()).Features); + return isRuleAdmin((await this.userService.getFeatures()).Features || []); } public async isCancelPwO(): Promise { - return isCancelPwO((await this.userService.getFeatures()).Features); + return isCancelPwO((await this.userService.getFeatures()).Features || []); } public async isResourceAdmin(): Promise { - return isResourceAdmin((await this.userService.getFeatures()).Features); + return isResourceAdmin((await this.userService.getFeatures()).Features || []); } public async isRoleAdmin(): Promise { - return isRoleAdmin((await this.userService.getFeatures()).Features); + return isRoleAdmin((await this.userService.getFeatures()).Features || []); } public async hasFeatures(features: string[]): Promise { - return hasFeatures((await this.userService.getFeatures()).Features, features); + return hasFeatures((await this.userService.getFeatures()).Features || [], features); } public async isRoleStatistics(): Promise { - return isRoleStatistics((await this.userService.getFeatures()).Features); + return isRoleStatistics((await this.userService.getFeatures()).Features || []); } public async isShopStatistics(): Promise { - return isShopStatistics((await this.userService.getFeatures()).Features); + return isShopStatistics((await this.userService.getFeatures()).Features || []); } public async isStructStatistics(): Promise { - return isStructStatistics((await this.userService.getFeatures()).Features); - } - public async isPasswordHelpdesk(): Promise { - return isPasswordHelpdesk((await this.userService.getFeatures()).Features); + return isStructStatistics((await this.userService.getFeatures()).Features || []); } public async isStatistics(): Promise { - return isStatistics((await this.userService.getFeatures()).Features); + return isStatistics((await this.userService.getFeatures()).Features || []); } - public async isAuditor(): Promise { - return isAuditor((await this.userService.getGroups()).map((group) => group.Name)); + public async isHyperviewNavigation(): Promise { + return isHyperviewNavigation((await this.userService.getFeatures()).Features || []); } - public async isTsbNameSpaceAdminBase(): Promise { - return isTsbNameSpaceAdminBase((await this.userService.getGroups()).map((group) => group.Name)); + public async isAuditor(): Promise { + return isAuditor((await this.userService.getGroups()).map((group) => group?.Name || '')); } } diff --git a/imxweb/projects/qer/src/lib/approval-workflows/approval-level-form/approval-level-form.component.html b/imxweb/projects/qer/src/lib/approval-workflows/approval-level-form/approval-level-form.component.html index b34cc463e..995cc6a95 100644 --- a/imxweb/projects/qer/src/lib/approval-workflows/approval-level-form/approval-level-form.component.html +++ b/imxweb/projects/qer/src/lib/approval-workflows/approval-level-form/approval-level-form.component.html @@ -1,24 +1,36 @@
    - + {{ requestData.HelpText }}
    - - + +
    - -
    diff --git a/imxweb/projects/qer/src/lib/approval-workflows/approval-level-form/approval-level-form.component.scss b/imxweb/projects/qer/src/lib/approval-workflows/approval-level-form/approval-level-form.component.scss index 987ded229..32ef97297 100644 --- a/imxweb/projects/qer/src/lib/approval-workflows/approval-level-form/approval-level-form.component.scss +++ b/imxweb/projects/qer/src/lib/approval-workflows/approval-level-form/approval-level-form.component.scss @@ -1,3 +1,3 @@ -@import '../approval-workflow-styles.scss'; +@import 'base/mixins'; @include Awm-Form-Sidesheet; diff --git a/imxweb/projects/qer/src/lib/approval-workflows/approval-level-form/approval-level-form.component.ts b/imxweb/projects/qer/src/lib/approval-workflows/approval-level-form/approval-level-form.component.ts index 803b48a4a..8151b7904 100644 --- a/imxweb/projects/qer/src/lib/approval-workflows/approval-level-form/approval-level-form.component.ts +++ b/imxweb/projects/qer/src/lib/approval-workflows/approval-level-form/approval-level-form.component.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -35,14 +35,14 @@ import { FormDataService } from '../form-data.service'; @Component({ selector: 'imx-approval-level-form', templateUrl: './approval-level-form.component.html', - styleUrls: ['./approval-level-form.component.scss'] + styleUrls: ['./approval-level-form.component.scss'], }) export class ApprovalLevelFormComponent implements OnInit, OnDestroy { public readonly formGroup: FormGroup; public cdrList: ColumnDependentReference[] = []; public isInActiveFormControl = new FormControl(); public initialState: { - [key: string]: any + [key: string]: any; }; private readonly subscriptions: Subscription[] = []; @@ -58,7 +58,7 @@ export class ApprovalLevelFormComponent implements OnInit, OnDestroy { this.subscriptions.push( this.sidesheetRef.closeClicked().subscribe(async () => { await this.formService.cancelChanges(this.formGroup, this.sidesheetRef, this.requestData); - }) + }), ); } get formArray(): FormArray { @@ -68,8 +68,8 @@ export class ApprovalLevelFormComponent implements OnInit, OnDestroy { public async ngOnInit(): Promise { const columnConstraints: ColumnConstraints = { LevelDisplay: { - minLength: 1 - } + minLength: 1, + }, }; this.cdrList = await this.formService.setup(this.requestData, columnConstraints); } diff --git a/imxweb/projects/qer/src/lib/approval-workflows/approval-step-form/approval-step-form.component.html b/imxweb/projects/qer/src/lib/approval-workflows/approval-step-form/approval-step-form.component.html index d847cb9ca..8a5763adf 100644 --- a/imxweb/projects/qer/src/lib/approval-workflows/approval-step-form/approval-step-form.component.html +++ b/imxweb/projects/qer/src/lib/approval-workflows/approval-step-form/approval-step-form.component.html @@ -1,8 +1,8 @@ - +
    - + {{ requestData.HelpText.General }}
    @@ -11,7 +11,7 @@ @@ -23,7 +23,7 @@
    - + {{ requestData.HelpText.Mail }}
    @@ -31,8 +31,8 @@ @@ -43,12 +43,16 @@
    - - diff --git a/imxweb/projects/qer/src/lib/approval-workflows/approval-workflow-edit/approval-workflow-edit-info/approval-workflow-edit-info.component.scss b/imxweb/projects/qer/src/lib/approval-workflows/approval-workflow-edit/approval-workflow-edit-info/approval-workflow-edit-info.component.scss deleted file mode 100644 index 3b6c8d112..000000000 --- a/imxweb/projects/qer/src/lib/approval-workflows/approval-workflow-edit/approval-workflow-edit-info/approval-workflow-edit-info.component.scss +++ /dev/null @@ -1,61 +0,0 @@ -@import "@elemental-ui/core/src/styles/_eui_palette.scss"; -@import "../../approval-workflow-styles.scss"; - -:host { - h2 { - font-weight: bold; - } - - .no-top { - margin-top: 0; - } - - .no-bottom { - margin-bottom: 0; - } - - mat-dialog-actions { - justify-content: flex-end; - } - ul { - margin: 5px 0; - } - li { - list-style-type: unset; - } - - kbd { - @include EUI-Elevation-1; - border-radius: 4px; - display: inline-block; - font-size: .85em; - font-weight: 700; - line-height: 1; - padding: 2px 4px; - margin: 5px; - white-space: nowrap; - } -} - -// Theming -:host { - kbd { - background-color: $color-gray-5; - } -} - -.eui-dark-theme { - :host { - kbd { - background-color: $color-gray-60; - } - } -} - -.eui-contrast-theme { - :host { - kbd { - background-color: $color-gray-80; - } - } -} diff --git a/imxweb/projects/qer/src/lib/approval-workflows/approval-workflow-edit/approval-workflow-edit.component.html b/imxweb/projects/qer/src/lib/approval-workflows/approval-workflow-edit/approval-workflow-edit.component.html index 345af7ffd..96197819d 100644 --- a/imxweb/projects/qer/src/lib/approval-workflows/approval-workflow-edit/approval-workflow-edit.component.html +++ b/imxweb/projects/qer/src/lib/approval-workflows/approval-workflow-edit/approval-workflow-edit.component.html @@ -1,41 +1,56 @@
    -
    - - - - -
    - - +
    + + + + +
    +
    -
    -
    -
    +
    +
    +
    @@ -54,7 +69,7 @@
    - - - - - - - - - - - -
    diff --git a/imxweb/projects/qer/src/lib/approval-workflows/approval-workflow-form/approval-workflow-form.component.scss b/imxweb/projects/qer/src/lib/approval-workflows/approval-workflow-form/approval-workflow-form.component.scss index 987ded229..32ef97297 100644 --- a/imxweb/projects/qer/src/lib/approval-workflows/approval-workflow-form/approval-workflow-form.component.scss +++ b/imxweb/projects/qer/src/lib/approval-workflows/approval-workflow-form/approval-workflow-form.component.scss @@ -1,3 +1,3 @@ -@import '../approval-workflow-styles.scss'; +@import 'base/mixins'; @include Awm-Form-Sidesheet; diff --git a/imxweb/projects/qer/src/lib/approval-workflows/approval-workflow-form/approval-workflow-form.component.ts b/imxweb/projects/qer/src/lib/approval-workflows/approval-workflow-form/approval-workflow-form.component.ts index 0c30f0c25..e2150f4d7 100644 --- a/imxweb/projects/qer/src/lib/approval-workflows/approval-workflow-form/approval-workflow-form.component.ts +++ b/imxweb/projects/qer/src/lib/approval-workflows/approval-workflow-form/approval-workflow-form.component.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -26,13 +26,13 @@ import { Component, ErrorHandler, Inject, OnDestroy, OnInit } from '@angular/core'; import { FormArray, FormBuilder, FormControl, FormGroup } from '@angular/forms'; -import { EuiSidesheetRef, EUI_SIDESHEET_DATA } from '@elemental-ui/core'; +import { EUI_SIDESHEET_DATA, EuiSidesheetRef } from '@elemental-ui/core'; import { TranslateService } from '@ngx-translate/core'; import { ColumnDependentReference } from 'qbm'; import { Subscription } from 'rxjs'; +import { ApprovalWorkflowDataService } from '../approval-workflow-data.service'; import { ColumnConstraints, RequestWorkflowData } from '../approval-workflow.interface'; import { FormDataService } from '../form-data.service'; -import { ApprovalWorkflowDataService } from '../approval-workflow-data.service'; @Component({ selector: 'imx-approval-workflow-form', @@ -44,7 +44,7 @@ export class ApprovalWorkflowFormComponent implements OnInit, OnDestroy { public cdrList: ColumnDependentReference[] = []; public isInActiveFormControl = new FormControl(); public initialState: { - [key: string]: any + [key: string]: any; }; private readonly subscriptions: Subscription[] = []; @@ -56,14 +56,14 @@ export class ApprovalWorkflowFormComponent implements OnInit, OnDestroy { public readonly translate: TranslateService, public readonly sidesheetRef: EuiSidesheetRef, private approvalWorkFlowDataService: ApprovalWorkflowDataService, - private errorHandler: ErrorHandler - ) { + private errorHandler: ErrorHandler, + ) { this.formGroup = new FormGroup({ formArray: formBuilder.array([]) }); this.subscriptions.push( this.sidesheetRef.closeClicked().subscribe(async () => { await this.formService.cancelChanges(this.formGroup, this.sidesheetRef, this.requestData); - }) + }), ); } get formArray(): FormArray { @@ -74,9 +74,9 @@ export class ApprovalWorkflowFormComponent implements OnInit, OnDestroy { const columnConstraints: ColumnConstraints = { DaysToAbort: { valueConstraint: { - MinValue: 0 - } - } + MinValue: 0, + }, + }, }; this.cdrList = this.formService.setup(this.requestData, columnConstraints); } @@ -86,7 +86,7 @@ export class ApprovalWorkflowFormComponent implements OnInit, OnDestroy { if (this.requestData.SaveBeforeClosing) { this.approvalWorkFlowDataService.handleOpenLoader(); try { - await this.requestData.Object.GetEntity().Commit(true); + await this.requestData.Object?.GetEntity().Commit(true); } catch (error) { this.errorHandler.handleError(error); closeSheet = false; diff --git a/imxweb/projects/qer/src/lib/approval-workflows/approval-workflow-home/approval-workflow-home.component.html b/imxweb/projects/qer/src/lib/approval-workflows/approval-workflow-home/approval-workflow-home.component.html index 7d65eb620..d7bd92251 100644 --- a/imxweb/projects/qer/src/lib/approval-workflows/approval-workflow-home/approval-workflow-home.component.html +++ b/imxweb/projects/qer/src/lib/approval-workflows/approval-workflow-home/approval-workflow-home.component.html @@ -1,7 +1,7 @@ -

    +

    {{ '#LDS#Heading Approval Workflows' | translate }} -

    + [options]="['search']" [busyService]="busyService" [settings]="dstSettings" - useThemedStyle="true" + [useThemedStyle]="true" (search)="getData({ search: $event })" (navigationStateChanged)="getData($event)" data-imx-identifier="approval-workflow-dst" @@ -20,15 +20,15 @@

    #dataTable [dst]="dst" class="imx-pickcategory-table" - detailViewVisible="false" - showSelectedItemsMenu="false" - selectable="true" + [detailViewVisible]="false" + [showSelectedItemsMenu]="false" + [selectable]="true" (selectionChanged)="onSelectionChanged($event)" mode="manual" (highlightedEntityChanged)="viewDetails({ workFlow: $event })" data-imx-identifier="approval-workflow-datatable" > - +
    {{ item.GetEntity().GetDisplay() }}
    {{ item.Description.Column.GetDisplayValue() }}
    @@ -48,16 +48,27 @@

    -
    - -
    - -

    - + > - + + -
    +
    -

    #LDS#Select select a recipient or requester whose requests you want to display.

    +

    #LDS#Select a recipient or requester whose requests you want to display.

    - {{ infoText | translate}} + {{ infoText | translate }}

    diff --git a/imxweb/projects/qer/src/lib/archived-requests/archived-requests.component.scss b/imxweb/projects/qer/src/lib/archived-requests/archived-requests.component.scss index c6d99aeef..fe3e5d20c 100644 --- a/imxweb/projects/qer/src/lib/archived-requests/archived-requests.component.scss +++ b/imxweb/projects/qer/src/lib/archived-requests/archived-requests.component.scss @@ -6,7 +6,7 @@ overflow: hidden; flex-grow: 1; - .imx-data-table-no-results { + .imx-no-results { text-align: center; margin: 20px 0; flex: 1 1 auto; @@ -14,10 +14,6 @@ flex-direction: column; justify-content: center; - .eui-icon { - font-size: 100px; - } - p { margin: 0; font-size: 18px; @@ -29,26 +25,14 @@ align-items: center; margin: 0 0 40px; - h1 { + h2 { font-weight: inherit; margin: 0; } } -.imx-content-card { - flex: 1 1 auto; - display: flex; - flex-direction: column; - overflow: hidden; - margin: 2px; -} - :host { - .imx-data-table-no-results { - .eui-icon { - color: $color-gray-10; - } - + .imx-no-results { p { color: $color-gray-80; } @@ -57,11 +41,7 @@ .eui-dark-theme { :host { - .imx-data-table-no-results { - eui-icon { - color: $color-gray-20; - } - + .imx-no-results { p { color: $color-gray-10; } @@ -71,11 +51,7 @@ .eui-contrast-theme { :host { - .imx-data-table-no-results { - eui-icon { - color: $color-gray-10; - } - + .imx-no-results { p { color: $color-gray-0; } diff --git a/imxweb/projects/qer/src/lib/archived-requests/archived-requests.component.ts b/imxweb/projects/qer/src/lib/archived-requests/archived-requests.component.ts index 643653a22..e38a10a09 100644 --- a/imxweb/projects/qer/src/lib/archived-requests/archived-requests.component.ts +++ b/imxweb/projects/qer/src/lib/archived-requests/archived-requests.component.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -25,10 +25,10 @@ */ import { Component, OnDestroy } from '@angular/core'; -import { AuthenticationService, ColumnDependentReference } from 'qbm'; import { AbstractControl, FormGroup } from '@angular/forms'; -import { ArchivedRequestsService } from './archived-requests.service'; +import { AuthenticationService, ColumnDependentReference, ISessionState } from 'qbm'; import { Subscription } from 'rxjs'; +import { ArchivedRequestsService } from './archived-requests.service'; @Component({ templateUrl: './archived-requests.component.html', @@ -43,9 +43,12 @@ export class ArchivedRequestsComponent implements OnDestroy { private sessionSubscription: Subscription; - constructor(private archived: ArchivedRequestsService, authService: AuthenticationService) { - this.sessionSubscription = authService.onSessionResponse.subscribe(async (session) => { - await this.initRecipientForm(session.UserUid, session.Username); + constructor( + private archived: ArchivedRequestsService, + authService: AuthenticationService, + ) { + this.sessionSubscription = authService.onSessionResponse.subscribe(async (session: ISessionState) => { + await this.initRecipientForm(session.UserUid || '', session.Username || ''); }); } diff --git a/imxweb/projects/qer/src/lib/archived-requests/archived-requests.module.ts b/imxweb/projects/qer/src/lib/archived-requests/archived-requests.module.ts index 3766f0864..f42195fba 100644 --- a/imxweb/projects/qer/src/lib/archived-requests/archived-requests.module.ts +++ b/imxweb/projects/qer/src/lib/archived-requests/archived-requests.module.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -24,7 +24,6 @@ * */ - import { CommonModule } from '@angular/common'; import { NgModule } from '@angular/core'; import { ReactiveFormsModule } from '@angular/forms'; @@ -41,22 +40,21 @@ import { DateModule, HELP_CONTEXTUAL, HelpContextualModule, - InfoButtonComponent, InfoModalDialogModule, MenuItem, MenuService, ParameterizedTextModule, QbmModule, - RouteGuardService + RouteGuardService, } from 'qbm'; +import { isShopAdmin } from '../admin/qer-permissions-helper'; import { ItshopModule } from '../itshop/itshop.module'; -import { RequestsFeatureGuardService } from '../requests-feature-guard.service'; import { JustificationModule } from '../justification/justification.module'; -import { ArchivedRequestsComponent } from './archived-requests.component'; -import {ArchivedRequestsService} from './archived-requests.service'; import { RequestHistoryModule } from '../request-history/request-history.module'; -import { isShopAdmin } from '../admin/qer-permissions-helper'; +import { RequestsFeatureGuardService } from '../requests-feature-guard.service'; +import { ArchivedRequestsComponent } from './archived-requests.component'; +import { ArchivedRequestsService } from './archived-requests.service'; const routes: Routes = [ { @@ -64,10 +62,10 @@ const routes: Routes = [ component: ArchivedRequestsComponent, canActivate: [RouteGuardService, RequestsFeatureGuardService], resolve: [RouteGuardService], - data:{ - contextId: HELP_CONTEXTUAL.ArchivedRequest - } - } + data: { + contextId: HELP_CONTEXTUAL.ArchivedRequest, + }, + }, ]; @NgModule({ @@ -89,54 +87,42 @@ const routes: Routes = [ TranslateModule, RequestHistoryModule, HelpContextualModule, - InfoModalDialogModule - ], - declarations: [ - ArchivedRequestsComponent + InfoModalDialogModule, ], - exports: [ - ArchivedRequestsComponent - ], - providers: [ - ArchivedRequestsService - ] + declarations: [ArchivedRequestsComponent], + exports: [ArchivedRequestsComponent], + providers: [ArchivedRequestsService], }) export class ArchivedRequestsModule { constructor( private readonly menuService: MenuService, - logger: ClassloggerService + logger: ClassloggerService, ) { logger.info(this, '▶️ ArchivedRequestsModule loaded'); this.setupMenu(); } private async setupMenu(): Promise { - this.menuService.addMenuFactories( - (preProps: string[], features: string[]) => { - - const items: MenuItem[] = []; - if (isShopAdmin(features)) { - items.push( - { - id: 'QER_Request_ArchivedRequest', - route: 'archivedrequest', - title: '#LDS#Menu Entry Archived requests', - sorting: '10-40', - } - ); - } + this.menuService.addMenuFactories((preProps: string[], features: string[]) => { + const items: MenuItem[] = []; + if (isShopAdmin(features)) { + items.push({ + id: 'QER_Request_ArchivedRequest', + route: 'archivedrequest', + title: '#LDS#Menu Entry Archived requests', + sorting: '10-40', + }); + } - if (items.length === 0) { - return null; - } - return { - id: 'ROOT_Request', - title: '#LDS#Requests', - sorting: '10', - items - }; - }, - ); + if (items.length === 0) { + return; + } + return { + id: 'ROOT_Request', + title: '#LDS#Requests', + sorting: '10', + items, + }; + }); } } - diff --git a/imxweb/projects/qer/src/lib/archived-requests/archived-requests.service.ts b/imxweb/projects/qer/src/lib/archived-requests/archived-requests.service.ts index 30c5f55b1..92f4e5b0d 100644 --- a/imxweb/projects/qer/src/lib/archived-requests/archived-requests.service.ts +++ b/imxweb/projects/qer/src/lib/archived-requests/archived-requests.service.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -25,10 +25,17 @@ */ import { Injectable } from '@angular/core'; -import { DisplayBuilder, FkCandidateProvider, IClientProperty, MetaTableRelationData, ReadWriteEntity, ValType } from 'imx-qbm-dbts'; +import { + DisplayBuilder, + FkCandidateProvider, + IClientProperty, + MetaTableRelationData, + ReadWriteEntity, + ValType, +} from '@imx-modules/imx-qbm-dbts'; +import { TranslateService } from '@ngx-translate/core'; import { BaseCdr, ImxTranslationProviderService } from 'qbm'; import { QerApiService } from '../qer-api-client.service'; -import { TranslateService } from '@ngx-translate/core'; @Injectable({ providedIn: 'root', @@ -37,28 +44,29 @@ export class ArchivedRequestsService { constructor( private readonly qerClient: QerApiService, private translate: TranslateService, - private translateService: ImxTranslationProviderService + private translateService: ImxTranslationProviderService, ) {} public createRecipientCdr(): BaseCdr { const columnProperties = {}; - const property = this.createRequesterProperty(); - columnProperties[property.ColumnName] = property; + const columnName = 'PersonColumnName'; + const property = this.createRequesterProperty(columnName); + columnProperties[columnName] = property; const entityColumn = new ReadWriteEntity( { Columns: columnProperties }, {}, this.createRequesterFkProvider(property.FkRelation), undefined, - new DisplayBuilder(this.translateService) - ).GetColumn(property.ColumnName); + new DisplayBuilder(this.translateService), + ).GetColumn(columnName); return new BaseCdr(entityColumn, '#LDS#Recipient or requester'); } - private createRequesterProperty(): IClientProperty { + private createRequesterProperty(columnName: string): IClientProperty { const fkRelation = { - ChildColumnName: 'PersonColumnName', + ChildColumnName: columnName, ParentTableName: 'Person', ParentColumnName: 'UID_Person', IsMemberRelation: false, @@ -71,11 +79,11 @@ export class ArchivedRequestsService { }; } - private createRequesterFkProvider(fkRelation: MetaTableRelationData): FkCandidateProvider { + private createRequesterFkProvider(fkRelation: MetaTableRelationData | undefined): FkCandidateProvider { return new FkCandidateProvider([ { - columnName: fkRelation.ChildColumnName, - fkTableName: fkRelation.ParentTableName, + columnName: fkRelation?.ChildColumnName || '', + fkTableName: fkRelation?.ParentTableName || '', parameterNames: ['OrderBy', 'StartIndex', 'PageSize', 'filter', 'search'], load: async (_, parameters = {}) => this.qerClient.client.portal_candidates_Person_get(parameters), getDataModel: async () => ({}), diff --git a/imxweb/projects/qer/src/lib/businessowner-addon-tile/businessowner-addon-tile.component.html b/imxweb/projects/qer/src/lib/businessowner-addon-tile/businessowner-addon-tile.component.html index 31385e239..f54b455db 100644 --- a/imxweb/projects/qer/src/lib/businessowner-addon-tile/businessowner-addon-tile.component.html +++ b/imxweb/projects/qer/src/lib/businessowner-addon-tile/businessowner-addon-tile.component.html @@ -1,3 +1,11 @@ - + diff --git a/imxweb/projects/qer/src/lib/businessowner-addon-tile/businessowner-addon-tile.component.ts b/imxweb/projects/qer/src/lib/businessowner-addon-tile/businessowner-addon-tile.component.ts index 3ad160621..3e82d5e65 100644 --- a/imxweb/projects/qer/src/lib/businessowner-addon-tile/businessowner-addon-tile.component.ts +++ b/imxweb/projects/qer/src/lib/businessowner-addon-tile/businessowner-addon-tile.component.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -28,10 +28,9 @@ import { Component, Input, Output, EventEmitter } from '@angular/core'; @Component({ templateUrl: './businessowner-addon-tile.component.html', - selector: 'imx-businessowner-addon-tile' + selector: 'imx-businessowner-addon-tile', }) export class BusinessOwnerAddOnTileComponent { - @Input() public squareText: string; @Input() public description: string; @Input() public actionText = '#LDS#View'; diff --git a/imxweb/projects/qer/src/lib/businessowner-addon-tile/businessowner-addon-tile.module.ts b/imxweb/projects/qer/src/lib/businessowner-addon-tile/businessowner-addon-tile.module.ts index 455e79651..33f86bdff 100644 --- a/imxweb/projects/qer/src/lib/businessowner-addon-tile/businessowner-addon-tile.module.ts +++ b/imxweb/projects/qer/src/lib/businessowner-addon-tile/businessowner-addon-tile.module.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -36,15 +36,7 @@ import { BusinessOwnerAddOnTileComponent } from './businessowner-addon-tile.comp @NgModule({ declarations: [BusinessOwnerAddOnTileComponent], - imports: [ - CommonModule, - TileModule, - TranslateModule, - FormsModule, - MatDialogModule, - MatTabsModule - ], + imports: [CommonModule, TileModule, TranslateModule, FormsModule, MatDialogModule, MatTabsModule], exports: [BusinessOwnerAddOnTileComponent], - }) -export class BusinessownerAddonTileModule { } +export class BusinessownerAddonTileModule {} diff --git a/imxweb/projects/qer/src/lib/businessowner-overview-tile/businessowner-overview-tile.component.html b/imxweb/projects/qer/src/lib/businessowner-overview-tile/businessowner-overview-tile.component.html index 482eda7e8..ce311eed6 100644 --- a/imxweb/projects/qer/src/lib/businessowner-overview-tile/businessowner-overview-tile.component.html +++ b/imxweb/projects/qer/src/lib/businessowner-overview-tile/businessowner-overview-tile.component.html @@ -1,3 +1,3 @@ - \ No newline at end of file + diff --git a/imxweb/projects/qer/src/lib/businessowner-overview-tile/businessowner-overview-tile.component.ts b/imxweb/projects/qer/src/lib/businessowner-overview-tile/businessowner-overview-tile.component.ts index da3cba16a..05948c2da 100644 --- a/imxweb/projects/qer/src/lib/businessowner-overview-tile/businessowner-overview-tile.component.ts +++ b/imxweb/projects/qer/src/lib/businessowner-overview-tile/businessowner-overview-tile.component.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -28,10 +28,9 @@ import { Component, Input, Output, EventEmitter } from '@angular/core'; @Component({ templateUrl: './businessowner-overview-tile.component.html', - selector: 'imx-businessowner-overview-tile' + selector: 'imx-businessowner-overview-tile', }) export class BusinessOwnerOverviewTileComponent { - /* TODO (TFS 806002) ExpressionColumnList({"ScriptItemUID":"ExpressionColumnList2","ColumnList":"GetConfig(PropertyList())"}); }*/ diff --git a/imxweb/projects/qer/src/lib/businessowner-overview-tile/businessowner-overview-tile.module.ts b/imxweb/projects/qer/src/lib/businessowner-overview-tile/businessowner-overview-tile.module.ts index ba30e971a..0de355962 100644 --- a/imxweb/projects/qer/src/lib/businessowner-overview-tile/businessowner-overview-tile.module.ts +++ b/imxweb/projects/qer/src/lib/businessowner-overview-tile/businessowner-overview-tile.module.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -37,14 +37,7 @@ import { BusinessOwnerOverviewTileComponent } from './businessowner-overview-til @NgModule({ declarations: [BusinessOwnerOverviewTileComponent], - imports: [ - CommonModule, - TileModule, - TranslateModule, - FormsModule, - MatDialogModule, - MatTabsModule - ], + imports: [CommonModule, TileModule, TranslateModule, FormsModule, MatDialogModule, MatTabsModule], exports: [BusinessOwnerOverviewTileComponent], }) -export class BusinessownerOverviewTileModule { } +export class BusinessownerOverviewTileModule {} diff --git a/imxweb/projects/qer/src/lib/data-explorer-view/data-explorer-registry.service.ts b/imxweb/projects/qer/src/lib/data-explorer-view/data-explorer-registry.service.ts index 47ccfc592..fc2a5c942 100644 --- a/imxweb/projects/qer/src/lib/data-explorer-view/data-explorer-registry.service.ts +++ b/imxweb/projects/qer/src/lib/data-explorer-view/data-explorer-registry.service.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -25,7 +25,7 @@ */ import { Injectable } from '@angular/core'; -import { ProjectConfig } from 'imx-api-qbm'; +import { ProjectConfig } from '@imx-modules/imx-api-qbm'; import { SideNavigationExtension, SideNavigationFactory } from 'qbm'; @Injectable({ @@ -34,10 +34,15 @@ import { SideNavigationExtension, SideNavigationFactory } from 'qbm'; export class DataExplorerRegistryService { private items: SideNavigationFactory[] = []; - public getNavItems(preProps: string[], features: string[], projectConfig?: ProjectConfig, groups?: string[]): SideNavigationExtension[] { + public getNavItems( + preProps: string[], + features: string[], + projectConfig?: ProjectConfig, + groups?: string[], + ): (SideNavigationExtension | undefined)[] { return this.items .map((factory) => factory(preProps, features, projectConfig, groups)) - .sort((a, b) => a.sortOrder - b.sortOrder) + .sort((a, b) => (a?.sortOrder ?? 0) - (b?.sortOrder ?? 0)) .filter((item) => item !== undefined); } diff --git a/imxweb/projects/qer/src/lib/data-explorer-view/data-explorer-view.component.html b/imxweb/projects/qer/src/lib/data-explorer-view/data-explorer-view.component.html index 4fc67b390..a0e4a7220 100644 --- a/imxweb/projects/qer/src/lib/data-explorer-view/data-explorer-view.component.html +++ b/imxweb/projects/qer/src/lib/data-explorer-view/data-explorer-view.component.html @@ -3,6 +3,6 @@ [isAdmin]="isAdmin" [componentName]="componentName" [componentTitle]="componentTitle" - [navItems]="navItems" + [navItems]="navItems ?? []" [contextId]="contextId" > diff --git a/imxweb/projects/qer/src/lib/data-explorer-view/data-explorer-view.component.scss b/imxweb/projects/qer/src/lib/data-explorer-view/data-explorer-view.component.scss index 4bc9c8950..7ec7b6c09 100644 --- a/imxweb/projects/qer/src/lib/data-explorer-view/data-explorer-view.component.scss +++ b/imxweb/projects/qer/src/lib/data-explorer-view/data-explorer-view.component.scss @@ -1,158 +1,4 @@ -@import '@elemental-ui/core/src/styles/_eui_palette.scss'; -@import '@elemental-ui/core/src/styles/_palette.scss'; :host { height: 100%; } - -.snavigation { - height: 100%; - - .mat-sidenav-container { - height: 100%; - background-color: $asher-gray; - - .mat-sidenav { - width: 230px; - - .snavigation-side { - display: flex; - flex-direction: column; - height: 100%; - - .snavigation-side-toggle { - display: none; - padding: 16px 12px 0; - margin-bottom: 10px; - - .mat-button { - min-width: 0; - padding: 0 4px; - height: 28px; - - .mat-icon { - margin-top: -12px; - } - } - } - - .snavigation-side-content { - flex: 1; - padding: 20px; - padding-bottom: 16px; - - .snavigation-side-heading { - font-size: 14px; - font-weight: bold; - margin-bottom: 10px; - white-space: nowrap; - } - - .snavigation-item { - margin: 0 -20px; - padding: 10px 20px; - display: flex; - align-items: center; - justify-content: flex-start; - cursor: pointer; - - & > .eui-icon { - margin-right: 8px; - color: rgba($black, 0.4); - } - - & > span { - flex: 1; - overflow: hidden; - text-overflow: ellipsis; - white-space: nowrap; - } - - &:hover:not(.snavigation-item--selected) { - background-color: rgba($iris-tint, 0.5); - } - - &.snavigation-item--selected { - background-color: $iris-blue; - color: $white; - } - } - } - } - } - - .mat-sidenav-content { - padding: 20px; - position: relative; - display: flex; - flex-direction: column; - - &.snavigation--backdrop-showing { - overflow: hidden; - } - - .snavigation-backdrop { - position: absolute; - top: 0; - left: 0; - right: 0; - bottom: 0; - background-color: rgba($black, 0.32); - z-index: 200; - } - - .mat-table tr:hover td { - background-color: rgba($black, 0.04); - cursor: pointer; - } - } - } -} - -@media only screen and (max-width: 768px) { - .snavigation .mat-sidenav-container { - .mat-sidenav { - transition: width 0.5s; - - .snavigation-side { - .snavigation-side-toggle { - display: block; - } - .snavigation-side-content { - padding: 16px; - } - } - - &:not(.snavigation-side--expanded) { - width: 58px; - - .snavigation-side-content { - display: none; - } - } - } - - .mat-sidenav-content { - padding: 16px; - } - } -} -.eui-dark-theme { - :host { - .snavigation .mat-sidenav-container{ - background-color: $color-gray-80; - } - } -} -.eui-contrast-theme { - :host { - .snavigation .mat-sidenav-container{ - background-color: $color-gray-100; - } - - .snavigation-item--selected { - border-top: 1px solid $color-gray-0; - border-bottom: 1px solid $color-gray-0; - } - } -} diff --git a/imxweb/projects/qer/src/lib/data-explorer-view/data-explorer-view.component.ts b/imxweb/projects/qer/src/lib/data-explorer-view/data-explorer-view.component.ts index fd48a2682..c70f8c8d6 100644 --- a/imxweb/projects/qer/src/lib/data-explorer-view/data-explorer-view.component.ts +++ b/imxweb/projects/qer/src/lib/data-explorer-view/data-explorer-view.component.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -40,13 +40,13 @@ export class DataExplorerViewComponent implements OnInit { public componentName = 'data-explorer-view'; public componentTitle = '#LDS#Heading Data Explorer'; public contextId = HELP_CONTEXTUAL.DataExplorer; - public navItems: SideNavigationExtension[] = []; + public navItems: (SideNavigationExtension | undefined)[] = []; constructor( private readonly systemInfoService: SystemInfoService, private readonly userModelService: UserModelService, private readonly dataExplorerRegistryService: DataExplorerRegistryService, - private cdref: ChangeDetectorRef + private cdref: ChangeDetectorRef, ) {} public async ngOnInit(): Promise { @@ -55,9 +55,9 @@ export class DataExplorerViewComponent implements OnInit { private async loadNavItems(): Promise { const systemInfo = await this.systemInfoService.get(); - const features = (await this.userModelService.getFeatures()).Features; - const groups = (await this.userModelService.getGroups()).map((group) => group.Name || ''); - this.navItems = this.dataExplorerRegistryService.getNavItems(systemInfo.PreProps, features, undefined, groups); + const features = (await this.userModelService.getFeatures()).Features || []; + const groups = (await this.userModelService.getGroups()).map((group) => group?.Name || ''); + this.navItems = this.dataExplorerRegistryService.getNavItems(systemInfo.PreProps || [], features, undefined, groups); this.cdref.detectChanges(); } } diff --git a/imxweb/projects/qer/src/lib/data-explorer-view/data-explorer-view.module.ts b/imxweb/projects/qer/src/lib/data-explorer-view/data-explorer-view.module.ts index bd06fc77e..d86fd0105 100644 --- a/imxweb/projects/qer/src/lib/data-explorer-view/data-explorer-view.module.ts +++ b/imxweb/projects/qer/src/lib/data-explorer-view/data-explorer-view.module.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -32,8 +32,7 @@ import { TranslateModule } from '@ngx-translate/core'; import { MatTooltipModule } from '@angular/material/tooltip'; import { RouteGuardService, SideNavigationViewModule } from 'qbm'; -import { ApplicationGuardService} from '../guards/application-guard.service'; -import { DataExplorerGuardService } from '../guards/data-explorer-guard.service'; +import { ApplicationGuardService } from '../guards/application-guard.service'; import { DataExplorerRegistryService } from './data-explorer-registry.service'; import { DataExplorerViewComponent } from './data-explorer-view.component'; @@ -41,21 +40,13 @@ const routes: Routes = [ { path: 'admin/dataexplorer', component: DataExplorerViewComponent, - canActivate: [ - RouteGuardService, - ApplicationGuardService, - DataExplorerGuardService - ], + canActivate: [RouteGuardService, ApplicationGuardService], resolve: [RouteGuardService], }, { path: 'admin/dataexplorer/:tab', component: DataExplorerViewComponent, - canActivate: [ - RouteGuardService, - ApplicationGuardService, - DataExplorerGuardService - ], + canActivate: [RouteGuardService, ApplicationGuardService], resolve: [RouteGuardService], }, ]; diff --git a/imxweb/projects/qer/src/lib/delegation/delegation-guard.service.ts b/imxweb/projects/qer/src/lib/delegation/delegation-guard.service.ts new file mode 100644 index 000000000..d1294fd62 --- /dev/null +++ b/imxweb/projects/qer/src/lib/delegation/delegation-guard.service.ts @@ -0,0 +1,56 @@ +/* + * ONE IDENTITY LLC. PROPRIETARY INFORMATION + * + * This software is confidential. One Identity, LLC. or one of its affiliates or + * subsidiaries, has supplied this software to you under terms of a + * license agreement, nondisclosure agreement or both. + * + * You may not copy, disclose, or use this software except in accordance with + * those terms. + * + * + * Copyright 2024 One Identity LLC. + * ALL RIGHTS RESERVED. + * + * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR + * WARRANTIES ABOUT THE SUITABILITY OF THE SOFTWARE, + * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED + * TO THE IMPLIED WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE, OR + * NON-INFRINGEMENT. ONE IDENTITY LLC. SHALL NOT BE + * LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE + * AS A RESULT OF USING, MODIFYING OR DISTRIBUTING + * THIS SOFTWARE OR ITS DERIVATIVES. + * + */ + +import { Injectable } from '@angular/core'; +import { Router } from '@angular/router'; +import { SystemInfoService } from 'qbm'; +import { ProjectConfigurationService } from '../project-configuration/project-configuration.service'; + +@Injectable({ + providedIn: 'root', +}) +export class DelegationGuardService { + constructor( + private projectConfig: ProjectConfigurationService, + private systemInfoService: SystemInfoService, + private readonly router: Router, + ) {} + + public async canActivate(): Promise { + const config = await this.projectConfig.getConfig(); + const preProps = (await this.systemInfoService.get()).PreProps ?? []; + + if ( + preProps.includes('ITSHOP') && + preProps.includes('DELEGATION') && + (config.EnableNewDelegationIndividual || config.EnableNewDelegationSubstitute) + ) { + return true; + } + this.router.navigate(['']); + return false; + } +} diff --git a/imxweb/projects/qer/src/lib/delegation/delegation.component.html b/imxweb/projects/qer/src/lib/delegation/delegation.component.html index e9a725a26..73542c035 100644 --- a/imxweb/projects/qer/src/lib/delegation/delegation.component.html +++ b/imxweb/projects/qer/src/lib/delegation/delegation.component.html @@ -1,13 +1,13 @@ -

    +

    {{ '#LDS#Heading Create Delegation' | translate }} -

    +

    - + {{ '#LDS#Create delegation for me' | translate }} @@ -16,7 +16,13 @@

    - + {{ '#LDS#Select the identity whose memberships and responsibilities you want to delegate' | translate }} @@ -28,8 +34,14 @@

    (controlCreated)="addControl(senderFormGroup, cdrPersonSender.column.ColumnName, $event)" >

    -
    -
    @@ -46,19 +58,29 @@

    >

    -
    -
    - + {{ '#LDS#Select the type of delegation' | translate }}
    - #LDS#Delegate all memberships and responsibilities + #LDS#Delegate memberships and responsibilities grouped by topic #LDS#Select individual memberships and responsibilities to delegate @@ -66,7 +88,7 @@

    -
    +
    @@ -90,7 +112,10 @@

    - + {{ '#LDS#Delegate compliance violation approval decisions' | translate }}

    @@ -103,7 +128,7 @@

    {{ '#LDS#Delegate manager responsibilities for one identity' | translate }} - {{ '#LDS#Delegate manager responsibilities for {0} identities' | translate | ldsReplace : countReports }} + {{ '#LDS#Delegate manager responsibilities for {0} identities' | translate | ldsReplace: countReports }}

    @@ -112,7 +137,7 @@

    {{ '#LDS#Delegate attestation approval decisions' | translate }}

    - +

    {{ '#LDS#Delegate responsibilities for roles of the following role classes' | translate }}:

    @@ -127,7 +152,7 @@

    {{ (roleClass.CountRolesOwned.value > 1 ? '#LDS#Responsible for {0} roles' : '#LDS#Responsible for one role') | translate - | ldsReplace : roleClass.CountRolesOwned.value + | ldsReplace: roleClass.CountRolesOwned.value }} @@ -139,10 +164,10 @@

    -
    +
    >
    {{ delegateable.TargetObjectKey.Column.GetDisplayValue() }} - ({{ delegateable.TargetType.Column.GetDisplayValue() }}) + + ({{ delegateable.TargetType.Column.GetDisplayValue() }})
    -
    ({{ delegateable.Criteria.Column.GetDisplayValue() }})
    +
    ({{ delegateable.Criteria.Column.GetDisplayValue() }})
    @@ -186,11 +213,15 @@

    -
    - +
    +
    - + {{ '#LDS#Specify additional options' | translate }}
    @@ -230,29 +267,32 @@

    [attr.data-imx-identifier]="'imx-delegation-step-4' + cdr.column.ColumnName" *ngFor="let cdr of cdrTimeSpan" [cdr]="cdr" - (controlCreated)="addControl(delegationForm, cdr.column.ColumnName, $event)" + (controlCreated)="addControl(delegationForm, cdr?.column?.ColumnName ?? '', $event)" > - {{ '#LDS#The specified validity period is invalid. The validity end date is before the validity start date. Please change the validity period.' | translate }} + {{ + '#LDS#The specified validity period is invalid. The validity end date is before the validity start date. Please change the validity period.' + | translate + }}

    -
    +
    @@ -289,9 +334,22 @@

    +
    + +
    + -
    +
    -

    {{ '#LDS#There are no role memberships or responsibilities you can delegate.' | translate }}

    +

    + {{ + (navigationState.search + ? '#LDS#There are no role memberships or responsibilities matching your search.' + : '#LDS#There are no role memberships or responsibilities you can delegate.' + ) | translate + }} +

    diff --git a/imxweb/projects/qer/src/lib/delegation/delegation.component.scss b/imxweb/projects/qer/src/lib/delegation/delegation.component.scss index 091437dce..5a767d1b6 100644 --- a/imxweb/projects/qer/src/lib/delegation/delegation.component.scss +++ b/imxweb/projects/qer/src/lib/delegation/delegation.component.scss @@ -1,4 +1,5 @@ @import '@elemental-ui/core/src/styles/_eui_palette.scss'; +@import 'base/mixins'; @mixin stepper-margin { margin-top: 16px; @@ -6,23 +7,12 @@ } :host { - display: flex; - flex-direction: column; - height: 100%; - overflow: hidden; + @include flex-column-container($height: 100%, $overflow: hidden); .imx-stepper-content { @include stepper-margin(); } - .imx-step-button, - .imx-step-button-save { - display: flex; - > *:not(:last-child) { - margin-right: 10px; - } - } - //For hiding components during loading .hidden { display: none; @@ -34,61 +24,35 @@ } .imx-roles-form { - display: flex; - flex-direction: column; - height: 390px; + @include flex-column-container($height: 390px); border-radius: 5px; padding: 5px; @include stepper-margin(); } - .imx-step-button-save { - align-self: flex-end; - margin-top: 16px; - } - .imx-type-selector { @include stepper-margin(); - > .mat-radio-button { - margin-left: 25px; - } } .imx-delegatable-elements { - overflow: hidden; margin-bottom: 10px; max-height: 600px; - display: flex; - flex: 1 1 auto; - } - - .imx-delegatable-elements mat-list-option .subtext { - font-size: 11px; - font-style: italic; - margin-bottom: 10px; - } - - .imx-delegatable-elements mat-list-option { - font-size: smaller; + @include flex-row-container-fill(); + overflow: hidden; } .imx-delegation-stepper { - flex: 1 1 auto; + @include flex-column-container-fill(); max-width: 100%; - display: flex; - flex-direction: column; margin: 3px; - overflow: hidden; > :first-child { - display: flex; - flex-direction: column; - flex: 1 1 auto; + @include flex-column-container-fill(); overflow: auto; } } - .imx-delegation-list { + .imx-list-container { display: flex; flex-direction: column; flex: 1 1 auto; @@ -105,41 +69,6 @@ > :last-child { flex: 1 1 auto; } - - ::ng-deep .mat-paginator { - box-shadow: none; - } - } - - .multi-select-formcontrol-eui-search { - width: 100%; - display: flex; - - .eui-search { - width: 100%; - } - - ::ng-deep .eui-search.mat-form-field.mat-form-field-appearance-outline { - min-width: 280px; - flex: 1; - margin-bottom: 10px; - } - } - - .imx-selected-entitlements { - margin: 0; - line-height: 36px; - font-size: 13.3px; - flex: auto; - - ::ng-deep .imx-badge.eui-badge .eui-badge-content { - font-size: 13.3px; - line-height: 14px; - } - } - - .imx-badge { - background-color: inherit; } } @@ -148,28 +77,19 @@ } .imx-small-error { - font-size: small; - margin: -25px 0 20px 10px; + font-size: 12px; + margin-bottom: 12px; } .imx-delegation-success { margin: 20px; - flex: 1 1 auto; width: max-content; } - .imx-alert-content { - flex: 1 1 auto; - display: flex; - flex-direction: column; - } - .imx-global-elements { + @include flex-column-container-fill(); padding-left: 1em; overflow-y: auto; - flex: 1 1 auto; - display: flex; - flex-direction: column; imx-busy-indicator { flex: 1 1 auto; @@ -194,7 +114,7 @@ margin: 30px 0 0 0; } - .imx-no-delegatable-items { + .imx-no-results { display: flex; margin: 20px 0; flex: 1 1 auto; @@ -202,10 +122,6 @@ flex-direction: column; align-items: center; - .eui-icon { - font-size: 100px; - } - p { margin: 0; font-size: 18px; @@ -214,18 +130,13 @@ .imx-additional-informations { @include stepper-margin(); - overflow: auto; } } // Theming .eui-light-theme { :host { - .imx-no-delegatable-items { - .eui-icon { - color: $color-gray-10; - } - + .imx-no-results { p { color: $color-gray-50; } @@ -234,24 +145,12 @@ .imx-roles-form { border: $color-gray-10 1px solid; } - - .imx-delegatable-elements mat-list-option .subtext { - color: $color-gray-40; - } } } .eui-dark-theme { :host { - .imx-delegatable-elements mat-list-option .subtext { - color: $color-gray-20; - } - - .imx-no-delegatable-items { - .eui-icon { - color: $color-gray-20; - } - + .imx-no-results { p { color: $color-gray-10; } @@ -261,15 +160,7 @@ .eui-contrast-theme { :host { - .imx-delegatable-elements mat-list-option .subtext { - color: $color-gray-0; - } - - .imx-no-delegatable-items { - .eui-icon { - color: $color-gray-10; - } - + .imx-no-results { p { color: $color-gray-0; } diff --git a/imxweb/projects/qer/src/lib/delegation/delegation.component.ts b/imxweb/projects/qer/src/lib/delegation/delegation.component.ts index 6da6a3cd5..1455064ee 100644 --- a/imxweb/projects/qer/src/lib/delegation/delegation.component.ts +++ b/imxweb/projects/qer/src/lib/delegation/delegation.component.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -24,29 +24,38 @@ * */ +import { STEPPER_GLOBAL_OPTIONS, StepperSelectionEvent } from '@angular/cdk/stepper'; import { ChangeDetectorRef, Component, OnDestroy, OnInit, ViewChild } from '@angular/core'; import { AbstractControl, UntypedFormControl, UntypedFormGroup, ValidatorFn } from '@angular/forms'; -import { StepperSelectionEvent, STEPPER_GLOBAL_OPTIONS } from '@angular/cdk/stepper'; -import { EuiLoadingService } from '@elemental-ui/core'; import { MatSelectionList, MatSelectionListChange } from '@angular/material/list'; import { PageEvent } from '@angular/material/paginator'; -import { Subscription } from 'rxjs'; -import { distinctUntilChanged, debounceTime } from 'rxjs/operators'; import { MatStep, MatStepper } from '@angular/material/stepper'; +import { EuiLoadingService } from '@elemental-ui/core'; +import { Subscription } from 'rxjs'; +import { debounceTime, distinctUntilChanged } from 'rxjs/operators'; -import { ColumnDependentReference, BaseCdr, EntityService, AuthenticationService, ClassloggerService, BusyService } from 'qbm'; import { - PortalDelegations, - PortalDelegable, - QerProjectConfig, GlobalDelegationInput, + PortalDelegable, + PortalDelegations, PortalDelegationsGlobalRoleclasses, -} from 'imx-api-qer'; + QerProjectConfig, +} from '@imx-modules/imx-api-qer'; +import { + AuthenticationService, + BaseCdr, + BusyService, + ClassloggerService, + ColumnDependentReference, + EntityService, + ISessionState, +} from 'qbm'; import { ProjectConfigurationService } from '../project-configuration/project-configuration.service'; -import { DelegationService } from './delegation.service'; import { UserModelService } from '../user/user-model.service'; +import { DelegationService } from './delegation.service'; -import { CollectionLoadParameters } from 'imx-qbm-dbts'; +import { CollectionLoadParameters } from '@imx-modules/imx-qbm-dbts'; +import moment from 'moment'; import { QerPermissionsService } from '../admin/qer-permissions.service'; /** @@ -87,19 +96,20 @@ export class DelegationComponent implements OnInit, OnDestroy { public cdrList: ColumnDependentReference[]; public completed = false; - public state: string; + public state: string | undefined; public withSubordinates = false; public isManager = false; public cdrPersonSender: ColumnDependentReference; - public readonly recipientFormGroup = new UntypedFormGroup({}); + public recipientFormGroup: UntypedFormGroup; public readonly delegationForm = new UntypedFormGroup({}, DelegationComponent.dateIsAscending()); - public readonly senderFormGroup = new UntypedFormGroup({}); + public senderFormGroup: UntypedFormGroup; public busyService = new BusyService(); public isLoading = false; public initialized = false; + public isSaving = false; @ViewChild(MatSelectionList) public roleAndMembershipList: MatSelectionList; @ViewChild('delegationObjects') public delegationObjects: MatStep; @@ -111,6 +121,9 @@ export class DelegationComponent implements OnInit, OnDestroy { public countReports: number; public roleClasses: PortalDelegationsGlobalRoleclasses[] = []; + public canDelegateAll: boolean = true; + public canDelegateSelected: boolean = true; + private subscriptions: Subscription[] = []; public navigationState: CollectionLoadParameters = { PageSize: 20 }; private projectConfig: QerProjectConfig; @@ -128,11 +141,13 @@ export class DelegationComponent implements OnInit, OnDestroy { private readonly permissions: QerPermissionsService, private readonly elementalBusy: EuiLoadingService, private readonly changeDetector: ChangeDetectorRef, - authenticationservice: AuthenticationService + authenticationservice: AuthenticationService, ) { this.initGlobalDelegation(); this.initSearchControl(); - this.subscriptions.push(authenticationservice.onSessionResponse.subscribe((session) => (this.uidPerson = session.UserUid))); + this.subscriptions.push( + authenticationservice.onSessionResponse.subscribe((session: ISessionState) => (this.uidPerson = session.UserUid || '')), + ); this.busyService.busyStateChanged.subscribe((value) => { this.isLoading = value; changeDetector.detectChanges(); @@ -148,7 +163,12 @@ export class DelegationComponent implements OnInit, OnDestroy { try { this.projectConfig = await this.projectConfigSvc.getConfig(); this.newDelegation = await this.delegationService.createDelegation(); - this.isManager = await this.permissions.isPersonManager(); + this.isManager = (await this.permissions.isPersonManager()) || (await this.permissions.isPersonAdmin()); + this.canDelegateAll = this.projectConfig.EnableNewDelegationSubstitute; + this.canDelegateSelected = this.projectConfig.EnableNewDelegationIndividual; + if (!this.canDelegateAll || !this.canDelegateSelected) { + this.isGlobalDelegation = this.canDelegateAll; // because if both were false, the component would not be displayed anyway + } } finally { isBusy.endBusy(); this.initialized = true; @@ -194,6 +214,7 @@ export class DelegationComponent implements OnInit, OnDestroy { */ public async saveDelegation(): Promise { let overlay = this.elementalBusy.show(); + this.isSaving = true; this.changeDetector.detectChanges(); try { if (this.isGlobalDelegation) { @@ -205,6 +226,7 @@ export class DelegationComponent implements OnInit, OnDestroy { this.state = 'done'; } finally { this.elementalBusy.hide(overlay); + this.isSaving = false; } } @@ -243,7 +265,7 @@ export class DelegationComponent implements OnInit, OnDestroy { */ public onSelectall(): void { const items = this.roleAndMembershipList.options.filter( - (elem) => this.selections.findIndex((sel) => sel.ObjectKeyToDelegate.value === elem.value.ObjectKeyToDelegate.value) === -1 + (elem) => this.selections.findIndex((sel) => sel.ObjectKeyToDelegate.value === elem.value.ObjectKeyToDelegate.value) === -1, ); items.forEach((element) => { @@ -287,7 +309,7 @@ export class DelegationComponent implements OnInit, OnDestroy { * @param cdr the cdr to check * @returns true, if the delegation is not global and the columnname is IsDelegable */ - public isShowCdr(cdr: BaseCdr): boolean { + public isShowCdr(cdr: ColumnDependentReference): boolean { return !this.isGlobalDelegation || cdr.column.ColumnName !== 'IsDelegable'; } @@ -357,11 +379,7 @@ export class DelegationComponent implements OnInit, OnDestroy { // Update date from cdr this.newDelegation.InsertValidFrom.value = this.cdrTimeSpan[0].column.GetValue(); this.newDelegation.InsertValidUntil.value = this.cdrTimeSpan[1].column.GetValue(); - - await this.delegationService.commitDelegations( - this.newDelegation, - this.selections.map((option) => option.ObjectKeyToDelegate.value) - ); + await this.delegationService.commitDelegations(this.newDelegation, this.selections); } /** @@ -387,7 +405,7 @@ export class DelegationComponent implements OnInit, OnDestroy { const delegations = await this.delegationService.getDelegatableItems( this.uidDelegator, this.newDelegation.UID_PersonReceiver.value, - this.navigationState + this.navigationState, ); this.paginatorConfig.length = delegations.totalCount; this.delegateableItems = delegations.Data; @@ -395,7 +413,7 @@ export class DelegationComponent implements OnInit, OnDestroy { this.logger.trace(this, 'Try marking items as selected'); if (this.roleAndMembershipList) { const preselectedElements = this.roleAndMembershipList.options.filter( - (elem) => this.selections.findIndex((sel) => sel.ObjectKeyToDelegate.value === elem.value.ObjectKeyToDelegate.value) !== -1 + (elem) => this.selections.findIndex((sel) => sel.ObjectKeyToDelegate.value === elem.value.ObjectKeyToDelegate.value) !== -1, ); preselectedElements.forEach((elem) => elem.toggle()); this.logger.trace(this, 'items marked es selected', preselectedElements); @@ -417,15 +435,15 @@ export class DelegationComponent implements OnInit, OnDestroy { * Inits the 'Select the identity which responsibilities you like to delegate' form */ private initSenderForm(): void { - Object.keys(this.senderFormGroup.controls).forEach((name) => this.recipientFormGroup.removeControl(name)); - this.cdrPersonSender = this.delegationService.buildSenderCdr(this.newDelegation); + this.senderFormGroup = new UntypedFormGroup({}); + this.cdrPersonSender = new BaseCdr(this.newDelegation.UID_PersonSender.Column); } /** * Inits the 'Select the identity to which you want to delegate' form */ private initRecipientForm(): void { - Object.keys(this.recipientFormGroup.controls).forEach((name) => this.recipientFormGroup.removeControl(name)); + this.recipientFormGroup = new UntypedFormGroup({}); this.cdrPersonRecipient = new BaseCdr(this.newDelegation.UID_PersonReceiver.Column); } @@ -437,7 +455,7 @@ export class DelegationComponent implements OnInit, OnDestroy { const values = [this.newDelegation.KeepMeInformed.Column, this.newDelegation.IsDelegable.Column, this.newDelegation.OrderReason.Column]; - if (this.projectConfig.ITShopConfig.VI_ITShop_EnablePWOPriorityChange) { + if (this.projectConfig.ITShopConfig?.VI_ITShop_EnablePWOPriorityChange) { values.push(this.newDelegation.PWOPriority.Column); } @@ -453,7 +471,7 @@ export class DelegationComponent implements OnInit, OnDestroy { const schema = this.delegationService.getDelegationSchema(); this.cdrTimeSpan = [schema.Columns.InsertValidFrom, schema.Columns.InsertValidUntil].map((property) => { property.IsReadOnly = false; - return new BaseCdr(this.entityService.createLocalEntityColumn(property, undefined, { ValueConstraint: { MinValue: new Date() } })); + return new BaseCdr(this.entityService.createLocalEntityColumn(property, undefined, { ValueConstraint: { MinValue: moment() } })); }); } @@ -467,7 +485,7 @@ export class DelegationComponent implements OnInit, OnDestroy { this.navigationState = { ...this.navigationState, ...{ search: value, StartIndex: 0 } }; this.paginatorConfig.index = 0; await this.navigateDelegateable(); - }) + }), ); } @@ -480,12 +498,12 @@ export class DelegationComponent implements OnInit, OnDestroy { private buildValidationFunction(): ValidatorFn { return (control: AbstractControl): { [key: string]: boolean } | null => { if (this.isGlobalDelegation) { - return this.isValidGlobalDelegation ? null : { invalid: true }; + return this.isValidGlobalDelegation() ? null : { invalid: true }; } // at least one item set? const group = control as UntypedFormGroup; - return group == null || group.get('items') == null || group.get('items').value == null || group.get('items').value.length > 0 + return group == null || group.get('items') == null || group.get('items')?.value == null || group.get('items')?.value.length > 0 ? null : { noRoleSelected: true }; }; diff --git a/imxweb/projects/qer/src/lib/delegation/delegation.module.ts b/imxweb/projects/qer/src/lib/delegation/delegation.module.ts index b7f1553f1..9c285adb5 100644 --- a/imxweb/projects/qer/src/lib/delegation/delegation.module.ts +++ b/imxweb/projects/qer/src/lib/delegation/delegation.module.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -27,33 +27,47 @@ import { CommonModule } from '@angular/common'; import { NgModule } from '@angular/core'; import { FormsModule, ReactiveFormsModule } from '@angular/forms'; -import { MatStepperModule, } from '@angular/material/stepper'; import { MatButtonModule } from '@angular/material/button'; -import { MatRadioModule } from '@angular/material/radio'; -import { MatListModule } from '@angular/material/list'; import { MatFormFieldModule } from '@angular/material/form-field'; +import { MatListModule } from '@angular/material/list'; +import { MatPaginatorModule } from '@angular/material/paginator'; +import { MatRadioModule } from '@angular/material/radio'; +import { MatStepperModule } from '@angular/material/stepper'; import { RouterModule, Routes } from '@angular/router'; -import { TranslateModule } from '@ngx-translate/core'; import { EuiCoreModule } from '@elemental-ui/core'; -import { MatPaginatorModule } from '@angular/material/paginator'; +import { TranslateModule } from '@ngx-translate/core'; -import { DataTableModule, RouteGuardService, ClassloggerService, CdrModule, LdsReplaceModule, MenuService, MenuItem, HELP_CONTEXTUAL, HelpContextualModule, BusyIndicatorModule, SelectedElementsModule } from 'qbm'; -import { DelegationComponent } from './delegation.component'; -import { DelegationService } from './delegation.service'; +import { MatCardModule } from '@angular/material/card'; import { MatCheckboxModule } from '@angular/material/checkbox'; import { MatProgressSpinnerModule } from '@angular/material/progress-spinner'; -import { MatCardModule } from '@angular/material/card'; +import { ProjectConfig, QerProjectConfig } from '@imx-modules/imx-api-qer'; +import { + BusyIndicatorModule, + CdrModule, + ClassloggerService, + DataTableModule, + HELP_CONTEXTUAL, + HelpContextualModule, + LdsReplaceModule, + MenuItem, + MenuService, + RouteGuardService, + SelectedElementsModule, +} from 'qbm'; +import { DelegationGuardService } from './delegation-guard.service'; +import { DelegationComponent } from './delegation.component'; +import { DelegationService } from './delegation.service'; const routes: Routes = [ { path: 'delegation', component: DelegationComponent, - canActivate: [RouteGuardService], + canActivate: [RouteGuardService, DelegationGuardService], resolve: [RouteGuardService], - data:{ - contextId: HELP_CONTEXTUAL.Delegation - } - } + data: { + contextId: HELP_CONTEXTUAL.Delegation, + }, + }, ]; @NgModule({ @@ -79,49 +93,46 @@ const routes: Routes = [ SelectedElementsModule, HelpContextualModule, BusyIndicatorModule, - SelectedElementsModule - ], - declarations: [ - DelegationComponent + SelectedElementsModule, ], - providers: [DelegationService] + declarations: [DelegationComponent], + providers: [DelegationService], }) export class DelegationModule { constructor( private readonly menuService: MenuService, - logger: ClassloggerService + logger: ClassloggerService, ) { logger.info(this, '▶️ DelegationModule loaded'); this.setupMenu(); } private setupMenu(): void { - this.menuService.addMenuFactories( - (preProps: string[], features: string[]) => { - - const items: MenuItem[] = []; + this.menuService.addMenuFactories((preProps: string[], features: string[], projectConfig: QerProjectConfig & ProjectConfig) => { + const items: MenuItem[] = []; - if (preProps.includes('ITSHOP') && preProps.includes('DELEGATION')) { - items.push( - { - id: 'QER_Responsibilities_Delegation', - route: 'delegation', - title: '#LDS#Menu Entry Delegation', - sorting: '30-10', - }, - ); - } + if ( + preProps.includes('ITSHOP') && + preProps.includes('DELEGATION') && + (projectConfig.EnableNewDelegationIndividual || projectConfig.EnableNewDelegationSubstitute) + ) { + items.push({ + id: 'QER_Responsibilities_Delegation', + route: 'delegation', + title: '#LDS#Menu Entry Delegation', + sorting: '30-10', + }); + } - if (items.length === 0) { - return null; - } - return { - id: 'ROOT_Responsibilities', - title: '#LDS#Responsibilities', - sorting: '30', - items - }; - }, - ); + if (items.length === 0) { + return; + } + return { + id: 'ROOT_Responsibilities', + title: '#LDS#Responsibilities', + sorting: '30', + items, + }; + }); } } diff --git a/imxweb/projects/qer/src/lib/delegation/delegation.service.ts b/imxweb/projects/qer/src/lib/delegation/delegation.service.ts index ae3e44fbe..84ffa49a1 100644 --- a/imxweb/projects/qer/src/lib/delegation/delegation.service.ts +++ b/imxweb/projects/qer/src/lib/delegation/delegation.service.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -26,15 +26,12 @@ import { Injectable } from '@angular/core'; -import { - CollectionLoadParameters, - EntitySchema, - ExtendedTypedEntityCollection, -} from 'imx-qbm-dbts'; -import { GlobalDelegationInput, PortalDelegable, PortalDelegations, PortalDelegationsGlobalRoleclasses } from 'imx-api-qer'; +import { GlobalDelegationInput, PortalDelegable, PortalDelegations, PortalDelegationsGlobalRoleclasses } from '@imx-modules/imx-api-qer'; +import { CollectionLoadParameters, EntitySchema, ExtendedTypedEntityCollection } from '@imx-modules/imx-qbm-dbts'; +import { TranslateService } from '@ngx-translate/core'; +import { Action, BaseCdr, EntityService, ProcessingQueueService } from 'qbm'; import { QerApiService } from '../qer-api-client.service'; -import { BaseCdr, EntityService } from 'qbm'; @Injectable({ providedIn: 'root', @@ -43,6 +40,8 @@ export class DelegationService { constructor( private readonly qerApiService: QerApiService, private readonly entityService: EntityService, + private readonly queueService: ProcessingQueueService, + private readonly translate: TranslateService, ) {} public getDelegationSchema(): EntitySchema { @@ -56,7 +55,7 @@ export class DelegationService { public async getDelegatableItems( uidUser: string, uidRecipient: string, - parameter: CollectionLoadParameters + parameter: CollectionLoadParameters, ): Promise> { return this.qerApiService.typedClient.PortalDelegable.Get(uidUser, uidRecipient, parameter); } @@ -74,38 +73,73 @@ export class DelegationService { const fkProviderItems = this.qerApiService.client.getFkProviderItems('portal/delegations').map((item) => ({ ...item, load: (_, parameters = {}) => this.qerApiService.client.portal_person_reports_get({ ...parameters, OnlyDirect: true }), - getDataModel: async (entity) => item.getDataModel(entity), - getFilterTree: async (entity, parentKey) => item.getFilterTree(entity, parentKey), + getDataModel: async (entity) => item.getDataModel?.(entity) || {}, + getFilterTree: async (entity, parentKey) => item.getFilterTree?.(entity, parentKey) || {}, })); const column = this.entityService.createLocalEntityColumn( schema.Columns.UID_PersonSender, fkProviderItems, undefined, - async (_, newValue: string) => await entity.UID_PersonSender.Column.PutValue(newValue) + async (_, newValue: string) => await entity.UID_PersonSender.Column.PutValue(newValue), ); return new BaseCdr(column); } - public async commitDelegations(reference: PortalDelegations, objectKeys: string[]): Promise { - reference.ObjectKeyDelegated.value = objectKeys[0]; + public async commitDelegations(reference: PortalDelegations, delegations: PortalDelegable[]): Promise { + reference.ObjectKeyDelegated.value = delegations[0].ObjectKeyToDelegate.value; - if (objectKeys.length > 1) { - objectKeys.shift(); - for (const objectKey of objectKeys) { - const element = await this.createDelegation(); - for (const key in this.qerApiService.typedClient.PortalDelegations.GetSchema().Columns) { - if (!key.startsWith('__') && reference[key].GetMetadata().CanEdit()) { - await element[key].Column.PutValueStruct({ - DataValue: reference[key].value, - DisplayValue: reference[key].Column.GetDisplayValue(), - }); + // If there is more delegations here, then use the queuing service + if (delegations.length > this.queueService.actionThreshold) { + const actions = delegations.map((delegation, index) => { + let action: () => Promise; + // Skip first, it is handled above and in the group action, append group action to final action + if (index == 0) { + action = async () => {}; + } else { + action = async () => { + const element = await this.createDelegation(); + for (const key in this.qerApiService.typedClient.PortalDelegations.GetSchema().Columns) { + if (!key.startsWith('__') && reference[key].GetMetadata().CanEdit()) { + await element[key].Column.PutValueStruct({ + DataValue: reference[key].value, + DisplayValue: reference[key].Column.GetDisplayValue(), + }); + } + } + element.ObjectKeyDelegated.value = delegation.ObjectKeyToDelegate.value; + await element.GetEntity().Commit(false); + }; + } + const title = [reference.GetEntity().GetSchema().DisplaySingular, delegation.GetEntity().GetDisplay()].join(': '); + return new Action(title, '', action); + }); + + actions.push( + new Action(this.translate.instant('#LDS#Completing delegations'), '', async () => await reference.GetEntity().Commit(false)), + ); + + const groupTitle = [reference.GetEntity().GetSchema().Display, reference.GetEntity().GetDisplay().trim()].join(' '); + this.queueService.submitGroupAction(groupTitle, actions); + } else { + // Classic approach to loop over other delegates + if (delegations.length > 1) { + delegations.shift(); + for (const delegation of delegations) { + const element = await this.createDelegation(); + for (const key in this.qerApiService.typedClient.PortalDelegations.GetSchema().Columns) { + if (!key.startsWith('__') && reference[key].GetMetadata().CanEdit()) { + await element[key].Column.PutValueStruct({ + DataValue: reference[key].value, + DisplayValue: reference[key].Column.GetDisplayValue(), + }); + } } + element.ObjectKeyDelegated.value = delegation.ObjectKeyToDelegate.value; + await element.GetEntity().Commit(false); } - element.ObjectKeyDelegated.value = objectKey; - await element.GetEntity().Commit(false); } + await reference.GetEntity().Commit(false); } - await reference.GetEntity().Commit(false); } } diff --git a/imxweb/projects/qer/src/lib/dynamic-exclusion-dialog/dynamic-exclusion-dialog.component.html b/imxweb/projects/qer/src/lib/dynamic-exclusion-dialog/dynamic-exclusion-dialog.component.html index b343747b6..86d6f2377 100644 --- a/imxweb/projects/qer/src/lib/dynamic-exclusion-dialog/dynamic-exclusion-dialog.component.html +++ b/imxweb/projects/qer/src/lib/dynamic-exclusion-dialog/dynamic-exclusion-dialog.component.html @@ -1,23 +1,19 @@ -

    +

    #LDS#Heading Specify Reason for Exclusion -

    +

    - - - - - #LDS#Reason - - + + + #LDS#Reason + -
    -
    +
    diff --git a/imxweb/projects/qer/src/lib/dynamic-exclusion-dialog/dynamic-exclusion-dialog.component.scss b/imxweb/projects/qer/src/lib/dynamic-exclusion-dialog/dynamic-exclusion-dialog.component.scss deleted file mode 100644 index 820cdcf6d..000000000 --- a/imxweb/projects/qer/src/lib/dynamic-exclusion-dialog/dynamic-exclusion-dialog.component.scss +++ /dev/null @@ -1,3 +0,0 @@ -.mat-form-field { - width: 100%; -} diff --git a/imxweb/projects/qer/src/lib/dynamic-exclusion-dialog/dynamic-exclusion-dialog.component.ts b/imxweb/projects/qer/src/lib/dynamic-exclusion-dialog/dynamic-exclusion-dialog.component.ts index 0d2fee141..3f216518b 100644 --- a/imxweb/projects/qer/src/lib/dynamic-exclusion-dialog/dynamic-exclusion-dialog.component.ts +++ b/imxweb/projects/qer/src/lib/dynamic-exclusion-dialog/dynamic-exclusion-dialog.component.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -31,26 +31,26 @@ import { MatDialogRef } from '@angular/material/dialog'; @Component({ selector: 'imx-dynamic-exclusion-dialog', templateUrl: './dynamic-exclusion-dialog.component.html', - styleUrls: ['./dynamic-exclusion-dialog.component.scss'] }) export class DynamicExclusionDialogComponent implements OnInit { - public dynamicExclusionForm: UntypedFormGroup; - constructor(private formBuilder: UntypedFormBuilder, public dialogRef: MatDialogRef) {} + constructor( + private formBuilder: UntypedFormBuilder, + public dialogRef: MatDialogRef, + ) {} public ngOnInit(): void { this.dynamicExclusionForm = this.formBuilder.group({ - description: [''] + description: [''], }); } public save(): void { - this.dialogRef.close(this.dynamicExclusionForm.get('description').value); + this.dialogRef.close(this.dynamicExclusionForm.get('description')?.value); } public cancel(): void { this.dialogRef.close(undefined); } - } diff --git a/imxweb/projects/qer/src/lib/dynamic-exclusion-dialog/dynamic-exclusion-dialog.module.ts b/imxweb/projects/qer/src/lib/dynamic-exclusion-dialog/dynamic-exclusion-dialog.module.ts index 3578b0969..96b01421c 100644 --- a/imxweb/projects/qer/src/lib/dynamic-exclusion-dialog/dynamic-exclusion-dialog.module.ts +++ b/imxweb/projects/qer/src/lib/dynamic-exclusion-dialog/dynamic-exclusion-dialog.module.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -24,17 +24,18 @@ * */ -import { CommonModule } from "@angular/common"; -import { NgModule } from "@angular/core"; -import { FormsModule, ReactiveFormsModule } from "@angular/forms"; -import { RouterModule } from "@angular/router"; -import { EuiCoreModule, EuiMaterialModule } from "@elemental-ui/core"; -import { TranslateModule } from "@ngx-translate/core"; -import { CdrModule, DataSourceToolbarModule, DataTableModule, LdsReplaceModule, FkAdvancedPickerModule } from "qbm"; -import { DynamicExclusionDialogComponent } from "./dynamic-exclusion-dialog.component"; +import { CommonModule } from '@angular/common'; +import { NgModule } from '@angular/core'; +import { FormsModule, ReactiveFormsModule } from '@angular/forms'; +import { RouterModule } from '@angular/router'; +import { EuiCoreModule, EuiMaterialModule } from '@elemental-ui/core'; +import { TranslateModule } from '@ngx-translate/core'; +import { CdrModule, DataSourceToolbarModule, DataTableModule, LdsReplaceModule, FkAdvancedPickerModule } from 'qbm'; +import { DynamicExclusionDialogComponent } from './dynamic-exclusion-dialog.component'; @NgModule({ - imports: [CommonModule, + imports: [ + CommonModule, FormsModule, ReactiveFormsModule, EuiCoreModule, @@ -45,9 +46,8 @@ import { DynamicExclusionDialogComponent } from "./dynamic-exclusion-dialog.comp DataTableModule, LdsReplaceModule, FkAdvancedPickerModule, - RouterModule + RouterModule, ], - declarations: [DynamicExclusionDialogComponent] + declarations: [DynamicExclusionDialogComponent], }) -export class DynamicExclusionDialogModule { -} \ No newline at end of file +export class DynamicExclusionDialogModule {} diff --git a/imxweb/projects/qer/src/lib/filter-sqlwizard/filter-sqlwizard.service.ts b/imxweb/projects/qer/src/lib/filter-sqlwizard/filter-sqlwizard.service.ts new file mode 100644 index 000000000..045365ee8 --- /dev/null +++ b/imxweb/projects/qer/src/lib/filter-sqlwizard/filter-sqlwizard.service.ts @@ -0,0 +1,45 @@ +/* + * ONE IDENTITY LLC. PROPRIETARY INFORMATION + * + * This software is confidential. One Identity, LLC. or one of its affiliates or + * subsidiaries, has supplied this software to you under terms of a + * license agreement, nondisclosure agreement or both. + * + * You may not copy, disclose, or use this software except in accordance with + * those terms. + * + * + * Copyright 2024 One Identity LLC. + * ALL RIGHTS RESERVED. + * + * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR + * WARRANTIES ABOUT THE SUITABILITY OF THE SOFTWARE, + * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED + * TO THE IMPLIED WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE, OR + * NON-INFRINGEMENT. ONE IDENTITY LLC. SHALL NOT BE + * LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE + * AS A RESULT OF USING, MODIFYING OR DISTRIBUTING + * THIS SOFTWARE OR ITS DERIVATIVES. + * + */ + +import { Injectable } from '@angular/core'; +import { CollectionLoadParameters, EntityCollectionData, FilterProperty } from '@imx-modules/imx-qbm-dbts'; +import { SqlWizardApiService } from 'qbm'; +import { QerApiService } from '../qer-api-client.service'; + +@Injectable() +export class FilterSqlWizardService extends SqlWizardApiService { + constructor(private readonly api: QerApiService) { + super(); + } + + public async getFilterProperties(table: string): Promise { + return (await this.api.client.portal_sqlwizard_tables_columns_get(table)).Properties || []; + } + + public async getCandidates(parentTable: string, options?: CollectionLoadParameters): Promise { + return await this.api.v2Client.portal_sqlwizard_candidates_get(parentTable, options); + } +} diff --git a/imxweb/projects/qer/src/lib/guards/application-guard.service.ts b/imxweb/projects/qer/src/lib/guards/application-guard.service.ts index f83045c5b..d628dd841 100644 --- a/imxweb/projects/qer/src/lib/guards/application-guard.service.ts +++ b/imxweb/projects/qer/src/lib/guards/application-guard.service.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -25,22 +25,22 @@ */ import { Injectable, OnDestroy } from '@angular/core'; -import { CanActivate, ActivatedRouteSnapshot, RouterStateSnapshot, Router } from '@angular/router'; +import { ActivatedRouteSnapshot, Router, RouterStateSnapshot } from '@angular/router'; import { Observable, Subscription } from 'rxjs'; -import { AppConfigService, AuthenticationService, ISessionState } from "qbm"; +import { AppConfigService, AuthenticationService, ISessionState } from 'qbm'; @Injectable({ providedIn: 'root', }) -export class ApplicationGuardService implements CanActivate, OnDestroy { +export class ApplicationGuardService implements OnDestroy { private onSessionResponse: Subscription; constructor( private readonly authentication: AuthenticationService, private readonly appConfig: AppConfigService, - private readonly router: Router - ) { } + private readonly router: Router, + ) {} public canActivate(route: ActivatedRouteSnapshot, _: RouterStateSnapshot): Observable { return new Observable((observer) => { @@ -48,7 +48,7 @@ export class ApplicationGuardService implements CanActivate, OnDestroy { if (sessionState.IsLoggedIn) { const isPortal = this.appConfig?.Config?.WebAppIdentifier?.toLocaleLowerCase() === 'portal'; if (!isPortal) { - this.router.navigate([this.appConfig.Config.routeConfig.start], { queryParams: {} }); + this.router.navigate([this.appConfig.Config?.routeConfig?.start], { queryParams: {} }); } observer.next(isPortal ? true : false); observer.complete(); diff --git a/imxweb/projects/qer/src/lib/guards/data-explorer-guard.service.ts b/imxweb/projects/qer/src/lib/guards/data-explorer-guard.service.ts deleted file mode 100644 index 9e0c493c0..000000000 --- a/imxweb/projects/qer/src/lib/guards/data-explorer-guard.service.ts +++ /dev/null @@ -1,87 +0,0 @@ -/* - * ONE IDENTITY LLC. PROPRIETARY INFORMATION - * - * This software is confidential. One Identity, LLC. or one of its affiliates or - * subsidiaries, has supplied this software to you under terms of a - * license agreement, nondisclosure agreement or both. - * - * You may not copy, disclose, or use this software except in accordance with - * those terms. - * - * - * Copyright 2023 One Identity LLC. - * ALL RIGHTS RESERVED. - * - * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR - * WARRANTIES ABOUT THE SUITABILITY OF THE SOFTWARE, - * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED - * TO THE IMPLIED WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE, OR - * NON-INFRINGEMENT. ONE IDENTITY LLC. SHALL NOT BE - * LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE - * AS A RESULT OF USING, MODIFYING OR DISTRIBUTING - * THIS SOFTWARE OR ITS DERIVATIVES. - * - */ - -import { Injectable, OnDestroy } from '@angular/core'; -import { CanActivate, Router } from '@angular/router'; -import { Observable, Subscription } from 'rxjs'; - -import { AppConfigService, AuthenticationService, ISessionState, SystemInfoService } from 'qbm'; -import { QerPermissionsService } from '../admin/qer-permissions.service'; - -@Injectable({ - providedIn: 'root', -}) -export class DataExplorerGuardService implements CanActivate, OnDestroy { - private onSessionResponse: Subscription; - - constructor( - private readonly qerPermissionService: QerPermissionsService, - private readonly authentication: AuthenticationService, - private readonly appConfig: AppConfigService, - private readonly router: Router, - private readonly systemInfoService: SystemInfoService - ) {} - - public canActivate(): Observable { - return new Observable((observer) => { - this.onSessionResponse = this.authentication.onSessionResponse.subscribe(async (sessionState: ISessionState) => { - if (sessionState.IsLoggedIn) { - const userIsAdmin = await this.qerPermissionService.isPersonAdmin(); - const userIsAuditor = await this.qerPermissionService.isAuditor(); - const userIsResourceAdmin = await this.qerPermissionService.isResourceAdmin(); - const userIsRoleAdmin = await this.qerPermissionService.isRoleAdmin(); - const userIsRoleStatistics = await this.qerPermissionService.isRoleStatistics(); - const userIsStructStatistics = await this.qerPermissionService.isStructStatistics(); - const userIsStructAdmin = await this.qerPermissionService.isStructAdmin(); - const userIsTsbNameSpaceAdminBase = await this.qerPermissionService.isTsbNameSpaceAdminBase(); - const systemInfo = await this.systemInfoService.get(); - const isItShop = systemInfo.PreProps.includes('ITSHOP'); - const isActive = - (isItShop && (userIsAdmin || userIsAuditor)) || - userIsResourceAdmin || - userIsAuditor || - userIsRoleAdmin || - userIsRoleStatistics || - userIsStructStatistics || - userIsStructAdmin || - (isItShop && userIsTsbNameSpaceAdminBase); - - if (!isActive) { - this.router.navigate([this.appConfig.Config.routeConfig.start], { queryParams: {} }); - } - observer.next(isActive); - observer.complete(); - } - }); - }); - } - - public ngOnDestroy(): void { - if (this.onSessionResponse) { - this.onSessionResponse.unsubscribe(); - } - } -} diff --git a/imxweb/projects/qer/src/lib/guards/feature-guard.service.ts b/imxweb/projects/qer/src/lib/guards/feature-guard.service.ts index 3cd287be3..19137027e 100644 --- a/imxweb/projects/qer/src/lib/guards/feature-guard.service.ts +++ b/imxweb/projects/qer/src/lib/guards/feature-guard.service.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -25,23 +25,23 @@ */ import { Injectable, OnDestroy } from '@angular/core'; -import { ActivatedRouteSnapshot, CanActivate, Router } from '@angular/router'; +import { ActivatedRouteSnapshot, Router } from '@angular/router'; import { Observable, Subscription, of } from 'rxjs'; -import { QerPermissionsService } from '../admin/qer-permissions.service'; import { AppConfigService, AuthenticationService, ISessionState } from 'qbm'; +import { QerPermissionsService } from '../admin/qer-permissions.service'; @Injectable({ providedIn: 'root', }) -export class FeatureGuardService implements CanActivate, OnDestroy { +export class FeatureGuardService implements OnDestroy { private onSessionResponse: Subscription; constructor( private readonly qerPermissionService: QerPermissionsService, private readonly authentication: AuthenticationService, private readonly appConfig: AppConfigService, - private readonly router: Router + private readonly router: Router, ) {} public canActivate(route: ActivatedRouteSnapshot): Observable { @@ -51,7 +51,7 @@ export class FeatureGuardService implements CanActivate, OnDestroy { if (sessionState.IsLoggedIn) { const hasFeature = await this.qerPermissionService.hasFeatures(route.data.features); if (!hasFeature) { - this.router.navigate([this.appConfig.Config.routeConfig.start], { queryParams: {} }); + this.router.navigate([this.appConfig.Config?.routeConfig?.start], { queryParams: {} }); } observer.next(hasFeature); observer.complete(); diff --git a/imxweb/projects/qer/src/lib/guards/itshop-pattern-guard.service.ts b/imxweb/projects/qer/src/lib/guards/itshop-pattern-guard.service.ts index f7632df3e..f136a4fb4 100644 --- a/imxweb/projects/qer/src/lib/guards/itshop-pattern-guard.service.ts +++ b/imxweb/projects/qer/src/lib/guards/itshop-pattern-guard.service.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -25,7 +25,7 @@ */ import { Injectable, OnDestroy } from '@angular/core'; -import { CanActivate, Router } from '@angular/router'; +import { Router } from '@angular/router'; import { Observable, Subscription } from 'rxjs'; import { AppConfigService, AuthenticationService, ISessionState } from 'qbm'; @@ -37,23 +37,23 @@ import { ProjectConfigurationService } from '../project-configuration/project-co @Injectable({ providedIn: 'root', }) -export class ItshopPatternGuardService implements CanActivate, OnDestroy { +export class ItshopPatternGuardService implements OnDestroy { private onSessionResponse: Subscription; constructor( private readonly projectConfig: ProjectConfigurationService, private readonly authentication: AuthenticationService, private readonly appConfig: AppConfigService, - private readonly router: Router - ) { } + private readonly router: Router, + ) {} public canActivate(): Observable { return new Observable((observer) => { this.onSessionResponse = this.authentication.onSessionResponse.subscribe(async (sessionState: ISessionState) => { if (sessionState.IsLoggedIn) { - const isRequestTemplateEnabled = (await this.projectConfig.getConfig()).ITShopConfig.VI_ITShop_ProductSelectionFromTemplate; + const isRequestTemplateEnabled = (await this.projectConfig.getConfig()).ITShopConfig?.VI_ITShop_ProductSelectionFromTemplate; if (!isRequestTemplateEnabled) { - this.router.navigate([this.appConfig.Config.routeConfig.start], { queryParams: {} }); + this.router.navigate([this.appConfig.Config?.routeConfig?.start], { queryParams: {} }); } observer.next(isRequestTemplateEnabled); observer.complete(); diff --git a/imxweb/projects/qer/src/lib/guards/manager-guard.service.ts b/imxweb/projects/qer/src/lib/guards/manager-guard.service.ts index 6258f9194..2e04c4ef1 100644 --- a/imxweb/projects/qer/src/lib/guards/manager-guard.service.ts +++ b/imxweb/projects/qer/src/lib/guards/manager-guard.service.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -25,7 +25,7 @@ */ import { Injectable, OnDestroy } from '@angular/core'; -import { CanActivate, Router } from '@angular/router'; +import { Router } from '@angular/router'; import { Observable, Subscription } from 'rxjs'; import { AppConfigService, AuthenticationService, ISessionState } from 'qbm'; @@ -34,15 +34,15 @@ import { QerPermissionsService } from '../admin/qer-permissions.service'; @Injectable({ providedIn: 'root', }) -export class ManagerGuardService implements CanActivate, OnDestroy { +export class ManagerGuardService implements OnDestroy { private onSessionResponse: Subscription; constructor( private readonly qerPermissionService: QerPermissionsService, private readonly authentication: AuthenticationService, private readonly appConfig: AppConfigService, - private readonly router: Router - ) { } + private readonly router: Router, + ) {} public canActivate(): Observable { return new Observable((observer) => { @@ -50,7 +50,7 @@ export class ManagerGuardService implements CanActivate, OnDestroy { if (sessionState.IsLoggedIn) { const userIsManager = await this.qerPermissionService.isPersonManager(); if (!userIsManager) { - this.router.navigate([this.appConfig.Config.routeConfig.start], { queryParams: {} }); + this.router.navigate([this.appConfig.Config?.routeConfig?.start], { queryParams: {} }); } observer.next(userIsManager); observer.complete(); diff --git a/imxweb/projects/qer/src/lib/guards/person-admin-guard.service.spec.ts b/imxweb/projects/qer/src/lib/guards/person-admin-guard.service.spec.ts index c40672dfd..69c144948 100644 --- a/imxweb/projects/qer/src/lib/guards/person-admin-guard.service.spec.ts +++ b/imxweb/projects/qer/src/lib/guards/person-admin-guard.service.spec.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -34,7 +34,6 @@ import { MockBuilder, MockRender } from 'ng-mocks'; import { Router, RouterModule } from '@angular/router'; import { QbmDefaultMocks } from '../../../../qbm/src/default-mocks.spec'; - describe('PersonAdminGuardService', () => { let service: PersonAdminGuardService; let isPersonAdmin = false; diff --git a/imxweb/projects/qer/src/lib/guards/person-admin-guard.service.ts b/imxweb/projects/qer/src/lib/guards/person-admin-guard.service.ts index 993aad640..a6f7c34b2 100644 --- a/imxweb/projects/qer/src/lib/guards/person-admin-guard.service.ts +++ b/imxweb/projects/qer/src/lib/guards/person-admin-guard.service.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -25,7 +25,7 @@ */ import { Injectable, OnDestroy } from '@angular/core'; -import { CanActivate, ActivatedRouteSnapshot, RouterStateSnapshot, Router } from '@angular/router'; +import { ActivatedRouteSnapshot, Router, RouterStateSnapshot } from '@angular/router'; import { Observable, Subscription } from 'rxjs'; import { AppConfigService, AuthenticationService, ISessionState } from 'qbm'; @@ -34,15 +34,15 @@ import { QerPermissionsService } from '../admin/qer-permissions.service'; @Injectable({ providedIn: 'root', }) -export class PersonAdminGuardService implements CanActivate, OnDestroy { +export class PersonAdminGuardService implements OnDestroy { private onSessionResponse: Subscription; constructor( private readonly qerPermissionService: QerPermissionsService, private readonly authentication: AuthenticationService, private readonly appConfig: AppConfigService, - private readonly router: Router - ) { } + private readonly router: Router, + ) {} public canActivate(route: ActivatedRouteSnapshot, _: RouterStateSnapshot): Observable { return new Observable((observer) => { @@ -50,7 +50,7 @@ export class PersonAdminGuardService implements CanActivate, OnDestroy { if (sessionState.IsLoggedIn) { const userIsAdmin = await this.qerPermissionService.isPersonAdmin(); if (!userIsAdmin) { - this.router.navigate([this.appConfig.Config.routeConfig.start], { queryParams: {} }); + this.router.navigate([this.appConfig.Config?.routeConfig?.start], { queryParams: {} }); } observer.next(userIsAdmin ? true : false); observer.complete(); diff --git a/imxweb/projects/qer/src/lib/guards/rule-admin-guard.service.ts b/imxweb/projects/qer/src/lib/guards/rule-admin-guard.service.ts index 98f04904d..04f669ec3 100644 --- a/imxweb/projects/qer/src/lib/guards/rule-admin-guard.service.ts +++ b/imxweb/projects/qer/src/lib/guards/rule-admin-guard.service.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -25,23 +25,23 @@ */ import { Injectable, OnDestroy } from '@angular/core'; -import { CanActivate, Router } from '@angular/router'; +import { Router } from '@angular/router'; import { Observable, Subscription } from 'rxjs'; import { AppConfigService, AuthenticationService, ISessionState } from 'qbm'; import { QerPermissionsService } from '../admin/qer-permissions.service'; @Injectable({ - providedIn: 'root' + providedIn: 'root', }) -export class RuleAdminGuardService implements CanActivate, OnDestroy{ +export class RuleAdminGuardService implements OnDestroy { private onSessionResponse: Subscription; constructor( private readonly qerPermissionService: QerPermissionsService, private readonly authentication: AuthenticationService, private readonly appConfig: AppConfigService, - private readonly router: Router - ) { } + private readonly router: Router, + ) {} public canActivate(): Observable { return new Observable((observer) => { @@ -49,7 +49,7 @@ export class RuleAdminGuardService implements CanActivate, OnDestroy{ if (sessionState.IsLoggedIn) { const userIsRuleAdmin = await this.qerPermissionService.isRuleAdmin(); if (!userIsRuleAdmin) { - this.router.navigate([this.appConfig.Config.routeConfig.start], { queryParams: {} }); + this.router.navigate([this.appConfig.Config?.routeConfig?.start], { queryParams: {} }); } observer.next(userIsRuleAdmin); observer.complete(); diff --git a/imxweb/projects/qer/src/lib/guards/shop-admin-guard.service.ts b/imxweb/projects/qer/src/lib/guards/shop-admin-guard.service.ts index 2182bc734..b6259f595 100644 --- a/imxweb/projects/qer/src/lib/guards/shop-admin-guard.service.ts +++ b/imxweb/projects/qer/src/lib/guards/shop-admin-guard.service.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -25,7 +25,7 @@ */ import { Injectable, OnDestroy } from '@angular/core'; -import { CanActivate, Router } from '@angular/router'; +import { Router } from '@angular/router'; import { Observable, Subscription } from 'rxjs'; import { AppConfigService, AuthenticationService, ISessionState } from 'qbm'; @@ -34,15 +34,15 @@ import { QerPermissionsService } from '../admin/qer-permissions.service'; @Injectable({ providedIn: 'root', }) -export class ShopAdminGuardService implements CanActivate, OnDestroy { +export class ShopAdminGuardService implements OnDestroy { private onSessionResponse: Subscription; constructor( private readonly qerPermissionService: QerPermissionsService, private readonly authentication: AuthenticationService, private readonly appConfig: AppConfigService, - private readonly router: Router - ) { } + private readonly router: Router, + ) {} public canActivate(): Observable { return new Observable((observer) => { @@ -50,7 +50,7 @@ export class ShopAdminGuardService implements CanActivate, OnDestroy { if (sessionState.IsLoggedIn) { const userIsShopAdmin = await this.qerPermissionService.isShopAdmin(); if (!userIsShopAdmin) { - this.router.navigate([this.appConfig.Config.routeConfig.start], { queryParams: {} }); + this.router.navigate([this.appConfig.Config?.routeConfig?.start], { queryParams: {} }); } observer.next(userIsShopAdmin); observer.complete(); diff --git a/imxweb/projects/qer/src/lib/guards/shop-guard.service.ts b/imxweb/projects/qer/src/lib/guards/shop-guard.service.ts index cfec1a340..8af8d26a9 100644 --- a/imxweb/projects/qer/src/lib/guards/shop-guard.service.ts +++ b/imxweb/projects/qer/src/lib/guards/shop-guard.service.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -25,7 +25,7 @@ */ import { Injectable, OnDestroy } from '@angular/core'; -import { CanActivate, Router } from '@angular/router'; +import { Router } from '@angular/router'; import { Observable, Subscription } from 'rxjs'; import { AppConfigService, AuthenticationService, ISessionState } from 'qbm'; @@ -34,15 +34,15 @@ import { QerPermissionsService } from '../admin/qer-permissions.service'; @Injectable({ providedIn: 'root', }) -export class ShopGuardService implements CanActivate, OnDestroy { +export class ShopGuardService implements OnDestroy { private onSessionResponse: Subscription; constructor( private readonly qerPermissionService: QerPermissionsService, private readonly authentication: AuthenticationService, private readonly appConfig: AppConfigService, - private readonly router: Router - ) { } + private readonly router: Router, + ) {} public canActivate(): Observable { return new Observable((observer) => { @@ -51,7 +51,7 @@ export class ShopGuardService implements CanActivate, OnDestroy { const userIsShopStatistics = await this.qerPermissionService.isShopStatistics(); const userIsShopAdmin = await this.qerPermissionService.isShopAdmin(); if (!userIsShopStatistics && !userIsShopAdmin) { - this.router.navigate([this.appConfig.Config.routeConfig.start], { queryParams: {} }); + this.router.navigate([this.appConfig.Config?.routeConfig?.start], { queryParams: {} }); } observer.next(userIsShopStatistics || userIsShopAdmin); observer.complete(); diff --git a/imxweb/projects/qer/src/lib/guards/shop-statistics-guard.service.ts b/imxweb/projects/qer/src/lib/guards/shop-statistics-guard.service.ts index dc47a8b71..a5643456f 100644 --- a/imxweb/projects/qer/src/lib/guards/shop-statistics-guard.service.ts +++ b/imxweb/projects/qer/src/lib/guards/shop-statistics-guard.service.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -25,7 +25,7 @@ */ import { Injectable, OnDestroy } from '@angular/core'; -import { CanActivate, Router } from '@angular/router'; +import { Router } from '@angular/router'; import { Observable, Subscription } from 'rxjs'; import { AppConfigService, AuthenticationService, ISessionState } from 'qbm'; @@ -34,15 +34,15 @@ import { QerPermissionsService } from '../admin/qer-permissions.service'; @Injectable({ providedIn: 'root', }) -export class ShopStatisticsGuardService implements CanActivate, OnDestroy { +export class ShopStatisticsGuardService implements OnDestroy { private onSessionResponse: Subscription; constructor( private readonly qerPermissionService: QerPermissionsService, private readonly authentication: AuthenticationService, private readonly appConfig: AppConfigService, - private readonly router: Router - ) { } + private readonly router: Router, + ) {} public canActivate(): Observable { return new Observable((observer) => { @@ -50,7 +50,7 @@ export class ShopStatisticsGuardService implements CanActivate, OnDestroy { if (sessionState.IsLoggedIn) { const userIsShopStatistics = await this.qerPermissionService.isShopStatistics(); if (!userIsShopStatistics) { - this.router.navigate([this.appConfig.Config.routeConfig.start], { queryParams: {} }); + this.router.navigate([this.appConfig.Config?.routeConfig?.start], { queryParams: {} }); } observer.next(userIsShopStatistics); observer.complete(); diff --git a/imxweb/projects/qer/src/lib/guards/statistics-guard.service.ts b/imxweb/projects/qer/src/lib/guards/statistics-guard.service.ts index 325dea081..713e37b76 100644 --- a/imxweb/projects/qer/src/lib/guards/statistics-guard.service.ts +++ b/imxweb/projects/qer/src/lib/guards/statistics-guard.service.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -25,7 +25,7 @@ */ import { Injectable, OnDestroy } from '@angular/core'; -import { CanActivate, Router } from '@angular/router'; +import { Router } from '@angular/router'; import { Observable, Subscription } from 'rxjs'; import { AppConfigService, AuthenticationService, ISessionState } from 'qbm'; @@ -34,15 +34,15 @@ import { QerPermissionsService } from '../admin/qer-permissions.service'; @Injectable({ providedIn: 'root', }) -export class StatisticsGuardService implements CanActivate, OnDestroy { +export class StatisticsGuardService implements OnDestroy { private onSessionResponse: Subscription; constructor( private readonly qerPermissionService: QerPermissionsService, private readonly authentication: AuthenticationService, private readonly appConfig: AppConfigService, - private readonly router: Router - ) { } + private readonly router: Router, + ) {} public canActivate(): Observable { return new Observable((observer) => { @@ -50,7 +50,7 @@ export class StatisticsGuardService implements CanActivate, OnDestroy { if (sessionState.IsLoggedIn) { const userIsStatistics = await this.qerPermissionService.isStatistics(); if (!userIsStatistics) { - this.router.navigate([this.appConfig.Config.routeConfig.start], { queryParams: {} }); + this.router.navigate([this.appConfig.Config?.routeConfig?.start], { queryParams: {} }); } observer.next(userIsStatistics); observer.complete(); diff --git a/imxweb/projects/qer/src/lib/guards/struct-admin-guard.service.ts b/imxweb/projects/qer/src/lib/guards/struct-admin-guard.service.ts index 3817d5627..b6939afcc 100644 --- a/imxweb/projects/qer/src/lib/guards/struct-admin-guard.service.ts +++ b/imxweb/projects/qer/src/lib/guards/struct-admin-guard.service.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -25,7 +25,7 @@ */ import { Injectable, OnDestroy } from '@angular/core'; -import { CanActivate, Router } from '@angular/router'; +import { Router } from '@angular/router'; import { Observable, Subscription } from 'rxjs'; import { AppConfigService, AuthenticationService, ISessionState } from 'qbm'; @@ -34,15 +34,15 @@ import { QerPermissionsService } from '../admin/qer-permissions.service'; @Injectable({ providedIn: 'root', }) -export class StructAdminGuardService implements CanActivate, OnDestroy { +export class StructAdminGuardService implements OnDestroy { private onSessionResponse: Subscription; constructor( private readonly qerPermissionService: QerPermissionsService, private readonly authentication: AuthenticationService, private readonly appConfig: AppConfigService, - private readonly router: Router - ) { } + private readonly router: Router, + ) {} public canActivate(): Observable { return new Observable((observer) => { @@ -50,7 +50,7 @@ export class StructAdminGuardService implements CanActivate, OnDestroy { if (sessionState.IsLoggedIn) { const userIsStructAdmin = await this.qerPermissionService.isStructAdmin(); if (!userIsStructAdmin) { - this.router.navigate([this.appConfig.Config.routeConfig.start], { queryParams: {} }); + this.router.navigate([this.appConfig.Config?.routeConfig?.start], { queryParams: {} }); } observer.next(userIsStructAdmin); observer.complete(); diff --git a/imxweb/projects/qer/src/lib/helper-alert-content/helper-alert-content.interface.ts b/imxweb/projects/qer/src/lib/helper-alert-content/helper-alert-content.interface.ts index efa4bbd6a..95e1b098f 100644 --- a/imxweb/projects/qer/src/lib/helper-alert-content/helper-alert-content.interface.ts +++ b/imxweb/projects/qer/src/lib/helper-alert-content/helper-alert-content.interface.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -25,6 +25,6 @@ */ export interface HelperAlertContent { - infoItems?: { description: string; value?: any; }[]; + infoItems?: { description: string; value?: any }[]; loading: boolean; } diff --git a/imxweb/projects/qer/src/lib/identities/create-new-identity/create-new-identity.component.html b/imxweb/projects/qer/src/lib/identities/create-new-identity/create-new-identity.component.html index fb22eb368..0e0d7277a 100644 --- a/imxweb/projects/qer/src/lib/identities/create-new-identity/create-new-identity.component.html +++ b/imxweb/projects/qer/src/lib/identities/create-new-identity/create-new-identity.component.html @@ -2,86 +2,129 @@
    - + {{ '#LDS#Unique data' | translate }} - + - -
    + +

    #LDS#There is already an identity linked to this central user account.

    -

    #LDS#You cannot create the identity using the specified central user account. Please enter a different name for the central user account.

    +

    {{ LdsKey }}

    -
    - -
    + +

    #LDS#There is at least one identity with the same first and last name.

    #LDS#You can view these identities or proceed.

    -
    - -
    + +

    #LDS#There is at least one identity with the same email address.

    #LDS#You can view these identities, change the email address, or proceed.

    -
    - + {{ '#LDS#Personal data' | translate }} - + - + {{ '#LDS#Organizational information' | translate }} - + + - + {{ '#LDS#Location information' | translate }} - +
    -
    -
    diff --git a/imxweb/projects/qer/src/lib/identities/create-new-identity/create-new-identity.component.scss b/imxweb/projects/qer/src/lib/identities/create-new-identity/create-new-identity.component.scss index 4af4d5ab4..678da4d90 100644 --- a/imxweb/projects/qer/src/lib/identities/create-new-identity/create-new-identity.component.scss +++ b/imxweb/projects/qer/src/lib/identities/create-new-identity/create-new-identity.component.scss @@ -1,27 +1,9 @@ @import '@elemental-ui/core/src/styles/_eui_palette.scss'; -.imx-info { - ::ng-deep .eui-alert { - width: auto; - margin-bottom: 10px; - } - ::ng-deep .eui-alert .eui-alert-header { - width: 100%; - } -} - -.imx-alert-button { - align-self: flex-end; -} - -.imx-flex-alert { - display: flex; - flex-direction: column; -} .eui-dark-theme { :host { background-color: $color-gray-80; - .eui-sidesheet-actions.mat-card.eui-sidesheet-actions--white{ + .eui-sidesheet-actions.mat-mdc-card.eui-sidesheet-actions--white { background-color: $color-gray-70; } } @@ -30,7 +12,7 @@ .eui-contrast-theme { :host { background-color: $color-gray-100; - .eui-sidesheet-actions.mat-card.eui-sidesheet-actions--white{ + .eui-sidesheet-actions.mat-mdc-card.eui-sidesheet-actions--white { background-color: $color-gray-90; } } diff --git a/imxweb/projects/qer/src/lib/identities/create-new-identity/create-new-identity.component.ts b/imxweb/projects/qer/src/lib/identities/create-new-identity/create-new-identity.component.ts index 74c70ab56..f58612790 100644 --- a/imxweb/projects/qer/src/lib/identities/create-new-identity/create-new-identity.component.ts +++ b/imxweb/projects/qer/src/lib/identities/create-new-identity/create-new-identity.component.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -25,30 +25,29 @@ */ import { Component, Inject, OnDestroy } from '@angular/core'; -import { FormArray, UntypedFormGroup } from '@angular/forms'; -import { EuiLoadingService, EuiSidesheetRef, EuiSidesheetService, EUI_SIDESHEET_DATA } from '@elemental-ui/core'; +import { UntypedFormGroup } from '@angular/forms'; +import { EUI_SIDESHEET_DATA, EuiLoadingService, EuiSidesheetRef, EuiSidesheetService } from '@elemental-ui/core'; import { TranslateService } from '@ngx-translate/core'; import { Subscription } from 'rxjs'; -import { PortalPersonReports, QerProjectConfig } from 'imx-api-qer'; -import { BaseCdr, ColumnDependentReference, ConfirmationService, SnackBarService, CdrFactoryService } from 'qbm'; +import { PortalPersonReports, QerProjectConfig } from '@imx-modules/imx-api-qer'; +import { CollectionLoadParameters } from '@imx-modules/imx-qbm-dbts'; +import { BaseCdr, calculateSidesheetWidth, CdrFactoryService, ColumnDependentReference, ConfirmationService, SnackBarService } from 'qbm'; import { IdentitiesService } from '../identities.service'; import { DuplicateCheckParameter } from './duplicate-check-parameter.interface'; import { DuplicatesSidesheetComponent } from './duplicates-sidesheet/duplicates-sidesheet.component'; -import { CollectionLoadParameters } from 'imx-qbm-dbts'; @Component({ selector: 'imx-create-new-identity', templateUrl: './create-new-identity.component.html', - styleUrls: ['./create-new-identity.component.scss'] + styleUrls: ['./create-new-identity.component.scss'], }) export class CreateNewIdentityComponent implements OnDestroy { - public identityForm = new UntypedFormGroup({}); - public cdrListPersonal: ColumnDependentReference[] = []; - public cdrListOrganizational: ColumnDependentReference[] = []; - public cdrListLocality: ColumnDependentReference[] = []; - public cdrListIdentifier: ColumnDependentReference[] = []; + public cdrListPersonal: (ColumnDependentReference | undefined)[] = []; + public cdrListOrganizational: (ColumnDependentReference | undefined)[] = []; + public cdrListLocality: (ColumnDependentReference | undefined)[] = []; + public cdrListIdentifier: (ColumnDependentReference | undefined)[] = []; public nameIsOff = 0; public accountIsOff = 0; public mailIsOff = 0; @@ -56,9 +55,10 @@ export class CreateNewIdentityComponent implements OnDestroy { private subscriptions: Subscription[] = []; constructor( - @Inject(EUI_SIDESHEET_DATA) public data: { - selectedIdentity: PortalPersonReports, - projectConfig: QerProjectConfig, + @Inject(EUI_SIDESHEET_DATA) + public data: { + selectedIdentity: PortalPersonReports; + projectConfig: QerProjectConfig; }, private readonly busyService: EuiLoadingService, private readonly snackbar: SnackBarService, @@ -67,28 +67,28 @@ export class CreateNewIdentityComponent implements OnDestroy { private readonly translate: TranslateService, private readonly confirm: ConfirmationService, private readonly cdrFactoryService: CdrFactoryService, - private readonly identityService: IdentitiesService) { + private readonly identityService: IdentitiesService, + ) { this.setup(); } public ngOnDestroy(): void { - this.subscriptions.forEach(s => s.unsubscribe()); + this.subscriptions.forEach((s) => s.unsubscribe()); } public async submit(): Promise { if (this.identityForm.valid) { - - let canSubmit = true; if (this.mailIsOff || this.nameIsOff) { canSubmit = await this.confirm.confirm({ Title: '#LDS#Heading Create Identity With Same Properties', - Message: this.mailIsOff && this.nameIsOff ? - '#LDS#There is at least one identity with the same properties. Are you sure you want to create the identity?' - : this.mailIsOff ? - '#LDS#There is at least one identity with the same email address. Are you sure you want to create the identity?' : - '#LDS#There is at least one identity with the same first and last name. Are you sure you want to create the identity?', - identifier: 'create-new-identity-confirm-saving' + Message: + this.mailIsOff && this.nameIsOff + ? '#LDS#There is at least one identity with the same properties. Are you sure you want to create the identity?' + : this.mailIsOff + ? '#LDS#There is at least one identity with the same email address. Are you sure you want to create the identity?' + : '#LDS#There is at least one identity with the same first and last name. Are you sure you want to create the identity?', + identifier: 'create-new-identity-confirm-saving', }); } @@ -120,99 +120,113 @@ export class CreateNewIdentityComponent implements OnDestroy { default: duplicateParameter = { firstName: this.data.selectedIdentity.GetEntity().GetColumn('FirstName').GetValue(), - lastName: this.data.selectedIdentity.GetEntity().GetColumn('LastName').GetValue() + lastName: this.data.selectedIdentity.GetEntity().GetColumn('LastName').GetValue(), }; break; } - await this.sidesheetService.open(DuplicatesSidesheetComponent, { - title: await this.translate.get('#LDS#Heading View Identities With Same Properties').toPromise(), - padding: '0px', - width: 'max(600px, 60%)', - icon: 'contactinfo', - testId: 'duplicate-identities-sidesheet', - data: { - projectConfig: this.data.projectConfig, - get: async (param: CollectionLoadParameters) => this.identityService.getDuplicates(param), - getFilter: (filter: DuplicateCheckParameter) => this.identityService.buildFilterForduplicates(filter), - duplicateParameter, - entitySchema: this.identityService.personAllSchema, - } - }).afterClosed().toPromise(); + await this.sidesheetService + .open(DuplicatesSidesheetComponent, { + title: await this.translate.get('#LDS#Heading View Identities With Same Properties').toPromise(), + padding: '0px', + width: calculateSidesheetWidth(), + icon: 'contactinfo', + testId: 'duplicate-identities-sidesheet', + data: { + projectConfig: this.data.projectConfig, + get: async (param: CollectionLoadParameters) => this.identityService.getDuplicates(param), + getFilter: (filter: DuplicateCheckParameter) => this.identityService.buildFilterForduplicates(filter), + duplicateParameter, + entitySchema: this.identityService.personAllSchema, + }, + }) + .afterClosed() + .toPromise(); } - public update(cdr: ColumnDependentReference, list: ColumnDependentReference[]): void { - const index = list.findIndex(elem => elem.column.ColumnName === cdr.column.ColumnName); - if (index === -1) { return; } + public update(cdr: ColumnDependentReference | undefined, list: (ColumnDependentReference | undefined)[]): void { + const cdrColumn = cdr?.column; + if (!cdrColumn || !!list.length) { + return; + } + const index = list.findIndex((elem) => elem?.column?.ColumnName === (cdrColumn?.ColumnName ?? '')); + if (index === -1) { + return; + } - this.identityForm.removeControl(cdr.column.ColumnName); - list.splice(index, 1, new BaseCdr(cdr.column)); + this.identityForm.removeControl(cdrColumn?.ColumnName ?? ''); + list.splice(index, 1, new BaseCdr(cdrColumn)); } - public async checkValues(name: string): Promise { + public async checkValues(name: string | undefined): Promise { switch (name) { case 'FirstName': case 'LastName': - this.nameIsOff = (await this.identityService.getDuplicates( - { - filter: this.identityService.buildFilterForduplicates( - { - firstName: this.data.selectedIdentity.GetEntity().GetColumn('FirstName').GetValue(), - lastName: this.data.selectedIdentity.GetEntity().GetColumn('LastName').GetValue(), - } - ), PageSize: -1 - } - )).totalCount; + this.nameIsOff = ( + await this.identityService.getDuplicates({ + filter: this.identityService.buildFilterForduplicates({ + firstName: this.data.selectedIdentity.GetEntity().GetColumn('FirstName').GetValue(), + lastName: this.data.selectedIdentity.GetEntity().GetColumn('LastName').GetValue(), + }), + PageSize: -1, + }) + ).totalCount; break; case 'CentralAccount': - this.accountIsOff = (await this.identityService.getDuplicates( - { - filter: this.identityService.buildFilterForduplicates( - { - centralAccount: this.data.selectedIdentity.GetEntity().GetColumn('CentralAccount').GetValue() - } - ), PageSize: -1 - } - )).totalCount; + this.accountIsOff = ( + await this.identityService.getDuplicates({ + filter: this.identityService.buildFilterForduplicates({ + centralAccount: this.data.selectedIdentity.GetEntity().GetColumn('CentralAccount').GetValue(), + }), + PageSize: -1, + }) + ).totalCount; break; case 'DefaultEmailAddress': - this.mailIsOff = (await this.identityService.getDuplicates( - { - filter: this.identityService.buildFilterForduplicates( - { - defaultEmailAddress: this.data.selectedIdentity.GetEntity().GetColumn('DefaultEmailAddress').GetValue() - } - ), PageSize: -1 - } - )).totalCount; + this.mailIsOff = ( + await this.identityService.getDuplicates({ + filter: this.identityService.buildFilterForduplicates({ + defaultEmailAddress: this.data.selectedIdentity.GetEntity().GetColumn('DefaultEmailAddress').GetValue(), + }), + PageSize: -1, + }) + ).totalCount; break; } } private setup(): void { - - this.subscriptions.push(this.sidesheetRef.closeClicked().subscribe(async () => { - if (this.identityForm.dirty) { - const close = await this.confirm.confirmLeaveWithUnsavedChanges(); - if (close) { + this.subscriptions.push( + this.sidesheetRef.closeClicked().subscribe(async () => { + if (this.identityForm.dirty) { + const close = await this.confirm.confirmLeaveWithUnsavedChanges(); + if (close) { + this.sidesheetRef.close(false); + } + } else { this.sidesheetRef.close(false); } - } else { - this.sidesheetRef.close(false); - } - })); + }), + ); const identifierColumns = ['FirstName', 'LastName', 'CentralAccount', 'DefaultEmailAddress']; - this.cdrListIdentifier = this.cdrFactoryService.buildCdrFromColumnList(this.data.selectedIdentity.GetEntity(),identifierColumns); + this.cdrListIdentifier = this.cdrFactoryService.buildCdrFromColumnList(this.data.selectedIdentity.GetEntity(), identifierColumns); - const personalColumns = this.data.projectConfig.PersonConfig.VI_Employee_MasterData_Attributes - .filter(personal => !identifierColumns.includes(personal)); - this.cdrListPersonal = this.cdrFactoryService.buildCdrFromColumnList(this.data.selectedIdentity.GetEntity(),personalColumns); + const personalColumns = (this.data.projectConfig.PersonConfig?.VI_Employee_MasterData_Attributes || []).filter( + (personal) => !identifierColumns.includes(personal), + ); + this.cdrListPersonal = this.cdrFactoryService.buildCdrFromColumnList(this.data.selectedIdentity.GetEntity(), personalColumns); - const organizationalColumns = this.data.projectConfig.PersonConfig.VI_Employee_MasterData_OrganizationalAttributes; - this.cdrListOrganizational = this.cdrFactoryService.buildCdrFromColumnList(this.data.selectedIdentity.GetEntity(),organizationalColumns); + const organizationalColumns = this.data.projectConfig.PersonConfig?.VI_Employee_MasterData_OrganizationalAttributes || []; + this.cdrListOrganizational = this.cdrFactoryService.buildCdrFromColumnList( + this.data.selectedIdentity.GetEntity(), + organizationalColumns, + ); - const localityColumns = this.data.projectConfig.PersonConfig.VI_Employee_MasterData_LocalityAttributes; - this.cdrListLocality = this.cdrFactoryService.buildCdrFromColumnList(this.data.selectedIdentity.GetEntity(),localityColumns); + const localityColumns = this.data.projectConfig.PersonConfig?.VI_Employee_MasterData_LocalityAttributes || []; + this.cdrListLocality = this.cdrFactoryService.buildCdrFromColumnList(this.data.selectedIdentity.GetEntity(), localityColumns); } + + public LdsKey = + '#LDS#You cannot create the identity using the specified central user account. Please enter a different name for the central user account.'; } diff --git a/imxweb/projects/qer/src/lib/identities/create-new-identity/duplicate-check-parameter.interface.ts b/imxweb/projects/qer/src/lib/identities/create-new-identity/duplicate-check-parameter.interface.ts index a6bb35d0d..bcee12853 100644 --- a/imxweb/projects/qer/src/lib/identities/create-new-identity/duplicate-check-parameter.interface.ts +++ b/imxweb/projects/qer/src/lib/identities/create-new-identity/duplicate-check-parameter.interface.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -24,7 +24,7 @@ * */ -import { CollectionLoadParameters } from 'imx-qbm-dbts'; +import { CollectionLoadParameters } from '@imx-modules/imx-qbm-dbts'; export interface DuplicateCheckParameter { firstName?: string; diff --git a/imxweb/projects/qer/src/lib/identities/create-new-identity/duplicates-sidesheet/duplicates-sidesheet.component.html b/imxweb/projects/qer/src/lib/identities/create-new-identity/duplicates-sidesheet/duplicates-sidesheet.component.html index 85be8f551..16a24b1f2 100644 --- a/imxweb/projects/qer/src/lib/identities/create-new-identity/duplicates-sidesheet/duplicates-sidesheet.component.html +++ b/imxweb/projects/qer/src/lib/identities/create-new-identity/duplicates-sidesheet/duplicates-sidesheet.component.html @@ -1,15 +1,25 @@
    - + - + noMatchingDataText="#LDS#There are no identities matching your search." + > - - + -
    \ No newline at end of file +
    diff --git a/imxweb/projects/qer/src/lib/identities/create-new-identity/duplicates-sidesheet/duplicates-sidesheet.component.scss b/imxweb/projects/qer/src/lib/identities/create-new-identity/duplicates-sidesheet/duplicates-sidesheet.component.scss index b9b8c7b0d..463b02e4c 100644 --- a/imxweb/projects/qer/src/lib/identities/create-new-identity/duplicates-sidesheet/duplicates-sidesheet.component.scss +++ b/imxweb/projects/qer/src/lib/identities/create-new-identity/duplicates-sidesheet/duplicates-sidesheet.component.scss @@ -1,19 +1,7 @@ -@import "@elemental-ui/core/src/styles/_palette.scss"; @import '@elemental-ui/core/src/styles/_eui_palette.scss'; :host { - background-color: $asher-gray; - - .imx-table-container { - display: flex; - flex-direction: column; - overflow: hidden; - - > span { - margin-bottom: 10px; - display: block; - } - } + background-color: $color-gray-2 } .eui-dark-theme { diff --git a/imxweb/projects/qer/src/lib/identities/create-new-identity/duplicates-sidesheet/duplicates-sidesheet.component.ts b/imxweb/projects/qer/src/lib/identities/create-new-identity/duplicates-sidesheet/duplicates-sidesheet.component.ts index 3e46c474c..d6b98efa3 100644 --- a/imxweb/projects/qer/src/lib/identities/create-new-identity/duplicates-sidesheet/duplicates-sidesheet.component.ts +++ b/imxweb/projects/qer/src/lib/identities/create-new-identity/duplicates-sidesheet/duplicates-sidesheet.component.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -24,34 +24,33 @@ * */ -import { OverlayRef } from '@angular/cdk/overlay'; import { Component, Inject, OnInit } from '@angular/core'; -import { EuiLoadingService, EuiSidesheetConfig, EuiSidesheetService, EUI_SIDESHEET_DATA } from '@elemental-ui/core'; +import { EUI_SIDESHEET_DATA, EuiLoadingService, EuiSidesheetConfig, EuiSidesheetService } from '@elemental-ui/core'; import { TranslateService } from '@ngx-translate/core'; -import { PortalPersonAll, QerProjectConfig } from 'imx-api-qer'; -import { CollectionLoadParameters, EntitySchema, FilterData, IClientProperty } from 'imx-qbm-dbts'; -import { DataSourceToolbarSettings, SettingsService } from 'qbm'; +import { QerProjectConfig } from '@imx-modules/imx-api-qer'; +import { CollectionLoadParameters, EntitySchema, FilterData, IClientProperty, TypedEntity } from '@imx-modules/imx-qbm-dbts'; +import { calculateSidesheetWidth, DataSourceToolbarSettings, SettingsService } from 'qbm'; import { AddressbookDetailComponent } from '../../../addressbook/addressbook-detail/addressbook-detail.component'; import { AddressbookService } from '../../../addressbook/addressbook.service'; import { DuplicateCheckParameter } from '../duplicate-check-parameter.interface'; @Component({ templateUrl: './duplicates-sidesheet.component.html', - styleUrls: ['./duplicates-sidesheet.component.scss'] + styleUrls: ['./duplicates-sidesheet.component.scss'], }) export class DuplicatesSidesheetComponent implements OnInit { - public dstSettings: DataSourceToolbarSettings; private displayedColumns: IClientProperty[] = []; constructor( - @Inject(EUI_SIDESHEET_DATA) public data: { - projectConfig: QerProjectConfig, - get: (param: CollectionLoadParameters) => Promise, - getFilter: (filter: DuplicateCheckParameter) => FilterData[], - duplicateParameter: DuplicateCheckParameter - entitySchema: EntitySchema, + @Inject(EUI_SIDESHEET_DATA) + public data: { + projectConfig: QerProjectConfig; + get: (param: CollectionLoadParameters) => Promise; + getFilter: (filter: DuplicateCheckParameter) => FilterData[]; + duplicateParameter: DuplicateCheckParameter; + entitySchema: EntitySchema; }, public readonly settings: SettingsService, private readonly busy: EuiLoadingService, @@ -59,47 +58,41 @@ export class DuplicatesSidesheetComponent implements OnInit { private readonly addressbookService: AddressbookService, private readonly translateService: TranslateService, ) { - this.displayedColumns = [ data.entitySchema.Columns.DefaultEmailAddress, data.entitySchema.Columns.IdentityType, data.entitySchema.Columns.UID_Department, - data.entitySchema.Columns.UID_Locality + data.entitySchema.Columns.UID_Locality, ]; - } public async ngOnInit(): Promise { await this.navigate({ PageSize: this.settings.DefaultPageSize }); } - public async navigate(parameter: CollectionLoadParameters): Promise { - const currentParameter = { ...parameter, ...{ filter: this.data.getFilter(this.data.duplicateParameter) } }; - let overlay: OverlayRef; - setTimeout(() => { - overlay = this.busy.show(); - }); + if (this.busy.overlayRefs.length === 0) { + this.busy.show(); + } try { const data = await this.data.get(currentParameter); this.dstSettings = { displayedColumns: this.displayedColumns, dataSource: data, entitySchema: this.data.entitySchema, - navigationState: currentParameter + navigationState: currentParameter, }; } finally { - setTimeout(() => { - this.busy.hide(overlay); - }); + this.busy.hide(); } } - public async onHighlightedEntityChanged(personAll: PortalPersonAll): Promise { - let overlayRef: OverlayRef; - setTimeout(() => overlayRef = this.busy.show()); + public async onHighlightedEntityChanged(personAll: TypedEntity): Promise { + if (this.busy.overlayRefs.length === 0) { + this.busy.show(); + } let config: EuiSidesheetConfig; @@ -108,15 +101,15 @@ export class DuplicatesSidesheetComponent implements OnInit { title: await this.translateService.get('#LDS#Heading View Identity Details').toPromise(), subTitle: personAll.GetEntity().GetDisplay(), padding: '0', - width: 'max(550px, 55%)', + width: calculateSidesheetWidth(), testId: 'duplicate-identity-detail-sidesheet', data: await this.addressbookService.getDetail( personAll, - this.data.projectConfig.PersonConfig.VI_MyData_WhitePages_DetailAttributes - ) + this.data.projectConfig.PersonConfig?.VI_MyData_WhitePages_DetailAttributes ?? [], + ), }; } finally { - setTimeout(() => this.busy.hide(overlayRef)); + this.busy.hide(); } this.sidesheet.open(AddressbookDetailComponent, config); diff --git a/imxweb/projects/qer/src/lib/identities/identities-reports.service.ts b/imxweb/projects/qer/src/lib/identities/identities-reports.service.ts index 4dad02f0b..2f9beb9d8 100644 --- a/imxweb/projects/qer/src/lib/identities/identities-reports.service.ts +++ b/imxweb/projects/qer/src/lib/identities/identities-reports.service.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -26,14 +26,22 @@ import { Overlay } from '@angular/cdk/overlay'; import { HttpClient } from '@angular/common/http'; -import { Injectable, Injector } from '@angular/core'; -import { EuiDownloadDirective, EuiSidesheetService } from '@elemental-ui/core'; +import { ElementRef, Injectable, Injector } from '@angular/core'; +import { EuiDownloadDirective, EuiDownloadService, EuiSidesheetService } from '@elemental-ui/core'; +import { PortalAdminPerson, PortalPersonReports } from '@imx-modules/imx-api-qer'; +import { CollectionLoadParameters, EntityCollectionData, ValType } from '@imx-modules/imx-qbm-dbts'; import { TranslateService } from '@ngx-translate/core'; -import { CollectionLoadParameters, EntityCollectionData, ValType } from 'imx-qbm-dbts'; -import { AppConfigService, BaseCdr, ColumnDependentReference, ElementalUiConfigService, EntityService, SettingsService } from 'qbm'; +import { + AppConfigService, + BaseCdr, + calculateSidesheetWidth, + CdrSidesheetComponent, + ColumnDependentReference, + ElementalUiConfigService, + EntityService, + SettingsService, +} from 'qbm'; import { QerApiService } from '../qer-api-client.service'; -import { CdrSidesheetComponent } from 'qbm'; -import { PortalAdminPerson, PortalPersonReports } from 'imx-api-qer'; @Injectable() export class IdentitiesReportsService { @@ -48,7 +56,8 @@ export class IdentitiesReportsService { private readonly elementalUiConfigService: ElementalUiConfigService, private readonly http: HttpClient, private readonly injector: Injector, - private readonly overlay: Overlay + private readonly overlay: Overlay, + private readonly downloadService: EuiDownloadService, ) {} public async personsReport(person: PortalPersonReports | PortalAdminPerson): Promise { @@ -60,7 +69,7 @@ export class IdentitiesReportsService { title: await this.translate.get('#LDS#Heading Download Report').toPromise(), subTitle: person.GetEntity().GetDisplay(), padding: '0px', - width: 'max(600px, 60%)', + width: calculateSidesheetWidth(), testId: 'identities-report-sidesheet', data: { cdrs: Object.values(cdrs), buttonCaption: '#LDS#Download report' }, }) @@ -87,7 +96,13 @@ export class IdentitiesReportsService { public async viewReport(url: string): Promise { // not pretty, but the download directive does not support dynamic URLs - const directive = new EuiDownloadDirective(null /* no element */, this.http, this.overlay, this.injector); + const directive = new EuiDownloadDirective( + new ElementRef('') /* no element */, + this.http, + this.overlay, + this.injector, + this.downloadService, + ); directive.downloadOptions = { ...this.elementalUiConfigService.Config.downloadOptions, fileMimeType: '', @@ -125,9 +140,9 @@ export class IdentitiesReportsService { MinLen: 0, }, undefined, - { Value: 30 } + { Value: 30 }, ), - '#LDS#Period to be considered (in days)' + '#LDS#Period to be considered (in days)', ), withSubIdentites: new BaseCdr( this.entityService.createLocalEntityColumn( @@ -137,9 +152,9 @@ export class IdentitiesReportsService { MinLen: 0, }, undefined, - { Value: false } + { Value: false }, ), - '#LDS#Include subidentities' + '#LDS#Include subidentities', ), }; } diff --git a/imxweb/projects/qer/src/lib/identities/identities.component.html b/imxweb/projects/qer/src/lib/identities/identities.component.html index a7bf89e12..9275f97e0 100644 --- a/imxweb/projects/qer/src/lib/identities/identities.component.html +++ b/imxweb/projects/qer/src/lib/identities/identities.component.html @@ -1,68 +1,165 @@ -
    -
    - #LDS#Identities +
    +
    +

    #LDS#Identities

    - +
    - - - + + + + {{ entitySchemaPersonReports?.Columns?.[DisplayColumns.DISPLAY_PROPERTYNAME]?.Display }} + +
    {{ item.GetEntity().GetDisplay() }}
    -
    {{ - item.DefaultEmailAddress.Column.GetDisplayValue() }}
    -
    -
    - - +
    {{ item.DefaultEmailAddress.Column.GetDisplayValue() }}
    + + + + + + {{ entitySchemaPersonReports?.Columns?.IsSecurityIncident?.Display }} + + + + + {{ entitySchemaPersonReports?.Columns?.IsSecurityIncident?.Display }} + + +
    {{ '#LDS#Security risk' | translate }}
    -
    -
    - - - - - - - - - - + + + + {{ entitySchemaPersonReports?.Columns?.UID_Department?.Display }} + +
    + + {{ item.GetEntity().GetColumn('UID_Department').GetDisplayValue() }} + +
    + +
    + + + + {{ entitySchemaPersonReports?.Columns?.XMarkedForDeletion?.Display }} + + + + + {{ entitySchemaPersonReports?.Columns?.XMarkedForDeletion?.Display }} + + +
    {{ item.XMarkedForDeletion.Column.GetDisplayValue() }}
    -
    -
    -
    - - + + + + + + {{ entitySchemaPersonReports?.Columns?.IdentityType?.Display }} + + + + + {{ entitySchemaPersonReports?.Columns?.IdentityType?.Display }} + + + + + {{ item.IdentityType.Column.GetDisplayValue() }} + + + + + + + {{ entitySchemaPersonReports?.Columns?.EmployeeType?.Display }} + + + + + {{ entitySchemaPersonReports?.Columns?.EmployeeType?.Display }} + + + + + {{ item.EmployeeType.Column.GetDisplayValue() }} + + + + + + + {{ entitySchemaPersonReports?.Columns?.IsExternal?.Display }} + + + + + {{ entitySchemaPersonReports?.Columns?.IsExternal?.Display }} + + + + + {{ item.IsExternal.Column.GetDisplayValue() }} + + + + +
    -
    - - - - +
    diff --git a/imxweb/projects/qer/src/lib/identities/identities.component.scss b/imxweb/projects/qer/src/lib/identities/identities.component.scss index fd70dcfb0..b9c939720 100644 --- a/imxweb/projects/qer/src/lib/identities/identities.component.scss +++ b/imxweb/projects/qer/src/lib/identities/identities.component.scss @@ -1,5 +1,5 @@ @import '@elemental-ui/core/src/styles/_eui_palette.scss'; -@import '../../../../../shared/scss/common-table.scss'; +@import 'base/mixins'; .data-explorer { &.data-explorer--identities { &.identities--fullscreen { @@ -14,16 +14,9 @@ } } } - -.data-explorer-bottom-button-row { - @include imx-button-bar(); -} - -.hidden { - display: none; -} -::ng-deep{ - imx-report-button, imx-report-button-ext{ +::ng-deep { + imx-report-button, + imx-report-button-ext { display: none; } } diff --git a/imxweb/projects/qer/src/lib/identities/identities.component.ts b/imxweb/projects/qer/src/lib/identities/identities.component.ts index d30d47d98..237e7ddb6 100644 --- a/imxweb/projects/qer/src/lib/identities/identities.component.ts +++ b/imxweb/projects/qer/src/lib/identities/identities.component.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -24,30 +24,38 @@ * */ -import { Component, OnInit, OnDestroy, Input, ViewChild, ViewContainerRef } from '@angular/core'; +import { Component, Input, OnDestroy, OnInit, ViewChild, ViewContainerRef } from '@angular/core'; import { MatDialog } from '@angular/material/dialog'; import { EuiLoadingService, EuiSidesheetService } from '@elemental-ui/core'; import { TranslateService } from '@ngx-translate/core'; import { Subscription } from 'rxjs'; -import { PortalAdminPerson, PortalPersonAll, PortalPersonReports, ProjectConfig, ViewConfigData } from 'imx-api-qer'; -import { CollectionLoadParameters, DataModel, DataModelProperty, DisplayColumns, EntitySchema, IClientProperty } from 'imx-qbm-dbts'; +import { PortalAdminPerson, PortalPersonReports, ProjectConfig, QerProjectConfig, ViewConfigData } from '@imx-modules/imx-api-qer'; +import { + CollectionLoadParameters, + DataModel, + DataModelProperty, + DisplayColumns, + EntitySchema, + IClientProperty, + TypedEntityCollectionData, +} from '@imx-modules/imx-qbm-dbts'; import { AuthenticationService, BusyService, + calculateSidesheetWidth, ClassloggerService, - DataSourceToolbarExportMethod, DataSourceToolbarFilter, - DataSourceToolbarGroupData, - DataSourceToolbarSettings, DataSourceToolbarViewConfig, DataTableGroupedData, + DataViewInitParameters, + DataViewSource, ExtService, HelpContextualValues, IExtension, ImxTranslationProviderService, + ISessionState, MessageDialogComponent, - SettingsService, SideNavigationComponent, } from 'qbm'; import { QerPermissionsService } from '../admin/qer-permissions.service'; @@ -62,6 +70,7 @@ import { IdentitySidesheetComponent } from './identity-sidesheet/identity-sidesh selector: 'imx-data-explorer-identities', templateUrl: './identities.component.html', styleUrls: ['./identities.component.scss'], + providers: [DataViewSource], }) export class DataExplorerIdentitiesComponent implements OnInit, OnDestroy, SideNavigationComponent { @Input() public applyIssuesFilter = false; @@ -77,20 +86,10 @@ export class DataExplorerIdentitiesComponent implements OnInit, OnDestroy, SideN @Input() public isAdmin = false; @Input() public contextId: HelpContextualValues; - /** - * Settings needed by the DataSourceToolbarComponent - */ - public dstSettings: DataSourceToolbarSettings; - - /** - * Page size, start index, search and filtering options etc. - */ - public navigationState: CollectionLoadParameters; - /** * Selected person */ - public selectedPerson: PortalPersonAll | PortalPersonReports; + public selectedPerson: PortalAdminPerson | PortalPersonReports; /** * Details of selected person @@ -108,17 +107,16 @@ export class DataExplorerIdentitiesComponent implements OnInit, OnDestroy, SideN public groupData: { [key: string]: DataTableGroupedData } = {}; public isManagerForPersons: boolean; public isPersonAdmin: boolean; + public isCreationAllowed: boolean; public isAuditor: boolean; public extensions: IExtension[] = []; - private projectConfig: ProjectConfig; + private projectConfig: ProjectConfig & QerProjectConfig; private displayedColumns: IClientProperty[] = []; private authorityDataDeleted$: Subscription; private sessionResponse$: Subscription; public busyService = new BusyService(); - private displayedInnerColumns: IClientProperty[] = []; - private groupingInfo: DataSourceToolbarGroupData; private dataModel: DataModel; private viewConfig: DataSourceToolbarViewConfig; private get viewConfigPath(): string { @@ -128,6 +126,7 @@ export class DataExplorerIdentitiesComponent implements OnInit, OnDestroy, SideN constructor( public translateProvider: ImxTranslationProviderService, + public dataSource: DataViewSource, private readonly sideSheet: EuiSidesheetService, private readonly busyServiceElemental: EuiLoadingService, private readonly logger: ClassloggerService, @@ -139,25 +138,19 @@ export class DataExplorerIdentitiesComponent implements OnInit, OnDestroy, SideN private readonly authService: AuthenticationService, qerPermissionService: QerPermissionsService, private identityReports: IdentitiesReportsService, - settingsService: SettingsService, - private extService: ExtService + private extService: ExtService, ) { - this.navigationState = { PageSize: settingsService.DefaultPageSize, StartIndex: 0 }; - this.authorityDataDeleted$ = this.identitiesService.authorityDataDeleted.subscribe(() => this.navigate()); + this.authorityDataDeleted$ = this.identitiesService.authorityDataDeleted.subscribe(() => this.dataSource.updateState()); - this.sessionResponse$ = this.authService.onSessionResponse.subscribe(async (session) => { + this.sessionResponse$ = this.authService.onSessionResponse.subscribe(async (session: ISessionState) => { if (session.IsLoggedIn) { - (this.currentUser = session.UserUid), (this.isManagerForPersons = await qerPermissionService.isPersonManager()); + (this.currentUser = session.UserUid || ''), (this.isManagerForPersons = await qerPermissionService.isPersonManager()); this.isPersonAdmin = await qerPermissionService.isPersonAdmin(); this.isAuditor = await qerPermissionService.isAuditor(); } }); } - get isMobile(): boolean { - return document.body.offsetWidth <= 768; - } - public async ngOnInit(): Promise { this.getDynamicMenuItems(); await this.init(); @@ -184,7 +177,10 @@ export class DataExplorerIdentitiesComponent implements OnInit, OnDestroy, SideN // !!TODO - Fix mat menu dynamic report components // Create dynamic report components and call viewReport function public async showDynamicReport(extension: IExtension): Promise { - const dynamicReportComponent = this.dynamicReport.createComponent(extension.instance, { index: 0 }); + if (!extension.instance) { + return; + } + const dynamicReportComponent = this.dynamicReport.createComponent(extension.instance, { index: 0 }); dynamicReportComponent.instance.referrer = this.currentUser; dynamicReportComponent.instance.inputData = extension.inputData; await dynamicReportComponent.instance.ngOnInit(); @@ -193,17 +189,8 @@ export class DataExplorerIdentitiesComponent implements OnInit, OnDestroy, SideN } } - /** - * Occurs when the navigation state has changed - e.g. users clicks on the next page button. - * - */ - public async onNavigationStateChanged(newState: CollectionLoadParameters): Promise { - this.navigationState = newState; - await this.navigate(); - } - public async personsManagedReport(): Promise { - this.identityReports.personsManagedReport(this.currentUser, '#LDS#Download report on identities you are directly responsible for'); + this.identityReports.personsManagedReport(this.currentUser, '#LDS#View identities you are directly responsible for'); } /** @@ -211,7 +198,7 @@ export class DataExplorerIdentitiesComponent implements OnInit, OnDestroy, SideN * * @param identity Selected identity. */ - public async onIdentityChanged(identity: PortalPersonAll | PortalPersonReports): Promise { + public async onIdentityChanged(identity: PortalAdminPerson | PortalPersonReports): Promise { const overlayRef = this.busyServiceElemental.show(); try { @@ -234,7 +221,7 @@ export class DataExplorerIdentitiesComponent implements OnInit, OnDestroy, SideN await dialogRef.afterClosed().toPromise(); // reload data - return this.navigate(); + return this.dataSource.updateState(); } await this.viewIdentity(this.selectedPersonDetail); } finally { @@ -242,44 +229,12 @@ export class DataExplorerIdentitiesComponent implements OnInit, OnDestroy, SideN } } - /** - * Occurs when user triggers search. - * - * @param keywords Search keywords. - */ - public async onSearch(keywords: string): Promise { - this.logger.debug(this, `Searching for: ${keywords}`); - this.navigationState.StartIndex = 0; - this.navigationState.search = keywords; - await this.navigate(); - } - - public async onGroupingChange(groupKey: string): Promise { - const isBusy = this.busyService.beginBusy(); - - try { - const groupData = this.groupData[groupKey]; - groupData.data = this.isAdmin - ? await this.identitiesService.getAllPersonAdmin(groupData.navigationState) - : await this.identitiesService.getReportsOfManager(groupData.navigationState); - groupData.settings = { - displayedColumns: this.displayedInnerColumns, - dataSource: groupData.data, - entitySchema: this.entitySchemaPersonReports, - navigationState: groupData.navigationState, - dataModel: this.dataModel, - }; - } finally { - isBusy.endBusy(); - } - } - public async createNewIdentity(): Promise { await this.sideSheet .open(CreateNewIdentityComponent, { title: await this.translate.get('#LDS#Heading Create Identity').toPromise(), padding: '0px', - width: 'max(650px, 65%)', + width: calculateSidesheetWidth(), disableClose: true, testId: 'create-new-identity-sidesheet', icon: 'contactinfo', @@ -291,7 +246,7 @@ export class DataExplorerIdentitiesComponent implements OnInit, OnDestroy, SideN .afterClosed() .toPromise(); - return this.navigate(); + return this.dataSource.updateState(); } private async init(): Promise { @@ -300,6 +255,7 @@ export class DataExplorerIdentitiesComponent implements OnInit, OnDestroy, SideN this.entitySchemaPersonReports = this.identitiesService.personReportsSchema; try { this.projectConfig = await this.configService.getConfig(); + this.isCreationAllowed = this.projectConfig.PersonConfig?.EnableNewPerson ?? false; this.displayedColumns = [ this.entitySchemaPersonReports.Columns[DisplayColumns.DISPLAY_PROPERTYNAME], this.entitySchemaPersonReports.Columns.IsSecurityIncident, @@ -310,86 +266,45 @@ export class DataExplorerIdentitiesComponent implements OnInit, OnDestroy, SideN this.displayedColumns.push( this.entitySchemaPersonReports.Columns.IdentityType, this.entitySchemaPersonReports.Columns.EmployeeType, - this.entitySchemaPersonReports.Columns.IsExternal + this.entitySchemaPersonReports.Columns.IsExternal, ); } // Ensure this column is always added last this.displayedColumns.push(this.entitySchemaPersonReports.Columns.XMarkedForDeletion); - this.displayedInnerColumns = [this.entitySchemaPersonReports.Columns[DisplayColumns.DISPLAY_PROPERTYNAME]]; - this.dataModel = this.isAdmin ? await this.identitiesService.getDataModelAdmin() : await this.identitiesService.getDataModelReport(); - this.filterOptions = this.dataModel.Filters; - this.groupingOptions = this.getGroupableProperties(this.dataModel.Properties); - if (!this.isAdmin) { - const indexActive = this.filterOptions.findIndex((elem) => elem.Name === 'isinactive'); - if (indexActive > -1) { - this.filterOptions[indexActive].InitialValue = '0'; - } - const reports = this.filterOptions.findIndex((elem) => elem.Name === 'reports'); - if (reports > -1) { - this.filterOptions[reports].InitialValue = '0'; - } - } - - if (this.applyIssuesFilter) { - const indexWithManagerFilter = this.filterOptions.findIndex((elem) => elem.Name === 'withmanager'); - if (indexWithManagerFilter > -1) { - this.filterOptions[indexWithManagerFilter].InitialValue = '0'; - } - } this.viewConfig = await this.viewConfigService.getInitialDSTExtension(this.dataModel, this.viewConfigPath); - await this.navigate(); - } finally { - isBusy.endBusy(); - } - } - - private async navigate(): Promise { - const isBusy = this.busyService.beginBusy(); - try { - this.logger.debug(this, `Retrieving person list`); - this.logger.trace('Navigation settings', this.navigationState); - if (!this.groupingInfo && this.groupingOptions.length > 0) { - this.groupingInfo = { - groups: [ + const dataViewInitParameters: DataViewInitParameters = { + execute: this.isAdmin + ? (params: CollectionLoadParameters, signal: AbortSignal): Promise> => + this.identitiesService.getAllPersonAdmin(params, signal) + : (params: CollectionLoadParameters, signal: AbortSignal): Promise> => + this.identitiesService.getReportsOfManager(params, signal), + schema: this.entitySchemaPersonReports, + columnsToDisplay: this.displayedColumns, + dataModel: this.dataModel, + groupExecute: (column: string, params: CollectionLoadParameters, signal: AbortSignal) => { + return this.identitiesService.getGroupedAllPerson( + column, { - property: this.groupingOptions[0], - getData: async () => { - return this.identitiesService.getGroupedAllPerson('IdentityType', { - PageSize: this.navigationState.PageSize, - StartIndex: 0, - withProperties: this.navigationState.withProperties, - }); - }, + PageSize: params.PageSize, + StartIndex: 0, + ...params, }, - ], - }; - } - - this.entitySchemaPersonReports = this.identitiesService.personReportsSchema; - const data = this.isAdmin - ? await this.identitiesService.getAllPersonAdmin(this.navigationState) - : await this.identitiesService.getReportsOfManager(this.navigationState); - const exportMethod: DataSourceToolbarExportMethod = this.isAdmin - ? this.identitiesService.exportAdminPerson(this.navigationState) - : this.identitiesService.exportPerson(this.navigationState); - exportMethod.initialColumns = this.displayedColumns.map((col) => col.ColumnName); - - this.dstSettings = { - displayedColumns: this.displayedColumns, - dataSource: data, - entitySchema: this.entitySchemaPersonReports, - navigationState: this.navigationState, - filters: this.filterOptions, - groupData: this.groupingInfo, - dataModel: this.dataModel, + signal, + ); + }, + exportFunction: this.isAdmin + ? this.identitiesService.exportAdminPerson(this.dataSource.state()) + : this.identitiesService.exportPerson(this.dataSource.state()), viewConfig: this.viewConfig, - exportMethod, + highlightEntity: (identity: PortalAdminPerson | PortalPersonReports) => { + this.onIdentityChanged(identity); + }, }; - this.logger.debug(this, `Head at ${data.Data.length + this.navigationState.StartIndex} of ${data.totalCount} item(s)`); + this.dataSource.init(dataViewInitParameters); } finally { isBusy.endBusy(); } @@ -398,21 +313,17 @@ export class DataExplorerIdentitiesComponent implements OnInit, OnDestroy, SideN public async updateConfig(config: ViewConfigData): Promise { await this.viewConfigService.putViewConfig(config); this.viewConfig = await this.viewConfigService.getDSTExtensionChanges(this.viewConfigPath); - this.dstSettings.viewConfig = this.viewConfig; + this.dataSource.viewConfig.set(this.viewConfig); } public async deleteConfigById(id: string): Promise { await this.viewConfigService.deleteViewConfig(id); this.viewConfig = await this.viewConfigService.getDSTExtensionChanges(this.viewConfigPath); - this.dstSettings.viewConfig = this.viewConfig; + this.dataSource.viewConfig.set(this.viewConfig); } private async getPersonDetails(id: string): Promise { - if (id == null || id.length <= 0) { - return null; - } this.logger.debug(this, `Retrieving details for admin person with id ${id}`); - return this.isAdmin ? this.identitiesService.getAdminPerson(id) : (await this.identitiesService.getPersonInteractive(id)).Data[0]; } @@ -423,7 +334,7 @@ export class DataExplorerIdentitiesComponent implements OnInit, OnDestroy, SideN subTitle: identity.GetEntity().GetDisplay(), padding: '0px', disableClose: true, - width: 'max(768px, 70%)', + width: calculateSidesheetWidth(1250, 0.7), icon: 'contactinfo', data: { isAdmin: this.isAdmin, @@ -435,12 +346,6 @@ export class DataExplorerIdentitiesComponent implements OnInit, OnDestroy, SideN }) .afterClosed() .toPromise(); - return this.navigate(); - } - - private getGroupableProperties(identityProperties: DataModelProperty[]): DataModelProperty[] { - let groupable: DataModelProperty[] = []; - groupable = identityProperties.filter((item) => item.IsGroupable); - return groupable; + return this.dataSource.updateState(); } } diff --git a/imxweb/projects/qer/src/lib/identities/identities.module.ts b/imxweb/projects/qer/src/lib/identities/identities.module.ts index e0ed7f297..60904d27c 100644 --- a/imxweb/projects/qer/src/lib/identities/identities.module.ts +++ b/imxweb/projects/qer/src/lib/identities/identities.module.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -24,8 +24,8 @@ * */ -import { NgModule } from '@angular/core'; import { CommonModule } from '@angular/common'; +import { NgModule } from '@angular/core'; import { FormsModule, ReactiveFormsModule } from '@angular/forms'; import { MatExpansionModule } from '@angular/material/expansion'; import { MatIconModule } from '@angular/material/icon'; @@ -34,6 +34,8 @@ import { RouterModule, Routes } from '@angular/router'; import { EuiCoreModule, EuiMaterialModule } from '@elemental-ui/core'; import { TranslateModule } from '@ngx-translate/core'; +import { MatMenuModule } from '@angular/material/menu'; +import { ProjectConfig } from '@imx-modules/imx-api-qbm'; import { BusyIndicatorModule, CdrModule, @@ -41,6 +43,7 @@ import { DataSourceToolbarModule, DataTableModule, DataTreeModule, + DataViewModule, DynamicTabsModule, ExtModule, HELP_CONTEXTUAL, @@ -51,23 +54,21 @@ import { ObjectHistoryModule, RouteGuardService, } from 'qbm'; -import { DataExplorerIdentitiesComponent } from './identities.component'; -import { IdentitiesService } from './identities.service'; -import { IdentitySidesheetComponent } from './identity-sidesheet/identity-sidesheet.component'; -import { IdentitiesReportsService } from './identities-reports.service'; import { isAuditor, isPersonAdmin, isPersonManager } from '../admin/qer-permissions-helper'; -import { RiskModule } from '../risk/risk.module'; import { DataExplorerRegistryService } from '../data-explorer-view/data-explorer-registry.service'; -import { AssignmentsComponent } from './identity-sidesheet/assignments/assignments.component'; -import { IdentityRoleMembershipsModule } from './identity-sidesheet/identity-role-memberships/identity-role-memberships.module'; +import { MyResponsibilitiesRegistryService } from '../my-responsibilities-view/my-responsibilities-registry.service'; +import { ObjectHyperviewModule } from '../object-hyperview/object-hyperview.module'; import { OrgChartModule } from '../org-chart/org-chart.module'; +import { RequestHistoryModule } from '../request-history/request-history.module'; +import { RiskModule } from '../risk/risk.module'; import { CreateNewIdentityComponent } from './create-new-identity/create-new-identity.component'; import { DuplicatesSidesheetComponent } from './create-new-identity/duplicates-sidesheet/duplicates-sidesheet.component'; -import { RequestHistoryModule } from '../request-history/request-history.module'; -import { ObjectHyperviewModule } from '../object-hyperview/object-hyperview.module'; -import { MyResponsibilitiesRegistryService } from '../my-responsibilities-view/my-responsibilities-registry.service'; -import { MatMenuModule } from '@angular/material/menu'; -import { ProjectConfig } from 'imx-api-qbm'; +import { IdentitiesReportsService } from './identities-reports.service'; +import { DataExplorerIdentitiesComponent } from './identities.component'; +import { IdentitiesService } from './identities.service'; +import { AssignmentsComponent } from './identity-sidesheet/assignments/assignments.component'; +import { IdentityRoleMembershipsModule } from './identity-sidesheet/identity-role-memberships/identity-role-memberships.module'; +import { IdentitySidesheetComponent } from './identity-sidesheet/identity-sidesheet.component'; const routes: Routes = [ { @@ -112,18 +113,18 @@ const routes: Routes = [ IdentityRoleMembershipsModule, RouterModule.forChild(routes), MatMenuModule, - HelpContextualModule + HelpContextualModule, + DataViewModule, ], providers: [IdentitiesService, IdentitiesReportsService], exports: [DataExplorerIdentitiesComponent], - entryComponents: [CreateNewIdentityComponent, DuplicatesSidesheetComponent], }) export class IdentitiesModule { constructor( private readonly dataExplorerRegistryService: DataExplorerRegistryService, private readonly menuService: MenuService, private readonly myResponsibilitiesRegistryService: MyResponsibilitiesRegistryService, - logger: ClassloggerService + logger: ClassloggerService, ) { logger.info(this, '▶️ IdentitiesModule loaded'); this.init(); @@ -132,50 +133,47 @@ export class IdentitiesModule { } private setupMenu(): void { - this.menuService.addMenuFactories( - (preProps: string[], features: string[], projectConfig: ProjectConfig, groups: string[]) => { - - const items: MenuItem[] = []; - if (preProps.includes('ITSHOP') && (isPersonAdmin(features) || isAuditor(groups))) { - items.push( - { - id: 'QER_DataExplorer', - navigationCommands: { commands: ['admin', 'dataexplorer'] }, - title: '#LDS#Menu Entry Data Explorer', - sorting: '40-10', - }, - ); - } - if (items.length === 0) { - return null; - } - return { - id: 'ROOT_Data', - title: '#LDS#Data administration', - sorting: '40', - items - }; - }, - ); - } - - private init(): void { + this.menuService.addMenuFactories((preProps: string[], features: string[], projectConfig: ProjectConfig, groups: string[]) => { + const items: MenuItem[] = []; + if (preProps.includes('ITSHOP') && (isPersonAdmin(features) || isPersonManager(features) || isAuditor(groups))) { + items.push({ + id: 'QER_DataExplorer', + navigationCommands: { commands: ['admin', 'dataexplorer'] }, + title: '#LDS#Menu Entry Data Explorer', + sorting: '40-10', + }); + } - this.dataExplorerRegistryService.registerFactory((preProps: string[], features: string[], projectConfig: ProjectConfig, groups: string[]) => { - if (!isPersonAdmin(features) && !isAuditor(groups)) { + if (items.length === 0) { return; } return { - instance: DataExplorerIdentitiesComponent, - sortOrder: 1, - name: 'identities', - caption: '#LDS#Identities', - icon: 'contactinfo', - contextId: HELP_CONTEXTUAL.DataExplorerIdentities + id: 'ROOT_Data', + title: '#LDS#Data administration', + sorting: '40', + items, }; }); } + private init(): void { + this.dataExplorerRegistryService.registerFactory( + (preProps: string[], features: string[], projectConfig: ProjectConfig, groups: string[]) => { + if (!isPersonAdmin(features) && !isPersonManager(features) && !isAuditor(groups)) { + return; + } + return { + instance: DataExplorerIdentitiesComponent, + sortOrder: 1, + name: 'identities', + caption: '#LDS#Identities', + icon: 'contactinfo', + contextId: HELP_CONTEXTUAL.DataExplorerIdentities, + }; + }, + ); + } + private setupMyResponsibilitiesView(): void { this.myResponsibilitiesRegistryService.registerFactory((preProps: string[], groups: string[]) => { if (!isPersonManager(groups)) { @@ -186,7 +184,7 @@ export class IdentitiesModule { sortOrder: 1, name: 'identities', caption: '#LDS#Identities', - contextId: HELP_CONTEXTUAL.MyResponsibilitiesIdentities + contextId: HELP_CONTEXTUAL.MyResponsibilitiesIdentities, }; }); } diff --git a/imxweb/projects/qer/src/lib/identities/identities.service.ts b/imxweb/projects/qer/src/lib/identities/identities.service.ts index c782f995b..f1efb9610 100644 --- a/imxweb/projects/qer/src/lib/identities/identities.service.ts +++ b/imxweb/projects/qer/src/lib/identities/identities.service.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -27,36 +27,41 @@ import { Injectable } from '@angular/core'; import { Subject } from 'rxjs'; -import { ClassloggerService, DataSourceToolbarExportMethod } from 'qbm'; +import { + PortalAdminPerson, + PortalPersonAll, + PortalPersonReports, + PortalPersonUid, + V2ApiClientMethodFactory, +} from '@imx-modules/imx-api-qer'; import { CollectionLoadParameters, - TypedEntityCollectionData, - FilterType, CompareOperator, - EntityCollectionData, - GroupInfoData, DataModel, + EntityCollectionData, EntitySchema, ExtendedTypedEntityCollection, FilterData, + FilterType, + GroupInfoData, MethodDefinition, MethodDescriptor, -} from 'imx-qbm-dbts'; -import { PortalPersonReports, PortalPersonAll, PortalAdminPerson, PortalPersonUid, ViewConfigData, V2ApiClientMethodFactory } from 'imx-api-qer'; -import { QerApiService } from '../qer-api-client.service'; + TypedEntityCollectionData, +} from '@imx-modules/imx-qbm-dbts'; +import { ClassloggerService, DataSourceToolbarExportMethod } from 'qbm'; import { QerPermissionsService } from '../admin/qer-permissions.service'; +import { QerApiService } from '../qer-api-client.service'; import { DuplicateCheckParameter } from './create-new-identity/duplicate-check-parameter.interface'; @Injectable() export class IdentitiesService { - public authorityDataDeleted: Subject = new Subject(); - constructor( private readonly qerClient: QerApiService, private readonly logger: ClassloggerService, - private readonly qerPermissions: QerPermissionsService) { } + private readonly qerPermissions: QerPermissionsService, + ) {} public get personReportsSchema(): EntitySchema { return this.qerClient.typedClient.PortalPersonReports.GetSchema(); @@ -74,14 +79,13 @@ export class IdentitiesService { return this.qerClient.typedClient.PortalAdminPerson.GetSchema(); } - - public getAttestationHelperAlertDescription(count: { total: number; forUser: number; }): { description: string; value?: any; }[] { + public getAttestationHelperAlertDescription(count: { total: number; forUser: number }): { description: string; value?: any }[] { // #LDS#There are currently no pending attestation cases. return [ { description: '#LDS#Here you can get an overview of all attestations cases for this object.' }, { description: '#LDS#Pending attestation cases: {0}', value: count.total }, - { description: '#LDS#Pending attestation cases you can approve or deny: {0}', value: count.forUser } + { description: '#LDS#Pending attestation cases you can approve or deny: {0}', value: count.forUser }, ]; } @@ -92,16 +96,22 @@ export class IdentitiesService { * * @returns Wrapped list of Persons. */ - public async getAllPerson(navigationState: CollectionLoadParameters): Promise> { + public async getAllPerson( + navigationState: CollectionLoadParameters, + signal?: AbortSignal, + ): Promise> { this.logger.debug(this, `Retrieving person list`); this.logger.trace('Navigation state', navigationState); - return this.qerClient.typedClient.PortalPersonAll.Get(navigationState); + return this.qerClient.typedClient.PortalPersonAll.Get(navigationState, { signal }); } - public async getAllPersonAdmin(navigationState: CollectionLoadParameters): Promise> { + public async getAllPersonAdmin( + navigationState: CollectionLoadParameters, + signal: AbortSignal, + ): Promise> { this.logger.debug(this, `Retrieving person list`); this.logger.trace('Navigation state', navigationState); - return this.qerClient.typedClient.PortalAdminPerson.Get(navigationState); + return this.qerClient.typedClient.PortalAdminPerson.Get(navigationState, { signal }); } /** @@ -122,13 +132,13 @@ export class IdentitiesService { getMethod: (withProperties: string, PageSize?: number) => { let method: MethodDescriptor; if (PageSize) { - method = factory.portal_admin_person_get({...navigationState, withProperties, PageSize, StartIndex: 0}) + method = factory.portal_admin_person_get({ ...navigationState, withProperties, PageSize, StartIndex: 0 }); } else { - method = factory.portal_admin_person_get({...navigationState, withProperties}) + method = factory.portal_admin_person_get({ ...navigationState, withProperties }); } return new MethodDefinition(method); - } - } + }, + }; } public exportPerson(navigationState?: CollectionLoadParameters): DataSourceToolbarExportMethod { @@ -137,13 +147,13 @@ export class IdentitiesService { getMethod: (withProperties: string, PageSize?: number) => { let method: MethodDescriptor; if (PageSize) { - method = factory.portal_person_reports_get({...navigationState, withProperties, PageSize, StartIndex: 0 }); + method = factory.portal_person_reports_get({ ...navigationState, withProperties, PageSize, StartIndex: 0 }); } else { - method = factory.portal_person_reports_get({...navigationState, withProperties}); + method = factory.portal_person_reports_get({ ...navigationState, withProperties }); } return new MethodDefinition(method); - } - } + }, + }; } /** @@ -153,14 +163,20 @@ export class IdentitiesService { * * @returns Wrapped list of Persons. */ - public async getReportsOfManager(navigationState: CollectionLoadParameters): - Promise> { + public async getReportsOfManager( + navigationState: CollectionLoadParameters, + signal: AbortSignal, + ): Promise> { this.logger.debug(this, `Retrieving reports of the manager`); this.logger.trace('Navigation state', navigationState); - return this.qerClient.typedClient.PortalPersonReports.Get(navigationState); + return this.qerClient.typedClient.PortalPersonReports.Get(navigationState, { signal }); } - public async getGroupedAllPerson(columns: string, navigationState: CollectionLoadParameters): Promise { + public async getGroupedAllPerson( + columns: string, + navigationState: CollectionLoadParameters, + signal: AbortSignal, + ): Promise { this.logger.debug(this, `Retrieving person list`); this.logger.trace('Navigation state', navigationState); @@ -170,12 +186,14 @@ export class IdentitiesService { def: '', StartIndex: navigationState.StartIndex, PageSize: navigationState.PageSize, + filter: navigationState.filter, withcount: true, - withmanager: '', - orphaned: '', - deletedintarget: '', - isinactive: '' - } + withmanager: navigationState?.withmanager || '', + orphaned: navigationState?.orphaned || '', + deletedintarget: navigationState?.deletedintarget || '', + isinactive: navigationState?.isinactive || '', + }, + { signal }, ); } @@ -219,9 +237,8 @@ export class IdentitiesService { } public buildFilterForduplicates(parameter: DuplicateCheckParameter): FilterData[] { - const filter = []; - if (parameter.firstName != null && parameter.firstName !== '' - && parameter.lastName != null && parameter.lastName !== '') { + const filter: FilterData[] = []; + if (parameter.firstName != null && parameter.firstName !== '' && parameter.lastName != null && parameter.lastName !== '') { filter.push(this.buildFilter('FirstName', parameter.firstName)); filter.push(this.buildFilter('LastName', parameter.lastName)); } @@ -237,9 +254,7 @@ export class IdentitiesService { return filter; } - public async getDuplicates(parameter: CollectionLoadParameters) - : Promise>> { - + public async getDuplicates(parameter: CollectionLoadParameters): Promise>> { if (parameter.filter?.length === 0) { return { Data: [], totalCount: 0 }; } @@ -251,7 +266,7 @@ export class IdentitiesService { CompareOp: CompareOperator.Equal, Type: FilterType.Compare, ColumnName: column, - Value1: value + Value1: value, }; } } diff --git a/imxweb/projects/qer/src/lib/identities/identity-sidesheet/assignments/assignments.component.html b/imxweb/projects/qer/src/lib/identities/identity-sidesheet/assignments/assignments.component.html index 70b213f58..c13bcd8f9 100644 --- a/imxweb/projects/qer/src/lib/identities/identity-sidesheet/assignments/assignments.component.html +++ b/imxweb/projects/qer/src/lib/identities/identity-sidesheet/assignments/assignments.component.html @@ -1,26 +1,4 @@ -
    - - -
    -
    - -
    - -
    -
    - {{ tab.inputData.label }} -
    -
    -
    -
    - -
    - -
    -
    -
    \ No newline at end of file + + + + diff --git a/imxweb/projects/qer/src/lib/identities/identity-sidesheet/assignments/assignments.component.scss b/imxweb/projects/qer/src/lib/identities/identity-sidesheet/assignments/assignments.component.scss index 9480887a7..69ac2dca7 100644 --- a/imxweb/projects/qer/src/lib/identities/identity-sidesheet/assignments/assignments.component.scss +++ b/imxweb/projects/qer/src/lib/identities/identity-sidesheet/assignments/assignments.component.scss @@ -1,156 +1,6 @@ -@import "@elemental-ui/core/src/styles/_palette.scss"; -@import '@elemental-ui/core/src/styles/_eui_palette.scss'; -@import '../../../../../../../shared/scss/side-navigation.scss'; -:host { - height: 100%; -} +@import 'base/mixins'; -.snavigation { +:host { + @include flex-column-container-fill(); height: 100%; - - .mat-sidenav-container { - height: 100%; - background-color: $asher-gray; - - .mat-sidenav { - width: 230px; - - .snavigation-side { - display: flex; - flex-direction: column; - height: 100%; - - .snavigation-side-toggle { - display: none; - padding: 16px 12px 0; - margin-bottom: 10px; - - .mat-button { - min-width: 0; - padding: 0 4px; - height: 28px; - - .mat-icon { - margin-top: -12px; - } - } - } - - .snavigation-side-content { - flex: 1; - padding: 32px; - padding-bottom: 16px; - - .snavigation-side-heading { - font-size: 14px; - font-weight: bold; - margin-bottom: 10px; - white-space: nowrap; - } - - .snavigation-item { - margin: 0 -32px; - padding: 10px 32px; - display: flex; - align-items: center; - justify-content: flex-start; - cursor: pointer; - - & > .eui-icon { - margin-right: 8px; - color: rgba($black, 0.4); - } - - & > span { - flex: 1; - } - - &:hover:not(.snavigation-item--selected) { - background-color: rgba($iris-tint, 0.5); - } - - &.snavigation-item--selected { - background-color: $iris-blue; - color: $white; - } - } - } - } - } - - .mat-sidenav-content { - padding: 20px; - position: relative; - display: flex; - flex-direction: column; - - &.snavigation--backdrop-showing { - overflow: hidden; - } - - .snavigation-backdrop { - position: absolute; - top: 0; - left: 0; - right: 0; - bottom: 0; - background-color: rgba($black, 0.32); - z-index: 200; - } - - .mat-table tr:hover td { - background-color: rgba($black, 0.04); - cursor: pointer; - } - } - } -} - -@media only screen and (max-width: 768px) { - .snavigation .mat-sidenav-container { - .mat-sidenav { - transition: width 0.5s; - - .snavigation-side { - .snavigation-side-toggle { - display: block; - } - .snavigation-side-content { - padding: 16px; - } - } - - &:not(.snavigation-side--expanded) { - width: 58px; - - .snavigation-side-content { - display: none; - } - } - } - - .mat-sidenav-content { - padding: 16px; - } - } -} - -.eui-dark-theme { - :host{ - .snavigation .mat-sidenav-container{ - background-color: $color-gray-80; - } - } -} - -.eui-contrast-theme { - :host{ - .snavigation .mat-sidenav-container{ - background-color: $color-gray-100; - } - - .snavigation-item--selected { - border: 1px solid $color-gray-0 - } - } } diff --git a/imxweb/projects/qer/src/lib/identities/identity-sidesheet/assignments/assignments.component.ts b/imxweb/projects/qer/src/lib/identities/identity-sidesheet/assignments/assignments.component.ts index 459456b14..4aedf1605 100644 --- a/imxweb/projects/qer/src/lib/identities/identity-sidesheet/assignments/assignments.component.ts +++ b/imxweb/projects/qer/src/lib/identities/identity-sidesheet/assignments/assignments.component.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -24,90 +24,106 @@ * */ -import { Component, ComponentFactoryResolver, Injector, Input, OnInit, ViewChild, ViewContainerRef } from '@angular/core'; +import { Component, Injector, Input, OnInit, ViewChild, ViewContainerRef } from '@angular/core'; -import { DynamicTabDataProviderDirective, ExtService, TabItem } from 'qbm'; +import { FormControl, FormGroup } from '@angular/forms'; +import { EuiSelectOption } from '@elemental-ui/core'; +import { TranslateService } from '@ngx-translate/core'; +import { DynamicTabDataProviderDirective, ExtService, isMobile, TabItem } from 'qbm'; import { IdentityRoleMembershipsComponent } from '../identity-role-memberships/identity-role-memberships.component'; import { IdentityRoleMembershipsService } from '../identity-role-memberships/identity-role-memberships.service'; +interface SelectorForm { + selector: FormControl; +} + @Component({ selector: 'imx-assignments', templateUrl: './assignments.component.html', - styleUrls: ['./assignments.component.scss'] + styleUrls: ['./assignments.component.scss'], }) export class AssignmentsComponent implements OnInit { - - public currentTab: TabItem; - public dynamicTabs: TabItem[] = []; - - get isMobile(): boolean { - return document.body.offsetWidth <= 768; - } + public currentTab: TabItem | undefined; public mobileSideNavExpanded = false; public showBackdrop = false; - public contentMargin = this.isMobile ? '10px' : '230px'; + public contentMargin = isMobile() ? '10px' : '230px'; + + public options: EuiSelectOption[]; + public formGroup: FormGroup = new FormGroup({ + selector: new FormControl('', { nonNullable: true }), + }); + + private tabItems: TabItem[] = []; @Input() public parameters: { objecttable: string; objectuid: string; tableName?: string }; - @ViewChild('sideNavContent', { read: ViewContainerRef, static: true }) private sideNavContentRef: ViewContainerRef; + @ViewChild('content', { static: true, read: ViewContainerRef }) content!: ViewContainerRef; constructor( private readonly roleService: IdentityRoleMembershipsService, - private readonly componentFactoryResolver: ComponentFactoryResolver, private readonly extService: ExtService, - private readonly injector: Injector - ) { } + private readonly injector: Injector, + private readonly translate: TranslateService, + ) {} public async ngOnInit(): Promise { - const tabs: TabItem[] = []; - this.roleService.targets.forEach(target => { + this.roleService.targets.forEach((target) => { const tabitem: TabItem = { instance: IdentityRoleMembershipsComponent, inputData: { id: target, - checkVisibility: async _ => true, - label: this.roleService.getTabData(target).label + checkVisibility: async (_) => true, + label: this.roleService.getTabData(target)?.label || '', }, - sortOrder: this.roleService.getTabData(target).index + sortOrder: this.roleService.getTabData(target)?.index, }; tabs.push(tabitem); }); + this.tabItems = [ + ...(await this.extService.getFittingComponents('identityAssignment', (ext) => + ext.inputData.checkVisibility(this.parameters), + )), + ...tabs, + ].sort((a: TabItem, b: TabItem) => (a?.sortOrder || 0) - (b?.sortOrder || 0)); - this.dynamicTabs = [...(await this.extService.getFittingComponents('identityAssignment', - (ext) => ext.inputData.checkVisibility(this.parameters))), ...tabs] - .sort((a: TabItem, b: TabItem) => a.sortOrder - b.sortOrder); + this.options = this.tabItems.map((elem) => ({ display: this.translate.instant(elem.inputData.label), value: elem.inputData.id })); + this.formGroup.controls.selector.setValue(this.options[0].value); - this.updateTab(this.dynamicTabs[0]); + this.updateTab(this.options[0]); } - public updateTab(tab: TabItem): void { - this.currentTab = tab; - this.sideNavContentRef.clear(); + public updateTab(tab: EuiSelectOption | EuiSelectOption[]): void { + const id = Object.hasOwn(tab, 'value') ? (tab as EuiSelectOption).value : ''; + this.currentTab = this.tabItems.find((elem) => elem.inputData.id === id); + if (this.currentTab == null) { + return; + } + this.content?.clear(); const dataProvider = Injector.create({ - providers: [{ - provide: DynamicTabDataProviderDirective, - useValue: { data: { ...this.parameters, ...{ tablename: tab.inputData.id } } } - }], + providers: [ + { + provide: DynamicTabDataProviderDirective, + useValue: { data: { ...this.parameters, ...{ tablename: this.currentTab.inputData.id } } }, + }, + ], parent: this.injector, }); - - this.sideNavContentRef.createComponent(this.componentFactoryResolver.resolveComponentFactory(this.currentTab.instance), - undefined, dataProvider); + if (this.currentTab?.instance != null) { + this.content.createComponent(this.currentTab.instance, { injector: dataProvider }); + } } public toggleMobileExpand(): void { this.mobileSideNavExpanded = !this.mobileSideNavExpanded; - const showBackdrop = this.isMobile && this.mobileSideNavExpanded; + const showBackdrop = isMobile() && this.mobileSideNavExpanded; setTimeout( () => { this.showBackdrop = showBackdrop; }, - showBackdrop ? 0 : 500 + showBackdrop ? 0 : 500, ); } - - } diff --git a/imxweb/projects/qer/src/lib/identities/identity-sidesheet/identity-role-memberships/identity-role-memberships-parameter.interface.ts b/imxweb/projects/qer/src/lib/identities/identity-sidesheet/identity-role-memberships/identity-role-memberships-parameter.interface.ts index 01ccf00f8..a6d49babd 100644 --- a/imxweb/projects/qer/src/lib/identities/identity-sidesheet/identity-role-memberships/identity-role-memberships-parameter.interface.ts +++ b/imxweb/projects/qer/src/lib/identities/identity-sidesheet/identity-role-memberships/identity-role-memberships-parameter.interface.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -24,7 +24,7 @@ * */ -import { CollectionLoadParameters, EntitySchema, EntityCollectionData } from 'imx-qbm-dbts'; +import { CollectionLoadParameters, EntitySchema, EntityCollectionData } from '@imx-modules/imx-qbm-dbts'; export interface IdentityRoleMembershipsParameter { /** diff --git a/imxweb/projects/qer/src/lib/identities/identity-sidesheet/identity-role-memberships/identity-role-memberships.component.html b/imxweb/projects/qer/src/lib/identities/identity-sidesheet/identity-role-memberships/identity-role-memberships.component.html index bb3651ba7..616514d1b 100644 --- a/imxweb/projects/qer/src/lib/identities/identity-sidesheet/identity-role-memberships/identity-role-memberships.component.html +++ b/imxweb/projects/qer/src/lib/identities/identity-sidesheet/identity-role-memberships/identity-role-memberships.component.html @@ -1,5 +1,8 @@ - - {{ '#LDS#Here you can get an overview of the memberships of the identity. Additionally, you can view the assignment analysis for each membership.' | translate }} + + {{ + '#LDS#Here you can get an overview of the memberships of the identity. Additionally, you can view the assignment analysis for each membership.' + | translate + }}
    - - + +
    {{ item.GetEntity().GetDisplay() }}
    diff --git a/imxweb/projects/qer/src/lib/identities/identity-sidesheet/identity-role-memberships/identity-role-memberships.component.scss b/imxweb/projects/qer/src/lib/identities/identity-sidesheet/identity-role-memberships/identity-role-memberships.component.scss index 220b6601f..bb0fa0525 100644 --- a/imxweb/projects/qer/src/lib/identities/identity-sidesheet/identity-role-memberships/identity-role-memberships.component.scss +++ b/imxweb/projects/qer/src/lib/identities/identity-sidesheet/identity-role-memberships/identity-role-memberships.component.scss @@ -1,4 +1,4 @@ -@import "@elemental-ui/core/src/styles/_palette.scss"; +@import '@elemental-ui/core/src/styles/_palette.scss'; :host { overflow: hidden; @@ -7,7 +7,6 @@ height: 100%; } - .imx-memberships { flex: 1 1 auto; display: flex; @@ -22,7 +21,3 @@ overflow: auto; margin-top: 20px; } - -.helper-alert { - margin: 20px 2px; -} \ No newline at end of file diff --git a/imxweb/projects/qer/src/lib/identities/identity-sidesheet/identity-role-memberships/identity-role-memberships.component.ts b/imxweb/projects/qer/src/lib/identities/identity-sidesheet/identity-role-memberships/identity-role-memberships.component.ts index 991140679..61d513f9c 100644 --- a/imxweb/projects/qer/src/lib/identities/identity-sidesheet/identity-role-memberships/identity-role-memberships.component.ts +++ b/imxweb/projects/qer/src/lib/identities/identity-sidesheet/identity-role-memberships/identity-role-memberships.component.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -24,13 +24,19 @@ * */ -import { OverlayRef } from '@angular/cdk/overlay'; import { Component, OnInit } from '@angular/core'; -import { EuiLoadingService, EuiSidesheetService } from '@elemental-ui/core'; +import { EuiSidesheetService } from '@elemental-ui/core'; import { TranslateService } from '@ngx-translate/core'; -import { CollectionLoadParameters, DisplayColumns, EntitySchema, IClientProperty, TypedEntity, ValType } from 'imx-qbm-dbts'; -import { BusyService, DataSourceToolbarSettings, DynamicTabDataProviderDirective, MetadataService, SettingsService } from 'qbm'; +import { CollectionLoadParameters, DisplayColumns, EntitySchema, IClientProperty, TypedEntity } from '@imx-modules/imx-qbm-dbts'; +import { + BusyService, + calculateSidesheetWidth, + DataSourceToolbarSettings, + DynamicTabDataProviderDirective, + MetadataService, + SettingsService, +} from 'qbm'; import { RoleService } from '../../../role-management/role.service'; import { SourceDetectiveSidesheetComponent, @@ -48,7 +54,7 @@ export class IdentityRoleMembershipsComponent implements OnInit { public readonly DisplayColumns = DisplayColumns; public displayedColumns: IClientProperty[]; public caption: string; - public entitySchema: EntitySchema; + public entitySchema: EntitySchema | undefined; public withActions: boolean; private referrer: { objectuid: string; tablename: string }; @@ -58,7 +64,6 @@ export class IdentityRoleMembershipsComponent implements OnInit { public busyService = new BusyService(); constructor( - private readonly busyServiceElemental: EuiLoadingService, private readonly metadataService: MetadataService, private readonly roleMembershipsService: IdentityRoleMembershipsService, private readonly membershipService: RoleService, @@ -68,10 +73,14 @@ export class IdentityRoleMembershipsComponent implements OnInit { dataProvider: DynamicTabDataProviderDirective, ) { this.referrer = dataProvider.data; - this.entitySchema = this.roleMembershipsService.getSchema(this.referrer.tablename); + this.navigationState = { PageSize: this.settingService.DefaultPageSize }; + this.withActions = this.roleMembershipsService.canAnalyseAssignment(this.referrer.tablename); + this.entitySchema = this.roleMembershipsService.getSchema(this.referrer.tablename); - this.navigationState = { PageSize: this.settingService.DefaultPageSize }; + if (!this.entitySchema) { + return; + } this.displayedColumns = [ this.entitySchema.Columns.XOrigin, this.entitySchema.Columns.XDateInserted, @@ -89,7 +98,7 @@ export class IdentityRoleMembershipsComponent implements OnInit { } finally { isBusy.endBusy(); } - this.caption = this.metadataService.tables[this.referrer.tablename].Display; + this.caption = this.metadataService.tables[this.referrer.tablename]?.Display || ''; return this.getData(); } @@ -99,7 +108,7 @@ export class IdentityRoleMembershipsComponent implements OnInit { } const uidPerson = this.referrer.objectuid; - const uidRole = this.membershipService.targetMap.get(this.referrer.tablename)?.membership.GetUidRole(entity.GetEntity()); + const uidRole = this.membershipService.targetMap.get(this.referrer.tablename)?.membership?.GetUidRole(entity.GetEntity()); if (uidRole == null) { return; } @@ -113,7 +122,7 @@ export class IdentityRoleMembershipsComponent implements OnInit { title: await this.translate.get('#LDS#Heading View Assignment Analysis').toPromise(), subTitle: entity.GetEntity().GetDisplay(), padding: '0px', - width: 'max(768px, 80%)', + width: calculateSidesheetWidth(1100, 0.7), disableClose: false, testId: 'identity-role-memberships-risk-sidesheet', data, @@ -138,9 +147,13 @@ export class IdentityRoleMembershipsComponent implements OnInit { try { const dataSource = await this.roleMembershipsService.get(this.referrer.tablename, this.referrer.objectuid, this.navigationState); + if (this.entitySchema == null) { + return; + } + this.dstSettings = { displayedColumns: this.displayedColumnsWithDisplay, - dataSource, + dataSource: dataSource, entitySchema: this.entitySchema, navigationState: this.navigationState, }; diff --git a/imxweb/projects/qer/src/lib/identities/identity-sidesheet/identity-role-memberships/identity-role-memberships.module.ts b/imxweb/projects/qer/src/lib/identities/identity-sidesheet/identity-role-memberships/identity-role-memberships.module.ts index 8e629a37e..29dfec11e 100644 --- a/imxweb/projects/qer/src/lib/identities/identity-sidesheet/identity-role-memberships/identity-role-memberships.module.ts +++ b/imxweb/projects/qer/src/lib/identities/identity-sidesheet/identity-role-memberships/identity-role-memberships.module.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -36,14 +36,6 @@ import { MatCardModule } from '@angular/material/card'; @NgModule({ declarations: [IdentityRoleMembershipsComponent], - imports: [ - CommonModule, - EuiCoreModule, - DataSourceToolbarModule, - DataTableModule, - TranslateModule, - MatButtonModule, - MatCardModule - ] + imports: [CommonModule, EuiCoreModule, DataSourceToolbarModule, DataTableModule, TranslateModule, MatButtonModule, MatCardModule], }) -export class IdentityRoleMembershipsModule { } +export class IdentityRoleMembershipsModule {} diff --git a/imxweb/projects/qer/src/lib/identities/identity-sidesheet/identity-role-memberships/identity-role-memberships.service.ts b/imxweb/projects/qer/src/lib/identities/identity-sidesheet/identity-role-memberships/identity-role-memberships.service.ts index a395110ec..f5a42e64d 100644 --- a/imxweb/projects/qer/src/lib/identities/identity-sidesheet/identity-role-memberships/identity-role-memberships.service.ts +++ b/imxweb/projects/qer/src/lib/identities/identity-sidesheet/identity-role-memberships/identity-role-memberships.service.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -31,19 +31,24 @@ import { PortalPersonRolemembershipsDepartment, PortalPersonRolemembershipsItshoporg, PortalPersonRolemembershipsLocality, - PortalPersonRolemembershipsProfitcenter -} from 'imx-api-qer'; -import { CollectionLoadParameters, EntitySchema, TypedEntity, TypedEntityBuilder, TypedEntityCollectionData } from 'imx-qbm-dbts'; + PortalPersonRolemembershipsProfitcenter, +} from '@imx-modules/imx-api-qer'; +import { + CollectionLoadParameters, + EntitySchema, + TypedEntity, + TypedEntityBuilder, + TypedEntityCollectionData, +} from '@imx-modules/imx-qbm-dbts'; import { QerApiService } from '../../../qer-api-client.service'; import { IdentityRoleMembershipsParameter, MembershipContolInfo } from './identity-role-memberships-parameter.interface'; @Injectable({ - providedIn: 'root' + providedIn: 'root', }) export class IdentityRoleMembershipsService { - public readonly targetMap: Map = new Map(); - public targets = []; + public targets: string[] = []; protected readonly localityTag = 'Locality'; protected readonly profitCenterTag = 'ProfitCenter'; @@ -55,29 +60,48 @@ export class IdentityRoleMembershipsService { this.addPredefinedTargets(); } - public async get(target: string, uidPerson:string, navigationState?: CollectionLoadParameters) - : Promise> { + public async get( + target: string, + uidPerson: string, + navigationState?: CollectionLoadParameters, + ): Promise | undefined> { const targetObject = this.targetMap.get(target); - if (!targetObject) { - throw new Error(`No target object registered for this target name '${target}'`); + if (!targetObject || !targetObject.get) { + // throw new Error(`No target object registered for this target name '${target}'`); + return undefined; } - const builder = new TypedEntityBuilder(targetObject.type); - const data = await targetObject.get(uidPerson,navigationState); + const entitySchema = targetObject.entitySchema; + if (!entitySchema) { + return undefined; + } + const data = await targetObject?.get(uidPerson, navigationState); + if (!data) { + return undefined; + } - return builder.buildReadWriteEntities(data, targetObject.entitySchema); + const builder = new TypedEntityBuilder(targetObject?.type); + return builder.buildReadWriteEntities(data, entitySchema); } - public getSchema(target: string): EntitySchema { - return this.targetMap.get(target)?.entitySchema; + public getSchema(target: string): EntitySchema | undefined { + if (!this.targetMap.has(target)) { + return undefined; + } + const targetObject = this.targetMap.get(target); + + if (!targetObject) { + return undefined; + } + return targetObject.entitySchema; } public canAnalyseAssignment(target: string): boolean { return this.targetMap.get(target)?.withAnalysis === true; } - public getTabData(target: string): MembershipContolInfo { + public getTabData(target: string): MembershipContolInfo | undefined { return this.targetMap.get(target)?.controlInfo; } @@ -95,14 +119,10 @@ export class IdentityRoleMembershipsService { label: '#LDS#Menu Entry Locations', index: 40, }, - get: async (uidPerson: string, parameter: CollectionLoadParameters) => - { - return this.qerApiClient.client.portal_person_rolememberships_Locality_get( - uidPerson, - parameter - )} - , - withAnalysis: true + get: async (uidPerson: string, parameter: CollectionLoadParameters) => { + return this.qerApiClient.client.portal_person_rolememberships_Locality_get(uidPerson, parameter); + }, + withAnalysis: true, }); this.addTarget({ @@ -113,11 +133,9 @@ export class IdentityRoleMembershipsService { label: '#LDS#Menu Entry Cost centers', index: 50, }, - get: async (uidPerson:string, parameter: CollectionLoadParameters) => this.qerApiClient.client.portal_person_rolememberships_ProfitCenter_get( - uidPerson, - parameter - ), - withAnalysis: true + get: async (uidPerson: string, parameter: CollectionLoadParameters) => + this.qerApiClient.client.portal_person_rolememberships_ProfitCenter_get(uidPerson, parameter), + withAnalysis: true, }); this.addTarget({ @@ -128,11 +146,9 @@ export class IdentityRoleMembershipsService { label: '#LDS#Menu Entry Departments', index: 30, }, - get: async (uidPerson: string, parameter: CollectionLoadParameters) => this.qerApiClient.client.portal_person_rolememberships_Department_get( - uidPerson, - parameter - ), - withAnalysis: true + get: async (uidPerson: string, parameter: CollectionLoadParameters) => + this.qerApiClient.client.portal_person_rolememberships_Department_get(uidPerson, parameter), + withAnalysis: true, }); this.addTarget({ @@ -143,11 +159,9 @@ export class IdentityRoleMembershipsService { label: '#LDS#Menu Entry Application roles', index: 60, }, - get: async (uidPerson: string, parameter: CollectionLoadParameters) => this.qerApiClient.client.portal_person_rolememberships_AERole_get( - uidPerson, - parameter - ), - withAnalysis: true + get: async (uidPerson: string, parameter: CollectionLoadParameters) => + this.qerApiClient.client.portal_person_rolememberships_AERole_get(uidPerson, parameter), + withAnalysis: true, }); this.addTarget({ @@ -158,14 +172,12 @@ export class IdentityRoleMembershipsService { label: '#LDS#Heading Shops', index: 90, }, - get: async (uidPerson: string,parameter: CollectionLoadParameters) => this.qerApiClient.client.portal_person_rolememberships_ITShopOrg_get( - uidPerson, - { + get: async (uidPerson: string, parameter: CollectionLoadParameters) => + this.qerApiClient.client.portal_person_rolememberships_ITShopOrg_get(uidPerson, { ...parameter, - type: 'CU' - } - ), - withAnalysis: false + type: 'CU', + }), + withAnalysis: false, }); } } diff --git a/imxweb/projects/qer/src/lib/identities/identity-sidesheet/identity-sidesheet.component.html b/imxweb/projects/qer/src/lib/identities/identity-sidesheet/identity-sidesheet.component.html index 2242867bb..a67b9bcfa 100644 --- a/imxweb/projects/qer/src/lib/identities/identity-sidesheet/identity-sidesheet.component.html +++ b/imxweb/projects/qer/src/lib/identities/identity-sidesheet/identity-sidesheet.component.html @@ -1,18 +1,19 @@ - + #LDS#Overview
    - - + + -
    +
    + [objectUid]="data?.selectedIdentity?.GetEntity()?.GetKeys()?.[0] ?? ''" + >
    @@ -38,8 +39,12 @@
    - - + +
    @@ -53,7 +58,7 @@
    - + {{ '#LDS#This identity will be deleted.' | translate }} @@ -63,78 +68,79 @@
    -
    +
    - +
    - - - - - {{ '#LDS#Personal data' | translate }} - - - - - - - - - {{ '#LDS#Organizational information' | translate }} - - - - - - - - - {{ '#LDS#Location information' | translate }} - - - - - - + + + + + + {{ '#LDS#Personal data' | translate }} + + + + + + + + + {{ '#LDS#Organizational information' | translate }} + + + + + + + + + {{ '#LDS#Location information' | translate }} + + + + + + +
    -
    @@ -152,10 +158,11 @@ #LDS#Requests
    -
    +
    - - + + +
    @@ -164,11 +171,7 @@ -
    -
    - -
    -
    +
    @@ -182,26 +185,52 @@ (click)="initiateDelete()" data-imx-identifier="identity-sidesheet-delete" > - + #LDS#Delete - - - - - diff --git a/imxweb/projects/qer/src/lib/identities/identity-sidesheet/identity-sidesheet.component.scss b/imxweb/projects/qer/src/lib/identities/identity-sidesheet/identity-sidesheet.component.scss index ece80de4a..7839579f8 100644 --- a/imxweb/projects/qer/src/lib/identities/identity-sidesheet/identity-sidesheet.component.scss +++ b/imxweb/projects/qer/src/lib/identities/identity-sidesheet/identity-sidesheet.component.scss @@ -1,35 +1,4 @@ -@import "@elemental-ui/core/src/styles/_palette.scss"; -@import "@elemental-ui/core/src/styles/_eui_palette.scss"; -.eui-sidesheet-content { - padding: 0; - - ::ng-deep .mat-tab-body-content { - display: flex; - flex-direction: column; - } -} - -.eui-sidesheet-actions { - .justify-start { - margin-right: auto; - - eui-icon { - font-size: 14px; - margin-right: 4px; - } - } - - button:not(:last-of-type):not(.justify-start) { - margin-right: 10px; - } -} - -.imx-helper-alert { - width: 100%; - ::ng-deep .eui-alert { - margin-bottom: 20px; - } -} +@import '@elemental-ui/core/src/styles/_eui_palette.scss'; .imx-security-badge { font-weight: 600; @@ -43,72 +12,16 @@ overflow: auto; } - .imx-account-ext { padding: 30px 30px 0px 30px; } -.imx-toggle-container{ - margin-bottom:16px; - >* {margin-right:20px;} -} - -.governance-sidesheet__tab-content-body { - &.imx-requests, &.imx-history { - .mat-card { - flex: 1 1 auto; - display: flex; - flex-direction: column; - height: 100%; - } - } -} - .governance-sidesheet__tab-content { - .mat-progress-spinner { - margin: auto; - } - imx-hyperview { overflow: hidden; } } -.imx-nested-group{ - &.eui-sidesheet-content{ - padding: 20px; - .mat-card{ - height: 100%; - padding: 0; - .mat-card{ - box-shadow: none; - } - ::ng-deep .mat-tab-group{ - border-radius: 4px; - imx-object-hyperview{ - .imx-tab-content-body{ - padding: 0; - } - } - .mat-ink-bar{ - background-color: $color-blue-90; - } - .governance-sidesheet{ - &__tab-content-body{ - ng-component{ - height: 100%; - .mat-card{ - padding: 0; - box-shadow: none; - } - } - } - } - } - } - } -} - @media screen and (max-width: 480px) { .marked-for-delete { margin: 10px 0 5px; @@ -116,84 +29,3 @@ width: 100%; } } - -::ng-deep .mat-tab-group { - height: 100%; - flex-grow: 1; - overflow: auto; - - .mat-tab-header { - padding: 0 32px; - background-color: $white; - } - - ::ng-deep .mat-tab-body-wrapper { - height: 100%; - } - - .imx-edit-fk-open-picker { - display: none; - } -} - -.eui-sidesheet-actions { - > *:not(:first-child) { - margin-left: 10px; - } -} - -.justify-start { - margin-right: auto; - justify-self: start; -} - -//Theming - -.eui-dark-theme { - :host { - .governance-sidesheet { - background: $color-gray-80; - ::ng-deep .mat-tab-group .mat-tab-header { - background-color: $color-gray-80; - } - ::ng-deep .mat-tab-label { - background-color: $color-gray-80; - } - - } - .imx-nested-group{ - ::ng-deep .mat-tab-group{ - .mat-tab-header{ - background-color: $color-gray-70; - .mat-ink-bar{ - background-color: $color-gray-0; - } - } - } - } - } -} - -.eui-contrast-theme { - :host { - ::ng-deep .mat-tab-group .mat-tab-header { - background-color: $color-gray-90; - } - .governance-sidesheet { - background: $color-gray-100; - ::ng-deep .mat-tab-label { - background-color: $color-gray-100; - } - } - .imx-nested-group{ - ::ng-deep .mat-tab-group{ - .mat-tab-header{ - background-color: $color-gray-90; - .mat-ink-bar{ - background-color: $color-gray-0; - } - } - } - } - } -} diff --git a/imxweb/projects/qer/src/lib/identities/identity-sidesheet/identity-sidesheet.component.ts b/imxweb/projects/qer/src/lib/identities/identity-sidesheet/identity-sidesheet.component.ts index 7d28325ba..1a775d782 100644 --- a/imxweb/projects/qer/src/lib/identities/identity-sidesheet/identity-sidesheet.component.ts +++ b/imxweb/projects/qer/src/lib/identities/identity-sidesheet/identity-sidesheet.component.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -24,36 +24,37 @@ * */ -import { OverlayRef } from '@angular/cdk/overlay'; -import { Component, OnDestroy, Inject, OnInit, ViewChild } from '@angular/core'; -import { UntypedFormGroup, UntypedFormControl } from '@angular/forms'; +import { Component, Inject, OnDestroy, OnInit, ViewChild } from '@angular/core'; +import { FormControl, FormGroup } from '@angular/forms'; import { MatSlideToggleChange } from '@angular/material/slide-toggle'; import { MatTabGroup } from '@angular/material/tabs'; import { Router } from '@angular/router'; -import { EuiLoadingService, EuiSidesheetService, EUI_SIDESHEET_DATA, EuiSidesheetRef } from '@elemental-ui/core'; -import { Subscription } from 'rxjs'; +import { EUI_SIDESHEET_DATA, EuiLoadingService, EuiSidesheetRef, EuiSidesheetService } from '@elemental-ui/core'; import { TranslateService } from '@ngx-translate/core'; +import { Subscription } from 'rxjs'; -import { IdentitiesService } from '../identities.service'; -import { FeatureConfig, PortalAdminPerson, PortalPersonReports, QerProjectConfig } from 'imx-api-qer'; +import { FeatureConfig, PortalAdminPerson, PortalPersonReports, QerProjectConfig } from '@imx-modules/imx-api-qer'; +import { DbObjectKey } from '@imx-modules/imx-qbm-dbts'; import { - ColumnDependentReference, - ClassloggerService, + AuthenticationService, BaseCdr, + calculateSidesheetWidth, + CdrFactoryService, + ClassloggerService, + ColumnDependentReference, + ConfirmationService, + ExtService, + ISessionState, SnackBarService, - AuthenticationService, SystemInfoService, - ConfirmationService, TabItem, - ExtService, - CdrFactoryService, } from 'qbm'; -import { DbObjectKey } from 'imx-qbm-dbts'; -import { IdentitiesReportsService } from '../identities-reports.service'; +import { FeatureConfigService } from '../../admin/feature-config.service'; import { PasscodeService } from '../../ops/passcode.service'; import { QerApiService } from '../../qer-api-client.service'; import { RiskAnalysisSidesheetComponent } from '../../risk/riskanalysis-sidesheet.component'; -import { FeatureConfigService } from '../../admin/feature-config.service'; +import { IdentitiesReportsService } from '../identities-reports.service'; +import { IdentitiesService } from '../identities.service'; @Component({ selector: 'imx-identity-sidesheet', @@ -63,21 +64,22 @@ import { FeatureConfigService } from '../../admin/feature-config.service'; export class IdentitySidesheetComponent implements OnInit, OnDestroy { @ViewChild('tabs') public tabs: MatTabGroup; - public readonly detailsFormGroup: UntypedFormGroup; - public cdrList: ColumnDependentReference[] = []; - public cdrListPersonal: ColumnDependentReference[] = []; - public cdrListOrganizational: ColumnDependentReference[] = []; - public cdrListLocality: ColumnDependentReference[] = []; + public readonly detailsFormGroup = new FormGroup({}); + public cdrList: (ColumnDependentReference | undefined)[] = []; + public cdrListPersonal: (ColumnDependentReference | undefined)[] = []; + public cdrListOrganizational: (ColumnDependentReference | undefined)[] = []; + public cdrListLocality: (ColumnDependentReference | undefined)[] = []; public valueChanges$: Subscription; - public readonly parameters: { objecttable: string; objectuid: string }; + public readonly parameters: { objecttable: string; objectuid: string; display: string }; public canAnalyzeRisk = false; - public isActiveFormControl = new UntypedFormControl(); - public isSecurityIncidentFormControl = new UntypedFormControl(); + public isActiveFormControl = new FormControl(false, { nonNullable: true }); + public isSecurityIncidentFormControl = new FormControl(false, { nonNullable: true }); public dynamicTabs: TabItem[] = []; private readonly subscriptions: Subscription[] = []; private currentUserUid: string; private featureConfig: FeatureConfig; + private isInactiveHasChanged = false; constructor( @Inject(EUI_SIDESHEET_DATA) @@ -100,11 +102,11 @@ export class IdentitySidesheetComponent implements OnInit, OnDestroy { private readonly router: Router, private readonly systemInfoService: SystemInfoService, private readonly translate: TranslateService, - private readonly extService: ExtService, + private readonly extService: ExtService, private readonly featureConfigService: FeatureConfigService, private readonly cdrFactoryService: CdrFactoryService, authentication: AuthenticationService, - confirm: ConfirmationService + confirm: ConfirmationService, ) { this.subscriptions.push( this.sidesheetRef.closeClicked().subscribe(async (result) => { @@ -116,20 +118,24 @@ export class IdentitySidesheetComponent implements OnInit, OnDestroy { } else { this.sidesheetRef.close(result); } - }) + }), ); - this.subscriptions.push(authentication.onSessionResponse.subscribe((sessionState) => (this.currentUserUid = sessionState.UserUid))); + this.subscriptions.push( + authentication.onSessionResponse.subscribe((sessionState: ISessionState) => (this.currentUserUid = sessionState.UserUid || '')), + ); - this.detailsFormGroup = new UntypedFormGroup({}); this.parameters = { - objecttable: PortalPersonReports.GetEntitySchema().TypeName, + objecttable: PortalPersonReports.GetEntitySchema().TypeName ?? '', objectuid: data.selectedIdentity.GetEntity().GetKeys()[0], + display: data.selectedIdentity.GetEntity().GetDisplay(), }; this.systemInfoService .get() - .then((i) => (this.canAnalyzeRisk = i.PreProps.includes('RISKINDEX') && data.selectedIdentity.RiskIndexCalculated.value > 0)); + .then( + (i) => (this.canAnalyzeRisk = (i.PreProps?.includes('RISKINDEX') && data.selectedIdentity.RiskIndexCalculated.value > 0) || false), + ); } get isIdentityMarkedForDelete(): boolean { @@ -167,7 +173,7 @@ export class IdentitySidesheetComponent implements OnInit, OnDestroy { public async personsManagedReport(): Promise { this.reports.personsManagedReport( this.data.selectedIdentity.GetEntity().GetKeys()[0], - '#LDS#Download report on identities this identity is directly responsible for' + '#LDS#View identities this identity is directly responsible for', ); } @@ -202,7 +208,11 @@ export class IdentitySidesheetComponent implements OnInit, OnDestroy { try { await this.data.selectedIdentity.GetEntity().Commit(true); this.detailsFormGroup.markAsPristine(); - this.snackbar.open({ key: '#LDS#The changes have been successfully saved.' }); + this.snackbar.open({ + key: this.isInactiveHasChanged + ? '#LDS#Your changes have been successfully saved. It may take some time for the changes to take effect.' + : '#LDS#The changes have been successfully saved.', + }); this.closeSidesheet(); } finally { this.busyService.hide(overlayRef); @@ -243,7 +253,7 @@ export class IdentitySidesheetComponent implements OnInit, OnDestroy { title: await this.translate.get('#LDS#Heading Analyze Risk').toPromise(), subTitle: this.data.selectedIdentity.GetEntity().GetDisplay(), padding: '0px', - width: '60%', + width: calculateSidesheetWidth(), testId: 'identity-sidesheet-analyze-risk-sidesheet', data: { objectKey: new DbObjectKey('Person', this.data.selectedIdentity.GetEntity().GetKeys()[0]).ToXmlString() }, }); @@ -251,12 +261,13 @@ export class IdentitySidesheetComponent implements OnInit, OnDestroy { public async generatePasscode(): Promise { let passcode; - let overlayRef: OverlayRef; - setTimeout(() => (overlayRef = this.busyService.show())); + if (this.busyService.overlayRefs.length === 0) { + this.busyService.show(); + } try { passcode = await this.passcodeService.getPasscodeWithPortalLogin(this.data.selectedIdentity.GetEntity().GetKeys()[0]); } finally { - setTimeout(() => this.busyService.hide(overlayRef)); + this.busyService.hide(); } if (!passcode) { return; @@ -264,8 +275,8 @@ export class IdentitySidesheetComponent implements OnInit, OnDestroy { return this.passcodeService.showPasscode( passcode, this.data.selectedIdentity.GetEntity().GetDisplay(), - null, - await this.passcodeService.getValidationDuration() + '', + await this.passcodeService.getValidationDuration(), ); } @@ -289,14 +300,19 @@ export class IdentitySidesheetComponent implements OnInit, OnDestroy { } } - public update(cdr: ColumnDependentReference, list: ColumnDependentReference[]): void { - const index = list.findIndex((elem) => elem.column.ColumnName === cdr.column.ColumnName); + public update(cdr: ColumnDependentReference | undefined, list: (ColumnDependentReference | undefined)[]): void { + const cdrColumn = cdr?.column; + if (!cdrColumn || !list.length) { + return; + } + const index = list.findIndex((elem) => elem?.column?.ColumnName === (cdrColumn?.ColumnName ?? '')); if (index === -1) { return; } - this.detailsFormGroup.removeControl(cdr.column.ColumnName); - list.splice(index, 1, new BaseCdr(cdr.column)); + this.isInactiveHasChanged = cdrColumn?.ColumnName === 'IsTemporaryDeactivated'; + this.detailsFormGroup.removeControl(cdrColumn?.ColumnName ?? ''); + list.splice(index, 1, new BaseCdr(cdrColumn)); } private closeSidesheet(): void { @@ -305,39 +321,57 @@ export class IdentitySidesheetComponent implements OnInit, OnDestroy { private async setup(): Promise { // Resolve an issue where the mat-tab navigation arrows could appear on first load - this.subscriptions.push( - this.sidesheetRef.componentInstance.onOpen().subscribe(() => { - // Recalculate header - this.tabs.updatePagination(); - }) - ); + if (this.sidesheetRef?.componentInstance) { + this.subscriptions.push( + this.sidesheetRef.componentInstance?.onOpen().subscribe(() => { + // Recalculate header + this.tabs.updatePagination(); + }), + ); + } // Handle the IsInActive column outside the context of a CDR editor so the UI can invert the meaning to make more sense to the user // This should be inversed on the api data response at some point, but until then we handle it in the UI this.isActiveFormControl.setValue(!this.data.selectedIdentity.IsInActive.value); + if (!this.data.canEdit || !this.data.selectedIdentity.IsInActive.GetMetadata().CanEdit()) { + this.isActiveFormControl.disable(); + } this.detailsFormGroup.addControl(this.data.selectedIdentity.IsInActive.Column.ColumnName, this.isActiveFormControl); - const personalColumns = this.data.projectConfig.PersonConfig.VI_Employee_MasterData_Attributes; - this.cdrListPersonal = this.cdrFactoryService.buildCdrFromColumnList(this.data.selectedIdentity.GetEntity(), personalColumns, !this.data.canEdit); + this.isSecurityIncidentFormControl.setValue(this.data.selectedIdentity.IsSecurityIncident.value); + if (!this.data.canEdit || !this.data.selectedIdentity.IsSecurityIncident.GetMetadata().CanEdit()) { + this.isSecurityIncidentFormControl.disable(); + } + this.detailsFormGroup.addControl(this.data.selectedIdentity.IsSecurityIncident.Column.ColumnName, this.isSecurityIncidentFormControl); + this.detailsFormGroup.markAsPristine(); - const organizationalColumns = this.data.projectConfig.PersonConfig.VI_Employee_MasterData_OrganizationalAttributes; - this.cdrListOrganizational = this.cdrFactoryService.buildCdrFromColumnList( + const personalColumns = this.data.projectConfig.PersonConfig?.VI_Employee_MasterData_Attributes || []; + this.cdrListPersonal = this.cdrFactoryService.buildCdrFromColumnList( this.data.selectedIdentity.GetEntity(), - organizationalColumns, !this.data.canEdit + personalColumns, + !this.data.canEdit, ); - const localityColumns = this.data.projectConfig.PersonConfig.VI_Employee_MasterData_LocalityAttributes; - this.cdrListLocality = this.cdrFactoryService.buildCdrFromColumnList(this.data.selectedIdentity.GetEntity(), localityColumns, !this.data.canEdit); + const organizationalColumns = this.data.projectConfig.PersonConfig?.VI_Employee_MasterData_OrganizationalAttributes || []; + this.cdrListOrganizational = this.cdrFactoryService.buildCdrFromColumnList( + this.data.selectedIdentity.GetEntity(), + organizationalColumns.filter((column) => column !== 'IsInActive'), + !this.data.canEdit, + ); - this.isSecurityIncidentFormControl.setValue(this.data.selectedIdentity.IsSecurityIncident.value); - this.detailsFormGroup.addControl(this.data.selectedIdentity.IsSecurityIncident.Column.ColumnName, this.isSecurityIncidentFormControl); + const localityColumns = this.data.projectConfig.PersonConfig?.VI_Employee_MasterData_LocalityAttributes || []; + this.cdrListLocality = this.cdrFactoryService.buildCdrFromColumnList( + this.data.selectedIdentity.GetEntity(), + localityColumns, + !this.data.canEdit, + ); this.busyService.show(); try { this.featureConfig = await this.featureConfigService.getFeatureConfig(); this.dynamicTabs = ( await this.extService.getFittingComponents('identitySidesheet', (ext) => ext.inputData.checkVisibility(this.parameters)) - ).sort((tab1: TabItem, tab2: TabItem) => tab1.sortOrder - tab2.sortOrder); + ).sort((tab1: TabItem, tab2: TabItem) => (tab1.sortOrder ?? 0) - (tab2.sortOrder ?? 0)); } finally { this.busyService.hide(); } diff --git a/imxweb/projects/qer/src/lib/identities/test/common-test-mocks.spec.ts b/imxweb/projects/qer/src/lib/identities/test/common-test-mocks.spec.ts index b967a11bb..573b04420 100644 --- a/imxweb/projects/qer/src/lib/identities/test/common-test-mocks.spec.ts +++ b/imxweb/projects/qer/src/lib/identities/test/common-test-mocks.spec.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -24,97 +24,94 @@ * */ -import { IEntityColumn, IEntity } from 'imx-qbm-dbts'; +import { IEntityColumn, IEntity } from '@imx-modules/imx-qbm-dbts'; import { ISessionState } from 'qbm'; import { Subject } from 'rxjs'; export class IdentitiesCommonTestData { - public static mockConfigService: any = { getConfig: () => { return Promise.resolve({ PersonConfig: { VI_MyData_WhitePages_ResultAttributes: { - Columns: ['col1', 'col2'] + Columns: ['col1', 'col2'], }, VI_PersonalData_Fields: { - Columns: ['col1', 'col2'] + Columns: ['col1', 'col2'], }, VI_MyData_WhitePages_DetailAttributes: { - Columns: ['col1', 'col2'] - } - } + Columns: ['col1', 'col2'], + }, + }, }); - } + }, }; public static mockAppConfigService: any = { Config: { Title: '', routeConfig: { - start: 'dashboard' - } + start: 'dashboard', + }, }, client: { imx_multilanguage_getcaptions_get: () => Promise.resolve({}), - imx_multilanguage_translations_get: () => Promise.resolve({}) - } + imx_multilanguage_translations_get: () => Promise.resolve({}), + }, }; public static mockAuthenticationServiceStub = { onSessionResponse: new Subject(), - update: jasmine.createSpy('update') + update: jasmine.createSpy('update'), }; public static mockSessionService: any = { TypedClient: { PortalTargetsystemUnsGroup: { - Get: () => Promise.resolve({}) + Get: () => Promise.resolve({}), }, PortalTargetsystemUnsAccount: { - Get: () => Promise.resolve({}) + Get: () => Promise.resolve({}), }, PortalPersonAll: { - Get: () => Promise.resolve({}) + Get: () => Promise.resolve({}), }, PortalAdminPerson: { - Get: () => Promise.resolve({}) + Get: () => Promise.resolve({}), }, PortalPerson: { - Get: () => Promise.resolve({Data: ['test1', 'test2']}) + Get: () => Promise.resolve({ Data: ['test1', 'test2'] }), }, - } + }, }; public static mockEntityColumn = { ColumnName: '', GetMetadata: () => { return { - CanEdit: () => false, + CanEdit: () => false, GetDisplay: () => '', - GetMinLength: () => 0 + GetMinLength: () => 0, }; }, - GetValue: () => '' - + GetValue: () => '', } as IEntityColumn; public static mockEntityColumnWithValue = { ColumnName: '', GetMetadata: () => { return { - CanEdit: () => false, + CanEdit: () => false, GetDisplay: () => '', - GetMinLength: () => 0 + GetMinLength: () => 0, }; }, - GetValue: () => 'Test value 1' - + GetValue: () => 'Test value 1', } as IEntityColumn; public static mockEntity = { GetDisplay: () => 'Display value', GetKeys: () => ['1'], - GetColumn: (name) => IdentitiesCommonTestData.mockEntityColumn + GetColumn: (name) => IdentitiesCommonTestData.mockEntityColumn, } as IEntity; } diff --git a/imxweb/projects/qer/src/lib/itshop-config/irequestable-entitlement-type.ts b/imxweb/projects/qer/src/lib/itshop-config/irequestable-entitlement-type.ts index b7e1d322c..61d859444 100644 --- a/imxweb/projects/qer/src/lib/itshop-config/irequestable-entitlement-type.ts +++ b/imxweb/projects/qer/src/lib/itshop-config/irequestable-entitlement-type.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -24,17 +24,16 @@ * */ -import { EntitySchema, TypedEntity } from "imx-qbm-dbts"; +import { EntitySchema, TypedEntity } from '@imx-modules/imx-qbm-dbts'; export interface IRequestableEntitlementType { - getTableName(): string; getFkColumnName(): string; - + addEntitlementSelections(shelfId: string, values: string[]): Promise; createAssignmentEntity(shelfId: string): TypedEntity; getSchema(): EntitySchema; -} \ No newline at end of file +} diff --git a/imxweb/projects/qer/src/lib/itshop-config/request-config-members/member-selector/member-selector.component.html b/imxweb/projects/qer/src/lib/itshop-config/request-config-members/member-selector/member-selector.component.html index fb0678368..29e523ff6 100644 --- a/imxweb/projects/qer/src/lib/itshop-config/request-config-members/member-selector/member-selector.component.html +++ b/imxweb/projects/qer/src/lib/itshop-config/request-config-members/member-selector/member-selector.component.html @@ -1,6 +1,12 @@
    - +
    @@ -18,7 +24,7 @@ -
    @@ -97,8 +121,8 @@
    + - @@ -31,7 +51,10 @@ {{ '#LDS#Heading Shelves' | translate }} - + @@ -39,7 +62,7 @@ {{ '#LDS#Heading Access' | translate }}
    - + +
    diff --git a/imxweb/projects/qer/src/lib/itshop-config/request-config-sidesheet/request-config-sidesheet.component.ts b/imxweb/projects/qer/src/lib/itshop-config/request-config-sidesheet/request-config-sidesheet.component.ts index 5f42525ee..a4d64ad2d 100644 --- a/imxweb/projects/qer/src/lib/itshop-config/request-config-sidesheet/request-config-sidesheet.component.ts +++ b/imxweb/projects/qer/src/lib/itshop-config/request-config-sidesheet/request-config-sidesheet.component.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -26,11 +26,11 @@ import { Component, Inject, OnInit } from '@angular/core'; import { UntypedFormArray, UntypedFormBuilder, UntypedFormGroup } from '@angular/forms'; -import { EuiSidesheetRef, EUI_SIDESHEET_DATA } from '@elemental-ui/core'; +import { EUI_SIDESHEET_DATA, EuiSidesheetRef } from '@elemental-ui/core'; -import { PortalShopConfigStructure } from 'imx-api-qer'; -import { TypedEntityCollectionData } from 'imx-qbm-dbts'; -import { BaseCdr, ClassloggerService, ColumnDependentReference, StorageService, HELPER_ALERT_KEY_PREFIX, ConfirmationService, HELP_CONTEXTUAL } from 'qbm'; +import { PortalShopConfigStructure } from '@imx-modules/imx-api-qer'; +import { TypedEntityCollectionData } from '@imx-modules/imx-qbm-dbts'; +import { BaseCdr, ClassloggerService, ColumnDependentReference, ConfirmationService, HELP_CONTEXTUAL } from 'qbm'; import { ACTION_DISMISS, RequestsService } from '../requests.service'; export interface RequestConfigSidesheetData { @@ -38,8 +38,6 @@ export interface RequestConfigSidesheetData { isNew?: boolean; } -const helperAlertKey = `${HELPER_ALERT_KEY_PREFIX}_requestShopDetails`; - @Component({ selector: 'imx-request-config-sidesheet', templateUrl: './request-config-sidesheet.component.html', @@ -52,16 +50,15 @@ export class RequestConfigSidesheetComponent implements OnInit { public detailsContextIds = HELP_CONTEXTUAL.ConfigurationRequestsDetail; private shelfCount: number; private memberCount: number; - private reload= false; + private reload = false; constructor( formBuilder: UntypedFormBuilder, public requestsService: RequestsService, @Inject(EUI_SIDESHEET_DATA) public data: RequestConfigSidesheetData, - private readonly storageService: StorageService, private readonly logger: ClassloggerService, private readonly sidesheetRef: EuiSidesheetRef, - confirm: ConfirmationService + confirm: ConfirmationService, ) { this.detailsFormGroup = new UntypedFormGroup({ formArray: formBuilder.array([]) }); sidesheetRef.closeClicked().subscribe(async () => { @@ -74,7 +71,7 @@ export class RequestConfigSidesheetComponent implements OnInit { get selectedRequestConfigKey(): string { const keys = this.data?.requestConfig?.GetEntity()?.GetKeys(); - return keys?.length ? keys[0] : undefined; + return !!keys?.length ? keys[0] : ''; } get requestConfigContainsShelves(): boolean { @@ -93,10 +90,6 @@ export class RequestConfigSidesheetComponent implements OnInit { return display; } - get showHelperAlert(): boolean { - return !this.storageService.isHelperAlertDismissed(helperAlertKey); - } - get formArray(): UntypedFormArray { return this.detailsFormGroup.get('formArray') as UntypedFormArray; } @@ -137,10 +130,6 @@ export class RequestConfigSidesheetComponent implements OnInit { } } - public onHelperDismissed(): void { - this.storageService.storeHelperAlertDismissal(helperAlertKey); - } - private async createNew(): Promise { this.requestsService.handleOpenLoader(); try { diff --git a/imxweb/projects/qer/src/lib/itshop-config/request-config.module.ts b/imxweb/projects/qer/src/lib/itshop-config/request-config.module.ts index 8fd7f1f6e..c305b966c 100644 --- a/imxweb/projects/qer/src/lib/itshop-config/request-config.module.ts +++ b/imxweb/projects/qer/src/lib/itshop-config/request-config.module.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -24,8 +24,9 @@ * */ +import { CommonModule } from '@angular/common'; import { CUSTOM_ELEMENTS_SCHEMA, NgModule } from '@angular/core'; -import { CommonModule } from '@angular/common'; import { FormsModule, ReactiveFormsModule } from '@angular/forms'; +import { FormsModule, ReactiveFormsModule } from '@angular/forms'; import { RouterModule, Routes } from '@angular/router'; import { EuiCoreModule, EuiMaterialModule } from '@elemental-ui/core'; import { TranslateModule } from '@ngx-translate/core'; @@ -35,6 +36,7 @@ import { ClassloggerService, DataSourceToolbarModule, DataTableModule, + DataViewModule, FkAdvancedPickerModule, HELP_CONTEXTUAL, HelpContextualModule, @@ -43,25 +45,25 @@ import { MenuItem, MenuService, RouteGuardService, - SelectedElementsModule + SelectedElementsModule, } from 'qbm'; -import { RequestsComponent } from './requests/requests.component'; -import { RequestConfigSidesheetComponent } from './request-config-sidesheet/request-config-sidesheet.component'; -import { RequestShelfSidesheetComponent } from './request-shelf-sidesheet/request-shelf-sidesheet.component'; -import { RequestShelvesComponent } from './request-shelves/request-shelves.component'; -import { RequestConfigMembersComponent } from './request-config-members/request-config-members.component'; -import { RequestShelfEntitlementsComponent } from './request-shelf-entitlements/request-shelf-entitlements.component'; -import { RequestsEntitySelectorComponent } from './requests-selector/requests-entity-selector.component'; -import { DynamicExclusionDialogModule } from '../dynamic-exclusion-dialog/dynamic-exclusion-dialog.module'; -import { MemberSelectorComponent } from './request-config-members/member-selector/member-selector.component'; +import { MatTableModule } from '@angular/material/table'; import { isShopAdmin, isShopStatistics } from '../admin/qer-permissions-helper'; -import { CREATE_SHELF_TOKEN } from './request-shelves/request-shelf-token'; -import { ObjectHyperviewModule } from '../object-hyperview/object-hyperview.module'; +import { DynamicExclusionDialogModule } from '../dynamic-exclusion-dialog/dynamic-exclusion-dialog.module'; import { ShopGuardService } from '../guards/shop-guard.service'; import { JustificationModule } from '../justification/justification.module'; +import { ObjectHyperviewModule } from '../object-hyperview/object-hyperview.module'; +import { MemberSelectorComponent } from './request-config-members/member-selector/member-selector.component'; import { ReasonSidesheetComponent } from './request-config-members/reason-sidesheet/reason-sidesheet.component'; - +import { RequestConfigMembersComponent } from './request-config-members/request-config-members.component'; +import { RequestConfigSidesheetComponent } from './request-config-sidesheet/request-config-sidesheet.component'; +import { RequestShelfEntitlementsComponent } from './request-shelf-entitlements/request-shelf-entitlements.component'; +import { RequestShelfSidesheetComponent } from './request-shelf-sidesheet/request-shelf-sidesheet.component'; +import { CREATE_SHELF_TOKEN } from './request-shelves/request-shelf-token'; +import { RequestShelvesComponent } from './request-shelves/request-shelves.component'; +import { RequestsEntitySelectorComponent } from './requests-selector/requests-entity-selector.component'; +import { RequestsComponent } from './requests/requests.component'; const routes: Routes = [ { @@ -69,9 +71,9 @@ const routes: Routes = [ component: RequestsComponent, canActivate: [RouteGuardService, ShopGuardService], resolve: [RouteGuardService], - data:{ - contextId: HELP_CONTEXTUAL.ConfigurationRequests - } + data: { + contextId: HELP_CONTEXTUAL.ConfigurationRequests, + }, }, ]; @@ -85,7 +87,7 @@ const routes: Routes = [ RequestConfigMembersComponent, RequestShelfEntitlementsComponent, RequestsEntitySelectorComponent, - ReasonSidesheetComponent + ReasonSidesheetComponent, ], imports: [ CommonModule, @@ -106,46 +108,43 @@ const routes: Routes = [ JustificationModule, RouterModule.forChild(routes), HelpContextualModule, + MatTableModule, + DataViewModule, ], - providers: [{provide: CREATE_SHELF_TOKEN, useValue: RequestShelfSidesheetComponent}], + providers: [{ provide: CREATE_SHELF_TOKEN, useValue: RequestShelfSidesheetComponent }], schemas: [CUSTOM_ELEMENTS_SCHEMA], }) export class RequestConfigModule { - constructor( private readonly menuService: MenuService, - logger: ClassloggerService) { + logger: ClassloggerService, + ) { logger.info(this, '▶︝ RequestConfigModule loaded'); this.setupMenu(); } private setupMenu(): void { - this.menuService.addMenuFactories( - (preProps: string[], features: string[]) => { - - const items: MenuItem[] = []; + this.menuService.addMenuFactories((preProps: string[], features: string[]) => { + const items: MenuItem[] = []; - if (isShopAdmin(features) || isShopStatistics(features)) { - items.push( - { - id: 'QER_Setup_ITShop', - route: 'configuration/requests', - title: '#LDS#Menu Entry Shops', - sorting: '60-20', - }, - ); - } + if (isShopAdmin(features) || isShopStatistics(features)) { + items.push({ + id: 'QER_Setup_ITShop', + route: 'configuration/requests', + title: '#LDS#Menu Entry Shops', + sorting: '60-20', + }); + } - if (items.length === 0) { - return null; - } - return { - id: 'ROOT_Setup', - title: '#LDS#Setup', - sorting: '60', - items - }; - }, - ); + if (items.length === 0) { + return; + } + return { + id: 'ROOT_Setup', + title: '#LDS#Setup', + sorting: '60', + items, + }; + }); } } diff --git a/imxweb/projects/qer/src/lib/itshop-config/request-shelf-entitlements/request-shelf-entitlements.component.html b/imxweb/projects/qer/src/lib/itshop-config/request-shelf-entitlements/request-shelf-entitlements.component.html index 406250a0f..82785987e 100644 --- a/imxweb/projects/qer/src/lib/itshop-config/request-shelf-entitlements/request-shelf-entitlements.component.html +++ b/imxweb/projects/qer/src/lib/itshop-config/request-shelf-entitlements/request-shelf-entitlements.component.html @@ -15,7 +15,7 @@ - +
    {{ item.GetEntity().GetDisplay() }}
    {{ entitlementTypes.get(item.GetEntity().GetKeys().toString()) }}
    - +
    {{ item.GetEntity().GetColumn('XOrigin').GetDisplayValue() }}
    @@ -39,7 +39,7 @@ >
    - +
    {{ item.GetEntity().GetColumn('XDateInserted').GetValue() | date }}
    @@ -47,13 +47,11 @@
    -
    -
    -
    +
    + - +
    diff --git a/imxweb/projects/qer/src/lib/itshop-config/request-shelf-entitlements/request-shelf-entitlements.component.ts b/imxweb/projects/qer/src/lib/itshop-config/request-shelf-entitlements/request-shelf-entitlements.component.ts index 3cb8e8237..df7318dba 100644 --- a/imxweb/projects/qer/src/lib/itshop-config/request-shelf-entitlements/request-shelf-entitlements.component.ts +++ b/imxweb/projects/qer/src/lib/itshop-config/request-shelf-entitlements/request-shelf-entitlements.component.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -28,20 +28,26 @@ import { Component, EventEmitter, Input, OnInit, Output, ViewChild } from '@angu import { EuiSidesheetService } from '@elemental-ui/core'; import { TranslateService } from '@ngx-translate/core'; -import { PortalRolesEntitlements } from 'imx-api-qer'; -import { CollectionLoadParameters, DbObjectKey, DisplayColumns, EntitySchema, IClientProperty } from 'imx-qbm-dbts'; +import { PortalRolesEntitlements } from '@imx-modules/imx-api-qer'; import { - DataSourceToolbarSettings, - DataSourceToolbarFilter, + CollectionLoadParameters, + DbObjectKey, + DisplayColumns, + EntitySchema, + IClientProperty, + TypedEntity, +} from '@imx-modules/imx-qbm-dbts'; +import { + BusyService, ClassloggerService, + DataSourceToolbarFilter, + DataSourceToolbarSettings, DataTableComponent, - StorageService, - HELPER_ALERT_KEY_PREFIX, - SettingsService, - MetadataService, DynamicMethodService, - BusyService, HELP_CONTEXTUAL, + MetadataService, + SettingsService, + calculateSidesheetWidth, } from 'qbm'; import { QerApiService } from '../../qer-api-client.service'; import { RequestsEntitySelectorComponent } from '../requests-selector/requests-entity-selector.component'; @@ -66,7 +72,7 @@ export class RequestShelfEntitlementsComponent implements OnInit { public dstSettings: DataSourceToolbarSettings; public navigationState: CollectionLoadParameters; public filterOptions: DataSourceToolbarFilter[] = []; - public selectedEntitlements: PortalRolesEntitlements[] = []; + public selectedEntitlements: TypedEntity[] = []; public productContextIds = HELP_CONTEXTUAL.ConfigurationRequestsShelvesProduct; private displayedColumns: IClientProperty[]; @@ -87,7 +93,7 @@ export class RequestShelfEntitlementsComponent implements OnInit { private readonly metadata: MetadataService, private readonly sidesheet: EuiSidesheetService, private readonly translate: TranslateService, - private readonly dynamicMethodService: DynamicMethodService + private readonly dynamicMethodService: DynamicMethodService, ) { this.navigationState = { PageSize: this.settingsService.DefaultPageSize, StartIndex: 0 }; this.entitySchema = qerApiService.typedClient.PortalRolesEntitlements.GetSchema(); @@ -98,10 +104,6 @@ export class RequestShelfEntitlementsComponent implements OnInit { ]; } - get isMobile(): boolean { - return document.body.offsetWidth <= 768; - } - public async ngOnInit(): Promise { await this.navigate(); } @@ -113,7 +115,7 @@ export class RequestShelfEntitlementsComponent implements OnInit { await this.navigate(); } - public onEntitlementSelected(selected: PortalRolesEntitlements[]): void { + public onEntitlementSelected(selected: TypedEntity[]): void { this.logger.debug(this, `Selected entitlements changed`); this.logger.trace(`New entitlement selections`, selected); this.selectedEntitlements = selected; @@ -135,7 +137,7 @@ export class RequestShelfEntitlementsComponent implements OnInit { title: await this.translate.get('#LDS#Heading Add Products').toPromise(), subTitle: this.shopDisplay, padding: '0px', - width: 'max(55%,550px)', + width: calculateSidesheetWidth(), testId: 'request-shelf-entitlements-add-products', data: { shelfId: this.shelfId, @@ -151,16 +153,16 @@ export class RequestShelfEntitlementsComponent implements OnInit { public async removeEntitlements(): Promise { const isBusy = this.busyService.beginBusy(); try { - const promises = []; + const promises: Promise[] = []; // TODO what if only some succeed? - this.selectedEntitlements.forEach((ent) => { + this.selectedEntitlements.forEach((ent: PortalRolesEntitlements) => { const entitlementKey = DbObjectKey.FromXml(ent.ObjectKeyElement.value); promises.push( this.dynamicMethodService.delete( this.qerApiService.apiClient, '/portal/shop/config/entitlements/' + this.shelfId + '/' + entitlementKey.TableName + '/' + entitlementKey.Keys[0], - {} - ) + {}, + ), ); }); await Promise.all(promises); @@ -177,7 +179,7 @@ export class RequestShelfEntitlementsComponent implements OnInit { private async processEntitlementSelections(values: string[]): Promise { const isBusy = this.busyService.beginBusy(); try { - await this.requestsService.selectedEntitlementType.addEntitlementSelections(this.shelfId, values); + await this.requestsService.selectedEntitlementType?.addEntitlementSelections(this.shelfId, values); this.requestsService.openSnackbar('#LDS#The products have been successfully added.', ACTION_DISMISS); await this.navigate(); } finally { @@ -207,7 +209,7 @@ export class RequestShelfEntitlementsComponent implements OnInit { navigationState: this.navigationState, filters: this.filterOptions, }; - this.logger.debug(this, `Head at ${data.Data.length + this.navigationState.StartIndex} of ${data.totalCount} item(s)`); + this.logger.debug(this, `Head at ${data.Data.length + (this.navigationState?.StartIndex || 0)} of ${data.totalCount} item(s)`); data.Data.forEach(async (item: PortalRolesEntitlements) => { const objKey = DbObjectKey.FromXml(item.ObjectKeyElement.value); @@ -215,10 +217,10 @@ export class RequestShelfEntitlementsComponent implements OnInit { var display: string; if (!this.entitlementTypes.has(objKey.TableName)) { const metadata = await this.metadata.GetTableMetadata(objKey.TableName); - this.entitlementTypes.set(uid, metadata.DisplaySingular); - display = metadata.DisplaySingular; + this.entitlementTypes.set(uid, metadata?.DisplaySingular || ''); + display = metadata?.DisplaySingular || ''; } else { - display = this.entitlementTypes.get(objKey.TableName); + display = this.entitlementTypes.get(objKey.TableName) || ''; } this.entitlementTypes.set(uid, display); diff --git a/imxweb/projects/qer/src/lib/itshop-config/request-shelf-sidesheet/request-shelf-sidesheet.component.html b/imxweb/projects/qer/src/lib/itshop-config/request-shelf-sidesheet/request-shelf-sidesheet.component.html index 09a2e875f..881063ef2 100644 --- a/imxweb/projects/qer/src/lib/itshop-config/request-shelf-sidesheet/request-shelf-sidesheet.component.html +++ b/imxweb/projects/qer/src/lib/itshop-config/request-shelf-sidesheet/request-shelf-sidesheet.component.html @@ -1,22 +1,32 @@ - + {{ '#LDS#Heading Details' | translate }}
    - +
    - + -
    -
    diff --git a/imxweb/projects/qer/src/lib/itshop-config/request-shelves/request-shelves.component.ts b/imxweb/projects/qer/src/lib/itshop-config/request-shelves/request-shelves.component.ts index c3fe4d70c..14f6e506a 100644 --- a/imxweb/projects/qer/src/lib/itshop-config/request-shelves/request-shelves.component.ts +++ b/imxweb/projects/qer/src/lib/itshop-config/request-shelves/request-shelves.component.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -29,18 +29,17 @@ import { Component, EventEmitter, Inject, Input, OnInit, Output } from '@angular import { EuiSidesheetService } from '@elemental-ui/core'; import { TranslateService } from '@ngx-translate/core'; -import { PortalShopConfigStructure } from 'imx-api-qer'; -import { CollectionLoadParameters, IClientProperty, DisplayColumns, EntitySchema } from 'imx-qbm-dbts'; +import { CollectionLoadParameters, DisplayColumns, EntitySchema, IClientProperty, TypedEntity } from '@imx-modules/imx-qbm-dbts'; import { - DataSourceToolbarSettings, - DataSourceToolbarFilter, - ClassloggerService, - HELPER_ALERT_KEY_PREFIX, - SettingsService, BusyService, + ClassloggerService, + DataSourceToolbarFilter, + DataSourceToolbarSettings, + HELP_CONTEXTUAL, HelpContextualComponent, HelpContextualService, - HELP_CONTEXTUAL + SettingsService, + calculateSidesheetWidth, } from 'qbm'; import { RequestsService } from '../requests.service'; import { CREATE_SHELF_TOKEN } from './request-shelf-token'; @@ -59,7 +58,7 @@ export class RequestShelvesComponent implements OnInit { public dstSettings: DataSourceToolbarSettings; public navigationState: CollectionLoadParameters; public filterOptions: DataSourceToolbarFilter[] = []; - public busyService= new BusyService(); + public busyService = new BusyService(); public shelvesContextIds = HELP_CONTEXTUAL.ConfigurationRequestsShelves; private displayedColumns: IClientProperty[] = []; @@ -71,7 +70,7 @@ export class RequestShelvesComponent implements OnInit { private readonly translate: TranslateService, public readonly requestsService: RequestsService, private readonly settingsService: SettingsService, - private readonly helpContextualService: HelpContextualService + private readonly helpContextualService: HelpContextualService, ) { this.navigationState = { PageSize: this.settingsService.DefaultPageSize, StartIndex: 0 }; this.entitySchemaShopStructure = requestsService.shopStructureSchema; @@ -93,7 +92,7 @@ export class RequestShelvesComponent implements OnInit { await this.navigate(); } - public async onRequestShelfChanged(requestConfig: PortalShopConfigStructure): Promise { + public async onRequestShelfChanged(requestConfig: TypedEntity): Promise { this.logger.debug(this, `Selected request shelf changed`); this.logger.trace(`New request shelf selected`, requestConfig); this.viewRequestShelf(requestConfig); @@ -117,9 +116,9 @@ export class RequestShelvesComponent implements OnInit { this.viewRequestShelf(newRequestShelf, true); } - private async viewRequestShelf(requestConfig: PortalShopConfigStructure, isNew: boolean = false): Promise { + private async viewRequestShelf(requestConfig: TypedEntity, isNew: boolean = false): Promise { const header = await this.translate.get(isNew ? '#LDS#Heading Create Shelf' : '#LDS#Heading Edit Shelf').toPromise(); - if(isNew){ + if (isNew) { this.helpContextualService.setHelpContextId(HELP_CONTEXTUAL.ConfigurationRequestsShelvesCreate); } const result = await this.sideSheet @@ -128,13 +127,13 @@ export class RequestShelvesComponent implements OnInit { subTitle: isNew ? '' : requestConfig.GetEntity().GetDisplay(), padding: '0px', disableClose: true, - width: '55%', + width: calculateSidesheetWidth(), testId: isNew ? 'request-shelves-create-shelf-sidesheet' : 'request-shelves-edit-shelf-sidesheet', data: { requestConfig, isNew, }, - headerComponent: isNew ? HelpContextualComponent : undefined + headerComponent: isNew ? HelpContextualComponent : undefined, }) .afterClosed() .toPromise(); @@ -160,7 +159,7 @@ export class RequestShelvesComponent implements OnInit { navigationState: this.navigationState, filters: this.filterOptions, }; - this.logger.debug(this, `Head at ${data.Data.length + this.navigationState.StartIndex} of ${data.totalCount} item(s)`); + this.logger.debug(this, `Head at ${data.Data.length + (this.navigationState?.StartIndex || 0)} of ${data.totalCount} item(s)`); } finally { isBusy.endBusy(); } diff --git a/imxweb/projects/qer/src/lib/itshop-config/requestable-entitlement-type.service.ts b/imxweb/projects/qer/src/lib/itshop-config/requestable-entitlement-type.service.ts index bcb0b0410..0edaed319 100644 --- a/imxweb/projects/qer/src/lib/itshop-config/requestable-entitlement-type.service.ts +++ b/imxweb/projects/qer/src/lib/itshop-config/requestable-entitlement-type.service.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -24,28 +24,21 @@ * */ -import { Injectable } from "@angular/core"; -import { QerApiService } from "../qer-api-client.service"; -import { IRequestableEntitlementType } from "./irequestable-entitlement-type"; -import { ResourceEntitlementType } from "./resource-entitlement-type"; +import { Injectable } from '@angular/core'; +import { QerApiService } from '../qer-api-client.service'; +import { IRequestableEntitlementType } from './irequestable-entitlement-type'; +import { ResourceEntitlementType } from './resource-entitlement-type'; @Injectable({ providedIn: 'root' }) export class RequestableEntitlementTypeService { - constructor(qerApi: QerApiService) { const types = [ - new ResourceEntitlementType("QERResource", - qerApi.typedClient.PortalShopConfigEntitlementsQerresource), - new ResourceEntitlementType("QERReuse", - qerApi.typedClient.PortalShopConfigEntitlementsQerreuse), - new ResourceEntitlementType("QERReuseUS", - qerApi.typedClient.PortalShopConfigEntitlementsQerreuseus), - new ResourceEntitlementType("QERAssign", - qerApi.typedClient.PortalShopConfigEntitlementsQerassign) - ]; - this.typeProviders = [ - () => Promise.resolve(this.enableResourceTypes ? types : []) + new ResourceEntitlementType('QERResource', qerApi.typedClient.PortalShopConfigEntitlementsQerresource), + new ResourceEntitlementType('QERReuse', qerApi.typedClient.PortalShopConfigEntitlementsQerreuse), + new ResourceEntitlementType('QERReuseUS', qerApi.typedClient.PortalShopConfigEntitlementsQerreuseus), + new ResourceEntitlementType('QERAssign', qerApi.typedClient.PortalShopConfigEntitlementsQerassign), ]; + this.typeProviders = [() => Promise.resolve(this.enableResourceTypes ? types : [])]; } private typeProviders: (() => Promise)[]; @@ -55,12 +48,11 @@ export class RequestableEntitlementTypeService { public enableResourceTypes: boolean = true; async GetTypes(): Promise { - const all = await Promise.all(this.typeProviders.map(x => x())); + const all = await Promise.all(this.typeProviders.map((x) => x())); return all.reduce((x, y) => x.concat(y)); } Register(typeProvider: () => Promise) { this.typeProviders.push(typeProvider); } - -} \ No newline at end of file +} diff --git a/imxweb/projects/qer/src/lib/itshop-config/requestable-entl-type.ts b/imxweb/projects/qer/src/lib/itshop-config/requestable-entl-type.ts index 6ac303856..d7f98a6fe 100644 --- a/imxweb/projects/qer/src/lib/itshop-config/requestable-entl-type.ts +++ b/imxweb/projects/qer/src/lib/itshop-config/requestable-entl-type.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -24,16 +24,16 @@ * */ -import { ApiClient, EntitySchema, TypedEntity } from "imx-qbm-dbts"; -import { DynamicMethodService, GenericTypedEntity } from "qbm"; -import { IRequestableEntitlementType } from "./irequestable-entitlement-type"; +import { ApiClient, EntitySchema, TypedEntity } from '@imx-modules/imx-qbm-dbts'; +import { DynamicMethodService, GenericTypedEntity } from 'qbm'; +import { IRequestableEntitlementType } from './irequestable-entitlement-type'; export class RequestableEntitlementType implements IRequestableEntitlementType { - - constructor(private readonly tableName: string, + constructor( + private readonly tableName: string, private readonly apiClient: ApiClient, private readonly fkColumnName: string, - private readonly dynamicMethodService: DynamicMethodService + private readonly dynamicMethodService: DynamicMethodService, ) { this.schema = this.createAssignmentEntity('dummy').GetEntity().GetSchema(); } @@ -53,27 +53,35 @@ export class RequestableEntitlementType implements IRequestableEntitlementType { } public addEntitlementSelections(shelfId: string, values: string[]): Promise { - const promises = []; - values.forEach(value => { + const promises: Promise[] = []; + values.forEach((value) => { const e = this.createAssignmentEntity(shelfId).GetEntity(); - promises.push(e.GetColumn(this.fkColumnName).PutValue(value) - .then(() => e.Commit())); + promises.push( + e + .GetColumn(this.fkColumnName) + .PutValue(value) + .then(() => e.Commit()), + ); }); return Promise.all(promises); } public createAssignmentEntity(shelfId: string): TypedEntity { - const entityColl = this.dynamicMethodService.createEntity(this.apiClient, { - path: '/portal/shop/config/entitlements/' + shelfId + '/' + this.tableName, - type: GenericTypedEntity, - schemaPath: 'portal/shop/config/entitlements/{UID_ITShopOrg}/' + this.tableName, - }, { - Columns: { - "UID_ITShopOrg": { - Value: shelfId - } - } - }); + const entityColl = this.dynamicMethodService.createEntity( + this.apiClient, + { + path: '/portal/shop/config/entitlements/' + shelfId + '/' + this.tableName, + type: GenericTypedEntity, + schemaPath: 'portal/shop/config/entitlements/{UID_ITShopOrg}/' + this.tableName, + }, + { + Columns: { + UID_ITShopOrg: { + Value: shelfId, + }, + }, + }, + ); return entityColl.Data[0]; } -} \ No newline at end of file +} diff --git a/imxweb/projects/qer/src/lib/itshop-config/requests-selector/requests-entity-selector.component.html b/imxweb/projects/qer/src/lib/itshop-config/requests-selector/requests-entity-selector.component.html index 84785a9a6..5d290e01a 100644 --- a/imxweb/projects/qer/src/lib/itshop-config/requests-selector/requests-entity-selector.component.html +++ b/imxweb/projects/qer/src/lib/itshop-config/requests-selector/requests-entity-selector.component.html @@ -22,7 +22,7 @@
    - diff --git a/imxweb/projects/qer/src/lib/itshop-config/requests-selector/requests-entity-selector.component.ts b/imxweb/projects/qer/src/lib/itshop-config/requests-selector/requests-entity-selector.component.ts index f515a9086..9d8cf4474 100644 --- a/imxweb/projects/qer/src/lib/itshop-config/requests-selector/requests-entity-selector.component.ts +++ b/imxweb/projects/qer/src/lib/itshop-config/requests-selector/requests-entity-selector.component.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -27,8 +27,8 @@ import { Component, Inject, OnInit } from '@angular/core'; import { EUI_SIDESHEET_DATA, EuiSidesheetRef } from '@elemental-ui/core'; -import { EntityCollectionData, FkProviderItem, IEntity, TypedEntity } from 'imx-qbm-dbts'; -import { BusyService, MetadataService } from 'qbm'; +import { EntityCollectionData, FilterTreeData, FkProviderItem, IEntity, TypedEntity } from '@imx-modules/imx-qbm-dbts'; +import { BusyService, FkCandidatesData, MetadataService, TypedEntityFkData } from 'qbm'; import { IRequestableEntitlementType } from '../irequestable-entitlement-type'; import { RequestableEntitlementTypeService } from '../requestable-entitlement-type.service'; import { RequestsService } from '../requests.service'; @@ -55,7 +55,7 @@ export class RequestsEntitySelectorComponent implements OnInit { }, public readonly requestsService: RequestsService, private metadata: MetadataService, - private requestTypeService: RequestableEntitlementTypeService + private requestTypeService: RequestableEntitlementTypeService, ) { requestsService.selectedEntitlementType = null; this.ReinitData(); @@ -63,13 +63,15 @@ export class RequestsEntitySelectorComponent implements OnInit { public async ngOnInit(): Promise { const isBusy = this.busyService.beginBusy(); - try{ - const rtypes = await this.requestTypeService.GetTypes(); - for (const type of rtypes) { - const display = (await this.metadata.GetTableMetadata(type.getTableName())).Display; - this.displays.set(type.getTableName(), display); - } - this.types = rtypes.sort((a, b) => (this.displays.get(a.getTableName()) > this.displays.get(b.getTableName()) ? 1 : -1)); + try { + const rtypes = await this.requestTypeService.GetTypes(); + for (const type of rtypes) { + const display = (await this.metadata.GetTableMetadata(type.getTableName()))?.Display; + this.displays.set(type.getTableName(), display); + } + this.types = rtypes.sort((a, b) => + (this.displays.get(a.getTableName()) || '') > (this.displays.get(b.getTableName()) || '') ? 1 : -1, + ); } finally { isBusy.endBusy(); } @@ -86,24 +88,25 @@ export class RequestsEntitySelectorComponent implements OnInit { this.selectedItems = items; } - public data; + public data: FkCandidatesData | TypedEntityFkData; private fkEntity: IEntity; private fk: FkProviderItem; /** Sets the data object to trigger the changes event on the Fk candidate selector*/ private ReinitData() { this.data = { - get: (parameters) => { + Get: (parameters: any) => { if (!this.fk) { return this.empty; } return this.fk.load(this.fkEntity, { ...parameters, ...{ UID_ITShopOrg: this.sidesheetData.shelfId } }); }, - GetFilterTree: (parentKey) => { + GetFilterTree: (parentKey: string) => { + const emptyResult: FilterTreeData = { Elements: [] }; if (!this.fk) { - return { Elements: [] }; + return Promise.resolve(emptyResult); } - return this.fk.getFilterTree(this.fkEntity, parentKey); + return this.fk.getFilterTree?.(this.fkEntity, parentKey) || Promise.resolve(emptyResult); }, isMultiValue: true, }; @@ -112,9 +115,12 @@ export class RequestsEntitySelectorComponent implements OnInit { public async optionSelected(newType: IRequestableEntitlementType) { this.fkEntity = newType.createAssignmentEntity(this.sidesheetData.shelfId).GetEntity(); const property = newType.getSchema().Columns[newType.getFkColumnName()]; - this.fk = this.fkEntity + const fkProviderItem = this.fkEntity .GetFkCandidateProvider() - .getProviderItem(property.FkRelation.ParentColumnName, property.FkRelation.ParentTableName); + .getProviderItem(property.FkRelation?.ParentColumnName || '', property.FkRelation?.ParentTableName || ''); + if (fkProviderItem) { + this.fk = fkProviderItem; + } this.ReinitData(); this.selectedItems = []; } @@ -123,10 +129,10 @@ export class RequestsEntitySelectorComponent implements OnInit { if (selected) { this.selectedItems = [selected]; } - const selectedValues = []; + const selectedValues: string[] = []; this.selectedItems.forEach((typedEntity) => { const keys = typedEntity.GetEntity().GetKeys(); - const val = keys?.length ? keys[0] : undefined; + const val = !!keys?.length ? keys[0] : ''; selectedValues.push(val); }); this.dialogRef.close(selectedValues); diff --git a/imxweb/projects/qer/src/lib/itshop-config/requests.service.ts b/imxweb/projects/qer/src/lib/itshop-config/requests.service.ts index ed716dfd4..545b465a5 100644 --- a/imxweb/projects/qer/src/lib/itshop-config/requests.service.ts +++ b/imxweb/projects/qer/src/lib/itshop-config/requests.service.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -24,20 +24,20 @@ * */ -import { OverlayRef } from '@angular/cdk/overlay'; import { Injectable } from '@angular/core'; import { EuiLoadingService } from '@elemental-ui/core'; -import { TranslateService } from '@ngx-translate/core'; -import { PortalRolesExclusions, PortalShopConfigMembers, PortalShopConfigStructure } from 'imx-api-qer'; +import { PortalRolesExclusions, PortalShopConfigMembers, PortalShopConfigStructure } from '@imx-modules/imx-api-qer'; import { CollectionLoadParameters, CompareOperator, EntityCollectionData, EntitySchema, + FilterData, FilterType, + TypedEntity, TypedEntityCollectionData, -} from 'imx-qbm-dbts'; +} from '@imx-modules/imx-qbm-dbts'; import { ClassloggerService, SnackBarService } from 'qbm'; import { QerApiService } from '../qer-api-client.service'; import { IRequestableEntitlementType } from './irequestable-entitlement-type'; @@ -55,17 +55,15 @@ export interface SelectedShopStructureData { }) export class RequestsService { public shelvesBlockedDeleteStatus: { [shelfId: string]: boolean } = {}; - private busyIndicator: OverlayRef; constructor( private readonly qerApiClient: QerApiService, private readonly logger: ClassloggerService, private readonly snackbar: SnackBarService, - private readonly translate: TranslateService, - private readonly busyService: EuiLoadingService + private readonly busyService: EuiLoadingService, ) {} - public selectedEntitlementType: IRequestableEntitlementType; + public selectedEntitlementType: IRequestableEntitlementType | null; public get shopStructureSchema(): EntitySchema { return this.qerApiClient.typedClient.PortalShopConfigStructure.GetSchema(); @@ -81,26 +79,31 @@ export class RequestsService { public async getShopStructures( navigationState: CollectionLoadParameters, - parentId: string = '' + parentId: string = '', + signal?: AbortSignal, ): Promise> { - let params: any = navigationState; + let params: CollectionLoadParameters = navigationState; if (!params) { params = {}; } - if (parentId == '') { - params.filter = [ - { - ColumnName: 'ITShopInfo', - CompareOp: CompareOperator.Equal, - Type: FilterType.Compare, - Value1: 'SH', - }, - ]; + if (parentId === '') { + const itShopColumnFilter: { filter: FilterData[] } = { + filter: [ + { + ColumnName: 'ITShopInfo', + CompareOp: CompareOperator.Equal, + Type: FilterType.Compare, + Value1: 'SH', + }, + ], + }; + const filter = itShopColumnFilter.filter.concat(params.filter ?? []); + params = { ...params, filter }; } params.ParentKey = parentId; this.logger.debug(this, `Retrieving shop config structures`); this.logger.trace('Navigation state', navigationState); - return this.qerApiClient.typedClient.PortalShopConfigStructure.Get(params); + return this.qerApiClient.typedClient.PortalShopConfigStructure.Get(params, { signal }); } public createRequestConfigEntity(): PortalShopConfigStructure { @@ -117,7 +120,7 @@ export class RequestsService { public getRequestConfigMembers( customerNodeId: string, - navigationState: CollectionLoadParameters + navigationState: CollectionLoadParameters, ): Promise> { return this.qerApiClient.typedClient.PortalShopConfigMembers.Get(customerNodeId, navigationState); } @@ -134,13 +137,13 @@ export class RequestsService { public createRequestConfigMember( customerNodeId: string, - newMember: PortalShopConfigMembers + newMember: PortalShopConfigMembers, ): Promise> { return this.qerApiClient.typedClient.PortalShopConfigMembers.Post(customerNodeId, newMember); } public addMultipleRequestConfigMembers(values: string[], customerNodeId: string): Promise { - const promises = []; + const promises: Promise[] = []; values.forEach((value) => { const entity = this.qerApiClient.typedClient.PortalShopConfigMembers.createEntity(); entity.UID_Person.value = value; @@ -152,13 +155,13 @@ export class RequestsService { public removeRequestConfigMembers( customerNodeId: string, uidDynamicGroup: string, - members: PortalShopConfigMembers[], - description?: string + members: TypedEntity[], + description?: string, ): Promise { - const promises = []; - members.forEach((member) => { + const promises: Promise[] = []; + members.forEach((member: PortalShopConfigMembers) => { // If the member is managed by a dynamic group, add an exclusion - // tslint:disable-next-line:no-bitwise + // eslint-disable-next-line no-bitwise if ((member.XOrigin?.value & 4) > 0) { const exclusionData = this.qerApiClient.typedClient.PortalRolesExclusions.createEntity(); exclusionData.UID_Person.value = member.UID_Person.value; @@ -172,9 +175,9 @@ export class RequestsService { return Promise.all(promises); } - public removeRequestConfigMemberExclusions(uidDynamicGroup: string, exclusions: PortalRolesExclusions[]): Promise { - const promises = []; - exclusions.forEach((exclusion) => { + public removeRequestConfigMemberExclusions(uidDynamicGroup: string, exclusions: TypedEntity[]): Promise { + const promises: Promise[] = []; + exclusions.forEach((exclusion: PortalRolesExclusions) => { const memberUid = exclusion.UID_Person?.value; promises.push(this.removeDynamicRoleExclusion(uidDynamicGroup, memberUid)); }); @@ -209,18 +212,13 @@ export class RequestsService { } public handleOpenLoader(): void { - if (!this.busyIndicator) { - this.busyIndicator = this.busyService.show(); + if (this.busyService.overlayRefs.length === 0) { + this.busyService.show(); } } public handleCloseLoader(): void { - if (this.busyIndicator) { - setTimeout(() => { - this.busyService.hide(this.busyIndicator); - this.busyIndicator = undefined; - }); - } + this.busyService.hide(); } public LdsSpecifyMembers = '#LDS#Here you can specify who can request the products assigned to the shop.'; diff --git a/imxweb/projects/qer/src/lib/itshop-config/requests/requests.component.html b/imxweb/projects/qer/src/lib/itshop-config/requests/requests.component.html index 16bf2df10..50fe3b931 100644 --- a/imxweb/projects/qer/src/lib/itshop-config/requests/requests.component.html +++ b/imxweb/projects/qer/src/lib/itshop-config/requests/requests.component.html @@ -1,49 +1,38 @@ -
    -

    +
    +

    {{ requestsService.LdsHeadingShops | translate }} -

    -
    +

    +
    +
    -
    - - - - - -
    {{ item.GetEntity().GetDisplay() }}
    -
    {{ item.Description.Column.GetDisplayValue() }}
    -
    -
    - -
    - -
    + + + + {{ entitySchemaShopStructure?.Columns?.[DisplayColumns.DISPLAY_PROPERTYNAME]?.Display }} + + +
    {{ item.GetEntity().GetDisplay() }}
    +
    {{ item.Description.Column.GetDisplayValue() }}
    + +
    + + + {{ entitySchemaShopStructure?.Columns?.UID_OrgAttestator?.Display }} + + +
    {{ item.UID_OrgAttestator.Column.GetDisplayValue() }}
    + +
    +
    +
    -
    - diff --git a/imxweb/projects/qer/src/lib/itshop-config/requests/requests.component.scss b/imxweb/projects/qer/src/lib/itshop-config/requests/requests.component.scss index a9483dc9d..ca9b7f650 100644 --- a/imxweb/projects/qer/src/lib/itshop-config/requests/requests.component.scss +++ b/imxweb/projects/qer/src/lib/itshop-config/requests/requests.component.scss @@ -1,5 +1,5 @@ @import '@elemental-ui/core/src/styles/_palette.scss'; -@import '../../../../../../shared/scss/common-table.scss'; +@import 'base/mixins'; :host { display: flex; flex-direction: column; @@ -13,46 +13,13 @@ overflow: hidden; } - div.imx-table-container { - @include imx-flex-fill-control-hidden-overflow(); - - .imx-requests-table { - flex-grow: 1; - overflow: auto; - } - } - .heading-wrapper { display: flex; margin-bottom: 16px; - h1 { + h2 { margin: 6px 0 40px; } - - .helper-alert { - margin-bottom: 15px; - } - - .alert-wrapper { - margin: 0 0 0 auto; - align-self: flex-end; - width: 50%; - } - } - - ::ng-deep { - .imx-data-table-row-highlighted { - background-color: inherit; - } - - .mat-row:hover { - cursor: pointer; - background-color: rgba($black-c, 0.2); - } - } - .request-config__action-buttons { - @include imx-button-bar(); } } @@ -60,23 +27,6 @@ :host { .heading-wrapper { display: block; - - .alert-wrapper { - margin: 0 0 20px 0; - width: 100%; - } - } - } -} - -.eui-contrast-theme { - :host { - .request-config { - &.request-config--full-page { - .request-config__action-buttons { - background-color: $color-gray-90; - } - } } } } diff --git a/imxweb/projects/qer/src/lib/itshop-config/requests/requests.component.ts b/imxweb/projects/qer/src/lib/itshop-config/requests/requests.component.ts index 22fb74b25..ca5af5df5 100644 --- a/imxweb/projects/qer/src/lib/itshop-config/requests/requests.component.ts +++ b/imxweb/projects/qer/src/lib/itshop-config/requests/requests.component.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -28,19 +28,24 @@ import { Component, OnDestroy, OnInit } from '@angular/core'; import { EuiSidesheetService } from '@elemental-ui/core'; import { TranslateService } from '@ngx-translate/core'; -import { PortalShopConfigStructure } from 'imx-api-qer'; -import { CollectionLoadParameters, IClientProperty, DisplayColumns, EntitySchema } from 'imx-qbm-dbts'; +import { PortalShopConfigStructure } from '@imx-modules/imx-api-qer'; +import { + CollectionLoadParameters, + DisplayColumns, + EntitySchema, + IClientProperty, + TypedEntityCollectionData, +} from '@imx-modules/imx-qbm-dbts'; import { - DataSourceToolbarSettings, - DataSourceToolbarFilter, - ClassloggerService, - StorageService, - HELPER_ALERT_KEY_PREFIX, - SettingsService, BusyService, + calculateSidesheetWidth, + DataViewInitParameters, + DataViewSource, + HELP_CONTEXTUAL, HelpContextualComponent, HelpContextualService, - HELP_CONTEXTUAL + HELPER_ALERT_KEY_PREFIX, + StorageService, } from 'qbm'; import { RequestConfigSidesheetComponent } from '../request-config-sidesheet/request-config-sidesheet.component'; import { RequestsService } from '../requests.service'; @@ -51,6 +56,7 @@ const helperAlertKey = `${HELPER_ALERT_KEY_PREFIX}_requestShop`; selector: 'imx-requests', templateUrl: './requests.component.html', styleUrls: ['./requests.component.scss'], + providers: [DataViewSource], }) export class RequestsComponent implements OnInit, OnDestroy { public get showHelperAlert(): boolean { @@ -59,9 +65,6 @@ export class RequestsComponent implements OnInit, OnDestroy { public readonly entitySchemaShopStructure: EntitySchema; public readonly DisplayColumns = DisplayColumns; - public dstSettings: DataSourceToolbarSettings; - public navigationState: CollectionLoadParameters; - public filterOptions: DataSourceToolbarFilter[] = []; public busyService = new BusyService(); @@ -69,14 +72,12 @@ export class RequestsComponent implements OnInit, OnDestroy { constructor( private readonly sidesheet: EuiSidesheetService, - private readonly logger: ClassloggerService, private readonly translate: TranslateService, private readonly storageService: StorageService, public readonly requestsService: RequestsService, - private readonly settingsService: SettingsService, - private readonly helpContextualService: HelpContextualService + private readonly helpContextualService: HelpContextualService, + public dataSource: DataViewSource, ) { - this.navigationState = { PageSize: this.settingsService.DefaultPageSize, StartIndex: 0 }; this.entitySchemaShopStructure = requestsService.shopStructureSchema; } @@ -85,7 +86,7 @@ export class RequestsComponent implements OnInit, OnDestroy { this.entitySchemaShopStructure.Columns[DisplayColumns.DISPLAY_PROPERTYNAME], this.entitySchemaShopStructure.Columns.UID_OrgAttestator, ]; - await this.navigate(); + await this.initDataTable(); } public ngOnDestroy(): void { @@ -96,39 +97,15 @@ export class RequestsComponent implements OnInit, OnDestroy { this.storageService.storeHelperAlertDismissal(helperAlertKey); } - public async onSearch(keywords: string): Promise { - this.logger.debug(this, `Searching for: ${keywords}`); - this.navigationState.StartIndex = 0; - this.navigationState.search = keywords; - await this.navigate(); - } - - public onRequestShopSelected(requestConfig: PortalShopConfigStructure): void { - this.logger.debug(this, `Selected shop changed`); - this.logger.trace(`New shop selected`, requestConfig); - this.viewRequestShop(requestConfig); - } - public async createRequestConfig(): Promise { const newRequestConfig = this.requestsService.createRequestConfigEntity(); newRequestConfig.ITShopInfo.value = 'SH'; this.viewRequestShop(newRequestConfig, true); } - /** - * Occurs when the navigation state has changed - e.g. users clicks on the next page button. - * - */ - public async onNavigationStateChanged(newState?: CollectionLoadParameters): Promise { - if (newState) { - this.navigationState = newState; - } - await this.navigate(); - } - private async viewRequestShop(requestConfig: PortalShopConfigStructure, isNew: boolean = false): Promise { const key = isNew ? this.requestsService.LdsHeadingCreateShop : this.requestsService.LdsHeadingEditShop; - if(isNew){ + if (isNew) { this.helpContextualService.setHelpContextId(HELP_CONTEXTUAL.ConfigurationRequestsCreate); } const result = await this.sidesheet @@ -137,38 +114,32 @@ export class RequestsComponent implements OnInit, OnDestroy { subTitle: isNew ? '' : requestConfig.GetEntity().GetDisplay(), padding: '0px', disableClose: true, - width: 'max(60%,600px)', + width: calculateSidesheetWidth(), testId: isNew ? 'requests-config-create-shop-sidesheet' : 'requests-config-edit-shop-sidesheet', data: { requestConfig, isNew, }, - headerComponent: isNew ? HelpContextualComponent : undefined + headerComponent: isNew ? HelpContextualComponent : undefined, }) .afterClosed() .toPromise(); // After the sidesheet closes, reload the current data to refresh any changes that might have been made if (result) { - this.navigate(); + this.dataSource.updateState(); } } - private async navigate(): Promise { - const isBusy = this.busyService.beginBusy(); - const getParams: any = this.navigationState; - - try { - const data = await this.requestsService.getShopStructures(getParams, ''); - this.dstSettings = { - displayedColumns: this.displayedColumns, - dataSource: data, - entitySchema: this.entitySchemaShopStructure, - navigationState: this.navigationState, - filters: this.filterOptions, - }; - this.logger.debug(this, `Head at ${data.Data.length + this.navigationState.StartIndex} of ${data.totalCount} item(s)`); - } finally { - isBusy?.endBusy(); - } + private initDataTable(): void { + const dataViewInitParameters: DataViewInitParameters = { + execute: (params: CollectionLoadParameters, signal: AbortSignal): Promise> => + this.requestsService.getShopStructures(params, '', signal), + schema: this.entitySchemaShopStructure, + columnsToDisplay: this.displayedColumns, + highlightEntity: (entity: PortalShopConfigStructure) => { + this.viewRequestShop(entity); + }, + }; + this.dataSource.init(dataViewInitParameters); } } diff --git a/imxweb/projects/qer/src/lib/itshop-config/resource-entitlement-type.ts b/imxweb/projects/qer/src/lib/itshop-config/resource-entitlement-type.ts index c655fd24e..a6a61b6a6 100644 --- a/imxweb/projects/qer/src/lib/itshop-config/resource-entitlement-type.ts +++ b/imxweb/projects/qer/src/lib/itshop-config/resource-entitlement-type.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -24,40 +24,46 @@ * */ -import { TypedEntity, CollectionLoadParameters, ExtendedTypedEntityCollection, EntitySchema, EntityData } from "imx-qbm-dbts"; -import { IRequestableEntitlementType } from "./irequestable-entitlement-type"; +import { CollectionLoadParameters, EntityData, EntitySchema, ExtendedTypedEntityCollection, TypedEntity } from '@imx-modules/imx-qbm-dbts'; +import { IRequestableEntitlementType } from './irequestable-entitlement-type'; export class ResourceEntitlementType implements IRequestableEntitlementType { - - constructor(private readonly resourceType: string, + constructor( + private readonly resourceType: string, private type: { GetSchema(): EntitySchema; createEntity(initialData?: EntityData): TypedEntity; Get(shelfUid: string, navigationState: CollectionLoadParameters): Promise>; Post(shelfId: string, entitlement: TypedEntity): Promise; - }) { } + }, + ) {} getFkColumnName(): string { - return "UID_" + this.getTableName(); + return 'UID_' + this.getTableName(); } public addEntitlementSelections(shelfId: string, values: string[]): Promise { - const promises = []; + const promises: Promise[] = []; values.forEach((value) => { const entitlement = this.type.createEntity(); - entitlement.GetEntity().GetColumn("UID_" + this.resourceType).PutValue(value); + entitlement + .GetEntity() + .GetColumn('UID_' + this.resourceType) + .PutValue(value); promises.push(this.type.Post(shelfId, entitlement)); }); return Promise.all(promises); } - public getTableName(): string { return this.resourceType }; + public getTableName(): string { + return this.resourceType; + } public createAssignmentEntity(shelfId: string): TypedEntity { const e = this.type.createEntity({ Columns: { - "UID_ITShopOrg": { Value: shelfId } - } + UID_ITShopOrg: { Value: shelfId }, + }, }); return e; } @@ -65,5 +71,4 @@ export class ResourceEntitlementType implements IRequestableEntitlementType { getSchema(): EntitySchema { return this.type.GetSchema(); } - -} \ No newline at end of file +} diff --git a/imxweb/projects/qer/src/lib/itshop-config/test/requests-configuration-mocks.ts b/imxweb/projects/qer/src/lib/itshop-config/test/requests-configuration-mocks.ts index 7ca398eb0..cc5136573 100644 --- a/imxweb/projects/qer/src/lib/itshop-config/test/requests-configuration-mocks.ts +++ b/imxweb/projects/qer/src/lib/itshop-config/test/requests-configuration-mocks.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -24,8 +24,8 @@ * */ -import { PortalShopConfigMembers, PortalShopConfigStructure } from 'imx-api-qer'; -import { CollectionLoadParameters, FkProviderItem, IEntity, IEntityColumn, TypedEntityCollectionData } from 'imx-qbm-dbts'; +import { PortalShopConfigMembers, PortalShopConfigStructure } from '@imx-modules/imx-api-qer'; +import { CollectionLoadParameters, FkProviderItem, IEntity, IEntityColumn, TypedEntityCollectionData } from '@imx-modules/imx-qbm-dbts'; import { of } from 'rxjs'; function mockData(): TypedEntityCollectionData { @@ -38,18 +38,17 @@ const mockEntityColumn = { return { CanEdit: () => false, GetDisplay: () => '', - GetMinLength: () => 0 + GetMinLength: () => 0, }; }, - GetValue: () => '' - + GetValue: () => '', } as IEntityColumn; const mockRequestEntity = { GetDisplay: () => 'Display value', GetKeys: () => ['testId'], GetColumn: (name) => mockEntityColumn, - Commit: (bool) => Promise.resolve() + Commit: (bool) => Promise.resolve(), } as IEntity; const mockfkProviderItem = { @@ -58,7 +57,7 @@ const mockfkProviderItem = { parameterNames: [], load: () => Promise.resolve(undefined), getDataModel: () => Promise.resolve({}), - getFilterTree: async () => ({}) + getFilterTree: async () => ({}), } as FkProviderItem; const mockEntityWithFk = { @@ -67,11 +66,11 @@ const mockEntityWithFk = { GetColumn: (name) => mockEntityColumn, GetFkCandidateProvider: () => { return { getProviderItem: (colName, table) => mockfkProviderItem }; - } + }, } as IEntity; const mockNewMemberEntity: any = { - GetEntity: () => mockEntityWithFk + GetEntity: () => mockEntityWithFk, } as PortalShopConfigMembers; export class RequestsConfigurationCommonMocks { @@ -145,10 +144,12 @@ export class RequestsConfigurationCommonMocks { }; public static readonly storage = {}; public static mockStorageService: any = { - isHelperAlertDismissed: jasmine.createSpy('isHelperAlertDismissed').and.callFake( - (key: string) => RequestsConfigurationCommonMocks.storage[key]), - storeHelperAlertDismissal: jasmine.createSpy('storeHelperAlertDismissal').and.callFake( - (key: string) => RequestsConfigurationCommonMocks.storage[key] = true), + isHelperAlertDismissed: jasmine + .createSpy('isHelperAlertDismissed') + .and.callFake((key: string) => RequestsConfigurationCommonMocks.storage[key]), + storeHelperAlertDismissal: jasmine + .createSpy('storeHelperAlertDismissal') + .and.callFake((key: string) => (RequestsConfigurationCommonMocks.storage[key] = true)), }; public static mockDialogRef = { afterClosed: () => of(undefined) }; diff --git a/imxweb/projects/qer/src/lib/itshop-pattern/duplicate-pattern-items/duplicate-pattern-item.ts b/imxweb/projects/qer/src/lib/itshop-pattern/duplicate-pattern-items/duplicate-pattern-item.ts index dfd0e67b1..426d051f1 100644 --- a/imxweb/projects/qer/src/lib/itshop-pattern/duplicate-pattern-items/duplicate-pattern-item.ts +++ b/imxweb/projects/qer/src/lib/itshop-pattern/duplicate-pattern-items/duplicate-pattern-item.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -28,8 +28,7 @@ * Class representing the service items that could not be added to the itshop pattern. */ export class DuplicatePatternItem { - - // tslint:disable-next-line: variable-name + // eslint-disable-next-line @typescript-eslint/naming-convention,no-underscore-dangle,id-blacklist,id-match public readonly Display: string; constructor(display: string) { diff --git a/imxweb/projects/qer/src/lib/itshop-pattern/duplicate-pattern-items/duplicate-pattern-items.component.html b/imxweb/projects/qer/src/lib/itshop-pattern/duplicate-pattern-items/duplicate-pattern-items.component.html index 0e86d932b..20566d90f 100644 --- a/imxweb/projects/qer/src/lib/itshop-pattern/duplicate-pattern-items/duplicate-pattern-items.component.html +++ b/imxweb/projects/qer/src/lib/itshop-pattern/duplicate-pattern-items/duplicate-pattern-items.component.html @@ -1,12 +1,12 @@ -

    - {{'#LDS#Heading Products Cannot Be Added to Product Bundle' | translate}} -

    +

    + {{ '#LDS#Heading Products Cannot Be Added to Product Bundle' | translate }} +

    - {{ description1 | translate}} + {{ description1 | translate }}
    - {{ description2 | translate}} + {{ description2 | translate }}
    @@ -18,11 +18,11 @@

    - +
    -
    +
    diff --git a/imxweb/projects/qer/src/lib/itshop-pattern/duplicate-pattern-items/duplicate-pattern-items.component.scss b/imxweb/projects/qer/src/lib/itshop-pattern/duplicate-pattern-items/duplicate-pattern-items.component.scss index 542a60e72..18b3745c8 100644 --- a/imxweb/projects/qer/src/lib/itshop-pattern/duplicate-pattern-items/duplicate-pattern-items.component.scss +++ b/imxweb/projects/qer/src/lib/itshop-pattern/duplicate-pattern-items/duplicate-pattern-items.component.scss @@ -1,9 +1,6 @@ -.mat-dialog-content{ - overflow: hidden; - display: flex; - flex-direction: column; +@import 'base/mixins'; + +.mat-mdc-dialog-content { + @include flex-column-container($overflow: hidden); - .mat-table { - margin-top: 20px; - } } diff --git a/imxweb/projects/qer/src/lib/itshop-pattern/duplicate-pattern-items/duplicate-pattern-items.component.ts b/imxweb/projects/qer/src/lib/itshop-pattern/duplicate-pattern-items/duplicate-pattern-items.component.ts index 51b99925c..90c66098f 100644 --- a/imxweb/projects/qer/src/lib/itshop-pattern/duplicate-pattern-items/duplicate-pattern-items.component.ts +++ b/imxweb/projects/qer/src/lib/itshop-pattern/duplicate-pattern-items/duplicate-pattern-items.component.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -35,25 +35,22 @@ import { DuplicatePatternItem } from './duplicate-pattern-item'; @Component({ selector: 'imx-duplicate-pattern-items', templateUrl: './duplicate-pattern-items.component.html', - styleUrls: ['./duplicate-pattern-items.component.scss'] + styleUrls: ['./duplicate-pattern-items.component.scss'], }) export class DuplicatePatternItemsComponent { - public get columnNames(): string[] { - return this.displayedColumns.map(c => c.name); + return this.displayedColumns.map((c) => c.name); } public description1 = '#LDS#Each product can be added to the product bundle only once.'; public description2 = '#LDS#The following products have already been added to the product bundle and cannot be added again.'; - public readonly displayedColumns = [ - { name: 'Display', title: '#LDS#Product' } - ]; + public readonly displayedColumns = [{ name: 'Display', title: '#LDS#Product' }]; constructor( - @Inject(MAT_DIALOG_DATA) public readonly data: { - duplicatePatternItems: DuplicatePatternItem[] - } - ) { - } + @Inject(MAT_DIALOG_DATA) + public readonly data: { + duplicatePatternItems: DuplicatePatternItem[]; + }, + ) {} } diff --git a/imxweb/projects/qer/src/lib/itshop-pattern/itshop-pattern-add-products/itshop-pattern-add-products.component.html b/imxweb/projects/qer/src/lib/itshop-pattern/itshop-pattern-add-products/itshop-pattern-add-products.component.html index b20591b3f..946da0132 100644 --- a/imxweb/projects/qer/src/lib/itshop-pattern/itshop-pattern-add-products/itshop-pattern-add-products.component.html +++ b/imxweb/projects/qer/src/lib/itshop-pattern/itshop-pattern-add-products/itshop-pattern-add-products.component.html @@ -1,31 +1,49 @@
    - + {{ description | translate }}
    - + - {{'#LDS#Show my products' | translate}} + {{ '#LDS#Show my products' | translate }} - {{'#LDS#Show products of another identity' | translate}} + {{ '#LDS#Show products of another identity' | translate }} - +
    - +
    -
    -
    diff --git a/imxweb/projects/qer/src/lib/itshop-pattern/itshop-pattern-add-products/itshop-pattern-add-products.component.scss b/imxweb/projects/qer/src/lib/itshop-pattern/itshop-pattern-add-products/itshop-pattern-add-products.component.scss index 660388a0c..2536a3f77 100644 --- a/imxweb/projects/qer/src/lib/itshop-pattern/itshop-pattern-add-products/itshop-pattern-add-products.component.scss +++ b/imxweb/projects/qer/src/lib/itshop-pattern/itshop-pattern-add-products/itshop-pattern-add-products.component.scss @@ -1,40 +1,16 @@ -@import "@elemental-ui/core/src/styles/_palette.scss"; @import '@elemental-ui/core/src/styles/_eui_palette.scss'; -:host { - - eui-alert { - margin-bottom: 10px; - } +@import 'base/mixins'; +:host { ::ng-deep imx-data-tiles { padding-left: 10px; } - ::ng-deep .mat-tab-body-content { - display: flex; - flex-direction: column; - } - - .eui-sidesheet-content { - display: flex; - flex-direction: column; - - >.mat-card { - display: flex; - flex-direction: column; - height: 100%; - } - } - .eui-sidesheet-actions { button:not(:last-of-type) { margin-right: 10px; } } - .mat-radio-button { - height: 70px; - margin-right: 20px; - } .imx-recipients { height: 100px; @@ -49,20 +25,14 @@ } } -.eui-dark-theme{ - :host{ +.eui-dark-theme { + :host { background-color: $color-gray-80; - .eui-sidesheet-actions{ - background-color: $color-gray-70; - } } } -.eui-contrast-theme{ - :host{ +.eui-contrast-theme { + :host { background-color: $color-gray-100; - .eui-sidesheet-actions{ - background-color: $color-gray-90; - } } } diff --git a/imxweb/projects/qer/src/lib/itshop-pattern/itshop-pattern-add-products/itshop-pattern-add-products.component.spec.ts b/imxweb/projects/qer/src/lib/itshop-pattern/itshop-pattern-add-products/itshop-pattern-add-products.component.spec.ts index 65b570479..121f4ac9d 100644 --- a/imxweb/projects/qer/src/lib/itshop-pattern/itshop-pattern-add-products/itshop-pattern-add-products.component.spec.ts +++ b/imxweb/projects/qer/src/lib/itshop-pattern/itshop-pattern-add-products/itshop-pattern-add-products.component.spec.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -39,11 +39,11 @@ describe('ItshopPatternAddProductsComponent', () => { beforeEach(() => { return MockBuilder([ItshopPatternAddProductsComponent, TranslateModule.forRoot()]) - .mock(ItshopPatternModule) + .mock(ItshopPatternModule) .mock(EuiSidesheetRef, { close: jasmine.createSpy('close'), closeClicked: jasmine.createSpy('closeClicked').and.returnValue(of(undefined)), - }) + }); }); beforeEach(() => { diff --git a/imxweb/projects/qer/src/lib/itshop-pattern/itshop-pattern-add-products/itshop-pattern-add-products.component.ts b/imxweb/projects/qer/src/lib/itshop-pattern/itshop-pattern-add-products/itshop-pattern-add-products.component.ts index a337cb7d1..8b9c4c98c 100644 --- a/imxweb/projects/qer/src/lib/itshop-pattern/itshop-pattern-add-products/itshop-pattern-add-products.component.ts +++ b/imxweb/projects/qer/src/lib/itshop-pattern/itshop-pattern-add-products/itshop-pattern-add-products.component.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -25,15 +25,23 @@ */ import { Component, Inject, OnDestroy, OnInit, ViewChild } from '@angular/core'; -import { MatSelectChange } from '@angular/material/select'; -import { EuiLoadingService, EuiSidesheetRef, EuiSidesheetService, EUI_SIDESHEET_DATA } from '@elemental-ui/core'; +import { MatRadioChange } from '@angular/material/radio'; +import { EUI_SIDESHEET_DATA, EuiLoadingService, EuiSidesheetRef, EuiSidesheetService } from '@elemental-ui/core'; import { TranslateService } from '@ngx-translate/core'; import { Subscription } from 'rxjs'; -import { PortalShopCategories, PortalShopServiceitems, QerProjectConfig } from 'imx-api-qer'; -import { EntityValue, IWriteValue, LocalProperty } from 'imx-qbm-dbts'; +import { PortalShopCategories, PortalShopServiceitems, QerProjectConfig } from '@imx-modules/imx-api-qer'; +import { EntityValue, IWriteValue, LocalProperty, TypedEntity } from '@imx-modules/imx-qbm-dbts'; -import { AuthenticationService, BaseCdr, ColumnDependentReference, DataTileMenuItem, EntityService } from 'qbm'; +import { + AuthenticationService, + BaseCdr, + calculateSidesheetWidth, + ColumnDependentReference, + DataTileMenuItem, + EntityService, + ISessionState, +} from 'qbm'; import { PersonService } from '../../person/person.service'; import { ProductDetailsSidesheetComponent } from '../../product-selection/product-details-sidesheet/product-details-sidesheet.component'; @@ -51,10 +59,9 @@ import { PatternItemCandidate } from '../pattern-item-candidate.interface'; @Component({ selector: 'imx-itshop-pattern-add-products', templateUrl: './itshop-pattern-add-products.component.html', - styleUrls: ['./itshop-pattern-add-products.component.scss'] + styleUrls: ['./itshop-pattern-add-products.component.scss'], }) export class ItshopPatternAddProductsComponent implements OnInit, OnDestroy { - @ViewChild(ServiceitemListComponent) public serviceitemListComponent: ServiceitemListComponent; public readonly dataSourceView = { selected: 'cardlist' }; @@ -65,17 +72,18 @@ export class ItshopPatternAddProductsComponent implements OnInit, OnDestroy { public canRequestForSomebodyElse: boolean; public recipientType: 'self' | 'others' = 'self'; - public description = '#LDS#Here you can add products to this product bundle that are available for you. You can also select another identity to view the products available for that identity.'; + public description = + '#LDS#Here you can add products to this product bundle that are available for you. You can also select another identity to view the products available for that identity.'; public serviceItemActions: DataTileMenuItem[] = [ { name: 'details', - description: '#LDS#Details' + description: '#LDS#Details', }, { name: 'addToTemplate', - description: '#LDS#Add' - } + description: '#LDS#Add', + }, ]; private projectConfig: QerProjectConfig; @@ -83,8 +91,9 @@ export class ItshopPatternAddProductsComponent implements OnInit, OnDestroy { private userUid: string; constructor( - @Inject(EUI_SIDESHEET_DATA) public data: { - shoppingCartPatternUid: string + @Inject(EUI_SIDESHEET_DATA) + public data: { + shoppingCartPatternUid: string; }, private readonly busyIndicator: EuiLoadingService, private readonly entityService: EntityService, @@ -96,12 +105,11 @@ export class ItshopPatternAddProductsComponent implements OnInit, OnDestroy { private readonly sideSheetRef: EuiSidesheetRef, private readonly translate: TranslateService, private readonly userModelService: UserModelService, - authentication: AuthenticationService + authentication: AuthenticationService, ) { - this.authSubscription = authentication.onSessionResponse.subscribe(elem => { - this.userUid = elem.UserUid; + this.authSubscription = authentication.onSessionResponse.subscribe((session: ISessionState) => { + this.userUid = session.UserUid || ''; }); - } public async ngOnInit(): Promise { @@ -113,11 +121,11 @@ export class ItshopPatternAddProductsComponent implements OnInit, OnDestroy { this.authSubscription.unsubscribe(); } - public onSelectionChanged(items: PortalShopServiceitems[]): void { - this.selectedItems = items; + public onSelectionChanged(items: TypedEntity[]): void { + this.selectedItems = items as PortalShopServiceitems[]; } - public async handlePatternItemAction(action: { name: string, item: PortalShopServiceitems }): Promise { + public async handlePatternItemAction(action: { name: string; item: PortalShopServiceitems }): Promise { if (action.name === 'addToTemplate') { this.addTemplateItem([action.item]); } @@ -127,49 +135,53 @@ export class ItshopPatternAddProductsComponent implements OnInit, OnDestroy { } public async requestDetails(item: PortalShopServiceitems): Promise { - await this.sidesheet.open(ProductDetailsSidesheetComponent, { - title: await this.translate.get('#LDS#Heading View Product Details').toPromise(), - subTitle: item.GetEntity().GetDisplay(), - padding: '0px', - width: 'max(700px, 60%)', - testId: 'product-details-sidesheet', - data: { - item, - projectConfig: this.projectConfig - } - }).afterClosed().toPromise(); + await this.sidesheet + .open(ProductDetailsSidesheetComponent, { + title: await this.translate.get('#LDS#Heading View Product Details').toPromise(), + subTitle: item.GetEntity().GetDisplay(), + padding: '0px', + width: calculateSidesheetWidth(1000), + testId: 'product-details-sidesheet', + data: { + item, + projectConfig: this.projectConfig, + }, + }) + .afterClosed() + .toPromise(); } public async addTemplateItem(serviceItems: PortalShopServiceitems[]): Promise { - const newPatternItems = serviceItems.map(item => { - return { - uidAccProduct: item.GetEntity().GetKeys()[0], - display: item.GetEntity().GetDisplay() + const newPatternItems = serviceItems.map((item) => { + return { + uidAccProduct: item.GetEntity().GetKeys()[0], + display: item.GetEntity().GetDisplay(), } as PatternItemCandidate; }); - setTimeout(() => this.busyIndicator.show()); + if (this.busyIndicator.overlayRefs.length === 0) { + this.busyIndicator.show(); + } try { - const assignedPatterns = await this.patternCreateService.assignItemsToPattern( - newPatternItems, this.data.shoppingCartPatternUid); - + const assignedPatterns = await this.patternCreateService.assignItemsToPattern(newPatternItems, this.data.shoppingCartPatternUid); + if (assignedPatterns > 0) { this.sideSheetRef.close(assignedPatterns); } } finally { - setTimeout(() => this.busyIndicator.hide()); - } + this.busyIndicator.hide(); + } } public async openCategoryTree(): Promise { const sidesheetRef = this.sidesheet.open(CategoryTreeComponent, { title: await this.translate.get('#LDS#Heading Select Service Category').toPromise(), - width: '600px', + width: calculateSidesheetWidth(600, 0.4), testId: 'categorytree-sidesheet', data: { selectedServiceCategory: this.selectedCategory, recipients: this.recipients, - showImage: false - } + showImage: false, + }, }); sidesheetRef.afterClosed().subscribe((category: PortalShopCategories) => { @@ -186,23 +198,22 @@ export class ItshopPatternAddProductsComponent implements OnInit, OnDestroy { this.selectedCategory = selectedCategory; } - public async selectedRecipientTypeChanged(arg: MatSelectChange): Promise { + public async selectedRecipientTypeChanged(arg: MatRadioChange): Promise { if (arg.value === 'self') { await this.recipients.Column.PutValueStruct({ DataValue: this.userUid, - DisplayValue: await this.getPersonDisplay(this.userUid) + DisplayValue: await this.getPersonDisplay(this.userUid), }); } else { await this.recipients.Column.PutValueStruct({ DataValue: '', - DisplayValue: '' + DisplayValue: '', }); } this.onRecipientsChanged(); } public async onRecipientsChanged(recipient?: string): Promise { - if (this.serviceitemListComponent) { this.serviceitemListComponent.deselectAll(); this.serviceitemListComponent.getData(); @@ -218,33 +229,23 @@ export class ItshopPatternAddProductsComponent implements OnInit, OnDestroy { recipientsProperty.FkRelation = this.qerClient.typedClient.PortalCartitem.GetSchema().Columns.UID_PersonOrdered.FkRelation; const dummyCartItemEntity = this.qerClient.typedClient.PortalCartitem.createEntity().GetEntity(); - const fkProviderItems = this.qerClient.client.getFkProviderItems('portal/cartitem').map(item => ({ + const fkProviderItems = this.qerClient.client.getFkProviderItems('portal/cartitem').map((item) => ({ ...item, load: (_, parameters = {}) => item.load(dummyCartItemEntity, parameters), - getDataModel: async (entity) => - item.getDataModel(entity), - getFilterTree: async (entity, parentKey) => item.getFilterTree(entity, parentKey) + getDataModel: async (entity) => item.getDataModel?.(entity) || {}, + getFilterTree: async (entity, parentKey) => item.getFilterTree?.(entity, parentKey) || {}, })); - const column = this.entityService.createLocalEntityColumn( - recipientsProperty, - fkProviderItems, - { Value: this.userUid } - ); + const column = this.entityService.createLocalEntityColumn(recipientsProperty, fkProviderItems, { Value: this.userUid }); this.recipients = new EntityValue(column); // preset recipient to the current user await this.recipients.Column.PutValueStruct({ DataValue: this.userUid, - DisplayValue: await this.getPersonDisplay(this.userUid) + DisplayValue: await this.getPersonDisplay(this.userUid), }); - - this.cartItemRecipients = new BaseCdr( - this.recipients.Column, - '#LDS#Identity' - ); - + this.cartItemRecipients = new BaseCdr(this.recipients.Column, '#LDS#Identity'); } private async getPersonDisplay(uid: string): Promise { @@ -254,5 +255,4 @@ export class ItshopPatternAddProductsComponent implements OnInit, OnDestroy { } return uid; } - } diff --git a/imxweb/projects/qer/src/lib/itshop-pattern/itshop-pattern-changed.enum.ts b/imxweb/projects/qer/src/lib/itshop-pattern/itshop-pattern-changed.enum.ts index 2db032e3a..c14481735 100644 --- a/imxweb/projects/qer/src/lib/itshop-pattern/itshop-pattern-changed.enum.ts +++ b/imxweb/projects/qer/src/lib/itshop-pattern/itshop-pattern-changed.enum.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -27,9 +27,9 @@ /** * The list of types a {@link ServiceCategory|PortalServicecategories} could changed. */ - export enum ItShopPatternChangedType { +export enum ItShopPatternChangedType { Saved, Deleted, TogglePublic, - CreateCopy + CreateCopy, } diff --git a/imxweb/projects/qer/src/lib/itshop-pattern/itshop-pattern-create-sidesheet/itshop-pattern-create-sidesheet.component.html b/imxweb/projects/qer/src/lib/itshop-pattern/itshop-pattern-create-sidesheet/itshop-pattern-create-sidesheet.component.html index aa9456278..bc49290ff 100644 --- a/imxweb/projects/qer/src/lib/itshop-pattern/itshop-pattern-create-sidesheet/itshop-pattern-create-sidesheet.component.html +++ b/imxweb/projects/qer/src/lib/itshop-pattern/itshop-pattern-create-sidesheet/itshop-pattern-create-sidesheet.component.html @@ -1,19 +1,23 @@
    - - {{ '#LDS#Private product bundle' | translate}} + + {{ '#LDS#Private product bundle' | translate }} - - {{'#LDS#Public product bundle' | translate}} + + {{ '#LDS#Public product bundle' | translate }} - - +
    -
    -
    diff --git a/imxweb/projects/qer/src/lib/itshop-pattern/itshop-pattern-create-sidesheet/itshop-pattern-create-sidesheet.component.scss b/imxweb/projects/qer/src/lib/itshop-pattern/itshop-pattern-create-sidesheet/itshop-pattern-create-sidesheet.component.scss index 75a636e6d..0bbbf69b6 100644 --- a/imxweb/projects/qer/src/lib/itshop-pattern/itshop-pattern-create-sidesheet/itshop-pattern-create-sidesheet.component.scss +++ b/imxweb/projects/qer/src/lib/itshop-pattern/itshop-pattern-create-sidesheet/itshop-pattern-create-sidesheet.component.scss @@ -1,41 +1,13 @@ -@import "@elemental-ui/core/src/styles/_palette.scss"; +@import '@elemental-ui/core/src/styles/_palette.scss'; @import '@elemental-ui/core/src/styles/_eui_palette.scss'; -.eui-sidesheet-content { - display: flex; - flex-direction: column; -} :host { - .eui-badge ::ng-deep .eui-badge-content { - font-size: 12px; - line-height: 12px; - margin-bottom: 20px; - } - - .imx-helper-alert { - width: 100%; - - ::ng-deep .eui-alert { - margin-bottom: 20px; - } - } - .imx-sidesheet-content { display: flex; flex-direction: column; height: 100%; } - .eui-sidesheet-actions { - .justify-start { - margin-right: auto; - } - - button:not(:last-of-type):not(.justify-start) { - margin-right: 10px; - } - } - .imx-errormessages { margin-bottom: 10px; @@ -45,22 +17,16 @@ } } -.eui-dark-theme{ - :host{ +.eui-dark-theme { + :host { background-color: $color-gray-80; color: $color-gray-2; - .eui-sidesheet-actions{ - background-color: $color-gray-70; - } } } -.eui-contrast-theme{ - :host{ +.eui-contrast-theme { + :host { background-color: $color-gray-100; color: $color-gray-2; - .eui-sidesheet-actions{ - background-color: $color-gray-90; - } } } diff --git a/imxweb/projects/qer/src/lib/itshop-pattern/itshop-pattern-create-sidesheet/itshop-pattern-create-sidesheet.component.ts b/imxweb/projects/qer/src/lib/itshop-pattern/itshop-pattern-create-sidesheet/itshop-pattern-create-sidesheet.component.ts index 9cc87c4a7..d3f222a83 100644 --- a/imxweb/projects/qer/src/lib/itshop-pattern/itshop-pattern-create-sidesheet/itshop-pattern-create-sidesheet.component.ts +++ b/imxweb/projects/qer/src/lib/itshop-pattern/itshop-pattern-create-sidesheet/itshop-pattern-create-sidesheet.component.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -24,24 +24,16 @@ * */ -import { Component, Inject, OnDestroy, OnInit, ViewChild } from '@angular/core'; +import { Component, Inject, OnDestroy, OnInit } from '@angular/core'; import { UntypedFormArray, UntypedFormBuilder, UntypedFormGroup } from '@angular/forms'; -import { EuiSidesheetRef, EUI_SIDESHEET_DATA } from '@elemental-ui/core'; +import { EUI_SIDESHEET_DATA, EuiSidesheetRef } from '@elemental-ui/core'; import { Subscription } from 'rxjs'; -import { PortalItshopPatternPrivate, } from 'imx-api-qer'; -import { TypedEntity } from 'imx-qbm-dbts'; +import { PortalItshopPatternPrivate } from '@imx-modules/imx-api-qer'; -import { - BaseCdr, - ClassloggerService, - ColumnDependentReference, - ConfirmationService, - DataTableComponent, - ErrorService, -} from 'qbm'; -import { ItshopPatternService } from '../itshop-pattern.service'; +import { BaseCdr, ClassloggerService, ColumnDependentReference, ConfirmationService, ErrorService } from 'qbm'; import { ItShopPatternChangedType } from '../itshop-pattern-changed.enum'; +import { ItshopPatternService } from '../itshop-pattern.service'; /** * Component displayed in a sidesheet with a form to create a itshop pattern. @@ -49,39 +41,39 @@ import { ItShopPatternChangedType } from '../itshop-pattern-changed.enum'; @Component({ selector: 'imx-itshop-pattern-create-sidesheet', templateUrl: './itshop-pattern-create-sidesheet.component.html', - styleUrls: ['./itshop-pattern-create-sidesheet.component.scss'] + styleUrls: ['./itshop-pattern-create-sidesheet.component.scss'], }) export class ItshopPatternCreateSidesheetComponent implements OnInit, OnDestroy { - public get formArray(): UntypedFormArray { return this.detailsFormGroup.get('formArray') as UntypedFormArray; } public cdrList: ColumnDependentReference[] = []; public readonly detailsFormGroup: UntypedFormGroup; - @ViewChild(DataTableComponent) public table: DataTableComponent; - private closeSubscription: Subscription; private disposable: () => void; constructor( formBuilder: UntypedFormBuilder, - @Inject(EUI_SIDESHEET_DATA) public data: { - pattern: PortalItshopPatternPrivate + @Inject(EUI_SIDESHEET_DATA) + public data: { + pattern: PortalItshopPatternPrivate; }, private readonly patternService: ItshopPatternService, private readonly sideSheetRef: EuiSidesheetRef, private readonly logger: ClassloggerService, errorService: ErrorService, - confirmation: ConfirmationService + confirmation: ConfirmationService, ) { this.detailsFormGroup = new UntypedFormGroup({ formArray: formBuilder.array([]) }); this.closeSubscription = this.sideSheetRef.closeClicked().subscribe(async () => { - if (await confirmation.confirm({ - Title: '#LDS#Heading Cancel Creating', - Message: '#LDS#Are you sure you want to cancel creating the product bundle?' - })) { + if ( + await confirmation.confirm({ + Title: '#LDS#Heading Cancel Creating', + Message: '#LDS#Are you sure you want to cancel creating the product bundle?', + }) + ) { this.sideSheetRef.close(); } }); @@ -115,11 +107,6 @@ export class ItshopPatternCreateSidesheetComponent implements OnInit, OnDestroy } private async setupDetailsTab(): Promise { - - this.cdrList = [ - new BaseCdr(this.data.pattern.Ident_ShoppingCartPattern.Column), - new BaseCdr(this.data.pattern.Description.Column), - ]; - + this.cdrList = [new BaseCdr(this.data.pattern.Ident_ShoppingCartPattern.Column), new BaseCdr(this.data.pattern.Description.Column)]; } } diff --git a/imxweb/projects/qer/src/lib/itshop-pattern/itshop-pattern-create-sidesheet/itshop-pattern-create.service.ts b/imxweb/projects/qer/src/lib/itshop-pattern/itshop-pattern-create-sidesheet/itshop-pattern-create.service.ts index c5e2dd83a..6d5c166f8 100644 --- a/imxweb/projects/qer/src/lib/itshop-pattern/itshop-pattern-create-sidesheet/itshop-pattern-create.service.ts +++ b/imxweb/projects/qer/src/lib/itshop-pattern/itshop-pattern-create-sidesheet/itshop-pattern-create.service.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -30,21 +30,28 @@ import { MatDialog } from '@angular/material/dialog'; import { EuiLoadingService, EuiSidesheetService } from '@elemental-ui/core'; import { TranslateService } from '@ngx-translate/core'; -import { PortalItshopPatternItem, PortalItshopPatternPrivate } from 'imx-api-qer'; - -import { ClassloggerService, HELP_CONTEXTUAL, HelpContextualComponent, HelpContextualService, SnackBarService, UserMessageService } from 'qbm'; +import { PortalItshopPatternItem, PortalItshopPatternPrivate } from '@imx-modules/imx-api-qer'; + +import { + calculateSidesheetWidth, + ClassloggerService, + HELP_CONTEXTUAL, + HelpContextualComponent, + HelpContextualService, + SnackBarService, + UserMessageService, +} from 'qbm'; import { QerApiService } from '../../qer-api-client.service'; import { DuplicatePatternItem } from '../duplicate-pattern-items/duplicate-pattern-item'; import { DuplicatePatternItemsComponent } from '../duplicate-pattern-items/duplicate-pattern-items.component'; import { ItShopPatternChangedType } from '../itshop-pattern-changed.enum'; -import { ItshopPatternCreateSidesheetComponent } from './itshop-pattern-create-sidesheet.component'; import { PatternItemCandidate } from '../pattern-item-candidate.interface'; +import { ItshopPatternCreateSidesheetComponent } from './itshop-pattern-create-sidesheet.component'; @Injectable({ - providedIn: 'root' + providedIn: 'root', }) export class ItshopPatternCreateService { - private busyIndicator: OverlayRef; private busyIndicatorCounter = 0; @@ -58,11 +65,10 @@ export class ItshopPatternCreateService { private readonly translate: TranslateService, private readonly errorHandler: ErrorHandler, private readonly snackBar: SnackBarService, - private readonly helpContextualService: HelpContextualService - ) { } + private readonly helpContextualService: HelpContextualService, + ) {} public async saveNewPatternAndItems(pattern: PortalItshopPatternPrivate, patternItems: PortalItshopPatternItem[]): Promise { - this.handleOpenLoader(); try { const uidPattern = await this.postPattern(pattern); @@ -71,16 +77,17 @@ export class ItshopPatternCreateService { if (patternItems && patternItems.length > 0) { await this.createPatternItems(patternItems, uidPattern, false); } - } finally { this.handleCloseLoader(); } - this.snackBar.open({ - key: '#LDS#The product bundle has been successfully created.', - parameters: [pattern.GetEntity().GetDisplay()] - }, '#LDS#Close'); - + this.snackBar.open( + { + key: '#LDS#The product bundle has been successfully created.', + parameters: [pattern.GetEntity().GetDisplay()], + }, + '#LDS#Close', + ); } /** @@ -93,32 +100,32 @@ export class ItshopPatternCreateService { return pattern.GetEntity()?.GetKeys()?.join(','); } - public async createPatternItems(selection: any, uidPattern: string, showResultInSnackbar: boolean = true): Promise { - - const newAssignedObjects = (await this.handlePromiseLoader( - Promise.all( - selection.map(async (selectedItem: { XObjectKey: { value: string; }; }) => { - const patternItem = this.qerClient.typedClient.PortalItshopPatternItem.createEntity(); - patternItem.UID_ShoppingCartPattern.value = uidPattern; - patternItem.UID_AccProduct.value = selectedItem.XObjectKey.value; - await patternItem.GetEntity().Commit(true); - }) + const newAssignedObjects = ( + await this.handlePromiseLoader( + Promise.all( + selection.map(async (selectedItem: { XObjectKey: { value: string } }) => { + const patternItem = this.qerClient.typedClient.PortalItshopPatternItem.createEntity(); + patternItem.UID_ShoppingCartPattern.value = uidPattern; + patternItem.UID_AccProduct.value = selectedItem.XObjectKey.value; + await patternItem.GetEntity().Commit(true); + }), + ), ) - )).length; + ).length; if (newAssignedObjects > 0 && showResultInSnackbar) { - this.snackBar.open({ - key: '#LDS#{0} identities have been successfully assigned.', - parameters: [newAssignedObjects] - }, '#LDS#Close'); + this.snackBar.open( + { + key: '#LDS#{0} identities have been successfully assigned.', + parameters: [newAssignedObjects], + }, + '#LDS#Close', + ); } return newAssignedObjects; } - public async assignItemsToPattern( - items: PatternItemCandidate[], - uidPattern: string = ''): Promise { - + public async assignItemsToPattern(items: PatternItemCandidate[], uidPattern: string = ''): Promise { if (uidPattern.length === 0) { // create new pattern const pattern = await this.createNewPattern(false); @@ -141,10 +148,9 @@ export class ItshopPatternCreateService { newAssignedObjects++; } catch (exception) { // 810303 == the combination of the fields Role/organization, Service item, Product bundle must be unique. - if (exception?.dataItems.length && exception.dataItems[0].Number === 810303 ) { + if (exception?.dataItems.length && exception.dataItems[0].Number === 810303) { duplicateItems.push(new DuplicatePatternItem(item.display)); - } - else { + } else { this.errorHandler.handleError(exception); } } @@ -153,8 +159,8 @@ export class ItshopPatternCreateService { if (duplicateItems.length > 0) { const dialogRef = this.dialogService.open(DuplicatePatternItemsComponent, { data: { - duplicatePatternItems: duplicateItems - } + duplicatePatternItems: duplicateItems, + }, }); await dialogRef.beforeClosed().toPromise(); @@ -162,55 +168,53 @@ export class ItshopPatternCreateService { return newAssignedObjects; } - public async createNewPattern(showSnackbar: boolean): Promise { + public async createNewPattern(showSnackbar: boolean): Promise { const newPattern = this.createNewPatternEntity(); this.logger.trace(this, 'new itshop pattern created', newPattern); if (newPattern) { this.helpContextualService.setHelpContextId(HELP_CONTEXTUAL.RequestTemplatesCreate); - const result = await this.sidesheet.open(ItshopPatternCreateSidesheetComponent, { - title: await this.translate.get('#LDS#Heading Create Product Bundle').toPromise(), - panelClass: 'imx-sidesheet', - disableClose: true, - padding: '0', - width: '600px', - testId: 'pattern-create-sidesheet', - data: { - pattern: newPattern - }, - headerComponent: HelpContextualComponent - }).afterClosed().toPromise(); + const result = await this.sidesheet + .open(ItshopPatternCreateSidesheetComponent, { + title: await this.translate.get('#LDS#Heading Create Product Bundle').toPromise(), + panelClass: 'imx-sidesheet', + disableClose: true, + padding: '0', + width: calculateSidesheetWidth(600, 0.4), + testId: 'pattern-create-sidesheet', + data: { + pattern: newPattern, + }, + headerComponent: HelpContextualComponent, + }) + .afterClosed() + .toPromise(); if (result === ItShopPatternChangedType.Saved) { - if (showSnackbar) { const snackBarMessage = '#LDS#The product bundle has been successfully created.'; this.snackBar.open({ key: snackBarMessage }); } return newPattern; } - } - else { + } else { this.messageService.subject.next({ - text: '#LDS#The sample could not be created. Please reload the page and try again.' + text: '#LDS#The sample could not be created. Please reload the page and try again.', }); - return null; + return undefined; } } public handleOpenLoader(): void { if (this.busyIndicatorCounter === 0) { - setTimeout(() => this.busyIndicator = this.busyService.show()); + this.busyService.show(); } this.busyIndicatorCounter++; } public handleCloseLoader(): void { if (this.busyIndicatorCounter === 1) { - setTimeout(() => { - this.busyService.hide(this.busyIndicator); - this.busyIndicator = undefined; - }); + this.busyService.hide(this.busyIndicator); } this.busyIndicatorCounter--; } diff --git a/imxweb/projects/qer/src/lib/itshop-pattern/itshop-pattern-item-edit/itshop-pattern-item-edit-parameter.interface.ts b/imxweb/projects/qer/src/lib/itshop-pattern/itshop-pattern-item-edit/itshop-pattern-item-edit-parameter.interface.ts index 8d754abdc..cc9d4d416 100644 --- a/imxweb/projects/qer/src/lib/itshop-pattern/itshop-pattern-item-edit/itshop-pattern-item-edit-parameter.interface.ts +++ b/imxweb/projects/qer/src/lib/itshop-pattern/itshop-pattern-item-edit/itshop-pattern-item-edit-parameter.interface.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -24,10 +24,10 @@ * */ -import { PortalShopServiceitems, ProjectConfig, QerProjectConfig } from "imx-api-qer" +import { PortalShopServiceitems, ProjectConfig, QerProjectConfig } from '@imx-modules/imx-api-qer'; export interface ItshopPatternItemEditParameter { patternItemUid: string; - serviceItem: PortalShopServiceitems; + serviceItem: PortalShopServiceitems; projectConfig: QerProjectConfig & ProjectConfig; } diff --git a/imxweb/projects/qer/src/lib/itshop-pattern/itshop-pattern-item-edit/itshop-pattern-item-edit.component.html b/imxweb/projects/qer/src/lib/itshop-pattern/itshop-pattern-item-edit/itshop-pattern-item-edit.component.html index 858d77fee..3f9631bf5 100644 --- a/imxweb/projects/qer/src/lib/itshop-pattern/itshop-pattern-item-edit/itshop-pattern-item-edit.component.html +++ b/imxweb/projects/qer/src/lib/itshop-pattern/itshop-pattern-item-edit/itshop-pattern-item-edit.component.html @@ -1,6 +1,6 @@
    - - {{ detailsInfoText | translate}} + + {{ detailsInfoText | translate }} @@ -16,18 +16,25 @@
    - + [attr.data-imx-identifier]="'citshop-pattern-item-edit-' + column.ColumnName" + >
    -
    -
    -
    @@ -39,7 +46,7 @@ -
    +

    {{ '#LDS#There are currently no request parameters specified for this product.' | translate }}

    diff --git a/imxweb/projects/qer/src/lib/itshop-pattern/itshop-pattern-item-edit/itshop-pattern-item-edit.component.scss b/imxweb/projects/qer/src/lib/itshop-pattern/itshop-pattern-item-edit/itshop-pattern-item-edit.component.scss index 0a81cdc9b..bf41727f7 100644 --- a/imxweb/projects/qer/src/lib/itshop-pattern/itshop-pattern-item-edit/itshop-pattern-item-edit.component.scss +++ b/imxweb/projects/qer/src/lib/itshop-pattern/itshop-pattern-item-edit/itshop-pattern-item-edit.component.scss @@ -1,22 +1,10 @@ -@import "@elemental-ui/core/src/styles/_palette.scss"; - -@mixin imx-flex-column-container { - display: flex; - flex-direction: column; -} +@import '@elemental-ui/core/src/styles/_palette.scss'; +@import 'base/mixins'; .eui-sidesheet-content { - @include imx-flex-column-container(); - - .mat-card { - margin-bottom: 20px; - } -} - -.imx-helper-alert { - width: 100%; + @include flex-column-container(); - ::ng-deep .eui-alert { + .mat-mdc-card { margin-bottom: 20px; } } @@ -28,7 +16,7 @@ margin-top: 20px; } -.imx-param-no-results { +.imx-no-results { text-align: center; margin: 20px 0; flex: 1 1 auto; @@ -36,14 +24,9 @@ flex-direction: column; justify-content: center; - .eui-icon { - font-size: 100px; - color: rgba($black-c, 0.55); - } - p { margin: 0; font-size: 18px; color: $black-9; } -} \ No newline at end of file +} diff --git a/imxweb/projects/qer/src/lib/itshop-pattern/itshop-pattern-item-edit/itshop-pattern-item-edit.component.spec.ts b/imxweb/projects/qer/src/lib/itshop-pattern/itshop-pattern-item-edit/itshop-pattern-item-edit.component.spec.ts index d901a76b2..299d0db4a 100644 --- a/imxweb/projects/qer/src/lib/itshop-pattern/itshop-pattern-item-edit/itshop-pattern-item-edit.component.spec.ts +++ b/imxweb/projects/qer/src/lib/itshop-pattern/itshop-pattern-item-edit/itshop-pattern-item-edit.component.spec.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -39,13 +39,13 @@ describe('ItshopPatternItemEditComponent', () => { beforeEach(() => { return MockBuilder([ItshopPatternItemEditComponent, TranslateModule.forRoot()]) - .mock(ItshopPatternService) - .mock(EuiSidesheetRef) - .beforeCompileComponents(testBed => { - testBed.configureTestingModule({ - schemas: [CUSTOM_ELEMENTS_SCHEMA] + .mock(ItshopPatternService) + .mock(EuiSidesheetRef) + .beforeCompileComponents((testBed) => { + testBed.configureTestingModule({ + schemas: [CUSTOM_ELEMENTS_SCHEMA], + }); }); - }); }); beforeEach(() => { @@ -56,7 +56,7 @@ describe('ItshopPatternItemEditComponent', () => { afterAll(() => { clearStylesFromDOM(); - }) + }); it('should create', () => { expect(component).toBeTruthy(); diff --git a/imxweb/projects/qer/src/lib/itshop-pattern/itshop-pattern-item-edit/itshop-pattern-item-edit.component.ts b/imxweb/projects/qer/src/lib/itshop-pattern/itshop-pattern-item-edit/itshop-pattern-item-edit.component.ts index ad3ca5092..478b167ea 100644 --- a/imxweb/projects/qer/src/lib/itshop-pattern/itshop-pattern-item-edit/itshop-pattern-item-edit.component.ts +++ b/imxweb/projects/qer/src/lib/itshop-pattern/itshop-pattern-item-edit/itshop-pattern-item-edit.component.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -26,10 +26,10 @@ import { Component, Inject, OnInit } from '@angular/core'; import { FormGroup } from '@angular/forms'; -import { EuiSidesheetRef, EUI_SIDESHEET_DATA } from '@elemental-ui/core'; -import { PortalItshopPatternItem } from 'imx-api-qer'; +import { EUI_SIDESHEET_DATA, EuiSidesheetRef } from '@elemental-ui/core'; +import { PortalItshopPatternItem } from '@imx-modules/imx-api-qer'; -import { DisplayColumns, IEntityColumn } from 'imx-qbm-dbts'; +import { DisplayColumns, IEntityColumn } from '@imx-modules/imx-qbm-dbts'; import { BaseReadonlyCdr, ClassloggerService, ColumnDependentReference } from 'qbm'; import { ExtendedEntityWrapper } from '../../parameter-data/extended-entity-wrapper.interface'; @@ -39,14 +39,15 @@ import { ItshopPatternItemEditParameter } from './itshop-pattern-item-edit-param @Component({ selector: 'imx-itshop-pattern-item-edit', templateUrl: './itshop-pattern-item-edit.component.html', - styleUrls: ['./itshop-pattern-item-edit.component.scss'] + styleUrls: ['./itshop-pattern-item-edit.component.scss'], }) export class ItshopPatternItemEditComponent implements OnInit { public readonly requestParamForm = new FormGroup({}); public columns: IEntityColumn[]; public cdrList: ColumnDependentReference[] = []; - public detailsInfoText = '#LDS#Here you can see the details of the product. Additionally, you can pre-fill the values of the request parameters.'; + public detailsInfoText = + '#LDS#Here you can see the details of the product. Additionally, you can pre-fill the values of the request parameters.'; public loadingParams = true; public hasParams: boolean = true; @@ -58,19 +59,19 @@ export class ItshopPatternItemEditComponent implements OnInit { private readonly sideSheetRef: EuiSidesheetRef, private readonly patternService: ItshopPatternService, private readonly logger: ClassloggerService, - ) { } + ) {} public async ngOnInit(): Promise { - const properties = this.data.projectConfig.ITShopConfig.AccProductProperties; + const properties = this.data.projectConfig.ITShopConfig?.AccProductProperties || []; this.cdrList = [ new BaseReadonlyCdr(this.data.serviceItem.GetEntity().GetColumn(DisplayColumns.DISPLAY_PROPERTYNAME)), new BaseReadonlyCdr(this.data.serviceItem.TableName.Column), new BaseReadonlyCdr(this.data.serviceItem.Tags.Column), - ...properties.map((prop: string) => new BaseReadonlyCdr(this.data.serviceItem.GetEntity().GetColumn(prop))) + ...properties.map((prop: string) => new BaseReadonlyCdr(this.data.serviceItem.GetEntity().GetColumn(prop))), ]; this.entityWrapper = await this.patternService.getInteractivePatternitem(this.data.patternItemUid); - this.columns = this.entityWrapper.parameterCategoryColumns.map(item => item.column); + this.columns = this.entityWrapper.parameterCategoryColumns.map((item) => item.column); this.hasParams = this.entityWrapper.parameterCategoryColumns?.length > 0; this.loadingParams = false; } @@ -83,6 +84,6 @@ export class ItshopPatternItemEditComponent implements OnInit { } finally { this.patternService.handleCloseLoader(); } - this.sideSheetRef.close(true) + this.sideSheetRef.close(true); } } diff --git a/imxweb/projects/qer/src/lib/itshop-pattern/itshop-pattern-sidesheet/itshop-pattern-sidesheet.component.html b/imxweb/projects/qer/src/lib/itshop-pattern/itshop-pattern-sidesheet/itshop-pattern-sidesheet.component.html index cf465f7f8..93197272e 100644 --- a/imxweb/projects/qer/src/lib/itshop-pattern/itshop-pattern-sidesheet/itshop-pattern-sidesheet.component.html +++ b/imxweb/projects/qer/src/lib/itshop-pattern/itshop-pattern-sidesheet/itshop-pattern-sidesheet.component.html @@ -1,86 +1,120 @@ -
    - - - -
    - - {{ (data.canEditAndDelete ? editableDetailsInfoText : detailsInfoText) | translate}} - - - - {{ '#LDS#Private product bundle' | translate}} - - - {{'#LDS#Public product bundle' | translate}} - - - - -
    -
    -
    - - -
    - - {{ (data.canEditAndDelete ? editableProductsInfoText : productsInfoText) | translate}} - - -
    - - - - - - - - -
    -
    -
    -
    -
    -
    -
    + + + +
    + + {{ (data.canEditAndDelete ? editableDetailsInfoText : detailsInfoText) | translate }} + + + + {{ '#LDS#Private product bundle' | translate }} + + + {{ '#LDS#Public product bundle' | translate }} + + + +
    +
    +
    + + +
    + + {{ (data.canEditAndDelete ? editableProductsInfoText : productsInfoText) | translate }} + + +
    + + + + + + + +
    +
    +
    +
    +
    +
    - - - -
    -
    - -
    diff --git a/imxweb/projects/qer/src/lib/itshop-pattern/itshop-pattern-sidesheet/itshop-pattern-sidesheet.component.scss b/imxweb/projects/qer/src/lib/itshop-pattern/itshop-pattern-sidesheet/itshop-pattern-sidesheet.component.scss index 6c6f3f27c..9f6c8f5ad 100644 --- a/imxweb/projects/qer/src/lib/itshop-pattern/itshop-pattern-sidesheet/itshop-pattern-sidesheet.component.scss +++ b/imxweb/projects/qer/src/lib/itshop-pattern/itshop-pattern-sidesheet/itshop-pattern-sidesheet.component.scss @@ -1,106 +1,13 @@ @import '@elemental-ui/core/src/styles/_eui_palette.scss'; - -@mixin imx-flex-column-container { - display: flex; - flex-direction: column; -} - -.eui-sidesheet-content { - @include imx-flex-column-container(); - padding: 0; -} - -:host { - ::ng-deep .mat-tab-body-content { - display: flex; - } - - .eui-badge ::ng-deep .eui-badge-content { - font-size: 12px; - line-height: 12px; - margin-bottom: 20px; - } - - .imx-helper-alert { - width: 100%; - - ::ng-deep .eui-alert { - margin-bottom: 20px; - } - } - - .eui-sidesheet-actions { - .justify-start { - margin-right: auto; - } - - .mat-stroked-button eui-icon { - font-size: 14px; - margin-right: 4px; - } - - button:not(:last-of-type):not(.justify-start) { - margin-right: 10px; - } - } - - ::ng-deep .mat-tab-body-wrapper { - flex: 1 1 auto; - - .mat-tab-body { - display: flex; - flex-direction: column; - flex: 1 1 auto; - } - } - - ::ng-deep .mat-tab-body-content { - display: flex; - flex-direction: column; - } - - ::ng-deep .mat-tab-group { - flex-grow: 1; - overflow: auto; - } -} - -.imx-tab-content { - flex: 1; - padding: 32px; - overflow: auto; - @include imx-flex-column-container(); - - .mat-card { - @include imx-flex-column-container(); - overflow: hidden; - - .imx-table-container { - overflow: auto; - @include imx-flex-column-container(); - } - } -} - -// Theming -:host { - ::ng-deep .mat-tab-group .mat-tab-header { - background-color: $color-gray-0; - } -} +@import 'base/mixins'; .eui-dark-theme { :host { background-color: $color-gray-80; color: $color-gray-0; - .eui-sidesheet-actions.mat-card.eui-sidesheet-actions--white{ + .eui-sidesheet-actions.mat-mdc-card.eui-sidesheet-actions--white { background-color: $color-gray-70; } - ::ng-deep .mat-tab-group { - .mat-tab-header { - background-color: $color-gray-80; - } - } } } @@ -108,14 +15,8 @@ :host { background-color: $color-gray-100; color: $color-gray-0; - .eui-sidesheet-actions.mat-card.eui-sidesheet-actions--white{ + .eui-sidesheet-actions.mat-mdc-card.eui-sidesheet-actions--white { background-color: $color-gray-90; } - ::ng-deep .mat-tab-group { - .mat-tab-header { - background-color: $color-gray-100; - } - } } } - diff --git a/imxweb/projects/qer/src/lib/itshop-pattern/itshop-pattern-sidesheet/itshop-pattern-sidesheet.component.spec.ts b/imxweb/projects/qer/src/lib/itshop-pattern/itshop-pattern-sidesheet/itshop-pattern-sidesheet.component.spec.ts index f8e54903b..c4360a0e2 100644 --- a/imxweb/projects/qer/src/lib/itshop-pattern/itshop-pattern-sidesheet/itshop-pattern-sidesheet.component.spec.ts +++ b/imxweb/projects/qer/src/lib/itshop-pattern/itshop-pattern-sidesheet/itshop-pattern-sidesheet.component.spec.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -24,7 +24,7 @@ * */ -import { FormsModule, ReactiveFormsModule } from '@angular/forms'; +import { FormArray, FormsModule, ReactiveFormsModule, UntypedFormArray, UntypedFormBuilder } from '@angular/forms'; import { EuiSidesheetRef, EUI_SIDESHEET_DATA } from '@elemental-ui/core'; import { TranslateModule } from '@ngx-translate/core'; import { of } from 'rxjs'; @@ -64,7 +64,7 @@ describe('ItshopPatternSidesheetComponent', () => { }; const patterServiceStub = { - togglePublic: jasmine.createSpy('makePublic').and.returnValue({}), + togglePublic: jasmine.createSpy('togglePublic').and.returnValue({}), createCopy: jasmine.createSpy('createCopy').and.returnValue({}), handleOpenLoader: jasmine.createSpy('handleOpenLoader').and.callThrough(), handleCloseLoader: jasmine.createSpy('handleCloseLoader').and.callThrough(), @@ -72,13 +72,17 @@ describe('ItshopPatternSidesheetComponent', () => { delete: jasmine.createSpy('delete').and.callThrough(), getPatternItems: jasmine.createSpy('getPatternItems').and.callThrough(), }; + const formBuilder = { + array: jasmine.createSpy('togglePublic').and.returnValue(new FormArray([])), + }; beforeEach(() => { - return MockBuilder([ItshopPatternSidesheetComponent, TranslateModule.forRoot(),FormsModule,ReactiveFormsModule]) + return MockBuilder([ItshopPatternSidesheetComponent, TranslateModule.forRoot(), FormsModule, ReactiveFormsModule]) .mock(ItshopPatternModule, { exportAll: true }) .mock(ItshopPatternService, patterServiceStub) .mock(EuiSidesheetRef, mockSidesheetRef) - .mock(EUI_SIDESHEET_DATA, sidesheetData ); + .mock(EUI_SIDESHEET_DATA, sidesheetData) + .mock(UntypedFormBuilder, formBuilder); }); beforeEach(() => { diff --git a/imxweb/projects/qer/src/lib/itshop-pattern/itshop-pattern-sidesheet/itshop-pattern-sidesheet.component.ts b/imxweb/projects/qer/src/lib/itshop-pattern/itshop-pattern-sidesheet/itshop-pattern-sidesheet.component.ts index 531a4c81c..61ee7ed43 100644 --- a/imxweb/projects/qer/src/lib/itshop-pattern/itshop-pattern-sidesheet/itshop-pattern-sidesheet.component.ts +++ b/imxweb/projects/qer/src/lib/itshop-pattern/itshop-pattern-sidesheet/itshop-pattern-sidesheet.component.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -27,17 +27,24 @@ import { Component, Inject, OnDestroy, OnInit, ViewChild } from '@angular/core'; import { UntypedFormArray, UntypedFormBuilder, UntypedFormGroup } from '@angular/forms'; import { MatTabChangeEvent } from '@angular/material/tabs'; -import { EuiSidesheetRef, EuiSidesheetService, EUI_SIDESHEET_DATA } from '@elemental-ui/core'; +import { EUI_SIDESHEET_DATA, EuiSidesheetRef, EuiSidesheetService } from '@elemental-ui/core'; import { TranslateService } from '@ngx-translate/core'; import { Subscription } from 'rxjs'; -import { PortalItshopPatternItem, PortalItshopPatternPrivate, PortalShopServiceitems, ProjectConfig, QerProjectConfig } from 'imx-api-qer'; -import { CollectionLoadParameters, CompareOperator, DisplayColumns, FilterType, TypedEntity } from 'imx-qbm-dbts'; +import { + PortalItshopPatternItem, + PortalItshopPatternPrivate, + PortalShopServiceitems, + ProjectConfig, + QerProjectConfig, +} from '@imx-modules/imx-api-qer'; +import { CollectionLoadParameters, CompareOperator, DisplayColumns, FilterType, TypedEntity } from '@imx-modules/imx-qbm-dbts'; import { BaseCdr, - BusyService, BaseReadonlyCdr, + BusyService, + calculateSidesheetWidth, ClassloggerService, ColumnDependentReference, ConfirmationService, @@ -46,20 +53,19 @@ import { DataTableComponent, SnackBarService, } from 'qbm'; -import { ItshopPatternService } from '../itshop-pattern.service'; -import { ItShopPatternChangedType } from '../itshop-pattern-changed.enum'; +import { ProjectConfigurationService } from '../../project-configuration/project-configuration.service'; +import { ServiceItemsService } from '../../service-items/service-items.service'; import { ItshopPatternAddProductsComponent } from '../itshop-pattern-add-products/itshop-pattern-add-products.component'; +import { ItShopPatternChangedType } from '../itshop-pattern-changed.enum'; import { ItshopPatternItemEditComponent } from '../itshop-pattern-item-edit/itshop-pattern-item-edit.component'; -import { ServiceItemsService } from '../../service-items/service-items.service'; -import { ProjectConfigurationService } from '../../project-configuration/project-configuration.service'; +import { ItshopPatternService } from '../itshop-pattern.service'; @Component({ selector: 'imx-itshop-pattern-sidesheet', templateUrl: './itshop-pattern-sidesheet.component.html', - styleUrls: ['./itshop-pattern-sidesheet.component.scss'] + styleUrls: ['./itshop-pattern-sidesheet.component.scss'], }) export class ItshopPatternSidesheetComponent implements OnInit, OnDestroy { - public get formArray(): UntypedFormArray { return this.detailsFormGroup.get('formArray') as UntypedFormArray; } @@ -69,7 +75,7 @@ export class ItshopPatternSidesheetComponent implements OnInit, OnDestroy { public busyService = new BusyService(); public dstWrapper: DataSourceWrapper; - public dstSettings: DataSourceToolbarSettings; + public dstSettings: DataSourceToolbarSettings | undefined; public selectedPatternItems: PortalItshopPatternItem[] = []; public adminMode: boolean; public selectedTabIndex = 0; @@ -78,8 +84,8 @@ export class ItshopPatternSidesheetComponent implements OnInit, OnDestroy { public editableDetailsInfoText = '#LDS#Here you can edit the details of this product bundle.'; public productsInfoText = '#LDS#Here you can get an overview of all products assigned to this product bundle.'; - public editableProductsInfoText = '#LDS#Here you can get an overview of all products assigned to this product bundle. Additionally, you can add and remove products.'; - + public editableProductsInfoText = + '#LDS#Here you can get an overview of all products assigned to this product bundle. Additionally, you can add and remove products.'; @ViewChild(DataTableComponent) public table: DataTableComponent; @@ -88,11 +94,12 @@ export class ItshopPatternSidesheetComponent implements OnInit, OnDestroy { constructor( formBuilder: UntypedFormBuilder, - @Inject(EUI_SIDESHEET_DATA) public data: { - pattern: PortalItshopPatternPrivate - isMyPattern: boolean, - adminMode: boolean, - canEditAndDelete: boolean + @Inject(EUI_SIDESHEET_DATA) + public data: { + pattern: PortalItshopPatternPrivate; + isMyPattern: boolean; + adminMode: boolean; + canEditAndDelete: boolean; }, private readonly translate: TranslateService, private readonly patternService: ItshopPatternService, @@ -102,15 +109,14 @@ export class ItshopPatternSidesheetComponent implements OnInit, OnDestroy { private readonly sideSheetRef: EuiSidesheetRef, private readonly snackBar: SnackBarService, private readonly logger: ClassloggerService, - private confirmation: ConfirmationService + private confirmation: ConfirmationService, ) { this.detailsFormGroup = new UntypedFormGroup({ formArray: formBuilder.array([]) }); this.closeSubscription = this.sideSheetRef.closeClicked().subscribe(async () => { - if (!this.detailsFormGroup.dirty - || await confirmation.confirmLeaveWithUnsavedChanges()) { - this.data.pattern.GetEntity().DiscardChanges(); - this.sideSheetRef.close(); + if (!this.detailsFormGroup.dirty || (await confirmation.confirmLeaveWithUnsavedChanges())) { + this.data.pattern.GetEntity().DiscardChanges(); + this.sideSheetRef.close(); } }); } @@ -144,7 +150,7 @@ export class ItshopPatternSidesheetComponent implements OnInit, OnDestroy { const parameters = { ...parameter, - ...filteredState + ...filteredState, }; this.dstSettings = await this.dstWrapper.getDstSettings(parameters); } finally { @@ -161,9 +167,9 @@ export class ItshopPatternSidesheetComponent implements OnInit, OnDestroy { } } - public onSelectionChanged(items: PortalItshopPatternItem[]): void { + public onSelectionChanged(items: TypedEntity[]): void { this.logger.trace(this, 'selection changed', items); - this.selectedPatternItems = items; + this.selectedPatternItems = items as PortalItshopPatternItem[]; } public async togglePublic(): Promise { @@ -172,10 +178,12 @@ export class ItshopPatternSidesheetComponent implements OnInit, OnDestroy { } public async delete(): Promise { - if (await this.confirmation.confirm({ - Title: '#LDS#Heading Delete Product Bundle', - Message: '#LDS#Are you sure you want to delete the product bundle?' - })) { + if ( + await this.confirmation.confirm({ + Title: '#LDS#Heading Delete Product Bundle', + Message: '#LDS#Are you sure you want to delete the product bundle?', + }) + ) { if (await this.patternService.delete([this.data.pattern])) { this.sideSheetRef.close(ItShopPatternChangedType.Deleted); } @@ -190,18 +198,20 @@ export class ItshopPatternSidesheetComponent implements OnInit, OnDestroy { } public async addProducts(): Promise { - - const result = await this.sidesheet.open(ItshopPatternAddProductsComponent, { - title: await this.translate.get('#LDS#Heading Add Products To Product Bundle').toPromise(), - subTitle: this.data.pattern.Ident_ShoppingCartPattern.value, - panelClass: 'imx-sidesheet', - padding: '0', - width: 'max(768px, 70%)', - testId: 'pattern-add-products-sidesheet', - data: { - shoppingCartPatternUid: this.shoppingCartPatternUid - } - }).afterClosed().toPromise(); + const result = await this.sidesheet + .open(ItshopPatternAddProductsComponent, { + title: await this.translate.get('#LDS#Heading Add Products To Product Bundle').toPromise(), + subTitle: this.data.pattern.Ident_ShoppingCartPattern.value, + panelClass: 'imx-sidesheet', + padding: '0', + width: calculateSidesheetWidth(1000), + testId: 'pattern-add-products-sidesheet', + data: { + shoppingCartPatternUid: this.shoppingCartPatternUid, + }, + }) + .afterClosed() + .toPromise(); if (result) { const snackBarMessage = '#LDS#The selected products have been successfully added to the product bundle.'; @@ -211,8 +221,7 @@ export class ItshopPatternSidesheetComponent implements OnInit, OnDestroy { } public selectedItemsCanBeDeleted(): boolean { - return this.selectedPatternItems != null - && this.selectedPatternItems.length > 0; + return this.selectedPatternItems != null && this.selectedPatternItems.length > 0; } public async createPrivateCopy(): Promise { @@ -234,14 +243,13 @@ export class ItshopPatternSidesheetComponent implements OnInit, OnDestroy { } } - public async onHighlightedEntityChanged(selectedItem: PortalItshopPatternItem): Promise { - await this.editPatternItem(selectedItem); + public async onHighlightedEntityChanged(selectedItem: TypedEntity): Promise { + await this.editPatternItem(selectedItem as PortalItshopPatternItem); } public async editPatternItem(selectedItem: PortalItshopPatternItem): Promise { - let projectConfig: QerProjectConfig & ProjectConfig; - let serviceItem: PortalShopServiceitems; + let serviceItem: PortalShopServiceitems | undefined; this.patternService.handleOpenLoader(); try { @@ -251,35 +259,32 @@ export class ItshopPatternSidesheetComponent implements OnInit, OnDestroy { this.patternService.handleCloseLoader(); } - this.sidesheet.open(ItshopPatternItemEditComponent, - { - title: await this.translate.get('#LDS#Heading View Product Details').toPromise(), - subTitle: selectedItem.GetEntity().GetDisplay(), - padding: '0px', - width: '600px', - testId: 'itshop-pattern-item-edit-sidesheet', - data: { - patternItemUid: selectedItem.GetEntity().GetKeys().join(''), - serviceItem, - projectConfig - } - } - ); + this.sidesheet.open(ItshopPatternItemEditComponent, { + title: await this.translate.get('#LDS#Heading View Product Details').toPromise(), + subTitle: selectedItem.GetEntity().GetDisplay(), + padding: '0px', + width: calculateSidesheetWidth(600, 0.4), + testId: 'itshop-pattern-item-edit-sidesheet', + data: { + patternItemUid: selectedItem.GetEntity().GetKeys().join(''), + serviceItem, + projectConfig, + }, + }); } private async setupDetailsTab(): Promise { - if (this.data.canEditAndDelete) { this.cdrList = [ new BaseCdr(this.data.pattern.Ident_ShoppingCartPattern.Column), new BaseCdr(this.data.pattern.Description.Column), - new BaseCdr(this.data.pattern.UID_Person.Column) + new BaseCdr(this.data.pattern.UID_Person.Column), ]; } else { this.cdrList = [ new BaseReadonlyCdr(this.data.pattern.Ident_ShoppingCartPattern.Column), new BaseReadonlyCdr(this.data.pattern.Description.Column), - new BaseReadonlyCdr(this.data.pattern.UID_Person.Column) + new BaseReadonlyCdr(this.data.pattern.UID_Person.Column), ]; } } @@ -287,11 +292,9 @@ export class ItshopPatternSidesheetComponent implements OnInit, OnDestroy { private setupProductsTab(): void { const entitySchema = this.patternService.itshopPatternItemSchema; this.dstWrapper = new DataSourceWrapper( - state => this.patternService.getPatternItems(state), - [ - entitySchema.Columns[DisplayColumns.DISPLAY_PROPERTYNAME] - ], - entitySchema + (state) => this.patternService.getPatternItems(state), + [entitySchema.Columns[DisplayColumns.DISPLAY_PROPERTYNAME]], + entitySchema, ); } } diff --git a/imxweb/projects/qer/src/lib/itshop-pattern/itshop-pattern.component.html b/imxweb/projects/qer/src/lib/itshop-pattern/itshop-pattern.component.html index 1b3cd3bfc..d3820aa40 100644 --- a/imxweb/projects/qer/src/lib/itshop-pattern/itshop-pattern.component.html +++ b/imxweb/projects/qer/src/lib/itshop-pattern/itshop-pattern.component.html @@ -1,56 +1,63 @@
    -
    -

    +
    +

    {{ '#LDS#Heading Product Bundles' | translate }} -

    +

    +
    - -
    - - - - - -
    {{ item.Ident_ShoppingCartPattern.Column.GetDisplayValue() }}
    -
    - {{ item.Description.Column.GetDisplayValue() }} -
    -
    -
    - - - -
    - -
    + + + + + {{ entitySchema?.Columns?.[DisplayColumns.DISPLAY_PROPERTYNAME]?.Display }} + + +
    {{ item.Ident_ShoppingCartPattern.Column.GetDisplayValue() }}
    +
    + {{ item.Description.Column.GetDisplayValue() }} +
    + +
    + + + + {{ entitySchema?.Columns?.UID_Person?.Display }} + + + + + {{ item.UID_Person.Column.GetDisplayValue() }} + + + + + + + {{ entitySchema?.Columns?.IsPublicPattern?.Display }} + + + + + {{ item.IsPublicPattern.Column.GetDisplayValue() }} + + + +
    +
    -
    - -
    - -
    diff --git a/imxweb/projects/qer/src/lib/itshop-pattern/itshop-pattern.component.scss b/imxweb/projects/qer/src/lib/itshop-pattern/itshop-pattern.component.scss index 8fdc7838c..bfcf0660a 100644 --- a/imxweb/projects/qer/src/lib/itshop-pattern/itshop-pattern.component.scss +++ b/imxweb/projects/qer/src/lib/itshop-pattern/itshop-pattern.component.scss @@ -1,68 +1,24 @@ -@import '../../../../../shared/scss/common-table.scss'; -@mixin imx-flex-column-container { - display: flex; - flex-direction: column; -} - -@mixin imx-flex-row-container { - display: flex; - flex-direction: row; -} - -.eui-sidesheet-content { - @include imx-flex-column-container(); -} +@import 'base/mixins'; .heading-wrapper { - @include imx-flex-row-container(); + @include flex-row-container(); flex: 0 0 auto; - - .helper-alert { - display: flex; - margin-bottom: 15px; - } } :host { - @include imx-flex-column-container(); - overflow: hidden; - height: 100%; - max-width: 100%; + @include flex-column-container($overflow: hidden, $height: 100%, $max-width: 100%); } .imx-pattern-page { background-color: inherit; - @include imx-flex-fill-control-hidden-overflow(); + @include flex-column-container-fill(); - .mat-card { - @include imx-flex-fill-control-hidden-overflow(); - } - - div.imx-table-container { - @include imx-flex-column-container(); - overflow: hidden; - height: inherit; - - .imx-patterns-table { - flex-grow: 1; - overflow: auto; - } - } - - .imx-button-bar { - @include imx-button-bar(); - } } @media screen and (max-width: 768px) { .imx-pattern-page { .heading-wrapper { display: block; - - .alert-wrapper { - margin: 0 0 20px 0; - width: 100%; - } } } } diff --git a/imxweb/projects/qer/src/lib/itshop-pattern/itshop-pattern.component.ts b/imxweb/projects/qer/src/lib/itshop-pattern/itshop-pattern.component.ts index a10f0d3e5..d196132d1 100644 --- a/imxweb/projects/qer/src/lib/itshop-pattern/itshop-pattern.component.ts +++ b/imxweb/projects/qer/src/lib/itshop-pattern/itshop-pattern.component.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -24,30 +24,31 @@ * */ -import { Component, OnDestroy, OnInit, ViewChild } from '@angular/core'; +import { Component, OnDestroy, OnInit } from '@angular/core'; import { EuiSidesheetService } from '@elemental-ui/core'; import { TranslateService } from '@ngx-translate/core'; import { Subscription } from 'rxjs'; -import { PortalItshopPatternAdmin, PortalItshopPatternPrivate } from 'imx-api-qer'; -import { CollectionLoadParameters, DisplayColumns, TypedEntity } from 'imx-qbm-dbts'; +import { PortalItshopPatternAdmin, PortalItshopPatternPrivate } from '@imx-modules/imx-api-qer'; +import { CollectionLoadParameters, DisplayColumns, EntitySchema, TypedEntity, TypedEntityCollectionData } from '@imx-modules/imx-qbm-dbts'; import { AuthenticationService, ClassloggerService, ConfirmationService, - DataSourceToolbarSettings, - DataSourceWrapper, - DataTableComponent, + DataViewInitParameters, + DataViewSource, HELP_CONTEXTUAL, HelpContextualValues, + ISessionState, SnackBarService, + calculateSidesheetWidth, } from 'qbm'; import { QerPermissionsService } from '../admin/qer-permissions.service'; +import { ItShopPatternChangedType } from './itshop-pattern-changed.enum'; +import { ItshopPatternCreateService } from './itshop-pattern-create-sidesheet/itshop-pattern-create.service'; import { ItshopPatternSidesheetComponent } from './itshop-pattern-sidesheet/itshop-pattern-sidesheet.component'; import { ItshopPatternService } from './itshop-pattern.service'; -import { ItshopPatternCreateService } from './itshop-pattern-create-sidesheet/itshop-pattern-create.service'; -import { ItShopPatternChangedType } from './itshop-pattern-changed.enum'; /** * Component that shows a list of all product bundles (internal names are itshop pattern and request templates) of the current user @@ -56,33 +57,26 @@ import { ItShopPatternChangedType } from './itshop-pattern-changed.enum'; @Component({ selector: 'imx-itshop-pattern', templateUrl: './itshop-pattern.component.html', - styleUrls: ['./itshop-pattern.component.scss'] + styleUrls: ['./itshop-pattern.component.scss'], + providers: [DataViewSource], }) export class ItshopPatternComponent implements OnInit, OnDestroy { - - /** - * the wrapper component for the {@link DataSourceToolbar|dataSourceToolbar}. - */ - public dstWrapper: DataSourceWrapper; - - public dstSettings: DataSourceToolbarSettings; - /** * The list of all selected product bundles. */ - public selectedPatterns: PortalItshopPatternAdmin[] = []; + public selectedPatterns: (PortalItshopPatternPrivate | PortalItshopPatternAdmin)[] = []; /** * Indicates wether the component should be shown for shop admins or not. */ public adminMode: boolean; - @ViewChild(DataTableComponent) public table: DataTableComponent; - public readonly status = { - enabled: (pattern: PortalItshopPatternAdmin): boolean => this.canBeEditedAndDeleted(pattern) + enabled: (pattern: PortalItshopPatternAdmin): boolean => this.canBeEditedAndDeleted(pattern), }; public helpContextId: HelpContextualValues; + public entitySchema: EntitySchema; + public readonly DisplayColumns = DisplayColumns; private readonly subscriptions: Subscription[] = []; private currentUserUid: string; @@ -96,12 +90,11 @@ export class ItshopPatternComponent implements OnInit, OnDestroy { private readonly translate: TranslateService, private readonly logger: ClassloggerService, private readonly confirmationService: ConfirmationService, - authentication: AuthenticationService + authentication: AuthenticationService, + public dataSource: DataViewSource, ) { this.subscriptions.push( - authentication.onSessionResponse.subscribe((sessionState) => - this.currentUserUid = sessionState.UserUid - ) + authentication.onSessionResponse.subscribe((sessionState: ISessionState) => (this.currentUserUid = sessionState.UserUid || '')), ); } @@ -110,24 +103,9 @@ export class ItshopPatternComponent implements OnInit, OnDestroy { try { this.adminMode = await this.qerPermissionService.isShopAdmin(); - this.helpContextId = this.adminMode ? HELP_CONTEXTUAL.RequestTemplates: HELP_CONTEXTUAL.RequestTemplatesUser; + this.helpContextId = this.adminMode ? HELP_CONTEXTUAL.RequestTemplates : HELP_CONTEXTUAL.RequestTemplatesUser; - const entitySchema = this.adminMode - ? this.patternService.itshopPatternAdminSchema - : this.patternService.itshopPatternPrivateSchema; - this.dstWrapper = new DataSourceWrapper( - state => this.adminMode - ? this.patternService.getPublicPatterns(state) - : this.patternService.getPrivatePatterns(state), - [ - entitySchema.Columns[DisplayColumns.DISPLAY_PROPERTYNAME], - entitySchema.Columns.UID_Person, - entitySchema.Columns.IsPublicPattern, - ], - entitySchema, - undefined, - 'itshop-pattern' - ); + this.entitySchema = this.adminMode ? this.patternService.itshopPatternAdminSchema : this.patternService.itshopPatternPrivateSchema; } finally { this.patternService.handleCloseLoader(); } @@ -135,84 +113,96 @@ export class ItshopPatternComponent implements OnInit, OnDestroy { } public ngOnDestroy(): void { - this.subscriptions.forEach(s => s.unsubscribe()); + this.subscriptions.forEach((s) => s.unsubscribe()); } - public isMyPattern(pattern: PortalItshopPatternPrivate | PortalItshopPatternAdmin): boolean { + public isMyPattern(entity: TypedEntity): boolean { + const pattern = entity as PortalItshopPatternPrivate | PortalItshopPatternAdmin; return this.currentUserUid === pattern.UID_Person.value; } - public canBeEditedAndDeleted(pattern: PortalItshopPatternPrivate | PortalItshopPatternAdmin): boolean { + public canBeEditedAndDeleted(pattern: TypedEntity): boolean { return this.isMyPattern(pattern) || this.adminMode; } public async delete(selectedPattern?: PortalItshopPatternPrivate | PortalItshopPatternAdmin): Promise { - if (await this.confirmationService.confirm({ - Title: '#LDS#Heading Delete Product Bundles', - Message: '#LDS#Are you sure you want to delete the selected product bundles?' - })) { + if ( + await this.confirmationService.confirm({ + Title: '#LDS#Heading Delete Product Bundles', + Message: '#LDS#Are you sure you want to delete the selected product bundles?', + }) + ) { await this.patternService.delete(selectedPattern ? [selectedPattern] : this.selectedPatterns, this.adminMode); - this.getData(); - this.table.clearSelection(); + this.dataSource.selection.clear(); + this.dataSource.updateState(); } } - public async publish(selectedPatterns: PortalItshopPatternPrivate[] | PortalItshopPatternAdmin[]): Promise { + public async publish(selectedPatterns: TypedEntity[]): Promise { await this.patternService.makePublic(selectedPatterns, true); - this.getData(); - this.table.clearSelection(); + this.dataSource.selection.clear(); + this.dataSource.updateState(); } - public async unpublish(selectedPatterns: PortalItshopPatternPrivate[] | PortalItshopPatternAdmin[]): Promise { + public async unpublish(selectedPatterns: TypedEntity[]): Promise { await this.patternService.makePublic(selectedPatterns, false); - this.getData(); - this.table.clearSelection(); + this.dataSource.selection.clear(); + this.dataSource.updateState(); } public async createNewPattern(): Promise { if (await this.patternCreateService.createNewPattern(true)) { - this.getData(); + this.dataSource.updateState(); } } - public async getData(parameter?: CollectionLoadParameters): Promise { - this.patternService.handleOpenLoader(); - try { - const parameters = { - ...parameter, - ...{ OrderBy: 'Ident_ShoppingCartPattern asc' } - }; - this.dstSettings = await this.dstWrapper.getDstSettings(parameters); - } finally { - this.patternService.handleCloseLoader(); - } + public async getData(): Promise { + this.dataSource.itemStatus = this.status; + const dataViewInitParameters: DataViewInitParameters = { + execute: this.adminMode + ? (params: CollectionLoadParameters, signal: AbortSignal): Promise> => + this.patternService.getPublicPatterns(params, signal) + : (params: CollectionLoadParameters, signal: AbortSignal): Promise> => + this.patternService.getPrivatePatterns(params, signal), + schema: this.entitySchema, + columnsToDisplay: [ + this.entitySchema.Columns[DisplayColumns.DISPLAY_PROPERTYNAME], + this.entitySchema.Columns.UID_Person, + this.entitySchema.Columns.IsPublicPattern, + ], + highlightEntity: (entity: PortalItshopPatternPrivate | PortalItshopPatternAdmin) => { + this.viewDetails(entity); + }, + selectionChange: (selection: (PortalItshopPatternPrivate | PortalItshopPatternAdmin)[]) => { + this.logger.trace(this, 'selection changed', selection); + this.selectedPatterns = selection; + }, + }; + this.dataSource.init(dataViewInitParameters); } public selectedItemsCanBePublished(): boolean { - return this.selectedPatterns != null - && this.selectedPatterns.length > 0 - && this.selectedPatterns.every(item => this.isMyPattern(item) && !item.IsPublicPattern.value); + return ( + this.selectedPatterns != null && + this.selectedPatterns.length > 0 && + this.selectedPatterns.every((item: PortalItshopPatternAdmin) => this.isMyPattern(item) && !item.IsPublicPattern.value) + ); } public selectedItemsCanBeUnpublished(): boolean { - return this.selectedPatterns != null - && this.selectedPatterns.length > 0 - && this.selectedPatterns.every(item => this.isMyPattern(item) && item.IsPublicPattern.value); + return ( + this.selectedPatterns != null && + this.selectedPatterns.length > 0 && + this.selectedPatterns.every((item: PortalItshopPatternAdmin) => this.isMyPattern(item) && item.IsPublicPattern.value) + ); } public selectedItemsCanBeDeleted(): boolean { - return this.selectedPatterns != null - && this.selectedPatterns.length > 0 - && this.selectedPatterns.every(item => this.canBeEditedAndDeleted(item)); - } - - public onSelectionChanged(items: PortalItshopPatternAdmin[]): void { - this.logger.trace(this, 'selection changed', items); - this.selectedPatterns = items; - } - - public async onHighlightedEntityChanged(selectedPattern: PortalItshopPatternPrivate | PortalItshopPatternAdmin): Promise { - await this.viewDetails(selectedPattern); + return ( + this.selectedPatterns != null && + this.selectedPatterns.length > 0 && + this.selectedPatterns.every((item) => this.canBeEditedAndDeleted(item)) + ); } private async viewDetails(selectedPattern: PortalItshopPatternPrivate | PortalItshopPatternAdmin): Promise { @@ -224,25 +214,28 @@ export class ItshopPatternComponent implements OnInit, OnDestroy { (pattern) => pattern.GetEntity().GetKeys()[0] === selectedPattern.GetEntity().GetKeys()[0], ); - const title = await this.translate.get(canEditAndDelete - ? '#LDS#Heading Edit Product Bundle' - : '#LDS#Heading View Product Bundle Details').toPromise(); - - const result = await this.sidesheet.open(ItshopPatternSidesheetComponent, { - title, - subTitle: pattern.Ident_ShoppingCartPattern.value, - panelClass: 'imx-sidesheet', - disableClose: true, - padding: '0', - width: '600px', - testId: 'pattern-details-sidesheet', - data: { - pattern, - isMyPattern, - adminMode: this.adminMode, - canEditAndDelete - } - }).afterClosed().toPromise(); + const title = await this.translate + .get(canEditAndDelete ? '#LDS#Heading Edit Product Bundle' : '#LDS#Heading View Product Bundle Details') + .toPromise(); + + const result = await this.sidesheet + .open(ItshopPatternSidesheetComponent, { + title, + subTitle: pattern?.Ident_ShoppingCartPattern.value, + panelClass: 'imx-sidesheet', + disableClose: true, + padding: '0', + width: calculateSidesheetWidth(), + testId: 'pattern-details-sidesheet', + data: { + pattern, + isMyPattern, + adminMode: this.adminMode, + canEditAndDelete, + }, + }) + .afterClosed() + .toPromise(); if (result === ItShopPatternChangedType.Saved) { const snackBarMessage = '#LDS#The product bundle has been successfully saved.'; @@ -251,6 +244,5 @@ export class ItshopPatternComponent implements OnInit, OnDestroy { } else if (result) { this.getData(); } - } } diff --git a/imxweb/projects/qer/src/lib/itshop-pattern/itshop-pattern.module.ts b/imxweb/projects/qer/src/lib/itshop-pattern/itshop-pattern.module.ts index 1e6fc1785..650c8bf0f 100644 --- a/imxweb/projects/qer/src/lib/itshop-pattern/itshop-pattern.module.ts +++ b/imxweb/projects/qer/src/lib/itshop-pattern/itshop-pattern.module.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -31,31 +31,32 @@ import { RouterModule, Routes } from '@angular/router'; import { EuiCoreModule, EuiMaterialModule } from '@elemental-ui/core'; import { TranslateModule } from '@ngx-translate/core'; -import { ProjectConfig } from 'imx-api-qbm'; -import { QerProjectConfig } from 'imx-api-qer'; +import { ProjectConfig } from '@imx-modules/imx-api-qbm'; +import { QerProjectConfig } from '@imx-modules/imx-api-qer'; import { CdrModule, ClassloggerService, DataSourceToolbarModule, DataTableModule, + DataViewModule, HELP_CONTEXTUAL, HelpContextualModule, MenuItem, MenuService, RouteGuardService, SelectedElementsModule, - UserMessageModule + UserMessageModule, } from 'qbm'; -import { ItshopPatternComponent } from './itshop-pattern.component'; -import { ItshopPatternSidesheetComponent } from './itshop-pattern-sidesheet/itshop-pattern-sidesheet.component'; -import { ItshopPatternCreateSidesheetComponent } from './itshop-pattern-create-sidesheet/itshop-pattern-create-sidesheet.component'; -import { ItshopPatternAddProductsComponent } from './itshop-pattern-add-products/itshop-pattern-add-products.component'; +import { ItshopPatternGuardService } from '../guards/itshop-pattern-guard.service'; import { ServiceItemsModule } from '../service-items/service-items.module'; -import { DuplicatePatternItemsComponent } from './duplicate-pattern-items/duplicate-pattern-items.component'; import { UserModule } from '../user/user.module'; -import { ItshopPatternGuardService } from '../guards/itshop-pattern-guard.service'; +import { DuplicatePatternItemsComponent } from './duplicate-pattern-items/duplicate-pattern-items.component'; +import { ItshopPatternAddProductsComponent } from './itshop-pattern-add-products/itshop-pattern-add-products.component'; +import { ItshopPatternCreateSidesheetComponent } from './itshop-pattern-create-sidesheet/itshop-pattern-create-sidesheet.component'; import { ItshopPatternItemEditComponent } from './itshop-pattern-item-edit/itshop-pattern-item-edit.component'; +import { ItshopPatternSidesheetComponent } from './itshop-pattern-sidesheet/itshop-pattern-sidesheet.component'; +import { ItshopPatternComponent } from './itshop-pattern.component'; const routes: Routes = [ { @@ -63,10 +64,10 @@ const routes: Routes = [ component: ItshopPatternComponent, canActivate: [RouteGuardService, ItshopPatternGuardService], resolve: [RouteGuardService], - data:{ - contextId: HELP_CONTEXTUAL.RequestTemplates - } - } + data: { + contextId: HELP_CONTEXTUAL.RequestTemplates, + }, + }, ]; @NgModule({ @@ -76,7 +77,7 @@ const routes: Routes = [ ItshopPatternCreateSidesheetComponent, ItshopPatternAddProductsComponent, DuplicatePatternItemsComponent, - ItshopPatternItemEditComponent + ItshopPatternItemEditComponent, ], imports: [ CdrModule, @@ -94,47 +95,43 @@ const routes: Routes = [ UserModule, SelectedElementsModule, HelpContextualModule, - ] + DataViewModule, + ], }) export class ItshopPatternModule { - constructor( private readonly menuService: MenuService, - logger: ClassloggerService + logger: ClassloggerService, ) { logger.info(this, '▶️ ItshopPatternModule loaded'); this.setupMenu(); } private setupMenu(): void { - this.menuService.addMenuFactories( - (preProps: string[], features: string[], projectConfig: QerProjectConfig & ProjectConfig) => { - const items: MenuItem[] = []; - const requestTemplatesEnabled = projectConfig.ITShopConfig.VI_ITShop_ProductSelectionFromTemplate; + this.menuService.addMenuFactories((preProps: string[], features: string[], projectConfig: QerProjectConfig & ProjectConfig) => { + const items: MenuItem[] = []; + const requestTemplatesEnabled = projectConfig.ITShopConfig?.VI_ITShop_ProductSelectionFromTemplate || false; - if (preProps.includes('ITSHOP') && requestTemplatesEnabled) { - items.push( - { - id: 'QER_Request_RequestTemplates', - navigationCommands: { - commands: ['itshop', 'requesttemplates'] - }, - title: '#LDS#Menu Entry Product bundles', - sorting: '10-50', - } - ); - } + if (preProps.includes('ITSHOP') && requestTemplatesEnabled) { + items.push({ + id: 'QER_Request_RequestTemplates', + navigationCommands: { + commands: ['itshop', 'requesttemplates'], + }, + title: '#LDS#Menu Entry Product bundles', + sorting: '10-50', + }); + } - if (items.length === 0) { - return null; - } - return { - id: 'ROOT_Request', - title: '#LDS#Requests', - sorting: '10', - items - }; + if (items.length === 0) { + return; } - ); + return { + id: 'ROOT_Request', + title: '#LDS#Requests', + sorting: '10', + items, + }; + }); } } diff --git a/imxweb/projects/qer/src/lib/itshop-pattern/itshop-pattern.service.ts b/imxweb/projects/qer/src/lib/itshop-pattern/itshop-pattern.service.ts index c31ec87ad..b3450a77a 100644 --- a/imxweb/projects/qer/src/lib/itshop-pattern/itshop-pattern.service.ts +++ b/imxweb/projects/qer/src/lib/itshop-pattern/itshop-pattern.service.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -28,8 +28,19 @@ import { OverlayRef } from '@angular/cdk/overlay'; import { ErrorHandler, Injectable } from '@angular/core'; import { EuiLoadingService } from '@elemental-ui/core'; -import { PortalItshopPatternAdmin, PortalItshopPatternItem, PortalItshopPatternPrivate } from 'imx-api-qer'; -import { CollectionLoadParameters, CompareOperator, EntitySchema, ExtendedTypedEntityCollection, FilterType, FkProviderItem, IFkCandidateProvider, InteractiveEntityWriteData, ParameterData, TypedEntity } from 'imx-qbm-dbts'; +import { PortalItshopPatternAdmin, PortalItshopPatternItem, PortalItshopPatternPrivate } from '@imx-modules/imx-api-qer'; +import { + CollectionLoadParameters, + CompareOperator, + EntitySchema, + ExtendedTypedEntityCollection, + FilterType, + FkProviderItem, + IFkCandidateProvider, + InteractiveEntityWriteData, + ParameterData, + TypedEntity, +} from '@imx-modules/imx-qbm-dbts'; import { ClassloggerService, SnackBarService } from 'qbm'; import { ExtendedEntityWrapper } from '../parameter-data/extended-entity-wrapper.interface'; @@ -37,10 +48,9 @@ import { QerApiService } from '../qer-api-client.service'; import { RequestParametersService } from '../shopping-cart/cart-item-edit/request-parameters.service'; @Injectable({ - providedIn: 'root' + providedIn: 'root', }) export class ItshopPatternService { - private busyIndicator: OverlayRef; private busyIndicatorCounter = 0; @@ -50,7 +60,8 @@ export class ItshopPatternService { private readonly logger: ClassloggerService, private readonly busyService: EuiLoadingService, private readonly errorHandler: ErrorHandler, - private readonly snackBar: SnackBarService) { } + private readonly snackBar: SnackBarService, + ) {} public get itshopPatternAdminSchema(): EntitySchema { return this.qerClient.typedClient.PortalItshopPatternAdmin.GetSchema(); @@ -64,17 +75,18 @@ export class ItshopPatternService { return this.qerClient.typedClient.PortalItshopPatternItem.GetSchema(); } - /** * Retrieves all private itshop patterns of a person. * * @returns A list of {@link PortalItshopPatternPrivate} entities. */ - public async getPrivatePatterns(navigationState?: CollectionLoadParameters): - Promise> { + public async getPrivatePatterns( + navigationState?: CollectionLoadParameters, + signal?: AbortSignal, + ): Promise> { this.logger.debug(this, `Retrieving private itshop patterns`); this.logger.trace('Navigation state', navigationState); - return this.qerClient.typedClient.PortalItshopPatternPrivate.Get(navigationState); + return this.qerClient.typedClient.PortalItshopPatternPrivate.Get(navigationState, { signal }); } /** @@ -102,8 +114,9 @@ export class ItshopPatternService { * * @returns A list of {@link PortalItshopPatternAdmin} entities. */ - public async getPatternItems(navigationState?: CollectionLoadParameters): - Promise> { + public async getPatternItems( + navigationState?: CollectionLoadParameters, + ): Promise> { this.logger.debug(this, `Retrieving public itshop patterns`); this.logger.trace('Navigation state', navigationState); return this.qerClient.typedClient.PortalItshopPatternItem.Get(navigationState); @@ -114,11 +127,13 @@ export class ItshopPatternService { * * @returns A list of {@link PortalItshopPatternAdmin} entities. */ - public async getPublicPatterns(navigationState?: CollectionLoadParameters): - Promise> { + public async getPublicPatterns( + navigationState?: CollectionLoadParameters, + signal?: AbortSignal, + ): Promise> { this.logger.debug(this, `Retrieving public itshop patterns`); this.logger.trace('Navigation state', navigationState); - return this.qerClient.typedClient.PortalItshopPatternAdmin.Get(navigationState); + return this.qerClient.typedClient.PortalItshopPatternAdmin.Get(navigationState, { signal }); } /** @@ -144,7 +159,7 @@ export class ItshopPatternService { * @param selectedPatterns the list of itshop pattern that should be delete. * @returns true if at least on pattern was successfully deleted. */ - public async delete(selectedPatterns: PortalItshopPatternPrivate[], adminMode?: boolean): Promise { + public async delete(selectedPatterns: TypedEntity[], adminMode?: boolean): Promise { let deleteCount = 0; this.handleOpenLoader(); try { @@ -155,9 +170,10 @@ export class ItshopPatternService { } if (deleteCount > 0) { - const message = deleteCount > 1 - ? '#LDS#The selected product bundles have been successfully deleted.' - : '#LDS#The product bundle has been successfully deleted.'; + const message = + deleteCount > 1 + ? '#LDS#The selected product bundles have been successfully deleted.' + : '#LDS#The product bundle has been successfully deleted.'; this.snackBar.open({ key: message }); } } finally { @@ -202,16 +218,17 @@ export class ItshopPatternService { const typedEntity = collection.Data[index]; + const columns = this.requestParametersService.createInteractiveParameterCategoryColumns( + { + Parameters: typedEntity.extendedDataRead?.Parameters, + index, + }, + (parameter) => this.getFkProviderItemsInteractive(typedEntity, parameter), + typedEntity, + ); return { typedEntity, - parameterCategoryColumns: this.requestParametersService.createInteractiveParameterCategoryColumns( - { - Parameters: typedEntity.extendedDataRead?.Parameters, - index - }, - parameter => this.getFkProviderItemsInteractive(typedEntity, parameter), - typedEntity - ) + parameterCategoryColumns: columns ?? [], }; } @@ -219,68 +236,64 @@ export class ItshopPatternService { return entityWrapper.typedEntity.GetEntity().Commit(true); } - public getFkProviderItemsInteractive( interactiveEntity: { InteractiveEntityWriteData: InteractiveEntityWriteData }, - parameterData: ParameterData + parameterData: ParameterData, ): IFkCandidateProvider { - const qerClient = this.qerClient; - return new class implements IFkCandidateProvider { + return new (class implements IFkCandidateProvider { getProviderItem(_columnName, fkTableName) { - if (parameterData.Property.FkRelation) { - return this.getFkProviderItemInteractive(interactiveEntity, parameterData.Property.ColumnName, parameterData.Property.FkRelation.ParentTableName); + if (parameterData.Property?.FkRelation != null) { + return this.getFkProviderItemInteractive( + interactiveEntity, + parameterData.Property?.ColumnName || '', + parameterData.Property?.FkRelation.ParentTableName || '', + ); } - if (parameterData.Property.ValidReferencedTables) { - const t = parameterData.Property.ValidReferencedTables.map(parentTableRef => - this.getFkProviderItemInteractive(interactiveEntity, parameterData.Property.ColumnName, parentTableRef.TableName) - ).filter(t => t.fkTableName == fkTableName); - if (t.length == 1) - return t[0]; - return null; + if (parameterData.Property?.ValidReferencedTables != null) { + const t = parameterData.Property?.ValidReferencedTables.map((parentTableRef) => + this.getFkProviderItemInteractive(interactiveEntity, parameterData.Property?.ColumnName || '', parentTableRef.TableName || ''), + ).filter((t) => t.fkTableName == fkTableName); + if (t.length == 1) return t[0]; + return undefined; } - return null; + return undefined; } private getFkProviderItemInteractive( interactiveEntity: { InteractiveEntityWriteData: InteractiveEntityWriteData }, columnName: string, - fkTableName: string + fkTableName: string, ): FkProviderItem { return { columnName, fkTableName, - parameterNames: [ - 'OrderBy', - 'StartIndex', - 'PageSize', - 'filter', - 'search' - ], + parameterNames: ['OrderBy', 'StartIndex', 'PageSize', 'filter', 'search'], load: async (__, parameters?) => { return qerClient.client.portal_itshop_pattern_item_interactive_parameter_candidates_post( columnName, fkTableName, interactiveEntity.InteractiveEntityWriteData, - parameters + parameters, ); }, getDataModel: async () => ({}), getFilterTree: async (__, parentkey) => { return qerClient.client.portal_itshop_pattern_item_interactive_parameter_candidates_filtertree_post( - columnName, fkTableName, interactiveEntity.InteractiveEntityWriteData, { parentkey: parentkey } + columnName, + fkTableName, + interactiveEntity.InteractiveEntityWriteData, + { parentkey: parentkey }, ); - } + }, }; } - - } + })(); } - /** * Toogle the IsPublicPattern value of a {@link PortalItshopPatternPrivate} and commit the changes to the server * @param uid the uid of itshop pattern that should be toggled. @@ -305,24 +318,23 @@ export class ItshopPatternService { return reload; } - public async makePublic(selectedPatterns: PortalItshopPatternAdmin[], shouldBePublic: boolean): Promise { + public async makePublic(selectedPatterns: TypedEntity[], shouldBePublic: boolean): Promise { let commitCount = 0; this.handleOpenLoader(); try { - for (const pattern of selectedPatterns) { + for (const pattern of selectedPatterns as PortalItshopPatternAdmin[]) { pattern.IsPublicPattern.value = shouldBePublic; if (await this.tryCommit(pattern)) { commitCount++; } } const message = shouldBePublic - ? (commitCount === 1 + ? commitCount === 1 ? '#LDS#The product bundle has been shared successfully. The product bundle is now available for all users.' - : '#LDS#The product bundles have been shared successfully. {0} product bundles are now available for all users.') - : (commitCount === 1 + : '#LDS#The product bundles have been shared successfully. {0} product bundles are now available for all users.' + : commitCount === 1 ? '#LDS#Sharing of the product bundle has been successfully undone. The product bundle is now only available for yourself.' - : '#LDS#Sharing of the product bundles has been successfully undone. {0} product bundles are now only available for yourself.' - ); + : '#LDS#Sharing of the product bundles has been successfully undone. {0} product bundles are now only available for yourself.'; this.snackBar.open({ key: message, parameters: [commitCount] }); } finally { this.handleCloseLoader(); @@ -332,17 +344,14 @@ export class ItshopPatternService { public handleOpenLoader(): void { if (this.busyIndicatorCounter === 0) { - setTimeout(() => this.busyIndicator = this.busyService.show()); + this.busyIndicator = this.busyService.show(); } this.busyIndicatorCounter++; } public handleCloseLoader(): void { if (this.busyIndicatorCounter === 1) { - setTimeout(() => { - this.busyService.hide(this.busyIndicator); - this.busyIndicator = undefined; - }); + this.busyService.hide(this.busyIndicator); } this.busyIndicatorCounter--; } @@ -373,7 +382,7 @@ export class ItshopPatternService { private async tryDeleteProducts(uid: string): Promise { try { - await this.qerClient.typedClient.PortalItshopPatternItem.Delete(uid); + await this.qerClient.typedClient.PortalItshopPatternItem.Delete(uid); return true; } catch (error) { this.errorHandler.handleError(error); diff --git a/imxweb/projects/qer/src/lib/itshop-pattern/pattern-item-candidate.interface.ts b/imxweb/projects/qer/src/lib/itshop-pattern/pattern-item-candidate.interface.ts index 474b0a8d1..55c32121c 100644 --- a/imxweb/projects/qer/src/lib/itshop-pattern/pattern-item-candidate.interface.ts +++ b/imxweb/projects/qer/src/lib/itshop-pattern/pattern-item-candidate.interface.ts @@ -1,5 +1,3 @@ - - /* * ONE IDENTITY LLC. PROPRIETARY INFORMATION * @@ -11,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -30,7 +28,6 @@ * Interface for the object that is used to create a new pattern item. */ export interface PatternItemCandidate { - /** * the display of the pattern item candidate. */ @@ -41,5 +38,3 @@ export interface PatternItemCandidate { */ uidAccProduct: string; } - - diff --git a/imxweb/projects/qer/src/lib/itshop/decision-history.service.ts b/imxweb/projects/qer/src/lib/itshop/decision-history.service.ts index 5ed6f0948..9242719e2 100644 --- a/imxweb/projects/qer/src/lib/itshop/decision-history.service.ts +++ b/imxweb/projects/qer/src/lib/itshop/decision-history.service.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -27,7 +27,7 @@ import { Injectable } from '@angular/core'; @Injectable({ - providedIn: 'root' + providedIn: 'root', }) export class DecisionHistoryService { public getDecisionTypeCssClass(decisiontype: string): string { @@ -36,10 +36,14 @@ export class DecisionHistoryService { case 'cancel': case 'abort': case 'unsubscribe': - case 'reject': return 'imx-negative'; - case 'grant': return 'imx-positive'; - case 'query': return 'imx-question'; - default: return 'imx-info'; + case 'reject': + return 'imx-negative'; + case 'grant': + return 'imx-positive'; + case 'query': + return 'imx-question'; + default: + return 'imx-info'; } } @@ -100,5 +104,6 @@ export class DecisionHistoryService { case 'Reset': return '#LDS#DisplayPersonHead_Reset'; } + return '#LDS#No data'; } } diff --git a/imxweb/projects/qer/src/lib/itshop/image.service.spec.ts b/imxweb/projects/qer/src/lib/itshop/image.service.spec.ts index 243647579..32b02d05c 100644 --- a/imxweb/projects/qer/src/lib/itshop/image.service.spec.ts +++ b/imxweb/projects/qer/src/lib/itshop/image.service.spec.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -39,17 +39,17 @@ describe('ImageService', () => { providers: [ { provide: QerApiService, - useValue: {} + useValue: {}, }, { provide: AppConfigService, useClass: class { public Config = { - BaseUrl: '' + BaseUrl: '', }; - } - } - ] + }, + }, + ], }); service = TestBed.inject(ImageService); }); diff --git a/imxweb/projects/qer/src/lib/itshop/image.service.ts b/imxweb/projects/qer/src/lib/itshop/image.service.ts index f141d7ff0..04fa746b5 100644 --- a/imxweb/projects/qer/src/lib/itshop/image.service.ts +++ b/imxweb/projects/qer/src/lib/itshop/image.service.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -26,13 +26,19 @@ import { Injectable } from '@angular/core'; -import { ITShopConfig, PortalItshopPattern, PortalItshopPatternItem, PortalServicecategories, PortalShopServiceitems, V2ApiClientMethodFactory } from 'imx-api-qer'; -import { MethodDefinition, MethodDescriptor } from 'imx-qbm-dbts'; +import { + ITShopConfig, + PortalItshopPatternItem, + PortalServicecategories, + PortalShopServiceitems, + V2ApiClientMethodFactory, +} from '@imx-modules/imx-api-qer'; +import { MethodDefinition, MethodDescriptor, TypedEntity } from '@imx-modules/imx-qbm-dbts'; import { AppConfigService, CdrFactoryService } from 'qbm'; import { QerApiService } from '../qer-api-client.service'; @Injectable({ - providedIn: 'root' + providedIn: 'root', }) export class ImageService { private readonly methodFactory = new V2ApiClientMethodFactory(); @@ -40,18 +46,22 @@ export class ImageService { constructor( private readonly api: QerApiService, private readonly config: AppConfigService, - ) { } + ) {} /** Returns the URL to the image for the specified service item. */ - public getPath(item: PortalShopServiceitems | PortalServicecategories | PortalItshopPatternItem): string { - const imageValue = item.ImageRef?.value ?? CdrFactoryService.tryGetColumn(item.GetEntity(), 'ImageRef')?.GetValue(); + public getPath(item: TypedEntity): string { + const imageValue = + (item as PortalShopServiceitems | PortalServicecategories | PortalItshopPatternItem).ImageRef?.value ?? + CdrFactoryService.tryGetColumn(item.GetEntity(), 'ImageRef')?.GetValue(); const tokens = imageValue?.split('/'); if (tokens?.length > 1) { - let path: MethodDescriptor; + let path: MethodDescriptor; if (tokens[0] === 'category') { path = this.methodFactory.portal_shop_categoryimage_get(tokens[1]); } else if (tokens[0] === 'product') { path = this.methodFactory.portal_shop_serviceitemimage_get(tokens[1]); + } else { + return ''; } if (path) { @@ -59,13 +69,13 @@ export class ImageService { return this.config.BaseUrl + new MethodDefinition(path).path; } } - return null; + return ''; } /** * @deprecated Use getPath() */ - public async get(serviceItem: PortalShopServiceitems, config: ITShopConfig): Promise { + public async get(serviceItem: PortalShopServiceitems, config: ITShopConfig): Promise { const tokens = serviceItem.ImageRef.value?.split('/'); if (tokens?.length > 1) { if (tokens[0] === 'category') { @@ -79,6 +89,6 @@ export class ImageService { } } - return null; + return undefined; } } diff --git a/imxweb/projects/qer/src/lib/itshop/itshop-request.service.ts b/imxweb/projects/qer/src/lib/itshop/itshop-request.service.ts index 0a2e9b263..76ad6e29d 100644 --- a/imxweb/projects/qer/src/lib/itshop/itshop-request.service.ts +++ b/imxweb/projects/qer/src/lib/itshop/itshop-request.service.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -26,9 +26,9 @@ import { Injectable } from '@angular/core'; -import { PwoData } from 'imx-api-qer'; -import { IEntity, IEntityColumn, ParameterData, WriteExtTypedEntity } from 'imx-qbm-dbts'; -import { AuthenticationService } from 'qbm'; +import { PwoData } from '@imx-modules/imx-api-qer'; +import { IEntity, IEntityColumn, ParameterData, WriteExtTypedEntity } from '@imx-modules/imx-qbm-dbts'; +import { AuthenticationService, ISessionState } from 'qbm'; import { Approval } from '../itshopapprove/approval'; import { ExtendedCollectionData } from '../parameter-data/extended-collection-data.interface'; import { ParameterDataService } from '../parameter-data/parameter-data.service'; @@ -42,17 +42,17 @@ export class ItshopRequestService { constructor( private readonly parameterDataService: ParameterDataService, private readonly itshopService: ItshopService, - authentication: AuthenticationService + authentication: AuthenticationService, ) { - authentication.onSessionResponse.subscribe((session) => (this.currentUser = session.UserUid)); + authentication.onSessionResponse.subscribe((session: ISessionState) => (this.currentUser = session.UserUid || '')); } - public createParameterColumns(entity: IEntity, parameters: ParameterData[]): IEntityColumn[] { + public createParameterColumns(entity: IEntity, parameters: ParameterData[]): (IEntityColumn | undefined)[] { return this.parameterDataService.createParameterColumns( entity, parameters, (loadParameters) => this.itshopService.getRequestParameterCandidates(loadParameters), - (treeParameters) => this.itshopService.getRequestParameterFilterTree(treeParameters) + (treeParameters) => this.itshopService.getRequestParameterFilterTree(treeParameters), ); } @@ -60,7 +60,7 @@ export class ItshopRequestService { public createRequestApprovalItem( typedEntity: WriteExtTypedEntity, - extendedCollectionData: ExtendedCollectionData + extendedCollectionData: ExtendedCollectionData | undefined, ): Approval { const entity = typedEntity.GetEntity(); @@ -68,14 +68,20 @@ export class ItshopRequestService { entity, extendedCollectionData, (loadParameters) => this.itshopService.getRequestParameterCandidates(loadParameters), - (treeParameters) => this.itshopService.getRequestParameterFilterTree(treeParameters) + (treeParameters) => this.itshopService.getRequestParameterFilterTree(treeParameters), ); return new Approval({ entity, uidCurrentUser: this.currentUser, isChiefApproval: this.itshopService.isChiefApproval, - pwoData: extendedDataWrapper.data, + pwoData: { + ...extendedDataWrapper.data, + WorkflowSteps: extendedCollectionData?.WorkflowSteps, + CanRecallDecision: extendedDataWrapper.data?.CanRecallDecision || false, + CanRevokeDelegation: extendedDataWrapper.data?.CanRevokeDelegation || false, + CanAskForHelp: extendedDataWrapper.data?.CanAskForHelp || false, + }, parameterColumns: extendedDataWrapper.parameterWrapper.columns, commit: async () => { typedEntity.extendedData = extendedDataWrapper.parameterWrapper.getEntityWriteDataColumns(); diff --git a/imxweb/projects/qer/src/lib/itshop/itshop.module.ts b/imxweb/projects/qer/src/lib/itshop/itshop.module.ts index 6d6243e93..11643a130 100644 --- a/imxweb/projects/qer/src/lib/itshop/itshop.module.ts +++ b/imxweb/projects/qer/src/lib/itshop/itshop.module.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -52,14 +52,9 @@ import { MatExpansionModule } from '@angular/material/expansion'; NonRequestableItemsComponent, PeerGroupComponent, ServiceItemDetailComponent, - ProductEntitlementsComponent - ], - exports: [ - RequestInfoComponent, - PeerGroupComponent, - ServiceItemDetailComponent, - ProductEntitlementsComponent + ProductEntitlementsComponent, ], + exports: [RequestInfoComponent, PeerGroupComponent, ServiceItemDetailComponent, ProductEntitlementsComponent], imports: [ BusyIndicatorModule, CdrModule, @@ -77,11 +72,8 @@ import { MatExpansionModule } from '@angular/material/expansion'; ExtModule, DateModule, DataTableModule, - DataSourceToolbarModule - ], - providers: [ - ItshopService, - ShelfService + DataSourceToolbarModule, ], + providers: [ItshopService, ShelfService], }) -export class ItshopModule { } +export class ItshopModule {} diff --git a/imxweb/projects/qer/src/lib/itshop/itshop.service.ts b/imxweb/projects/qer/src/lib/itshop/itshop.service.ts index e4e79941e..073af887f 100644 --- a/imxweb/projects/qer/src/lib/itshop/itshop.service.ts +++ b/imxweb/projects/qer/src/lib/itshop/itshop.service.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -26,16 +26,15 @@ import { Injectable } from '@angular/core'; -import { ClassloggerService } from 'qbm'; import { PortalItshopApproveHistory, PortalItshopCart, - PortalItshopPersondecision, PortalItshopPeergroupMemberships, + PortalItshopPersondecision, + PortalShopServiceitems, PwoData, ServiceItemsExtendedData, - PortalShopServiceitems, -} from 'imx-api-qer'; +} from '@imx-modules/imx-api-qer'; import { ApiRequestOptions, CollectionLoadParameters, @@ -47,10 +46,11 @@ import { FilterType, TypedEntityBuilder, TypedEntityCollectionData, -} from 'imx-qbm-dbts'; +} from '@imx-modules/imx-qbm-dbts'; +import { ClassloggerService } from 'qbm'; +import { ServiceItemParameters } from '../new-request/new-request-product/service-item-parameters'; import { ParameterDataLoadParameters } from '../parameter-data/parameter-data-load-parameters.interface'; import { QerApiService } from '../qer-api-client.service'; -import { ServiceItemParameters } from '../new-request/new-request-product/service-item-parameters'; @Injectable({ providedIn: 'root', @@ -64,7 +64,10 @@ export class ItshopService { private readonly historyBuilder = new TypedEntityBuilder(PortalItshopApproveHistory); - constructor(private readonly qerClient: QerApiService, private readonly logger: ClassloggerService) {} + constructor( + private readonly qerClient: QerApiService, + private readonly logger: ClassloggerService, + ) {} public async get( parameters: CollectionLoadParameters & { @@ -74,12 +77,12 @@ export class ItshopService { UID_AccProductParent?: string; UID_PersonReference?: string; UID_PersonPeerGroup?: string; - } + }, ): Promise> { return this.qerClient.typedClient.PortalShopServiceitems.Get(parameters); } - public async getServiceItem(serviceItemUid: string, isSkippable?: boolean): Promise { + public async getServiceItem(serviceItemUid: string, isSkippable?: boolean): Promise { const serviceItemCollection = await this.get({ IncludeChildCategories: false, filter: [ @@ -93,7 +96,7 @@ export class ItshopService { }); if (serviceItemCollection == null || serviceItemCollection.Data == null || serviceItemCollection.Data.length === 0) { if (isSkippable) { - return null; + return undefined; } throw new Error('getServiceItem - service item not found'); } @@ -102,8 +105,8 @@ export class ItshopService { } public async getPeerGroupMemberships( - parameters: (CollectionLoadParameters | ServiceItemParameters), - requestOpts?: ApiRequestOptions + parameters: CollectionLoadParameters | ServiceItemParameters, + requestOpts?: ApiRequestOptions, ): Promise> { return this.qerClient.typedClient.PortalItshopPeergroupMemberships.Get(parameters, requestOpts); } @@ -112,38 +115,38 @@ export class ItshopService { if (pwoData?.WorkflowHistory) { return this.historyBuilder.buildReadWriteEntities( pwoData.WorkflowHistory, - this.qerClient.typedClient.PortalItshopApproveHistory.GetSchema() + this.qerClient.typedClient.PortalItshopApproveHistory.GetSchema(), ).Data; } - return undefined; + return []; } public async getRequestParameterCandidates(parameters: ParameterDataLoadParameters): Promise { return this.qerClient.client.portal_itshop_requests_parameter_candidates_post( parameters.columnName, - parameters.fkTableName, - parameters.diffData, + parameters.fkTableName || '', + parameters.diffData || {}, { OrderBy: parameters.OrderBy, StartIndex: parameters.StartIndex, PageSize: parameters.PageSize, filter: parameters.filter, search: parameters.search, - ParentKey: parameters.ParentKey - } + ParentKey: parameters.ParentKey, + }, ); } public async getRequestParameterFilterTree(parameters: ParameterDataLoadParameters): Promise { return this.qerClient.client.portal_itshop_requests_parameter_candidates_filtertree_post( parameters.columnName, - parameters.fkTableName, - parameters.diffData, + parameters.fkTableName || '', + parameters.diffData || {}, { filter: parameters.filter, - parentkey: parameters.ParentKey - } + parentkey: parameters.ParentKey, + }, ); } diff --git a/imxweb/projects/qer/src/lib/itshop/non-requestable-items/non-requestable-items.component.html b/imxweb/projects/qer/src/lib/itshop/non-requestable-items/non-requestable-items.component.html index 99c18d6eb..d0c2446ba 100644 --- a/imxweb/projects/qer/src/lib/itshop/non-requestable-items/non-requestable-items.component.html +++ b/imxweb/projects/qer/src/lib/itshop/non-requestable-items/non-requestable-items.component.html @@ -1,10 +1,9 @@ -

    {{'#LDS#Heading Products Cannot Be Requested' | translate}}

    +

    {{ '#LDS#Heading Products Cannot Be Requested' | translate }}

    - {{'#LDS#The following products could not be added to the shopping cart for the following recipients.' | translate}} + {{ '#LDS#The following products could not be added to the shopping cart for the following recipients.' | translate }}

    - +
    - +
    {{ column.title | translate }} @@ -14,9 +13,9 @@

    {{'#LDS#Heading Products Cannot Be Requested' | translate}}

    -
    - -
    \ No newline at end of file +
    + +
    diff --git a/imxweb/projects/qer/src/lib/itshop/non-requestable-items/non-requestable-items.component.scss b/imxweb/projects/qer/src/lib/itshop/non-requestable-items/non-requestable-items.component.scss index e110d11b2..248a268c5 100644 --- a/imxweb/projects/qer/src/lib/itshop/non-requestable-items/non-requestable-items.component.scss +++ b/imxweb/projects/qer/src/lib/itshop/non-requestable-items/non-requestable-items.component.scss @@ -1 +1 @@ -// add styles if necessary \ No newline at end of file +// add styles if necessary diff --git a/imxweb/projects/qer/src/lib/itshop/non-requestable-items/non-requestable-items.component.spec.ts b/imxweb/projects/qer/src/lib/itshop/non-requestable-items/non-requestable-items.component.spec.ts index fcacabb0f..e796fbf02 100644 --- a/imxweb/projects/qer/src/lib/itshop/non-requestable-items/non-requestable-items.component.spec.ts +++ b/imxweb/projects/qer/src/lib/itshop/non-requestable-items/non-requestable-items.component.spec.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -35,33 +35,28 @@ describe('NonRequestableItemsComponent', () => { let fixture: ComponentFixture; const mockMatDialogRef = { - close: jasmine.createSpy('close') + close: jasmine.createSpy('close'), }; const dialogData = { - nonRequestableProductsForPersons: [] - } + nonRequestableProductsForPersons: [], + }; beforeEach(waitForAsync(() => { TestBed.configureTestingModule({ - declarations: [ - NonRequestableItemsComponent - ], - imports: [ - MatTableModule, - ], + declarations: [NonRequestableItemsComponent], + imports: [MatTableModule], providers: [ { provide: MatDialogRef, - useValue: mockMatDialogRef + useValue: mockMatDialogRef, }, { provide: MAT_DIALOG_DATA, - useValue: dialogData - } - ] - }) - .compileComponents(); + useValue: dialogData, + }, + ], + }).compileComponents(); })); beforeEach(() => { diff --git a/imxweb/projects/qer/src/lib/itshop/non-requestable-items/non-requestable-items.component.ts b/imxweb/projects/qer/src/lib/itshop/non-requestable-items/non-requestable-items.component.ts index b20d2249e..7e603ccc5 100644 --- a/imxweb/projects/qer/src/lib/itshop/non-requestable-items/non-requestable-items.component.ts +++ b/imxweb/projects/qer/src/lib/itshop/non-requestable-items/non-requestable-items.component.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -26,32 +26,27 @@ import { Component, Inject } from '@angular/core'; import { MAT_DIALOG_DATA } from '@angular/material/dialog'; -import { RequestableProductForPerson } from 'imx-api-qer'; +import { RequestableProductForPerson } from '@imx-modules/imx-api-qer'; @Component({ selector: 'imx-non-requestable-items', templateUrl: './non-requestable-items.component.html', - styleUrls: ['./non-requestable-items.component.scss'] + styleUrls: ['./non-requestable-items.component.scss'], }) export class NonRequestableItemsComponent { - public get columnNames(): string[] { - return this.displayedColumns.map(c => c.name); + return this.displayedColumns.map((c) => c.name); } public readonly displayedColumns = [ { name: 'Display', title: '#LDS#Product' }, - { name: 'DisplayRecipient', title: '#LDS#Recipient' } + { name: 'DisplayRecipient', title: '#LDS#Recipient' }, ]; constructor( - @Inject(MAT_DIALOG_DATA) public readonly data: { - nonRequestableProductsForPersons: RequestableProductForPerson[] - } - ) { } - - - - - + @Inject(MAT_DIALOG_DATA) + public readonly data: { + nonRequestableProductsForPersons: RequestableProductForPerson[]; + }, + ) {} } diff --git a/imxweb/projects/qer/src/lib/itshop/peer-group/peer-group.component.html b/imxweb/projects/qer/src/lib/itshop/peer-group/peer-group.component.html index ee2c776fc..a9ecce5b0 100644 --- a/imxweb/projects/qer/src/lib/itshop/peer-group/peer-group.component.html +++ b/imxweb/projects/qer/src/lib/itshop/peer-group/peer-group.component.html @@ -1,4 +1,7 @@
    - {{ '#LDS#Assigned to {0} of {1} other identities of the peer group ({2}%)' - | translate | ldsReplace:item.CountInPeerGroup.value:peerGroupSize:getPeerGroupPercentage() }} + {{ + '#LDS#Assigned to {0} of {1} other identities of the peer group ({2}%)' + | translate + | ldsReplace: item.CountInPeerGroup.value : peerGroupSize : getPeerGroupPercentage() + }}
    diff --git a/imxweb/projects/qer/src/lib/itshop/peer-group/peer-group.component.ts b/imxweb/projects/qer/src/lib/itshop/peer-group/peer-group.component.ts index e66d07e6d..8a593e29c 100644 --- a/imxweb/projects/qer/src/lib/itshop/peer-group/peer-group.component.ts +++ b/imxweb/projects/qer/src/lib/itshop/peer-group/peer-group.component.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -26,15 +26,15 @@ import { Component, Input } from '@angular/core'; -import { IReadValue } from 'imx-qbm-dbts'; +import { IReadValue } from '@imx-modules/imx-qbm-dbts'; @Component({ selector: 'imx-peer-group', templateUrl: './peer-group.component.html', - styleUrls: ['./peer-group.component.scss'] + styleUrls: ['./peer-group.component.scss'], }) export class PeerGroupComponent { - @Input() public item: { CountInPeerGroup: IReadValue; }; + @Input() public item: { CountInPeerGroup: IReadValue }; @Input() public peerGroupSize: number; @Input() public width = '100%'; diff --git a/imxweb/projects/qer/src/lib/itshop/request-info/approver-container.spec.ts b/imxweb/projects/qer/src/lib/itshop/request-info/approver-container.spec.ts index 78ad9b628..c7618ec1f 100644 --- a/imxweb/projects/qer/src/lib/itshop/request-info/approver-container.spec.ts +++ b/imxweb/projects/qer/src/lib/itshop/request-info/approver-container.spec.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -24,8 +24,8 @@ * */ -import { ITShopConfig, PwoData } from 'imx-api-qer'; -import { EntityData } from 'imx-qbm-dbts'; +import { ITShopConfig, PwoData } from '@imx-modules/imx-api-qer'; +import { EntityData } from '@imx-modules/imx-qbm-dbts'; import { ApproverContainer } from './approver-container'; describe('ApproverContainer', () => { @@ -34,15 +34,15 @@ describe('ApproverContainer', () => { decisionLevel: level, qerWorkingMethod: uidWorkingMethode, pwoData: buildPwoData(steps, data), - approvers + approvers, }; } function buildPwoData(steps?: EntityData[], data?: EntityData[]): PwoData { return { WorkflowSteps: steps == null ? {} : { TotalCount: steps.length, IsLimitReached: true, Entities: steps }, - WorkflowData: data == null ? {} : { TotalCount: data.length, IsLimitReached: true, Entities: data } - } as PwoData + WorkflowData: data == null ? {} : { TotalCount: data.length, IsLimitReached: true, Entities: data }, + } as PwoData; } function buildStep(uidWorkingMethode?: string, level?: number, positive?: number, uidstep?: string): EntityData { @@ -52,8 +52,8 @@ describe('ApproverContainer', () => { LevelNumber: { Value: level }, PositiveSteps: { Value: positive }, }, - Keys: uidstep == null ? [] : [uidstep] - } + Keys: uidstep == null ? [] : [uidstep], + }; } function buildData(uidWorkingStep?: string, uidPersonHead?: string): EntityData { @@ -72,11 +72,11 @@ describe('ApproverContainer', () => { it('should create', () => { const test = new ApproverContainer( {} as { - decisionLevel: number, - qerWorkingMethod: string, - pwoData: PwoData, - approvers: string[] - } + decisionLevel: number; + qerWorkingMethod: string; + pwoData: PwoData; + approvers: string[]; + }, ); expect(test).toBeTruthy(); }); @@ -84,66 +84,107 @@ describe('ApproverContainer', () => { for (const testcase of [ { descriprion: 'with null values', pwo: {}, personNow: [], personsFuture: [] }, { - descriprion: 'with empty values', pwo: buildPwo('uidQerWorkingMethode', 0, [], [], []), personNow: [], personsFuture: [] + descriprion: 'with empty values', + pwo: buildPwo('uidQerWorkingMethode', 0, [], [], []), + personNow: [], + personsFuture: [], }, { - descriprion: 'with single step', pwo: buildPwo('uidQerWorkingMethode', 0, - [buildStep('uidQerWorkingMethode', 0, 0, 'uidStep')], [buildData('uidStep', 'person')], ['person']), - personNow: ['person'], personsFuture: [] - }, { - descriprion: 'with multiple steps (only 1 match)', pwo: buildPwo('uidQerWorkingMethode', 0, + descriprion: 'with single step', + pwo: buildPwo( + 'uidQerWorkingMethode', + 0, + [buildStep('uidQerWorkingMethode', 0, 0, 'uidStep')], + [buildData('uidStep', 'person')], + ['person'], + ), + personNow: ['person'], + personsFuture: [], + }, + { + descriprion: 'with multiple steps (only 1 match)', + pwo: buildPwo( + 'uidQerWorkingMethode', + 0, [buildStep('uidQerWorkingMethode', 0, 0, 'uidStep'), buildStep('uidQerWorkingMethode', 1, 2, 'uidStep2')], - [buildData('uidStep', 'person')], ['person']), personNow: ['person'], personsFuture: [] - }, { - descriprion: 'with multiple steps (but only 1 approver)', pwo: buildPwo('uidQerWorkingMethode', 0, + [buildData('uidStep', 'person')], + ['person'], + ), + personNow: ['person'], + personsFuture: [], + }, + { + descriprion: 'with multiple steps (but only 1 approver)', + pwo: buildPwo( + 'uidQerWorkingMethode', + 0, [buildStep('uidQerWorkingMethode', 0, 0, 'uidStep'), buildStep('uidQerWorkingMethode', 1, 1, 'uidStep2')], - [buildData('uidStep', 'person'), buildData('uidStep2', 'person2')], ['person']), - personNow: ['person'], personsFuture: [] - }, { - descriprion: 'with multiple steps (future and now)', pwo: buildPwo('uidQerWorkingMethode', 0, + [buildData('uidStep', 'person'), buildData('uidStep2', 'person2')], + ['person'], + ), + personNow: ['person'], + personsFuture: [], + }, + { + descriprion: 'with multiple steps (future and now)', + pwo: buildPwo( + 'uidQerWorkingMethode', + 0, [buildStep('uidQerWorkingMethode', 0, 1, 'uidStep'), buildStep('uidQerWorkingMethode', 1, 1, 'uidStep2')], - [buildData('uidStep', 'person'), buildData('uidStep2', 'person2')], ['person', 'person2']), - personNow: ['person'], personsFuture: ['person2'] - }, { - descriprion: 'with multiple steps (multiple future and now)', pwo: buildPwo('uidQerWorkingMethode', 0, - [buildStep('uidQerWorkingMethode', 0, 1, 'uidStep'), - buildStep('uidQerWorkingMethode', 1, 1, 'uidStep2'), - buildStep('uidQerWorkingMethode', 2, 1, 'uidStep3')], - [buildData('uidStep', 'person'), - buildData('uidStep', 'person2'), - buildData('uidStep2', 'person2'), - buildData('uidStep3', 'person3')], - ['person', 'person2', 'person3']), - personNow: ['person', 'person2'], personsFuture: ['person2', 'person3'] - } - + [buildData('uidStep', 'person'), buildData('uidStep2', 'person2')], + ['person', 'person2'], + ), + personNow: ['person'], + personsFuture: ['person2'], + }, + { + descriprion: 'with multiple steps (multiple future and now)', + pwo: buildPwo( + 'uidQerWorkingMethode', + 0, + [ + buildStep('uidQerWorkingMethode', 0, 1, 'uidStep'), + buildStep('uidQerWorkingMethode', 1, 1, 'uidStep2'), + buildStep('uidQerWorkingMethode', 2, 1, 'uidStep3'), + ], + [ + buildData('uidStep', 'person'), + buildData('uidStep', 'person2'), + buildData('uidStep2', 'person2'), + buildData('uidStep3', 'person3'), + ], + ['person', 'person2', 'person3'], + ), + personNow: ['person', 'person2'], + personsFuture: ['person2', 'person3'], + }, ]) { it(`can initialize ${testcase.descriprion}`, () => { const container = new ApproverContainer( testcase.pwo as { - decisionLevel: number, - qerWorkingMethod: string, - pwoData: PwoData, - approvers: string[] - } + decisionLevel: number; + qerWorkingMethod: string; + pwoData: PwoData; + approvers: string[]; + }, ); expect(container.approverNow.length).toEqual(testcase.personNow.length); for (const approver of testcase.personNow) { - const result = container.approverNow.map(app => app.Columns.UID_PersonHead.Value); + const result = container.approverNow.map((app) => app.Columns.UID_PersonHead.Value); expect(result.includes(approver)).toBeTruthy(); } expect(container.approverFuture.length).toEqual(testcase.personsFuture.length); for (const approver of testcase.personsFuture) { - const result = container.approverFuture.map(app => app.Columns.UID_PersonHead.Value); + const result = container.approverFuture.map((app) => app.Columns.UID_PersonHead.Value); expect(result.includes(approver)).toBeTruthy(); } - }) + }); } it('can initialize with multiple approvers (now)', () => { - const stepUid = 'uidStep0' + const stepUid = 'uidStep0'; const personsSteps = { person1: stepUid, @@ -158,26 +199,24 @@ describe('ApproverContainer', () => { const positiveSteps = 1; - const steps = [ - buildStep(uidQerWorkingMethod, level, positiveSteps, stepUid) - ]; + const steps = [buildStep(uidQerWorkingMethod, level, positiveSteps, stepUid)]; const data = []; - persons.forEach(person => data.push(buildData(personsSteps[person], person))) + persons.forEach((person) => data.push(buildData(personsSteps[person], person))); const container = new ApproverContainer( { decisionLevel: level, qerWorkingMethod: uidQerWorkingMethod, pwoData: buildPwoData(steps, data), - approvers: persons + approvers: persons, }, - { VI_ITShop_CurrentApproversCanBeSeen: true } as ITShopConfig + { VI_ITShop_CurrentApproversCanBeSeen: true } as ITShopConfig, ); expect(container.approverNow.length).toEqual(persons.length); persons.forEach((approver, index) => expect(container.approverNow[index].Columns.UID_PersonHead.DisplayValue).toEqual(approver)); - }) + }); it('can initialize with multiple future steps', () => { const personsFutureSteps = { @@ -196,28 +235,30 @@ describe('ApproverContainer', () => { const steps = [ buildStep(uidQerWorkingMethod, level, positiveSteps, 'uidStep0'), buildStep(uidQerWorkingMethod, level + positiveSteps, positiveSteps, personsFutureSteps.person1), - buildStep(uidQerWorkingMethod, level + positiveSteps * 2, positiveSteps, personsFutureSteps.person2) + buildStep(uidQerWorkingMethod, level + positiveSteps * 2, positiveSteps, personsFutureSteps.person2), ]; const data = [buildData('uidStep', 'person')]; - personsFuture.forEach(person => data.push(buildData(personsFutureSteps[person], person))) + personsFuture.forEach((person) => data.push(buildData(personsFutureSteps[person], person))); const container = new ApproverContainer( { decisionLevel: level, qerWorkingMethod: uidQerWorkingMethod, pwoData: buildPwoData(steps, data), - approvers: undefined + approvers: undefined, }, - { VI_ITShop_NextApproverCanBeSeen: true } as ITShopConfig + { VI_ITShop_NextApproverCanBeSeen: true } as ITShopConfig, ); expect(container.approverFuture.length).toEqual(personsFuture.length); - personsFuture.forEach((approver, index) => expect(container.approverFuture[index].Columns.UID_PersonHead.DisplayValue).toEqual(approver)); - }) + personsFuture.forEach((approver, index) => + expect(container.approverFuture[index].Columns.UID_PersonHead.DisplayValue).toEqual(approver), + ); + }); it('can initialize with auto steps', () => { - const stepUids = ['0', '1'] + const stepUids = ['0', '1']; const uidQerWorkingMethod = 'uidQerWorkingMethod'; @@ -225,22 +266,18 @@ describe('ApproverContainer', () => { const positiveSteps = 1; - const steps = stepUids.map((stepUid, index) => - buildStep(uidQerWorkingMethod, level + index * positiveSteps, positiveSteps, stepUid) - ); + const steps = stepUids.map((stepUid, index) => buildStep(uidQerWorkingMethod, level + index * positiveSteps, positiveSteps, stepUid)); - const data = stepUids.map(stepUid => buildData(stepUid)); + const data = stepUids.map((stepUid) => buildData(stepUid)); - const container = new ApproverContainer( - { - decisionLevel: level, - qerWorkingMethod: uidQerWorkingMethod, - pwoData: buildPwoData(steps, data), - approvers: ['some approver'] - } - ); + const container = new ApproverContainer({ + decisionLevel: level, + qerWorkingMethod: uidQerWorkingMethod, + pwoData: buildPwoData(steps, data), + approvers: ['some approver'], + }); expect(container.approverNow.length).toEqual(0); expect(container.approverFuture.length).toEqual(0); - }) + }); }); diff --git a/imxweb/projects/qer/src/lib/itshop/request-info/approver-container.ts b/imxweb/projects/qer/src/lib/itshop/request-info/approver-container.ts index f36954ceb..b88437e81 100644 --- a/imxweb/projects/qer/src/lib/itshop/request-info/approver-container.ts +++ b/imxweb/projects/qer/src/lib/itshop/request-info/approver-container.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -24,7 +24,7 @@ * */ -import { EntityCollectionData, EntityData, MultiValueProperty } from 'imx-qbm-dbts'; +import { EntityCollectionData, EntityData, MultiValueProperty } from '@imx-modules/imx-qbm-dbts'; import { ClassloggerService } from 'qbm'; import { OrderedWorkingStep } from './ordered-working-step.interface'; @@ -37,6 +37,8 @@ export class ApproverContainer { */ public approverNow: EntityData[] = []; + public canSeeSteps: boolean; + /** * List of next approvers */ @@ -58,31 +60,34 @@ export class ApproverContainer { VI_ITShop_CurrentApproversCanBeSeen?: boolean; VI_ITShop_NextApproverCanBeSeen?: boolean; } = {}, - private logger?: ClassloggerService + private logger?: ClassloggerService, ) { - this.isInWorkflow = this.request.isInWorkflow; + this.isInWorkflow = this.request.isInWorkflow ?? false; if (this.config?.VI_ITShop_NextApproverCanBeSeen || this.config?.VI_ITShop_CurrentApproversCanBeSeen) { - this.initApproverContainer(this.config.VI_ITShop_CurrentApproversCanBeSeen, this.config.VI_ITShop_NextApproverCanBeSeen); + this.initApproverContainer( + this.config.VI_ITShop_CurrentApproversCanBeSeen ?? false, + this.config.VI_ITShop_NextApproverCanBeSeen ?? false, + ); } else { this.initApproverContainer(true, true); } } public getApproverSortedByStep(future = true): { display: string; data: EntityData[] }[] { - const ret = []; + const ret: { display: string; data: EntityData[] }[] = []; const steps = [ ...new Set( - this.request.pwoData.WorkflowSteps?.Entities.sort((a, b) => a.Columns.LevelNumber.Value - b.Columns.LevelNumber.Value).map( + this.request.pwoData.WorkflowSteps?.Entities?.sort((a, b) => a.Columns?.LevelNumber.Value - b.Columns?.LevelNumber.Value).map( (elem) => - elem.Columns.UID_QERWorkingStep.Value + + elem.Columns?.UID_QERWorkingStep.Value + MultiValueProperty.DefaultSeparator + - (elem.Columns.Ident_PWODecisionStep.DisplayValue ?? elem.Columns.Ident_PWODecisionStep.Value) - ) + (elem.Columns?.Ident_PWODecisionStep.DisplayValue ?? elem.Columns?.Ident_PWODecisionStep.Value), + ), ), ]; - this.logger.trace(this, 'following approval steps are available', steps); + this.logger?.trace(this, 'following approval steps are available', steps); steps.forEach((element) => { const uid = element.split(MultiValueProperty.DefaultSeparator)[0]; @@ -90,18 +95,18 @@ export class ApproverContainer { const approver = future ? this.approverFuture?.filter( (workflowData, index, newArray) => - workflowData.Columns.UID_QERWorkingStep.Value === uid && - newArray.findIndex((checkData) => checkData.Columns.UID_PersonHead.Value === workflowData.Columns.UID_PersonHead.Value) === - index + workflowData.Columns?.UID_QERWorkingStep.Value === uid && + newArray.findIndex((checkData) => checkData.Columns?.UID_PersonHead.Value === workflowData.Columns?.UID_PersonHead.Value) === + index, ) : this.approverNow?.filter( (workflowData, index, newArray) => - workflowData.Columns.UID_QERWorkingStep.Value === uid && - newArray.findIndex((checkData) => checkData.Columns.UID_PersonHead.Value === workflowData.Columns.UID_PersonHead.Value) === - index + workflowData.Columns?.UID_QERWorkingStep.Value === uid && + newArray.findIndex((checkData) => checkData.Columns?.UID_PersonHead.Value === workflowData.Columns?.UID_PersonHead.Value) === + index, ); - this.logger.trace(this, `analysing ${future ? 'future' : 'current'} step ${uid} (${display}):`, approver); + this.logger?.trace(this, `analysing ${future ? 'future' : 'current'} step ${uid} (${display}):`, approver); if (approver?.length > 0) { ret.push({ display: display, data: approver }); @@ -120,20 +125,33 @@ export class ApproverContainer { const orderedWorkingSteps = this.buildOrderedWorkingSteps(); this.logger?.trace(this, 'working steps with order', orderedWorkingSteps); + this.canSeeSteps = !this.request.pwoData?.WorkflowSteps?.Entities ? false : this.request.pwoData?.WorkflowSteps?.Entities.length > 0; + if (canSeeCurrent) { const currentSteps = orderedWorkingSteps.filter((step) => step.order === 1); this.logger?.trace(this, 'current steps', currentSteps); this.approverNow = - this.request == null || this.request.pwoData == null || this.request.pwoData.WorkflowData == null || currentSteps.length === 0 + this.request == null || + this.request.pwoData == null || + this.request.pwoData.WorkflowData == null || + this.request.pwoData.WorkflowData.Entities == null || + currentSteps.length === 0 ? [] - : this.request.pwoData.WorkflowData.Entities.filter( + : this.request.pwoData.WorkflowData?.Entities?.filter( (data) => - !this.isDecided(data,this.request.pwoData.WorkflowData.Entities.filter((elem) => elem.Columns.Decision?.Value !== '')) && - data.Columns.UID_PersonHead.Value && - currentSteps.some((step) => data.Columns.UID_QERWorkingStep.Value === step.uidWorkingStep) && - this.request.approvers.includes(data.Columns.UID_PersonHead.Value) - ).sort((data1, data2) => data1.Columns.UID_PersonHead.DisplayValue.localeCompare(data2.Columns.UID_PersonHead.DisplayValue)); + !this.isDecided( + data, + !this.request.pwoData.WorkflowData?.Entities + ? [] + : this.request.pwoData.WorkflowData?.Entities?.filter((elem) => elem.Columns?.Decision?.Value !== ''), + ) && + data.Columns?.UID_PersonHead.Value && + currentSteps.some((step) => data.Columns?.UID_QERWorkingStep.Value === step.uidWorkingStep) && + this.request.approvers.includes(data.Columns?.UID_PersonHead.Value), + ).sort((data1, data2) => + (data1.Columns?.UID_PersonHead.DisplayValue || '').localeCompare(data2.Columns?.UID_PersonHead.DisplayValue || ''), + ); this.logger?.trace(this, 'personWantsOrg should be approved by', this.approverNow); } @@ -142,13 +160,21 @@ export class ApproverContainer { this.logger?.trace(this, 'future steps', futureSteps); this.approverFuture = - this.request == null || this.request.pwoData == null || this.request.pwoData.WorkflowData == null || futureSteps == null + this.request == null || + this.request.pwoData == null || + this.request.pwoData.WorkflowData == null || + this.request.pwoData.WorkflowData.Entities == null || + futureSteps == null ? [] - : this.request.pwoData.WorkflowData.Entities.filter( + : this.request.pwoData.WorkflowData?.Entities?.filter( (data) => - data.Columns.UID_PersonHead.Value && - futureSteps.map((step) => step.uidWorkingStep).includes(data.Columns.UID_QERWorkingStep.Value) - ).sort((data1, data2) => data1.Columns.UID_PersonHead.DisplayValue.localeCompare(data2.Columns.UID_PersonHead.DisplayValue)); + data.Columns?.UID_PersonHead.Value && + futureSteps.map((step) => step.uidWorkingStep).includes(data.Columns?.UID_QERWorkingStep.Value), + ).sort((data1, data2) => + (!data1.Columns?.UID_PersonHead?.DisplayValue ? '' : data1.Columns.UID_PersonHead.DisplayValue).localeCompare( + !data2.Columns?.UID_PersonHead?.DisplayValue ? '' : data2.Columns.UID_PersonHead.DisplayValue, + ), + ); this.logger?.trace(this, 'personWantsOrg should be approved in the future by', this.approverFuture); } } @@ -156,11 +182,11 @@ export class ApproverContainer { /* * Checks, if a workflowData item is already decided (by any person in the same sub step) */ - private isDecided(data: EntityData, decidedEntries:EntityData[]): boolean { + private isDecided(data: EntityData, decidedEntries: EntityData[]): boolean { return decidedEntries.some( (elem) => - elem.Columns.LevelNumber.Value === data.Columns.LevelNumber.Value && - elem.Columns.SubLevelNumber.Value === data.Columns.SubLevelNumber.Value + elem.Columns?.LevelNumber.Value === data.Columns?.LevelNumber.Value && + elem.Columns?.SubLevelNumber.Value === data.Columns?.SubLevelNumber.Value, ); } @@ -173,13 +199,13 @@ export class ApproverContainer { const currentLevel = this.request.decisionLevel; const workingMethod = this.request.qerWorkingMethod; - const stepsForWorkingMethod = this.request.pwoData.WorkflowSteps.Entities.filter( - (elem) => elem.Columns.UID_QERWorkingMethod.Value === workingMethod - ); + const stepsForWorkingMethod = !this.request.pwoData.WorkflowSteps?.Entities + ? [] + : this.request.pwoData.WorkflowSteps?.Entities?.filter((elem) => elem.Columns?.UID_QERWorkingMethod.Value === workingMethod); this.logger?.trace(this, `calculate steps for method ${workingMethod}`, stepsForWorkingMethod); const startSteps = stepsForWorkingMethod.filter( - (n, i, arr) => arr.findIndex((elem) => elem.Keys[0] === n.Keys[0] && elem.Columns.LevelNumber.Value === currentLevel) === i + (n, i, arr) => arr.findIndex((elem) => elem.Keys?.[0] === n.Keys?.[0] && elem.Columns?.LevelNumber.Value === currentLevel) === i, ); this.logger?.trace(this, 'starting with step', startSteps); @@ -191,11 +217,11 @@ export class ApproverContainer { orderedSteps.push( ...startSteps.map((elem) => ({ - uidWorkingStep: elem.Keys[0], + uidWorkingStep: !elem.Keys ? '' : elem.Keys?.[0], decisionLevel: currentLevel, - positiveSteps: elem.Columns.PositiveSteps.Value, + positiveSteps: elem.Columns?.PositiveSteps.Value, order: 1, - })) + })), ); this.logger?.debug(this, 'first working steps are added'); @@ -210,7 +236,7 @@ export class ApproverContainer { (join) => join.orderedStep != null && join.orderedStep.positiveSteps !== 0 && - orderedSteps.findIndex((workunit) => workunit.uidWorkingStep === join.workingStep.Keys[0]) === -1 + orderedSteps.findIndex((workunit) => workunit.uidWorkingStep === join.workingStep.Keys?.[0]) === -1, ); this.logger?.debug(this, 'new steps has been filtered'); @@ -219,11 +245,11 @@ export class ApproverContainer { this.logger?.debug(this, 'at least one new step has been calculated'); orderedSteps = orderedSteps.concat( filteredJoin.map((join) => ({ - decisionLevel: join.workingStep.Columns.LevelNumber.Value, + decisionLevel: join.workingStep.Columns?.LevelNumber.Value, order: join.orderedStep.order + 1, - positiveSteps: join.workingStep.Columns.PositiveSteps.Value, - uidWorkingStep: join.workingStep.Keys[0], - })) + positiveSteps: join.workingStep.Columns?.PositiveSteps.Value, + uidWorkingStep: !join.workingStep.Keys ? '' : join.workingStep.Keys?.[0], + })), ); this.logger?.trace(this, 'new step list', orderedSteps); } @@ -233,14 +259,14 @@ export class ApproverContainer { private joinOrderedStepsWithOthers( workingSteps: EntityData[], - orderedSteps: OrderedWorkingStep[] + orderedSteps: OrderedWorkingStep[], ): { orderedStep: OrderedWorkingStep; workingStep: EntityData }[] { let join: { orderedStep: OrderedWorkingStep; workingStep: EntityData }[] = []; for (const workingStep of workingSteps) { this.logger?.trace(this, 'working step for join', workingStep); const filteredOrderedSteps = orderedSteps.filter( - (step) => workingStep.Columns.LevelNumber.Value === step.decisionLevel + step.positiveSteps + (step) => workingStep.Columns?.LevelNumber.Value === step.decisionLevel + step.positiveSteps, ); this.logger?.trace(this, 'filtered order steps', filteredOrderedSteps); @@ -249,7 +275,7 @@ export class ApproverContainer { filteredOrderedSteps.map((orderedStep) => ({ orderedStep, workingStep, - })) + })), ); } } diff --git a/imxweb/projects/qer/src/lib/itshop/request-info/decision-history.component.html b/imxweb/projects/qer/src/lib/itshop/request-info/decision-history.component.html index fc48b2b70..dc2d1fb40 100644 --- a/imxweb/projects/qer/src/lib/itshop/request-info/decision-history.component.html +++ b/imxweb/projects/qer/src/lib/itshop/request-info/decision-history.component.html @@ -1,6 +1,9 @@
      -
    • +
    • @@ -8,16 +11,24 @@ step.approveHistory.DecisionType.Column.GetDisplayValue() }} - - {{ step.approveHistory.XDateInserted.value | localizedDate }} + {{ step.approveHistory.XDateInserted.value ?? step.approveHistory.DateHead.value | localizedDate }} + - {{ step.approveHistory.Ident_PWODecisionStep?.Column?.GetDisplayValue() }} + + {{ step.approveHistory.Ident_PWODecisionStep?.Column?.GetDisplayValue() }} + - {{ - '#LDS#Approval decision by chief approval team' | translate - }} + {{ '#LDS#Approval decision by chief approval team' | translate }}
      @@ -35,15 +46,26 @@
    • -
    • +
    • - {{ '#LDS#The next approval step is currently being calculated. The request might also be waiting on a pending approval decision of another request.' | translate }} + {{ + '#LDS#The next approval step is currently being calculated. The request might also be waiting on a pending approval decision of another request.' + | translate + }}
    • @@ -60,7 +82,7 @@ {{ approvalStep.display }}
    • - {{ pnow.Columns.UID_PersonHead.DisplayValue }} + {{ pnow.Columns?.UID_PersonHead?.DisplayValue }}
    @@ -70,7 +92,11 @@
  • @@ -87,7 +113,7 @@ {{ approvalStep.display }}
  • - {{ pnext.Columns.UID_PersonHead.DisplayValue }} + {{ pnext.Columns?.UID_PersonHead?.DisplayValue }}
    diff --git a/imxweb/projects/qer/src/lib/itshop/request-info/decision-history.component.scss b/imxweb/projects/qer/src/lib/itshop/request-info/decision-history.component.scss index 64aef0737..933dbc567 100644 --- a/imxweb/projects/qer/src/lib/itshop/request-info/decision-history.component.scss +++ b/imxweb/projects/qer/src/lib/itshop/request-info/decision-history.component.scss @@ -1,4 +1,4 @@ -@import "@elemental-ui/core/src/styles/_palette.scss"; +@import '@elemental-ui/core/src/styles/_palette.scss'; @import '@elemental-ui/core/src/styles/_eui_palette.scss'; :host { display: flex; @@ -7,7 +7,7 @@ } .chief-approval-badge { - margin-bottom: .5em; + margin-bottom: 0.5em; } .imx-reason { @@ -25,7 +25,7 @@ letter-spacing: 0.1em; } -.mat-card-title { +.mat-mdc-card-title { margin-bottom: 15px; :first-child { font-weight: bold; @@ -47,7 +47,7 @@ li.imx-event::before { background-color: $white; height: 24px; width: 28px; - content: ""; + content: ''; float: left; margin-top: -2px; } @@ -61,7 +61,7 @@ li.imx-event.imx-positive::before { font-family: Cadence-Icon; font-size: 24px; color: $aspen-green; - content: "\e049"; + content: '\e049'; } li.imx-event.imx-negative { @@ -73,7 +73,7 @@ li.imx-event.imx-negative::before { font-family: Cadence-Icon; font-size: 24px; color: $phoenix-red; - content: "\e05c"; + content: '\e05c'; } li.imx-event.imx-question { @@ -85,7 +85,7 @@ li.imx-event.imx-question::before { font-family: Cadence-Icon; font-size: 24px; color: $iris-blue; - content: "\e009"; + content: '\e009'; } li.imx-event.imx-info { @@ -97,7 +97,7 @@ li.imx-event.imx-info::before { font-family: Cadence-Icon; font-size: 24px; color: $iris-blue; - content: "\e010"; + content: '\e010'; } li.imx-event.imx-pending { @@ -109,19 +109,18 @@ li.imx-event.imx-pending::before { font-family: Cadence-Icon; font-size: 24px; color: $black-b; - content: "\e009"; + content: '\e009'; } -.mat-card-header { - margin-left: -16px; +.mat-mdc-card-header { margin-bottom: 10px; - .mat-card-title { + .mat-mdc-card-title { font-size: 1.05em; margin-bottom: 0; } - .mat-card-subtitle.imx-approveHistory-pwodecisionstep { + .mat-mdc-card-subtitle.imx-approveHistory-pwodecisionstep { margin: 5px 0; } } @@ -149,10 +148,10 @@ div[step] { } div[step-caption]{ margin-bottom: 10px; - span[caption]{ + span[caption] { font-weight: 600; font-size: 16px; - } + } } div[approver] { @@ -161,7 +160,12 @@ div[approver] { .eui-dark-theme { :host { - li.imx-event.imx-info::before , li.imx-event.imx-pending::before, li.imx-event.imx-question::before, li.imx-event.imx-positive::before , li.imx-event.imx-negative::before, li.imx-event.imx-info::before{ + li.imx-event.imx-info::before, + li.imx-event.imx-pending::before, + li.imx-event.imx-question::before, + li.imx-event.imx-positive::before, + li.imx-event.imx-negative::before, + li.imx-event.imx-info::before { background-color: $color-gray-70; } } @@ -169,7 +173,12 @@ div[approver] { .eui-contrast-theme { :host { - li.imx-event.imx-info::before , li.imx-event.imx-pending::before, li.imx-event.imx-question::before, li.imx-event.imx-positive::before , li.imx-event.imx-negative::before, li.imx-event.imx-info::before{ + li.imx-event.imx-info::before, + li.imx-event.imx-pending::before, + li.imx-event.imx-question::before, + li.imx-event.imx-positive::before, + li.imx-event.imx-negative::before, + li.imx-event.imx-info::before { background-color: $color-gray-90; } } diff --git a/imxweb/projects/qer/src/lib/itshop/request-info/decision-history.component.ts b/imxweb/projects/qer/src/lib/itshop/request-info/decision-history.component.ts index db45595da..528940f0c 100644 --- a/imxweb/projects/qer/src/lib/itshop/request-info/decision-history.component.ts +++ b/imxweb/projects/qer/src/lib/itshop/request-info/decision-history.component.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -24,8 +24,8 @@ * */ -import { Component, Input, OnChanges, OnInit, SimpleChanges } from '@angular/core'; -import { EntityData } from 'imx-qbm-dbts'; +import { Component, Input, OnChanges, SimpleChanges } from '@angular/core'; +import { EntityData } from '@imx-modules/imx-qbm-dbts'; import { DecisionHistoryService } from '../decision-history.service'; import { ApproverContainer } from './approver-container'; @@ -34,20 +34,18 @@ import { WorkflowHistoryItemWrapper } from './workflow-history-item-wrapper'; @Component({ selector: 'imx-decision-history', templateUrl: './decision-history.component.html', - styleUrls: ['./decision-history.component.scss'] + styleUrls: ['./decision-history.component.scss'], }) export class DecisionHistoryComponent implements OnChanges { @Input() public approverContainer: ApproverContainer; @Input() public workflow: WorkflowHistoryItemWrapper[]; - public approverNow:{ display: string; data: EntityData[] }[] = []; - public approverFuture:{ display: string; data: EntityData[] }[] = []; - constructor( - public readonly decisionHistory: DecisionHistoryService - ) { } + public approverNow: { display: string; data: EntityData[] }[] = []; + public approverFuture: { display: string; data: EntityData[] }[] = []; + constructor(public readonly decisionHistory: DecisionHistoryService) {} public ngOnChanges(changes: SimpleChanges): void { - if(changes.approverContainer){ + if (changes.approverContainer) { this.approverFuture = this.approverContainer?.getApproverSortedByStep(); this.approverNow = this.approverContainer?.getApproverSortedByStep(false); } diff --git a/imxweb/projects/qer/src/lib/itshop/request-info/itshop-request-data.spec.ts b/imxweb/projects/qer/src/lib/itshop/request-info/itshop-request-data.spec.ts index ef6c5c472..0f9fb0624 100644 --- a/imxweb/projects/qer/src/lib/itshop/request-info/itshop-request-data.spec.ts +++ b/imxweb/projects/qer/src/lib/itshop/request-info/itshop-request-data.spec.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -24,8 +24,8 @@ * */ -import { IClientProperty } from 'imx-qbm-dbts'; -import { ItshopRequestData } from "./itshop-request-data"; +import { IClientProperty } from '@imx-modules/imx-qbm-dbts'; +import { ItshopRequestData } from './itshop-request-data'; describe('ItshopRequestData', () => { function createParameterData(value, name) { @@ -34,29 +34,23 @@ describe('ItshopRequestData', () => { it('should init request parameters', () => { const propertyColumnName = 'DisplayOrg'; - const properties = { }; + const properties = {}; properties[propertyColumnName] = { ColumnName: propertyColumnName, - GetValue: () => 'some value' + GetValue: () => 'some value', }; const parameters = [ - [ - createParameterData('some value 1.0', '1'), - createParameterData('some value 2.0', '2'), - ], - [ - createParameterData('some value 1.1', '3'), - createParameterData('some value 2.1', '4'), - ] + [createParameterData('some value 1.0', '1'), createParameterData('some value 2.0', '2')], + [createParameterData('some value 1.1', '3'), createParameterData('some value 2.1', '4')], ]; const extendedCollectionData = { index: 0, Parameters: { parameterCategory1: [[parameters[0][0]], [parameters[1][0]]], - parameterCategory2: [[parameters[0][1]], [parameters[1][1]]] - } + parameterCategory2: [[parameters[0][1]], [parameters[1][1]]], + }, }; const request = new ItshopRequestData(extendedCollectionData); diff --git a/imxweb/projects/qer/src/lib/itshop/request-info/itshop-request-data.ts b/imxweb/projects/qer/src/lib/itshop/request-info/itshop-request-data.ts index b4204f83c..68204c6b4 100644 --- a/imxweb/projects/qer/src/lib/itshop/request-info/itshop-request-data.ts +++ b/imxweb/projects/qer/src/lib/itshop/request-info/itshop-request-data.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -24,8 +24,8 @@ * */ -import { PwoData, PwoExtendedData } from 'imx-api-qer'; -import { ParameterData } from 'imx-qbm-dbts'; +import { PwoData, PwoExtendedData } from '@imx-modules/imx-api-qer'; +import { ParameterData } from '@imx-modules/imx-qbm-dbts'; export class ItshopRequestData { public readonly parameters: ParameterData[] = []; @@ -33,10 +33,10 @@ export class ItshopRequestData { constructor(extendedCollectionData: { index: number } & PwoExtendedData) { if (extendedCollectionData.Parameters) { - Object.keys(extendedCollectionData.Parameters).forEach(parameterCategoryName => { - const parameterCategory = extendedCollectionData.Parameters[parameterCategoryName]; + Object.keys(extendedCollectionData.Parameters).forEach((parameterCategoryName) => { + const parameterCategory = extendedCollectionData.Parameters?.[parameterCategoryName]; if (parameterCategory && parameterCategory[extendedCollectionData.index]) { - parameterCategory[extendedCollectionData.index].forEach(parameterData => this.parameters.push(parameterData)); + parameterCategory[extendedCollectionData.index].forEach((parameterData) => this.parameters.push(parameterData)); } }); } diff --git a/imxweb/projects/qer/src/lib/itshop/request-info/itshop-request-entity-wrapper.interface.ts b/imxweb/projects/qer/src/lib/itshop/request-info/itshop-request-entity-wrapper.interface.ts index 12463f9b8..dc7cb4f6f 100644 --- a/imxweb/projects/qer/src/lib/itshop/request-info/itshop-request-entity-wrapper.interface.ts +++ b/imxweb/projects/qer/src/lib/itshop/request-info/itshop-request-entity-wrapper.interface.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -24,8 +24,8 @@ * */ -import { IEntity, IEntityColumn } from 'imx-qbm-dbts'; -import { PwoData } from 'imx-api-qer'; +import { PwoData } from '@imx-modules/imx-api-qer'; +import { IEntity, IEntityColumn } from '@imx-modules/imx-qbm-dbts'; export interface ItshopRequestEntityWrapper { entity: IEntity; @@ -33,5 +33,5 @@ export interface ItshopRequestEntityWrapper { uidCurrentUser?: string; isChiefApproval?: boolean; parameterColumns: IEntityColumn[]; - commit?: () => Promise; + commit: () => Promise; } diff --git a/imxweb/projects/qer/src/lib/itshop/request-info/ordered-working-step.interface.ts b/imxweb/projects/qer/src/lib/itshop/request-info/ordered-working-step.interface.ts index dd3a794f0..46c034edb 100644 --- a/imxweb/projects/qer/src/lib/itshop/request-info/ordered-working-step.interface.ts +++ b/imxweb/projects/qer/src/lib/itshop/request-info/ordered-working-step.interface.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR diff --git a/imxweb/projects/qer/src/lib/itshop/request-info/request-info.component.html b/imxweb/projects/qer/src/lib/itshop/request-info/request-info.component.html index f907175e6..fa2dfc73e 100644 --- a/imxweb/projects/qer/src/lib/itshop/request-info/request-info.component.html +++ b/imxweb/projects/qer/src/lib/itshop/request-info/request-info.component.html @@ -1,5 +1,5 @@ - +
    @@ -8,12 +8,12 @@ - + - #LDS#Information on the associated service item - + #LDS#Information on the associated service item + @@ -22,7 +22,7 @@ -
    +
    @@ -30,14 +30,17 @@ -
    +
    - + @@ -45,5 +48,4 @@ --> - diff --git a/imxweb/projects/qer/src/lib/itshop/request-info/request-info.component.scss b/imxweb/projects/qer/src/lib/itshop/request-info/request-info.component.scss index 0f79b45f7..24e4b29e6 100644 --- a/imxweb/projects/qer/src/lib/itshop/request-info/request-info.component.scss +++ b/imxweb/projects/qer/src/lib/itshop/request-info/request-info.component.scss @@ -1,4 +1,4 @@ -@import "@elemental-ui/core/src/styles/_eui_palette.scss"; +@import '@elemental-ui/core/src/styles/_eui_palette.scss'; :host { display: flex; flex-direction: column; @@ -15,26 +15,6 @@ align-items: center; } - .mat-tab-group { - height: 100%; - overflow: hidden; - - ::ng-deep .mat-tab-body-wrapper { - flex: 1 1 auto; - - .mat-tab-body-content { - height: 100%; - overflow: hidden; - display: flex; - flex-direction: column; - } - } - } - - ::ng-deep .eui-alert { - margin-bottom: 20px; - } - .imx-additional-info { margin: 0 20px 20px; @@ -51,10 +31,15 @@ .imx-request-entitlements, .imx-request-history, .imx-request-item-detail { - margin: 20px; + padding: 20px; overflow: auto; } + .imx-request-history { + padding-bottom: 3px; + padding-right: 3px; + } + .imx-request-entitlements { display: flex; flex-direction: column; @@ -69,32 +54,8 @@ .imx-request-item-detail mat-card { background-color: transparent; } - imx-ext{ + imx-ext { height: 100%; overflow: auto; } } - -:host { - ::ng-deep .mat-tab-labels { - background-color: $color-gray-0; - } -} - -.eui-dark-theme { - :host { - background-color: $color-gray-80; - ::ng-deep .mat-tab-labels { - background-color: $color-gray-80; - } - } -} - -.eui-contrast-theme { - :host { - background-color: $color-gray-90; - ::ng-deep .mat-tab-labels { - background-color: $color-gray-90; - } - } -} diff --git a/imxweb/projects/qer/src/lib/itshop/request-info/request-info.component.ts b/imxweb/projects/qer/src/lib/itshop/request-info/request-info.component.ts index a1c44e0a3..ea8f836e8 100644 --- a/imxweb/projects/qer/src/lib/itshop/request-info/request-info.component.ts +++ b/imxweb/projects/qer/src/lib/itshop/request-info/request-info.component.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -24,18 +24,18 @@ * */ -import { OverlayRef } from '@angular/cdk/overlay'; -import { Component, OnInit, Input, OnDestroy } from '@angular/core';import { Subscription } from 'rxjs'; +import { Component, Input, OnDestroy, OnInit } from '@angular/core'; +import { Subscription } from 'rxjs'; +import { PortalShopServiceitems, QerProjectConfig } from '@imx-modules/imx-api-qer'; +import moment from 'moment'; import { BaseReadonlyCdr, BusyService, ClassloggerService, ColumnDependentReference, ExtService, IExtension } from 'qbm'; import { ProjectConfigurationService } from '../../project-configuration/project-configuration.service'; -import { ApproverContainer } from './approver-container'; +import { DecisionHistoryService } from '../decision-history.service'; import { ItshopService } from '../itshop.service'; +import { ApproverContainer } from './approver-container'; import { RequestParameterDataEntity } from './request-parameter-data-entity.interface'; import { WorkflowHistoryItemWrapper } from './workflow-history-item-wrapper'; -import { DecisionHistoryService } from '../decision-history.service'; -import { PortalShopServiceitems, QerProjectConfig } from 'imx-api-qer'; - @Component({ templateUrl: './request-info.component.html', @@ -48,13 +48,13 @@ export class RequestInfoComponent implements OnInit, OnDestroy { @Input() public userId: string; @Input() public isApproval: boolean; - public parameters: BaseReadonlyCdr[]; + public parameters: (BaseReadonlyCdr | undefined)[]; public propertyInfo: ColumnDependentReference[]; public approverContainer: ApproverContainer; public workflow: WorkflowHistoryItemWrapper[]; public readonly ruleViolationDetailId = 'cpl.ruleViolationDetail'; public extensions: IExtension[] = []; - public serviceItem: PortalShopServiceitems; + public serviceItem: PortalShopServiceitems | undefined; public projectConfig: QerProjectConfig; public isRoleAssignment: boolean; public isLoading = false; @@ -67,26 +67,29 @@ export class RequestInfoComponent implements OnInit, OnDestroy { private readonly logger: ClassloggerService, private readonly itshopService: ItshopService, private readonly decisionHistory: DecisionHistoryService, - private readonly ext: ExtService + private readonly ext: ExtService, ) { this.extensions = this.ext.Registry[this.ruleViolationDetailId]; this.subscriptions.push( this.busyService.busyStateChanged.subscribe((state: boolean) => { this.isLoading = state; - }) + }), ); } public async ngOnInit(): Promise { - const isBusy = this.busyService.beginBusy(); try { this.projectConfig = await this.projectConfigService.getConfig(); this.propertyInfo = this.request == null || this.request.propertyInfo == null ? [] : this.request.propertyInfo.filter((elem) => this.isForView(elem)); - this.parameters = this.request.parameterColumns.map((column) => new BaseReadonlyCdr(column)); + this.parameters = this.request.parameterColumns + .map((column) => { + return column != null ? new BaseReadonlyCdr(column) : undefined; + }) + .filter((elem) => elem != null); this.approverContainer = new ApproverContainer( { @@ -95,22 +98,30 @@ export class RequestInfoComponent implements OnInit, OnDestroy { isInWorkflow: ['OrderProduct', 'OrderUnsubscribe', 'OrderProlongate'].includes(this.request.UiOrderState.value), pwoData: this.request.pwoData, approvers: (await this.itshopService.getApprovers(this.request.GetEntity().GetKeys()[0])).Data.map( - (elem) => elem.UID_Person.value + (elem) => elem.UID_Person.value, ), }, this.projectConfig.ITShopConfig, - this.logger + this.logger, ); this.workflow = this.itshopService .createTypedHistory(this.request.pwoData) - .map((item) => new WorkflowHistoryItemWrapper(item, this.decisionHistory)); + .map((item) => new WorkflowHistoryItemWrapper(item, this.decisionHistory)) + .sort((item1, item2) => { + if (item1.approveHistory.XDateInserted.value && item2.approveHistory.XDateInserted.value) + return moment(item1.approveHistory.XDateInserted.value).isAfter(item2.approveHistory.XDateInserted.value) ? 1 : -1; + + return moment(item1.approveHistory.DateHead.value).isAfter(item2.approveHistory.DateHead.value) ? 1 : -1; + }); this.isRoleAssignment = ['ESet', 'QERAssign'].includes(this.request.TableName.value); if (!this.isRoleAssignment) { - this.serviceItem = await this.itshopService.getServiceItem(this.request.UID_AccProduct.value, + this.serviceItem = await this.itshopService.getServiceItem( + this.request.UID_AccProduct.value, // if the service item is not in the catalog, just use null - true); + true, + ); } } finally { isBusy.endBusy(); diff --git a/imxweb/projects/qer/src/lib/itshop/request-info/request-parameter-data-entity.interface.ts b/imxweb/projects/qer/src/lib/itshop/request-info/request-parameter-data-entity.interface.ts index 63f9b9e4e..c5b108c85 100644 --- a/imxweb/projects/qer/src/lib/itshop/request-info/request-parameter-data-entity.interface.ts +++ b/imxweb/projects/qer/src/lib/itshop/request-info/request-parameter-data-entity.interface.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -24,8 +24,8 @@ * */ -import { IReadValue, IEntityColumn, IEntity } from 'imx-qbm-dbts'; -import { PwoData } from 'imx-api-qer'; +import { PwoData } from '@imx-modules/imx-api-qer'; +import { IEntity, IEntityColumn, IReadValue } from '@imx-modules/imx-qbm-dbts'; import { ColumnDependentReference } from 'qbm'; export interface RequestParameterDataEntity { @@ -35,7 +35,7 @@ export interface RequestParameterDataEntity { propertyInfo: ColumnDependentReference[]; pwoData: PwoData; qerWorkingMethod?: string; - parameterColumns: IEntityColumn[]; + parameterColumns: (IEntityColumn | undefined)[]; GetEntity: () => IEntity; complianceRuleViolation?: boolean; isArchived?: boolean; diff --git a/imxweb/projects/qer/src/lib/itshop/request-info/service-item-detail/product-details.service.ts b/imxweb/projects/qer/src/lib/itshop/request-info/service-item-detail/product-details.service.ts index bf83f9719..a0eaa3404 100644 --- a/imxweb/projects/qer/src/lib/itshop/request-info/service-item-detail/product-details.service.ts +++ b/imxweb/projects/qer/src/lib/itshop/request-info/service-item-detail/product-details.service.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -26,28 +26,24 @@ import { Injectable } from '@angular/core'; -import { PortalShopServiceitemsEntitlements } from 'imx-api-qer'; -import { CollectionLoadParameters, EntitySchema, ExtendedTypedEntityCollection } from 'imx-qbm-dbts'; +import { PortalShopServiceitemsEntitlements } from '@imx-modules/imx-api-qer'; +import { CollectionLoadParameters, EntitySchema, ExtendedTypedEntityCollection } from '@imx-modules/imx-qbm-dbts'; import { QerApiService } from '../../../qer-api-client.service'; @Injectable({ - providedIn: 'root' + providedIn: 'root', }) export class ProductDetailsService { - - constructor( - private readonly qerapiService: QerApiService - ) { } - + constructor(private readonly qerapiService: QerApiService) {} public get productEntitlementSchema(): EntitySchema { return this.qerapiService.typedClient.PortalShopServiceitemsEntitlements.GetSchema(); } - public async getRoleEntitlements(uidAccProduct: string, parameter?: CollectionLoadParameters): - Promise> { + public async getRoleEntitlements( + uidAccProduct: string, + parameter?: CollectionLoadParameters, + ): Promise> { return this.qerapiService.typedClient.PortalShopServiceitemsEntitlements.Get(uidAccProduct, parameter); } - - } diff --git a/imxweb/projects/qer/src/lib/itshop/request-info/service-item-detail/product-entitlements/product-entitlements.component.html b/imxweb/projects/qer/src/lib/itshop/request-info/service-item-detail/product-entitlements/product-entitlements.component.html index 8ce91349f..619d2a1e7 100644 --- a/imxweb/projects/qer/src/lib/itshop/request-info/service-item-detail/product-entitlements/product-entitlements.component.html +++ b/imxweb/projects/qer/src/lib/itshop/request-info/service-item-detail/product-entitlements/product-entitlements.component.html @@ -1,27 +1,41 @@ - + - {{helperText}} + {{ helperText }} - - + + - - + + - {{item.TargetEntitlement.Column.GetDisplayValue()}} + {{ item.TargetEntitlement.Column.GetDisplayValue() }} - + -
    {{entitlementTypes.get(item.GetEntity().GetKeys().toString())}}
    +
    {{ entitlementTypes.get(item.GetEntity().GetKeys().toString()) }}
    -
    \ No newline at end of file +
    diff --git a/imxweb/projects/qer/src/lib/itshop/request-info/service-item-detail/product-entitlements/product-entitlements.component.scss b/imxweb/projects/qer/src/lib/itshop/request-info/service-item-detail/product-entitlements/product-entitlements.component.scss index 681be1f52..71541833c 100644 --- a/imxweb/projects/qer/src/lib/itshop/request-info/service-item-detail/product-entitlements/product-entitlements.component.scss +++ b/imxweb/projects/qer/src/lib/itshop/request-info/service-item-detail/product-entitlements/product-entitlements.component.scss @@ -3,32 +3,4 @@ display: flex; flex-direction: column; flex: 1 1 auto; - - - .mat-card { - display: flex; - flex-direction: column; - flex: 1 1 auto; - margin: 3px; - } -} - -.imx-helper-alert { - margin-bottom: 15px; -} - -.eui-dark-theme { - :host { - .imx-helper-alert { - color: $color-gray-2; - } - } -} - -.eui-contrast-theme { - :host { - .imx-helper-alert { - color: $color-gray-0; - } - } } diff --git a/imxweb/projects/qer/src/lib/itshop/request-info/service-item-detail/product-entitlements/product-entitlements.component.ts b/imxweb/projects/qer/src/lib/itshop/request-info/service-item-detail/product-entitlements/product-entitlements.component.ts index 966f5248d..cc7641c2c 100644 --- a/imxweb/projects/qer/src/lib/itshop/request-info/service-item-detail/product-entitlements/product-entitlements.component.ts +++ b/imxweb/projects/qer/src/lib/itshop/request-info/service-item-detail/product-entitlements/product-entitlements.component.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -24,26 +24,25 @@ * */ -import { OverlayRef } from '@angular/cdk/overlay'; import { Component, Input, OnInit } from '@angular/core'; import { EuiLoadingService } from '@elemental-ui/core'; -import { PortalShopServiceitemsEntitlements } from 'imx-api-qer'; -import { CollectionLoadParameters, DbObjectKey, DisplayColumns, EntitySchema, IClientProperty, ValType } from 'imx-qbm-dbts'; +import { PortalShopServiceitemsEntitlements } from '@imx-modules/imx-api-qer'; +import { CollectionLoadParameters, DbObjectKey, DisplayColumns, EntitySchema, ValType } from '@imx-modules/imx-qbm-dbts'; import { ClientPropertyForTableColumns, DataSourceToolbarSettings, MetadataService } from 'qbm'; import { ProductDetailsService } from '../product-details.service'; @Component({ selector: 'imx-product-entitlements', templateUrl: './product-entitlements.component.html', - styleUrls: ['./product-entitlements.component.scss'] + styleUrls: ['./product-entitlements.component.scss'], }) export class ProductEntitlementsComponent implements OnInit { - public dstSettings: DataSourceToolbarSettings; public entitySchema: EntitySchema; public DisplayColumns = DisplayColumns; public showHelperAlert = true; - public helperText = '#LDS#Here you can get an overview of the entitlements associated with the product. If you approve the request, the recipient will get the following entitlements.'; + public helperText = + '#LDS#Here you can get an overview of the entitlements associated with the product. If you approve the request, the recipient will get the following entitlements.'; @Input() public uidAccProduct: string; public entitlementTypes: Map; @@ -53,16 +52,16 @@ export class ProductEntitlementsComponent implements OnInit { constructor( private readonly busy: EuiLoadingService, private readonly metadata: MetadataService, - private readonly detailsProvider: ProductDetailsService + private readonly detailsProvider: ProductDetailsService, ) { this.entitySchema = detailsProvider.productEntitlementSchema; this.displayColumns = this.displayColumns = [ { Type: ValType.String, ColumnName: 'entitlementDisplay', - untranslatedDisplay: '#LDS#Actions' + untranslatedDisplay: '#LDS#Actions', }, - this.entitySchema.Columns.TargetEntitlement + this.entitySchema.Columns.TargetEntitlement, ]; } @@ -79,33 +78,32 @@ export class ProductEntitlementsComponent implements OnInit { } public async navigate(parameter?: CollectionLoadParameters): Promise { - let overlay: OverlayRef; - setTimeout(() => { overlay = this.busy.show(); }); + if (this.busy.overlayRefs.length === 0) { + this.busy.show(); + } try { const dataSource = await this.detailsProvider.getRoleEntitlements(this.uidAccProduct, parameter); this.entitlementTypes = new Map(); - dataSource.Data.forEach(async item => { + dataSource.Data.forEach(async (item) => { this.entitlementTypes.set(item.GetEntity().GetKeys().toString(), await this.getTypeDescription(item)); }); this.dstSettings = { dataSource, entitySchema: this.entitySchema, - navigationState: parameter, + navigationState: parameter || {}, displayedColumns: this.displayColumns, }; } finally { - setTimeout(() => { this.busy.hide(overlay); }); + this.busy.hide(); } - } private async getTypeDescription(item: PortalShopServiceitemsEntitlements): Promise { const objKey = DbObjectKey.FromXml(item.TargetEntitlement.value); const metadata = await this.metadata.GetTableMetadata(objKey.TableName); - return metadata.DisplaySingular; + return metadata?.DisplaySingular || ''; } - } diff --git a/imxweb/projects/qer/src/lib/itshop/request-info/service-item-detail/service-item-detail.component.html b/imxweb/projects/qer/src/lib/itshop/request-info/service-item-detail/service-item-detail.component.html index 996f6b5d0..47eacb93b 100644 --- a/imxweb/projects/qer/src/lib/itshop/request-info/service-item-detail/service-item-detail.component.html +++ b/imxweb/projects/qer/src/lib/itshop/request-info/service-item-detail/service-item-detail.component.html @@ -1,3 +1,3 @@ - - - + + + diff --git a/imxweb/projects/qer/src/lib/itshop/request-info/service-item-detail/service-item-detail.component.scss b/imxweb/projects/qer/src/lib/itshop/request-info/service-item-detail/service-item-detail.component.scss deleted file mode 100644 index 0578d5e4a..000000000 --- a/imxweb/projects/qer/src/lib/itshop/request-info/service-item-detail/service-item-detail.component.scss +++ /dev/null @@ -1,6 +0,0 @@ -:host { - - .mat-card { - margin:3px; - } -} diff --git a/imxweb/projects/qer/src/lib/itshop/request-info/service-item-detail/service-item-detail.component.ts b/imxweb/projects/qer/src/lib/itshop/request-info/service-item-detail/service-item-detail.component.ts index 53c1f2c84..26ef4ae7e 100644 --- a/imxweb/projects/qer/src/lib/itshop/request-info/service-item-detail/service-item-detail.component.ts +++ b/imxweb/projects/qer/src/lib/itshop/request-info/service-item-detail/service-item-detail.component.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -25,14 +25,13 @@ */ import { Component, Input, OnInit } from '@angular/core'; -import { PortalShopServiceitems, QerProjectConfig } from 'imx-api-qer'; -import { DisplayColumns } from 'imx-qbm-dbts'; -import { ColumnDependentReference, BaseReadonlyCdr } from 'qbm'; +import { PortalShopServiceitems, QerProjectConfig } from '@imx-modules/imx-api-qer'; +import { DisplayColumns } from '@imx-modules/imx-qbm-dbts'; +import { BaseReadonlyCdr, ColumnDependentReference } from 'qbm'; @Component({ selector: 'imx-service-item-detail', templateUrl: './service-item-detail.component.html', - styleUrls: ['./service-item-detail.component.scss'] }) export class ServiceItemDetailComponent implements OnInit { @Input() public serviceItem: PortalShopServiceitems; @@ -42,19 +41,16 @@ export class ServiceItemDetailComponent implements OnInit { public isRoleAssignment = true; - constructor() { } + constructor() {} public async ngOnInit(): Promise { - this.cdrList = [ new BaseReadonlyCdr(this.serviceItem.GetEntity().GetColumn(DisplayColumns.DISPLAY_PROPERTYNAME)), new BaseReadonlyCdr(this.serviceItem.TableName.Column), - new BaseReadonlyCdr(this.serviceItem.Tags.Column) + new BaseReadonlyCdr(this.serviceItem.Tags.Column), ]; - const properties = this.projectConfig.ITShopConfig.AccProductProperties; - this.cdrList = this.cdrList.concat( - properties.map(prop => new BaseReadonlyCdr(this.serviceItem.GetEntity().GetColumn(prop)))); + const properties = this.projectConfig.ITShopConfig?.AccProductProperties; + this.cdrList = this.cdrList.concat(properties?.map((prop) => new BaseReadonlyCdr(this.serviceItem.GetEntity().GetColumn(prop))) || []); } - } diff --git a/imxweb/projects/qer/src/lib/itshop/request-info/workflow-history-item-wrapper.spec.ts b/imxweb/projects/qer/src/lib/itshop/request-info/workflow-history-item-wrapper.spec.ts index 00acc560d..5a6e167be 100644 --- a/imxweb/projects/qer/src/lib/itshop/request-info/workflow-history-item-wrapper.spec.ts +++ b/imxweb/projects/qer/src/lib/itshop/request-info/workflow-history-item-wrapper.spec.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -24,7 +24,7 @@ * */ -import { PortalItshopApproveHistory } from 'imx-api-qer'; +import { PortalItshopApproveHistory } from '@imx-modules/imx-api-qer'; import { DecisionHistoryService } from '../decision-history.service'; import { WorkflowHistoryItemWrapper } from './workflow-history-item-wrapper'; @@ -33,18 +33,18 @@ function createProperty(name?, value?, display?) { ColumnName: name, GetValue: () => value, GetDisplayValue: () => value, - GetMetadata: () => ({ GetDisplay: () => display || name }) + GetMetadata: () => ({ GetDisplay: () => display || name }), }; return { value: value, Column: column, - GetMetadata: () => column.GetMetadata() + GetMetadata: () => column.GetMetadata(), }; } describe('WorkflowHistoryItemWrapper', () => { - const expectedDefaultColumns: { name: string, display?: string }[] = []; + const expectedDefaultColumns: { name: string; display?: string }[] = []; for (const testcase of [ {}, @@ -63,7 +63,7 @@ describe('WorkflowHistoryItemWrapper', () => { { decisionType: 'Unsubscribe' }, { decisionType: 'Deny' }, { decisionType: 'AddAdditional' }, - { decisionType: 'AddAdditional', personRelated: 'value', expectedAdditionalColumns: [{ name: 'UID_PersonRelated' }] } + { decisionType: 'AddAdditional', personRelated: 'value', expectedAdditionalColumns: [{ name: 'UID_PersonRelated' }] }, ]) { it('can be initialized with data', () => { const expectedColumns = expectedDefaultColumns.concat(testcase.expectedAdditionalColumns || []); @@ -77,18 +77,18 @@ describe('WorkflowHistoryItemWrapper', () => { UID_PWODecisionRule: createProperty('UID_PWODecisionRule', testcase.pwoDecisionRule), UID_PersonRelated: createProperty('UID_PersonRelated', testcase.personRelated), IsFromDelegation: createProperty('IsFromDelegation', testcase.isFromDelegation), - IsDecisionBySystem: createProperty('IsDecisionBySystem') + IsDecisionBySystem: createProperty('IsDecisionBySystem'), } as PortalItshopApproveHistory; - const decision = { } as DecisionHistoryService; + const decision = {} as DecisionHistoryService; - const historyItemWrapper = new WorkflowHistoryItemWrapper(history,decision); + const historyItemWrapper = new WorkflowHistoryItemWrapper(history, decision); expect(historyItemWrapper.approveHistory).toEqual(history); expect(historyItemWrapper.columns.length).toEqual(expectedColumns.length); - expectedColumns.forEach(expectedColumn => { - const cdr = historyItemWrapper.columns.find(cdr => cdr.column.ColumnName === expectedColumn.name); + expectedColumns.forEach((expectedColumn) => { + const cdr = historyItemWrapper.columns.find((cdr) => cdr.column.ColumnName === expectedColumn.name); expect(cdr.column).toBeDefined(); if (expectedColumn.display) { expect(cdr.display).toContain(expectedColumn.display); @@ -108,7 +108,7 @@ describe('WorkflowHistoryItemWrapper', () => { { decisionType: 'Query', reason: 'value', expectedDisplay: 'Query' }, { decisionType: 'Create', reason: 'value', expectedDisplay: 'ReasonHead' }, { decisionType: 'Order', reason: 'value', expectedDisplay: 'ReasonHead' }, - ].forEach(testcase => + ].forEach((testcase) => it('should getReasonDisplay', () => { const history = { DecisionType: createProperty('DecisionType', testcase.decisionType), @@ -119,10 +119,11 @@ describe('WorkflowHistoryItemWrapper', () => { RulerLevel: {}, } as PortalItshopApproveHistory; - const decision = { getColumnDescriptionForDisplayPersonHead: orderType => orderType} as DecisionHistoryService; + const decision = { getColumnDescriptionForDisplayPersonHead: (orderType) => orderType } as DecisionHistoryService; - const historyItemWrapper = new WorkflowHistoryItemWrapper(history,decision); + const historyItemWrapper = new WorkflowHistoryItemWrapper(history, decision); expect(historyItemWrapper.getReasonDisplay()).toContain(testcase.expectedDisplay); - })); + }), + ); }); diff --git a/imxweb/projects/qer/src/lib/itshop/request-info/workflow-history-item-wrapper.ts b/imxweb/projects/qer/src/lib/itshop/request-info/workflow-history-item-wrapper.ts index d18795399..763ac3b6d 100644 --- a/imxweb/projects/qer/src/lib/itshop/request-info/workflow-history-item-wrapper.ts +++ b/imxweb/projects/qer/src/lib/itshop/request-info/workflow-history-item-wrapper.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -24,18 +24,20 @@ * */ -import { PortalItshopApproveHistory } from 'imx-api-qer'; -import { IReadValue } from 'imx-qbm-dbts'; +import { PortalItshopApproveHistory } from '@imx-modules/imx-api-qer'; +import { IReadValue } from '@imx-modules/imx-qbm-dbts'; import { BaseReadonlyCdr, ColumnDependentReference } from 'qbm'; import { DecisionHistoryService } from '../decision-history.service'; export class WorkflowHistoryItemWrapper { - public readonly approver: ColumnDependentReference; - public readonly columns: ColumnDependentReference[]; + public readonly approver: ColumnDependentReference | undefined; + public readonly columns: (ColumnDependentReference | undefined)[]; - constructor(public readonly approveHistory: PortalItshopApproveHistory, public readonly decisionHistory: DecisionHistoryService) { - this.approver = this.createApproverCdr(this.approveHistory), - this.columns = this.createCdrList(this.approveHistory); + constructor( + public readonly approveHistory: PortalItshopApproveHistory, + public readonly decisionHistory: DecisionHistoryService, + ) { + (this.approver = this.createApproverCdr(this.approveHistory)), (this.columns = this.createCdrList(this.approveHistory)); } public getReasonDisplay(): string { @@ -48,10 +50,12 @@ export class WorkflowHistoryItemWrapper { return this.approveHistory.ReasonHead.GetMetadata().GetDisplay(); } - private createApproverCdr(historyItem: PortalItshopApproveHistory): BaseReadonlyCdr { + private createApproverCdr(historyItem: PortalItshopApproveHistory): BaseReadonlyCdr | undefined { if (historyItem.DisplayPersonHead.value) { - return new BaseReadonlyCdr(historyItem.DisplayPersonHead.Column, - this.decisionHistory.getColumnDescriptionForDisplayPersonHead(historyItem.DecisionType.value)); + return new BaseReadonlyCdr( + historyItem.DisplayPersonHead.Column, + this.decisionHistory.getColumnDescriptionForDisplayPersonHead(historyItem.DecisionType.value), + ); } if (historyItem.IsDecisionBySystem.value) { @@ -61,7 +65,7 @@ export class WorkflowHistoryItemWrapper { return undefined; } - private createCdrList(historyItem: PortalItshopApproveHistory): BaseReadonlyCdr[] { + private createCdrList(historyItem: PortalItshopApproveHistory): (BaseReadonlyCdr | undefined)[] { const properties = [ historyItem.RulerLevel.value !== 0 ? historyItem.RulerLevel : undefined, historyItem.UID_PWODecisionRule, @@ -69,7 +73,7 @@ export class WorkflowHistoryItemWrapper { historyItem.IsFromDelegation, historyItem.ValidUntil, historyItem.ValidUntilProlongation, - historyItem.ValidUntilUnsubscribe + historyItem.ValidUntilUnsubscribe, ]; const customDisplays = { @@ -77,19 +81,25 @@ export class WorkflowHistoryItemWrapper { historyItem.DecisionType.value === 'AddInsteadOf' ? '#LDS#Delegated approver' : historyItem.DecisionType.value === 'AddAdditional' - ? '#LDS#Additional approver' - : historyItem.DecisionType.value === 'Query' - ? '#LDS#Recipient' - : undefined, + ? '#LDS#Additional approver' + : historyItem.DecisionType.value === 'Query' + ? '#LDS#Recipient' + : undefined, }; - return properties.filter(property => this.isToView(property)).map(property => - new BaseReadonlyCdr(property.Column, customDisplays[property.Column.ColumnName]) - ); + return properties + .filter((property) => property?.Column != null && this.isToView(property)) + .map((property) => { + return property?.Column == null + ? undefined + : new BaseReadonlyCdr(property?.Column, customDisplays[property?.Column.ColumnName || '']); + }); } - private isToView(property: IReadValue): boolean { - if (!property || property.value == null || property.value === '') { return false; } + private isToView(property: IReadValue | undefined): boolean { + if (!property || property.value == null || property.value === '') { + return false; + } return property.Column.ColumnName !== 'IsFromDelegation' || property.value; } } diff --git a/imxweb/projects/qer/src/lib/itshop/shelf-selection-sidesheet.model.ts b/imxweb/projects/qer/src/lib/itshop/shelf-selection-sidesheet.model.ts index 9ea3bbbbb..f4a8bc47c 100644 --- a/imxweb/projects/qer/src/lib/itshop/shelf-selection-sidesheet.model.ts +++ b/imxweb/projects/qer/src/lib/itshop/shelf-selection-sidesheet.model.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -25,21 +25,20 @@ */ export interface ShelfObject { - uidItShopOrg: string; - displayShelf: string; + uidItShopOrg?: string; + displayShelf?: string; } export interface PersonForProduct { uidItShopOrg?: string; - uidPerson: string; - displayPerson: string; + uidPerson?: string; + displayPerson?: string; shelfsObjects: ShelfObject[]; } export interface ShelfSelectionObject { - uidAccproduct: string; - displayAccProduct: string; + uidAccproduct?: string; + displayAccProduct?: string; personsForProduct: PersonForProduct[]; possibleShelfObjects: ShelfObject[]; } - diff --git a/imxweb/projects/qer/src/lib/itshop/shelf-selection.component.html b/imxweb/projects/qer/src/lib/itshop/shelf-selection.component.html index 1813bcd76..f96e3ade1 100644 --- a/imxweb/projects/qer/src/lib/itshop/shelf-selection.component.html +++ b/imxweb/projects/qer/src/lib/itshop/shelf-selection.component.html @@ -1,40 +1,47 @@
    - - #LDS#One or more selected products are included in several shelves. For each product, select from which shelf you want to request the product. You can select a default shelf that will be used for all recipients or select a shelf individually for each recipient. + + {{ LdsKey }}
    - - + - {{shelfSelectionObject.displayAccProduct}} + {{ shelfSelectionObject.displayAccProduct }}
    - - {{'#LDS#Select a default shelf' | translate}} - - - {{so.displayShelf}} + + {{ '#LDS#Select a default shelf' | translate }} + + + {{ so.displayShelf }}
    - {{personForProduct.displayPerson}}
    + {{ personForProduct.displayPerson }} +
    - {{'#LDS#Select a shelf' | translate}} + {{ '#LDS#Select a shelf' | translate }} - - {{so.displayShelf}} + [attr.data-imx-identifier]="'shelf-selection-person-shelf-object-' + personForProduct.uidPerson" + [formControl]="getFormControl(shelfSelectionObject, personForProduct)" + [required]="true" + > + + {{ so.displayShelf }} @@ -42,12 +49,17 @@
    -
    -
    - -
    \ No newline at end of file + +
    diff --git a/imxweb/projects/qer/src/lib/itshop/shelf-selection.component.scss b/imxweb/projects/qer/src/lib/itshop/shelf-selection.component.scss index a2ed29334..0e16a6f6b 100644 --- a/imxweb/projects/qer/src/lib/itshop/shelf-selection.component.scss +++ b/imxweb/projects/qer/src/lib/itshop/shelf-selection.component.scss @@ -1,4 +1,4 @@ -@import "@elemental-ui/core/src/styles/_palette.scss"; +@import '@elemental-ui/core/src/styles/_palette.scss'; @import '@elemental-ui/core/src/styles/_eui_palette.scss'; :host { @@ -22,7 +22,7 @@ } } -.eui-sidesheet-actions.mat-card { +.eui-sidesheet-actions.mat-mdc-card { margin: 0; display: flex; justify-content: flex-end; @@ -51,18 +51,13 @@ white-space: nowrap; } -.mat-form-field { +.mat-mdc-form-field { margin-bottom: -20px; } -.imx-helper-alert { - margin-bottom: 20px; - display: block; -} - .eui-dark-theme { :host { - .eui-sidesheet-actions.mat-card { + .eui-sidesheet-actions.mat-mdc-card { background-color: $color-gray-70; } } @@ -70,7 +65,7 @@ .eui-contrast-theme { :host { - .eui-sidesheet-actions.mat-card { + .eui-sidesheet-actions.mat-mdc-card { background-color: $color-gray-90; } } diff --git a/imxweb/projects/qer/src/lib/itshop/shelf-selection.component.ts b/imxweb/projects/qer/src/lib/itshop/shelf-selection.component.ts index 1d017ef09..f6cc99446 100644 --- a/imxweb/projects/qer/src/lib/itshop/shelf-selection.component.ts +++ b/imxweb/projects/qer/src/lib/itshop/shelf-selection.component.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -26,19 +26,17 @@ import { Component, Inject } from '@angular/core'; import { UntypedFormControl, UntypedFormGroup, Validators } from '@angular/forms'; -import { EuiSidesheetRef, EUI_SIDESHEET_DATA } from '@elemental-ui/core'; +import { EUI_SIDESHEET_DATA, EuiSidesheetRef } from '@elemental-ui/core'; import { PersonForProduct, ShelfObject, ShelfSelectionObject } from './shelf-selection-sidesheet.model'; @Component({ selector: 'imx-shelf-selection', templateUrl: './shelf-selection.component.html', - styleUrls: ['./shelf-selection.component.scss'] + styleUrls: ['./shelf-selection.component.scss'], }) export class ShelfSelectionComponent { - public showHelperAlert = true; - public shelfSelectionObjects: ShelfSelectionObject[] = []; public formGroup: UntypedFormGroup; @@ -46,16 +44,17 @@ export class ShelfSelectionComponent { constructor( @Inject(EUI_SIDESHEET_DATA) public data: ShelfSelectionObject[], - public readonly sideSheetRef: EuiSidesheetRef) { + public readonly sideSheetRef: EuiSidesheetRef, + ) { this.setup(); } public optionSelected(uidItShopOrg: string, uidAccproduct: string): void { const group = this.formGroup.get(uidAccproduct) as UntypedFormGroup; - const persons = this.shelfSelectionObjects.find(elem => elem.uidAccproduct === uidAccproduct); - persons.personsForProduct.forEach(person => { - const control = group.get(person.uidPerson); - if (control?.value === '' && person.shelfsObjects.some(shelf => shelf.uidItShopOrg === uidItShopOrg)) { + const persons = this.shelfSelectionObjects.find((elem) => elem.uidAccproduct === uidAccproduct); + persons?.personsForProduct.forEach((person) => { + const control = group.get(person.uidPerson ?? ''); + if (control?.value === '' && person.shelfsObjects.some((shelf) => shelf.uidItShopOrg === uidItShopOrg)) { control.setValue(uidItShopOrg); } }); @@ -68,21 +67,23 @@ export class ShelfSelectionComponent { } public needsDefaultShelf(product: ShelfSelectionObject): boolean { - return product.personsForProduct.filter(person => person.shelfsObjects.length > 1).length > 1; + return product.personsForProduct.filter((person) => person.shelfsObjects.length > 1).length > 1; } - public getFormControl(shelfSelectionObject: ShelfSelectionObject, personForProduct: PersonForProduct): UntypedFormControl { - return (this.formGroup.get(shelfSelectionObject.uidAccproduct) as UntypedFormGroup).get(personForProduct.uidPerson) as UntypedFormControl; + return (this.formGroup.get(shelfSelectionObject.uidAccproduct ?? '') as UntypedFormGroup).get( + personForProduct.uidPerson ?? '', + ) as UntypedFormControl; } public submit(): void { - this.shelfSelectionObjects.forEach(product => { - product.personsForProduct.filter(elem => elem.shelfsObjects.length > 1).forEach(person => { - const control = this.getFormControl(product, person); - person.uidItShopOrg = control.value; - } - ); + this.shelfSelectionObjects.forEach((product) => { + product.personsForProduct + .filter((elem) => elem.shelfsObjects.length > 1) + .forEach((person) => { + const control = this.getFormControl(product, person); + person.uidItShopOrg = control.value; + }); }); this.sideSheetRef.close(this.shelfSelectionObjects); } @@ -91,14 +92,17 @@ export class ShelfSelectionComponent { this.shelfSelectionObjects = this.data; this.formGroup = new UntypedFormGroup({}); - this.shelfSelectionObjects.forEach(element => { + this.shelfSelectionObjects.forEach((element) => { const personGroup = new UntypedFormGroup({}); - element.personsForProduct.filter(elem => elem.shelfsObjects.length > 1).forEach(person => - personGroup.addControl(person.uidPerson, new UntypedFormControl(person.uidItShopOrg, Validators.required)) - ); - this.formGroup.addControl(element.uidAccproduct, personGroup); + element.personsForProduct + .filter((elem) => elem.shelfsObjects.length > 1) + .forEach((person) => + personGroup.addControl(person.uidPerson ?? '', new UntypedFormControl(person.uidItShopOrg, Validators.required)), + ); + this.formGroup.addControl(element.uidAccproduct ?? '', personGroup); }); } - + public LdsKey = + '#LDS#One or more selected products are included in several shelves. For each product, select from which shelf you want to request the product. You can select a default shelf that will be used for all recipients or select a shelf individually for each recipient.'; } diff --git a/imxweb/projects/qer/src/lib/itshop/shelf.service.ts b/imxweb/projects/qer/src/lib/itshop/shelf.service.ts index 5c60a4f5e..4e75c01e2 100644 --- a/imxweb/projects/qer/src/lib/itshop/shelf.service.ts +++ b/imxweb/projects/qer/src/lib/itshop/shelf.service.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -26,17 +26,16 @@ import { Injectable } from '@angular/core'; import { MatDialog } from '@angular/material/dialog'; -import { TranslateService } from '@ngx-translate/core'; import { EuiLoadingService, EuiSidesheetService } from '@elemental-ui/core'; -import { OverlayRef } from '@angular/cdk/overlay'; +import { TranslateService } from '@ngx-translate/core'; -import { ClassloggerService, MessageDialogComponent } from 'qbm'; -import { RequestableProductForPerson, ServiceItemForPerson } from 'imx-api-qer'; -import { ShelfSelectionComponent } from './shelf-selection.component'; +import { RequestableProductForPerson, ServiceItemForPerson } from '@imx-modules/imx-api-qer'; +import _ from 'lodash'; +import { ClassloggerService, MessageDialogComponent, calculateSidesheetWidth } from 'qbm'; import { QerApiService } from '../qer-api-client.service'; import { NonRequestableItemsComponent } from './non-requestable-items/non-requestable-items.component'; import { PersonForProduct, ShelfObject, ShelfSelectionObject } from './shelf-selection-sidesheet.model'; -import _ from 'lodash'; +import { ShelfSelectionComponent } from './shelf-selection.component'; @Injectable({ providedIn: 'root', @@ -48,7 +47,7 @@ export class ShelfService { private readonly logger: ClassloggerService, private readonly dialogService: MatDialog, private readonly translate: TranslateService, - private readonly busyService: EuiLoadingService + private readonly busyService: EuiLoadingService, ) {} public async setShops(requestableServiceItemsForPersons: RequestableProductForPerson[]): Promise { @@ -82,8 +81,8 @@ export class ShelfService { data.some( (shelf) => elem.UidAccProduct === shelf.uidAccproduct && - shelf.personsForProduct.find((person) => person.uidPerson === elem.UidPerson)?.shelfsObjects.length > 0 - ) + !!shelf.personsForProduct.find((person) => person.uidPerson === (elem?.UidPerson || ''))?.shelfsObjects.length, + ), ); if (!(await this.setElementsWithSideSheet(requested, data))) { @@ -109,7 +108,7 @@ export class ShelfService { DisplayRecipient: person.displayPerson, }); } - }) + }), ); } @@ -138,7 +137,7 @@ export class ShelfService { const sidesheetRef = this.sideSheet.open(ShelfSelectionComponent, { title: await this.translate.get('#LDS#Heading Select Shelf').toPromise(), padding: '0px', - width: 'max(500px, 50%)', + width: calculateSidesheetWidth(800, 0.5), testId: 'shelf-selection-sidesheet', data: ssos, }); @@ -151,7 +150,9 @@ export class ShelfService { // TODO TASK 321664: This is only a temporary fix to choose to all items with the same uid, regardless of if they are optional or not. const items = requested.filter( (elem) => - elem.UidAccProduct === requestedProduct.uidAccproduct && elem.UidPerson === person.uidPerson && person.shelfsObjects.length > 0 + elem.UidAccProduct === requestedProduct.uidAccproduct && + elem.UidPerson === (person.uidPerson || '') && + person.shelfsObjects.length > 0, ); items.forEach((item) => { item.UidITShopOrg = person.uidItShopOrg; @@ -159,7 +160,7 @@ export class ShelfService { // const item = requested.find(elem => // elem.UidAccProduct === requestedProduct.uidAccproduct && elem.UidPerson === person.uidPerson); // item.UidITShopOrg = person.uidItShopOrg; - }) + }), ); return true; } @@ -168,7 +169,7 @@ export class ShelfService { // Here we set any unique products with a unique shelf, unique is defined as only one UID for AccProduct, Person for (const serviceItemForPerson of requested.filter((elem) => elem.UidITShopOrg == null || elem.UidITShopOrg === '')) { const possibleRequestableServiceItems = productsWithShops.filter( - (item) => item.UidAccProduct === serviceItemForPerson.UidAccProduct && item.UidPerson === serviceItemForPerson.UidPerson + (item) => item.UidAccProduct === serviceItemForPerson.UidAccProduct && item.UidPerson === serviceItemForPerson.UidPerson, ); if (possibleRequestableServiceItems.length === 1) { serviceItemForPerson.UidITShopOrg = possibleRequestableServiceItems[0].UidITShopOrg; @@ -183,7 +184,7 @@ export class ShelfService { private buildShelfSelection( requested: RequestableProductForPerson[], - productsWithShops: RequestableProductForPerson[] + productsWithShops: RequestableProductForPerson[], ): ShelfSelectionObject[] { // Build the shelf selection object to then ask the user to set values on return requested @@ -192,27 +193,27 @@ export class ShelfService { .map((elem) => ({ uidAccproduct: elem.uid, displayAccProduct: elem.display, - personsForProduct: this.getPersonsForProduct(requested, productsWithShops, elem.uid), - possibleShelfObjects: this.getPossibleShelfs(productsWithShops, elem.uid), + personsForProduct: this.getPersonsForProduct(requested, productsWithShops, elem.uid ?? ''), + possibleShelfObjects: this.getPossibleShelfs(productsWithShops, elem.uid ?? ''), })) .filter((elem) => this.hasMultipleShelfs(elem)) - .sort((a, b) => a.displayAccProduct.localeCompare(b.displayAccProduct)); + .sort((a, b) => (a.displayAccProduct ?? '').localeCompare(b.displayAccProduct ?? '')); } private getPersonsForProduct( requested: RequestableProductForPerson[], productsWithShops: RequestableProductForPerson[], - uid: string + uid: string, ): PersonForProduct[] { const elements = requested.filter((elem) => elem.UidAccProduct === uid); return elements .map((elem) => ({ uidPerson: elem.UidPerson, - uidItShopOrg: this.tryGetItShop(productsWithShops, uid, elem.UidPerson), + uidItShopOrg: this.tryGetItShop(productsWithShops, uid, elem.UidPerson ?? ''), displayPerson: elem.DisplayRecipient, - shelfsObjects: this.getShelfObjects(productsWithShops, uid, elem.UidPerson), + shelfsObjects: this.getShelfObjects(productsWithShops, uid, elem.UidPerson ?? ''), })) - .sort((a, b) => a.displayPerson.localeCompare(b.displayPerson)); + .sort((a, b) => (a.displayPerson ?? '').localeCompare(b.displayPerson ?? '')); } private getPossibleShelfs(productsWithShops: RequestableProductForPerson[], uid: string): ShelfObject[] { @@ -225,18 +226,22 @@ export class ShelfService { .filter(this.uniqueShelfs); } - private uniqueProducts(value: { display: string; uid: string }, index: number, self: { display: string; uid: string }[]): boolean { + private uniqueProducts( + value: { display: string | undefined; uid?: string | undefined }, + index: number, + self: { display: string; uid: string }[], + ): boolean { return self.findIndex((elem) => value.uid === elem.uid) === index; } private tryGetItShop(productsWithShops: RequestableProductForPerson[], uidAcc: string, uidPerson: string): string { - const shelf = productsWithShops.filter((elem) => elem.UidAccProduct === uidAcc && elem.UidPerson === uidPerson); - return shelf.length === 1 ? shelf[0].UidITShopOrg : ''; + const shelf = productsWithShops.filter((elem) => elem.UidAccProduct === uidAcc && (elem.UidPerson || '') === uidPerson); + return shelf.length === 1 ? shelf[0].UidITShopOrg ?? '' : ''; } private getShelfObjects(productsWithShops: RequestableProductForPerson[], uidAcc: string, uidPerson: string): ShelfObject[] { return productsWithShops - .filter((elem) => elem.UidAccProduct === uidAcc && elem.UidPerson === uidPerson) + .filter((elem) => elem.UidAccProduct === uidAcc && (elem.UidPerson || '') === uidPerson) .map((elem) => ({ displayShelf: elem.Display, uidItShopOrg: elem.UidITShopOrg })); } @@ -247,13 +252,14 @@ export class ShelfService { private async findUniqueProductsInShops(serviceItemsForPersons: ServiceItemForPerson[]): Promise { // Get all unique products within the itshop let products: RequestableProductForPerson[]; - let overlay: OverlayRef; - setTimeout(() => (overlay = this.busyService.show())); + if (this.busyService.overlayRefs.length === 0) { + this.busyService.show(); + } try { products = await this.qerClient.client.portal_itshop_findproducts_post(serviceItemsForPersons); products = _.uniqWith(products, _.isEqual); } finally { - setTimeout(() => this.busyService.hide(overlay)); + this.busyService.hide(); } return products; } diff --git a/imxweb/projects/qer/src/lib/itshop/workflow-data-wrapper.spec.ts b/imxweb/projects/qer/src/lib/itshop/workflow-data-wrapper.spec.ts index 4815e193f..175275878 100644 --- a/imxweb/projects/qer/src/lib/itshop/workflow-data-wrapper.spec.ts +++ b/imxweb/projects/qer/src/lib/itshop/workflow-data-wrapper.spec.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -24,22 +24,23 @@ * */ -import { EntityCollectionData } from 'imx-qbm-dbts'; +import { EntityCollectionData } from '@imx-modules/imx-qbm-dbts'; import { WorkflowDataWrapper } from './workflow-data-wrapper'; describe('WorkflowDataWrapper', () => { - const createWorkflowCollection = (data) => ({ - Entities: data.map(item => { - const Columns = {}; - Object.keys(item).forEach(key => Columns[key] = { Value: item[key] }); - return { Columns } - }) - } as EntityCollectionData); + const createWorkflowCollection = (data) => + ({ + Entities: data.map((item) => { + const Columns = {}; + Object.keys(item).forEach((key) => (Columns[key] = { Value: item[key] })); + return { Columns }; + }), + }) as EntityCollectionData; const testcaseToString = (testcase) => { const tokens = []; - Object.keys(testcase).forEach(key => - Object.keys(testcase[key]).forEach(itemkey => tokens.push(itemkey + '="' + testcase[key][itemkey] + '"')) + Object.keys(testcase).forEach((key) => + Object.keys(testcase[key]).forEach((itemkey) => tokens.push(itemkey + '="' + testcase[key][itemkey] + '"')), ); return tokens.join(); }; @@ -50,16 +51,14 @@ describe('WorkflowDataWrapper', () => { const LevelNumber = 1; const UID_QERWorkingStep = 'some workingstep'; - const workflow = new WorkflowDataWrapper( - { - WorkflowData: createWorkflowCollection([{ UID_PersonHead, LevelNumber, UID_QERWorkingStep }]), - WorkflowSteps: createWorkflowCollection([{ UID_QERWorkingStep: 'some other workingstep', DirectSteps: '1' }]) - } - ); + const workflow = new WorkflowDataWrapper({ + WorkflowData: createWorkflowCollection([{ UID_PersonHead, LevelNumber, UID_QERWorkingStep }]), + WorkflowSteps: createWorkflowCollection([{ UID_QERWorkingStep: 'some other workingstep', DirectSteps: '1' }]), + }); const directSteps = workflow.getDirectSteps(UID_PersonHead, LevelNumber); - expect(directSteps).toBeUndefined(); + expect(directSteps).toEqual([]); }); it('returns the directSteps for the matching item', () => { @@ -67,12 +66,10 @@ describe('WorkflowDataWrapper', () => { const LevelNumber = 1; const workflowStep = { UID_QERWorkingStep: 'some workingstep', DirectSteps: '1' }; - const workflow = new WorkflowDataWrapper( - { - WorkflowData: createWorkflowCollection([{ UID_PersonHead, LevelNumber, UID_QERWorkingStep: workflowStep.UID_QERWorkingStep }]), - WorkflowSteps: createWorkflowCollection([ workflowStep ]) - } - ); + const workflow = new WorkflowDataWrapper({ + WorkflowData: createWorkflowCollection([{ UID_PersonHead, LevelNumber, UID_QERWorkingStep: workflowStep.UID_QERWorkingStep }]), + WorkflowSteps: createWorkflowCollection([workflowStep]), + }); const directSteps = workflow.getDirectSteps(UID_PersonHead, LevelNumber); @@ -84,21 +81,16 @@ describe('WorkflowDataWrapper', () => { const LevelNumber = 1; const SubLevelNumber = 0; const workflowStep = { UID_QERWorkingStep: 'some workingstep', DirectSteps: '1' }; - const workflowStepOther = { UID_QERWorkingStep: 'some other workingstep', DirectSteps: '2' };; + const workflowStepOther = { UID_QERWorkingStep: 'some other workingstep', DirectSteps: '2' }; - const workflow = new WorkflowDataWrapper( - { - WorkflowData: createWorkflowCollection([ - { UID_PersonHead, LevelNumber, SubLevelNumber: SubLevelNumber + 1, UID_QERWorkingStep: workflowStepOther.UID_QERWorkingStep }, - { UID_PersonHead, LevelNumber, SubLevelNumber, UID_QERWorkingStep: workflowStep.UID_QERWorkingStep }, - { UID_PersonHead, LevelNumber, SubLevelNumber: SubLevelNumber + 2, UID_QERWorkingStep: workflowStepOther.UID_QERWorkingStep } - ]), - WorkflowSteps: createWorkflowCollection([ - workflowStep, - workflowStepOther - ]) - } - ); + const workflow = new WorkflowDataWrapper({ + WorkflowData: createWorkflowCollection([ + { UID_PersonHead, LevelNumber, SubLevelNumber: SubLevelNumber + 1, UID_QERWorkingStep: workflowStepOther.UID_QERWorkingStep }, + { UID_PersonHead, LevelNumber, SubLevelNumber, UID_QERWorkingStep: workflowStep.UID_QERWorkingStep }, + { UID_PersonHead, LevelNumber, SubLevelNumber: SubLevelNumber + 2, UID_QERWorkingStep: workflowStepOther.UID_QERWorkingStep }, + ]), + WorkflowSteps: createWorkflowCollection([workflowStep, workflowStepOther]), + }); const directSteps = workflow.getDirectSteps(UID_PersonHead, LevelNumber); @@ -112,12 +104,10 @@ describe('WorkflowDataWrapper', () => { const LevelNumber = 1; const UID_QERWorkingStep = 'some workingstep'; - const workflow = new WorkflowDataWrapper( - { - WorkflowData: createWorkflowCollection([{ UID_PersonHead, LevelNumber, UID_QERWorkingStep }]), - WorkflowSteps: createWorkflowCollection([{ UID_QERWorkingStep: 'some other workingstep' }]) - } - ); + const workflow = new WorkflowDataWrapper({ + WorkflowData: createWorkflowCollection([{ UID_PersonHead, LevelNumber, UID_QERWorkingStep }]), + WorkflowSteps: createWorkflowCollection([{ UID_QERWorkingStep: 'some other workingstep' }]), + }); expect(workflow.isAdditionalAllowed(UID_PersonHead, LevelNumber)).toBeFalsy(); }); @@ -126,27 +116,26 @@ describe('WorkflowDataWrapper', () => { { workflowData: { IsFromDelegation: true }, workflowStep: { IsAdditionalAllowed: true } }, { workflowData: { UID_PersonAdditional: 'id of some additional person' }, workflowStep: { IsAdditionalAllowed: true } }, { workflowData: { UID_PersonInsteadOf: 'id of some other person' }, workflowStep: { IsAdditionalAllowed: true } }, - { workflowStep: { IsAdditionalAllowed: false } } - ].forEach(testcase => - it('returns false if matching item has ' + testcaseToString(testcase), () => { - const UID_PersonHead = 'some user id'; - const LevelNumber = 1; - const workflowStep = { ...{ UID_QERWorkingStep: 'some workingstep' }, ...testcase.workflowStep }; - - const workflow = new WorkflowDataWrapper( - { + { workflowStep: { IsAdditionalAllowed: false } }, + ].forEach((testcase) => + it('returns false if matching item has ' + testcaseToString(testcase), () => { + const UID_PersonHead = 'some user id'; + const LevelNumber = 1; + const workflowStep = { ...{ UID_QERWorkingStep: 'some workingstep' }, ...testcase.workflowStep }; + + const workflow = new WorkflowDataWrapper({ WorkflowData: createWorkflowCollection([ { ...{ UID_PersonHead, LevelNumber, UID_QERWorkingStep: workflowStep.UID_QERWorkingStep }, - ...testcase.workflowData - } + ...testcase.workflowData, + }, ]), - WorkflowSteps: createWorkflowCollection([ workflowStep ]) - } - ); + WorkflowSteps: createWorkflowCollection([workflowStep]), + }); - expect(workflow.isAdditionalAllowed(UID_PersonHead, LevelNumber)).toBeFalsy(); - })); + expect(workflow.isAdditionalAllowed(UID_PersonHead, LevelNumber)).toBeFalsy(); + }), + ); it('returns true if matching item', () => { const UID_PersonHead = 'some user id'; @@ -155,14 +144,12 @@ describe('WorkflowDataWrapper', () => { const UID_PersonAdditional = ''; const UID_PersonInsteadOf = ''; - const workflow = new WorkflowDataWrapper( - { - WorkflowData: createWorkflowCollection([ - { UID_PersonHead, LevelNumber, UID_QERWorkingStep: workflowStep.UID_QERWorkingStep, UID_PersonAdditional, UID_PersonInsteadOf } - ]), - WorkflowSteps: createWorkflowCollection([ workflowStep ]) - } - ); + const workflow = new WorkflowDataWrapper({ + WorkflowData: createWorkflowCollection([ + { UID_PersonHead, LevelNumber, UID_QERWorkingStep: workflowStep.UID_QERWorkingStep, UID_PersonAdditional, UID_PersonInsteadOf }, + ]), + WorkflowSteps: createWorkflowCollection([workflowStep]), + }); expect(workflow.isAdditionalAllowed(UID_PersonHead, LevelNumber)).toBeTruthy(); }); @@ -174,12 +161,10 @@ describe('WorkflowDataWrapper', () => { const LevelNumber = 1; const UID_QERWorkingStep = 'some workingstep'; - const workflow = new WorkflowDataWrapper( - { - WorkflowData: createWorkflowCollection([{ UID_PersonHead, LevelNumber, UID_QERWorkingStep }]), - WorkflowSteps: createWorkflowCollection([{ UID_QERWorkingStep: 'some other workingstep' }]) - } - ); + const workflow = new WorkflowDataWrapper({ + WorkflowData: createWorkflowCollection([{ UID_PersonHead, LevelNumber, UID_QERWorkingStep }]), + WorkflowSteps: createWorkflowCollection([{ UID_QERWorkingStep: 'some other workingstep' }]), + }); expect(workflow.isInsteadOfAllowed(UID_PersonHead, LevelNumber)).toBeFalsy(); }); @@ -188,27 +173,26 @@ describe('WorkflowDataWrapper', () => { { workflowData: { IsFromDelegation: true }, workflowStep: { IsInsteadOfAllowed: true } }, { workflowData: { UID_PersonAdditional: 'id of some additional person' }, workflowStep: { IsInsteadOfAllowed: true } }, { workflowData: { UID_PersonInsteadOf: 'id of some other person' }, workflowStep: { IsInsteadOfAllowed: true } }, - { workflowStep: { IsInsteadOfAllowed: false } } - ].forEach(testcase => - it('returns false if matching item has ' + testcaseToString(testcase), () => { - const UID_PersonHead = 'some user id'; - const LevelNumber = 1; - const workflowStep = { ...{ UID_QERWorkingStep: 'some workingstep' }, ...testcase.workflowStep }; - - const workflow = new WorkflowDataWrapper( - { + { workflowStep: { IsInsteadOfAllowed: false } }, + ].forEach((testcase) => + it('returns false if matching item has ' + testcaseToString(testcase), () => { + const UID_PersonHead = 'some user id'; + const LevelNumber = 1; + const workflowStep = { ...{ UID_QERWorkingStep: 'some workingstep' }, ...testcase.workflowStep }; + + const workflow = new WorkflowDataWrapper({ WorkflowData: createWorkflowCollection([ { ...{ UID_PersonHead, LevelNumber, UID_QERWorkingStep: workflowStep.UID_QERWorkingStep }, - ...testcase.workflowData - } + ...testcase.workflowData, + }, ]), - WorkflowSteps: createWorkflowCollection([ workflowStep ]) - } - ); + WorkflowSteps: createWorkflowCollection([workflowStep]), + }); - expect(workflow.isInsteadOfAllowed(UID_PersonHead, LevelNumber)).toBeFalsy(); - })); + expect(workflow.isInsteadOfAllowed(UID_PersonHead, LevelNumber)).toBeFalsy(); + }), + ); it('returns true if matching item', () => { const UID_PersonHead = 'some user id'; @@ -217,14 +201,12 @@ describe('WorkflowDataWrapper', () => { const UID_PersonAdditional = ''; const UID_PersonInsteadOf = ''; - const workflow = new WorkflowDataWrapper( - { - WorkflowData: createWorkflowCollection([ - { UID_PersonHead, LevelNumber, UID_QERWorkingStep: workflowStep.UID_QERWorkingStep, UID_PersonAdditional, UID_PersonInsteadOf } - ]), - WorkflowSteps: createWorkflowCollection([ workflowStep ]) - } - ); + const workflow = new WorkflowDataWrapper({ + WorkflowData: createWorkflowCollection([ + { UID_PersonHead, LevelNumber, UID_QERWorkingStep: workflowStep.UID_QERWorkingStep, UID_PersonAdditional, UID_PersonInsteadOf }, + ]), + WorkflowSteps: createWorkflowCollection([workflowStep]), + }); expect(workflow.isInsteadOfAllowed(UID_PersonHead, LevelNumber)).toBeTruthy(); }); @@ -236,12 +218,10 @@ describe('WorkflowDataWrapper', () => { const UID_PersonHead = 'some user id'; const LevelNumber = 1; - const workflow = new WorkflowDataWrapper( - { - CanRevokeDelegation, - WorkflowData: createWorkflowCollection([{ UID_PersonHead: 'some other user id', LevelNumber }]) - } - ); + const workflow = new WorkflowDataWrapper({ + CanRevokeDelegation, + WorkflowData: createWorkflowCollection([{ UID_PersonHead: 'some other user id', LevelNumber }]), + }); expect(workflow.canRevokeAdditionalApprover(UID_PersonHead, LevelNumber)).toBeFalsy(); }); @@ -252,12 +232,10 @@ describe('WorkflowDataWrapper', () => { const LevelNumber = 1; const UID_PersonAdditional = 'some other user id'; - const workflow = new WorkflowDataWrapper( - { - CanRevokeDelegation, - WorkflowData: createWorkflowCollection([{ UID_PersonHead, LevelNumber, UID_PersonAdditional }]) - } - ); + const workflow = new WorkflowDataWrapper({ + CanRevokeDelegation, + WorkflowData: createWorkflowCollection([{ UID_PersonHead, LevelNumber, UID_PersonAdditional }]), + }); expect(workflow.canRevokeAdditionalApprover(UID_PersonHead, LevelNumber)).toBeFalsy(); }); @@ -267,12 +245,10 @@ describe('WorkflowDataWrapper', () => { const UID_PersonHead = 'some user id'; const LevelNumber = 1; - const workflow = new WorkflowDataWrapper( - { - CanRevokeDelegation, - WorkflowData: createWorkflowCollection([{ UID_PersonHead, LevelNumber }]) - } - ); + const workflow = new WorkflowDataWrapper({ + CanRevokeDelegation, + WorkflowData: createWorkflowCollection([{ UID_PersonHead, LevelNumber }]), + }); expect(workflow.canRevokeAdditionalApprover(UID_PersonHead, LevelNumber)).toBeFalsy(); }); @@ -283,12 +259,10 @@ describe('WorkflowDataWrapper', () => { const LevelNumber = 1; const UID_PersonAdditional = 'some other user id'; - const workflow = new WorkflowDataWrapper( - { - CanRevokeDelegation, - WorkflowData: createWorkflowCollection([{ UID_PersonHead, LevelNumber, UID_PersonAdditional }]) - } - ); + const workflow = new WorkflowDataWrapper({ + CanRevokeDelegation, + WorkflowData: createWorkflowCollection([{ UID_PersonHead, LevelNumber, UID_PersonAdditional }]), + }); expect(workflow.canRevokeAdditionalApprover(UID_PersonHead, LevelNumber)).toBeTruthy(); }); @@ -300,12 +274,10 @@ describe('WorkflowDataWrapper', () => { const UID_PersonHead = 'some user id'; const LevelNumber = 1; - const workflow = new WorkflowDataWrapper( - { - CanRevokeDelegation, - WorkflowData: createWorkflowCollection([{ UID_PersonHead: 'some other user id', LevelNumber }]) - } - ); + const workflow = new WorkflowDataWrapper({ + CanRevokeDelegation, + WorkflowData: createWorkflowCollection([{ UID_PersonHead: 'some other user id', LevelNumber }]), + }); expect(workflow.canRevokeDelegatedApprover(UID_PersonHead, LevelNumber)).toBeFalsy(); }); @@ -316,12 +288,10 @@ describe('WorkflowDataWrapper', () => { const LevelNumber = 1; const UID_PersonInsteadOf = 'some other user id'; - const workflow = new WorkflowDataWrapper( - { - CanRevokeDelegation, - WorkflowData: createWorkflowCollection([{ UID_PersonHead, LevelNumber, UID_PersonInsteadOf }]) - } - ); + const workflow = new WorkflowDataWrapper({ + CanRevokeDelegation, + WorkflowData: createWorkflowCollection([{ UID_PersonHead, LevelNumber, UID_PersonInsteadOf }]), + }); expect(workflow.canRevokeDelegatedApprover(UID_PersonHead, LevelNumber)).toBeFalsy(); }); @@ -331,12 +301,10 @@ describe('WorkflowDataWrapper', () => { const UID_PersonHead = 'some user id'; const LevelNumber = 1; - const workflow = new WorkflowDataWrapper( - { - CanRevokeDelegation, - WorkflowData: createWorkflowCollection([{ UID_PersonHead, LevelNumber }]) - } - ); + const workflow = new WorkflowDataWrapper({ + CanRevokeDelegation, + WorkflowData: createWorkflowCollection([{ UID_PersonHead, LevelNumber }]), + }); expect(workflow.canRevokeDelegatedApprover(UID_PersonHead, LevelNumber)).toBeFalsy(); }); @@ -347,12 +315,10 @@ describe('WorkflowDataWrapper', () => { const LevelNumber = 1; const UID_PersonInsteadOf = 'some other user id'; - const workflow = new WorkflowDataWrapper( - { - CanRevokeDelegation, - WorkflowData: createWorkflowCollection([{ UID_PersonHead, LevelNumber, UID_PersonInsteadOf }]) - } - ); + const workflow = new WorkflowDataWrapper({ + CanRevokeDelegation, + WorkflowData: createWorkflowCollection([{ UID_PersonHead, LevelNumber, UID_PersonInsteadOf }]), + }); expect(workflow.canRevokeDelegatedApprover(UID_PersonHead, LevelNumber)).toBeTruthy(); }); @@ -364,12 +330,10 @@ describe('WorkflowDataWrapper', () => { const UID_PersonHead = 'some user id'; const LevelNumber = 1; - const workflow = new WorkflowDataWrapper( - { - CanRevokeDelegation, - WorkflowData: createWorkflowCollection([{ UID_PersonHead: 'some other user id', LevelNumber }]) - } - ); + const workflow = new WorkflowDataWrapper({ + CanRevokeDelegation, + WorkflowData: createWorkflowCollection([{ UID_PersonHead: 'some other user id', LevelNumber }]), + }); expect(workflow.canDenyDecision(UID_PersonHead, LevelNumber)).toBeFalsy(); }); @@ -379,11 +343,9 @@ describe('WorkflowDataWrapper', () => { const LevelNumber = 1; const IsFromDelegation = false; - const workflow = new WorkflowDataWrapper( - { - WorkflowData: createWorkflowCollection([{ UID_PersonHead, LevelNumber, IsFromDelegation }]) - } - ); + const workflow = new WorkflowDataWrapper({ + WorkflowData: createWorkflowCollection([{ UID_PersonHead, LevelNumber, IsFromDelegation }]), + }); expect(workflow.canDenyDecision(UID_PersonHead, LevelNumber)).toBeFalsy(); }); @@ -393,11 +355,9 @@ describe('WorkflowDataWrapper', () => { const LevelNumber = 1; const IsFromDelegation = false; - const workflow = new WorkflowDataWrapper( - { - WorkflowData: createWorkflowCollection([{ UID_PersonHead, LevelNumber, IsFromDelegation }]) - } - ); + const workflow = new WorkflowDataWrapper({ + WorkflowData: createWorkflowCollection([{ UID_PersonHead, LevelNumber, IsFromDelegation }]), + }); expect(workflow.canDenyDecision(UID_PersonHead, LevelNumber)).toBeFalsy(); }); @@ -408,11 +368,9 @@ describe('WorkflowDataWrapper', () => { const LevelNumber = 1; const workflowStep = { EscalationSteps: 1, LevelNumber: 2 }; - const workflow = new WorkflowDataWrapper( - { - WorkflowSteps: createWorkflowCollection([ workflowStep ]) - } - ); + const workflow = new WorkflowDataWrapper({ + WorkflowSteps: createWorkflowCollection([workflowStep]), + }); expect(workflow.canEscalateDecision(LevelNumber)).toBeFalsy(); }); @@ -421,11 +379,9 @@ describe('WorkflowDataWrapper', () => { const LevelNumber = 1; const workflowStep = { EscalationSteps: 0, LevelNumber }; - const workflow = new WorkflowDataWrapper( - { - WorkflowSteps: createWorkflowCollection([ workflowStep ]) - } - ); + const workflow = new WorkflowDataWrapper({ + WorkflowSteps: createWorkflowCollection([workflowStep]), + }); expect(workflow.canEscalateDecision(LevelNumber)).toBeFalsy(); }); @@ -434,11 +390,9 @@ describe('WorkflowDataWrapper', () => { const LevelNumber = 1; const workflowStep = { EscalationSteps: 1, LevelNumber }; - const workflow = new WorkflowDataWrapper( - { - WorkflowSteps: createWorkflowCollection([ workflowStep ]) - } - ); + const workflow = new WorkflowDataWrapper({ + WorkflowSteps: createWorkflowCollection([workflowStep]), + }); expect(workflow.canEscalateDecision(LevelNumber)).toBeTruthy(); }); diff --git a/imxweb/projects/qer/src/lib/itshop/workflow-data-wrapper.ts b/imxweb/projects/qer/src/lib/itshop/workflow-data-wrapper.ts index 7e4f9d728..4377ce1b6 100644 --- a/imxweb/projects/qer/src/lib/itshop/workflow-data-wrapper.ts +++ b/imxweb/projects/qer/src/lib/itshop/workflow-data-wrapper.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -24,7 +24,7 @@ * */ -import { EntityCollectionData, EntityData, MultiValue } from 'imx-qbm-dbts'; +import { EntityCollectionData, EntityData, MultiValue } from '@imx-modules/imx-qbm-dbts'; export class WorkflowDataWrapper { constructor( @@ -33,23 +33,23 @@ export class WorkflowDataWrapper { WorkflowData?: EntityCollectionData; WorkflowSteps?: EntityCollectionData; CanRevokeDelegation?: boolean; - } + }, ) {} public canEscalateDecision(decisionLevel: number): boolean { - const workflowStep = this.data?.WorkflowSteps?.Entities?.find((step) => step.Columns.LevelNumber.Value === decisionLevel)?.Columns; + const workflowStep = this.data?.WorkflowSteps?.Entities?.find((step) => step.Columns?.LevelNumber.Value === decisionLevel)?.Columns; return (workflowStep?.EscalationSteps?.Value ?? 0) !== 0; } public userAskedLastQuestion(userUid: string, decisionLevel: number): boolean { - const questionHistory = this.data.WorkflowHistory.Entities.filter( - (entityData) => entityData.Columns.DecisionLevel.Value === decisionLevel - ).sort((item1, item2) => this.ascendingDate(item1.Columns.XDateInserted?.Value, item2.Columns.XDateInserted?.Value)); + const questionHistory = this.data.WorkflowHistory?.Entities?.filter( + (entityData) => entityData.Columns?.DecisionLevel.Value === decisionLevel, + ).sort((item1, item2) => this.ascendingDate(item1.Columns?.XDateInserted?.Value, item2.Columns?.XDateInserted?.Value)); return ( - questionHistory.length > 0 && - questionHistory[0].Columns.DecisionType.Value === 'Query' && - questionHistory[0].Columns.UID_PersonHead.Value === userUid + !!questionHistory?.length && + questionHistory[0].Columns?.DecisionType.Value === 'Query' && + questionHistory[0].Columns?.UID_PersonHead.Value === userUid ); } @@ -59,13 +59,15 @@ export class WorkflowDataWrapper { public canRevokeDelegatedApprover(userUid: string, decisionLevel: number): boolean { return ( - this.data.CanRevokeDelegation && this.getWorkflowDataItem(userUid, decisionLevel)?.Columns?.UID_PersonInsteadOf?.Value?.length > 0 + (this.data.CanRevokeDelegation && !!this.getWorkflowDataItem(userUid, decisionLevel)?.Columns?.UID_PersonInsteadOf?.Value?.length) || + false ); } public canRevokeAdditionalApprover(userUid: string, decisionLevel: number): boolean { return ( - this.data.CanRevokeDelegation && this.getWorkflowDataItem(userUid, decisionLevel)?.Columns?.UID_PersonAdditional?.Value?.length > 0 + (this.data.CanRevokeDelegation && !!this.getWorkflowDataItem(userUid, decisionLevel)?.Columns?.UID_PersonAdditional?.Value?.length) || + false ); } @@ -77,10 +79,10 @@ export class WorkflowDataWrapper { if (workflowStep) { return ( - !workflowDataItem.Columns.IsFromDelegation?.Value && - !workflowDataItem.Columns.UID_PersonAdditional?.Value?.length && - !workflowDataItem.Columns.UID_PersonInsteadOf?.Value?.length && - workflowStep.Columns.IsInsteadOfAllowed?.Value + !workflowDataItem.Columns?.IsFromDelegation?.Value && + !workflowDataItem.Columns?.UID_PersonAdditional?.Value?.length && + !workflowDataItem.Columns?.UID_PersonInsteadOf?.Value?.length && + workflowStep.Columns?.IsInsteadOfAllowed?.Value ); } } @@ -96,10 +98,10 @@ export class WorkflowDataWrapper { if (workflowStep) { return ( - !workflowDataItem.Columns.IsFromDelegation?.Value && - !workflowDataItem.Columns.UID_PersonAdditional?.Value?.length && - !workflowDataItem.Columns.UID_PersonInsteadOf?.Value?.length && - workflowStep.Columns.IsAdditionalAllowed?.Value + !workflowDataItem.Columns?.IsFromDelegation?.Value && + !workflowDataItem.Columns?.UID_PersonAdditional?.Value?.length && + !workflowDataItem.Columns?.UID_PersonInsteadOf?.Value?.length && + workflowStep.Columns?.IsAdditionalAllowed?.Value ); } } @@ -114,26 +116,26 @@ export class WorkflowDataWrapper { const workflowStep = this.getWorkflowStep(workflowDataItem); if (workflowStep) { - return MultiValue.FromString(workflowStep.Columns.DirectSteps.Value) + return MultiValue.FromString(workflowStep.Columns?.DirectSteps.Value) .GetValues() .map((step) => Number(step)); } } - return undefined; + return []; } - private getWorkflowDataItem(userUid: string, decisionLevel: number): EntityData { - return this.data.WorkflowData?.Entities.filter( - (item) => item.Columns.UID_PersonHead.Value === userUid && item.Columns.LevelNumber.Value === decisionLevel + private getWorkflowDataItem(userUid: string, decisionLevel: number): EntityData | undefined { + return this.data.WorkflowData?.Entities?.filter( + (item) => item.Columns?.UID_PersonHead.Value === userUid && item.Columns?.LevelNumber.Value === decisionLevel, ) - .sort((item1, item2) => this.ascending(item1.Columns.SubLevelNumber?.Value, item2.Columns.SubLevelNumber?.Value)) + .sort((item1, item2) => this.ascending(item1.Columns?.SubLevelNumber?.Value, item2.Columns?.SubLevelNumber?.Value)) .pop(); } - private getWorkflowStep(workflowDataItem: EntityData): EntityData { - return this.data.WorkflowSteps?.Entities.filter( - (item) => item.Columns.UID_QERWorkingStep.Value === workflowDataItem.Columns.UID_QERWorkingStep.Value + private getWorkflowStep(workflowDataItem: EntityData): EntityData | undefined { + return this.data.WorkflowSteps?.Entities?.filter( + (item) => item.Columns?.UID_QERWorkingStep.Value === workflowDataItem.Columns?.UID_QERWorkingStep.Value, ).pop(); } diff --git a/imxweb/projects/qer/src/lib/itshopapprove/approval.spec.ts b/imxweb/projects/qer/src/lib/itshopapprove/approval.spec.ts index e7d1bb8e9..88a579cdd 100644 --- a/imxweb/projects/qer/src/lib/itshopapprove/approval.spec.ts +++ b/imxweb/projects/qer/src/lib/itshopapprove/approval.spec.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -24,80 +24,77 @@ * */ -import { IEntity, IEntityColumn, EntityCollectionData, EntityColumnData, IClientProperty } from 'imx-qbm-dbts'; -import { ITShopConfig, PwoData } from 'imx-api-qer'; +import { ITShopConfig, PwoData } from '@imx-modules/imx-api-qer'; +import { EntityCollectionData, EntityColumnData, IClientProperty, IEntity, IEntityColumn } from '@imx-modules/imx-qbm-dbts'; import { Approval } from './approval'; describe('Approval', () => { function createColumn(value?) { return { GetMetadata: () => ({ CanEdit: () => true }), - GetValue: () => value + GetValue: () => value, } as IEntityColumn; } function createEntitySchema(columnNames) { const clientProperties = {}; - columnNames.forEach(name => - clientProperties[name] = {} as IClientProperty - ); + columnNames.forEach((name) => (clientProperties[name] = {} as IClientProperty)); return { Columns: clientProperties }; } function createEntity(columns: { [name: string]: IEntityColumn } = {}, key?) { return { GetDisplay: () => '', - GetColumn: name => columns[name] || createColumn(), + GetColumn: (name) => columns[name] || createColumn(), GetKeys: () => [key], - GetSchema: () => createEntitySchema(Object.keys(columns ?? {})) + GetSchema: () => createEntitySchema(Object.keys(columns ?? {})), } as IEntity; } [ { orderState: '', canSet: true }, { orderState: 'OrderUnsubscribe', canSet: false }, - ].forEach(testcase => + ].forEach((testcase) => it('checks if user can set ValidFrom', () => { - const approval = new Approval( - { - entity: createEntity({ - OrderState: createColumn(testcase.orderState), - ValidFrom: undefined - }), - parameterColumns: [] - } - ); + const approval = new Approval({ + commit: () => Promise.resolve(), + entity: createEntity({ + OrderState: createColumn(testcase.orderState), + ValidFrom: undefined, + }), + parameterColumns: [], + }); expect(approval.canSetValidFrom()).toEqual(testcase.canSet); - })); + }), + ); [ { orderState: '', canSet: true }, { orderState: 'OrderUnsubscribe', canSet: false }, - ].forEach(testcase => + ].forEach((testcase) => it('checks if user can set ValidUntil', () => { - const approval = new Approval( - { - entity: createEntity({ - OrderState: createColumn(testcase.orderState), - ValidUntil: undefined - }), - parameterColumns: [] - } - ); + const approval = new Approval({ + commit: () => Promise.resolve(), + entity: createEntity({ + OrderState: createColumn(testcase.orderState), + ValidUntil: undefined, + }), + parameterColumns: [], + }); expect(approval.canSetValidUntil({} as ITShopConfig)).toEqual(testcase.canSet); - })); + }), + ); it('provides decisionOffset', () => { const decisionLevel = 23; const levelNumber = 3; const expectedDecisionOffset = levelNumber - decisionLevel; - const approval = new Approval( - { - entity: createEntity({ DecisionLevel: createColumn(decisionLevel) }), - parameterColumns: [] - } - ); - approval.updateDirectDecisionTarget({ GetColumn: name => ({ LevelNumber: createColumn(levelNumber) }[name]) } as IEntity); + const approval = new Approval({ + commit: () => Promise.resolve(), + entity: createEntity({ DecisionLevel: createColumn(decisionLevel) }), + parameterColumns: [], + }); + approval.updateDirectDecisionTarget({ GetColumn: (name) => ({ LevelNumber: createColumn(levelNumber) })[name] } as IEntity); expect(approval.decisionOffset).toEqual(expectedDecisionOffset); }); @@ -107,47 +104,49 @@ describe('Approval', () => { const decisionLevel = 0; const uidWorkingStep = 'some workingstep uid'; - const approval = new Approval( - { - entity: createEntity({ + const approval = new Approval({ + commit: () => Promise.resolve(), + entity: createEntity( + { DecisionLevel: createColumn(decisionLevel), CanDelegateOrAddApprover: createColumn(true), - }, approvalKey), - parameterColumns: [], - pwoData: { - WorkflowSteps: { - TotalCount: 1, - Entities: [ - { - Columns: { - DirectSteps: { Value: '1' }, - LevelNumber:{Value: 0}, - IsAdditionalAllowed: { Value: true }, - IsInsteadOfAllowed: { Value: true }, - EscalationSteps: { Value: 1 }, - UID_QERWorkingStep: { Value: uidWorkingStep } - } as { [key: string]: EntityColumnData } - } - ] - } as EntityCollectionData, - WorkflowData: { - TotalCount: 1, - Entities: [ - { - Columns: { - LevelNumber: { Value: decisionLevel }, - UID_PersonAdditional: { Value: '' }, - UID_PersonInsteadOf: { Value: '' }, - IsFromDelegation: { Value: false }, - UID_PersonHead: { Value: userUid }, - UID_QERWorkingStep: { Value: uidWorkingStep } - } as { [key: string]: EntityColumnData } - } - ] - } as EntityCollectionData - } as PwoData - } - ); + }, + approvalKey, + ), + parameterColumns: [], + pwoData: { + WorkflowSteps: { + TotalCount: 1, + Entities: [ + { + Columns: { + DirectSteps: { Value: '1' }, + LevelNumber: { Value: 0 }, + IsAdditionalAllowed: { Value: true }, + IsInsteadOfAllowed: { Value: true }, + EscalationSteps: { Value: 1 }, + UID_QERWorkingStep: { Value: uidWorkingStep }, + } as { [key: string]: EntityColumnData }, + }, + ], + } as EntityCollectionData, + WorkflowData: { + TotalCount: 1, + Entities: [ + { + Columns: { + LevelNumber: { Value: decisionLevel }, + UID_PersonAdditional: { Value: '' }, + UID_PersonInsteadOf: { Value: '' }, + IsFromDelegation: { Value: false }, + UID_PersonHead: { Value: userUid }, + UID_QERWorkingStep: { Value: uidWorkingStep }, + } as { [key: string]: EntityColumnData }, + }, + ], + } as EntityCollectionData, + } as PwoData, + }); expect(approval.canRerouteDecision(userUid)).toEqual(true); expect(approval.canAddApprover(userUid)).toEqual(true); @@ -158,32 +157,32 @@ describe('Approval', () => { [ { value: true, expected: 1 }, { value: false, expected: 0 }, - { value: undefined, expected: 0 } - ].forEach(testcase => - it('adds IsCrossFunctional to propertyInfo only if it is "true"', () => { - const approval = new Approval( - { + { value: undefined, expected: 0 }, + ].forEach((testcase) => + it('adds IsCrossFunctional to propertyInfo only if it is "true"', () => { + const approval = new Approval({ + commit: () => Promise.resolve(), entity: createEntity({ IsCrossFunctional: { GetValue: () => testcase.value } as IEntityColumn }), - parameterColumns: [] - } - ); + parameterColumns: [], + }); - expect(approval.propertyInfo.length).toEqual(testcase.expected); - })); + expect(approval.propertyInfo.length).toEqual(testcase.expected); + }), + ); [ { value: 'some reason', expected: 1 }, { value: '', expected: 0 }, - { value: undefined, expected: 0 } - ].forEach(testcase => - it('adds OrderReason to propertyInfo only if it is non-empty', () => { - const approval = new Approval( - { + { value: undefined, expected: 0 }, + ].forEach((testcase) => + it('adds OrderReason to propertyInfo only if it is non-empty', () => { + const approval = new Approval({ + commit: () => Promise.resolve(), entity: createEntity({ OrderReason: { GetValue: () => testcase.value } as IEntityColumn }), - parameterColumns: [] - } - ); + parameterColumns: [], + }); - expect(approval.propertyInfo.length).toEqual(testcase.expected); - })); + expect(approval.propertyInfo.length).toEqual(testcase.expected); + }), + ); }); diff --git a/imxweb/projects/qer/src/lib/itshopapprove/approval.ts b/imxweb/projects/qer/src/lib/itshopapprove/approval.ts index 7a94e0681..416acb47c 100644 --- a/imxweb/projects/qer/src/lib/itshopapprove/approval.ts +++ b/imxweb/projects/qer/src/lib/itshopapprove/approval.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -24,8 +24,8 @@ * */ -import { PortalItshopApproveRequests, PwoData, ITShopConfig } from 'imx-api-qer'; -import { IEntity, IEntityColumn } from 'imx-qbm-dbts'; +import { ITShopConfig, PortalItshopApproveRequests, PwoData } from '@imx-modules/imx-api-qer'; +import { IEntity, IEntityColumn } from '@imx-modules/imx-qbm-dbts'; import { BaseReadonlyCdr } from 'qbm'; import { ItshopRequestEntityWrapper } from '../itshop/request-info/itshop-request-entity-wrapper.interface'; import { RequestParameterDataEntity } from '../itshop/request-info/request-parameter-data-entity.interface'; @@ -67,7 +67,7 @@ export class Approval extends PortalItshopApproveRequests implements RequestPara this.workflowWrapper = new WorkflowDataWrapper(this.pwoData); } - this.parameterColumns = entityWrapper.parameterColumns; + this.parameterColumns = entityWrapper.parameterColumns || []; this.propertyInfo = [ this.DisplayOrg, @@ -91,11 +91,11 @@ export class Approval extends PortalItshopApproveRequests implements RequestPara property.value != null && property.value !== '' && property.value !== false && - !this.parameterColumns.find((column) => column.ColumnName === property.Column.ColumnName) + !this.parameterColumns.find((column) => column.ColumnName === property.Column.ColumnName), ) .map((property) => new BaseReadonlyCdr(property.Column)); - this.currentUser = entityWrapper.uidCurrentUser; + this.currentUser = entityWrapper.uidCurrentUser ?? ''; } public async commit(): Promise { @@ -106,12 +106,12 @@ export class Approval extends PortalItshopApproveRequests implements RequestPara return this.ValidFrom.GetMetadata().CanEdit() && !this.entityWrapper.isChiefApproval && this.OrderState.value !== 'OrderUnsubscribe'; } - public canSetValidUntil(itShopConfig: ITShopConfig): boolean { + public canSetValidUntil(itShopConfig: ITShopConfig | undefined): boolean { return ( this.ValidUntil.GetMetadata().CanEdit() && !this.entityWrapper.isChiefApproval && this.OrderState.value !== 'OrderUnsubscribe' && - (!itShopConfig.VI_ITShop_ShowValidUntilQERReuse || this.TableName.value !== 'QERReuse') + (!itShopConfig?.VI_ITShop_ShowValidUntilQERReuse || this.TableName.value !== 'QERReuse') ); } diff --git a/imxweb/projects/qer/src/lib/itshopapprove/approvals-decision.enum.ts b/imxweb/projects/qer/src/lib/itshopapprove/approvals-decision.enum.ts index fb975800d..47093f06f 100644 --- a/imxweb/projects/qer/src/lib/itshopapprove/approvals-decision.enum.ts +++ b/imxweb/projects/qer/src/lib/itshopapprove/approvals-decision.enum.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -28,5 +28,5 @@ export enum ApprovalsDecision { none, approve, deny, - denydecision + denydecision, } diff --git a/imxweb/projects/qer/src/lib/itshopapprove/approvals-load-parameters.ts b/imxweb/projects/qer/src/lib/itshopapprove/approvals-load-parameters.ts index e1a089e88..ee5131036 100644 --- a/imxweb/projects/qer/src/lib/itshopapprove/approvals-load-parameters.ts +++ b/imxweb/projects/qer/src/lib/itshopapprove/approvals-load-parameters.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -24,7 +24,7 @@ * */ -import { CollectionLoadParameters } from "imx-qbm-dbts"; +import { CollectionLoadParameters } from '@imx-modules/imx-qbm-dbts'; export interface ApprovalsLoadParameters extends CollectionLoadParameters { Escalation?: boolean; diff --git a/imxweb/projects/qer/src/lib/itshopapprove/approvals-sidesheet/approvals-sidesheet.component.html b/imxweb/projects/qer/src/lib/itshopapprove/approvals-sidesheet/approvals-sidesheet.component.html index e58dae3bd..0a896f93a 100644 --- a/imxweb/projects/qer/src/lib/itshopapprove/approvals-sidesheet/approvals-sidesheet.component.html +++ b/imxweb/projects/qer/src/lib/itshopapprove/approvals-sidesheet/approvals-sidesheet.component.html @@ -1,19 +1,18 @@ -
    +
    - - #LDS#Based on the peer group analysis, it is recommended that you approve this request. + + {{ LdsKeyApprove }} - - #LDS#Based on the peer group analysis, it is recommended that you deny this request. + + {{ LdsKeyDeny }} @@ -33,8 +32,17 @@ --> - - + + + mat-stroked-button + *ngIf="data.pwo.CanAskForHelp.value" + data-imx-identifier="approvals-sidesheet-button-ask-for-helpl" + title="{{ '#LDS#Sends an inquiry about this request to an identity' | translate }}" + (click)="actionService.askForHelp([data.pwo], currentUserId)" + > + {{ '#LDS#Send inquiry' | translate }} + - + - +
    - - - -
    - - - - - - - - - - {{ pwo.UiOrderState.value === 'OrderProduct' ? ('#LDS#Requested' | translate) : '' }} - {{ - pwo.UiOrderState.value === 'OrderProlongate' - ? ('#LDS#Renewed' | translate) + - ' ' + - (pwo.ValidUntilProlongation.value ? ('#LDS#Until' | translate) + ' ' + (pwo.ValidUntilProlongation.value | shortDate) : ('#LDS#unlimited' | translate)) - : '' - }} - {{ ['OrderProduct', 'OrderProlongate'].includes(pwo.UiOrderState.value) ? '' : pwo.UiOrderState.Column.GetDisplayValue() }} - - - - - - -
    -
    - - {{ '#LDS#Priority' | translate }}: {{ pwo.PWOPriority.Column.GetDisplayValue() }} -
    -
    - - {{ '#LDS#Rule violation' | translate }} -
    -
    - - {{ '#LDS#Reserved' | translate }} -
    + + + {{ entitySchema?.Columns?.DisplayOrg?.Display }} + + + + + + + + + {{ entitySchema?.Columns?.UiOrderState?.Display }} + + + + {{ pwo.UiOrderState.value === 'OrderProduct' ? ('#LDS#Requested' | translate) : '' }} + {{ + pwo.UiOrderState.value === 'OrderProlongate' + ? ('#LDS#Renewed' | translate) + + ' ' + + (pwo.ValidUntilProlongation.value + ? ('#LDS#Until' | translate) + ' ' + (pwo.ValidUntilProlongation.value | shortDate) + : ('#LDS#unlimited' | translate)) + : '' + }} + {{ ['OrderProduct', 'OrderProlongate'].includes(pwo.UiOrderState.value) ? '' : pwo.UiOrderState.Column.GetDisplayValue() }} + + + + + + {{ entitySchema?.Columns?.OrderDate?.Display }} + + +
    {{ pwo.OrderDate?.Column.GetDisplayValue() }}
    + +
    + + + +
    +
    + + {{ '#LDS#Priority' | translate }}: {{ pwo.PWOPriority.Column.GetDisplayValue() }}
    - - - - -
    - - +
    + + {{ '#LDS#Rule violation' | translate }}
    - - - - -
    - +
    + + {{ '#LDS#Reserved' | translate }}
    - - - -
    - +
    + + + + + +
    + + +
    + +
    + + + +
    + +
    + +
    + + -
    - -
    +
    + - - + - diff --git a/imxweb/projects/qer/src/lib/itshopapprove/approvals-table.component.scss b/imxweb/projects/qer/src/lib/itshopapprove/approvals-table.component.scss index dbcd9ec0c..22fe5ab14 100644 --- a/imxweb/projects/qer/src/lib/itshopapprove/approvals-table.component.scss +++ b/imxweb/projects/qer/src/lib/itshopapprove/approvals-table.component.scss @@ -1,12 +1,12 @@ -@import '../../../../../shared/scss/common-table.scss'; @import '@elemental-ui/core/src/styles/_eui_palette.scss'; +@import 'base/mixins'; :host { - @include imx-flex-fill-control-hidden-overflow(); + @include flex-column-container-fill(); - .mat-stroked-button, - .mat-raised-button { - @include imx-icon-for-image-button(); + .mat-mdc-outlined-button, + .mat-mdc-unelevated-button { + @include image-button-icon(); } .recommendation-approve-icon { @@ -17,26 +17,6 @@ color: $color-red-60; } - .escalation-approver-toggle { - margin: 0.5em; - } - - .imx-table-container { - flex-grow: 1; - overflow: auto; - } - - .imx-button-bar { - @include imx-button-bar(); - } - - .imx-decision { - @include imx-button-column-right(); - > button:not(:last-of-type) { - margin-right: 5px; - } - } - @media only screen and (max-width: 1024px) { ::ng-deep .mat-column-OrderDate, ::ng-deep .mat-column-decision { @@ -47,7 +27,8 @@ .toggle-wrapper { /* so that the tooltip on the toggle is centered */ flex-grow: 0; - display: inline; + display:flex; + justify-content: space-between; } .imx-badge-container { @@ -65,51 +46,6 @@ flex-direction: column; height: 100%; } - - .imx-icons-container { - padding-right: 15px; - .table-icon { - display: flex; - align-items: center; - font-weight: 600; - height: 14px; - &:not(:first-of-type) { - margin-left: 8px; - padding-left: 8px; - } - .mat-icon, - .eui-icon { - padding-right: 6px; - } - } - } -} - -:host { - .imx-icons-container { - .table-icon { - color: $color-gray-60; - &--warning { - .eui-icon { - color: $color-orange-60; - } - } - &--primary { - .mat-icon { - color: $color-blue-60; - } - } - &--alert { - .eui-icon, - span { - color: $color-red-60; - } - } - &:not(:first-of-type) { - border-left: 1px solid $color-gray-20; - } - } - } } .eui-dark-theme { @@ -117,31 +53,6 @@ .imx-data-tree-container { background-color: $color-gray-70; } - .imx-icons-container { - .table-icon { - color: $color-gray-10; - - &--warning { - .eui-icon { - color: $color-orange-40; - } - } - &--primary { - .mat-icon { - color: $color-blue-40; - } - } - &--alert { - .eui-icon, - span { - color: $color-red-40; - } - } - &:not(:first-of-type) { - border-left: 1px solid $color-gray-10; - } - } - } } } @@ -150,30 +61,6 @@ .imx-data-tree-container { background-color: $color-gray-100; } - .imx-icons-container { - .table-icon { - color: $color-gray-0; - &--warning { - .eui-icon { - color: $color-orange-40; - } - } - &--primary { - .mat-icon { - color: $color-blue-40; - } - } - &--alert { - .eui-icon, - span { - color: $color-red-40; - } - } - &:not(:first-of-type) { - border-left: 1px solid $color-gray-10; - } - } - } } } diff --git a/imxweb/projects/qer/src/lib/itshopapprove/approvals-table.component.spec.ts b/imxweb/projects/qer/src/lib/itshopapprove/approvals-table.component.spec.ts index aa976343a..af247e0aa 100644 --- a/imxweb/projects/qer/src/lib/itshopapprove/approvals-table.component.spec.ts +++ b/imxweb/projects/qer/src/lib/itshopapprove/approvals-table.component.spec.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -25,19 +25,18 @@ */ import { EuiSidesheetService } from '@elemental-ui/core'; -import { of, Subject } from 'rxjs'; import { MockBuilder, MockedComponentFixture, MockRender } from 'ng-mocks'; +import { of, Subject } from 'rxjs'; -import { IEntity, IEntityColumn } from 'imx-qbm-dbts'; +import { IEntity, IEntityColumn } from '@imx-modules/imx-qbm-dbts'; -import { clearStylesFromDOM, ExtService } from 'qbm'; -import { ApprovalsTableComponent } from './approvals-table.component'; +import { clearStylesFromDOM, DataViewSource, ExtService, FakeDataViewSource } from 'qbm'; import { ProjectConfigurationService } from '../project-configuration/project-configuration.service'; -import { ApprovalsService } from './approvals.service'; -import { Approval } from './approval'; -import { WorkflowActionService } from './workflow-action/workflow-action.service'; import { UserModelService } from '../user/user-model.service'; +import { Approval } from './approval'; +import { ApprovalsTableComponent } from './approvals-table.component'; import { ApprovalsModule } from './approvals.module'; +import { WorkflowActionService } from './workflow-action/workflow-action.service'; describe('ApprovalsTable', () => { let component: ApprovalsTableComponent; @@ -62,7 +61,7 @@ describe('ApprovalsTable', () => { getConfig: jasmine.createSpy('getConfig').and.returnValue( Promise.resolve({ ITShopConfig: {}, - }) + }), ), }; @@ -89,10 +88,10 @@ describe('ApprovalsTable', () => { .mock(ApprovalsModule) .mock(ExtService, extServiceStub as unknown) .mock(EuiSidesheetService, sideSheetTestHelper.servicestub) - .mock(UserModelService,{ getFeatures: () => Promise.resolve({}) }) - .mock(WorkflowActionService, { applied: new Subject() }) + .mock(UserModelService, { getFeatures: () => Promise.resolve({}) }) + .mock(WorkflowActionService, { applied: new Subject() }) .mock(ProjectConfigurationService, projectConfigurationServiceStub) - .mock(ApprovalsService); + .mock(DataViewSource, FakeDataViewSource); }); beforeEach(() => { @@ -151,6 +150,6 @@ describe('ApprovalsTable', () => { component.onSelectionChanged([approval]); expect(component.selectedItems.length).toBe(1); - expect(component.selectedItems[0].DocumentNumber.value).toBe('123'); + expect((component.selectedItems[0] as Approval).DocumentNumber.value).toBe('123'); }); }); diff --git a/imxweb/projects/qer/src/lib/itshopapprove/approvals-table.component.ts b/imxweb/projects/qer/src/lib/itshopapprove/approvals-table.component.ts index dca15aaa9..080532230 100644 --- a/imxweb/projects/qer/src/lib/itshopapprove/approvals-table.component.ts +++ b/imxweb/projects/qer/src/lib/itshopapprove/approvals-table.component.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -24,44 +24,54 @@ * */ -import { Component, Input, OnDestroy, OnInit, ViewChild } from '@angular/core'; +import { Component, Input, OnDestroy, OnInit } from '@angular/core'; import { Params } from '@angular/router'; import { EuiSidesheetService } from '@elemental-ui/core'; -import { Subscription } from 'rxjs'; import { TranslateService } from '@ngx-translate/core'; +import { Subscription } from 'rxjs'; -import { PwoExtendedData, RecommendationEnum, ViewConfigData } from 'imx-api-qer'; -import { ValType, ExtendedTypedEntityCollection, TypedEntity, EntitySchema, DataModel, IClientProperty } from 'imx-qbm-dbts'; +import { PwoExtendedData, RecommendationEnum, ViewConfigData } from '@imx-modules/imx-api-qer'; +import { + CollectionLoadParameters, + DataModel, + EntitySchema, + ExtendedTypedEntityCollection, + IClientProperty, + ValType, +} from '@imx-modules/imx-qbm-dbts'; import { - DataSourceToolbarSettings, - ClassloggerService, AuthenticationService, - DataTableComponent, - SettingsService, - IExtension, - ExtService, - buildAdditionalElementsString, - DataSourceToolbarViewConfig, - ClientPropertyForTableColumns, BusyService, + calculateSidesheetWidth, + ClassloggerService, + ClientPropertyForTableColumns, + DataSourceToolbarSettings, + DataSourceToolbarViewConfig, + DataViewInitParameters, + DataViewSource, + ExtService, + IExtension, + ISessionState, + SettingsService, } from 'qbm'; -import { ApprovalsSidesheetComponent } from './approvals-sidesheet/approvals-sidesheet.component'; -import { Approval } from './approval'; +import { QerPermissionsService } from '../admin/qer-permissions.service'; import { ProjectConfigurationService } from '../project-configuration/project-configuration.service'; -import { ApprovalsService } from './approvals.service'; -import { WorkflowActionService } from './workflow-action/workflow-action.service'; -import { ApprovalsLoadParameters } from './approvals-load-parameters'; -import { ApprovalsDecision } from './approvals-decision.enum'; import { UserModelService } from '../user/user-model.service'; +import { Approval } from './approval'; +import { ApprovalsDecision } from './approvals-decision.enum'; +import { ApprovalsLoadParameters } from './approvals-load-parameters'; +import { ApprovalsSidesheetComponent } from './approvals-sidesheet/approvals-sidesheet.component'; +import { ApprovalsService } from './approvals.service'; import { RecommendationSidesheetComponent } from './recommendation-sidesheet/recommendation-sidesheet.component'; -import { QerPermissionsService } from '../admin/qer-permissions.service'; +import { WorkflowActionService } from './workflow-action/workflow-action.service'; -import { ViewConfigService } from '../view-config/view-config.service'; import { isCancelPwO } from '../admin/qer-permissions-helper'; +import { ViewConfigService } from '../view-config/view-config.service'; @Component({ templateUrl: './approvals-table.component.html', selector: 'imx-approvals-table', styleUrls: ['./approvals-table.component.scss'], + providers: [DataViewSource], }) export class ApprovalsTableComponent implements OnInit, OnDestroy { public recApprove = RecommendationEnum.Approve; @@ -69,39 +79,42 @@ export class ApprovalsTableComponent implements OnInit, OnDestroy { private isChiefApprover = false; - public get tableReady() { return this.countTableLoading == 0; } - private countTableLoading = 0; - @Input() public params: Params = {}; + @Input() hideToolbar = true; public isUserEscalationApprover = false; + public abortController: AbortController = new AbortController(); + public get canWithdrawAdditionalApprover(): boolean { - return this.selectedItems.every((item) => item.canWithdrawAdditionalApprover(this.currentUserId)); + return this.selectedItems.every((item: Approval) => item.canWithdrawAdditionalApprover(this.currentUserId)); } public get canAddApprover(): boolean { - return this.selectedItems.every((item) => item.canAddApprover(this.currentUserId)); + return this.selectedItems.every((item: Approval) => item.canAddApprover(this.currentUserId)); } public get canDelegateDecision(): boolean { - return this.selectedItems.every((item) => item.canDelegateDecision(this.currentUserId)); + return this.selectedItems.every((item: Approval) => item.canDelegateDecision(this.currentUserId)); } public get canDenyApproval(): boolean { - return this.selectedItems.every((item) => item.canDenyApproval(this.currentUserId)); + return this.selectedItems.every((item: Approval) => item.canDenyApproval(this.currentUserId)); } public get canEscalateDecision(): boolean { - return this.selectedItems.every((item) => item.canEscalateDecision); + return this.selectedItems.every((item: Approval) => item.canEscalateDecision); } public get canRerouteDecision(): boolean { - return this.selectedItems.every((item) => item.canRerouteDecision(this.currentUserId)); + return this.selectedItems.every((item: Approval) => item.canRerouteDecision(this.currentUserId)); } - public get canResetReservation(): boolean{ - return this.selectedItems.every((item)=> item.canResetReservation(this.isChiefApprover)); + public get canResetReservation(): boolean { + return this.selectedItems.every((item: Approval) => item.canResetReservation(this.isChiefApprover)); } - public get canRecallInquiry(): boolean{ - return this.selectedItems.every((item)=> item.canRecallInquiry); + public get canSendInquiry(): boolean { + return this.selectedItems.every((item: Approval) => item.CanAskForHelp.value); } + public get canRecallInquiry(): boolean { + return this.selectedItems.every((item: Approval) => item.canRecallInquiry); + } public get canPerformActions(): boolean { return ( @@ -112,22 +125,19 @@ export class ApprovalsTableComponent implements OnInit, OnDestroy { this.canDenyApproval || this.canRerouteDecision || this.canEscalateDecision || - this.canRecallInquiry || this.canResetReservation) + this.canSendInquiry || + this.canRecallInquiry || + this.canResetReservation) ); } public currentUserId: string; - public dstSettings: DataSourceToolbarSettings; public readonly entitySchema: EntitySchema; public canBeDelegated = false; public selectedItems: Approval[] = []; - public approvalsCollection: ExtendedTypedEntityCollection; - public hasData = false; public busyService = new BusyService(); - @ViewChild(DataTableComponent) private readonly table: DataTableComponent; - private navigationState: ApprovalsLoadParameters; private approvalsDecision: ApprovalsDecision = ApprovalsDecision.none; private extensions: IExtension[] = []; @@ -151,7 +161,8 @@ export class ApprovalsTableComponent implements OnInit, OnDestroy { private readonly userModelService: UserModelService, authentication: AuthenticationService, private readonly ext: ExtService, - private readonly permissions : QerPermissionsService, + private readonly permissions: QerPermissionsService, + public dataSource: DataViewSource, ) { this.navigationState = { PageSize: settingsService.DefaultPageSize, StartIndex: 0 }; this.entitySchema = approvalsService.PortalItshopApproveRequestsSchema; @@ -164,27 +175,27 @@ export class ApprovalsTableComponent implements OnInit, OnDestroy { ColumnName: 'decision', Type: ValType.String, afterAdditionals: true, - untranslatedDisplay: '#LDS#Approval decision' + untranslatedDisplay: '#LDS#Approval decision', }, { ColumnName: 'recommendations', Type: ValType.String, - untranslatedDisplay: '#LDS#Recommendation' + untranslatedDisplay: '#LDS#Recommendation', }, ]; this.subscriptions.push( this.actionService.applied.subscribe(async () => { - this.getData(); - this.table.clearSelection(); - }) + this.dataSource.selection.clear(); + this.dataSource.updateState(); + }), ); this.subscriptions.push( - authentication.onSessionResponse.subscribe((state) => { - this.currentUserId = state.UserUid; + authentication.onSessionResponse.subscribe((state: ISessionState) => { + this.currentUserId = state.UserUid || ''; if (state.IsLoggedIn) { this.viewEscalation = false; } - }) + }), ); this.userModelService.getFeatures().then((featureInfo) => { this.isUserEscalationApprover = isCancelPwO(featureInfo.Features || []); @@ -193,8 +204,11 @@ export class ApprovalsTableComponent implements OnInit, OnDestroy { this.extensions = this.ext.Registry[this.UID_ComplianceRuleId]; if (this.extensions && this.extensions.length > 0) { - this.extensions[0].subject.subscribe((dstSettings: DataSourceToolbarSettings) => { - this.dstSettings = dstSettings; + this.extensions[0].subject?.subscribe((dstSettings: DataSourceToolbarSettings) => { + this.dataSource.collectionData.update((collectionData) => ({ + ...collectionData, + Data: dstSettings.dataSource?.Data as Approval[], + })); }); } } @@ -204,9 +218,20 @@ export class ApprovalsTableComponent implements OnInit, OnDestroy { const isBusy = this.busyService.beginBusy(); try { - this.dataModel = await this.approvalsService.getApprovalDataModel(); + this.dataModel = await this.approvalsService.getApprovalDataModel(this.abortController.signal); this.isChiefApprover = await this.permissions.isCancelPwO(); - this.viewConfig = await this.viewConfigService.getInitialDSTExtension(this.dataModel, this.viewConfigPath); + if (this.abortController.signal.aborted) { + return; + } + this.viewConfig = await this.viewConfigService.getInitialDSTExtension( + this.dataModel, + this.viewConfigPath, + this.abortController.signal, + ); + + if (this.abortController.signal.aborted) { + return; + } await this.getData(); this.handleDecision(); @@ -217,6 +242,8 @@ export class ApprovalsTableComponent implements OnInit, OnDestroy { public ngOnDestroy(): void { this.approvalsService.abortCall(); + this.dataSource?.abortCall(); + this.abortController.abort(); // Set service value back to false since the toggle value is stored there this.approvalsService.isChiefApproval = false; this.subscriptions.forEach((s) => s.unsubscribe()); @@ -225,13 +252,13 @@ export class ApprovalsTableComponent implements OnInit, OnDestroy { public async updateConfig(config: ViewConfigData): Promise { await this.viewConfigService.putViewConfig(config); this.viewConfig = await this.viewConfigService.getDSTExtensionChanges(this.viewConfigPath); - this.dstSettings.viewConfig = this.viewConfig; + this.dataSource.viewConfig.set(this.viewConfig); } public async deleteConfigById(id: string): Promise { await this.viewConfigService.deleteViewConfig(id); this.viewConfig = await this.viewConfigService.getDSTExtensionChanges(this.viewConfigPath); - this.dstSettings.viewConfig = this.viewConfig; + this.dataSource.viewConfig.set(this.viewConfig); } public get viewEscalation(): boolean { @@ -241,40 +268,56 @@ export class ApprovalsTableComponent implements OnInit, OnDestroy { this.approvalsService.isChiefApproval = val; } - public switchEscalation(): Promise { - // Set start index to 0 and clear selection before changing - const navigationState = { - ...this.navigationState, - ...{ - StartIndex: 0, - }, - }; - this.table.clearSelection(); - return this.getData(navigationState); + public switchEscalation(): void { + this.dataSource.selection.clear(); + this.dataSource.state.update((state) => ({ ...state, StartIndex: 0 })); + this.dataSource.updateState(); } - public getAdditionalText(entity: Approval, additional: IClientProperty[]): string { - return buildAdditionalElementsString(entity.GetEntity(), additional); + public getAdditionalText(entity: Approval): string { + return ( + this.dataSource + .additionalListColumns() + ?.map((elem: IClientProperty) => { + return `${elem?.Display || elem?.ColumnName}: ${elem?.ColumnName == null ? '-' : entity.GetEntity().GetColumn(elem.ColumnName).GetDisplayValue() || '-'}`; + }) + .filter((elem) => !!elem) + .join('; ') || '' + ); } - public async getData(parameters?: ApprovalsLoadParameters): Promise { - if (parameters) { - this.navigationState = parameters; - } - - const isBusy = this.busyService.beginBusy(); - - try { - this.approvalsCollection = await this.approvalsService.get(this.navigationState, {signal: this.approvalsService.abortController.signal}); - this.hasData = this.approvalsCollection?.totalCount > 0 || (this.navigationState.search ?? '') !== ''; - this.updateTable(); - - if (this.extensions && this.extensions[0]) { - this.extensions[0].inputData = this.dstSettings; - } - } finally { - isBusy.endBusy(); - } + public async getData(): Promise { + const dataViewInitParameters: DataViewInitParameters = { + execute: ( + params: CollectionLoadParameters, + signal: AbortSignal, + ): Promise | undefined> => { + return Promise.resolve( + this.approvalsService.get(params, { signal }).then((collectionData) => { + if (this.extensions) { + const dstSettings: DataSourceToolbarSettings = { + dataSource: collectionData, + navigationState: this.dataSource.state, + entitySchema: this.entitySchema, + extendedData: collectionData?.extendedData?.Data, + }; + this.extensions[0].inputData = dstSettings; + } + return collectionData; + }), + ); + }, + schema: this.entitySchema, + columnsToDisplay: this.displayedColumns, + dataModel: this.dataModel, + exportFunction: this.approvalsService.exportApprovalRequests(this.dataSource.state()), + viewConfig: this.viewConfig, + highlightEntity: (approval: Approval) => { + this.editPwo(approval); + }, + selectionChange: (approval: Approval[]) => this.onSelectionChanged(approval), + }; + this.dataSource.init(dataViewInitParameters); } /** @@ -289,7 +332,7 @@ export class ApprovalsTableComponent implements OnInit, OnDestroy { title: await this.translator.get('#LDS#Heading View Request Details').toPromise(), subTitle: pwo.GetEntity().GetDisplay(), padding: '0', - width: 'max(700px, 60%)', + width: calculateSidesheetWidth(1000), testId: 'approvals-sidesheet', data: { pwo, @@ -301,7 +344,7 @@ export class ApprovalsTableComponent implements OnInit, OnDestroy { .toPromise(); if (doUpdate) { - await this.getData(); + await this.dataSource.updateState(); } } @@ -318,9 +361,9 @@ export class ApprovalsTableComponent implements OnInit, OnDestroy { subTitle: pwo.GetEntity().GetDisplay(), panelClass: 'imx-sidesheet', padding: '0', - width: 'max(700px, 60%)', + width: calculateSidesheetWidth(1000), testId: 'approval-recommendation-sidesheet', - data: pwo.pwoData.Recommendation, + data: { recommendations: pwo.pwoData.Recommendation }, }) .afterClosed() .toPromise(); @@ -332,43 +375,11 @@ export class ApprovalsTableComponent implements OnInit, OnDestroy { } } - public onSearch(keywords: string): Promise { - const navigationState = { - ...this.navigationState, - ...{ - StartIndex: 0, - search: keywords, - }, - }; - - return this.getData(navigationState); - } - public onSelectionChanged(items: Approval[]): void { this.logger.trace(this, 'selection changed', items); this.selectedItems = items; } - private updateTable(): void { - if (this.approvalsCollection) { - const exportMethod = this.approvalsService.exportApprovalRequests(this.navigationState); - exportMethod.initialColumns = this.displayedColumns.map(col => col.ColumnName); - this.dstSettings = { - dataSource: this.approvalsCollection, - extendedData: this.approvalsCollection.extendedData.Data, - entitySchema: this.entitySchema, - navigationState: this.navigationState, - displayedColumns: this.displayedColumns, - dataModel: this.dataModel, - viewConfig: this.viewConfig, - filters: this.dataModel.Filters, - exportMethod - }; - } else { - this.dstSettings = undefined; - } - } - private parseParams(): void { // Cases: VI_BuildITShopLink_Approve, VI_BuildITShopLink_Deny, VI_BuildITShopLink_Reject if (this.params.uid_personwantsorg && this.params.uid_pwohelperpwo && this.params.decision) { @@ -392,23 +403,19 @@ export class ApprovalsTableComponent implements OnInit, OnDestroy { } private handleDecision(): void { - if ( - this.approvalsDecision === ApprovalsDecision.none || - this.approvalsCollection.Data == null || - this.approvalsCollection.Data.length === 0 - ) { + if (this.approvalsDecision === ApprovalsDecision.none || !!this.dataSource.collectionData()?.Data?.length) { return; } switch (this.approvalsDecision) { case ApprovalsDecision.approve: - this.actionService.approve(this.approvalsCollection.Data); + this.actionService.approve(this.dataSource.collectionData()?.Data || []); break; case ApprovalsDecision.deny: - this.actionService.deny(this.approvalsCollection.Data); + this.actionService.deny(this.dataSource.collectionData()?.Data || []); break; case ApprovalsDecision.denydecision: - this.actionService.denyDecisions(this.approvalsCollection.Data); + this.actionService.denyDecisions(this.dataSource.collectionData()?.Data || []); break; } } diff --git a/imxweb/projects/qer/src/lib/itshopapprove/approvals.component.html b/imxweb/projects/qer/src/lib/itshopapprove/approvals.component.html index 9b83e7d3e..bf8faa4ca 100644 --- a/imxweb/projects/qer/src/lib/itshopapprove/approvals.component.html +++ b/imxweb/projects/qer/src/lib/itshopapprove/approvals.component.html @@ -1,26 +1,38 @@ -
    -

    +
    +

    #LDS#Heading Pending Requests -

    +

    + + +
    - + - + - + - - + + +
    + + + + diff --git a/imxweb/projects/qer/src/lib/itshopapprove/approvals.component.scss b/imxweb/projects/qer/src/lib/itshopapprove/approvals.component.scss index 30c1daf85..edbaec5f7 100644 --- a/imxweb/projects/qer/src/lib/itshopapprove/approvals.component.scss +++ b/imxweb/projects/qer/src/lib/itshopapprove/approvals.component.scss @@ -1,4 +1,4 @@ -@import "@elemental-ui/core/src/styles/_eui_palette.scss"; +@import '@elemental-ui/core/src/styles/_eui_palette.scss'; :host { display: flex; @@ -15,61 +15,7 @@ overflow: hidden; } -.mat-tab-group { - height: 100%; - overflow: hidden; - - ::ng-deep .mat-tab-body-wrapper { - flex: 1 1 auto; - - .mat-tab-body-content { - height: 100%; - overflow: hidden; - display: flex; - flex-direction: column; - } - } -} - .heading-wrapper { display: flex; align-items: flex-start; - - .helper-alert { - display: flex; - margin: 0 0 20px auto; - align-self: flex-end; - flex-basis: 50%; - span { - display: block; - } - } -} - -:host { - .mat-tab-group { - ::ng-deep .mat-tab-labels { - background-color: $color-gray-0; - } - } -} - -.eui-dark-theme { - :host { - .mat-tab-group { - ::ng-deep .mat-tab-labels { - background-color: $color-gray-70; - } - } - } -} - -.eui-contrast-theme { - :host { - .mat-tab-group { - ::ng-deep .mat-tab-labels { - background-color: $color-gray-100; - } - } - } } diff --git a/imxweb/projects/qer/src/lib/itshopapprove/approvals.component.spec.ts b/imxweb/projects/qer/src/lib/itshopapprove/approvals.component.spec.ts index 7215ac024..7b59f23e3 100644 --- a/imxweb/projects/qer/src/lib/itshopapprove/approvals.component.spec.ts +++ b/imxweb/projects/qer/src/lib/itshopapprove/approvals.component.spec.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -41,13 +41,17 @@ describe('Approvals', () => { beforeEach(() => { return MockBuilder(ApprovalsComponent, ApprovalsModule) .mock(EuiSidesheetService) - .mock(UserModelService,{getPendingItems: jasmine.createSpy('getPendingItems').and.returnValue(Promise.resolve({}))},{export:true}) + .mock( + UserModelService, + { getPendingItems: jasmine.createSpy('getPendingItems').and.returnValue(Promise.resolve({})) }, + { export: true }, + ) .mock( ActivatedRoute, { queryParams: from([]), }, - { export: true } + { export: true }, ); }); diff --git a/imxweb/projects/qer/src/lib/itshopapprove/approvals.component.ts b/imxweb/projects/qer/src/lib/itshopapprove/approvals.component.ts index c69a48a26..16e18a557 100644 --- a/imxweb/projects/qer/src/lib/itshopapprove/approvals.component.ts +++ b/imxweb/projects/qer/src/lib/itshopapprove/approvals.component.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -24,13 +24,16 @@ * */ -import { Component, OnInit } from '@angular/core'; +import { ChangeDetectorRef, Component, OnInit, ViewChild } from '@angular/core'; import { ActivatedRoute, Params } from '@angular/router'; import { first } from 'rxjs/operators'; +import { PwoExtendedData } from '@imx-modules/imx-api-qer'; +import { DataViewSource, HELP_CONTEXTUAL, HelpContextualValues } from 'qbm'; import { PendingItemsType } from '../user/pending-items-type.interface'; import { UserModelService } from '../user/user-model.service'; -import { HELP_CONTEXTUAL, HelpContextualValues } from 'qbm'; +import { Approval } from './approval'; +import { ApprovalsTableComponent } from './approvals-table.component'; @Component({ templateUrl: './approvals.component.html', @@ -42,10 +45,13 @@ export class ApprovalsComponent implements OnInit { public tabIndex = 0; public hasInquiries = false; public viewReady = false; + public dataSource: DataViewSource; + @ViewChild('approvalsTableComponent', { static: false }) public approvalsTableComponent: ApprovalsTableComponent; constructor( private readonly activatedRoute: ActivatedRoute, - private readonly usermodelService: UserModelService + private readonly usermodelService: UserModelService, + private changeDetectionRef: ChangeDetectorRef, ) {} public async ngOnInit(): Promise { @@ -54,24 +60,29 @@ export class ApprovalsComponent implements OnInit { this.hasInquiries = pendingItems.OpenInquiries > 0; const queryParams = await this.activatedRoute.queryParams.pipe(first()).toPromise(); const result = {}; - for (const [key, value] of Object.entries(queryParams)) { - result[key.toLowerCase()] = value; + if (queryParams) { + for (const [key, value] of Object.entries(queryParams)) { + result[key.toLowerCase()] = value; + } } this.params = result; if (this.params.inquiries) { this.tabIndex = 1; - this.hasInquiries = true;} + this.hasInquiries = true; + } } finally { this.viewReady = true; + this.changeDetectionRef.detectChanges(); + this.dataSource = this.approvalsTableComponent?.dataSource; } } - public get contextId(): HelpContextualValues{ - if(this.tabIndex === 0){ + public get contextId(): HelpContextualValues { + if (this.tabIndex === 0) { return HELP_CONTEXTUAL.PendingRequest; - }else{ + } else { return HELP_CONTEXTUAL.PendingRequestInquiries; } } diff --git a/imxweb/projects/qer/src/lib/itshopapprove/approvals.module.ts b/imxweb/projects/qer/src/lib/itshopapprove/approvals.module.ts index edee8dc8c..56850e22e 100644 --- a/imxweb/projects/qer/src/lib/itshopapprove/approvals.module.ts +++ b/imxweb/projects/qer/src/lib/itshopapprove/approvals.module.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -24,56 +24,56 @@ * */ -import { NgModule } from '@angular/core'; import { CommonModule } from '@angular/common'; +import { NgModule } from '@angular/core'; import { FormsModule, ReactiveFormsModule } from '@angular/forms'; +import { MatTabsModule } from '@angular/material/tabs'; import { RouterModule, Routes } from '@angular/router'; -import { TranslateModule } from '@ngx-translate/core'; import { EuiCoreModule, EuiMaterialModule } from '@elemental-ui/core'; -import { MatTabsModule } from '@angular/material/tabs'; +import { TranslateModule } from '@ngx-translate/core'; import { BulkPropertyEditorModule, + BusyIndicatorModule, CdrModule, ClassloggerService, DataSourceToolbarModule, DataTableModule, + DataViewModule, DateModule, EntityModule, + HelpContextualModule, LdsReplaceModule, MenuItem, MenuService, - BusyIndicatorModule, RouteGuardService, SelectedElementsModule, - HelpContextualModule, - HELP_CONTEXTUAL } from 'qbm'; -import { ApprovalsComponent } from './approvals.component'; -import { ApprovalsTableComponent } from './approvals-table.component'; -import { ApprovalsService } from './approvals.service'; -import { ApprovalsSidesheetComponent } from './approvals-sidesheet/approvals-sidesheet.component'; -import { QueryPersonComponent } from './workflow-actions/query-person.component'; -import { WorkflowActionComponent } from './workflow-action/workflow-action.component'; +import { MatCheckboxModule } from '@angular/material/checkbox'; import { ItshopModule } from '../itshop/itshop.module'; +import { JustificationModule } from '../justification/justification.module'; import { RequestHistoryModule } from '../request-history/request-history.module'; import { RequestsFeatureGuardService } from '../requests-feature-guard.service'; -import { JustificationModule } from '../justification/justification.module'; -import { WorkflowMultiActionComponent } from './workflow-action/workflow-multi-action/workflow-multi-action.component'; -import { WorkflowSingleActionComponent } from './workflow-action/workflow-single-action/workflow-single-action.component'; +import { ApprovalsSidesheetComponent } from './approvals-sidesheet/approvals-sidesheet.component'; +import { ApprovalsTableComponent } from './approvals-table.component'; +import { ApprovalsComponent } from './approvals.component'; +import { ApprovalsService } from './approvals.service'; +import { InquiriesComponent } from './inquiries/inquiries.component'; import { RecommendationSidesheetComponent } from './recommendation-sidesheet/recommendation-sidesheet.component'; import { ApprovalHistoryComponent } from './workflow-action/approval-history/approval-history.component'; import { HistoryFilterComponent } from './workflow-action/approval-history/history-filter/history-filter.component'; -import { MatCheckboxModule } from '@angular/material/checkbox'; -import { InquiriesComponent } from './inquiries/inquiries.component' +import { WorkflowActionComponent } from './workflow-action/workflow-action.component'; +import { WorkflowMultiActionComponent } from './workflow-action/workflow-multi-action/workflow-multi-action.component'; +import { WorkflowSingleActionComponent } from './workflow-action/workflow-single-action/workflow-single-action.component'; +import { QueryPersonComponent } from './workflow-actions/query-person.component'; const routes: Routes = [ { path: 'itshop/approvals', component: ApprovalsComponent, canActivate: [RouteGuardService, RequestsFeatureGuardService], - resolve: [RouteGuardService] + resolve: [RouteGuardService], }, ]; @@ -89,7 +89,7 @@ const routes: Routes = [ RecommendationSidesheetComponent, InquiriesComponent, ApprovalHistoryComponent, - HistoryFilterComponent + HistoryFilterComponent, ], imports: [ BulkPropertyEditorModule, @@ -114,52 +114,44 @@ const routes: Routes = [ TranslateModule, SelectedElementsModule, HelpContextualModule, + DataViewModule, ], - providers: [ - ApprovalsService - ], - exports: [ - RecommendationSidesheetComponent - ] + providers: [ApprovalsService], + exports: [RecommendationSidesheetComponent, WorkflowActionComponent], }) export class ApprovalsModule { constructor( private readonly menuService: MenuService, - logger: ClassloggerService + logger: ClassloggerService, ) { logger.info(this, '▶️ ApprovalsModule loaded'); this.setupMenu(); } private setupMenu(): void { - this.menuService.addMenuFactories( - (preProps: string[], features: string[]) => { - - const items: MenuItem[] = []; + this.menuService.addMenuFactories((preProps: string[], features: string[]) => { + const items: MenuItem[] = []; - if (preProps.includes('ITSHOP')) { - items.push( - { - id: 'QER_Request_PendingRequests', - navigationCommands: { - commands: ['itshop', 'approvals'] - }, - title: '#LDS#Menu Entry Pending requests', - sorting: '10-30', - }, - ); - } + if (preProps.includes('ITSHOP')) { + items.push({ + id: 'QER_Request_PendingRequests', + navigationCommands: { + commands: ['itshop', 'approvals'], + }, + title: '#LDS#Menu Entry Pending requests', + sorting: '10-30', + }); + } - if (items.length === 0) { - return null; - } - return { - id: 'ROOT_Request', - title: '#LDS#Requests', - sorting: '10', - items - }; - }, - ); + if (items.length === 0) { + return; + } + return { + id: 'ROOT_Request', + title: '#LDS#Requests', + sorting: '10', + items, + }; + }); } } diff --git a/imxweb/projects/qer/src/lib/itshopapprove/approvals.service.ts b/imxweb/projects/qer/src/lib/itshopapprove/approvals.service.ts index 91539e6c6..3543ef311 100644 --- a/imxweb/projects/qer/src/lib/itshopapprove/approvals.service.ts +++ b/imxweb/projects/qer/src/lib/itshopapprove/approvals.service.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -26,30 +26,41 @@ import { Injectable } from '@angular/core'; -import { ExtendedTypedEntityCollection, EntitySchema, DataModel, MethodDescriptor, EntityCollectionData, MethodDefinition, ApiRequestOptions } from 'imx-qbm-dbts'; import { - PortalItshopApproveRequests, - OtherApproverInput, - DirectDecisionInput, DecisionInput, - PwoExtendedData, - RecallDecisionInput, - ReasonInput, DenyDecisionInput, + DirectDecisionInput, + OtherApproverInput, + PortalItshopApproveRequests, + PwoExtendedData, PwoQueryInput, + ReasonInput, + RecallDecisionInput, V2ApiClientMethodFactory, -} from 'imx-api-qer'; -import { Approval } from './approval'; +} from '@imx-modules/imx-api-qer'; +import { + ApiRequestOptions, + DataModel, + EntityCollectionData, + EntitySchema, + ExtendedTypedEntityCollection, + MethodDefinition, + MethodDescriptor, +} from '@imx-modules/imx-qbm-dbts'; +import { DataSourceToolbarExportMethod } from 'qbm'; +import { ItshopRequestService } from '../itshop/itshop-request.service'; import { QerApiService } from '../qer-api-client.service'; +import { Approval } from './approval'; import { ApprovalsLoadParameters } from './approvals-load-parameters'; -import { ItshopRequestService } from '../itshop/itshop-request.service'; -import { DataSourceToolbarExportMethod } from 'qbm'; @Injectable() export class ApprovalsService { public abortController = new AbortController(); - constructor(private readonly apiService: QerApiService, private readonly itshopRequest: ItshopRequestService) {} + constructor( + private readonly apiService: QerApiService, + private readonly itshopRequest: ItshopRequestService, + ) {} public get PortalItshopApproveRequestsSchema(): EntitySchema { return this.apiService.typedClient.PortalItshopApproveRequests.GetSchema(); @@ -70,21 +81,27 @@ export class ApprovalsService { public async get( parameters: ApprovalsLoadParameters, - requestOpts?: ApiRequestOptions - ): Promise> { - const collection = await this.apiService.typedClient.PortalItshopApproveRequests.Get({ - Escalation: this.isChiefApproval, - ...parameters, - },requestOpts); - - return collection == null ? undefined: { - tableName: collection.tableName, - totalCount: collection.totalCount, - Data: collection.Data.map((element, index) => - this.itshopRequest.createRequestApprovalItem(element, { ...collection.extendedData, ...{ index } }) - ), - extendedData: collection.extendedData, - }; + requestOpts?: ApiRequestOptions, + ): Promise | undefined> { + const collection = await this.apiService.typedClient.PortalItshopApproveRequests.Get( + { + Escalation: this.isChiefApproval, + ...parameters, + }, + requestOpts, + ); + + return collection == null + ? undefined + : { + tableName: collection.tableName, + totalCount: collection.totalCount, + Data: collection.Data.map((element, index) => { + const parameter = collection.extendedData ? { ...collection.extendedData, ...{ index } } : undefined; + return this.itshopRequest.createRequestApprovalItem(element, parameter); + }), + extendedData: collection.extendedData, + }; } public exportApprovalRequests(parameters: ApprovalsLoadParameters): DataSourceToolbarExportMethod { @@ -106,8 +123,8 @@ export class ApprovalsService { }; } - public async getApprovalDataModel(): Promise { - return this.apiService.client.portal_itshop_approve_requests_datamodel_get(undefined); + public async getApprovalDataModel(signal?: AbortSignal): Promise { + return this.apiService.client.portal_itshop_approve_requests_datamodel_get(undefined, { signal }); } public async recallDecision(pwo: PortalItshopApproveRequests, approver: RecallDecisionInput): Promise { diff --git a/imxweb/projects/qer/src/lib/itshopapprove/decision-step.service.ts b/imxweb/projects/qer/src/lib/itshopapprove/decision-step.service.ts index f05eb8b6b..8d68b9382 100644 --- a/imxweb/projects/qer/src/lib/itshopapprove/decision-step.service.ts +++ b/imxweb/projects/qer/src/lib/itshopapprove/decision-step.service.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -25,29 +25,32 @@ */ import { Injectable } from '@angular/core'; -import { EntityColumnData, EntityData, IEntityColumn, TypedEntity, ValType } from 'imx-qbm-dbts'; -import { EntityService, AuthenticationService, ColumnDependentReference, BaseReadonlyCdr, CdrFactoryService } from 'qbm'; +import { EntityColumnData, EntityData, IEntityColumn, TypedEntity, ValType } from '@imx-modules/imx-qbm-dbts'; +import { AuthenticationService, BaseReadonlyCdr, ColumnDependentReference, EntityService, ISessionState } from 'qbm'; @Injectable({ providedIn: 'root', }) export class DecisionStepSevice { private uidUser: string; - constructor(private readonly entityService: EntityService, authentication: AuthenticationService) { - authentication.onSessionResponse.subscribe((session) => (this.uidUser = session.UserUid)); + constructor( + private readonly entityService: EntityService, + authentication: AuthenticationService, + ) { + authentication.onSessionResponse.subscribe((session: ISessionState) => (this.uidUser = session.UserUid || '')); } - public getCurrentStepCdr(entity: TypedEntity, extended: any, display: string): ColumnDependentReference { + public getCurrentStepCdr(entity: TypedEntity, extended: any, display: string): ColumnDependentReference | undefined { const steps = extended.WorkflowSteps?.Entities?.filter( (elem) => elem?.Columns?.UID_QERWorkingMethod.Value === entity.GetEntity().GetColumn('UID_QERWorkingMethod').GetValue() && - elem.Columns.LevelNumber.Value === entity.GetEntity().GetColumn('DecisionLevel').GetValue() + elem.Columns.LevelNumber.Value === entity.GetEntity().GetColumn('DecisionLevel').GetValue(), ); const step = steps.find((elem) => this.isFitting(extended.WorkflowData?.Entities, elem)); return step?.Columns.Ident_PWODecisionStep == null - ? null + ? undefined : new BaseReadonlyCdr(this.createEntityColumn(step.Columns.Ident_PWODecisionStep), display); } @@ -59,7 +62,7 @@ export class DecisionStepSevice { return workflowData.some( (elem) => elem?.Columns?.UID_QERWorkingStep.Value === step?.Columns?.UID_QERWorkingStep.Value && - elem?.Columns?.UID_PersonHead.Value === this.uidUser + elem?.Columns?.UID_PersonHead.Value === this.uidUser, ); } } diff --git a/imxweb/projects/qer/src/lib/itshopapprove/inquiries/inquiries.component.html b/imxweb/projects/qer/src/lib/itshopapprove/inquiries/inquiries.component.html index 3b5ed2aa7..317f881cc 100644 --- a/imxweb/projects/qer/src/lib/itshopapprove/inquiries/inquiries.component.html +++ b/imxweb/projects/qer/src/lib/itshopapprove/inquiries/inquiries.component.html @@ -1,65 +1,66 @@ - - + + - - -
    - - - - - - - - - {{ getInquiryText(item) }} - - - - - {{ getInquirer(item) }} - - - - - {{ getQueryDate(item) | shortDate }} - - - - - -
    - -
    -
    -
    -
    -
    - + + + {{ entitySchema.Columns.DisplayOrg?.Display }} + + + + + + + + {{ '#LDS#Query' | translate }} + + + {{ getInquiryText(item) }} + + + + + {{ '#LDS#Inquiry made by' | translate }} + + + {{ getInquirer(item) }} + + + + + {{ '#LDS#Inquiry made on' | translate }} + + + {{ (getQueryDate(item) | shortDate) || '' }} + + + + + +
    + +
    + +
    + +
    diff --git a/imxweb/projects/qer/src/lib/itshopapprove/inquiries/inquiries.component.scss b/imxweb/projects/qer/src/lib/itshopapprove/inquiries/inquiries.component.scss index eeda36bbe..e1691c119 100644 --- a/imxweb/projects/qer/src/lib/itshopapprove/inquiries/inquiries.component.scss +++ b/imxweb/projects/qer/src/lib/itshopapprove/inquiries/inquiries.component.scss @@ -1,4 +1,4 @@ -@import '../../../../../../shared/scss/common-table.scss'; +@import 'base/mixins'; :host { display: flex; @@ -7,26 +7,14 @@ flex-grow: 1; } -.imx-table-container { - flex-grow: 1; - overflow: auto; -} - -.imx-mat-card-container { - overflow: hidden; - display: flex; - flex-direction: column; - height: 100%; -} - .imx-margin-right { margin-right: 10px; } -.mat-stroked-button { - @include imx-icon-for-image-button(); +.mat-mdc-outlined-button { + @include image-button-icon(); } -.imx-button-column { - @include imx-button-column-right(); -} +.mat-mdc-card.imx-card-fill{ + margin: 0 0 3px 0; +} \ No newline at end of file diff --git a/imxweb/projects/qer/src/lib/itshopapprove/inquiries/inquiries.component.ts b/imxweb/projects/qer/src/lib/itshopapprove/inquiries/inquiries.component.ts index d704a88ff..662d3b4d0 100644 --- a/imxweb/projects/qer/src/lib/itshopapprove/inquiries/inquiries.component.ts +++ b/imxweb/projects/qer/src/lib/itshopapprove/inquiries/inquiries.component.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -24,47 +24,49 @@ * */ -import { OverlayRef } from '@angular/cdk/overlay'; -import { Component, OnDestroy, OnInit, ViewChild } from '@angular/core'; -import { EuiLoadingService, EuiSidesheetService } from '@elemental-ui/core'; -import { Subscription } from 'rxjs'; +import { Component, OnDestroy, OnInit } from '@angular/core'; +import { EuiSidesheetService } from '@elemental-ui/core'; import { TranslateService } from '@ngx-translate/core'; +import { Subscription } from 'rxjs'; -import { PwoExtendedData, ViewConfigData } from 'imx-api-qer'; -import { ValType, ExtendedTypedEntityCollection, TypedEntity, EntitySchema, DataModel, EntityData } from 'imx-qbm-dbts'; +import { PwoExtendedData, ViewConfigData } from '@imx-modules/imx-api-qer'; +import { + CollectionLoadParameters, + DataModel, + EntityData, + EntitySchema, + ExtendedTypedEntityCollection, + TypedEntity, + ValType, +} from '@imx-modules/imx-qbm-dbts'; import { - DataSourceToolbarSettings, - ClassloggerService, AuthenticationService, - DataTableComponent, - SettingsService, - SnackBarService, - ClientPropertyForTableColumns, BusyService, + calculateSidesheetWidth, + ClassloggerService, + ClientPropertyForTableColumns, DataSourceToolbarViewConfig, + DataViewInitParameters, + DataViewSource, + ISessionState, + SnackBarService, } from 'qbm'; -import { ApprovalsSidesheetComponent } from '../approvals-sidesheet/approvals-sidesheet.component'; -import { Approval } from '../approval'; import { ProjectConfigurationService } from '../../project-configuration/project-configuration.service'; +import { ViewConfigService } from '../../view-config/view-config.service'; +import { Approval } from '../approval'; +import { ApprovalsSidesheetComponent } from '../approvals-sidesheet/approvals-sidesheet.component'; import { ApprovalsService } from '../approvals.service'; import { WorkflowActionService } from '../workflow-action/workflow-action.service'; -import { ApprovalsLoadParameters } from '../approvals-load-parameters'; -import { ViewConfigService } from '../../view-config/view-config.service'; @Component({ templateUrl: './inquiries.component.html', selector: 'imx-inquiries', styleUrls: ['./inquiries.component.scss'], + providers: [DataViewSource], }) export class InquiriesComponent implements OnInit, OnDestroy { - public dstSettings: DataSourceToolbarSettings; public readonly entitySchema: EntitySchema; - public approvalsCollection: ExtendedTypedEntityCollection; - public hasData = false; - - @ViewChild(DataTableComponent) private readonly table: DataTableComponent; - private navigationState: ApprovalsLoadParameters; private displayedColumns: ClientPropertyForTableColumns[]; private readonly subscriptions: Subscription[] = []; private dataModel: DataModel; @@ -83,12 +85,11 @@ export class InquiriesComponent implements OnInit, OnDestroy { private readonly projectConfig: ProjectConfigurationService, private readonly translator: TranslateService, snackbar: SnackBarService, - settingsService: SettingsService, - authentication: AuthenticationService + authentication: AuthenticationService, + public dataSource: DataViewSource, ) { - this.navigationState = { PageSize: settingsService.DefaultPageSize, StartIndex: 0 }; this.entitySchema = approvalsService.PortalItshopApproveRequestsSchema; - this.displayedColumns = [ + (this.displayedColumns = [ { ColumnName: 'query', Type: ValType.String, @@ -110,24 +111,23 @@ export class InquiriesComponent implements OnInit, OnDestroy { Type: ValType.String, untranslatedDisplay: '#LDS#Actions', }, - ], - this.subscriptions.push( - this.actionService.applied.subscribe(async () => { - if (this.dstSettings.dataSource.totalCount === 1) { - snackbar.open({ - key: '#LDS#There are currently no inquiries.', - }); - } - this.getData(); - this.table.clearSelection(); - }) - ); + ]), + this.subscriptions.push( + this.actionService.applied.subscribe(async () => { + if (this.dataSource.collectionData().totalCount === 1) { + snackbar.open({ + key: '#LDS#There are currently no inquiries.', + }); + } + this.dataSource.selection.clear(); + this.dataSource.updateState(); + }), + ); this.approvalsService.isChiefApproval = false; - this.subscriptions.push(authentication.onSessionResponse.subscribe((session) => (this.userUid = session.UserUid))); + this.subscriptions.push(authentication.onSessionResponse.subscribe((session: ISessionState) => (this.userUid = session.UserUid || ''))); } public async ngOnInit(): Promise { - this.navigationState.forinquiry = true; const isBusy = this.busyService.beginBusy(); try { @@ -146,32 +146,35 @@ export class InquiriesComponent implements OnInit, OnDestroy { this.subscriptions.forEach((s) => s.unsubscribe()); } - public async getData(parameters?: ApprovalsLoadParameters): Promise { - if (parameters) { - this.navigationState = parameters; - } - - const isBusy = this.busyService.beginBusy(); - - try { - this.approvalsCollection = await this.approvalsService.get(this.navigationState); - this.hasData = this.approvalsCollection.totalCount > 0 || (this.navigationState.search ?? '') !== ''; - this.updateTable(); - } finally { - isBusy.endBusy(); - } + public async getData(): Promise { + const dataViewInitParameters: DataViewInitParameters = { + execute: ( + params: CollectionLoadParameters, + signal: AbortSignal, + ): Promise | undefined> => + this.approvalsService.get({ ...params, forinquiry: true }, { signal }), + schema: this.entitySchema, + columnsToDisplay: this.displayedColumns, + dataModel: this.dataModel, + exportFunction: this.approvalsService.exportApprovalRequests(this.dataSource.state()), + viewConfig: this.viewConfig, + highlightEntity: (approval: Approval) => { + this.editPwo(approval); + }, + }; + this.dataSource.init(dataViewInitParameters); } public async updateConfig(config: ViewConfigData): Promise { await this.viewConfigService.putViewConfig(config); this.viewConfig = await this.viewConfigService.getDSTExtensionChanges(this.viewConfigPath); - this.dstSettings.viewConfig = this.viewConfig; + this.dataSource.viewConfig.set(this.viewConfig); } public async deleteConfigById(id: string): Promise { await this.viewConfigService.deleteViewConfig(id); this.viewConfig = await this.viewConfigService.getDSTExtensionChanges(this.viewConfigPath); - this.dstSettings.viewConfig = this.viewConfig; + this.dataSource.viewConfig.set(this.viewConfig); } /** @@ -179,14 +182,14 @@ export class InquiriesComponent implements OnInit, OnDestroy { * * @param pwo Selected PortalItshopApproveRequests. */ - public async editPwo(pwo: Approval): Promise { + public async editPwo(pwo: TypedEntity): Promise { this.logger.trace('New selected pwo', pwo); const doUpdate = await this.sideSheet .open(ApprovalsSidesheetComponent, { title: await this.translator.get('#LDS#Heading View Request Details').toPromise(), subTitle: pwo.GetEntity().GetDisplay(), padding: '0', - width: 'max(700px, 60%)', + width: calculateSidesheetWidth(1000), testId: 'inqueries-sidesheet', data: { pwo, @@ -203,32 +206,20 @@ export class InquiriesComponent implements OnInit, OnDestroy { } public getInquiryText(pwo: Approval): string { - return this.getPwoData(pwo).Columns.ReasonHead.Value; + return this.getPwoData(pwo)?.Columns?.ReasonHead.Value || ''; } public getInquirer(pwo: Approval): string { - return this.getPwoData(pwo).Columns.DisplayPersonHead.Value; + return this.getPwoData(pwo)?.Columns?.DisplayPersonHead.Value || ''; } - public getQueryDate(pwo: Approval): Date { - return new Date(this.getPwoData(pwo).Columns.DateHead.Value); + public getQueryDate(pwo: Approval): string { + return this.getPwoData(pwo)?.Columns?.DateHead.Value ?? ''; } - public onSearch(keywords: string): Promise { - const navigationState = { - ...this.navigationState, - ...{ - StartIndex: 0, - search: keywords, - }, - }; - - return this.getData(navigationState); - } - - private getPwoData(pwo: Approval): EntityData { - const questionHistory = pwo.pwoData.WorkflowHistory.Entities.filter( - (entityData) => entityData.Columns.DecisionLevel.Value === pwo.DecisionLevel.value - ).sort((item1, item2) => this.ascendingDate(item1.Columns.XDateInserted?.Value, item2.Columns.XDateInserted?.Value)); - return questionHistory[0]; + private getPwoData(pwo: Approval): EntityData | undefined { + const questionHistory = pwo.pwoData.WorkflowHistory?.Entities?.filter( + (entityData) => entityData.Columns?.DecisionLevel.Value === pwo.DecisionLevel.value, + ).sort((item1, item2) => this.ascendingDate(item1.Columns?.XDateInserted?.Value, item2.Columns?.XDateInserted?.Value)); + return questionHistory?.[0]; } private ascendingDate(value1: Date, value2: Date): number { @@ -242,23 +233,4 @@ export class InquiriesComponent implements OnInit, OnDestroy { return 0; } - - private updateTable(): void { - if (this.approvalsCollection) { - const exportMethod = this.approvalsService.exportApprovalRequests(this.navigationState); - exportMethod.initialColumns = this.displayedColumns.map(col => col.ColumnName); - this.dstSettings = { - dataSource: this.approvalsCollection, - extendedData: this.approvalsCollection.extendedData.Data, - entitySchema: this.entitySchema, - navigationState: this.navigationState, - displayedColumns: this.displayedColumns, - dataModel: this.dataModel, - viewConfig: this.viewConfig, - exportMethod - }; - } else { - this.dstSettings = undefined; - } - } } diff --git a/imxweb/projects/qer/src/lib/itshopapprove/recommendation-sidesheet/recommendation-sidesheet.component.html b/imxweb/projects/qer/src/lib/itshopapprove/recommendation-sidesheet/recommendation-sidesheet.component.html index 0042573d4..4529668e5 100644 --- a/imxweb/projects/qer/src/lib/itshopapprove/recommendation-sidesheet/recommendation-sidesheet.component.html +++ b/imxweb/projects/qer/src/lib/itshopapprove/recommendation-sidesheet/recommendation-sidesheet.component.html @@ -1,40 +1,55 @@
    - - - {{'#LDS#Based on an analysis of currently available data, it is recommended that you approve this request.'| translate}} + + {{ + (data?.informationTexts?.approve != null + ? data?.informationTexts?.approve || '' + : '#LDS#Based on an analysis of currently available data, it is recommended that you approve this request.' + ) | translate + }} - - {{'#LDS#Based on an analysis of currently available data, it is recommended that you deny this request.'| translate}} + + {{ + (data?.informationTexts?.reject != null + ? data?.informationTexts?.reject || '' + : '#LDS#Based on an analysis of currently available data, it is recommended that you deny this request.' + ) | translate + }} - - {{'#LDS#Based on an analysis of currently available data, no definitive recommendation can be made for this request.'| translate}} + + {{ + (data?.informationTexts?.noRecord != null + ? data?.informationTexts?.noRecord || '' + : '#LDS#Based on an analysis of currently available data, no definitive recommendation can be made for this request.' + ) | translate + }}
    -

    {{'#LDS#The following factors were considered in this recommendation.' | translate}}

    +

    {{ '#LDS#The following factors were considered in this recommendation.' | translate }}

    - - + +
    - {{item.Display}} + {{ item.Display }} - {{item.Detail}} + {{ item.Detail }}
    -
    - - +
    + +
    - - - diff --git a/imxweb/projects/qer/src/lib/itshopapprove/recommendation-sidesheet/recommendation-sidesheet.component.scss b/imxweb/projects/qer/src/lib/itshopapprove/recommendation-sidesheet/recommendation-sidesheet.component.scss index afdb73fdd..d3cba8702 100644 --- a/imxweb/projects/qer/src/lib/itshopapprove/recommendation-sidesheet/recommendation-sidesheet.component.scss +++ b/imxweb/projects/qer/src/lib/itshopapprove/recommendation-sidesheet/recommendation-sidesheet.component.scss @@ -1,12 +1,8 @@ -@import "@elemental-ui/core/src/styles/_palette.scss"; @import '@elemental-ui/core/src/styles/_eui_palette.scss'; +@import 'base/mixins'; :host { - ::ng-deep .eui-alert { - margin-bottom: 20px; - } - - .mat-card-avatar { + .mat-mdc-card-avatar { display: flex; align-items: center; justify-content: center; @@ -15,20 +11,6 @@ .recommendation-item { margin-bottom: 20px; } - - .imx-icon-warning { - color: $corbin-orange; - } - - .imx-icon-ok { - color: $aspen-green - } - - .eui-sidesheet-actions { - > * { - margin-left: 5px; - } - } } .eui-dark-theme { @@ -38,7 +20,7 @@ background-color: $color-gray-80; } .eui-sidesheet-content { - .recommendation-items , .eui-alert.eui-alert-condensed .eui-alert-header{ + .recommendation-items { color: $color-gray-2; } } @@ -52,7 +34,7 @@ background-color: $color-gray-100; } .eui-sidesheet-content { - .recommendation-items , .eui-alert.eui-alert-condensed .eui-alert-header{ + .recommendation-items { color: $color-gray-0; } } diff --git a/imxweb/projects/qer/src/lib/itshopapprove/recommendation-sidesheet/recommendation-sidesheet.component.ts b/imxweb/projects/qer/src/lib/itshopapprove/recommendation-sidesheet/recommendation-sidesheet.component.ts index 8d697f19b..a4578f7ad 100644 --- a/imxweb/projects/qer/src/lib/itshopapprove/recommendation-sidesheet/recommendation-sidesheet.component.ts +++ b/imxweb/projects/qer/src/lib/itshopapprove/recommendation-sidesheet/recommendation-sidesheet.component.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -25,13 +25,13 @@ */ import { Component, Inject } from '@angular/core'; -import { EuiSidesheetRef, EUI_SIDESHEET_DATA } from '@elemental-ui/core'; -import { RecommendationData, RecommendationDataItem, RecommendationEnum } from 'imx-api-qer'; +import { EUI_SIDESHEET_DATA, EuiSidesheetRef } from '@elemental-ui/core'; +import { RecommendationData, RecommendationDataItem, RecommendationEnum } from '@imx-modules/imx-api-qer'; @Component({ selector: 'imx-recommendation-sidesheet', templateUrl: './recommendation-sidesheet.component.html', - styleUrls: ['./recommendation-sidesheet.component.scss'] + styleUrls: ['./recommendation-sidesheet.component.scss'], }) export class RecommendationSidesheetComponent { public isRecApprove: boolean; @@ -41,19 +41,19 @@ export class RecommendationSidesheetComponent { constructor( private sideSheetRef: EuiSidesheetRef, - @Inject(EUI_SIDESHEET_DATA) private data: RecommendationData + @Inject(EUI_SIDESHEET_DATA) + public data: { recommendations: RecommendationData; informationTexts?: { approve: string; reject: string; noRecord: string } }, ) { - if (data.Recommendation === RecommendationEnum.Approve) { + if (data.recommendations.Recommendation === RecommendationEnum.Approve) { this.isRecApprove = true; - } else if (data.Recommendation === RecommendationEnum.Deny) { + } else if (data.recommendations.Recommendation === RecommendationEnum.Deny) { this.isRecReject = true; } else { this.isNoRec = true; } - this.recommendationItems = data.Items; + this.recommendationItems = data.recommendations.Items || []; } - public onApprove(): void { this.sideSheetRef.close('approve'); } @@ -61,5 +61,4 @@ export class RecommendationSidesheetComponent { public onDeny(): void { this.sideSheetRef.close('deny'); } - } diff --git a/imxweb/projects/qer/src/lib/itshopapprove/workflow-action/approval-history/approval-history.component.html b/imxweb/projects/qer/src/lib/itshopapprove/workflow-action/approval-history/approval-history.component.html index 30079d238..76891e024 100644 --- a/imxweb/projects/qer/src/lib/itshopapprove/workflow-action/approval-history/approval-history.component.html +++ b/imxweb/projects/qer/src/lib/itshopapprove/workflow-action/approval-history/approval-history.component.html @@ -1,7 +1,7 @@ - + {{ alertText | translate }} - +
    - +
    - - - - + + + + {{ approver.caption }} - +
    -
    +
    #LDS#Heading No Filter Applied
    {{ '#LDS#Select at least one filter.' | translate }}
    diff --git a/imxweb/projects/qer/src/lib/itshopapprove/workflow-action/approval-history/approval-history.component.scss b/imxweb/projects/qer/src/lib/itshopapprove/workflow-action/approval-history/approval-history.component.scss index c1859530a..464b14aa0 100644 --- a/imxweb/projects/qer/src/lib/itshopapprove/workflow-action/approval-history/approval-history.component.scss +++ b/imxweb/projects/qer/src/lib/itshopapprove/workflow-action/approval-history/approval-history.component.scss @@ -1,7 +1,7 @@ -@import "@elemental-ui/core/src/styles/_palette.scss"; +@import '@elemental-ui/core/src/styles/_palette.scss'; :host { - ::ng-deep .mat-card > :last-child:not(.mat-card-footer) { + ::ng-deep .mat-mdc-card > :last-child:not(.mat-mdc-card-footer) { margin-bottom: auto; } display: flex; @@ -10,24 +10,6 @@ height: 100%; } -.imx-table-container { - display: flex; - flex-direction: column; - overflow: hidden; - height: 100%; -} - -.mat-card { - flex: 1 1 auto; - display: flex; - flex-direction: column; - overflow: hidden; -} - -.imx-alert { - margin-bottom: 15px; -} - .imx-data-table-no-results { margin: auto; margin-top: auto; @@ -36,11 +18,6 @@ align-items: center; color: $black-9; - .eui-icon { - font-size: 100px; - color: rgba($black-c, 0.55); - } - div[headline] { margin: 0; font-size: 18px; diff --git a/imxweb/projects/qer/src/lib/itshopapprove/workflow-action/approval-history/approval-history.component.ts b/imxweb/projects/qer/src/lib/itshopapprove/workflow-action/approval-history/approval-history.component.ts index c886760c7..7d2629b98 100644 --- a/imxweb/projects/qer/src/lib/itshopapprove/workflow-action/approval-history/approval-history.component.ts +++ b/imxweb/projects/qer/src/lib/itshopapprove/workflow-action/approval-history/approval-history.component.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -24,19 +24,20 @@ * */ -import { OverlayRef } from '@angular/cdk/overlay'; import { Component, Input, OnInit } from '@angular/core'; import { EuiLoadingService, EuiSidesheetService } from '@elemental-ui/core'; import { TranslateService } from '@ngx-translate/core'; -import { HistoryFilterMode, ITShopConfig } from 'imx-api-qer'; -import { CollectionLoadParameters, EntityData, EntitySchema, IClientProperty, TypedEntity, ValType } from 'imx-qbm-dbts'; +import { HistoryFilterMode, ITShopConfig } from '@imx-modules/imx-api-qer'; +import { CollectionLoadParameters, EntityData, EntitySchema, TypedEntity, ValType } from '@imx-modules/imx-qbm-dbts'; import { AuthenticationService, + calculateSidesheetWidth, ClassloggerService, ClientPropertyForTableColumns, DataSourceToolbarFilter, DataSourceToolbarSettings, + ISessionState, } from 'qbm'; import { ProjectConfigurationService } from '../../../project-configuration/project-configuration.service'; import { ItshopRequest } from '../../../request-history/itshop-request'; @@ -53,7 +54,7 @@ export class ApprovalHistoryComponent implements OnInit { @Input() public approval: Approval; public dstSettings: DataSourceToolbarSettings; public entitySchema: EntitySchema; - // tslint:disable-next-line: no-bitwise + // eslint-disable-next-line no-bitwise public filtermode: HistoryFilterMode = HistoryFilterMode.SameAccProduct | HistoryFilterMode.SameStep; public filters: DataSourceToolbarFilter[] = []; public hasFilterApplied = true; @@ -64,7 +65,7 @@ export class ApprovalHistoryComponent implements OnInit { private navigationState: CollectionLoadParameters = { OrderBy: 'OrderDate' }; private currentUser: string; private displayedColumns: ClientPropertyForTableColumns[]; - private itShopConfig: ITShopConfig; + private itShopConfig: ITShopConfig | undefined; constructor( private readonly approvalHistoryservice: ApprovalHistoryService, @@ -73,25 +74,21 @@ export class ApprovalHistoryComponent implements OnInit { private readonly translate: TranslateService, private readonly sideSheet: EuiSidesheetService, private readonly projectConfig: ProjectConfigurationService, - auth: AuthenticationService + auth: AuthenticationService, ) { - auth.onSessionResponse.subscribe((session) => (this.currentUser = session.UserUid)); + auth.onSessionResponse.subscribe((session: ISessionState) => (this.currentUser = session.UserUid || '')); } public async ngOnInit(): Promise { this.entitySchema = this.approvalHistoryservice.PortalItshopRequestsSchema; this.filters = await this.buildFilter(); - let overlay: OverlayRef; - - setTimeout(() => { - overlay = this.busy.show(); - }); + if (this.busy.overlayRefs.length === 0) { + this.busy.show(); + } try { this.itShopConfig = (await this.projectConfig.getConfig()).ITShopConfig; } finally { - setTimeout(() => { - this.busy.hide(overlay); - }); + this.busy.hide(); } return this.navigate(); } @@ -113,26 +110,27 @@ export class ApprovalHistoryComponent implements OnInit { return this.navigate(); } - public isApproved(pwo: ItshopRequest): { caption: string; color: string;} { - const approvalStep = pwo.pwoData.WorkflowHistory.Entities.filter( - (entity) => entity.Columns.UID_PersonHead.Value === this.currentUser && entity.Columns.DecisionType.Value !== 'Order' - ).sort((a, b) => new Date(b.Columns.DateHead.Value).valueOf() - new Date(a.Columns.DateHead.Value).valueOf()); + public isApproved(pwo: ItshopRequest): { caption: string; color: string } | undefined { + const approvalStep = pwo.pwoData.WorkflowHistory?.Entities?.find( + (entity) => + entity.Columns?.DecisionLevel.Value === this.approval.DecisionLevel.value && + entity.Columns?.UID_PersonHead.Value === this.currentUser && + entity.Columns?.DecisionType.Value !== 'Order', + ); - if (approvalStep?.length === 0) { + if (approvalStep == null) { this.logger.warn(this, 'no approval step found'); - return null; + return undefined; } - const stepForDisplay = approvalStep.find((elem) => elem.Columns.DecisionLevel.Value === this.approval.DecisionLevel.value) ?? approvalStep[0]; - return { - caption: stepForDisplay.Columns.DecisionType.DisplayValue ?? stepForDisplay.Columns.DecisionType.Value, + caption: approvalStep.Columns?.DecisionType.DisplayValue || '', color: - stepForDisplay.Columns.DecisionType.Value === 'Grant' + approvalStep.Columns?.DecisionType.Value === 'Grant' ? 'green' - : stepForDisplay.Columns.DecisionType.Value === 'Dismiss' - ? 'red' - : 'gray', + : approvalStep.Columns?.DecisionType.Value === 'Dissmiss' + ? 'red' + : 'gray', }; } @@ -142,7 +140,7 @@ export class ApprovalHistoryComponent implements OnInit { } public get isSameStepActive(): boolean { - // tslint:disable-next-line: no-bitwise + // eslint-disable-next-line no-bitwise return (this.filtermode & HistoryFilterMode.SameStep) === HistoryFilterMode.SameStep; } @@ -152,7 +150,7 @@ export class ApprovalHistoryComponent implements OnInit { title: await this.translate.get('#LDS#Heading View Request Details').toPromise(), subTitle: pwo.GetEntity().GetDisplay(), padding: '0px', - width: 'max(700px, 60%)', + width: calculateSidesheetWidth(1000), testId: 'imx-approval-history-request-detail', data: { isReadOnly: true, @@ -167,12 +165,11 @@ export class ApprovalHistoryComponent implements OnInit { } private async navigate(): Promise { - let overlay: OverlayRef; let result: any; - setTimeout(() => { - overlay = this.busy.show(); - }); + if (this.busy.overlayRefs.length === 0) { + this.busy.show(); + } try { this.hasFilterApplied = this.filtermode !== HistoryFilterMode.None; if (!this.hasFilterApplied) { @@ -186,26 +183,29 @@ export class ApprovalHistoryComponent implements OnInit { return; } - result = await this.approvalHistoryservice.getRequests( - currentHelperPwo.Columns.UID_PWOHelperPWO.Value, - this.filtermode, - this.currentUser, - this.navigationState - ); + result = currentHelperPwo.Columns?.UID_PWOHelperPWO.Value + ? await this.approvalHistoryservice.getRequests( + currentHelperPwo.Columns?.UID_PWOHelperPWO.Value, + this.filtermode, + this.currentUser, + this.navigationState, + ) + : undefined; } } finally { - setTimeout(() => { - this.busy.hide(overlay); - }); + this.busy.hide(); } - if (result) { + if (result != null) { this.displayedColumns = [ this.entitySchema.Columns.UID_PersonOrdered, this.entitySchema.Columns.OrderDate, this.entitySchema.Columns.UiOrderState, - this.isSameStepActive ? { Type: ValType.String, ColumnName: 'decision', untranslatedDisplay: '#LDS#Approval decision' } : null, - ].filter((elem) => elem != null); + ]; + + if (this.isSameStepActive) { + this.displayedColumns.push({ Type: ValType.String, ColumnName: 'decision', untranslatedDisplay: '#LDS#Approval decision' }); + } this.dstSettings = { dataSource: { @@ -221,19 +221,19 @@ export class ApprovalHistoryComponent implements OnInit { } } - private getCurrentPwoHelperPwo(): EntityData { - const currentStep = this.approval.pwoData.WorkflowSteps.Entities.find( + private getCurrentPwoHelperPwo(): EntityData | undefined { + const currentStep = this.approval.pwoData.WorkflowSteps?.Entities?.find( (elem) => - elem.Columns.UID_QERWorkingMethod.Value === this.approval.UID_QERWorkingMethod.value && - elem.Columns.LevelNumber.Value === this.approval.DecisionLevel.value + elem.Columns?.UID_QERWorkingMethod.Value === this.approval.UID_QERWorkingMethod.value && + elem.Columns?.LevelNumber.Value === this.approval.DecisionLevel.value, ); this.logger.trace(this, 'current step the user has to decide', currentStep); - return this.approval.pwoData.WorkflowData.Entities.find( + return this.approval.pwoData.WorkflowData?.Entities?.find( (elem) => - elem.Columns.RulerLevel.Value === 0 && - elem.Columns.UID_QERWorkingStep.Value === currentStep.Columns.UID_QERWorkingStep.Value && - elem.Columns.UID_PersonHead.Value === this.currentUser + elem.Columns?.RulerLevel.Value === 0 && + elem.Columns?.UID_QERWorkingStep.Value === currentStep?.Columns?.UID_QERWorkingStep.Value && + elem.Columns?.UID_PersonHead.Value === this.currentUser, ); } diff --git a/imxweb/projects/qer/src/lib/itshopapprove/workflow-action/approval-history/approval-history.service.ts b/imxweb/projects/qer/src/lib/itshopapprove/workflow-action/approval-history/approval-history.service.ts index 9c8892053..f504d9efd 100644 --- a/imxweb/projects/qer/src/lib/itshopapprove/workflow-action/approval-history/approval-history.service.ts +++ b/imxweb/projects/qer/src/lib/itshopapprove/workflow-action/approval-history/approval-history.service.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -25,8 +25,8 @@ */ import { Injectable } from '@angular/core'; -import { HistoryFilterMode, PwoExtendedData } from 'imx-api-qer'; -import { CollectionLoadParameters, CompareOperator, DataModel, EntitySchema, ExtendedTypedEntityCollection, FilterType } from 'imx-qbm-dbts'; +import { HistoryFilterMode, PwoExtendedData } from '@imx-modules/imx-api-qer'; +import { CollectionLoadParameters, DataModel, EntitySchema, ExtendedTypedEntityCollection } from '@imx-modules/imx-qbm-dbts'; import { ItshopRequestService } from '../../../itshop/itshop-request.service'; import { ItshopRequestData } from '../../../itshop/request-info/itshop-request-data'; import { QerApiService } from '../../../qer-api-client.service'; @@ -36,8 +36,10 @@ import { ItshopRequest } from '../../../request-history/itshop-request'; providedIn: 'root', }) export class ApprovalHistoryService { - constructor(private api: QerApiService, private itshopRequest: ItshopRequestService) {} - + constructor( + private api: QerApiService, + private itshopRequest: ItshopRequestService, + ) {} public async getDataModel(): Promise { return this.api.client.portal_itshop_requests_datamodel_get(); @@ -47,18 +49,19 @@ export class ApprovalHistoryService { uidhelperpwo: string, filtermode: HistoryFilterMode, uidperson: string, - parameter: CollectionLoadParameters + parameter: CollectionLoadParameters, ): Promise> { - const collection = await this.api.typedClient.PortalItshopRequests.Get({ ...parameter, status: '4,1', // closed or active uidhelperpwo, filtermode, - // tslint:disable-next-line: no-bitwise - UID_PersonDecision: (filtermode & HistoryFilterMode.SameStep) === HistoryFilterMode.SameStep ? uidperson : undefined + // eslint-disable-next-line no-bitwise + UID_PersonDecision: (filtermode & HistoryFilterMode.SameStep) === HistoryFilterMode.SameStep ? uidperson : undefined, }); + const data: PwoExtendedData | undefined = collection.extendedData; + return { tableName: collection.tableName, totalCount: collection.totalCount, @@ -66,7 +69,12 @@ export class ApprovalHistoryService { Data: collection.Data.map((element, index) => { const requestData = new ItshopRequestData({ ...collection.extendedData, ...{ index } }); const parameterColumns = this.itshopRequest.createParameterColumns(element.GetEntity(), requestData.parameters); - return new ItshopRequest(element.GetEntity(), requestData.pwoData, parameterColumns, uidperson); + return new ItshopRequest( + element.GetEntity(), + { ...requestData.pwoData, WorkflowSteps: data?.WorkflowSteps }, + parameterColumns, + uidperson, + ); }), }; } diff --git a/imxweb/projects/qer/src/lib/itshopapprove/workflow-action/approval-history/history-filter/history-filter.component.html b/imxweb/projects/qer/src/lib/itshopapprove/workflow-action/approval-history/history-filter/history-filter.component.html index 8b0471437..a0414f839 100644 --- a/imxweb/projects/qer/src/lib/itshopapprove/workflow-action/approval-history/history-filter/history-filter.component.html +++ b/imxweb/projects/qer/src/lib/itshopapprove/workflow-action/approval-history/history-filter/history-filter.component.html @@ -1,7 +1,11 @@ -

    {{ modeFilter?.Description | translate }}

    +

    {{ modeFilter?.Description || '' | translate }}

    - + {{ option.display }}
    diff --git a/imxweb/projects/qer/src/lib/itshopapprove/workflow-action/approval-history/history-filter/history-filter.component.scss b/imxweb/projects/qer/src/lib/itshopapprove/workflow-action/approval-history/history-filter/history-filter.component.scss index ef6505dd6..66866812e 100644 --- a/imxweb/projects/qer/src/lib/itshopapprove/workflow-action/approval-history/history-filter/history-filter.component.scss +++ b/imxweb/projects/qer/src/lib/itshopapprove/workflow-action/approval-history/history-filter/history-filter.component.scss @@ -5,4 +5,4 @@ p[title] { .mat-divider { margin-top: 15px; -} \ No newline at end of file +} diff --git a/imxweb/projects/qer/src/lib/itshopapprove/workflow-action/approval-history/history-filter/history-filter.component.ts b/imxweb/projects/qer/src/lib/itshopapprove/workflow-action/approval-history/history-filter/history-filter.component.ts index c48ae8127..cce7eb036 100644 --- a/imxweb/projects/qer/src/lib/itshopapprove/workflow-action/approval-history/history-filter/history-filter.component.ts +++ b/imxweb/projects/qer/src/lib/itshopapprove/workflow-action/approval-history/history-filter/history-filter.component.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -26,7 +26,7 @@ import { Component, EventEmitter, Input, OnChanges, Output } from '@angular/core'; -import { HistoryFilterMode } from 'imx-api-qer'; +import { HistoryFilterMode } from '@imx-modules/imx-api-qer'; import { DataSourceToolbarComponent, DataSourceToolbarFilter, DataSourceToolbarSelectedFilter } from 'qbm'; @Component({ @@ -35,22 +35,23 @@ import { DataSourceToolbarComponent, DataSourceToolbarFilter, DataSourceToolbarS styleUrls: ['./history-filter.component.scss'], }) export class HistoryFilterComponent implements OnChanges { - @Input() public dst?: DataSourceToolbarComponent; + @Input() public dst: DataSourceToolbarComponent; @Input() public filter: DataSourceToolbarFilter[]; @Input() public filtermode: HistoryFilterMode; @Output() public selectedFiltersChanged = new EventEmitter(); public options: { display: string; value: HistoryFilterMode; checked: boolean; initialValue: string }[] = []; - public modeFilter: DataSourceToolbarFilter; + public modeFilter: DataSourceToolbarFilter | undefined; public ngOnChanges(): void { this.modeFilter = this.filter?.find((elem) => elem.Name === 'filtermode'); - this.options = this.modeFilter?.Options.map((elem) => ({ - display: elem.Display, - value: this.convertToFilter(elem.Value), - initialValue: elem.Value, - checked: this.isChecked(elem.Value), - })); + this.options = + this.modeFilter?.Options?.map((elem) => ({ + display: elem.Display ?? '', + value: this.convertToFilter(elem.Value ?? ''), + initialValue: elem.Value ?? '', + checked: this.isChecked(elem.Value ?? ''), + })) || []; this.updateFilter(false); } @@ -59,7 +60,7 @@ export class HistoryFilterComponent implements OnChanges { if (!sf) { this.options.forEach((elem) => (elem.checked = false)); } else { - const filter = this.options.find((elem) => elem.initialValue === sf.selectedOption.Value); + const filter = this.options.find((elem) => elem.initialValue === sf?.selectedOption?.Value ?? ''); if (filter) { filter.checked = false; } @@ -68,10 +69,9 @@ export class HistoryFilterComponent implements OnChanges { }); } - public updateFilter( emit: boolean = true): void { + public updateFilter(emit: boolean = true): void { const checked = this.options?.filter((elem) => elem.checked); - if (!checked) - { + if (!checked) { return; } @@ -90,7 +90,7 @@ export class HistoryFilterComponent implements OnChanges { let applyedfilter = HistoryFilterMode.None; filtermode.forEach((element) => { - // tslint:disable-next-line: no-bitwise + // eslint-disable-next-line no-bitwise applyedfilter |= element.value; }); this.selectedFiltersChanged.emit(applyedfilter); @@ -106,7 +106,7 @@ export class HistoryFilterComponent implements OnChanges { private isChecked(id: string): boolean { const value = this.convertToFilter(id); - // tslint:disable-next-line: no-bitwise + // eslint-disable-next-line no-bitwise return (this.filtermode & value) === value; } diff --git a/imxweb/projects/qer/src/lib/itshopapprove/workflow-action/workflow-action-edit-wrapper.interface.ts b/imxweb/projects/qer/src/lib/itshopapprove/workflow-action/workflow-action-edit-wrapper.interface.ts index 4396bc517..92a601eb1 100644 --- a/imxweb/projects/qer/src/lib/itshopapprove/workflow-action/workflow-action-edit-wrapper.interface.ts +++ b/imxweb/projects/qer/src/lib/itshopapprove/workflow-action/workflow-action-edit-wrapper.interface.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR diff --git a/imxweb/projects/qer/src/lib/itshopapprove/workflow-action/workflow-action-edit.interface.ts b/imxweb/projects/qer/src/lib/itshopapprove/workflow-action/workflow-action-edit.interface.ts index 59023539e..9897c3760 100644 --- a/imxweb/projects/qer/src/lib/itshopapprove/workflow-action/workflow-action-edit.interface.ts +++ b/imxweb/projects/qer/src/lib/itshopapprove/workflow-action/workflow-action-edit.interface.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -24,9 +24,8 @@ * */ -import { EntitySchema, IClientProperty, IEntity } from 'imx-qbm-dbts'; +import { EntitySchema, IClientProperty, IEntity, TypedEntity } from '@imx-modules/imx-qbm-dbts'; import { ColumnDependentReference } from 'qbm'; -import { Approval } from '../approval'; import { WorkflowActionParameters } from './workflow-action-parameters.interface'; /** @@ -44,7 +43,7 @@ export interface WorkflowActionEdit { /** * The requests to make a decision for. */ - requests: Approval[]; + requests: TypedEntity[]; /** * Whether or not the decision is an approval. @@ -59,18 +58,17 @@ export interface WorkflowActionEdit { /** * Whether or not the decision shows the decision guidance tab */ - withGuidance?:boolean; - + withGuidance?: boolean; /** * Information about the workflow so far. */ workflow?: { - entitySchema: EntitySchema, - display: { primary: IClientProperty, secondary?: IClientProperty }, - data: { [key: string]: IEntity[] }, - title: string, - placeholder: string + entitySchema: EntitySchema; + display: { primary: IClientProperty; secondary?: IClientProperty }; + data: { [key: string]: IEntity[] }; + title: string; + placeholder: string; }; /** @@ -79,8 +77,8 @@ export interface WorkflowActionEdit { * If given and specified these values are meant to be applied to all requests where such a value can be applied. */ showValidDate?: { - validFrom?: { key: string, placeholder: string }; - validUntil?: { key: string, placeholder: string }; + validFrom?: { key: string; placeholder: string }; + validUntil?: { key: string; placeholder: string }; }; /** @@ -88,6 +86,6 @@ export interface WorkflowActionEdit { */ customValidation?: { validate: () => boolean; - message: string + message: string; }; } diff --git a/imxweb/projects/qer/src/lib/itshopapprove/workflow-action/workflow-action-parameters.interface.ts b/imxweb/projects/qer/src/lib/itshopapprove/workflow-action/workflow-action-parameters.interface.ts index ea07a4046..1e51e86d2 100644 --- a/imxweb/projects/qer/src/lib/itshopapprove/workflow-action/workflow-action-parameters.interface.ts +++ b/imxweb/projects/qer/src/lib/itshopapprove/workflow-action/workflow-action-parameters.interface.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR diff --git a/imxweb/projects/qer/src/lib/itshopapprove/workflow-action/workflow-action.component.html b/imxweb/projects/qer/src/lib/itshopapprove/workflow-action/workflow-action.component.html index 97630e259..956ac1070 100644 --- a/imxweb/projects/qer/src/lib/itshopapprove/workflow-action/workflow-action.component.html +++ b/imxweb/projects/qer/src/lib/itshopapprove/workflow-action/workflow-action.component.html @@ -7,17 +7,14 @@
    -
    - +
    - - - +
    @@ -29,7 +26,7 @@
    - +
    @@ -39,7 +36,14 @@ - diff --git a/imxweb/projects/qer/src/lib/itshopapprove/workflow-action/workflow-action.component.scss b/imxweb/projects/qer/src/lib/itshopapprove/workflow-action/workflow-action.component.scss index 30c399bdb..06928cfb6 100644 --- a/imxweb/projects/qer/src/lib/itshopapprove/workflow-action/workflow-action.component.scss +++ b/imxweb/projects/qer/src/lib/itshopapprove/workflow-action/workflow-action.component.scss @@ -1,4 +1,4 @@ -@import "@elemental-ui/core/src/styles/_eui_palette.scss"; +@import '@elemental-ui/core/src/styles/_eui_palette.scss'; :host { display: flex; @@ -12,32 +12,9 @@ display: flex; flex-direction: column; overflow: hidden; - - .mat-tab-group { - flex-grow: 1; - overflow: auto; - } - - ::ng-deep .mat-tab-body-wrapper { - height: 100%; - } - - ::ng-deep .mat-tab-body-content { - display: flex; - flex-direction: column; - } - - ::ng-deep .mat-tab-group { - height: 100%; - - .mat-tab-header { - padding: 0 32px; - } - } } .imx-tab-content { - display: flex; flex-direction: column; height: 100%; @@ -55,9 +32,6 @@ :host { background-color: $color-gray-80; color: $color-gray-2; - .eui-sidesheet-actions{ - background-color: $color-gray-70; - } } } @@ -65,8 +39,5 @@ :host { background-color: $color-gray-100; color: $color-gray-0; - .eui-sidesheet-actions{ - background-color: $color-gray-90; - } } } diff --git a/imxweb/projects/qer/src/lib/itshopapprove/workflow-action/workflow-action.component.ts b/imxweb/projects/qer/src/lib/itshopapprove/workflow-action/workflow-action.component.ts index 3f42e5dc4..823364a95 100644 --- a/imxweb/projects/qer/src/lib/itshopapprove/workflow-action/workflow-action.component.ts +++ b/imxweb/projects/qer/src/lib/itshopapprove/workflow-action/workflow-action.component.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -28,6 +28,7 @@ import { Component, Inject } from '@angular/core'; import { UntypedFormGroup } from '@angular/forms'; import { EUI_SIDESHEET_DATA, EuiSidesheetRef } from '@elemental-ui/core'; +import { Approval } from '../approval'; import { WorkflowActionEdit } from './workflow-action-edit.interface'; /** @@ -51,7 +52,7 @@ import { WorkflowActionEdit } from './workflow-action-edit.interface'; @Component({ selector: 'imx-workflow-action', templateUrl: './workflow-action.component.html', - styleUrls: ['./workflow-action.component.scss'] + styleUrls: ['./workflow-action.component.scss'], }) export class WorkflowActionComponent { /** @@ -59,6 +60,10 @@ export class WorkflowActionComponent { */ public readonly formGroup = new UntypedFormGroup({}); + public get approval(): Approval { + return this.data.requests[0] as Approval; + } + /** * Creates a new WorkflowActionComponent * @param data The pre-calculated data object. @@ -66,11 +71,10 @@ export class WorkflowActionComponent { */ constructor( @Inject(EUI_SIDESHEET_DATA) public readonly data: WorkflowActionEdit, - public readonly sideSheetRef: EuiSidesheetRef + public readonly sideSheetRef: EuiSidesheetRef, ) { - if (this.data.customValidation) { - this.formGroup.setValidators(_ => this.data.customValidation.validate() ? null : ({ required: true })); + this.formGroup.setValidators((_) => (this.data.customValidation?.validate() ? null : { required: true })); } } } diff --git a/imxweb/projects/qer/src/lib/itshopapprove/workflow-action/workflow-action.service.ts b/imxweb/projects/qer/src/lib/itshopapprove/workflow-action/workflow-action.service.ts index 92b6c8e5e..d4cd1daa4 100644 --- a/imxweb/projects/qer/src/lib/itshopapprove/workflow-action/workflow-action.service.ts +++ b/imxweb/projects/qer/src/lib/itshopapprove/workflow-action/workflow-action.service.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -25,31 +25,50 @@ */ import { Injectable, Type } from '@angular/core'; -import { OverlayRef } from '@angular/cdk/overlay'; import { EuiLoadingService, EuiSidesheetService } from '@elemental-ui/core'; import { TranslateService } from '@ngx-translate/core'; import { Subject } from 'rxjs'; -import { CompareOperator, FilterType, EntityData, ValType } from 'imx-qbm-dbts'; -import { BaseCdr, BaseReadonlyCdr, ClassloggerService, EntityService, ExtService, SnackBarService } from 'qbm'; -import { WorkflowActionComponent } from './workflow-action.component'; -import { ProjectConfigurationService } from '../../project-configuration/project-configuration.service'; +import { + CollectionLoadParameters, + CompareOperator, + EntityData, + FilterData, + FilterType, + FkProviderItem, + MetaTableRelationData, + TypedEntity, + ValType, +} from '@imx-modules/imx-qbm-dbts'; +import { + Action, + BaseCdr, + BaseReadonlyCdr, + ClassloggerService, + EntityService, + ExtService, + ProcessingQueueService, + SnackBarService, + calculateSidesheetWidth, +} from 'qbm'; +import { JustificationType } from '../../justification/justification-type.enum'; +import { JustificationService } from '../../justification/justification.service'; import { PersonService } from '../../person/person.service'; +import { ProjectConfigurationService } from '../../project-configuration/project-configuration.service'; +import { QerApiService } from '../../qer-api-client.service'; +import { TermsOfUseAcceptComponent } from '../../terms-of-use/terms-of-use-accept.component'; +import { UserModelService } from '../../user/user-model.service'; import { Approval } from '../approval'; import { ApprovalsService } from '../approvals.service'; -import { QerApiService } from '../../qer-api-client.service'; -import { JustificationService } from '../../justification/justification.service'; -import { JustificationType } from '../../justification/justification-type.enum'; import { WorkflowActionEditWrapper } from './workflow-action-edit-wrapper.interface'; import { WorkflowActionParameters } from './workflow-action-parameters.interface'; -import { TermsOfUseAcceptComponent } from '../../terms-of-use/terms-of-use-accept.component'; -import { UserModelService } from '../../user/user-model.service'; +import { WorkflowActionComponent } from './workflow-action.component'; @Injectable({ providedIn: 'root', }) export class WorkflowActionService { - public readonly applied = new Subject(); + public readonly applied = new Subject(); constructor( private readonly apiService: QerApiService, @@ -63,11 +82,12 @@ export class WorkflowActionService { private readonly projectConfig: ProjectConfigurationService, private readonly approvalsService: ApprovalsService, private readonly justificationService: JustificationService, + private readonly extService: ExtService, private readonly userService: UserModelService, - private readonly extService: ExtService + private readonly queueService: ProcessingQueueService, ) {} - public async directDecisions(requests: Approval[], userUid: string): Promise { + public async directDecisions(requests: (Approval | TypedEntity)[], userUid: string): Promise { const actionParameters = { reason: this.createCdrReason(), }; @@ -81,7 +101,8 @@ export class WorkflowActionService { data: {}, }; - for (const request of requests) { + for (const req of requests) { + const request = req as Approval; const workFlowDataCollection = await this.apiService.typedClient.PortalWorkflow.Get(request.key, { PageSize: 1000 /* TODO: why 1000? */, }); @@ -89,7 +110,7 @@ export class WorkflowActionService { if (workFlowDataCollection && workFlowDataCollection.Data) { const levelNumbers = request.getLevelNumbers(userUid); workflow.data[request.key] = workFlowDataCollection.Data.filter((item) => levelNumbers.includes(item.LevelNumber.value)).map( - (item) => item.GetEntity() + (item) => item.GetEntity(), ); } } @@ -110,7 +131,7 @@ export class WorkflowActionService { }); } - public async addAdditionalApprovers(requests: Approval[]): Promise { + public async addAdditionalApprovers(requests: TypedEntity[]): Promise { const actionParameters = { uidPerson: this.createCdrPerson('#LDS#Additional approver'), reason: this.createCdrReason(), @@ -132,7 +153,7 @@ export class WorkflowActionService { }); } - public async withDrawApprover(requests: Approval[]): Promise { + public async withDrawApprover(requests: TypedEntity[]): Promise { const actionParameters = { reason: this.createCdrReason(), }; @@ -149,7 +170,7 @@ export class WorkflowActionService { }); } - public async delegateDecisions(requests: Approval[]): Promise { + public async delegateDecisions(requests: TypedEntity[]): Promise { const actionParameters = { uidPerson: this.createCdrPerson('#LDS#Delegate to'), reason: this.createCdrReason(), @@ -171,7 +192,7 @@ export class WorkflowActionService { }); } - public async revokeDelegations(requests: Approval[], withdrawAddApprover: boolean = true): Promise { + public async revokeDelegations(requests: TypedEntity[], withdrawAddApprover: boolean = true): Promise { const actionParameters = { reason: this.createCdrReason(), }; @@ -187,7 +208,7 @@ export class WorkflowActionService { }); } - public async denyDecisions(requests: Approval[]): Promise { + public async denyDecisions(requests: TypedEntity[]): Promise { const actionParameters = { reason: this.createCdrReason(), }; @@ -206,7 +227,7 @@ export class WorkflowActionService { }); } - public async escalateDecisions(requests: Approval[]): Promise { + public async escalateDecisions(requests: TypedEntity[]): Promise { const actionParameters = { reason: this.createCdrReason(), }; @@ -224,12 +245,12 @@ export class WorkflowActionService { public async checkMFA(uidPwo: string[]): Promise { this.busyService.show(); - let workflowActionId: string; - let mfaComponent: Type; - let response: boolean; + let workflowActionId: string = ''; + let mfaComponent: Type | undefined; + let response: boolean = false; try { - workflowActionId = await this.getStepupId(uidPwo); - mfaComponent = (await this.extService.getFittingComponent('mfaComponent')).instance; + workflowActionId = (await this.getStepupId(uidPwo)) || ''; + mfaComponent = (await this.extService.getFittingComponent('mfaComponent'))?.instance; } catch (err) { throw Error('The OLG module is not configured correctly'); } finally { @@ -240,7 +261,7 @@ export class WorkflowActionService { title: await this.translate.get('#LDS#Heading Authenticate Using OneLogin').toPromise(), padding: '0px', testId: 'imx-request-approval-mfa', - width: 'max(700px, 60%)', + width: calculateSidesheetWidth(1000), data: { workflowActionId, }, @@ -256,9 +277,9 @@ export class WorkflowActionService { return this.apiService.v2Client.portal_itshop_approve_requests_stepup_post({ UidPwo: uidPwo }); } - public async approve(requests: Approval[]): Promise { - - const term = (await this.checkTermsOfUse(requests)); + public async approve(entities: (Approval | TypedEntity)[]): Promise { + const requests = entities as Approval[]; + const term = await this.checkTermsOfUse(requests); if (!term.isChecked) { this.snackBar.open({ key: '#LDS#You have canceled the action.' }); return; @@ -268,25 +289,24 @@ export class WorkflowActionService { const schema = this.apiService.typedClient.PortalItshopApproveRequests.GetSchema(); const mfaRequests = requests.filter((req) => req.IsApproveRequiresMfa?.value); - if (itShopConfig.StepUpAuthenticationProvider !== 'NoAuth' && mfaRequests.length > 0) { + if (itShopConfig && itShopConfig.StepUpAuthenticationProvider !== 'NoAuth' && mfaRequests.length > 0) { // Check for MFA, don't continue unless true - const isMFA = term.isAuthenticated || await this.checkMFA(mfaRequests.map((request) => request.key)); + const isMFA = term.isAuthenticated || (await this.checkMFA(mfaRequests.map((request) => request.key))); if (!isMFA) { return; } } - let justification: BaseCdr; + let justification: BaseCdr | undefined; - let busyIndicator: OverlayRef; - setTimeout(() => (busyIndicator = this.busyService.show())); + this.showBusyIndicator(); const maxApproveReasonType = Math.max(...requests.map((elem) => elem.ApproveReasonType.value)); try { justification = await this.justificationService.createCdr(JustificationType.approve); } finally { - setTimeout(() => this.busyService.hide(busyIndicator)); + this.busyService.hide(); } const actionParameters: WorkflowActionParameters = { @@ -299,7 +319,7 @@ export class WorkflowActionService { const minDateFrom = new Date(); - if (itShopConfig.VI_ITShop_ApproverCanSetValidFrom && requests.some((item) => item.canSetValidFrom())) { + if (itShopConfig && itShopConfig.VI_ITShop_ApproverCanSetValidFrom && requests.some((item) => item.canSetValidFrom())) { showValidDate.validFrom = { key: 'validFrom', placeholder: '#LDS#immediately' }; const validFromColumn = this.entityService.createLocalEntityColumn(schema.Columns.ValidFrom, undefined, { @@ -309,7 +329,7 @@ export class WorkflowActionService { actionParameters[showValidDate.validFrom.key] = new BaseCdr(validFromColumn); } - if (itShopConfig.VI_ITShop_ApproverCanSetValidUntil && requests.some((item) => item.canSetValidUntil(itShopConfig))) { + if (itShopConfig && itShopConfig.VI_ITShop_ApproverCanSetValidUntil && requests.some((item) => item.canSetValidUntil(itShopConfig))) { showValidDate.validUntil = { key: 'validUntil', placeholder: '#LDS#unlimited' }; const minDateUntil = new Date(); @@ -365,19 +385,18 @@ export class WorkflowActionService { }); } - public async deny(requests: Approval[]): Promise { + public async deny(requests: TypedEntity[]): Promise { const itShopConfig = (await this.projectConfig.getConfig()).ITShopConfig; - let justification: BaseCdr; + let justification: BaseCdr | undefined; - let busyIndicator: OverlayRef; - setTimeout(() => (busyIndicator = this.busyService.show())); + this.showBusyIndicator(); - const maxDenyReasonType = Math.max(...requests.map((elem) => elem.DenyReasonType.value)); + const maxDenyReasonType = Math.max(...requests.map((elem: Approval) => elem.DenyReasonType.value)); try { justification = await this.justificationService.createCdr(JustificationType.deny); } finally { - setTimeout(() => this.busyService.hide(busyIndicator)); + this.busyService.hide(); } const actionParameters: WorkflowActionParameters = { @@ -394,7 +413,7 @@ export class WorkflowActionService { requests, actionParameters, withGuidance: true, - customValidation: itShopConfig.VI_ITShop_ApproverReasonMandatoryOnDeny + customValidation: itShopConfig?.VI_ITShop_ApproverReasonMandatoryOnDeny ? { validate: () => { const reasonValue = actionParameters.reason.column.GetValue(); @@ -421,7 +440,7 @@ export class WorkflowActionService { }); } - public async recallInquiry(requests: Approval[]): Promise { + public async recallInquiry(requests: TypedEntity[]): Promise { const actionParameters = { reason: this.createCdrReason(), }; @@ -437,7 +456,7 @@ export class WorkflowActionService { }); } - public async resetReservation(requests: Approval[]): Promise { + public async resetReservation(requests: TypedEntity[]): Promise { const actionParameters = { reason: this.createCdrReason(), }; @@ -485,22 +504,22 @@ export class WorkflowActionService { this.entityService.createLocalEntityColumn( { Type: ValType.Date, ColumnName: 'DateHead', Display: '#LDS#Inquiry made on' }, undefined, - pwo.Columns.DateHead - ) + pwo?.Columns?.DateHead, + ), ), new BaseReadonlyCdr( this.entityService.createLocalEntityColumn( { Type: ValType.String, ColumnName: 'ReasonHead', Display: '#LDS#Inquiry' }, undefined, - pwo.Columns.ReasonHead - ) + pwo?.Columns?.ReasonHead, + ), ), new BaseReadonlyCdr( this.entityService.createLocalEntityColumn( { Type: ValType.String, ColumnName: 'DisplayPersonHead', Display: '#LDS#Inquiry made by' }, undefined, - pwo.Columns.DisplayPersonHead - ) + pwo?.Columns?.DisplayPersonHead, + ), ), ]; @@ -516,22 +535,24 @@ export class WorkflowActionService { }); } - public getPwoData(pwo: Approval, userUid: string): EntityData { - return pwo.pwoData.WorkflowHistory.Entities.find( + public getPwoData(pwo: Approval, userUid: string): EntityData | undefined { + return pwo.pwoData.WorkflowHistory?.Entities?.find( (entityData) => - entityData.Columns.DecisionType.Value === 'Query' && - entityData.Columns.UID_PersonRelated.Value === userUid && - entityData.Columns.DecisionLevel.Value === pwo.DecisionLevel.value + entityData.Columns?.DecisionType.Value === 'Query' && + entityData.Columns?.UID_PersonRelated.Value === userUid && + entityData.Columns?.DecisionLevel.Value === pwo.DecisionLevel.value, ); } private async editAction(config: WorkflowActionEditWrapper): Promise { + const title = this.translate.instant(config.title); + const result = await this.sideSheet .open(WorkflowActionComponent, { - title: await this.translate.get(config.title).toPromise(), + title, subTitle: config.data.requests.length === 1 ? config.data.requests[0].GetEntity().GetDisplay() : '', padding: '0', - width: config.data.withGuidance && config.data.requests.length === 1 ? 'max(700px, 70%)' : '600px', + width: config.data.withGuidance && config.data.requests.length === 1 ? '700px' : '600px', testId: 'workflow-action', data: config.data, }) @@ -539,29 +560,48 @@ export class WorkflowActionService { .toPromise(); if (result) { - let busyIndicator: OverlayRef; - setTimeout(() => (busyIndicator = this.busyService.show())); - - let success: boolean; - try { + if (config.data.requests.length > this.queueService.actionThreshold) { + const actions: Action[] = []; for (const request of config.data.requests) { - await config.apply(request); + actions.push( + new Action( + request.GetEntity().GetDisplay(), + '', + async () => { + await config.apply(request as Approval); + }, + request.GetEntity().GetKeys().join(','), + ), + ); + } + this.queueService.submitGroupAction(title, actions, async () => { + // Once all actions are complete, reload the data + await this.userService.reloadPendingItems(); + this.applied.next(); + }); + } else { + this.showBusyIndicator(); + let success: boolean; + try { + for (const request of config.data.requests) { + await config.apply(request as Approval); + } + success = true; + } finally { + this.busyService.hide(); } - success = true; - } finally { - setTimeout(() => this.busyService.hide(busyIndicator)); - } - if (success) { - this.snackBar.open({ - key: config.message, - parameters: [ - config.data.requests.length, - config.data.actionParameters.uidPerson ? config.data.actionParameters.uidPerson.column.GetDisplayValue() : '', - ], - }); - await this.userService.reloadPendingItems(); - this.applied.next(); + if (success) { + this.snackBar.open({ + key: config.message, + parameters: [ + config.data.requests.length, + config.data.actionParameters.uidPerson ? config.data.actionParameters.uidPerson.column.GetDisplayValue() : '', + ], + }); + await this.userService.reloadPendingItems(); + this.applied.next(); + } } } else { if (config.discardChangesOnAbort) { @@ -610,7 +650,7 @@ export class WorkflowActionService { FkRelation: fkRelation, MinLen: 1, }, - [this.person.createFkProviderItem(fkRelation)] + [this.createFkProviderItemItShopInstead(fkRelation)], ); return new BaseCdr(column, display); @@ -635,7 +675,7 @@ export class WorkflowActionService { this.person.createFkProviderItem(fkRelation, [ { ColumnName: 'UID_Person', CompareOp: CompareOperator.NotEqual, Type: FilterType.Compare, Value1: uidPerson }, ]), - ] + ], ); return new BaseCdr(column, '#LDS#Recipient of the inquiry'); @@ -644,20 +684,20 @@ export class WorkflowActionService { private async checkTermsOfUse(requests: Approval[]): Promise<{ isChecked: boolean; isAuthenticated: boolean }> { // get all cart items with terms of uses const approvalItemsWithTermsOfUseToAccept = requests.filter( - (item) => item.UID_QERTermsOfUse?.value !== null && item.UID_QERTermsOfUse?.value !== '' + (item) => item.UID_QERTermsOfUse?.value !== null && item.UID_QERTermsOfUse?.value !== '', ); if (approvalItemsWithTermsOfUseToAccept.length > 0) { this.logger.debug( this, - `There are ${approvalItemsWithTermsOfUseToAccept.length} service items with terms of use the user have to accepted.` + `There are ${approvalItemsWithTermsOfUseToAccept.length} service items with terms of use the user have to accepted.`, ); const termsOfUseAccepted = await this.sideSheet .open(TermsOfUseAcceptComponent, { title: await this.translate.get('#LDS#Heading Accept Terms of Use').toPromise(), padding: '0px', - width: 'max(600px, 60%)', + width: calculateSidesheetWidth(), data: { acceptCartItems: false, approvalItems: approvalItemsWithTermsOfUseToAccept, @@ -670,7 +710,25 @@ export class WorkflowActionService { return termsOfUseAccepted; } else { this.logger.debug(this, 'there are no service items with terms of use the user have to accepted.'); - return { isChecked: true, isAuthenticated: false} + return { isChecked: true, isAuthenticated: false }; + } + } + + private createFkProviderItemItShopInstead(fkRelation: MetaTableRelationData, filter?: FilterData[]): FkProviderItem { + return { + columnName: fkRelation.ChildColumnName || '', + fkTableName: fkRelation.ParentTableName || '', + parameterNames: ['OrderBy', 'StartIndex', 'PageSize', 'filter', 'withProperties', 'search', 'foritshopapprover'], + load: async (_, parameters: CollectionLoadParameters = {}) => + this.apiService.v2Client.portal_candidates_Person_get({ ...parameters, filter, foritshopapprover: true }), + getDataModel: async () => ({}), + getFilterTree: async () => ({ Elements: [] }), + }; + } + + private showBusyIndicator(): void { + if (this.busyService.overlayRefs.length === 0) { + this.busyService.show(); } } } diff --git a/imxweb/projects/qer/src/lib/itshopapprove/workflow-action/workflow-multi-action/workflow-multi-action.component.html b/imxweb/projects/qer/src/lib/itshopapprove/workflow-action/workflow-multi-action/workflow-multi-action.component.html index aeb6c483c..fd51662d1 100644 --- a/imxweb/projects/qer/src/lib/itshopapprove/workflow-action/workflow-multi-action/workflow-multi-action.component.html +++ b/imxweb/projects/qer/src/lib/itshopapprove/workflow-action/workflow-multi-action/workflow-multi-action.component.html @@ -35,10 +35,11 @@
    - + {{ '#LDS#Heading Individual Settings' | translate }} {{ - '#LDS#Here you can see all products you have selected. You can make individual settings for specific products if applicable.' | translate + '#LDS#Here you can see all products you have selected. You can make individual settings for specific products if applicable.' + | translate }} diff --git a/imxweb/projects/qer/src/lib/itshopapprove/workflow-action/workflow-multi-action/workflow-multi-action.component.ts b/imxweb/projects/qer/src/lib/itshopapprove/workflow-action/workflow-multi-action/workflow-multi-action.component.ts index fe8ae6fb0..f45ad7c27 100644 --- a/imxweb/projects/qer/src/lib/itshopapprove/workflow-action/workflow-multi-action/workflow-multi-action.component.ts +++ b/imxweb/projects/qer/src/lib/itshopapprove/workflow-action/workflow-multi-action/workflow-multi-action.component.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -26,7 +26,8 @@ import { Component, Input, OnInit } from '@angular/core'; import { UntypedFormGroup } from '@angular/forms'; -import { BaseCdr, BaseReadonlyCdr, BulkItem, BulkItemStatus } from 'qbm'; +import { BaseCdr, BulkItem, BulkItemStatus } from 'qbm'; +import { Approval } from '../../approval'; import { DecisionStepSevice } from '../../decision-step.service'; import { WorkflowActionEdit } from '../workflow-action-edit.interface'; @@ -75,40 +76,47 @@ export class WorkflowMultiActionComponent implements OnInit { */ public ngOnInit(): void { this.requests = this.data.requests.map((item) => { + const approval = item as Approval; const bulkItem: BulkItem = { entity: item, - additionalInfo: item.OrderState.Column.GetDisplayValue(), + additionalInfo: item.GetEntity().GetColumn('OrderState')?.GetDisplayValue(), properties: [], status: BulkItemStatus.valid, }; if (this.data.showValidDate) { - if (this.data.showValidDate.validFrom) { - bulkItem.properties.push(new BaseReadonlyCdr(item.ValidFrom.Column)); + if ( + (this.data.showValidDate.validFrom && approval.ValidFrom.Column.GetValue() !== '') || + approval.ValidFrom.GetMetadata().CanEdit() + ) { + bulkItem.properties.push(new BaseCdr(approval.ValidFrom.Column)); } - if (this.data.showValidDate.validUntil) { - bulkItem.properties.push(new BaseReadonlyCdr(item.ValidUntil.Column)); + if ( + (this.data.showValidDate.validUntil && approval.ValidUntil.Column.GetValue() !== '') || + approval.ValidUntil.GetMetadata().CanEdit() + ) { + bulkItem.properties.push(new BaseCdr(approval.ValidUntil.Column)); } } - const step = this.stepService.getCurrentStepCdr(item, item.pwoData, '#LDS#Current approval step'); + const step = this.stepService.getCurrentStepCdr(item, approval.pwoData, '#LDS#Current approval step'); if (step != null) { bulkItem.properties.unshift(step); } - item.parameterColumns.forEach((column) => - bulkItem.properties.push(this.data.approve ? new BaseCdr(column) : new BaseReadonlyCdr(column)) - ); - + approval.parameterColumns.forEach((column) => { + if (this.data.approve && (column.GetValue() !== '' || column.GetMetadata().CanEdit())) + bulkItem.properties.push(new BaseCdr(column)); + }); if (this.data.workflow) { bulkItem.customSelectProperties = [ { title: this.data.workflow.title, placeholder: this.data.workflow.placeholder, - entities: this.data.workflow.data[item.key], + entities: this.data.workflow.data[approval.key], selectionChange: (entity) => { - if (item.updateDirectDecisionTarget) { - item.updateDirectDecisionTarget(entity); + if (approval.updateDirectDecisionTarget) { + approval.updateDirectDecisionTarget(entity); } }, }, diff --git a/imxweb/projects/qer/src/lib/itshopapprove/workflow-action/workflow-single-action/workflow-single-action.component.html b/imxweb/projects/qer/src/lib/itshopapprove/workflow-action/workflow-single-action/workflow-single-action.component.html index f6bd00d27..41763088b 100644 --- a/imxweb/projects/qer/src/lib/itshopapprove/workflow-action/workflow-single-action/workflow-single-action.component.html +++ b/imxweb/projects/qer/src/lib/itshopapprove/workflow-action/workflow-single-action/workflow-single-action.component.html @@ -3,6 +3,7 @@ @@ -27,7 +28,7 @@ > - + - this.requestParameterColumns.push(this.data.approve ? new BaseCdr(pCol) : new BaseReadonlyCdr(pCol)) + this.requestParameterColumns.push(this.data.approve ? new BaseCdr(pCol) : new BaseReadonlyCdr(pCol)), ); } - this.currentStepCdr = this.stepService.getCurrentStepCdr(this.request, this.request.pwoData, '#LDS#Current approval step'); + if (this.request.pwoData) { + this.currentStepCdr = this.stepService.getCurrentStepCdr(this.request, this.request.pwoData, '#LDS#Current approval step'); + } } /** diff --git a/imxweb/projects/qer/src/lib/itshopapprove/workflow-actions/answer-questions.component.html b/imxweb/projects/qer/src/lib/itshopapprove/workflow-actions/answer-questions.component.html index 6ffac2364..fdba19766 100644 --- a/imxweb/projects/qer/src/lib/itshopapprove/workflow-actions/answer-questions.component.html +++ b/imxweb/projects/qer/src/lib/itshopapprove/workflow-actions/answer-questions.component.html @@ -1,55 +1,53 @@ -

    {{'#LDS#Heading Request Inquiries' | translate}}

    +

    {{ '#LDS#Heading Request Inquiries' | translate }}

    -

    {{'#LDS#There are no pending approval inquiries.' | translate}}>

    +

    {{ '#LDS#There are no pending approval inquiries.' | translate }}>

    -

    {{'#LDS#You have been asked to answer inquiries about the following requests.' | translate}}

    - - - - - - - -
    - -
    - -
    -
    -
    - -
    +
    +
    +
    +
    - -

    {{'#LDS#Respond to an inquiry' | translate}}

    - +

    {{ '#LDS#Respond to an inquiry' | translate }}

    + +

    {{ '#LDS#Question' | translate }}:

    -

    {{'#LDS#Question' | translate}}:

    - - - - -
    - - - - - -
    \ No newline at end of file + + + + + + +
    diff --git a/imxweb/projects/qer/src/lib/itshopapprove/workflow-actions/answer-questions.component.ts b/imxweb/projects/qer/src/lib/itshopapprove/workflow-actions/answer-questions.component.ts index f788350bc..68fd44595 100644 --- a/imxweb/projects/qer/src/lib/itshopapprove/workflow-actions/answer-questions.component.ts +++ b/imxweb/projects/qer/src/lib/itshopapprove/workflow-actions/answer-questions.component.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -24,45 +24,48 @@ * */ -import { Component, OnInit, TemplateRef, ViewChild } from "@angular/core"; +import { Component, OnInit, TemplateRef, ViewChild } from '@angular/core'; import { ImxTranslationProviderService, imx_SessionService } from 'qbm'; import { MatDialog } from '@angular/material/dialog'; import { MatSnackBar } from '@angular/material/snack-bar'; @Component({ - templateUrl: "./answer-questions.component.html" + templateUrl: './answer-questions.component.html', }) export class AnswerQuestionsComponent implements OnInit { + constructor( + private translator: ImxTranslationProviderService, + private dialogService: MatDialog, + private session: imx_SessionService, + private snackBar: MatSnackBar, + ) {} - constructor(private translator: ImxTranslationProviderService, private dialogService: MatDialog, - private session : imx_SessionService, private snackBar: MatSnackBar) { } + Notice: string; // TODO caption = translate("#LDS#Your answer") - Notice : string; // TODO caption = translate("#LDS#Your answer") + public ngOnInit(): void { + // TODO load from API + } - public ngOnInit(): void { - // TODO load from API - } + PersonWantsOrg: any[] = []; - PersonWantsOrg : any[] = []; + @ViewChild('Call1') public tplCall1: TemplateRef; - @ViewChild('Call1') public tplCall1: TemplateRef; + public Button3(): void { + this.Notice = ''; + this.dialogService.open(this.tplCall1); + } - public Button3(): void { - this.Notice = ""; - this.dialogService.open(this.tplCall1); - } + public async Button4(): Promise { + // TODO validate - public async Button4(): Promise { - // TODO validate + await this.session.Client.portal_itshop_answerquery_post(uidPwo, { + Reason: this.Notice, + }); + // TODO update open items + ActionOnControl({ ActionType: 'CloseDialog' }); + // TODO reload data + this.snackBar.open(await this.translator.Translate('#LDS#Your answer has been submitted.').toPromise()); + } - await this.session.Client.portal_itshop_answerquery_post(uidPwo, { - Reason: this.Notice - }); - // TODO update open items - ActionOnControl({ "ActionType": "CloseDialog" }); - // TODO reload data - this.snackBar.open(await this.translator.Translate("#LDS#Your answer has been submitted.").toPromise()); - } - - // Parameter: aeweb_uid_pwohelperpwo (FreeText) (optional) + // Parameter: aeweb_uid_pwohelperpwo (FreeText) (optional) } diff --git a/imxweb/projects/qer/src/lib/itshopapprove/workflow-actions/query-person.component.html b/imxweb/projects/qer/src/lib/itshopapprove/workflow-actions/query-person.component.html index 5c9c94281..b9af83a71 100644 --- a/imxweb/projects/qer/src/lib/itshopapprove/workflow-actions/query-person.component.html +++ b/imxweb/projects/qer/src/lib/itshopapprove/workflow-actions/query-person.component.html @@ -1,14 +1,13 @@ -

    {{'#LDS#Heading Send Inquiry' | translate}}

    +

    {{ '#LDS#Heading Send Inquiry' | translate }}

    -

    - {{'#LDS#Select the identity to which you want to send an inquiry.' | translate}} -

    - +

    + {{ '#LDS#Select the identity to which you want to send an inquiry.' | translate }} +

    + - +
    - - - \ No newline at end of file + + + diff --git a/imxweb/projects/qer/src/lib/itshopapprove/workflow-actions/query-person.component.ts b/imxweb/projects/qer/src/lib/itshopapprove/workflow-actions/query-person.component.ts index ff6338a1a..2e4965efe 100644 --- a/imxweb/projects/qer/src/lib/itshopapprove/workflow-actions/query-person.component.ts +++ b/imxweb/projects/qer/src/lib/itshopapprove/workflow-actions/query-person.component.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -27,45 +27,48 @@ import { Component, Input } from '@angular/core'; import { MatSnackBar } from '@angular/material/snack-bar'; -import { IWriteValue } from 'imx-qbm-dbts'; -import { PortalItshopApproveRequests } from 'imx-api-qer'; +import { PortalItshopApproveRequests } from '@imx-modules/imx-api-qer'; +import { IWriteValue } from '@imx-modules/imx-qbm-dbts'; -import { ImxTranslationProviderService } from 'qbm'; +import { TranslateService } from '@ngx-translate/core'; +import { LdsReplacePipe } from 'qbm'; import { QerApiService } from '../../qer-api-client.service'; @Component({ - templateUrl: './query-person.component.html', - selector: 'imx-itshop-queryperson' + templateUrl: './query-person.component.html', + selector: 'imx-itshop-queryperson', }) export class QueryPersonComponent { + public Notice: IWriteValue; + // TODO minlen=1, caption:#LDS#Your question - public Notice: IWriteValue; - // TODO minlen=1, caption:#LDS#Your question + public UID_Person: IWriteValue; + // TDO configure as FK to person - public UID_Person: IWriteValue; - // TDO configure as FK to person + @Input() public PersonWantsOrg: PortalItshopApproveRequests; - @Input() public PersonWantsOrg: PortalItshopApproveRequests; + constructor( + private readonly ldsReplace: LdsReplacePipe, + private readonly translate: TranslateService, + private readonly snackBar: MatSnackBar, + private readonly apiService: QerApiService, + ) {} - constructor( - private translator: ImxTranslationProviderService, - private snackBar: MatSnackBar, - private apiService: QerApiService) { } + public async Button3(): Promise { + // ActionOnControl({ 'ActionType': 'PerformValidation' }); - public async Button3(): Promise { - // ActionOnControl({ 'ActionType': 'PerformValidation' }); + await this.apiService.client.portal_itshop_query_post(this.PersonWantsOrg.GetEntity().GetKeys()[0], { + Text: this.Notice.value, + UidPerson: this.UID_Person.value, + }); - await this.apiService.client.portal_itshop_query_post(this.PersonWantsOrg.GetEntity().GetKeys()[0], { - Text: this.Notice.value, - UidPerson: this.UID_Person.value - }); - - // TODO reload all data - - this.snackBar.open(await this.translator.Translate({ - key: '#LDS#Your question was submitted to {0}.', - parameters: [this.UID_Person.Column.GetDisplayValue()] - }).toPromise()); - } + // TODO reload all data + this.snackBar.open( + this.ldsReplace.transform( + await this.translate.get('#LDS#Your question was submitted to {0}.').toPromise(), + this.UID_Person.Column.GetDisplayValue(), + ), + ); + } } diff --git a/imxweb/projects/qer/src/lib/justification/decision-reason/decision-reason.component.html b/imxweb/projects/qer/src/lib/justification/decision-reason/decision-reason.component.html index f04687ebc..5739ba843 100644 --- a/imxweb/projects/qer/src/lib/justification/decision-reason/decision-reason.component.html +++ b/imxweb/projects/qer/src/lib/justification/decision-reason/decision-reason.component.html @@ -1,10 +1,15 @@ - + data-imx-identifier="reason-decision-standard" +> - - \ No newline at end of file + data-imx-identifier="reason-decision-freetext" +> + diff --git a/imxweb/projects/qer/src/lib/justification/decision-reason/decision-reason.component.scss b/imxweb/projects/qer/src/lib/justification/decision-reason/decision-reason.component.scss index 60d9e401f..4cef8a0ce 100644 --- a/imxweb/projects/qer/src/lib/justification/decision-reason/decision-reason.component.scss +++ b/imxweb/projects/qer/src/lib/justification/decision-reason/decision-reason.component.scss @@ -1,4 +1,4 @@ :host { display: flex; flex-direction: column; -} \ No newline at end of file +} diff --git a/imxweb/projects/qer/src/lib/justification/decision-reason/decision-reason.component.ts b/imxweb/projects/qer/src/lib/justification/decision-reason/decision-reason.component.ts index aeb2809a7..46ff9682f 100644 --- a/imxweb/projects/qer/src/lib/justification/decision-reason/decision-reason.component.ts +++ b/imxweb/projects/qer/src/lib/justification/decision-reason/decision-reason.component.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -25,11 +25,10 @@ */ import { AfterViewInit, ChangeDetectorRef, Component, EventEmitter, Input, OnInit, Output } from '@angular/core'; -import { AbstractControl, FormControl, FormGroup} from '@angular/forms'; -import _ from 'lodash'; +import { AbstractControl, FormControl, FormGroup } from '@angular/forms'; -import { ValueStruct } from 'imx-qbm-dbts'; -import { BaseCdr } from 'qbm'; +import { ValueStruct } from '@imx-modules/imx-qbm-dbts'; +import { BaseCdr, ColumnDependentReference } from 'qbm'; import { JustificationService } from '../justification.service'; interface ReasonFormGroup { @@ -42,19 +41,30 @@ interface ReasonFormGroup { styleUrls: ['./decision-reason.component.scss'], }) export class DecisionReasonComponent implements OnInit, AfterViewInit { - @Input() public reasonStandard: BaseCdr; - @Input() public reasonFreetext: BaseCdr; + @Input() public reasonStandard: ColumnDependentReference; + @Input() public reasonFreetext: ColumnDependentReference; @Input() public maxReasonType: number; @Output() public controlCreated = new EventEmitter(); private readonly formGroup = new FormGroup({}); - constructor(private readonly justificationService: JustificationService, private readonly changeDetector: ChangeDetectorRef) {} + constructor( + private readonly justificationService: JustificationService, + private readonly changeDetector: ChangeDetectorRef, + ) {} public ngOnInit(): void { - this.reasonStandard?.updateMinLength((this.maxReasonType ?? 0) === 1 ? 1 : 0); - this.reasonFreetext?.updateMinLength((this.maxReasonType ?? 0) === 0 ? 0 : 1); + this.reasonStandardCdr?.updateMinLength((this.maxReasonType ?? 0) === 1 ? 1 : 0); + this.reasonFreetextCdr?.updateMinLength((this.maxReasonType ?? 0) === 0 ? 0 : 1); + } + + private get reasonStandardCdr(): BaseCdr { + return this.reasonStandard as BaseCdr; + } + + private get reasonFreetextCdr(): BaseCdr { + return this.reasonFreetext as BaseCdr; } public ngAfterViewInit(): void { @@ -71,15 +81,17 @@ export class DecisionReasonComponent implements OnInit, AfterViewInit { public async updateMinLength() { switch (this.maxReasonType) { - case 0: { // nothing is mandatory, unless the justification requires a free text + case 0: { + // nothing is mandatory, unless the justification requires a free text const justification = this.formGroup.controls.standard?.value?.DataValue ? await this.justificationService.get(this.formGroup.controls.standard?.value?.DataValue) : undefined; - this.reasonFreetext?.updateMinLength(Math.max(justification && justification.RequiresText.value ? 1 : 0)); + this.reasonFreetextCdr?.updateMinLength(Math.max(justification && justification.RequiresText.value ? 1 : 0)); this.changeDetector.detectChanges(); return; } - case 1:{ // at least one reason (standard or free) is mandatory + case 1: { + // at least one reason (standard or free) is mandatory const justificationRequired = this.formGroup.controls.freetext?.value.length === 0; const justification = this.formGroup.controls.standard?.value?.DataValue @@ -88,12 +100,13 @@ export class DecisionReasonComponent implements OnInit, AfterViewInit { const freetextRequired = (justification == null && this.formGroup.controls.freetext?.value.length === 0) || !!justification?.RequiresText?.value; - this.reasonStandard?.updateMinLength(justificationRequired ? 1 : 0); - this.reasonFreetext?.updateMinLength(freetextRequired ? 1 : 0); + this.reasonStandardCdr?.updateMinLength(justificationRequired ? 1 : 0); + this.reasonFreetextCdr?.updateMinLength(freetextRequired ? 1 : 0); this.changeDetector.detectChanges(); - return ; + return; } - default: return; + default: + return; } } } diff --git a/imxweb/projects/qer/src/lib/justification/justification-type.enum.ts b/imxweb/projects/qer/src/lib/justification/justification-type.enum.ts index 9430f8504..619c996c0 100644 --- a/imxweb/projects/qer/src/lib/justification/justification-type.enum.ts +++ b/imxweb/projects/qer/src/lib/justification/justification-type.enum.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -34,5 +34,5 @@ export enum JustificationType { approveRuleViolation = 64, denyRuleViolation = 128, approvePolicyViolation = 256, - denyPolicyViolation = 512 + denyPolicyViolation = 512, } diff --git a/imxweb/projects/qer/src/lib/justification/justification.module.ts b/imxweb/projects/qer/src/lib/justification/justification.module.ts index 326de05b1..294288a6c 100644 --- a/imxweb/projects/qer/src/lib/justification/justification.module.ts +++ b/imxweb/projects/qer/src/lib/justification/justification.module.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -30,21 +30,10 @@ import { JustificationService } from './justification.service'; import { DecisionReasonComponent } from './decision-reason/decision-reason.component'; import { CdrModule } from 'qbm'; - - @NgModule({ - declarations: [ - DecisionReasonComponent - ], - imports: [ - CdrModule, - CommonModule - ], - providers: [ - JustificationService - ], - exports: [ - DecisionReasonComponent - ] + declarations: [DecisionReasonComponent], + imports: [CdrModule, CommonModule], + providers: [JustificationService], + exports: [DecisionReasonComponent], }) -export class JustificationModule { } +export class JustificationModule {} diff --git a/imxweb/projects/qer/src/lib/justification/justification.service.ts b/imxweb/projects/qer/src/lib/justification/justification.service.ts index 388480ef6..aee865887 100644 --- a/imxweb/projects/qer/src/lib/justification/justification.service.ts +++ b/imxweb/projects/qer/src/lib/justification/justification.service.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -26,7 +26,7 @@ import { Injectable } from '@angular/core'; -import { PortalJustifications } from 'imx-api-qer'; +import { PortalJustifications } from '@imx-modules/imx-api-qer'; import { CollectionLoadParameters, CompareOperator, @@ -36,9 +36,8 @@ import { IClientProperty, MetaTableRelationData, ValType, -} from 'imx-qbm-dbts'; -import { ImxTranslationProviderService } from 'qbm'; -import { BaseCdr, EntityService } from 'qbm'; +} from '@imx-modules/imx-qbm-dbts'; +import { BaseCdr, EntityService, ImxTranslationProviderService } from 'qbm'; import { QerApiService } from '../qer-api-client.service'; import { JustificationType } from './justification-type.enum'; @@ -51,10 +50,10 @@ export class JustificationService { constructor( private readonly apiService: QerApiService, private readonly entityService: EntityService, - private readonly translate: ImxTranslationProviderService + private readonly translate: ImxTranslationProviderService, ) {} - public async get(uid: string): Promise { + public async get(uid: string): Promise { const collection = await this.apiService.typedClient.PortalJustifications.Get({ filter: [ { @@ -68,13 +67,13 @@ export class JustificationService { return collection && collection.Data && collection.Data.length > 0 ? collection.Data[0] : undefined; } - public async createCdr(justificationType: JustificationType): Promise { + public async createCdr(justificationType: JustificationType): Promise { if ((await this.getByType(justificationType))?.TotalCount === 0) { return undefined; } const property = this.createProperty(); - const fkProviderItem = this.createFkProviderItem(property.FkRelation, justificationType); + const fkProviderItem = this.createFkProviderItem(property.FkRelation || {}, justificationType); const column = this.entityService.createLocalEntityColumn(property, [fkProviderItem]); const cdr = new BaseCdr(column, '#LDS#Reason for your decision'); return cdr; @@ -100,8 +99,8 @@ export class JustificationService { private createFkProviderItem(fkRelation: MetaTableRelationData, justificationType: JustificationType): FkProviderItem { return { - columnName: fkRelation.ChildColumnName, - fkTableName: fkRelation.ParentTableName, + columnName: fkRelation.ChildColumnName || '', + fkTableName: fkRelation.ParentTableName || '', parameterNames: ['OrderBy', 'StartIndex', 'PageSize', 'filter', 'search'], load: async (_, parameters = {}) => this.getByType(justificationType, parameters), getDataModel: async () => ({}), @@ -112,11 +111,11 @@ export class JustificationService { private async getByType(justificationType: JustificationType, parameters: CollectionLoadParameters = {}): Promise { const collection = await this.apiService.client.portal_justifications_get(parameters); - // tslint:disable-next-line:no-bitwise - const entities = collection.Entities.filter((entityData) => (entityData.Columns.JustificationType.Value & justificationType) > 0); + // eslint-disable-next-line no-bitwise + const entities = collection.Entities?.filter((entityData) => (entityData.Columns?.JustificationType.Value & justificationType) > 0); return { - TotalCount: entities.length, + TotalCount: entities?.length || 0, IsLimitReached: collection.IsLimitReached, Entities: entities, TableName: collection.TableName, diff --git a/imxweb/projects/qer/src/lib/metadata/portal-metadata.service.ts b/imxweb/projects/qer/src/lib/metadata/portal-metadata.service.ts new file mode 100644 index 000000000..377e500f5 --- /dev/null +++ b/imxweb/projects/qer/src/lib/metadata/portal-metadata.service.ts @@ -0,0 +1,51 @@ +/* + * ONE IDENTITY LLC. PROPRIETARY INFORMATION + * + * This software is confidential. One Identity, LLC. or one of its affiliates or + * subsidiaries, has supplied this software to you under terms of a + * license agreement, nondisclosure agreement or both. + * + * You may not copy, disclose, or use this software except in accordance with + * those terms. + * + * + * Copyright 2024 One Identity LLC. + * ALL RIGHTS RESERVED. + * + * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR + * WARRANTIES ABOUT THE SUITABILITY OF THE SOFTWARE, + * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED + * TO THE IMPLIED WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE, OR + * NON-INFRINGEMENT. ONE IDENTITY LLC. SHALL NOT BE + * LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE + * AS A RESULT OF USING, MODIFYING OR DISTRIBUTING + * THIS SOFTWARE OR ITS DERIVATIVES. + * + */ + +import { Injectable } from '@angular/core'; +import { MetaTableData } from '@imx-modules/imx-qbm-dbts'; + +import { ApiClientService, MetadataService } from 'qbm'; +import { QerApiService } from '../qer-api-client.service'; + +@Injectable({ + providedIn: 'root', +}) +export class PortalMetadataService extends MetadataService { + constructor( + private readonly apiClient: QerApiService, + private readonly apiProvider: ApiClientService, + ) { + super(); + } + + protected async getTable(tableName: string, options?: any): Promise { + return this.apiProvider.request(() => + this.apiClient.client.portal_metadata_table_get(tableName, options, { + signal: this.abortController.signal, + }), + ); + } +} diff --git a/imxweb/projects/qer/src/lib/my-responsibilities-view/my-responsibilities-registry.service.ts b/imxweb/projects/qer/src/lib/my-responsibilities-view/my-responsibilities-registry.service.ts index 105e1620e..6d8da63d1 100644 --- a/imxweb/projects/qer/src/lib/my-responsibilities-view/my-responsibilities-registry.service.ts +++ b/imxweb/projects/qer/src/lib/my-responsibilities-view/my-responsibilities-registry.service.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -25,7 +25,7 @@ */ import { Injectable } from '@angular/core'; -import { ProjectConfig } from 'imx-api-qbm'; +import { ProjectConfig } from '@imx-modules/imx-api-qbm'; import { SideNavigationExtension, SideNavigationFactory } from 'qbm'; @Injectable({ @@ -34,11 +34,11 @@ import { SideNavigationExtension, SideNavigationFactory } from 'qbm'; export class MyResponsibilitiesRegistryService { private items: SideNavigationFactory[] = []; - public getNavItems(preProps: string[], features: string[], projectConfig?: ProjectConfig): SideNavigationExtension[] { + public getNavItems(preProps: string[], features: string[], projectConfig?: ProjectConfig): (SideNavigationExtension | undefined)[] { return this.items .map((factory) => factory(preProps, features, projectConfig)) - .sort((a, b) => a.sortOrder - b.sortOrder) - .filter((item) => item !== undefined); + .filter((item) => item?.name !== '') + .sort((a, b) => (a?.sortOrder ?? 0) - (b?.sortOrder ?? 0)); } public registerFactory(...factories: SideNavigationFactory[]): void { diff --git a/imxweb/projects/qer/src/lib/my-responsibilities-view/my-responsibilities-view.component.html b/imxweb/projects/qer/src/lib/my-responsibilities-view/my-responsibilities-view.component.html index 4fc67b390..a0e4a7220 100644 --- a/imxweb/projects/qer/src/lib/my-responsibilities-view/my-responsibilities-view.component.html +++ b/imxweb/projects/qer/src/lib/my-responsibilities-view/my-responsibilities-view.component.html @@ -3,6 +3,6 @@ [isAdmin]="isAdmin" [componentName]="componentName" [componentTitle]="componentTitle" - [navItems]="navItems" + [navItems]="navItems ?? []" [contextId]="contextId" > diff --git a/imxweb/projects/qer/src/lib/my-responsibilities-view/my-responsibilities-view.component.ts b/imxweb/projects/qer/src/lib/my-responsibilities-view/my-responsibilities-view.component.ts index 6242a0103..e121eba61 100644 --- a/imxweb/projects/qer/src/lib/my-responsibilities-view/my-responsibilities-view.component.ts +++ b/imxweb/projects/qer/src/lib/my-responsibilities-view/my-responsibilities-view.component.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -25,12 +25,12 @@ */ import { ChangeDetectorRef, Component, OnInit } from '@angular/core'; -import { SideNavigationExtension, SystemInfoService, HELP_CONTEXTUAL } from 'qbm'; +import { ProjectConfig } from '@imx-modules/imx-api-qbm'; +import { QerProjectConfig } from '@imx-modules/imx-api-qer'; +import { HELP_CONTEXTUAL, SideNavigationExtension, SystemInfoService } from 'qbm'; +import { ProjectConfigurationService } from '../project-configuration/project-configuration.service'; import { UserModelService } from '../user/user-model.service'; import { MyResponsibilitiesRegistryService } from './my-responsibilities-registry.service'; -import { ProjectConfigurationService } from '../project-configuration/project-configuration.service'; -import { ProjectConfig } from 'imx-api-qbm'; -import { QerProjectConfig } from 'imx-api-qer'; @Component({ selector: 'imx-my-responsibilities-view', @@ -43,7 +43,7 @@ export class MyResponsibilitiesViewComponent implements OnInit { public componentName = 'my-responsibilities-view'; public componentTitle = '#LDS#Heading My Responsibilities'; public contextId = HELP_CONTEXTUAL.MyResponsibilities; - public navItems: SideNavigationExtension[] = []; + public navItems: (SideNavigationExtension | undefined)[] = []; constructor( private readonly systemInfoService: SystemInfoService, private readonly myResponsibilitiesRegistryService: MyResponsibilitiesRegistryService, @@ -61,8 +61,13 @@ export class MyResponsibilitiesViewComponent implements OnInit { const userConfig = await this.userModelService.getUserConfig(); const config: QerProjectConfig & ProjectConfig = await this.projectConfig.getConfig(); this.navItems = this.myResponsibilitiesRegistryService - .getNavItems(systemInfo.PreProps, features, config) - .filter((elem) => elem.name === 'identities' || elem.name === 'devices' || userConfig.Ownerships.find(own => own.TableName === elem.name)?.Count > 0); + .getNavItems(systemInfo.PreProps ?? [], features, config) + .filter( + (elem) => + elem?.name === 'identities' || + elem?.name === 'devices' || + !!userConfig.Ownerships?.find((own) => own.TableName === elem?.name)?.Count, + ); this.cdref.detectChanges(); } } diff --git a/imxweb/projects/qer/src/lib/my-responsibilities-view/my-responsibilities-view.module.ts b/imxweb/projects/qer/src/lib/my-responsibilities-view/my-responsibilities-view.module.ts index a883f0786..15623fad3 100644 --- a/imxweb/projects/qer/src/lib/my-responsibilities-view/my-responsibilities-view.module.ts +++ b/imxweb/projects/qer/src/lib/my-responsibilities-view/my-responsibilities-view.module.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -56,7 +56,11 @@ const routes: Routes = [ providers: [MyResponsibilitiesRegistryService], }) export class MyResponsibilitiesViewModule { - constructor(readonly router: Router, private readonly menuService: MenuService, logger: ClassloggerService) { + constructor( + readonly router: Router, + private readonly menuService: MenuService, + logger: ClassloggerService, + ) { const config = router.config; routes.forEach((route) => { config.splice(config.length - 1, 0, route); diff --git a/imxweb/projects/qbm/src/lib/select/select-content-provider.interface.ts b/imxweb/projects/qer/src/lib/new-request/constants.ts similarity index 82% rename from imxweb/projects/qbm/src/lib/select/select-content-provider.interface.ts rename to imxweb/projects/qer/src/lib/new-request/constants.ts index 32fab8248..e4eefe6dc 100644 --- a/imxweb/projects/qbm/src/lib/select/select-content-provider.interface.ts +++ b/imxweb/projects/qer/src/lib/new-request/constants.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -24,8 +24,4 @@ * */ -export interface SelectContentProvider { - display: (item: T) => string; - displayLong?: (item: T) => string; - key: (item: T) => string; -} +export const NEW_REQUEST_ROUTE = 'newrequest'; diff --git a/imxweb/projects/qer/src/lib/new-request/current-product-source.ts b/imxweb/projects/qer/src/lib/new-request/current-product-source.ts index a0f2c6534..e599d24a4 100644 --- a/imxweb/projects/qer/src/lib/new-request/current-product-source.ts +++ b/imxweb/projects/qer/src/lib/new-request/current-product-source.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -24,8 +24,8 @@ * */ -import { DataSourceToolbarComponent } from "qbm"; -import { SelectedProductSource } from "./new-request-selected-products/selected-product-item.interface"; +import { DataSourceToolbarComponent } from 'qbm'; +import { SelectedProductSource } from './new-request-selected-products/selected-product-item.interface'; export interface CurrentProductSource { dst: DataSourceToolbarComponent; diff --git a/imxweb/projects/qer/src/lib/new-request/element-visibility.directive.ts b/imxweb/projects/qer/src/lib/new-request/element-visibility.directive.ts index d872734fb..67b313c2d 100644 --- a/imxweb/projects/qer/src/lib/new-request/element-visibility.directive.ts +++ b/imxweb/projects/qer/src/lib/new-request/element-visibility.directive.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -34,7 +34,10 @@ export class ElementVisibilityDirective implements OnInit, OnDestroy { @Output() public elementVisibile = new EventEmitter(); - constructor(private element: ElementRef, private zone: NgZone) {} + constructor( + private element: ElementRef, + private zone: NgZone, + ) {} public ngOnInit(): void { this.zone.runOutsideAngular(() => { diff --git a/imxweb/projects/qer/src/lib/new-request/new-request-add-to-cart.service.ts b/imxweb/projects/qer/src/lib/new-request/new-request-add-to-cart.service.ts index 7f9f4c199..f3e84491d 100644 --- a/imxweb/projects/qer/src/lib/new-request/new-request-add-to-cart.service.ts +++ b/imxweb/projects/qer/src/lib/new-request/new-request-add-to-cart.service.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -26,38 +26,37 @@ import { Injectable } from '@angular/core'; -import { MultiValue, ValueStruct } from 'imx-qbm-dbts'; import { PortalItshopPatternRequestable, PortalItshopPeergroupMemberships, PortalShopServiceitems, QerProjectConfig, - RequestableProductForPerson -} from 'imx-api-qer'; + RequestableProductForPerson, +} from '@imx-modules/imx-api-qer'; +import { MultiValue, ValueStruct } from '@imx-modules/imx-qbm-dbts'; -import { SnackBarService } from 'qbm'; -import { ProjectConfigurationService } from '../project-configuration/project-configuration.service'; -import { DependencyService } from '../product-selection/optional-items-sidesheet/dependency.service'; import { EuiLoadingService, EuiSidesheetService } from '@elemental-ui/core'; -import { OptionalItemsSidesheetComponent } from '../product-selection/optional-items-sidesheet/optional-items-sidesheet.component'; import { TranslateService } from '@ngx-translate/core'; +import { SnackBarService, calculateSidesheetWidth } from 'qbm'; +import { ShelfService } from '../itshop/shelf.service'; +import { PatternItemService } from '../pattern-item-list/pattern-item.service'; +import { DependencyService } from '../product-selection/optional-items-sidesheet/dependency.service'; +import { OptionalItemsSidesheetComponent } from '../product-selection/optional-items-sidesheet/optional-items-sidesheet.component'; +import { RecipientsWrapper } from '../product-selection/recipients-wrapper'; import { ServiceItemOrder } from '../product-selection/service-item-order.interface'; +import { ProjectConfigurationService } from '../project-configuration/project-configuration.service'; import { ServiceItemsService } from '../service-items/service-items.service'; -import { PatternItemService } from '../pattern-item-list/pattern-item.service'; -import { ShelfService } from '../itshop/shelf.service'; import { CartItemsService } from '../shopping-cart/cart-items.service'; -import { SelectedProductSource } from './new-request-selected-products/selected-product-item.interface'; +import { UserModelService } from '../user/user-model.service'; import { NewRequestOrchestrationService } from './new-request-orchestration.service'; +import { SelectedProductSource } from './new-request-selected-products/selected-product-item.interface'; import { NewRequestSelectionService } from './new-request-selection.service'; -import { RecipientsWrapper } from '../product-selection/recipients-wrapper'; -import { UserModelService } from '../user/user-model.service'; // TODO: not used anymore - can be removed @Injectable({ providedIn: 'root', }) export class NewRequestAddToCartService { - private projectConfig: QerProjectConfig; private savedItems = 0; private possibleItems = 0; @@ -74,12 +73,11 @@ export class NewRequestAddToCartService { private readonly shelfService: ShelfService, private readonly snackbar: SnackBarService, private readonly sidesheetService: EuiSidesheetService, - private readonly translate: TranslateService, private readonly userModelService: UserModelService, + private readonly translate: TranslateService, ) {} public async addItemsToCart(): Promise { - if (this.orchestration.recipients == null) { return; } @@ -99,9 +97,10 @@ export class NewRequestAddToCartService { // show snackbar if (this.savedItems !== this.possibleItems) { this.snackbar.open({ - key: this.savedItems === 0 - ? '#LDS#No product could be added to your shopping cart.' - : '#LDS#{0} of {1} products could not be added to your shopping cart.', + key: + this.savedItems === 0 + ? '#LDS#No product could be added to your shopping cart.' + : '#LDS#{0} of {1} products could not be added to your shopping cart.', parameters: [this.possibleItems - this.savedItems, this.possibleItems], }); } else { @@ -122,84 +121,95 @@ export class NewRequestAddToCartService { return recipientsUids.map((uid, index) => ({ DataValue: uid, DisplayValue: recipientsDisplays[index], - })) + })); } private async addRequestablesToCart(requestableProductForPerson: RequestableProductForPerson[]): Promise { if (requestableProductForPerson && requestableProductForPerson.length > 0) { const hasItems = await this.shelfService.setShops(requestableProductForPerson); if (hasItems) { - setTimeout(() => this.busyIndicator.show()); + if (this.busyIndicator.overlayRefs.length === 0) { + this.busyIndicator.show(); + } try { this.copyShopInfoForDups(requestableProductForPerson); - const items = requestableProductForPerson.filter((item) => item.UidITShopOrg?.length > 0); - this.possibleItems = items.length; - this.savedItems = await this.cartItemsProvider.addItems(items); + const items = requestableProductForPerson.filter((item) => !!item.UidITShopOrg?.length); + const itemResult = await this.cartItemsProvider.addItems(items); + this.possibleItems = itemResult.possibleItems; + this.savedItems = itemResult.savedItems; } finally { - setTimeout(() => this.busyIndicator.hide()); + this.busyIndicator.hide(); } } } } private async addOrgsToCart(): Promise { - const roles = this.selectionService.selectedProducts - .filter(x => x.source === SelectedProductSource.PeerGroupOrgs || x.source === SelectedProductSource.ReferenceUserOrgs); + const roles = this.selectionService.selectedProducts.filter( + (x) => x.source === SelectedProductSource.PeerGroupOrgs || x.source === SelectedProductSource.ReferenceUserOrgs, + ); if (roles && roles.length > 0) { const recipientsWrapper = new RecipientsWrapper(this.orchestration.recipients); - setTimeout(() => this.busyIndicator.show()); + this.showBusyIndicator(); try { - const orgs = roles.map(x => x.item) as PortalItshopPeergroupMemberships[] + const orgs = roles.map((x) => x.item) as PortalItshopPeergroupMemberships[]; await this.cartItemsProvider.addItemsFromRoles( orgs.map((item) => item.XObjectKey.value), - recipientsWrapper?.uids + recipientsWrapper?.uids, ); - this.possibleItems += roles.length; - this.savedItems += roles.length; + this.possibleItems = roles.length; + this.savedItems = roles.length; } finally { - setTimeout(() => this.busyIndicator.hide()); + this.busyIndicator.hide(); } } } private async createRequestableProductsFromServiceItems(recipients: ValueStruct[]): Promise { - const requests = this.selectionService.selectedProducts - .filter(x => x.source === SelectedProductSource.AllProducts - || x.source === SelectedProductSource.PeerGroupProducts - || x.source === SelectedProductSource.ReferenceUserProducts ); + const requests = this.selectionService.selectedProducts.filter( + (x) => + x.source === SelectedProductSource.AllProducts || + x.source === SelectedProductSource.PeerGroupProducts || + x.source === SelectedProductSource.ReferenceUserProducts, + ); let serviceItemsForPersons: RequestableProductForPerson[] = []; let optionalItemsForPersons: RequestableProductForPerson[] = []; if (requests && requests.length > 0) { - const serviceItems = requests.map(x => x.item) as PortalShopServiceitems[]; + const serviceItems = requests.map((x) => x.item) as PortalShopServiceitems[]; // first get all optional service items if (this.projectConfig?.ITShopConfig?.VI_ITShop_AddOptionalProductsOnInsert) { optionalItemsForPersons = await this.openOptionalSideSheet(serviceItems); } - setTimeout(() => this.busyIndicator.show()); + this.showBusyIndicator(); try { serviceItemsForPersons = this.serviceItemsProvider.getServiceItemsForPersons(serviceItems, recipients); } finally { - setTimeout(() => this.busyIndicator.hide()); + this.busyIndicator.hide(); } } return serviceItemsForPersons.concat(...optionalItemsForPersons); } - private async createRequestableProductsFromBundleItems (recipients: ValueStruct[]):Promise { - const requests = this.selectionService.selectedProducts.filter(x => x.source === SelectedProductSource.ProductBundles); + private async createRequestableProductsFromBundleItems(recipients: ValueStruct[]): Promise { + const requests = this.selectionService.selectedProducts.filter((x) => x.source === SelectedProductSource.ProductBundles); let productBundleItems: PortalItshopPatternRequestable[] = []; let productBundleItemsForPersons: RequestableProductForPerson[] = []; if (requests && requests.length > 0) { - setTimeout(() => this.busyIndicator.show()); + this.showBusyIndicator(); try { - productBundleItems = requests.map(x => x.item) as PortalItshopPatternRequestable[]; - productBundleItemsForPersons = await this.patternItemsService.getPatternItemsForPersons(productBundleItems, recipients, null, true); + productBundleItems = requests.map((x) => x.item) as PortalItshopPatternRequestable[]; + productBundleItemsForPersons = await this.patternItemsService.getPatternItemsForPersons( + productBundleItems, + recipients, + undefined, + true, + ); } finally { - setTimeout(() => this.busyIndicator.hide()); + this.busyIndicator.hide(); } } return productBundleItemsForPersons; @@ -207,12 +217,12 @@ export class NewRequestAddToCartService { private async openOptionalSideSheet(serviceItems: PortalShopServiceitems[]): Promise { const serviceItemTree = await this.optionalItemsService.checkForOptionalTree(serviceItems, this.orchestration.recipients); - if (serviceItemTree?.totalOptional > 0) { + if (!!serviceItemTree?.totalOptional) { const selectedOptionalOrder: ServiceItemOrder = await this.sidesheetService .open(OptionalItemsSidesheetComponent, { title: await this.translate.get('#LDS#Heading Request Optional Products').toPromise(), padding: '0px', - width: 'max(700px, 60%)', + width: calculateSidesheetWidth(1000), testId: 'optional-items-sidesheet', disableClose: true, data: { @@ -223,7 +233,7 @@ export class NewRequestAddToCartService { .afterClosed() .toPromise(); if (selectedOptionalOrder) { - return selectedOptionalOrder.requestables; + return selectedOptionalOrder.requestables || []; } } return []; @@ -235,19 +245,26 @@ export class NewRequestAddToCartService { * @returns */ private copyShopInfoForDups(serviceItemsForPersons: RequestableProductForPerson[]): void { - const itemsWithItShop = serviceItemsForPersons.filter((item) => item.UidITShopOrg && item.UidITShopOrg.length > 0); - if (itemsWithItShop.length === serviceItemsForPersons.length ) { + if (itemsWithItShop.length === serviceItemsForPersons.length) { // All items have itshops, we can skip - return + return; } itemsWithItShop.forEach((itemWithItShop) => { // Loop over all items that have an ITShop, get any service items that match its uid and also have no itshop set yet, and set them serviceItemsForPersons - .filter((item) => !item.UidITShopOrg && item.UidAccProduct === itemWithItShop.UidAccProduct && item.UidPerson === itemWithItShop.UidPerson) + .filter( + (item) => + !item.UidITShopOrg && item.UidAccProduct === itemWithItShop.UidAccProduct && item.UidPerson === itemWithItShop.UidPerson, + ) .forEach((item) => (item.UidITShopOrg = itemWithItShop.UidITShopOrg)); }); return; } -} + private showBusyIndicator(): void { + if (this.busyIndicator.overlayRefs.length === 0) { + this.busyIndicator.show(); + } + } +} diff --git a/imxweb/projects/qer/src/lib/new-request/new-request-content/new-request-content.component.html b/imxweb/projects/qer/src/lib/new-request/new-request-content/new-request-content.component.html index 5798d6741..e0daab734 100644 --- a/imxweb/projects/qer/src/lib/new-request/new-request-content/new-request-content.component.html +++ b/imxweb/projects/qer/src/lib/new-request/new-request-content/new-request-content.component.html @@ -1,4 +1,4 @@ -

    -
    - +
    +
    + + + + + + + + + + + + + + + + -
    - - - diff --git a/imxweb/projects/qer/src/lib/view-devices/view-devices-home/view-devices.component.scss b/imxweb/projects/qer/src/lib/view-devices/view-devices-home/view-devices.component.scss index 52f351d3b..4d217384c 100644 --- a/imxweb/projects/qer/src/lib/view-devices/view-devices-home/view-devices.component.scss +++ b/imxweb/projects/qer/src/lib/view-devices/view-devices-home/view-devices.component.scss @@ -1,62 +1,10 @@ -@import '../../../../../../shared/scss/common-table.scss'; -@mixin imx-flex-column-container { - display: flex; - flex-direction: column; -} - -@mixin imx-flex-row-container { - display: flex; - flex-direction: row; -} +@import 'base/mixins'; :host { - @include imx-flex-column-container(); - overflow: hidden; - max-width: 100%; - height: 100%; + @include flex-column-container($overflow: hidden, $height: 100%, $max-width: 100%); } .heading-wrapper { - @include imx-flex-row-container(); + @include flex-row-container(); flex: 0 0 auto; } - -.mat-card { - @include imx-flex-fill-control-hidden-overflow(); - - div.imx-table-container { - @include imx-flex-column-container(); - overflow: hidden; - flex: 1 1 auto; - - .mat-card { - height: inherit; - overflow: hidden; - display: flex; - flex-direction: column; - } - - .imx-pickcategory-table { - flex-grow: 1; - overflow: auto; - } - } - &-actions { - display: flex; - flex-direction: row-reverse; - padding: 16px 0; - gap: 16px; - align-items: center; - } -} - -.imx-button-bar { - @include imx-button-bar(); - - button { - eui-icon { - font-size: 14px; - margin-right: 4px; - } - } -} diff --git a/imxweb/projects/qer/src/lib/view-devices/view-devices-home/view-devices.component.ts b/imxweb/projects/qer/src/lib/view-devices/view-devices-home/view-devices.component.ts index c61da9991..8ce892aa4 100644 --- a/imxweb/projects/qer/src/lib/view-devices/view-devices-home/view-devices.component.ts +++ b/imxweb/projects/qer/src/lib/view-devices/view-devices-home/view-devices.component.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -25,53 +25,58 @@ */ import { Component, OnDestroy, OnInit } from '@angular/core'; -import { ViewDevicesService } from '../view-devices.service'; +import { EuiLoadingService, EuiSidesheetService } from '@elemental-ui/core'; +import { DeviceConfig, PortalCandidatesHardwaretype, PortalDevices } from '@imx-modules/imx-api-qer'; +import { + CollectionLoadParameters, + DataModel, + DisplayColumns, + EntitySchema, + ExtendedTypedEntityCollection, + IClientProperty, + TypedEntityCollectionData, + ValueStruct, +} from '@imx-modules/imx-qbm-dbts'; +import { TranslateService } from '@ngx-translate/core'; import { AuthenticationService, - BusyService, DataModelWrapper, - DataSourceToolbarSettings, - DataSourceWrapper, + BusyService, + DataViewInitParameters, + DataViewSource, + HELP_CONTEXTUAL, HelpContextualComponent, HelpContextualService, - HELP_CONTEXTUAL, - SideNavigationComponent + ISessionState, + SideNavigationComponent, + calculateSidesheetWidth, } from 'qbm'; -import { DeviceConfig, PortalCandidatesHardwaretype, PortalDevices } from 'imx-api-qer'; -import { CollectionLoadParameters, DisplayColumns, EntitySchema, ValueStruct } from 'imx-qbm-dbts'; -import { OverlayRef } from '@angular/cdk/overlay'; -import { EuiLoadingService, EuiSidesheetService } from '@elemental-ui/core'; -import { ViewDevicesSidesheetComponent } from '../view-devices-sidesheet/view-devices-sidesheet.component'; -import { TranslateService } from '@ngx-translate/core'; -import { ProjectConfigurationService } from '../../project-configuration/project-configuration.service'; -import { QerPermissionsService } from '../../admin/qer-permissions.service'; import { Subscription } from 'rxjs'; +import { QerPermissionsService } from '../../admin/qer-permissions.service'; import { IdentitiesService } from '../../identities/identities.service'; +import { ProjectConfigurationService } from '../../project-configuration/project-configuration.service'; import { CreateNewDeviceComponent } from '../create-new-device/create-new-device.component'; +import { ViewDevicesSidesheetComponent } from '../view-devices-sidesheet/view-devices-sidesheet.component'; +import { ViewDevicesService } from '../view-devices.service'; @Component({ selector: 'imx-view-devices-home', templateUrl: './view-devices.component.html', styleUrls: ['./view-devices.component.scss'], + providers: [DataViewSource], }) -export class ViewDevicesComponent implements OnInit, OnDestroy, SideNavigationComponent{ - public dataModelWrapper: DataModelWrapper; - public hardwareTypeDataModelWrapper: DataModelWrapper; - public dstWrapper: DataSourceWrapper; - public dstWrapperHardwareType: DataSourceWrapper; +export class ViewDevicesComponent implements OnInit, OnDestroy, SideNavigationComponent { public entitySchema: EntitySchema; - public entitySchemaHardwareType: EntitySchema; - public dstSettings: DataSourceToolbarSettings; - public dstSettingsHardwareType: DataSourceToolbarSettings; + public dataModel: DataModel; + public displayedColumns: IClientProperty[]; + public hardwareCandidates: ExtendedTypedEntityCollection; public DisplayColumns = DisplayColumns; - public deviceModelValueStruct: ValueStruct[]; - public hardwareBasicTypeList: { type: string, basicType: string, key: string }[]; + public deviceModelValueStruct: ValueStruct[] | undefined; + public hardwareBasicTypeList: { type: string; basicType: string; key: string }[]; public busyService = new BusyService(); public contextId = HELP_CONTEXTUAL.PortalDevices; - - public deviceConfig: DeviceConfig; + public deviceConfig: DeviceConfig | undefined; public managerId: string; public isAdmin = false; - public currentUser: string; public isManagerForPersons: boolean; public isAuditor: boolean; @@ -86,16 +91,13 @@ export class ViewDevicesComponent implements OnInit, OnDestroy, SideNavigationCo private readonly authService: AuthenticationService, private readonly identitiesService: IdentitiesService, private readonly helpContextualService: HelpContextualService, - qerPermissionService: QerPermissionsService, + public qerPermissionService: QerPermissionsService, + public dataSource: DataViewSource, ) { this.entitySchema = this.viewDevicesService.devicesSchema; - - this.entitySchemaHardwareType = this.viewDevicesService.hardwareTypeSchema; - - this.sessionResponse$ = this.authService.onSessionResponse.subscribe(async (session) => { + this.sessionResponse$ = this.authService.onSessionResponse.subscribe(async (session: ISessionState) => { if (session.IsLoggedIn) { - this.currentUser = session.UserUid, - this.isManagerForPersons = await qerPermissionService.isPersonManager(); + (this.currentUser = session.UserUid || ''), (this.isManagerForPersons = await qerPermissionService.isPersonManager()); this.isAuditor = await qerPermissionService.isStructStatistics(); } }); @@ -119,137 +121,117 @@ export class ViewDevicesComponent implements OnInit, OnDestroy, SideNavigationCo if (this.deviceConfig == null) { this.deviceConfig = (await this.projectConfigService.getConfig()).DeviceConfig; } - - this.dataModelWrapper = { - dataModel: await this.viewDevicesService.getDataModel(), - }; - - this.hardwareTypeDataModelWrapper = { - dataModel: await this.viewDevicesService.getHardwareTypeDataModel(), - }; - } finally { - isBusy.endBusy(); - } - - this.dstWrapper = new DataSourceWrapper( - (state) => this.viewDevicesService.get(state), - [ + this.dataModel = await this.viewDevicesService.getDataModel(); + this.displayedColumns = [ this.entitySchema.Columns[DisplayColumns.DISPLAY_PROPERTYNAME], this.entitySchema.Columns.UID_HardwareType, this.entitySchema.Columns.UID_PersonOwner, - ], - this.entitySchema, - this.dataModelWrapper, - 'view-devices' - ); - - this.dstWrapperHardwareType = new DataSourceWrapper( - (state) => this.viewDevicesService.getPortalCandidatesHardwaretype(state), - [ - this.entitySchemaHardwareType.Columns[DisplayColumns.DISPLAY_PROPERTYNAME], - ], - this.entitySchemaHardwareType, - this.hardwareTypeDataModelWrapper, - 'hardware-type' - ); - - this.getData(); - } - - public async getData(newState?: CollectionLoadParameters): Promise { - const isbusy = this.busyService.beginBusy(); - try { - this.dstSettings = await this.dstWrapper.getDstSettings(newState); - this.dstSettingsHardwareType = await this.dstWrapperHardwareType.getDstSettings(newState); - - this.deviceModelValueStruct = this.dstSettingsHardwareType.dataSource.Data.map(d => { + ]; + this.hardwareCandidates = await this.viewDevicesService.getPortalCandidatesHardwaretype({}); + this.deviceModelValueStruct = await this.hardwareCandidates?.Data.map((d) => { return { - DataValue: d.GetEntity().GetKeys()[0], - DisplayValue: d.GetEntity().GetDisplay() + DataValue: d.GetEntity().GetKeys()[0], + DisplayValue: d.GetEntity().GetDisplay(), }; - }); + }); } finally { - isbusy.endBusy(); + isBusy.endBusy(); } + this.getData(); + } + + public async getData(): Promise { + const dataViewInitParameters: DataViewInitParameters = { + execute: async (params: CollectionLoadParameters, signal: AbortSignal): Promise> => + this.viewDevicesService.get(params, signal), + schema: this.entitySchema, + columnsToDisplay: this.displayedColumns, + dataModel: this.dataModel, + highlightEntity: (entity: PortalDevices) => { + this.onHighlightedEntityChanged(entity); + }, + }; + this.dataSource.init(dataViewInitParameters); } public async onHighlightedEntityChanged(portalDevices: PortalDevices): Promise { if (portalDevices) { - let overlayRef: OverlayRef; - setTimeout(() => (overlayRef = this.euiBusyService.show())); + if (this.euiBusyService.overlayRefs.length === 0) { + this.euiBusyService.show(); + } let extendedEntity; - let deviceEntityConfig = this.deviceConfig['VI_Hardware_Fields_Default']; + let deviceEntityConfig = this.deviceConfig?.['VI_Hardware_Fields_Default']; try { const key = portalDevices.GetEntity().GetKeys().join(','); extendedEntity = await this.viewDevicesService.getPortalDeviceEntity(key); const hardwareBasicType = extendedEntity.Data[0].HardwareBasicType.value; - - if (this.deviceConfig[`VI_Hardware_Fields_${hardwareBasicType}`]) { - deviceEntityConfig = this.deviceConfig[`VI_Hardware_Fields_${hardwareBasicType}`]; + if (this.deviceConfig?.[`VI_Hardware_Fields_${hardwareBasicType}`]) { + deviceEntityConfig = this.deviceConfig?.[`VI_Hardware_Fields_${hardwareBasicType}`]; } } finally { - setTimeout(() => this.euiBusyService.hide(overlayRef)); + this.euiBusyService.hide(); } if (!extendedEntity || !deviceEntityConfig) { return; } - this.helpContextualService.setHelpContextId(HELP_CONTEXTUAL.PortalDevicesEdit); - const result = await this.sideSheet - .open(ViewDevicesSidesheetComponent, { - title: await this.translate.get('#LDS#Heading Edit Device').toPromise(), - subTitle: portalDevices.GetEntity().GetDisplay(), - padding: '0', - width: 'max(600px, 60%)', - disableClose: true, - testId: 'devices-sidesheet', - data: { - device: extendedEntity.Data[0], - deviceEntityConfig: deviceEntityConfig, - }, - headerComponent: HelpContextualComponent - }) - .afterClosed() - .toPromise(); + this.helpContextualService.setHelpContextId(HELP_CONTEXTUAL.PortalDevicesEdit); + const result = await this.sideSheet + .open(ViewDevicesSidesheetComponent, { + title: await this.translate.get('#LDS#Heading Edit Device').toPromise(), + subTitle: portalDevices.GetEntity().GetDisplay(), + padding: '0', + width: calculateSidesheetWidth(), + disableClose: true, + testId: 'devices-sidesheet', + data: { + device: extendedEntity.Data[0], + deviceEntityConfig: deviceEntityConfig, + }, + headerComponent: HelpContextualComponent, + }) + .afterClosed() + .toPromise(); if (result) { - this.getData(); + this.dataSource.updateState(); } } } public async createNewDevice(key: string, index: number): Promise { - let deviceEntityConfig = this.deviceConfig['VI_Hardware_Fields_Default']; - const hardwareBasicTypeListElement = this.hardwareBasicTypeList.find(hardwareType => hardwareType.key === key); + let deviceEntityConfig = this.deviceConfig?.['VI_Hardware_Fields_Default']; + const hardwareBasicTypeListElement = this.hardwareBasicTypeList.find((hardwareType) => hardwareType.key === key); if (hardwareBasicTypeListElement) { const hardwareBasicType = this.hardwareBasicTypeList[this.hardwareBasicTypeList.indexOf(hardwareBasicTypeListElement)].basicType; - deviceEntityConfig = this.deviceConfig[`VI_Hardware_Fields_${hardwareBasicType}`]; + deviceEntityConfig = this.deviceConfig ? this.deviceConfig[`VI_Hardware_Fields_${hardwareBasicType}`] : undefined; } - let deviceModelValueStruct = this.deviceModelValueStruct[index]; - - this.helpContextualService.setHelpContextId(HELP_CONTEXTUAL.PortalDevicesCreate); - const result = await this.sideSheet - .open(CreateNewDeviceComponent, { - title: await this.translate.get('#LDS#Heading Create Device').toPromise(), - padding: '0px', - width: 'max(650px, 65%)', - disableClose: false, - testId: 'create-new-device-sidesheet', - data: { - newDevice: await this.viewDevicesService.createNewDevice(), - deviceEntityConfig: deviceEntityConfig, - deviceModelValueStruct: deviceModelValueStruct, - }, - headerComponent: HelpContextualComponent - }) - .afterClosed() - .toPromise(); + let deviceModelValueStruct = this.deviceModelValueStruct ? this.deviceModelValueStruct[index] : undefined; + this.helpContextualService.setHelpContextId(HELP_CONTEXTUAL.PortalDevicesCreate); + const newDeviceEntity = await this.viewDevicesService.createNewDevice(); + await newDeviceEntity.UID_HardwareType.Column.PutValue(key); + const result = await this.sideSheet + .open(CreateNewDeviceComponent, { + title: await this.translate.get('#LDS#Heading Create Device').toPromise(), + padding: '0px', + width: calculateSidesheetWidth(1000), + disableClose: false, + testId: 'create-new-device-sidesheet', + data: { + newDevice: newDeviceEntity, + deviceEntityConfig: deviceEntityConfig, + deviceModelValueStruct: deviceModelValueStruct, + }, + headerComponent: HelpContextualComponent, + }) + .afterClosed() + .toPromise(); if (result) { - this.getData(); + this.dataSource.updateState(); } } diff --git a/imxweb/projects/qer/src/lib/view-devices/view-devices-sidesheet/view-devices-sidesheet.component.html b/imxweb/projects/qer/src/lib/view-devices/view-devices-sidesheet/view-devices-sidesheet.component.html index aa9207a21..9acc17bd3 100644 --- a/imxweb/projects/qer/src/lib/view-devices/view-devices-sidesheet/view-devices-sidesheet.component.html +++ b/imxweb/projects/qer/src/lib/view-devices/view-devices-sidesheet/view-devices-sidesheet.component.html @@ -1,24 +1,24 @@ -
    - +
    + -
    +
    -
    +
    diff --git a/imxweb/projects/qer/src/lib/view-devices/view-devices-sidesheet/view-devices-sidesheet.component.scss b/imxweb/projects/qer/src/lib/view-devices/view-devices-sidesheet/view-devices-sidesheet.component.scss index 2427b4dc0..e69de29bb 100644 --- a/imxweb/projects/qer/src/lib/view-devices/view-devices-sidesheet/view-devices-sidesheet.component.scss +++ b/imxweb/projects/qer/src/lib/view-devices/view-devices-sidesheet/view-devices-sidesheet.component.scss @@ -1,20 +0,0 @@ -:host { - eui-icon { - font-size: 14px; - margin-right: 4px; - } -} - -.eui-sidesheet-actions { - button:not(:last-of-type) { - margin-right: 10px; - } -} - -.imx-devices-sidesheet { - ul { - li { - list-style-type: disc; - } - } -} diff --git a/imxweb/projects/qer/src/lib/view-devices/view-devices-sidesheet/view-devices-sidesheet.component.ts b/imxweb/projects/qer/src/lib/view-devices/view-devices-sidesheet/view-devices-sidesheet.component.ts index 46feed41a..72787121d 100644 --- a/imxweb/projects/qer/src/lib/view-devices/view-devices-sidesheet/view-devices-sidesheet.component.ts +++ b/imxweb/projects/qer/src/lib/view-devices/view-devices-sidesheet/view-devices-sidesheet.component.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -24,20 +24,19 @@ * */ -import { Component, Inject, OnDestroy } from "@angular/core"; -import { UntypedFormGroup } from "@angular/forms"; -import { EUI_SIDESHEET_DATA, EuiLoadingService, EuiSidesheetRef } from "@elemental-ui/core"; -import { PortalDevices } from "imx-api-qer"; -import { IEntity } from "imx-qbm-dbts"; -import { BaseCdr, ColumnDependentReference, ConfirmationService, SnackBarService } from "qbm"; -import { ViewDevicesService } from "../view-devices.service"; -import { Subscription } from "rxjs"; -import { OverlayRef } from "@angular/cdk/overlay"; +import { Component, Inject, OnDestroy } from '@angular/core'; +import { UntypedFormGroup } from '@angular/forms'; +import { EUI_SIDESHEET_DATA, EuiLoadingService, EuiSidesheetRef } from '@elemental-ui/core'; +import { PortalDevices } from '@imx-modules/imx-api-qer'; +import { IEntity } from '@imx-modules/imx-qbm-dbts'; +import { BaseCdr, ColumnDependentReference, ConfirmationService, SnackBarService } from 'qbm'; +import { Subscription } from 'rxjs'; +import { ViewDevicesService } from '../view-devices.service'; @Component({ selector: 'imx-view-devices-sidesheet', templateUrl: './view-devices-sidesheet.component.html', - styleUrls: ['./view-devices-sidesheet.component.scss'] + styleUrls: ['./view-devices-sidesheet.component.scss'], }) export class ViewDevicesSidesheetComponent implements OnDestroy { public readonly formGroup = new UntypedFormGroup({}); @@ -59,15 +58,17 @@ export class ViewDevicesSidesheetComponent implements OnDestroy { this.canEdit = data.device.UID_HardwareType.GetMetadata().CanEdit(); - this.subscriptions.push(this.sidesheetRef.closeClicked().subscribe(async () => { - if (this.formGroup.pristine || await this.confirmation.confirmLeaveWithUnsavedChanges()) { - this.sidesheetRef.close(); - } - })); + this.subscriptions.push( + this.sidesheetRef.closeClicked().subscribe(async () => { + if (this.formGroup.pristine || (await this.confirmation.confirmLeaveWithUnsavedChanges())) { + this.sidesheetRef.close(); + } + }), + ); } private createCdrList(entity: IEntity): BaseCdr[] { - const cdrList = []; + const cdrList: BaseCdr[] = []; const columnNames: string[] = this.data.deviceEntityConfig; columnNames?.forEach((name) => { try { @@ -99,21 +100,24 @@ export class ViewDevicesSidesheetComponent implements OnDestroy { Message: '#LDS#Are you sure you want to delete the device?', }) ) { - let overlayRef: OverlayRef; - setTimeout(() => (overlayRef = this.euiBusyService.show())); + if (this.euiBusyService.overlayRefs.length === 0) { + this.euiBusyService.show(); + } let confirmMessage = '#LDS#The device has been successfully deleted.'; try { - const uid = this.data.device.EntityKeysData.Keys[0]; - await this.viewDevicesService.deleteDevice(uid); + const uid = this.data.device.EntityKeysData.Keys?.[0] ?? ''; + if (uid != '') { + await this.viewDevicesService.deleteDevice(uid); + } this.sidesheetRef.close(true); this.snackbar.open({ key: confirmMessage }); } finally { - setTimeout(() => this.euiBusyService.hide(overlayRef)); + this.euiBusyService.hide(); } } } ngOnDestroy(): void { - this.subscriptions.forEach(s => s.unsubscribe()); + this.subscriptions.forEach((s) => s.unsubscribe()); } } diff --git a/imxweb/projects/qer/src/lib/view-devices/view-devices.module.ts b/imxweb/projects/qer/src/lib/view-devices/view-devices.module.ts index b7530cb3b..eea90dd4f 100644 --- a/imxweb/projects/qer/src/lib/view-devices/view-devices.module.ts +++ b/imxweb/projects/qer/src/lib/view-devices/view-devices.module.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -24,25 +24,30 @@ * */ -import { NgModule } from '@angular/core'; -import { ViewDevicesComponent } from './view-devices-home/view-devices.component'; -import { ViewDevicesSidesheetComponent } from './view-devices-sidesheet/view-devices-sidesheet.component' -import { CdrModule, ClassloggerService, DataSourceToolbarModule, DataTableModule, HelpContextualModule, LdsReplaceModule } from 'qbm'; -import { QerProjectConfig } from 'imx-api-qer'; import { CommonModule } from '@angular/common'; +import { NgModule } from '@angular/core'; +import { ReactiveFormsModule } from '@angular/forms'; +import { MatTableModule } from '@angular/material/table'; import { EuiCoreModule, EuiMaterialModule } from '@elemental-ui/core'; +import { ProjectConfig } from '@imx-modules/imx-api-qbm'; +import { QerProjectConfig } from '@imx-modules/imx-api-qer'; import { TranslateModule } from '@ngx-translate/core'; -import { ReactiveFormsModule } from '@angular/forms'; -import { ProjectConfig } from 'imx-api-qbm'; -import { CreateNewDeviceComponent } from './create-new-device/create-new-device.component'; +import { + CdrModule, + ClassloggerService, + DataSourceToolbarModule, + DataTableModule, + DataViewModule, + HelpContextualModule, + LdsReplaceModule, +} from 'qbm'; import { MyResponsibilitiesRegistryService } from '../my-responsibilities-view/my-responsibilities-registry.service'; +import { CreateNewDeviceComponent } from './create-new-device/create-new-device.component'; +import { ViewDevicesComponent } from './view-devices-home/view-devices.component'; +import { ViewDevicesSidesheetComponent } from './view-devices-sidesheet/view-devices-sidesheet.component'; @NgModule({ - declarations: [ - ViewDevicesComponent, - ViewDevicesSidesheetComponent, - CreateNewDeviceComponent - ], + declarations: [ViewDevicesComponent, ViewDevicesSidesheetComponent, CreateNewDeviceComponent], imports: [ CommonModule, CdrModule, @@ -54,31 +59,33 @@ import { MyResponsibilitiesRegistryService } from '../my-responsibilities-view/m DataSourceToolbarModule, DataTableModule, HelpContextualModule, + MatTableModule, + DataViewModule, ], - exports: [ - ViewDevicesComponent, - ] + exports: [ViewDevicesComponent, ViewDevicesSidesheetComponent], }) export class ViewDevicesModule { - constructor( private readonly myResponsibilitiesRegistryService: MyResponsibilitiesRegistryService, logger: ClassloggerService, - ) { + ) { logger.info(this, '▶️ ViewDevicesModule loaded'); this.setupMyResponsibilitiesView(); } - private setupMyResponsibilitiesView(): void{ - - this.myResponsibilitiesRegistryService.registerFactory((preProps: string[], features: string[], projectConfig: QerProjectConfig & ProjectConfig) => { - if (preProps.includes('MAC') && projectConfig.DeviceConfig.VI_Hardware_Enabled) { - return { - instance: ViewDevicesComponent, - sortOrder: 13, - name: 'devices', - caption: '#LDS#Heading Devices', + private setupMyResponsibilitiesView(): void { + this.myResponsibilitiesRegistryService.registerFactory( + (preProps: string[], features: string[], projectConfig: QerProjectConfig & ProjectConfig) => { + if (preProps.includes('MAC') && projectConfig.DeviceConfig && projectConfig.DeviceConfig.VI_Hardware_Enabled) { + return { + instance: ViewDevicesComponent, + sortOrder: 13, + name: 'devices', + caption: '#LDS#Heading Devices', + }; + } else { + return { caption: '', name: '' }; } - } - }); + }, + ); } } diff --git a/imxweb/projects/qer/src/lib/view-devices/view-devices.service.ts b/imxweb/projects/qer/src/lib/view-devices/view-devices.service.ts index d5d930a49..e7a8ae940 100644 --- a/imxweb/projects/qer/src/lib/view-devices/view-devices.service.ts +++ b/imxweb/projects/qer/src/lib/view-devices/view-devices.service.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -24,51 +24,46 @@ * */ -import { OverlayRef } from '@angular/cdk/overlay'; import { Injectable } from '@angular/core'; -import { QerApiService } from '../qer-api-client.service'; import { EuiLoadingService } from '@elemental-ui/core'; -import { CollectionLoadParameters, DataModel, EntityCollectionData, EntitySchema, ExtendedTypedEntityCollection } from 'imx-qbm-dbts'; -import { PortalCandidatesHardwaretype, PortalCandidatesHardwaretypeWrapper, PortalDevices } from 'imx-api-qer'; +import { PortalCandidatesHardwaretype, PortalDevices } from '@imx-modules/imx-api-qer'; +import { CollectionLoadParameters, DataModel, EntitySchema, ExtendedTypedEntityCollection } from '@imx-modules/imx-qbm-dbts'; +import { QerApiService } from '../qer-api-client.service'; @Injectable({ providedIn: 'root', }) export class ViewDevicesService { - private busyIndicator: OverlayRef; - constructor( private readonly qerClient: QerApiService, - private readonly busyService: EuiLoadingService - ) {} + private readonly busyService: EuiLoadingService, + ) {} public get devicesSchema(): EntitySchema { return this.qerClient.typedClient.PortalDevices.GetSchema(); } - public get hardwareTypeSchema(): EntitySchema { - return this.qerClient.typedClient.PortalCandidatesHardwaretype.GetSchema(); - } - public handleOpenLoader(): void { - if (!this.busyIndicator) { - setTimeout(() => (this.busyIndicator = this.busyService.show())); + if (this.busyService.overlayRefs.length === 0) { + this.busyService.show(); } } public handleCloseLoader(): void { - if(this.busyIndicator) { - setTimeout(() => { - this.busyService.hide(this.busyIndicator); - this.busyIndicator = undefined; - }); - } + this.busyService.hide(); } - public async get(parameters: CollectionLoadParameters): Promise> { + public async get( + parameters: CollectionLoadParameters, + signal: AbortSignal, + ): Promise> { return this.qerClient.typedClient.PortalDevices.Get(parameters); } + public get hardwareTypeSchema(): EntitySchema { + return this.qerClient.typedClient.PortalCandidatesHardwaretype.GetSchema(); + } + public async getDataModel(): Promise { return this.qerClient.client.portal_devices_datamodel_get(); } @@ -85,7 +80,9 @@ export class ViewDevicesService { await this.qerClient.client.portal_devices_delete(uid); } - public async getPortalCandidatesHardwaretype(parameters: CollectionLoadParameters): Promise> { + public async getPortalCandidatesHardwaretype( + parameters: CollectionLoadParameters, + ): Promise> { return await this.qerClient.typedClient.PortalCandidatesHardwaretype.Get(parameters); } diff --git a/imxweb/projects/qer/src/lib/wport/businessowner-chartsummary/businessowner-chartsummary.component.html b/imxweb/projects/qer/src/lib/wport/businessowner-chartsummary/businessowner-chartsummary.component.html index 0d0644d78..abcc1b6e6 100644 --- a/imxweb/projects/qer/src/lib/wport/businessowner-chartsummary/businessowner-chartsummary.component.html +++ b/imxweb/projects/qer/src/lib/wport/businessowner-chartsummary/businessowner-chartsummary.component.html @@ -1,15 +1,20 @@ - + [caption]="'#LDS#Heading My Responsibilities' | translate" + [identifier]="'my-responsibilities'" + [size]="'Dashboard'" + [hideActionButton]="true" + [subtitle]="'#LDS#View and manage objects you are responsible for.' | translate" + [contentType]="'Container'" +>
    @@ -17,57 +22,85 @@ - +
    -

    - {{'#LDS#Heading My Direct Reports' | translate}} - ({{reports.length }}) -

    +

    + {{ '#LDS#Heading My Direct Reports' | translate }} + ({{ reports.length }}) +

    - {{'#LDS#View and manage identities you are directly responsible for.' | translate}} + {{ '#LDS#View and manage identities you are directly responsible for.' | translate }}

    -
    - +
    - + -
    {{'#LDS#Heading My Direct Reports' | translate}}
    +
    {{ '#LDS#Heading My Direct Reports' | translate }}
    -
    {{'#LDS#View and manage identities you are directly responsible for.' | translate}}
    +
    {{ '#LDS#View and manage identities you are directly responsible for.' | translate }}
    -
    -
    \ No newline at end of file +
    diff --git a/imxweb/projects/qer/src/lib/wport/businessowner-chartsummary/businessowner-chartsummary.component.scss b/imxweb/projects/qer/src/lib/wport/businessowner-chartsummary/businessowner-chartsummary.component.scss index 2ff365de7..82d3ec7c5 100644 --- a/imxweb/projects/qer/src/lib/wport/businessowner-chartsummary/businessowner-chartsummary.component.scss +++ b/imxweb/projects/qer/src/lib/wport/businessowner-chartsummary/businessowner-chartsummary.component.scss @@ -1,5 +1,5 @@ @import '@elemental-ui/core/src/styles/_eui_palette.scss'; -@import "../../../../../qbm/src/lib/tile/tile-variables.scss"; +@import 'base/variables'; :host { display: flex; @@ -58,7 +58,7 @@ line-height: 40px; } -.imx-generic-tile-caption h1 { +.imx-generic-tile-caption h3 { font-size: 1.15em; font-weight: 600; text-overflow: ellipsis; @@ -67,13 +67,12 @@ flex: 1 1 auto; } -.imx-generic-tile-caption h1 > :last-child { +.imx-generic-tile-caption h3 > :last-child { margin-left: 1ex; } -.mat-button { - text-transform: uppercase; - margin-right: -16px; +.mat-mdc-button { + padding-right: 0; } .imx-generic-tile-caption h4 { @@ -104,25 +103,25 @@ } :host > .imx-create-identity-tile { - ::ng-deep .mat-card { + ::ng-deep .mat-mdc-card { height: 140px; display: flex; - width: $tile-width; - min-width: $tile-width; + width: $IMX_Tile_Width; + min-width: $IMX_Tile_Width; flex-direction: column; cursor: auto; padding: 25px; padding-bottom: 10px; } - .mat-card-title { + .mat-mdc-card-title { font-size: 1.15em; font-weight: 600; display: flex; cursor: auto; } - - .mat-card-subtitle { + + .mat-mdc-card-subtitle { flex: 1; font-size: small; text-align: left; @@ -130,14 +129,14 @@ overflow-x: hidden; margin-bottom: 0; } - - .mat-card-actions { + + .mat-mdc-card-actions { margin-left: 0; margin-right: 0; display: flex; } - .mat-card-actions:last-child { + .mat-mdc-card-actions:last-child { margin-bottom: 0; margin-left: -16px; margin-top: -10px; @@ -155,7 +154,7 @@ background-color: $color-gray-10; } - .imx-generic-tile-caption h1 > :last-child { + .imx-generic-tile-caption h3 > :last-child { color: $color-gray-40; } @@ -163,13 +162,11 @@ color: $color-gray-40; } - .mat-card-subtitle { + .mat-mdc-card-subtitle { color: $color-gray-40; } - } - .eui-dark-theme { :host { .imx-valuelist a { diff --git a/imxweb/projects/qer/src/lib/wport/businessowner-chartsummary/businessowner-chartsummary.component.ts b/imxweb/projects/qer/src/lib/wport/businessowner-chartsummary/businessowner-chartsummary.component.ts index ecb9bbac3..f3a700150 100644 --- a/imxweb/projects/qer/src/lib/wport/businessowner-chartsummary/businessowner-chartsummary.component.ts +++ b/imxweb/projects/qer/src/lib/wport/businessowner-chartsummary/businessowner-chartsummary.component.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -24,20 +24,20 @@ * */ -import { OverlayRef } from '@angular/cdk/overlay'; import { Component, ErrorHandler, OnInit } from '@angular/core'; import { Router } from '@angular/router'; import { EuiLoadingService, EuiSidesheetService } from '@elemental-ui/core'; +import { OwnershipInformation, PortalPersonReports, ProjectConfig } from '@imx-modules/imx-api-qer'; import { TranslateService } from '@ngx-translate/core'; -import { OwnershipInformation, PortalPersonReports, ProjectConfig } from 'imx-api-qer'; +import { calculateSidesheetWidth } from 'qbm'; import { QerPermissionsService } from '../../admin/qer-permissions.service'; +import { CreateNewIdentityComponent } from '../../identities/create-new-identity/create-new-identity.component'; +import { IdentitiesService } from '../../identities/identities.service'; import { IdentitySidesheetComponent } from '../../identities/identity-sidesheet/identity-sidesheet.component'; import { ProjectConfigurationService } from '../../project-configuration/project-configuration.service'; import { QerApiService } from '../../qer-api-client.service'; import { UserModelService } from '../../user/user-model.service'; import { DashboardService } from '../start/dashboard.service'; -import { CreateNewIdentityComponent } from '../../identities/create-new-identity/create-new-identity.component'; -import { IdentitiesService } from '../../identities/identities.service'; @Component({ templateUrl: './businessowner-chartsummary.component.html', @@ -46,12 +46,14 @@ import { IdentitiesService } from '../../identities/identities.service'; }) export class BusinessOwnerChartSummaryComponent implements OnInit { public reports: PortalPersonReports[]; - public ownerships: OwnershipInformation[]; + public ownerships: OwnershipInformation[] | undefined; public get viewReady(): boolean { return !this.dashboardService.isBusy; } public allReportsCount: number; + public isPersonManager: boolean; + private projectConfig: ProjectConfig; constructor( @@ -65,7 +67,7 @@ export class BusinessOwnerChartSummaryComponent implements OnInit { private readonly identitiesService: IdentitiesService, private readonly userModelService: UserModelService, public readonly qerPermissions: QerPermissionsService, - public readonly translate: TranslateService + public readonly translate: TranslateService, ) {} public async ngOnInit(): Promise { @@ -73,6 +75,7 @@ export class BusinessOwnerChartSummaryComponent implements OnInit { try { const userConfig = await this.userModelService.getUserConfig(); this.ownerships = userConfig.Ownerships; + this.isPersonManager = await this.qerPermissions.isPersonManager(); this.projectConfig = await this.configService.getConfig(); @@ -90,13 +93,14 @@ export class BusinessOwnerChartSummaryComponent implements OnInit { const uid = identity.GetEntity().GetKeys()[0]; let selectedIdentity: PortalPersonReports; - let overlayRef: OverlayRef; - setTimeout(() => (overlayRef = this.busyService.show())); + if (this.busyService.overlayRefs.length === 0) { + this.busyService.show(); + } try { const identityCollection = await this.qerClient.typedClient.PortalPersonReportsInteractive.Get_byid(uid); selectedIdentity = identityCollection?.Data?.[0]; } finally { - setTimeout(() => this.busyService.hide(overlayRef)); + this.busyService.hide(); } if (!selectedIdentity) { @@ -110,14 +114,14 @@ export class BusinessOwnerChartSummaryComponent implements OnInit { subTitle: selectedIdentity.GetEntity().GetDisplay(), padding: '0px', disableClose: true, - width: 'max(768px, 90%)', + width: calculateSidesheetWidth(1100, 0.7), icon: 'contactinfo', testId: 'businessowner-identity-sidesheet', data: { isAdmin: false, projectConfig: this.projectConfig, selectedIdentity, - canEdit: true + canEdit: true, }, }) .afterClosed() @@ -127,19 +131,22 @@ export class BusinessOwnerChartSummaryComponent implements OnInit { } public async openCreateNewIdentitySidesheet(): Promise { - const identityCreated = await this.sideSheet.open(CreateNewIdentityComponent, { - title: await this.translate.get('#LDS#Heading Create Identity').toPromise(), - headerColour: 'iris-blue', - padding: '0px', - width: 'max(650px, 65%)', - disableClose: true, - testId: 'create-new-identity-sidesheet', - icon: 'contactinfo', - data: { - selectedIdentity: await this.identitiesService.createEmptyEntity(), - projectConfig: this.projectConfig - } - }).afterClosed().toPromise(); + const identityCreated = await this.sideSheet + .open(CreateNewIdentityComponent, { + title: await this.translate.get('#LDS#Heading Create Identity').toPromise(), + headerColour: 'iris-blue', + padding: '0px', + width: calculateSidesheetWidth(1000), + disableClose: true, + testId: 'create-new-identity-sidesheet', + icon: 'contactinfo', + data: { + selectedIdentity: await this.identitiesService.createEmptyEntity(), + projectConfig: this.projectConfig, + }, + }) + .afterClosed() + .toPromise(); if (identityCreated) { const busy = this.dashboardService.beginBusy(); @@ -148,7 +155,8 @@ export class BusinessOwnerChartSummaryComponent implements OnInit { } finally { busy.endBusy(); } - } } + } + } public openOwnership(ownerShip: OwnershipInformation): void { this.router.navigate(['myresponsibilities', ownerShip.TableName]); @@ -156,7 +164,7 @@ export class BusinessOwnerChartSummaryComponent implements OnInit { private async getData(): Promise { await this.loadIndirectOrDirectReports(); - if (this.allReportsCount > 0 ) { + if (this.allReportsCount > 0) { await this.loadDirectReports(); } } @@ -167,7 +175,7 @@ export class BusinessOwnerChartSummaryComponent implements OnInit { await this.qerClient.typedClient.PortalPersonReports.Get({ OnlyDirect: true, // direct reports only PageSize: 10000, - isinactive: '0' + isinactive: '0', }) ).Data; } @@ -175,9 +183,11 @@ export class BusinessOwnerChartSummaryComponent implements OnInit { private async loadIndirectOrDirectReports(): Promise { if (await this.qerPermissions.isPersonManager()) { - this.allReportsCount = (await this.qerClient.typedClient.PortalPersonReports.Get({ - PageSize: -1 - })).totalCount; + this.allReportsCount = ( + await this.qerClient.typedClient.PortalPersonReports.Get({ + PageSize: -1, + }) + ).totalCount; } } } diff --git a/imxweb/projects/qer/src/lib/wport/start/dashboard.service.ts b/imxweb/projects/qer/src/lib/wport/start/dashboard.service.ts index 6bd4a5946..a0f582134 100644 --- a/imxweb/projects/qer/src/lib/wport/start/dashboard.service.ts +++ b/imxweb/projects/qer/src/lib/wport/start/dashboard.service.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -24,10 +24,8 @@ * */ -import { Injectable } from "@angular/core"; -import { BusyService } from "qbm"; +import { Injectable } from '@angular/core'; +import { BusyService } from 'qbm'; @Injectable({ providedIn: 'root' }) -export class DashboardService extends BusyService { - -} \ No newline at end of file +export class DashboardService extends BusyService {} diff --git a/imxweb/projects/qer/src/lib/wport/start/start.component.html b/imxweb/projects/qer/src/lib/wport/start/start.component.html index 1a0c75cea..0dc625df4 100644 --- a/imxweb/projects/qer/src/lib/wport/start/start.component.html +++ b/imxweb/projects/qer/src/lib/wport/start/start.component.html @@ -1,14 +1,14 @@ -

    {{ '#LDS#Welcome' | translate }}

    +

    {{ '#LDS#Welcome' | translate }}

    -
    +
    @@ -19,7 +19,7 @@

    {{ '#LDS#Welcome' | translate }}

    [caption]="'#LDS#Heading Pending Requests' | translate" [tooltip]="'#LDS#Shows the pending requests you can approve or deny.' | translate" *ngIf="userConfig?.IsITShopEnabled && GetCountPendingRequests() > 0" - [value]="GetCountPendingRequests()" + [value]="GetCountPendingRequests().toString()" [identifier]="'it-shop-approvals'" (actionClick)="GoToItshopApprovals()" > @@ -30,9 +30,9 @@

    {{ '#LDS#Welcome' | translate }}

    [caption]="'#LDS#Heading My Pending Requests' | translate" [tooltip]="'#LDS#Shows your pending requests others can approve or deny.' | translate" *ngIf="userConfig?.IsITShopEnabled && GetCountInRequestHistory() > 0" - [value]="GetCountInRequestHistory()" + [value]="GetCountInRequestHistory().toString()" [identifier]="'request-history'" - (actionClick)="router.navigate(['requesthistory'], { queryParams: { ShowMyPending: 1 } })" + (actionClick)="router.navigate(['requesthistory'], { queryParams: { showMyPendings: true } })" >
    @@ -40,7 +40,7 @@

    {{ '#LDS#Welcome' | translate }}

    data-imx-identifier="start-tile-it-shop-approval-inquiries" [caption]="'#LDS#Heading Request Inquiries' | translate" *ngIf="userConfig?.IsITShopEnabled && GetCountRequestInquiries() > 0" - [value]="GetCountRequestInquiries()" + [value]="GetCountRequestInquiries().toString()" [identifier]="'it-shop-approval-inquiries'" (actionClick)="GoToItShopApprovalInquiries()" > @@ -50,7 +50,7 @@

    {{ '#LDS#Welcome' | translate }}

    data-imx-identifier="start-tile-my-processes" [caption]="'#LDS#Heading My Processes' | translate" *ngIf="GetCountNewProcesses() > 0" - [value]="GetCountNewProcesses()" + [value]="GetCountNewProcesses().toString()" [identifier]="'my-processes'" (actionClick)="GoToMyProcesses()" > @@ -58,15 +58,15 @@

    {{ '#LDS#Welcome' | translate }}

    -
    +
    {{ '#LDS#Welcome' | translate }} [identifier]="'no-password-query-and-answer-set'" > - - + + {{ '#LDS#Welcome' | translate }} [image]="'key'" > - @@ -114,9 +130,15 @@

    {{ '#LDS#Welcome' | translate }}

    [image]="'key'" > - @@ -130,9 +152,15 @@

    {{ '#LDS#Welcome' | translate }}

    *ngIf="viewReady && ShowNewRequestLink()" > - diff --git a/imxweb/projects/qer/src/lib/wport/start/start.component.scss b/imxweb/projects/qer/src/lib/wport/start/start.component.scss index 5b0245796..8075e0f2d 100644 --- a/imxweb/projects/qer/src/lib/wport/start/start.component.scss +++ b/imxweb/projects/qer/src/lib/wport/start/start.component.scss @@ -1,4 +1,4 @@ -@import '../../../../../qbm/src/lib/tile/tile-variables.scss'; +@import 'base/variables'; :host { display: flex; @@ -7,14 +7,13 @@ height: 100%; } - .imx-flexible-tile-row { display: flex; - flex-wrap: wrap ; + flex-wrap: wrap; } -.mat-card { - width: $tile-width; +.mat-mdc-card { + width: $IMX_Tile_Width; height: 108px; overflow: auto; padding: 0; @@ -31,14 +30,6 @@ display: flex; } -.mat-button{ - text-transform: uppercase; -} - -.mat-button ::ng-deep eui-icon{ - margin-left: 15px; -} - .hidden { display: none; } diff --git a/imxweb/projects/qer/src/lib/wport/start/start.component.ts b/imxweb/projects/qer/src/lib/wport/start/start.component.ts index c2a8401b6..3bfabe20a 100644 --- a/imxweb/projects/qer/src/lib/wport/start/start.component.ts +++ b/imxweb/projects/qer/src/lib/wport/start/start.component.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -27,12 +27,12 @@ import { ChangeDetectorRef, Component, OnInit } from '@angular/core'; import { Router } from '@angular/router'; -import { UserConfig, ProjectConfig, QerProjectConfig } from 'imx-api-qer'; -import { UserModelService } from '../../user/user-model.service'; -import { PendingItemsType } from '../../user/pending-items-type.interface'; -import { ProjectConfigurationService } from '../../project-configuration/project-configuration.service'; +import { SystemInfo } from '@imx-modules/imx-api-qbm'; +import { ProjectConfig, QerProjectConfig, UserConfig } from '@imx-modules/imx-api-qer'; import { imx_SessionService, SystemInfoService } from 'qbm'; -import { SystemInfo } from 'imx-api-qbm'; +import { ProjectConfigurationService } from '../../project-configuration/project-configuration.service'; +import { PendingItemsType } from '../../user/pending-items-type.interface'; +import { UserModelService } from '../../user/user-model.service'; import { DashboardService } from './dashboard.service'; @Component({ @@ -55,11 +55,11 @@ export class StartComponent implements OnInit { private readonly systemInfoService: SystemInfoService, private readonly sessionService: imx_SessionService, private readonly detectRef: ChangeDetectorRef, - private readonly projectConfigurationService: ProjectConfigurationService + private readonly projectConfigurationService: ProjectConfigurationService, ) {} public async ngOnInit(): Promise { - this.dashboardService.busyStateChanged.subscribe(busy => { + this.dashboardService.busyStateChanged.subscribe((busy) => { this.viewReady = !busy; this.detectRef.detectChanges(); }); @@ -69,7 +69,7 @@ export class StartComponent implements OnInit { this.pendingItems = await this.userModelSvc.getPendingItems(); this.projectConfig = await this.projectConfigurationService.getConfig(); this.systemInfo = await this.systemInfoService.get(); - this.userUid = (await this.sessionService.getSessionState()).UserUid; + this.userUid = (await this.sessionService.getSessionState()).UserUid || ''; } finally { busy.endBusy(); } @@ -80,7 +80,9 @@ export class StartComponent implements OnInit { } public ShowPasswordMgmtTile(): boolean { - return this.projectConfig?.PasswordConfig.VI_MyData_MyPassword_Visibility && !!this.projectConfig?.PasswordConfig.PasswordMgmtUrl; + return ( + (this.projectConfig.PasswordConfig?.VI_MyData_MyPassword_Visibility && !!this.projectConfig.PasswordConfig?.PasswordMgmtUrl) ?? false + ); } public GoToMyPassword(): void { @@ -88,7 +90,7 @@ export class StartComponent implements OnInit { } public GoToPasswordMgmtWeb(): void { - this.router.navigate(['/externalRedirect', { externalUrl: this.projectConfig?.PasswordConfig.PasswordMgmtUrl }]); + this.router.navigate(['/externalRedirect', { externalUrl: this.projectConfig.PasswordConfig?.PasswordMgmtUrl }]); } public GoToShoppingCart(): void { @@ -104,7 +106,7 @@ export class StartComponent implements OnInit { } public GoToItShopApprovalInquiries(): void { - this.router.navigate(['itshop', 'approvals'], {queryParams: {inquiries:true}}); + this.router.navigate(['itshop', 'approvals'], { queryParams: { inquiries: true } }); } public GoToMyProcesses(): void { @@ -112,7 +114,7 @@ export class StartComponent implements OnInit { } public ShowQpmIntegration(): boolean { - return !!this.projectConfig?.PasswordConfig.QpmBaseUrl; + return !!this.projectConfig.PasswordConfig?.QpmBaseUrl; } public GoToQpm(): void { @@ -159,6 +161,6 @@ export class StartComponent implements OnInit { public ShowNewRequestLink(): boolean { // Starting a new request is only allowed when the session has an identity and the ITShop(Requests) feature is enabled - return this.userConfig?.IsITShopEnabled && this.userUid && this.systemInfo.PreProps.includes('ITSHOP'); + return (this.userConfig?.IsITShopEnabled && !!this.userUid?.length && this.systemInfo.PreProps?.includes('ITSHOP')) || false; } } diff --git a/imxweb/projects/qer/src/public_api.ts b/imxweb/projects/qer/src/public_api.ts index e66b665af..3b8e43281 100644 --- a/imxweb/projects/qer/src/public_api.ts +++ b/imxweb/projects/qer/src/public_api.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -30,8 +30,11 @@ export { AddressbookComponent } from './lib/addressbook/addressbook.component'; export { AddressbookModule } from './lib/addressbook/addressbook.module'; +export { AuthenticationFactors } from './lib/admin/authentication-factors.interface'; export { FeatureConfigService } from './lib/admin/feature-config.service'; +export { isAuditor, isRoleAdmin, isRoleStatistics } from './lib/admin/qer-permissions-helper'; export { QerPermissionsService } from './lib/admin/qer-permissions.service'; +export { ApprovalWorkFlowModule } from './lib/approval-workflows/approval-workflows.module'; export { ArchivedRequestsComponent } from './lib/archived-requests/archived-requests.component'; export { ArchivedRequestsModule } from './lib/archived-requests/archived-requests.module'; export { BusinessOwnerAddOnTileComponent } from './lib/businessowner-addon-tile/businessowner-addon-tile.component'; @@ -50,11 +53,6 @@ export { HelperAlertContent } from './lib/helper-alert-content/helper-alert-cont export { IdentitiesReportsService } from './lib/identities/identities-reports.service'; export { DataExplorerIdentitiesComponent } from './lib/identities/identities.component'; export { IdentitiesModule } from './lib/identities/identities.module'; -export { NotificationRegistryService } from './lib/notifications/notification-registry.service'; -export { NotificationStreamService } from './lib/notifications/notification-stream.service'; -export { NotificationTileComponent } from './lib/tiles/notification-tile/notification-tile.component'; -export { BadgeTileComponent } from './lib/tiles/badge-tile/badge-tile.component'; -export { IconTileComponent } from './lib/tiles/icon-tile/icon-tile.component'; export { IdentitiesService } from './lib/identities/identities.service'; export { IdentityRoleMembershipsParameter, @@ -83,18 +81,24 @@ export { ServiceItemDetailComponent } from './lib/itshop/request-info/service-it export { ShelfService } from './lib/itshop/shelf.service'; export { WorkflowDataWrapper } from './lib/itshop/workflow-data-wrapper'; export { ApprovalsModule } from './lib/itshopapprove/approvals.module'; -export { ApprovalWorkFlowModule } from './lib/approval-workflows/approval-workflows.module'; export { DecisionStepSevice } from './lib/itshopapprove/decision-step.service'; export { RecommendationSidesheetComponent } from './lib/itshopapprove/recommendation-sidesheet/recommendation-sidesheet.component'; +export { WorkflowActionComponent } from './lib/itshopapprove/workflow-action/workflow-action.component'; export { DecisionReasonComponent } from './lib/justification/decision-reason/decision-reason.component'; export { JustificationType } from './lib/justification/justification-type.enum'; export { JustificationModule } from './lib/justification/justification.module'; export { JustificationService } from './lib/justification/justification.service'; export { MyResponsibilitiesRegistryService } from './lib/my-responsibilities-view/my-responsibilities-registry.service'; export { MyResponsibilitiesViewModule } from './lib/my-responsibilities-view/my-responsibilities-view.module'; +export { NewRequestSelectionService } from './lib/new-request/new-request-selection.service'; export * from './lib/new-request/new-request.component'; export * from './lib/new-request/new-request.module'; +export { NotificationRegistryService } from './lib/notifications/notification-registry.service'; +export { NotificationStreamService } from './lib/notifications/notification-stream.service'; export { ObjectAttestationStatistics } from './lib/object-attestation/object-attestation-statistics.interface'; +export { ObjectHyperviewComponent } from './lib/object-hyperview/object-hyperview.component'; +export { ObjectHyperviewModule } from './lib/object-hyperview/object-hyperview.module'; +export { ObjectHyperviewService } from './lib/object-hyperview/object-hyperview.service'; export { ObjectOverviewContainer } from './lib/ops/objectOverviewContainer'; export { ObjectOverviewPersonComponent } from './lib/ops/objectOverviewPerson.component'; export { OpsModule } from './lib/ops/ops.module'; @@ -102,21 +106,24 @@ export { PasscodeService } from './lib/ops/passcode.service'; export { OpSupportUserService } from './lib/ops/user.service'; export { OwnerControlComponent } from './lib/owner-control/owner-control.component'; export { OwnerControlModule } from './lib/owner-control/owner-control.module'; +export { ExtendedEntityWrapper } from './lib/parameter-data/extended-entity-wrapper.interface'; export { ParameterContainer } from './lib/parameter-data/parameter-container'; export { ParameterDataContainer } from './lib/parameter-data/parameter-data-container'; export { ParameterDataLoadParameters } from './lib/parameter-data/parameter-data-load-parameters.interface'; export { ParameterDataService } from './lib/parameter-data/parameter-data.service'; +export { PasswordQuestionsComponent } from './lib/password-questions/password-questions.component'; +export { PasswordQuestionsModule } from './lib/password-questions/password-questions.module'; export { PasswordDashboardComponent } from './lib/password/dashboard.component'; export { PasscodeLoginModule } from './lib/password/passcode-login/passcode-login.module'; export { PasswordQueryComponent } from './lib/password/password-query.component'; export { PasswordResetComponent } from './lib/password/password-reset.component'; export { PasswordModule } from './lib/password/password.module'; +export { PasswordService } from './lib/password/password.service'; export { QaLoginModule } from './lib/password/qa-login/qa-login.module'; export { PersonService } from './lib/person/person.service'; export { ProductSelectionModule } from './lib/product-selection/product-selection.module'; export { ProfileComponent } from './lib/profile/profile.component'; export { ProfileModule } from './lib/profile/profile.module'; -export { PasswordQuestionsComponent } from './lib/profile/password-questions/password-questions.component'; export { ProjectConfigurationModule } from './lib/project-configuration/project-configuration.module'; export { ProjectConfigurationService } from './lib/project-configuration/project-configuration.service'; export { QerApiService } from './lib/qer-api-client.service'; @@ -135,15 +142,15 @@ export { RiskConfigModule } from './lib/risk-config/risk-config.module'; export { RiskModule } from './lib/risk/risk.module'; export { RiskAnalysisSidesheetComponent } from './lib/risk/riskanalysis-sidesheet.component'; export { RiskAnalysisComponent } from './lib/risk/riskanalysis.component'; +export { DataManagementService } from './lib/role-management/data-management.service'; export { BaseTreeRoleRestoreHandler } from './lib/role-management/restore/restore-handler'; export { IRoleDataModel } from './lib/role-management/role-data-model.interface'; -export { BaseTreeEntitlement, IRoleEntitlements } from './lib/role-management/role-entitlements/entitlement-handlers'; export { RoleDetailComponent } from './lib/role-management/role-detail/role-detail.component'; -export { RoleRecommendationsComponent } from './lib/role-management/role-entitlements/role-recommendations/role-recommendations.component'; +export { BaseTreeEntitlement, IRoleEntitlements } from './lib/role-management/role-entitlements/entitlement-handlers'; +export { RoleEntitlementActionService } from './lib/role-management/role-entitlements/role-entitlement-action.service'; export { RoleRecommendationResultItem } from './lib/role-management/role-entitlements/role-recommendations/role-recommendation-result-item'; -export { RoleEntitlementActionService } from './lib/role-management/role-entitlements/role-entitlement-action.service' +export { RoleRecommendationsComponent } from './lib/role-management/role-entitlements/role-recommendations/role-recommendations.component'; export { RoleManangementModule } from './lib/role-management/role-manangement.module'; -export { DataManagementService } from './lib/role-management/data-management.service'; export { BaseMembership, IRoleMembershipType } from './lib/role-management/role-memberships/membership-handlers'; export { RoleMembershipsComponent } from './lib/role-management/role-memberships/role-memberships.component'; export { RoleMembershipsModule } from './lib/role-management/role-memberships/role-memberships.module'; @@ -155,52 +162,51 @@ export { ServiceItemTagsComponent } from './lib/service-item-tags/service-item-t export { ServiceItemTagsModule } from './lib/service-item-tags/service-item-tags.module'; export { ServiceItemTagsService } from './lib/service-item-tags/service-item-tags.service'; export { - additionalColumnsForServiceItemsKey, ServiceItemsEditFormComponent, + additionalColumnsForServiceItemsKey, } from './lib/service-items-edit/service-items-edit-form/service-items-edit-form.component'; export { ServiceItemsEditFormModule } from './lib/service-items-edit/service-items-edit-form/service-items-edit-form.module'; export { ServiceItemsEditModule } from './lib/service-items-edit/service-items-edit.module'; -export { StartComponent } from './lib/wport/start/start.component'; +export { SettingsComponent } from './lib/settings/settings.component'; export { BaseViewerComponent } from './lib/shopping-cart-validation-detail/base-viewer/base-viewer.component'; export { DetailViewerComponent } from './lib/shopping-cart-validation-detail/detail-viewer/detail-viewer.component'; export { DetailsView } from './lib/shopping-cart-validation-detail/details-view.interface'; -export { isRoleAdmin, isRoleStatistics, isAuditor} from './lib/admin/qer-permissions-helper'; -export { SettingsComponent } from './lib/settings/settings.component'; -export * from './lib/new-request/new-request.module'; -export * from './lib/new-request/new-request.component'; -export { ViewConfigService } from './lib/view-config/view-config.service'; - -export { StatisticsForObjectsComponent } from './lib/statistics/statistics-for-objects/statistics-for-objects.component'; -export { ChartInfoTyped } from './lib/statistics/statistics-home-page/chart-info-typed'; - -export { ObjectHyperviewModule } from './lib/object-hyperview/object-hyperview.module'; -export { ObjectHyperviewComponent } from './lib/object-hyperview/object-hyperview.component'; -export { ObjectHyperviewService } from './lib/object-hyperview/object-hyperview.service'; export { DuplicateCheckComponent } from './lib/shopping-cart-validation-detail/duplicate-check/duplicate-check.component'; export { ExclusionCheckComponent } from './lib/shopping-cart-validation-detail/exclusion-check/exclusion-check.component'; export { ShoppingCartValidationDetailModule } from './lib/shopping-cart-validation-detail/shopping-cart-validation-detail.module'; export { ShoppingCartValidationDetailService } from './lib/shopping-cart-validation-detail/shopping-cart-validation-detail.service'; +export { CartItemsExtensionService } from './lib/shopping-cart/cart-items-extension.service'; +export { ICartItemsExtensionService } from './lib/shopping-cart/cart-items.model'; +export { RequestableProduct } from './lib/shopping-cart/requestable-product.interface'; export { ShoppingCartModule } from './lib/shopping-cart/shopping-cart.module'; +export { QueueStatusComponent } from './lib/queue/queue-status/queue-status.component'; export { SourceDetectiveSidesheetComponent, SourceDetectiveSidesheetData } from './lib/sourcedetective/sourcedetective-sidesheet.component'; export { SourceDetectiveType } from './lib/sourcedetective/sourcedetective-type.enum'; export { SourceDetectiveComponent } from './lib/sourcedetective/sourcedetective.component'; export { SourceDetectiveModule } from './lib/sourcedetective/sourcedetective.module'; +export { ChartTileComponent } from './lib/statistics/charts/chart-tile/chart-tile.component'; +export { PointStatVisualService } from './lib/statistics/charts/chart-tile/point-stat-visual/point-stat-visual.service'; +export { StatisticsChartHandlerService } from './lib/statistics/charts/statistics-chart-handler.service'; +export { StatisticsForObjectsComponent } from './lib/statistics/statistics-for-objects/statistics-for-objects.component'; +export { ChartInfoTyped } from './lib/statistics/statistics-home-page/chart-info-typed'; export { StatisticsModule } from './lib/statistics/statistics.module'; export { TeamResponsibilitiesModule } from './lib/team-responsibilities/team-responsibilities.module'; export { TermsOfUseItem } from './lib/terms-of-use/terms-of-use-item'; export { TermsOfUseViewerComponent } from './lib/terms-of-use/terms-of-use-viewer/terms-of-use-viewer.component'; export { TermsOfUseModule } from './lib/terms-of-use/terms-of-use.module'; export { TermsOfUseService } from './lib/terms-of-use/terms-of-use.service'; +export { BadgeTileComponent } from './lib/tiles/badge-tile/badge-tile.component'; +export { IconTileComponent } from './lib/tiles/icon-tile/icon-tile.component'; +export { NotificationTileComponent } from './lib/tiles/notification-tile/notification-tile.component'; export { TilesModule } from './lib/tiles/tiles.module'; +export { UserProcessComponent } from './lib/user-process/user-process.component'; +export { UserProcessModule } from './lib/user-process/user-process.module'; export { PendingItemsType } from './lib/user/pending-items-type.interface'; export { UserModelService } from './lib/user/user-model.service'; export { UserModule } from './lib/user/user.module'; -export { UserProcessComponent } from './lib/user-process/user-process.component'; -export { UserProcessModule } from './lib/user-process/user-process.module'; -export { DashboardService } from './lib/wport/start/dashboard.service'; -export { NewRequestSelectionService } from './lib/new-request/new-request-selection.service'; -export { ViewDevicesModule } from './lib/view-devices/view-devices.module'; +export { ViewConfigService } from './lib/view-config/view-config.service'; export { ViewDevicesComponent } from './lib/view-devices/view-devices-home/view-devices.component'; export { ViewDevicesSidesheetComponent } from './lib/view-devices/view-devices-sidesheet/view-devices-sidesheet.component'; -export { AuthenticationFactors } from './lib/admin/authentication-factors.interface'; - +export { ViewDevicesModule } from './lib/view-devices/view-devices.module'; +export { DashboardService } from './lib/wport/start/dashboard.service'; +export { StartComponent } from './lib/wport/start/start.component'; diff --git a/imxweb/projects/qer/src/test.ts b/imxweb/projects/qer/src/test.ts index 1f09d8a87..9794e7c90 100644 --- a/imxweb/projects/qer/src/test.ts +++ b/imxweb/projects/qer/src/test.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -26,23 +26,17 @@ // This file is required by karma.conf.js and loads recursively all the .spec and framework files -import 'core-js/es7/reflect'; -import 'zone.js/dist/zone'; -import 'zone.js/dist/zone-testing'; +// Zone must be imported first. Be careful with prettier import organizing +import 'zone.js'; +import 'zone.js/testing'; + import { getTestBed } from '@angular/core/testing'; import { BrowserDynamicTestingModule, platformBrowserDynamicTesting } from '@angular/platform-browser-dynamic/testing'; +import 'core-js/es/reflect'; import { TestHelperModule } from 'qbm'; import { QerDefaultMocks } from './default-mocks.spec'; - -declare const require: any; - // First, initialize the Angular testing environment. getTestBed().initTestEnvironment([BrowserDynamicTestingModule, TestHelperModule], platformBrowserDynamicTesting()); -// Then we find all the tests. -const context = require.context('./', true, /\.spec\.ts$/); -// And load the modules. -context.keys().map(context); - QerDefaultMocks.registerDefaultMocks(); diff --git a/imxweb/projects/qer/tsconfig.lib.json b/imxweb/projects/qer/tsconfig.lib.json index 6bc419f84..f76eeaeb4 100644 --- a/imxweb/projects/qer/tsconfig.lib.json +++ b/imxweb/projects/qer/tsconfig.lib.json @@ -7,10 +7,11 @@ "declarationMap": true, "sourceMap": true, "inlineSources": true, - "types": [] + "types": [], + "strictNullChecks": true }, - "exclude": [ - "src/test.ts", - "**/*.spec.ts" - ] + "exclude": ["src/test.ts", "**/*.spec.ts"], + "angularCompilerOptions": { + "strictTemplates": true + } } diff --git a/imxweb/projects/qer/tsconfig.spec.json b/imxweb/projects/qer/tsconfig.spec.json index 16da33db0..6bd74e1f7 100644 --- a/imxweb/projects/qer/tsconfig.spec.json +++ b/imxweb/projects/qer/tsconfig.spec.json @@ -1,17 +1,10 @@ { "extends": "../../tsconfig.json", "compilerOptions": { + "strictNullChecks": false, "outDir": "../../out-tsc/spec", - "types": [ - "jasmine", - "node" - ] + "types": ["jasmine", "node"] }, - "files": [ - "src/test.ts" - ], - "include": [ - "**/*.spec.ts", - "**/*.d.ts" - ] + "files": ["src/test.ts"], + "include": ["**/*.spec.ts", "**/*.d.ts"] } diff --git a/imxweb/projects/qer/tslint.json b/imxweb/projects/qer/tslint.json deleted file mode 100644 index 8bab15f53..000000000 --- a/imxweb/projects/qer/tslint.json +++ /dev/null @@ -1,17 +0,0 @@ -{ - "extends": "../../tslint.json", - "rules": { - "directive-selector": [ - true, - "attribute", - "imx", - "camelCase" - ], - "component-selector": [ - true, - "element", - "imx", - "kebab-case" - ] - } -} diff --git a/imxweb/projects/rmb/.compodocrc.json b/imxweb/projects/rmb/.compodocrc.json index 865166461..b6670d351 100644 --- a/imxweb/projects/rmb/.compodocrc.json +++ b/imxweb/projects/rmb/.compodocrc.json @@ -1,6 +1,6 @@ { "name": "IMX Web - RMB Library", - "output": "../../documentation/v92/rmb", + "output": "../../documentation/v93/rmb", "theme": "material", "assetsFolder": "../../compodoc/assets", "customLogo": "../../compodoc/assets/images/oneidentity-logo.png", diff --git a/imxweb/projects/rmb/.eslintrc.json b/imxweb/projects/rmb/.eslintrc.json new file mode 100644 index 000000000..b1f055e0f --- /dev/null +++ b/imxweb/projects/rmb/.eslintrc.json @@ -0,0 +1,35 @@ +{ + "extends": "../../.eslintrc.json", + "ignorePatterns": ["!**/*", "**/*.spec.ts"], + "overrides": [ + { + "files": ["*.ts"], + "parserOptions": { + "project": ["imxweb/projects/rmb/tsconfig.lib.json", "imxweb/projects/rmb/tsconfig.spec.json"], + "createDefaultProgram": true + }, + "rules": { + "@angular-eslint/directive-selector": [ + "error", + { + "type": "attribute", + "prefix": "imx", + "style": "camelCase" + } + ], + "@angular-eslint/component-selector": [ + "error", + { + "type": "element", + "prefix": "imx", + "style": "kebab-case" + } + ] + } + }, + { + "files": ["*.html"], + "rules": {} + } + ] +} diff --git a/imxweb/projects/rmb/imx-plugin-config.json b/imxweb/projects/rmb/imx-plugin-config.json index d8f895bdb..b14aa58c8 100644 --- a/imxweb/projects/rmb/imx-plugin-config.json +++ b/imxweb/projects/rmb/imx-plugin-config.json @@ -5,4 +5,4 @@ "Name": "RmbConfigModule" } ] -} \ No newline at end of file +} diff --git a/imxweb/projects/rmb/karma.conf.js b/imxweb/projects/rmb/karma.conf.js index 211193c9d..3e53a3ac8 100644 --- a/imxweb/projects/rmb/karma.conf.js +++ b/imxweb/projects/rmb/karma.conf.js @@ -15,7 +15,7 @@ module.exports = function (config) { require('karma-junit-reporter'), ], client: { - clearContext: false // leave Jasmine Spec Runner output visible in browser + clearContext: false, // leave Jasmine Spec Runner output visible in browser }, coverageIstanbulReporter: { dir: require('path').join(__dirname, 'results'), @@ -23,7 +23,7 @@ module.exports = function (config) { fixWebpackSourcePaths: true, 'report-config': { html: { - subdir: 'coverage-html' + subdir: 'coverage-html', }, }, thresholds: { @@ -40,13 +40,14 @@ module.exports = function (config) { port: 9876, captureTimeout: 210000, browserDisconnectTolerance: 3, - browserDisconnectTimeout : 210000, - browserNoActivityTimeout : 210000, + browserDisconnectTimeout: 210000, + browserNoActivityTimeout: 210000, colors: true, logLevel: config.LOG_INFO, autoWatch: true, browsers: ['Chrome'], singleRun: false, - restartOnFileChange: true + failOnEmptyTestSuite: false, + restartOnFileChange: true, }); }; diff --git a/imxweb/projects/rmb/ng-package.dynamic.json b/imxweb/projects/rmb/ng-package.dynamic.json index c7ee1a178..72d34a165 100644 --- a/imxweb/projects/rmb/ng-package.dynamic.json +++ b/imxweb/projects/rmb/ng-package.dynamic.json @@ -16,12 +16,11 @@ "@elemental-ui/core", "@ngx-translate/core", "@ngx-translate/http-loader", - "applicationinsights-js", "billboard.js" ], - "dest": "../../html/rmb", + "dest": "../../html/qer-app-portal/rmb", "lib": { "entryFile": "src/public_api.ts", - "styleIncludePaths": ["../../shared/assets"] + "styleIncludePaths": ["../../shared/scss"] } } diff --git a/imxweb/projects/rmb/ng-package.json b/imxweb/projects/rmb/ng-package.json index 8c47e5aa7..7645b7ed0 100644 --- a/imxweb/projects/rmb/ng-package.json +++ b/imxweb/projects/rmb/ng-package.json @@ -3,6 +3,6 @@ "dest": "../../dist/rmb", "lib": { "entryFile": "src/public_api.ts", - "styleIncludePaths": ["../../shared/assets"] + "styleIncludePaths": ["../../shared/scss"] } } diff --git a/imxweb/projects/rmb/package.json b/imxweb/projects/rmb/package.json index 57b92335c..bcb509eeb 100644 --- a/imxweb/projects/rmb/package.json +++ b/imxweb/projects/rmb/package.json @@ -1,6 +1,6 @@ { "name": "rmb", - "version": "9.2.1", + "version": "9.3.0", "private": true, "bundledDependencies": [ "imx-api-rmb" diff --git a/imxweb/projects/rmb/project.json b/imxweb/projects/rmb/project.json new file mode 100644 index 000000000..89a52c932 --- /dev/null +++ b/imxweb/projects/rmb/project.json @@ -0,0 +1,64 @@ +{ + "$schema": "../../node_modules/nx/schemas/project-schema.json", + "name": "rmb", + "sourceRoot": "projects/rmb/src", + "implicitDependencies": ["qer"], + "projectType": "library", + "prefix": "imx", + "generators": { + "@schematics/angular:component": { + "style": "scss" + } + }, + "targets": { + "build": { + "executor": "@angular-devkit/build-angular:ng-packagr", + "options": { + "tsConfig": "projects/rmb/tsconfig.lib.json", + "project": "projects/rmb/ng-package.json" + }, + "configurations": { + "production": { + "tsConfig": "projects/rmb/tsconfig.lib.prod.json" + }, + "development": { + "tsConfig": "projects/rmb/tsconfig.lib.json" + }, + "dynamic": { + "project": "projects/rmb/ng-package.dynamic.json" + }, + "remote-dev": { + "tsConfig": "projects/rmb/tsconfig.lib.json" + }, + "remote-qs": { + "tsConfig": "projects/rmb/tsconfig.lib.json" + } + }, + "outputs": ["{workspaceRoot}/dist/rmb"] + }, + "test": { + "executor": "@angular-devkit/build-angular:karma", + "options": { + "main": "projects/rmb/src/test.ts", + "tsConfig": "projects/rmb/tsconfig.spec.json", + "karmaConfig": "projects/rmb/karma.conf.js", + "stylePreprocessorOptions": { + "includePaths": [ + "./shared/assets", + "./shared/scss", + "./node_modules", + "./node_modules/@elemental-ui/cadence-icon", + "./node_modules/@elemental-ui/core" + ] + } + } + }, + "lint": { + "executor": "@angular-devkit/build-angular:tslint", + "options": { + "tsConfig": ["projects/rmb/tsconfig.lib.json", "projects/rmb/tsconfig.spec.json"], + "exclude": ["**/node_modules/**", "**/*.spec.ts", "**/*.json"] + } + } + } +} diff --git a/imxweb/projects/rmb/src/lib/init.service.ts b/imxweb/projects/rmb/src/lib/init.service.ts index 149e85864..5d29e842f 100644 --- a/imxweb/projects/rmb/src/lib/init.service.ts +++ b/imxweb/projects/rmb/src/lib/init.service.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -26,9 +26,20 @@ import { Injectable } from '@angular/core'; import { Route, Router } from '@angular/router'; +import { ProjectConfig } from '@imx-modules/imx-api-qbm'; +import { RoleExtendedDataWrite } from '@imx-modules/imx-api-qer'; -import { DynamicMethodService, ImxTranslationProviderService, imx_SessionService, MenuService, ExtService, HELP_CONTEXTUAL } from 'qbm'; -import { PortalAdminRoleOrg, PortalPersonRolemembershipsOrg, PortalRespOrg, V2ApiClientMethodFactory } from 'imx-api-rmb'; +import { PortalAdminRoleOrg, PortalPersonRolemembershipsOrg, PortalRespOrg, V2ApiClientMethodFactory } from '@imx-modules/imx-api-rmb'; +import { + CollectionLoadParameters, + EntityCollectionData, + EntitySchema, + ExtendedTypedEntityCollection, + MethodDefinition, + MethodDescriptor, + WriteExtTypedEntity, +} from '@imx-modules/imx-qbm-dbts'; +import { DynamicMethodService, ExtService, HELP_CONTEXTUAL, ImxTranslationProviderService, MenuService, imx_SessionService } from 'qbm'; import { BaseTreeEntitlement, BaseTreeRoleRestoreHandler, @@ -46,10 +57,7 @@ import { import { OrgDataModel } from './org-data-model'; import { OrgMembership } from './org-membership'; import { RmbApiService } from './rmb-api-client.service'; -import { EntitySchema, ExtendedTypedEntityCollection, WriteExtTypedEntity, CollectionLoadParameters, EntityCollectionData, MethodDescriptor, MethodDefinition } from 'imx-qbm-dbts'; -import { RoleExtendedDataWrite } from 'imx-api-qer'; import { TeamRoleComponent } from './team-role/team-role.component'; -import { ProjectConfig } from 'imx-api-qbm'; @Injectable({ providedIn: 'root' }) export class InitService { @@ -68,7 +76,7 @@ export class InitService { private readonly identityRoleMembershipService: IdentityRoleMembershipsService, private readonly myResponsibilitiesRegistryService: MyResponsibilitiesRegistryService, private readonly extService: ExtService, - private readonly qerPermissionsService: QerPermissionsService + private readonly qerPermissionsService: QerPermissionsService, ) {} public onInit(routes: Route[]): void { @@ -83,7 +91,7 @@ export class InitService { }, private getByIdApi: { Get_byid(id: string): Promise, unknown>>; - } + }, ) {} Get(): Promise, unknown>> { @@ -105,7 +113,7 @@ export class InitService { (uid) => this.api.client.portal_roles_Org_restore_byid_get(uid), (uid) => this.api.client.portal_resp_Org_restore_byid_get(uid), (uidRole, actions) => this.api.client.portal_roles_Org_restore_byid_post(uidRole, actions), - (uidRole, actions) => this.api.client.portal_resp_Org_restore_byid_post(uidRole, actions) + (uidRole, actions) => this.api.client.portal_resp_Org_restore_byid_post(uidRole, actions), ); this.roleService.targetMap.set(this.orgTag, { @@ -124,12 +132,16 @@ export class InitService { interactiveResp: new ApiWrapper(this.api.typedClient.PortalRespOrgInteractive, this.api.typedClient.PortalRespOrgInteractive), interactiveAdmin: new ApiWrapper( this.api.typedClient.PortalAdminRoleOrgInteractive, - this.api.typedClient.PortalAdminRoleOrgInteractive + this.api.typedClient.PortalAdminRoleOrgInteractive, ), - adminCanCreate: true, - respCanCreate: true, + adminCanCreate: async () => { + return (await this.api.client.portal_roles_config_businessroles_get()).EnableNewOrg; + }, + respCanCreate: async () => { + return (await this.api.client.portal_roles_config_businessroles_get()).EnableNewOrg; + }, entitlements: new BaseTreeEntitlement(this.qerApi, this.session, this.dynamicMethodService, this.translator, this.orgTag, (e) => - e.GetColumn('UID_OrgRoot').GetValue() + e.GetColumn('UID_OrgRoot').GetValue(), ), membership: new OrgMembership(this.api, this.session, this.translator), canUseRecommendations: true, @@ -159,6 +171,8 @@ export class InitService { editHeading: '#LDS#Heading Edit Business Role', createSnackbar: '#LDS#The business role has been successfully created.', }, + adminHelpContextId: HELP_CONTEXTUAL.DataExplorerBusinessRolesRoleEntitlements, + respHelpContextId: HELP_CONTEXTUAL.MyResponsibilitiesBusinessRolesRoleEntitlements, }); this.identityRoleMembershipService.addTarget({ @@ -176,22 +190,24 @@ export class InitService { this.setupMenu(); - this.dataExplorerRegistryService.registerFactory((preProps: string[], features: string[], projectConfig: ProjectConfig, groups: string[]) => { - if (!isRoleAdmin(features) && !isRoleStatistics(features) && !isAuditor(groups)) { - return; - } - return { - instance: RolesOverviewComponent, - data: { - TableName: this.orgTag, - Count: 0, - }, - contextId: HELP_CONTEXTUAL.DataExplorerBusinessRoles, - sortOrder: 7, - name: 'businessroles', - caption: '#LDS#Menu Entry Business roles', - }; - }); + this.dataExplorerRegistryService.registerFactory( + (preProps: string[], features: string[], projectConfig: ProjectConfig, groups: string[]) => { + if (!isRoleAdmin(features) && !isRoleStatistics(features) && !isAuditor(groups)) { + return undefined; + } + return { + instance: RolesOverviewComponent, + data: { + TableName: this.orgTag, + Count: 0, + }, + contextId: HELP_CONTEXTUAL.DataExplorerBusinessRoles, + sortOrder: 7, + name: 'businessroles', + caption: '#LDS#Menu Entry Business roles', + }; + }, + ); this.myResponsibilitiesRegistryService.registerFactory((preProps: string[], features: string[]) => ({ instance: RolesOverviewComponent, @@ -202,7 +218,7 @@ export class InitService { TableName: this.orgTag, Count: 0, }, - contextId: HELP_CONTEXTUAL.MyResponsibilitiesBusinessRoles + contextId: HELP_CONTEXTUAL.MyResponsibilitiesBusinessRoles, })); this.extService.register('Dashboard-MediumTiles', { instance: TeamRoleComponent }); } @@ -210,7 +226,7 @@ export class InitService { private setupMenu(): void { this.menuService.addMenuFactories((preProps: string[], features: string[], projectConfig: ProjectConfig, groups: string[]) => { if (!isRoleAdmin(features) && !isRoleStatistics(features) && !isAuditor(groups)) { - return null; + return undefined; } const menu = { id: 'ROOT_Data', diff --git a/imxweb/projects/rmb/src/lib/org-data-model.ts b/imxweb/projects/rmb/src/lib/org-data-model.ts index 7d12d43a3..0fedb3c09 100644 --- a/imxweb/projects/rmb/src/lib/org-data-model.ts +++ b/imxweb/projects/rmb/src/lib/org-data-model.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -24,18 +24,15 @@ * */ -import { FilterData, DataModel } from 'imx-qbm-dbts'; +import { FilterData, DataModel } from '@imx-modules/imx-qbm-dbts'; import { IRoleDataModel } from 'qer'; import { RmbApiService } from './rmb-api-client.service'; export class OrgDataModel implements IRoleDataModel { - - constructor( - private readonly api: RmbApiService - ) { } + constructor(private readonly api: RmbApiService) {} public async getModel(filter: FilterData[], isAdmin: boolean): Promise { - return isAdmin ? - this.api.client.portal_admin_role_org_datamodel_get({ filter: filter }) + return isAdmin + ? this.api.client.portal_admin_role_org_datamodel_get({ filter: filter }) : this.api.client.portal_resp_org_datamodel_get({ filter: filter }); } } diff --git a/imxweb/projects/rmb/src/lib/org-membership.ts b/imxweb/projects/rmb/src/lib/org-membership.ts index 6c870af88..28d72150a 100644 --- a/imxweb/projects/rmb/src/lib/org-membership.ts +++ b/imxweb/projects/rmb/src/lib/org-membership.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -24,77 +24,27 @@ * */ -import { CollectionLoadParameters, ExtendedTypedEntityCollection, TypedEntity, EntityCollectionData, EntitySchema, IEntity, DataModel } from 'imx-qbm-dbts'; -import { IRoleMembershipType } from 'qer'; -import { DynamicMethod, ImxTranslationProviderService, imx_SessionService } from 'qbm'; +import { + CollectionLoadParameters, + EntityCollectionData, + EntitySchema, + ExtendedTypedEntityCollection, + TypedEntity, +} from '@imx-modules/imx-qbm-dbts'; +import { ImxTranslationProviderService, imx_SessionService } from 'qbm'; +import { BaseMembership } from 'qer'; import { RmbApiService } from './rmb-api-client.service'; // do not inherit from BaseMembership because classes cannot inherit across modules :-( -export class OrgMembership implements IRoleMembershipType { - - public supportsDynamicMemberships = true; - private readonly schemaPaths: Map = new Map(); - - private readonly basePath = 'portal/roles/config/membership/Org'; - +export class OrgMembership extends BaseMembership { constructor( - private readonly api: RmbApiService, - private readonly session: imx_SessionService, - private readonly translator: ImxTranslationProviderService + private api: RmbApiService, + private session: imx_SessionService, + private translator: ImxTranslationProviderService, ) { - this.schemaPaths.set('get', `${this.basePath}/{UID_Org}`); - this.schemaPaths.set('candidates', `${this.basePath}/{UID_Org}/UID_Person/candidates`); - } - - public async get(id: string, navigationState?: CollectionLoadParameters): Promise> { - const api = new DynamicMethod( - this.schemaPaths.get('get'), - `/${this.basePath}/${id}`, - this.api.apiClient, - this.session, - this.translator - ); - - return api.Get(navigationState); - } - - public getSchema(key: string): EntitySchema { - return this.session.Client.getSchema(this.schemaPaths.get(key)); - } - - public GetUidPerson(entity: IEntity) { - return entity.GetColumn('UID_Person').GetValue(); - } - - public GetUidRole(entity: IEntity): string { - return entity.GetColumn("UID_Org").GetValue(); - } - - public async getCandidates( - id: string, - navigationState?: CollectionLoadParameters - ): Promise> { - const api = new DynamicMethod( - this.schemaPaths.get('candidates'), - `/${this.basePath}/${id}/UID_Person/candidates`, - this.api.apiClient, - this.session, - this.translator - ); - - return api.Get(navigationState); - } - - public async getCandidatesDataModel(id: string): Promise { - const dynamicMethod = new DynamicMethod( - this.schemaPaths.get('candidates'), - `/${this.basePath}/${id}/UID_Person/candidates`, - this.api.apiClient, - this.session, - this.translator - ); - return dynamicMethod.getDataModei(); + super(api, session, translator); + this.setRoleName('Org', 'UID_Org'); } public async delete(role: string, identity: string): Promise { @@ -107,7 +57,7 @@ export class OrgMembership implements IRoleMembershipType { public getPrimaryMembers( uid: string, - navigationstate: CollectionLoadParameters + navigationstate: CollectionLoadParameters, ): Promise> { return this.api.typedClient.PortalRolesConfigOrgPrimarymembers.Get(uid, navigationstate); } diff --git a/imxweb/projects/rmb/src/lib/rmb-api-client.service.ts b/imxweb/projects/rmb/src/lib/rmb-api-client.service.ts index 0c780cafd..be05db22f 100644 --- a/imxweb/projects/rmb/src/lib/rmb-api-client.service.ts +++ b/imxweb/projects/rmb/src/lib/rmb-api-client.service.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -25,12 +25,12 @@ */ import { Injectable } from '@angular/core'; -import { V2Client, TypedClient } from 'imx-api-rmb'; -import { ApiClient } from 'imx-qbm-dbts'; +import { V2Client, TypedClient } from '@imx-modules/imx-api-rmb'; +import { ApiClient } from '@imx-modules/imx-qbm-dbts'; import { AppConfigService, ClassloggerService, ImxTranslationProviderService } from 'qbm'; @Injectable({ - providedIn: 'root' + providedIn: 'root', }) export class RmbApiService { private tc: TypedClient; @@ -50,7 +50,8 @@ export class RmbApiService { constructor( private readonly config: AppConfigService, private readonly logger: ClassloggerService, - private readonly translationProvider: ImxTranslationProviderService) { + private readonly translationProvider: ImxTranslationProviderService, + ) { try { this.logger.debug(this, 'Initializing RMB API service'); diff --git a/imxweb/projects/rmb/src/lib/rmb-config.module.ts b/imxweb/projects/rmb/src/lib/rmb-config.module.ts index b63c30081..f7f45b707 100644 --- a/imxweb/projects/rmb/src/lib/rmb-config.module.ts +++ b/imxweb/projects/rmb/src/lib/rmb-config.module.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -30,14 +30,10 @@ import { Routes, RouterModule } from '@angular/router'; import { InitService } from './init.service'; import { TeamRoleModule } from './team-role/team-role.module'; -const routes: Routes = [ -]; +const routes: Routes = []; @NgModule({ - imports: [ - RouterModule.forChild(routes), - TeamRoleModule - ], + imports: [RouterModule.forChild(routes), TeamRoleModule], }) export class RmbConfigModule { constructor(private readonly initializer: InitService) { diff --git a/imxweb/projects/rmb/src/lib/team-role/team-role.component.html b/imxweb/projects/rmb/src/lib/team-role/team-role.component.html index bc66ee537..5656acc31 100644 --- a/imxweb/projects/rmb/src/lib/team-role/team-role.component.html +++ b/imxweb/projects/rmb/src/lib/team-role/team-role.component.html @@ -2,7 +2,9 @@ data-imx-identifier="start-tile-team-role" [caption]="'#LDS#Heading Team Role' | translate" [subtitle]=" - existTeamRole ? ('#LDS#Manage your team role, its memberships and entitlements.' | translate) : ('#LDS#Manage the entitlements required for your team using a team role.' | translate) + existTeamRole + ? ('#LDS#Manage your team role, its memberships and entitlements.' | translate) + : ('#LDS#Manage the entitlements required for your team using a team role.' | translate) " [identifier]="'team-role'" [loadingState]="loadingState" @@ -10,12 +12,12 @@ > - - diff --git a/imxweb/projects/rmb/src/lib/team-role/team-role.component.scss b/imxweb/projects/rmb/src/lib/team-role/team-role.component.scss deleted file mode 100644 index 4acc7d302..000000000 --- a/imxweb/projects/rmb/src/lib/team-role/team-role.component.scss +++ /dev/null @@ -1,3 +0,0 @@ -.mat-button { - text-transform: uppercase; -} diff --git a/imxweb/projects/rmb/src/lib/team-role/team-role.component.ts b/imxweb/projects/rmb/src/lib/team-role/team-role.component.ts index c4a453dcb..fea9043a0 100644 --- a/imxweb/projects/rmb/src/lib/team-role/team-role.component.ts +++ b/imxweb/projects/rmb/src/lib/team-role/team-role.component.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -25,11 +25,12 @@ */ import { Component, OnInit } from '@angular/core'; -import { PortalAdminRoleOrg, PortalRespOrg, TeamRoleData } from 'imx-api-rmb'; import { ActivatedRoute } from '@angular/router'; -import { IEntity, ReadOnlyEntity } from 'imx-qbm-dbts'; import { EuiSidesheetService } from '@elemental-ui/core'; +import { PortalAdminRoleOrg, TeamRoleData } from '@imx-modules/imx-api-rmb'; +import { IEntity, ReadOnlyEntity } from '@imx-modules/imx-qbm-dbts'; import { TranslateService } from '@ngx-translate/core'; +import { calculateSidesheetWidth, SnackBarService } from 'qbm'; import { DataManagementService, QerPermissionsService, @@ -40,12 +41,10 @@ import { RoleService, } from 'qer'; import { RmbApiService } from '../rmb-api-client.service'; -import { MetadataService } from 'qbm'; @Component({ selector: 'imx-team-role', templateUrl: './team-role.component.html', - styleUrls: ['./team-role.component.scss'], }) export class TeamRoleComponent implements OnInit { public teamRole: TeamRoleData; @@ -61,12 +60,14 @@ export class TeamRoleComponent implements OnInit { private readonly route: ActivatedRoute, private readonly permissionService: QerPermissionsService, private readonly roleEntitlementActionService: RoleEntitlementActionService, + private readonly snackbar: SnackBarService, ) {} async ngOnInit(): Promise { - if(await this.permissionService.isPersonManager()){ - this.showTeamRole = true; + const canCreate = (await this.rmbApiService.client.portal_roles_config_businessroles_get()).EnableNewTeamRole; + if (await this.permissionService.isPersonManager()) { await this.getTeamRole(); + this.showTeamRole = canCreate || this.existTeamRole; } } @@ -74,22 +75,32 @@ export class TeamRoleComponent implements OnInit { * Load team role data and open details sidesheet */ public async onManageTeamRole(): Promise { + if (!this.teamRole.Uid) { + return; + } try { this.loadingState = true; - const roleItemCollection = await this.roleService.targetMap.get(this.orgTag).interactiveResp.Get_byid(this.teamRole.Uid); - const roleItem = roleItemCollection.Data[0].GetEntity(); + const roleItem = ( + await this.roleService.targetMap.get(this.orgTag)?.interactiveResp?.Get_byid(this.teamRole.Uid) + )?.Data[0].GetEntity(); + if (!roleItem) { + throw new Error('There was an error getting details about this role'); + } await this.setRoleData(roleItem); await this.dataManagementService.setInteractive(); - this.sidesheetService.open(RoleDetailComponent, { - title: this.translateService.instant('#LDS#Heading Edit Team Role'), - subTitle: roleItem.GetDisplay(), - padding: '0px', - width: 'max(768px, 80%)', - disableClose: true, - testId: `${this.orgTag}-role-detail-sidesheet`, - }).afterClosed().subscribe(() =>{ - this.getTeamRole(); - }) + this.sidesheetService + .open(RoleDetailComponent, { + title: this.translateService.instant('#LDS#Heading Edit Team Role'), + subTitle: roleItem.GetDisplay(), + padding: '0px', + width: calculateSidesheetWidth(1250, 0.7), + disableClose: true, + testId: `${this.orgTag}-role-detail-sidesheet`, + }) + .afterClosed() + .subscribe(() => { + this.getTeamRole(); + }); } finally { this.loadingState = false; } @@ -105,23 +116,26 @@ export class TeamRoleComponent implements OnInit { .open(RoleRecommendationsComponent, { title: this.translateService.instant('#LDS#Heading Create Team Role'), padding: '0px', - width: 'max(650px, 65%)', + width: calculateSidesheetWidth(1000), testId: 'role-recommendation-sidesheet', data: { recommendation: teamRoleRecommendOptions.Items || [], canEdit: true, infoText: - '#LDS#Here you can create a team role. To do this, select the entitlements that are currently assigned individually to the members of your team. This team role will then be automatically assigned to all members of your team (along with the previously mentioned entitlements).', + '#LDS#Here you can create a team role. To do this, select the entitlements that are currently assigned individually to the members of your team. After you have created the team role, the entitlements are added to your shopping cart and you must submit the request. This team role will then be automatically assigned to all members of your team (along with the aforementioned entitlements).', selectionTitle: '#LDS#Selected entitlements', submitButtonTitle: '#LDS#Create team role', actionColumnTitle: '#LDS#Distribution among the team', - hideActionConfirmation: true + hideActionConfirmation: true, + applyWithoutSelection: true, + noDataText: + '#LDS#Currently, no entitlements can be recommended. You can still create the team role and assign entitlements later.', }, }) .afterClosed() - .subscribe((result: RoleRecommendationResultItem[]) => { + .subscribe((result: { items: RoleRecommendationResultItem[] }) => { if (!!result) { - this.saveRecommendations(result); + this.saveRecommendations(result.items); } }); } finally { @@ -155,11 +169,19 @@ export class TeamRoleComponent implements OnInit { try { // It can take a moment for the team role to become visible over the ownerships API because of DBQUeue calculations. this.loadingState = true; - const collectionData = await this.rmbApiService.client.portal_resp_team_teamrole_post({ObjectKeys: resultItem.map(item => item.ObjectKey.value)}); + const collectionData = await this.rmbApiService.client.portal_resp_team_teamrole_post({ + ObjectKeys: resultItem.map((item) => item.ObjectKey.value), + }); // This entity represents the new team role. + if (!collectionData.Entities) { + throw new Error('There was an error posting this role recommendation'); + } const entity = new ReadOnlyEntity(PortalAdminRoleOrg.GetEntitySchema(), collectionData.Entities[0]); await this.setRoleData(entity); - await this.roleEntitlementActionService.addRecommendation(entity, resultItem); + const count = await this.roleEntitlementActionService.addRecommendation(entity, resultItem); + if (count > 0) { + this.snackbar.open({ key: '#LDS#The entitlement assignments have been successfully added to your shopping cart.' }, '#LDS#Close'); + } this.getTeamRole(); } finally { this.loadingState = false; @@ -170,7 +192,7 @@ export class TeamRoleComponent implements OnInit { * Set role service sidesheet data with the required params. * @param IEntity */ - private async setRoleData(entity: IEntity): Promise{ + private async setRoleData(entity: IEntity): Promise { const isAdmin = this.route.snapshot?.url[0]?.path === 'admin'; const isStructureAdmin = await this.permissionService.isStructAdmin(); this.roleService.setSidesheetData({ diff --git a/imxweb/projects/rmb/src/lib/team-role/team-role.module.ts b/imxweb/projects/rmb/src/lib/team-role/team-role.module.ts index 11179f705..8505a4d03 100644 --- a/imxweb/projects/rmb/src/lib/team-role/team-role.module.ts +++ b/imxweb/projects/rmb/src/lib/team-role/team-role.module.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -24,26 +24,16 @@ * */ -import { CommonModule } from "@angular/common"; -import { NgModule } from "@angular/core"; -import { EuiCoreModule, EuiMaterialModule } from "@elemental-ui/core"; -import { TranslateModule } from "@ngx-translate/core"; +import { CommonModule } from '@angular/common'; +import { NgModule } from '@angular/core'; +import { EuiCoreModule, EuiMaterialModule } from '@elemental-ui/core'; +import { TranslateModule } from '@ngx-translate/core'; import { TeamRoleComponent } from './team-role.component'; import { RoleManangementModule, TilesModule } from 'qer'; -import { FormsModule, ReactiveFormsModule } from "@angular/forms"; +import { FormsModule, ReactiveFormsModule } from '@angular/forms'; @NgModule({ - declarations: [ - TeamRoleComponent - ], - imports: [ - CommonModule, - EuiCoreModule, - EuiMaterialModule, - TranslateModule, - TilesModule, - FormsModule, - ReactiveFormsModule, - ] + declarations: [TeamRoleComponent], + imports: [CommonModule, EuiCoreModule, EuiMaterialModule, TranslateModule, TilesModule, FormsModule, ReactiveFormsModule], }) export class TeamRoleModule {} diff --git a/imxweb/projects/rmb/src/public_api.ts b/imxweb/projects/rmb/src/public_api.ts index 14c1b71fb..4c1c7e0de 100644 --- a/imxweb/projects/rmb/src/public_api.ts +++ b/imxweb/projects/rmb/src/public_api.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR diff --git a/imxweb/projects/rmb/src/test.ts b/imxweb/projects/rmb/src/test.ts index f7ac7d548..159c87d7d 100644 --- a/imxweb/projects/rmb/src/test.ts +++ b/imxweb/projects/rmb/src/test.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -26,24 +26,14 @@ // This file is required by karma.conf.js and loads recursively all the .spec and framework files -import 'core-js/es7/reflect'; -import 'zone.js/dist/zone'; -import 'zone.js/dist/zone-testing'; +// Zone must be imported first. Be careful with prettier import organizing +import 'zone.js'; +import 'zone.js/testing'; + import { getTestBed } from '@angular/core/testing'; -import { - BrowserDynamicTestingModule, - platformBrowserDynamicTesting -} from '@angular/platform-browser-dynamic/testing'; +import { BrowserDynamicTestingModule, platformBrowserDynamicTesting } from '@angular/platform-browser-dynamic/testing'; +import 'core-js/es/reflect'; import { TestHelperModule } from 'qbm'; -declare const require: any; - // First, initialize the Angular testing environment. -getTestBed().initTestEnvironment( - [BrowserDynamicTestingModule, TestHelperModule], - platformBrowserDynamicTesting() -); -// Then we find all the tests. -const context = require.context('./', true, /\.spec\.ts$/); -// And load the modules. -context.keys().map(context); +getTestBed().initTestEnvironment([BrowserDynamicTestingModule, TestHelperModule], platformBrowserDynamicTesting()); diff --git a/imxweb/projects/rmb/tsconfig.lib.json b/imxweb/projects/rmb/tsconfig.lib.json index 6bc419f84..534c734a0 100644 --- a/imxweb/projects/rmb/tsconfig.lib.json +++ b/imxweb/projects/rmb/tsconfig.lib.json @@ -1,16 +1,17 @@ /* To learn more about this file see: https://angular.io/config/tsconfig. */ { "extends": "../../tsconfig.json", + "angularCompilerOptions": { + "strictTemplates": true + }, "compilerOptions": { "outDir": "../../out-tsc/lib", + "strictNullChecks": true, "declaration": true, "declarationMap": true, "sourceMap": true, "inlineSources": true, "types": [] }, - "exclude": [ - "src/test.ts", - "**/*.spec.ts" - ] + "exclude": ["src/test.ts", "**/*.spec.ts"] } diff --git a/imxweb/projects/rmb/tsconfig.lib.prod.json b/imxweb/projects/rmb/tsconfig.lib.prod.json index 61c7592e7..fb40dbbb0 100644 --- a/imxweb/projects/rmb/tsconfig.lib.prod.json +++ b/imxweb/projects/rmb/tsconfig.lib.prod.json @@ -3,8 +3,5 @@ "extends": "./tsconfig.lib.json", "compilerOptions": { "declarationMap": false - }, - "angularCompilerOptions": { - "enableIvy": true } } diff --git a/imxweb/projects/rmb/tsconfig.spec.json b/imxweb/projects/rmb/tsconfig.spec.json index 16da33db0..6bd74e1f7 100644 --- a/imxweb/projects/rmb/tsconfig.spec.json +++ b/imxweb/projects/rmb/tsconfig.spec.json @@ -1,17 +1,10 @@ { "extends": "../../tsconfig.json", "compilerOptions": { + "strictNullChecks": false, "outDir": "../../out-tsc/spec", - "types": [ - "jasmine", - "node" - ] + "types": ["jasmine", "node"] }, - "files": [ - "src/test.ts" - ], - "include": [ - "**/*.spec.ts", - "**/*.d.ts" - ] + "files": ["src/test.ts"], + "include": ["**/*.spec.ts", "**/*.d.ts"] } diff --git a/imxweb/projects/rmb/tslint.json b/imxweb/projects/rmb/tslint.json deleted file mode 100644 index 8bab15f53..000000000 --- a/imxweb/projects/rmb/tslint.json +++ /dev/null @@ -1,17 +0,0 @@ -{ - "extends": "../../tslint.json", - "rules": { - "directive-selector": [ - true, - "attribute", - "imx", - "camelCase" - ], - "component-selector": [ - true, - "element", - "imx", - "kebab-case" - ] - } -} diff --git a/imxweb/projects/rms/.compodocrc.json b/imxweb/projects/rms/.compodocrc.json index 4c5abfeda..1201ca1f1 100644 --- a/imxweb/projects/rms/.compodocrc.json +++ b/imxweb/projects/rms/.compodocrc.json @@ -1,6 +1,6 @@ { "name": "IMX Web - RMS Library", - "output": "../../documentation/v92/rms", + "output": "../../documentation/v93/rms", "theme": "material", "assetsFolder": "../../compodoc/assets", "customLogo": "../../compodoc/assets/images/oneidentity-logo.png", diff --git a/imxweb/projects/rms/.eslintrc.json b/imxweb/projects/rms/.eslintrc.json new file mode 100644 index 000000000..b2cbe8700 --- /dev/null +++ b/imxweb/projects/rms/.eslintrc.json @@ -0,0 +1,35 @@ +{ + "extends": "../../.eslintrc.json", + "ignorePatterns": ["!**/*", "**/*.spec.ts"], + "overrides": [ + { + "files": ["*.ts"], + "parserOptions": { + "project": ["imxweb/projects/rms/tsconfig.lib.json", "imxweb/projects/rms/tsconfig.spec.json"], + "createDefaultProgram": true + }, + "rules": { + "@angular-eslint/directive-selector": [ + "error", + { + "type": "attribute", + "prefix": "imx", + "style": "camelCase" + } + ], + "@angular-eslint/component-selector": [ + "error", + { + "type": "element", + "prefix": "imx", + "style": "kebab-case" + } + ] + } + }, + { + "files": ["*.html"], + "rules": {} + } + ] +} diff --git a/imxweb/projects/rms/imx-plugin-config.json b/imxweb/projects/rms/imx-plugin-config.json index 7868825da..6499fc339 100644 --- a/imxweb/projects/rms/imx-plugin-config.json +++ b/imxweb/projects/rms/imx-plugin-config.json @@ -5,4 +5,4 @@ "Name": "RmsConfigModule" } ] -} \ No newline at end of file +} diff --git a/imxweb/projects/rms/karma.conf.js b/imxweb/projects/rms/karma.conf.js index 211193c9d..3e53a3ac8 100644 --- a/imxweb/projects/rms/karma.conf.js +++ b/imxweb/projects/rms/karma.conf.js @@ -15,7 +15,7 @@ module.exports = function (config) { require('karma-junit-reporter'), ], client: { - clearContext: false // leave Jasmine Spec Runner output visible in browser + clearContext: false, // leave Jasmine Spec Runner output visible in browser }, coverageIstanbulReporter: { dir: require('path').join(__dirname, 'results'), @@ -23,7 +23,7 @@ module.exports = function (config) { fixWebpackSourcePaths: true, 'report-config': { html: { - subdir: 'coverage-html' + subdir: 'coverage-html', }, }, thresholds: { @@ -40,13 +40,14 @@ module.exports = function (config) { port: 9876, captureTimeout: 210000, browserDisconnectTolerance: 3, - browserDisconnectTimeout : 210000, - browserNoActivityTimeout : 210000, + browserDisconnectTimeout: 210000, + browserNoActivityTimeout: 210000, colors: true, logLevel: config.LOG_INFO, autoWatch: true, browsers: ['Chrome'], singleRun: false, - restartOnFileChange: true + failOnEmptyTestSuite: false, + restartOnFileChange: true, }); }; diff --git a/imxweb/projects/rms/ng-package.dynamic.json b/imxweb/projects/rms/ng-package.dynamic.json index 5b3ce79a3..59353c540 100644 --- a/imxweb/projects/rms/ng-package.dynamic.json +++ b/imxweb/projects/rms/ng-package.dynamic.json @@ -16,12 +16,11 @@ "@elemental-ui/core", "@ngx-translate/core", "@ngx-translate/http-loader", - "applicationinsights-js", "billboard.js" ], - "dest": "../../html/rms", + "dest": "../../html/qer-app-portal/rms", "lib": { "entryFile": "src/public_api.ts", - "styleIncludePaths": ["../../shared/assets"] + "styleIncludePaths": ["../../shared/scss"] } } diff --git a/imxweb/projects/rms/ng-package.json b/imxweb/projects/rms/ng-package.json index 83d381811..2aecf77cf 100644 --- a/imxweb/projects/rms/ng-package.json +++ b/imxweb/projects/rms/ng-package.json @@ -3,6 +3,6 @@ "dest": "../../dist/rms", "lib": { "entryFile": "src/public_api.ts", - "styleIncludePaths": ["../../shared/assets"] + "styleIncludePaths": ["../../shared/scss"] } } diff --git a/imxweb/projects/rms/package.json b/imxweb/projects/rms/package.json index 5fd9bf564..8e0d653df 100644 --- a/imxweb/projects/rms/package.json +++ b/imxweb/projects/rms/package.json @@ -1,6 +1,6 @@ { "name": "rms", - "version": "9.2.1", + "version": "9.3.0", "private": true, "bundledDependencies": [ "imx-api-rms" diff --git a/imxweb/projects/rms/project.json b/imxweb/projects/rms/project.json new file mode 100644 index 000000000..493ba4126 --- /dev/null +++ b/imxweb/projects/rms/project.json @@ -0,0 +1,64 @@ +{ + "$schema": "../../node_modules/nx/schemas/project-schema.json", + "name": "rms", + "sourceRoot": "projects/rms/src", + "implicitDependencies": ["qer"], + "projectType": "library", + "prefix": "imx", + "generators": { + "@schematics/angular:component": { + "style": "scss" + } + }, + "targets": { + "build": { + "executor": "@angular-devkit/build-angular:ng-packagr", + "options": { + "tsConfig": "projects/rms/tsconfig.lib.json", + "project": "projects/rms/ng-package.json" + }, + "configurations": { + "production": { + "tsConfig": "projects/rms/tsconfig.lib.prod.json" + }, + "development": { + "tsConfig": "projects/rms/tsconfig.lib.json" + }, + "dynamic": { + "project": "projects/rms/ng-package.dynamic.json" + }, + "remote-dev": { + "tsConfig": "projects/rms/tsconfig.lib.json" + }, + "remote-qs": { + "tsConfig": "projects/rms/tsconfig.lib.json" + } + }, + "outputs": ["{workspaceRoot}/dist/rms"] + }, + "test": { + "executor": "@angular-devkit/build-angular:karma", + "options": { + "main": "projects/rms/src/test.ts", + "tsConfig": "projects/rms/tsconfig.spec.json", + "karmaConfig": "projects/rms/karma.conf.js", + "stylePreprocessorOptions": { + "includePaths": [ + "./shared/assets", + "./shared/scss", + "./node_modules", + "./node_modules/@elemental-ui/cadence-icon", + "./node_modules/@elemental-ui/core" + ] + } + } + }, + "lint": { + "executor": "@angular-devkit/build-angular:tslint", + "options": { + "tsConfig": ["projects/rms/tsconfig.lib.json", "projects/rms/tsconfig.spec.json"], + "exclude": ["**/node_modules/**", "**/*.spec.ts", "**/*.json"] + } + } + } +} diff --git a/imxweb/projects/rms/src/lib/eset-data-model.ts b/imxweb/projects/rms/src/lib/eset-data-model.ts index 64e2c121a..1decea492 100644 --- a/imxweb/projects/rms/src/lib/eset-data-model.ts +++ b/imxweb/projects/rms/src/lib/eset-data-model.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -24,18 +24,15 @@ * */ -import { FilterData, DataModel } from 'imx-qbm-dbts'; +import { FilterData, DataModel } from '@imx-modules/imx-qbm-dbts'; import { IRoleDataModel } from 'qer'; import { RmsApiService } from './rms-api-client.service'; export class EsetDataModel implements IRoleDataModel { - - constructor( - private readonly api: RmsApiService - ) { } + constructor(private readonly api: RmsApiService) {} public async getModel(filter: FilterData[], isAdmin: boolean): Promise { - return isAdmin ? - this.api.client.portal_admin_role_eset_datamodel_get({ filter: filter }) + return isAdmin + ? this.api.client.portal_admin_role_eset_datamodel_get({ filter: filter }) : this.api.client.portal_resp_eset_datamodel_get({ filter: filter }); } } diff --git a/imxweb/projects/rms/src/lib/eset-entitlements.ts b/imxweb/projects/rms/src/lib/eset-entitlements.ts index 34c666ea2..5972c09ac 100644 --- a/imxweb/projects/rms/src/lib/eset-entitlements.ts +++ b/imxweb/projects/rms/src/lib/eset-entitlements.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -24,34 +24,44 @@ * */ -import { RoleAssignmentData } from "imx-api-qer"; -import { CollectionLoadParameters, CompareOperator, ExtendedTypedEntityCollection, FilterType, IEntity, TypedEntity } from "imx-qbm-dbts"; -import { DynamicMethodService, GenericTypedEntity, ImxTranslationProviderService } from "qbm"; -import { IRoleEntitlements } from "qer"; -import { RmsApiService } from "./rms-api-client.service"; +import { RoleAssignmentData } from '@imx-modules/imx-api-qer'; +import { + CollectionLoadParameters, + CompareOperator, + ExtendedTypedEntityCollection, + FilterType, + IEntity, + TypedEntity, +} from '@imx-modules/imx-qbm-dbts'; +import { ImxTranslationProviderService } from 'qbm'; +import { IRoleEntitlements } from 'qer'; +import { RmsApiService } from './rms-api-client.service'; export class EsetEntitlements implements IRoleEntitlements { + public entitlementFkName = 'Entitlement'; // column name in ESetHasEntitlement + constructor( private readonly api: RmsApiService, - private readonly dynamicMethodSvc: DynamicMethodService, - protected readonly translator: ImxTranslationProviderService + protected readonly translator: ImxTranslationProviderService, ) {} public async getCollection( id: string, navigationState?: CollectionLoadParameters, - objectKeyForFiltering?: string + objectKeyForFiltering?: string, ): Promise> { - return await this.api.typedClient.PortalRolesConfigEntitlementsEset.Get(id, { + return this.api.typedClient.PortalRolesConfigEntitlementsEset.Get(id, { ...navigationState, - filter: objectKeyForFiltering ? [ - { - ColumnName: 'Entitlement', - CompareOp: CompareOperator.Equal, - Type: FilterType.Compare, - Value1: objectKeyForFiltering, - }, - ] : undefined, + filter: objectKeyForFiltering + ? [ + { + ColumnName: 'Entitlement', + CompareOp: CompareOperator.Equal, + Type: FilterType.Compare, + Value1: objectKeyForFiltering, + }, + ] + : undefined, }); } @@ -59,26 +69,13 @@ export class EsetEntitlements implements IRoleEntitlements { return this.api.client.portal_roles_config_classes_ESet_get(); } - public getEntitlementFkName() { - return 'Entitlement'; // column name in ESetHasEntitlement - } - async delete(roleId: string, entity: IEntity): Promise { const esethasentl = entity.GetKeys()[0]; await this.api.client.portal_roles_config_entitlements_ESet_delete(roleId, esethasentl); } - public createEntitlementAssignmentEntity(role: IEntity, entlType: RoleAssignmentData): IEntity { + public createEntitlementAssignmentEntity(role: IEntity): IEntity { const uidESet = role.GetKeys()[0]; - const entityColl = this.dynamicMethodSvc.createEntity( - this.api.apiClient, - { - path: '/portal/roles/config/entitlements/ESet/' + uidESet, - type: GenericTypedEntity, - schemaPath: 'portal/roles/config/entitlements/ESet/{' + entlType.RoleFk + '}', - }, - { Columns: { UID_ESet: { Value: uidESet } } } - ); - return entityColl.Data[0].GetEntity(); + return this.api.typedClient.PortalRolesConfigEntitlementsEset.createEntity({ Columns: { UID_ESet: { Value: uidESet } } }).GetEntity(); } -} \ No newline at end of file +} diff --git a/imxweb/projects/rms/src/lib/eset-membership.ts b/imxweb/projects/rms/src/lib/eset-membership.ts index 3525af436..df14725d9 100644 --- a/imxweb/projects/rms/src/lib/eset-membership.ts +++ b/imxweb/projects/rms/src/lib/eset-membership.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -24,63 +24,27 @@ * */ -import { CollectionLoadParameters, ExtendedTypedEntityCollection, TypedEntity, EntityCollectionData, EntitySchema, IEntity, DataModel } from 'imx-qbm-dbts'; -import { IRoleMembershipType } from 'qer'; -import { DynamicMethod, ImxTranslationProviderService, imx_SessionService } from 'qbm'; +import { + CollectionLoadParameters, + EntityCollectionData, + EntitySchema, + ExtendedTypedEntityCollection, + TypedEntity, +} from '@imx-modules/imx-qbm-dbts'; +import { ImxTranslationProviderService, imx_SessionService } from 'qbm'; +import { BaseMembership } from 'qer'; import { RmsApiService } from './rms-api-client.service'; -export class EsetMembership implements IRoleMembershipType { - +export class EsetMembership extends BaseMembership { public supportsDynamicMemberships = false; - private readonly schemaPaths: Map = new Map(); - - private readonly basePath = 'portal/roles/config/membership/ESet'; constructor( private readonly api: RmsApiService, private readonly session: imx_SessionService, - private readonly translator: ImxTranslationProviderService + private readonly translator: ImxTranslationProviderService, ) { - this.schemaPaths.set('get', `${this.basePath}/{UID_ESet}`); - this.schemaPaths.set('candidates', `${this.basePath}/{UID_ESet}/UID_Person/candidates`); - } - - public async get(id: string, navigationState?: CollectionLoadParameters): Promise> { - return this.api.typedClient.PortalRolesConfigMembershipEset.Get(id, navigationState); - } - - public getSchema(key: string): EntitySchema { - return this.session.Client.getSchema(this.schemaPaths.get(key)); - } - - public GetUidPerson(entity: IEntity) { - return entity.GetColumn('UID_Person').GetValue(); - } - - public async getCandidates( - id: string, - navigationState?: CollectionLoadParameters - ): Promise> { - const api = new DynamicMethod( - this.schemaPaths.get('candidates'), - `/${this.basePath}/${id}/UID_Person/candidates`, - this.api.apiClient, - this.session, - this.translator - ); - - return api.Get(navigationState); - } - - public async getCandidatesDataModel(id: string): Promise { - const dynamicMethod = new DynamicMethod( - this.schemaPaths.get('candidates'), - `/${this.basePath}/${id}/UID_Person/candidates`, - this.api.apiClient, - this.session, - this.translator - ); - return dynamicMethod.getDataModei(); + super(api, session, translator); + this.setRoleName('ESet', 'UID_ESet'); } public async delete(role: string, identity: string): Promise { @@ -91,13 +55,9 @@ export class EsetMembership implements IRoleMembershipType { return false; } - public GetUidRole(entity: IEntity): string { - return entity.GetColumn("UID_ESet").GetValue(); - } - public getPrimaryMembers( uid: string, - navigationstate: CollectionLoadParameters + navigationstate: CollectionLoadParameters, ): Promise> { throw new Error('System roles do not allow primary memberships.'); } diff --git a/imxweb/projects/rms/src/lib/init.service.ts b/imxweb/projects/rms/src/lib/init.service.ts index 27872d642..78c83d602 100644 --- a/imxweb/projects/rms/src/lib/init.service.ts +++ b/imxweb/projects/rms/src/lib/init.service.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -26,20 +26,21 @@ import { Injectable } from '@angular/core'; import { Route, Router } from '@angular/router'; -import { RoleExtendedDataWrite } from 'imx-api-qer'; +import { RoleExtendedDataWrite } from '@imx-modules/imx-api-qer'; -import { PortalAdminRoleEset, PortalPersonRolemembershipsEset, PortalRespEset, V2ApiClientMethodFactory } from 'imx-api-rms'; +import { ProjectConfig } from '@imx-modules/imx-api-qbm'; +import { PortalAdminRoleEset, PortalPersonRolemembershipsEset, PortalRespEset, V2ApiClientMethodFactory } from '@imx-modules/imx-api-rms'; import { + CollectionLoadParameters, + EntityCollectionData, EntitySchema, ExtendedTypedEntityCollection, + MethodDefinition, + MethodDescriptor, TypedEntity, WriteExtTypedEntity, - CollectionLoadParameters, - MethodDescriptor, - EntityCollectionData, - MethodDefinition, -} from 'imx-qbm-dbts'; -import { DynamicMethodService, ImxTranslationProviderService, imx_SessionService, MenuService, HELP_CONTEXTUAL } from 'qbm'; +} from '@imx-modules/imx-qbm-dbts'; +import { HELP_CONTEXTUAL, ImxTranslationProviderService, MenuService, imx_SessionService } from 'qbm'; import { DataExplorerRegistryService, IdentityRoleMembershipsService, @@ -54,13 +55,6 @@ import { EsetDataModel } from './eset-data-model'; import { EsetEntitlements } from './eset-entitlements'; import { EsetMembership } from './eset-membership'; import { RmsApiService } from './rms-api-client.service'; -import { ProjectConfig } from 'imx-api-qbm'; - -export interface test { - GetSchema(): EntitySchema; - Get_byid(id: string): Promise>; - Get(): Promise>; -} @Injectable({ providedIn: 'root' }) export class InitService { @@ -71,26 +65,25 @@ export class InitService { private readonly api: RmsApiService, private readonly session: imx_SessionService, private readonly translator: ImxTranslationProviderService, - private readonly dynamicMethodSvc: DynamicMethodService, private readonly dataExplorerRegistryService: DataExplorerRegistryService, private readonly menuService: MenuService, private readonly roleService: RoleService, private readonly identityRoleMembershipService: IdentityRoleMembershipsService, - private readonly myResponsibilitiesRegistryService: MyResponsibilitiesRegistryService + private readonly myResponsibilitiesRegistryService: MyResponsibilitiesRegistryService, ) {} public onInit(routes: Route[]): void { this.addRoutes(routes); // wrapper class for interactive methods - // tslint:disable-next-line: max-classes-per-file + // eslint-disable-next-line max-classes-per-file class ApiWrapper { constructor( private getByIdApi: { GetSchema(): EntitySchema; Get_byid(id: string): Promise>; Get?(): Promise>; - } + }, ) {} public async Get(): Promise, unknown>> { @@ -136,15 +129,20 @@ export class InitService { search: parameter.search, risk: parameter.risk, esettype: parameter.esettype, + withProperties: parameter.withProperties, }), }, adminSchema: this.api.typedClient.PortalAdminRoleEset.GetSchema(), dataModel: new EsetDataModel(this.api), - respCanCreate: false, - adminCanCreate: true, + adminCanCreate: async () => { + return (await this.api.client.portal_roles_config_systemroles_get()).EnableNewESet; + }, + respCanCreate: async () => { + return (await this.api.client.portal_roles_config_systemroles_get()).EnableNewESet; + }, interactiveResp: new ApiWrapper(this.api.typedClient.PortalRespEsetInteractive), interactiveAdmin: new ApiWrapper(this.api.typedClient.PortalAdminRoleEsetInteractive), - entitlements: new EsetEntitlements(this.api, this.dynamicMethodSvc, this.translator), + entitlements: new EsetEntitlements(this.api, this.translator), membership: new EsetMembership(this.api, this.session, this.translator), canUseRecommendations: true, exportMethod: (navigationState: CollectionLoadParameters, isAdmin: boolean) => { @@ -171,6 +169,8 @@ export class InitService { editHeading: '#LDS#Heading Edit System Role', createSnackbar: '#LDS#The system role has been successfully created.', }, + adminHelpContextId: HELP_CONTEXTUAL.DataExplorerSystemRolesRoleEntitlements, + respHelpContextId: HELP_CONTEXTUAL.MyResponsibilitiesSystemRolesRoleEntitlements, }); this.identityRoleMembershipService.addTarget({ @@ -190,8 +190,8 @@ export class InitService { this.dataExplorerRegistryService.registerFactory( (preProps: string[], features: string[], projectConfig: ProjectConfig, groups: string[]) => { - if (!isRoleAdmin(features) && !isRoleStatistics(features) && !isAuditor(groups)) { - return; + if (isRoleAdmin(features) && !isRoleStatistics(features) && !isAuditor(groups)) { + return undefined; } return { instance: RolesOverviewComponent, @@ -204,7 +204,7 @@ export class InitService { name: 'systemroles', caption: '#LDS#Menu Entry System roles', }; - } + }, ); this.myResponsibilitiesRegistryService.registerFactory((preProps: string[], features: string[]) => ({ @@ -223,7 +223,7 @@ export class InitService { private setupMenu(): void { this.menuService.addMenuFactories((preProps: string[], features: string[], projectConfig: ProjectConfig, groups: string[]) => { if (!isRoleAdmin(features) && !isRoleStatistics(features) && !isAuditor(groups)) { - return null; + return undefined; } return { id: 'ROOT_Data', diff --git a/imxweb/projects/rms/src/lib/requestable-systemrole-type.ts b/imxweb/projects/rms/src/lib/requestable-systemrole-type.ts index 6760760c3..6fbc69f56 100644 --- a/imxweb/projects/rms/src/lib/requestable-systemrole-type.ts +++ b/imxweb/projects/rms/src/lib/requestable-systemrole-type.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -24,25 +24,25 @@ * */ -import { EntitySchema, TypedEntity } from "imx-qbm-dbts"; -import { IRequestableEntitlementType } from "qer"; -import { DynamicMethodService, GenericTypedEntity } from "qbm"; -import { RmsApiService } from "./rms-api-client.service"; +import { EntitySchema, TypedEntity } from '@imx-modules/imx-qbm-dbts'; +import { DynamicMethodService, GenericTypedEntity } from 'qbm'; +import { IRequestableEntitlementType } from 'qer'; +import { RmsApiService } from './rms-api-client.service'; export class RequestableSystemRoleType implements IRequestableEntitlementType { - - constructor(private readonly dynamicMethodService: DynamicMethodService, - private readonly rmsApi: RmsApiService + constructor( + private readonly dynamicMethodService: DynamicMethodService, + private readonly rmsApi: RmsApiService, ) { this.schema = this.createAssignmentEntity('dummy').GetEntity().GetSchema(); } getTableName() { - return "ESet"; + return 'ESet'; } getFkColumnName() { - return "UID_ESet"; + return 'UID_ESet'; } private schema: EntitySchema; @@ -52,27 +52,35 @@ export class RequestableSystemRoleType implements IRequestableEntitlementType { } public addEntitlementSelections(shelfId: string, values: string[]): Promise { - const promises = []; - values.forEach(value => { + const promises: Promise[] = []; + values.forEach((value) => { const e = this.createAssignmentEntity(shelfId).GetEntity(); - promises.push(e.GetColumn(this.getFkColumnName()).PutValue(value) - .then(() => e.Commit())); + promises.push( + e + .GetColumn(this.getFkColumnName()) + .PutValue(value) + .then(() => e.Commit()), + ); }); return Promise.all(promises); } public createAssignmentEntity(shelfId: string): TypedEntity { - const entityColl = this.dynamicMethodService.createEntity(this.rmsApi.apiClient, { - path: '/portal/shop/config/entitlements/' + shelfId + '/' + this.getTableName(), - type: GenericTypedEntity, - schemaPath: 'portal/shop/config/entitlements/{UID_ITShopOrg}/' + this.getTableName(), - }, { - Columns: { - "UID_ITShopOrg": { - Value: shelfId - } - } - }); + const entityColl = this.dynamicMethodService.createEntity( + this.rmsApi.apiClient, + { + path: '/portal/shop/config/entitlements/' + shelfId + '/' + this.getTableName(), + type: GenericTypedEntity, + schemaPath: 'portal/shop/config/entitlements/{UID_ITShopOrg}/' + this.getTableName(), + }, + { + Columns: { + UID_ITShopOrg: { + Value: shelfId, + }, + }, + }, + ); return entityColl.Data[0]; } -} \ No newline at end of file +} diff --git a/imxweb/projects/rms/src/lib/rms-api-client.service.ts b/imxweb/projects/rms/src/lib/rms-api-client.service.ts index 5a722334e..ca3a21db5 100644 --- a/imxweb/projects/rms/src/lib/rms-api-client.service.ts +++ b/imxweb/projects/rms/src/lib/rms-api-client.service.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -25,14 +25,14 @@ */ import { Injectable } from '@angular/core'; -import { V2Client, TypedClient } from 'imx-api-rms'; -import { ApiClient } from 'imx-qbm-dbts'; +import { V2Client, TypedClient } from '@imx-modules/imx-api-rms'; +import { ApiClient } from '@imx-modules/imx-qbm-dbts'; import { AppConfigService, ClassloggerService, DynamicMethodService, ImxTranslationProviderService } from 'qbm'; import { IRequestableEntitlementType, RequestableEntitlementTypeService } from 'qer'; import { RequestableSystemRoleType } from './requestable-systemrole-type'; @Injectable({ - providedIn: 'root' + providedIn: 'root', }) export class RmsApiService { private tc: TypedClient; @@ -54,7 +54,8 @@ export class RmsApiService { private readonly logger: ClassloggerService, private readonly entlTypeService: RequestableEntitlementTypeService, private readonly dynamicMethodService: DynamicMethodService, - private readonly translationProvider: ImxTranslationProviderService) { + private readonly translationProvider: ImxTranslationProviderService, + ) { try { this.logger.debug(this, 'Initializing RMS API service'); @@ -63,7 +64,7 @@ export class RmsApiService { this.c = new V2Client(this.config.apiClient, schemaProvider); this.tc = new TypedClient(this.c, this.translationProvider); - this.entlTypeService.Register(() => this.GetSystemRoleType()) + this.entlTypeService.Register(() => this.GetSystemRoleType()); } catch (e) { this.logger.error(this, e); } diff --git a/imxweb/projects/rms/src/lib/rms-config.module.ts b/imxweb/projects/rms/src/lib/rms-config.module.ts index 05cd20540..fc09a8c6f 100644 --- a/imxweb/projects/rms/src/lib/rms-config.module.ts +++ b/imxweb/projects/rms/src/lib/rms-config.module.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -29,13 +29,10 @@ import { Routes, RouterModule } from '@angular/router'; import { InitService } from './init.service'; -const routes: Routes = [ -]; +const routes: Routes = []; @NgModule({ - imports: [ - RouterModule.forChild(routes) - ] + imports: [RouterModule.forChild(routes)], }) export class RmsConfigModule { constructor(private readonly initializer: InitService) { diff --git a/imxweb/projects/rms/src/public_api.ts b/imxweb/projects/rms/src/public_api.ts index 8e00308c2..01293fbd3 100644 --- a/imxweb/projects/rms/src/public_api.ts +++ b/imxweb/projects/rms/src/public_api.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR diff --git a/imxweb/projects/rms/src/test.ts b/imxweb/projects/rms/src/test.ts index f7ac7d548..159c87d7d 100644 --- a/imxweb/projects/rms/src/test.ts +++ b/imxweb/projects/rms/src/test.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -26,24 +26,14 @@ // This file is required by karma.conf.js and loads recursively all the .spec and framework files -import 'core-js/es7/reflect'; -import 'zone.js/dist/zone'; -import 'zone.js/dist/zone-testing'; +// Zone must be imported first. Be careful with prettier import organizing +import 'zone.js'; +import 'zone.js/testing'; + import { getTestBed } from '@angular/core/testing'; -import { - BrowserDynamicTestingModule, - platformBrowserDynamicTesting -} from '@angular/platform-browser-dynamic/testing'; +import { BrowserDynamicTestingModule, platformBrowserDynamicTesting } from '@angular/platform-browser-dynamic/testing'; +import 'core-js/es/reflect'; import { TestHelperModule } from 'qbm'; -declare const require: any; - // First, initialize the Angular testing environment. -getTestBed().initTestEnvironment( - [BrowserDynamicTestingModule, TestHelperModule], - platformBrowserDynamicTesting() -); -// Then we find all the tests. -const context = require.context('./', true, /\.spec\.ts$/); -// And load the modules. -context.keys().map(context); +getTestBed().initTestEnvironment([BrowserDynamicTestingModule, TestHelperModule], platformBrowserDynamicTesting()); diff --git a/imxweb/projects/rms/tsconfig.lib.json b/imxweb/projects/rms/tsconfig.lib.json index 6bc419f84..534c734a0 100644 --- a/imxweb/projects/rms/tsconfig.lib.json +++ b/imxweb/projects/rms/tsconfig.lib.json @@ -1,16 +1,17 @@ /* To learn more about this file see: https://angular.io/config/tsconfig. */ { "extends": "../../tsconfig.json", + "angularCompilerOptions": { + "strictTemplates": true + }, "compilerOptions": { "outDir": "../../out-tsc/lib", + "strictNullChecks": true, "declaration": true, "declarationMap": true, "sourceMap": true, "inlineSources": true, "types": [] }, - "exclude": [ - "src/test.ts", - "**/*.spec.ts" - ] + "exclude": ["src/test.ts", "**/*.spec.ts"] } diff --git a/imxweb/projects/rms/tsconfig.lib.prod.json b/imxweb/projects/rms/tsconfig.lib.prod.json index 61c7592e7..fb40dbbb0 100644 --- a/imxweb/projects/rms/tsconfig.lib.prod.json +++ b/imxweb/projects/rms/tsconfig.lib.prod.json @@ -3,8 +3,5 @@ "extends": "./tsconfig.lib.json", "compilerOptions": { "declarationMap": false - }, - "angularCompilerOptions": { - "enableIvy": true } } diff --git a/imxweb/projects/rms/tsconfig.spec.json b/imxweb/projects/rms/tsconfig.spec.json index 16da33db0..6bd74e1f7 100644 --- a/imxweb/projects/rms/tsconfig.spec.json +++ b/imxweb/projects/rms/tsconfig.spec.json @@ -1,17 +1,10 @@ { "extends": "../../tsconfig.json", "compilerOptions": { + "strictNullChecks": false, "outDir": "../../out-tsc/spec", - "types": [ - "jasmine", - "node" - ] + "types": ["jasmine", "node"] }, - "files": [ - "src/test.ts" - ], - "include": [ - "**/*.spec.ts", - "**/*.d.ts" - ] + "files": ["src/test.ts"], + "include": ["**/*.spec.ts", "**/*.d.ts"] } diff --git a/imxweb/projects/rms/tslint.json b/imxweb/projects/rms/tslint.json deleted file mode 100644 index 8bab15f53..000000000 --- a/imxweb/projects/rms/tslint.json +++ /dev/null @@ -1,17 +0,0 @@ -{ - "extends": "../../tslint.json", - "rules": { - "directive-selector": [ - true, - "attribute", - "imx", - "camelCase" - ], - "component-selector": [ - true, - "element", - "imx", - "kebab-case" - ] - } -} diff --git a/imxweb/projects/rps/.compodocrc.json b/imxweb/projects/rps/.compodocrc.json index 3515829fd..30423db42 100644 --- a/imxweb/projects/rps/.compodocrc.json +++ b/imxweb/projects/rps/.compodocrc.json @@ -1,6 +1,6 @@ { "name": "IMX Web - RPS Library", - "output": "../../documentation/v92/rps", + "output": "../../documentation/v93/rps", "theme": "material", "assetsFolder": "../../compodoc/assets", "customLogo": "../../compodoc/assets/images/oneidentity-logo.png", diff --git a/imxweb/projects/rps/.eslintrc.json b/imxweb/projects/rps/.eslintrc.json new file mode 100644 index 000000000..4bddb1138 --- /dev/null +++ b/imxweb/projects/rps/.eslintrc.json @@ -0,0 +1,35 @@ +{ + "extends": "../../.eslintrc.json", + "ignorePatterns": ["!**/*", "**/*.spec.ts"], + "overrides": [ + { + "files": ["*.ts"], + "parserOptions": { + "project": ["imxweb/projects/rps/tsconfig.lib.json", "imxweb/projects/rps/tsconfig.spec.json"], + "createDefaultProgram": true + }, + "rules": { + "@angular-eslint/directive-selector": [ + "error", + { + "type": "attribute", + "prefix": "imx", + "style": "camelCase" + } + ], + "@angular-eslint/component-selector": [ + "error", + { + "type": "element", + "prefix": "imx", + "style": "kebab-case" + } + ] + } + }, + { + "files": ["*.html"], + "rules": {} + } + ] +} diff --git a/imxweb/projects/rps/imx-plugin-config.json b/imxweb/projects/rps/imx-plugin-config.json index 520f0e43c..c2b844e89 100644 --- a/imxweb/projects/rps/imx-plugin-config.json +++ b/imxweb/projects/rps/imx-plugin-config.json @@ -1,8 +1,8 @@ { "qer-app-portal": [ - { - "Container": "rps", - "Name": "RpsConfigModule" - } + { + "Container": "rps", + "Name": "RpsConfigModule" + } ] } diff --git a/imxweb/projects/rps/karma.conf.js b/imxweb/projects/rps/karma.conf.js index 211193c9d..3e53a3ac8 100644 --- a/imxweb/projects/rps/karma.conf.js +++ b/imxweb/projects/rps/karma.conf.js @@ -15,7 +15,7 @@ module.exports = function (config) { require('karma-junit-reporter'), ], client: { - clearContext: false // leave Jasmine Spec Runner output visible in browser + clearContext: false, // leave Jasmine Spec Runner output visible in browser }, coverageIstanbulReporter: { dir: require('path').join(__dirname, 'results'), @@ -23,7 +23,7 @@ module.exports = function (config) { fixWebpackSourcePaths: true, 'report-config': { html: { - subdir: 'coverage-html' + subdir: 'coverage-html', }, }, thresholds: { @@ -40,13 +40,14 @@ module.exports = function (config) { port: 9876, captureTimeout: 210000, browserDisconnectTolerance: 3, - browserDisconnectTimeout : 210000, - browserNoActivityTimeout : 210000, + browserDisconnectTimeout: 210000, + browserNoActivityTimeout: 210000, colors: true, logLevel: config.LOG_INFO, autoWatch: true, browsers: ['Chrome'], singleRun: false, - restartOnFileChange: true + failOnEmptyTestSuite: false, + restartOnFileChange: true, }); }; diff --git a/imxweb/projects/rps/ng-package.dynamic.json b/imxweb/projects/rps/ng-package.dynamic.json index 999b58e82..eec3ee75f 100644 --- a/imxweb/projects/rps/ng-package.dynamic.json +++ b/imxweb/projects/rps/ng-package.dynamic.json @@ -16,12 +16,11 @@ "@elemental-ui/core", "@ngx-translate/core", "@ngx-translate/http-loader", - "applicationinsights-js", "billboard.js" ], - "dest": "../../html/rps", + "dest": "../../html/qer-app-portal/rps", "lib": { "entryFile": "src/public_api.ts", - "styleIncludePaths": ["../../shared/assets"] + "styleIncludePaths": ["../../shared/scss"] } } diff --git a/imxweb/projects/rps/ng-package.json b/imxweb/projects/rps/ng-package.json index e3eda4426..ca8402cfe 100644 --- a/imxweb/projects/rps/ng-package.json +++ b/imxweb/projects/rps/ng-package.json @@ -3,6 +3,6 @@ "dest": "../../dist/rps", "lib": { "entryFile": "src/public_api.ts", - "styleIncludePaths": ["../../shared/assets"] + "styleIncludePaths": ["../../shared/scss"] } } diff --git a/imxweb/projects/rps/package.json b/imxweb/projects/rps/package.json index aef856677..7e051f677 100644 --- a/imxweb/projects/rps/package.json +++ b/imxweb/projects/rps/package.json @@ -1,6 +1,6 @@ { "name": "rps", - "version": "9.2.1", + "version": "9.3.0", "private": true, "bundledDependencies": [ "imx-api-rps" diff --git a/imxweb/projects/rps/project.json b/imxweb/projects/rps/project.json new file mode 100644 index 000000000..21c5ed937 --- /dev/null +++ b/imxweb/projects/rps/project.json @@ -0,0 +1,64 @@ +{ + "$schema": "../../node_modules/nx/schemas/project-schema.json", + "name": "rps", + "sourceRoot": "projects/rps/src", + "implicitDependencies": ["qer"], + "projectType": "library", + "generators": { + "@schematics/angular:component": { + "style": "scss" + } + }, + "prefix": "imx", + "targets": { + "build": { + "executor": "@angular-devkit/build-angular:ng-packagr", + "options": { + "tsConfig": "projects/rps/tsconfig.lib.json", + "project": "projects/rps/ng-package.json" + }, + "configurations": { + "production": { + "tsConfig": "projects/rps/tsconfig.lib.prod.json" + }, + "development": { + "tsConfig": "projects/rps/tsconfig.lib.json" + }, + "dynamic": { + "project": "projects/rps/ng-package.dynamic.json" + }, + "remote-dev": { + "tsConfig": "projects/rps/tsconfig.lib.json" + }, + "remote-qs": { + "tsConfig": "projects/rps/tsconfig.lib.json" + } + }, + "outputs": ["{workspaceRoot}/dist/rps"] + }, + "test": { + "executor": "@angular-devkit/build-angular:karma", + "options": { + "main": "projects/rps/src/test.ts", + "tsConfig": "projects/rps/tsconfig.spec.json", + "karmaConfig": "projects/rps/karma.conf.js", + "stylePreprocessorOptions": { + "includePaths": [ + "./shared/assets", + "./shared/scss", + "./node_modules", + "./node_modules/@elemental-ui/cadence-icon", + "./node_modules/@elemental-ui/core" + ] + } + } + }, + "lint": { + "executor": "@angular-devkit/build-angular:tslint", + "options": { + "tsConfig": ["projects/rps/tsconfig.lib.json", "projects/rps/tsconfig.spec.json"], + "exclude": ["**/node_modules/**", "**/*.spec.ts", "**/*.json"] + } + } + } +} diff --git a/imxweb/projects/rps/src/lib/admin/permissions-helper.ts b/imxweb/projects/rps/src/lib/admin/permissions-helper.ts index 054f9fc5e..3e8ac6e4a 100644 --- a/imxweb/projects/rps/src/lib/admin/permissions-helper.ts +++ b/imxweb/projects/rps/src/lib/admin/permissions-helper.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -24,6 +24,6 @@ * */ -export function isRpsAdmin(groups: string[]): boolean { - return groups.find(item => item === 'vi_4_RPSADMIN_ADMIN') != null; +export function isRpsAdmin(groups: (string | undefined)[]): boolean { + return groups.find((item) => item === 'vi_4_RPSADMIN_ADMIN') != null; } diff --git a/imxweb/projects/rps/src/lib/admin/rps-permissions.service.ts b/imxweb/projects/rps/src/lib/admin/rps-permissions.service.ts index e4ff5e57a..13708ab0c 100644 --- a/imxweb/projects/rps/src/lib/admin/rps-permissions.service.ts +++ b/imxweb/projects/rps/src/lib/admin/rps-permissions.service.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -30,13 +30,12 @@ import { UserModelService } from 'qer'; import { isRpsAdmin } from './permissions-helper'; @Injectable({ - providedIn: 'root' + providedIn: 'root', }) export class RpsPermissionsService { - constructor(private readonly userService: UserModelService) { } + constructor(private readonly userService: UserModelService) {} public async isRpsAdmin(): Promise { - return isRpsAdmin((await this.userService.getGroups()).map(group => group.Name)); + return isRpsAdmin((await this.userService.getGroups()).map((group) => group.Name)); } - } diff --git a/imxweb/projects/rps/src/lib/init.service.ts b/imxweb/projects/rps/src/lib/init.service.ts index d34b28ad0..5120940d4 100644 --- a/imxweb/projects/rps/src/lib/init.service.ts +++ b/imxweb/projects/rps/src/lib/init.service.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -25,13 +25,14 @@ */ import { Injectable } from '@angular/core'; -import { Router, Route } from '@angular/router'; +import { Route, Router } from '@angular/router'; import { DynamicMethodService, ExtService, TabItem } from 'qbm'; import { RequestableEntitlementType, RequestableEntitlementTypeService } from 'qer'; import { ReportButtonComponent } from './report-button/report-button.component'; +import { ReportButtonMailComponent } from './report-button/report-button-mail.component'; import { RpsApiService } from './rps-api-client.service'; -import { SubscriptionsComponent } from './subscriptions/subscriptions.component'; import { StatisticReportButtonComponent } from './statistic-report-button/statistic-report-button.component'; +import { SubscriptionsComponent } from './subscriptions/subscriptions.component'; @Injectable({ providedIn: 'root' }) export class InitService { @@ -40,7 +41,7 @@ export class InitService { private readonly entlTypeService: RequestableEntitlementTypeService, private readonly apiService: RpsApiService, private readonly dynamicMethodService: DynamicMethodService, - private readonly extService: ExtService + private readonly extService: ExtService, ) {} public onInit(routes: Route[]): void { @@ -59,7 +60,7 @@ export class InitService { instance: ReportButtonComponent, inputData: { uidReport: 'CPL-77d3c04ac2084a968433ef7daf7e56ff', - caption: '#LDS#Download report on rule violations by identities you are directly responsible for', + caption: '#LDS#View rule violations by identities you are directly responsible for', preprop: ['COMPLIANCE'], features: ['Portal_UI_PersonManager'] } @@ -99,6 +100,11 @@ export class InitService { } }); + this.extService.register('presetReportButton', { + instance: ReportButtonMailComponent, + }); + + this.entlTypeService.Register(async () => [ new RequestableEntitlementType('RPSReport', this.apiService.apiClient, 'UID_RPSReport', this.dynamicMethodService), ]); diff --git a/imxweb/projects/rps/src/lib/list-report-viewer/list-report-data-provider.interface.ts b/imxweb/projects/rps/src/lib/list-report-viewer/list-report-data-provider.interface.ts index 5adc06a15..5f87a9ff0 100644 --- a/imxweb/projects/rps/src/lib/list-report-viewer/list-report-data-provider.interface.ts +++ b/imxweb/projects/rps/src/lib/list-report-viewer/list-report-data-provider.interface.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -24,13 +24,13 @@ * */ -import { CollectionLoadParameters, DataModel, EntitySchema, ExtendedTypedEntityCollection, GroupInfoData } from 'imx-qbm-dbts'; -import { ListReportContentData, PortalReportData } from 'imx-api-rps'; +import { CollectionLoadParameters, DataModel, EntitySchema, ExtendedTypedEntityCollection, GroupInfoData } from '@imx-modules/imx-qbm-dbts'; +import { ListReportContentData, PortalReportData } from '@imx-modules/imx-api-rps'; /** - * Provides methods for API interaction + * Provides methods for API interaction * Is used for navigating though the data of a list report - * + * */ export interface ListReportDataProvider { /** diff --git a/imxweb/projects/rps/src/lib/list-report-viewer/list-report-viewer.component.html b/imxweb/projects/rps/src/lib/list-report-viewer/list-report-viewer.component.html index 6739b70fe..6a71fea84 100644 --- a/imxweb/projects/rps/src/lib/list-report-viewer/list-report-viewer.component.html +++ b/imxweb/projects/rps/src/lib/list-report-viewer/list-report-viewer.component.html @@ -13,10 +13,10 @@ diff --git a/imxweb/projects/rps/src/lib/list-report-viewer/list-report-viewer.component.scss b/imxweb/projects/rps/src/lib/list-report-viewer/list-report-viewer.component.scss index 61459b1c2..69cc32493 100644 --- a/imxweb/projects/rps/src/lib/list-report-viewer/list-report-viewer.component.scss +++ b/imxweb/projects/rps/src/lib/list-report-viewer/list-report-viewer.component.scss @@ -1,21 +1,6 @@ -:host { - flex: 1 1 auto; - display: flex; - flex-direction: column; - overflow: hidden; +@import 'base/mixins'; - .mat-card { - flex: 1 1 auto; - display: flex; - flex-direction: column; - overflow: hidden; - margin: 3px; - } +:host { + @include flex-column-container-fill(); - .imx-table-container { - display: flex; - flex-direction: column; - overflow: hidden; - flex: 1 1 auto; - } } diff --git a/imxweb/projects/rps/src/lib/list-report-viewer/list-report-viewer.component.ts b/imxweb/projects/rps/src/lib/list-report-viewer/list-report-viewer.component.ts index cf29e4d86..50f86bec3 100644 --- a/imxweb/projects/rps/src/lib/list-report-viewer/list-report-viewer.component.ts +++ b/imxweb/projects/rps/src/lib/list-report-viewer/list-report-viewer.component.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -27,8 +27,15 @@ import { Component, Input, OnInit } from '@angular/core'; import _ from 'lodash'; -import { BusyService, ClassloggerService, DataSourceToolbarGroupData, DataSourceToolbarSettings, createGroupData } from 'qbm'; -import { CollectionLoadParameters, DataModel, DisplayColumns, EntitySchema } from 'imx-qbm-dbts'; +import { CollectionLoadParameters, DataModel, DisplayColumns, EntitySchema } from '@imx-modules/imx-qbm-dbts'; +import { + BusyService, + ClassloggerService, + DataSourceToolbarGroupData, + DataSourceToolbarSettings, + DataTableGroupedData, + createGroupData, +} from 'qbm'; import { ListReportDataProvider } from './list-report-data-provider.interface'; /** @@ -60,9 +67,10 @@ export class ListReportViewerComponent implements OnInit { public busyService = new BusyService(); public dstSettings: DataSourceToolbarSettings; public entitySchema: EntitySchema; - public groupData: DataSourceToolbarGroupData; + public groupedData: { [key: string]: DataTableGroupedData } = {}; private dataModel: DataModel; + private groupData: DataSourceToolbarGroupData | undefined; private reportColumns: string[]; private navigationState: CollectionLoadParameters = {}; @@ -105,16 +113,18 @@ export class ListReportViewerComponent implements OnInit { const isBusy = this.busyService.beginBusy(); try { - const groupedData = this.groupData[groupKey]; - const navigationState = { ...groupedData.navigationState }; - groupedData.data = await this.dataService.get(navigationState); - groupedData.settings = { - displayedColumns: this.dstSettings.displayedColumns, - dataModel: this.dstSettings.dataModel, - dataSource: groupedData.data, - entitySchema: this.dstSettings.entitySchema, - navigationState, - }; + if (this.groupData?.[groupKey]) { + const groupedData = this.groupData[groupKey]; + const navigationState = { ...groupedData.navigationState }; + groupedData.data = await this.dataService.get(navigationState); + groupedData.settings = { + displayedColumns: this.dstSettings.displayedColumns, + dataModel: this.dstSettings.dataModel, + dataSource: groupedData.data, + entitySchema: this.dstSettings.entitySchema, + navigationState, + }; + } } finally { isBusy.endBusy(); } @@ -158,13 +168,15 @@ export class ListReportViewerComponent implements OnInit { this.dataModel = await this.dataService.getDataModel(); const data = await this.dataService.get({ PageSize: -1 }); - this.reportColumns = data.extendedData.Columns; + if (data.extendedData?.Columns) { + this.reportColumns = data.extendedData.Columns; + } // create a copy of listReportSchema and add additional columns to it (because the schema only provides the display at this point) this.entitySchema = _.cloneDeep(this.dataService.entitySchema) as any; for (const column of this.reportColumns) { - (this.entitySchema.Columns[column] as any) = data.extendedData.AdditionalProperties.find((elem) => elem.ColumnName === column); + (this.entitySchema.Columns[column] as any) = data.extendedData?.AdditionalProperties?.find((elem) => elem.ColumnName === column); } this.navigationState = { ...this.navigationState }; @@ -183,7 +195,7 @@ export class ListReportViewerComponent implements OnInit { }, ...parameters, }), - [] + [], ); } } diff --git a/imxweb/projects/rps/src/lib/list-report-viewer/list-report-viewer.module.ts b/imxweb/projects/rps/src/lib/list-report-viewer/list-report-viewer.module.ts index d1154bc14..8a0d3e941 100644 --- a/imxweb/projects/rps/src/lib/list-report-viewer/list-report-viewer.module.ts +++ b/imxweb/projects/rps/src/lib/list-report-viewer/list-report-viewer.module.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -30,11 +30,9 @@ import { ListReportViewerComponent } from './list-report-viewer.component'; import { DataSourceToolbarModule, DataTableModule } from 'qbm'; import { MatCardModule } from '@angular/material/card'; - - @NgModule({ declarations: [ListReportViewerComponent], - imports: [CommonModule,MatCardModule, DataSourceToolbarModule,DataTableModule], + imports: [CommonModule, MatCardModule, DataSourceToolbarModule, DataTableModule], exports: [ListReportViewerComponent], }) export class ListReportViewerModule {} diff --git a/imxweb/projects/rps/src/lib/list-report-viewer/list-report-viewer.service.ts b/imxweb/projects/rps/src/lib/list-report-viewer/list-report-viewer.service.ts index 9fcd0dcc7..690a60d82 100644 --- a/imxweb/projects/rps/src/lib/list-report-viewer/list-report-viewer.service.ts +++ b/imxweb/projects/rps/src/lib/list-report-viewer/list-report-viewer.service.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -26,8 +26,8 @@ import { Injectable } from '@angular/core'; -import { CollectionLoadParameters, DataModel, EntitySchema, ExtendedTypedEntityCollection, GroupInfoData } from 'imx-qbm-dbts'; -import { ListReportContentData, PortalReportData } from 'imx-api-rps'; +import { CollectionLoadParameters, DataModel, EntitySchema, ExtendedTypedEntityCollection, GroupInfoData } from '@imx-modules/imx-qbm-dbts'; +import { ListReportContentData, PortalReportData } from '@imx-modules/imx-api-rps'; import { RpsApiService } from '../rps-api-client.service'; import { ListReportDataProvider } from './list-report-data-provider.interface'; diff --git a/imxweb/projects/rps/src/lib/report-button/parameter-sidesheet/parameter-sidesheet.component.html b/imxweb/projects/rps/src/lib/report-button/parameter-sidesheet/parameter-sidesheet.component.html index b6ef09098..adc8fa03e 100644 --- a/imxweb/projects/rps/src/lib/report-button/parameter-sidesheet/parameter-sidesheet.component.html +++ b/imxweb/projects/rps/src/lib/report-button/parameter-sidesheet/parameter-sidesheet.component.html @@ -1,12 +1,20 @@
    - + -
    +
    - - -
    \ No newline at end of file + + +
    diff --git a/imxweb/projects/rps/src/lib/report-button/parameter-sidesheet/parameter-sidesheet.component.scss b/imxweb/projects/rps/src/lib/report-button/parameter-sidesheet/parameter-sidesheet.component.scss deleted file mode 100644 index 735131a3c..000000000 --- a/imxweb/projects/rps/src/lib/report-button/parameter-sidesheet/parameter-sidesheet.component.scss +++ /dev/null @@ -1,4 +0,0 @@ -.mat-spinner{ - margin-right: 10px; - align-self: center; -} \ No newline at end of file diff --git a/imxweb/projects/rps/src/lib/report-button/parameter-sidesheet/parameter-sidesheet.component.ts b/imxweb/projects/rps/src/lib/report-button/parameter-sidesheet/parameter-sidesheet.component.ts index 7b1a76f26..364acf897 100644 --- a/imxweb/projects/rps/src/lib/report-button/parameter-sidesheet/parameter-sidesheet.component.ts +++ b/imxweb/projects/rps/src/lib/report-button/parameter-sidesheet/parameter-sidesheet.component.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -24,18 +24,17 @@ * */ -import { ChangeDetectorRef, Component, Inject } from '@angular/core'; -import { UntypedFormControl, UntypedFormGroup } from '@angular/forms'; -import { EuiSidesheetRef, EUI_SIDESHEET_DATA } from '@elemental-ui/core'; +import { ChangeDetectorRef, Component, Inject, OnInit } from '@angular/core'; +import { AbstractControl, UntypedFormGroup } from '@angular/forms'; +import { EUI_SIDESHEET_DATA, EuiSidesheetRef } from '@elemental-ui/core'; import { ClassloggerService, ColumnDependentReference } from 'qbm'; import { ReportSubscription } from '../../subscriptions/report-subscription/report-subscription'; @Component({ selector: 'imx-parameter-sidesheet', templateUrl: './parameter-sidesheet.component.html', - styleUrls: ['./parameter-sidesheet.component.scss'] }) -export class ParameterSidesheetComponent { +export class ParameterSidesheetComponent implements OnInit { public readonly reportFormGroup = new UntypedFormGroup({}); public cdrs: ColumnDependentReference[]; @@ -43,10 +42,9 @@ export class ParameterSidesheetComponent { constructor( private readonly sidesheetRef: EuiSidesheetRef, private readonly changeDetectorRef: ChangeDetectorRef, - @Inject(EUI_SIDESHEET_DATA) public readonly data: { subscription: ReportSubscription }, - logger: ClassloggerService + @Inject(EUI_SIDESHEET_DATA) public readonly data: { subscription: ReportSubscription; presetParameter: { [key: string]: string } }, + logger: ClassloggerService, ) { - this.cdrs = data.subscription.getParameterCdr(); data.subscription.reportEntityWrapper.startWriteData.subscribe(() => { this.writeOperators = this.writeOperators + 1; logger.debug(this, 'number of write operations:', this.writeOperators); @@ -59,12 +57,21 @@ export class ParameterSidesheetComponent { }); } - public addFormControl(name: string, control: UntypedFormControl) { + public async ngOnInit(): Promise { + if (this.data.presetParameter) { + await this.data.subscription.fillColumnsWithPreset(this.data.presetParameter); + this.cdrs = this.data.subscription.getParameterCdr(Object.entries(this.data.presetParameter).map((elem) => elem[0])); + } else { + this.cdrs = this.data.subscription.getParameterCdr(); + } + } + + public addFormControl(name: string, control: AbstractControl) { this.reportFormGroup.addControl(name, control); this.changeDetectorRef.detectChanges(); } - public viewReport() { + public async viewReport(): Promise { this.sidesheetRef.close(true); } } diff --git a/imxweb/projects/rps/src/lib/report-button/report-button-mail.component.html b/imxweb/projects/rps/src/lib/report-button/report-button-mail.component.html new file mode 100644 index 000000000..0d4a2fb0f --- /dev/null +++ b/imxweb/projects/rps/src/lib/report-button/report-button-mail.component.html @@ -0,0 +1,3 @@ + diff --git a/imxweb/projects/rps/src/lib/report-button/report-button-mail.component.scss b/imxweb/projects/rps/src/lib/report-button/report-button-mail.component.scss new file mode 100644 index 000000000..248a268c5 --- /dev/null +++ b/imxweb/projects/rps/src/lib/report-button/report-button-mail.component.scss @@ -0,0 +1 @@ +// add styles if necessary diff --git a/imxweb/projects/rps/src/lib/report-button/report-button-mail.component.ts b/imxweb/projects/rps/src/lib/report-button/report-button-mail.component.ts new file mode 100644 index 000000000..a938a60ad --- /dev/null +++ b/imxweb/projects/rps/src/lib/report-button/report-button-mail.component.ts @@ -0,0 +1,119 @@ +/* + * ONE IDENTITY LLC. PROPRIETARY INFORMATION + * + * This software is confidential. One Identity, LLC. or one of its affiliates or + * subsidiaries, has supplied this software to you under terms of a + * license agreement, nondisclosure agreement or both. + * + * You may not copy, disclose, or use this software except in accordance with + * those terms. + * + * + * Copyright 2024 One Identity LLC. + * ALL RIGHTS RESERVED. + * + * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR + * WARRANTIES ABOUT THE SUITABILITY OF THE SOFTWARE, + * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED + * TO THE IMPLIED WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE, OR + * NON-INFRINGEMENT. ONE IDENTITY LLC. SHALL NOT BE + * LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE + * AS A RESULT OF USING, MODIFYING OR DISTRIBUTING + * THIS SOFTWARE OR ITS DERIVATIVES. + * + */ + +import { Component, OnDestroy } from '@angular/core'; +import { EuiLoadingService, EuiSidesheetService } from '@elemental-ui/core'; +import { TranslateService } from '@ngx-translate/core'; + +import { calculateSidesheetWidth, SnackBarService } from 'qbm'; +import { ReportSubscription } from '../subscriptions/report-subscription/report-subscription'; +import { ReportSubscriptionService } from '../subscriptions/report-subscription/report-subscription.service'; +import { ParameterSidesheetComponent } from './parameter-sidesheet/parameter-sidesheet.component'; + +@Component({ + templateUrl: './report-button-mail.component.html', + styleUrls: ['./report-button-mail.component.scss'], +}) +export class ReportButtonMailComponent implements OnDestroy { + public referrer: { uid: string; presetParameters: { [key: string]: string } }; + + private subscription: ReportSubscription | undefined; + + constructor( + private readonly reportSubscriptionService: ReportSubscriptionService, + private readonly busy: EuiLoadingService, + private readonly sideSheet: EuiSidesheetService, + private readonly translator: TranslateService, + private readonly snackbarService: SnackBarService, + ) {} + + public ngOnDestroy(): void { + this.subscription?.unsubscribeEvents; + } + + public async sendReport(): Promise { + let over = this.busy.show(); + + try { + if (this.subscription != null) { + this.subscription.unsubscribeEvents(); + this.subscription = undefined; + } + this.subscription = await this.reportSubscriptionService.createNewSubscription(this.referrer.uid, Date.now().toFixed()); + } finally { + this.busy.hide(over); + } + if (!this.subscription) { + return; + } + + this.subscription.subscription.ExportFormat.value = 'PDF'; + + if (this.hasParametersToCompleteByUser()) { + const result = await this.sideSheet + .open(ParameterSidesheetComponent, { + title: await this.translator.get('#LDS#Heading Specify Parameters').toPromise(), + padding: '0px', + width: calculateSidesheetWidth(), + testId: 'report-button-view-parameter-sidesheet', + data: { subscription: this.subscription, presetParameter: this.referrer?.presetParameters }, + }) + .afterClosed() + .toPromise(); + + if (!result) { + return; + } + } + + let errors = false; + over = this.busy.show(); + try { + await this.subscription.submit(); + await this.reportSubscriptionService.sendViaMail(this.subscription.subscription.GetEntity().GetKeys()[0]); + } catch { + errors = true; + } finally { + this.busy.hide(over); + if (!errors) { + this.snackbarService.open({ + key: '#LDS#The report "{0}" will be sent to you.', + parameters: [this.subscription.subscription.UID_RPSReport.Column.GetDisplayValue()], + }); + } + } + } + + private hasParametersToCompleteByUser(): boolean { + if (!this.referrer?.presetParameters) { + return this.subscription?.hasParameter || false; + } + + const presetParameter = Object.entries(this.referrer.presetParameters).map((elem) => elem[0]); + + return !!this.subscription?.parameterNames.filter((elem) => presetParameter.indexOf(elem) === -1); + } +} diff --git a/imxweb/projects/rps/src/lib/report-button/report-button-parameter.ts b/imxweb/projects/rps/src/lib/report-button/report-button-parameter.ts index 1af5dbcc2..dd11f8f66 100644 --- a/imxweb/projects/rps/src/lib/report-button/report-button-parameter.ts +++ b/imxweb/projects/rps/src/lib/report-button/report-button-parameter.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR diff --git a/imxweb/projects/rps/src/lib/report-button/report-button.component.html b/imxweb/projects/rps/src/lib/report-button/report-button.component.html index f30621741..606602bfa 100644 --- a/imxweb/projects/rps/src/lib/report-button/report-button.component.html +++ b/imxweb/projects/rps/src/lib/report-button/report-button.component.html @@ -1,3 +1,3 @@ \ No newline at end of file + {{ inputData.caption | translate }} + diff --git a/imxweb/projects/rps/src/lib/report-button/report-button.component.scss b/imxweb/projects/rps/src/lib/report-button/report-button.component.scss index e110d11b2..248a268c5 100644 --- a/imxweb/projects/rps/src/lib/report-button/report-button.component.scss +++ b/imxweb/projects/rps/src/lib/report-button/report-button.component.scss @@ -1 +1 @@ -// add styles if necessary \ No newline at end of file +// add styles if necessary diff --git a/imxweb/projects/rps/src/lib/report-button/report-button.component.ts b/imxweb/projects/rps/src/lib/report-button/report-button.component.ts index 1ee69ff73..7919bbd38 100644 --- a/imxweb/projects/rps/src/lib/report-button/report-button.component.ts +++ b/imxweb/projects/rps/src/lib/report-button/report-button.component.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -26,18 +26,18 @@ import { Overlay } from '@angular/cdk/overlay'; import { HttpClient } from '@angular/common/http'; -import { Component, Injector, OnDestroy, OnInit } from '@angular/core'; -import { EuiDownloadDirective, EuiDownloadOptions, EuiLoadingService, EuiSidesheetService } from '@elemental-ui/core'; +import { Component, ElementRef, Injector, OnDestroy, OnInit } from '@angular/core'; +import { EuiDownloadDirective, EuiDownloadOptions, EuiDownloadService, EuiLoadingService, EuiSidesheetService } from '@elemental-ui/core'; import { TranslateService } from '@ngx-translate/core'; -import { V2ApiClientMethodFactory } from 'imx-api-rps'; -import { MethodDefinition } from 'imx-qbm-dbts'; -import { AppConfigService, ElementalUiConfigService, SystemInfoService } from 'qbm'; +import { V2ApiClientMethodFactory } from '@imx-modules/imx-api-rps'; +import { MethodDefinition } from '@imx-modules/imx-qbm-dbts'; +import { AppConfigService, ElementalUiConfigService, SystemInfoService, calculateSidesheetWidth } from 'qbm'; import { UserModelService } from 'qer'; import { ReportSubscription } from '../subscriptions/report-subscription/report-subscription'; import { ReportSubscriptionService } from '../subscriptions/report-subscription/report-subscription.service'; -import { ReportButtonParameter } from './report-button-parameter'; import { ParameterSidesheetComponent } from './parameter-sidesheet/parameter-sidesheet.component'; +import { ReportButtonParameter } from './report-button-parameter'; @Component({ selector: 'imx-report-button', @@ -51,7 +51,7 @@ export class ReportButtonComponent implements OnInit, OnDestroy { public isButtonRendered = true; public referrer: any; - private subscription: ReportSubscription; + private subscription: ReportSubscription | undefined; private readonly apiMethodFactory: V2ApiClientMethodFactory = new V2ApiClientMethodFactory(); @@ -66,7 +66,8 @@ export class ReportButtonComponent implements OnInit, OnDestroy { private readonly system: SystemInfoService, private readonly sideSheet: EuiSidesheetService, private readonly translator: TranslateService, - private readonly userModelService: UserModelService + private readonly userModelService: UserModelService, + private readonly downloadService: EuiDownloadService, ) {} public ngOnDestroy(): void { @@ -74,25 +75,22 @@ export class ReportButtonComponent implements OnInit, OnDestroy { } public async ngOnInit(): Promise { - if (this.inputData.groups == null && this.inputData.preprop == null) { + if (this.inputData.groups && this.inputData.preprop) { this.isButtonRendered = true; return; } const over = this.busy.show(); try { - const info = await this.system.get(); - const user = (await this.userModelService.getGroups()).map((elem) => elem.Name); - const userFeatures = (await this.userModelService.getFeatures()).Features; + const preprops = (await this.system.get())?.PreProps?.map((elem) => elem?.toUpperCase() ?? '') ?? []; + const user = (await this.userModelService.getGroups()).map((elem) => elem?.Name?.toUpperCase() ?? ''); + const userFeatures = (await this.userModelService.getFeatures()).Features ?? []; - const pre = - this.inputData.preprop == null || - this.inputData.preprop.some((elem) => info.PreProps.find((item) => item.toUpperCase() === elem.toUpperCase()) != null); + const pre = !this.inputData.preprop || this.inputData.preprop.some((elem) => preprops.find((item) => item === elem.toUpperCase())); const groups = - this.inputData.groups == null || - this.inputData.groups.some((elem) => user.find((item) => item.toUpperCase() === elem.toUpperCase()) != null); - const features = this.inputData?.features.some(feature => userFeatures.find(userFeature => feature === userFeature) != null); + !this.inputData.groups || this.inputData.groups.some((elem) => user.find((item) => item.toUpperCase() === elem.toUpperCase())); + const features = this.inputData?.features?.some((feature) => userFeatures.find((userFeature) => feature === userFeature)); - this.isButtonRendered = pre && (groups || features); + this.isButtonRendered = pre && (groups || !!features); } finally { this.busy.hide(over); } @@ -100,19 +98,16 @@ export class ReportButtonComponent implements OnInit, OnDestroy { public async viewReport(): Promise { const over = this.busy.show(); + if (this.subscription) { + this.subscription.unsubscribeEvents(); + this.subscription = undefined; + } try { - if (this.subscription != null) { - this.subscription.unsubscribeEvents(); - this.subscription = null; - } this.subscription = await this.reportSubscriptionService.createNewSubscription(this.inputData.uidReport); } finally { this.busy.hide(over); } - if (!this.subscription) { - return; - } this.subscription.subscription.ExportFormat.value = 'PDF'; @@ -122,7 +117,7 @@ export class ReportButtonComponent implements OnInit, OnDestroy { title: await this.translator.get('#LDS#Heading Specify Parameters').toPromise(), subTitle: await this.translator.get(this.inputData.caption).toPromise(), padding: '0px', - width: 'max(600px,60%)', + width: calculateSidesheetWidth(), testId: 'report-button-view-parameter-sidesheet', data: { subscription: this.subscription }, }) @@ -138,7 +133,13 @@ export class ReportButtonComponent implements OnInit, OnDestroy { const def = new MethodDefinition(this.apiMethodFactory.portal_subscription_interactive_report_get(parameters.entityid, parameters)); // not pretty, but the download directive does not support dynamic URLs - const directive = new EuiDownloadDirective(null /* no element */, this.http, this.overlay, this.injector); + const directive = new EuiDownloadDirective( + new ElementRef('') /* no element */, + this.http, + this.overlay, + this.injector, + this.downloadService, + ); directive.downloadOptions = { ...this.elementalUiConfigService.Config.downloadOptions, fileMimeType: '', // override elementalUiConfigService; get mime type from server diff --git a/imxweb/projects/rps/src/lib/report-button/report-button.module.ts b/imxweb/projects/rps/src/lib/report-button/report-button.module.ts index 5ed0be136..f8066c055 100644 --- a/imxweb/projects/rps/src/lib/report-button/report-button.module.ts +++ b/imxweb/projects/rps/src/lib/report-button/report-button.module.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -31,16 +31,17 @@ import { EuiCoreModule } from '@elemental-ui/core'; import { TranslateModule } from '@ngx-translate/core'; import { ReportButtonComponent } from './report-button.component'; +import { ReportButtonMailComponent } from './report-button-mail.component'; import { ParameterSidesheetComponent } from './parameter-sidesheet/parameter-sidesheet.component'; import { ReactiveFormsModule } from '@angular/forms'; import { MatButtonModule } from '@angular/material/button'; import { MatCardModule } from '@angular/material/card'; -import { CdrModule} from 'qbm'; +import { CdrModule } from 'qbm'; import { MatProgressSpinnerModule } from '@angular/material/progress-spinner'; @NgModule({ - declarations: [ReportButtonComponent, ParameterSidesheetComponent], + declarations: [ReportButtonComponent, ReportButtonMailComponent, ParameterSidesheetComponent], imports: [ CommonModule, CdrModule, @@ -50,8 +51,8 @@ import { MatProgressSpinnerModule } from '@angular/material/progress-spinner'; MatCardModule, EuiCoreModule, TranslateModule, - ReactiveFormsModule + ReactiveFormsModule, ], - exports: [ReportButtonComponent] + exports: [ReportButtonComponent], }) -export class ReportButtonModule { } +export class ReportButtonModule {} diff --git a/imxweb/projects/rps/src/lib/reports/edit-report-sidesheet/edit-report-sidesheet.component.html b/imxweb/projects/rps/src/lib/reports/edit-report-sidesheet/edit-report-sidesheet.component.html index 3ef509ae3..7d650c45b 100644 --- a/imxweb/projects/rps/src/lib/reports/edit-report-sidesheet/edit-report-sidesheet.component.html +++ b/imxweb/projects/rps/src/lib/reports/edit-report-sidesheet/edit-report-sidesheet.component.html @@ -17,23 +17,35 @@ - + {{ ldsUnsupportedExpression | translate }} {{ '#LDS#Conditions' | translate }}* - + {{ ldsAllRowsInfoText | translate }} - +
    -
    diff --git a/imxweb/projects/rps/src/lib/reports/edit-report-sidesheet/edit-report-sidesheet.component.scss b/imxweb/projects/rps/src/lib/reports/edit-report-sidesheet/edit-report-sidesheet.component.scss index 44349dc24..e69de29bb 100644 --- a/imxweb/projects/rps/src/lib/reports/edit-report-sidesheet/edit-report-sidesheet.component.scss +++ b/imxweb/projects/rps/src/lib/reports/edit-report-sidesheet/edit-report-sidesheet.component.scss @@ -1,25 +0,0 @@ -.eui-sidesheet-content { - display: flex; - flex-direction: column; -} - -:host { - .eui-sidesheet-actions { - .justify-start { - margin-right: auto; - } - - button:not(:last-of-type):not(.justify-start) { - margin-right: 10px; - } - } -} - -eui-alert { - display: block; - margin-bottom: 1em; -} - -mat-card { - margin-bottom: 1em; -} \ No newline at end of file diff --git a/imxweb/projects/rps/src/lib/reports/edit-report-sidesheet/edit-report-sidesheet.component.ts b/imxweb/projects/rps/src/lib/reports/edit-report-sidesheet/edit-report-sidesheet.component.ts index 38c0409fc..83f3c9c8a 100644 --- a/imxweb/projects/rps/src/lib/reports/edit-report-sidesheet/edit-report-sidesheet.component.ts +++ b/imxweb/projects/rps/src/lib/reports/edit-report-sidesheet/edit-report-sidesheet.component.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -26,28 +26,28 @@ import { ChangeDetectorRef, Component, Inject, OnDestroy, OnInit, ViewChild } from '@angular/core'; import { AbstractControl, UntypedFormArray, UntypedFormBuilder, UntypedFormGroup } from '@angular/forms'; -import { EuiLoadingService, EuiSidesheetRef, EUI_SIDESHEET_DATA } from '@elemental-ui/core'; +import { EUI_SIDESHEET_DATA, EuiLoadingService, EuiSidesheetRef } from '@elemental-ui/core'; import _ from 'lodash'; -import { ListReportDefinitionDto, ListReportDefinitionRead, PortalReportsEdit } from 'imx-api-rps'; +import { ListReportDefinitionDto, ListReportDefinitionRead, PortalReportsEdit } from '@imx-modules/imx-api-rps'; import { ExtendedTypedEntityCollection, - SqlWizardExpression, - isExpressionInvalid, - ValType, FkProviderItem, SqlExpression, -} from 'imx-qbm-dbts'; + SqlWizardExpression, + ValType, + isExpressionInvalid, +} from '@imx-modules/imx-qbm-dbts'; import { BaseCdr, + BaseReadonlyCdr, + CdrFactoryService, ColumnDependentReference, ConfirmationService, EntityService, SnackBarService, SqlWizardComponent, - CdrFactoryService, - BaseReadonlyCdr, } from 'qbm'; import { ProjectConfigurationService } from 'qer'; import { Subscription } from 'rxjs'; @@ -65,9 +65,6 @@ export class EditReportSidesheetComponent implements OnInit, OnDestroy { public cdrList: ColumnDependentReference[] = []; public readonly detailsFormGroup: UntypedFormGroup; - public get sqlExpression(): SqlWizardExpression { - return this.definition?.Data; - } public definition: ListReportDefinitionDto; public report: PortalReportsEdit; @@ -83,9 +80,14 @@ export class EditReportSidesheetComponent implements OnInit, OnDestroy { ); } + public get isCondition(): boolean { + return !!this.sqlExpression?.Expression?.Expressions && this.sqlExpression?.Expression?.Expressions?.length < 1; + } + private closeSubscription: Subscription; - public lastSavedExpression: SqlExpression; + public sqlExpression: SqlWizardExpression; + public lastSavedExpression: SqlExpression | undefined; public exprHasntChanged = true; public checkChanges(): void { @@ -111,7 +113,7 @@ export class EditReportSidesheetComponent implements OnInit, OnDestroy { private readonly cdref: ChangeDetectorRef, private readonly config: ProjectConfigurationService, private readonly cdrFactoryService: CdrFactoryService, - confirmation: ConfirmationService + confirmation: ConfirmationService, ) { this.detailsFormGroup = new UntypedFormGroup({ formArray: formBuilder.array([]) }); @@ -125,7 +127,12 @@ export class EditReportSidesheetComponent implements OnInit, OnDestroy { // Save a local copy of the definition object. The entity will change with every update // of the interactive entity that comes back from the server - this.definition = this.report.extendedDataRead?.Definition[0]; + if (!!this.report.extendedDataRead?.Definition) { + this.definition = this.report.extendedDataRead.Definition[0]; + } + if (this.definition?.Data) { + this.sqlExpression = this.definition.Data; + } this.lastSavedExpression = _.cloneDeep(this.sqlExpression?.Expression); } @@ -135,15 +142,17 @@ export class EditReportSidesheetComponent implements OnInit, OnDestroy { this.cdrList = this.cdrFactoryService.buildCdrFromColumnList( this.report.GetEntity(), - c.OwnershipConfig.EditableFields[this.report.GetEntity().TypeName], - this.data.isReadonly + c?.OwnershipConfig?.EditableFields?.[this.report.GetEntity().TypeName] ?? [], + this.data.isReadonly, ); if (this.definition) { // is it a list report? this.cdrList.push(await this.buildTableCdr()); } - this.cdrList.push(this.data.isReadonly ? new BaseReadonlyCdr(this.report.AvailableTo.Column): new BaseCdr(this.report.AvailableTo.Column)); + this.cdrList.push( + this.data.isReadonly ? new BaseReadonlyCdr(this.report.AvailableTo.Column) : new BaseCdr(this.report.AvailableTo.Column), + ); } public addCdr(control: AbstractControl): void { @@ -170,7 +179,7 @@ export class EditReportSidesheetComponent implements OnInit, OnDestroy { { SelectedColumns: this.definition.SelectedColumns, Data: { - Filters: [this.definition.Data.Expression], + Filters: this.definition.Data?.Expression ? [this.definition.Data?.Expression] : [], }, }, ], @@ -191,7 +200,7 @@ export class EditReportSidesheetComponent implements OnInit, OnDestroy { return false; } // not a list report? - if (this.definition.SelectedColumns.filter((elem) => elem != null && elem !== '').length < 1) { + if (!this.definition.SelectedColumns || this.definition.SelectedColumns?.filter((elem) => !!elem).length === 0) { return true; } // must select at least one column @@ -204,11 +213,14 @@ export class EditReportSidesheetComponent implements OnInit, OnDestroy { return isExpressionInvalid(this.sqlExpression) || !this.hasValuesSet(this.sqlExpression.Expression); } - private hasValuesSet(sqlExpression: SqlExpression, checkCurrent: boolean = false): boolean { + private hasValuesSet(sqlExpression: SqlExpression | undefined, checkCurrent: boolean = false): boolean { + if (!sqlExpression) { + return false; + } const current = !checkCurrent || sqlExpression.Value != null; - if (sqlExpression.Expressions?.length > 0) { - return current && sqlExpression.Expressions.every((elem) => this.hasValuesSet(elem, true)); + if (sqlExpression.Expressions) { + return current && sqlExpression.Expressions?.every((elem) => this.hasValuesSet(elem, true)); } return current; @@ -239,7 +251,7 @@ export class EditReportSidesheetComponent implements OnInit, OnDestroy { ValidReferencedTables: [{ TableName: fkProviderItem.fkTableName }], MinLen: 1, }, - [fkProviderItem] + [fkProviderItem], ); await tableCol.PutValueStruct({ DataValue: this.definition.TableName, @@ -254,7 +266,12 @@ export class EditReportSidesheetComponent implements OnInit, OnDestroy { }, ], }); - this.definition = this.report.extendedDataRead?.Definition[0]; + if (!!this.report.extendedDataRead?.Definition) { + this.definition = this.report.extendedDataRead.Definition[0]; + } + if (this.definition.Data) { + this.sqlExpression = this.definition.Data; + } this.cdref.detectChanges(); }); diff --git a/imxweb/projects/rps/src/lib/reports/edit-report.component.html b/imxweb/projects/rps/src/lib/reports/edit-report.component.html index fda46275a..df8487d80 100644 --- a/imxweb/projects/rps/src/lib/reports/edit-report.component.html +++ b/imxweb/projects/rps/src/lib/reports/edit-report.component.html @@ -1,55 +1,33 @@
    -
    -

    +
    +

    {{ '#LDS#Heading Reports' | translate }} -

    +

    +
    - -
    - - - - - -
    {{ item.GetEntity().GetDisplay() }}
    -
    {{ item.Description.Column.GetDisplayValue() }}
    -
    -
    -
    - -
    + + + +
    + + + + -
    - -
    +
    + - diff --git a/imxweb/projects/rps/src/lib/reports/edit-report.component.scss b/imxweb/projects/rps/src/lib/reports/edit-report.component.scss index 966a40141..f643adde8 100644 --- a/imxweb/projects/rps/src/lib/reports/edit-report.component.scss +++ b/imxweb/projects/rps/src/lib/reports/edit-report.component.scss @@ -1,80 +1,24 @@ -@import '../../../../../shared/scss/common-table.scss'; -@mixin imx-flex-column-container { - display: flex; - flex-direction: column; -} - -@mixin imx-flex-row-container { - display: flex; - flex-direction: row; -} - -.eui-sidesheet-content { - @include imx-flex-column-container(); -} +@import 'base/mixins'; .heading-wrapper { - @include imx-flex-row-container(); + @include flex-row-container(); flex: 0 0 auto; - - .helper-alert { - display: flex; - margin-bottom: 15px; - } - - .alert-wrapper { - margin: 0 0 0 auto; - align-self: flex-end; - width: 50%; - } } :host { - @include imx-flex-column-container(); - overflow: hidden; - height: 100%; - max-width: 100%; -} - -.imx-content-card { - @include imx-flex-fill-control-hidden-overflow(); - margin: 3px; + @include flex-column-container($overflow: hidden, $height: 100%, $max-width: 100%); } .imx-reports-page { + @include flex-column-container($overflow: hidden); background-color: inherit; - @include imx-flex-column-container(); - overflow: hidden; - display: flex; - flex-direction: column; flex: 1 1 auto; - - div.imx-table-container { - @include imx-flex-column-container(); - overflow: hidden; - height: inherit; - flex: 1 1 auto; - - .imx-reports-table { - flex-grow: 1; - overflow: auto; - } - } - - .imx-button-bar { - @include imx-button-bar(); - } } @media screen and (max-width: 768px) { .imx-reports-page { .heading-wrapper { display: block; - - .alert-wrapper { - margin: 0 0 20px 0; - width: 100%; - } } } } diff --git a/imxweb/projects/rps/src/lib/reports/edit-report.component.ts b/imxweb/projects/rps/src/lib/reports/edit-report.component.ts index b6dce5d9d..85923ca2c 100644 --- a/imxweb/projects/rps/src/lib/reports/edit-report.component.ts +++ b/imxweb/projects/rps/src/lib/reports/edit-report.component.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -24,45 +24,47 @@ * */ -import { Component, OnDestroy, OnInit, ViewChild } from '@angular/core'; +import { Component, OnInit } from '@angular/core'; import { EuiLoadingService, EuiSidesheetService } from '@elemental-ui/core'; import { TranslateService } from '@ngx-translate/core'; -import { ListReportDefinitionRead, PortalReports, PortalReportsEdit } from 'imx-api-rps'; -import { CollectionLoadParameters, DisplayColumns, ExtendedTypedEntityCollection } from 'imx-qbm-dbts'; +import { ListReportDefinitionRead, PortalReports, PortalReportsEdit } from '@imx-modules/imx-api-rps'; +import { + CollectionLoadParameters, + DisplayColumns, + ExtendedTypedEntityCollection, + IClientProperty, + StaticSchema, + TypedEntityCollectionData, +} from '@imx-modules/imx-qbm-dbts'; import { BusyService, + calculateSidesheetWidth, ConfirmationService, - DataSourceToolbarSettings, - DataSourceWrapper, - DataTableComponent, - SnackBarService, + DataViewInitParameters, + DataViewSource, + HELP_CONTEXTUAL, HelpContextualComponent, HelpContextualService, - HELP_CONTEXTUAL + SnackBarService, } from 'qbm'; -import { Subscription } from 'rxjs'; +import { RpsPermissionsService } from '../admin/rps-permissions.service'; import { EditReportSidesheetComponent } from './edit-report-sidesheet/edit-report-sidesheet.component'; import { EditReportService } from './edit-report.service'; -import { QerPermissionsService } from 'qer'; -import { RpsPermissionsService } from '../admin/rps-permissions.service'; @Component({ templateUrl: './edit-report.component.html', styleUrls: ['./edit-report.component.scss'], + providers: [DataViewSource], }) -export class EditReportComponent implements OnInit, OnDestroy { +export class EditReportComponent implements OnInit { public readonly DisplayColumns = DisplayColumns; - public dstWrapper: DataSourceWrapper; - @ViewChild('dataTable') private reportsTable: DataTableComponent; - public dstSettings: DataSourceToolbarSettings; public selectedReports: PortalReports[] = []; - + public displayedColumns: IClientProperty[]; public busyService = new BusyService(); - public entitySchema = this.reportService.reportSchema; - - private readonly subscriptions: Subscription[] = []; + public entitySchema: StaticSchema; + private isRpsAdmin: boolean; constructor( private readonly reportService: EditReportService, @@ -72,34 +74,30 @@ export class EditReportComponent implements OnInit, OnDestroy { private readonly confirmationService: ConfirmationService, private readonly rpsPermissionService: RpsPermissionsService, private readonly snackBarService: SnackBarService, - private readonly helpContextualService: HelpContextualService - ) {} + private readonly helpContextualService: HelpContextualService, + public dataSource: DataViewSource, + ) { + this.entitySchema = this.reportService.reportSchema; + } public async ngOnInit(): Promise { - const isRpsAdmin = await this.rpsPermissionService.isRpsAdmin(); - this.dstWrapper = new DataSourceWrapper( - (state) => (isRpsAdmin ? this.reportService.getAllReports(state) : this.reportService.getReportsOwnedByUser(state)), - [this.entitySchema.Columns[DisplayColumns.DISPLAY_PROPERTYNAME]], - this.entitySchema - ); - - await this.getData(); + this.isRpsAdmin = await this.rpsPermissionService.isRpsAdmin(); + this.displayedColumns = [this.entitySchema.Columns[DisplayColumns.DISPLAY_PROPERTYNAME]]; + this.getData(); } - public ngOnDestroy(): void { - this.subscriptions.forEach((s) => s.unsubscribe()); - } - - public async getData(parameter?: CollectionLoadParameters): Promise { - const isBusy = this.busyService.beginBusy(); - try { - const parameters = { - ...parameter, - }; - this.dstSettings = await this.dstWrapper.getDstSettings(parameters); - } finally { - isBusy.endBusy(); - } + public getData(): void { + const dataViewInitParameters: DataViewInitParameters = { + execute: (params: CollectionLoadParameters, signal: AbortSignal): Promise> => + this.isRpsAdmin ? this.reportService.getAllReports(params, signal) : this.reportService.getReportsOwnedByUser(params, signal), + schema: this.entitySchema, + columnsToDisplay: this.displayedColumns, + highlightEntity: (entity: PortalReports) => { + this.viewDetails(entity); + }, + selectionChange: (selection: PortalReports[]) => this.onSelectionChanged(selection), + }; + this.dataSource.init(dataViewInitParameters); } public onSelectionChanged(items: PortalReports[]): void { @@ -116,29 +114,25 @@ export class EditReportComponent implements OnInit, OnDestroy { } if (report) { - await this.openSidesheet(report, true,false); + await this.openSidesheet(report, true, false); } } public async viewDetails(selectedReport: PortalReports): Promise { const overlay = this.busy.show(); - let report; - try { - report = await this.reportService.getReport(selectedReport.GetEntity().GetKeys()[0]); - } finally { - this.busy.hide(overlay); - } - + const entity = selectedReport.GetEntity(); + const report = await this.reportService.getReport(entity.GetKeys()[0]); + this.busy.hide(overlay); if (report) { - await this.openSidesheet(report, false,selectedReport.IsOob.value); + await this.openSidesheet(report, false, entity.GetColumn('IsOob').GetValue()); } } private async openSidesheet( report: ExtendedTypedEntityCollection, isNew: boolean, - isReadonly: boolean + isReadonly: boolean, ): Promise { this.helpContextualService.setHelpContextId(isNew ? HELP_CONTEXTUAL.ReportsCreate : HELP_CONTEXTUAL.ReportsEdit); const result = await this.sidesheet @@ -148,20 +142,20 @@ export class EditReportComponent implements OnInit, OnDestroy { panelClass: 'imx-sidesheet', disableClose: true, padding: '0', - width: 'max(768px, 80%)', + width: calculateSidesheetWidth(1100, 0.7), testId: isNew ? 'report-create-sidesheet' : 'report-details-sidesheet', data: { report, isNew, - isReadonly + isReadonly, }, - headerComponent: HelpContextualComponent + headerComponent: HelpContextualComponent, }) .afterClosed() .toPromise(); if (result) { - this.getData(); + this.dataSource.updateState(); } } @@ -184,7 +178,8 @@ export class EditReportComponent implements OnInit, OnDestroy { } this.snackBarService.open({ key: '#LDS#The reports have been successfully deleted.' }, '#LDS#Close'); - this.reportsTable.clearSelection(); + this.dataSource.selection.clear(); + this.dataSource.updateState(); await this.getData(); } finally { this.busy.hide(overlay); diff --git a/imxweb/projects/rps/src/lib/reports/edit-report.module.ts b/imxweb/projects/rps/src/lib/reports/edit-report.module.ts index d25f788a8..aae730e69 100644 --- a/imxweb/projects/rps/src/lib/reports/edit-report.module.ts +++ b/imxweb/projects/rps/src/lib/reports/edit-report.module.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -27,40 +27,39 @@ import { DragDropModule } from '@angular/cdk/drag-drop'; import { CommonModule } from '@angular/common'; import { NgModule } from '@angular/core'; -import { MatCardModule } from '@angular/material/card'; import { FormsModule, ReactiveFormsModule } from '@angular/forms'; +import { MatCardModule } from '@angular/material/card'; import { EuiCoreModule, EuiMaterialModule } from '@elemental-ui/core'; import { TranslateModule } from '@ngx-translate/core'; +import { MatTableModule } from '@angular/material/table'; import { CdrModule, DataSourceToolbarModule, DataTableModule, + DataViewModule, HelpContextualModule, MenuItem, MenuService, OrderedListModule, SelectedElementsModule, SqlWizardApiService, - SqlWizardModule + SqlWizardModule, } from 'qbm'; -import { EditReportComponent } from './edit-report.component'; +import { RpsPermissionsService } from '../admin/rps-permissions.service'; import { EditReportSidesheetComponent } from './edit-report-sidesheet/edit-report-sidesheet.component'; +import { EditReportComponent } from './edit-report.component'; import { EditReportSqlWizardService } from './editreport-sqlwizard.service'; -import { RpsPermissionsService } from '../admin/rps-permissions.service'; @NgModule({ - declarations: [ - EditReportComponent, - EditReportSidesheetComponent - ], + declarations: [EditReportComponent, EditReportSidesheetComponent], providers: [ { // This does not work for some reason! provide: SqlWizardApiService, - useClass: EditReportSqlWizardService + useClass: EditReportSqlWizardService, }, - RpsPermissionsService + RpsPermissionsService, ], imports: [ CdrModule, @@ -78,48 +77,39 @@ import { RpsPermissionsService } from '../admin/rps-permissions.service'; SqlWizardModule, SelectedElementsModule, HelpContextualModule, - ] + MatTableModule, + DataViewModule, + ], }) export class EditReportModule { - - constructor( - private readonly menuService: MenuService, - ) { + constructor(private readonly menuService: MenuService) { this.setupMenu(); } private setupMenu(): void { - this.menuService.addMenuFactories( - (preProps: string[], features: string[]) => { - - const items: MenuItem[] = []; + this.menuService.addMenuFactories((preProps: string[], features: string[]) => { + const items: MenuItem[] = []; - if (preProps.includes('REPORT_SUBSCRIPTION')) { - items.push( - { - id: 'RPS_Reports', - navigationCommands: { - commands: ['reports'] - }, - title: '#LDS#Menu Entry Reports', - sorting: '60-70', - }, - ); - } + if (preProps.includes('REPORT_SUBSCRIPTION')) { + items.push({ + id: 'RPS_Reports', + navigationCommands: { + commands: ['reports'], + }, + title: '#LDS#Menu Entry Reports', + sorting: '60-70', + }); + } - if (items.length === 0) { - return null; - } - return { - id: 'ROOT_Setup', - title: '#LDS#Setup', - sorting: '60', - items - }; - }, - ); + if (items.length === 0) { + return undefined; + } + return { + id: 'ROOT_Setup', + title: '#LDS#Setup', + sorting: '60', + items, + }; + }); } - - - } diff --git a/imxweb/projects/rps/src/lib/reports/edit-report.service.ts b/imxweb/projects/rps/src/lib/reports/edit-report.service.ts index e0b130205..c72dc523e 100644 --- a/imxweb/projects/rps/src/lib/reports/edit-report.service.ts +++ b/imxweb/projects/rps/src/lib/reports/edit-report.service.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -26,21 +26,18 @@ import { Injectable } from '@angular/core'; -import { ListReportDefinitionRead, PortalReports, PortalReportsEditInteractive } from 'imx-api-rps'; -import { CollectionLoadParameters, ExtendedTypedEntityCollection } from 'imx-qbm-dbts'; +import { ListReportDefinitionRead, PortalReports, PortalReportsEdit, PortalReportsEditInteractive } from '@imx-modules/imx-api-rps'; +import { CollectionLoadParameters, ExtendedTypedEntityCollection } from '@imx-modules/imx-qbm-dbts'; import { RpsApiService } from '../rps-api-client.service'; @Injectable({ - providedIn: 'root' + providedIn: 'root', }) export class EditReportService { + constructor(private readonly api: RpsApiService) {} - constructor( - private readonly api: RpsApiService, - ) { } - - public reportSchema = PortalReportsEditInteractive.GetEntitySchema(); + public reportSchema = PortalReportsEdit.GetEntitySchema(); public async getReport(id: string): Promise> { return await this.api.typedClient.PortalReportsEditInteractive.Get_byid(id); @@ -50,14 +47,18 @@ export class EditReportService { return this.api.typedClient.PortalReportsEditInteractive.Get(); } - public async getReportsOwnedByUser(navigationState?: CollectionLoadParameters): - Promise> { - return this.api.typedClient.PortalReports.Get({ owned: true, ...navigationState }); + public async getReportsOwnedByUser( + navigationState?: CollectionLoadParameters, + signal?: AbortSignal, + ): Promise> { + return this.api.typedClient.PortalReports.Get({ owned: true, ...navigationState }, { signal }); } - public async getAllReports(navigationState?: CollectionLoadParameters): - Promise> { - return this.api.typedClient.PortalReports.Get(navigationState); + public async getAllReports( + navigationState?: CollectionLoadParameters, + signal?: AbortSignal, + ): Promise> { + return this.api.typedClient.PortalReports.Get(navigationState, { signal }); } public async deleteReport(report: PortalReports) { diff --git a/imxweb/projects/rps/src/lib/reports/editreport-sqlwizard.service.ts b/imxweb/projects/rps/src/lib/reports/editreport-sqlwizard.service.ts index 95b327525..31433d2e7 100644 --- a/imxweb/projects/rps/src/lib/reports/editreport-sqlwizard.service.ts +++ b/imxweb/projects/rps/src/lib/reports/editreport-sqlwizard.service.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -24,20 +24,20 @@ * */ -import { Injectable } from "@angular/core"; -import { CollectionLoadParameters, EntityCollectionData, FilterProperty } from "imx-qbm-dbts"; -import { SqlWizardApiService } from "qbm"; -import { RpsApiService } from "../rps-api-client.service"; +import { Injectable } from '@angular/core'; +import { CollectionLoadParameters, EntityCollectionData, FilterProperty } from '@imx-modules/imx-qbm-dbts'; +import { SqlWizardApiService } from 'qbm'; +import { RpsApiService } from '../rps-api-client.service'; @Injectable({ providedIn: 'root' }) export class EditReportSqlWizardService implements SqlWizardApiService { - constructor(private readonly api: RpsApiService) { } + constructor(private readonly api: RpsApiService) {} public async getFilterProperties(table: string): Promise { - return (await this.api.client.portal_reports_sqlwizard_tables_columns_get(table)).Properties; + return (await this.api.client.portal_reports_sqlwizard_tables_columns_get(table)).Properties ?? []; } public async getCandidates(parentTable: string, options?: CollectionLoadParameters): Promise { return await this.api.client.portal_reports_sqlwizard_candidates_get(parentTable, options); } -} \ No newline at end of file +} diff --git a/imxweb/projects/rps/src/lib/rps-api-client.service.ts b/imxweb/projects/rps/src/lib/rps-api-client.service.ts index 95f2ac6e9..c03eaaff0 100644 --- a/imxweb/projects/rps/src/lib/rps-api-client.service.ts +++ b/imxweb/projects/rps/src/lib/rps-api-client.service.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -25,12 +25,12 @@ */ import { Injectable } from '@angular/core'; -import { V2Client, TypedClient } from 'imx-api-rps'; -import { ApiClient } from 'imx-qbm-dbts'; +import { V2Client, TypedClient } from '@imx-modules/imx-api-rps'; +import { ApiClient } from '@imx-modules/imx-qbm-dbts'; import { AppConfigService, ClassloggerService, ImxTranslationProviderService } from 'qbm'; @Injectable({ - providedIn: 'root' + providedIn: 'root', }) export class RpsApiService { private tc: TypedClient; @@ -50,7 +50,8 @@ export class RpsApiService { constructor( private readonly config: AppConfigService, private readonly logger: ClassloggerService, - private readonly translationProvider: ImxTranslationProviderService) { + private readonly translationProvider: ImxTranslationProviderService, + ) { try { this.logger.debug(this, 'Initializing RPS API service'); diff --git a/imxweb/projects/rps/src/lib/rps-config.module.ts b/imxweb/projects/rps/src/lib/rps-config.module.ts index 36c9c18d9..9180c8f4e 100644 --- a/imxweb/projects/rps/src/lib/rps-config.module.ts +++ b/imxweb/projects/rps/src/lib/rps-config.module.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -33,7 +33,7 @@ import { SubscriptionsModule } from './subscriptions/subscriptions.module'; import { EditReportComponent } from './reports/edit-report.component'; import { EditReportModule } from './reports/edit-report.module'; import { ReportButtonModule } from './report-button/report-button.module'; -import {StatisticReportButtonModule} from './statistic-report-button/statistic-report-button.module'; +import { StatisticReportButtonModule } from './statistic-report-button/statistic-report-button.module'; const routes: Routes = [ { @@ -41,20 +41,15 @@ const routes: Routes = [ component: EditReportComponent, canActivate: [RouteGuardService], resolve: [RouteGuardService], - data:{ - contextId: HELP_CONTEXTUAL.Reports - } - } + data: { + contextId: HELP_CONTEXTUAL.Reports, + }, + }, ]; @NgModule({ - imports: [ - EditReportModule, - SubscriptionsModule, - ReportButtonModule, - StatisticReportButtonModule, - RouterModule.forChild(routes) - ] + imports: [EditReportModule, SubscriptionsModule, ReportButtonModule, StatisticReportButtonModule, RouterModule.forChild(routes)], + declarations: [], }) export class RpsConfigModule { constructor(private readonly initializer: InitService) { diff --git a/imxweb/projects/rps/src/lib/statistic-report-button/statistic-report-button.component.html b/imxweb/projects/rps/src/lib/statistic-report-button/statistic-report-button.component.html index 33c854d0f..ac74e248b 100644 --- a/imxweb/projects/rps/src/lib/statistic-report-button/statistic-report-button.component.html +++ b/imxweb/projects/rps/src/lib/statistic-report-button/statistic-report-button.component.html @@ -1,4 +1,4 @@ - \ No newline at end of file + #LDS#View source data + diff --git a/imxweb/projects/rps/src/lib/statistic-report-button/statistic-report-button.component.scss b/imxweb/projects/rps/src/lib/statistic-report-button/statistic-report-button.component.scss index 84f1418af..2a8491b97 100644 --- a/imxweb/projects/rps/src/lib/statistic-report-button/statistic-report-button.component.scss +++ b/imxweb/projects/rps/src/lib/statistic-report-button/statistic-report-button.component.scss @@ -1,20 +1,12 @@ - -@mixin Ease-Transition($duration: .4s) { - transition: all $duration ease; -} - -@mixin EUI-Elevation-1 { - box-shadow: 0px 1px 1px rgba(0, 0, 0, 0.14), 0px 2px 1px rgba(0, 0, 0, 0.12), 0px 1px 3px rgba(0, 0, 0, 0.2); -} +@import 'base/mixins'; :host { display: flex; flex-direction: row; - + button { display: flex; - @include EUI-Elevation-1; - @include Ease-Transition; + @include ease-transition; eui-icon { margin-right: 4px; } diff --git a/imxweb/projects/rps/src/lib/statistic-report-button/statistic-report-button.component.ts b/imxweb/projects/rps/src/lib/statistic-report-button/statistic-report-button.component.ts index dca2a4ac9..d3a4702e2 100644 --- a/imxweb/projects/rps/src/lib/statistic-report-button/statistic-report-button.component.ts +++ b/imxweb/projects/rps/src/lib/statistic-report-button/statistic-report-button.component.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -28,9 +28,10 @@ import { Component } from '@angular/core'; import { EuiSidesheetService } from '@elemental-ui/core'; import { TranslateService } from '@ngx-translate/core'; -import { StatisticReportButtonService } from './statistic-report-button.service'; -import { ListReportViewerSidesheetComponent } from '../subscriptions/list-report-viewer-sidesheet/list-report-viewer-sidesheet.component'; +import { calculateSidesheetWidth } from 'qbm'; import { ChartInfoTyped } from 'qer'; +import { ListReportViewerSidesheetComponent } from '../subscriptions/list-report-viewer-sidesheet/list-report-viewer-sidesheet.component'; +import { StatisticReportButtonService } from './statistic-report-button.service'; @Component({ selector: 'imx-statistic-report-button', @@ -43,7 +44,7 @@ export class StatisticReportButtonComponent { constructor( private readonly statisticService: StatisticReportButtonService, private readonly sideSheet: EuiSidesheetService, - private readonly translate: TranslateService + private readonly translate: TranslateService, ) {} /** @@ -51,12 +52,12 @@ export class StatisticReportButtonComponent { */ public viewReport(): void { this.statisticService.setIdStatistic(this.referrer.Id.value); - const data = { dataService: this.statisticService}; + const data = { dataService: this.statisticService }; this.sideSheet.open(ListReportViewerSidesheetComponent, { - title: this.translate.instant('#LDS#Heading View Report'), + title: this.translate.instant('#LDS#Heading View Source Data'), subTitle: this.referrer.GetDisplay(), padding: '0', - width: 'max(550px,55%)', + width: calculateSidesheetWidth(), testId: 'statistic-report-button-report-viewer', data, }); diff --git a/imxweb/projects/rps/src/lib/statistic-report-button/statistic-report-button.module.ts b/imxweb/projects/rps/src/lib/statistic-report-button/statistic-report-button.module.ts index 5546fdc57..e5215fe9c 100644 --- a/imxweb/projects/rps/src/lib/statistic-report-button/statistic-report-button.module.ts +++ b/imxweb/projects/rps/src/lib/statistic-report-button/statistic-report-button.module.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -27,13 +27,12 @@ import { NgModule } from '@angular/core'; import { CommonModule } from '@angular/common'; -import {StatisticReportButtonComponent} from './statistic-report-button.component'; +import { StatisticReportButtonComponent } from './statistic-report-button.component'; import { MatButtonModule } from '@angular/material/button'; import { TranslateModule } from '@ngx-translate/core'; import { EuiCoreModule } from '@elemental-ui/core'; import { MatProgressSpinnerModule } from '@angular/material/progress-spinner'; - @NgModule({ declarations: [StatisticReportButtonComponent], imports: [CommonModule, MatButtonModule, TranslateModule, EuiCoreModule, MatProgressSpinnerModule], diff --git a/imxweb/projects/rps/src/lib/statistic-report-button/statistic-report-button.service.ts b/imxweb/projects/rps/src/lib/statistic-report-button/statistic-report-button.service.ts index c49927778..2f5b01d0b 100644 --- a/imxweb/projects/rps/src/lib/statistic-report-button/statistic-report-button.service.ts +++ b/imxweb/projects/rps/src/lib/statistic-report-button/statistic-report-button.service.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -26,8 +26,8 @@ import { Injectable } from '@angular/core'; -import { CollectionLoadParameters, DataModel, EntitySchema, ExtendedTypedEntityCollection, GroupInfoData } from 'imx-qbm-dbts'; -import { ListReportContentData, PortalReportData } from 'imx-api-rps'; +import { CollectionLoadParameters, DataModel, EntitySchema, ExtendedTypedEntityCollection, GroupInfoData } from '@imx-modules/imx-qbm-dbts'; +import { ListReportContentData, PortalReportData } from '@imx-modules/imx-api-rps'; import { RpsApiService } from '../rps-api-client.service'; import { ListReportDataProvider } from '../list-report-viewer/list-report-data-provider.interface'; diff --git a/imxweb/projects/rps/src/lib/subscriptions/list-report-viewer-sidesheet/list-report-viewer-sidesheet.component.html b/imxweb/projects/rps/src/lib/subscriptions/list-report-viewer-sidesheet/list-report-viewer-sidesheet.component.html index c2c23038f..01171b347 100644 --- a/imxweb/projects/rps/src/lib/subscriptions/list-report-viewer-sidesheet/list-report-viewer-sidesheet.component.html +++ b/imxweb/projects/rps/src/lib/subscriptions/list-report-viewer-sidesheet/list-report-viewer-sidesheet.component.html @@ -1,8 +1,8 @@
    - +
    - -
    \ No newline at end of file +
    diff --git a/imxweb/projects/rps/src/lib/subscriptions/list-report-viewer-sidesheet/list-report-viewer-sidesheet.component.scss b/imxweb/projects/rps/src/lib/subscriptions/list-report-viewer-sidesheet/list-report-viewer-sidesheet.component.scss index 1d7a151a2..005b37b1d 100644 --- a/imxweb/projects/rps/src/lib/subscriptions/list-report-viewer-sidesheet/list-report-viewer-sidesheet.component.scss +++ b/imxweb/projects/rps/src/lib/subscriptions/list-report-viewer-sidesheet/list-report-viewer-sidesheet.component.scss @@ -1,4 +1,4 @@ -:host{ +:host { flex: 1 1 auto; display: flex; flex-direction: column; @@ -8,4 +8,4 @@ display: flex; flex-direction: column; } -} \ No newline at end of file +} diff --git a/imxweb/projects/rps/src/lib/subscriptions/list-report-viewer-sidesheet/list-report-viewer-sidesheet.component.ts b/imxweb/projects/rps/src/lib/subscriptions/list-report-viewer-sidesheet/list-report-viewer-sidesheet.component.ts index d4a6722f7..e81a7b4f4 100644 --- a/imxweb/projects/rps/src/lib/subscriptions/list-report-viewer-sidesheet/list-report-viewer-sidesheet.component.ts +++ b/imxweb/projects/rps/src/lib/subscriptions/list-report-viewer-sidesheet/list-report-viewer-sidesheet.component.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -26,9 +26,9 @@ import { Component, Inject } from '@angular/core'; import { EUI_SIDESHEET_DATA } from '@elemental-ui/core'; +import { ListReportDataProvider } from '../../list-report-viewer/list-report-data-provider.interface'; import { ReportSubscription } from '../report-subscription/report-subscription'; import { ReportSubscriptionService } from '../report-subscription/report-subscription.service'; -import { ListReportDataProvider } from '../../list-report-viewer/list-report-data-provider.interface'; /** * Represents the content of a side sheet, that shows the data of a list report @@ -50,7 +50,7 @@ export class ListReportViewerSidesheetComponent { constructor( @Inject(EUI_SIDESHEET_DATA) public readonly data: { dataService: ListReportDataProvider; subscription?: ReportSubscription }, - private readonly reportSubscriptionService: ReportSubscriptionService + private readonly reportSubscriptionService: ReportSubscriptionService, ) { if (data.subscription) { this.reportParameter = data.subscription.getParameterDictionary(); @@ -58,9 +58,11 @@ export class ListReportViewerSidesheetComponent { } /** - * Downloads the subscription + * Downloads the subscription */ public async downloadReport(): Promise { - this.reportSubscriptionService.downloadSubsciption(this.data.subscription); + if (this.data.subscription) { + this.reportSubscriptionService.downloadSubsciption(this.data.subscription); + } } } diff --git a/imxweb/projects/rps/src/lib/subscriptions/report-subscription/report-parameter-wrapper.ts b/imxweb/projects/rps/src/lib/subscriptions/report-subscription/report-parameter-wrapper.ts index 68a9dc1c9..8403c9ed8 100644 --- a/imxweb/projects/rps/src/lib/subscriptions/report-subscription/report-parameter-wrapper.ts +++ b/imxweb/projects/rps/src/lib/subscriptions/report-subscription/report-parameter-wrapper.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -24,10 +24,16 @@ * */ -import { EntityWriteDataColumn, IFkCandidateProvider, IEntityColumn, ParameterData, ReadWriteExtTypedEntity } from 'imx-qbm-dbts'; -import { ParameterContainer } from 'qer'; -import { ClassloggerService, ImxTranslationProviderService } from 'qbm'; import { EventEmitter } from '@angular/core'; +import { + EntityWriteDataColumn, + IEntityColumn, + IFkCandidateProvider, + ParameterData, + ReadWriteExtTypedEntity, +} from '@imx-modules/imx-qbm-dbts'; +import { ClassloggerService, ImxTranslationProviderService } from 'qbm'; +import { ParameterContainer } from 'qer'; export class ReportParameterWrapper { public startWriteData = new EventEmitter(); @@ -40,7 +46,7 @@ export class ReportParameterWrapper { private readonly logger: ClassloggerService, private parameters: ParameterData[], private getFkProviderItems: (parameter: ParameterData) => IFkCandidateProvider, - private typedEntity: ReadWriteExtTypedEntity + private typedEntity: ReadWriteExtTypedEntity, ) { this.container = new ParameterContainer(this.translationService, this.getFkProviderItems, this.logger, this.typedEntity); this.container.updateExtendedDataTriggered.subscribe((columnName) => { @@ -65,7 +71,9 @@ export class ReportParameterWrapper { const newParameters: ParameterData[] = this.typedEntity.extendedDataRead[0]; newParameters.forEach((parameter) => { - this.container.update(parameter.Property.ColumnName, parameter); + if (parameter.Property?.ColumnName) { + this.container.update(parameter.Property.ColumnName, parameter); + } // TODO: remove parameters not returned by the server }); @@ -76,16 +84,18 @@ export class ReportParameterWrapper { } this.parameters?.forEach((parameter) => { - const extendedDataGenerator = (newValue) => [ - [ - { - Name: parameter.Property.ColumnName, - Value: newValue, - }, - ], - ]; - const column = this.container.add(parameter.Property.ColumnName, parameter, extendedDataGenerator); - columns.push(column); + if (parameter.Property?.ColumnName) { + const extendedDataGenerator = (newValue) => [ + [ + { + Name: parameter?.Property?.ColumnName, + Value: newValue, + }, + ], + ]; + const column = this.container.add(parameter.Property.ColumnName, parameter, extendedDataGenerator); + if (column) columns.push(column); + } }); return columns; diff --git a/imxweb/projects/rps/src/lib/subscriptions/report-subscription/report-subscription.service.ts b/imxweb/projects/rps/src/lib/subscriptions/report-subscription/report-subscription.service.ts index b6e3963ee..bbe22f2f9 100644 --- a/imxweb/projects/rps/src/lib/subscriptions/report-subscription/report-subscription.service.ts +++ b/imxweb/projects/rps/src/lib/subscriptions/report-subscription/report-subscription.service.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -24,26 +24,26 @@ * */ -import { Injectable, Injector } from '@angular/core'; +import { ElementRef, Injectable, Injector } from '@angular/core'; -import { PortalReports, PortalSubscription, V2ApiClientMethodFactory } from 'imx-api-rps'; +import { Overlay } from '@angular/cdk/overlay'; +import { HttpClient } from '@angular/common/http'; +import { EuiDownloadDirective, EuiDownloadService } from '@elemental-ui/core'; +import { PortalReports, PortalSubscription, V2ApiClientMethodFactory } from '@imx-modules/imx-api-rps'; import { CollectionLoadParameters, EntitySchema, + ExtendedTypedEntityCollection, FkProviderItem, - ParameterData, IFkCandidateProvider, - TypedEntityBuilder, - ExtendedTypedEntityCollection, MethodDefinition, -} from 'imx-qbm-dbts'; + ParameterData, + TypedEntityBuilder, +} from '@imx-modules/imx-qbm-dbts'; +import { AppConfigService, ElementalUiConfigService, ImxTranslationProviderService } from 'qbm'; import { ParameterDataService } from 'qer'; import { RpsApiService } from '../../rps-api-client.service'; import { ReportSubscription } from './report-subscription'; -import { EuiDownloadDirective } from '@elemental-ui/core'; -import { AppConfigService, ElementalUiConfigService, ImxTranslationProviderService } from 'qbm'; -import { HttpClient } from '@angular/common/http'; -import { Overlay } from '@angular/cdk/overlay'; @Injectable({ providedIn: 'root', @@ -59,7 +59,8 @@ export class ReportSubscriptionService { private readonly overlay: Overlay, private readonly injector: Injector, private readonly translator: ImxTranslationProviderService, - private readonly parameterDataService: ParameterDataService + private readonly parameterDataService: ParameterDataService, + private readonly downloadService: EuiDownloadService, ) {} public get PortalSubscriptionInteractiveSchema(): EntitySchema { @@ -73,13 +74,19 @@ export class ReportSubscriptionService { } public buildRpsSubscription(subscription: PortalSubscription): ReportSubscription { - return new ReportSubscription(subscription, this.translator, (entity, data) => this.getFkProvider(entity, data), this.parameterDataService); + return new ReportSubscription( + subscription, + this.translator, + (entity, data) => this.getFkProvider(entity, data), + this.parameterDataService, + ); } - public async createNewSubscription(uidReport: string): Promise { + public async createNewSubscription(uidReport: string, suffix?: string): Promise { const subscription = await this.api.typedClient.PortalSubscriptionInteractive.Get(); await subscription.Data[0].UID_RPSReport.Column.PutValue(uidReport); - await subscription.Data[0].Ident_RPSSubscription.Column.PutValue(subscription.Data[0].UID_RPSReport.Column.GetDisplayValue()); + await subscription.Data[0].Ident_RPSSubscription.Column.PutValue(subscription.Data[0].UID_RPSReport.Column.GetDisplayValue() + (suffix ?? ''), + ); const allowedFormats = subscription.Data[0].ExportFormat.Column.GetMetadata().GetLimitedValues(); if (allowedFormats && allowedFormats.filter((f) => f.Value == 'PDF').length > 0) { await subscription.Data[0].ExportFormat.Column.PutValue('PDF'); @@ -93,7 +100,13 @@ export class ReportSubscriptionService { const def = new MethodDefinition(this.apiMethodFactory.portal_subscription_interactive_report_get(parameters.entityid, parameters)); // not pretty, but the download directive does not support dynamic URLs - const directive = new EuiDownloadDirective(null /* no element */, this.http, this.overlay, this.injector); + const directive = new EuiDownloadDirective( + new ElementRef('') /* no element */, + this.http, + this.overlay, + this.injector, + this.downloadService, + ); directive.downloadOptions = { ...this.elementalUiConfigService.Config.downloadOptions, fileMimeType: '', // override elementalUiConfigService; get mime type from server @@ -106,34 +119,43 @@ export class ReportSubscriptionService { private getFkProvider(subscription: PortalSubscription, parameterData: ParameterData): IFkCandidateProvider { var api = this.api; - return new class implements IFkCandidateProvider { - getProviderItem(_columnName, fkTableName) { - if (parameterData.Property.FkRelation) { - return this.getFkProviderItem(subscription, parameterData.Property.ColumnName, parameterData.Property.FkRelation.ParentTableName); + return new (class implements IFkCandidateProvider { + getProviderItem(_columnName, fkTableName): FkProviderItem { + if (parameterData?.Property?.FkRelation) { + return this.getFkProviderItem( + subscription, + _columnName, + parameterData?.Property?.FkRelation?.ParentTableName, + parameterData?.Property?.FkRelation?.ParentColumnName, + ); } - if (parameterData.Property.ValidReferencedTables) { + if (parameterData?.Property?.ValidReferencedTables) { const t = parameterData.Property.ValidReferencedTables.map((parentTableRef) => - this.getFkProviderItem(subscription, parameterData.Property.ColumnName, parentTableRef.TableName) - ).filter(t => t.fkTableName == fkTableName); - if (t.length == 1) - return t[0]; - return null; + this.getFkProviderItem(subscription, parameterData?.Property?.ColumnName, parentTableRef?.TableName, 'XObjectKey'), + ).filter((t) => t.fkTableName == fkTableName); + if (t.length == 1) return t[0]; } + return this.getFkProviderItem(subscription); } - - private getFkProviderItem(subscription: PortalSubscription, columnName: string, fkTableName: string): FkProviderItem { + private getFkProviderItem( + subscription: PortalSubscription, + columnName: string | undefined = '', + fkTableName: string | undefined = '', + fkColumnName: string | undefined = '', + ): FkProviderItem { return { columnName, fkTableName, + fkColumnName, parameterNames: ['OrderBy', 'StartIndex', 'PageSize', 'filter', 'withProperties', 'search'], load: async (__entity, parameters?) => { return api.client.portal_subscription_interactive_parameter_candidates_post( columnName, fkTableName, subscription.InteractiveEntityWriteData, - parameters + parameters, ); }, getDataModel: async () => ({}), @@ -142,11 +164,15 @@ export class ReportSubscriptionService { columnName, fkTableName, subscription.InteractiveEntityWriteData, - { parentkey } + { parentkey }, ); }, }; } - } + })(); + } + + public async sendViaMail(uid: string): Promise{ + return this.api.client.portal_subscription_sendmail_post(uid); } } diff --git a/imxweb/projects/rps/src/lib/subscriptions/report-subscription/report-subscription.ts b/imxweb/projects/rps/src/lib/subscriptions/report-subscription/report-subscription.ts index 5b16c13b5..0003a40d5 100644 --- a/imxweb/projects/rps/src/lib/subscriptions/report-subscription/report-subscription.ts +++ b/imxweb/projects/rps/src/lib/subscriptions/report-subscription/report-subscription.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -26,8 +26,8 @@ import { EventEmitter } from '@angular/core'; -import { PortalSubscription } from 'imx-api-rps'; -import { IFkCandidateProvider, IClientProperty, IEntityColumn, ParameterData } from 'imx-qbm-dbts'; +import { PortalSubscription } from '@imx-modules/imx-api-rps'; +import { IClientProperty, IEntityColumn, IFkCandidateProvider, ParameterData } from '@imx-modules/imx-qbm-dbts'; import { BaseCdr, ColumnDependentReference, ImxTranslationProviderService } from 'qbm'; import { ParameterDataService } from 'qer'; @@ -40,6 +40,8 @@ export class ReportSubscription { private parameterColumns: IEntityColumn[] = []; + public parameterNames: string[]; + public startWriteData = new EventEmitter(); public endWriteData = new EventEmitter(); @@ -47,18 +49,19 @@ export class ReportSubscription { public subscription: PortalSubscription, translationService: ImxTranslationProviderService, private getFkProviderItem: (cartItem: PortalSubscription, parameter: ParameterData) => IFkCandidateProvider, - parameterDataService: ParameterDataService + parameterDataService: ParameterDataService, ) { this.reportEntityWrapper = new ReportParameterWrapper( translationService, parameterDataService.logger, - this.subscription?.extendedDataRead?.length ? this.subscription.extendedDataRead[0] : null, + this.subscription?.extendedDataRead?.length ? this.subscription.extendedDataRead[0] : [], (parameterData) => this.getFkProviderItem(this.subscription, parameterData), - this.subscription + this.subscription, ); this.hasParameter = this.subscription?.extendedDataRead?.[0]?.length > 0; this.parameterColumns = this.hasParameter ? this.reportEntityWrapper.columns : []; + this.parameterNames = this.parameterColumns.map((elem) => elem.ColumnName); this.reportEntityWrapper.startWriteData.subscribe((elem) => this.startWriteData.emit(elem)); this.reportEntityWrapper.endWriteData.subscribe(() => this.endWriteData.emit()); @@ -78,13 +81,21 @@ export class ReportSubscription { this.subscription.ExportFormat.Column, this.subscription.AddtlSubscribers.Column, ] - : properties.map((prop) => this.subscription.GetEntity().GetColumn(prop.ColumnName)); + : properties.map((prop) => this.subscription.GetEntity().GetColumn(prop.ColumnName ?? '')); return columns.map((col) => new BaseCdr(col)); } - public getParameterCdr(): ColumnDependentReference[] { - return this.parameterColumns.map((col) => new BaseCdr(col)); + public getParameterCdr(hiddenColumns: string[] = []): ColumnDependentReference[] { + return this.parameterColumns.filter(elem=> hiddenColumns.indexOf(elem.ColumnName) === -1).map((col) => new BaseCdr(col)); + } + + public async fillColumnsWithPreset(presetParameter: { [key: string]: string }): Promise { + Object.entries(presetParameter).forEach(async ([key, value]) => { + const test = this.parameterColumns.find((elem) => elem.ColumnName === key); + await test?.PutValue(value); + + }); } public getParameterDictionary(): { [key: string]: any } { @@ -104,7 +115,7 @@ export class ReportSubscription { ].concat(this.parameterColumns); } - public async submit(reload:boolean = false): Promise { + public async submit(reload: boolean = false): Promise { this.subscription.extendedData = [this.parameterColumns.map((col) => ({ Name: col.ColumnName, Value: col.GetValue() }))]; return this.subscription.GetEntity().Commit(reload); diff --git a/imxweb/projects/rps/src/lib/subscriptions/report-view-config/report-view-config.component.html b/imxweb/projects/rps/src/lib/subscriptions/report-view-config/report-view-config.component.html index ff638ff7d..d26ea5ec6 100644 --- a/imxweb/projects/rps/src/lib/subscriptions/report-view-config/report-view-config.component.html +++ b/imxweb/projects/rps/src/lib/subscriptions/report-view-config/report-view-config.component.html @@ -22,7 +22,7 @@
    @@ -37,7 +37,13 @@
    - diff --git a/imxweb/projects/rps/src/lib/subscriptions/report-view-config/report-view-config.component.scss b/imxweb/projects/rps/src/lib/subscriptions/report-view-config/report-view-config.component.scss index fcfb1d417..4c582e9ec 100644 --- a/imxweb/projects/rps/src/lib/subscriptions/report-view-config/report-view-config.component.scss +++ b/imxweb/projects/rps/src/lib/subscriptions/report-view-config/report-view-config.component.scss @@ -18,7 +18,7 @@ overflow: hidden; } - .imx-export-type{ + .imx-export-type { display: flex; flex-direction: row; @@ -27,7 +27,7 @@ } } - .mat-card { + .mat-mdc-card { margin: 3px; } @@ -35,14 +35,6 @@ margin-top: 20px; } - .mat-radio-group { - margin-bottom: 10px; - - > .mat-radio-button { - margin-right: 10px; - } - } - .imx-report-form { flex: 1 1 auto; display: flex; @@ -69,10 +61,6 @@ display: none; } - .imx-report-alert { - margin-top: 20px; - } - .imx-no-results { text-align: center; display: flex; @@ -82,10 +70,6 @@ align-items: center; justify-content: center; - .eui-icon { - font-size: 100px; - } - p { margin: 0; font-size: 18px; @@ -97,10 +81,6 @@ :host { .imx-no-results { - .eui-icon { - color: $color-gray-10; - } - p { color: $color-gray-40; } @@ -110,10 +90,6 @@ .eui-dark-theme { :host { .imx-no-results { - .eui-icon { - color: $color-gray-20; - } - p { color: $color-gray-10; } @@ -124,10 +100,6 @@ .eui-contrast-theme { :host { .imx-no-results { - .eui-icon { - color: $color-gray-10; - } - p { color: $color-gray-0; } diff --git a/imxweb/projects/rps/src/lib/subscriptions/report-view-config/report-view-config.component.ts b/imxweb/projects/rps/src/lib/subscriptions/report-view-config/report-view-config.component.ts index 70f726472..09a53ec4c 100644 --- a/imxweb/projects/rps/src/lib/subscriptions/report-view-config/report-view-config.component.ts +++ b/imxweb/projects/rps/src/lib/subscriptions/report-view-config/report-view-config.component.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -25,21 +25,21 @@ */ import { ChangeDetectorRef, Component, OnDestroy } from '@angular/core'; -import { FormArray, FormControl, FormGroup, UntypedFormControl, Validators } from '@angular/forms'; +import { AbstractControl, FormArray, FormControl, FormGroup, Validators } from '@angular/forms'; import { EuiSidesheetRef, EuiSidesheetService } from '@elemental-ui/core'; -import { Subscription } from 'rxjs'; import { TranslateService } from '@ngx-translate/core'; +import { Subscription } from 'rxjs'; -import { BaseCdr, BusyService, ColumnDependentReference, ErrorService } from 'qbm'; +import { BaseCdr, BusyService, calculateSidesheetWidth, ColumnDependentReference, ErrorService } from 'qbm'; +import { ListReportViewerService } from '../../list-report-viewer/list-report-viewer.service'; +import { ListReportViewerSidesheetComponent } from '../list-report-viewer-sidesheet/list-report-viewer-sidesheet.component'; import { ReportSubscription } from '../report-subscription/report-subscription'; import { ReportSubscriptionService } from '../report-subscription/report-subscription.service'; -import { ListReportViewerSidesheetComponent } from '../list-report-viewer-sidesheet/list-report-viewer-sidesheet.component'; -import { ListReportViewerService } from '../../list-report-viewer/list-report-viewer.service'; interface reportForm { viewType: FormControl<'view' | 'export'>; - reportTable: FormControl; - exportType: FormControl + reportTable: FormControl; + exportType: FormControl; parameters: FormArray; } @Component({ @@ -49,12 +49,12 @@ interface reportForm { }) export class ReportViewConfigComponent implements OnDestroy { public readonly reportFormGroup = new FormGroup({ - viewType: new FormControl('view'), - reportTable: new FormControl(undefined, Validators.required), - exportType: new FormControl(undefined), - parameters: new FormArray([]), + viewType: new FormControl('view', { nonNullable: true }), + reportTable: new FormControl(undefined, { nonNullable: true, validators: Validators.required }), + exportType: new FormControl(undefined, { nonNullable: true }), + parameters: new FormArray([]), }); - public newSubscription: ReportSubscription; + public newSubscription: ReportSubscription | undefined; public parameterCdrList: ColumnDependentReference[] = []; public formatCdr: ColumnDependentReference; public busyService = new BusyService(); @@ -84,26 +84,26 @@ export class ReportViewConfigComponent implements OnDestroy { private readonly cdref: ChangeDetectorRef, private readonly translate: TranslateService, private readonly viewReportService: ListReportViewerService, - errorService: ErrorService + errorService: ErrorService, ) { this.subscriptions.push( this.sidesheetRef.closeClicked().subscribe(async () => { this.sidesheetRef.close(false); - }) + }), ); this.subscriptions.push( this.busyService.busyStateChanged.subscribe((elem) => { this.isLoading = elem; this.cdref.detectChanges(); - }) + }), ); this.subscriptions.push( this.reportFormGroup.controls.reportTable.valueChanges.subscribe(async (val) => { const isBusy = this.busyService.beginBusy(); try { - this.uidReport = val; + this.uidReport = val ?? ''; this.formControls.clear(); // Standard caption is "Format (e-mail attachment)" -> change @@ -122,18 +122,17 @@ export class ReportViewConfigComponent implements OnDestroy { this.formatCdr = new BaseCdr(this.newSubscription.subscription.ExportFormat.Column, format); this.parameterCdrList = [...this.newSubscription.getParameterCdr()]; this.cdref.detectChanges(); - } else this.newSubscription = null; + } else this.newSubscription = undefined; } finally { isBusy.endBusy(); - this.reportIsLoaded = this.newSubscription != null; + this.reportIsLoaded = !!this.newSubscription; } - }) + }), ); this.disposable = errorService.setTarget('sidesheet'); } - public ngOnDestroy(): void { // sometimes there are problems with usage of disposed components setTimeout(() => { @@ -147,23 +146,29 @@ export class ReportViewConfigComponent implements OnDestroy { if (this.reportFormGroup.controls.viewType.value === 'view' && this.isListReport) { await this.viewReportInTable(); } else { - this.reportSubscriptionService.downloadSubsciption(this.newSubscription); + if (this.newSubscription) { + this.reportSubscriptionService.downloadSubsciption(this.newSubscription); + } } } - public addFormControl(control: UntypedFormControl): void { + public addFormControl(control: AbstractControl): void { this.formControls.push(control); this.cdref.detectChanges(); } + public addExportControl(control: AbstractControl): void { + this.reportFormGroup.controls.exportType = control.value; + } + private async viewReportInTable(): Promise { this.viewReportService.setUidReport(this.uidReport); const data = { dataService: this.viewReportService, subscription: this.newSubscription }; this.sideSheet.open(ListReportViewerSidesheetComponent, { title: await this.translate.get('#LDS#Heading View Report').toPromise(), - subTitle: this.newSubscription.subscription.GetEntity().GetDisplay(), + subTitle: this.newSubscription?.subscription.GetEntity().GetDisplay(), padding: '0', - width: 'max(550px,55%)', + width: calculateSidesheetWidth(), testId: 'report-view-config-report-viewer', data, }); diff --git a/imxweb/projects/rps/src/lib/subscriptions/subscription-details/subscription-details.component.html b/imxweb/projects/rps/src/lib/subscriptions/subscription-details/subscription-details.component.html index 6a5ac50b4..abdc75da7 100644 --- a/imxweb/projects/rps/src/lib/subscriptions/subscription-details/subscription-details.component.html +++ b/imxweb/projects/rps/src/lib/subscriptions/subscription-details/subscription-details.component.html @@ -7,7 +7,13 @@
    -
    diff --git a/imxweb/projects/rps/src/lib/subscriptions/subscription-details/subscription-details.component.scss b/imxweb/projects/rps/src/lib/subscriptions/subscription-details/subscription-details.component.scss index e07bc8be0..aac8fbdeb 100644 --- a/imxweb/projects/rps/src/lib/subscriptions/subscription-details/subscription-details.component.scss +++ b/imxweb/projects/rps/src/lib/subscriptions/subscription-details/subscription-details.component.scss @@ -3,16 +3,3 @@ flex-direction: column; max-height: 100%; } - - -.button-row { - border-top-style: solid; - border-top-width: 0px; - display: flex; - flex-direction: row; - justify-content: flex-end; - padding: 16px 8px 16px 24px; -} -.button-row > * { - margin-left: 10px; -} \ No newline at end of file diff --git a/imxweb/projects/rps/src/lib/subscriptions/subscription-details/subscription-details.component.ts b/imxweb/projects/rps/src/lib/subscriptions/subscription-details/subscription-details.component.ts index e77f874f4..ee7c07b14 100644 --- a/imxweb/projects/rps/src/lib/subscriptions/subscription-details/subscription-details.component.ts +++ b/imxweb/projects/rps/src/lib/subscriptions/subscription-details/subscription-details.component.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -26,19 +26,17 @@ import { Component, Inject, OnDestroy } from '@angular/core'; import { UntypedFormGroup } from '@angular/forms'; -import { EuiLoadingService, EuiSidesheetRef, EUI_SIDESHEET_DATA } from '@elemental-ui/core'; +import { EUI_SIDESHEET_DATA, EuiLoadingService, EuiSidesheetRef } from '@elemental-ui/core'; import { Subscription } from 'rxjs'; -import { OverlayRef } from '@angular/cdk/overlay'; import { ColumnDependentReference, ConfirmationService } from 'qbm'; import { ReportSubscription } from '../report-subscription/report-subscription'; @Component({ templateUrl: './subscription-details.component.html', - styleUrls: ['./subscription-details.component.scss'] + styleUrls: ['./subscription-details.component.scss'], }) export class SubscriptionDetailsComponent implements OnDestroy { - public readonly formGroup = new UntypedFormGroup({}); public readonly cdrList: ColumnDependentReference[]; public closeClickSubscription: Subscription; @@ -48,11 +46,10 @@ export class SubscriptionDetailsComponent implements OnDestroy { @Inject(EUI_SIDESHEET_DATA) public readonly subscription: ReportSubscription, public readonly sidesheetRef: EuiSidesheetRef, private readonly busyService: EuiLoadingService, - private readonly confirmation: ConfirmationService + private readonly confirmation: ConfirmationService, ) { this.closeClickSubscription = this.sidesheetRef.closeClicked().subscribe(async () => { - if (!this.formGroup.dirty - || await this.confirmation.confirmLeaveWithUnsavedChanges()) { + if (!this.formGroup.dirty || (await this.confirmation.confirmLeaveWithUnsavedChanges())) { this.sidesheetRef.close(this.reload); } }); @@ -63,12 +60,13 @@ export class SubscriptionDetailsComponent implements OnDestroy { } public async submit(): Promise { - let overlayRef: OverlayRef; - setTimeout(() => overlayRef = this.busyService.show()); + if (this.busyService.overlayRefs.length === 0) { + this.busyService.show(); + } try { await this.subscription.submit(true); } finally { - setTimeout(() => this.busyService.hide(overlayRef)); + this.busyService.hide(); this.reload = true; this.formGroup.markAsPristine(); } diff --git a/imxweb/projects/rps/src/lib/subscriptions/subscription-properties/subscription-properties.component.html b/imxweb/projects/rps/src/lib/subscriptions/subscription-properties/subscription-properties.component.html index d067d362a..bcd63b47b 100644 --- a/imxweb/projects/rps/src/lib/subscriptions/subscription-properties/subscription-properties.component.html +++ b/imxweb/projects/rps/src/lib/subscriptions/subscription-properties/subscription-properties.component.html @@ -1,35 +1,49 @@ -
    +

    - {{'#LDS#Heading Subscription Details' | translate}} + {{ '#LDS#Heading Subscription Details' | translate }}

    - +

    - {{'#LDS#Heading Parameters' | translate}} + {{ '#LDS#Heading Parameters' | translate }}

    - +
    - {{'#LDS#There are no parameters for this subscription.' | translate}} + {{ '#LDS#There are no parameters for this subscription.' | translate }}
    - + - +
    -
    \ No newline at end of file + diff --git a/imxweb/projects/rps/src/lib/subscriptions/subscription-properties/subscription-properties.component.scss b/imxweb/projects/rps/src/lib/subscriptions/subscription-properties/subscription-properties.component.scss index 32f1f29d8..134cd679b 100644 --- a/imxweb/projects/rps/src/lib/subscriptions/subscription-properties/subscription-properties.component.scss +++ b/imxweb/projects/rps/src/lib/subscriptions/subscription-properties/subscription-properties.component.scss @@ -1,4 +1,3 @@ - .imx-parameter-grid { display: grid; grid-template-columns: 1fr 1fr; @@ -11,9 +10,9 @@ h4 { margin-bottom: 40px; } -@media only screen and (max-width: 1024px) { +@media only screen and (max-width: 1024px) { .imx-parameter-grid > div { grid-column-start: 1; grid-column-end: 3; - } -} \ No newline at end of file + } +} diff --git a/imxweb/projects/rps/src/lib/subscriptions/subscription-properties/subscription-properties.component.ts b/imxweb/projects/rps/src/lib/subscriptions/subscription-properties/subscription-properties.component.ts index 251e9d437..c9d6a56fe 100644 --- a/imxweb/projects/rps/src/lib/subscriptions/subscription-properties/subscription-properties.component.ts +++ b/imxweb/projects/rps/src/lib/subscriptions/subscription-properties/subscription-properties.component.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -25,19 +25,18 @@ */ import { Component, Input, OnChanges, OnInit } from '@angular/core'; -import { UntypedFormArray, UntypedFormControl, UntypedFormGroup } from '@angular/forms'; +import { AbstractControl, UntypedFormArray, UntypedFormGroup } from '@angular/forms'; -import { IClientProperty } from 'imx-qbm-dbts'; +import { IClientProperty } from '@imx-modules/imx-qbm-dbts'; import { ColumnDependentReference } from 'qbm'; import { ReportSubscription } from '../report-subscription/report-subscription'; @Component({ selector: 'imx-subscription-properties', templateUrl: './subscription-properties.component.html', - styleUrls: ['./subscription-properties.component.scss'] + styleUrls: ['./subscription-properties.component.scss'], }) export class SubscriptionPropertiesComponent implements OnInit, OnChanges { - public cdrList: ColumnDependentReference[] = []; public parameterCdrList: ColumnDependentReference[] = []; public readonly subscriptionPropertiesFormArray = new UntypedFormArray([]); @@ -58,7 +57,6 @@ export class SubscriptionPropertiesComponent implements OnInit, OnChanges { } public ngOnChanges(): void { - this.subscriptionPropertiesFormArray.clear(); this.cdrList = this.subscription == null ? [] : this.subscription.getCdrs(this.displayedColumns); @@ -75,7 +73,7 @@ export class SubscriptionPropertiesComponent implements OnInit, OnChanges { } } - public addFormControl(array: UntypedFormArray, control: UntypedFormControl): void { + public addFormControl(array: UntypedFormArray, control: AbstractControl): void { setTimeout(() => { array.push(control); }); diff --git a/imxweb/projects/rps/src/lib/subscriptions/subscription-wizard/report-selector/report-selector.component.html b/imxweb/projects/rps/src/lib/subscriptions/subscription-wizard/report-selector/report-selector.component.html index 1eb105405..c03f8a199 100644 --- a/imxweb/projects/rps/src/lib/subscriptions/subscription-wizard/report-selector/report-selector.component.html +++ b/imxweb/projects/rps/src/lib/subscriptions/subscription-wizard/report-selector/report-selector.component.html @@ -1,17 +1,33 @@
    - + -
    - +
    +
    {{ '#LDS#Report' | translate }} - - - + + +
    {{ candidate.GetEntity().GetDisplay() }}
    {{ candidate.Description.Column.GetDisplayValue() }}
    diff --git a/imxweb/projects/rps/src/lib/subscriptions/subscription-wizard/report-selector/report-selector.component.scss b/imxweb/projects/rps/src/lib/subscriptions/subscription-wizard/report-selector/report-selector.component.scss index 0c13d3358..46fd915fe 100644 --- a/imxweb/projects/rps/src/lib/subscriptions/subscription-wizard/report-selector/report-selector.component.scss +++ b/imxweb/projects/rps/src/lib/subscriptions/subscription-wizard/report-selector/report-selector.component.scss @@ -1,4 +1,4 @@ -@import "@elemental-ui/core/src/styles/_palette.scss"; +@import '@elemental-ui/core/src/styles/_palette.scss'; :host { flex: 1; @@ -8,16 +8,6 @@ .report-selector-eui-search { display: flex; - - .eui-search { - width: 100%; - } - - ::ng-deep .eui-search.mat-form-field.mat-form-field-appearance-outline { - min-width: 280px; - flex: 1; - margin-bottom: 10px; - } } .imx-candidate { @@ -53,15 +43,9 @@ } } - .imx-report-listing { flex: 1; display: grid; grid-template-columns: 1fr 21px; margin-right: -21px; } - -.mat-spinner { - margin-top: 15px; - margin-left: 5px; -} diff --git a/imxweb/projects/rps/src/lib/subscriptions/subscription-wizard/report-selector/report-selector.component.ts b/imxweb/projects/rps/src/lib/subscriptions/subscription-wizard/report-selector/report-selector.component.ts index aea127694..a86dae8bf 100644 --- a/imxweb/projects/rps/src/lib/subscriptions/subscription-wizard/report-selector/report-selector.component.ts +++ b/imxweb/projects/rps/src/lib/subscriptions/subscription-wizard/report-selector/report-selector.component.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -24,18 +24,16 @@ * */ -import { ListRange } from '@angular/cdk/collections'; -import { CdkVirtualScrollViewport } from '@angular/cdk/scrolling'; -import { AfterViewInit, ChangeDetectorRef, Component, forwardRef, Input, OnDestroy, OnInit, ViewChild } from '@angular/core'; -import { ControlValueAccessor, UntypedFormControl, NG_VALUE_ACCESSOR } from '@angular/forms'; +import { AfterViewInit, ChangeDetectorRef, Component, forwardRef, Input, OnDestroy, OnInit } from '@angular/core'; +import { ControlValueAccessor, NG_VALUE_ACCESSOR, UntypedFormControl } from '@angular/forms'; import { MatSelectionListChange } from '@angular/material/list'; import { Subscription } from 'rxjs'; import { debounceTime, distinctUntilChanged } from 'rxjs/operators'; -import { PortalReports } from 'imx-api-rps'; -import { CollectionLoadParameters } from 'imx-qbm-dbts'; -import { ReportSubscriptionService } from '../../report-subscription/report-subscription.service'; +import { PortalReports } from '@imx-modules/imx-api-rps'; +import { CollectionLoadParameters } from '@imx-modules/imx-qbm-dbts'; import { SettingsService } from 'qbm'; +import { ReportSubscriptionService } from '../../report-subscription/report-subscription.service'; @Component({ selector: 'imx-report-selector', @@ -68,7 +66,7 @@ export class ReportSelectorComponent implements ControlValueAccessor, OnInit, On constructor( private readonly changeDetectorRef: ChangeDetectorRef, private readonly settings: SettingsService, - private readonly reportSubscriptionService: ReportSubscriptionService + private readonly reportSubscriptionService: ReportSubscriptionService, ) {} public async ngOnInit(): Promise { @@ -107,8 +105,10 @@ export class ReportSelectorComponent implements ControlValueAccessor, OnInit, On public updateSelected(elem: MatSelectionListChange): void { // Only one can be selected const chosenElem = elem.options.find((ele) => ele.selected); - this.writeValue(chosenElem.value.GetEntity().GetKeys()[0]); - this.onChange(chosenElem.value.GetEntity().GetKeys()[0]); + if (chosenElem) { + this.writeValue(chosenElem.value.GetEntity().GetKeys()[0]); + this.onChange(chosenElem.value.GetEntity().GetKeys()[0]); + } } private async loadReports(newState?: CollectionLoadParameters): Promise { @@ -128,7 +128,7 @@ export class ReportSelectorComponent implements ControlValueAccessor, OnInit, On this.searchControl.valueChanges.pipe(distinctUntilChanged(), debounceTime(300)).subscribe(async (value) => { await this.loadReports({ StartIndex: 0, PageSize: this.settings.PageSizeForAllElements, search: value }); this.changeDetectorRef.detectChanges(); - }) + }), ); } } diff --git a/imxweb/projects/rps/src/lib/subscriptions/subscription-wizard/subscription-overview/subscription-overview.component.html b/imxweb/projects/rps/src/lib/subscriptions/subscription-wizard/subscription-overview/subscription-overview.component.html index f58a45c78..c4d01482b 100644 --- a/imxweb/projects/rps/src/lib/subscriptions/subscription-wizard/subscription-overview/subscription-overview.component.html +++ b/imxweb/projects/rps/src/lib/subscriptions/subscription-wizard/subscription-overview/subscription-overview.component.html @@ -2,27 +2,35 @@
    -
    - +
    + - {{'#LDS#You cannot receive the report. You have not specified an email address. Please add an email address to your user account.' | - translate}} + {{ + '#LDS#You cannot receive the report. You have not specified an email address. Please add an email address to your user account.' + | translate + }}
    -
    - - - {{'#LDS#The following subscribers cannot receive the report. No email addresses have been specified for the user accounts of these subscribers.' |translate}} - - - {{additionalRecipientWithoutEmail.join('; ')}} - +
    + + + {{ + '#LDS#The following subscribers cannot receive the report. No email addresses have been specified for the user accounts of these subscribers.' + | translate + }} + + + {{ additionalRecipientWithoutEmail.join('; ') }} +
    - {{'#LDS#The overview is calculated. Please wait.' | translate}} -
    \ No newline at end of file + {{ '#LDS#The overview is calculated. Please wait.' | translate }} +
    diff --git a/imxweb/projects/rps/src/lib/subscriptions/subscription-wizard/subscription-overview/subscription-overview.component.scss b/imxweb/projects/rps/src/lib/subscriptions/subscription-wizard/subscription-overview/subscription-overview.component.scss index 24b9d07b6..129269625 100644 --- a/imxweb/projects/rps/src/lib/subscriptions/subscription-wizard/subscription-overview/subscription-overview.component.scss +++ b/imxweb/projects/rps/src/lib/subscriptions/subscription-wizard/subscription-overview/subscription-overview.component.scss @@ -1,4 +1,4 @@ -@import "@elemental-ui/core/src/styles/_palette.scss"; +@import '@elemental-ui/core/src/styles/_palette.scss'; .imx-report-table { display: flex; @@ -14,10 +14,6 @@ imx-property-viewer { gap: 10px 20px; } -.imx-overview-alert { - margin: 10px 0; -} - .imx-wait-for-overview-load { margin: 10px 0; } diff --git a/imxweb/projects/rps/src/lib/subscriptions/subscription-wizard/subscription-overview/subscription-overview.component.ts b/imxweb/projects/rps/src/lib/subscriptions/subscription-wizard/subscription-overview/subscription-overview.component.ts index a4d0d48bb..6efd8da64 100644 --- a/imxweb/projects/rps/src/lib/subscriptions/subscription-wizard/subscription-overview/subscription-overview.component.ts +++ b/imxweb/projects/rps/src/lib/subscriptions/subscription-wizard/subscription-overview/subscription-overview.component.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -25,22 +25,22 @@ */ import { Component, Input, OnDestroy, OnInit } from '@angular/core'; -import { IEntityColumn } from 'imx-qbm-dbts'; -import { BehaviorSubject } from 'rxjs'; import { EuiLoadingService } from '@elemental-ui/core'; -import { OverlayRef } from '@angular/cdk/overlay'; +import { IEntityColumn } from '@imx-modules/imx-qbm-dbts'; +import { BehaviorSubject } from 'rxjs'; -import { MultiValueService, AuthenticationService } from 'qbm'; +import { AuthenticationService, MultiValueService } from 'qbm'; import { PersonService } from 'qer'; import { ReportSubscription } from '../../report-subscription/report-subscription'; +type NameAddress = { name: string; address: string }; + @Component({ selector: 'imx-subscription-overview', templateUrl: './subscription-overview.component.html', - styleUrls: ['./subscription-overview.component.scss'] + styleUrls: ['./subscription-overview.component.scss'], }) export class SubscriptionOverviewComponent implements OnInit, OnDestroy { - public userIsMissingEMail = false; public additionalRecipientWithoutEmail: string[] = []; public setProperties: IEntityColumn[] = []; @@ -55,14 +55,15 @@ export class SubscriptionOverviewComponent implements OnInit, OnDestroy { private readonly multiValue: MultiValueService, private readonly busyService: EuiLoadingService, private readonly personService: PersonService, - authentication: AuthenticationService) { - authentication.onSessionResponse.subscribe(state => this.currentUserId = state.UserUid); + authentication: AuthenticationService, + ) { + authentication.onSessionResponse.subscribe((state) => (this.currentUserId = state.UserUid ?? '')); } public ngOnInit(): void { if (this.subscribersChanged) { this.subscribersChanged.subscribe(async () => { - if (this.subscription != null) { + if (this.subscription) { this.setProperties = this.subscription.getDisplayableColums(); } await this.checkEmailAddresses(); @@ -77,35 +78,37 @@ export class SubscriptionOverviewComponent implements OnInit, OnDestroy { } private async checkEmailAddresses(): Promise { - if (this.subscription == null) { + if (!this.subscription) { return; } - let overlayRef: OverlayRef; - setTimeout(() => overlayRef = this.busyService.show()); + if (this.busyService.overlayRefs.length === 0) { + this.busyService.show(); + } try { - this.userIsMissingEMail = (await this.getPersonNameAndAddress(this.currentUserId)).address === ''; - const subscribers = this.multiValue.getValues(this.subscription.subscription.AddtlSubscribers.value); - const subscriberMails = []; + const subscribers = this.multiValue.getValues(this.subscription.subscription.AddtlSubscribers.value) ?? []; + const subscriberMails: NameAddress[] = []; for (const value of subscribers) { const mail = await this.getPersonNameAndAddress(value); subscriberMails.push(mail); } this.additionalRecipientWithoutEmail = subscriberMails - .filter(elem => elem.address == null || elem.address === '').map(elem => elem.name); + .filter((elem) => elem.address == null || elem.address === '') + .map((elem) => elem.name); } finally { - setTimeout(() => this.busyService.hide(overlayRef)); + this.busyService.hide(); } } - private async getPersonNameAndAddress(uid: string): Promise<{ name: string, address: string }> { + private async getPersonNameAndAddress(uid: string): Promise { const user = await this.personService.get(uid); - return user.Data.length > 0 ? { - name: user.Data[0].GetEntity().GetDisplay(), - address: user.Data[0].DefaultEmailAddress.value - } : null; + return user.Data.length > 0 + ? { + name: user.Data[0].GetEntity().GetDisplay(), + address: user.Data[0].DefaultEmailAddress.value, + } + : { name: '', address: '' }; } } - diff --git a/imxweb/projects/rps/src/lib/subscriptions/subscription-wizard/subscription-wizard.component.html b/imxweb/projects/rps/src/lib/subscriptions/subscription-wizard/subscription-wizard.component.html index 907927116..bb39922bd 100644 --- a/imxweb/projects/rps/src/lib/subscriptions/subscription-wizard/subscription-wizard.component.html +++ b/imxweb/projects/rps/src/lib/subscriptions/subscription-wizard/subscription-wizard.component.html @@ -5,8 +5,14 @@
    -
    -
    @@ -23,11 +29,17 @@ [subscription]="newSubscription" >
    -
    +
    -
    @@ -46,7 +58,7 @@ formControlName="additionalSubscribers" > -
    +
    @@ -58,12 +70,18 @@ {{ '#LDS#Check and create subscription' | translate }} - -
    + +
    - +
    diff --git a/imxweb/projects/rps/src/lib/subscriptions/subscription-wizard/subscription-wizard.component.scss b/imxweb/projects/rps/src/lib/subscriptions/subscription-wizard/subscription-wizard.component.scss index 97991f3be..1c8b2f24d 100644 --- a/imxweb/projects/rps/src/lib/subscriptions/subscription-wizard/subscription-wizard.component.scss +++ b/imxweb/projects/rps/src/lib/subscriptions/subscription-wizard/subscription-wizard.component.scss @@ -1,4 +1,4 @@ -@import "@elemental-ui/core/src/styles/_palette.scss"; +@import '@elemental-ui/core/src/styles/_palette.scss'; .imx-report-table { display: flex; margin-top: 10px; @@ -18,12 +18,6 @@ imx-property-viewer { margin: 30px 0; } -.imx-step-button { - > :first-child { - margin-right: 10px; - } -} - @media only screen and (max-width: 1024px) { .imx-wizard-info { margin: 0; diff --git a/imxweb/projects/rps/src/lib/subscriptions/subscription-wizard/subscription-wizard.component.ts b/imxweb/projects/rps/src/lib/subscriptions/subscription-wizard/subscription-wizard.component.ts index 8e7901481..c550ddbc5 100644 --- a/imxweb/projects/rps/src/lib/subscriptions/subscription-wizard/subscription-wizard.component.ts +++ b/imxweb/projects/rps/src/lib/subscriptions/subscription-wizard/subscription-wizard.component.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -24,14 +24,13 @@ * */ -import { OverlayRef } from '@angular/cdk/overlay'; import { StepperSelectionEvent } from '@angular/cdk/stepper'; import { Component, OnDestroy, ViewChild } from '@angular/core'; import { UntypedFormControl, UntypedFormGroup, Validators } from '@angular/forms'; import { EuiLoadingService, EuiSidesheetRef } from '@elemental-ui/core'; import { BehaviorSubject, Subscription } from 'rxjs'; -import { EntitySchema, IClientProperty } from 'imx-qbm-dbts'; +import { EntitySchema, IClientProperty } from '@imx-modules/imx-qbm-dbts'; import { ConfirmationService, MultiSelectFormcontrolComponent } from 'qbm'; import { ReportSubscription } from '../report-subscription/report-subscription'; import { ReportSubscriptionService } from '../report-subscription/report-subscription.service'; @@ -39,16 +38,15 @@ import { ReportSubscriptionService } from '../report-subscription/report-subscri @Component({ selector: 'imx-subscription-wizard', templateUrl: './subscription-wizard.component.html', - styleUrls: ['./subscription-wizard.component.scss'] + styleUrls: ['./subscription-wizard.component.scss'], }) export class SubscriptionWizardComponent implements OnDestroy { - public readonly reportFormGroup = new UntypedFormGroup({ - reportTable: new UntypedFormControl(undefined, Validators.required) + reportTable: new UntypedFormControl(undefined, Validators.required), }); public readonly reportParameterFormGroup = new UntypedFormGroup({}); public readonly additionalSubscribersFormGroup = new UntypedFormGroup({ - additionalSubscribers: new UntypedFormControl(undefined) + additionalSubscribers: new UntypedFormControl(undefined), }); public isLoadingOverview = false; public newSubscription: ReportSubscription; @@ -73,8 +71,10 @@ export class SubscriptionWizardComponent implements OnDestroy { this.entitySchema.Columns.ExportFormat, ]; this.closeClickSubscription = this.sidesheetRef.closeClicked().subscribe(async () => { - if ((!this.reportFormGroup.dirty && !this.reportParameterFormGroup.dirty && !this.additionalSubscribersFormGroup.dirty) - || await this.confirmation.confirmLeaveWithUnsavedChanges()) { + if ( + (!this.reportFormGroup.dirty && !this.reportParameterFormGroup.dirty && !this.additionalSubscribersFormGroup.dirty) || + (await this.confirmation.confirmLeaveWithUnsavedChanges()) + ) { this.sidesheetRef.close(false); } }); @@ -86,16 +86,16 @@ export class SubscriptionWizardComponent implements OnDestroy { public async selectedStepChanged(event: StepperSelectionEvent): Promise { if (event.selectedIndex === 1 && event.previouslySelectedIndex === 0) { - let overlayRef: OverlayRef; - setTimeout(() => overlayRef = this.busyService.show()); + if (this.busyService.overlayRefs.length === 0) { + this.busyService.show(); + } try { - this.newSubscription = - await this.reportSubscriptionService.createNewSubscription(this.reportFormGroup.get('reportTable').value); - this.additionalSubscribersFormGroup.get('additionalSubscribers') - .setValue(this.newSubscription.subscription.AddtlSubscribers.Column); - + this.newSubscription = await this.reportSubscriptionService.createNewSubscription(this.reportFormGroup.get('reportTable')?.value); + this.additionalSubscribersFormGroup + .get('additionalSubscribers') + ?.setValue(this.newSubscription.subscription.AddtlSubscribers.Column); } finally { - setTimeout(() => this.busyService.hide(overlayRef)); + this.busyService.hide(); } } @@ -108,14 +108,15 @@ export class SubscriptionWizardComponent implements OnDestroy { } public async submit(): Promise { - let overlayRef: OverlayRef; - setTimeout(() => overlayRef = this.busyService.show()); + if (this.busyService.overlayRefs.length === 0) { + this.busyService.show(); + } try { await this.newSubscription.submit(); this.newSubscription.unsubscribeEvents(); this.sidesheetRef.close(true); } finally { - setTimeout(() => this.busyService.hide(overlayRef)); + this.busyService.hide(); } } } diff --git a/imxweb/projects/rps/src/lib/subscriptions/subscriptions.component.html b/imxweb/projects/rps/src/lib/subscriptions/subscriptions.component.html index 7c3abe49c..53d662e52 100644 --- a/imxweb/projects/rps/src/lib/subscriptions/subscriptions.component.html +++ b/imxweb/projects/rps/src/lib/subscriptions/subscriptions.component.html @@ -1,4 +1,4 @@ - +
    - - + + @@ -32,10 +41,21 @@ - - - diff --git a/imxweb/projects/rps/src/lib/subscriptions/subscriptions.component.scss b/imxweb/projects/rps/src/lib/subscriptions/subscriptions.component.scss index 46ace64b8..a5ae8d46d 100644 --- a/imxweb/projects/rps/src/lib/subscriptions/subscriptions.component.scss +++ b/imxweb/projects/rps/src/lib/subscriptions/subscriptions.component.scss @@ -1,11 +1,8 @@ @import '@elemental-ui/core/src/styles/_palette.scss'; -@import '../../../../../shared/scss/common-table.scss'; +@import 'base/mixins'; :host { - display: flex; - flex-direction: column; - overflow: hidden; - height: inherit; + @include flex-column-container-fill(); } imx-data-table { @@ -17,50 +14,18 @@ imx-data-table { margin-right: 10px; } -:host ::ng-deep imx-data-table .mat-header-row .mat-header-cell { - font-weight: 600; - font-size: 14px; - padding: 0 10px; -} - -:host ::ng-deep imx-data-table .mat-row .mat-cell { - padding: 0 10px; -} - .imx-separate-menu-item { border-top: 1px solid $black-c; } -.imx-table-container { - @include imx-flex-fill-control-hidden-overflow(); -} - -:host ::ng-deep eui-sidesheet .eui-sidesheet__content { - display: flex; - flex-direction: column; - max-height: 100%; - box-sizing: content-box; -} - -.mat-card { - display: flex; - flex-direction: column; - height: inherit; - overflow: hidden; - - .mat-card-content { +.mat-mdc-card { + .mat-mdc-card-content { + @include flex-column-container-fill(); overflow-y: auto; overflow-x: hidden; - flex: 1 1 auto; - display: flex; - flex-direction: column; } } -.mat-stroked-button { - @include imx-icon-for-image-button(); -} - -.imx-button-bar { - @include imx-button-bar(); +.mat-mdc-outlined-button { + @include image-button-icon(); } diff --git a/imxweb/projects/rps/src/lib/subscriptions/subscriptions.component.ts b/imxweb/projects/rps/src/lib/subscriptions/subscriptions.component.ts index c476d87c2..bee66bb3f 100644 --- a/imxweb/projects/rps/src/lib/subscriptions/subscriptions.component.ts +++ b/imxweb/projects/rps/src/lib/subscriptions/subscriptions.component.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -24,22 +24,28 @@ * */ -import { OverlayRef } from '@angular/cdk/overlay'; import { Component, OnInit } from '@angular/core'; import { EuiLoadingService, EuiSidesheetService } from '@elemental-ui/core'; import { TranslateService } from '@ngx-translate/core'; -import { PortalSubscription } from 'imx-api-rps'; -import { CollectionLoadParameters, DisplayColumns, EntitySchema, ValType } from 'imx-qbm-dbts'; -import { ConfirmationService, DataSourceToolbarSettings, ClientPropertyForTableColumns, SnackBarService, BusyService } from 'qbm'; +import { PortalSubscription } from '@imx-modules/imx-api-rps'; +import { CollectionLoadParameters, DisplayColumns, EntitySchema, TypedEntity, ValType } from '@imx-modules/imx-qbm-dbts'; +import { + BusyService, + ClientPropertyForTableColumns, + ConfirmationService, + DataSourceToolbarSettings, + SnackBarService, + calculateSidesheetWidth, +} from 'qbm'; +import { ListReportViewerService } from '../list-report-viewer/list-report-viewer.service'; +import { ListReportViewerSidesheetComponent } from './list-report-viewer-sidesheet/list-report-viewer-sidesheet.component'; import { ReportSubscription } from './report-subscription/report-subscription'; import { ReportSubscriptionService } from './report-subscription/report-subscription.service'; import { ReportViewConfigComponent } from './report-view-config/report-view-config.component'; import { SubscriptionDetailsComponent } from './subscription-details/subscription-details.component'; import { SubscriptionWizardComponent } from './subscription-wizard/subscription-wizard.component'; import { SubscriptionsService } from './subscriptions.service'; -import { ListReportViewerSidesheetComponent } from './list-report-viewer-sidesheet/list-report-viewer-sidesheet.component'; -import { ListReportViewerService } from '../list-report-viewer/list-report-viewer.service'; @Component({ selector: 'imx-subscriptions', @@ -66,7 +72,7 @@ export class SubscriptionsComponent implements OnInit { private readonly snackbar: SnackBarService, private readonly translate: TranslateService, private readonly busyServiceElemental: EuiLoadingService, - private readonly listReportViewerService: ListReportViewerService + private readonly listReportViewerService: ListReportViewerService, ) { this.entitySchema = subscriptionService.PortalSubscriptionSchema; this.displayedColumns = [ @@ -130,7 +136,7 @@ export class SubscriptionsComponent implements OnInit { title: await this.translate.get('#LDS#Heading View Report').toPromise(), subTitle: subscription.GetEntity().GetDisplay(), padding: '0', - width: 'max(550px,55%)', + width: calculateSidesheetWidth(), testId: 'subscription-report-viewer', data, }); @@ -144,12 +150,13 @@ export class SubscriptionsComponent implements OnInit { identifier: 'subscriptions-confirm-unsubscribe-report', }) ) { - let overlayRef: OverlayRef; - setTimeout(() => (overlayRef = this.busyServiceElemental.show())); + if (this.busyServiceElemental.overlayRefs.length === 0) { + this.busyServiceElemental.show(); + } try { await this.subscriptionService.deleteSubscription(subscription.GetEntity().GetKeys()[0]); } finally { - setTimeout(() => this.busyServiceElemental.hide(overlayRef)); + this.busyServiceElemental.hide(); } const message = { key: '#LDS#You have successfully unsubscribed from the report "{0}".', @@ -161,17 +168,18 @@ export class SubscriptionsComponent implements OnInit { } } - public async editSubscription(subscription: PortalSubscription): Promise { - let rpsSubscription: ReportSubscription; - let overlayRef: OverlayRef; - setTimeout(() => (overlayRef = this.busyServiceElemental.show())); + public async editSubscription(subscription: TypedEntity): Promise { + let rpsSubscription: ReportSubscription | undefined = undefined; + if (this.busyServiceElemental.overlayRefs.length === 0) { + this.busyServiceElemental.show(); + } try { const sub = await this.subscriptionService.getSubscriptionInteractive(subscription.GetEntity().GetKeys()[0]); if (sub.Data.length > 0) { rpsSubscription = this.rpsReportService.buildRpsSubscription(sub.Data[0]); } } finally { - setTimeout(() => this.busyServiceElemental.hide(overlayRef)); + this.busyServiceElemental.hide(); } if (rpsSubscription) { @@ -180,7 +188,7 @@ export class SubscriptionsComponent implements OnInit { subTitle: subscription.GetEntity().GetDisplay(), testId: 'edit-subscription-sidesheet', padding: '0px', - width: 'max(700px,70%)', + width: calculateSidesheetWidth(1000), disableClose: true, data: rpsSubscription, }); @@ -195,7 +203,7 @@ export class SubscriptionsComponent implements OnInit { const sidesheetRef = this.sideSheet.open(SubscriptionWizardComponent, { title: await this.translate.get('#LDS#Heading Add Report Subscription').toPromise(), padding: '0px', - width: '70%', + width: calculateSidesheetWidth(1000), disableClose: true, testId: 'subscriptions-create', }); @@ -211,7 +219,7 @@ export class SubscriptionsComponent implements OnInit { const sidesheetRef = this.sideSheet.open(ReportViewConfigComponent, { title: await this.translate.get('#LDS#Heading View a Report').toPromise(), padding: '0px', - width: '70%', + width: calculateSidesheetWidth(1000), testId: 'subscriptions-view-config', }); diff --git a/imxweb/projects/rps/src/lib/subscriptions/subscriptions.module.ts b/imxweb/projects/rps/src/lib/subscriptions/subscriptions.module.ts index 10002c9fd..5eb75acb2 100644 --- a/imxweb/projects/rps/src/lib/subscriptions/subscriptions.module.ts +++ b/imxweb/projects/rps/src/lib/subscriptions/subscriptions.module.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -41,7 +41,7 @@ import { MultiSelectFormcontrolModule, UserMessageModule, RouteGuardService, - BusyIndicatorModule + BusyIndicatorModule, } from 'qbm'; import { ReportSelectorComponent } from './subscription-wizard/report-selector/report-selector.component'; import { ReportSubscriptionService } from './report-subscription/report-subscription.service'; @@ -53,52 +53,44 @@ import { SubscriptionsService } from './subscriptions.service'; import { SubscriptionWizardComponent } from './subscription-wizard/subscription-wizard.component'; import { ReportViewConfigComponent } from './report-view-config/report-view-config.component'; import { ListReportViewerModule } from '../list-report-viewer/list-report-viewer.module'; -import { HttpClientModule } from '@angular/common/http'; +import { provideHttpClient, withInterceptorsFromDi } from '@angular/common/http'; import { OverlayModule } from '@angular/cdk/overlay'; import { ListReportViewerSidesheetComponent } from './list-report-viewer-sidesheet/list-report-viewer-sidesheet.component'; - const routes: Routes = [ { path: 'reportsubscriptions', component: SubscriptionsComponent, canActivate: [RouteGuardService], - resolve: [RouteGuardService] - } + resolve: [RouteGuardService], + }, ]; -@NgModule({ - declarations: [ - ReportSelectorComponent, - ReportViewConfigComponent, - SubscriptionDetailsComponent, - SubscriptionPropertiesComponent, - SubscriptionOverviewComponent, - SubscriptionWizardComponent, - SubscriptionsComponent, - ListReportViewerSidesheetComponent, - ], - imports: [ - CdrModule, - CommonModule, - ConfirmationModule, - DataSourceToolbarModule, - DataTableModule, - EuiCoreModule, - EuiMaterialModule, - FormsModule, - HttpClientModule, - LdsReplaceModule, - MultiSelectFormcontrolModule, - OverlayModule, - ReactiveFormsModule, - RouterModule.forChild(routes), - ScrollingModule, - TranslateModule, - UserMessageModule, - BusyIndicatorModule, - ListReportViewerModule, - ], - providers: [ReportSubscriptionService, SubscriptionsService], -}) +@NgModule({ declarations: [ + ReportSelectorComponent, + ReportViewConfigComponent, + SubscriptionDetailsComponent, + SubscriptionPropertiesComponent, + SubscriptionOverviewComponent, + SubscriptionWizardComponent, + SubscriptionsComponent, + ListReportViewerSidesheetComponent, + ], imports: [CdrModule, + CommonModule, + ConfirmationModule, + DataSourceToolbarModule, + DataTableModule, + EuiCoreModule, + EuiMaterialModule, + FormsModule, + LdsReplaceModule, + MultiSelectFormcontrolModule, + OverlayModule, + ReactiveFormsModule, + RouterModule.forChild(routes), + ScrollingModule, + TranslateModule, + UserMessageModule, + BusyIndicatorModule, + ListReportViewerModule], providers: [ReportSubscriptionService, SubscriptionsService, provideHttpClient(withInterceptorsFromDi())] }) export class SubscriptionsModule {} diff --git a/imxweb/projects/rps/src/lib/subscriptions/subscriptions.service.ts b/imxweb/projects/rps/src/lib/subscriptions/subscriptions.service.ts index 1f84c57ff..08edf1881 100644 --- a/imxweb/projects/rps/src/lib/subscriptions/subscriptions.service.ts +++ b/imxweb/projects/rps/src/lib/subscriptions/subscriptions.service.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -26,25 +26,26 @@ import { Injectable } from '@angular/core'; -import { PortalSubscription, PortalSubscriptionInteractive } from 'imx-api-rps'; -import { CollectionLoadParameters, EntitySchema, ExtendedEntityCollectionData, ExtendedTypedEntityCollection } from 'imx-qbm-dbts'; +import { PortalSubscription, PortalSubscriptionInteractive } from '@imx-modules/imx-api-rps'; +import { + CollectionLoadParameters, + EntitySchema, + ExtendedEntityCollectionData, + ExtendedTypedEntityCollection, +} from '@imx-modules/imx-qbm-dbts'; import { RpsApiService } from '../rps-api-client.service'; @Injectable({ - providedIn: 'root' + providedIn: 'root', }) export class SubscriptionsService { - - constructor(private readonly api: RpsApiService) { - } + constructor(private readonly api: RpsApiService) {} public get PortalSubscriptionSchema(): EntitySchema { return this.api.typedClient.PortalSubscription.GetSchema(); } - public async getSubscriptions(parameters?: CollectionLoadParameters): - Promise> { - + public async getSubscriptions(parameters?: CollectionLoadParameters): Promise> { return this.api.typedClient.PortalSubscription.Get(parameters); } diff --git a/imxweb/projects/rps/src/public_api.ts b/imxweb/projects/rps/src/public_api.ts index 993943c42..6fad357ed 100644 --- a/imxweb/projects/rps/src/public_api.ts +++ b/imxweb/projects/rps/src/public_api.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -31,5 +31,5 @@ export { RpsConfigModule } from './lib/rps-config.module'; export { SubscriptionsModule } from './lib/subscriptions/subscriptions.module'; export { SubscriptionsComponent } from './lib/subscriptions/subscriptions.component'; -export { ReportButtonModule} from './lib/report-button/report-button.module'; -export { ReportButtonComponent} from './lib/report-button/report-button.component'; +export { ReportButtonModule } from './lib/report-button/report-button.module'; +export { ReportButtonComponent } from './lib/report-button/report-button.component'; diff --git a/imxweb/projects/rps/src/test.ts b/imxweb/projects/rps/src/test.ts index f7ac7d548..159c87d7d 100644 --- a/imxweb/projects/rps/src/test.ts +++ b/imxweb/projects/rps/src/test.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -26,24 +26,14 @@ // This file is required by karma.conf.js and loads recursively all the .spec and framework files -import 'core-js/es7/reflect'; -import 'zone.js/dist/zone'; -import 'zone.js/dist/zone-testing'; +// Zone must be imported first. Be careful with prettier import organizing +import 'zone.js'; +import 'zone.js/testing'; + import { getTestBed } from '@angular/core/testing'; -import { - BrowserDynamicTestingModule, - platformBrowserDynamicTesting -} from '@angular/platform-browser-dynamic/testing'; +import { BrowserDynamicTestingModule, platformBrowserDynamicTesting } from '@angular/platform-browser-dynamic/testing'; +import 'core-js/es/reflect'; import { TestHelperModule } from 'qbm'; -declare const require: any; - // First, initialize the Angular testing environment. -getTestBed().initTestEnvironment( - [BrowserDynamicTestingModule, TestHelperModule], - platformBrowserDynamicTesting() -); -// Then we find all the tests. -const context = require.context('./', true, /\.spec\.ts$/); -// And load the modules. -context.keys().map(context); +getTestBed().initTestEnvironment([BrowserDynamicTestingModule, TestHelperModule], platformBrowserDynamicTesting()); diff --git a/imxweb/projects/rps/tsconfig.lib.json b/imxweb/projects/rps/tsconfig.lib.json index 6bc419f84..534c734a0 100644 --- a/imxweb/projects/rps/tsconfig.lib.json +++ b/imxweb/projects/rps/tsconfig.lib.json @@ -1,16 +1,17 @@ /* To learn more about this file see: https://angular.io/config/tsconfig. */ { "extends": "../../tsconfig.json", + "angularCompilerOptions": { + "strictTemplates": true + }, "compilerOptions": { "outDir": "../../out-tsc/lib", + "strictNullChecks": true, "declaration": true, "declarationMap": true, "sourceMap": true, "inlineSources": true, "types": [] }, - "exclude": [ - "src/test.ts", - "**/*.spec.ts" - ] + "exclude": ["src/test.ts", "**/*.spec.ts"] } diff --git a/imxweb/projects/rps/tsconfig.lib.prod.json b/imxweb/projects/rps/tsconfig.lib.prod.json index 61c7592e7..fb40dbbb0 100644 --- a/imxweb/projects/rps/tsconfig.lib.prod.json +++ b/imxweb/projects/rps/tsconfig.lib.prod.json @@ -3,8 +3,5 @@ "extends": "./tsconfig.lib.json", "compilerOptions": { "declarationMap": false - }, - "angularCompilerOptions": { - "enableIvy": true } } diff --git a/imxweb/projects/rps/tsconfig.spec.json b/imxweb/projects/rps/tsconfig.spec.json index 16da33db0..6bd74e1f7 100644 --- a/imxweb/projects/rps/tsconfig.spec.json +++ b/imxweb/projects/rps/tsconfig.spec.json @@ -1,17 +1,10 @@ { "extends": "../../tsconfig.json", "compilerOptions": { + "strictNullChecks": false, "outDir": "../../out-tsc/spec", - "types": [ - "jasmine", - "node" - ] + "types": ["jasmine", "node"] }, - "files": [ - "src/test.ts" - ], - "include": [ - "**/*.spec.ts", - "**/*.d.ts" - ] + "files": ["src/test.ts"], + "include": ["**/*.spec.ts", "**/*.d.ts"] } diff --git a/imxweb/projects/rps/tslint.json b/imxweb/projects/rps/tslint.json deleted file mode 100644 index 8bab15f53..000000000 --- a/imxweb/projects/rps/tslint.json +++ /dev/null @@ -1,17 +0,0 @@ -{ - "extends": "../../tslint.json", - "rules": { - "directive-selector": [ - true, - "attribute", - "imx", - "camelCase" - ], - "component-selector": [ - true, - "element", - "imx", - "kebab-case" - ] - } -} diff --git a/imxweb/projects/sac/.compodocrc.json b/imxweb/projects/sac/.compodocrc.json index a6c3a50eb..6c98fce8a 100644 --- a/imxweb/projects/sac/.compodocrc.json +++ b/imxweb/projects/sac/.compodocrc.json @@ -1,6 +1,6 @@ { "name": "IMX Web - SAC Library", - "output": "../../documentation/v92/sac", + "output": "../../documentation/v93/sac", "theme": "material", "assetsFolder": "../../compodoc/assets", "customLogo": "../../compodoc/assets/images/oneidentity-logo.png", diff --git a/imxweb/projects/sac/.eslintrc.json b/imxweb/projects/sac/.eslintrc.json new file mode 100644 index 000000000..e30ddf787 --- /dev/null +++ b/imxweb/projects/sac/.eslintrc.json @@ -0,0 +1,35 @@ +{ + "extends": "../../.eslintrc.json", + "ignorePatterns": ["!**/*", "**/*.spec.ts"], + "overrides": [ + { + "files": ["*.ts"], + "parserOptions": { + "project": ["imxweb/projects/sac/tsconfig.lib.json", "imxweb/projects/sac/tsconfig.spec.json"], + "createDefaultProgram": true + }, + "rules": { + "@angular-eslint/directive-selector": [ + "error", + { + "type": "attribute", + "prefix": "imx", + "style": "camelCase" + } + ], + "@angular-eslint/component-selector": [ + "error", + { + "type": "element", + "prefix": "imx", + "style": "kebab-case" + } + ] + } + }, + { + "files": ["*.html"], + "rules": {} + } + ] +} diff --git a/imxweb/projects/sac/imx-plugin-config.json b/imxweb/projects/sac/imx-plugin-config.json index c0e0963e8..4c90b46d7 100644 --- a/imxweb/projects/sac/imx-plugin-config.json +++ b/imxweb/projects/sac/imx-plugin-config.json @@ -1,8 +1,8 @@ { "qer-app-portal": [ - { - "Container": "sac", - "Name": "SacConfigModule" - } + { + "Container": "sac", + "Name": "SacConfigModule" + } ] } diff --git a/imxweb/projects/sac/karma.conf.js b/imxweb/projects/sac/karma.conf.js index 211193c9d..3e53a3ac8 100644 --- a/imxweb/projects/sac/karma.conf.js +++ b/imxweb/projects/sac/karma.conf.js @@ -15,7 +15,7 @@ module.exports = function (config) { require('karma-junit-reporter'), ], client: { - clearContext: false // leave Jasmine Spec Runner output visible in browser + clearContext: false, // leave Jasmine Spec Runner output visible in browser }, coverageIstanbulReporter: { dir: require('path').join(__dirname, 'results'), @@ -23,7 +23,7 @@ module.exports = function (config) { fixWebpackSourcePaths: true, 'report-config': { html: { - subdir: 'coverage-html' + subdir: 'coverage-html', }, }, thresholds: { @@ -40,13 +40,14 @@ module.exports = function (config) { port: 9876, captureTimeout: 210000, browserDisconnectTolerance: 3, - browserDisconnectTimeout : 210000, - browserNoActivityTimeout : 210000, + browserDisconnectTimeout: 210000, + browserNoActivityTimeout: 210000, colors: true, logLevel: config.LOG_INFO, autoWatch: true, browsers: ['Chrome'], singleRun: false, - restartOnFileChange: true + failOnEmptyTestSuite: false, + restartOnFileChange: true, }); }; diff --git a/imxweb/projects/sac/ng-package.dynamic.json b/imxweb/projects/sac/ng-package.dynamic.json index cf1da4569..92e2e6b4f 100644 --- a/imxweb/projects/sac/ng-package.dynamic.json +++ b/imxweb/projects/sac/ng-package.dynamic.json @@ -16,12 +16,11 @@ "@elemental-ui/core", "@ngx-translate/core", "@ngx-translate/http-loader", - "applicationinsights-js", "billboard.js" ], - "dest": "../../html/sac", + "dest": "../../html/qer-app-portal/sac", "lib": { "entryFile": "src/public_api.ts", - "styleIncludePaths": ["../../shared/assets"] + "styleIncludePaths": ["../../shared/scss"] } } diff --git a/imxweb/projects/sac/ng-package.json b/imxweb/projects/sac/ng-package.json index 78073cb8b..657dc704f 100644 --- a/imxweb/projects/sac/ng-package.json +++ b/imxweb/projects/sac/ng-package.json @@ -16,12 +16,11 @@ "@elemental-ui/core", "@ngx-translate/core", "@ngx-translate/http-loader", - "applicationinsights-js", "billboard.js" ], "dest": "../../dist/sac", "lib": { "entryFile": "src/public_api.ts", - "styleIncludePaths": ["../../shared/assets"] + "styleIncludePaths": ["../../shared/scss"] } } diff --git a/imxweb/projects/sac/package.json b/imxweb/projects/sac/package.json index 61cfeef62..1143c92c1 100644 --- a/imxweb/projects/sac/package.json +++ b/imxweb/projects/sac/package.json @@ -1,29 +1,7 @@ { "name": "sac", - "version": "9.2.1", + "version": "9.3.0", "private": true, - "peerDependencies": { - - }, - "dependencies": { - "@angular/animations": "^11.2.14", - "@angular/cdk": "^11.2.13", - "@angular/common": "^11.2.14", - "@angular/compiler": "^11.2.14", - "@angular/core": "^11.2.14", - "@angular/forms": "^11.2.14", - "@angular/material": "^11.2.13", - "@angular/material-moment-adapter": "^11.2.13", - "@angular/platform-browser": "^11.2.14", - "@angular/platform-browser-dynamic": "^11.2.14", - "@angular/router": "^11.2.14", - "@elemental-ui/cadence-icon": "file:imx-modules/elemental-ui_cadence-icon.tgz", - "@elemental-ui/core": "file:imx-modules/elemental-ui_core.tgz", - "@ngx-translate/core": "^11.0.1", - "@ngx-translate/http-loader": "^4.0.0", - "applicationinsights-js": "^1.0.21", - "billboard.js": "^1.8.0" - }, "bundledDependencies": [ "imx-api-sac" ] diff --git a/imxweb/projects/sac/project.json b/imxweb/projects/sac/project.json new file mode 100644 index 000000000..eae60b493 --- /dev/null +++ b/imxweb/projects/sac/project.json @@ -0,0 +1,49 @@ +{ + "$schema": "../../node_modules/nx/schemas/project-schema.json", + "name": "sac", + "sourceRoot": "projects/sac/src", + "implicitDependencies": ["qer"], + "projectType": "library", + "generators": { + "@schematics/angular:component": { + "style": "scss" + } + }, + "prefix": "imx", + "targets": { + "build": { + "executor": "@angular-devkit/build-angular:ng-packagr", + "options": { + "tsConfig": "projects/sac/tsconfig.lib.json", + "project": "projects/sac/ng-package.json" + }, + "configurations": { + "production": { + "tsConfig": "projects/sac/tsconfig.lib.prod.json" + }, + "dynamic": { + "project": "projects/sac/ng-package.dynamic.json" + } + }, + "outputs": ["{workspaceRoot}/dist/sac"] + }, + "test": { + "executor": "@angular-devkit/build-angular:karma", + "options": { + "main": "projects/sac/src/test.ts", + "tsConfig": "projects/sac/tsconfig.spec.json", + "karmaConfig": "projects/sac/karma.conf.js", + "stylePreprocessorOptions": { + "includePaths": ["./shared/assets", "./shared/scss"] + } + } + }, + "lint": { + "executor": "@angular-devkit/build-angular:tslint", + "options": { + "tsConfig": ["projects/sac/tsconfig.lib.json", "projects/sac/tsconfig.spec.json"], + "exclude": ["**/node_modules/**", "**/*.spec.ts", "**/*.json"] + } + } + } +} diff --git a/imxweb/projects/sac/src/lib/init.service.ts b/imxweb/projects/sac/src/lib/init.service.ts index ee065dc5c..8afb476de 100644 --- a/imxweb/projects/sac/src/lib/init.service.ts +++ b/imxweb/projects/sac/src/lib/init.service.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -24,18 +24,18 @@ * */ -import { Injectable } from "@angular/core"; -import { ExtService } from "qbm"; -import { SapComplianceViolationComponent } from "./sap-compliance-violation/sap-compliance-violation.component"; +import { Injectable } from '@angular/core'; +import { ExtService } from 'qbm'; +import { SapComplianceViolationComponent } from './sap-compliance-violation/sap-compliance-violation.component'; @Injectable({ providedIn: 'root' }) export class InitService { - - constructor( - private readonly extService: ExtService - ) { } + constructor(private readonly extService: ExtService) {} onInit() { - this.extService.register('RuleViolationsTab', { instance: SapComplianceViolationComponent, inputData: {label: '#LDS#Heading SAP Functions'}}); + this.extService.register('RuleViolationsTab', { + instance: SapComplianceViolationComponent, + inputData: { label: '#LDS#Heading SAP Functions' }, + }); } } diff --git a/imxweb/projects/sac/src/lib/sac-api-client.service.ts b/imxweb/projects/sac/src/lib/sac-api-client.service.ts index 263f341f8..bcb0688da 100644 --- a/imxweb/projects/sac/src/lib/sac-api-client.service.ts +++ b/imxweb/projects/sac/src/lib/sac-api-client.service.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -25,12 +25,12 @@ */ import { Injectable } from '@angular/core'; -import { V2Client, TypedClient } from 'imx-api-sac'; -import { ApiClient } from 'imx-qbm-dbts'; +import { V2Client, TypedClient } from '@imx-modules/imx-api-sac'; +import { ApiClient } from '@imx-modules/imx-qbm-dbts'; import { AppConfigService, ClassloggerService, ImxTranslationProviderService } from 'qbm'; @Injectable({ - providedIn: 'root' + providedIn: 'root', }) export class SapComplianceApiService { private tc: TypedClient; @@ -50,7 +50,8 @@ export class SapComplianceApiService { constructor( private readonly config: AppConfigService, private readonly logger: ClassloggerService, - private readonly translationProvider: ImxTranslationProviderService) { + private readonly translationProvider: ImxTranslationProviderService, + ) { try { // Use schema loaded by QBM client const schemaProvider = config.client; diff --git a/imxweb/projects/sac/src/lib/sac-config.module.ts b/imxweb/projects/sac/src/lib/sac-config.module.ts index 1795bf4d1..f5f442a4d 100644 --- a/imxweb/projects/sac/src/lib/sac-config.module.ts +++ b/imxweb/projects/sac/src/lib/sac-config.module.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -61,7 +61,10 @@ import { MatSortModule } from '@angular/material/sort'; ], }) export class SacConfigModule { - constructor(private readonly initservice: InitService, private readonly logger: ClassloggerService) { + constructor( + private readonly initservice: InitService, + private readonly logger: ClassloggerService, + ) { this.logger.info(this, '🔥 SAC loaded'); this.initservice.onInit(); this.logger.info(this, '▶️ SAC initialized'); diff --git a/imxweb/projects/sac/src/lib/sap-compliance-violation/sap-compliance-violation-views-by-ability/sap-compliance-violation-views-by-ability-builder.ts b/imxweb/projects/sac/src/lib/sap-compliance-violation/sap-compliance-violation-views-by-ability/sap-compliance-violation-views-by-ability-builder.ts index 6ab88b244..60fc66aa7 100644 --- a/imxweb/projects/sac/src/lib/sap-compliance-violation/sap-compliance-violation-views-by-ability/sap-compliance-violation-views-by-ability-builder.ts +++ b/imxweb/projects/sac/src/lib/sap-compliance-violation/sap-compliance-violation-views-by-ability/sap-compliance-violation-views-by-ability-builder.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -24,9 +24,9 @@ * */ -import { DbObjectKey, EntityCollectionData, EntityData, TypedEntityBuilder, TypedEntityCollectionData } from 'imx-qbm-dbts'; +import { DbObjectKey, EntityCollectionData, EntityData, TypedEntityBuilder, TypedEntityCollectionData } from '@imx-modules/imx-qbm-dbts'; import { SapComplianceByAbilityEntity } from './sap-compliance-violation-views-by-ability-entity'; -import { SAPUserFunctionSrcFLD } from 'imx-api-sac'; +import { SAPUserFunctionSrcFLD } from '@imx-modules/imx-api-sac'; export class SapComplianceByAbilityBuilder { public readonly entitySchema = SapComplianceByAbilityEntity.GetEntitySchema(); diff --git a/imxweb/projects/sac/src/lib/sap-compliance-violation/sap-compliance-violation-views-by-ability/sap-compliance-violation-views-by-ability-entity.ts b/imxweb/projects/sac/src/lib/sap-compliance-violation/sap-compliance-violation-views-by-ability/sap-compliance-violation-views-by-ability-entity.ts index fbc57bc87..cf78c926a 100644 --- a/imxweb/projects/sac/src/lib/sap-compliance-violation/sap-compliance-violation-views-by-ability/sap-compliance-violation-views-by-ability-entity.ts +++ b/imxweb/projects/sac/src/lib/sap-compliance-violation/sap-compliance-violation-views-by-ability/sap-compliance-violation-views-by-ability-entity.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -24,7 +24,7 @@ * */ -import { TypedEntity, EntitySchema, DisplayColumns, ValType, IReadValue } from 'imx-qbm-dbts'; +import { TypedEntity, EntitySchema, DisplayColumns, ValType, IReadValue } from '@imx-modules/imx-qbm-dbts'; export class SapComplianceByAbilityEntity extends TypedEntity { public readonly Ident_SAPProfile: IReadValue = this.GetEntityValue('Ident_SAPProfile'); diff --git a/imxweb/projects/sac/src/lib/sap-compliance-violation/sap-compliance-violation-views-by-ability/sap-compliance-violation-views-by-ability.component.html b/imxweb/projects/sac/src/lib/sap-compliance-violation/sap-compliance-violation-views-by-ability/sap-compliance-violation-views-by-ability.component.html index 1671260df..9a2fa46b7 100644 --- a/imxweb/projects/sac/src/lib/sap-compliance-violation/sap-compliance-violation-views-by-ability/sap-compliance-violation-views-by-ability.component.html +++ b/imxweb/projects/sac/src/lib/sap-compliance-violation/sap-compliance-violation-views-by-ability/sap-compliance-violation-views-by-ability.component.html @@ -19,16 +19,29 @@ [groupData]="groupData" [mode]="'manual'" data-imx-identifier="role-recommendation-result-data-table" - detailViewVisible="false" + [detailViewVisible]="false" (groupDataChanged)="onGroupingChange($event)" > - - - - - - - + + + + + + + + + + + + + +
    diff --git a/imxweb/projects/sac/src/lib/sap-compliance-violation/sap-compliance-violation-views-by-ability/sap-compliance-violation-views-by-ability.component.scss b/imxweb/projects/sac/src/lib/sap-compliance-violation/sap-compliance-violation-views-by-ability/sap-compliance-violation-views-by-ability.component.scss index a11973441..111600262 100644 --- a/imxweb/projects/sac/src/lib/sap-compliance-violation/sap-compliance-violation-views-by-ability/sap-compliance-violation-views-by-ability.component.scss +++ b/imxweb/projects/sac/src/lib/sap-compliance-violation/sap-compliance-violation-views-by-ability/sap-compliance-violation-views-by-ability.component.scss @@ -1,12 +1,12 @@ -@import "@elemental-ui/core/src/styles/_eui_palette.scss"; +@import '@elemental-ui/core/src/styles/_eui_palette.scss'; -.sap-analysis{ +.sap-analysis { display: flex; flex-direction: column; height: 100%; justify-content: space-between; gap: 16px; - &__table{ + &__table { overflow: hidden auto; flex-grow: 1; } diff --git a/imxweb/projects/sac/src/lib/sap-compliance-violation/sap-compliance-violation-views-by-ability/sap-compliance-violation-views-by-ability.component.ts b/imxweb/projects/sac/src/lib/sap-compliance-violation/sap-compliance-violation-views-by-ability/sap-compliance-violation-views-by-ability.component.ts index 10abcdf37..b3eb30f3d 100644 --- a/imxweb/projects/sac/src/lib/sap-compliance-violation/sap-compliance-violation-views-by-ability/sap-compliance-violation-views-by-ability.component.ts +++ b/imxweb/projects/sac/src/lib/sap-compliance-violation/sap-compliance-violation-views-by-ability/sap-compliance-violation-views-by-ability.component.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -24,9 +24,8 @@ * */ -import { Component, Input, ViewChild } from '@angular/core'; -import { MatSort } from '@angular/material/sort'; -import { ByAbilityResult, SAPUserFunctionSrcFLD } from 'imx-api-sac'; +import { Component, Input } from '@angular/core'; +import { ByAbilityResult, SAPUserFunctionSrcFLD } from '@imx-modules/imx-api-sac'; import { CollectionLoadParameters, EntitySchema, @@ -35,11 +34,11 @@ import { GroupInfoData, TypedEntityCollectionData, ValType, -} from 'imx-qbm-dbts'; +} from '@imx-modules/imx-qbm-dbts'; +import { TranslateService } from '@ngx-translate/core'; import { DataSourceToolBarGroup, DataSourceToolbarGroupData, DataSourceToolbarSettings, DataTableGroupedData } from 'qbm'; import { SapComplianceByAbilityBuilder } from './sap-compliance-violation-views-by-ability-builder'; import { SapComplianceByAbilityEntity } from './sap-compliance-violation-views-by-ability-entity'; -import { TranslateService } from '@ngx-translate/core'; @Component({ selector: 'imx-sap-compliance-violation-views-by-ability', templateUrl: './sap-compliance-violation-views-by-ability.component.html', @@ -71,19 +70,26 @@ export class SapComplianceViolationViewsByAbilityComponent { * Called when search action is emitted. * @param searchValue current search param */ - public onSearch(searchValue: string): void { - if (!!searchValue) { + public onSearch(searchValue: string | undefined): void { + if (searchValue) { searchValue = searchValue.toLocaleLowerCase(); - this.dstSettings.dataSource.Data = this.defaultData.filter( + const Data = this.defaultData.filter( (profile) => - profile.Ident_SAPProfile.value.toLocaleLowerCase().includes(searchValue) || - profile.Ident_SAPAuthObject.value.toLocaleLowerCase().includes(searchValue) || - profile.Ident_SAPField.value.toLocaleLowerCase().includes(searchValue) || - profile.LowerLimit.value.toLocaleLowerCase().includes(searchValue) || - profile.UpperLimit.value.toLocaleLowerCase().includes(searchValue) + profile.Ident_SAPProfile.value.toLocaleLowerCase().includes(searchValue!) || + profile.Ident_SAPAuthObject.value.toLocaleLowerCase().includes(searchValue!) || + profile.Ident_SAPField.value.toLocaleLowerCase().includes(searchValue!) || + profile.LowerLimit.value.toLocaleLowerCase().includes(searchValue!) || + profile.UpperLimit.value.toLocaleLowerCase().includes(searchValue!), ); + this.dstSettings.dataSource = { + Data, + totalCount: Data.length, + }; } else { - this.dstSettings.dataSource.Data = this.defaultData; + this.dstSettings.dataSource = { + Data: this.defaultData, + totalCount: this.defaultData.length, + }; } this.dstSettings = { ...this.dstSettings, navigationState: { ...this.dstSettings.navigationState, search: searchValue } }; } @@ -94,8 +100,9 @@ export class SapComplianceViolationViewsByAbilityComponent { */ public onGroupingChange(groupKey: string): void { const groupedData = this.groupData[groupKey]; - let filter = groupedData.navigationState?.filter; - groupedData.data = this.getFilteredData(filter[0]); + if (groupedData.navigationState?.filter) { + groupedData.data = this.getFilteredData(groupedData.navigationState.filter[0]); + } groupedData.settings = { displayedColumns: this.dstSettings.displayedColumns, dataModel: this.dstSettings.dataModel, @@ -104,7 +111,7 @@ export class SapComplianceViolationViewsByAbilityComponent { totalCount: groupedData.data.length, }, entitySchema: this.dstSettings.entitySchema, - navigationState: groupedData.navigationState, + navigationState: groupedData.navigationState ?? {}, }; } @@ -149,8 +156,8 @@ export class SapComplianceViolationViewsByAbilityComponent { Property: { Type: ValType.String, ColumnName: 'DisplaySapFunctionInstance', - Display: this.translateService.instant('#LDS#SAP function instance'), }, + Display: this.translateService.instant('#LDS#SAP function instance'), }, getData: async () => await this.groupingData('DisplaySapFunctionInstance'), }, @@ -159,8 +166,8 @@ export class SapComplianceViolationViewsByAbilityComponent { Property: { Type: ValType.String, ColumnName: 'DisplaySapTransaction', - Display: this.translateService.instant('#LDS#SAP transaction'), }, + Display: this.translateService.instant('#LDS#SAP transaction'), }, getData: async () => await this.groupingData('DisplaySapTransaction'), }, @@ -176,7 +183,7 @@ export class SapComplianceViolationViewsByAbilityComponent { public async groupingData(groupColumn: string): Promise { const Groups: GroupInfo[] = []; this.dataSource.Data?.map((item, index) => { - if (Groups.every((groupItem) => item[groupColumn].value !== groupItem.Display[0].Display)) { + if (Groups.every((groupItem) => item[groupColumn].value !== (groupItem?.Display?.[0]?.Display ?? ''))) { const groupItems = this.dataSource.Data.filter((row) => row[groupColumn].value === item[groupColumn].value); Groups.push({ Display: [{ Display: item[groupColumn].value }], @@ -197,6 +204,6 @@ export class SapComplianceViolationViewsByAbilityComponent { * @returns Filtered data source. */ private getFilteredData(filter: FilterData): SapComplianceByAbilityEntity[] { - return this.dataSource.Data.filter((dataRow) => filter.Values.indexOf(dataRow[filter.ColumnName].value) >= 0); + return this.dataSource.Data.filter((dataRow) => (filter?.Values?.indexOf(dataRow?.[filter.ColumnName ?? '']?.value) ?? -1) >= 0); } } diff --git a/imxweb/projects/sac/src/lib/sap-compliance-violation/sap-compliance-violation-views-by-role/sap-compliance-violation-views-by-role.component.html b/imxweb/projects/sac/src/lib/sap-compliance-violation/sap-compliance-violation-views-by-role/sap-compliance-violation-views-by-role.component.html index bd8d0c546..688027a54 100644 --- a/imxweb/projects/sac/src/lib/sap-compliance-violation/sap-compliance-violation-views-by-role/sap-compliance-violation-views-by-role.component.html +++ b/imxweb/projects/sac/src/lib/sap-compliance-violation/sap-compliance-violation-views-by-role/sap-compliance-violation-views-by-role.component.html @@ -1,7 +1,7 @@
    - -
    -

    {{'#LDS#Heading Rule Analysis by Role' | translate}}

    + +
    +

    {{ '#LDS#Heading Rule Analysis by Role' | translate }}

    -
    {{ '#LDS#Created on' | translate }} @@ -27,7 +27,7 @@

    > { const isBusy = this.busyService.beginBusy(); - let overlayRef: OverlayRef; - setTimeout(() => overlayRef = this.euiLoadingService.show()); + if (this.euiLoadingService.overlayRefs.length === 0) { + this.euiLoadingService.show(); + } try { this.userProcesses = await this.userProcessService.get(); - this.displayedColumns = ['xDateInserted', 'display', 'processState' ]; + this.displayedColumns = ['xDateInserted', 'display', 'processState']; } finally { - setTimeout(() => this.euiLoadingService.hide(overlayRef)); + this.euiLoadingService.hide(); isBusy.endBusy(); } } - } diff --git a/imxweb/projects/qer/src/lib/user-process/user-process.module.ts b/imxweb/projects/qer/src/lib/user-process/user-process.module.ts index ab99e3c7d..4b6fc8da4 100644 --- a/imxweb/projects/qer/src/lib/user-process/user-process.module.ts +++ b/imxweb/projects/qer/src/lib/user-process/user-process.module.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -24,30 +24,28 @@ * */ -import { NgModule } from "@angular/core"; -import { UserProcessComponent } from "./user-process.component"; -import { CommonModule } from "@angular/common"; -import { DateModule, RouteGuardService } from "qbm"; -import { EuiCoreModule, EuiMaterialModule } from "@elemental-ui/core"; -import { TranslateModule } from "@ngx-translate/core"; -import { FormsModule, ReactiveFormsModule } from "@angular/forms"; -import { RouterModule, Routes } from "@angular/router"; -import { MatCardModule } from "@angular/material/card"; -import { MatTableModule } from "@angular/material/table"; +import { NgModule } from '@angular/core'; +import { UserProcessComponent } from './user-process.component'; +import { CommonModule } from '@angular/common'; +import { DateModule, RouteGuardService } from 'qbm'; +import { EuiCoreModule, EuiMaterialModule } from '@elemental-ui/core'; +import { TranslateModule } from '@ngx-translate/core'; +import { FormsModule, ReactiveFormsModule } from '@angular/forms'; +import { RouterModule, Routes } from '@angular/router'; +import { MatCardModule } from '@angular/material/card'; +import { MatTableModule } from '@angular/material/table'; const routes: Routes = [ { path: 'userprocess', component: UserProcessComponent, canActivate: [RouteGuardService], - resolve: [RouteGuardService] - } + resolve: [RouteGuardService], + }, ]; @NgModule({ - declarations: [ - UserProcessComponent - ], + declarations: [UserProcessComponent], imports: [ CommonModule, EuiCoreModule, @@ -60,8 +58,6 @@ const routes: Routes = [ EuiMaterialModule, DateModule, ], - exports: [ - UserProcessComponent - ], + exports: [UserProcessComponent], }) export class UserProcessModule {} diff --git a/imxweb/projects/qer/src/lib/user-process/user-processes.service.ts b/imxweb/projects/qer/src/lib/user-process/user-processes.service.ts index 9960e5298..e095c7490 100644 --- a/imxweb/projects/qer/src/lib/user-process/user-processes.service.ts +++ b/imxweb/projects/qer/src/lib/user-process/user-processes.service.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -26,20 +26,15 @@ import { Injectable } from '@angular/core'; import { QerApiService } from '../qer-api-client.service'; -import { ProcessChain } from 'imx-api-qer'; +import { ProcessChain } from '@imx-modules/imx-api-qer'; @Injectable({ providedIn: 'root', }) export class UserProcessService { - - constructor( - private readonly qerApiService: QerApiService, - ) {} + constructor(private readonly qerApiService: QerApiService) {} public async get(): Promise { return this.qerApiService.v2Client.portal_userprocess_get(); } - } - diff --git a/imxweb/projects/qer/src/lib/user/pending-items-type.interface.ts b/imxweb/projects/qer/src/lib/user/pending-items-type.interface.ts index b71dbe928..a17b3edd1 100644 --- a/imxweb/projects/qer/src/lib/user/pending-items-type.interface.ts +++ b/imxweb/projects/qer/src/lib/user/pending-items-type.interface.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -25,5 +25,5 @@ */ export interface PendingItemsType { - [key: string]: number; + [key: string]: number; } diff --git a/imxweb/projects/qer/src/lib/user/user-model.service.ts b/imxweb/projects/qer/src/lib/user/user-model.service.ts index 79a6d8f45..f7bcad3a5 100644 --- a/imxweb/projects/qer/src/lib/user/user-model.service.ts +++ b/imxweb/projects/qer/src/lib/user/user-model.service.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -27,11 +27,11 @@ import { Injectable } from '@angular/core'; import { Subject } from 'rxjs'; -import { PortalPersonReports, UserConfig, UserFeatureInfo, UserGroupInfo } from 'imx-api-qer'; -import { PendingItemsType } from './pending-items-type.interface'; -import { QerApiService } from '../qer-api-client.service'; +import { PortalPersonReports, UserConfig, UserFeatureInfo, UserGroupInfo } from '@imx-modules/imx-api-qer'; +import { CachedPromise } from '@imx-modules/imx-qbm-dbts'; import { CacheService, SettingsService } from 'qbm'; -import { CachedPromise } from 'imx-qbm-dbts'; +import { QerApiService } from '../qer-api-client.service'; +import { PendingItemsType } from './pending-items-type.interface'; @Injectable() export class UserModelService { @@ -42,15 +42,21 @@ export class UserModelService { private pendingItemsCache: CachedPromise; private cachedGroups: CachedPromise; private cachedFeatures: CachedPromise; + private cachedUserConfig: CachedPromise; - constructor(private readonly qerClient: QerApiService, private readonly settingsService: SettingsService, cacheService: CacheService) { + constructor( + private readonly qerClient: QerApiService, + private readonly settingsService: SettingsService, + cacheService: CacheService, + ) { this.pendingItemsCache = cacheService.buildCache(() => this.qerClient.client.portal_pendingitems_get()); this.cachedGroups = cacheService.buildCache(() => this.qerClient.client.portal_usergroups_get()); this.cachedFeatures = cacheService.buildCache(() => this.qerClient.client.portal_features_get()); + this.cachedUserConfig = cacheService.buildCache(() => this.qerClient.client.portal_person_config_get()); } public getUserConfig(): Promise { - return this.qerClient.client.portal_person_config_get(); + return this.cachedUserConfig.get(); } public getPendingItems(): Promise { @@ -72,7 +78,7 @@ export class UserModelService { public async getDirectReports(uidperson?: string): Promise { const features = (await this.cachedFeatures.get()).Features; - if (features.find((feature) => feature === 'Portal_UI_PersonManager')) { + if (features?.find((feature) => feature === 'Portal_UI_PersonManager')) { return ( await this.qerClient.typedClient.PortalPersonReports.Get({ OnlyDirect: true, diff --git a/imxweb/projects/qer/src/lib/user/user.module.ts b/imxweb/projects/qer/src/lib/user/user.module.ts index 134b2b84d..c47175845 100644 --- a/imxweb/projects/qer/src/lib/user/user.module.ts +++ b/imxweb/projects/qer/src/lib/user/user.module.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -31,11 +31,7 @@ import { UserModelService } from './user-model.service'; @NgModule({ declarations: [], - imports: [ - CommonModule - ], - providers: [ - UserModelService - ] + imports: [CommonModule], + providers: [UserModelService], }) -export class UserModule { } +export class UserModule {} diff --git a/imxweb/projects/qer/src/lib/view-config/view-config.service.ts b/imxweb/projects/qer/src/lib/view-config/view-config.service.ts index 76d750baf..5add231db 100644 --- a/imxweb/projects/qer/src/lib/view-config/view-config.service.ts +++ b/imxweb/projects/qer/src/lib/view-config/view-config.service.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -25,29 +25,26 @@ */ import { Injectable } from '@angular/core'; -import { ViewConfigData } from 'imx-api-qer'; +import { ViewConfigData } from '@imx-modules/imx-api-qer'; +import { DataModel } from '@imx-modules/imx-qbm-dbts'; import { DataSourceToolbarViewConfig, DSTViewConfig, isConfigDefault, isDefaultId } from 'qbm'; import { QerApiService } from '../qer-api-client.service'; -import { DataModel } from 'imx-qbm-dbts'; @Injectable({ - providedIn: 'root' + providedIn: 'root', }) export class ViewConfigService { + private allConfigs: DSTViewConfig[] = []; - private allConfigs: DSTViewConfig[]; - - constructor( - private readonly qerClient: QerApiService, - ) { } + constructor(private readonly qerClient: QerApiService) {} /** * Get all configs associated to the current viewId * @param viewId ViewConfigData.ViewId * @returns viewConfigData[] */ - public async getViewConfig(viewId: string): Promise { - return (await this.qerClient.v2Client.portal_viewconfig_get()).filter(config => config.ViewId === viewId); + public async getViewConfig(viewId: string, signal?: AbortSignal): Promise { + return (await this.qerClient.v2Client.portal_viewconfig_get(undefined, { signal })).filter((config) => config.ViewId === viewId); } /** @@ -72,30 +69,28 @@ export class ViewConfigService { * @param viewId ViewConfigData.ViewId * @returns The list of available configs along with the viewId for the DST */ - public async getInitialDSTExtension(dataModel: DataModel, viewId: string): Promise { + public async getInitialDSTExtension(dataModel: DataModel, viewId: string, signal?: AbortSignal): Promise { // Take configs from the data model, this should be a superset of the user's configs. - const userConfigs = await this.getViewConfig(viewId); - const userDefault = userConfigs.find(config => config.UseAsDefault); - this.allConfigs = dataModel?.Configurations?.map(config => { - // If we have a user default, set that as the default here, otherwise set the default, if there is no default then set as false - const UseAsDefault = userDefault - ? userDefault.Id === config?.Id - : (dataModel?.DefaultConfigId - ? dataModel.DefaultConfigId === config?.Id - : false); + const userConfigs = await this.getViewConfig(viewId, signal); + const userDefault = userConfigs.find((config) => config.UseAsDefault); + this.allConfigs = + dataModel?.Configurations?.map((config) => { + // If we have a user default, set that as the default here, otherwise set the default from the default config id which is stored as the display name on the DataModelConfig, if there is no default then set as false + const UseAsDefault = userDefault + ? userDefault.Id === config?.Id + : dataModel?.DefaultConfigId + ? dataModel.DefaultConfigId === config?.DisplayName + : false; - // Use the user config if it exists, if not this is a readonly config - let IsReadOnly: boolean; - const userConfig = userConfigs.find(userConfig => config?.Id === userConfig?.Id); - userConfig - ? config = userConfig - : IsReadOnly = true; + // Use the user config if it exists, if not this is a readonly config + let IsReadOnly: boolean = false; + const userConfig = userConfigs.find((userConfig) => config?.Id === userConfig?.Id); + userConfig ? (config = userConfig) : (IsReadOnly = true); - return config?.DisplayName - ? {...config, UseAsDefault, IsReadOnly, ViewId: viewId} - : {...config, UseAsDefault, IsReadOnly, DisplayName: config?.Id, ViewId: viewId}; - } - ); + return config?.DisplayName + ? { ...config, UseAsDefault, IsReadOnly, ViewId: viewId } + : { ...config, UseAsDefault, IsReadOnly, DisplayName: config?.Id, ViewId: viewId }; + }) || []; if (!this.allConfigs) { // There were no data model configs, use the user configs as is @@ -103,34 +98,36 @@ export class ViewConfigService { } return { viewConfigs: this.allConfigs, - viewId - } + viewId, + }; } - /** + /** * Now assumes the datamodel is out of sync and will only update the configs based on what isn't present in the user configs * @param viewId ViewConfigData.ViewId * @returns The list of available configs along with the viewId for the DST */ - public async getDSTExtensionChanges(viewId: string): Promise { - const userConfigs = await this.getViewConfig(viewId); - const userConfigIds = userConfigs.map(config => config?.Id); - // Filter out any removed configs that aren't marked as readonly - this.allConfigs.filter(config => config.IsReadOnly || userConfigIds.includes(config.Id)); - // Add / update any new configs - userConfigs.forEach(userConfig => { - const ind = this.allConfigs.findIndex(oldConfig => oldConfig.Id === userConfig.Id) - ind < 0 - ? this.allConfigs.push(userConfig) - : this.allConfigs[ind] = userConfig; - }) - return { - viewConfigs: this.allConfigs, - viewId - } - } + public async getDSTExtensionChanges(viewId: string): Promise { + const userConfigs = await this.getViewConfig(viewId); + const userConfigIds = userConfigs.map((config) => config?.Id); + // Filter out any removed configs that aren't marked as readonly + this.allConfigs = this.allConfigs.filter((config) => config.IsReadOnly || userConfigIds.includes(config.Id)); + // Add / update any new configs + userConfigs.forEach((userConfig) => { + const ind = this.allConfigs.findIndex((oldConfig) => oldConfig.Id === userConfig.Id); + ind < 0 ? this.allConfigs.push(userConfig) : (this.allConfigs[ind] = userConfig); + }); + return { + viewConfigs: this.allConfigs, + viewId, + }; + } + /** + * Check to see if we have a user config set as the default view + * @returns if we are using a user config as default + */ public isDefaultConfigSet(): boolean { - return !!this.allConfigs.find(config => isConfigDefault(config) && !isDefaultId(config)); + return !!this.allConfigs.find((config) => isConfigDefault(config) && !isDefaultId(config)); } } diff --git a/imxweb/projects/qer/src/lib/view-devices/create-new-device/create-new-device.component.html b/imxweb/projects/qer/src/lib/view-devices/create-new-device/create-new-device.component.html index 93b967c6d..dd794c327 100644 --- a/imxweb/projects/qer/src/lib/view-devices/create-new-device/create-new-device.component.html +++ b/imxweb/projects/qer/src/lib/view-devices/create-new-device/create-new-device.component.html @@ -1,12 +1,12 @@
    - + -
    +
    @@ -20,7 +20,7 @@ data-imx-identifier="new-device-sidesheet-button-save" (click)="createDevice()" [disabled]="formGroup.pristine || formGroup.invalid" - > - {{'#LDS#Create'| translate}} + > + {{ '#LDS#Create' | translate }}
    diff --git a/imxweb/projects/qer/src/lib/view-devices/create-new-device/create-new-device.component.scss b/imxweb/projects/qer/src/lib/view-devices/create-new-device/create-new-device.component.scss index 3b1922649..e69de29bb 100644 --- a/imxweb/projects/qer/src/lib/view-devices/create-new-device/create-new-device.component.scss +++ b/imxweb/projects/qer/src/lib/view-devices/create-new-device/create-new-device.component.scss @@ -1,7 +0,0 @@ -.imx-new-device-sidesheet { - ul { - li { - list-style-type: disc; - } - } -} diff --git a/imxweb/projects/qer/src/lib/view-devices/create-new-device/create-new-device.component.ts b/imxweb/projects/qer/src/lib/view-devices/create-new-device/create-new-device.component.ts index 4035c2389..555862fbb 100644 --- a/imxweb/projects/qer/src/lib/view-devices/create-new-device/create-new-device.component.ts +++ b/imxweb/projects/qer/src/lib/view-devices/create-new-device/create-new-device.component.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -24,25 +24,26 @@ * */ -import { Component, Inject } from "@angular/core"; -import { UntypedFormGroup } from "@angular/forms"; -import { EUI_SIDESHEET_DATA, EuiSidesheetRef } from "@elemental-ui/core"; -import { PortalDevices } from "imx-api-qer"; -import { IEntity, ValueStruct } from "imx-qbm-dbts"; -import { BaseCdr, ColumnDependentReference, SnackBarService } from "qbm"; -import { ViewDevicesService } from "../view-devices.service"; +import { Component, Inject } from '@angular/core'; +import { UntypedFormGroup } from '@angular/forms'; +import { EUI_SIDESHEET_DATA, EuiSidesheetRef } from '@elemental-ui/core'; +import { PortalDevices } from '@imx-modules/imx-api-qer'; +import { IEntity, ValueStruct } from '@imx-modules/imx-qbm-dbts'; +import { BaseCdr, ColumnDependentReference, SnackBarService } from 'qbm'; +import { ViewDevicesService } from '../view-devices.service'; @Component({ selector: 'imx-create-new-device', templateUrl: './create-new-device.component.html', - styleUrls: ['./create-new-device.component.scss'] + styleUrls: ['./create-new-device.component.scss'], }) export class CreateNewDeviceComponent { public readonly formGroup = new UntypedFormGroup({}); public cdrList: ColumnDependentReference[] = []; constructor( - @Inject(EUI_SIDESHEET_DATA) public data: { newDevice: PortalDevices, deviceEntityConfig: string[], deviceModelValueStruct: ValueStruct }, + @Inject(EUI_SIDESHEET_DATA) + public data: { newDevice: PortalDevices; deviceEntityConfig: string[]; deviceModelValueStruct: ValueStruct }, public viewDevicesService: ViewDevicesService, private readonly sidesheetRef: EuiSidesheetRef, private readonly snackbar: SnackBarService, @@ -52,14 +53,11 @@ export class CreateNewDeviceComponent { } private createCdrList(entity: IEntity): BaseCdr[] { - const cdrList = []; + const cdrList: BaseCdr[] = []; const columnNames: string[] = this.data.deviceEntityConfig; - columnNames?.forEach(async (name) => { + columnNames?.forEach((name) => { try { - if (name === 'UID_HardwareType') { - await entity.GetColumn(name).PutValueStruct(this.data.deviceModelValueStruct); - cdrList.unshift(new BaseCdr(entity.GetColumn(name), null, true)); - } else { + if (name !== 'UID_HardwareType') { cdrList.push(new BaseCdr(entity.GetColumn(name))); } } catch {} diff --git a/imxweb/projects/qer/src/lib/view-devices/view-devices-home/view-devices.component.html b/imxweb/projects/qer/src/lib/view-devices/view-devices-home/view-devices.component.html index de3bc03e9..063ba9807 100644 --- a/imxweb/projects/qer/src/lib/view-devices/view-devices-home/view-devices.component.html +++ b/imxweb/projects/qer/src/lib/view-devices/view-devices-home/view-devices.component.html @@ -1,50 +1,67 @@ - - -
    -
    - #LDS#Heading Devices + +
    +
    +

    #LDS#Heading Devices

    -
    - - - - - - - - - - - -
    + + + +
    + {{ entitySchema?.Columns?.[DisplayColumns.DISPLAY_PROPERTYNAME]?.Display }} + +
    + {{ item?.GetEntity()?.GetDisplay() }} +
    +
    + {{ entitySchema?.Columns?.UID_HardwareType?.Display }} + + + {{ item.UID_HardwareType.Column.GetDisplayValue() }} + + + {{ entitySchema?.Columns?.UID_PersonOwner?.Display }} + + + {{ item.UID_PersonOwner?.Column.GetDisplayValue() }} + + + {{ '#LDS#Display name' | translate }} + +
    {{ item.GetEntity().GetDisplay() }}
    +
    {{ item.Description.Column.GetDisplayValue() }}
    +
    +
    - - + + - + - +
    - {{'#LDS#Group name' | translate}} + {{ '#LDS#Group name' | translate }} - {{'#LDS#Description' | translate}}{{ data.Description }}{{ '#LDS#Description' | translate }} + {{ data.Description }} + {{'#LDS#Group type' | translate}}{{ '#LDS#Group type' | translate }} {{ data.GroupType }}
    - -
    + +
    -

    {{'#LDS#Heading Selected Role' | translate}}: {{selectedRole?.GroupName}}

    +

    + {{ '#LDS#Heading Selected Role' | translate }}: {{ selectedRole?.GroupName }} +

    - - +
    - +
    - + - + - + - + - + @@ -91,7 +99,7 @@

    {{'#LDS#Headi

    {{'#LDS#Authentication' | translate}}{{ '#LDS#Authentication' | translate }} {{ data.Ident_SAPProfile }} {{'#LDS#Objects' | translate}}{{ '#LDS#Objects' | translate }} {{ data.Objects }} {{'#LDS#Field' | translate}}{{ '#LDS#Field' | translate }} {{ data.Field }} {{'#LDS#From' | translate}}{{ '#LDS#From' | translate }} {{ data.LowerLimit }} {{'#LDS#To' | translate}}{{ '#LDS#To' | translate }} {{ data.UpperLimit }}
    -

    {{ '#LDS#No data' | translate}}

    +

    {{ '#LDS#No data' | translate }}

    diff --git a/imxweb/projects/sac/src/lib/sap-compliance-violation/sap-compliance-violation-views-by-role/sap-compliance-violation-views-by-role.component.scss b/imxweb/projects/sac/src/lib/sap-compliance-violation/sap-compliance-violation-views-by-role/sap-compliance-violation-views-by-role.component.scss index 48bdc1bc5..f697d3ed8 100644 --- a/imxweb/projects/sac/src/lib/sap-compliance-violation/sap-compliance-violation-views-by-role/sap-compliance-violation-views-by-role.component.scss +++ b/imxweb/projects/sac/src/lib/sap-compliance-violation/sap-compliance-violation-views-by-role/sap-compliance-violation-views-by-role.component.scss @@ -1,108 +1,84 @@ -@import "@elemental-ui/core/src/styles/_eui_palette.scss"; +@import '@elemental-ui/core/src/styles/_eui_palette.scss'; +@import 'base/mixins'; -.sap-analysis{ +.sap-analysis { display: flex; gap: 16px; height: 100%; justify-content: space-between; - &__table{ + &__table { overflow: hidden auto; flex-grow: 1; } - .mat-card{ - width: 100%; + .mat-mdc-card { + @include flex-column-container($width: 100%); transition: width 400ms ease; - display: flex; - flex-direction: column; gap: 20px; - &--decreased{ + + &--decreased { padding: 0; width: 48px; - .mat-card__header{ + + .mat-mdc-card__header { height: 100%; - &__title{ - display:none; + + &__title { + display: none; } - button{ + + button { width: 48px; padding: 20px 0; min-width: unset; height: 100%; - ::ng-deep .mat-button-wrapper{ + ::ng-deep .mdc-button__label { height: 100%; display: flex; flex-direction: column; } - h3{ + + h3 { display: block; margin: auto 0; rotate: -90deg; + text-wrap: nowrap; } - .eui-icon{ + + .eui-icon { rotate: 180deg; } } - } - .sap-analysis__table, eui-search{ + + .sap-analysis__table, + eui-search { display: none; } } - &__header{ - display:flex; + + &__header { + display: flex; align-items: center; justify-content: space-between; - &__title{ - &--wide{ - margin:auto; + + &__title { + &--wide { + margin: auto; } } - button{ + + button { padding: 0; min-width: 32px; - h3{ + + h3 { display: none; } - .eui-icon{ + + .eui-icon { transition: rotate 400ms ease; } } } } - .mat-table{ - box-shadow: none; - .td--no-wrap{ - white-space: nowrap; - } - .sap-analysis-table-row-highlighted:hover{ - background-color: $color-gray-5; - cursor: pointer; - } - } -} -:host ::ng-deep .mat-table{ - tbody{ - .mat-row{ - .mat-cell{ - .imx-table-column-ellipsis{ - width:120px; - display: block; - white-space: nowrap; - overflow-x:hidden; - text-overflow: ellipsis; - } - } - } - } -} -.eui-dark-theme{ - :host{ - .sap-analysis{ - .mat-table{ - .sap-analysis-table-row-highlighted:hover{ - background-color: $color-gray-60; - } - } - } - } } diff --git a/imxweb/projects/sac/src/lib/sap-compliance-violation/sap-compliance-violation-views-by-role/sap-compliance-violation-views-by-role.component.ts b/imxweb/projects/sac/src/lib/sap-compliance-violation/sap-compliance-violation-views-by-role/sap-compliance-violation-views-by-role.component.ts index 4cdc5eba8..5f23e69f6 100644 --- a/imxweb/projects/sac/src/lib/sap-compliance-violation/sap-compliance-violation-views-by-role/sap-compliance-violation-views-by-role.component.ts +++ b/imxweb/projects/sac/src/lib/sap-compliance-violation/sap-compliance-violation-views-by-role/sap-compliance-violation-views-by-role.component.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -24,16 +24,14 @@ * */ -import { AfterViewInit, ChangeDetectorRef, Component, Input, OnInit, ViewChild } from '@angular/core'; -import { ByRoleResult, ByRoleResultElement, SAPUserFunctionSrcPROF } from 'imx-api-sac'; -import { SapRoleTreeNodeModel } from './../sap-compliance-violation.model'; import { FlatTreeControl } from '@angular/cdk/tree'; -import { MatTreeFlatDataSource, MatTreeFlattener } from '@angular/material/tree'; -import { MatTableDataSource } from '@angular/material/table'; -import { EntitySchema, IClientProperty, TypedEntityCollectionData, ValType } from 'imx-qbm-dbts'; -import { DataSourceToolbarSettings } from 'qbm'; -import { MatSort } from '@angular/material/sort'; +import { ChangeDetectorRef, Component, Input, OnInit, ViewChild } from '@angular/core'; import { FormControl } from '@angular/forms'; +import { MatSort } from '@angular/material/sort'; +import { MatTableDataSource } from '@angular/material/table'; +import { MatTreeFlatDataSource, MatTreeFlattener } from '@angular/material/tree'; +import { ByRoleResult, ByRoleResultElement, SAPUserFunctionSrcPROF } from '@imx-modules/imx-api-sac'; +import { SapRoleTreeNodeModel } from './../sap-compliance-violation.model'; @Component({ selector: 'imx-sap-compliance-violation-views-by-role', @@ -67,13 +65,13 @@ export class SapComplianceViolationViewsByRoleComponent implements OnInit { }; public treeControl = new FlatTreeControl( (node) => node.level, - (node) => node.expandable + (node) => node.expandable, ); public treeFlattener = new MatTreeFlattener( this.transformer, (node) => node.level, (node) => node.expandable, - (node) => node.ChildElements + (node) => node.ChildElements, ); public dataSource = new MatTreeFlatDataSource(this.treeControl, this.treeFlattener); public selectedProfiles: SAPUserFunctionSrcPROF[] = []; @@ -82,7 +80,7 @@ export class SapComplianceViolationViewsByRoleComponent implements OnInit { public extendProfiles = true; public showProfiles = false; public selectedRole: SapRoleTreeNodeModel; - public profileSearchControl = new FormControl(''); + public profileSearchControl = new FormControl('', { nonNullable: true }); private _resultByRole: ByRoleResult; constructor(private cdref: ChangeDetectorRef) {} @@ -125,11 +123,11 @@ export class SapComplianceViolationViewsByRoleComponent implements OnInit { searchValue = searchValue.toLocaleLowerCase(); this.profileDataSource.data = this.selectedProfiles.filter( (profile) => - profile.Ident_SAPProfile.toLocaleLowerCase().includes(searchValue) || - profile.Objects.toLocaleLowerCase().includes(searchValue) || - profile.Field.toLocaleLowerCase().includes(searchValue)|| - profile.LowerLimit.toLocaleLowerCase().includes(searchValue)|| - profile.UpperLimit.toLocaleLowerCase().includes(searchValue) + profile.Ident_SAPProfile?.toLocaleLowerCase().includes(searchValue) || + profile.Objects?.toLocaleLowerCase().includes(searchValue) || + profile.Field?.toLocaleLowerCase().includes(searchValue) || + profile.LowerLimit?.toLocaleLowerCase().includes(searchValue) || + profile.UpperLimit?.toLocaleLowerCase().includes(searchValue), ); } else { this.profileDataSource.data = this.selectedProfiles; diff --git a/imxweb/projects/sac/src/lib/sap-compliance-violation/sap-compliance-violation.component.html b/imxweb/projects/sac/src/lib/sap-compliance-violation/sap-compliance-violation.component.html index 45f3168e9..0aa767490 100644 --- a/imxweb/projects/sac/src/lib/sap-compliance-violation/sap-compliance-violation.component.html +++ b/imxweb/projects/sac/src/lib/sap-compliance-violation/sap-compliance-violation.component.html @@ -1,30 +1,46 @@
    - - {{ '#LDS#SAP user' | translate }} - - + + {{ '#LDS#SAP user account' | translate }} + + {{ account.GetEntity().GetDisplay() }} {{ '#LDS#Rule analysis' | translate }}: - - + + {{ option.label | translate }} - - + +
    -
    +

    {{ '#LDS#No data' | translate }}

    diff --git a/imxweb/projects/sac/src/lib/sap-compliance-violation/sap-compliance-violation.component.scss b/imxweb/projects/sac/src/lib/sap-compliance-violation/sap-compliance-violation.component.scss index 75ffea6d1..ab4b043de 100644 --- a/imxweb/projects/sac/src/lib/sap-compliance-violation/sap-compliance-violation.component.scss +++ b/imxweb/projects/sac/src/lib/sap-compliance-violation/sap-compliance-violation.component.scss @@ -1,38 +1,35 @@ -@import "@elemental-ui/core/src/styles/_eui_palette.scss"; +@import '@elemental-ui/core/src/styles/_eui_palette.scss'; -.eui-sidesheet-content{ +.eui-sidesheet-content { display: flex; flex-direction: column; - imx-sap-compliance-violation-views-by-role, imx-sap-compliance-violation-views-by-ability{ + + imx-sap-compliance-violation-views-by-role, + imx-sap-compliance-violation-views-by-ability { display: block; overflow: hidden; - height: 100%; - } - .mat-progress-spinner { - margin: auto; + flex-grow: 1; } - .mat-chip{ + + .mat-mdc-chip { cursor: pointer; } - .imx-sap-compliance-selection{ + + .imx-sap-compliance-selection { display: flex; - align-items: baseline; + align-items: center; font-size: 14px; gap: 20px; - span{ - padding-bottom: 20px; - } + padding-bottom: 20px; } - ::ng-deep .no-results{ + + .imx-no-results { height: 100%; display: flex; flex-direction: column; align-items: center; justify-content: center; - .eui-icon{ - font-size: 100px; - color: $color-gray-10; - } + p { margin: 0; font-size: 18px; @@ -43,15 +40,9 @@ .eui-dark-theme { :host { - .eui-sidesheet-content{ - ::ng-deep .no-results { - eui-icon { - color: $color-gray-20; - } - - p { - color: $color-gray-10; - } + .imx-no-results { + p { + color: $color-gray-10; } } } diff --git a/imxweb/projects/sac/src/lib/sap-compliance-violation/sap-compliance-violation.component.ts b/imxweb/projects/sac/src/lib/sap-compliance-violation/sap-compliance-violation.component.ts index 171e9b023..ecd41fe94 100644 --- a/imxweb/projects/sac/src/lib/sap-compliance-violation/sap-compliance-violation.component.ts +++ b/imxweb/projects/sac/src/lib/sap-compliance-violation/sap-compliance-violation.component.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -25,8 +25,8 @@ */ import { Component, OnInit } from '@angular/core'; -import { PortalRules, PortalRulesViolations } from 'imx-api-cpl'; -import { ByAbilityResult, ByRoleResult, PortalTargetsystemSapuser } from 'imx-api-sac'; +import { PortalRules, PortalRulesViolations } from '@imx-modules/imx-api-cpl'; +import { ByAbilityResult, ByRoleResult, PortalTargetsystemSapuser } from '@imx-modules/imx-api-sac'; import { SapComplianceApiService } from '../sac-api-client.service'; import { SapSelectionOptions, SapSelectionTypeEnum } from './sap-compliance-violation.model'; @@ -94,11 +94,11 @@ export class SapComplianceViolationComponent implements OnInit { const uidsapuser = this.selectedAccount.GetEntity().GetKeys()[0]; this.resultByAbility = await this.api.client.portal_sap_ruleanalysis_fld_get( uidsapuser, - this.data.complianceRule?.EntityKeysData?.Keys?.[0] + this.data.complianceRule?.EntityKeysData?.Keys?.[0] ?? '', ); this.resultByRole = await this.api.client.portal_sap_ruleanalysis_byrole_get( uidsapuser, - this.data.complianceRule?.EntityKeysData?.Keys?.[0] + this.data.complianceRule?.EntityKeysData?.Keys?.[0] ?? '', ); this.loading = false; } diff --git a/imxweb/projects/sac/src/lib/sap-compliance-violation/sap-compliance-violation.model.ts b/imxweb/projects/sac/src/lib/sap-compliance-violation/sap-compliance-violation.model.ts index 3931573fc..bc798c1d8 100644 --- a/imxweb/projects/sac/src/lib/sap-compliance-violation/sap-compliance-violation.model.ts +++ b/imxweb/projects/sac/src/lib/sap-compliance-violation/sap-compliance-violation.model.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -24,20 +24,19 @@ * */ +import { ByRoleResultElement } from '@imx-modules/imx-api-sac'; -import { ByRoleResultElement } from 'imx-api-sac'; - -export interface SapRoleTreeNodeModel extends ByRoleResultElement{ +export interface SapRoleTreeNodeModel extends ByRoleResultElement { level: number; expandable: boolean; } export enum SapSelectionTypeEnum { ROLE = 'ROLE', - ABILITY = 'ABILITY' + ABILITY = 'ABILITY', } -export interface SapSelectionOptions{ +export interface SapSelectionOptions { label: string; - value: SapSelectionTypeEnum + value: SapSelectionTypeEnum; } diff --git a/imxweb/projects/sac/src/public_api.ts b/imxweb/projects/sac/src/public_api.ts index a043e4ff9..e5b8c4e4c 100644 --- a/imxweb/projects/sac/src/public_api.ts +++ b/imxweb/projects/sac/src/public_api.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR diff --git a/imxweb/projects/sac/src/test.ts b/imxweb/projects/sac/src/test.ts index f7ac7d548..159c87d7d 100644 --- a/imxweb/projects/sac/src/test.ts +++ b/imxweb/projects/sac/src/test.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -26,24 +26,14 @@ // This file is required by karma.conf.js and loads recursively all the .spec and framework files -import 'core-js/es7/reflect'; -import 'zone.js/dist/zone'; -import 'zone.js/dist/zone-testing'; +// Zone must be imported first. Be careful with prettier import organizing +import 'zone.js'; +import 'zone.js/testing'; + import { getTestBed } from '@angular/core/testing'; -import { - BrowserDynamicTestingModule, - platformBrowserDynamicTesting -} from '@angular/platform-browser-dynamic/testing'; +import { BrowserDynamicTestingModule, platformBrowserDynamicTesting } from '@angular/platform-browser-dynamic/testing'; +import 'core-js/es/reflect'; import { TestHelperModule } from 'qbm'; -declare const require: any; - // First, initialize the Angular testing environment. -getTestBed().initTestEnvironment( - [BrowserDynamicTestingModule, TestHelperModule], - platformBrowserDynamicTesting() -); -// Then we find all the tests. -const context = require.context('./', true, /\.spec\.ts$/); -// And load the modules. -context.keys().map(context); +getTestBed().initTestEnvironment([BrowserDynamicTestingModule, TestHelperModule], platformBrowserDynamicTesting()); diff --git a/imxweb/projects/sac/tsconfig.lib.json b/imxweb/projects/sac/tsconfig.lib.json index d2c384016..ba946e3ca 100644 --- a/imxweb/projects/sac/tsconfig.lib.json +++ b/imxweb/projects/sac/tsconfig.lib.json @@ -2,6 +2,7 @@ "extends": "../../tsconfig.json", "compilerOptions": { "outDir": "../../out-tsc/lib", + "strictNullChecks": true, "declarationMap": true, "target": "es2020", "module": "es2015", @@ -13,20 +14,14 @@ "experimentalDecorators": true, "importHelpers": true, "types": [], - "lib": [ - "dom", - "es2018" - ] + "lib": ["dom", "es2018"] }, "angularCompilerOptions": { "skipTemplateCodegen": true, "strictMetadataEmit": true, - "fullTemplateTypeCheck": true, + "strictTemplates": true, "strictInjectionParameters": true, "enableResourceInlining": true }, - "exclude": [ - "src/test.ts", - "**/*.spec.ts" - ] + "exclude": ["src/test.ts", "**/*.spec.ts"] } diff --git a/imxweb/projects/sac/tsconfig.lib.prod.json b/imxweb/projects/sac/tsconfig.lib.prod.json index a05c79305..46634e44f 100644 --- a/imxweb/projects/sac/tsconfig.lib.prod.json +++ b/imxweb/projects/sac/tsconfig.lib.prod.json @@ -2,8 +2,5 @@ "extends": "./tsconfig.lib.json", "compilerOptions": { "declarationMap": false - }, - "angularCompilerOptions": { - "enableIvy": true } } diff --git a/imxweb/projects/sac/tsconfig.spec.json b/imxweb/projects/sac/tsconfig.spec.json index 16da33db0..6bd74e1f7 100644 --- a/imxweb/projects/sac/tsconfig.spec.json +++ b/imxweb/projects/sac/tsconfig.spec.json @@ -1,17 +1,10 @@ { "extends": "../../tsconfig.json", "compilerOptions": { + "strictNullChecks": false, "outDir": "../../out-tsc/spec", - "types": [ - "jasmine", - "node" - ] + "types": ["jasmine", "node"] }, - "files": [ - "src/test.ts" - ], - "include": [ - "**/*.spec.ts", - "**/*.d.ts" - ] + "files": ["src/test.ts"], + "include": ["**/*.spec.ts", "**/*.d.ts"] } diff --git a/imxweb/projects/sac/tslint.json b/imxweb/projects/sac/tslint.json deleted file mode 100644 index 8bab15f53..000000000 --- a/imxweb/projects/sac/tslint.json +++ /dev/null @@ -1,17 +0,0 @@ -{ - "extends": "../../tslint.json", - "rules": { - "directive-selector": [ - true, - "attribute", - "imx", - "camelCase" - ], - "component-selector": [ - true, - "element", - "imx", - "kebab-case" - ] - } -} diff --git a/imxweb/projects/tsb/.compodocrc.json b/imxweb/projects/tsb/.compodocrc.json index 103e340ed..8a4482ad7 100644 --- a/imxweb/projects/tsb/.compodocrc.json +++ b/imxweb/projects/tsb/.compodocrc.json @@ -1,6 +1,6 @@ { "name": "IMX Web - TSB Library", - "output": "../../documentation/v92/tsb", + "output": "../../documentation/v93/tsb", "theme": "material", "assetsFolder": "../../compodoc/assets", "customLogo": "../../compodoc/assets/images/oneidentity-logo.png", diff --git a/imxweb/projects/tsb/.eslintrc.json b/imxweb/projects/tsb/.eslintrc.json new file mode 100644 index 000000000..45f490f30 --- /dev/null +++ b/imxweb/projects/tsb/.eslintrc.json @@ -0,0 +1,35 @@ +{ + "extends": "../../.eslintrc.json", + "ignorePatterns": ["!**/*", "**/*.spec.ts"], + "overrides": [ + { + "files": ["*.ts"], + "parserOptions": { + "project": ["imxweb/projects/tsb/tsconfig.lib.json", "imxweb/projects/tsb/tsconfig.spec.json"], + "createDefaultProgram": true + }, + "rules": { + "@angular-eslint/directive-selector": [ + "error", + { + "type": "attribute", + "prefix": "imx", + "style": "camelCase" + } + ], + "@angular-eslint/component-selector": [ + "error", + { + "type": "element", + "prefix": "imx", + "style": "kebab-case" + } + ] + } + }, + { + "files": ["*.html"], + "rules": {} + } + ] +} diff --git a/imxweb/projects/tsb/imx-plugin-config.json b/imxweb/projects/tsb/imx-plugin-config.json index 777bcb8d1..a3e41fcd5 100644 --- a/imxweb/projects/tsb/imx-plugin-config.json +++ b/imxweb/projects/tsb/imx-plugin-config.json @@ -1,8 +1,8 @@ { "qer-app-portal": [ - { - "Container": "tsb", - "Name": "TsbConfigModule" - } + { + "Container": "tsb", + "Name": "TsbConfigModule" + } ] } diff --git a/imxweb/projects/tsb/karma.conf.js b/imxweb/projects/tsb/karma.conf.js index 211193c9d..3e53a3ac8 100644 --- a/imxweb/projects/tsb/karma.conf.js +++ b/imxweb/projects/tsb/karma.conf.js @@ -15,7 +15,7 @@ module.exports = function (config) { require('karma-junit-reporter'), ], client: { - clearContext: false // leave Jasmine Spec Runner output visible in browser + clearContext: false, // leave Jasmine Spec Runner output visible in browser }, coverageIstanbulReporter: { dir: require('path').join(__dirname, 'results'), @@ -23,7 +23,7 @@ module.exports = function (config) { fixWebpackSourcePaths: true, 'report-config': { html: { - subdir: 'coverage-html' + subdir: 'coverage-html', }, }, thresholds: { @@ -40,13 +40,14 @@ module.exports = function (config) { port: 9876, captureTimeout: 210000, browserDisconnectTolerance: 3, - browserDisconnectTimeout : 210000, - browserNoActivityTimeout : 210000, + browserDisconnectTimeout: 210000, + browserNoActivityTimeout: 210000, colors: true, logLevel: config.LOG_INFO, autoWatch: true, browsers: ['Chrome'], singleRun: false, - restartOnFileChange: true + failOnEmptyTestSuite: false, + restartOnFileChange: true, }); }; diff --git a/imxweb/projects/tsb/ng-package.dynamic.json b/imxweb/projects/tsb/ng-package.dynamic.json index 64fcab96b..ce71b33fe 100644 --- a/imxweb/projects/tsb/ng-package.dynamic.json +++ b/imxweb/projects/tsb/ng-package.dynamic.json @@ -16,12 +16,11 @@ "@elemental-ui/core", "@ngx-translate/core", "@ngx-translate/http-loader", - "applicationinsights-js", "billboard.js" ], - "dest": "../../html/tsb", + "dest": "../../html/qer-app-portal/tsb", "lib": { "entryFile": "src/public_api.ts", - "styleIncludePaths": ["../../shared/assets"] + "styleIncludePaths": ["../../shared/scss"] } } diff --git a/imxweb/projects/tsb/ng-package.json b/imxweb/projects/tsb/ng-package.json index 6b46cbd04..729a15375 100644 --- a/imxweb/projects/tsb/ng-package.json +++ b/imxweb/projects/tsb/ng-package.json @@ -3,6 +3,6 @@ "dest": "../../dist/tsb", "lib": { "entryFile": "src/public_api.ts", - "styleIncludePaths": ["../../shared/assets"] + "styleIncludePaths": ["../../shared/scss"] } } diff --git a/imxweb/projects/tsb/package.json b/imxweb/projects/tsb/package.json index cb36ff59f..aa04edb90 100644 --- a/imxweb/projects/tsb/package.json +++ b/imxweb/projects/tsb/package.json @@ -1,6 +1,6 @@ { "name": "tsb", - "version": "9.2.1", + "version": "9.3.0", "private": true, "bundledDependencies": [ "imx-api-tsb" diff --git a/imxweb/projects/tsb/project.json b/imxweb/projects/tsb/project.json new file mode 100644 index 000000000..8d9eb2bc8 --- /dev/null +++ b/imxweb/projects/tsb/project.json @@ -0,0 +1,64 @@ +{ + "$schema": "../../node_modules/nx/schemas/project-schema.json", + "name": "tsb", + "sourceRoot": "projects/tsb/src", + "implicitDependencies": ["qer"], + "projectType": "library", + "prefix": "imx", + "generators": { + "@schematics/angular:component": { + "style": "scss" + } + }, + "targets": { + "build": { + "executor": "@angular-devkit/build-angular:ng-packagr", + "options": { + "tsConfig": "projects/tsb/tsconfig.lib.json", + "project": "projects/tsb/ng-package.json" + }, + "configurations": { + "production": { + "tsConfig": "projects/tsb/tsconfig.lib.prod.json" + }, + "development": { + "tsConfig": "projects/tsb/tsconfig.lib.json" + }, + "dynamic": { + "project": "projects/tsb/ng-package.dynamic.json" + }, + "remote-dev": { + "tsConfig": "projects/tsb/tsconfig.lib.json" + }, + "remote-qs": { + "tsConfig": "projects/tsb/tsconfig.lib.json" + } + }, + "outputs": ["{workspaceRoot}/dist/tsb"] + }, + "test": { + "executor": "@angular-devkit/build-angular:karma", + "options": { + "main": "projects/tsb/src/test.ts", + "tsConfig": "projects/tsb/tsconfig.spec.json", + "karmaConfig": "projects/tsb/karma.conf.js", + "stylePreprocessorOptions": { + "includePaths": [ + "./shared/assets", + "./shared/scss", + "./node_modules", + "./node_modules/@elemental-ui/cadence-icon", + "./node_modules/@elemental-ui/core" + ] + } + } + }, + "lint": { + "executor": "@angular-devkit/build-angular:tslint", + "options": { + "tsConfig": ["projects/tsb/tsconfig.lib.json", "projects/tsb/tsconfig.spec.json"], + "exclude": ["**/node_modules/**", "**/*.spec.ts", "**/*.json"] + } + } + } +} diff --git a/imxweb/projects/tsb/src/lib/accounts/account-ext/account-ext.service.ts b/imxweb/projects/tsb/src/lib/accounts/account-ext/account-ext.service.ts index eb94ff575..9e5bd51d5 100644 --- a/imxweb/projects/tsb/src/lib/accounts/account-ext/account-ext.service.ts +++ b/imxweb/projects/tsb/src/lib/accounts/account-ext/account-ext.service.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -26,14 +26,13 @@ import { Injectable } from '@angular/core'; -import { PortalPersonAccounts, portal_person_accounts_get_args } from 'imx-api-tsb'; -import { EntitySchema, ExtendedTypedEntityCollection } from 'imx-qbm-dbts'; +import { PortalPersonAccounts, portal_person_accounts_get_args } from '@imx-modules/imx-api-tsb'; +import { EntitySchema, ExtendedTypedEntityCollection } from '@imx-modules/imx-qbm-dbts'; import { TsbApiService } from '../../tsb-api-client.service'; @Injectable({ providedIn: 'root' }) export class AccountsExtService { - - constructor(private readonly apiService: TsbApiService) { } + constructor(private readonly apiService: TsbApiService) {} public get portalPersonAccountsSchema(): EntitySchema { return this.apiService.typedClient.PortalPersonAccounts.GetSchema(); @@ -42,5 +41,4 @@ export class AccountsExtService { public getAccounts(uid: string, parameters?: portal_person_accounts_get_args): Promise> { return this.apiService.typedClient.PortalPersonAccounts.Get(uid, parameters); } - } diff --git a/imxweb/projects/tsb/src/lib/accounts/account-ext/accounts-ext.component.html b/imxweb/projects/tsb/src/lib/accounts/account-ext/accounts-ext.component.html index 6973ae9e7..25928253f 100644 --- a/imxweb/projects/tsb/src/lib/accounts/account-ext/accounts-ext.component.html +++ b/imxweb/projects/tsb/src/lib/accounts/account-ext/accounts-ext.component.html @@ -1,28 +1,33 @@ - - +
    - - + + -
    {{item.GetEntity().GetDisplay()}}
    +
    {{ item.GetEntity().GetDisplay() }}
    - - - + + -
    {{item.UID_UNSRoot.Column.GetDisplayValue()}}
    -
    {{item.UID_DPRNameSpace.Column.GetDisplayValue()}}
    +
    {{ item.UID_UNSRoot.Column.GetDisplayValue() }}
    +
    {{ item.UID_DPRNameSpace.Column.GetDisplayValue() }}
    - +
    {{ item.XMarkedForDeletion.Column.GetDisplayValue() }} @@ -32,4 +37,4 @@
    - \ No newline at end of file + diff --git a/imxweb/projects/tsb/src/lib/accounts/account-ext/accounts-ext.component.scss b/imxweb/projects/tsb/src/lib/accounts/account-ext/accounts-ext.component.scss index 445b669d8..bb0fa0525 100644 --- a/imxweb/projects/tsb/src/lib/accounts/account-ext/accounts-ext.component.scss +++ b/imxweb/projects/tsb/src/lib/accounts/account-ext/accounts-ext.component.scss @@ -1,4 +1,4 @@ -@import "@elemental-ui/core/src/styles/_palette.scss"; +@import '@elemental-ui/core/src/styles/_palette.scss'; :host { overflow: hidden; @@ -7,7 +7,6 @@ height: 100%; } - .imx-memberships { flex: 1 1 auto; display: flex; @@ -22,4 +21,3 @@ overflow: auto; margin-top: 20px; } - diff --git a/imxweb/projects/tsb/src/lib/accounts/account-ext/accounts-ext.component.ts b/imxweb/projects/tsb/src/lib/accounts/account-ext/accounts-ext.component.ts index 13420292d..8f1164a7f 100644 --- a/imxweb/projects/tsb/src/lib/accounts/account-ext/accounts-ext.component.ts +++ b/imxweb/projects/tsb/src/lib/accounts/account-ext/accounts-ext.component.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -26,8 +26,8 @@ import { Component, Input, OnInit } from '@angular/core'; -import { CollectionLoadParameters, DisplayColumns, EntitySchema, IClientProperty } from 'imx-qbm-dbts'; -import { DataSourceToolbarSettings, DynamicTabDataProviderDirective, SettingsService, BusyService } from 'qbm'; +import { CollectionLoadParameters, DisplayColumns, EntitySchema, IClientProperty } from '@imx-modules/imx-qbm-dbts'; +import { BusyService, DataSourceToolbarSettings, DynamicTabDataProviderDirective, SettingsService } from 'qbm'; import { AccountsExtService } from './account-ext.service'; @Component({ @@ -37,7 +37,7 @@ import { AccountsExtService } from './account-ext.service'; export class AccountsExtComponent implements OnInit { @Input() public referrer: { objecttable?: string; - objectuid?: string; + objectuid: string; tablename?: string; }; @@ -53,7 +53,7 @@ export class AccountsExtComponent implements OnInit { constructor( private readonly settingService: SettingsService, private readonly accountsService: AccountsExtService, - dataProvider: DynamicTabDataProviderDirective + dataProvider: DynamicTabDataProviderDirective, ) { this.referrer = dataProvider?.data; this.navigationState = { PageSize: this.settingService.DefaultPageSize }; diff --git a/imxweb/projects/tsb/src/lib/accounts/account-sidesheet/account-sidesheet.component.html b/imxweb/projects/tsb/src/lib/accounts/account-sidesheet/account-sidesheet.component.html index f2e2d7442..bf111fccc 100644 --- a/imxweb/projects/tsb/src/lib/accounts/account-sidesheet/account-sidesheet.component.html +++ b/imxweb/projects/tsb/src/lib/accounts/account-sidesheet/account-sidesheet.component.html @@ -1,54 +1,64 @@ - + -
    -
    - -
    - -
    - - #LDS#The manager assigned to this user account differs from the manager assigned to the listed identity. - - - #LDS#There is no manager assigned to this user account. - - - #LDS#Synchronize the user account's manager with the listed identity - -
    -
    -
    -
    -
    - - - -
    +
    + +
    + +
    + + #LDS#The manager assigned to this user account differs from the manager assigned to the listed identity. + + + #LDS#There is no manager assigned to this user account. + + + #LDS#Synchronize the user account's manager with the listed identity + +
    +
    +
    +
    +
    + + +
    -
    -
    - - -
    +
    + +
    -
    +
    diff --git a/imxweb/projects/tsb/src/lib/accounts/account-sidesheet/account-sidesheet.component.scss b/imxweb/projects/tsb/src/lib/accounts/account-sidesheet/account-sidesheet.component.scss index a3c1b00af..a94edcb97 100644 --- a/imxweb/projects/tsb/src/lib/accounts/account-sidesheet/account-sidesheet.component.scss +++ b/imxweb/projects/tsb/src/lib/accounts/account-sidesheet/account-sidesheet.component.scss @@ -1,98 +1,14 @@ - -@import "@elemental-ui/core/src/styles/_palette.scss"; +@import '@elemental-ui/core/src/styles/_palette.scss'; @import '@elemental-ui/core/src/styles/_eui_palette.scss'; - -.eui-sidesheet-content:not(.imx-hyperview-sidesheet){ - padding: 0; - - ::ng-deep .mat-tab-body-content { - display: flex; - flex-direction: column; - } -} - -.eui-sidesheet-actions { - .justify-start { - margin-right: auto; - } - - button:not(:last-of-type):not(.justify-start) { - margin-right: 10px; - } -} - -.governance-sidesheet__tab-content { - display: flex; - flex-direction: column; - overflow: hidden; - > .governance-sidesheet__tab-content-body { - - .imx-tab-card{ - margin:20px; - } - flex: 1 1 auto; - overflow: auto; - padding: 0px; - - > :first-child { - overflow: auto; - } - - > .imx-ext { - overflow: hidden; - } - } -} - -.imx-entitlements-card{ +.imx-entitlements-card { flex: 1 1 auto; display: flex; flex-direction: column; } -.mat-checkbox { +.mat-mdc-checkbox { display: flex; margin-bottom: 15px; } - -::ng-deep .mat-tab-group { - height: 100%; - flex-grow: 1; - overflow: auto; - - .mat-tab-header { - padding: 0 32px; - background-color: $white; - } - - ::ng-deep .mat-tab-body-wrapper { - height: 100%; - } - - - .imx-edit-fk-open-picker { - display: none; - } -} - -.eui-dark-theme { - :host { - ::ng-deep .mat-tab-group { - .mat-tab-header { - background-color: $color-gray-80; - } - } - } -} - -.eui-contrast-theme { - :host { - ::ng-deep .mat-tab-group { - .mat-tab-header { - background-color: $color-gray-90; - } - } - } -} diff --git a/imxweb/projects/tsb/src/lib/accounts/account-sidesheet/account-sidesheet.component.ts b/imxweb/projects/tsb/src/lib/accounts/account-sidesheet/account-sidesheet.component.ts index 25698d2d4..0c99b7754 100644 --- a/imxweb/projects/tsb/src/lib/accounts/account-sidesheet/account-sidesheet.component.ts +++ b/imxweb/projects/tsb/src/lib/accounts/account-sidesheet/account-sidesheet.component.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -24,27 +24,25 @@ * */ -import { Component, OnInit, Inject } from '@angular/core'; -import { UntypedFormBuilder, UntypedFormGroup, UntypedFormArray, UntypedFormControl } from '@angular/forms'; +import { Component, Inject, OnInit } from '@angular/core'; +import { UntypedFormArray, UntypedFormBuilder, UntypedFormControl, UntypedFormGroup } from '@angular/forms'; +import { MatSlideToggleChange } from '@angular/material/slide-toggle'; +import { EUI_SIDESHEET_DATA, EuiDownloadOptions, EuiLoadingService, EuiSidesheetRef } from '@elemental-ui/core'; +import { DbObjectKey } from '@imx-modules/imx-qbm-dbts'; import { - ColumnDependentReference, - BaseCdr, + CdrFactoryService, ClassloggerService, - SnackBarService, + ColumnDependentReference, ElementalUiConfigService, - TabItem, ExtService, - CdrFactoryService, + SnackBarService, + TabItem, } from 'qbm'; -import { DbObjectKey } from 'imx-qbm-dbts'; -import { EuiLoadingService, EuiSidesheetRef, EUI_SIDESHEET_DATA } from '@elemental-ui/core'; -import { AccountSidesheetData } from '../accounts.models'; import { IdentitiesService, ProjectConfigurationService } from 'qer'; -import { MatSlideToggleChange } from '@angular/material/slide-toggle'; -import { AccountsService } from '../accounts.service'; -import { EuiDownloadOptions } from '@elemental-ui/core'; -import { AccountsReportsService } from '../accounts-reports.service'; import { AccountTypedEntity } from '../account-typed-entity'; +import { AccountsReportsService } from '../accounts-reports.service'; +import { AccountSidesheetData } from '../accounts.models'; +import { AccountsService } from '../accounts.service'; @Component({ selector: 'imx-account-sidesheet', @@ -54,12 +52,12 @@ import { AccountTypedEntity } from '../account-typed-entity'; export class AccountSidesheetComponent implements OnInit { public readonly detailsFormGroup: UntypedFormGroup; public cdrList: ColumnDependentReference[] = []; - public linkedIdentitiesManager: DbObjectKey; + public linkedIdentitiesManager: DbObjectKey | undefined; public unsavedSyncChanges = false; public initialAccountManagerValue: string; public reportDownload: EuiDownloadOptions; public neverConnectFormControl = new UntypedFormControl(); - public parameters: { objecttable: string; objectuid: string }; + public parameters: { objecttable: string; objectuid: string; display: string }; public dynamicTabs: TabItem[] = []; @@ -76,13 +74,14 @@ export class AccountSidesheetComponent implements OnInit { private readonly accountsService: AccountsService, private readonly reports: AccountsReportsService, private readonly tabService: ExtService, - private cdrFactory: CdrFactoryService + private cdrFactory: CdrFactoryService, ) { this.detailsFormGroup = new UntypedFormGroup({ formArray: formBuilder.array([]) }); this.parameters = { objecttable: sidesheetData.unsDbObjectKey?.TableName, objectuid: sidesheetData.unsDbObjectKey?.Keys.join(','), + display: this.sidesheetData.selectedAccount.GetEntity().GetDisplay(), }; this.reportDownload = { @@ -135,13 +134,13 @@ export class AccountSidesheetComponent implements OnInit { } get accountManagerIsEditable(): boolean { - return this.selectedAccount.objectKeyManagerColumn?.GetMetadata().CanEdit(); + return this.selectedAccount.objectKeyManagerColumn?.GetMetadata().CanEdit() ?? false; } public async syncToIdentityManager(event: MatSlideToggleChange): Promise { const objectKeyManagerColumn = this.selectedAccount.objectKeyManagerColumn; - if (objectKeyManagerColumn != null && event.checked) { + if (objectKeyManagerColumn && this.linkedIdentitiesManager && event.checked) { await objectKeyManagerColumn.PutValue(this.linkedIdentitiesManager.ToXmlString()); this.detailsFormGroup.markAsDirty(); this.unsavedSyncChanges = true; @@ -149,13 +148,13 @@ export class AccountSidesheetComponent implements OnInit { } private async setup(): Promise { - const cols = (await this.configService.getConfig()).OwnershipConfig.EditableFields[this.parameters.objecttable]; + const cols = (await this.configService.getConfig())?.OwnershipConfig?.EditableFields?.[this.parameters.objecttable] ?? []; this.cdrList = this.cdrFactory.buildCdrFromColumnList(this.selectedAccount.GetEntity(), cols); this.dynamicTabs = ( await this.tabService.getFittingComponents('accountSidesheet', (ext) => ext.inputData.checkVisibility(this.parameters)) - ).sort((tab1: TabItem, tab2: TabItem) => tab1.sortOrder - tab2.sortOrder); + ).sort((tab1: TabItem, tab2: TabItem) => tab1.sortOrder! - tab2.sortOrder!); this.setupIdentityManagerSync(); } @@ -168,7 +167,7 @@ export class AccountSidesheetComponent implements OnInit { } } - private async getLinkedIdentitiesManager(linkedIdentityId: string, tableName: string): Promise { + private async getLinkedIdentitiesManager(linkedIdentityId: string, tableName: string): Promise { const identityData = await this.identitiesService.getPerson(linkedIdentityId); if (identityData?.UID_PersonHead.value) { const managerAccountData = await this.accountsService.getAccount( @@ -176,7 +175,7 @@ export class AccountSidesheetComponent implements OnInit { TableName: tableName, Keys: [identityData.UID_PersonHead.value], }, - 'UID_Person' + 'UID_Person', ); if (managerAccountData) { diff --git a/imxweb/projects/tsb/src/lib/accounts/account-typed-entity.ts b/imxweb/projects/tsb/src/lib/accounts/account-typed-entity.ts index 12e2bac11..9f9eadf2d 100644 --- a/imxweb/projects/tsb/src/lib/accounts/account-typed-entity.ts +++ b/imxweb/projects/tsb/src/lib/accounts/account-typed-entity.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -24,7 +24,7 @@ * */ -import { DisplayColumns, IEntityColumn, TypedEntity } from 'imx-qbm-dbts'; +import { DisplayColumns, IEntityColumn, TypedEntity } from '@imx-modules/imx-qbm-dbts'; import { CdrFactoryService } from 'qbm'; export class AccountTypedEntity extends TypedEntity { diff --git a/imxweb/projects/tsb/src/lib/accounts/accounts-reports.service.ts b/imxweb/projects/tsb/src/lib/accounts/accounts-reports.service.ts index cfb66aec2..217f2f41f 100644 --- a/imxweb/projects/tsb/src/lib/accounts/accounts-reports.service.ts +++ b/imxweb/projects/tsb/src/lib/accounts/accounts-reports.service.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -25,18 +25,18 @@ */ import { Injectable } from '@angular/core'; -import { CollectionLoadParameters, TypedEntityCollectionData } from 'imx-qbm-dbts'; -import { - PortalTargetsystemUnsAccount -} from 'imx-api-tsb'; +import { CollectionLoadParameters, TypedEntityCollectionData } from '@imx-modules/imx-qbm-dbts'; +import { PortalTargetsystemUnsAccount } from '@imx-modules/imx-api-tsb'; import { AppConfigService, SettingsService } from 'qbm'; import { TsbApiService } from '../tsb-api-client.service'; @Injectable({ providedIn: 'root' }) export class AccountsReportsService { - constructor(private tsbClient: TsbApiService, + constructor( + private tsbClient: TsbApiService, private readonly settings: SettingsService, - private appConfig: AppConfigService) { } + private appConfig: AppConfigService, + ) {} public accountsReport(historyDays: number, accountId: string, tableName: string): string { const path = `targetsystem/uns/account/${tableName}/${accountId}/report?historydays=${historyDays}`; diff --git a/imxweb/projects/tsb/src/lib/accounts/accounts.component.html b/imxweb/projects/tsb/src/lib/accounts/accounts.component.html index 0fe2fa93c..1e7a7f948 100644 --- a/imxweb/projects/tsb/src/lib/accounts/accounts.component.html +++ b/imxweb/projects/tsb/src/lib/accounts/accounts.component.html @@ -1,77 +1,74 @@ -
    -
    - #LDS#Heading User Accounts +
    +
    +

    #LDS#Heading User Accounts

    - - -
    - -
    -
    - -
    - -
    - - - #LDS#There is currently no data synchronization configured for the selected domain. - - -
    + > +
    - - - + + + + {{ entitySchemaUnsAccount?.Columns?.[this.DisplayColumns.DISPLAY_PROPERTYNAME]?.Display }} + +
    {{ item.GetEntity().GetDisplay() }}
    -
    -
    - - -
    {{ item.UID_Person.Column.GetDisplayValue() }}
    -
    -
    - - - + + + + + {{ entitySchemaUnsAccount?.Columns?.UID_Person?.Display }} + + +
    + {{ item.UID_Person.Column.GetDisplayValue() }} +
    + +
    + + {{ entitySchemaUnsAccount?.Columns?.AccountDisabled?.Display }} + +
    {{ item.AccountDisabled.Column.GetDisplayValue() }}
    + +
    + + {{ entitySchemaUnsAccount?.Columns?.UID_UNSRoot?.Display }} +
    {{ item.UID_UNSRoot.Column.GetDisplayValue() }}
    {{ item.UID_DPRNameSpace.Column.GetDisplayValue() }}
    -
    -
    - - + + + + +
    {{ item.XMarkedForDeletion.Column.GetDisplayValue() }}
    -
    -
    -
    - + + + +
    -
    +
    diff --git a/imxweb/projects/tsb/src/lib/accounts/target-system-report/target-system-report.component.scss b/imxweb/projects/tsb/src/lib/accounts/target-system-report/target-system-report.component.scss index 675781889..d742eb934 100644 --- a/imxweb/projects/tsb/src/lib/accounts/target-system-report/target-system-report.component.scss +++ b/imxweb/projects/tsb/src/lib/accounts/target-system-report/target-system-report.component.scss @@ -3,12 +3,6 @@ display: flex; } -.eui-sidesheet-content { - overflow: hidden; - display: flex; - flex-direction: column; -} - .imx-content-card { margin-top: 10px; flex: 1 1 auto; diff --git a/imxweb/projects/tsb/src/lib/accounts/target-system-report/target-system-report.component.ts b/imxweb/projects/tsb/src/lib/accounts/target-system-report/target-system-report.component.ts index 22ece1f68..c6b4ab885 100644 --- a/imxweb/projects/tsb/src/lib/accounts/target-system-report/target-system-report.component.ts +++ b/imxweb/projects/tsb/src/lib/accounts/target-system-report/target-system-report.component.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -26,21 +26,20 @@ import { Overlay } from '@angular/cdk/overlay'; import { HttpClient } from '@angular/common/http'; -import { Component, Injector, OnInit } from '@angular/core'; -import { EuiDownloadDirective, EuiLoadingService } from '@elemental-ui/core'; +import { Component, ElementRef, Injector, OnInit } from '@angular/core'; +import { EuiDownloadDirective, EuiDownloadService, EuiLoadingService } from '@elemental-ui/core'; -import { IEntity } from 'imx-qbm-dbts'; -import { FilterTreeEntityWrapperService, FilterTreeDatabase, ElementalUiConfigService } from 'qbm'; +import { IEntity } from '@imx-modules/imx-qbm-dbts'; +import { ElementalUiConfigService, FilterTreeDatabase, FilterTreeEntityWrapperService } from 'qbm'; import { AccountsReportsService } from '../accounts-reports.service'; import { AccountsService } from '../accounts.service'; @Component({ selector: 'imx-target-system-report', templateUrl: './target-system-report.component.html', - styleUrls: ['./target-system-report.component.scss'] + styleUrls: ['./target-system-report.component.scss'], }) export class TargetSystemReportComponent implements OnInit { - public showHelperAlert = true; public database: FilterTreeDatabase; public selectedEntity: IEntity; @@ -54,19 +53,20 @@ export class TargetSystemReportComponent implements OnInit { private readonly http: HttpClient, private readonly injector: Injector, private readonly overlay: Overlay, - ) { } + private readonly downloadService: EuiDownloadService, + ) {} public async ngOnInit(): Promise { - this.database = new FilterTreeDatabase(this.entityWrapper, + this.database = new FilterTreeDatabase( + this.entityWrapper, async (parentkey) => { return this.accountsService.getFilterTree({ parentkey, - container: undefined, - system: undefined, - filter: undefined + filter: undefined, }); - } - , this.busyService); + }, + this.busyService, + ); } public onHelperDismissed(): void { @@ -74,7 +74,7 @@ export class TargetSystemReportComponent implements OnInit { } public onNodeSelected(entity: IEntity): void { - this.selectedEntity = entity; + this.selectedEntity = entity; } public loadReport(): void { @@ -87,18 +87,25 @@ export class TargetSystemReportComponent implements OnInit { const columnName = val.ColumnName; if (columnName === 'UID_UNSRoot') { url = this.accountReport.accountsByRootReport(30, val.Value1); - } - else if (columnName === 'UID_UNSContainer') { + } else if (columnName === 'UID_UNSContainer') { url = this.accountReport.accountsByContainerReport(30, val.Value1); + } else { + return; } - const directive = new EuiDownloadDirective(null, this.http, this.overlay, this.injector); + const directive = new EuiDownloadDirective( + new ElementRef('') /* no element */, + this.http, + this.overlay, + this.injector, + this.downloadService, + ); if (directive && url !== '') { directive.downloadOptions = { - ... this.elementalUiConfigService.Config.downloadOptions, + ...this.elementalUiConfigService.Config.downloadOptions, url, fileName: `${this.selectedEntity.GetDisplay()}.pdf`, - disableElement: false + disableElement: false, }; directive.onClick(); } diff --git a/imxweb/projects/tsb/src/lib/admin/tsb-permissions-helper.ts b/imxweb/projects/tsb/src/lib/admin/tsb-permissions-helper.ts index dc6a462de..303d57502 100644 --- a/imxweb/projects/tsb/src/lib/admin/tsb-permissions-helper.ts +++ b/imxweb/projects/tsb/src/lib/admin/tsb-permissions-helper.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -24,6 +24,6 @@ * */ -export function isTsbNameSpaceAdminBase(groups: string[]): boolean { - return groups.find(item => item.toUpperCase() === 'TSB_4_NAMESPACEADMIN_BASE') != null; +export function isTsbNameSpaceAdminBase(groups: (string | undefined)[]): boolean { + return groups.find((item) => item && item.toUpperCase() === 'TSB_4_NAMESPACEADMIN_BASE') != null; } diff --git a/imxweb/projects/tsb/src/lib/admin/tsb-permissions.service.ts b/imxweb/projects/tsb/src/lib/admin/tsb-permissions.service.ts index 95a161d8f..bb9e4e6fe 100644 --- a/imxweb/projects/tsb/src/lib/admin/tsb-permissions.service.ts +++ b/imxweb/projects/tsb/src/lib/admin/tsb-permissions.service.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -30,12 +30,12 @@ import { UserModelService } from 'qer'; import { isTsbNameSpaceAdminBase } from './tsb-permissions-helper'; @Injectable({ - providedIn: 'root' + providedIn: 'root', }) export class TsbPermissionsService { - constructor(private readonly userService: UserModelService) { } + constructor(private readonly userService: UserModelService) {} public async isTsbNameSpaceAdminBase(): Promise { - return isTsbNameSpaceAdminBase((await this.userService.getGroups()).map(userGroupInfo => userGroupInfo.Name)); + return isTsbNameSpaceAdminBase((await this.userService.getGroups()).map((userGroupInfo) => userGroupInfo.Name)); } } diff --git a/imxweb/projects/tsb/src/lib/claim-group/claim-group.component.html b/imxweb/projects/tsb/src/lib/claim-group/claim-group.component.html index 590c92c5b..8536fed0b 100644 --- a/imxweb/projects/tsb/src/lib/claim-group/claim-group.component.html +++ b/imxweb/projects/tsb/src/lib/claim-group/claim-group.component.html @@ -1,23 +1,41 @@ -

    +

    {{ '#LDS#Heading Assign an Owner for a System Entitlement' | translate }} -

    +
    - +
    - +
    - +
    + +
    - {{ '#LDS#Specify the owner for the system entitlement "{0}".' | translate | ldsReplace : entitlementCdr.column.GetDisplayValue() }} + {{ '#LDS#Specify the owner for the system entitlement "{0}".' | translate | ldsReplace: entitlementCdr.column.GetDisplayValue() }} {{ '#LDS#Specify the owner' | translate }} @@ -31,24 +49,36 @@

    }}

    - + {{ option.title | translate }}
    - +
    - - +
    + + +
    - {{ '#LDS#Assign ownership for the system entitlement "{0}" to "{1}".' | translate | ldsReplace : entitlementCdr.column.GetDisplayValue() : ownerDisplay }} + {{ + '#LDS#Assign ownership for the system entitlement "{0}" to "{1}".' + | translate + | ldsReplace: entitlementCdr.column.GetDisplayValue() : ownerDisplay + }} {{ '#LDS#Assign ownership' | translate }} @@ -59,11 +89,18 @@

    {{ '#LDS#Your changes have been successfully saved. It may take some time for the changes to take effect.' | translate }}

    - +

    -

    {{ '#LDS#You cannot currently assign owners for system entitlements. The system entitlement ownership attestation policy is deactivated.' | translate }}

    +

    + {{ + '#LDS#You cannot currently assign owners for system entitlements. The system entitlement ownership attestation policy is deactivated.' + | translate + }} +

    diff --git a/imxweb/projects/tsb/src/lib/claim-group/claim-group.component.scss b/imxweb/projects/tsb/src/lib/claim-group/claim-group.component.scss index dfdb6cf97..c56cbacea 100644 --- a/imxweb/projects/tsb/src/lib/claim-group/claim-group.component.scss +++ b/imxweb/projects/tsb/src/lib/claim-group/claim-group.component.scss @@ -6,31 +6,22 @@ overflow: hidden; } -mat-radio-group { - display: flex; - flex-direction: column; -} - -.imx-button-previous { - margin-right: 10px; -} - .imx-owner-assigned { display: flex; flex-direction: column; - >*:not(:last-child) { + > *:not(:last-child) { margin-bottom: 10px; } - >button { - align-self: flex-end; + > button { + align-self: flex-end; } } -.imx-system-entitlement-stepper{ +.imx-system-entitlement-stepper { flex: 1 1 auto; max-width: 100%; overflow: auto; display: flex; flex-direction: column; -} \ No newline at end of file +} diff --git a/imxweb/projects/tsb/src/lib/claim-group/claim-group.component.ts b/imxweb/projects/tsb/src/lib/claim-group/claim-group.component.ts index 0e770c08b..d50f700df 100644 --- a/imxweb/projects/tsb/src/lib/claim-group/claim-group.component.ts +++ b/imxweb/projects/tsb/src/lib/claim-group/claim-group.component.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -27,34 +27,35 @@ import { StepperSelectionEvent } from '@angular/cdk/stepper'; import { Component, ErrorHandler, OnDestroy, OnInit } from '@angular/core'; import { UntypedFormGroup } from '@angular/forms'; -import { OverlayRef } from '@angular/cdk/overlay'; import { MatRadioChange } from '@angular/material/radio'; import { EuiLoadingService } from '@elemental-ui/core'; import { Subscription } from 'rxjs'; import { AuthenticationService, BaseCdr, ISessionState } from 'qbm'; import { PersonService } from 'qer'; -import { ClaimGroupService } from './claim-group.service'; import { TargetSystemService } from '../target-system/target-system.service'; +import { ClaimGroupService } from './claim-group.service'; @Component({ styleUrls: ['./claim-group.component.scss'], - templateUrl: './claim-group.component.html' + templateUrl: './claim-group.component.html', }) export class ClaimGroupComponent implements OnInit, OnDestroy { - public get ownerDisplay(): string { return this.ownerCdr ? this.ownerCdr.column.GetDisplayValue() : this.user.name; } + public get ownerDisplay(): string { + return this.ownerCdr ? this.ownerCdr.column.GetDisplayValue() : this.user.name; + } public entitlementCdr: BaseCdr; public ownerCdr: BaseCdr; - public ownershipOptions: { title: string; createOwnerCdr: () => BaseCdr; }[]; + public ownershipOptions: { title: string; createOwnerCdr: () => BaseCdr | undefined }[] = []; public ownerAssigned = false; public canClaimGroup = false; public readonly entitlementForm = new UntypedFormGroup({}); public readonly ownerForm = new UntypedFormGroup({}); - private readonly entitlementFkValue: { table?: string, key?: string } = { }; - private readonly user: { uid?: string; name?: string; } = { }; + private readonly entitlementFkValue: { table: string; key: string } = { table: '', key: '' }; + private readonly user: { uid: string; name: string } = { uid: '', name: '' }; private readonly subscriptions: Subscription[] = []; constructor( @@ -63,31 +64,32 @@ export class ClaimGroupComponent implements OnInit, OnDestroy { private readonly personService: PersonService, private readonly busyService: EuiLoadingService, private readonly authentication: AuthenticationService, - private readonly errorHandler: ErrorHandler + private readonly errorHandler: ErrorHandler, ) { this.initEntitlementCdr(); - this.subscriptions.push(this.authentication.onSessionResponse.subscribe(async (sessionState: ISessionState) => { - if (sessionState) { - this.user.uid = sessionState.UserUid; - this.user.name = sessionState.Username; - } - })); + this.subscriptions.push( + this.authentication.onSessionResponse.subscribe(async (sessionState: ISessionState) => { + if (sessionState) { + this.user.uid = sessionState.UserUid!; + this.user.name = sessionState.Username!; + } + }), + ); } public async ngOnInit(): Promise { - let overlayRef: OverlayRef; - setTimeout(() => overlayRef = this.busyService.show()); + this.showBusyIndicator(); try { // TODO wrap in cache this.canClaimGroup = (await this.targetSystem.getUserConfig()).CanClaimGroup; } finally { - setTimeout(() => this.busyService.hide(overlayRef)); + this.busyService.hide(); } } public ngOnDestroy(): void { - this.subscriptions.forEach(subscription => subscription.unsubscribe()); + this.subscriptions.forEach((subscription) => subscription.unsubscribe()); } public resetForms(): void { @@ -121,12 +123,11 @@ export class ClaimGroupComponent implements OnInit, OnDestroy { let hasSuggestedOwners = false; - let overlayRef: OverlayRef; - setTimeout(() => overlayRef = this.busyService.show()); + this.showBusyIndicator(); try { hasSuggestedOwners = await this.claimGroupService.hasSuggestedOwners(this.entitlementFkValue.table, this.entitlementFkValue.key); } finally { - setTimeout(() => this.busyService.hide(overlayRef)); + this.busyService.hide(); } const display = '#LDS#Designated owner'; // TODO: globalize; @@ -135,57 +136,61 @@ export class ClaimGroupComponent implements OnInit, OnDestroy { this.ownershipOptions.push({ title: '#LDS#I want to take ownership of this system entitlement', - createOwnerCdr: () => undefined + createOwnerCdr: () => undefined, }); if (hasSuggestedOwners) { this.ownershipOptions.push({ title: '#LDS#Select from the suggested possible owners', - createOwnerCdr: () => new BaseCdr( - this.claimGroupService.createColumnSuggestedOwner(this.entitlementFkValue.table, this.entitlementFkValue.key), - display - ) + createOwnerCdr: () => + new BaseCdr( + this.claimGroupService.createColumnSuggestedOwner(this.entitlementFkValue.table, this.entitlementFkValue.key), + display, + ), }); } this.ownershipOptions.push({ title: '#LDS#Select another owner', - createOwnerCdr: () => new BaseCdr( - this.personService.createColumnCandidatesPerson(), - display - ) + createOwnerCdr: () => new BaseCdr(this.personService.createColumnCandidatesPerson(), display), }); this.initOwnerCdr(this.ownershipOptions[0].createOwnerCdr()); } public async assignOwner(): Promise { - let overlayRef: OverlayRef; - setTimeout(() => overlayRef = this.busyService.show()); + this.showBusyIndicator(); try { await this.claimGroupService.assignOwner( this.entitlementFkValue.table, this.entitlementFkValue.key, - this.ownerCdr ? this.ownerCdr.column.GetValue() : this.user.uid + this.ownerCdr ? this.ownerCdr.column.GetValue() : this.user.uid, ); this.ownerAssigned = true; } catch (error) { this.errorHandler.handleError(error); } finally { - setTimeout(() => this.busyService.hide(overlayRef)); + this.busyService.hide(); } } private initEntitlementCdr(): void { - Object.keys(this.entitlementForm.controls).forEach(name => this.entitlementForm.removeControl(name)); + Object.keys(this.entitlementForm.controls).forEach((name) => this.entitlementForm.removeControl(name)); this.entitlementCdr = this.claimGroupService.createCdrSystemEntitlement(); } - private initOwnerCdr(cdr: BaseCdr): void { - Object.keys(this.ownerForm.controls).forEach(name => this.ownerForm.removeControl(name)); + private initOwnerCdr(cdr: BaseCdr | undefined): void { + Object.keys(this.ownerForm.controls).forEach((name) => this.ownerForm.removeControl(name)); + if (cdr) { + this.ownerCdr = cdr; + } + } - this.ownerCdr = cdr; + private showBusyIndicator(): void { + if (this.busyService.overlayRefs.length === 0) { + this.busyService.show(); + } } } diff --git a/imxweb/projects/tsb/src/lib/claim-group/claim-group.module.ts b/imxweb/projects/tsb/src/lib/claim-group/claim-group.module.ts index 9298bafb9..13ab85e20 100644 --- a/imxweb/projects/tsb/src/lib/claim-group/claim-group.module.ts +++ b/imxweb/projects/tsb/src/lib/claim-group/claim-group.module.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -37,9 +37,7 @@ import { CdrModule, HelpContextualModule, LdsReplaceModule } from 'qbm'; import { ClaimGroupComponent } from './claim-group.component'; @NgModule({ - declarations: [ - ClaimGroupComponent - ], + declarations: [ClaimGroupComponent], imports: [ CdrModule, CommonModule, @@ -52,7 +50,6 @@ import { ClaimGroupComponent } from './claim-group.component'; ReactiveFormsModule, TranslateModule, HelpContextualModule, - ] + ], }) -export class ClaimGroupModule { -} +export class ClaimGroupModule {} diff --git a/imxweb/projects/tsb/src/lib/claim-group/claim-group.service.ts b/imxweb/projects/tsb/src/lib/claim-group/claim-group.service.ts index 4c2bafa41..6ca86e397 100644 --- a/imxweb/projects/tsb/src/lib/claim-group/claim-group.service.ts +++ b/imxweb/projects/tsb/src/lib/claim-group/claim-group.service.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -26,15 +26,25 @@ import { Injectable } from '@angular/core'; -import { CollectionLoadParameters, DbObjectKey, EntityCollectionData, IEntityColumn, MetaTableRelationData, ValType } from 'imx-qbm-dbts'; +import { + CollectionLoadParameters, + DbObjectKey, + EntityCollectionData, + IEntityColumn, + MetaTableRelationData, + ValType, +} from '@imx-modules/imx-qbm-dbts'; import { BaseCdr, EntityService } from 'qbm'; import { TsbApiService } from '../tsb-api-client.service'; @Injectable({ - providedIn: 'root' + providedIn: 'root', }) export class ClaimGroupService { - constructor(private readonly apiService: TsbApiService, private readonly entityService: EntityService) { } + constructor( + private readonly apiService: TsbApiService, + private readonly entityService: EntityService, + ) {} public async hasSuggestedOwners(tableName: string, key: string): Promise { const collection = await this.getOwnerCandidates(tableName, key); @@ -45,11 +55,11 @@ export class ClaimGroupService { return this.apiService.client.portal_claimgroup_post(uidOwner, tableName, key); } - public getFkValue(column: IEntityColumn): { table?: string, key?: string; } { + public getFkValue(column: IEntityColumn): { table: string; key: string } { const dbObjectKey = DbObjectKey.FromXml(column.GetValue()); return { table: dbObjectKey.TableName, - key: dbObjectKey.Keys[0] + key: dbObjectKey.Keys[0], }; } @@ -59,9 +69,9 @@ export class ClaimGroupService { ChildColumnName: 'UID_UNSGroup', IsMemberRelation: false, ParentTableName: 'UNSGroup', - ParentColumnName: 'XObjectKey' + ParentColumnName: 'XObjectKey', }, - parameters => this.apiService.client.portal_claimgroup_group_get(parameters) + (parameters) => this.apiService.client.portal_claimgroup_group_get(parameters), ); return new BaseCdr(column, '#LDS#System entitlement' /* TODO: globalize */); @@ -72,58 +82,47 @@ export class ClaimGroupService { ChildColumnName: 'UID_Owner', IsMemberRelation: false, ParentTableName: tableName, - ParentColumnName: 'XObjectKey' + ParentColumnName: 'XObjectKey', }; - return this.createColumn( - fkRelation, - parameters => this.getOwnerCandidates(fkRelation.ParentTableName, key, parameters) - ); + return this.createColumn(fkRelation, (parameters) => this.getOwnerCandidates(fkRelation.ParentTableName, key, parameters)); } private createColumn( fkRelation: MetaTableRelationData, - loadFkCandidates: (parameters: CollectionLoadParameters) => Promise + loadFkCandidates: (parameters: CollectionLoadParameters) => Promise, ): IEntityColumn { return this.entityService.createLocalEntityColumn( { - ColumnName: fkRelation.ChildColumnName, + ColumnName: fkRelation.ChildColumnName!, Type: ValType.String, MinLen: 1, - FkRelation: fkRelation + FkRelation: fkRelation, }, - [{ - columnName: fkRelation.ChildColumnName, - fkTableName: fkRelation.ParentTableName, - parameterNames: [ - 'OrderBy', - 'StartIndex', - 'PageSize', - 'filter', - 'search', - ], - load: async (_, parameters: CollectionLoadParameters = {}) => loadFkCandidates(parameters), - getDataModel: async () => ({}), - getFilterTree: async () => ({ Elements: [] }) - }] + [ + { + columnName: fkRelation.ChildColumnName!, + fkTableName: fkRelation.ParentTableName!, + parameterNames: ['OrderBy', 'StartIndex', 'PageSize', 'filter', 'search'], + load: async (_, parameters: CollectionLoadParameters = {}) => loadFkCandidates(parameters), + getDataModel: async () => ({}), + getFilterTree: async () => ({ Elements: [] }), + }, + ], ); } private async getOwnerCandidates( - tableName: string, uid: string, parameters: CollectionLoadParameters = {} + tableName: string, + uid: string, + parameters: CollectionLoadParameters = {}, ): Promise { - const collection = await this.apiService.client.portal_claimgroup_suggestedowner_get( - tableName, - uid, - parameters); + const collection = await this.apiService.client.portal_claimgroup_suggestedowner_get(tableName, uid, parameters); if (collection.Entities && collection.Entities.length > 0) { return collection; } - return this.apiService.client.portal_claimgroup_suggestedowner2_get( - tableName, - uid, - parameters); + return this.apiService.client.portal_claimgroup_suggestedowner2_get(tableName, uid, parameters); } } diff --git a/imxweb/projects/tsb/src/lib/container-list/container-tree-database-wrapper.ts b/imxweb/projects/tsb/src/lib/container-list/container-tree-database-wrapper.ts index f35c39b5e..258e08a26 100644 --- a/imxweb/projects/tsb/src/lib/container-list/container-tree-database-wrapper.ts +++ b/imxweb/projects/tsb/src/lib/container-list/container-tree-database-wrapper.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -24,22 +24,18 @@ * */ -import { CollectionLoadParameters, IEntity } from 'imx-qbm-dbts'; +import { CollectionLoadParameters, IEntity } from '@imx-modules/imx-qbm-dbts'; import { BusyService, EntityTreeDatabase } from 'qbm'; import { DeHelperService } from '../de-helper.service'; export class ContainerTreeDatabaseWrapper { - public get targetSystemFilterValue(): string { return this.system; } public set targetSystemFilterValue(value: string) { this.system = value; - this.entityTreeDatabase = new EntityTreeDatabase( - parameters => this.getEntities(parameters, value), - this.busyService - ); + this.entityTreeDatabase = new EntityTreeDatabase((parameters) => this.getEntities(parameters, value), this.busyService); } public selectionEnabled = false; @@ -50,12 +46,9 @@ export class ContainerTreeDatabaseWrapper { constructor( private readonly busyService: BusyService, - private readonly dataHelper: DeHelperService + private readonly dataHelper: DeHelperService, ) { - this.entityTreeDatabase = new EntityTreeDatabase( - parameters => this.getEntities(parameters), - this.busyService - ); + this.entityTreeDatabase = new EntityTreeDatabase((parameters) => this.getEntities(parameters), this.busyService); } private async getEntities(parameters: CollectionLoadParameters = {}, system: string = ''): Promise { @@ -67,6 +60,6 @@ export class ContainerTreeDatabaseWrapper { navigationState.system = system; } const containerData = await this.dataHelper.getContainers(navigationState); - return containerData.Data.map(element => element.GetEntity()); + return containerData.Data.map((element) => element.GetEntity()); } } diff --git a/imxweb/projects/tsb/src/lib/data-filters/data-explorer-filters.component.html b/imxweb/projects/tsb/src/lib/data-filters/data-explorer-filters.component.html index e32ca8b4f..8d720c353 100644 --- a/imxweb/projects/tsb/src/lib/data-filters/data-explorer-filters.component.html +++ b/imxweb/projects/tsb/src/lib/data-filters/data-explorer-filters.component.html @@ -6,22 +6,37 @@ (optionsClear)="clearTargetSystemFilterSelection(false)" [options]="targetSystemOptions" [isPending]="pendingAsyncApiCall" - class="imx-de-targetsystem-filter" - #tsSelect> + class="imx-margin-bottom-15" + #tsSelect +> -
    - - - +
    + class="imx-container-search" + #containerSelect + >
    -
    - - +
    diff --git a/imxweb/projects/tsb/src/lib/data-filters/data-explorer-filters.component.scss b/imxweb/projects/tsb/src/lib/data-filters/data-explorer-filters.component.scss index 57c720621..6ffef42ef 100644 --- a/imxweb/projects/tsb/src/lib/data-filters/data-explorer-filters.component.scss +++ b/imxweb/projects/tsb/src/lib/data-filters/data-explorer-filters.component.scss @@ -1,10 +1,5 @@ -.imx-de-targetsystem-filter { - margin-bottom: 15px; -} - .imx-de-container-tree-filter { - display: flex; align-items: center; margin-bottom: 15px; @@ -20,16 +15,9 @@ overflow: hidden; text-overflow: ellipsis; } - - .container-search { - &--hidden { - display: none; - } - } - } -::ng-deep .mat-menu-panel { +::ng-deep .mat-mdc-menu-panel { &.container-filter-menu { min-width: 250px; max-width: 400px; @@ -37,5 +25,3 @@ padding: 0 10px; } } - - diff --git a/imxweb/projects/tsb/src/lib/data-filters/data-explorer-filters.component.ts b/imxweb/projects/tsb/src/lib/data-filters/data-explorer-filters.component.ts index 2a3061df3..88ec77278 100644 --- a/imxweb/projects/tsb/src/lib/data-filters/data-explorer-filters.component.ts +++ b/imxweb/projects/tsb/src/lib/data-filters/data-explorer-filters.component.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -26,15 +26,15 @@ import { Component, EventEmitter, Input, OnInit, Output, ViewChild } from '@angular/core'; import { EuiSelectComponent, EuiSelectOption } from '@elemental-ui/core'; -import { PortalTargetsystemUnsSystem } from 'imx-api-tsb'; -import { IEntity } from 'imx-qbm-dbts'; +import { PortalTargetsystemUnsSystem } from '@imx-modules/imx-api-tsb'; +import { IEntity } from '@imx-modules/imx-qbm-dbts'; import { DataSourceToolbarComponent, DataSourceToolbarSelectedFilter } from 'qbm'; import { ContainerTreeDatabaseWrapper } from '../container-list/container-tree-database-wrapper'; import { DeHelperService } from '../de-helper.service'; export enum DataExplorerFilterTypes { TargetSystem = 'targetsystem', - Container = 'container' + Container = 'container', } @Component({ @@ -43,7 +43,6 @@ export enum DataExplorerFilterTypes { styleUrls: ['./data-explorer-filters.component.scss'], }) export class DataExplorerFiltersComponent implements OnInit { - public targetSystemOptions: EuiSelectOption[] = []; public selectedTargetSystemUid: string; public dstTargetSystemFilterRef: DataSourceToolbarSelectedFilter; @@ -66,12 +65,12 @@ export class DataExplorerFiltersComponent implements OnInit { private skipSelectionEmitMode = false; - constructor(private readonly dataHelper: DeHelperService) { } + constructor(private readonly dataHelper: DeHelperService) {} public get selectedTreeNodeFilterDisplay(): string { let display = ''; if (this.selectedContainerUid) { - display = `Container: ${this.dstContainerFilterRef.selectedOption.Display}`; + display = `Container: ${this.dstContainerFilterRef.selectedOption?.Display}`; } return display; } @@ -119,7 +118,9 @@ export class DataExplorerFiltersComponent implements OnInit { } } - public targetSystemSelected(selected: EuiSelectOption): void { + public targetSystemSelected(chosen: EuiSelectOption | EuiSelectOption[]): void { + const selected = Array.isArray(chosen) ? chosen[0] : chosen; + this.selectedTargetSystemUid = selected.value; this.updateDataSyncStateForTs(selected); if (this.treeDbWrapper) { @@ -134,7 +135,7 @@ export class DataExplorerFiltersComponent implements OnInit { this.dstTargetSystemFilterRef = { selectedOption: { Value: selected.value, Display: selected.display }, filter: { Name: DataExplorerFilterTypes.TargetSystem }, - isCustom: true + isCustom: true, }; this.dst.selectedFilters.push(this.dstTargetSystemFilterRef); } @@ -205,10 +206,12 @@ export class DataExplorerFiltersComponent implements OnInit { const selectedValue: string = entity.GetKeys()[0]; // Set the selected value on the search control as well this.containerSelect.writeValue(selectedValue); - this.setSelectedContainer({value: selectedValue, display: entity.GetDisplay()}); + this.setSelectedContainer({ value: selectedValue, display: entity.GetDisplay() }); } - public setSelectedContainer(selected: EuiSelectOption): void { + public setSelectedContainer(chosen: EuiSelectOption | EuiSelectOption[]): void { + const selected = Array.isArray(chosen) ? chosen[0] : chosen; + this.selectedContainerUid = selected.value; if (this.dst) { @@ -216,9 +219,9 @@ export class DataExplorerFiltersComponent implements OnInit { this.clearDstSelectedFilter(this.dstContainerFilterRef); if (selected.value && selected.value.length > 0) { this.dstContainerFilterRef = { - selectedOption: { Value: selected.value, Display: selected.display}, + selectedOption: { Value: selected.value, Display: selected.display }, filter: { Name: DataExplorerFilterTypes.Container }, - isCustom: true + isCustom: true, }; this.dst.selectedFilters.push(this.dstContainerFilterRef); } @@ -236,8 +239,8 @@ export class DataExplorerFiltersComponent implements OnInit { this.containerSearchMode = !this.containerSearchMode; if (this.containerSearchMode) { if (this.treeDbWrapper?.entityTreeDatabase?.topLevelEntities) { - this.containerSelectOptions = this.treeDbWrapper.entityTreeDatabase.topLevelEntities.map(d => - this.convertEntityToEuiSelectOption(d) + this.containerSelectOptions = this.treeDbWrapper.entityTreeDatabase.topLevelEntities.map((d) => + this.convertEntityToEuiSelectOption(d), ); } else { this.getContainers(); @@ -257,15 +260,15 @@ export class DataExplorerFiltersComponent implements OnInit { if (!sf) { // If no singular filter is supplied, then all have been cleared this.clearAllSelectedFilters(); - } else if (sf.filter.Name === DataExplorerFilterTypes.TargetSystem) { + } else if (sf.filter?.Name === DataExplorerFilterTypes.TargetSystem) { this.clearTargetSystemFilterSelection(true); - } else if (sf.filter.Name === DataExplorerFilterTypes.Container) { + } else if (sf.filter?.Name === DataExplorerFilterTypes.Container) { this.clearContainerFilterSelection(true); } }); } - private updateDataSyncStateForTs(selectedOption?: EuiSelectOption): void { + private updateDataSyncStateForTs(selectedOption: EuiSelectOption): void { this.selectedTsOption = selectedOption; this.tsIssueMode = ''; if (this.showTsSyncStatus) { @@ -278,22 +281,19 @@ export class DataExplorerFiltersComponent implements OnInit { } private clearDstSelectedFilter(selectedFilterRef: DataSourceToolbarSelectedFilter): void { - if (this.dst && selectedFilterRef) { + if (this.dst && selectedFilterRef && selectedFilterRef.selectedOption?.Value) { // Remove the 'isCustom' property to avoid an event being triggered in dst code selectedFilterRef.isCustom = undefined; // Then make call to remove selected filter - this.dst.removeSelectedFilter( - selectedFilterRef.filter, - false, - selectedFilterRef.selectedOption.Value, - selectedFilterRef - ); + this.dst.removeSelectedFilter(selectedFilterRef.filter, false, selectedFilterRef.selectedOption.Value, selectedFilterRef); } } private async getTargetSystemOptions(search?: string): Promise { const data = await this.dataHelper.getAuthorityData(search, true); - this.setupTsSelectOptions(data.authorities); + if (data.authorities) { + this.setupTsSelectOptions(data.authorities); + } } private async getContainers(search?: string): Promise { @@ -301,11 +301,11 @@ export class DataExplorerFiltersComponent implements OnInit { navState.search = search ? search : undefined; navState.system = this.selectedTargetSystemUid ? this.selectedTargetSystemUid : undefined; const data = await this.dataHelper.getContainers(navState); - this.containerSelectOptions = data?.Data.map(d => this.convertEntityToEuiSelectOption(d.GetEntity())); + this.containerSelectOptions = data?.Data.map((d) => this.convertEntityToEuiSelectOption(d.GetEntity())); } private setupTsSelectOptions(targetSystems: PortalTargetsystemUnsSystem[]): void { - this.targetSystemOptions = targetSystems.map(d => this.convertTsToEuiSelectOption(d)); + this.targetSystemOptions = targetSystems.map((d) => this.convertTsToEuiSelectOption(d)); } private convertTsToEuiSelectOption(tEntity: PortalTargetsystemUnsSystem): EuiSelectOption { @@ -318,5 +318,4 @@ export class DataExplorerFiltersComponent implements OnInit { private convertEntityToEuiSelectOption(entity: IEntity): EuiSelectOption { return { display: entity.GetDisplay(), value: entity.GetKeys()[0] }; } - } diff --git a/imxweb/projects/tsb/src/lib/data-filters/data-filters.module.ts b/imxweb/projects/tsb/src/lib/data-filters/data-filters.module.ts index 832e333d6..35f3aa17b 100644 --- a/imxweb/projects/tsb/src/lib/data-filters/data-filters.module.ts +++ b/imxweb/projects/tsb/src/lib/data-filters/data-filters.module.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -36,12 +36,10 @@ import { TranslateModule } from '@ngx-translate/core'; import { DataSourceToolbarModule, DataTableModule, CdrModule, LdsReplaceModule, DataTreeModule } from 'qbm'; -import { DataExplorerFiltersComponent} from './data-explorer-filters.component'; +import { DataExplorerFiltersComponent } from './data-explorer-filters.component'; @NgModule({ - declarations: [ - DataExplorerFiltersComponent - ], + declarations: [DataExplorerFiltersComponent], imports: [ CommonModule, FormsModule, @@ -57,12 +55,9 @@ import { DataExplorerFiltersComponent} from './data-explorer-filters.component'; DataSourceToolbarModule, DataTableModule, LdsReplaceModule, - DataTreeModule - ], - providers: [ + DataTreeModule, ], - exports: [ - DataExplorerFiltersComponent - ] + providers: [], + exports: [DataExplorerFiltersComponent], }) export class DataFiltersModule {} diff --git a/imxweb/projects/tsb/src/lib/de-helper.service.ts b/imxweb/projects/tsb/src/lib/de-helper.service.ts index 6b74f1dfa..e6609af4d 100644 --- a/imxweb/projects/tsb/src/lib/de-helper.service.ts +++ b/imxweb/projects/tsb/src/lib/de-helper.service.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -25,14 +25,10 @@ */ import { Injectable } from '@angular/core'; -import { - ExtendedTypedEntityCollection, - CollectionLoadParameters, - TypedEntityCollectionData, -} from 'imx-qbm-dbts'; -import { PortalTargetsystemUnsContainer, PortalTargetsystemUnsSystem } from 'imx-api-tsb'; -import { Subject } from 'rxjs'; import { EuiLoadingService } from '@elemental-ui/core'; +import { PortalTargetsystemUnsContainer, PortalTargetsystemUnsSystem } from '@imx-modules/imx-api-tsb'; +import { CollectionLoadParameters, ExtendedTypedEntityCollection, TypedEntityCollectionData } from '@imx-modules/imx-qbm-dbts'; +import { Subject } from 'rxjs'; import { TsbApiService } from './tsb-api-client.service'; @Injectable({ providedIn: 'root' }) @@ -41,7 +37,7 @@ export class DeHelperService { constructor( private loader: EuiLoadingService, - private tsbClient: TsbApiService + private tsbClient: TsbApiService, ) {} public async getAuthorityData(search?: string, skipLoader?: boolean): Promise { @@ -50,7 +46,7 @@ export class DeHelperService { loadParams.search = search; } const method = this.tsbClient.typedClient.PortalTargetsystemUnsSystem; - let data: ExtendedTypedEntityCollection; + let data: ExtendedTypedEntityCollection; if (skipLoader) { data = await method.Get(loadParams); } else { @@ -63,7 +59,7 @@ export class DeHelperService { } public async getContainers( - navigationState: CollectionLoadParameters + navigationState: CollectionLoadParameters, ): Promise> { return this.tsbClient.typedClient.PortalTargetsystemUnsContainer.Get(navigationState); } diff --git a/imxweb/projects/tsb/src/lib/groups/group-memberships-ext/group-memberships-ext.component.html b/imxweb/projects/tsb/src/lib/groups/group-memberships-ext/group-memberships-ext.component.html index 5353ee53a..f509598d3 100644 --- a/imxweb/projects/tsb/src/lib/groups/group-memberships-ext/group-memberships-ext.component.html +++ b/imxweb/projects/tsb/src/lib/groups/group-memberships-ext/group-memberships-ext.component.html @@ -1,28 +1,39 @@ - - {{ '#LDS#Here you can get an overview of the memberships of the identity. Additionally, you can view the assignment analysis for each membership.' | translate }} + + {{ + '#LDS#Here you can get an overview of the memberships of the identity. Additionally, you can view the assignment analysis for each membership.' + | translate + }} - - -
    - - - + + + + + {{ entitySchema?.Columns?.[DisplayColumns.DISPLAY_PROPERTYNAME]?.Display }} + + +
    {{ item.GetEntity().GetDisplay() }}
    -
    + @if (item.XIsInEffect?.value !== true) { + {{ '#LDS#Not effective' | translate }} + } +
    + @if (item.GetEntity().GetDisplay() !== item.GetEntity().GetDisplayLong()) { +
    {{ item.GetEntity().GetDisplayLong() }}
    - - - - - -
    + } + +
    + + @for (column of displayColumns; track column.ColumnName) { + + {{ column.Display }} + + {{ item.GetEntity().GetColumn(column.ColumnName)?.GetDisplayValue() }} + + + } +
    + diff --git a/imxweb/projects/tsb/src/lib/groups/group-memberships-ext/group-memberships-ext.component.scss b/imxweb/projects/tsb/src/lib/groups/group-memberships-ext/group-memberships-ext.component.scss index 4ee2d6742..593fe0ef5 100644 --- a/imxweb/projects/tsb/src/lib/groups/group-memberships-ext/group-memberships-ext.component.scss +++ b/imxweb/projects/tsb/src/lib/groups/group-memberships-ext/group-memberships-ext.component.scss @@ -1,4 +1,3 @@ - :host { overflow: hidden; display: flex; @@ -6,7 +5,6 @@ height: 100%; } - .imx-memberships { flex: 1 1 auto; display: flex; @@ -22,6 +20,12 @@ margin-top: 20px; } -.helper-alert { - margin: 20px 2px; -} \ No newline at end of file +.fill-cell { + width: 100%; + display: flex; + flex-direction: row; + + eui-badge { + align-self: flex-end; + } +} diff --git a/imxweb/projects/tsb/src/lib/groups/group-memberships-ext/group-memberships-ext.component.ts b/imxweb/projects/tsb/src/lib/groups/group-memberships-ext/group-memberships-ext.component.ts index e08f627b0..2d4df374d 100644 --- a/imxweb/projects/tsb/src/lib/groups/group-memberships-ext/group-memberships-ext.component.ts +++ b/imxweb/projects/tsb/src/lib/groups/group-memberships-ext/group-memberships-ext.component.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -28,20 +28,36 @@ import { Component, Input, OnInit } from '@angular/core'; import { EuiSidesheetService } from '@elemental-ui/core'; import { TranslateService } from '@ngx-translate/core'; -import { CollectionLoadParameters, DbObjectKey, DisplayColumns, EntitySchema, IClientProperty, TypedEntity } from 'imx-qbm-dbts'; -import { BusyService, DataSourceToolbarSettings, DynamicTabDataProviderDirective, SettingsService } from 'qbm'; -import { GroupMembershipsExtService } from './group-memberships-ext.service'; +import { PortalPersonGroupmemberships } from '@imx-modules/imx-api-tsb'; +import { + CollectionLoadParameters, + DbObjectKey, + DisplayColumns, + EntitySchema, + ExtendedTypedEntityCollection, + IClientProperty, + TypedEntity, +} from '@imx-modules/imx-qbm-dbts'; +import { + BusyService, + calculateSidesheetWidth, + DataSourceToolbarSettings, + DataViewInitParameters, + DataViewSource, + DynamicTabDataProviderDirective, +} from 'qbm'; import { SourceDetectiveSidesheetComponent, SourceDetectiveSidesheetData, SourceDetectiveType } from 'qer'; -import { PortalPersonGroupmemberships } from 'imx-api-tsb'; +import { GroupMembershipsExtService } from './group-memberships-ext.service'; @Component({ templateUrl: './group-memberships-ext.component.html', styleUrls: ['./group-memberships-ext.component.scss'], + providers: [DataViewSource], }) export class GroupMembershipsExtComponent implements OnInit { @Input() public referrer: { - objecttable?: string; - objectuid?: string; + objecttable: string; + objectuid: string; tablename?: string; }; @@ -51,50 +67,36 @@ export class GroupMembershipsExtComponent implements OnInit { public entitySchema: EntitySchema; public displayColumns: IClientProperty[] = []; - private displayedColumnsWithDisplay = []; + private displayedColumnsWithDisplay: IClientProperty[] = []; private navigationState: CollectionLoadParameters; public busyService = new BusyService(); constructor( - private readonly settingService: SettingsService, private readonly groupService: GroupMembershipsExtService, private readonly translate: TranslateService, private readonly sidesheet: EuiSidesheetService, - dataProvider: DynamicTabDataProviderDirective + dataProvider: DynamicTabDataProviderDirective, + public dataSource: DataViewSource, ) { this.referrer = dataProvider?.data; - this.navigationState = { PageSize: this.settingService.DefaultPageSize }; this.entitySchema = groupService.portalPersonGroupmembershipsSchema; this.displayColumns = [ - this.entitySchema.Columns.XOrigin, + this.entitySchema.Columns?.XOrigin, this.entitySchema.Columns.XDateInserted, this.entitySchema.Columns.OrderState, this.entitySchema.Columns.ValidUntil, ]; - this.displayedColumnsWithDisplay = [...[this.entitySchema.Columns[DisplayColumns.DISPLAY_PROPERTYNAME]], ...this.displayColumns]; + this.displayedColumnsWithDisplay = [this.entitySchema.Columns[DisplayColumns.DISPLAY_PROPERTYNAME], ...this.displayColumns]; } public async ngOnInit(): Promise { return this.getData(); } - public async onNavigationStateChanged(newState?: CollectionLoadParameters): Promise { - if (newState) { - this.navigationState = newState; - } - await this.getData(); - } - - public async onSearch(keywords: string): Promise { - this.navigationState.StartIndex = 0; - this.navigationState.search = keywords; - await this.getData(); - } - - public async onShowDetails(entity: PortalPersonGroupmemberships): Promise { - const unsGroupId = DbObjectKey.FromXml(entity.ObjectKeyGroup.value); + public async onShowDetails(entity: TypedEntity): Promise { + const unsGroupId = DbObjectKey.FromXml(entity.GetEntity().GetColumn('ObjectKeyGroup').GetValue()); const data: SourceDetectiveSidesheetData = { UID_Person: this.referrer.objectuid, @@ -107,24 +109,30 @@ export class GroupMembershipsExtComponent implements OnInit { title: await this.translate.get('#LDS#Heading View Assignment Analysis').toPromise(), subTitle: entity.GetEntity().GetDisplay(), padding: '0px', - width: '800px', + width: calculateSidesheetWidth(800, 0.5), disableClose: false, testId: 'group-membership-assingment-analysis', data, }); - } private async getData(): Promise { - const isBusy = this.busyService.beginBusy(); + const isBusy = this.busyService.beginBusy(); try { - const groupsPerIdentity = await this.groupService.getGroupMemberships(this.referrer.objectuid, this.navigationState); - this.dstSettings = { - displayedColumns: this.displayedColumnsWithDisplay, - dataSource: groupsPerIdentity, - entitySchema: this.entitySchema, - navigationState: this.navigationState, + const dataViewInitParameters: DataViewInitParameters = { + execute: ( + params: CollectionLoadParameters, + signal: AbortSignal, + ): Promise> => { + return this.groupService.getGroupMemberships(this.referrer.objectuid, params, signal); + }, + schema: this.entitySchema, + columnsToDisplay: this.displayedColumnsWithDisplay, + highlightEntity: (identity: PortalPersonGroupmemberships) => { + this.onShowDetails(identity); + }, }; + await this.dataSource.init(dataViewInitParameters); } finally { isBusy.endBusy(); } diff --git a/imxweb/projects/tsb/src/lib/groups/group-memberships-ext/group-memberships-ext.service.ts b/imxweb/projects/tsb/src/lib/groups/group-memberships-ext/group-memberships-ext.service.ts index a473291ff..4ada06578 100644 --- a/imxweb/projects/tsb/src/lib/groups/group-memberships-ext/group-memberships-ext.service.ts +++ b/imxweb/projects/tsb/src/lib/groups/group-memberships-ext/group-memberships-ext.service.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -26,8 +26,8 @@ import { Injectable } from '@angular/core'; -import { PortalPersonGroupmemberships, portal_person_groupmemberships_get_args } from 'imx-api-tsb'; -import { EntitySchema, ExtendedTypedEntityCollection } from 'imx-qbm-dbts'; +import { PortalPersonGroupmemberships, portal_person_groupmemberships_get_args } from '@imx-modules/imx-api-tsb'; +import { EntitySchema, ExtendedTypedEntityCollection } from '@imx-modules/imx-qbm-dbts'; import { TsbApiService } from '../../tsb-api-client.service'; @Injectable({ providedIn: 'root' }) @@ -38,7 +38,11 @@ export class GroupMembershipsExtService { return this.apiService.typedClient.PortalPersonGroupmemberships.GetSchema(); } - public getGroupMemberships(uid: string, parameters: portal_person_groupmemberships_get_args): Promise> { - return this.apiService.typedClient.PortalPersonGroupmemberships.Get(uid, parameters); + public getGroupMemberships( + uid: string, + parameters: portal_person_groupmemberships_get_args, + signal: AbortSignal, + ): Promise> { + return this.apiService.typedClient.PortalPersonGroupmemberships.Get(uid, parameters, { signal }); } } diff --git a/imxweb/projects/tsb/src/lib/groups/group-sidesheet/child-system-entitlements/child-system-entitlements.component.html b/imxweb/projects/tsb/src/lib/groups/group-sidesheet/child-system-entitlements/child-system-entitlements.component.html index a7f044b5b..c83c01b91 100644 --- a/imxweb/projects/tsb/src/lib/groups/group-sidesheet/child-system-entitlements/child-system-entitlements.component.html +++ b/imxweb/projects/tsb/src/lib/groups/group-sidesheet/child-system-entitlements/child-system-entitlements.component.html @@ -1,8 +1,12 @@ - + - + - \ No newline at end of file + diff --git a/imxweb/projects/tsb/src/lib/groups/group-sidesheet/child-system-entitlements/child-system-entitlements.component.spec.ts b/imxweb/projects/tsb/src/lib/groups/group-sidesheet/child-system-entitlements/child-system-entitlements.component.spec.ts index 18b215081..ddf8da26e 100644 --- a/imxweb/projects/tsb/src/lib/groups/group-sidesheet/child-system-entitlements/child-system-entitlements.component.spec.ts +++ b/imxweb/projects/tsb/src/lib/groups/group-sidesheet/child-system-entitlements/child-system-entitlements.component.spec.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -26,13 +26,13 @@ import { ComponentFixture, TestBed, waitForAsync } from '@angular/core/testing'; import { EuiLoadingService } from '@elemental-ui/core'; -import { TypedEntityCollectionData } from 'imx-qbm-dbts'; +import { TypedEntityCollectionData } from '@imx-modules/imx-qbm-dbts'; import { GroupsService } from '../../groups.service'; import { ChildSystemEntitlementsComponent } from './child-system-entitlements.component'; function mockGetGroups(): TypedEntityCollectionData { - return {totalCount: 100, Data: ['1', '2']}; + return { totalCount: 100, Data: ['1', '2'] }; } describe('ChildSystemEntitlementsComponent', () => { @@ -41,7 +41,8 @@ describe('ChildSystemEntitlementsComponent', () => { const euiLoadingServiceStub = { hide: jasmine.createSpy('hide'), - show: jasmine.createSpy('show') + show: jasmine.createSpy('show'), + overlayRefs: [], }; beforeEach(waitForAsync(() => { @@ -49,26 +50,25 @@ describe('ChildSystemEntitlementsComponent', () => { declarations: [ChildSystemEntitlementsComponent], providers: [ { - provide: EuiLoadingService, - useValue: euiLoadingServiceStub - }, - { - provide: GroupsService, - useValue: { - getDataModel:jasmine.createSpy('getDataModel').and.returnValue(Promise.resolve({})), - getGroupsGroupMembers: jasmine.createSpy('getGroupsGroupMembers').and.returnValue(Promise.resolve(mockGetGroups())), - UnsGroupMembersSchema: { - Columns: { - __Display: { ColumnName: '__Display' }, - UID_UNSGroupChild: { ColumnName: 'UID_UNSGroupChild' }, - XDateInserted: { ColumnName: 'XDateInserted' } - } - } - } - } - ] - }) - .compileComponents(); + provide: EuiLoadingService, + useValue: euiLoadingServiceStub, + }, + { + provide: GroupsService, + useValue: { + getDataModel: jasmine.createSpy('getDataModel').and.returnValue(Promise.resolve({})), + getGroupsGroupMembers: jasmine.createSpy('getGroupsGroupMembers').and.returnValue(Promise.resolve(mockGetGroups())), + UnsGroupMembersSchema: { + Columns: { + __Display: { ColumnName: '__Display' }, + UID_UNSGroupChild: { ColumnName: 'UID_UNSGroupChild' }, + XDateInserted: { ColumnName: 'XDateInserted' }, + }, + }, + }, + }, + ], + }).compileComponents(); })); beforeEach(() => { diff --git a/imxweb/projects/tsb/src/lib/groups/group-sidesheet/child-system-entitlements/child-system-entitlements.component.ts b/imxweb/projects/tsb/src/lib/groups/group-sidesheet/child-system-entitlements/child-system-entitlements.component.ts index e9df0ef57..22511560b 100644 --- a/imxweb/projects/tsb/src/lib/groups/group-sidesheet/child-system-entitlements/child-system-entitlements.component.ts +++ b/imxweb/projects/tsb/src/lib/groups/group-sidesheet/child-system-entitlements/child-system-entitlements.component.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -24,18 +24,23 @@ * */ -import { OverlayRef } from '@angular/cdk/overlay'; import { Component, Input, OnInit } from '@angular/core'; import { EuiLoadingService } from '@elemental-ui/core'; -import { PortalTargetsystemUnsGroupmembers } from 'imx-api-tsb'; -import { CollectionLoadParameters, DataModel, DisplayColumns, EntitySchema, IClientProperty, TypedEntityCollectionData } from 'imx-qbm-dbts'; +import { PortalTargetsystemUnsGroupmembers } from '@imx-modules/imx-api-tsb'; +import { + CollectionLoadParameters, + DisplayColumns, + EntitySchema, + IClientProperty, + TypedEntityCollectionData, +} from '@imx-modules/imx-qbm-dbts'; import { DataSourceToolbarSettings, SettingsService } from 'qbm'; import { GroupsService } from '../../groups.service'; @Component({ selector: 'imx-child-system-entitlements', templateUrl: './child-system-entitlements.component.html', - styleUrls: ['./child-system-entitlements.component.scss'] + styleUrls: ['./child-system-entitlements.component.scss'], }) export class ChildSystemEntitlementsComponent implements OnInit { @Input() public groupId: string; @@ -47,12 +52,11 @@ export class ChildSystemEntitlementsComponent implements OnInit { public readonly entitySchemaUnsGroupMemberships: EntitySchema; private groupDisplayedColumns: IClientProperty[] = []; - private dataModel: DataModel; constructor( private readonly busyService: EuiLoadingService, private readonly settingsService: SettingsService, - private readonly groupsService: GroupsService + private readonly groupsService: GroupsService, ) { this.navigationState = { PageSize: settingsService.DefaultPageSize, StartIndex: 0 }; this.entitySchemaUnsGroupMemberships = groupsService.UnsGroupMembersSchema; @@ -65,14 +69,6 @@ export class ChildSystemEntitlementsComponent implements OnInit { this.entitySchemaUnsGroupMemberships.Columns.XDateInserted, ]; - let overlayRef: OverlayRef; - setTimeout(() => (overlayRef = this.busyService.show())); - - try { - this.dataModel = await this.groupsService.getDataModel(this.isAdmin); - } finally { - setTimeout(() => this.busyService.hide(overlayRef)); - } await this.groupNavigate(); } @@ -81,8 +77,9 @@ export class ChildSystemEntitlementsComponent implements OnInit { } private async groupNavigate(newState?: CollectionLoadParameters): Promise { - let overlayRef: OverlayRef; - setTimeout(() => overlayRef = this.busyService.show()); + if (this.busyService.overlayRefs.length === 0) { + this.busyService.show(); + } try { if (newState) { @@ -95,12 +92,9 @@ export class ChildSystemEntitlementsComponent implements OnInit { dataSource: this.groupsGroupMembershipData, entitySchema: this.entitySchemaUnsGroupMemberships, navigationState: this.navigationState, - dataModel: this.dataModel }; } finally { - setTimeout(() => this.busyService.hide(overlayRef)); + this.busyService.hide(); } - } - } diff --git a/imxweb/projects/tsb/src/lib/groups/group-sidesheet/group-members/group-members.component.html b/imxweb/projects/tsb/src/lib/groups/group-sidesheet/group-members/group-members.component.html index ac88d2f8c..5a6f48efb 100644 --- a/imxweb/projects/tsb/src/lib/groups/group-sidesheet/group-members/group-members.component.html +++ b/imxweb/projects/tsb/src/lib/groups/group-sidesheet/group-members/group-members.component.html @@ -1,79 +1,111 @@
    - - {{ LdsDirectlyAssigned - | translate }} - {{ LdsIndirectlyAssigned - | translate }} + + + {{ LdsDirectlyAssigned | translate }} + + + {{ LdsIndirectlyAssigned | translate }} +
    - - - {{ '#LDS#Here you can manage the memberships of the system entitlement. You can request and remove memberships and view the assignment analysis for each membership.' | translate }} - - {{LdsNotUnsubscribableHint | translate}} - - - +@if (membershipView === 'direct') { + + {{ + '#LDS#Here you can manage the memberships of the system entitlement. You can request and remove memberships and view the assignment analysis for each membership.' + | translate + }} + + @if (showUnsubscribeWarning) { + {{ + LdsNotUnsubscribableHint | translate + }} + } + + + + + {{ entitySchemaGroupDirectMemberships.Columns.UID_Person.Display }} + +
    +
    {{ item.UID_Person.Column.GetDisplayValue() }}
    + @if (item.XIsInEffect?.value !== true) { + {{ '#LDS#Not effective' | translate }} + } +
    + +
    - - - - - - - - - - - - - - - -
    - {{ item.XMarkedForDeletion.Column.GetDisplayValue() }} -
    -
    -
    -
    + @for (column of automaticColumnDirect; track column.ColumnName) { + + {{ column.Display }} + + {{ item.GetEntity().GetColumn(column.ColumnName)?.GetDisplayValue() }} + + + } + + + +
    + @if (item.XMarkedForDeletion.value !== 0) { + {{ item.XMarkedForDeletion.Column.GetDisplayValue() }} + } +
    + +
    +
    + +
    + +} @else if (membershipView === 'nested') { + + {{ + '#LDS#Here you can get an overview of the memberships of the system entitlement. Additionally, you can view the assignment analysis for each membership.' + | translate + }} + - -
    + + + + + {{ entitySchemaGroupNestedMemberships.Columns.UID_Person.Display }} + +
    +
    {{ item.UID_Person.Column.GetDisplayValue() }}
    +
    + +
    - - - {{ '#LDS#Here you can get an overview of the memberships of the system entitlement. Additionally, you can view the assignment analysis for each membership.' | translate }} - - - + + {{ entitySchemaGroupNestedMemberships.Columns.UID_UNSGroupChild.Display }} + +
    +
    {{ item.UID_UNSGroupChild.Column.GetDisplayValue() }}
    +
    + +
    - - - - - - - -
    - {{ item.XMarkedForDeletion.Column.GetDisplayValue() }} -
    -
    -
    -
    - -
    + + + +
    + @if (item.XMarkedForDeletion.value !== 0) { + {{ item.XMarkedForDeletion.Column.GetDisplayValue() }} + } +
    + +
    +
    + +
    +} diff --git a/imxweb/projects/tsb/src/lib/groups/group-sidesheet/group-members/group-members.component.scss b/imxweb/projects/tsb/src/lib/groups/group-sidesheet/group-members/group-members.component.scss index bd5a2a596..257ed61b0 100644 --- a/imxweb/projects/tsb/src/lib/groups/group-sidesheet/group-members/group-members.component.scss +++ b/imxweb/projects/tsb/src/lib/groups/group-sidesheet/group-members/group-members.component.scss @@ -6,21 +6,17 @@ flex-direction: column; } -.mat-button-toggle-group { - margin-bottom: 10px; - - .mat-button-toggle-checked { - background-color: $color-orange-20; - } +.imx-selection-toggle { + min-height: 40px; + display: flex; } -::ng-deep .mat-checkbox-disabled { - cursor: not-allowed; +.filled-cell { + width: 100% !important; } - -.helper-alert { - margin: 20px 2px; +.mat-button-toggle-group { + margin-bottom: 10px; } @media screen and (max-width: 768px) { @@ -28,13 +24,3 @@ width: 100%; } } - -.eui-dark-theme { - :host { - ::ng-deep.mat-button-toggle-group { - .mat-button-toggle-checked { - background-color: $color-gray-60; - } - } - } -} diff --git a/imxweb/projects/tsb/src/lib/groups/group-sidesheet/group-members/group-members.component.ts b/imxweb/projects/tsb/src/lib/groups/group-sidesheet/group-members/group-members.component.ts index d38a33033..421a7314a 100644 --- a/imxweb/projects/tsb/src/lib/groups/group-sidesheet/group-members/group-members.component.ts +++ b/imxweb/projects/tsb/src/lib/groups/group-sidesheet/group-members/group-members.component.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -24,22 +24,26 @@ * */ -import { OverlayRef } from '@angular/cdk/overlay'; -import { Component, Input, OnInit, ViewChild } from '@angular/core'; +import { Component, Input, OnInit } from '@angular/core'; import { UntypedFormControl } from '@angular/forms'; import { MatButtonToggleChange } from '@angular/material/button-toggle'; import { EuiLoadingService, EuiSidesheetService } from '@elemental-ui/core'; import { TranslateService } from '@ngx-translate/core'; -import { PortalTargetsystemUnsDirectmembers, PortalTargetsystemUnsGroupServiceitem, PortalTargetsystemUnsNestedmembers } from 'imx-api-tsb'; -import { CollectionLoadParameters, EntitySchema, TypedEntity, TypedEntityCollectionData, ValType } from 'imx-qbm-dbts'; import { + PortalTargetsystemUnsDirectmembers, + PortalTargetsystemUnsGroupServiceitem, + PortalTargetsystemUnsNestedmembers, +} from '@imx-modules/imx-api-tsb'; +import { CollectionLoadParameters, EntitySchema, IClientProperty, TypedEntity, TypedEntityCollectionData } from '@imx-modules/imx-qbm-dbts'; +import { + calculateSidesheetWidth, ConfirmationService, - DataSourceToolbarSettings, - DataTableComponent, + DataViewInitParameters, + DataViewSource, + DataViewSourceFactoryService, FkAdvancedPickerComponent, - ClientPropertyForTableColumns, - SettingsService, + isMobile, SnackBarService, } from 'qbm'; import { SourceDetectiveSidesheetComponent, SourceDetectiveSidesheetData, SourceDetectiveType } from 'qer'; @@ -51,25 +55,13 @@ import { NewMembershipService } from './new-membership/new-membership.service'; selector: 'imx-group-members', templateUrl: './group-members.component.html', styleUrls: ['./group-members.component.scss'], + providers: [DataViewSource], }) export class GroupMembersComponent implements OnInit { @Input() public groupDirectMembershipData: TypedEntityCollectionData; @Input() public groupNestedMembershipData: TypedEntityCollectionData; @Input() public unsGroupDbObjectKey: DbObjectKeyBase; - @ViewChild('membersTable') public membersTable: DataTableComponent; - - /** - * Settings needed by the DataSourceToolbarComponent - */ - public dstSettings: DataSourceToolbarSettings; - public dstNestedGroupSettings: DataSourceToolbarSettings; - - /** - * Page size, start index, search and filtering options etc. - */ - public navigationState: CollectionLoadParameters; - public nestedNavigationState: CollectionLoadParameters; public viewDirectMemberships = new UntypedFormControl(true); public showUnsubscribeWarning = false; @@ -86,13 +78,19 @@ export class GroupMembersComponent implements OnInit { }, }; - private displayedColumns: ClientPropertyForTableColumns[] = []; - private nestedDisplayColumns: ClientPropertyForTableColumns[] = []; - private selectedItems: TypedEntity[] = []; + protected abortController: AbortController; + + public get selectedItemsCount() { + return this.dataSourceDirect.selection.selected.length; + } + private selectedMembershipView: 'direct' | 'nested' = 'direct'; - private busyIndicator: OverlayRef; private groupId: string; + public automaticColumnDirect: IClientProperty[]; + public dataSourceDirect: DataViewSource; + public dataSourceNested: DataViewSource; + constructor( private readonly busyService: EuiLoadingService, private readonly snackBarService: SnackBarService, @@ -101,12 +99,20 @@ export class GroupMembersComponent implements OnInit { private readonly confirmationService: ConfirmationService, private readonly membershipService: NewMembershipService, private readonly translate: TranslateService, - private readonly settingsService: SettingsService + dataSourceFactory: DataViewSourceFactoryService, ) { + this.abortController = new AbortController(); this.entitySchemaGroupDirectMemberships = groupsService.UnsGroupDirectMembersSchema; this.entitySchemaGroupNestedMemberships = groupsService.UnsGroupNestedMembersSchema; - this.navigationState = { PageSize: settingsService.DefaultPageSize, StartIndex: 0 }; - this.nestedNavigationState = { PageSize: settingsService.DefaultPageSize, StartIndex: 0 }; + this.dataSourceDirect = dataSourceFactory.getDataSource(); + this.dataSourceNested = dataSourceFactory.getDataSource(); + this.automaticColumnDirect = [ + this.entitySchemaGroupDirectMemberships.Columns.UID_UNSAccount, + this.entitySchemaGroupDirectMemberships.Columns?.XOrigin, + this.entitySchemaGroupDirectMemberships.Columns.XDateInserted, + this.entitySchemaGroupDirectMemberships.Columns.OrderState, + this.entitySchemaGroupDirectMemberships.Columns.ValidUntil, + ]; } public get membershipView(): 'direct' | 'nested' { @@ -114,80 +120,45 @@ export class GroupMembersComponent implements OnInit { } get isMobile(): boolean { - return document.body.offsetWidth <= 768; + return isMobile(); } public async ngOnInit(): Promise { - this.displayedColumns = [ - this.entitySchemaGroupDirectMemberships.Columns.UID_Person, - this.entitySchemaGroupDirectMemberships.Columns.UID_UNSAccount, - this.entitySchemaGroupDirectMemberships.Columns.XOrigin, - this.entitySchemaGroupDirectMemberships.Columns.XDateInserted, - this.entitySchemaGroupDirectMemberships.Columns.OrderState, - this.entitySchemaGroupDirectMemberships.Columns.ValidUntil, - this.entitySchemaGroupDirectMemberships.Columns.XMarkedForDeletion, - ]; - this.nestedDisplayColumns = [ - this.entitySchemaGroupNestedMemberships.Columns.UID_Person, - this.entitySchemaGroupNestedMemberships.Columns.UID_UNSGroupChild, - this.entitySchemaGroupNestedMemberships.Columns.XMarkedForDeletion, - ]; - this.groupId = this.unsGroupDbObjectKey.Keys[0]; await this.navigateDirect(); } - get selectedItemsCount(): number { - return this.selectedItems.length; - } - - public onSelectionChanged(items: TypedEntity[]): void { - this.selectedItems = items; - } - public canUnsubscribeSelected(): boolean { return ( - this.selectedItems != null && - this.selectedItemsCount > 0 && - this.selectedItems.every( + this.dataSourceDirect.selection.selected != null && + this.dataSourceDirect.selection.selected.length > 0 && + this.dataSourceDirect.selection.selected.every( (elem) => elem.GetEntity().GetColumn('UID_PersonWantsOrg').GetValue() !== '' && - elem.GetEntity().GetColumn('IsRequestCancellable').GetValue() + elem.GetEntity().GetColumn('IsRequestCancellable').GetValue(), ) ); } public canDeleteSelected(): boolean { + this.dataSourceDirect.selection != null; return ( - this.selectedItems != null && - this.selectedItemsCount > 0 && - this.selectedItems.every((elem) => elem.GetEntity().GetColumn('XOrigin').GetValue() === 1) + this.dataSourceDirect.selection.selected != null && + this.dataSourceDirect.selection.selected.length > 0 && + this.dataSourceDirect.selection.selected.every((elem) => elem.GetEntity().GetColumn('XOrigin').GetValue() === 1) ); } public async onToggleChanged(change: MatButtonToggleChange): Promise { this.selectedMembershipView = change.value; - this.selectedItems = []; + this.abortController.abort(); + if (this.selectedMembershipView === 'direct') { - return this.onDirectNavigationStateChanged({ PageSize: this.settingsService.DefaultPageSize, StartIndex: 0 }); + await this.navigateDirect(); } else { - return this.onNestedNavigationStateChanged({ PageSize: this.settingsService.DefaultPageSize, StartIndex: 0 }); - } - } - - public async onDirectNavigationStateChanged(newState?: CollectionLoadParameters): Promise { - if (newState) { - this.navigationState = newState; - } - await this.navigateDirect(); - } - - public async onNestedNavigationStateChanged(newState?: CollectionLoadParameters): Promise { - if (newState) { - this.nestedNavigationState = newState; + await this.navigateNested(); } - await this.navigateNested(); } public async deleteMembers(): Promise { @@ -201,11 +172,12 @@ export class GroupMembersComponent implements OnInit { ) { this.handleOpenLoader(); try { + console.log(this.dataSourceDirect.selection.selected); await this.groupsService.deleteGroupMembers( this.unsGroupDbObjectKey, - this.selectedItems.map((i) => i.GetEntity().GetColumn('UID_UNSAccount').GetValue()) + this.dataSourceDirect.selection.selected.map((i) => i.GetEntity().GetColumn('UID_UNSAccount').GetValue()), ); - this.membersTable.clearSelection(); + this.dataSourceDirect.selection.clear(); this.snackBarService.open({ key: '#LDS#The memberships have been successfully removed.' }, '#LDS#Close'); await this.navigateDirect(); } finally { @@ -216,10 +188,10 @@ export class GroupMembersComponent implements OnInit { public async requestMembership(serviceItem: PortalTargetsystemUnsGroupServiceitem): Promise { const sidesheetRef = this.sidesheet.open(FkAdvancedPickerComponent, { - title: await this.translate.get('#LDS#Heading Request Memberships').toPromise(), + title: await this.translate.instant('#LDS#Heading Request Memberships'), subTitle: serviceItem.GetEntity().GetDisplay(), padding: '0px', - width: 'max(600px, 60%)', + width: calculateSidesheetWidth(), icon: 'usergroup', testId: 'systementitlements-reqeust-memberships', data: { @@ -244,10 +216,12 @@ export class GroupMembersComponent implements OnInit { public async unsubscribeMembership(): Promise { // if there is at least 1 item, that is not unsubscribable, show a warning instead - const notSubscribable = this.selectedItems.some((entity) => entity.GetEntity().GetColumn('IsRequestCancellable').GetValue() === false); + const notSubscribable = this.dataSourceDirect.selection.selected.some( + (entity) => entity.GetEntity().GetColumn('IsRequestCancellable').GetValue() === false, + ); if (notSubscribable) { this.showUnsubscribeWarning = true; - this.membersTable.clearSelection(); + this.dataSourceDirect.selection.clear(); return; } if ( @@ -259,32 +233,30 @@ export class GroupMembersComponent implements OnInit { ) { this.handleOpenLoader(); try { - await Promise.all(this.selectedItems.map((entity) => this.membershipService.unsubscribeMembership(entity))); + await Promise.all(this.dataSourceDirect.selection.selected.map((entity) => this.membershipService.unsubscribeMembership(entity))); this.snackBarService.open({ key: '#LDS#The memberships have been successfully unsubscribed. It may take some time for the changes to take effect. The displayed data may differ from the actual state.', }); } finally { this.handleCloseLoader(); - this.membersTable.clearSelection(); + this.dataSourceDirect.selection.clear(); await this.navigateDirect(); } } } - public async onShowDetails(item: PortalTargetsystemUnsDirectmembers): Promise { - const uidPerson = item.UID_Person.value; - + public async onShowDetails(item: TypedEntity): Promise { const data: SourceDetectiveSidesheetData = { - UID_Person: uidPerson, + UID_Person: item.GetEntity().GetColumn('UID_Person').GetValue(), Type: SourceDetectiveType.MembershipOfSystemEntitlement, UID: this.unsGroupDbObjectKey.Keys[0], TableName: this.unsGroupDbObjectKey.TableName, }; this.sidesheet.open(SourceDetectiveSidesheetComponent, { - title: await this.translate.get('#LDS#Heading View Assignment Analysis').toPromise(), + title: await this.translate.instant('#LDS#Heading View Assignment Analysis'), subTitle: item.GetEntity().GetDisplay(), padding: '0px', - width: '800px', + width: calculateSidesheetWidth(800, 0.5), disableClose: false, testId: 'systementitlements-membership-assingment-analysis', data, @@ -292,49 +264,57 @@ export class GroupMembersComponent implements OnInit { } private async navigateDirect(): Promise { - this.handleOpenLoader(); - try { - this.groupDirectMembershipData = await this.groupsService.getGroupDirectMembers(this.groupId, this.navigationState); - this.dstSettings = { - displayedColumns: this.displayedColumns, - dataSource: this.groupDirectMembershipData, - entitySchema: this.entitySchemaGroupDirectMemberships, - navigationState: this.navigationState, - }; - } finally { - this.handleCloseLoader(); - } + this.dataSourceDirect.itemStatus = this.itemStatus; + const columnsToDisplay = [ + this.entitySchemaGroupDirectMemberships.Columns.UID_Person, + ...this.automaticColumnDirect, + this.entitySchemaGroupDirectMemberships.Columns.XMarkedForDeletion, + ]; + const dataViewInitParameters: DataViewInitParameters = { + execute: ( + params: CollectionLoadParameters, + signal: AbortSignal, + ): Promise> => { + return this.groupsService.getGroupDirectMembers(this.groupId, params, signal); + }, + schema: this.entitySchemaGroupDirectMemberships, + columnsToDisplay, + highlightEntity: (identity: PortalTargetsystemUnsDirectmembers) => { + this.onShowDetails(identity); + }, + }; + await this.dataSourceDirect.init(dataViewInitParameters); } private async navigateNested(): Promise { this.showUnsubscribeWarning = false; - this.handleOpenLoader(); - try { - this.groupNestedMembershipData = await this.groupsService.getGroupNestedMembers(this.groupId, this.nestedNavigationState); - this.dstNestedGroupSettings = { - displayedColumns: this.nestedDisplayColumns, - dataSource: this.groupNestedMembershipData, - entitySchema: this.entitySchemaGroupNestedMemberships, - navigationState: this.nestedNavigationState, - }; - } finally { - this.handleCloseLoader(); - } + const columnsToDisplay = [ + this.entitySchemaGroupNestedMemberships.Columns.UID_Person, + this.entitySchemaGroupNestedMemberships.Columns.UID_UNSGroupChild, + this.entitySchemaGroupNestedMemberships.Columns.XMarkedForDeletion, + ]; + const dataViewInitParameters: DataViewInitParameters = { + execute: ( + params: CollectionLoadParameters, + signal: AbortSignal, + ): Promise> => { + return this.groupsService.getGroupNestedMembers(this.groupId, params, signal); + }, + schema: this.entitySchemaGroupNestedMemberships, + columnsToDisplay, + highlightEntity: (identity: PortalTargetsystemUnsNestedmembers) => { + this.onShowDetails(identity); + }, + }; + await this.dataSourceNested.init(dataViewInitParameters); } private handleOpenLoader(): void { - if (!this.busyIndicator) { - this.busyIndicator = this.busyService.show(); - } + this.busyService.show(); } private handleCloseLoader(): void { - if (this.busyIndicator) { - setTimeout(() => { - this.busyService.hide(this.busyIndicator); - this.busyIndicator = undefined; - }); - } + this.busyService.hide(); } public LdsNotUnsubscribableHint = diff --git a/imxweb/projects/tsb/src/lib/groups/group-sidesheet/group-members/new-membership/new-membership.service.ts b/imxweb/projects/tsb/src/lib/groups/group-sidesheet/group-members/new-membership/new-membership.service.ts index 085a0f4bf..feded685a 100644 --- a/imxweb/projects/tsb/src/lib/groups/group-sidesheet/group-members/new-membership/new-membership.service.ts +++ b/imxweb/projects/tsb/src/lib/groups/group-sidesheet/group-members/new-membership/new-membership.service.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -24,14 +24,13 @@ * */ -import { OverlayRef } from '@angular/cdk/overlay'; import { Injectable } from '@angular/core'; import { EuiLoadingService } from '@elemental-ui/core'; -import { RequestableProductForPerson } from 'imx-api-qer'; -import { PortalTargetsystemUnsGroupServiceitem } from 'imx-api-tsb'; -import { IForeignKeyInfo, TypedEntity, ValueStruct } from 'imx-qbm-dbts'; -import { ShelfService, QerApiService, UserModelService } from 'qer'; +import { RequestableProductForPerson } from '@imx-modules/imx-api-qer'; +import { PortalTargetsystemUnsGroupServiceitem } from '@imx-modules/imx-api-tsb'; +import { IForeignKeyInfo, TypedEntity, ValueStruct } from '@imx-modules/imx-qbm-dbts'; +import { QerApiService, ShelfService, UserModelService } from 'qer'; @Injectable({ providedIn: 'root', @@ -41,7 +40,7 @@ export class NewMembershipService { private readonly itShop: ShelfService, private readonly qerClient: QerApiService, private readonly busyService: EuiLoadingService, - private readonly userService: UserModelService + private readonly userService: UserModelService, ) {} public async requestMembership(members: ValueStruct[], product: PortalTargetsystemUnsGroupServiceitem): Promise { @@ -52,23 +51,25 @@ export class NewMembershipService { return false; } - let busyIndicator: OverlayRef; - setTimeout(() => (busyIndicator = this.busyService.show())); + this.busyService.show(); try { - items = items.filter((elem) => elem.UidITShopOrg != null && elem.UidITShopOrg !== ''); + items = items.filter((elem) => elem.UidITShopOrg && elem.UidITShopOrg.length > 0); + + const promises: Promise[] = []; for (const item of items) { - const entity = this.qerClient.typedClient.PortalCartitem.createEntity(); - entity.UID_ITShopOrg.value = item.UidITShopOrg; - entity.UID_PersonOrdered.value = item.UidPerson; - await this.qerClient.typedClient.PortalCartitem.Post(entity); + if (item.UidITShopOrg && item.UidPerson) { + const entity = this.qerClient.typedClient.PortalCartitem.createEntity(); + entity.UID_ITShopOrg.value = item.UidITShopOrg; + entity.UID_PersonOrdered.value = item.UidPerson; + promises.push(this.qerClient.typedClient.PortalCartitem.Post(entity)); + } } + await Promise.all(promises); await this.userService.reloadPendingItems(); } finally { - setTimeout(() => { - this.busyService.hide(busyIndicator); - }); + this.busyService.hide(); } return true; } @@ -83,7 +84,7 @@ export class NewMembershipService { private getServiceItemsForPersons( serviceItem: PortalTargetsystemUnsGroupServiceitem, - recipients: ValueStruct[] + recipients: ValueStruct[], ): RequestableProductForPerson[] { return recipients .map((recipient) => ({ @@ -92,6 +93,6 @@ export class NewMembershipService { Display: serviceItem.GetEntity().GetDisplay(), DisplayRecipient: recipient.DisplayValue, })) - .reduce((a, b) => a.concat(b), []); + .reduce((a: RequestableProductForPerson[], b) => a.concat(b), []); } } diff --git a/imxweb/projects/tsb/src/lib/groups/group-sidesheet/group-sidesheet.component.html b/imxweb/projects/tsb/src/lib/groups/group-sidesheet/group-sidesheet.component.html index 39669b54f..d812b3dbd 100644 --- a/imxweb/projects/tsb/src/lib/groups/group-sidesheet/group-sidesheet.component.html +++ b/imxweb/projects/tsb/src/lib/groups/group-sidesheet/group-sidesheet.component.html @@ -1,45 +1,54 @@ - +
    #LDS#Heading Main Data  - +
    -
    -
    - -
    - -
    -
    -
    -
    -
    - - - -
    +
    + +
    + +
    +
    +
    +
    +
    + +
    +
    @@ -48,36 +57,51 @@
    #LDS#Heading Service Item   - +
    -
    -
    - - -
    -
    - -
    +
    + + +
    +
    +
    -
    -
    - -
    -
    - @@ -100,57 +124,46 @@ > #LDS#Unsubscribe -
    -
    - -
    +
    -
    -
    - -
    +
    +
    -
    - +
    + +
    -
    -
    +
    + -
    +
    - + -
    -
    - -
    +
    +
    diff --git a/imxweb/projects/tsb/src/lib/groups/group-sidesheet/group-sidesheet.component.scss b/imxweb/projects/tsb/src/lib/groups/group-sidesheet/group-sidesheet.component.scss index 609f90919..73df6baf8 100644 --- a/imxweb/projects/tsb/src/lib/groups/group-sidesheet/group-sidesheet.component.scss +++ b/imxweb/projects/tsb/src/lib/groups/group-sidesheet/group-sidesheet.component.scss @@ -1,5 +1,6 @@ -@import "@elemental-ui/core/src/styles/_palette.scss"; -@import "@elemental-ui/core/src/styles/_eui_palette.scss"; +@import '@elemental-ui/core/src/styles/_palette.scss'; +@import '@elemental-ui/core/src/styles/_eui_palette.scss'; +@import 'base/mixins'; .product-owner-datasource-container { margin: 10px 0 25px; @@ -10,23 +11,21 @@ color: $black-9; padding-bottom: 2px; } - mat-radio-button { - margin-right: 10px; - } .hidden { display: none; } - .help-icon { - color: $iris-blue; - font-size: 16px; + .imx-icon-info { margin-left: 5px; } +} - .mat-radio-group { - display: block; - margin-bottom: 10px; +.imx-dynamic-content { + @include flex-column-container-fill(); + :first-child { + height: 100%; + @include flex-column-container-fill(); } } @@ -37,84 +36,14 @@ background: $corbin-orange; } } - - ::ng-deep .mat-tab-group { - height: 100%; - flex-grow: 1; - overflow: auto; - - .mat-tab-header { - padding: 0 32px; - background-color: $white; - } - - ::ng-deep .mat-tab-body-wrapper { - height: 100%; - } - - .imx-edit-fk-open-picker { - display: none; - } - } } @media screen and (max-width: 769px) { - .product-owner-datasource-container .help-icon { + .product-owner-datasource-container .imx-icon-info { display: none; } } -.governance-sidesheet__tab-content { - display: flex; - flex-direction: column; - overflow: hidden; - > .governance-sidesheet__tab-content-body { - flex: 1 1 auto; - overflow: auto; - padding: 20px; - - > :first-child { - overflow: auto; - - } - - > .imx-ext { - overflow: hidden; - } - } - - .imx-flex-child { - ng-container { - flex: 1 1 auto; - display: flex; - } - } - - eui-icon { - font-size: 14px; - margin-right: 4px; - } -} - -.mat-tab-body-content { - display: flex; - flex-direction: column; - overflow: hidden; -} - -.imx-dirty-indicator { - color: $corbin_orange; -} - -.eui-sidesheet-content:not(.imx-hyperview-sidesheet) { - padding: 0; - - ::ng-deep .mat-tab-body-content { - display: flex; - flex-direction: column; - } -} - .eui-sidesheet-actions { .justify-start { margin-right: auto; @@ -148,12 +77,6 @@ color: $color-gray-10; } } - - ::ng-deep .mat-tab-group { - .mat-tab-header { - background-color: $color-gray-80; - } - } } } @@ -164,11 +87,5 @@ color: $color-gray-0; } } - - ::ng-deep .mat-tab-group { - .mat-tab-header { - background-color: $color-gray-90; - } - } } } diff --git a/imxweb/projects/tsb/src/lib/groups/group-sidesheet/group-sidesheet.component.ts b/imxweb/projects/tsb/src/lib/groups/group-sidesheet/group-sidesheet.component.ts index 5a14f333a..7579cf146 100644 --- a/imxweb/projects/tsb/src/lib/groups/group-sidesheet/group-sidesheet.component.ts +++ b/imxweb/projects/tsb/src/lib/groups/group-sidesheet/group-sidesheet.component.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -24,33 +24,29 @@ * */ -import { OverlayRef } from '@angular/cdk/overlay'; -import { Component, OnInit, Inject, ViewChild } from '@angular/core'; -import { UntypedFormGroup, UntypedFormBuilder, UntypedFormArray } from '@angular/forms'; -import { EuiDownloadOptions, EuiLoadingService, EuiSidesheetRef, EUI_SIDESHEET_DATA } from '@elemental-ui/core'; +import { Component, Inject, OnInit, ViewChild } from '@angular/core'; +import { UntypedFormArray, UntypedFormBuilder, UntypedFormGroup } from '@angular/forms'; +import { EUI_SIDESHEET_DATA, EuiDownloadOptions, EuiLoadingService, EuiSidesheetRef } from '@elemental-ui/core'; +import { PortalTargetsystemUnsGroupServiceitem } from '@imx-modules/imx-api-tsb'; +import { TypedEntity } from '@imx-modules/imx-qbm-dbts'; import { + BaseCdr, + ClassloggerService, ColumnDependentReference, - BaseCdr, ClassloggerService, - SystemInfoService, - SnackBarService, - ElementalUiConfigService, ConfirmationService, - TabItem, + ElementalUiConfigService, ExtService, + SnackBarService, + SystemInfoService, + TabItem, } from 'qbm'; -import { - HelperAlertContent, - ProjectConfigurationService, - ServiceItemsEditFormComponent -} from 'qer'; -import { PortalTargetsystemUnsGroupServiceitem } from 'imx-api-tsb'; -import { TypedEntity } from 'imx-qbm-dbts'; -import { GroupsService } from '../groups.service'; -import { GroupSidesheetData } from '../groups.models'; +import { HelperAlertContent, ProjectConfigurationService, ServiceItemsEditFormComponent } from 'qer'; +import { DbObjectKeyBase } from '../../target-system/db-object-key-wrapper.interface'; import { GroupsReportsService } from '../groups-reports.service'; +import { GroupSidesheetData } from '../groups.models'; +import { GroupsService } from '../groups.service'; import { GroupMembersComponent } from './group-members/group-members.component'; -import { DbObjectKeyBase } from '../../target-system/db-object-key-wrapper.interface'; @Component({ selector: 'imx-group-sidesheet', @@ -63,17 +59,17 @@ export class GroupSidesheetComponent implements OnInit { } public get isAdmin(): boolean { - return this.sidesheetData.isAdmin; + return this.sidesheetData?.isAdmin ?? false; } public readonly serviceItemFormGroup: UntypedFormGroup; public readonly detailsFormGroup: UntypedFormGroup; public cdrList: ColumnDependentReference[] = []; public isRequestable: boolean; - public parameters: { objecttable: string; objectuid: string; }; + public parameters: { objecttable: string; objectuid: string; display: string }; public unsGroupDbObjectKey: DbObjectKeyBase; public reportDownload: EuiDownloadOptions; - public buttonBarExtensionReferrer: { type: string, uidGroup: string, defaultDownloadOptions: EuiDownloadOptions }; + public buttonBarExtensionReferrer: { type: string; uidGroup: string; defaultDownloadOptions?: EuiDownloadOptions }; public readonly pendingAttestations: HelperAlertContent = { loading: false }; public canCreateServiceItem = false; @@ -86,7 +82,7 @@ export class GroupSidesheetComponent implements OnInit { constructor( formBuilder: UntypedFormBuilder, public groups: GroupsService, - @Inject(EUI_SIDESHEET_DATA) private readonly sidesheetData: GroupSidesheetData, + @Inject(EUI_SIDESHEET_DATA) public readonly sidesheetData: GroupSidesheetData, private readonly logger: ClassloggerService, private readonly busyService: EuiLoadingService, private readonly snackbar: SnackBarService, @@ -98,7 +94,6 @@ export class GroupSidesheetComponent implements OnInit { private readonly tabService: ExtService, private readonly confirmation: ConfirmationService, ) { - this.sidesheetRef.closeClicked().subscribe(async () => { if (!this.detailsFormGroup.dirty && !this.serviceItemFormGroup.dirty) { this.sidesheetRef.close(); @@ -116,7 +111,7 @@ export class GroupSidesheetComponent implements OnInit { this.isRequestable = sidesheetData.groupServiceItem != null && !sidesheetData.groupServiceItem.IsInActive.value; this.reportDownload = { - ... this.elementalUiConfigService.Config.downloadOptions, + ...this.elementalUiConfigService.Config.downloadOptions, url: this.reports.groupsByGroupReport(30, this.groupId), }; @@ -125,7 +120,8 @@ export class GroupSidesheetComponent implements OnInit { if (this.sidesheetData.unsGroupDbObjectKey) { this.parameters = { objecttable: this.unsGroupDbObjectKey.TableName, - objectuid: this.unsGroupDbObjectKey.Keys[0] + objectuid: this.unsGroupDbObjectKey.Keys[0], + display: this.sidesheetData.group.GetEntity().GetDisplay(), }; } this.canCreateServiceItem = !sidesheetData.group.GetEntity().GetColumn('XReadOnlyMemberships')?.GetValue(); @@ -133,7 +129,7 @@ export class GroupSidesheetComponent implements OnInit { this.buttonBarExtensionReferrer = { type: this.sidesheetData.unsGroupDbObjectKey.TableName, uidGroup: this.sidesheetData.group.GetEntity().GetKeys()[0], - defaultDownloadOptions: this.elementalUiConfigService.Config.downloadOptions + defaultDownloadOptions: this.elementalUiConfigService.Config.downloadOptions, }; } @@ -166,7 +162,7 @@ export class GroupSidesheetComponent implements OnInit { public async createServiceItem(): Promise { this.sidesheetData.group.extendedData = { - CreateServiceItem: true + CreateServiceItem: true, }; await this.saveChanges(this.detailsFormGroup, this.sidesheetData.group, '#LDS#The service item has been successfully created.', true); } @@ -186,7 +182,7 @@ export class GroupSidesheetComponent implements OnInit { }; confirmMessage = '#LDS#The service item has been successfully saved. It may take some time for the changes to take effect.'; } else { - this.groupServiceItem.extendedData = undefined; + this.groupServiceItem.extendedData = { CopyAllMembers: false }; } this.saveChanges(this.serviceItemFormGroup, this.groupServiceItem, confirmMessage); } @@ -216,33 +212,34 @@ export class GroupSidesheetComponent implements OnInit { } private async setup(): Promise { - let overlayRef: OverlayRef; - setTimeout(() => overlayRef = this.busyService.show()); + if (this.busyService.overlayRefs.length === 0) { + this.busyService.show(); + } try { const systemInfo = await this.systemInfoService.get(); const config = (await this.configService.getConfig()).OwnershipConfig; const type = this.parameters?.objecttable; - this.dynamicTabs = (await this.tabService.getFittingComponents('groupSidesheet', - (ext) => ext.inputData.checkVisibility(this.parameters))) - .sort((tab1: TabItem, tab2: TabItem) => tab1.sortOrder - tab2.sortOrder); + this.dynamicTabs = ( + await this.tabService.getFittingComponents('groupSidesheet', (ext) => ext.inputData.checkVisibility(this.parameters)) + ).sort((tab1: TabItem, tab2: TabItem) => tab1.sortOrder! - tab2.sortOrder!); - const cols = this.sidesheetData.group - .getColumns(systemInfo.PreProps.includes('RISKINDEX'), type == null ? [] : config.EditableFields[type]); + const cols = this.sidesheetData.group.getColumns( + systemInfo?.PreProps?.includes('RISKINDEX') ?? false, + config?.EditableFields?.[type] ?? [], + ); - this.cdrList = cols - .map(column => new BaseCdr(column)); + this.cdrList = cols.map((column) => new BaseCdr(column)); } finally { - setTimeout(() => this.busyService.hide(overlayRef)); + this.busyService.hide(); } } - private async saveChanges( formGroup: UntypedFormGroup, objectToSave: TypedEntity, confirmationText: string, - reloadServiceItem: boolean = false + reloadServiceItem: boolean = false, ): Promise { if (formGroup.valid) { this.logger.debug(this, `Saving group changes`); diff --git a/imxweb/projects/tsb/src/lib/groups/group-typed-entity.ts b/imxweb/projects/tsb/src/lib/groups/group-typed-entity.ts index 10e8bc7fd..9a8c95f22 100644 --- a/imxweb/projects/tsb/src/lib/groups/group-typed-entity.ts +++ b/imxweb/projects/tsb/src/lib/groups/group-typed-entity.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -24,22 +24,20 @@ * */ -import { IEntityColumn, WriteExtTypedEntity } from 'imx-qbm-dbts'; +import { IEntityColumn, WriteExtTypedEntity } from '@imx-modules/imx-qbm-dbts'; import { CdrFactoryService } from 'qbm'; export class GroupTypedEntity extends WriteExtTypedEntity { public getColumns(showRiskIndex: boolean, propertyList: string[]): ReadonlyArray { - // TODO: for each property, determine from dynamic entity schema (282445) - if (propertyList.indexOf('DisplayName') === -1) { + if (!propertyList.includes('DisplayName')) { propertyList.unshift('DisplayName'); } - if (showRiskIndex && propertyList.indexOf('RiskIndex') === -1) { + if (showRiskIndex && !propertyList.includes('RiskIndex')) { propertyList.push('RiskIndex'); } - - return propertyList.map(elem=> CdrFactoryService.tryGetColumn(this.GetEntity(),elem)).filter(elem=>elem != null); + return propertyList.map((elem) => CdrFactoryService.tryGetColumn(this.GetEntity(), elem)).filter(Boolean) as IEntityColumn[]; } } diff --git a/imxweb/projects/tsb/src/lib/groups/groups-reports.service.ts b/imxweb/projects/tsb/src/lib/groups/groups-reports.service.ts index 2e0ce8fa0..3241cb25f 100644 --- a/imxweb/projects/tsb/src/lib/groups/groups-reports.service.ts +++ b/imxweb/projects/tsb/src/lib/groups/groups-reports.service.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -25,16 +25,18 @@ */ import { Injectable } from '@angular/core'; -import { CollectionLoadParameters, TypedEntityCollectionData } from 'imx-qbm-dbts'; -import { PortalTargetsystemUnsGroup } from 'imx-api-tsb'; +import { CollectionLoadParameters, TypedEntityCollectionData } from '@imx-modules/imx-qbm-dbts'; +import { PortalTargetsystemUnsGroup } from '@imx-modules/imx-api-tsb'; import { AppConfigService, SettingsService } from 'qbm'; import { TsbApiService } from '../tsb-api-client.service'; @Injectable({ providedIn: 'root' }) export class GroupsReportsService { - constructor(private tsbClient: TsbApiService, + constructor( + private tsbClient: TsbApiService, private readonly settings: SettingsService, - private appConfig: AppConfigService) { } + private appConfig: AppConfigService, + ) {} public groupsByGroupReport(historyDays: number, groupId: string): string { const path = `targetsystem/uns/group/${groupId}/report?historydays=${historyDays}`; diff --git a/imxweb/projects/tsb/src/lib/groups/groups.component.html b/imxweb/projects/tsb/src/lib/groups/groups.component.html index 57d749f5a..3b866710f 100644 --- a/imxweb/projects/tsb/src/lib/groups/groups.component.html +++ b/imxweb/projects/tsb/src/lib/groups/groups.component.html @@ -1,17 +1,17 @@ - -
    -
    - #LDS#Heading System Entitlements + +
    +
    +

    #LDS#Heading System Entitlements

    -
    +
    - +
    @@ -19,56 +19,53 @@
    - - - +
    - - - + + + {{ entitySchemaUnsGroup?.Columns?.[DisplayColumns.DISPLAY_PROPERTYNAME]?.Display }} + +
    {{ item.GetEntity().GetDisplay() }}
    {{ item.Description.Column.GetDisplayValue() }}
    -
    -
    - - + + + + {{ entitySchemaUnsGroup?.Columns?.Requestable?.Display }} + + +
    {{ item.Requestable.Column.GetDisplayValue() }}
    + +
    + - + {{ entitySchemaUnsGroup?.Columns?.XMarkedForDeletion?.Display }} +
    {{ item.XMarkedForDeletion.Column.GetDisplayValue() }}
    -
    -
    - - + + + + {{ entitySchemaUnsGroup?.Columns?.UID_UNSRoot?.Display }} + - - -
    - + + + +
    - -
    - - diff --git a/imxweb/projects/tsb/src/lib/groups/groups.component.scss b/imxweb/projects/tsb/src/lib/groups/groups.component.scss index 0e0119e1a..744080ca8 100644 --- a/imxweb/projects/tsb/src/lib/groups/groups.component.scss +++ b/imxweb/projects/tsb/src/lib/groups/groups.component.scss @@ -1,6 +1,8 @@ -@import '../../../../../shared/scss/common-table.scss'; +@import 'base/mixins'; + :host { overflow: hidden; + height: 100%; } .data-explorer--groups > :nth-child(2) { @@ -22,31 +24,8 @@ } } -.imx-tab-card { - margin: 20px; - flex: 1 1 auto; -} -.eui-sidesheet-actions { - .imx-spacer { - flex: 1 1 auto; - } -} -.data-explorer-bottom-button-row { - display: flex; - flex-direction: row; - align-items: flex-end; - margin-top: 15px; - - .mat-stroked-button{ - @include imx-icon-for-image-button(); - } - - .imx-spacer { - flex: 1 1 auto; - } -} .hidden { display: none; } diff --git a/imxweb/projects/tsb/src/lib/groups/groups.component.ts b/imxweb/projects/tsb/src/lib/groups/groups.component.ts index 57fb0622d..1de2bb2ed 100644 --- a/imxweb/projects/tsb/src/lib/groups/groups.component.ts +++ b/imxweb/projects/tsb/src/lib/groups/groups.component.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -24,40 +24,40 @@ * */ -import { OverlayRef } from '@angular/cdk/overlay'; +import { Component, Input, OnDestroy, OnInit } from '@angular/core'; import { UntypedFormControl } from '@angular/forms'; import { ActivatedRoute } from '@angular/router'; import { EuiLoadingService, EuiSidesheetService } from '@elemental-ui/core'; -import { TranslateService } from '@ngx-translate/core'; -import { Component, OnInit, Input, OnDestroy, ViewChild } from '@angular/core'; -import { - CollectionLoadParameters, - IClientProperty, - DisplayColumns, - DbObjectKey, - EntitySchema, - DataModel, - FilterData, - ValType, -} from 'imx-qbm-dbts'; -import { ViewConfigData } from 'imx-api-qer'; +import { ViewConfigData } from '@imx-modules/imx-api-qer'; import { EntityWriteDataBulk, + PortalRespUnsgroup, PortalTargetsystemUnsGroup, PortalTargetsystemUnsGroupServiceitem, PortalTargetsystemUnsSystem, -} from 'imx-api-tsb'; +} from '@imx-modules/imx-api-tsb'; +import { + CollectionLoadParameters, + DataModel, + DbObjectKey, + DisplayColumns, + EntitySchema, + IClientProperty, + TypedEntityCollectionData, + ValType, +} from '@imx-modules/imx-qbm-dbts'; +import { TranslateService } from '@ngx-translate/core'; import { BusyService, ClassloggerService, DataSourceToolbarFilter, - DataSourceToolbarSettings, - DataTableComponent, - SettingsService, - SideNavigationComponent, - SnackBarService, DataSourceToolbarViewConfig, + DataViewInitParameters, + DataViewSource, HelpContextualValues, + SideNavigationComponent, + SnackBarService, + calculateSidesheetWidth, } from 'qbm'; import { SourceDetectiveSidesheetComponent, SourceDetectiveSidesheetData, SourceDetectiveType, ViewConfigService } from 'qer'; import { Subscription } from 'rxjs'; @@ -65,7 +65,7 @@ import { Subscription } from 'rxjs'; import { ContainerTreeDatabaseWrapper } from '../container-list/container-tree-database-wrapper'; import { DeHelperService } from '../de-helper.service'; import { GroupSidesheetComponent } from './group-sidesheet/group-sidesheet.component'; -import { GetGroupsOptionalParameters, GroupSidesheetData } from './groups.models'; +import { GroupSidesheetData } from './groups.models'; import { GroupsService } from './groups.service'; import { ProductOwnerSidesheetComponent } from './product-owner-sidesheet/product-owner-sidesheet.component'; @@ -73,6 +73,7 @@ import { ProductOwnerSidesheetComponent } from './product-owner-sidesheet/produc selector: 'imx-data-explorer-groups', templateUrl: './groups.component.html', styleUrls: ['./groups.component.scss'], + providers: [DataViewSource], }) export class DataExplorerGroupsComponent implements OnInit, OnDestroy, SideNavigationComponent { @Input() public unsAccountIdFilter: string; @@ -84,23 +85,12 @@ export class DataExplorerGroupsComponent implements OnInit, OnDestroy, SideNavig @Input() public uidPerson = ''; @Input() public usedInSidesheet = false; @Input() public contextId: HelpContextualValues; - - @ViewChild('dataTable', { static: false }) public dataTable: DataTableComponent; - /** - * Settings needed by the DataSourceToolbarComponent - */ - - public dstSettings: DataSourceToolbarSettings; - /** - * Page size, start index, search and filtering options etc. - */ - public navigationState: CollectionLoadParameters; public filterOptions: DataSourceToolbarFilter[] = []; public treeDbWrapper: ContainerTreeDatabaseWrapper; public requestableBulkUpdateCtrl = new UntypedFormControl(true); public entitySchemaUnsGroup: EntitySchema; public readonly DisplayColumns = DisplayColumns; - public selectedGroupsForUpdate: PortalTargetsystemUnsGroup[] = []; + public selectedGroupsForUpdate: Array = []; public data: any; public busyService = new BusyService(); @@ -128,12 +118,11 @@ export class DataExplorerGroupsComponent implements OnInit, OnDestroy, SideNavig private readonly dataHelper: DeHelperService, private readonly translate: TranslateService, private readonly snackbar: SnackBarService, - settingsService: SettingsService + public dataSource: DataViewSource, ) { this.isAdmin = this.route.snapshot?.url[0]?.path === 'admin'; - this.navigationState = { PageSize: settingsService.DefaultPageSize, StartIndex: 0 }; this.entitySchemaUnsGroup = this.groupsService.unsGroupsSchema(this.isAdmin); - this.authorityDataDeleted$ = this.dataHelper.authorityDataDeleted.subscribe(() => this.navigate()); + this.authorityDataDeleted$ = this.dataHelper.authorityDataDeleted.subscribe(() => this.dataSource.updateState()); this.treeDbWrapper = new ContainerTreeDatabaseWrapper(this.busyService, dataHelper); } @@ -152,38 +141,54 @@ export class DataExplorerGroupsComponent implements OnInit, OnDestroy, SideNavig if (this.unsAccountIdFilter) { this.displayedColumns.push({ ColumnName: 'action', Type: ValType.String }); } - const isBusy = this.busyService.beginBusy(); try { this.filterOptions = await this.groupsService.getFilterOptions(this.isAdmin); + this.dataSource.itemStatus = this.itemStatus; this.dataModel = await this.groupsService.getDataModel(this.isAdmin); this.viewConfigPath = this.isAdmin || this.unsAccountIdFilter ? 'targetsystem/uns/group' : 'resp/unsgroup'; this.viewConfig = await this.viewConfigService.getInitialDSTExtension(this.dataModel, this.viewConfigPath); + const dataViewInitParameters: DataViewInitParameters = { + execute: + this.isAdmin || this.unsAccountIdFilter // Wenn wir filtern, muss auch der Admin-Endpoint genutzt werden + ? (params: CollectionLoadParameters, signal: AbortSignal): Promise> => { + if (this.unsAccountIdFilter) { + params = { ...params, uid_unsaccount: this.unsAccountIdFilter }; + } + return this.groupsService.getGroups(params, signal); + } + : (params: CollectionLoadParameters, signal: AbortSignal): Promise> => + this.groupsService.getGroupsResp(params, signal), + schema: this.entitySchemaUnsGroup, + columnsToDisplay: this.displayedColumns, + dataModel: this.dataModel, + exportFunction: + this.isAdmin || this.unsAccountIdFilter + ? this.groupsService.exportGroups(this.dataSource.state()) + : this.groupsService.exportGroupsResp(this.dataSource.state()), + viewConfig: this.viewConfig, + highlightEntity: (identity: PortalTargetsystemUnsGroup | PortalRespUnsgroup) => { + this.onGroupChanged(identity); + }, + filterTree: { + filterMethode: async (parentkey) => { + return this.groupsService.getFilterTree({ + parentkey, + container: this.dataSource.state().container, + system: this.dataSource.state().system, + uid_unsaccount: this.unsAccountIdFilter, + }); + }, + multiSelect: false, + }, + selectionChange: (selection: Array) => this.onGroupSelected(selection), + }; + this.dataSource.init(dataViewInitParameters); } finally { isBusy.endBusy(); } - if (this.applyIssuesFilter && !this.issuesFilterMode) { - const ownerFilter = this.filterOptions.find((f) => { - return f.Name === 'withowner'; - }); - - if (ownerFilter) { - ownerFilter.InitialValue = '0'; - } - } - - if (this.applyIssuesFilter && this.issuesFilterMode === 'requestable') { - const requestableFliter = this.filterOptions.find((f) => { - return f.Name === 'published'; - }); - - if (requestableFliter) { - requestableFliter.InitialValue = '0'; - } - } - await this.navigate(); } public ngOnDestroy(): void { @@ -195,13 +200,13 @@ export class DataExplorerGroupsComponent implements OnInit, OnDestroy, SideNavig public async updateConfig(config: ViewConfigData): Promise { await this.viewConfigService.putViewConfig(config); this.viewConfig = await this.viewConfigService.getDSTExtensionChanges(this.viewConfigPath); - this.dstSettings.viewConfig = this.viewConfig; + this.dataSource.viewConfig.set(this.viewConfig); } public async deleteConfigById(id: string): Promise { await this.viewConfigService.deleteViewConfig(id); this.viewConfig = await this.viewConfigService.getDSTExtensionChanges(this.viewConfigPath); - this.dstSettings.viewConfig = this.viewConfig; + this.dataSource.viewConfig.set(this.viewConfig); } public get itemsAreNotRequestable(): boolean { @@ -212,18 +217,7 @@ export class DataExplorerGroupsComponent implements OnInit, OnDestroy, SideNavig return this.selectedGroupsForUpdate.every((elem) => elem.Requestable.value); } - /** - * Occurs when the navigation state has changed - e.g. users clicks on the next page button. - * - */ - public async onNavigationStateChanged(newState?: CollectionLoadParameters): Promise { - if (newState) { - this.navigationState = newState; - } - await this.navigate(); - } - - public async onGroupChanged(group: PortalTargetsystemUnsGroup): Promise { + public async onGroupChanged(group: PortalTargetsystemUnsGroup | PortalRespUnsgroup): Promise { if (this.unsAccountIdFilter) { return; } @@ -232,13 +226,12 @@ export class DataExplorerGroupsComponent implements OnInit, OnDestroy, SideNavig this.logger.trace(this, `New group selected`, group); let data: GroupSidesheetData; - let busy: OverlayRef; - const isBusy = this.busyService.beginBusy(); + const hideOverlayRef = this.busyServiceElemental.show(); try { - const objKey = DbObjectKey.FromXml(group.XObjectKey.value); + const objKey = DbObjectKey.FromXml(group.GetEntity().GetColumn('XObjectKey').GetValue()); - const uidAccProduct = group.UID_AccProduct.value; + const uidAccProduct = group.GetEntity().GetColumn('UID_AccProduct').GetValue(); data = { uidAccProduct, @@ -248,31 +241,13 @@ export class DataExplorerGroupsComponent implements OnInit, OnDestroy, SideNavig isAdmin: this.isAdmin, }; } finally { - isBusy.endBusy(); + this.busyServiceElemental.hide(hideOverlayRef); } this.viewGroup(data); } - /** - * Occurs when user triggers search. - * - * @param keywords Search keywords. - */ - public async onSearch(keywords: string): Promise { - this.logger.debug(this, `Searching for: ${keywords}`); - this.navigationState.StartIndex = 0; - this.navigationState.search = keywords; - await this.navigate(); - } - - public async filterByTree(filters: FilterData[]): Promise { - this.navigationState.filter = filters; - this.navigationState.StartIndex = 0; - return this.navigate(); - } - - public onGroupSelected(selected: PortalTargetsystemUnsGroup[]): void { + public onGroupSelected(selected: Array): void { this.selectedGroupsForUpdate = selected; } @@ -292,7 +267,7 @@ export class DataExplorerGroupsComponent implements OnInit, OnDestroy, SideNavig title: await this.translate.get('#LDS#Heading View Assignment Analysis').toPromise(), subTitle: item.GetEntity().GetDisplay(), padding: '0px', - width: 'max(600px, 60%)', + width: calculateSidesheetWidth(), disableClose: false, testId: 'system-entitlement-role-membership-details', data, @@ -334,88 +309,42 @@ export class DataExplorerGroupsComponent implements OnInit, OnDestroy, SideNavig private async updateOwnerForSelectedGroups(selectedOwner: { uidPerson?: string; uidRole?: string }): Promise { let confirmMessage = ''; - let busy: OverlayRef; + if (this.busyServiceElemental.overlayRefs.length === 0) { + this.busyServiceElemental.show(); + } try { - setTimeout(() => (busy = this.busyServiceElemental.show())); confirmMessage = await this.groupsService.updateMultipleOwner( this.selectedGroupsForUpdate.map((elem) => elem.UID_AccProduct.value), - selectedOwner + selectedOwner, ); } finally { - setTimeout(() => this.busyServiceElemental.hide(busy)); + this.busyServiceElemental.hide(); } if (confirmMessage) { this.snackbar.open({ key: confirmMessage }); } - return this.navigate(); + return this.dataSource.updateState(); } private async updateSelectedGroups(updateData: EntityWriteDataBulk): Promise { this.selectedGroupsForUpdate.forEach((group: PortalTargetsystemUnsGroup) => { const serviceItemUid = group?.UID_AccProduct.value; - if (serviceItemUid?.length) { + if (serviceItemUid?.length && updateData.Keys) { updateData.Keys.push([serviceItemUid]); } }); - let busy: OverlayRef; + if (this.busyServiceElemental.overlayRefs.length === 0) { + this.busyServiceElemental.show(); + } try { - setTimeout(() => (busy = this.busyServiceElemental.show())); await this.groupsService.bulkUpdateGroupServiceItems(updateData); - await this.navigate(); - this.dataTable.clearSelection(); + await this.dataSource.updateState(); + this.dataSource.selection.clear(); this.requestableBulkUpdateCtrl.setValue(true, { emitEvent: false }); } finally { - setTimeout(() => this.busyServiceElemental.hide(busy)); - } - } - - private async navigate(): Promise { - const isBusy = this.busyService.beginBusy(); - - const getParams: GetGroupsOptionalParameters = this.navigationState; - - try { - if (this.unsAccountIdFilter) { - getParams.uid_unsaccount = this.unsAccountIdFilter; - } - - const data = - this.isAdmin || this.unsAccountIdFilter // Wenn wir filtern, muss auch der Admin-Endpoint genutzt werden - ? await this.groupsService.getGroups(getParams) - : await this.groupsService.getGroupsResp(getParams); - - const exportMethod = - this.isAdmin || this.unsAccountIdFilter - ? this.groupsService.exportGroups(getParams) - : this.groupsService.exportGroupsResp(getParams); - exportMethod.initialColumns = this.displayedColumns.map((col) => col.ColumnName); - - this.dstSettings = { - displayedColumns: this.displayedColumns, - dataSource: data, - entitySchema: this.entitySchemaUnsGroup, - navigationState: this.navigationState, - filters: this.filterOptions, - filterTree: { - filterMethode: async (parentkey) => { - return this.groupsService.getFilterTree({ - parentkey, - container: getParams.container, - system: getParams.system, - uid_unsaccount: getParams.uid_unsaccount, - }); - }, - multiSelect: false, - }, - dataModel: this.dataModel, - viewConfig: this.viewConfig, - exportMethod, - }; - this.logger.debug(this, `Head at ${data.Data.length + this.navigationState.StartIndex} of ${data.totalCount} item(s)`); - } finally { - isBusy.endBusy(); + this.busyServiceElemental.hide(); } } @@ -424,13 +353,13 @@ export class DataExplorerGroupsComponent implements OnInit, OnDestroy, SideNavig title: await this.translate.get('#LDS#Heading Edit System Entitlement').toPromise(), subTitle: data.group.GetEntity().GetDisplay(), padding: '0px', - width: `max(650px, ${this.sidesheetWidth})`, + width: calculateSidesheetWidth(1250, 0.7), icon: 'usergroup', data, testId: 'edit-system-entitlement-sidesheet', disableClose: true, }); // After the sidesheet closes, reload the current data to refresh any changes that might have been made - sidesheetRef.afterClosed().subscribe(() => this.navigate()); + sidesheetRef.afterClosed().subscribe(() => this.dataSource.updateState()); } } diff --git a/imxweb/projects/tsb/src/lib/groups/groups.models.ts b/imxweb/projects/tsb/src/lib/groups/groups.models.ts index dcdaa860f..820c5506c 100644 --- a/imxweb/projects/tsb/src/lib/groups/groups.models.ts +++ b/imxweb/projects/tsb/src/lib/groups/groups.models.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -24,10 +24,10 @@ * */ -import { CollectionLoadParameters } from 'imx-qbm-dbts'; -import { PortalTargetsystemUnsGroupServiceitem } from 'imx-api-tsb'; -import { GroupTypedEntity } from './group-typed-entity'; +import { PortalTargetsystemUnsGroupServiceitem } from '@imx-modules/imx-api-tsb'; +import { CollectionLoadParameters } from '@imx-modules/imx-qbm-dbts'; import { DbObjectKeyBase } from '../target-system/db-object-key-wrapper.interface'; +import { GroupTypedEntity } from './group-typed-entity'; export interface GetGroupsOptionalParameters extends CollectionLoadParameters { uid_unsaccount?: string; @@ -46,8 +46,8 @@ export interface GroupSidesheetData { } export interface GroupsFilterTreeParameters { - container: string; - system: string; - uid_unsaccount: string; - parentkey:string; + container: string | undefined; + system: string | undefined; + uid_unsaccount: string | undefined; + parentkey: string; } diff --git a/imxweb/projects/tsb/src/lib/groups/groups.module.ts b/imxweb/projects/tsb/src/lib/groups/groups.module.ts index 564d09b03..4e5f1557b 100644 --- a/imxweb/projects/tsb/src/lib/groups/groups.module.ts +++ b/imxweb/projects/tsb/src/lib/groups/groups.module.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -24,36 +24,37 @@ * */ -import { NgModule } from '@angular/core'; import { CommonModule } from '@angular/common'; +import { NgModule } from '@angular/core'; import { FormsModule, ReactiveFormsModule } from '@angular/forms'; import { RouterModule } from '@angular/router'; import { EuiCoreModule, EuiMaterialModule } from '@elemental-ui/core'; import { TranslateModule } from '@ngx-translate/core'; import { + BusyIndicatorModule, + CdrModule, DataSourceToolbarModule, DataTableModule, - CdrModule, - LdsReplaceModule, DataTreeModule, - ExtModule, + DataViewModule, DynamicTabsModule, + ExtModule, + HelpContextualModule, + LdsReplaceModule, ObjectHistoryModule, - BusyIndicatorModule, SelectedElementsModule, - HelpContextualModule - } from 'qbm'; +} from 'qbm'; -import { GroupSidesheetComponent } from './group-sidesheet/group-sidesheet.component'; +import { IdentityRoleMembershipsModule, ObjectHyperviewModule, OwnerControlModule, ServiceItemsEditFormModule } from 'qer'; +import { DataFiltersModule } from '../data-filters/data-filters.module'; +import { NoDataModule } from '../no-data/no-data.module'; +import { GroupMembershipsExtComponent } from './group-memberships-ext/group-memberships-ext.component'; +import { ChildSystemEntitlementsComponent } from './group-sidesheet/child-system-entitlements/child-system-entitlements.component'; import { GroupMembersComponent } from './group-sidesheet/group-members/group-members.component'; +import { GroupSidesheetComponent } from './group-sidesheet/group-sidesheet.component'; import { DataExplorerGroupsComponent } from './groups.component'; -import { ChildSystemEntitlementsComponent } from './group-sidesheet/child-system-entitlements/child-system-entitlements.component'; -import { NoDataModule } from '../no-data/no-data.module'; -import { DataFiltersModule } from '../data-filters/data-filters.module'; import { ProductOwnerSidesheetComponent } from './product-owner-sidesheet/product-owner-sidesheet.component'; -import { IdentityRoleMembershipsModule, ObjectHyperviewModule, OwnerControlModule, ServiceItemsEditFormModule } from 'qer'; -import { GroupMembershipsExtComponent } from './group-memberships-ext/group-memberships-ext.component'; @NgModule({ declarations: [ @@ -88,7 +89,8 @@ import { GroupMembershipsExtComponent } from './group-memberships-ext/group-memb ObjectHistoryModule, IdentityRoleMembershipsModule, SelectedElementsModule, - HelpContextualModule + HelpContextualModule, + DataViewModule, ], exports: [DataExplorerGroupsComponent, ChildSystemEntitlementsComponent], }) diff --git a/imxweb/projects/tsb/src/lib/groups/groups.service.ts b/imxweb/projects/tsb/src/lib/groups/groups.service.ts index a915e274d..e649e0331 100644 --- a/imxweb/projects/tsb/src/lib/groups/groups.service.ts +++ b/imxweb/projects/tsb/src/lib/groups/groups.service.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -25,47 +25,49 @@ */ import { Injectable } from '@angular/core'; -import { ClassloggerService, DataSourceToolbarExportMethod } from 'qbm'; +import { + EntityWriteDataBulk, + PortalRespUnsgroup, + PortalTargetsystemUnsDirectmembers, + PortalTargetsystemUnsGroup, + PortalTargetsystemUnsGroupServiceitem, + PortalTargetsystemUnsGroupmembers, + PortalTargetsystemUnsNestedmembers, + V2ApiClientMethodFactory, +} from '@imx-modules/imx-api-tsb'; import { CollectionLoadParameters, - TypedEntityCollectionData, - FilterType, CompareOperator, + DataModel, DataModelFilter, + EntityCollectionData, EntitySchema, + FilterData, FilterTreeData, - DataModel, - EntityCollectionData, + FilterType, + MethodDefinition, MethodDescriptor, - MethodDefinition -} from 'imx-qbm-dbts'; -import { - PortalTargetsystemUnsGroup, - PortalTargetsystemUnsGroupServiceitem, - PortalTargetsystemUnsGroupmembers, - EntityWriteDataBulk, - PortalTargetsystemUnsDirectmembers, - PortalTargetsystemUnsNestedmembers, - PortalRespUnsgroup, - V2ApiClientMethodFactory -} from 'imx-api-tsb'; -import { GroupsFilterTreeParameters, GetGroupsOptionalParameters } from './groups.models'; + TypedEntityCollectionData, +} from '@imx-modules/imx-qbm-dbts'; +import { ClassloggerService, DataSourceToolbarExportMethod } from 'qbm'; +import { DbObjectKeyBase } from '../target-system/db-object-key-wrapper.interface'; +import { TargetSystemDynamicMethodService } from '../target-system/target-system-dynamic-method.service'; import { TsbApiService } from '../tsb-api-client.service'; import { GroupTypedEntity } from './group-typed-entity'; -import { TargetSystemDynamicMethodService } from '../target-system/target-system-dynamic-method.service'; -import { DbObjectKeyBase } from '../target-system/db-object-key-wrapper.interface'; +import { GetGroupsOptionalParameters, GroupsFilterTreeParameters } from './groups.models'; @Injectable({ providedIn: 'root' }) export class GroupsService { constructor( private readonly tsbClient: TsbApiService, private readonly logger: ClassloggerService, - private readonly dynamicMethod: TargetSystemDynamicMethodService - ) { } + private readonly dynamicMethod: TargetSystemDynamicMethodService, + ) {} public unsGroupsSchema(isAdmin: boolean): EntitySchema { - return isAdmin ? this.tsbClient.typedClient.PortalTargetsystemUnsGroup.GetSchema() : - this.tsbClient.typedClient.PortalRespUnsgroup.GetSchema(); + return isAdmin + ? this.tsbClient.typedClient.PortalTargetsystemUnsGroup.GetSchema() + : this.tsbClient.typedClient.PortalRespUnsgroup.GetSchema(); } public get UnsGroupMembersSchema(): EntitySchema { @@ -84,8 +86,11 @@ export class GroupsService { return this.tsbClient.client.portal_targetsystem_uns_group_filtertree_get(options); } - public async getGroups(navigationState: GetGroupsOptionalParameters): Promise> { - return this.tsbClient.typedClient.PortalTargetsystemUnsGroup.Get(navigationState); + public async getGroups( + navigationState: GetGroupsOptionalParameters, + signal: AbortSignal, + ): Promise> { + return this.tsbClient.typedClient.PortalTargetsystemUnsGroup.Get(navigationState, { signal }); } public exportGroups(navigationState: GetGroupsOptionalParameters): DataSourceToolbarExportMethod { @@ -94,17 +99,20 @@ export class GroupsService { getMethod: (withProperties: string, PageSize?: number) => { let method: MethodDescriptor; if (PageSize) { - method = factory.portal_targetsystem_uns_group_get({...navigationState, withProperties, PageSize, StartIndex: 0}) + method = factory.portal_targetsystem_uns_group_get({ ...navigationState, withProperties, PageSize, StartIndex: 0 }); } else { - method = factory.portal_targetsystem_uns_group_get({...navigationState, withProperties}) + method = factory.portal_targetsystem_uns_group_get({ ...navigationState, withProperties }); } return new MethodDefinition(method); - } - } + }, + }; } - public async getGroupsResp(navigationState: GetGroupsOptionalParameters): Promise> { - return this.tsbClient.typedClient.PortalRespUnsgroup.Get(navigationState); + public async getGroupsResp( + navigationState: GetGroupsOptionalParameters, + signal: AbortSignal, + ): Promise> { + return this.tsbClient.typedClient.PortalRespUnsgroup.Get(navigationState, { signal }); } public exportGroupsResp(navigationState: GetGroupsOptionalParameters): DataSourceToolbarExportMethod { @@ -113,13 +121,13 @@ export class GroupsService { getMethod: (withProperties: string, PageSize?: number) => { let method: MethodDescriptor; if (PageSize) { - method = factory.portal_resp_unsgroup_get({...navigationState, withProperties, PageSize, StartIndex: 0}) + method = factory.portal_resp_unsgroup_get({ ...navigationState, withProperties, PageSize, StartIndex: 0 }); } else { - method = factory.portal_resp_unsgroup_get({...navigationState, withProperties}) + method = factory.portal_resp_unsgroup_get({ ...navigationState, withProperties }); } return new MethodDefinition(method); - } - } + }, + }; } public async getGroupDetails(dbObjectKey: DbObjectKeyBase): Promise { @@ -131,14 +139,14 @@ export class GroupsService { } public async getGroupServiceItem(key: string): Promise { - const navigationState: CollectionLoadParameters = { filter: [] }; - navigationState.filter.push({ + const filter: FilterData[] = []; + filter.push({ ColumnName: 'UID_AccProduct', Type: FilterType.Compare, CompareOp: CompareOperator.Equal, Value1: key, }); - return (await this.tsbClient.typedClient.PortalTargetsystemUnsGroupServiceitem.Get(navigationState)).Data[0]; + return (await this.tsbClient.typedClient.PortalTargetsystemUnsGroupServiceitem.Get({ filter })).Data[0]; } public async bulkUpdateGroupServiceItems(updateData: EntityWriteDataBulk): Promise { @@ -147,20 +155,22 @@ export class GroupsService { public async getGroupDirectMembers( groupId: string, - navigationState: CollectionLoadParameters + navigationState: CollectionLoadParameters, + signal?: AbortSignal, ): Promise> { this.logger.debug(this, `Retrieving group direct memberships`); this.logger.trace('GroupId', groupId); - return this.tsbClient.typedClient.PortalTargetsystemUnsDirectmembers.Get(groupId, navigationState); + return this.tsbClient.typedClient.PortalTargetsystemUnsDirectmembers.Get(groupId, navigationState, { signal }); } public async getGroupNestedMembers( groupId: string, - navigationState: CollectionLoadParameters + navigationState: CollectionLoadParameters, + signal?: AbortSignal, ): Promise> { this.logger.debug(this, `Retrieving group nested memberships`); this.logger.trace('GroupId', groupId); - return this.tsbClient.typedClient.PortalTargetsystemUnsNestedmembers.Get(groupId, navigationState); + return this.tsbClient.typedClient.PortalTargetsystemUnsNestedmembers.Get(groupId, navigationState, { signal }); } public async deleteGroupMembers(dbObjectKey: DbObjectKeyBase, uidAccountList: string[]): Promise { @@ -171,20 +181,19 @@ export class GroupsService { const groupId = dbObjectKey.Keys[0]; - return Promise.all(uidAccountList.map(accountId => - this.dynamicMethod.delete( - dbObjectKey.TableName, - { + return Promise.all( + uidAccountList.map((accountId) => + this.dynamicMethod.delete(dbObjectKey.TableName, { path: '{groupId}/memberships/{accountId}', - parameters: { groupId, accountId } - } - ) - )); + parameters: { groupId, accountId }, + }), + ), + ); } public async getGroupsGroupMembers( groupId: string, - navigationState: CollectionLoadParameters + navigationState: CollectionLoadParameters, ): Promise> { this.logger.debug(this, `Retrieving groups group memberships`); this.logger.trace('GroupId', groupId); @@ -192,16 +201,19 @@ export class GroupsService { } public async getFilterOptions(forAdmin: boolean): Promise { - return forAdmin ? (await this.tsbClient.client.portal_targetsystem_uns_group_datamodel_get(undefined)).Filters + const filters = forAdmin + ? (await this.tsbClient.client.portal_targetsystem_uns_group_datamodel_get(undefined)).Filters : (await this.tsbClient.client.portal_resp_unsgroup_datamodel_get(undefined)).Filters; + return filters ?? []; } public async getDataModel(forAdmin: boolean): Promise { - return forAdmin ? this.tsbClient.client.portal_targetsystem_uns_group_datamodel_get(undefined) + return forAdmin + ? this.tsbClient.client.portal_targetsystem_uns_group_datamodel_get(undefined) : this.tsbClient.client.portal_resp_unsgroup_datamodel_get(undefined); } - public async updateMultipleOwner(uidAccProducts: string[], uidPerson: { uidPerson?: string; uidRole?: string; }): Promise { + public async updateMultipleOwner(uidAccProducts: string[], uidPerson: { uidPerson?: string; uidRole?: string }): Promise { let confirmMessage = '#LDS#The product owner has been successfully assigned.'; try { for (const data of uidAccProducts) { @@ -212,8 +224,6 @@ export class GroupsService { CopyAllMembers: true, }; confirmMessage = '#LDS#The product owner has been successfully assigned. It may take some time for the changes to take effect.'; - } else { - product.extendedData = undefined; } if (uidPerson.uidRole) { product.UID_OrgRuler.value = uidPerson.uidRole; diff --git a/imxweb/projects/tsb/src/lib/groups/product-owner-sidesheet/product-owner-sidesheet.component.html b/imxweb/projects/tsb/src/lib/groups/product-owner-sidesheet/product-owner-sidesheet.component.html index d901016b4..ab3fb909b 100644 --- a/imxweb/projects/tsb/src/lib/groups/product-owner-sidesheet/product-owner-sidesheet.component.html +++ b/imxweb/projects/tsb/src/lib/groups/product-owner-sidesheet/product-owner-sidesheet.component.html @@ -1,14 +1,8 @@ -
    -
    -
    - - -
    - - - -
    -
    \ No newline at end of file +
    + +
    +
    + +
    diff --git a/imxweb/projects/tsb/src/lib/groups/product-owner-sidesheet/product-owner-sidesheet.component.scss b/imxweb/projects/tsb/src/lib/groups/product-owner-sidesheet/product-owner-sidesheet.component.scss index fb54bb970..88ef5ff3c 100644 --- a/imxweb/projects/tsb/src/lib/groups/product-owner-sidesheet/product-owner-sidesheet.component.scss +++ b/imxweb/projects/tsb/src/lib/groups/product-owner-sidesheet/product-owner-sidesheet.component.scss @@ -1,4 +1,4 @@ -@import "@elemental-ui/core/src/styles/_palette.scss"; +@import '@elemental-ui/core/src/styles/_palette.scss'; .governance-sidesheet__tab-content { display: flex; diff --git a/imxweb/projects/tsb/src/lib/groups/product-owner-sidesheet/product-owner-sidesheet.component.ts b/imxweb/projects/tsb/src/lib/groups/product-owner-sidesheet/product-owner-sidesheet.component.ts index 138b1e391..7abe45a4a 100644 --- a/imxweb/projects/tsb/src/lib/groups/product-owner-sidesheet/product-owner-sidesheet.component.ts +++ b/imxweb/projects/tsb/src/lib/groups/product-owner-sidesheet/product-owner-sidesheet.component.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -28,18 +28,17 @@ import { Component, Inject, ViewChild } from '@angular/core'; import { AbstractControl } from '@angular/forms'; import { EuiSidesheetRef, EUI_SIDESHEET_DATA } from '@elemental-ui/core'; -import { PortalTargetsystemUnsGroupServiceitem } from 'imx-api-tsb'; -import { IEntityColumn } from 'imx-qbm-dbts'; +import { PortalTargetsystemUnsGroupServiceitem } from '@imx-modules/imx-api-tsb'; +import { IEntityColumn } from '@imx-modules/imx-qbm-dbts'; import { BaseCdr } from 'qbm'; import { OwnerControlComponent } from 'qer'; import { ProductOwnerSidesheetService } from './product-owner-sidesheet.service'; @Component({ templateUrl: './product-owner-sidesheet.component.html', - styleUrls: ['./product-owner-sidesheet.component.scss'] + styleUrls: ['./product-owner-sidesheet.component.scss'], }) export class ProductOwnerSidesheetComponent { - public productOwnerCdr: BaseCdr; public column: IEntityColumn; @@ -50,7 +49,7 @@ export class ProductOwnerSidesheetComponent { constructor( private readonly sidesheetRef: EuiSidesheetRef, ownerService: ProductOwnerSidesheetService, - @Inject(EUI_SIDESHEET_DATA) sidesheetData: PortalTargetsystemUnsGroupServiceitem + @Inject(EUI_SIDESHEET_DATA) sidesheetData: PortalTargetsystemUnsGroupServiceitem, ) { this.column = ownerService.buildOrgRulerColumn(sidesheetData.GetEntity()); } @@ -64,5 +63,4 @@ export class ProductOwnerSidesheetComponent { public returnProductOwner(): void { this.sidesheetRef.close({ uidPerson: this.ownercontrol.uidPersonSelected, uidRole: this.ownercontrol.uidRoleSelected }); } - } diff --git a/imxweb/projects/tsb/src/lib/groups/product-owner-sidesheet/product-owner-sidesheet.service.ts b/imxweb/projects/tsb/src/lib/groups/product-owner-sidesheet/product-owner-sidesheet.service.ts index e8893da6d..44e867b8f 100644 --- a/imxweb/projects/tsb/src/lib/groups/product-owner-sidesheet/product-owner-sidesheet.service.ts +++ b/imxweb/projects/tsb/src/lib/groups/product-owner-sidesheet/product-owner-sidesheet.service.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -26,26 +26,24 @@ import { Injectable } from '@angular/core'; -import { IEntity, IEntityColumn } from 'imx-qbm-dbts'; +import { IEntity, IEntityColumn } from '@imx-modules/imx-qbm-dbts'; import { EntityService } from 'qbm'; import { TsbApiService } from '../../tsb-api-client.service'; @Injectable({ - providedIn: 'root' + providedIn: 'root', }) export class ProductOwnerSidesheetService { - constructor( private readonly entityService: EntityService, - private readonly api: TsbApiService - ) { } + private readonly api: TsbApiService, + ) {} public buildOrgRulerColumn(ref: IEntity): IEntityColumn { const provider = ref.GetFkCandidateProvider().getProviderItem('UID_OrgRuler', 'AERole'); return this.entityService.createLocalEntityColumn( this.api.typedClient.PortalTargetsystemUnsGroupServiceitem.GetSchema().Columns.UID_OrgRuler, - [provider] + provider ? [provider] : undefined, ); } - } diff --git a/imxweb/projects/tsb/src/lib/guards/tsb-namespace-admin-guard.service.ts b/imxweb/projects/tsb/src/lib/guards/tsb-namespace-admin-guard.service.ts index 3ee6a4071..54f4bd4bc 100644 --- a/imxweb/projects/tsb/src/lib/guards/tsb-namespace-admin-guard.service.ts +++ b/imxweb/projects/tsb/src/lib/guards/tsb-namespace-admin-guard.service.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -25,7 +25,7 @@ */ import { Injectable, OnDestroy } from '@angular/core'; -import { CanActivate, ActivatedRouteSnapshot, RouterStateSnapshot, Router } from '@angular/router'; +import { ActivatedRouteSnapshot, Router, RouterStateSnapshot } from '@angular/router'; import { Observable, Subscription } from 'rxjs'; import { AppConfigService, AuthenticationService, ISessionState } from 'qbm'; @@ -34,25 +34,25 @@ import { TsbPermissionsService } from '../admin/tsb-permissions.service'; @Injectable({ providedIn: 'root', }) -export class TsbNamespaceAdminGuardService implements CanActivate, OnDestroy { +export class TsbNamespaceAdminGuardService implements OnDestroy { private onSessionResponse: Subscription; constructor( private readonly authentication: AuthenticationService, private readonly permissionService: TsbPermissionsService, private readonly appConfig: AppConfigService, - private readonly router: Router - ) { } + private readonly router: Router, + ) {} public canActivate(route: ActivatedRouteSnapshot, _: RouterStateSnapshot): Observable { return new Observable((observer) => { this.onSessionResponse = this.authentication.onSessionResponse.subscribe(async (sessionState: ISessionState) => { if (sessionState.IsLoggedIn) { // TODO Later: Berechtigungen sind noch nicht genau genug, non-admin-Pages lassen sich im Moment immer ansteuern - const navigateToAdmin = route.url[0].path === 'admin'; + const navigateToAdmin = route.url[0].path === 'admin'; const userIsAdmin = await this.permissionService.isTsbNameSpaceAdminBase(); if (navigateToAdmin && !userIsAdmin) { - this.router.navigate([this.appConfig.Config.routeConfig.start], { queryParams: {} }); + this.router.navigate([this.appConfig.Config?.routeConfig?.start], { queryParams: {} }); } observer.next(!navigateToAdmin || userIsAdmin); diff --git a/imxweb/projects/tsb/src/lib/init.service.ts b/imxweb/projects/tsb/src/lib/init.service.ts index b94eac55e..479937b53 100644 --- a/imxweb/projects/tsb/src/lib/init.service.ts +++ b/imxweb/projects/tsb/src/lib/init.service.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -28,8 +28,9 @@ import { Injectable } from '@angular/core'; import { Route, Router } from '@angular/router'; import { Subscription } from 'rxjs'; -import { UnsConfig } from 'imx-api-tsb'; -import { CachedPromise } from 'imx-qbm-dbts'; +import { ProjectConfig } from '@imx-modules/imx-api-qbm'; +import { UnsConfig } from '@imx-modules/imx-api-tsb'; +import { CachedPromise } from '@imx-modules/imx-qbm-dbts'; import { AuthenticationService, CacheService, @@ -38,7 +39,7 @@ import { HELP_CONTEXTUAL, ISessionState, MenuService, - TabItem + TabItem, } from 'qbm'; import { DataExplorerRegistryService, @@ -51,11 +52,10 @@ import { import { AccountsExtComponent } from './accounts/account-ext/accounts-ext.component'; import { DataExplorerAccountsComponent } from './accounts/accounts.component'; import { isTsbNameSpaceAdminBase } from './admin/tsb-permissions-helper'; +import { GroupMembershipsExtComponent } from './groups/group-memberships-ext/group-memberships-ext.component'; import { DataExplorerGroupsComponent } from './groups/groups.component'; import { ReportButtonExtComponent } from './report-button-ext/report-button-ext.component'; import { TsbApiService } from './tsb-api-client.service'; -import { GroupMembershipsExtComponent } from './groups/group-memberships-ext/group-memberships-ext.component'; -import { ProjectConfig } from 'imx-api-qbm'; @Injectable({ providedIn: 'root' }) export class InitService { @@ -73,7 +73,7 @@ export class InitService { private readonly extService: ExtService, private readonly cacheService: CacheService, private readonly myResponsibilitiesRegistryService: MyResponsibilitiesRegistryService, - private readonly permissions: QerPermissionsService + private readonly permissions: QerPermissionsService, ) {} public ngOnDestroy(): void { @@ -87,12 +87,12 @@ export class InitService { this.onSessionResponse = this.authentication.onSessionResponse.subscribe(async (sessionState: ISessionState) => { if (sessionState.IsLoggedIn) { - if(await this.permissions.isPersonManager()){ + if (await this.permissions.isPersonManager()) { this.extService.register('identityReportsManager', { instance: ReportButtonExtComponent, inputData: { - caption: '#LDS#Download report on user accounts of identities you are directly responsible for' - } + caption: '#LDS#View user accounts of identities you are directly responsible for', + }, }); } } @@ -107,16 +107,15 @@ export class InitService { sortOrder: 10, } as TabItem); - this.extService.register('identityAssignment', { - instance: GroupMembershipsExtComponent, - inputData: { - id: 'groups', - label: '#LDS#System entitlements', - checkVisibility: async (_) => true, - }, - sortOrder: 10, - } as TabItem); - + this.extService.register('identityAssignment', { + instance: GroupMembershipsExtComponent, + inputData: { + id: 'groups', + label: '#LDS#System entitlements', + checkVisibility: async (_) => true, + }, + sortOrder: 10, + } as TabItem); this.addRoutes(routes); this.setupMenu(); @@ -146,9 +145,9 @@ export class InitService { name: 'groups', caption: '#LDS#System entitlements', icon: 'usergroup', - contextId: HELP_CONTEXTUAL.DataExplorerGroups + contextId: HELP_CONTEXTUAL.DataExplorerGroups, }; - } + }, ); this.entlTypeService.Register(async () => [ @@ -160,17 +159,27 @@ export class InitService { name: 'UNSGroup', caption: '#LDS#System entitlements', icon: 'usergroup', - contextId: HELP_CONTEXTUAL.MyResponsibilitiesGroups + contextId: HELP_CONTEXTUAL.MyResponsibilitiesGroups, })); } private async loadUnsTypes(): Promise { const config = await this.cachedUnsConfig.get(); const types: IRequestableEntitlementType[] = []; + if (!config.ShopAssign) { + return types; + } for (const key of Object.keys(config.ShopAssign)) { - types.push( - new RequestableEntitlementType(key, this.tsbApiService.apiClient, config.ShopAssign[key].GroupColumnName, this.dynamicMethodService) - ); + if (config.ShopAssign[key]?.GroupColumnName) { + types.push( + new RequestableEntitlementType( + key, + this.tsbApiService.apiClient, + config.ShopAssign[key].GroupColumnName!, + this.dynamicMethodService, + ), + ); + } } return types; } @@ -187,7 +196,7 @@ export class InitService { this.menuService.addMenuFactories( (preProps: string[], __: string[]) => { if (!preProps.includes('ITSHOP')) { - return null; + return undefined; } return { @@ -206,7 +215,7 @@ export class InitService { }, (preProps: string[], features: string[], projectConfig: ProjectConfig, groups: string[]) => { if (!preProps.includes('ITSHOP') || !isTsbNameSpaceAdminBase(groups)) { - return null; + return undefined; } return { @@ -222,7 +231,7 @@ export class InitService { }, ], }; - } + }, ); } } diff --git a/imxweb/projects/tsb/src/lib/no-data/no-data.component.html b/imxweb/projects/tsb/src/lib/no-data/no-data.component.html index 8af2d414f..d0b294b45 100644 --- a/imxweb/projects/tsb/src/lib/no-data/no-data.component.html +++ b/imxweb/projects/tsb/src/lib/no-data/no-data.component.html @@ -1,12 +1,12 @@
    - -

    #LDS#Heading No Synchronization Configured

    + +

    #LDS#Heading No Synchronization Configured

    #LDS#Please configure a synchronization using the Synchronization Editor.

    - -

    #LDS#Heading No Data Synchronized

    + +

    #LDS#Heading No Data Synchronized

    #LDS#A synchronization has been configured in the Synchronization Editor, but not run yet.

    -
    \ No newline at end of file +
    diff --git a/imxweb/projects/tsb/src/lib/no-data/no-data.component.scss b/imxweb/projects/tsb/src/lib/no-data/no-data.component.scss index e298c049a..1e2aead52 100644 --- a/imxweb/projects/tsb/src/lib/no-data/no-data.component.scss +++ b/imxweb/projects/tsb/src/lib/no-data/no-data.component.scss @@ -1,4 +1,4 @@ -@import '@elemental-ui/core/src/styles/_palette.scss'; +@import '@elemental-ui/core/src/styles/_eui_palette.scss'; .data-explorer-sync-status { height: 100%; @@ -14,12 +14,11 @@ } .eui-icon { - font-size: 150px; - color: $black-9; + color: $color-gray-40; margin-bottom: 30px; } - h1 { + h2 { font-size: 32px; font-weight: 400; } @@ -28,6 +27,6 @@ font-size: 18px; margin-top: 10px; margin-bottom: 75px; - color: $black-9; + color: $color-gray-40; } } diff --git a/imxweb/projects/tsb/src/lib/no-data/no-data.component.ts b/imxweb/projects/tsb/src/lib/no-data/no-data.component.ts index 02cb8b589..edfa98766 100644 --- a/imxweb/projects/tsb/src/lib/no-data/no-data.component.ts +++ b/imxweb/projects/tsb/src/lib/no-data/no-data.component.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR diff --git a/imxweb/projects/tsb/src/lib/no-data/no-data.module.ts b/imxweb/projects/tsb/src/lib/no-data/no-data.module.ts index 7353dda03..0708e80c3 100644 --- a/imxweb/projects/tsb/src/lib/no-data/no-data.module.ts +++ b/imxweb/projects/tsb/src/lib/no-data/no-data.module.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -24,7 +24,6 @@ * */ - import { NgModule } from '@angular/core'; import { CommonModule } from '@angular/common'; import { EuiCoreModule } from '@elemental-ui/core'; @@ -33,16 +32,8 @@ import { TranslateModule } from '@ngx-translate/core'; import { DataExplorerNoDataComponent } from './no-data.component'; @NgModule({ - declarations: [ - DataExplorerNoDataComponent - ], - exports: [ - DataExplorerNoDataComponent - ], - imports: [ - CommonModule, - EuiCoreModule, - TranslateModule - ] + declarations: [DataExplorerNoDataComponent], + exports: [DataExplorerNoDataComponent], + imports: [CommonModule, EuiCoreModule, TranslateModule], }) -export class NoDataModule { } +export class NoDataModule {} diff --git a/imxweb/projects/tsb/src/lib/report-button-ext/report-button-ext.component.html b/imxweb/projects/tsb/src/lib/report-button-ext/report-button-ext.component.html index 1dc62b5f7..518e5a206 100644 --- a/imxweb/projects/tsb/src/lib/report-button-ext/report-button-ext.component.html +++ b/imxweb/projects/tsb/src/lib/report-button-ext/report-button-ext.component.html @@ -1,3 +1,3 @@ diff --git a/imxweb/projects/tsb/src/lib/report-button-ext/report-button-ext.component.scss b/imxweb/projects/tsb/src/lib/report-button-ext/report-button-ext.component.scss index e110d11b2..248a268c5 100644 --- a/imxweb/projects/tsb/src/lib/report-button-ext/report-button-ext.component.scss +++ b/imxweb/projects/tsb/src/lib/report-button-ext/report-button-ext.component.scss @@ -1 +1 @@ -// add styles if necessary \ No newline at end of file +// add styles if necessary diff --git a/imxweb/projects/tsb/src/lib/report-button-ext/report-button-ext.component.ts b/imxweb/projects/tsb/src/lib/report-button-ext/report-button-ext.component.ts index 989790196..2b3d52b72 100644 --- a/imxweb/projects/tsb/src/lib/report-button-ext/report-button-ext.component.ts +++ b/imxweb/projects/tsb/src/lib/report-button-ext/report-button-ext.component.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -24,19 +24,18 @@ * */ -import { Component, Injector, OnInit } from '@angular/core'; -import { EuiDownloadDirective, EuiDownloadOptions } from '@elemental-ui/core'; +import { Component, ElementRef, Injector, OnInit } from '@angular/core'; +import { EuiDownloadDirective, EuiDownloadOptions, EuiDownloadService } from '@elemental-ui/core'; +import { Overlay } from '@angular/cdk/overlay'; +import { HttpClient } from '@angular/common/http'; import { ElementalUiConfigService } from 'qbm'; -import { QerPermissionsService } from 'qer'; import { AccountsReportsService } from '../accounts/accounts-reports.service'; -import { HttpClient } from '@angular/common/http'; -import { Overlay } from '@angular/cdk/overlay'; @Component({ selector: 'imx-report-button-ext', templateUrl: './report-button-ext.component.html', - styleUrls: ['./report-button-ext.component.scss'] + styleUrls: ['./report-button-ext.component.scss'], }) export class ReportButtonExtComponent implements OnInit { public downloadOptions: EuiDownloadOptions; @@ -50,20 +49,26 @@ export class ReportButtonExtComponent implements OnInit { private readonly http: HttpClient, private readonly injector: Injector, private readonly overlay: Overlay, - - ) { } + private readonly downloadService: EuiDownloadService, + ) {} public async ngOnInit(): Promise { const url = this.service.accountsOwnedByManagedReport(30, this.referrer); this.downloadOptions = { ...this.elementalUiConfigService.Config.downloadOptions, - url + url, }; } - public viewReport():void{ - const directive = new EuiDownloadDirective(null, this.http, this.overlay, this.injector); + public viewReport(): void { + const directive = new EuiDownloadDirective( + new ElementRef('') /* no element */, + this.http, + this.overlay, + this.injector, + this.downloadService, + ); directive.downloadOptions = { ...this.downloadOptions, disableElement: false, diff --git a/imxweb/projects/tsb/src/lib/report-button-ext/report-button-ext.module.ts b/imxweb/projects/tsb/src/lib/report-button-ext/report-button-ext.module.ts index 85e6322dc..ba8b4614e 100644 --- a/imxweb/projects/tsb/src/lib/report-button-ext/report-button-ext.module.ts +++ b/imxweb/projects/tsb/src/lib/report-button-ext/report-button-ext.module.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -33,12 +33,7 @@ import { TranslateModule } from '@ngx-translate/core'; import { ReportButtonExtComponent } from './report-button-ext.component'; @NgModule({ declarations: [ReportButtonExtComponent], - imports: [ - CommonModule, - MatMenuModule, - EuiCoreModule, - TranslateModule - ], - exports: [ReportButtonExtComponent] + imports: [CommonModule, MatMenuModule, EuiCoreModule, TranslateModule], + exports: [ReportButtonExtComponent], }) -export class ReportButtonExtModule { } +export class ReportButtonExtModule {} diff --git a/imxweb/projects/tsb/src/lib/target-system/db-object-key-wrapper.interface.ts b/imxweb/projects/tsb/src/lib/target-system/db-object-key-wrapper.interface.ts index d2a406628..b4725c516 100644 --- a/imxweb/projects/tsb/src/lib/target-system/db-object-key-wrapper.interface.ts +++ b/imxweb/projects/tsb/src/lib/target-system/db-object-key-wrapper.interface.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -24,9 +24,9 @@ * */ -import { DbObjectKey } from 'imx-qbm-dbts'; +import { DbObjectKey } from '@imx-modules/imx-qbm-dbts'; -export type DbObjectKeyBase = { TableName: string; Keys: ReadonlyArray; } | DbObjectKey; +export type DbObjectKeyBase = { TableName: string; Keys: ReadonlyArray } | DbObjectKey; export interface DbObjectKeyWrapper { dbObjectKey: DbObjectKeyBase; diff --git a/imxweb/projects/tsb/src/lib/target-system/path-parameter-wrapper.ts b/imxweb/projects/tsb/src/lib/target-system/path-parameter-wrapper.ts index ba160cd86..d7f586e51 100644 --- a/imxweb/projects/tsb/src/lib/target-system/path-parameter-wrapper.ts +++ b/imxweb/projects/tsb/src/lib/target-system/path-parameter-wrapper.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR diff --git a/imxweb/projects/tsb/src/lib/target-system/target-system-dynamic-method.service.ts b/imxweb/projects/tsb/src/lib/target-system/target-system-dynamic-method.service.ts index 14608d2be..9774239bd 100644 --- a/imxweb/projects/tsb/src/lib/target-system/target-system-dynamic-method.service.ts +++ b/imxweb/projects/tsb/src/lib/target-system/target-system-dynamic-method.service.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -26,26 +26,26 @@ import { Injectable } from '@angular/core'; -import { CompareOperator, ExtendedTypedEntityCollection, FilterType, IEntity, TypedEntity } from 'imx-qbm-dbts'; +import { CompareOperator, ExtendedTypedEntityCollection, FilterType, IEntity, TypedEntity } from '@imx-modules/imx-qbm-dbts'; import { DynamicCollectionLoadParameters, DynamicMethodService, MetadataService } from 'qbm'; import { TsbApiService } from '../tsb-api-client.service'; import { DbObjectKeyWrapper } from './db-object-key-wrapper.interface'; import { PathParameterWrapper } from './path-parameter-wrapper'; @Injectable({ - providedIn: 'root' + providedIn: 'root', }) export class TargetSystemDynamicMethodService { constructor( private readonly tsbClient: TsbApiService, private readonly dynamicMethod: DynamicMethodService, - private readonly metadata: MetadataService - ) { } + private readonly metadata: MetadataService, + ) {} public async getCollection( type: new (e: IEntity) => TEntity, tableName: string, - parameters: DynamicCollectionLoadParameters = {} + parameters: DynamicCollectionLoadParameters = {}, ): Promise> { const path = '/portal/targetsystem/' + tableName; return this.dynamicMethod.get(this.tsbClient.apiClient, { type, path }, parameters); @@ -53,35 +53,42 @@ export class TargetSystemDynamicMethodService { public async getById( type: new (e: IEntity) => TEntity, - dbObjectKeyWrapper: DbObjectKeyWrapper + dbObjectKeyWrapper: DbObjectKeyWrapper, ): Promise { const key = dbObjectKeyWrapper.dbObjectKey.Keys[0]; const tableName = dbObjectKeyWrapper.dbObjectKey.TableName.toLowerCase(); const path = '/portal/targetsystem/' + tableName + '/interactive'; - return (await this.dynamicMethod.getInteractive(this.tsbClient.apiClient, { type, key, path }, { - name: dbObjectKeyWrapper.columnName, value: key - })).Data[0]; + return ( + await this.dynamicMethod.getInteractive( + this.tsbClient.apiClient, + { type, key, path }, + { + name: dbObjectKeyWrapper.columnName!, + value: key, + }, + ) + ).Data[0]; } public async get( type: new (e: IEntity) => TEntity, - dbObjectKeyWrapper: DbObjectKeyWrapper + dbObjectKeyWrapper: DbObjectKeyWrapper, ): Promise { await this.metadata.updateNonExisting([dbObjectKeyWrapper.dbObjectKey.TableName]); const tableMetadata = this.metadata.tables[dbObjectKeyWrapper.dbObjectKey.TableName]; - const filter = [{ - ColumnName: dbObjectKeyWrapper.columnName ?? tableMetadata.PrimaryKeyColumns[0], - Type: FilterType.Compare, - CompareOp: CompareOperator.Equal, - Value1: dbObjectKeyWrapper.dbObjectKey.Keys[0] - }]; + const filter = [ + { + ColumnName: dbObjectKeyWrapper.columnName ?? tableMetadata?.PrimaryKeyColumns?.[0] ?? '', + Type: FilterType.Compare, + CompareOp: CompareOperator.Equal, + Value1: dbObjectKeyWrapper.dbObjectKey.Keys[0], + }, + ]; - return (await this.getCollection( - type, dbObjectKeyWrapper.dbObjectKey.TableName, { filter } - ))?.Data[0]; + return (await this.getCollection(type, dbObjectKeyWrapper.dbObjectKey.TableName, { filter }))?.Data[0]; } public async delete(tableName: string, pathParameterWrapper: PathParameterWrapper): Promise { diff --git a/imxweb/projects/tsb/src/lib/target-system/target-system.service.ts b/imxweb/projects/tsb/src/lib/target-system/target-system.service.ts index ad0fbfba9..d6e0e934e 100644 --- a/imxweb/projects/tsb/src/lib/target-system/target-system.service.ts +++ b/imxweb/projects/tsb/src/lib/target-system/target-system.service.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -26,14 +26,14 @@ import { Injectable } from '@angular/core'; -import { TsbUserConfig } from 'imx-api-tsb'; +import { TsbUserConfig } from '@imx-modules/imx-api-tsb'; import { TsbApiService } from '../tsb-api-client.service'; @Injectable({ - providedIn: 'root' + providedIn: 'root', }) export class TargetSystemService { - constructor(private readonly apiService: TsbApiService) { } + constructor(private readonly apiService: TsbApiService) {} public async getUserConfig(): Promise { return this.apiService.client.portal_targetsystem_userconfig_get(); diff --git a/imxweb/projects/tsb/src/lib/test/common-test-mocks.spec.ts b/imxweb/projects/tsb/src/lib/test/common-test-mocks.spec.ts index 35a577398..531c03138 100644 --- a/imxweb/projects/tsb/src/lib/test/common-test-mocks.spec.ts +++ b/imxweb/projects/tsb/src/lib/test/common-test-mocks.spec.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -24,96 +24,93 @@ * */ -import { IEntityColumn, IEntity } from 'imx-qbm-dbts'; +import { IEntityColumn, IEntity } from '@imx-modules/imx-qbm-dbts'; import { ISessionState } from 'qbm'; import { Subject } from 'rxjs'; export class TsbCommonTestData { - public static mockConfigService: any = { getConfig: () => { return Promise.resolve({ PersonConfig: { VI_MyData_WhitePages_ResultAttributes: { - Columns: ['col1', 'col2'] + Columns: ['col1', 'col2'], }, VI_PersonalData_Fields: { - Columns: ['col1', 'col2'] - } - } + Columns: ['col1', 'col2'], + }, + }, }); - } + }, }; public static mockAppConfigService: any = { Config: { Title: '', routeConfig: { - start: 'dashboard' - } + start: 'dashboard', + }, }, client: { imx_multilanguage_getcaptions_get: () => Promise.resolve({}), - imx_multilanguage_translations_get: () => Promise.resolve({}) - } + imx_multilanguage_translations_get: () => Promise.resolve({}), + }, }; public static mockAuthenticationServiceStub = { onSessionResponse: new Subject(), - update: jasmine.createSpy('update') + update: jasmine.createSpy('update'), }; public static mockSessionService: any = { TypedClient: { PortalTargetsystemUnsGroup: { - Get: () => Promise.resolve({}) + Get: () => Promise.resolve({}), }, PortalTargetsystemUnsAccount: { - Get: () => Promise.resolve({}) + Get: () => Promise.resolve({}), }, PortalPersonAll: { - Get: () => Promise.resolve({}) + Get: () => Promise.resolve({}), }, PortalAdminPerson: { - Get: () => Promise.resolve({}) + Get: () => Promise.resolve({}), }, PortalPerson: { - Get: () => Promise.resolve({Data: ['test1', 'test2']}) + Get: () => Promise.resolve({ Data: ['test1', 'test2'] }), }, - } + }, }; public static mockEntityColumn = { ColumnName: '', GetMetadata: () => { return { - CanEdit: () => false, + CanEdit: () => false, GetDisplay: () => '', - GetMinLength: () => 0 + GetMinLength: () => 0, }; }, GetDisplayValue: () => '', - GetValue: () => '', - PutValue: _ => {}, - + GetValue: () => '', + PutValue: (_) => {}, } as IEntityColumn; public static mockEntityColumnWithValue = { ColumnName: '', GetMetadata: () => { return { - CanEdit: () => false, + CanEdit: () => false, GetDisplay: () => '', - GetMinLength: () => 0 + GetMinLength: () => 0, }; }, - GetValue: () => 'Test value 1' - + GetValue: () => 'Test value 1', } as IEntityColumn; public static mockEntity = { GetDisplay: () => 'Display value', GetKeys: () => ['1'], - GetColumn: (name) => TsbCommonTestData.mockEntityColumn + GetColumn: (name) => TsbCommonTestData.mockEntityColumn, } as IEntity; } diff --git a/imxweb/projects/tsb/src/lib/tsb-api-client.service.ts b/imxweb/projects/tsb/src/lib/tsb-api-client.service.ts index e8d8d8f73..d0d149543 100644 --- a/imxweb/projects/tsb/src/lib/tsb-api-client.service.ts +++ b/imxweb/projects/tsb/src/lib/tsb-api-client.service.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -25,12 +25,12 @@ */ import { Injectable } from '@angular/core'; -import { V2Client, TypedClient } from 'imx-api-tsb'; -import { ApiClient } from 'imx-qbm-dbts'; +import { V2Client, TypedClient } from '@imx-modules/imx-api-tsb'; +import { ApiClient } from '@imx-modules/imx-qbm-dbts'; import { AppConfigService, ClassloggerService, ImxTranslationProviderService } from 'qbm'; @Injectable({ - providedIn: 'root' + providedIn: 'root', }) export class TsbApiService { private tc: TypedClient; @@ -50,7 +50,8 @@ export class TsbApiService { constructor( private readonly config: AppConfigService, private readonly logger: ClassloggerService, - private readonly translationProvider: ImxTranslationProviderService) { + private readonly translationProvider: ImxTranslationProviderService, + ) { try { this.logger.debug(this, 'Initializing TSB API service'); diff --git a/imxweb/projects/tsb/src/lib/tsb-config.module.ts b/imxweb/projects/tsb/src/lib/tsb-config.module.ts index 053a6d115..76cf6464c 100644 --- a/imxweb/projects/tsb/src/lib/tsb-config.module.ts +++ b/imxweb/projects/tsb/src/lib/tsb-config.module.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -46,21 +46,20 @@ const routes: Routes = [ path: 'claimgroup', component: ClaimGroupComponent, canActivate: [RouteGuardService], - data:{ - contextId: HELP_CONTEXTUAL.ClaimGroup - } + data: { + contextId: HELP_CONTEXTUAL.ClaimGroup, + }, }, { path: 'resp/UNSGroup', component: DataExplorerGroupsComponent, canActivate: [RouteGuardService], - resolve: [RouteGuardService] - } + resolve: [RouteGuardService], + }, ]; @NgModule({ - declarations: [ - ], + declarations: [], imports: [ AccountsModule, BusinessownerAddonTileModule, @@ -73,11 +72,9 @@ const routes: Routes = [ MatListModule, TileModule, TranslateModule, - ReportButtonExtModule + ReportButtonExtModule, ], - providers: [ - TsbNamespaceAdminGuardService - ] + providers: [TsbNamespaceAdminGuardService], }) export class TsbConfigModule { constructor(private readonly initializer: InitService) { diff --git a/imxweb/projects/tsb/src/public_api.ts b/imxweb/projects/tsb/src/public_api.ts index de3cc8424..01bf56b81 100644 --- a/imxweb/projects/tsb/src/public_api.ts +++ b/imxweb/projects/tsb/src/public_api.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR diff --git a/imxweb/projects/tsb/src/test.ts b/imxweb/projects/tsb/src/test.ts index 8a6ea30b8..e07515d40 100644 --- a/imxweb/projects/tsb/src/test.ts +++ b/imxweb/projects/tsb/src/test.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -26,27 +26,16 @@ // This file is required by karma.conf.js and loads recursively all the .spec and framework files -import 'core-js/es7/reflect'; -import 'zone.js/dist/zone'; -import 'zone.js/dist/zone-testing'; +// Zone must be imported first. Be careful with prettier import organizing +import 'zone.js'; +import 'zone.js/testing'; + import { getTestBed } from '@angular/core/testing'; -import { - BrowserDynamicTestingModule, - platformBrowserDynamicTesting -} from '@angular/platform-browser-dynamic/testing'; +import { BrowserDynamicTestingModule, platformBrowserDynamicTesting } from '@angular/platform-browser-dynamic/testing'; +import 'core-js/es/reflect'; import { TestHelperModule } from 'qbm'; -declare const require: any; - // First, initialize the Angular testing environment. -getTestBed().initTestEnvironment( - [BrowserDynamicTestingModule, TestHelperModule], - platformBrowserDynamicTesting(), - { - teardown: { destroyAfterEach: false } - } -); -// Then we find all the tests. -const context = require.context('./', true, /\.spec\.ts$/); -// And load the modules. -context.keys().map(context); +getTestBed().initTestEnvironment([BrowserDynamicTestingModule, TestHelperModule], platformBrowserDynamicTesting(), { + teardown: { destroyAfterEach: false }, +}); diff --git a/imxweb/projects/tsb/tsconfig.lib.json b/imxweb/projects/tsb/tsconfig.lib.json index 6bc419f84..534c734a0 100644 --- a/imxweb/projects/tsb/tsconfig.lib.json +++ b/imxweb/projects/tsb/tsconfig.lib.json @@ -1,16 +1,17 @@ /* To learn more about this file see: https://angular.io/config/tsconfig. */ { "extends": "../../tsconfig.json", + "angularCompilerOptions": { + "strictTemplates": true + }, "compilerOptions": { "outDir": "../../out-tsc/lib", + "strictNullChecks": true, "declaration": true, "declarationMap": true, "sourceMap": true, "inlineSources": true, "types": [] }, - "exclude": [ - "src/test.ts", - "**/*.spec.ts" - ] + "exclude": ["src/test.ts", "**/*.spec.ts"] } diff --git a/imxweb/projects/tsb/tsconfig.lib.prod.json b/imxweb/projects/tsb/tsconfig.lib.prod.json index 61c7592e7..fb40dbbb0 100644 --- a/imxweb/projects/tsb/tsconfig.lib.prod.json +++ b/imxweb/projects/tsb/tsconfig.lib.prod.json @@ -3,8 +3,5 @@ "extends": "./tsconfig.lib.json", "compilerOptions": { "declarationMap": false - }, - "angularCompilerOptions": { - "enableIvy": true } } diff --git a/imxweb/projects/tsb/tsconfig.spec.json b/imxweb/projects/tsb/tsconfig.spec.json index 16da33db0..6bd74e1f7 100644 --- a/imxweb/projects/tsb/tsconfig.spec.json +++ b/imxweb/projects/tsb/tsconfig.spec.json @@ -1,17 +1,10 @@ { "extends": "../../tsconfig.json", "compilerOptions": { + "strictNullChecks": false, "outDir": "../../out-tsc/spec", - "types": [ - "jasmine", - "node" - ] + "types": ["jasmine", "node"] }, - "files": [ - "src/test.ts" - ], - "include": [ - "**/*.spec.ts", - "**/*.d.ts" - ] + "files": ["src/test.ts"], + "include": ["**/*.spec.ts", "**/*.d.ts"] } diff --git a/imxweb/projects/tsb/tslint.json b/imxweb/projects/tsb/tslint.json deleted file mode 100644 index 8bab15f53..000000000 --- a/imxweb/projects/tsb/tslint.json +++ /dev/null @@ -1,17 +0,0 @@ -{ - "extends": "../../tslint.json", - "rules": { - "directive-selector": [ - true, - "attribute", - "imx", - "camelCase" - ], - "component-selector": [ - true, - "element", - "imx", - "kebab-case" - ] - } -} diff --git a/imxweb/projects/uci/.compodocrc.json b/imxweb/projects/uci/.compodocrc.json index 235acc0e1..98cc812db 100644 --- a/imxweb/projects/uci/.compodocrc.json +++ b/imxweb/projects/uci/.compodocrc.json @@ -1,6 +1,6 @@ { "name": "IMX Web - UCI Library", - "output": "../../documentation/v92/uci", + "output": "../../documentation/v93/uci", "theme": "material", "assetsFolder": "../../compodoc/assets", "customLogo": "../../compodoc/assets/images/oneidentity-logo.png", diff --git a/imxweb/projects/uci/.eslintrc.json b/imxweb/projects/uci/.eslintrc.json new file mode 100644 index 000000000..23897dab8 --- /dev/null +++ b/imxweb/projects/uci/.eslintrc.json @@ -0,0 +1,35 @@ +{ + "extends": "../../.eslintrc.json", + "ignorePatterns": ["!**/*", "**/*.spec.ts"], + "overrides": [ + { + "files": ["*.ts"], + "parserOptions": { + "project": ["imxweb/projects/uci/tsconfig.lib.json", "imxweb/projects/uci/tsconfig.spec.json"], + "createDefaultProgram": true + }, + "rules": { + "@angular-eslint/directive-selector": [ + "error", + { + "type": "attribute", + "prefix": "imx", + "style": "camelCase" + } + ], + "@angular-eslint/component-selector": [ + "error", + { + "type": "element", + "prefix": "imx", + "style": "kebab-case" + } + ] + } + }, + { + "files": ["*.html"], + "rules": {} + } + ] +} diff --git a/imxweb/projects/uci/.vscode/settings.json b/imxweb/projects/uci/.vscode/settings.json index ed94f44b1..23830fb42 100644 --- a/imxweb/projects/uci/.vscode/settings.json +++ b/imxweb/projects/uci/.vscode/settings.json @@ -1,3 +1,3 @@ { "git.ignoreLimitWarning": true -} \ No newline at end of file +} diff --git a/imxweb/projects/uci/imx-plugin-config.json b/imxweb/projects/uci/imx-plugin-config.json index 2b08904c2..4da4a4d5c 100644 --- a/imxweb/projects/uci/imx-plugin-config.json +++ b/imxweb/projects/uci/imx-plugin-config.json @@ -1,8 +1,8 @@ { "qer-app-operationssupport": [ - { - "Container": "uci", - "Name": "UciConfigModule" - } + { + "Container": "uci", + "Name": "UciConfigModule" + } ] } diff --git a/imxweb/projects/uci/karma.conf.js b/imxweb/projects/uci/karma.conf.js index 211193c9d..3e53a3ac8 100644 --- a/imxweb/projects/uci/karma.conf.js +++ b/imxweb/projects/uci/karma.conf.js @@ -15,7 +15,7 @@ module.exports = function (config) { require('karma-junit-reporter'), ], client: { - clearContext: false // leave Jasmine Spec Runner output visible in browser + clearContext: false, // leave Jasmine Spec Runner output visible in browser }, coverageIstanbulReporter: { dir: require('path').join(__dirname, 'results'), @@ -23,7 +23,7 @@ module.exports = function (config) { fixWebpackSourcePaths: true, 'report-config': { html: { - subdir: 'coverage-html' + subdir: 'coverage-html', }, }, thresholds: { @@ -40,13 +40,14 @@ module.exports = function (config) { port: 9876, captureTimeout: 210000, browserDisconnectTolerance: 3, - browserDisconnectTimeout : 210000, - browserNoActivityTimeout : 210000, + browserDisconnectTimeout: 210000, + browserNoActivityTimeout: 210000, colors: true, logLevel: config.LOG_INFO, autoWatch: true, browsers: ['Chrome'], singleRun: false, - restartOnFileChange: true + failOnEmptyTestSuite: false, + restartOnFileChange: true, }); }; diff --git a/imxweb/projects/uci/ng-package.dynamic-ops.json b/imxweb/projects/uci/ng-package.dynamic-ops.json new file mode 100644 index 000000000..f0dd7ead5 --- /dev/null +++ b/imxweb/projects/uci/ng-package.dynamic-ops.json @@ -0,0 +1,26 @@ +{ + "$schema": "../../node_modules/ng-packagr/ng-package.schema.json", + "allowedNonPeerDependencies": [ + "@angular/animations", + "@angular/cdk", + "@angular/common", + "@angular/compiler", + "@angular/core", + "@angular/forms", + "@angular/material", + "@angular/material-moment-adapter", + "@angular/platform-browser", + "@angular/platform-browser-dynamic", + "@angular/router", + "@elemental-ui/cadence-icon", + "@elemental-ui/core", + "@ngx-translate/core", + "@ngx-translate/http-loader", + "billboard.js" + ], + "dest": "../../html/qer-app-operationssupport/uci", + "lib": { + "entryFile": "src/public_api.ts", + "styleIncludePaths": ["../../shared/scss"] + } +} diff --git a/imxweb/projects/uci/ng-package.json b/imxweb/projects/uci/ng-package.json index 52dc5e513..6172a35c6 100644 --- a/imxweb/projects/uci/ng-package.json +++ b/imxweb/projects/uci/ng-package.json @@ -3,6 +3,6 @@ "dest": "../../dist/uci", "lib": { "entryFile": "src/public_api.ts", - "styleIncludePaths": ["../../shared/assets"] + "styleIncludePaths": ["../../shared/scss"] } } diff --git a/imxweb/projects/uci/package.json b/imxweb/projects/uci/package.json index 07b309c06..fb3b8ac0d 100644 --- a/imxweb/projects/uci/package.json +++ b/imxweb/projects/uci/package.json @@ -1,6 +1,6 @@ { "name": "uci", - "version": "9.2.1", + "version": "9.3.0", "private": true, "bundledDependencies": [ "imx-api-uci" diff --git a/imxweb/projects/uci/project.json b/imxweb/projects/uci/project.json new file mode 100644 index 000000000..e8a3ff980 --- /dev/null +++ b/imxweb/projects/uci/project.json @@ -0,0 +1,70 @@ +{ + "$schema": "../../node_modules/nx/schemas/project-schema.json", + "name": "uci", + "sourceRoot": "projects/uci/src", + "implicitDependencies": [ + "qer" + ], + "projectType": "library", + "prefix": "imx", + "targets": { + "build": { + "executor": "@angular-devkit/build-angular:ng-packagr", + "options": { + "tsConfig": "projects/uci/tsconfig.lib.json", + "project": "projects/uci/ng-package.json" + }, + "configurations": { + "production": { + "tsConfig": "projects/uci/tsconfig.lib.prod.json" + }, + "development": { + "tsConfig": "projects/uci/tsconfig.lib.json" + }, + "dynamic-ops": { + "project": "projects/uci/ng-package.dynamic-ops.json" + }, + "remote-dev": { + "tsConfig": "projects/uci/tsconfig.lib.json" + }, + "remote-qs": { + "tsConfig": "projects/uci/tsconfig.lib.json" + } + }, + "outputs": [ + "{workspaceRoot}/dist/uci" + ] + }, + "test": { + "executor": "@angular-devkit/build-angular:karma", + "options": { + "main": "projects/uci/src/test.ts", + "tsConfig": "projects/uci/tsconfig.spec.json", + "karmaConfig": "projects/uci/karma.conf.js", + "stylePreprocessorOptions": { + "includePaths": [ + "./shared/assets", + "./shared/scss", + "./node_modules", + "./node_modules/@elemental-ui/cadence-icon", + "./node_modules/@elemental-ui/core" + ] + } + } + }, + "lint": { + "executor": "@angular-devkit/build-angular:tslint", + "options": { + "tsConfig": [ + "projects/uci/tsconfig.lib.json", + "projects/uci/tsconfig.spec.json" + ], + "exclude": [ + "**/node_modules/**", + "**/*.spec.ts", + "**/*.json" + ] + } + } + } +} diff --git a/imxweb/projects/uci/src/lib/changeview/change-sidesheet.component.html b/imxweb/projects/uci/src/lib/changeview/change-sidesheet.component.html index b89ec20ca..c2514a805 100644 --- a/imxweb/projects/uci/src/lib/changeview/change-sidesheet.component.html +++ b/imxweb/projects/uci/src/lib/changeview/change-sidesheet.component.html @@ -4,25 +4,28 @@

    {{ '#LDS#Heading Requested Operation' | translate }} ({{ idx + 1 }}/{{ changeDetail.length }}) - {{ '#LDS#Successful' | translate }} - {{ '#LDS#Pending' | translate }} - {{ '#LDS#Failed' | translate }} + {{ '#LDS#Successful' | translate }} + {{ '#LDS#Pending' | translate }} + {{ '#LDS#Failed' | translate }}

    - + {{ - '#LDS#Here you can see the details of the provisioning process. Additionally, you can change the status of the provisioning process if creating the object in the cloud application was successful or failed.' | translate + '#LDS#Here you can see the details of the provisioning process. Additionally, you can change the status of the provisioning process if creating the object in the cloud application was successful or failed.' + | translate }} {{ - '#LDS#Here you can see the details of the provisioning process. Additionally, you can change the status of the provisioning process if deleting the object in the cloud application was successful or failed.' | translate + '#LDS#Here you can see the details of the provisioning process. Additionally, you can change the status of the provisioning process if deleting the object in the cloud application was successful or failed.' + | translate }} {{ - '#LDS#Here you can see the details of the provisioning process. Additionally, you can change the status of the provisioning process if changing the object in the cloud application was successful or failed.' | translate + '#LDS#Here you can see the details of the provisioning process. Additionally, you can change the status of the provisioning process if changing the object in the cloud application was successful or failed.' + | translate }} @@ -31,9 +34,13 @@

    -
    - - +
    + +
    diff --git a/imxweb/projects/uci/src/lib/changeview/change-sidesheet.component.scss b/imxweb/projects/uci/src/lib/changeview/change-sidesheet.component.scss index 6b6d143c5..e97ff8366 100644 --- a/imxweb/projects/uci/src/lib/changeview/change-sidesheet.component.scss +++ b/imxweb/projects/uci/src/lib/changeview/change-sidesheet.component.scss @@ -1,4 +1,4 @@ -@import "@elemental-ui/core/src/styles/_palette.scss"; +@import '@elemental-ui/core/src/styles/_palette.scss'; @import '@elemental-ui/core/src/styles/_eui_palette.scss'; :host { @@ -8,22 +8,10 @@ height: 100%; } -.mat-card { +.mat-mdc-card { margin-bottom: 10px; } -.imx-helper-alert { - margin: 10px 0 20px auto; - display: block; -} - -.state-badge { - vertical-align: middle; -} - -.button-bar button:not(:last-child) { - margin-right: 1em; -} .eui-dark-theme { :host { diff --git a/imxweb/projects/uci/src/lib/changeview/change-sidesheet.component.ts b/imxweb/projects/uci/src/lib/changeview/change-sidesheet.component.ts index 5b820e25f..8d084fa74 100644 --- a/imxweb/projects/uci/src/lib/changeview/change-sidesheet.component.ts +++ b/imxweb/projects/uci/src/lib/changeview/change-sidesheet.component.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -26,10 +26,10 @@ import { Component, Inject } from '@angular/core'; -import { EuiSidesheetRef, EUI_SIDESHEET_DATA } from '@elemental-ui/core'; +import { EUI_SIDESHEET_DATA, EuiSidesheetRef } from '@elemental-ui/core'; -import { ManualChangeOperation, ManualChangeOperationData, OpsupportUciChangedetail } from 'imx-api-uci'; -import { ExtendedTypedEntityCollection, IEntityColumn, LocalEntityColumn } from 'imx-qbm-dbts'; +import { ManualChangeOperation, ManualChangeOperationData, OpsupportUciChangedetail } from '@imx-modules/imx-api-uci'; +import { ExtendedTypedEntityCollection, IEntityColumn, LocalEntityColumn } from '@imx-modules/imx-qbm-dbts'; import { ConfirmationService } from 'qbm'; import { UciApiService } from '../uci-api-client.service'; @@ -46,17 +46,16 @@ export class ChangeSidesheetComponent { constructor( @Inject(EUI_SIDESHEET_DATA) change: ExtendedTypedEntityCollection, private readonly uciApi: UciApiService, - private readonly sidesheetRef: EuiSidesheetRef, - private readonly confirmation: ConfirmationService - ) { - + private readonly sidesheetRef: EuiSidesheetRef, + private readonly confirmation: ConfirmationService, + ) { this.changeDetail = change.Data; - this.manualChangeData = change.extendedData.Operations; + this.manualChangeData = change?.extendedData?.Operations ?? []; // build entity columns from extended data this.changeProperties = this.manualChangeData.map((d) => { return d.map((c) => { - const prop = new LocalEntityColumn(c.Property, null, null, { + const prop = new LocalEntityColumn(c.Property!, undefined, undefined, { Value: c.DiffValue, }); @@ -66,22 +65,27 @@ export class ChangeSidesheetComponent { } public async markAsDone(detail: OpsupportUciChangedetail): Promise { - if (await this.confirmation.confirm({ - Title: '#LDS#Heading Mark As Successful', - Message: '#LDS#The provisioning process will be marked as successful. Are you sure you have made the requested change in the cloud application?' - })) { + if ( + await this.confirmation.confirm({ + Title: '#LDS#Heading Mark As Successful', + Message: + '#LDS#The provisioning process will be marked as successful. Are you sure you have made the requested change in the cloud application?', + }) + ) { await this.save(detail, true); - }; - + } } public async markAsError(detail: OpsupportUciChangedetail): Promise { - if (await this.confirmation.confirm({ - Title: '#LDS#Heading Mark As Failed', - Message: '#LDS#The provisioning process will be marked as failed. Are you sure you cannot make the requested change in the cloud application?' - })) { + if ( + await this.confirmation.confirm({ + Title: '#LDS#Heading Mark As Failed', + Message: + '#LDS#The provisioning process will be marked as failed. Are you sure you cannot make the requested change in the cloud application?', + }) + ) { await this.save(detail, false); - }; + } } public canMarkAsDone(detail: OpsupportUciChangedetail): boolean { diff --git a/imxweb/projects/uci/src/lib/changeview/change-view.component.html b/imxweb/projects/uci/src/lib/changeview/change-view.component.html index 9ed784a5d..45e5a3087 100644 --- a/imxweb/projects/uci/src/lib/changeview/change-view.component.html +++ b/imxweb/projects/uci/src/lib/changeview/change-view.component.html @@ -1,40 +1,47 @@
    -

    - {{'#LDS#Heading Pending Provisioning Processes' | translate}} -

    +

    + {{ '#LDS#Heading Pending Provisioning Processes' | translate }} +

    - - - - - -
    {{ prod.ObjectKeyElement.Column.GetDisplayValue() }}
    -
    {{ getTableDisplay(prod) }}
    -
    -
    - - -
    - {{'#LDS#Successful' | translate }} - {{'#LDS#Pending' | translate }} - {{'#LDS#Failed' | translate }} -
    -
    -
    - - - - -
    - - -
    \ No newline at end of file + + + + + +
    {{ prod.ObjectKeyElement.Column.GetDisplayValue() }}
    +
    {{ getTableDisplay(prod) }}
    +
    +
    + + +
    + {{ '#LDS#Successful' | translate }} + {{ '#LDS#Pending' | translate }} + {{ '#LDS#Failed' | translate }} +
    +
    +
    + + +
    + + diff --git a/imxweb/projects/uci/src/lib/changeview/change-view.component.scss b/imxweb/projects/uci/src/lib/changeview/change-view.component.scss index 5f738d967..cf23f5a10 100644 --- a/imxweb/projects/uci/src/lib/changeview/change-view.component.scss +++ b/imxweb/projects/uci/src/lib/changeview/change-view.component.scss @@ -1,18 +1,10 @@ -@import "@elemental-ui/core/src/styles/_palette.scss"; +@import '@elemental-ui/core/src/styles/_palette.scss'; :host { display: flex; flex-direction: column; overflow: hidden; flex-grow: 1; - -} - -.imx-table-container { - flex: 1 1 auto; - display: flex; - flex-direction: column; - overflow: auto; } .subtitle { @@ -23,17 +15,12 @@ white-space: nowrap; } -.state-badge { - vertical-align: middle; -} - .imx-table-container, .imx-table-card { display: flex; flex-direction: column; overflow: hidden; height: inherit; - flex: 1 1 auto; + flex: 1 1 auto; margin: 2px; } - diff --git a/imxweb/projects/uci/src/lib/changeview/change-view.component.ts b/imxweb/projects/uci/src/lib/changeview/change-view.component.ts index 017da9598..1cf6a28ab 100644 --- a/imxweb/projects/uci/src/lib/changeview/change-view.component.ts +++ b/imxweb/projects/uci/src/lib/changeview/change-view.component.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -28,9 +28,16 @@ import { Component, OnInit } from '@angular/core'; import { EuiSidesheetService } from '@elemental-ui/core'; import { TranslateService } from '@ngx-translate/core'; -import { ManualChangeOperationData, OpsupportUciChangedetail, OpsupportUciChanges } from 'imx-api-uci'; -import { CollectionLoadParameters, DataModel, DbObjectKey, EntitySchema, ExtendedTypedEntityCollection, TypedEntity, ValType } from 'imx-qbm-dbts'; -import { DataSourceToolbarFilter, DataSourceToolbarSettings, DataSourceWrapper, MetadataService } from 'qbm'; +import { ManualChangeOperationData, OpsupportUciChangedetail, OpsupportUciChanges } from '@imx-modules/imx-api-uci'; +import { + CollectionLoadParameters, + DataModel, + DbObjectKey, + EntitySchema, + ExtendedTypedEntityCollection, + TypedEntity, +} from '@imx-modules/imx-qbm-dbts'; +import { calculateSidesheetWidth, DataSourceToolbarFilter, DataSourceToolbarSettings, DataSourceWrapper, MetadataService } from 'qbm'; import { UciApiService } from '../uci-api-client.service'; import { ChangeSidesheetComponent } from './change-sidesheet.component'; import { ChangeViewService } from './change-view.service'; @@ -42,95 +49,98 @@ import { ChangeViewService } from './change-view.service'; }) export class ChangeViewComponent implements OnInit { public dstWrapper: DataSourceWrapper; - public dstSettings: DataSourceToolbarSettings; - public selectedChange: OpsupportUciChanges; + public dstSettings: DataSourceToolbarSettings; + public selectedChange: OpsupportUciChanges; public entitySchema: EntitySchema; - private filterOptions: DataSourceToolbarFilter[] = []; + private filterOptions: DataSourceToolbarFilter[] = []; - constructor( + constructor( private readonly translator: TranslateService, - private readonly uciApi: UciApiService, - private readonly changeviewService: ChangeViewService, - private readonly sidesheet: EuiSidesheetService, - private readonly metadatasvc: MetadataService, - ) { + private readonly uciApi: UciApiService, + private readonly changeviewService: ChangeViewService, + private readonly sidesheet: EuiSidesheetService, + private readonly metadatasvc: MetadataService, + ) { this.entitySchema = this.uciApi.typedClient.OpsupportUciChanges.GetSchema(); - } - - public async ngOnInit(): Promise { - const dataModel = await this.getDataModel(); - this.filterOptions = dataModel.Filters; - - // set initial value for state =0 (only pending processes) - const idx = this.filterOptions.findIndex(elem => elem.Name === 'state'); - if (idx > -1) { - this.filterOptions[idx].InitialValue = '0'; - } - - this.dstWrapper = new DataSourceWrapper( - state => this.uciApi.typedClient.OpsupportUciChanges.Get(state), - [ - this.entitySchema.Columns.ObjectKeyElement, - this.entitySchema.Columns.IsProcessed, - this.entitySchema.Columns.UID_UCIRoot, - this.entitySchema.Columns.XDateInserted - ], - this.entitySchema, - { - dataModel: dataModel, - } - ); - - await this.getData({ state: '0' }); - } - - public async getData(newState?: CollectionLoadParameters & { state?: string }): Promise { - this.changeviewService.handleOpenLoader(); - try { - const s = await this.dstWrapper.getDstSettings(newState); - - for (var d of s.dataSource.Data) { - const tableName = DbObjectKey.FromXml(d.GetEntity().GetColumn('ObjectKeyElement').GetValue()).TableName; - await this.metadatasvc.updateNonExisting([tableName]); - } - - this.dstSettings = s; - } finally { - this.changeviewService.handleCloseLoader(); - } - } - - public getTableDisplay(d: TypedEntity) { - const tableName = DbObjectKey.FromXml(d.GetEntity().GetColumn('ObjectKeyElement').GetValue()).TableName; - return this.metadatasvc.tables[tableName].DisplaySingular; - } - - public async viewDetails(change: OpsupportUciChanges): Promise { - this.changeviewService.handleOpenLoader(); - var details: ExtendedTypedEntityCollection; - try { - const uidChange = change.GetEntity().GetKeys()[0]; - details = await this.uciApi.typedClient.OpsupportUciChangedetail.Get(uidChange); - } - finally { - this.changeviewService.handleCloseLoader(); - } - - const result = await this.sidesheet.open(ChangeSidesheetComponent, { - title: await this.translator.get('#LDS#Heading View Provisioning Process Details').toPromise(), - subTitle: change.ObjectKeyElement.Column.GetDisplayValue(), - padding: '0', - width: '600px', - testId: 'changeview-details-sidesheet', - data: details - }).afterClosed().toPromise(); - - if (result) { - this.getData(); - } - } - - public async getDataModel(): Promise { - return this.uciApi.client.opsupport_uci_changes_datamodel_get(); - } + } + + public async ngOnInit(): Promise { + const dataModel = await this.getDataModel(); + this.filterOptions = dataModel.Filters ?? []; + + // set initial value for state =0 (only pending processes) + const idx = this.filterOptions.findIndex((elem) => elem.Name === 'state'); + if (idx > -1) { + this.filterOptions[idx].InitialValue = '0'; + } + + this.dstWrapper = new DataSourceWrapper( + (state) => this.uciApi.typedClient.OpsupportUciChanges.Get(state), + [ + this.entitySchema.Columns.ObjectKeyElement, + this.entitySchema.Columns.IsProcessed, + this.entitySchema.Columns.UID_UCIRoot, + this.entitySchema.Columns.XDateInserted, + ], + this.entitySchema, + { + dataModel: dataModel, + }, + ); + + await this.getData({ state: '0' }); + } + + public async getData(newState?: CollectionLoadParameters & { state?: string }): Promise { + this.changeviewService.handleOpenLoader(); + try { + const settings = await this.dstWrapper.getDstSettings(newState); + + if (settings) { + for (var d of settings.dataSource?.Data ?? []) { + const tableName = DbObjectKey.FromXml(d.GetEntity().GetColumn('ObjectKeyElement').GetValue()).TableName; + await this.metadatasvc.updateNonExisting([tableName]); + } + this.dstSettings = settings; + } + } finally { + this.changeviewService.handleCloseLoader(); + } + } + + public getTableDisplay(d: TypedEntity) { + const tableName = DbObjectKey.FromXml(d.GetEntity().GetColumn('ObjectKeyElement').GetValue()).TableName; + return this.metadatasvc.tables?.[tableName]?.DisplaySingular; + } + + public async viewDetails(change: TypedEntity): Promise { + this.changeviewService.handleOpenLoader(); + var details: ExtendedTypedEntityCollection; + try { + const uidChange = change.GetEntity().GetKeys()[0]; + details = await this.uciApi.typedClient.OpsupportUciChangedetail.Get(uidChange); + } finally { + this.changeviewService.handleCloseLoader(); + } + + const result = await this.sidesheet + .open(ChangeSidesheetComponent, { + title: await this.translator.get('#LDS#Heading View Provisioning Process Details').toPromise(), + subTitle: change.GetEntity().GetColumn('ObjectKeyElement').GetDisplayValue(), + padding: '0', + width: calculateSidesheetWidth(600, 0.4), + testId: 'changeview-details-sidesheet', + data: details, + }) + .afterClosed() + .toPromise(); + + if (result) { + this.getData(); + } + } + + public async getDataModel(): Promise { + return this.uciApi.client.opsupport_uci_changes_datamodel_get(); + } } diff --git a/imxweb/projects/uci/src/lib/changeview/change-view.service.ts b/imxweb/projects/uci/src/lib/changeview/change-view.service.ts index 7ea87617a..97531ea9e 100644 --- a/imxweb/projects/uci/src/lib/changeview/change-view.service.ts +++ b/imxweb/projects/uci/src/lib/changeview/change-view.service.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -24,31 +24,22 @@ * */ -import { OverlayRef } from "@angular/cdk/overlay"; -import { Injectable } from "@angular/core"; -import { EuiLoadingService } from "@elemental-ui/core"; +import { Injectable } from '@angular/core'; +import { EuiLoadingService } from '@elemental-ui/core'; @Injectable({ - providedIn: 'root' + providedIn: 'root', }) export class ChangeViewService { - - constructor(private readonly busyService: EuiLoadingService) { } - - private busyIndicator: OverlayRef; + constructor(private readonly busyService: EuiLoadingService) {} public handleOpenLoader(): void { - if (!this.busyIndicator) { - setTimeout(() => this.busyIndicator = this.busyService.show()); + if (this.busyService.overlayRefs.length === 0) { + this.busyService.show(); } } public handleCloseLoader(): void { - if (this.busyIndicator) { - setTimeout(() => { - this.busyService.hide(this.busyIndicator); - this.busyIndicator = undefined; - }); - } + this.busyService.hide(); } -} \ No newline at end of file +} diff --git a/imxweb/projects/uci/src/lib/changeview/changeview.module.ts b/imxweb/projects/uci/src/lib/changeview/changeview.module.ts index 06e7e7662..fb9acf2c1 100644 --- a/imxweb/projects/uci/src/lib/changeview/changeview.module.ts +++ b/imxweb/projects/uci/src/lib/changeview/changeview.module.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -24,20 +24,17 @@ * */ -import { CommonModule } from "@angular/common"; -import { NgModule } from "@angular/core"; -import { MatCardModule } from "@angular/material/card"; -import { EuiCoreModule, EuiMaterialModule } from "@elemental-ui/core"; -import { TranslateModule } from "@ngx-translate/core"; -import { CdrModule, DataSourceToolbarModule, DataTableModule, QbmModule } from "qbm"; -import { ChangeSidesheetComponent } from "./change-sidesheet.component"; -import { ChangeViewComponent } from "./change-view.component"; +import { CommonModule } from '@angular/common'; +import { NgModule } from '@angular/core'; +import { MatCardModule } from '@angular/material/card'; +import { EuiCoreModule, EuiMaterialModule } from '@elemental-ui/core'; +import { TranslateModule } from '@ngx-translate/core'; +import { CdrModule, DataSourceToolbarModule, DataTableModule, QbmModule } from 'qbm'; +import { ChangeSidesheetComponent } from './change-sidesheet.component'; +import { ChangeViewComponent } from './change-view.component'; @NgModule({ - declarations: [ - ChangeViewComponent, - ChangeSidesheetComponent - ], + declarations: [ChangeViewComponent, ChangeSidesheetComponent], imports: [ CommonModule, EuiCoreModule, @@ -47,9 +44,7 @@ import { ChangeViewComponent } from "./change-view.component"; MatCardModule, CdrModule, QbmModule, - TranslateModule - ] + TranslateModule, + ], }) -export class ChangeViewModule { - -} \ No newline at end of file +export class ChangeViewModule {} diff --git a/imxweb/projects/uci/src/lib/init.service.ts b/imxweb/projects/uci/src/lib/init.service.ts index 7733933ff..21d4df9c9 100644 --- a/imxweb/projects/uci/src/lib/init.service.ts +++ b/imxweb/projects/uci/src/lib/init.service.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -25,15 +25,14 @@ */ import { Injectable } from '@angular/core'; -import { Router, Route } from '@angular/router'; +import { Route, Router } from '@angular/router'; import { MenuItem, MenuService } from 'qbm'; @Injectable({ providedIn: 'root' }) export class InitService { - constructor( private readonly router: Router, - private readonly menuService: MenuService + private readonly menuService: MenuService, ) { this.setupMenu(); } @@ -44,42 +43,38 @@ export class InitService { private addRoutes(routes: Route[]): void { const config = this.router.config; - routes.forEach(route => { + routes.forEach((route) => { config.unshift(route); }); this.router.resetConfig(config); } private setupMenu(): void { - this.menuService.addMenuFactories( - (preProps: string[], groups: string[]) => { - - const items: MenuItem[] = []; + this.menuService.addMenuFactories((preProps: string[], groups: string[]) => { + const items: MenuItem[] = []; - if (groups.includes('UCI_4_CLOUD_OPERATOR') - // || groups.includes('UCI_4_CLOUD_AUDITOR') - || groups.includes('UCI_4_CLOUD_ADMINISTRATOR') - ) { - items.push( - { - id: 'UCI_PendingOperations', - route: 'provisioning', - title: '#LDS#Menu Entry Pending provisioning processes', - sorting: '30-40', - }, - ); - } + if ( + groups.includes('UCI_4_CLOUD_OPERATOR') || + // || groups.includes('UCI_4_CLOUD_AUDITOR') + groups.includes('UCI_4_CLOUD_ADMINISTRATOR') + ) { + items.push({ + id: 'UCI_PendingOperations', + route: 'provisioning', + title: '#LDS#Menu Entry Pending provisioning processes', + sorting: '30-40', + }); + } - if (items.length === 0) { - return null; - } - return { - id: 'OpsWeb_ROOT_Synchronization', - title: '#LDS#Synchronization', - sorting: '30', - items - }; - }, - ); + if (items.length === 0) { + return undefined; + } + return { + id: 'OpsWeb_ROOT_Synchronization', + title: '#LDS#Synchronization', + sorting: '30', + items, + }; + }); } } diff --git a/imxweb/projects/uci/src/lib/uci-api-client.service.ts b/imxweb/projects/uci/src/lib/uci-api-client.service.ts index 6c86a29b8..8f243bd64 100644 --- a/imxweb/projects/uci/src/lib/uci-api-client.service.ts +++ b/imxweb/projects/uci/src/lib/uci-api-client.service.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -25,12 +25,12 @@ */ import { Injectable } from '@angular/core'; -import { V2Client, TypedClient } from 'imx-api-uci'; -import { ApiClient } from 'imx-qbm-dbts'; +import { V2Client, TypedClient } from '@imx-modules/imx-api-uci'; +import { ApiClient } from '@imx-modules/imx-qbm-dbts'; import { AppConfigService, ClassloggerService, ImxTranslationProviderService } from 'qbm'; @Injectable({ - providedIn: 'root' + providedIn: 'root', }) export class UciApiService { private tc: TypedClient; @@ -50,7 +50,8 @@ export class UciApiService { constructor( private readonly config: AppConfigService, private readonly logger: ClassloggerService, - private readonly translationProvider: ImxTranslationProviderService) { + private readonly translationProvider: ImxTranslationProviderService, + ) { try { this.logger.debug(this, 'Initializing UCI API service'); diff --git a/imxweb/projects/uci/src/lib/uci-config.module.ts b/imxweb/projects/uci/src/lib/uci-config.module.ts index 371d0bd47..772f9fe8a 100644 --- a/imxweb/projects/uci/src/lib/uci-config.module.ts +++ b/imxweb/projects/uci/src/lib/uci-config.module.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -38,20 +38,13 @@ const routes: Routes = [ path: 'provisioning', component: ChangeViewComponent, canActivate: [RouteGuardService], - resolve: [RouteGuardService] - } + resolve: [RouteGuardService], + }, ]; @NgModule({ - declarations: [ - - ], - imports: [ - CommonModule, - RouterModule.forChild(routes), - ChangeViewModule, - TranslateModule - ] + declarations: [], + imports: [CommonModule, RouterModule.forChild(routes), ChangeViewModule, TranslateModule], }) export class UciConfigModule { constructor(private readonly initializer: InitService) { diff --git a/imxweb/projects/uci/src/public_api.ts b/imxweb/projects/uci/src/public_api.ts index aff57fb89..108ed3473 100644 --- a/imxweb/projects/uci/src/public_api.ts +++ b/imxweb/projects/uci/src/public_api.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR diff --git a/imxweb/projects/uci/src/test.ts b/imxweb/projects/uci/src/test.ts index f7ac7d548..159c87d7d 100644 --- a/imxweb/projects/uci/src/test.ts +++ b/imxweb/projects/uci/src/test.ts @@ -9,7 +9,7 @@ * those terms. * * - * Copyright 2023 One Identity LLC. + * Copyright 2024 One Identity LLC. * ALL RIGHTS RESERVED. * * ONE IDENTITY LLC. MAKES NO REPRESENTATIONS OR @@ -26,24 +26,14 @@ // This file is required by karma.conf.js and loads recursively all the .spec and framework files -import 'core-js/es7/reflect'; -import 'zone.js/dist/zone'; -import 'zone.js/dist/zone-testing'; +// Zone must be imported first. Be careful with prettier import organizing +import 'zone.js'; +import 'zone.js/testing'; + import { getTestBed } from '@angular/core/testing'; -import { - BrowserDynamicTestingModule, - platformBrowserDynamicTesting -} from '@angular/platform-browser-dynamic/testing'; +import { BrowserDynamicTestingModule, platformBrowserDynamicTesting } from '@angular/platform-browser-dynamic/testing'; +import 'core-js/es/reflect'; import { TestHelperModule } from 'qbm'; -declare const require: any; - // First, initialize the Angular testing environment. -getTestBed().initTestEnvironment( - [BrowserDynamicTestingModule, TestHelperModule], - platformBrowserDynamicTesting() -); -// Then we find all the tests. -const context = require.context('./', true, /\.spec\.ts$/); -// And load the modules. -context.keys().map(context); +getTestBed().initTestEnvironment([BrowserDynamicTestingModule, TestHelperModule], platformBrowserDynamicTesting()); diff --git a/imxweb/projects/uci/tsconfig.lib.json b/imxweb/projects/uci/tsconfig.lib.json index 6bc419f84..534c734a0 100644 --- a/imxweb/projects/uci/tsconfig.lib.json +++ b/imxweb/projects/uci/tsconfig.lib.json @@ -1,16 +1,17 @@ /* To learn more about this file see: https://angular.io/config/tsconfig. */ { "extends": "../../tsconfig.json", + "angularCompilerOptions": { + "strictTemplates": true + }, "compilerOptions": { "outDir": "../../out-tsc/lib", + "strictNullChecks": true, "declaration": true, "declarationMap": true, "sourceMap": true, "inlineSources": true, "types": [] }, - "exclude": [ - "src/test.ts", - "**/*.spec.ts" - ] + "exclude": ["src/test.ts", "**/*.spec.ts"] } diff --git a/imxweb/projects/uci/tsconfig.lib.prod.json b/imxweb/projects/uci/tsconfig.lib.prod.json index 61c7592e7..fb40dbbb0 100644 --- a/imxweb/projects/uci/tsconfig.lib.prod.json +++ b/imxweb/projects/uci/tsconfig.lib.prod.json @@ -3,8 +3,5 @@ "extends": "./tsconfig.lib.json", "compilerOptions": { "declarationMap": false - }, - "angularCompilerOptions": { - "enableIvy": true } } diff --git a/imxweb/projects/uci/tsconfig.spec.json b/imxweb/projects/uci/tsconfig.spec.json index 16da33db0..6bd74e1f7 100644 --- a/imxweb/projects/uci/tsconfig.spec.json +++ b/imxweb/projects/uci/tsconfig.spec.json @@ -1,17 +1,10 @@ { "extends": "../../tsconfig.json", "compilerOptions": { + "strictNullChecks": false, "outDir": "../../out-tsc/spec", - "types": [ - "jasmine", - "node" - ] + "types": ["jasmine", "node"] }, - "files": [ - "src/test.ts" - ], - "include": [ - "**/*.spec.ts", - "**/*.d.ts" - ] + "files": ["src/test.ts"], + "include": ["**/*.spec.ts", "**/*.d.ts"] } diff --git a/imxweb/projects/uci/tslint.json b/imxweb/projects/uci/tslint.json deleted file mode 100644 index 8bab15f53..000000000 --- a/imxweb/projects/uci/tslint.json +++ /dev/null @@ -1,17 +0,0 @@ -{ - "extends": "../../tslint.json", - "rules": { - "directive-selector": [ - true, - "attribute", - "imx", - "camelCase" - ], - "component-selector": [ - true, - "element", - "imx", - "kebab-case" - ] - } -} diff --git a/imxweb/remove-local-package-locks.js b/imxweb/remove-local-package-locks.js index 7a9a83b05..f6e9b72cc 100644 --- a/imxweb/remove-local-package-locks.js +++ b/imxweb/remove-local-package-locks.js @@ -4,40 +4,38 @@ var data = require(path); var anyChanges = false; for (const name of [ - // these are the local packages that must not be included in package-lock.json. // This script removes the entries in the package-lock dependencies object // for these packages. // Add any custom API client libraries to this list (imx-api-ccc is already // included by default.) - 'imx-api-ccc', - 'imx-qbm-dbts', - 'imx-api-qbm', - 'imx-api-dpr', - 'imx-api-tsb', - 'imx-api-aob', - 'imx-api-apc', - 'imx-api-qer', - 'imx-api-rps', - 'imx-api-sac', - 'imx-api-cpl', - 'imx-api-pol', - 'imx-api-aad', - 'imx-api-o3t', - 'imx-api-rmb', - 'imx-api-rms', - 'imx-api-hds', - 'imx-api-att', - 'imx-api-uci', - 'imx-api-olg', - 'imx-api-o3e' + '@imx-modules/imx-api-ccc', + '@imx-modules/imx-qbm-dbts', + '@imx-modules/imx-api-qbm', + '@imx-modules/imx-api-dpr', + '@imx-modules/imx-api-tsb', + '@imx-modules/imx-api-aob', + '@imx-modules/imx-api-apc', + '@imx-modules/imx-api-qer', + '@imx-modules/imx-api-rps', + '@imx-modules/imx-api-sac', + '@imx-modules/imx-api-cpl', + '@imx-modules/imx-api-pol', + '@imx-modules/imx-api-aad', + '@imx-modules/imx-api-rmb', + '@imx-modules/imx-api-rms', + '@imx-modules/imx-api-hds', + '@imx-modules/imx-api-att', + '@imx-modules/imx-api-uci', + '@imx-modules/imx-api-olg', + '@elemental-ui/core', + '@elemental-ui/cadence-icon' ]) { if (data?.dependencies && data.dependencies[name]) { delete data.dependencies[name]; anyChanges = true; } - const nodeModuleName = 'node_modules/' + name; if (data.packages[nodeModuleName]) { delete data.packages[nodeModuleName]; @@ -62,5 +60,4 @@ fs.writeFile(path, toWrite, 'utf8', (err) => { } }); -if (error) - throw error; +if (error) throw error; diff --git a/imxweb/shared/assets/variables.scss b/imxweb/shared/assets/variables.scss deleted file mode 100644 index 1ba4d16ba..000000000 --- a/imxweb/shared/assets/variables.scss +++ /dev/null @@ -1,29 +0,0 @@ -@import '@elemental-ui/core/src/styles/_palette.scss'; - -$baseFontFamily: "Source Sans Pro", "Trebuchet MS", sans-serif; -$IMX_Mediaquery_Smartphone: "all and (max-width: 760px)"; -$IMX_Mediaquery_SmallDesktops: "all and (min-width: 761px) and (max-width: 1024px)"; -$PopupWidthLarge: 750; -$propcellminheight: 1.6em; -$propertylabelwidth: 220px; -$QBM_Primary_Black: #162c36; -$QBM_Primary_Orange: #FF9C00; -$VI_Common_Color_Blue_1: #69CCE9; -$VI_Common_Color_Blue_3: #03556D; -$VI_Common_Color_Button_Danger_Hover: #d82a30; -$VI_Common_Color_Button_Default_Hover: #0582a7; -$VI_Common_Color_Button_Font_Disabled: #b7b7b7; -$VI_Common_Color_Button_Outline: #6a6a6a; -$VI_Common_Color_Button_Success_Hover: #77af4c; -$VI_Common_Color_Font: #2f2f2f; -$VI_Common_Color_Font_Secondary: #282828; -$VI_Common_Color_Gray: #6A6A6A; -$VI_Common_Color_LightGray: #B7B7B7; -$Imx_White-two: #e9e9e9; -$Imx_Ellipse_Gray: rgba(204, 204, 204, 0.5); -$Imx_Checkbox: rgb(130, 213, 237); -$ImxLoginControlsMargin: 0.7em; - -/*To Do*/ -$link: test; -$permanentlink: test; diff --git a/imxweb/shared/scss/base/colors.scss b/imxweb/shared/scss/base/colors.scss new file mode 100644 index 000000000..8e856bf49 --- /dev/null +++ b/imxweb/shared/scss/base/colors.scss @@ -0,0 +1,46 @@ +.imx { + &-white { + color: $color-gray-0; + } + + &-black { + color: $color-gray-100; + } + + &-info { + color: $color-blue-60; + } + + &-new { + color: $color-green-60; + } + + &-warning { + color: $color-orange-60; + } + + &-error { + color: $color-red-60; + } +} + +.eui-dark-theme, +.eui-contrast-theme { + .imx { + &-info { + color: $color-blue-40; + } + + &-new { + color: $color-green-40; + } + + &-warning { + color: $color-orange-40; + } + + &-error { + color: $color-red-40; + } + } +} diff --git a/imxweb/shared/scss/base/fonts.scss b/imxweb/shared/scss/base/fonts.scss new file mode 100644 index 000000000..795364b22 --- /dev/null +++ b/imxweb/shared/scss/base/fonts.scss @@ -0,0 +1,6 @@ +@font-face { + font-family: 'fa-identity'; + src: url('../../assets/fonts/fa-identity.ttf'); + font-weight: normal; + font-style: normal; +} diff --git a/imxweb/shared/scss/base/margins-paddings.scss b/imxweb/shared/scss/base/margins-paddings.scss new file mode 100644 index 000000000..7fe2f7e9c --- /dev/null +++ b/imxweb/shared/scss/base/margins-paddings.scss @@ -0,0 +1,59 @@ +$spaceamounts: (0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 15, 16, 20, 24, 25, 30, 32, 35, 40, 45, 48, 50, 64, 75, 80, 100); +$sides: (top, bottom, left, right); + +@each $space in $spaceamounts { + @each $side in $sides { + .imx-margin-#{$side}-#{$space} { + margin-#{$side}: #{$space}px !important; + } + + .imx-padding-#{$side}-#{$space} { + padding-#{$side}: #{$space}px !important; + } + } + + .imx-margin-horizontal-#{$space} { + margin: 0 #{$space}px !important; + } + + .imx-margin-vertical-#{$space} { + margin: #{$space}px 0 !important; + } + + .imx-margin-#{$space} { + margin: #{$space}px !important; + } + + .imx-padding-horizontal-#{$space} { + padding: 0 #{$space}px !important; + } + + .imx-padding-vertical-#{$space} { + padding: #{$space}px 0 !important; + } + + .imx-padding-#{$space} { + padding: #{$space}px !important; + } +} + +@each $side in $sides { + .imx-margin-#{$side}-auto { + margin-#{$side}: auto !important; + } + + .imx-padding-#{$side}-auto { + padding-#{$side}: auto !important; + } +} + +@for $nLines from 1 through 4 { + .imx-text-overflow--#{$nLines} { + overflow: hidden; + text-overflow: ellipsis; + display: -webkit-box; + -webkit-line-clamp: $nLines; /* number of lines to show */ + line-clamp: $nLines; + -webkit-box-orient: vertical; + } +} diff --git a/imxweb/shared/scss/base/mixins.scss b/imxweb/shared/scss/base/mixins.scss new file mode 100644 index 000000000..a32b194be --- /dev/null +++ b/imxweb/shared/scss/base/mixins.scss @@ -0,0 +1,237 @@ +@import '@elemental-ui/core/src/styles/_palette.scss'; + +@mixin eui-elevation-1 { + box-shadow: + 0px 1px 1px rgba(0, 0, 0, 0.14), + 0px 2px 1px rgba(0, 0, 0, 0.12), + 0px 1px 3px rgba(0, 0, 0, 0.2); +} + +@mixin eui-elevation-2 { + box-shadow: + 0px 4px 5px rgba(0, 0, 0, 0.14), + 0px 1px 10px rgba(0, 0, 0, 0.12), + 0px 2px 4px rgba(0, 0, 0, 0.2); +} + +@mixin eui-elevation-3 { + box-shadow: + 0px 24px 38px rgba(0, 0, 0, 0.14), + 0px 9px 46px rgba(0, 0, 0, 0.12), + 0px 11px 15px rgba(0, 0, 0, 0.2); +} + +@mixin ease-transition($duration: 0.4s) { + transition: all $duration ease; +} + +@mixin flex-column-container($overflow: null, $height: null, $width: null, $max-height: null, $max-width: null) { + display: flex; + flex-direction: column; + overflow: $overflow; + height: $height; + width: $width; + max-height: $max-height; + max-width: $max-width; +} + +@mixin flex-row-container($overflow: null, $height: null, $width: null, $max-height: null, $max-width: null) { + display: flex; + flex-direction: row; + overflow: $overflow; + height: $height; + width: $width; + max-height: $max-height; + max-width: $max-width; +} + +@mixin flex-column-container-fill { + @include flex-column-container($overflow: hidden); + flex: 1 1 auto; +} + +@mixin flex-row-container-fill { + @include flex-row-container(); + flex: 1 1 auto; +} + +@mixin align-button-content($text-color) { + color: $text-color; + + ::ng-deep .mat-mdc-button-wrapper { + display: flex; + align-items: center; + } +} + +@mixin image-button-icon { + eui-icon { + font-size: 14px; + margin-right: 4px; + } +} + +@mixin button-bar { + @include flex-row-container(); + justify-content: flex-end; + margin-top: 16px; + + > button:not(:last-of-type) { + margin-right: 16px; + } + + .imx-menu-spacer { + flex: 1 1 auto; + } + + .mat-mdc-stroked-button, + .mat-mdc-raised-button { + @include image-button-icon; + } +} + +@mixin button-column-right { + @include flex-row-container(); + justify-content: flex-end; + + .mat-mdc-stroked-button { + @include image-button-icon; + margin-right: 16px; + } +} + +@mixin text-overflow-ellipsis { + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; +} + +@mixin transform-enlarge($scale: 1.03) { + transform: translate3D(0, -1px, 0) scale($scale); +} + +@mixin transform-shrink($scale: 0.97) { + transform: translate3D(0, -1px, 0) scale($scale); +} + +// $header-type: Values: body, title, label, emphasize, description +// $primary: Sets the text color, Values: Boolean, default: false +@mixin new-request-text($header-type: body, $primary: false) { + font-size: 14px; + font-weight: 600; + + @if $header-type == title { + font-size: 26px; + line-height: 33px; + } @else if $header-type == emphasize { + font-size: 20px; + line-height: 25px; + } @else if $header-type == label { + line-height: 18px; + } @else if $header-type == description { + color: $color-gray-40; + font-weight: 400; + line-height: 18px; + margin-left: 5px; + } +} + +@mixin new-request-orange-border($theme: eui-light-theme) { + border-radius: 4px; + border-width: 1px; + border-style: solid; + outline-width: 1px; + outline-style: solid; + + @if $theme == eui-light-theme { + outline-color: $color-orange-40; + border-color: $color-orange-40; + } @else if $theme == eui-dark-theme { + outline-color: $color-orange-60; + border-color: $color-orange-60; + } @else if $theme == eui-contrast-theme { + outline-color: $color-orange-60; + border-color: $color-orange-60; + } +} + +@mixin eui-sidesheet-actions__mixin_01( + $align-items: null, + $overflow-y: null, + $flex-wrap: null, + $padding: null, + $margin: null, + $margin-top: null, + $margin-right: null, + $margin-bottom: null, + $margin-left: null +) { + display: flex; + justify-content: flex-end; + align-items: $align-items; + overflow-y: $overflow-y; + flex-wrap: $flex-wrap; + padding: $padding; + margin: $margin; + > * { + margin-top: $margin-top; + margin-right: $margin-right; + margin-bottom: $margin-bottom; + margin-left: $margin-left; + } +} + +// Approval-workflow styles +@mixin Awm-Colors($theme: eui-light-theme) { + @if $theme == eui-light-theme { + --awm-node-level: #{$color-gray-20}; + --awm-node-step: #{$color-gray-2}; + --awm-edge-root: #{$color-gray-100}; + --awm-edge-approval: #{$color-green-60}; + --awm-edge-reject: #{$color-red-60}; + --awm-edge-escalation: #{$color-orange-60}; + --awm-edge-redirect: #{$color-blue-80}; + --awm-text: #{$color-gray-80}; + --awm-selected: #{$color-blue-40}; + } @else if $theme == eui-dark-theme { + --awm-node-level: #{$color-gray-50}; + --awm-node-step: #{$color-gray-70}; + --awm-edge-root: #{$color-gray-10}; + --awm-edge-approval: #{$color-green-40}; + --awm-edge-reject: #{$color-red-40}; + --awm-edge-escalation: #{$color-orange-40}; + --awm-edge-redirect: #{$color-blue-40}; + --awm-text: #{$color-gray-2}; + --awm-selected: #{$color-blue-60}; + } @else if $theme == eui-contrast-theme { + --awm-node-level: #{$color-gray-70}; + --awm-node-step: #{$color-gray-90}; + --awm-edge-root: #{$color-gray-0}; + --awm-edge-approval: #{$color-green-40}; + --awm-edge-reject: #{$color-red-40}; + --awm-edge-escalation: #{$color-orange-40}; + --awm-edge-redirect: #{$color-blue-40}; + --awm-text: #{$color-gray-0}; + --awm-selected: #{$color-blue-60}; + } @else { + @error "#{$theme} is not defined in approval-workflow-styles: Awm-Colors"; + } +} + +@mixin Awm-Form-Sidesheet { + :host { + .form-wrapper { + margin-top: 20px; + display: flex; + flex-direction: column; + overflow: auto; + .mat-mdc-card { + @include eui-elevation-1; + } + } + + .eui-sidesheet-actions { + column-gap: 15px; + } + } +} diff --git a/imxweb/shared/scss/theme.scss b/imxweb/shared/scss/base/theme.scss similarity index 67% rename from imxweb/shared/scss/theme.scss rename to imxweb/shared/scss/base/theme.scss index bd6e9dc82..4bbefc0a8 100644 --- a/imxweb/shared/scss/theme.scss +++ b/imxweb/shared/scss/base/theme.scss @@ -1,20 +1,25 @@ + + + @use 'sass:map'; @use '@angular/material' as mat; @mixin theme($theme-name, $theme) { - $color-config: mat.get-color-config($theme); + $color-config: mat.m2-get-color-config($theme); $primary-palette: map.get($color-config, 'primary'); $accent-palette: map.get($color-config, 'accent'); $warn-palette: map.get($color-config, 'warn'); $is-dark-theme: map.get($color-config, 'is-dark'); + body.#{unquote($theme-name)} { @include login-theme($primary-palette); } } + @mixin login-theme($primary-palette){ .imx-loginPage { - background-color: mat.get-color-from-palette($primary-palette, default); - color: mat.get-color-from-palette($primary-palette, default-contrast); + background-color: mat.m2-get-color-from-palette($primary-palette, default); + color: mat.m2-get-color-from-palette($primary-palette, default-contrast); } } diff --git a/imxweb/shared/scss/base/variables.scss b/imxweb/shared/scss/base/variables.scss new file mode 100644 index 000000000..b5f4d0784 --- /dev/null +++ b/imxweb/shared/scss/base/variables.scss @@ -0,0 +1,54 @@ +@import '@elemental-ui/core/src/styles/_eui_palette.scss'; +@import '@elemental-ui/core/src/styles/_palette.scss'; + +$IMX_Color_White: $color-gray-0; +$IMX_Color_Black: $color-gray-100; + +$IMX_Color_Light_Info: $color-blue-60; +$IMX_Color_Light_New: $color-green-60; +$IMX_Color_Light_Warning: $color-orange-60; +$IMX_Color_Light_Error: $color-red-60; + +$IMX_Color_Dark_Info: $color-blue-40; +$IMX_Color_Dark_New: $color-green-40; +$IMX_Color_Dark_Warning: $color-orange-40; +$IMX_Color_Dark_Error: $color-red-40; + +$IMX_Color_Contrast_Info: $color-blue-40; +$IMX_Color_Contrast_New: $color-green-40; +$IMX_Color_Contrast_Warning: $color-orange-40; +$IMX_Color_Contrast_Error: $color-red-40; + +$Path_Material_Icons_Font: '~node_modules/@elemental-ui/core/assets/MaterialIcons'; +$Path_Cadence_Font: '~node_modules/@elemental-ui/core/assets/Cadence'; +$Path_Source_Sans_Pro_Font: '~node_modules/@elemental-ui/core/assets/Source_Sans_Pro'; + +$IMX_Mediaquery_Smartphone: 'all and (max-width: 760px)'; +$IMX_Mediaquery_SmallDesktops: 'all and (min-width: 761px) and (max-width: 1024px)'; +$IMX_Base_FontFamily: 'Source Sans Pro', 'Trebuchet MS', sans-serif; +$IMX_White_2: #e9e9e9; +$IMX_Ellipse_Gray: rgba(204, 204, 204, 0.5); +$IMX_Checkbox: rgb(130, 213, 237); +$IMX_Material_Gray: rgba(#000, 0.38); +$IMX_Material_Gray_Hover: rgba(#2f3233, 0.87); +$IMX_Material_LightGray: rgba(#fff, 0.38); +$IMX_Material_LightGray_Hover: rgba(#fff, 0.87); +$IMX_Login_Controls_Margin: 0.7em; +$IMX_Login_Input_Width: calc(40vw + 2px); +$IMX_Identity_PhotoSize: 45px; +$IMX_OrgChart_HalfPhotoSize: calc($IMX_Identity_PhotoSize / 2); +$IMX_OrgChart_BorderWidth: 2px; +$IMX_OrgChart_Width: 100px; +/* Horizontal margin from one level to the next */ +$IMX_OrgChart_LevelMargin: 15px; +$IMX_OrgChart_PeersMargin: $IMX_Identity_PhotoSize + $IMX_OrgChart_LevelMargin; +$IMX_OrgChart_ReportsMargin: (2 * $IMX_Identity_PhotoSize) + (2 * $IMX_OrgChart_LevelMargin); +$IMX_OrgChart_BorderContainerReportsLeft: $IMX_OrgChart_PeersMargin + $IMX_OrgChart_HalfPhotoSize; +$IMX_OrgChart_ConnectorReportsLeft: $IMX_OrgChart_ReportsMargin + $IMX_OrgChart_HalfPhotoSize; +$IMX_MessageDialog_MaxWidth: 750px; +$IMX_PropCell_MinHeight: 1.6em; +$IMX_PropertyLabel_Width: 220px; +$IMX_Tile_Width: 395px; +$IMX_Application_Details_Component_Height: calc(100vh - 180px); +$IMX_SearchBar_Width: 535px; +$IMX_SearchBar_Height: 45px; diff --git a/imxweb/shared/scss/common-table.scss b/imxweb/shared/scss/common-table.scss deleted file mode 100644 index 03fac355c..000000000 --- a/imxweb/shared/scss/common-table.scss +++ /dev/null @@ -1,44 +0,0 @@ -@mixin imx-icon-for-image-button { - eui-icon { - font-size: 14px; - margin-right: 4px; - } -} - -@mixin imx-flex-fill-control-hidden-overflow{ - flex: 1 1 auto; - display: flex; - flex-direction: column; - overflow: hidden; -} - -@mixin imx-button-bar { - display: flex; - flex-direction: row; - justify-content: flex-end; - margin-top: 16px; - - > button:not(:last-of-type) { - margin-right: 16px; - } - - .imx-menu-spacer { - flex: 1 1 auto; - } - - .mat-stroked-button, - .mat-raised-button { - @include imx-icon-for-image-button; - } -} - -@mixin imx-button-column-right{ - display: flex; - flex-direction: row; - justify-content: flex-end; - - .mat-stroked-button { - @include imx-icon-for-image-button; - margin-right: 16px; - } -} \ No newline at end of file diff --git a/imxweb/shared/scss/common/captcha-login.scss b/imxweb/shared/scss/common/captcha-login.scss new file mode 100644 index 000000000..27ffa44bc --- /dev/null +++ b/imxweb/shared/scss/common/captcha-login.scss @@ -0,0 +1,68 @@ +@import '@elemental-ui/core/src/styles/_eui_palette.scss'; + +.imx-loginInput { + margin: auto 12px; + + input { + box-sizing: content-box; + margin-bottom: 9px; + height: 30px; + width: calc(40vw - 6px); + } + .mat-mdc-card{ + color: $color-gray-80; + flex-direction: row; + } +} + +:host { + eui-alert{ + color: $color-gray-80; + } +} + +.buttonbar { + margin-top: 1.5em; + display: flex; + justify-content: center; + gap: 1em; +} + +.passcode, .pwd-answer { + margin-top: 1em; + margin-bottom: 1em; +} + +.eui-dark-theme, +.eui-contrast-theme { + :host { + eui-alert { + color: $color-gray-0; + } + } + .imx-loginInput { + .mat-mdc-card { + color: $color-gray-0; + } + } +} + +.eui-dark-theme { + :host { + .imx-loginInput { + .imx-input-login { + background-color: $color-gray-70 !important; + } + } + } +} + +.eui-contrast-theme { + :host { + .imx-loginInput { + .imx-input-login { + background-color: $color-gray-90 !important; + } + } + } +} diff --git a/imxweb/shared/scss/common/mitigating-controls.scss b/imxweb/shared/scss/common/mitigating-controls.scss new file mode 100644 index 000000000..4cdff3905 --- /dev/null +++ b/imxweb/shared/scss/common/mitigating-controls.scss @@ -0,0 +1,136 @@ +@import '@elemental-ui/core/src/styles/_eui_palette.scss'; +@import 'base/mixins'; + +:host { + height: 100%; + display: flex; + flex-direction: column; + justify-content: space-between; + + .eui-sidesheet-actions { + @include eui-sidesheet-actions__mixin_01($padding: 16px 20px); + } + + .control-container { + display: flex; + flex-direction: column; + overflow: auto; + } + + .imx-mitigating-control { + margin-bottom: 15px; + display: flex; + justify-content: space-between; + align-items: center; + + &.bordered { + border-bottom: 1px solid $color-gray-50; + } + + eui-select { + flex: 1 1 auto; + } + + &-properties { + display: flex; + flex-direction: column; + width: 100%; + margin-right: 15px; + gap: 15px; + } + + &-content { + flex: 1 1 auto; + margin: 3px; + display: flex; + flex-direction: column; + overflow: auto; + + .content { + overflow: auto; + display: flex; + flex: 1 1 auto; + flex-direction: column; + } + } + + .imx-delete-button { + margin-top: 15px; + align-self: flex-start; + } + } + + .imx-no-mitigating-controls { + flex: 1 1 auto; + margin: 3px; + display: flex; + align-items: center; + justify-content: center; + } + + .imx-no-results { + text-align: center; + margin: 20px 0; + justify-self: center; + + p { + margin: 0; + font-size: 18px; + } + + button { + margin-top: 10px; + } + } +} + +// Theming +:host { + .imx-no-results { + p { + color: $color-gray-50; + } + } + + .imx-no-mitigating-controls { + color: $color-gray-50; + } +} + +.eui-dark-theme { + :host { + .imx-no-results { + p { + color: $color-gray-10; + } + } + .imx-no-mitigating-controls { + color: $color-gray-10; + } + + .imx-mitigating-control { + .bordered { + border-bottom: 1px solid $color-gray-10; + } + } + } +} + +.eui-contrast-theme { + :host { + .imx-data-no-results { + p { + color: $color-gray-0; + } + } + .imx-no-mitigating-controls { + color: $color-gray-0; + } + + .imx-mitigating-control { + .bordered { + border-bottom: 1px solid $color-gray-0; + } + } + } +} diff --git a/imxweb/shared/scss/common/select.scss b/imxweb/shared/scss/common/select.scss new file mode 100644 index 000000000..f1ff68f91 --- /dev/null +++ b/imxweb/shared/scss/common/select.scss @@ -0,0 +1,35 @@ +:host { + display: flex; + flex-direction: column; + align-items: baseline; + + > * { + margin-right: 10px; + } +} + +input { + flex: 1; +} + +.imx-spacer { + height: 30px; +} + +.mat-mdc-button { + min-width: initial; +} + +.mat-mdc-error { + margin-top: 5px; + font-size: small; +} + +.imx-suffix-container { + display: flex; + + > *:not(:last-child) { + margin-right: 5px; + margin-top: 0; + } +} diff --git a/imxweb/shared/scss/components/alert.scss b/imxweb/shared/scss/components/alert.scss new file mode 100644 index 000000000..b67777ba4 --- /dev/null +++ b/imxweb/shared/scss/components/alert.scss @@ -0,0 +1,88 @@ +@import 'base/mixins'; + +/* Elemental UI */ +eui-alert { + display: flex; + width: auto; + margin-bottom: 16px; + max-height: max(50%, 200px); + + .eui-alert-header { + width: 100%; + } + + .eui-alert-content { + width: 100%; + overflow: auto; + } + + span { + display: block; + } +} + +/* Angular Material */ + +/* Imx */ +.imx-alert { + &-start { + &-50 { + width: 50%; + } + + &-70 { + width: 70%; + } + + &-100 { + width: 100%; + } + } + + &-end { + &-50 { + margin-left: auto; + width: 50%; + } + + &-70 { + margin-left: auto; + width: 70%; + } + } + + &-flex { + &-column { + @include flex-column-container(); + + &-end { + @extend .imx-alert-flex-column; + align-items: end; + } + } + } + + &-grid { + &-first-row { + grid-column: 1/3; + } + } + + &-shadow { + @include eui-elevation-1; + } + + &-content { + &-font-small { + font-size: 14px; + } + + &-end { + align-self: end; + } + } +} + +/* Dark theme */ + +/* High-contrast theme */ diff --git a/imxweb/shared/scss/components/autocomplete.scss b/imxweb/shared/scss/components/autocomplete.scss new file mode 100644 index 000000000..3f0147787 --- /dev/null +++ b/imxweb/shared/scss/components/autocomplete.scss @@ -0,0 +1,20 @@ +@import 'base/variables'; + +/* Elemental UI */ + +/* Angular Material */ + +/* Imx */ +.imx-autocomplete { + &-icon { + &.mat-mdc-autocomplete-panel.mat-mdc-autocomplete-visible { + min-width: $IMX_SearchBar_Width; + margin-left: -35px; + margin-top: 11px; + } + } +} + +/* Dark theme */ + +/* High-contrast theme */ diff --git a/imxweb/shared/scss/components/badge.scss b/imxweb/shared/scss/components/badge.scss new file mode 100644 index 000000000..7a71fbf77 --- /dev/null +++ b/imxweb/shared/scss/components/badge.scss @@ -0,0 +1,44 @@ +@import '@elemental-ui/core/src/styles/_eui_palette.scss'; + +/* Elemental UI */ + +.eui-badge { + vertical-align: middle; +} + +.eui-badge .eui-badge-content { + font-size: 12px; + line-height: 12px; +} +/* Angular Material */ + +/* Imx */ +.imx-badge { + &-gray { + background-color: $color-gray-60; + } +} + +.mat-mdc-table { + .mat-mdc-cell { + .eui-badge { + .eui-badge-content { + white-space: nowrap; + } + } + } +} + +/* Dark theme */ + +/* High-contrast theme */ + +/* Dark theme + High-contrast theme */ +.eui-dark-theme, +.eui-contrast-theme { + .imx-badge { + &-gray { + background-color: $color-gray-40; + } + } +} diff --git a/imxweb/shared/scss/components/button-toggle.scss b/imxweb/shared/scss/components/button-toggle.scss new file mode 100644 index 000000000..e20953038 --- /dev/null +++ b/imxweb/shared/scss/components/button-toggle.scss @@ -0,0 +1,72 @@ +$icon-size: (14, 16, 24, 32, 36); + +/* Elemental UI */ + +/* Angular Material */ + +/* Imx */ +.imx-button-toggle { + &-group { + &-info { + &.mat-mdc-button-toggle-group { + .mat-mdc-button-toggle.mat-mdc-button-toggle-appearance-standard.mat-mdc-button-toggle-checked { + background-color: $color-blue-60; + color: $color-gray-0; + } + } + } + + &-warning { + &.mat-mdc-button-toggle-group { + .mat-mdc-button-toggle.mat-mdc-button-toggle-appearance-standard.mat-mdc-button-toggle-checked { + background-color: $color-orange-60; + color: $color-gray-0; + } + } + } + } + + @each $size in $icon-size { + &-icon-#{$size} { + &.mat-mdc-button-toggle-appearance-standard .mat-mdc-button-toggle-label-content { + padding: 0 calc(((#{$size}px - 24px) / -2) + 12px); + } + } + } +} +body { + .mat-button-toggle-group { + .mat-button-toggle-label-content { + .eui-icon { + vertical-align: middle; + } + } + } +} + +/* Dark theme */ +.eui-dark-theme { + .imx-button-toggle { + &-group { + &-info { + &.mat-mdc-button-toggle-group { + .mat-mdc-button-toggle.mat-mdc-button-toggle-appearance-standard.mat-mdc-button-toggle-checked { + background-color: $color-blue-40; + color: $color-gray-80; + } + } + } + + &-warning { + &.mat-mdc-button-toggle-group { + .mat-mdc-button-toggle.mat-mdc-button-toggle-appearance-standard.mat-mdc-button-toggle-checked { + background-color: $color-orange-40; + color: $color-gray-80; + } + } + } + } + } +} + +/* High-contrast theme */ diff --git a/imxweb/shared/scss/components/button.scss b/imxweb/shared/scss/components/button.scss new file mode 100644 index 000000000..bf1edc379 --- /dev/null +++ b/imxweb/shared/scss/components/button.scss @@ -0,0 +1,247 @@ +@import '@elemental-ui/core/src/styles/_eui_palette.scss'; +@import 'base/mixins'; +@import 'base/variables'; + +/* Elemental UI */ + +/* Angular Material */ +.mat-mdc-button, +.mat-mdc-stroked-button, +.mat-mdc-flat-button, +.mat-mdc-raised-button { + &:not(.mat-icon-button, .tree-item-button) { + // This is not applied to buttons that have a single mat-icon||eui-icon child + span.mat-mdc-button-wrapper:has(:not(mat-icon:only-child, eui-icon:only-child)) { + display: flex; + justify-content: center; + align-items: center; + } + } +} + +/* Imx */ +.imx-button { + color: $color-gray-0; + background-color: $color-blue-60; + + &-hover { + @include ease-transition(); + + &-info { + @extend .imx-button-hover; + + &:hover:not(:disabled) { + background-color: $color-blue-60; + } + } + + &-warning { + @extend .imx-button-hover; + + &:hover:not(:disabled) { + background-color: $color-orange-60; + } + } + } + + &-icon { + eui-icon.small, + eui-icon.medium, + eui-icon.large, + eui-icon.x-large { + margin-right: 4px; + } + + &-14 { + eui-icon.small, + eui-icon.medium, + eui-icon.large, + eui-icon.x-large { + font-size: 14px; + margin-right: 4px; + } + } + + &-20 { + eui-icon.small, + eui-icon.medium, + eui-icon.large, + eui-icon.x-large { + font-size: 20px; + margin-right: 4px; + } + } + + &-hover { + @include ease-transition(); + + &-info { + @extend .imx-button-hover; + + &:hover:not(:disabled) { + color: $color-blue-60; + } + } + + &-warning { + @extend .imx-button-hover; + + &:hover:not(:disabled) { + color: $color-orange-60; + } + } + } + } + + &-uppercase { + text-transform: uppercase; + } + + &-close-dialog { + right: -15px; + top: -15px; + } + + &-stepper { + @include flex-row-container(); + margin-top: 10px; + + button:not(:last-of-type) { + margin-right: 16px; + } + + &-vertical { + @include flex-column-container(); + + button:not(:last-of-type) { + margin-bottom: 5px; + } + } + } + + &-bar, + &-bar.mat-mdc-card { + @extend .imx-button-icon-14; + display: flex; + flex-direction: row; + align-items: center; + justify-content: flex-end; + margin-top: 16px; + border-top: 1px solid rgba(0, 0, 0, 0.12); + background-color: $color-gray-0; + + &-transparent { + @extend .imx-button-bar; + background-color: transparent; + border-top: none; + min-height: 48px; + } + + .justify-start { + margin-right: auto; + } + + .mat-mdc-checkbox:not(:last-child), + button:not(:last-child, .mdc-switch) { + margin-right: 16px; + } + } + + &-column { + @extend .imx-button-bar-transparent; + margin-top: 0; + margin-right: 16px; + + button:not(:last-of-type) { + margin-right: 5px; + } + } + + &-container { + @include flex-row-container(); + justify-content: flex-end; + + .justify-start { + margin-right: auto; + } + } + + &-refresh { + margin-right: 5px; + height: 50px; + } + + &:hover { + text-decoration: none; + } + + &:focus { + text-decoration: none; + outline: 1px $color-gray-60 dotted; + outline-offset: 1px; + } + + &:disabled { + cursor: not-allowed; + } +} + +/* Dark theme */ +.eui-dark-theme { + .imx-button { + &-bar { + background-color: $color-gray-70; + } + } +} + +/* High-contrast theme */ +.eui-contrast-theme { + .imx-button { + &-bar { + background-color: $color-gray-90; + } + } +} + +/* Dark theme + High-contrast theme */ +.eui-dark-theme, +.eui-contrast-theme { + .imx-button { + &-hover { + &-info { + &:hover:not(:disabled) { + background-color: $color-blue-40; + } + } + + &-warning { + &:hover:not(:disabled) { + background-color: $color-orange-40; + } + } + } + + &-icon { + &-hover { + &-info { + &:hover:not(:disabled) { + color: $color-blue-40; + } + } + + &-warning { + &:hover:not(:disabled) { + color: $color-orange-40; + } + } + } + } + + &-bar { + &-transparent { + background-color: transparent; + } + } + } +} diff --git a/imxweb/shared/scss/components/card.scss b/imxweb/shared/scss/components/card.scss new file mode 100644 index 000000000..e34cf968e --- /dev/null +++ b/imxweb/shared/scss/components/card.scss @@ -0,0 +1,160 @@ +@import 'base/mixins'; +@import 'components/icon'; + +/* Elemental UI */ + +/* Angular Material */ +.mat-mdc-card { + padding: 16px; + .mat-mdc-card-content, + .mat-mdc-card-header { + padding: 0 16px 0 0 !important; + } +} + +/* Imx */ +.mat-mdc-card.imx-card, +div.imx-card { + @include flex-column-container($overflow: hidden); + + &-border { + border: 1px solid $color-gray-20; + } + + &-fill { + @include flex-column-container-fill(); + } + + &-fill-sidesheet-margin { + @include flex-column-container-fill(); + margin: 20px; + } + + &-sidesheet { + height: 100%; + overflow: auto; + } + + &-data-explorer { + &-header { + background-color: $color-gray-0; + border-top-left-radius: 4px; + border-top-right-radius: 4px; + z-index: 100; + border: 1px solid rgba($color-blue-60, 0.6); + margin-bottom: 20px; + + &-bg { + border-top-left-radius: 4px; + border-top-right-radius: 4px; + background-color: $color-blue-20; + padding: 10px 24px; + display: flex; + align-items: center; + justify-content: flex-start; + height: 45px; + + & > h3 { + font-size: 20px; + font-weight: 400; + } + } + } + } + + &-select { + box-shadow: none; + border: 3px solid transparent; + cursor: pointer; + + &.selected { + border: 3px solid $color-blue-60; + } + } + + &-title { + font-weight: 600; + + &-s { + font-size: 16px; + } + + &-m { + font-size: 20px; + } + + &-l { + font-size: 24px; + } + + &-xl { + font-size: 28px; + } + } + + &-scroll-content { + @include flex-column-container($overflow: hidden); + .mat-mdc-card-content { + overflow: auto; + } + } +} + +.mat-mdc-card.imx-centered-filled-card { + flex: 1 1 auto; + display: flex; + flex-direction: column; + overflow: hidden; + margin: 3px; + display: flex; +} + +.imx-padding-for-cards { + padding-left: 3px; + padding-bottom: 3px; +} + +/* Dark theme */ +.eui-dark-theme { + .mat-mdc-card.imx-card, + div.imx-card { + &-border { + border: 1px solid $color-gray-60; + } + } +} + +/* High-contrast theme */ +.eui-contrast-theme { + .mat-mdc-card.imx-card, + div.imx-card { + &-border { + border: 1px solid $color-gray-0; + } + } +} + +/* Dark theme + High-contrast theme */ +.eui-dark-theme, +.eui-contrast-theme { + .mat-mdc-card.imx-card, + div.imx-card { + &-data-explorer { + &-header { + &-bg { + background-color: $color-blue-80; + } + + .eui-icon { + color: $color-gray-0; + } + } + } + + &-select { + &.selected { + border: 3px solid $color-blue-40; + } + } + } +} diff --git a/imxweb/shared/scss/components/chart.scss b/imxweb/shared/scss/components/chart.scss new file mode 100644 index 000000000..53ddd8a4b --- /dev/null +++ b/imxweb/shared/scss/components/chart.scss @@ -0,0 +1,63 @@ +/* Elemental UI */ + +/* Angular Material */ + +/* Imx */ + +.imx-chart { + &-container { + display: flex; + + &-center { + @extend .imx-chart-container; + justify-content: center; + } + + &-full { + width: 100%; + height: 100%; + margin: auto; + overflow: hidden; + } + } + + &-card { + display: flex; + flex-grow: 1; + + &-border { + @include eui-elevation-1; + @extend .imx-chart-card; + border: 1px solid $color-gray-10; + } + } + + &-title { + font-weight: 400; + margin-bottom: 10px; + } + + &-paginator { + display: flex; + align-items: center; + justify-content: flex-end; + } + + &-zoom { + cursor: crosshair; + } +} + +/* Dark theme */ +.eui-dark-theme { + .imx-chart-card-border { + border: 1px solid $color-gray-50; + } +} + +/* High-contrast theme */ +.eui-contrast-theme { + .imx-chart-card-border { + border: 1px solid $color-gray-70; + } +} diff --git a/imxweb/shared/scss/components/checkbox.scss b/imxweb/shared/scss/components/checkbox.scss new file mode 100644 index 000000000..12b9856c0 --- /dev/null +++ b/imxweb/shared/scss/components/checkbox.scss @@ -0,0 +1,67 @@ +/* Elemental UI */ + +/* Angular Material */ +.mat-mdc-checkbox-disabled { + cursor: not-allowed; +} + +/* Imx */ +.imx-checkbox { + &-info { + .mat-mdc-checkbox-frame { + color: $color-blue-60; + } + } + + &-new { + .mat-mdc-checkbox-frame { + color: $color-green-60; + } + } + + &-warning { + .mat-mdc-checkbox-frame { + color: $color-orange-60; + } + } + + &-error { + .mat-mdc-checkbox-frame { + color: $color-red-60; + } + } +} + +/* Dark theme */ + +/* High-contrast theme */ + +/* Dark theme + High-contrast theme */ +.eui-dark-theme, +.eui-contrast-theme { + .imx-checkbox { + &-info { + .mat-mdc-checkbox-frame { + color: $color-blue-40; + } + } + + &-new { + .mat-mdc-checkbox-frame { + color: $color-green-40; + } + } + + &-warning { + .mat-mdc-checkbox-frame { + color: $color-orange-40; + } + } + + &-error { + .mat-mdc-checkbox-frame { + color: $color-red-40; + } + } + } +} diff --git a/imxweb/shared/scss/components/chips.scss b/imxweb/shared/scss/components/chips.scss new file mode 100644 index 000000000..3c07e8355 --- /dev/null +++ b/imxweb/shared/scss/components/chips.scss @@ -0,0 +1,58 @@ +/* Elemental UI */ + +/* Angular Material */ +.mat-mdc-chip { + &-value { + max-width: 200px; + white-space: nowrap; + text-overflow: ellipsis; + overflow: hidden; + } + + &-icon { + flex: 0 0 30px; + } +} +.mdc-evolution-chip-set__chips { + align-items: center; +} + +/* Imx */ +.imx-chip { + &-info { + &.mat-mdc-chip.mat-mdc-standard-chip { + background-color: $color-blue-60; + } + } +} + +/* Dark theme */ + +/* High-contrast theme */ +.eui-contrast-theme { + .mat-mdc-chip { + border: 1px solid $color-gray-0; + + span.tag-name { + color: $color-gray-0; + } + } +} + +/* Dark + High-contrast theme */ +.eui-dark-theme, +.eui-contrast-theme { + .imx-chip { + &-info { + &.mat-mdc-chip.mat-mdc-standard-chip { + background-color: $color-blue-40; + + span.tag-name, + .eui-icon.remove, + .imx-icon-chip-remove { + color: $color-gray-80; + } + } + } + } +} diff --git a/imxweb/shared/scss/components/clickable.scss b/imxweb/shared/scss/components/clickable.scss new file mode 100644 index 000000000..62f1d111e --- /dev/null +++ b/imxweb/shared/scss/components/clickable.scss @@ -0,0 +1,12 @@ +/* Elemental UI */ + +/* Angular Material */ + +/* Imx */ +.imx-clickable { + cursor: pointer; +} + +/* Dark theme */ + +/* High-contrast theme */ diff --git a/imxweb/shared/scss/components/data-source-toolbar.scss b/imxweb/shared/scss/components/data-source-toolbar.scss new file mode 100644 index 000000000..fb2138ed4 --- /dev/null +++ b/imxweb/shared/scss/components/data-source-toolbar.scss @@ -0,0 +1,21 @@ +/* Elemental UI */ + +/* Angular Material */ + +/* Imx */ +imx-data-source-toolbar { + &-custom { + display: flex; + align-items: center; + height: 100%; + margin-right: 5px; + + button { + height: 100%; + + &:not(:last-of-type) { + margin-right: 5px; + } + } + } +} diff --git a/imxweb/shared/scss/components/date-picker.scss b/imxweb/shared/scss/components/date-picker.scss new file mode 100644 index 000000000..f2d1431f4 --- /dev/null +++ b/imxweb/shared/scss/components/date-picker.scss @@ -0,0 +1,28 @@ +/* Elemental UI */ +eui-date-picker { + .mat-mdc-form-field { + .mat-mdc-form-field-wrapper { + padding: 0; + + .mat-mdc-form-field-subscript-wrapper { + margin: 0; + } + + .mat-mdc-form-field-flex { + padding: 0 0 0 10px; + + .mat-mdc-form-field-infix { + padding: 5px 0 5px 0; + } + } + } + } +} + +/* Angular Material */ + +/* Imx */ + +/* Dark theme */ + +/* High-contrast theme */ diff --git a/imxweb/shared/scss/components/dialog.scss b/imxweb/shared/scss/components/dialog.scss new file mode 100644 index 000000000..0fcec0e67 --- /dev/null +++ b/imxweb/shared/scss/components/dialog.scss @@ -0,0 +1,42 @@ +@import 'base/mixins'; + +/* Elemental UI */ + +/* Angular Material */ +.mat-mdc-dialog-container { + .mat-mdc-dialog-title { + display: flex; + align-items: baseline; + margin: 0 0 10px; + } + + .mat-mdc-dialog-actions { + justify-content: flex-end; + + .justify-start { + margin-right: auto; + } + } +} + +/* Imx */ +.imx-dialog { + &-title { + font-weight: 600; + font-size: 24px; + } + + &-content { + &-flex { + &-column { + &.mat-mdc-dialog-content { + @include flex-column-container($overflow: auto, $height: 100%); + } + } + } + } +} + +/* Dark theme */ + +/* High-contrast theme */ diff --git a/imxweb/shared/scss/components/divider.scss b/imxweb/shared/scss/components/divider.scss new file mode 100644 index 000000000..dd0ac9bc0 --- /dev/null +++ b/imxweb/shared/scss/components/divider.scss @@ -0,0 +1,19 @@ +/* Elemental UI */ + +/* Angular Material */ +mat-divider.mat-mdc-divider-horizontal { + position: inherit; +} + +/* Imx */ +.imx-divider { + &-dashed { + mat-divider.mat-mdc-divider-horizontal { + border-top-style: dashed; + } + } +} + +/* Dark theme */ + +/* High-contrast theme */ diff --git a/imxweb/shared/scss/components/download.scss b/imxweb/shared/scss/components/download.scss new file mode 100644 index 000000000..d8dff3dbd --- /dev/null +++ b/imxweb/shared/scss/components/download.scss @@ -0,0 +1,9 @@ +/* Elemental UI */ + +/* Angular Material */ + +/* Imx */ + +/* Dark theme */ + +/* High-contrast theme */ diff --git a/imxweb/shared/scss/components/expansion-panel.scss b/imxweb/shared/scss/components/expansion-panel.scss new file mode 100644 index 000000000..e1d69783c --- /dev/null +++ b/imxweb/shared/scss/components/expansion-panel.scss @@ -0,0 +1,109 @@ +@import 'base/mixins'; + +/* Elemental UI */ + +/* Angular Material */ + +/* Imx */ +mat-expansion-panel.imx-expansion-panel { + margin-bottom: 20px; + + &-violation { + @extend .imx-expansion-panel; + + .mat-expansion-panel-header-title { + font-size: 24px; + font-weight: 500; + } + } + + &-page { + .mat-expansion-panel-header, + .mat-expansion-panel-header.mat-expanded { + height: 50px; + } + .mat-expansion-panel-header-title { + font-size: 20px; + } + } + + &-filter { + .mat-expansion-panel-body { + @include flex-column-container(); + background-color: $color-gray-2; + padding-top: 10px; + } + + .mat-expansion-panel-header-title { + align-items: center; + margin-right: 0; + } + } + + &-bulk-item { + @extend .imx-expansion-panel; + margin-top: 20px; + + .mat-expansion-panel { + &-header { + min-height: 24px; + height: auto; + padding: 12px 24px; + + &-title { + flex-basis: auto; + } + + &-description { + justify-content: end; + } + } + } + } + + &-header { + &-fix { + .mat-expansion-panel-header, + .mat-expansion-panel-header.mat-expanded { + height: 50px; + } + } + } +} + +mat-expansion-panel.imx-expansion-panel { + &-page { + .mat-expansion-panel-header{ + background-color: $color-gray-20; + color: $color-gray-100; + } + .mat-expansion-panel-header.mat-expanded{ + background-color: $color-blue-40; + color: $color-gray-0; + + } + + } +} + +/* Dark theme */ +.eui-dark-theme { + mat-expansion-panel.imx-expansion-panel { + &-filter { + .mat-expansion-panel-body { + background-color: $color-gray-80; + } + } + } +} + +/* High-contrast theme */ +.eui-contrast-theme { + mat-expansion-panel.imx-expansion-panel { + &-filter { + .mat-expansion-panel-body { + background-color: $color-gray-100; + } + } + } +} diff --git a/imxweb/shared/scss/components/form-field.scss b/imxweb/shared/scss/components/form-field.scss new file mode 100644 index 000000000..48d6e2c5a --- /dev/null +++ b/imxweb/shared/scss/components/form-field.scss @@ -0,0 +1,100 @@ +/* Elemental UI */ +/* Angular Material */ + +mat-form-field:not(.eui-search, .eui-input--no-margin) { + &.mat-mdc-form-field { + .mat-mdc-text-field-wrapper { + margin-top: 5px; + } + &-prefix { + .mat-mdc-spinner { + margin-right: 10px; + } + + .mat-mdc-spinner, + .mat-mdc-spinner svg { + max-height: 16px; + max-width: 16px; + } + } + + &-underline { + position: static; + } + &-subscript-wrapper { + position: static; + } + .input-hidden { + display: none; + } + } +} +.eui-date-picker, .eui-form-field{ + .mat-mdc-form-field { + .mat-mdc-text-field-wrapper { + margin-top: 0px !important; + } + } +} +.mat-mdc-autocomplete-panel { + .eui-time-picker-option { + padding: 8px 6px; + } +} +.mdc-notched-outline__trailing { + margin-right: 1px; +} + +/* Imx */ +.imx-form-field { + &-width { + &-150 { + width: 150px; + } + + &-full { + width: 100%; + } + } + + &-flex.mat-mdc-form-field { + flex: 1; + } + + &-matsuffix { + &.mat-mdc-form-field { + [matsuffix] { + display: flex; + margin-left: 10px; // set margin to infix + + eui-icon { + margin-top: unset; // correct margin-top: -16px from _material_fixes.scss + display: block; + } + + mat-spinner { + display: inline-flex; + margin-right: 10px; + } + } + } + } +} + +/* Dark theme */ + +.eui-dark-theme { + .mat-mdc-form-field { + .mat-mdc-text-field-wrapper { + background-color: inherit !important; + } + } +} +/* High-contrast theme */ +.eui-contrast-theme { + .mat-mdc-form-field { + .mat-mdc-text-field-wrapper { + background-color: inherit !important; + } + } +} diff --git a/imxweb/shared/scss/components/icon.scss b/imxweb/shared/scss/components/icon.scss new file mode 100644 index 000000000..393f727f6 --- /dev/null +++ b/imxweb/shared/scss/components/icon.scss @@ -0,0 +1,216 @@ +@import '@elemental-ui/core/src/styles/_eui_palette.scss'; +@import 'base/mixins'; + +/* Elemental UI */ +/* https://elemental.dev.oneidentity.com/design/cadence-icons */ +/* size = + "s" => 16px + "m" => 24px (default) + "l" => 36px + "xl" => 48px */ + +.eui-sidesheet-actions { + button:not(.mat-icon-button) { + .mat-mdc-icon, + eui-icon.medium { + font-size: 14px; + margin-right: 4px; + } + } +} +/* Angular Material */ + +/* Imx */ +.imx-icon { + &-size { + @for $i from 1 through 100 { + &-#{$i} { + &.mat-mdc-icon { + font-size: #{$i}px; + width: #{$i}px; + height: #{$i}px; + } + + &.eui-icon.small, + &.eui-icon.medium, + &.eui-icon.large, + &.eui-icon.x-large { + font-size: #{$i}px; + } + } + } + } + + &-white { + color: $color-gray-0; + } + + &-black { + color: $color-gray-100; + } + + &-info { + color: $color-blue-60; + } + + &-new { + color: $color-green-60; + } + + &-warning { + color: $color-orange-60; + } + + &-error { + color: $color-red-60; + } + + &-disabled { + cursor: default; + color: $color-gray-30; + } + + &-hidden { + visibility: hidden; + } + + &-visible { + visibility: visible; + } + + &-upload { + &.eui-icon.medium { + font-size: 200px; + line-height: 200px; + } + } + + &-circle { + color: $color-gray-80; + background-color: $color-gray-20; + opacity: 0.6; + border-radius: 50%; + text-align: center; + line-height: 35px; + min-width: 35px; + min-height: 35px; + margin-right: 12px; + } + + &-table-container { + padding-right: 15px; + + .imx-icon-table { + display: flex; + align-items: center; + color: $color-gray-60; + font-weight: 600; + height: 14px; + + .mat-mdc-icon { + width: auto; + } + + .mat-mdc-icon, + .eui-icon { + padding-right: 6px; + } + + &:not(:first-of-type) { + margin-left: 8px; + border-left: 1px solid $color-gray-20; + padding-left: 8px; + } + } + } + + &-selector-list { + @include flex-row-container; + + eui-icon { + color: $color-gray-40; + user-select: none; + } + } + + &-chip-remove { + color: $color-gray-60; + opacity: 0.3; + font-size: 18px; + margin-right: -10px; + } +} + +.imx-no-results { + .eui-icon { + font-size: 100px !important; + line-height: 100px; + color: $color-gray-10; + } +} + +/* Dark theme */ +.eui-dark-theme { + .imx-no-results { + .eui-icon { + color: $color-gray-20; + } + } + + .imx-icon { + &-circle { + color: $color-gray-20; + background-color: $color-gray-80; + } + } +} + +/* High-contrast theme */ +.eui-contrast-theme { + .imx-no-results { + .eui-icon { + color: $color-gray-10; + } + } + + .imx-icon { + &-circle { + color: $color-gray-100; + background-color: $color-gray-0; + opacity: 1; + } + } +} + +/* Dark + High-contrast theme */ +.eui-dark-theme, +.eui-contrast-theme { + .imx-icon-table-container { + .imx-icon-table { + color: $color-gray-10; + } + } + + .imx-icon { + &-info { + color: $color-blue-40; + } + + &-new { + color: $color-green-40; + } + + &-warning { + color: $color-orange-40; + } + + &-error { + color: $color-red-40; + } + + &-chip-remove { + opacity: unset; + color: $color-gray-0; + } + } +} diff --git a/imxweb/shared/scss/components/input.scss b/imxweb/shared/scss/components/input.scss new file mode 100644 index 000000000..38a71b094 --- /dev/null +++ b/imxweb/shared/scss/components/input.scss @@ -0,0 +1,64 @@ +/* Elemental UI */ + +/* Angular Material */ + +/* Imx */ +.imx-input { + &-info { + color: $color-blue-60; + } + + &-file-hidden { + &[type='file'] { + display: none; + } + } + + &-login { + width: $IMX_PropertyLabel_Width; + box-sizing: content-box; + height: 30px; + padding-left: 6px; + width: calc(40vw - 6px); + } + + &-searchbar { + border: 0 solid transparent !important; + color: inherit; + background-color: transparent; + + &::placeholder { + font-style: italic; + } + + &::-ms-clear { + /* hide input-clear button (the 'X') in > IE 10 */ + display: none; + width: 0; + height: 0; + } + } +} + +.imx-textarea { + &-content-box { + &.mat-mdc-input-element.cdk-textarea-autosize { + box-sizing: content-box; + } + } +} + +/* Dark + High-contrast theme */ +.eui-dark-theme, +.eui-contrast-theme { + .imx-input { + &-info { + color: $color-blue-40; + } + + &-login { + border: none; + color: $color-gray-0; + } + } +} diff --git a/imxweb/shared/scss/components/layout-grid.scss b/imxweb/shared/scss/components/layout-grid.scss new file mode 100644 index 000000000..d8dff3dbd --- /dev/null +++ b/imxweb/shared/scss/components/layout-grid.scss @@ -0,0 +1,9 @@ +/* Elemental UI */ + +/* Angular Material */ + +/* Imx */ + +/* Dark theme */ + +/* High-contrast theme */ diff --git a/imxweb/shared/scss/components/list.scss b/imxweb/shared/scss/components/list.scss new file mode 100644 index 000000000..ebb530e2e --- /dev/null +++ b/imxweb/shared/scss/components/list.scss @@ -0,0 +1,103 @@ +/* Elemental UI */ + +/* Angular Material */ +.mat-mdc-list.mat-mdc-list-base { + .mat-mdc-list-option, + .mat-mdc-list-item { + height: auto; + } +} + +/* Imx */ +.imx-list { + &-subtitle { + color: $color-gray-40; + font-size: smaller; + font-style: italic; + } + + &-multi-action.mat-mdc-list-base { + overflow: auto; + + mat-list-item { + &.mat-mdc-2-line { + font-size: 14px; + margin-bottom: 10px; + height: auto; + } + + .mat-mdc-line { + white-space: normal; + } + + .imx-list-item-subtitle { + &.mat-mdc-line:nth-child(n + 2) { + @extend .imx-list-subtitle; + } + } + } + + mat-list-option { + font-size: smaller; + + .mat-mdc-list-text { + .imx-list-option-subtitle { + @extend .imx-list-subtitle; + font-size: 11px; + font-style: italic; + margin-bottom: 10px; + } + } + } + } + + &-data-tree { + .mat-mdc-list-option { + background-color: transparent; + + &:hover { + background-color: $color-gray-2; + } + } + } +} +.imx-list-container-reverse{ + .mat-mdc-list-option{ + flex-direction: row-reverse; + .mdc-list-item__end{ + margin-left: 0; + } + } +} + +/* Dark theme */ +.eui-dark-theme { + .imx-list { + &-subtitle { + color: $color-gray-10; + } + + &-data-tree { + .mat-mdc-list-option:hover { + background-color: $color-gray-60; + } + } + } +} + +/* High-contrast theme */ +.eui-contrast-theme { + .imx-list { + &-subtitle { + color: $color-gray-0; + } + + &-data-tree { + .mat-mdc-list-option:hover { + background-color: $color-gray-80; + } + } + } +} + +/* Dark + High-contrast theme */ diff --git a/imxweb/shared/scss/components/logo.scss b/imxweb/shared/scss/components/logo.scss new file mode 100644 index 000000000..73046b17d --- /dev/null +++ b/imxweb/shared/scss/components/logo.scss @@ -0,0 +1,14 @@ +/* Elemental UI */ +eui-logo { + &.no-logo { + display: none; + } +} + +/* Angular Material */ + +/* Imx */ + +/* Dark theme */ + +/* High-contrast theme */ diff --git a/imxweb/shared/scss/components/masthead.scss b/imxweb/shared/scss/components/masthead.scss new file mode 100644 index 000000000..d8c803bc2 --- /dev/null +++ b/imxweb/shared/scss/components/masthead.scss @@ -0,0 +1,41 @@ +/* Elemental UI */ + +/* Angular Material */ + +/* Imx */ + +/* Dark theme */ + +/* High-contrast theme */ + +/* Dark + High-contrast theme */ +.eui-dark-theme, +.eui-contrast-theme { + eui-masthead { + header.eui-masthead { + background-color: $color-blue-80; + } + + .mat-toolbar.mat-primary { + background-color: $color-blue-80; + color: $color-gray-0; + } + } +} + +/* Responsivity */ +@media only screen and (max-width: 768px) { + eui-masthead { + .mat-toolbar { + .mat-toolbar-row { + width: unset; + justify-content: center; + } + + .imx-masthead-space, + .imx-masthead--controls { + display: none; + } + } + } +} diff --git a/imxweb/shared/scss/components/menu.scss b/imxweb/shared/scss/components/menu.scss new file mode 100644 index 000000000..09c0bc828 --- /dev/null +++ b/imxweb/shared/scss/components/menu.scss @@ -0,0 +1,29 @@ +/* Elemental UI */ + +/* Angular Material */ + +/* Imx */ +.imx-menu { + &-with-spinner { + display: flex; + flex-direction: row; + align-items: center; + margin-right: 16px; + + .mat-mdc-progress-spinner { + overflow: visible; + } + } +} +.imx-config-menu{ + .mat-mdc-menu-item-text{ + display:flex; + align-items: center; + justify-content: space-between; + width: 100%; + } +} + +/* Dark theme */ + +/* High-contrast theme */ diff --git a/imxweb/shared/scss/components/paginator.scss b/imxweb/shared/scss/components/paginator.scss new file mode 100644 index 000000000..b9f05dbb6 --- /dev/null +++ b/imxweb/shared/scss/components/paginator.scss @@ -0,0 +1,26 @@ +/* Elemental UI */ + +/* Angular Material */ +mat-paginator { + box-shadow: none; + + &.hide-paginator { + display: none; + } + &.mat-mdc-paginator { + border-top: unset; + } +} + +.mat-mdc-paginator-navigation-next.mat-icon-button, +.mat-mdc-paginator-navigation-previous.mat-icon-button { + background: transparent; + width: 16px; + margin-right: 10px; +} + +/* Imx */ + +/* Dark theme */ + +/* High-contrast theme */ diff --git a/imxweb/shared/scss/components/progress-bar.scss b/imxweb/shared/scss/components/progress-bar.scss new file mode 100644 index 000000000..31a411226 --- /dev/null +++ b/imxweb/shared/scss/components/progress-bar.scss @@ -0,0 +1,66 @@ +@mixin standard-progress() { + flex: 1 1 auto; + width: auto; + align-self: center; +} + +/* Elemental UI */ + +/* Angular Material */ +mat-progress-bar { + @include standard-progress(); +} + +/* Imx */ + +.imx-child-progress-bar { + margin-left: 10px; + max-width: 60%; +} + +.imx-tree-text { + mat-progress-bar { + @include standard-progress(); + } +} + +imx-progress { + flex: 1 1 auto; +} + +td .imx-progress-bar { + &-container { + padding: 0 10px; + } +} + +.imx-progress-bar { + display: flex; + column-gap: 5px; + align-items: baseline; + + .mat-mdc-progress-bar { + width: 200px; + flex-grow: 0; + } + + &-container { + display: flex; + flex-direction: column; + } + + &-texts { + font-size: 12px; + text-align: left; + } + + &-line { + display: flex; + flex-direction: row; + align-items: center; + } +} + +/* Dark theme */ + +/* High-contrast theme */ diff --git a/imxweb/shared/scss/components/radio-button.scss b/imxweb/shared/scss/components/radio-button.scss new file mode 100644 index 000000000..9057a255f --- /dev/null +++ b/imxweb/shared/scss/components/radio-button.scss @@ -0,0 +1,61 @@ +/* Elemental UI */ + +/* Angular Material */ + +.mat-mdc-radio-group { + display: flex; + gap: 25px; + min-height: 30px; +} + +.mat-mdc-radio-button { + display: block; + margin-right: 5px; + .mdc-form-field{ + align-items: center !important; + } + .mdc-label { + display: flex; + flex-direction: column; + padding: 0; + .imx-radio-label-strong{ + font-weight: 600; + } + } +} + +/* Imx */ + +.imx-filter-radio-group { + display: block; +} + +.imx-radio-group-flex-column { + flex-direction: column; + margin-bottom: 15px; + gap: 15px; +} + +.imx-filter-radio-button.mat-mdc-radio-button { + display: block; + + label.mat-mdc-radio-label { + white-space: normal; + } +} + +.imx-fk-table-radio { + > *:not(:last-child) { + margin-right: 30px; + } +} + +/* Dark theme */ + +/* High-contrast theme */ + +.eui-contrast-theme { + ::ng-deep .mat-mdc-radio-outer-circle { + border-color: $color-gray-100; + } +} diff --git a/imxweb/shared/scss/components/ripple.scss b/imxweb/shared/scss/components/ripple.scss new file mode 100644 index 000000000..998e13925 --- /dev/null +++ b/imxweb/shared/scss/components/ripple.scss @@ -0,0 +1,13 @@ +/* Elemental UI */ + +/* Angular Material */ + +.mat-mdc-ripple-element { + background: transparent !important; +} + +/* Imx */ + +/* Dark theme */ + +/* High-contrast theme */ diff --git a/imxweb/shared/scss/components/scrollbar.scss b/imxweb/shared/scss/components/scrollbar.scss new file mode 100644 index 000000000..8f89bc2fe --- /dev/null +++ b/imxweb/shared/scss/components/scrollbar.scss @@ -0,0 +1,14 @@ +/* Elemental UI */ + +/* Angular Material */ + +/* Imx */ + +.imx-scroll-pad > .eui-scroll-container { + padding-right: 5px; +} + +.imx-scroll-pad-left > .eui-scroll-container { + padding-left: 5px; + padding-right: 10px; +} diff --git a/imxweb/shared/scss/components/search.scss b/imxweb/shared/scss/components/search.scss new file mode 100644 index 000000000..8ad49f9a1 --- /dev/null +++ b/imxweb/shared/scss/components/search.scss @@ -0,0 +1,19 @@ +/* Elemental UI */ + +.eui-search { + width: 100%; + + &.mat-mdc-form-field.mat-mdc-form-field-appearance-outline { + min-width: 280px; + flex: 1; + } +} + +/* Angular Material */ + +/* Imx */ + +.imx-multi-select { + width: 100%; + display: flex; +} diff --git a/imxweb/shared/scss/components/select.scss b/imxweb/shared/scss/components/select.scss new file mode 100644 index 000000000..2d8fb8b9c --- /dev/null +++ b/imxweb/shared/scss/components/select.scss @@ -0,0 +1,115 @@ +/* Elemental UI */ +eui-select { + .mat-mdc-form-field { + &-wrapper { + padding: 0; + } + } +} + +/* Angular Material */ + +.mat-mdc-form-field-infix .mat-mdc-select-trigger { + vertical-align: middle; + + .mat-mdc-select-arrow-wrapper { + vertical-align: bottom; + } +} + +// Until elemental changes the default to use the accent theme, important is needed +.mat-mdc-option.mdc-list-item--selected:not(.mdc-list-item--disabled) { + color: $color-orange-60 !important; +} + +.mat-primary .mat-pseudo-checkbox-checked.mat-pseudo-checkbox-full { + background-color: $color-orange-60 !important; +} + +.cdk-overlay-pane .mat-mdc-select-panel .mat-mdc-option { + line-height: normal; + + .mat-mdc-option-text { + white-space: normal; + margin: 5px 16px; + } +} + +/* Imx */ +.imx-data-source-filter-menu { + .mat-mdc-select .mat-mdc-select-trigger { + margin-top: 5px; + } + + .mat-mdc-select .mat-mdc-select-value { + max-width: none; + white-space: normal; + .mat-mdc-select-value-text { + white-space: normal; + } + } +} + +.mat-mdc-option.imx-candidate-option { + line-height: 1.5em; + display: flex; + width: 100%; + height: 50px; + + .imx-candidate-item { + width: 100%; + + .imx-candidate-content { + width: 100%; + overflow: hidden; + + .imx-candidate-display { + font-size: 14px; + line-height: 14px; + text-overflow: ellipsis; + overflow: hidden; + width: 100vw; + } + + .imx-candidate-longdisplay { + font-size: 12px; + text-overflow: ellipsis; + overflow: hidden; + } + } + } +} + +.imx-export-column--field { + width: 100%; + margin: 0 10px; +} + +.imx-eui-select-100 { + width: 100%; +} + +.imx-eui-select-toolbar { + width: 110px; +} + +.imx-container-search { + &--hidden { + display: none; + } +} + +/* Dark theme */ +.eui-dark-theme, +.eui-contrast-theme { + // Until elemental changes the default to use the accent theme, important is needed + .mat-option.mat-selected:not(.mat-option-disabled) { + color: $color-orange-40 !important; + } + + .mat-primary .mat-pseudo-checkbox-checked.mat-pseudo-checkbox-full { + background-color: $color-orange-40 !important; + } +} + +/* High-contrast theme */ diff --git a/imxweb/shared/scss/components/side-navigation.scss b/imxweb/shared/scss/components/side-navigation.scss new file mode 100644 index 000000000..fdf3bd668 --- /dev/null +++ b/imxweb/shared/scss/components/side-navigation.scss @@ -0,0 +1,438 @@ +@import '@elemental-ui/core/src/styles/_eui_palette.scss'; +:host { + height: 100%; +} + +@mixin side() { + display: flex; + flex-direction: column; + height: 100%; +} + +/* Imx */ + +.imx-snavigation { + height: 100%; + + .mat-sidenav-container { + height: 100%; + + .mat-sidenav { + width: 230px; + + .imx-snavigation-side { + @include side(); + + .imx-snavigation-side-toggle { + display: none; + padding: 16px 12px 0; + margin-bottom: 10px; + + .mat-mdc-button { + min-width: 0; + padding: 0 4px; + height: 28px; + + .mat-mdc-icon { + margin-top: -12px; + } + } + } + + .imx-snavigation-side-content { + flex: 1; + padding: 20px; + padding-bottom: 16px; + overflow-x: hidden; + + .imx-snavigation-side-heading { + display: flex; + align-items: center; + margin-bottom: 10px; + white-space: nowrap; + h2{ + font-size: 14px; + font-weight: 700; + } + imx-help-contextual { + display: inline-block; + } + } + + .imx-snavigation-item { + margin: 0 -20px; + padding: 10px 20px; + display: flex; + align-items: center; + justify-content: flex-start; + cursor: pointer; + + & > .eui-icon { + margin-right: 8px; + } + + & > span { + flex: 1; + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; + } + } + } + } + } + + .mat-sidenav-content { + padding: 20px; + position: relative; + display: flex; + flex-direction: column; + + &.imx-snavigation--backdrop-showing { + overflow: hidden; + } + + .imx-snavigation-backdrop { + position: absolute; + top: 0; + left: 0; + right: 0; + bottom: 0; + background-color: rgba($color-gray-100, 0.32); + z-index: 200; + } + .mat-mdc-card{ + margin: 2px; + } + } + } +} + +.imx-flex-container { + display: flex; + align-items: stretch; + margin-top: 2em; + flex-direction: column; + + &-100 { + height: 100%; + } +} + +.imx-flex-container { + display: flex; + align-items: stretch; + margin-top: 2em; + flex-direction: column; +} + +imx-sidenav-tree { + .imx-snavigation { + width: 100% !important; + } +} + +/**/ + +.imx-snavigation-tree.mat-mdc-card { + height: 100%; + padding: 0; + + .mat-sidenav-container { + height: 100%; + border-radius: 4px; + + .mat-sidenav { + width: 100%; + overflow: hidden; + border-radius: 4px; + border-right: none; + + .mat-drawer-inner-container { + overflow: unset; + } + .imx-snavigation-side { + @include side(); + + .imx-snavigation-side-toggle { + display: flex; + justify-content: flex-end; + margin: 5px 0; + + .imx-snavigation-side-toggle-header { + margin: auto; + margin-left: 24px; + font-size: 16px; + line-height: 20px; + font-weight: 600; + } + + .toolbar--hidden { + width: 0; + } + + .expand-control-button { + .mdc-button__label { + width: 100%; + height: 100%; + display: flex; + flex-direction: column; + justify-content: center; + } + + .rotate-90 { + margin: auto; + rotate: -90deg; + translate: 0 100%; + width: inherit; + -webkit-backface-visibility: hidden; // Handle the anti-aliasing from chrome on rotations + backface-visibility: hidden; + font-size: 16px; + white-space: nowrap; + } + } + } + + .imx-snavigation-side-content--center { + justify-content: center; + display: flex; + align-items: center; + } + + .imx-no-results { + display: flex; + flex-direction: column; + align-items: center; + } + + .imx-snavigation-side-content { + height: 100%; + overflow: auto; + margin: 0 24px 24px; + } + } + + &:not(.imx-snavigation-side--expanded) { + .imx-snavigation-side-toggle { + height: 100%; + margin: 0; + } + .imx-snavigation-side-toggle-header, + .imx-snavigation-side-content { + display: none; + } + .expand-control-button { + height: 100%; + width: 48px; + min-width: unset; + padding: 0; + display: flex; + justify-content: center; + flex-direction: column; + align-items: center; + border-radius: 0; + .mat-mdc-button-persistent-ripple { + border-radius: 0; + } + } + } + + &:is(.imx-snavigation-side--expanded) { + .mat-mdc-drawer-inner-container { + overflow: hidden; + } + .imx-snavigation-side-toggle { + align-items: center; + } + + .expand-control-button { + margin-right: 16px; + } + .rotate-90 { + display: none; + } + } + } + + .mat-sidenav-content { + padding: 32px; + position: relative; + display: flex; + flex-direction: column; + } + + // .mat-mdc-drawer-side seems to have a scss style - seems to leak from material + .mat-mdc-drawer-side { + border-right: none; + } + } + &.mat-mdc-card--hidden { + .mat-sidenav-container { + .mat-sidenav { + .imx-snavigation-side { + .imx-snavigation-side-content { + margin: 0; + } + } + } + } + } +} + +@media only screen and (max-width: 768px) { + .imx-snavigation .mat-sidenav-container { + .mat-sidenav { + transition: width 0.5s; + + .imx-snavigation-side { + .imx-snavigation-side-toggle { + display: block; + } + .imx-snavigation-side-content { + padding: 16px; + } + } + + &:not(.imx-snavigation-side--expanded) { + width: 58px; + + .imx-snavigation-side-content { + display: none; + } + } + } + + .mat-sidenav-content { + padding: 16px; + } + } +} + +// Theming + +.imx-snavigation { + .mat-sidenav-container { + background-color: $color-gray-2; + .mat-sidenav { + .imx-snavigation-side { + .imx-snavigation-side-content { + .imx-snavigation-item { + & > .eui-icon { + margin-right: 8px; + color: rgba($color-gray-100, 0.4); + } + + &:hover:not(.imx-snavigation-item--selected) { + background-color: rgba($color-blue-40, 0.5); + } + + &.imx-snavigation-item--selected { + background-color: $color-blue-60; + color: $color-gray-0; + } + } + } + } + } + } +} + +.imx-snavigation-tree.mat-mdc-card { + .imx-snavigation-side-toggle-header { + color: $color-gray-60; + } + + .mat-mdc-tree { + background-color: transparent; + } + + .imx-snavigation.imx-snavigation--expanded { + border: 1px solid $color-gray-20; + &.mat-mdc-card--hidden { + border: none; + box-shadow: none; + } + } + + .mat-sidenav:not(.imx-snavigation-side--expanded) { + .expand-control-button { + background-color: $color-blue-10; + border: 1px solid $color-blue-20; + } + } + .imx-snavigation-side-content { + background-color: $color-blue-10; + border: 1px solid $color-blue-20; + } +} + +/* Dark theme */ +.eui-dark-theme { + .imx-snavigation { + .mat-sidenav-container { + background-color: $color-gray-80; + } + } + + .mat-sidenav-content { + background: $color-gray-80; + } + + .imx-snavigation-tree.mat-mdc-card { + border: 1px solid $color-gray-60; + + .imx-snavigation-side-toggle-header { + color: $color-gray-20; + } + + .imx-snavigation.imx-snavigation--expanded { + border: 1px solid $color-gray-60; + } + + .mat-sidenav:not(.imx-snavigation-side--expanded) { + .expand-control-button { + background-color: $color-blue-80; + border: 1px solid $color-blue-60; + } + } + .imx-snavigation-side-content { + background-color: $color-blue-80; + border: 1px solid $color-blue-60; + } + } +} + +/* High-contrast theme */ +.eui-contrast-theme { + .imx-snavigation { + .mat-sidenav-container { + background-color: $color-gray-100; + } + } + + .mat-sidenav-content { + background: $color-gray-100; + } + .imx-snavigation-tree.mat-mdc-card { + border: 1px solid $color-gray-60; + + .imx-snavigation-side-toggle-header { + color: $color-gray-0; + } + + .imx-snavigation.imx-snavigation--expanded { + border: 1px solid $color-gray-60; + } + + .mat-sidenav:not(.imx-snavigation-side--expanded) { + .expand-control-button { + background-color: $color-gray-90; + border: 1px solid $color-gray-0; + } + } + .imx-snavigation-side-content { + background-color: $color-gray-90; + border: 1px solid $color-gray-0; + } + } +} diff --git a/imxweb/shared/scss/components/sidesheet.scss b/imxweb/shared/scss/components/sidesheet.scss new file mode 100644 index 000000000..cfcb854b9 --- /dev/null +++ b/imxweb/shared/scss/components/sidesheet.scss @@ -0,0 +1,61 @@ +@import 'base/mixins'; +@import 'base/margins-paddings'; + +/* Elemental UI */ +.eui-sidesheet { + .eui-sidesheet-actions { + &--flex { + display: flex; + flex-direction: row; + } + .justify-start { + margin-right: auto; + } + button:not(:last-child):not(.justify-start) { + margin-right: 10px; + } + .mat-mdc-button-base + .mat-mdc-button-base { + margin-left: 0; + } + } +} + +.eui-sidesheet { + max-width: 90% !important; + &__content { + width: 100% !important; + } +} + +/* Angular Material */ + +/* Imx */ +.imx-sidesheet { + &-content { + &-padding-0.eui-sidesheet-content { + padding: 0; + } + + &-flex-container.eui-sidesheet-content { + @include flex-column-container(); + } + + &-flex-container-row.eui-sidesheet-content { + @include flex-row-container(); + } + + &__overflow { + @include flex-column-container($overflow: hidden, $height: inherit); + } + + &__flex { + flex: 1 1 auto; + } + } +} + +@media screen and (max-width: 768px) { + .eui-sidesheet { + max-width: 100% !important; + } +} diff --git a/imxweb/shared/scss/components/slide-toggle.scss b/imxweb/shared/scss/components/slide-toggle.scss new file mode 100644 index 000000000..7f98db56a --- /dev/null +++ b/imxweb/shared/scss/components/slide-toggle.scss @@ -0,0 +1,41 @@ +@import 'base/mixins'; +/* Elemental UI */ + +/* Angular Material */ + +/* Imx */ +form { + .mat-mdc-slide-toggle { + margin-left: 8px; + } +} +.escalation-approver-toggle { + margin: 0.5em; +} + +.imx-slide-toggle { + margin-left: 10px; + margin-top: 13px; + overflow: hidden; + white-space: nowrap; + text-overflow: ellipsis; +} + +.imx-tab-group-slider { + align-self: center; + margin-right: 46px; + font-size: 14px; + font-weight: 400; +} + +.imx-flex-toggle-container { + margin-bottom: 20px; + @include flex-row-container(); + > * { + margin-right: 20px; + } +} + +/* Dark theme */ + +/* High-contrast theme */ diff --git a/imxweb/shared/scss/components/slider.scss b/imxweb/shared/scss/components/slider.scss new file mode 100644 index 000000000..d787059ce --- /dev/null +++ b/imxweb/shared/scss/components/slider.scss @@ -0,0 +1,55 @@ +/* Elemental UI */ + +/* Angular Material */ + +/* Imx */ +.imx-risk-slider { + .mat-mdc-slider-thumb-container { + .mat-mdc-slider-thumb-label { + transform: rotate(45deg); + border-radius: 50% 50% 0; + } + .mat-mdc-slider-thumb { + transform: scale(0); + } + .mat-mdc-slider-thumb-label-text { + opacity: 1; + } + } +} + +.slider-container { + display: flex; + align-items: center; + + .mat-mdc-slider { + width: 300px; + flex-grow: 2; + } + + .slider-label { + &__main { + display: block; + } + &__prefix { + font-size: 14px; + margin-right: 8px; + } + &__suffix { + font-size: 14px; + margin-left: 8px; + } + } +} + +@media only screen and (max-width: 320px) { + .slider-container { + .mat-mdc-slider-horizontal { + min-width: unset; + } + } +} + +/* Dark theme */ + +/* High-contrast theme */ diff --git a/imxweb/shared/scss/components/snackbar.scss b/imxweb/shared/scss/components/snackbar.scss new file mode 100644 index 000000000..d8dff3dbd --- /dev/null +++ b/imxweb/shared/scss/components/snackbar.scss @@ -0,0 +1,9 @@ +/* Elemental UI */ + +/* Angular Material */ + +/* Imx */ + +/* Dark theme */ + +/* High-contrast theme */ diff --git a/imxweb/shared/scss/components/sort-header.scss b/imxweb/shared/scss/components/sort-header.scss new file mode 100644 index 000000000..d8dff3dbd --- /dev/null +++ b/imxweb/shared/scss/components/sort-header.scss @@ -0,0 +1,9 @@ +/* Elemental UI */ + +/* Angular Material */ + +/* Imx */ + +/* Dark theme */ + +/* High-contrast theme */ diff --git a/imxweb/shared/scss/components/spinner.scss b/imxweb/shared/scss/components/spinner.scss new file mode 100644 index 000000000..8cff8498a --- /dev/null +++ b/imxweb/shared/scss/components/spinner.scss @@ -0,0 +1,31 @@ +/* Elemental UI */ + +/* Angular Material */ +mat-spinner { + margin: auto; + align-self: center; +} + +/* Imx */ +.mat-mdc-progress-spinner.imx-spinner-inline { + display: inline-block; +} + +.mat-mdc-progress-spinner.imx-spinner-inline-flex { + display: inline-flex; +} + +.mat-mdc-progress-spinner.imx-sprinner-tile, +.mat-mdc-progress-spinner.imx-sprinner-tile svg { + max-height: 40px; + max-width: 40px; +} + +.imx-small-spinner { + font-size: 16px; + line-height: 16px; +} + +/* Dark theme */ + +/* High-contrast theme */ diff --git a/imxweb/shared/scss/components/stepper.scss b/imxweb/shared/scss/components/stepper.scss new file mode 100644 index 000000000..1be7f2a7a --- /dev/null +++ b/imxweb/shared/scss/components/stepper.scss @@ -0,0 +1,34 @@ +/* Elemental UI */ + +/* Angular Material */ + +/* Imx */ +.imx-stepper-samples.mat-mdc-stepper-vertical { + @include flex-column-container($max-height: 100%); + + .mat-mdc-step { + @include flex-column-container($max-height: calc(100% - 144px)); + flex: 1 1 auto; + + .mat-mdc-vertical-content-container { + @include flex-column-container($height: calc(100% - 72px)); + + .mat-mdc-vertical-content { + @include flex-column-container-fill(); + height: 100%; + + imx-pick-category-select-identities { + @include flex-column-container($max-height: calc(100% - 36px)); + } + } + } + } + + .imx-summary-intro { + margin: 15px 0; + } +} + +/* Dark theme */ + +/* High-contrast theme */ diff --git a/imxweb/shared/scss/components/table.scss b/imxweb/shared/scss/components/table.scss new file mode 100644 index 000000000..4ffca7a6b --- /dev/null +++ b/imxweb/shared/scss/components/table.scss @@ -0,0 +1,337 @@ +@import '@elemental-ui/core/src/styles/_eui_palette.scss'; +@import 'base/mixins'; + +/* Elemental UI */ + +/* Angular Material */ + +/* Angular Material - table*/ + +.mat-mdc-table { + tbody { + .mat-mdc-row { + .mat-mdc-cell { + .imx-table-column-ellipsis { + width: 120px; + display: block; + white-space: nowrap; + overflow-x: hidden; + text-overflow: ellipsis; + } + } + } + } +} + +table.mat-mdc-table { + box-shadow: none; + padding: 1px; +} +/* Angular Material - cell */ + +td.mat-mdc-cell { + padding-right: 10px; + .mdc-button { + white-space: nowrap; + } +} +td.imx-table-cell { + div { + @include flex-row-container($height: fit-content, $width: fit-content); + } +} + +// Handle cursor icons, make sure divs are minimal so we don't have the text icon too much +.imx-data-table-highlightedActive { + .mat-mdc-row { + &:hover { + cursor: pointer; + } + } + .mat-mdc-cell { + // Make sure to exclude checkboxes and class imx-progress-column as they behave differently with content fitting + *:not( + .mat-mdc-checkbox, + .imx-progress-column, + .imx-progress-column *, + .mdc-button, + .mdc-button *, + .mdc-icon-button, + imx-info-badge, + imx-info-badge * + ) { + &:hover { + cursor: text; + } + &:only-child { + @include flex-row-container($height: fit-content, $width: fit-content); + } + } + + > .mdc-button, + .mat-mdc-stroked-button, + .mat-mdc-raised-button, + .mat-mdc-flat-button, + .mat-icon-button { + &:hover { + cursor: pointer; + } + & *:hover { + cursor: inherit !important; + } + } + } +} + +/* Imx */ + +.mat-mdc-card.imx-table-container, +.div.imx-table-container, +.imx-table-container { + @include flex-column-container-fill(); + height: inherit; + + > imx-data-table { + flex-grow: 2; + } +} + +.imx-table-container.overflow-auto { + overflow: auto; +} + +.imx-table-container-for-simple-table { + @include flex-column-container-fill(); + overflow: auto; +} + +.imx-simple-table { + width: 100%; + max-height: 100%; + box-shadow: none; + overflow: auto; +} + +/* Imx - table */ +.imx-data-table-grouped { + @include flex-column-container-fill(); + + .spaced-left { + margin-left: 5px; + } + + td.mat-mdc-cell { + padding-top: 6px; + padding-bottom: 6px; + + div { + overflow: hidden; + + &.group-row-expanded { + margin-bottom: 15px; + } + } + table { + td.mat-mdc-cell { + div { + overflow: unset; + } + } + } + } + + .imx-data-table-grouped-content { + flex: 1 1 auto; + overflow: auto; + } +} + +.imx-table-action-row { + display: flex; + align-items: baseline; + justify-content: space-between; +} + +/* Imx - row*/ +.imx-hidden-header.mat-mdc-header-row { + display: none; +} + +.mat-mdc-row.imx_MatTableRow { + min-height: 60px; +} + +/* Imx - column*/ + +.imx-table-column.mat-mdc-column-select { + overflow: initial; + max-width: 50px; + min-width: 50px; + width: 50px; + margin-right: 15px; +} + +.imx-table-column { + padding-right: 15px; + .mat-mdc-checkbox { + &:hover { + cursor: pointer; + } + & *:hover { + cursor: inherit !important; + } + } +} + +.imx-long-title-table .mat-mdc-row .mat-mdc-cell { + padding: 0 10px; + div[imxTitle] { + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; + .button-row { + border-top-style: solid; + border-top-width: 0px; + @include flex-row-container(); + justify-content: flex-end; + } + } +} + +.imx-table-column { + padding-right: 15px; +} + +td.mat-mdc-cell div[subtitle] { + font-size: smaller; + color: $color-gray-40; + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; + max-width: 500px; +} + +.mat-mdc-cell.imx_ColumnCell { + text-overflow: ellipsis; +} + +.imx_ColumnHeader { + overflow: hidden; + text-overflow: ellipsis; +} + +.mat-mdc-header-cell.imx_CheckableCell { + flex: 0 0 45px; +} + +.mat-mdc-cell.imx_CheckableCell { + flex: 0 0 45px; +} + +/* Media Screens*/ + +@media screen and (max-width: 768px) { + td.mat-mdc-cell div[subtitle] { + max-width: 250px; + } +} + +/* Default theme */ + +.imx-data-table-row-highlighted { + background-color: $color-gray-5; +} + +.imx-data-table-row-conditional { + background-color: $color-red-20; +} + +.imx-data-table-highlightedActive .mat-mdc-row:hover, +.mat-mdc-row:hover { + background-color: $color-blue-10; +} + +/* Dark theme */ + +.eui-dark-theme { + .mat-mdc-header-cell { + color: $color-gray-10; + border-bottom-color: $color-gray-60; + } + .mat-mdc-table { + background-color: $color-gray-70; + } + + .custom-row td { + border-bottom-color: $color-gray-60; + } + + .imx-data-table-row-highlighted, + .imx-data-table-highlightedActive.mat-mdc-row:hover, + .mat-mdc-row:hover { + background-color: $color-gray-60; + } + + .custom-row:hover { + background-color: $color-gray-60 !important; + } + + .imx-data-table-row-conditional { + background-color: $color-red-80; + } +} + +/* High-contrast theme */ + +.eui-contrast-theme { + .mat-mdc-header-cell { + color: $color-gray-0; + border-bottom-color: $color-gray-60; + } + + .mat-mdc-table { + background-color: $color-gray-90; + } + + .imx-data-table-row-highlighted, + .imx-data-table-highlightedActive .mat-mdc-row:hover, + .mat-mdc-row:hover { + background-color: $color-gray-0 !important; + + td.mat-mdc-cell { + color: $color-gray-100; + } + + .mat-mdc-checkbox-frame { + border-color: $color-gray-100; + } + } + + table { + border-top: none; + } + + th:after, + th:before { + content: ''; + position: absolute; + left: 0; + width: 100%; + } + th:before { + top: 0; + border-top: 1px solid white; + } + th:after { + bottom: 0; + border-bottom: 1px solid white; + } + + .imx-data-table-row-conditional { + background-color: $color-red-80; + } + + .imx-data-table-selection-info { + color: $color-blue-40; + } +} diff --git a/imxweb/shared/scss/components/tabs.scss b/imxweb/shared/scss/components/tabs.scss new file mode 100644 index 000000000..b3a916c9e --- /dev/null +++ b/imxweb/shared/scss/components/tabs.scss @@ -0,0 +1,262 @@ +@import 'base/mixins'; +@import '@elemental-ui/core/src/styles/_eui_palette.scss'; + +/* Elemental UI */ + +/* Angular Material */ + +.mat-mdc-tab-group { + flex-grow: 1; + overflow: auto; + height: 100%; + .mat-mdc-tab-header { + padding: 0; + } +} + +.mat-mdc-tab-body-content { + @include flex-column-container(); +} + +.mat-mdc-tab-body-wrapper { + height: 100%; + flex: 1 1 auto; + .mat-mdc-tab-body { + display: flex; + flex-direction: column; + flex: 1 1 auto; + } +} + +/* Imx */ + +.imx-tab-content { + @include flex-column-container($height: 100%); + + .imx-tab-content-body { + @include flex-column-container-fill(); + + .mat-mdc-card { + > form { + padding-right: 10px; + } + } + } +} + +.imx-tab-content-sidesheet-with-table { + height: 100%; + padding: 0; + + .imx-sidesheet-content__overflow { + @include flex-column-container-fill(); + + .imx-sidesheet-content__overflow { + imx-data-table { + height: 100%; + } + } + } +} + +.imx-tab-margin { + .mat-mdc-tab-body-content { + margin: 20px; + } +} + +.imx-tab-header-indent { + .mat-mdc-tab-header { + margin-left: 20px; + } +} + +.imx-tab-card.imx-card-fill { + margin: 20px; +} + +.imx-tab-container { + padding: 20px; + + &-full { + @include flex-column-container-fill(); + height: 100%; + } +} + +.imx-tab-group-wrapper { + @include flex-row-container-fill(); + overflow: auto; + + .mat-mdc-tab-group { + width: 100%; + } +} + +.imx-nested-group { + &.eui-sidesheet-content { + padding: 20px; + .mat-mdc-card { + height: 100%; + padding: 0; + .mat-mdc-card:not(.imx-card-shadow) { + box-shadow: none; + border-style: none; + } + ::ng-deep .mat-mdc-tab-group { + border-radius: 4px; + imx-object-hyperview { + .imx-tab-content-body { + padding: 0; + } + } + .mat-mdc-ink-bar { + background-color: $color-blue-90; + } + .governance-sidesheet { + &__tab-content-body { + ng-component { + height: 100%; + .mat-mdc-card { + padding: 0; + box-shadow: none; + } + } + } + } + } + } + } +} + +/* IMX ~ menu*/ +.imx-menu-like-tabs { + .mat-mdc-tab-link { + font-style: normal; + font-stretch: normal; + line-height: normal; + letter-spacing: normal; + color: $color-gray-60; + min-width: 10px !important; + } + + .mat-mdc-tab-link, + .mat-mdc-tab-link:focus, + .mat-mdc-tab-link:hover { + text-decoration: none; + } + + .mat-mdc-tab-link.mat-mdc-tab-label-active { + font-weight: bold; + } + + .mat-mdc-tab-nav-bar { + background-color: $color-gray-0; + + .mat-mdc-tab-link { + font-size: 16px; + color: $color-gray-60; + } + } +} + +/* Light theme */ + +.mat-mdc-tab-group.imx-card-heading { + .mat-mdc-tab-header { + background-color: $color-gray-0; + } +} + +/* Dark theme */ + +.eui-dark-theme { + .mat-mdc-tab-group { + .mat-mdc-tab-header { + background-color: $color-gray-80; + } + } + + .mat-mdc-tab-group.imx-card-heading { + .mat-mdc-tab-header { + background-color: $color-gray-70; + } + } + + .mat-mdc-tab-group.imx-aob { + .mat-mdc-tab-body { + background-color: $color-gray-70; + } + .mat-mdc-tab-header { + background-color: $color-gray-70; + } + } + + .imx-nested-group { + .mat-mdc-tab-group { + .mat-mdc-tab-header { + background-color: $color-gray-70; + .mat-mdc-ink-bar { + background-color: $color-gray-0; + } + } + } + } + + .imx-menu-like-tabs { + background-color: $color-gray-80; + + .mat-mdc-tab-link { + color: $color-gray-5; + } + + .mat-mdc-tab-nav-bar { + background-color: $color-gray-80; + + .mat-mdc-tab-link { + color: $color-gray-5; + } + } + } +} + +/* High-contrast theme */ + +.eui-contrast-theme { + .mat-mdc-tab-group { + .mat-mdc-tab-header { + background-color: $color-gray-90; + } + } + + .mat-mdc-tab-group.imx-card-heading { + .mat-mdc-tab-header { + background-color: $color-gray-100; + } + } + .imx-nested-group { + .mat-mdc-tab-group { + .mat-mdc-tab-header { + background-color: $color-gray-90; + .mat-mdc-ink-bar { + background-color: $color-gray-0; + } + } + } + } + .imx-menu-like-tabs { + background-color: $color-gray-100; + + .mat-mdc-tab-link { + color: $color-gray-0; + } + + .mat-mdc-tab-nav-bar { + background-color: $color-gray-100; + + .mat-mdc-tab-link { + color: $color-gray-0; + } + } + } +} diff --git a/imxweb/shared/scss/components/theme-switcher.scss b/imxweb/shared/scss/components/theme-switcher.scss new file mode 100644 index 000000000..20b8c6df7 --- /dev/null +++ b/imxweb/shared/scss/components/theme-switcher.scss @@ -0,0 +1,15 @@ +/* Elemental UI */ +eui-theme-switcher { + width: 100%; + + .mat-mdc-form-field { + width: 100%; + } +} +/* Angular Material */ + +/* Imx */ + +/* Dark theme */ + +/* High-contrast theme */ diff --git a/imxweb/shared/scss/components/time-picker.scss b/imxweb/shared/scss/components/time-picker.scss new file mode 100644 index 000000000..88b666063 --- /dev/null +++ b/imxweb/shared/scss/components/time-picker.scss @@ -0,0 +1,39 @@ +@import '@elemental-ui/core/src/styles/_eui_palette.scss'; +/* Elemental UI */ +eui-time-picker { + .eui-time-picker-container { + display: flex !important; + align-items: center; + .mdc-text-field--outlined{ + padding: 0px 10px; + } + } +} + +/* Angular Material */ + +/* Imx */ +.imx-time-picker-container { + padding: 5px; +} + +.imx-time-picker-container { + background: $color-gray-0; + border: 1px solid $color-gray-60; +} + +/* Dark theme */ +.eui-dark-theme { + .imx-time-picker-container { + background: $color-gray-60; + border: 1px solid $color-gray-90; + } +} + +/* High-contrast theme */ +.eui-contrast-theme { + .imx-time-picker-container { + background: $color-gray-100; + border: 1px solid $color-gray-0; + } +} diff --git a/imxweb/shared/scss/components/toolbar.scss b/imxweb/shared/scss/components/toolbar.scss new file mode 100644 index 000000000..942870fc0 --- /dev/null +++ b/imxweb/shared/scss/components/toolbar.scss @@ -0,0 +1,63 @@ +/* Elemental UI */ + +eui-sidesheet { + .eui-sidesheet { + .mat-toolbar { + justify-content: start; + .eui-sidesheet__heading-text { + flex-basis: auto; + } + imx-help-contextual { + .mat-icon-button { + color: $color-gray-0; + } + } + .eui-sidesheet-close { + margin-left: auto; + } + } + } +} + +/* Angular Material */ + +.mat-toolbar { + background-color: inherit; +} + +.mat-toolbar > button { + margin-left: 5px; +} +/* Imx */ + +/* Light theme */ +.mat-toolbar { + color: $color-gray-100; +} + +/* Dark theme */ + +.eui-dark-theme { + .mat-toolbar { + color: $color-gray-10; + } + + .eui-sidesheet { + .mat-toolbar { + background-color: $color-blue-80; + } + } +} + +/* High-contrast theme */ +.eui-contrast-theme { + .mat-toolbar { + color: $color-gray-0; + } + + .eui-sidesheet { + .mat-toolbar { + background-color: $color-blue-90; + } + } +} diff --git a/imxweb/shared/scss/components/tooltip.scss b/imxweb/shared/scss/components/tooltip.scss new file mode 100644 index 000000000..f7c3b33ff --- /dev/null +++ b/imxweb/shared/scss/components/tooltip.scss @@ -0,0 +1,24 @@ +@import '@elemental-ui/core/src/styles/_eui_palette.scss'; + +/* Elemental UI */ + +/* Angular Material */ +.mat-mdc-tooltip-component .mat-mdc-tooltip.custom-tooltip { + background: $color-gray-0; + color: $color-gray-100; + margin: 5px; + max-width: unset; + font-size: 12px; + border: 1px solid $color-gray-80; + border-radius: 4px; +} + +.mat-mdc-tooltip-hide { + display: none !important; +} + +/* Imx */ + +/* Dark theme */ + +/* High-contrast theme */ diff --git a/imxweb/shared/scss/components/top-navigation.scss b/imxweb/shared/scss/components/top-navigation.scss new file mode 100644 index 000000000..cf2428140 --- /dev/null +++ b/imxweb/shared/scss/components/top-navigation.scss @@ -0,0 +1,25 @@ +/* Elemental UI */ + +@media only screen and (max-width: 768px) { + .eui-top-navigation-mobile { + .eui-top-navigation-mobile-footer { + .mat-mdc-button { + &.imx-masthead--icon-button { + width: 100%; + + .mat-mdc-button-wrapper span { + display: inline-block; + } + } + } + } + } +} + +/* Angular Material */ + +/* Imx */ + +/* Dark theme */ + +/* High-contrast theme */ diff --git a/imxweb/shared/scss/components/tree.scss b/imxweb/shared/scss/components/tree.scss new file mode 100644 index 000000000..322b3226b --- /dev/null +++ b/imxweb/shared/scss/components/tree.scss @@ -0,0 +1,117 @@ +/* Elemental UI */ + +/* Angular Material */ +.mat-tree-node .mat-icon-button.mat-mdc-button-base { + flex: 0 0 40px; +} + +.mat-tree { + flex-grow: 1; +} + +/* Imx */ + +.imx-snavigation-side-content { + flex: 1 1 auto; + mat-tree { + background-color: transparent !important; + } + + .mat-tree-node { + border-radius: 4px; + } + + /* + * This padding sets alignment of the nested nodes. + */ + .tree .mat-nested-tree-node div[role='group'] { + margin-left: 20px; + } + + .tree-item-button { + width: 100%; + padding: 0; + color: unset; + text-overflow: ellipsis; + white-space: nowrap; + overflow: hidden; + + .mdc-button__label { + width: 100%; + } + } + .tree-invisible { + display: none; + } +} + +.imx-upper-case { + text-transform: uppercase; + align-items: center; +} + +/* Dark theme */ + +.eui-light-theme { + .mat-mdc-button.mat-primary.tree-item-button:not(.mat-tree-node--selected) { + color: unset; + } + + .mat-tree-node--selected { + background-color: $color-gray-0; + border: 1px solid $color-blue-40; + color: $color-orange-60; + } + + .imx-tree-control { + .imx-snavigation-side-content { + background-color: $color-blue-10; + border: 1px solid $color-blue-20; + } + } +} + +.eui-dark-theme { + .mat-tree-node--selected { + background-color: $color-gray-80; + border: 1px solid $color-blue-40; + color: $color-orange-40; + + .imx-tree-root { + color: $color-orange-40; + } + } + + .imx-tree-control { + .imx-snavigation-side-content { + background-color: $color-blue-80; + border: 1px solid $color-blue-40; + } + } +} + +/* High-contrast theme */ + +.eui-contrast-theme { + .mat-tree-node--selected { + background-color: $color-gray-20; + border: 1px solid $color-blue-40; + color: $color-orange-80; + } + .imx-tree-root { + color: $color-gray-0; + } + .imx-tree-root--selected { + color: $color-orange-80; + .imx-icon-warning { + color: $color-orange-80; + } + } + + .imx-tree-control { + .imx-snavigation-side-content { + background-color: $color-gray-100; + border: 1px solid $color-gray-0; + } + } +} diff --git a/imxweb/shared/scss/side-navigation.scss b/imxweb/shared/scss/side-navigation.scss deleted file mode 100644 index cf039aac1..000000000 --- a/imxweb/shared/scss/side-navigation.scss +++ /dev/null @@ -1,176 +0,0 @@ -@import '@elemental-ui/core/src/styles/_eui_palette.scss'; -:host { - height: 100%; -} - -.snavigation { - height: 100%; - - .mat-sidenav-container { - height: 100%; - - .mat-sidenav { - width: 230px; - - .snavigation-side { - display: flex; - flex-direction: column; - height: 100%; - - .snavigation-side-toggle { - display: none; - padding: 16px 12px 0; - margin-bottom: 10px; - - .mat-button { - min-width: 0; - padding: 0 4px; - height: 28px; - - .mat-icon { - margin-top: -12px; - } - } - } - - .snavigation-side-content { - flex: 1; - padding: 20px; - padding-bottom: 16px; - - .snavigation-side-heading { - font-size: 14px; - font-weight: bold; - margin-bottom: 10px; - white-space: nowrap; - imx-help-contextual{ - display: inline-block; - } - } - - .snavigation-item { - margin: 0 -20px; - padding: 10px 20px; - display: flex; - align-items: center; - justify-content: flex-start; - cursor: pointer; - - & > .eui-icon { - margin-right: 8px; - } - - & > span { - flex: 1; - overflow: hidden; - text-overflow: ellipsis; - white-space: nowrap; - } - } - } - } - } - - .mat-sidenav-content { - padding: 20px; - position: relative; - display: flex; - flex-direction: column; - - &.snavigation--backdrop-showing { - overflow: hidden; - } - - .snavigation-backdrop { - position: absolute; - top: 0; - left: 0; - right: 0; - bottom: 0; - background-color: rgba($color-gray-100, 0.32); - z-index: 200; - } - - .mat-table tr:hover td { - background-color: rgba($color-gray-100, 0.04); - cursor: pointer; - } - } - } -} - -@media only screen and (max-width: 768px) { - .snavigation .mat-sidenav-container { - .mat-sidenav { - transition: width 0.5s; - - .snavigation-side { - .snavigation-side-toggle { - display: block; - } - .snavigation-side-content { - padding: 16px; - } - } - - &:not(.snavigation-side--expanded) { - width: 58px; - - .snavigation-side-content { - display: none; - } - } - } - - .mat-sidenav-content { - padding: 16px; - } - } -} - -// Theming - -.snavigation { - .mat-sidenav-container { - background-color: $color-gray-2; - .mat-sidenav { - .snavigation-side { - .snavigation-side-content { - .snavigation-item { - & > .eui-icon { - margin-right: 8px; - color: rgba($color-gray-100, 0.4); - } - - &:hover:not(.snavigation-item--selected) { - background-color: rgba($color-blue-40, 0.5); - } - - &.snavigation-item--selected { - background-color: $color-blue-60; - color: $color-gray-0; - } - } - } - } - } - } -} -.eui-dark-theme { - :host { - .snavigation { - .mat-sidenav-container { - background-color: $color-gray-80; - } - } - } -} -.eui-contrast-theme { - :host { - .snavigation { - .mat-sidenav-container { - background-color: $color-gray-100; - } - } - } -} diff --git a/imxweb/shared/assets/styles.scss b/imxweb/shared/scss/styles.scss similarity index 63% rename from imxweb/shared/assets/styles.scss rename to imxweb/shared/scss/styles.scss index b4c5b11d3..4ae4b6fcd 100644 --- a/imxweb/shared/assets/styles.scss +++ b/imxweb/shared/scss/styles.scss @@ -1,32 +1,77 @@ -@import 'variables'; @import '@elemental-ui/core/src/styles/_eui_palette.scss'; -/* Elemental UI */ -.imx-eui-icon { - margin: 10px; +@import 'base/colors'; +@import 'base/fonts'; +@import 'base/margins-paddings'; +@import 'base/mixins'; +@import 'base/variables'; + +@import 'components/alert'; +@import 'components/autocomplete'; +@import 'components/badge'; +@import 'components/button'; +@import 'components/button-toggle'; +@import 'components/card'; +@import 'components/chart'; +@import 'components/checkbox'; +@import 'components/chips'; +@import 'components/scrollbar'; +@import 'components/search'; +@import 'components/sidesheet'; +@import 'components/side-navigation'; +@import 'components/clickable'; +@import 'components/data-source-toolbar'; +@import 'components/date-picker'; +@import 'components/dialog'; +@import 'components/divider'; +@import 'components/download'; +@import 'components/expansion-panel'; +@import 'components/form-field'; +@import 'components/icon'; +@import 'components/input'; +@import 'components/layout-grid'; +@import 'components/list'; +@import 'components/logo'; +@import 'components/masthead'; +@import 'components/menu'; +@import 'components/paginator'; +@import 'components/progress-bar'; +@import 'components/radio-button'; +@import 'components/ripple'; +@import 'components/spinner'; +@import 'components/select'; +@import 'components/slide-toggle'; +@import 'components/slider'; +@import 'components/stepper'; +@import 'components/table'; +@import 'components/tabs'; +@import 'components/theme-switcher'; +@import 'components/time-picker'; +@import 'components/toolbar'; +@import 'components/tooltip'; +@import 'components/tree'; +@import 'components/top-navigation'; + +/* Imx */ +.imx-flex-container-100 { + display: flex; + flex-direction: column; + align-items: stretch; + height: 100%; +} + +.imx-no-results { + height: 100%; + display: flex; + flex-direction: column; + justify-content: center; + align-items: center; +} + +.imx-hidden { + display: none !important; } -/* Elemental UI END */ - -/* #region VI_Styles_RendererSettings_Default (FontFamily) */ -@font-face { - font-family: 'fa-identity'; - src: url('fonts/fa-identity.ttf'); - font-weight: normal; - font-style: normal; -} -/*#endregion*/ - -/* #region VI_Styles_RendererSettings_Default (Icons) */ -.imx-icon { - background-position: 0 center; - display: inline-block; - min-height: 18px; - background-repeat: no-repeat; - padding-left: 20px; -} -/*#endregion*/ - /* #region VI_Styles_RendererSettings_Default (Flex styles) */ /* not a smartphone and not a tablet... */ @media not #{$IMX_Mediaquery_Smartphone} { @@ -39,6 +84,10 @@ .imx-flex-child { flex: 1 1 auto; overflow: auto; + &-hidden { + flex: 1 1 auto; + overflow: hidden; + } } } @@ -48,10 +97,14 @@ flex-basis: auto; } - .imx-flex-child { flex: 1 1 auto; overflow: auto; + + &-hidden { + flex: 1 1 auto; + overflow: hidden; + } } .k-ie10 .imx-flex-child { @@ -61,32 +114,6 @@ /*#endregion*/ -/* #region VI_Styles_Button_Default (CSS) */ -.imx-button { - color: $white; - background-color: $iris-blue; -} - -.imx-button:hover { - background-color: $VI_Common_Color_Button_Default_Hover; - text-decoration: none; -} - -.imx-button:focus { - background-color: $VI_Common_Color_Button_Default_Hover; - text-decoration: none; - outline: 1px $VI_Common_Color_Button_Outline dotted; - outline-offset: 1px; -} - -.imx-button:Disabled { - color: $VI_Common_Color_Button_Font_Disabled; - // background-color: mat-color($asher-gray-palette, 900); - cursor: not-allowed; -} - -/*#endregion*/ - /* #region VI_Styles_RendererSettings_Default (Icon font) */ /* CUI Icon Font */ @@ -101,7 +128,7 @@ .cux-icon, .cux-pane__collapse-icon, [data-icon]::before { - font-family: "fa-identity" !important; + font-family: 'fa-identity' !important; -moz-osx-font-smoothing: grayscale; -webkit-font-smoothing: antialiased; -webkit-backface-visibility: hidden; @@ -113,27 +140,27 @@ text-transform: none; } .cux-icon--caret-down:before { - content: "\f0d7"; + content: '\f0d7'; } .cux-icon--caret-right:before { - content: "\f0da"; + content: '\f0da'; } .cux-icon--shopping-cart:before { - content: "\f07a"; + content: '\f07a'; } .cux-icon--chain-broken:before { - content: "\f127"; + content: '\f127'; } .cux-icon--tasks:before { - content: "\f0ae"; + content: '\f0ae'; } .cux-icon--table:before { - content: "\f0ce"; + content: '\f0ce'; } /*#endregion*/ @@ -162,9 +189,9 @@ input[accesskey]:after, label[accesskey]:after, legend[accesskey]:after, textarea[accesskey]:after { - padding-left: .3em; + padding-left: 0.3em; display: inline; - content: "[" attr(accesskey) "]"; + content: '[' attr(accesskey) ']'; color: $white; } /*#endregion*/ @@ -183,7 +210,7 @@ div.timeline-content { } div.timeline-axis { - border-color: $VI_Common_Color_Gray; + border-color: $color-gray-60; border-top-style: solid; border-width: 1px; box-sizing: border-box; @@ -201,7 +228,7 @@ div.timeline-axis-grid-minor { } div.timeline-axis-text { - color: $VI_Common_Color_Font; + color: $color-gray-80; padding: 3px; white-space: nowrap; font-size: 14px; @@ -217,9 +244,9 @@ div.timeline-event { } div.timeline-event-selected { - background-color: $VI_Common_Color_Blue_1; + background-color: $color-blue-40; border-color: $black-6; - color: $VI_Common_Color_Font; + color: $color-gray-80; z-index: 999; } @@ -229,12 +256,12 @@ div.timeline-event-dot { } div.timeline-event-cluster { - background: $VI_Common_Color_Blue_1; - color: $VI_Common_Color_Font; + background: $color-blue-40; + color: $color-gray-80; } div.timeline-event-cluster div.timeline-event-dot { - border-color: $VI_Common_Color_Blue_1; + border-color: $color-blue-40; } div.timeline-event-box { @@ -280,7 +307,7 @@ div.timeline-event-content { } div.timeline-groups-axis { - border-color: $VI_Common_Color_Gray; + border-color: $color-gray-60; border-width: 1px; box-sizing: border-box; } @@ -294,13 +321,13 @@ div.timeline-groups-axis-onright { } div.timeline-groups-text { - color: $VI_Common_Color_Font_Secondary; + color: $color-gray-80; padding-left: 10px; padding-right: 10px; } div.timeline-currenttime { - background-color: $QBM_Primary_Orange; + background-color: $color-orange-60; box-sizing: border-box; width: 2px; } @@ -333,13 +360,13 @@ div.timeline-navigation-new { /* separator between new and navigation buttons */ div.timeline-navigation-new-line { - border-right: 1px solid $VI_Common_Color_Gray; + border-right: 1px solid $color-gray-60; } div.imx-timeline-event-objectcreate, div.imx-timeline-event-propertychange { border-color: $iris-blue; - background-color: $VI_Common_Color_Blue_1; + background-color: $color-blue-40; } div.imx-timeline-event-addaccount, @@ -358,7 +385,7 @@ div.imx-timeline-event-removemembership, div.imx-timeline-event-removepermission, div.imx-timeline-event-removeresponsibility { border-color: $phoenix-red; - background-color: $QBM_Primary_Orange; + background-color: $color-orange-60; } .imx-timeline-detail-header { @@ -402,8 +429,6 @@ div.imx-timeline-event-removeresponsibility { } /*#endregion*/ - - /* #region VI_Styles_RendererSettings_Mobile (Performance improvements) */ * { text-shadow: none; @@ -413,18 +438,10 @@ div.imx-timeline-event-removeresponsibility { /*#endregion*/ -/* #region QBM-Page styles (CSS) */ - -body { - background-color: $Imx_White-two -} - -/*#endregion*/ - /* #region Angular Material Komponenten*/ -.mat-primary .mat-pseudo-checkbox-checked, -.mat-primary .mat-pseudo-checkbox-indeterminate { +.mat-primary .mat-mdc-pseudo-checkbox-checked, +.mat-primary .mat-mdc-pseudo-checkbox-indeterminate { background-color: $iris-blue; } @@ -434,7 +451,7 @@ textarea:focus { } .simpleText { - color: $VI_Common_Color_Font; + color: $color-gray-80; } .mat-icon-button.imx-searchbar-tablecellsmall { @@ -447,10 +464,9 @@ textarea:focus { } /*#endregion*/ -.mat-paginator, -.mat-table { +.mat-mdc-table { box-shadow: 0 4px 4px 0 rgba(0, 0, 0, 0.25); - font-family: $baseFontFamily; + font-family: $IMX_Base_FontFamily; } .imx-title { @@ -461,7 +477,7 @@ textarea:focus { font-stretch: normal; line-height: 1.5; letter-spacing: normal; - color: $VI_Common_Color_Font; + color: $color-gray-80; } .imx-subtitle { @@ -472,7 +488,7 @@ textarea:focus { font-stretch: normal; line-height: 1.71; letter-spacing: normal; - color: $VI_Common_Color_Gray; + color: $color-gray-60; } .imx_processTitle { @@ -483,7 +499,7 @@ textarea:focus { font-stretch: normal; line-height: 1.6; letter-spacing: normal; - color: $VI_Common_Color_Gray; + color: $color-gray-60; } .imx-normalCell { @@ -494,7 +510,7 @@ textarea:focus { font-stretch: normal; line-height: 2; letter-spacing: normal; - color: $VI_Common_Color_Gray; + color: $color-gray-60; } /* #region overrides Angular Material styles*/ @@ -508,20 +524,59 @@ textarea:focus { .imx-messageDialog { margin: auto auto; - max-width: $PopupWidthLarge + px; + max-width: $IMX_MessageDialog_MaxWidth; min-width: 550px; font-size: 14px; top: 100px; position: absolute !important; } +/* Extends the properties of .imx-messageDialog */ +.imx-messageDialog-error { + @extend .imx-messageDialog; + border-left: 4px solid $color-red-60; + border-radius: 6px; +} + +/* Sets the error icon style in the error dialog */ +.imx-error-icon-in-error-dialog { + display: inline-block; + color: $color-red-60; + margin-right: 10px; +} + +/* Sets the h2 tag style in the error dialog */ +.h2-in-error-dialog, +.h2-in-session-expired-dialog { + display: inline-block !important; + vertical-align: sub; +} + +.h2-in-session-expired-dialog { + color: $color-red-60; +} + +.eui-dark-theme { + .imx-messageDialog-error { + border-left-color: $color-red-40; + } + + .imx-error-icon-in-error-dialog { + color: $color-red-40; + } + + .h2-in-session-expired-dialog { + color: $color-red-40; + } +} + /* #region Elemental UI fixes */ -.mat-form-field-infix .mat-select-trigger { +.mat-mdc-form-field-infix .mat-mdc-select-trigger { vertical-align: baseline; - .mat-select-arrow-wrapper { - vertical-align: middle; + .mat-mdc-select-arrow-wrapper { + transform: none; } } @@ -529,91 +584,89 @@ button { letter-spacing: normal; } -.mat-card-title { +.mat-mdc-card-title { margin-bottom: 16px; } /*#endregion*/ /* #region Fix for the bug with mat-hint of Angular Material */ -.imx-form .mat-form-field .mat-form-field-wrapper { +.imx-form .mat-mdc-form-field .mat-mdc-form-field-wrapper { padding-bottom: 0; - .mat-form-field-underline { + .mat-mdc-form-field-underline { position: initial; display: block; margin-top: -1px; } - .mat-form-field-subscript-wrapper, - .mat-form-field-ripple { + .mat-mdc-form-field-subscript-wrapper, + .mat-mdc-form-field-ripple { position: relative; display: inline-flex; - .mat-form-field-hint-wrapper { + .mat-mdc-form-field-hint-wrapper { flex-wrap: wrap; } } - .mat-form-field-subscript-wrapper { + .mat-mdc-form-field-subscript-wrapper { min-height: calc(1em + 1px); } } /* #endregion */ -/* #region mat-paginator styling */ -.mat-paginator-navigation-next.mat-icon-button, -.mat-paginator-navigation-previous.mat-icon-button { - background: transparent; - width: 16px; - margin-right: 10px; -} -/* #endregion */ - /* bugfix for the mat-error overlapping error for more information see: https://github.com/angular/components/issues/4580#issuecomment-510290576 */ -mat-form-field { - &.ng-valid { - .mat-form-field-wrapper { - padding-bottom: 1.25em; - } - } - - &.ng-invalid, - &.mat-form-field-invalid { - .mat-form-field-wrapper { - padding-bottom: 7px; - } - } - - &.ng-untouched { - .mat-form-field-wrapper { - padding-bottom: 1.25em; - } - } - - .mat-form-field { - &-underline { - position: static; - } - - &-subscript-wrapper { - position: static; - } - } -} +// mat-form-field { +// &.ng-valid { +// .mat-mdc-form-field-wrapper { +// padding-bottom: 1.25em; +// } +// } + +// &.ng-invalid, +// &.mat-mdc-form-field-invalid { +// .mat-mdc-form-field-wrapper { +// padding-bottom: 7px; +// } +// } + +// &.ng-untouched { +// .mat-mdc-form-field-wrapper { +// padding-bottom: 1.25em; +// } +// } + +// .mat-mdc-form-field { +// &-underline { +// position: static; +// } + +// &-subscript-wrapper { +// position: static; +// } +// } +// } /* remove the max-width of the menu-panel #304731*/ -.cdk-overlay-pane .mat-menu-panel { - max-width: initial; +.cdk-overlay-pane .mat-mdc-menu-panel { + max-width: initial; +} +/* Show recaptcha badge only in login page */ +.recaptcha .grecaptcha-badge { + visibility: visible; +} +.grecaptcha-badge { + visibility: hidden; } .eui-dark-theme { - .imx-title { - color: $color-gray-5; - } + .imx-title { + color: $color-gray-5; + } - .simpleText { - color: $color-gray-5; - } + .simpleText { + color: $color-gray-5; + } } .eui-contrast-theme { @@ -625,7 +678,3 @@ mat-form-field { color: $color-gray-0; } } - -// Fix tooltip flash bug on delayed tooltips: https://github.com/angular/components/issues/24614 -.mat-tooltip-hide { display: none!important; } - diff --git a/imxweb/tsconfig.json b/imxweb/tsconfig.json index 670d2b69c..bdfe5949f 100644 --- a/imxweb/tsconfig.json +++ b/imxweb/tsconfig.json @@ -1,4 +1,3 @@ -/* To learn more about this file see: https://angular.io/config/tsconfig. */ { "compileOnSave": false, "compilerOptions": { @@ -6,55 +5,51 @@ "outDir": "./dist/out-tsc", "forceConsistentCasingInFileNames": true, "strict": false, - "strictNullChecks": false, + "strictNullChecks": true, "noImplicitOverride": false, + "esModuleInterop": true, "noPropertyAccessFromIndexSignature": false, "noImplicitReturns": false, - "allowSyntheticDefaultImports": true, "resolveJsonModule": true, "allowJs": true, "paths": { + "aad": ["dist/aad"], + "aad/*": ["dist/aad/*"], + "aob": ["dist/aob"], + "aob/*": ["dist/aob/*"], + "apc": ["dist/apc"], + "apc/*": ["dist/apc/*"], + "att": ["dist/att"], + "att/*": ["dist/att/*"], "dpr": ["dist/dpr"], "dpr/*": ["dist/dpr/*"], + "o3t": ["dist/o3t"], + "o3t/*": ["dist/o3t/*"], "qbm": ["dist/qbm"], "qbm/*": ["dist/qbm/*"], "qer": ["dist/qer"], "qer/*": ["dist/qer/*"], - "aob": ["dist/aob"], - "aob/*": ["dist/aob/*"], - "tsb": ["dist/tsb"], - "tsb/*": ["dist/tsb/*"], - "att": ["dist/att"], - "att/*": ["dist/att/*"], "rps": ["dist/rps"], "rps/*": ["dist/rps/*"], - "o3t": ["dist/o3t"], - "o3t/*": ["dist/o3t/*"], - "aad": ["dist/aad"], - "aad/*": ["dist/aad/*"], - "apc": ["dist/apc"], - "apc/*": ["dist/apc/*"] + "tsb": ["dist/tsb"], + "tsb/*": ["dist/tsb/*"] }, "noFallthroughCasesInSwitch": true, "sourceMap": true, "declaration": false, - "downlevelIteration": true, "emitDecoratorMetadata": true, "experimentalDecorators": true, "moduleResolution": "node", "importHelpers": true, - "target": "es2020", - "module": "es2020", - "lib": [ - "es2020", - "dom" - ] + "target": "es2022", + "module": "es2022", + "lib": ["es2022", "dom"] }, "angularCompilerOptions": { "enableI18nLegacyMessageIdFormat": false, "strictInjectionParameters": false, "strictInputAccessModifiers": true, - "strictTemplates": false, - "strictNullInputTypes": false, + "strictTemplates": true, + "strictNullInputTypes": false } } diff --git a/imxweb/tslint.json b/imxweb/tslint.json deleted file mode 100644 index 68c99bfeb..000000000 --- a/imxweb/tslint.json +++ /dev/null @@ -1,158 +0,0 @@ -{ - "extends": "tslint:recommended", - "linterOptions": { - "exclude": [ - "**/*.spec.ts" - ] - }, - "rulesDirectory": [ - "codelyzer" - ], - "rules": { - "align": { - "options": [ - "parameters", - "statements" - ] - }, - "array-type": false, - "arrow-parens": false, - "arrow-return-shorthand": true, - "deprecation": { - "severity": "warn" - }, - "curly": true, - "import-blacklist": [ - true, - "rxjs/Rx" - ], - "interface-name": false, - "eofline": true, - "max-classes-per-file": [ - true, - 1, - "exclude-class-expressions" - ], - "import-spacing": true, - "indent": { - "options": [ - "spaces" - ] - }, - "max-line-length": [ - true, - { - "limit": 140, - "ignore-pattern": "^import [^,]+ from" - } - ], - "member-access": true, - "member-ordering": [ - true, - { - "order": [ - "static-field", - "public-instance-field", - "protected-instance-field", - "private-instance-field", - "constructor", - "public-instance-method", - "protected-instance-method", - "private-instance-method", - "static-method" - ] - } - ], - "no-consecutive-blank-lines": false, - "no-console": [ - true, - "debug", - "info", - "time", - "timeEnd", - "trace" - ], - "no-empty": true, - "no-inferrable-types": [ - true, - "ignore-params" - ], - "no-non-null-assertion": true, - "no-redundant-jsdoc": true, - "no-return-await": true, - "no-shadowed-variable": true, - "no-switch-case-fall-through": true, - "no-var-requires": false, - "object-literal-key-quotes": [ - true, - "as-needed" - ], - "object-literal-sort-keys": false, - "ordered-imports": false, - "quotemark": [ - true, - "single" - ], - "trailing-comma": false, - "typedef": [ - true, - "call-signature", - "parameter", - "property-declaration" - ], - "variable-name": [ true, "ban-keywords", "check-format" ], - "no-output-on-prefix": true, - "no-inputs-metadata-property": true, - "no-outputs-metadata-property": true, - "no-host-metadata-property": true, - "no-input-rename": true, - "no-output-rename": true, - "semicolon": { - "options": [ - "always" - ] - }, - "space-before-function-paren": { - "options": { - "anonymous": "never", - "asyncArrow": "always", - "constructor": "never", - "method": "never", - "named": "never" - } - }, - "use-lifecycle-interface": true, - "use-pipe-transform-interface": true, - "typedef-whitespace": { - "options": [ - { - "call-signature": "nospace", - "index-signature": "nospace", - "parameter": "nospace", - "property-declaration": "nospace", - "variable-declaration": "nospace" - }, - { - "call-signature": "onespace", - "index-signature": "onespace", - "parameter": "onespace", - "property-declaration": "onespace", - "variable-declaration": "onespace" - } - ] - }, - "component-class-suffix": true, - "directive-class-suffix": true, - "prefer-const": true, - "whitespace": { - "options": [ - "check-branch", - "check-decl", - "check-operator", - "check-separator", - "check-type", - "check-typecast" - ] - } - } -}

    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⪼wWYX=oQjKF9*wE=}W-o;SYBZ7!wfT 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%0AF4`)`S?I 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

    ~xQluDOn0Cy3f;^XYO*P6p^1ytCzVW}| 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

  • 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

    5&%66Z3bU^eYD<`C-C) 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 GMwO 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

    &p4g7Y%*8wbF>b3RyUzQbse4A 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

    yGGOuZk?HSJfk}Uv*Cu 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ⅇ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

    T&OC#+n$bj5_#U%MtAFd7V|krwam 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≷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 diff --git a/imxweb/imx-modules/elemental-ui_core.tgz b/imxweb/imx-modules/elemental-ui_core.tgz deleted file mode 100644 index 3ee82f45a27742e5739a140a276a904e158fcd85..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1322765 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 x*2}UtUUc{6@N<`Yiq*a0#CE*E+(#(!chS3;o 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�T>;k$e!4ON=7c)ASR`P@jWyCo#@5HqpI+CJlT-exNK~-g!+fIw2Uoh{Xj$=SWw7 z<&yzu=D?^ddpzCws+_c={YJ&0+a}snU3g|v^1f8lD0hK@4U^}z-jV6HdMbOFy)~{Z zItS*m`Zre#Q4m?3WR2g=ov_9xAg==*j!Zsf0XKm-;&C_vwNxYymuR%=xG^gTF;liK ziUEw0AWThSNls;%agI@ewd6*=4h8Zj0Y~z6(lVijTe24{(+fQRP3i!6@~mZ1Ou=P= z$L$TUFRr8vVwBW%M}lsd;3RhX3O+ZlU%R3EDQdrt@1b)6n1KIOLFUc)=KB17D9XQ; z;-azxFvJ|w`B?G(o78DC86c)?Q3QYTvhdPxRJK&Ej+-|o3aj??0A)a$zl17LDRn_T zxxH9#y0XQlF-5HJmRkj;!^+;|M}N3&XIQek=LCp%f?xnS5s3m18z1(F3S=EhWMhjw z8;p+Bc@Rb3CTRkDSf+lFT?}nn78;%cjmyI%lhy_LjyGVv&pPT1;0T8u?4^FC)4_TVR)oRKu7&h7yD&gO*D!1L_DX{aK$-( z3)e$x(GO@*EIL~AayNzN^Xnal@~IDY0rP5mVs)x4lH$%n%`KMxvQ4sWlRnZoX%zCeX|$K($yC%eM;NcfY|D)tYP`q5j1pvu}IIoSQEfRz1nGHMazn0 zj!)sODkRcX?u0fBX(T4a0KMe?(W8fU+TXa=JgS6tJi)XZSVYaOP;Adfx|dg}O9dq7 zWmS7hhUc~~SvJ)P3_aaRQ~+w)U{VoCE(-0IQUZdyLgug$KbeOBHZ&1T`7~3xZ0KVn z!O8(1yA-W!a%E&+oN$-J4oZO0NPZ=~w3U#`4kF;`3DxF3vb>kU?q*WFOI%@>R~;Ge zc!&=tUczBU<|Hp)`uE?fR|$&HPSO#1-Jij^%x92Th0Gk8`~q$1T%l0hC}X1+_PS&e z0{e)n??5!_x#i{8Q+&X>2|vgtpTr; zcw~oHFF4_)&VsF6i;(5{9=7z@RACOC%-HDfD_NF2wop>kk#aR~RlMoBmGt~Tnt zvbpDIaFeT(DQ<0RayOVApEc1;&gri`clf$kW75H@8Rnaje}BZe72IchdP9gnv@#S2 zy4_v`jQ((QFYLM7XtY&PY4i@JLB{%-fGDsod<4JZN{@JJJEUH(iqZ=X-KQ0uH`dq) zO}};3aeEHR!>gdwT$IMYJ*ZtLXLij`(vkiC^5}``2G@ z1k_`8>6iH{yy7FrC%j`yu=~&2c_+EXJtvhB0Y9d$K|zuni<|L{r(X-O4Bk~-N!?gQ zZEP|x$cI8DzH#qr^PQ{NAnn>I)7WuDm#Z9N@`sEMVVwsQVl|zxZBn8~g z_89ccS}|ahw%NSXdLS#NlP+n!)n!eHDqYaL>KHp^ZJj9#S%GSdlM5zbRg>1U=gj(; zXJz+zTEOjV`r=G_hbdC6JJ6c5pkq9eQd&h9jA}b?Y%P8kvC;XqXu68_8SHL zF$6`O*3GfFW-2#ZO{fmkIskpup(2Z$LUW}~9;mKVG^`KM$i94_Ms=`0Tw8GG!{(u$ zE(0Hhe?C|gx?chuN$z}jj-2b5K_2?3NYOH~Tp;f{i(9qbE<$Xu&04=@goYhG>!p@A%vF}XC)ZKr$QLi1L-N>UbD zw}2?Fmx#yXB3+C_=BFl83lQu;GBQECxaeZvUhfZWuc{F^x&b&rcnc2cEF)4n$4umo zQ5n^Mf|7>-2UUuh!NM#l*Eq>SfR{ijsGJjwO=bis?W}v+B^GTCaefv$zK9Zw*72I0 zmi}Vl5XzRl8WVFV@X{0lgki3{Y!Q-wbX~7W+fr@EhQ3S}pcrrf%g8JE&FR0a0J)7> z&$@C0mGb)r6ri61%qa$U`2sA6cMtYnv>J}zupS=wb*q`I-seaf8a852C_B(c_Cm1L zkzN49-K-;(ypFfwe2MLECalaQrMF?DN=sj4vxgP1HQj=$6yFC@howU6ujXSo+$aZ|Pt$Uuyte~!>+$;`es)6F z%Xu_vE~mI^6%QqgF98=158dnsKTl9ycR0^yg8H#y6~h%NSHiAvCdh^K)Pj3)$teC; zHzQo2RTbCVn=Ws*Vw3f;b5)rI;>pAQ;r-W#gJ;9xl)7*p*0(O)53d*r`D4Lu680xj zfrb954e0ZHey|FK^TBwdZg3t@rHig=qwN=MjFYet4DSQMQ5XOjwE?||i_sgq3Xjx- z0bOq0PE-$6z@FBP?d`KN$x`t)7OTgz3bIgv#q~zh+SX)kv(~X9v`Jq6ke4}l5QI~SiUQiM*cdcVuJHom#@n10rv)p)jh>Yuy4)%x zltu2f$TufiwF4H^+Qy%k4H-)77NFg53%9~8fZG7HaO0mEF2FEj+nQXvZJ6eplk4tK zA<6+6)2sHJD<5s^C)YU?XG-NY&aCtmDE)=QmoE`68AQhbmqbeh05eL%UMDazm({@k zMD!mLrNRtt;|#IyY?4^6R;x??=8>l)&?WYbkJgY7X1xEunS_Upz}GeTh9LPSn0RIA z%;5bNBUj?K!yd)lxdIBQk%_P*6H1pY2v`AsAh8LhPuYhQA&a6|wi=KEu8nZeYVsM1 zbramg(!9MG0)J!${&d zM1Ji$R;Vt2gnKRxhEl_omet{}Xko2NUaYY|JmQ6OQzli68VlQ4jaCc;7vZ}8?xhil zuw_AWU+kR3M(vH*PL`^wkj1H$`a=VXAyKF61b6I?-YvD7nZ5^8nz#rP6n@Upoup+S zPcN80yA4+4U1$)s!$;SC<^&HjxJAOI36=JPp}XsMHX)S6R8yNlliSTT{qw~O<9#@Jy6G6tX*7}RfA!&J0& zHy|vr`k)uzW8q|)L%|GbZ6y-oRx+Nm)pVK9rx`cBhcrBt1#FU?W2(>eZJJLpf*A!$ zLeP}-mUdM)*_W9yQ^@1MN(>|pw4Xb&)Je7+O$2>;3YIiI`%#rCv+NCUtK;l_k3X32pf(uK)m$_s{41J4_{kFyd|JG~mX)<2&`FRy(wY^Q#AOyW( zWpT6jf+xUuY&lMfooy;TF$oP2dC z>1uvRfZS#$$)TuoXvPfBi314QRdA>PlDZxysX(yf?G1)WfZFHl-gX)dOz{S%zc@m7 z>u!X6EZ7J@-t1QK?1)%-uQYR=Fd@$PJpwJDb8gbMak5u*BS;Mz*9{K!mfJH%1M>`6 zZ48#==j7648}9BdpMC)wEA52Jj~Csubn)hHvA~GZ>)(dPzGd(Y<^;e+{4;0I*jZn@uzk0Z`wF!d9;3bWN+Sd$1 z{h3hp;%6hU)Vi@-0=`R2MMky}IY8dSMy=!Hmk^?hlmbILs2;{-b{fDz3~^j{fc-RhZ?x(&~cv++0^LpN!s zdChjLMX~u$(`qD`dKixzBxG4>h6^ism^iR}e|sT)*|)GLz`>5yNXWlYHUftO4s1;B z@EQ0%Bej%Fo|i7FfdcDMx;#Xxk@lir11vfgc{<%9;xdv&F0T6;tjc9^b~F(*C910M z7t=y5;W-ke2g~~5aj1$F5~s$d2WxDWf>#+$vPIaa$1W4J>S>yuD@1D3SR{1c!lemW zdX`S7)@z>0_z`4O2a*)8mE?VQ>5TBaz)O~aGPtAsgvEf3aBA+KIXT}vu)CyJf2El-7{OAg|j~ zsMEBkA^6bKzIeZ0PcdRiTCTkbRK2D>jOH*F(}2%`N@2!tx@s zX_}r(UB}QfS7wWep zEzf5oupp)4xte7%AeA$2TaHTjbV#)|-xm%l|B|(=_D}cW{=NH0WabwpEYw&CcwKV_ zIR{(Y>py!yjRh%#_1dzLZLqz;!Q-Q6{X;px=#AN=-Mhs?K%QnAU!T|*>q~cCySRyD zd}(|!Qzod*$7oP>aD4seM+ekGkbViYCCx^0YoXDmeIjmuCeG9L@X*ResW(_Hfgz}8 zLi@)8Q>G(~jkhSKokT3snSQ|3W@KZ&SQKCmB;OQ^y8#v#CV_L3X9b4tqf+#+2`ZLf z#Sog?a)uq4?k^tYp!OA5p3vh2Q&G)UXUExMN4+>gEeUrr%4aLMa#%Tf<&~778OGdq z>7oh4D+ahp-ro^!*A!^tz!EO5-B*GPuc-0_YgFVnUW5Pb$&7W%OSZ!06>Y*_6Cpr%UCE7$0?HH>RSPW%sX&Lw z&kfuBB{CvObi@Eg%DYX3&AFN_zs~H~d>=$o8uQJtQMC<%2Fk2w1Pgd&3hf;LtRvycV?@1=CA3>^i#br(R-J5F#?9VGcWkUsFiZl6 zn#~-b#$@p|lmjbwU$JU8>cO~ZfOjgF<=$G$62UimZE9Q}to2wAtt_%%R**M6zPGsh zhOvSa_(WCpoi_9a(?u>JvFHKu74Me#n4hiAAPHzT*XeAvBSO`_SApgQh_?8@RDW6+ z+_Jy;LKW)f<)P@AytKqyNZX1VspZ+F!e=pTRdvU`{(uf6cD`&ky5?fDac}+Eh-^2Q zj}2!cg8NMryu?;JOW#*4XZrr5mot6e7XNRsoU)L!oay_@}ZoU^yeRac}+E zh%Kj>k7mo6zQ4qBVobp5D~ZAeHo1wcJn`#c35DZ>UD-cDN`(j^T3e}uLnFvzhMytE zu_T^;`f_`lGKxjEnrgE>Srp<=?8;Qd#Kxh5?82lMsC9=P21Dh#q_cucyWtjpk{4Qg zd&9Tv30!!Z{%&n=w=Q!Zvr9I1^;cf8m1m=JN$>GXiLM_1ZjuX$WGjLzlY#*Zo)^8S zHMgxQcZo9tPS_#gyLZu&ws?}Ea0u_(@oJ>6+HUe>k!`9_T+08(QYddGWzt4z>PAo3 zmhjr5X1ba#H+0#vqXyY~*>0zuLh}5L-&ZRfbS2W~I){?pw$iG83=_GyY z+@*x@1%zdGR(4dPbOY?ImLC&@MTVh=pnYh=*h8G-;9DfXkoj=*9AX!`m3ZCR+8btD z2hqD-{1QkW7p0moq6=J(kYt`FKZBh2L{e-88o*T?-M30I7bAK-5nhK#j-9Gq8Xv{I zs!^m6cp%X8$l6ff8&Ro-?!H);i(G-_WLZpC%vB(=GLlAI=;CU8xQ*5Jlcm5DZWEGC ziR*JEPJ%d_5c&0OE>I!V`{y=4j(0Iuo1V05H#%Wh=1@uBlH}!f2aA6r{(gJoRRzrL z^(0k(MBPYYU-+_w6<-gHW%%5^I?u??opfdZ35&^(8!Rq4M_l6D#l_cv)@ z%+q{9K`N>gCV?ZtT2$Uj!JegO2a6|X^X{C23XB>%&jm>(cZ(J)56-ygFQ3@Bw%!{A;c*s^(r;%i{EOn)T0M8k$@_ z6+>m=q12eR#DHXmav5+R(CS1W@XB?864WJ6a3g)pAd}{;W8X!b!XJ@TkRdhyKVEg+{2NzY2WiQ2WmJ^u7OGW<%5R)J-}Y0)c@H z5Z=5?XLLa!??}pI#V2<(sVEp*2}-Q_i1gqj>_z@mk`1EG1tx`4Bk5W_WKvy@HuZO# zfn?k!N61_9>fH2Cx#*KrgUgcgLe+#uCRtz1{j6_c=_#Zycio?mLd5pJ=8NN!qe$mk zh3HI!Iy*gU?KmM%#I*I#>LjQN!Yu|P;JsHJM77ebjw^_5TN9j(JL=5Sc~rakPSTpR zl3voff8U(P2t2ZMlRjx;;IP>Gbvs@=W_lxth94r@acx^@;%O=1JXFhG70reF8X$;4W*1S73#uD(Oox!_%m^t zo@TM6K+jI_tXY-Ho6a;L^K;k~U*N2TbWPTH+; zdM@^TSIlTS%?vRhpEnFy&~McYThl~g>n8kM`eQ!MmhT`UqZ~L~Ks6)h)K@6GsK(4e zGz;i$eunr>AzjN@CTOUqb&Yz0U^}!0W3LsC;@AnSJ*Ib4!D-`T$yJdxI9aMNo8#mL zNX~|dNUkH!Hr$;<@~6Pd+gLAJHk4F39gnS(v56<*+I1KCdc&jec-Wi%Y>ZekU!J!s zaAcDj*eS(I*Pg^j*=)6j6q;o23tLGpWzt&VAk7d|?pY6MQA`y{a6m$PLHj_!CLZ%p zLAL9>o8+Sj)zM8u4M`nC&ouUrpAR`~716*(kR8>C1o@kRXdfn}!NlU8(h@7XiooFB zrcIq7V7$tR0&iF)1G|Iu#Rx1*&mLF_UTfVg@$0ZSXB^c}yws-lAK9wnHY| zaXyC|TarFFM{yONZog@oKpC#m>J>l5I=Y0sC(qKk0Lil+C`c-uU~8Ek+u7y>SJp?{ z5a|{ST>3tmdcD4P}8N_fc z@X$g84fB;80_FNhDYX@tg$k6*V*W&6`Sdg;vGiINvalnse_MH;^r4Yv|LJH{tY%Bt z9w0YFnNUX?zL9ctQ*0cjp4_q$OJbAi0+6KPZ%U8k3e{;ZOfX~T`5dB|NOA|3f+_>q zB(A73+ZWW2?BuoWjihIVyx~ZSkuGfk`oDm17MR(hB({-`04S41?M*Hjp|I=~WFTWB zM8mzP1O|1NJc~&Ym`curS@U^C7bz`<;P!yQQHPVS=Y|uDOc%XnnZn&65_Q9g_~ayr zWcG2DRPZOJgs+Bnb%w)%U?=5F@!|qKU~Cd*hOt=9AbBajx&$6CWO%z+*CDi1zdR~d z6rXpevT%gVts7f2Qb}(h5>AMv3LIR252@1bE|Sao2j53^T-BYm*sAC@l6}+D)od#v zzKL%n-uIeq)PTEMXA@mqimf6_A&7?`rE{=+fqR@TX|O&8pO4vCkSfT^2pkNbM}?@^ z4d7c&hxk;EE#=@u49klwC<(y;*jAT}(HBL$WUPq^%I9hxTCI8uAzQQT@R?%Ig4R4g zkx7Ddv|4#939?__RiXRGS{M6bk#-Wz%8s#5SE+Z^jt*fxVcJ2(OcD)Bj$XeaeOC5Cu#ULugbf(=fP# zSF{l+1N+dCDkCv-r=IwcSt$hbpPzjsx;GvHqE5`wNbXD7px&11S?@~qLTyS7#OzA* zN}mm9pI&$!OW(&_W3gqZ;#KpGiP=#(1+YivL5xq3<0l{)H-liKc**>{bOBW3 zF^?f#=2h?z7@2H4K%xS|7AOZr?RQ8>+e0C(g~n*hA#x|NBk?Elx9=HQDorDcsR$S| z7w@-s#2+-87C*lJ+GA=_2M<(2DfJY{uwR3$*4I19^=~%?N8^3oCfnn{m0fn{t8&t| zs2~c)kayg76lK9

    oP14#TIPI9Di%&55}Z_uV1hj%{G5a`tGop~5?C2i{WKt(Nsk zd&D~7NwJHL8M(*?i{cG9xfXo#bTpD|E*i%upDPny0Ul|MM z%?G4f97|mMrulSie+o%Df=5zee>#-pPtGDE%+`CqUW!~xN5#Ej*VdogBb9WX!cUHG;I0kf~*HBaCwp6wv1i{V13a1OReOeKy| z3O4Jqq_($S{$H@Xl!lka?uYy{cw_DbS0fveZGT8G%tAf}(x!*#GPwwKhNCYoA2c>b zTtsLNp7JJ|6x? zoLg+Mp7Zp5{hSLXH#+CQ07vIse7u4=7f`F_99i{ z_gglb>)i~J`;FfVjy>pKx56LzRsbFhmB2Ok0q1%JN1mQ-&Ce(fLax~3LWLBYsNHqekqK5+1SyJ%#(*eoxoCEpX_30zqo90A zPr=De+oga@60rqQ{vH+-^wnD00uQ%=$OcFIh4i%F2!tciRJyJmCd(6=WLAnSOcy8= zV8!D3I{Er*DtEGAJg=q8>LlBNec|p&#xyK+M1lo{B)Hm*H*xjc6ECgtWFZ5Y-m(pP zSri4b(1khW)oDCb`A#pEJzOxc;-3}nvHeZk?BQkO_Z_)haJH)MUw z?hF4uD>emMJyQ^9RZUrZSa)nx@=LAWIx$A6 z&;S!vnL-fw93pE8Dg%S~pPVoNqP0Hzu7L1&taQ3uF5rx&n?Ud7V+`d^;h(=wT3zfN z9@Lhp1SSihoTcde$`DkC=ci&@EcCh+Yu(vwWd^q9Kjaov zb`S8x4fyT0T0NC-8WbaRykM88Vxp$b$_x(A63mtjM;&4HS7t8Zdo%f)i^-@NdnXz+ z5Xxks!dNlKK%Qm-K5LyLeBo<_AI*Z*t_G9`wQCo2fEqI1gC=sDX$>d@H+uy=@=1tI zjejWPlVhg`*U2|jgvT%I(t${ctC&Vfr&)7I@0bgWJCCx!8Z${X^jumku=z|9zipzw zLRmqaMB%}y{+u}}RW1NZ_d)UIXMk%QX-d4n9@xMBNR@3 z;g$;IzX;~DDCUoKQ((0Sb*O_4d(LR4wwr>2Y` z`n7NZ&6$z8d*$O*CgkEP{WrNnbVI7wSBiN0qa_N&$Il9ZBL(&;@lEz9U5+LP6t}jM zJOK|-@%QN}Tb$Fw{d6{-f>Du&gcblvW{A-8?%URqqb?i}E*_6C~&@g{7t97R**HCIF za6_Lg(o?`JcdX1wzxZn`3WQdkftoL9hut+GP2MGO`@G5L4+}CeCzArFz#^MNeqC|X zxHTasgLwBLd8zY~ik}=m`F^l&=LKhY8_`%;1 z*z;!($y{6AU2L0!_Jf};I>-v@3Rhcu0E#uW!l421a&^2(aSg2|;D9151q#dD2~U6r z)ZCvI(1FaW$-wH8cbuCZ;Vkq(31_Oq$0Gs9W`?&Cfg{=sVPmHg#YZ=4nhT*4*4&TG zxje90AVi2b1Y*r~81$sA4EfKB<9td)(T41SDtpJt(ROv0-IIJSt~mJjXpzoJkQ!9d z&`^@dXHrN5>3oEINR-yauTYOuw04UKaH$?$$IWiHn=VdE_2T8Lh-cB9(D|(dO3N78 zn-R|t|qT#&5Qc^Kouv zAM{x#P4YI#peRljA``EqVE?j3o=&%b6|kz%5vihkbkPtx>coi?1+v@SvKh24sIaHy zWmvl!p6;WVIiHPNgK0yQ9n1+HMlWS70hzLA53*`lv;JOak}6*9%UGXv0mG@`MJqW@ z+3&6>D-dORasqN^^3zVre4H7(d_i)|AR9(-K)RKlIVlkibOdK05@d!Q5^YMEE^)Ug zhBL-SYOu&ix(uUAHLVKu)DeqxGMAe_xD_yh138984-L}$v^DUu;mo|=m-mkzJ&Xsi z(0!1}s4GY)D>*d{mCk)n;sxS;uYgemVeCt>`Xnb-dyxq^aqa%5C!Pd;xcpxxFN?R? zVw%p6L?=!&gn=f-;*+H>^l^ug|CQppwk3bq77(y>mPxOO5e1+D{MrSYL&IQDs2p5V zqNrYg?jznLR*>OF)d&$;p&|l`%JGOUp(qisfZ6pCNn%g{29*%>CO8c0d%l;*QJ~=R zHdh7HNT`KW+!T}qkqw-xK-y*fjG{-V#|LPH?)p^~9#8&;3;h!3+%%_`K<^EAquku8 z0&7-Cb+GA@F&4GK!Wp{L^j$Clf7ZoXd$u?`WY1Tcyqqku6L(scg22l_h4T7%nnInc zov6^N-L{?JKGkG~_x@IT`N<^~&Yso=;_l?7zA4Noj8HjpbX+KYx19&lDL{Fq*}6JH zdVdB1s6eUGfDWcZ+(`soH~?9w7@%TjuaeNMq;t&x+I5uZp_l_PH$;D0ceJ$k4PDYf zazt|6A!R(z3zCB*f%$lvQCIR>{Iw;~H2`fg8`HdmDs zq>+xE!A@-SZcHeRQ=IICF)P`14m&U#fn%!&Ai~=4My|?VVkA!JZ7I&9 zniVcLV520M#4_8D$z}$!0EO9-|%ELcy=%|m;|^ZNCt!t5b`4_v*-))m1v zrZ;~tA!-!1q9fx#N-A+FQ7q~}Y9+ExsY?lF5yq8>XM2BC`Rp`%n@z)!-#}h6&gRPr z73wC}fDnf<;BzOLh#f9=qYOO?c}22pE`Cw*P`~ku3Re0@5p8aLYGGzaiF20-r58Id zaej&rTWA8FqyHRJ8O}-9ey#+H7UvXVlu)7mZc>z40EjY;A~(H?=*3jE3e`KeiG#20 z=Q}b~L(g2#pT*H5ifKGc`Z~;nJA3n5t4DjB0y=dXR=cjN-M*DvM{|6Xe0&1g@tTrj z%K}_kfxGXFeYM;L*zSh0L{Az_9?I8B8!Z z5xL1AHfR|eY%x+#0XCDY-uM+7OBm%os1r0Q_*^>ospPWgi6QV=@)G{_M+XkCqe=F5 zQOs6z^m~<0;AhYh+YgeVi(1#doxj%tKLEv~damfV!4=P@G%T-Y1@PRw!s7u4=Tr8u^v6!*<`jDpY{g<2O_No;vd17t zxZ)@)9O8dNhy1F}o`BDKYzECwnMgUIrI~Lqk`UN^r;dcR*NBD+xiO+_g=O{ zz8hT_m^9*kQ7#|m2khO<#RFCp%5xT)VkT=6NS6`xL65tdCj;C;zNLVG}z z7q{Nasv6~}EFluATSOuXx8y4Xp7CYt`77CdEUI8hv%N$=WVBz}itSc8&BxjP>|g~K zwT^ILc5Swrl}2GlF_lXrFsu|;nqj|!c=Y;&gX8T#*`htQ!GusMmYhNj}T$ zY;e*5AEy*1_&8n21j@9Ny5UKpMD$jRj$*#v+M=VQu2G;}bR!I0+&ZmMt+0`WZfdP|p+w-ESIAl|_`VjWLWcMMCN&UhtEsWLC}85ONs<$rT(sokPZ^%gh~O6jPE z)s99w&P$r#jdf<;j>oU}2nM~nTP!dnPi5YhL^T^!Swi*Fo;AuDj4`1x;~QD#VAKXR zhs7evep#hcm0@%J`J`Oi)UkNh#BniNp|$mKF+T4WCnsgL{1Ll%^H%cRKmS!d?6|QK zoUFx}hX!2ppJIW&bSQ@{jVTSNb5jd;V1QR;1H@Ccxx&rd0(zB>xiunoG1qUzD;5yx z3%v_XUK06sx7Y102oU~l2yw?&S&u+XDMUDQN8^VNiuZP;r&%(}AGbCpKuO~soD{_p z<7fSiekCs_`B>~pXzL4l)y-!D^CG1{kwC5PdLdO_);0Dj6l*0AS*6(kCh6JnYH_M# zzxd*rs_pfKw-?viXetm7k41vgdH70pwOUxu1UhVxmY=;@+$KwCnyr~BcbC=IKpnxC zwq}g*vQ~`wazm~t(^e-zgZE3Ap}RuBT-q9boD47|_M@&-M3{xR07O-(5^(!dD+{cX z2(qR?AgCY1R_PJTbk{mPXrcZQ4iiB|NnBkLRGOI8atnUE=A>SKlGm9Ueg^f)no5+K zjp@O4lqXm;qB{v_P_TGNfl{qTaa###Q7UvPSiMS>QmIhE+SU4$pjL%8Lr|&Ws#d58 zSF;k-uSlrAdc{++d}^E!#0Zx<|DKPVRVheIHoy^8SR!fYFz44pXERyJcofPPp$hBT zOW2lwS7GaK(2IH)nul!)M>n_pu?@-oItUTF9@pOPBh7j)cUGciJ_c{< z4Hj6A;L!?{(dAE2Hn0B~erxD7xKA-sWX4 zaJ4vikp3D4jHWu*k7Kx&o40N!3YgZAU%SCH_{Fmekm^G{DZ{Yyg!04NqRZS& zuecG$Ro)IZXt6gT?~p_>H>Dotwho^f3g3Dry^2a%*+E!0<45au`=v~|5rRvubJZt) zEfa;P9R>LV31T=Q#r0~T^?1)qvOM_d%fnOUJ_THlMg?61@FZPLm&walNn31Lanqq^ z<3_+rfzAmDcDd(b3t% zOcI$v4C4^DQ8^+eMFl4Q=}SZCi`U8pXG6`^L(K94`v!f)&LATxpw<)J=eIx_6yTFuyu%D%*w8o^td6*8^Kv5UVYcq% zOsrWxm)dkND@oGiofz&sJ=JUbQdAjd;x5Ww>FBKQ-o5L-`=(ngPPcyS?{6(v0_Wud zbz%Uua!YTdEq8xBf-GNVg)6oPtVUa=HpU15wxPpoT(VnO%voyhES)NFUhqJ!TYc?< z(pisFL6ZSd5ZkBlO>BIfD_d109(bR2c)N}?_$>~6BLsa+IJ4*Bt12{Rs;dcXIZM)N zY{+uCxYhwPl{o~K)N~t}m&nm=Y;Yr%g`pmMoRsw4k6B59t>6TWAiRV{mAZI?k{l^C zN4W^21}?$z%4;k*WI3R&xGa}#%#Yo~^}On~Q>nYB=V%p17BN7PmhlTu!3}m%%*3JI z>jwg4HaY{>B{}hjb;+7n!&gSEcN%;J2G}R|=!n>TGCk{p%HpEvReEH6mxv zZhLDhxz^o4oPeiH4u-__EWD_Ee=9*(`z}4|5Cj6sbpd5G1#e9?HL4EI2{!?PQi4sS zLE?B>M0Ww|8|V-?5z18VMh3&$7G2SuP^W}msB@ravpW~0o%XfY&3r4G!HovN4(2H| zRhlq0^rB)Sm2)T+l)ZR20ds~ny<=ul^ul!AitZ5Xt^~1TL!juc0Lp6if(`42oISRL z4kn-@8^sP4+l)m=nGHbLTD99)lpNonEExDh={Gw{lqGJQjpk^rqT|Jk*pXr6^x1@S z1gYr@GO__s_5F5gtTBMVJiEbMg7H`4Y-E=UHvjRDWF1uF zMsA6P<8hZabj3(~TpJbG@6>ywdnj8O8xbX)9P`{s((hxhsM=J;D7(R((3ZqE>^4 z$u*`!cC~d&2YuG$dX!3DP$aXGbvA2_HnQEWrxQ1YO;JIGInMS+~)mtfa}O|un&cw zak%r1+JF$j6^llCVO()MrbytNbtDJfv-oPuZopgVB*EqaRr6+CS%T?6iIy!` z8H-uNf@!a&Y~}xL>EJ5%NZT&i9T&5V^71l%`4enc$4m&W>_|!GHxcPGyENC?IdY&M zv3c;)ui8DD((K5LT}abbY^j@DtEomsUWuDq(>y|tq;KoStL^vg`A4OYq)t{-K9|So z!t+S^i1{#z#NU#%JfDr4%!!;2@g=?5pcegW*Uldm<5e(v`uNROD!yAL1&3&&na@tE zYL%*xZ8{RK6UbM@bNI&U>Fh;3gRKi_HyxkWLpX*~Ue!XN<+H;{mM!Z6VA;(Q3VU!6 zz1M@lV&Te!h8lv9jzlh`LAn^%LKulcUPW*&JucqYSC$2R0QtOZP+OF8t3E~>_`Ou^ zf)2c-ySN@;U|#{Gxu8d~MQ!!5F6sdhpNrFa09eeg{5BsqX`aft)lu^;+RB*FBv7?%Qq#Kxj*4P>++ebnR4!C~ zna>+l7v;R_i>$$bMIjl1N)b9_J4ldBfTkdA)6w4;xx!vD0>XXEce43r?t1ply2kl? zeLI_%?mfxAu*;9XWw)An?c7%8gL4O&5B9}k-ka-!y)!p~c^Rr~(6@Q#U}p9qgeU#a z`t+Jl3?rJC9M`e89Eq{l)6gt>D2siv5D9y)(F1$OPriB0PPFyX+Y{C?v|sDv#a`=U z!zPFkZfqmFbhi9txD)xp;XZVTsw5d_f)8A1+glk(?fqXz?+EPr{DM^w-SPUz_Fkl2!s91!-AdT?rW#uc+GLn1) zCWumG!26Yf_@J@!;V7Z~X|@oU70#@`9$mp}9dD&jM3A^p#(FTm3>8rQ@SxQ&S+r0O zBJ+_luQ1w)jJpTQ0`=v7mI|z(KZH6!|Hg-bH%@F?P$WhFRzS$7)8j(iI8i97fcez` zT6j`Jup-lmYF0pDvH2OP0_InDtjfC3;HH4RD)4+hcOik8X7dEU^51BF90K$Nuh!Un zAq2X8`S19g?G^84(;^)|EMPlC!OBwl$L18vyU+FQ#3s~hAwHdOpT{~10vG%z-V+$9 zK=&~SQ~Ip_*1`$zH5W=`pFJ#2i+D#)3;ZYEg-2<*oQQKA192w5>mPAYk1Vqoqe`pA^#CB{4uwd3bWx8q(G>$M{TYX#f+DoM*k z7mYv-FRP$v%8A$(Sr$F?C6?JNv5@^#F}nFpN-B2VITy=9!z=w*Ybk$Sbthrc__%(yy*F%o%v?}ji8+<^GUhQh^ zU#k|IXP_%_Da8F>IRavbyJF$~GxTuW(#@4yV<=1iR!k&XVmK6|0tVD!iBFsPSksCX z(p%1tb^JkgLQGZ1Vwr-HD&nCdj8ez`8h`KbDE4QEQ88a__Jh6mmnOac~wz#6CC#3Y&o-Vu*bYvduB3av7_x_XviBv?;oIQs{?w z>0$;^fz@-iSQHEWRIV_h3kyI(*0vNMB%Eue2QgFtg~48qcAw{$u!b>8XEFdqK)Syp zIKY5Wfak}Ob%BAuquruoeSvfffj-cZq*L;SrmP;zWKz6KPSQmJGGFW&NmuZv>>f{l z!>6T~->IG!>832UAqJ-jb?OJz7cqWu@bc3cWwORO()QK~*k9+zf)T&e5jfq}5;(45}&N|5yoR@guCIC^}n|V6Rrs%m5?NgeNbVwrKLT*IB7YXEF(x&aK zZ3C9~;Nt2+NPfiv^aa&TSKshjnxANGyVvnzCb8mGjm)|{h&m)BMVG_NH`%#b+gClv zzq2E8Ask4y>iXSYCiaPS_7g-C_8S>og5X_L_vdbwjgQ4Xd_-rWOjtBO@IGQ-M*=4= ztT&|UuwKoltMUMDf$-ZWQ*j4Rt#7MYxtc@wvhiS&F4ED`sXQyh{H~_JueiMtYhb-B z-dK-fevy%omo?bl00RBo=P9Jji51dI^m$HPP(c(e1<^G>Q@`R0mYTBWRM!+_GT^Hp zPnF6fT)1i=p1R~S+zIRHJG}a}iVMHSdb$UHk}8x5b%m?uKB`H$>e$ZUCx3+g)r6#X zANDC8Go|67@TX7u&xVhW@GS+@px1}Phj;O%Kr<)w>geDJz7Yeu@+i)h48*7!x?AFZ zOkGdY&feJQkb^srQH?n;3jV9&9bYDX@Fxr)tQbTFyFnb`P08P_9jm!2Mzh{Y>9M%@ z#06UwuNI?^;Qm@<>A09p&y%H003ahsQdrU*y9lz7bun9c1#s-OE^GY>2pYdJBqQ|3 z=s8=8^~n@cd!%P=7+$nN?qF5qXWXVbtM_#)XbSxSfB|2Mznyo=a(F>DBQ?3Pc zOD8<08M9vTsfv6s(_RAm8vHQRw;3O29M!PLWtR2zbFu zm~Qf7=54sFUgTgM_0>)md37j{A#4xBKnRabik9&^A}XH!ZGD85$=VpMy*cJW3{#D{ zUU|BRz~9w!7pXHz6w=kBNady zx(n7;>>}CFVaFT~xIRoUB7S_}**dzkq50XxH=pZJedcR?-3z?o&At9%gUkGPJ7ahk zUdh>ls5r#B`%xML;SyEYjHvj=7UOUrfR4rK!WhXFP%?GVJ;%hUF6Z-3|_ma(*Sphecqs zubGv!SpGW}&%g6~kfj!1!ltt- z{guU0tt$h%s)Su@W$gNCwzZXHrFdL!j&oG#Z$hkZD3B%phD(iCKw03+HdvL#qv``#&p% ze6_clPb#lB`EiO7>4-Z~O7Zhuah|J(d(%m6jCI#F_VxJV$q|}x7-n{!L+Zy5u?$9Y zcNTlWxizVcPV%YfW%FDE6+;i?oMOP@lWgY<9YwY*;gECqK}E z{wcn{)u{%x{1E-tHscVkk_if!Ppv`VtyNn|9@eU)2*0%|IaHljH^|pTN^#C1Qlu8a zdi5@=nphW*dmCS-{-r9q^4@jpN2FgKn3cFS!VuUU3Wb8TYkeL+`ElDKU{6-ZqIA-K zvY#BTh$<4u7s9wy7!@r>80dw$RtC$g5pm@b^{Wh&YAZ8hrn+`0u1d5%HVMqSL5 zwQ4pQm5GL;efXng>*AeMSF8(d60fb|i`4fp5o= zxQ}R^P-Ks2VK2*5K z5$vlDM$s?7?7jRl|37U8To>hg^_N z`G&y1^MU_so%-K*Yn?{TY&UTlHS=%vs)DD-gu3Zf3$?VNd&eyOXqV?-F?~n za_1BN*BAfcpL_Rq9`&C;@0{-T`=`5|0le?`i`{Q_JNx2y=STQw0B_(~lo&#Zr~Uo} zU+iNIDtfQq|8M>7#f~U6-F*lzo>HNwve1vZ&;SbETOy?AROor2P{04+n?36F{ykA+ zQ0xV2++#JK_J=9IO!l zz#g4}VoT!34XoEEfDgp5bm=~nxyK&Q2Xf0^AK26V{hsRMz?*ory7%1fnSb=QFndUE zr0={bQbWK!g?)S!Y)-A(uLHAcv~q{xmD`8@4dpm)?5?+iLhIq|AeyMB^3*(K1%HH7 zsTSn@E-eVI1&jnsq$ zn4!o4{`0VZ_vc+g%TE3MK!=yWS^-IFCEI9`{auuYd1!pi9ZOr6{l@e7m#Sg${7)O#HsLPy4{Ga?PqD2GM`R zsyx(JH>)zWsvv?_6%M}M4K*?u#u~xT_wdNduj&9HytCc+^3XT{cd3dfvf4eUDj_b# z!E*S_kgYGCcc7t_?0~o}aXbS_7>a%hLUE|blz(a3b?;ZCAAi)vaBKcYkN+I+^k0!I zJ)lAdvd|NaGgrHCVGAnLIiQA~LA;=r{Tq2-I-h+sJRJlnDF?QiCWQU72OB^8unl7Q zB(MzuLt7qU3lwx0S7?t;3>H^)`g9{bwLgT~N6c@CP4Rv32^%bNP*imMq5o{OL7ySn_0L$WB2aUG;>@pIcinh(4i z2#Xm`2)h?wJToVKIVW~Qm3v4}_HxeyjK$StAL-hXqIU>tXS=8?8S#W^<@*8hYkQ1c zb9S7we35Ox+|@`wT+pW_ZdeBZJ7ESWzCUz3q0r3$Z-ji;nXduN*LQn_<0`JvHqrkjAzf=$8&p~Wkefu!h2h(z9ujn8E zX28Wz>-A9a0S?6Hv3{k250C7Y&95}D68UamQ8?wf_ur}7oe|3O@r;n$&eywuu=&Z8 zE#5m;2*bi#e1va`-Pjnt9Z$rYz~v97Bp}$i?$dTV{o!=?`&~nO{rJ4|izx7m78xE+ z2A;(5DHc!?!^LhuBKJ&RZm9tB?AL*6q7Sl2c5d{okZnkL^l1X@ZqJiNE~=(Jz1gz%Ju9`)}Ej#8avSA6rt znj8NTz5nw-$ztN-n;#^lsn3p<+0AyjkOt%q$9tBx%ll8}35=VGBb7CK~< z-aSCryy-W4*HB7>ck0$)upaLp;rK0?Ns!}z3Yf}a_AM5Fy6f?Sj{45Nn4!*FRR=E! z!=E;)qbLF#?f;4Moffw_b}y+2i#e~5-x#eES8)#KyFt!bwLJCsT!UN9J45N2%i_j> zEkQ_@qnemBYCzdfly^jT>t&9+s$Z41~^E@ zl=yudYE)-bx(iEoVy=)!nm3Try^w?}m_2>7WGl_-Al3reA z@bj+6Kz(x2fb96!PY1_h-HOwJK&N3w>6i1zA1N9b{9dwwKY(yx@Rx94ec`}SY8|YA zaNxULE*wxCj1dhyt`!ZymhU&*@!0IYcKc6n>}s6O6f-AUb8~Pnq+R;isCHi53u$)# z4+mfdqrcB~c>#6naxIxvz@`?lz*v8Ox*t@45sireh80~D=xKZJnIQfiq?XQU=a>8a z{@Yzkrt@j=;rTreFq7}>R#MXzvFt(#C_9zNDM~E^#o=o^NxmV41e{=g)IWH^xFygH zifIzpj(qnCr)m412iVNW**eqYKnYCK{BqMoq>ZE$Y`$Xn{XSzX4qe9Lq0d+dD&ycC zzI|YGX7`Lf0lIN*pbd!*3^(A_;dT?lZ+1g<9J>FW&2qdC)^WIwe8AZb0b{x6GB;A1 zf(oq{sCLAuegT9xOeOq!MrZW}5b)*~@_8?Sox_v*LJFc}4V1OK0OOGm6!SF%L| zeNjVDBAb0n5A$Z12`!8;!jr0<4SpSHc4=a=leM5#V+BdWDK+ZR0ebcw{S+sBO2hEj~1L*XRF@oD- z;-)^>&}t~KzwB~6>@3PaAA(_6{uutMnKLuiyA_>!3Z1fqS5HIh?}|E~BKzj>&Bn%r zO9?~LEQ=|a`+8lq@_n+gjrPxQ9e)2N9$(L;>1*^4^v;55d3*QI&$JW|2LDIg2>*K8 ze;y{_wzvN~K#(fxa#%-QK8#V9rl0?cvJSzvfp~l*m&P$x+U0gc`t$=K_WVDg3dfp~ zdtOIuKCdD+;nuw|U{*x?dSe(Ar4H$jN-lwthDTt3gv(ik3rk_KDtu$8Bqx61LoNfC zg=JfQVJ-^B!oM~yye~+Bp_s1+{{ebpPqSDrjM15t1MTaT9@wnSJ%yE5nlJ%Hhg1H* zE}v_2mcGe$~61ok2JCeTDN$w|6sQ3o`)S6^PbTYX7>qC zDHS6#^JVuaDM_%Pq!p`*PRI(>S}IPYiF=F+@cm~)s3|a<45T^^_pv}$nX-j@jwfvJ z?XK3hg2Z-!Vhr4)AmtuOdKcF7xfCXWl<}!V6F`SO)hI*Y<%gu@jVf_L3-$w3sTvNQ z3!;?1@5g|C^EucP-eVWMVC3%joy(_A|W|F)BHfGYtjsVpv6L1N`pg} zfZd>v3X^j}sh&g)9gqA&8@0* zy?nceq@=z-!SXI3Y@?2Q6x2C9g6n{ezH#;N7SAIE%y9sR6e)l;`;8Ul26|XZezQ&N zl(~6d8OsHPs7z(F&V=BJ_SE;r49pfuL%%X(0q;7`gvcF`nGfUeL+@OB!;t3IDg6R9 zGf|qA^k;_*_&0lfSKw?6CyYj)A2P5!^-OCGM}faAR1$Hha@5xNfgeFos#G`w8T(KB ztPQ>&tXqkx?XkR|jHIc9A$pgCxRU89>h(i94awN{hw(KLjV}fcy7SM|(1yVgLa0{A z7ve`BsRwwP@9rsQCuOCxudn;3Z1XGXgiMLDPlx(2#kWp{4x{hJcdw6lwr3H)pz%rO}_0ohn|Q7 zAU_Y(R#ziY7F1e=r$jE6F^Dlwk=311Ih|*A8pz7u7fqk;9@q^0gfEQUe5gx)^R_ex zZOHG^7%ju`llVEsi{*u+8(z5Lq0kLebL|<6s&G#%?mKPLs&y}HaqOtrvLSiDytu@f zWM)QB!M!P9NN+?7+(yi7uhdu-5)B=~#AfR7m%%}1hc!J!iq@X-3n^6=5IbVy4u9Ug zMEef)30&2lZEJVnV#Vi{!uRJv=(?kWgtE)0sOxRoGlkC&-E9EU!2ieIn{KypEa{^6 z_kIet``%-_Wr-L#2v+Z2jjSpR1P6g22!eZi^}$2}ASPiV0WUq)d5H5?H^<5;vZ_E* zvb-&=B?&-f{6w;xI{#K2p4z0`sv~)>IKy7ra?}XNbg+w8Kj? zq(Oy}y);M4y+7$ollYfj2FdE998wZ}JxCTE@lL+bjlg5cSplH2vgj4jSSgfmmQ|p# zSRU*d-ty>1OFrkdbgFHIrkr`Mq*Ci2u(@RgV^rD2a3vK6}c%YbLY_K|72ShBx zO65T*e^u9(R8kD&*{du#V%as;v~Dmo9@_KX-{NXuqTa6oay< zZ3tb`bbO*TFmAo*45ac+%b*cnVi-irn8yR8VgAZ*$k{pfCgl(e$$1pKhBDtSRNn;s z<|W~4O=4e(rnoR9QYjpohp*hMjs&|n6|d8?73;=Y(Iu9xDDr7bGc@|0c)B(Dg_ zmRM9dGNfvu4EwstanQ6Y*@)(Z=)|ySuS9<2&=mU)*tb!Zd2Z~D@FB4AbOM40;Yy|K ztHCXwtOm)9IVgLqhJn!r)G|Q-j1oA^SJIxVwt#Yy$ zR~0Ei$^jIH^}Y`|3GfMC)4`9pb|vsK5e@DP-9Zr>F=>%xwhn`#rl>PL7;^DWpR^mp zya( z2jg_;J%>U=9CllqLW4Bp!xYiIOWZdC1&-&1R|dSrC|8EeNxs?y0F1t3GaewwOzq!< z@W6Ur>BjIm*UC`|ukT+;5%0nj@y5s$@#tpHMRdF>hNui$dE}xcz8G^D`z53~veJ5o z9!TzBgSSR1hDXRC_pnF5X512X7P)xkC`mnzeMBAei6GyTXNx>Wbo~pR44$SKnIPYk z?XVc7V?i?VqLPjvyNG7Vl7K*co`u@6!frVib*eJ4@*ZT}6{M3?Vh5zHovCNy|0|(3 zgbd2QuW0FHafVb5J=Od*a-N&|K(;A74OE^9-Gy!Fy>y>`$ws>>hC8jT{JBT2oGW@( z9Tx;0QU}#sUk6BkVw^-h7vkM;I|z0_vl>l@UF4pzJu{RT_s%kyjNTxK$!M-|3`vLr zAtgHB5gK%H0llz~RMsJ3Zq2i8{T_s_XW7ofU(s(T`u@Z8FKc2+3ODzv3DortkwC$o z@hwR%`ieBJsX7^sA}9mW)wSaHrme9XP;;*NLft4*BSi5cUFPIAXV{Vr{wqIeHg)p0D?w_mV8Fq-RV3gr-p zA=m0L3V9{M`<{gkQFR9aVK^O94T2#Av~-DNAZ38L=XRLXZnbIkb|^3K6#nZ(R@f`` zFcI;B%t6rHlrpd$+a8`rGRJL{B6M? z?b!`s!=|)EDhz5u?a721q&zy~0ROJ(uqex`(fhq-&yt(hmBEZllmjKGXxg-aMnoa^ zNO|>;P7rQxC!;^Alx_F9O|muRAN8q08>C_3KgIwYB!hzHI31!KULj+P*J@hI&nk5V zF8hjjY`k4BzVz*ySNy2%-A%k-rtiJ{8xKZBXZq-cPNXM)VJFgOlWW!fMSWI5cU16N zQ*|wyXBG!~94?$JQ$659RnfFl5q)DW(A{fW-DR?rUs_r-dMKRhQog6qbv5+I&Q9ul z**@AmKWN3YUb%joQv3=m1Errux_2w8U1geIxHhjUQ1VL#VhSy-_h&E2u?J+Bc}W!q zP!%7`k%RH-UDAv9%&)u7yo<=~unNq)ovUB|_V@()UP}|Q078M0#x|&4qy?qGZ9JvG zdncuUCI2v|?SN7W#CrTkx`8F33;+nMM_K|vU)9$Vh|7+W;AWTSaZQM$Rfr`$5LRO) z!AwbT0X1361|_!^cBZ$K;Wu@^6_*CWNsi!X7ZsVeo}?T#VMRvWa- zEyCeBUTkTr8L;&)H8BDt}iTLWP$I0!1BXSCsA6i|Un_qri3KO!>=!>*uZ zF${o8qZA zJE%h#T)Bpf3d;FodL@DI`)zPzinXHNcBOH3&=>wxJzX%)B(NFFjPZ^ zs~}@huz5b9&a=32i9g_s`}xU}O63kWAXu7b{mj>mxWq51|Xyn|Tu1HhFe0rfIr%#RMzC4Equ zf~_Y4Ehr}=+|%7GG314;G9@P&{YUYwz$l~Yg7eW|(#K#^B>@-ILF zg}h!~M8K8u!cSP`q!f#_tt@;SE;iRRs1K!l?xe1HyT6K)%eiv#j`4;m11hi}vgGQk zz_u4fYMy`{{d=yAdoI)30Mfh}ExHHIzdZ=O-Euk2L?gj3A`R^EU~Z#B0Elb_6pap)3al3y*hd}}d^Fs*!dKGR3-0>b~MPky9|A;`3 zyhS*3@A?(vJo;G_*PfT#S$N&YzSqVJAak0p!usWh>ld0?{BO;I;84_8S}~Lar~4Yk zE94lMaoTIlZj_M&ucHD7cAq>a$9Xw_!GHk5l=i*s4hIv0|%t955Y9jmY7!6J^kj zmTaRZY&{GhVL3@?H(x81l?ooRZ=v!wDcmF|e}DA&XfeaebU=n)ELy{*zM{kfR0U=H zcoL&*sc8--OZehu^2RBFGt6t3;e{5~t*DIK7r9Om_Q61DqA_I3^+uz;l(c!W>*b~( z?mcOBWbBL25+ze7*py@wRj+I$RUAl;J)Hutn0WDrEF2aE9<(hOo-&4CGoVa?7XrHg zzA5G>fy=`VxB%wA%6$!DNg9_d54;`S^9XHm$dYt(qlpS~SSfbr7z~HPjL!zdOW}ql ziS7}TA1udtlef0Qin{Xv-!hH*v=PoQjTT1>EP82k2YJ>kmorL>2s*TUii{YmhI<|p zJU+ZH=I`p-HQA_IsKoCBZf^acV zfT9Ylby9Q!RvfVo$~7nm)kyPz*8Gz%x=^TszJkx3qf6}usv}a)A!pMSiUD01l-A7< z$0C+X(Dy+vOm)j@JjsZkm!4_ft7wN~Ho`$JioQ1&8@>}_=Y|-ybs`y`>ewcpOUL%Y zl`=!>Qus0}g;)IO#B1X@@CjeN4jh3DGoQQ{UVrm{VIQ=M*N63gp#X)i>^yMSicvbA z_chR;M5+tVfvZ^00Wxj#31_X?V`~Bc<%%U(EyBvnC!_`g1bhc(lFTQVc~{!Dt130{ z4qG?|LOzdzyxez%gFI&d;y!P-PyNzU?_FmueB2{a^bk~2Y1mJz`3IlHbFgF_x%UZf z>Ii@QNu2lp>B6-DDOK#aXQoyP)>`NO%8ANUfp3LLgv~ z78OlH%DWh-U(fTt8h4VJrL)sd<(Fqv@DQV12-Ac49G&1J!`cf#DOBS;yP(i&Nd&11 zGW_FeMRAXsqHbvQl*Z^VjHr`+Rm~-$bdWjNln%$5mG8ckAC>Bw&i&OSkP%YN1z$!2 z;T1o+@!I?7mp6x=Q&vxn$}f~aF8|V@l)tKD^PkkSIZj5c$JhGh{q-t7)vxYUUHZ#- zRaal%ty--V7*BXmd`XtC@>1VHBjtn6&X~ z$n&*ldOAt7Da6rltcxbz)Qw1;RWnj&nvaOAi{VkFC>HLK%eWv5R;Nck;8GIgpkkW^ z4}B{XsLQj32kjNwfe4Cy839vmII-fXc5P#G8B3h}u^$stQz6`=iV<^?F60`1FLzIk z(ORxQy}i!Gt1U3KKqcrvboP8y9oefPDWU9_&#ApJS7XWuk>`*Xtjt9co5($Oq`E4a zJ+)9=AOiO?RQ3uQlEqkvt=$$Pn@3Fx<@Sgi@oR&u|Ey)X+lq`{VmvG%OK$bC;FdWoCfRhtsEiKBVmJn` zJvnm4Bs(Zn8n8FVmUg&f+l;yWj3NWkz-R5RblA*p6~opLQPfz-uOhf43_PZF41~4= zYmp{dET*IqITwIzqE=V9huV8$wjlOI+_-QVovLd@OW%F&78(vXfqaC0Pvk|>`8?8{ z>L4GGt8!7;ZA`?g_761{uF>m_TmpHKbW$MPYlwqhQ@dHHyNwYN+ZH9CRK^eIrOb8< z7tx~zua$d2AywXjfe;{o|>%Z*%4YFA;Cz}=U2&-YQ1ZJ)q` z4o_YR3#uo91%18vt-LXvd_hbjFobKoi`nZ1as5DyuZpg#S~7J#9isQDn9&s;&`^(} zwceZW|n2$$qCPo2+0Xa3|HKHu!1MbmOIM$L$<4HZE;N8o#P)BZ!FuKFp=^ zBJ`BV79ACYqlL>&O1XTCv#2EFOA?4~9`p+_uz+eq)Xy3+kh+GX1CuAgjF%YU*+%mD+oZeld~C5$#h>-#S8&8ELM$`pVEy);Uqf2Bu>79@aI0n?1Ql=L*SA0C}*hT1zG&yGVjQ(1T!7024sGWF}pU zltz7UPc0LX&N%#lQ6U>!;Eq=!PfQz!zV;|w>&}JN0$p;VccClAg!VcC%PrW~*OM@L zuV4vt7$spw8{SJf^tuveR{?H%r4sms%(Rkn9@F4%I@ovP9V06^ds)B&$kuTiN$Oc8 z9u;c_nzgXG(sLL;%-S)(S_~*3gk!jy89V3-+(mXY9r)H;i1N)&mC1lA(EKS<5(JR-QULE)!DZmA$I zMVO|xx%d4fY;}4tb~Vbp{vK1G$?ea`OYTOH?=KGzTE+u(rellS&UntCi5dDNfdFAy zKJ6dr;Yy2|At)MQ_|hGJM;=c$OS$_k4ba<1agwRx$=oB;<1*Bla7>1CHmE1w87Fn! zkBD<^<9oNrA@eJSbu3r$dTGNcJ%4MVj@f1i5WELdPtk~x30Zu-W?2lN!e7;JS2h+8 zqwb1pK7PB${2>iz>at{E5RFV3jhqyAXrxJxCR=4tV>;TB^CH_K+z`svLNMeDNzg#3 zFjWdEZ5vWHESm~b-rOLXTDb}&Rig^N@t%D5nlYE5!F0vBkdM+?TBxvy<3J!1@VvZ(2n?d(y+4g(!>5`zBVC%RxOjzDM@Csaph+v_>IH#G zJ&47mp1UxqyujkA7M@&6;Ihf7iVL!8wSvXsE#%8vv}1hc;sHqMmGc#SLTCarH9BJd zhqx=mmc)>;b1w$9TD^dX!X^r+^vS;j?*nJ~hAID_?*qPm8I+J3-$87TcZdN2dO&f2 zHRb|hzb{jTfG6WQST})3H1Py-a_f8HX?p?l7s%TS)7Df&O%C9XrW$s1Uo55vk`Dyi z!L?=Q1n7V0jF9i#RzP+Sg)q!`@AC|V&uI-B8T=xO=pIq!PjJV_oWvv>jj0z$5;vtax~==o=k#5e9>Y=@^TDcaQ!Tb3JE8eq9|80 zBGj(~g)3?0nKr}eN8M-`aun4`)g&}9&k(hSuKqL>EM=4~1DtUe3P=M)WcSg>tskrP zpCUl*A3@MTK-fsJSU{{HLW?o>bbR6z*=B%XSd3&Kk^Wsa2Z_a2Sjz=gTPzkS&F3VI ztQR6l+Jc$=f#7YWj7YLda;P^5syUY^#ha56ylWC;a+CU zCaI%P5gXC(gdMtH0MR@W6nPAT991Do`h61hP~Y3ZS=P!%){f+r_95~kmFgBkGU9fv ziUsf(BSCwaFA zq{9G5eJlGXug)aK#>j9x7o%}yT5$~8VUQv!nqQU#3DE~Br)5B)xZI#)!`Ntnyd4pjh?|?i)~DSrB@4K`1Q#`G z;ylOIsqWk$_@!T73sa%#?lSJp07VRM3uU7fG0y-9-#~bP;D@5HWj(>@-pQ z@>?oA2Cp%|fK7ZM?(|b$HGaQG!m%+>1JgnldQ}i%u$yE7UQN)v;xG@!kcCQ=20~|i zP#NRb;fcBql-fodRf-oq1BON0Vj!ctO}4Q`+?FKvH5i%%nY5TKPR?U!53uBdM9;NN zeOAx|m}X!sjp4$@gvN@%^c9r5q?Ada8cR%$JkN|M92(&HFo-tYDM0CPMAQqXj!aYv zwGZUJ1q7;c5>N}r7tJdG8SFyfSfW6k09;YbN_k~qIA`l*gT?Mgj}o|OZNpb4Ba{Zj zha&#zn9*MW%550X9Ts@3V$X}Tau68ulb_Fj^7U7jW(09i=-MGqA_5gnX$wN|Kp{o9 z5uq_PwxSLgC)Nm!YJ~NG;>i+*^gumWHPY095(GnaC$OWLuhktz>`C|PJ8GPvV6BGe z3_+dze$z7hO!m79QPHCpnIJ8B$Vv(wqBAR*-3lE5#?quKNw&mbYnTL}GXMmXGFTPi^LbAwQR#F_Plvp~_AIj+M%uqKuUp6!o=wPOgBLPl2et@hMSx2?j)z zm-7;}&+J|~LKQ6})5HVz?xKnK?>OPmMig^T(zMB1M!F!Fny?PNX+cHV!M7Ym86t(v zLiiLUk(UfPt4dGkXYTgIxxiP)!w{nDR%|pQTu*`y3B~7%sb&Rwg-hvDu8xWf#4a2i zU)O)!zOXZ>uB@=5k(5@(wFvl1omAz`Wy2z==95R-j=Q(85qkWTme?otaAb&MN%1cdG&1)_Q zW)Q+HO-2R<11IM|C%7MBY>YxCKHwkwd zSV^d8s2FF_WfxCI;DX-*lR)ZmnP-5ZAe5{YX=DaIHm*|!gYD2aK{f)ZavMg2EGV<2 z0j#-Zw8V>~ zbYQ>X8++-O>F6}SC_93)EekL7dHADT9%9OUaDw@3z$VmtX%+q;r;F1Vr;Fz6dQeoq zc^{984y23lZE#lb;#ma;-(x#{kL~mlCmOSF6YpmifSlBFIYL}Sj$$?X6xzKd(R)&Y zJ)-^v_6V2`t_rP&XZXJDwi@M7Z_pQ5Z{Bz3qA%}Ul(^&vw99hny-+~fwY*m35MD%% z)F8o5ah7nWD7y-I0Wrg2ALvc(J}LZpcD z&QSW!)ryL9p%rC~`R_>%4kgJ}O9E7EsU>(>z`Bbf6bnvq0ZbOrE;?WxP5?L}u6Icg z8L|#1=)^}Le?W2dtd`*sNlTZ>YB9#AvI-V5(GmdjV!lIy19TR}wSrSLE}$%)6f%}s zRgdu3%U4K*zf(2BUq?mdKcUblZVR17@tp;h%X2fM@j^#W&tk}ls*s3?+%{X;LV*FVHL`TJ(@E27Q9r2!r&KaZ*=Pukm-WLgl+Lat=DJ3kBQ3XrpOO-^iN`$8&;}*_LOGKi zXA6~OlhJ*HasXXW4&^m=`vzxVN#>mP2)XTUCCwp}m9$uDS=CKr9hp>p|G94yw?NC4 zO!lkhf7X#fD7{!0O8cdp=kjwi<4%S?kHszQ&SKcz5}?f?t0#ncHLzQ-D@E{BOcthb zr;5QK+g+=6SOQJoJ5?+}>CppXSZ<-xpkWZE(ftyEG?e{tf^a)IgtL=*JA-e+W0Rnc z28<~L;}pJ)>e+BChU_W)IeJf{bv^mEdhhl8L?n4Ct`esM)2KLalWiq#CQhhv&gBjS z1cr%H-AK7eoQ-2QpnR@NWFjo-jfj!YN4ud)@T5V?Or2Pd{lu@^5z>}^T>G_f%AaiH z=2vXJ6r*J8v;K2CkHOl&)(=YgezC5wgTEsE8@^hMzci#oRNPw<2Ovm4Uv^&}bxh^Vd(+SzZL|dxZzJ>!)tja?)8pJdUo}T>N$Tvf zRdXNrcT~+$HBBcB+pbrX&@?1hk!7Y%)x9+ew7#hzpCL~0_D$M9XMU1Q@gr6sQ~RXR z>%UM7BiNG{)(B9l`KRg&q1!LL%J++DC2Y$@o$4SDWZe2K6t|w;Z!Fp$rI)E2fzKFD zKcq_eLQ`b?ihIj@Td}KG)GoW0m^chqP2!={w?@im_pvJ;;5l_GQ< z6-k5wJyD%KLbfyq3u*C8X_|%85=dS^-OMswI^-WE)ug zfC77iZ?MoCoUS@7gTG-A>B#ho_LWg;Jg*Iwx=+5L1Qeo^oY#mOH=#Eaw@rG(dNXo!S}etI&98uR?##W6q@J@ouaFd4+840#W)k`d@1KWx_ru{^G{U! zoO0N4)eg-tW8CDVP3$Z*-sgF+DlK(gPhHoJvN_r<{W`qIois#EE9x0t%$JuQV0L>d z89|EWYLiC$JiS<%5#s97O}9$Tx;3a4Vt_e90Uo!xW840p%$D$m|@`T8?>6Tb9>#WcAQ9v8!-e zSX5;}T8+9%pU4Fh@OZ&ZU@+iF!-5z>1o$;P6Nw+1rRO!m%4u$aS(uJM^EVx$7_tk9 z-9*z1YT>W6gt8a+U7@IHHAtw^G;;I|JB+yt??B~0^h%~b9pqI_`%ilF3j(YhsOu-W zUVgx(czH9HH1+B<`4=ItX4@P37)89OTkIUkrH0q0GMIQ~geTme#nb5SBu$iV^Skz> zG^7{^0lS~I_}kC!XW4$+eKw80%CH1La#ie8*QqzR$0Se2B*ILk#$MO0Fd^w9b?){0 zMddzNsViQm+7V4lksi4$=C~EePN@O4u_6|BSAALZUd;+E1b2i+QGhf2@L0-!tSj>T zYe}95C9366Gu9~ypBsF`sgif;0YrN?$(GQ!@u7HRwLkY_FNPel?LS1gnPl4POIDBDw-Xp7?2 z5C=3RE7Rc3m60_Yl!_5Wrm4GV=Oy2Nl_a@}%%vLgX+&3>rW<-O@q(*lOk!(9lUyj? z95~6xaPHA0mjK=NRk#7sBvkP4C?L0Dh(!}gwkUFBYb1?wDno6mkTmBp5!P{T{xbiyN-yq5K2WM3g9UD&4m0}=(C0CA~tH&8=p(N{IvPF323 zth!X#m7<#^#ER`j$eadwExWK*EiP4%EI}pdHEhkHP{qW>ra^7MuTH{QStVDHVrWI& z5mjewr8<;srBupDv=CjV&nG6zM9j)s_d$%un&u8}A2d1#A7`BTg%2rlY`nONeKl#Xpu=e z(VgyP>4?;J-upW9H@~`a(2#^nRS8@wCQLD#?P|bobIUOZ*Dn-(0g>g*;vvkE0m5}s zd6UsyCW=L3XIb*-6QBNX@Bf5s7)nn0oOc3w2G|nl! z#lDqsG`}>|woqM2$tV#>MyYXOP{dLfTroo5v9>Qs3CJ*suEK)?0$4G+h0>;CZVNSS z20Tb~`h#SbJS-@&o7F2$s0{JUt<0e8+#&}RyTRz{AY0G+&{C#)t%}YXJyGfA#NLhX z?MP(MkWqQf3A6Dg3nWt&q3T)bh@fL z-6ww;#(BmU2q+&e0Ji7^m9{V-GqMx#odItdP+qj87AZ+}h_W-nLhNIB(|tlQ8B zEyXDUs}s!)k^D{n*+ z092ky)bg!!*wmiOVG~`M=8MBRe`C}Ze;kp+CluWii8IPT87)v0_?k$y*NVYK%Hqto zAb|s?6pJ8d%_cPy?Uap_u5??C`NZL}B6GSE@<*<2H z2w(+<=ddh{kc5^c!>RLbD_$#A0B%5$zXGBJlPicEek>R{#{U4l&IC9>-`)&h1Qg{G>gWEF=8!zV=wPG1A9FZ--iIKs54rt36gtX9r&X*#CqeN{V5iU^PP} zgE~SAP!hb}iFw2bIjV{xM^5M&{JxV7Gm=?Vi8z@k_Gh8^qs%gednn$G_-9plQc7F_7&(d0W^h{ zQF_poV$6bdZsCqHpVfGPz$AF+Dy>5@ljRkIlNk1`jBd^k4n22t=c1wrUxrFxn(NnuC6Fg}49&8sO*{+n z100ayG#WsWwS+Qk=9wCQq0@sySkdPAZafyC5jQ|6RT3InS0AdO45Y%`2$dGb)bQQ0 zM_?7Gc=OnI$FP&6lyt02 zgCRFH$S3M_)LErNihJ26-CAODF32U9#AF~bOa-$}M&wW<&YNt%YOVxAP?F3=RBopw z**1Vfpi2q>a}K`~E4A;LmU9IJ-qafn`9qr)QAI~@)>^Xw%UTbSd-fSL8bvC27-5}U zwUQ>$0EVurW7CsICX4C>?;NyL845vKbT8~I1#pQwhw&_pgTRP33q*JX!$ImoKDD&^ z?%frd`eDrPtmiIE4V9{1Z)BA3q35vhg(n*fbrZ)`0vnk;Xyl~OvF%nswEX>>4uq0vT60b6-C$y6@DGuwuyg1b1g$ zv5Y&4+IMm!45Sc?EU!tskDeKZ2EJ_(iC&kt72N^3eyh$o+GRaq)KwXB8+s~Ti3AY0 z85tze65N~lVCk7+WGK>IDwrf5kT&2wE+CsiezKIls?4C>tCwm3b5T<*EV7D_47Tdk z-MAD%pipDw85^R3%_NO{3d~m08-EkfGw?R4j%Ehxm+5v)2v!7`jQLfy!uWHFht-bd zZtZequR!Gcmq9&=EmWDheQB z2C29z?*%SMpGqNd*%)*|n#A#0`TIz^AWgi`2MK>Gm89z70F`362{r=wM191(by2z} zJ)pW~;K9XB4AzhbivE5hJ)8HV73q(N;La}@%bdmiqmY)8WW|vWc&w-@SyEF)eUjAq zqmmC&OgB6)#2{-W^{u>u5tR!1f++J4#XjQ$5J7JD@Jw>MY9!8pk2=o0e)npqwp1~H zol`)0S}m05fUnK8#L-)GG{@)30m3t$pto*q^w#4`!~^*z-X-h}vhlkSEwaZ666JNeoMKvDtXD7A14w zgwt7DT!^h`HY1=Fmy=zo;(|3&Q35r|l~S%NT$*`&2DgUvLNrC;Cd8D{b=?ai&&>Fd zCVF<|jI{I@o_ru1{d5lwNcY~(0?T5e#iGtLpIYNSpt(L#16IxD!71jDVkPN&F&;Rk zampyzkdN@acZQM~WOaLoN+%+1m%CeKnYOwKxTNf=GP2juu&87#eb2s#$_RI4t`MWM zQT2{eXJc?gH>sl0X`xJ@ykX|Krb|qP6grGhCeA!5wGx_0AM$+|rG@v-2o7;MCnaXU znNB9L$vS3%(*vrcNbuDVj^S7~ckWfAnpg-z&H=oD8=%VdPFuJ`X)ETjlVM%!i6><0 zJTzjX5pr)Jaw6$liRZq(8$QDfk|N#wjINeSKWIkFyh3=3HIJhRTe8UQU`UPsP+m62 z${}(u9xWlWK0*$Ku(?**#%EvCTwA5)T6qjv~@hYLi=cszBucFAwQ!cj!()~$_Hoo-r@94aHI{Cufq~(_4_eZT40VdNC zx3)(ynO^fdoo=eCTmrYhnc7^EXdNJr;U?`BzV zg+oCwDfBq^kgTa39~Xznvmkv15Ft9Fx-?D(QNI(oL>e`DIem3 zt&C}1LQoQ!K)Ac7HosTPbs+W&Fddjvvg3yg0Ul}i*fKLWm}MKcL0eWCdDc5pt#1$+ z4j76)2x&W1afHV@U?QPmVsWbbp&`;7x(`vr5NSO*M-e@#r3B~#pl;H~$rH9f&sXee za+nMY95g?P-7V+oCcp#5lE?sGMuPW7f*|L)g(L%NA5Rul3Of$S_2EosTJ6KeM`M$0YLvvD z`xW_5$oXwuHe8ruei#_LPm}CENmnmWh!rA97H`->?bL6*t z##g1#KXduzcXo|?@wKV;2bFxM2?U_^mofmYH}Wr~4BHCn-g#-O!pxQyalhV6v5<+A zJ*CTw#I;}S#58*MvM}=%393qrw6=(5xJymE(DOvRU>Q+6N|;O@p;UW;%f0+oVlh+( zecyUT=w_$#6%Ff>^Iqc>Zf54Yt|h?*S-WC}3l-+bvvalBorELM{w1q4e_!oC@C|6ZBK0#s{3q%jHeYk`vq>huKcCiR!H zo18^9IBDR)XAw5|c!O5ADqB7|6|T~65HVn@uHn4I;11$r(3f&nhn0O87xVQwQizd4 zo9mX#DI^?U9Wu(!v;-!0hb8gUB%n9@WY;9Bl|M|f){+4J?8jPVTiVQ{2@Yj~YF#7z z3X}A`=zW-Z;EtdH9l2uhMpbIeRz{s5A`#E*|?~w<&RL`v)-_T z8L4-}6O1@B8!uS0qH4YXi?Cz}RWvy`rNJ7>E0rP(He_fTL-4ex&<}6^|j1qLpeNB@oCt$e~B9FqHqfq3mmh5~`X% zU@XBAh{mdj{$r()M+3QEYpUKS zEBv@2MjOZ?9Y3u*QER|eCogQs<%wd#Oat!$71@U|1r`^&Mw8ukhVh}yx8!QP0tgmb zI*s=rDr~s4=V}lL4Op+aAl#Y*p-n{F4DDoLwo~U&61co9&tOylS)Uz1jESujmo>BV zJw`5XWY;)qTUEJ(6F*A zI?fs;>l5LvMB8v`_K9Ym9EEHK-}^-C6L6kr&F#sf0J&GYR4`TPUN7~+hE=L5;()+7 zA!5Y2GoKinz2U}ag(*_w`S2qon!DXWD`9)}?6lj&?;260^5CZNMYf92R*w^^o4!{4 zrbXFP)qn!>3|9|(oh^f@i{%4h#kh_zQpy=iX2x3bIb0?wfz*-wb`w#8l-lkUinXu= z298crK?f0uxws@Ku@Ww>Dm9TB+#)i2h;Kyx1I6kx7@!~ZSWpY#I7#)L^-5(48b&t+JrP*=tr~4dO#U%6C%+))oQD7whQ$%8mY3U zJSJpGrsN2vHk^KCd&OCGjLat@$2Pd#8~j|hd+T9*hT0T1&QL25BRlDuZW1*uc1%CQ zQPuEphr^hNgTfl{XAr~@Wrl11>Qj~EIhq_xbQ9$eo8e@bOSW}j1#2o^W z#!|NS!91L54_ZB;_L%tY+b={DqR7&g+9N2r(J{OCqSnTx59SK>lLgTR>WFb|}=z3Y03*wj?B4H7t~|ympt{M5k83 z`>!Fw8onyVQ$X;OLeI|kA;`Upe9fC1tW0gV8HQbu2lr&7rUuwetNprQpI_Q&T$&3F za5ppeKI8JB-BKog5=XbDVBIxu;#Py-NDt?X9myP)kQ&Mn_cAA;J;ppxGZ{Bc*P zLD6(V2ijGSHlJm7jVNDU?xLqZR2?}pqpM>xh%H_F zz2>|(MG-X9P%OM=sQv*r1_O?*?GyV*S%H#to6&6LsWlMfYm(`uI!*p2uOB3jeT(zy z1BJAoD)lks3$8Ph&!zWm$RrhKicn+sX z8A6+0wA^8=LE}13ZVkTH2{hiHoW_;Vn5%D1+a0zh+FQ_B?wo0Kli*DOE<0clg3x7Q zq7rL`Sa{#kZ9>8TdH)-d2558sn4>wO_3IAM%fCDfUD|&!v`+pV-MAy3Dq<@6t_r<3eZ$fRKiCN?nTP!)kC^CgwTnyN>rG)Uco z+Agh0H;$vG2+`C-)TbK0KMOk&NeRRF1kpffHjlMRBNCFC@MUJGPz)=Lp(ru7k=@^b zVp2H_z&XzC5cZc^VL7R7yYJeI(f%aB1nh9Atb@en=^b+2MuZ}f&4G+Qimd>8&ln#& zg7(sLtWVAIxly>^hwYI=j8}e^Es2q^_*`&aG-!w6?&o%A=T6M%h!!z`O29|vUahF*3mf}C%J&Yix=Bx5KRo#Ki!e}iSn zQac8AU=t}SN~i4@dK`%&(1N`8QIg;$#+)(&nXs5>5k$tLi&a zZiSYfTEvr!)>ZZybQ?6%>51tX6Nqme0u!sznWSBrLiH z`XE#{#u>1j51f{ikTJzmt~%1-8hsKPhmt*zPv8YAMoVJkY7ceJvQnEW5Xj=#q>wM? znGZE%$CF++pKHL-y9hnQYeO$~xGeRH$@L#>FMy!MGO`BMk)T(CM(ogz!yvh8k!{IN zh%{}#Y*xrXBOACMVcpA9-ru;@PZb?%*a(IlmmB2;)vZ^EM;(PHsmsU^rHm^DbbZi5 znB-s?oi-7AAbC$DsKF^_+kOBcQ=KOwaihKkGH zwsOb};UZ5>LjwS*h86JdPOwYTkYn^E8X}{#7`B%rco1mexm*z_UeMAe=#g@6jd`r> z*|h6W1htrUBfpDCD9w~PRCqXB8w=h3Gl6cAIm@ISjsKH-if;sy+;nKl6_biDCgz(!|K~StPD9d!C}Q5 zCi*Y~rqKd}XvaAXAJq#h$y+g`0Mxt4`+kOh zm&d-3<)2s{BlPsyN95wC4_-!6r?bg_8In3)@kJYV-NgIl;3&wi0+`Tib%fobrxVaJl|E~ZA$UuSdI+a2*op0!fq-H z^CBU6YDQXvjM51+44Oo9c9X+^aFRKdRqpT9vD3V$e6 z$4|Hpc2D|4nc_Vv0G04B!vv40pm=^ONhUIrfmeoxl*byRM4H2^D@mkTt^cyZsaBql zb2}s7pwXnfk}N1Q3ql|X3eIDLX(fA3l64 z<4GE}?G&Y-QY($f0L-uX@@zPj^~?)zkQ>a=8SY_+ANrch?NvY5_NKDbu$`^-?z zL!(NYxp5~|85ST=hZ0V;A4t4Pxuh5bYJ{P;N4a(Ll!ZYzap--v!up&%+@h)Nmh%p2;F?@%r*v zC?XW&+Po>{4^bM4`oxD)SgK(X&t4^}!WeIwLr<%MBE~xd##AB|RXZJBja^QzM*PY3 z>?7(f=l!x6`1!H-uMzK|x-;+p*9*4ryc>2wnf}E{rKwR|CGz&xh`ha3UaZuC=0e?7 zTi zO4x+=h|0zJMAwJs>i7H^YVETB8&mpu;Xgd3lgp6@g)S@@M-^~WIM#F|qy_IS9SPax zwHMzMNO*==1x3tNA_HDFw!RYnEVPOlgVrz^c3jtpk(c%~X_eehR$+9D@Rp!NHrq*- z;oN0B$Q27DQRd|I5{;8WAv$2-$rQ>a z(zkF0VXJO;X_QxTQ&H+fROGsRr?VmFIk|aWnP3#K8SaEz&&9-etx%O1dzoymv6rz8 zSL|h37+e@P9+s~~g7MH6$;^xJ3W2a_X4qz^*Ky~beE9IGl%EITQ5Js>-hbIWxb9Nd zBCQI#QMD<0~k(g%or z)J2@*LcEAm2PBrO@S1>cl_E{F7&J%2k`+$V$hH#|={sI>!mrHjS0X~3SM$X=N=&qO zCTJ4i@EdmUm_rnEEshe~pFB`lH{!wsB@pT1^bk`3<_X%M#H)hXLJZakjSO!exh`$a z_!;!t1zmxp7rRv05G$$&M9E2}Cv!!z0dK@MIodIc!#)ajh{Hbel8VU|X7|g>)0tuz z-F<@+9i+RPAMuzP25<{r#%Q zn-b{gSB6y`#=XVXbj;A)3vHtTg!_cHV9M5Byi+Qrgo_jxDiW(iE)INscdU*B6t_IQ z9hZmqTFc`I8B^f^eZ2)j`XzdWcss5T@3mIQ7wwn0HL^j*BKZWJw&bGdI2$6biELq1 z^401KQA$VX9CA^jaR-{*+d;U`Fv!t1*hkV^A*hk_v`oAePE>CN-1ngcJTGW6^7Lm* z15o5&-$>k&FzFsST?o!pSbp0|-O^LzuNj&9aR`ApX^5IusAoI>Qp}g1Am4y1g=4f? zVtN|xq$jaJ`V1m!prvnyIfUkx5$6aXe&L;HAOoWFlD|o$5X7&;=)%kT0#VnMY#ZMa zw0E<9*i-z+vwW>C0C&9O2mbbjc(i=J?~gn!MpxAWlXetCvgn~k7?-5@(>yzlX?HXfAr~i_1_m!q!K|;~#rcH5 zMph}>tITHvSBud~>fw?D0w9@r9NR~tgu|h|NiZs@uI&2?xFlp6`;h0Xz;MiOL!V3{ zeS1*>x;2HdjIumIAVai`8<-$E)V`wPm7#uVoL*NLQt@^d%8h8T z4dJ9zrqPfK3e_!@L&$MO_H3K{-B~^WzbU|=n=u}W{6!-vo1h&*138R+-`zj-xlF`en3R;sQ7)6 z=Zzll2J(K^HuJ5<6KNbcN=S;B6KB_y&p4c>3Hk$wh^^Hv=2)}A>3VSAxOt;N?z1)@ ztU86G0<|4`Ak+SbgHpaZv-&#m+=jU-~t(EdH0~rSm9M0 z#3gt@UjSX88tNaQS#$5SGFAce%pYt*_rH$u`7ClCLYw|YlI`o9m ztFlGfDQa82KBjjxdT}FKhx!i!buD6%uBQPIgd`y8-t;5LF&x$bB;2M~wi!6&5On$g))$LdE!*LPa%lmh#3l^Zh~^ z(e?NV(a5og-h;@;E>%jCPj`9(suQddL7C-3J`dIRxT|fI%JVW4?o3;y9MjB}MZS!T zFIuLuESbIhO@7jHU^)aIgo#;YDd-h$n^rCPv-X~&PTH$b1+@g)7n#OUq;R6<$Y5$9 zXyway{{n-h75OhZauo6sS~2aFUp)W5@V_toqzgazzVQDw7Csij_{twRWw24<7zx4# zH{;x;8L)r?i9U)+@QCCzc|>9NJtAeI@HDht}5W38YRhPZV7;82Zd$TTk2tJ?IF|V%4h$6Xnb*qeNwp5Dyp?ddsR_-*ovv8ccmOYHnElx zq8-lQ!A}SOLi2$+5LXrMG2F|+&a;9&VH1LUdG-15+_Bg0s+WJsg@m#K{t|V7_ z)wSW(CJUcNjN6QqHT7s8P6eA(H7`u|NA#WJaNyZH6>ui^{o3wJK|7f~6^211=k&6$ zjk^L&X(&O7#xd7~`?8&!7^P5weS7cMYt$MHM@AI+DhmW+2Na&S7lV2I{>iw(F3T;)=-Z;@$ zCGR1=EFY1*F0I;_cb~t={AGw4eU_0F`!Al;c@5)7Z5v1`bjl>np(WR** zmO(9Oiz;Engkrw(gaDtFYvmGJ9V3IOr+#dBWGrY*-%SX)E9^tGgDQAfMHp+;o}cI@ zGE_sBhwwBOF~kVSEFN4d&WzfFKF0^E&R62u6Mq&u;t)5*8-*v<3A~ozCk>31Lm+vL z@rs5mOGo%80L~EPl|$r4ZOT_dgc^^|ZM-7cfz_83Zd(el^y!Kvb7JNxj!YL6j&?zJ zq6cbmt{Ri1k_+@n(j*-`@Ixsu>pSU6$vV6=9av;Xs?fENh={nNq}1)%&`ro#+XgE8 zE+z^7&~|fu0)gJ?reFccLr)?j8wG1@_|Vy2KTm#i=M!#;dvJ!I9YUS|Mt1)8RXV?+ z_-GZ=e&U{`?IlubhAwhSU`FuXO&8^K)5$p9bP`TC0lw*)q??v|sJaVC{X?Jwq?{n4Pk-x~Gi%eU>;WYU{!U*2`5AM!k<%_boMZX|Nj~tuv#ozb6k~|=0h7pD$W1@ll65?~|OR2 zz4^M=#n1QuHo%i&zTEqL&lA(*m%Z|2*z4f`uLr%yVA5&L7OPQfIhaoNKJVSlr{ldJ z|GPE0$G^?@JJWgZ#}6`>v(~aU!BZ2p=9j&@U-r)OSN~Hx&wG{sLHW!7@$*-CJCAW| z*_#hqqx}VW6HnK<%<(_=T8q6wioNoKR_qT(qO_UF&ewb;W9K^_PbX%wtTX5KYPq!2 zAMo_=-t7-M(+T}YEQ_e4{7Myz85xnq&paLZv+NHR@03J)f8SHSebCeK_i-BjNj@Lk?fvv`{MUD#(R9(v%Zg77pqREw^;mWR$|^;uI3Z`ytnN3 z?pmu6+!&tB%KSr;dXffuWIkz?T|5q!oxV|FlJwnjdOCf?)2+4W{q(b0;ST;4S9jbR zjeh(UdSd*lHnO)Gyj9Pgw{KZKAAo$uz3yN&28$T)R0PjRFN62BJD*+W0vQauk9ltY z+o}~w{`T$v`@1!upZ|BFA*I_x4=#-78rJCZ9{(kr2MG$9++R$}lflxO-~VP+*_7Ew4hU0NU2qW51u>0Y^hP~WMf{Gr2<-mrjb~Vxz}fxq zpa1su?LQ}ED7{dK`Kj}>Ey%D$fCTgIpOd$5|LdQVe@_0hJ6N*?^Y?#RmH6imd;gf+ z(^c^se$3Yu`L(rN&gn5jepip3fBx`aq}2Z;S&<`P?;qq}l8XF~Uv-uBmOm%!5I@cw z%${&w|G6(RV%aWcEs`a9p|l*2)Y8ZJ1i^xRR1r9vCGH-YFUg7J$z&1MS6D!yrM*>u zbmvEo>VN*gQvC-WuREnaeEqfBqcF)&9V}Ho{EQQYD_A^YJ=(&8z}pd#1k{%4GJ<%c z+gi5XE_;jRpc_-S|6(u5F(LoZ@uW#&x}3{u_{)Fp^m$8&SB+>Cl;!Tx|ZD4Z-> zpk@goBx;gi{~al}+nPVTUG{t9-rhSh7@-JC2d_0C7c%4b9@!n=Ssj4Kw>SE|jg#Ha zr>jZ#*MC1aI5;{u{%nL+c-@A9cgWgem`ge{KjEgn)3$%AdDY;zd;Q0NE zOZmM$opI45ak7%fCzVNQ*@1_s&ySvo~$R#BPkkyZ7 z`ro8mTYJ;VXtTHI%zM4bUTf0b`)S;Idiyx&F8jak9UtM2{`vProxmoWG2Wk(lydMs zm9!MvG%?vH(@F31>umM1HtAIA|N9VrTtD)W{57?g+S67->O*__^mfs2b*GQ`DOne3 z{Cw}K`Y@X=2IP+WYpab7L?@}8a+u4}PI-;ikzx<& zXyEJZZ&V%Co8T*KXV7D6sfPhRGFvU_ zWtnOc@Gn2`r$7A0)LPNGm+#E1%XfOdDbk}O@Z;c0&f&J@ZIiEhL<+!pN$$Dy? zgBJr)!gNWe@Xwcn*=$65`3HJzkP&C5r96FOEV?7U?+)Gtt3eqz*R9qgouO5TYI*vD zZkG)dfBpm65=eohGOF>A>N72q;=6NP8dYUls!B4m&U(uh(GYz}jcsQ-Z{cRr1)?jt z>6z6p%9!$ZNOg2vNH!JyP(ykACpQ$cwfB)aH zP_UYJdS|WK43Ad*^7QXSrSL2Mif`&v^|U`+OeY`OtwrzX;FsR!By)RnvTZeTtMYKV zJ@rn;t;W*`e;zdP|D8#7*&G*E?eX>IbbP*U-=H=Ayy|*~pE{fJqC7cYcW+LHx7R1@ zcD6dW7?cM%k8L}9y=i8yx8>oiT^<~)PB*~c%=x-AuCF`Uli_LRY1SO%`t9QNrt76~ z*@vs!oANrQ4k=oPFPHzcTTCy?qtv22KJ2#}tUWii$3eSMcrme;GF9oKOlJzRdHPRk%^s-hhv4Ji+&DYPEy z3tTR$@iwbzsvE7X$E03osj{dyOJ6+4?LS-KF+i6aQpdu_(*XZQ>X4%Cq2=KEp5SLE z{F$CdFv7n*u>QST-s1LtV(ks{5_Kf)C~0-vF7X(j^M1JwL|(l9P#$!=FVZ+&X66~~ z<#oh;S?`E8vAK}Od1R4yk;3n#?nT)rw9I0c%%usg1O9$K#dYWT(7MpExYB=%s^2O8 z?ew&Of4e?Y`(zcSFW@|`AJq15WcyirBF0o52Ri4-m?mlus}pTc!+XNz6)qFBht+}4 zPrioa7-Vm8{m9x~Xmf&%PkB+pzt!0MEnQ?tz0NO0dwO-e_HIU=XbYL2?T0h*4zHhl zcI)xJW#fB%OV)1cfS3FDNY>L?5cUP>^GEzYS!X`3GjAJP=StrXcA67SrGfeZHnzDE!-YH4z#R`G_GU1D)Q#*NgG4HXR_b)F;wQHT8B-} zkE;W2FREXWIZDP)D{q&5A(g0)*t$K(zn!al(K+8^Yo4t8Wxcwf^PtgXYdg~ydjeax z#=do(qI)ji`^+;$uBk4bhhp#V)cfc>b$NYSx+dwe9cRAY9IJjelEKAA;la;5Mj@gGHCl{cGWX0)B^-HOKkQ z@VliZ`yaLHWv$=wxkTpuDLHrO*>$zpkaYO@oTg9dvPCtMTXl=%oGu?VHsy6?Fzd7j z`A_8l4cl3C*cp!|ty1;=Dswn02cw7E#$l>;b9q?y%a3Qn6One&YMhVSlXIM=uxNXz z)@pR8-O|~8eSE#evQg%?aY@sjrk_?f#lsnq53tN|-`gO+ok>69%PD@py1-?uTI1_s z*Lx&op0vlK)TxIWt;TisvT-IkDE6qwcAD$mzPG@h1}H@-VW zE3|%j+(xu%-Q40j)N$Wx^W+H6lYY0r#=AN$Z1B7ue+;hEtvc(2D(`P~oIVa%-{ZFD zarvLfSXG?!?cu&tx*oKPqhYxi&J$d&UB*=w(f;eCX}xDs zHJ&F3ujBqzu`sx8JSyq&-(qCi`;WE!g#FIe6YHmRr#<4Ii=%PbyYII}oi>Mf%{+}N zHQv`At=GC!x}4!L-JVYH9S8R>&6my9r1@@JH?xR*&u6_c%NNhtFwNaHoqIXFhG?5l zH&e1-&G5V!b;y0hV|x-#Gr7H~-s61?&%gT_o}1fl>15U(ckX*>wNCw1t2o-8j%B}f zOQXlzT0Zyj3hx!!^K>(FKI&x8CPrO1w>OvR&iH_&8Fh=7quX&I-7Y!WUpg6eOV=B` z$HC=Yu`wj=V`aSmR2iUr3(q?|SMWT2ysr#$G|g@18t;Fkf3AJDejM#9ooDghK5Th; zd}r&=aG#s~i_ePOSv%V$>#dLH#I%CvZTLR^+sqWUxGyFhyic}^kCTfL@NCmLlKrB# zHIK*OdUo0{_m$K#%nv9F-zgtjH`mLP?M#{1w0`#|nUq!sZ5%RqZPn7|eRg?@_l?`) zDBZ4g)bYb-AKn`pPbp`9o9E9vI;QpWMf2u-Tk#%_$bO60;p%oH=TK*So$BJTEf*2E z*Pr5Zxl^n!PivRQ_V|%!*SV&@X5-ZxG(GQl|slM%g#C z4ui+RM=w~OUi16{EaQ|$8!Bhv_1fG#M9FAmobY-1h~+UN&*3w%a5BPs{iZv%`*b$@rL%Z|3u4RdoOC!|3@iO_Nz@|AJ=SOA!!aoncGgWu)_76G5MjNYB!$DdMX>^$+J{vvIPx z#m~gNuHbcz%br)RNEw$iyuZ$H+olyIO(RoCbxY+Ho~yHFExo{bjM@b{E^_UR&lhbx z=2eoW{?u=duNU~aXvahI=CY6XC43%U&Tjq0?Rg{W@UckK(|Lf;Uow8AeB3{|Eol!s z*XsDU^5(pR4#=GP=;h>m8nQmczwth%fitVofYXj|C5{lX*})r zMvKJcPjUQDse^3h(Bywg9c44$`Jetw{7;;U==aZG-e{Cw-xjYIctih#3`Sx3sm|u4 zi_5~oS$c%)a@0r@!%iAs?6FWZ?rur_i6N(YMGPcebeZaWYYL}xd?;PD$Aw`lb<(Gb zgYoSQ3);_7_~0_I&`J-j>3tPn>N=V8P3r~;1&5ChNj$DyEFd$bhjQV*za8f`_=103 zt0AV$@Q}yHfC|J^_?5~JE_B{v0kVF7i3OS}9j8nF&dEn{D3^=Z2c(a0aeo*}FJ7PU z(kJ@=p4Fci=;~N_rI!WecfDQZ0=~fFys^MKDi_&hty~nBHAIE~(*dgDdA7v!2A6j@ zx>YXg;sR9>{}1xZGBE^>b77gMHI&8mU6IQM7Y06+z0^G}Ytzo2sOh%d#`%y4Y9bvM z$Z0*4i|(;1#D{qXh|Xo4&JdPF-B2F4VcX1}%vk*o?(6ts)Y+hHt9Xqs9M>Bn+~3v^ zUq?u+BXU8-<9&krNC;TxtRDtw)y`guHmsRaDolfgsHf4#?exAm&Jp3c-ySZ7V!$rTO4U!gD}7pm^Ku;@1Gc&lY9pe4qkt=%}cwb86x}@40G$8$r`)YQZ zp>vD;M(eE!s~)14kXGX)O_X|cz40=cFnMT3|!^W7MPxs<{Qu^V(QaUFWv&AXC zVBs@h)@|VP3D4EexI3zZ<>t5o9oOaR{SJLc&V}m*zx2lTVY7yY-JA0iIaB!M@t(Ai z^({L~$i9i&Mdo6v*%;Yltd)6YuB{wSGq|})eZRnbN%@}$eOMUW;Q|mT|7TJMhZ&3i z6~FOa{{K_*zcLsa@n_qK<#jhY*WdSQt2QYod~NPNU2j0bpZ zTa&%sn)KIWzelJS~4KI!}6!Vhkk_qgHjj zUcc^L%p#EStMz*Hjeq<@AHoZk<8Qz1QRwqs3)hb1KF0H9kHGflW9F#) zH?@DJxKTd=6ukTUd$W0OJ(#W*vJR78ue;b=PWRe9wflQ_qzIA|sWIsu;tGwEjav`B zy~S!yD%@J`Eqco(NkMAAoX+;T)81n8Bc6~gJUH}M-hTY*a5bLowc69w(k84G^?CO{ zq|9Dd!LWk#o~^s3KK60B7;pUa^Si~WO=d#7_tQ^5@BRJ11Z`+ zgk^;ewGeM^Z?x#a^rTQZPJU8&_FneJ({*oQPd2)9kY8u`7}h6;lh;&ROz$SWCu0r4 zHHOHCjj{P(|7-8xfZv&KaW}!}zFSS?Sb@DvH#feV@LbSyT;q-zbXud20`a}~Bc7>0 z>Y!$-N)jtrfAsF%JL~t)AB?gomYce(8wm@BrVvn@$8FF1*gdY4|hTC3u7^ z;%C{>xVqhGXEi2lviH4ZFzS(y3$&r_JI4ppPp%>O`5&p@KG=Qyj=GhTVkPM~`DU+3 zlh~IZvtOCkmzNqx>KjkltBO_@XRmDAY(8BBjgxPGsrHeA2i;z`OxEpuI$i$w)d@M2 zzK)^eklg|Eae#glb_;(294KDRE9C2WVoc8Q_uE-BQ(v_vXR4CA*3RToEJ!^H#cl&Pe!NN^G$P;TeKR065U42QAIUTWSQ3x+-YyPQC2#dLZSUWliL?lFy_%5GY-=omEqv!Lo*N*WgYd1b26L zcV9pV?(QBexVr@p?(XjHt}D1L92SSOf5NWXRdYAh-^F(^Gu{36`y68ybW_hAo(l$f zatbh_EOOn|w^|e9qA*8MCsq$&^lCF6n+2`YhACXKI3O(cxjB3(V!Pug%fWTbU4fkH zke!`ap_Xop=HS#&`Q5 z9%wqeF|i!^yPmtttr65t9e$oSS)hFUO?2_j?^lgoHu!kcl$69z7!-}5dbju*5-a~$ zU<*PP-%qlb3Oarl$9zW(IxIcnl5F!;Hoc2&5tdiIFRy2+`>w8Uv8a9~ zpt&NDHwgGsWps(yKXK%yDqw0{gJu`E>lb`xU^D^JBm4WzhMs%fX-q0!l-uHqj{X=p z&zoVSFQE0tpX0E0-J#drJu}PZEvoK`abr=*(4}OX4eFB1aB!`hS>AjtWw`AbEt*)W zxPyqZ^CWdU^AljA-nJ?iIeq?h7P)eDQOHBY+?*yUVDxwIZZGj1Xy%MN>*d^JpcWUy zc>m?52EI4LzvqPP5JEJJX@@n+ngc1Dr;Q9!taghEM$1 zylpXOn+wfABt+MOGUj2>b3I$Y@qmzVg{3INt(-Ik`E%|yr{+`aVHi#Z?G3EsK9Y#JwWe%EH=n zYDy(fLI|l`$=h?r+Zv|2XHi-A+&T2pvR+)}-w(TVr^GorNxV#az#yMy1g!A9x8^YJ zv=IFy``SxskmjW4iB2HpJkJcjfPvGIBNc2x?)rRkEJ*OG>LH-#;V|9!uCy$2mLxDet!0b4=QKT&n>CI#oX1# zlZzmio>#Xz>S^vqz*ek6gN+m_@ej}W!#OOX#NvS~$erH} zz204vDXG_v-?GpF=6Lr_p1mogO{yK`Hfz9_Xlpy?RrQ6ug@4wf0L#et-5`R-OYxWB z{R|Ou=gq$4eu&?dz}3sTP@;hSi=jNsk7w_OobxUm41(5MmJv4>SgsYEAk;kwxMl#$ zMoOPZm>c=*e%S`BR!hlx5yOMYq}^(p>i|syB=}1!p#B+i4v062qr1X!AV|mGrCLt( z4A>OQBCZHY(Iq-3Zt2LWKfC9o-(hH@=rEn%GhZ~QVK$y-)E@$& zEz_7gG~mMVPtn1Cn9KI)uz2Gm9G*-zC{z1%r`ne=2$EiD%~x?ZE5QT{NwpZ0724D9 zF^2hDu%FSn{wv9J9gr+2-Gu4ReOqz^GFYerf!fo(;d$3RGP7{33PR1s^T3Y9G{nCd%!gqeJ5`7GS z{X~a>So;A?pCzfjr+_CP%z&tmXYHAfY^Fl(46<){!ug}9vpd%(7~a4o{Sa{ycpD29*Pqh}AZY(K!XW7}gfvJq z_M0A_Bb!em!aHEGx3bO-GgTs^qU$E&n2&CtiOaBBdqQ_ymG=?a!-`Bl1=POJpp7qf zvoTXM5%{jiW<-{9qnFi|E~yPs9!jQqGoV^jZ^}aUa7(X(tTp>xD^{VblRM#dn^j{N z7H(3kum=6@=5K=|9&N-x#UnVp?B`i_H!|+4>#4>WhMmp|aKThYerSz8T6Rt{!Kr-w zNVODwBCUy%>OqUmyFp<)TvP1V-W$AbOZ@NhBmylQE2fIni%B?_@1wt5i~~N-SN1wr znB@WQe)C#nGCGXK&Cis>Zuiu=I^l_zo(&wiTcauAVP#OF_w7gCwg(p=Bu6xu*mz- zQ$MKCld~z1N33@muA^_sb60;m2sUhVgmI|*0AH;dc|L2iFqOj0J9h8#I_m5bG3%oZulsQaj!*Q(2K8lk*fz@ z)kFv3ne#ylw%sp|xVJj~7>pQ}ZsQXzB0y<reQ?%Dw_oAC5@qbF`dF3($XD{^DM5k}%H) z9}q<^2ZiW{fU2addXdLSxWQ?j!?>JamdhLLej&h}^5Hk=U3KE{; zF-u0CbWDc7TQq{6tbK(XU+r_HZJ?}01pIDTb6J#@evQ6Km6k&$@@m3+k{08g^v+#K z()acqTCYnLN`06u#u9oD$oLDj{0S3!em3ow@mKi9^j;7*8BwIpFe%D~pst-rc|ql! zn0F(lXEd_##5F|#V)Ov$%dqMH^|c1o4y}45r382`GK@ z3cf4Q3`ygB|NS#?XZh+sp+5f~3jR;1Xd}{1{jgD{!3|M6*-rk{fkFHNq0lfYZ_GYo zb%Yl5VQQgo%xA`=j0-)X%bXy>L%+=X_DDO;Zb~Ig2qHhS7?;Z)Xz*n5TkgtpMr*LA zMZA1dFbuFB+P&8?r;21Gr$>y$dCQ)yO-$rXAXHULoT|DY8=X;hN)dbmCJhB695>_z zX5G7%6zvp#!SAiRU5FfFq18tLmzAF{ezV-JKSLG>%NSF+7Qo3(?q$G{jU?fROS+p| zL8Wwo+(pUkMN#5bB=9Op9+O?r~X<{)kB(Or!Q(-A^Y?m_zfypJvR|@$P4Z`N;IBTBGehc6q?`bwz8)kq6rr&+zUl|30ho^C zSBXIu0y1?xGG^w&@Ud3{twT$*6P?GjtsYOZ9#?C`zw-5a%wtl4OvSE4#DB1Fj45ds z>Iis72Q%u7_Pwr)@CbJYXROb)?Wt~iUr+RZ3p}N~BcLg7-?XGxW8XzxmIB(*6PdOu zTyGF5_1k-hHrQ`?ub3`Gi2QkqR-~Zj7}-D#1@joMR5#jhUCDkheKIqo@Mto6uW~P5 zIDpZQB&03$Fzc#vc9(wTw2F~u347|_*=Kj<2=JZSZ*I7Syo1271|5}IxG0D|OpAg7 zZ4FbpK_?yev4*#GT2YTeXcZNFByrFk%WDd;?(Wr2LA^Ry&sZw9qu4U*v&g24dNbHf zmKgN~%@ty3h`9pRDFNnCI=&12UT^29WjFPIws3!2s;Cz*kOHH!K~dem;tIxEDCQe! z9OWp=f5#O#{ZM?k9F#-CA1SYd>*Z6bnobY^4Br4CVGCM3HN&u-)qDW4gk-mN1U`)c zMg!bp_=PYoA(#^_crTpZ;IeS}j_)`RGQ;3_6>F%gZXzwk{H;Pvn>WB{1m_+gFl7=zfd!RJ0zb$%e`F_wCTdI5y-*Z4G)E znS#!V{s^UpN&~90?`0M7=|6rsNzqlP!BlHyGdw?ZHLtRIL0tHioIPL9Q6Z?ibt~SZ z?`FSQtnM_O=lW6CNOF?HTP1`VReeyLj}efvh)X-L31tWLHC(d>%P;0mTAht4q>|A^ z0wrf;T`X;GxbMkD`D)--VwPC+oAdLM^@8W?hFHz?d~E@yNDwyRek0gc_xuWdLu%e8 zzcbCX6a|MDbZ-_d817M(!xzFW{8VF0V`#5Am;^LYeSoD0kxEVO0}E+Q?FVY)erv&M zo^>EIZf*uc-Fo}RGNlcgWFm$mjViTh3*DDe$KQksREu%~z_OgJzxobU)wD6`HyLUI zO*-CLIcfcsyJAMvK^n^GXow4dIu6SzT=@_bY)Sckf|#>yl9O38u}&LETvequWx|MFzy5D@&WFeFLa6NW`~qzy<^&zOi*Hm}YlwkYO`$5W0~WRjlEQph?{l+P1WNMO8mW}2rlAxb}`|7J9d9-}#; zx*&3LNMF2?`R{1(URF+fNUhzho?$MbJzh(^6{xUA(QF0Fe^Amfyod^oc8f@~xe> ztI?A4=J3fp_?fne#jnWyd=0<6yg#||r<#7H5v@7@n?K26+S-7oVNFzf@=vo|D2JZh zit=$4w7AXc9QchtUM2Et%?oMTNBE2mc}DS3>1iEDl%sA73{N)GiWISSA82NSeD!Z% zm=C?tYe{hy*z+4IlyB3Te1&(Ij*GqNFA`7!cFF7MqOvfWXYGVl?%m%W`p_smmwF}Fx`0C(|X7rR1g zb9{@-GU(*&qQF6$TdS;8Cv>gB!!5=wK+>jX(%uH* z6`y_eFWoKud~~A4deYURlz=+vakKq_UdlT!2YZ~wSiV2}XaWT`2}%kIEexpRwP4TH z9M%D11kgu2Sxu-3YVl2LP_IxgXEzg|{OS8I3lgDT8`1Vz+U$UUhrj;R8~nAv3PEqQ z_U!H5O=9DA&(z;HeW%OOUt`7ll}TuZQ`c^BM`epX20eh4d1xgG!8Z>5gi+2L_0P@H z0bcsUuqEnLgvJL2F^to3S&XHoj{4q)?13JKw0_YBmx*?iEFYgm`_lYN?jum15oHt2 zI_a^DT!S?iy>pF6?+eTL=XR@;fDp$j##LQ zpaTvVNQ(37KYv=}U0?e!EBy%Lj{Ps-BWIld9TB z5JQQeLYF6X4I~eMp@|w~cT#%sllJh^SfMhzMn9)j^yIo-dal->_5;}fT6bMS8NKNQ zsmjJ4e?>uVB6)|{L5tr@qiEk813qCJG8y|P0HdhY|uVSO>UTXn==s@g{zur zUJUNE_$U8WODO@7Xi^Q4O|!Y>5$4v)52+LS1w>QLZh)*yMb2gDe9mQ-QGcv9(5#!w z*ji;Z?(&84!EeSuCq3+(UX^g7YRL+AV$ABV$qcqp;B?5;FlPbN3<*>CjPiIlmO7g9 z#*Eg;P#0t|>aa%5>~br*&o>3uX!k$CY&o2k0Wc57ktY>n+&Mpc(b8BMU;8tgk9{li z=r&L)lV(_?&*(v4bu+Jdilbr4tb%BN7dKwe>zJlm^3x%DDHDea2~u8AFC5+J`@-ju zvyd52F^craCv)9@&U3JQ%$Sfx`nO*T7GeK0UH!P`*Z}xYP`RJ}Rh95sH2&D}=<&1~ z6^;`S;^*P|ht;CBiq;r6V^}NSDjY5Dvw`%aEWQ|J>rF9cSv-pV*uVYwrNkd~n%Cdl zgvkk|2O@x6Jk>t8#&kF2>7+{X*|*i`iD=7?tLJayvjG&p6`(_(uV)l6<+Cx?-GH7g zOx`h7CJFqudxt&FGE6RCON)b_C%5oKf3iBj4r-x(SUa(AX1FgmNzJa<5tTXuixUgs zX$UggW~-SrT@qC~Z1K}j&S*d6`bLeT_=PvSZEW)#y7cbob5RR7G$1`f&Ip5i7qutR zsl6Lx8=7mCke-N6@SIy}5**e4D%T z3}VGF4ecBU(xfOomj_&k8JZMU3!yt#S>~GLA-_)AaqAQMWt5mtDWQ)i5AS=y`eG>T ztTS*}dpz-fL9*J zj%r%g8rOy6KBllnmkR@Y{BUS3Y7`e+Y^Ms{tOMj$X7c3Mg0(-W4i0h#j>Om=$B9o{ z#zsJ?wyJSsMj{h0zqxzMfXkUYePHuaTgl8d|)UaAe~ zW3neu!uKgR+q;5B)|!z7m$t;fca-zza2cXw)M-0!;P8Ua?FSk>u0U}>j~#gDZesA$ zK<&ffRNy}KOWB%KXQJXPjwr$=Cg zUXoM#yN}&E{rJVHbaVq!-Lqf-T9tg0nb=w%ipwBV5DbEKZ()e3=_~Jp1npMPC`gc?!z{4{>QG5D1x(VuPsr1GR!XYcp z?#SxDx#oh&WvLf3Q)COSAa7F($tyS!+s0hQi=|#ku~}7`27iNAAGK9Bf?fnif56v| zl=seYQcgIXTQYh-CX&R@vQZ~#K_K8OK_`Nv3XRS`e5XSitg9~v9XpJr(0EwNXeO~) zztbC``o3%MVg$w2mD};2os6VMK^D&4lH;-(u`KiP?cDt6HsBLqnU0o8<=F|)+{YB$ zQXjzHX~@9z{eAcC2?Z#3oslly2TUL2x{jEt*;UW9>kGHNgw5MmK)H!*$0^}Oa8sXL zb1W5+7H6FEP0a_RL5FKq>tZt0C+{!*Bk4}6`-oXXD^ue$}=p+`~&}U#$&}1nj(rd zRXDM+&ESjKD~6qu{4egW_o4!7L#Kid>B5PWMvQ-?h9_R5ji$Bk#(hnN&Ee(srxBS; z$MJLph~3Q*?;r8( zfF$BMQG4hWWSNEm-anFImPOyBpp!(SW)OrT)1G+TnSa2>^>qxtcvejN8({i^$XL^h11Qaijq zjs$<|1wpi)wJ0Kg$zHA}XqdrNxXTAMHerro=tTfq! zqw&64fndB*BR0Tf+|t zhKtD+ZJr#p&RM?R<9NR)5a>(W3-tv!3># zGOEOZtL{wyLnIITZwp3+L8F?NZ~ZK4CpEKy{>Ac;kHDK65%A*D+Dy` zRk6a04oASHZaJVE1>@KB40R&kxLQDy-B6V82HuA5-6jm|+w(Uy@2v6K9wjW@5gBOqww7sw04iz*#_iLkr{ zQVZ0v!(UQEy}em+8oe=mbqmF4!YDsuk)KaeJ`Zp7yEb~-mG}dy$X2*>i9fcGMWOu; zhX(r~7_Z(>J!Hh~hmVZn$!FWi&FRnnqAC2(np~sn%CUU|qtt-i3Mgr1Nk<$6!SCe{n0U8Q=mmx0&}4fQ5x5yg`j7SAd0>Ox&(!YuwwxE2Nsu;f@E~N z^tk?PLqi*z-HQdzZ8>QOl5w;j9Am3!!Wr9)_6|WotlP4(Xl;{1Pv<1V;G5?KQW5M@ zb=f$v*h4*VPQ#{KrhaLAz;v;0<;fEJ>4;b#E_L|9k!J)lG|SxETu#4+5CCQ zE8{7l&CCvJU@61u##}S$cKCWtngSAf2a9?JeB~$2pzKJR<;0qibU1@u2XsiF;D90* zC=zKRErM;V#@8~lb_5Ip3F9PC$Us+16od!?A-s3b;d*m=1cRx=zt9^cPOH|Cb!Pc) z1o6**_K3NM`L>S8FF)DPB0igF^deKDvyLz~xPF>1Up=pTE2w6DBuk+$Mqm1S*C(DS zkCct?zI{j-RubXNn77=$_6~GhR}#fDPK6@mdqaL9hM))DrHyHGif!e7TUDlQaYbGSxU<7Q8 z&dh@=6&14nc{(eO=0I`+G4peNIwpN1H#1>J1hs9EA_iJQ`CX0~FI+qT@=x7iRGQA= zGs57T2Yt!V_D6bA7Kl3Z0U#_>Xh^HqDFp&iovJ@Jt5X$roZ9QZ>vz!wF)S6?30uQc z6tU8AAa^KgXYZXg(%u_wOE?skqxqmVzj~gy4?uoDGa@iZf3|(?3vKe>GI2D?`JfF! zzJf+9X}5#@rUPLp860pF!bUX3qX_eU5U8PTg?=4*^T_9@3^&_MR>V2c$6p#6F5172 zmUQ7p23e26F*GJ{PjV&rkg<^1>k1ox#yLlrwK3VMft_!c;nl-Ws7nry{3JT7o~&J- zp6eXHNZSZ4pogHq&xT0c5ClCY9WzUznyb{@5glt69 z&_IbWO_1v>ypU8c0KcaXcf`JP6&>!kp9qWnr?U{zamCM3h|V`YV``7CpI&{v88gzK zj=Q_wZA7kk^||%$0Dgq+?6F7wch=Qb637qSS#wJKg$7-*oa`pdWX5kRT`mw_=i}Z+ z;^c)?|F-__STR(hom2P0WvbhdSu)+kxhLN=1hK9~k4Ls5H&YAQW){AlFQJH@%nq{% znq43eb*-cpC@L)DBJ>*M>G29_6X?*vFC^Y~t6><&EaL|$^#R6b5YF{htv$Iu>GhD8 zJXI3VFCES*kB80(0NMb&I|Kh^>A>;nwoSm_9Z|2WTlRWLXTg#z#x|5jZJF{$!B_IM zgBQk|yve~SUGtOsa$^HhDA`a>MA2eQ?21tGNH?K41R2+}mY`cx_lf#g$ngtm8S1gv z#kCi4h)O7s7L=sqZfy?Laxfx19te^PZ#RvFe}^sv&2QN07Q$M-?O6tr@E(#!P-O#< z0MYcME0M&LNu zVCDf;iwubOowN4t-NuI4D2ecle0x6Af1l&!)`vscq!x%~MLgx-0jVCWbM3_f^pvKvVd6#wqRMvld5 zK(dLQeji~%>_96kiCekSs1i~h$_mgq8$!B|sZHKJx3YX>*w(cp9F?RcGU9yxkutB_aLv?6XsN zo5|Kz8csIr4ege`gNP2D;`xi^F%* zj-NyCHWmjpYwr0)XB_k${0>MmsX}NSts!`&Iu3Z|RiR@c?}5=rOis)C)qlG}DT0%s zMR#Sp2tb9R`4S7GCt*h|GMFGJ4%@`21(|@oB0nhW8;x373Q5z9(*gfJtOt#Ed_el7 zKyfW^YwnOtOJy417aEIdXN+df9ewTF(GwyOq`mvzAa)Pcr7}wP4^{I?7|^p)O(dfJ z+TvH1{zu$p-}Bj_-5zvo1Jxk$O+G+QfI+etU!j8arf;`XXt-omdjfz;?18vs+ZYyC zK?ER%#s@22a(_8)6uR!Ym2kW?B?JHQx;$uoo_}H|$Lrf?{u30qn}2d2+=|7v6(Yt> zv^6QmE-jh2pePbL)R55C&Zd19BrhrSmfvm2gZvs|+bfJO9FO{O9W=R!US|Zx{l`Ie zdw)P#2E)D|;R7EKfR={*81MZo9vE}v9YHD77?%vKJzYzKy(QQnY9bs+&{*8;Bw$wc zKEbTu5HRb3HIc3Rr)^i|gO+3T?5Bzgwj_^gz%nxOcT{NDx9h5QjNGBGlz!h84&hV4 zvl+S-&&qvG`?g%YF!!51JRKgSX%*+IPK=!AC+Fu1nA6g-g0A#%WQuv3lA0R2vcZn9 zBDByvN01Q+PU8cQ|0t0^isBg1l7#AM}Um{d6lpL3YbaWHbw@hFBVk6mitD7 z1*tKt0@~d@8{uKkx%R>h^i%m8)AbT{RmRq&E0b0!E!^J@A{b}Zrq12FhyzM1uJkm0 zw(cKQV7}`+Ez;lo*?J^v8Y+bO*{8Em=K>Mh9iO5 zN(bZFoRp;X8BKk+rgw_PE6;aRKbm%4q_ErIewN;|HVlMQ5ENWW`${N78hk~E{_XCb z7>lP4%&CdWa&;~~PzE>0HTCCqRoxB5+N1vJ2VK*GxoNF&-;ZZQQ+YP~hQNkg1i++M zkd;ba{j`UUirG%WaM6LeBmvSxzY`0M@$WeHbwj@_W?3j406_7aP#F=vstBTB2XzWF9%Scec|S`|i&e-V(rQyosKNS+(Z zSmkU);jSfXY_tey#}IIA?kVIJxEha>AwDtQ{3vqf@8$5pV47=P zkRsZ8p|KQy4f-MqZ0L7(-5%vQ~|F2MRy zI8L#wro{LjCLMgwi6GLOw!bi{TIu$6yt01Akjqknz37b@Cti1kh&*ApONO$%tq%oNH<=fFH#_wJJG=V9G82Mc5x{O!t5T?c1*djT%uZ77#uB7|CiJg_2A~KnZ zRP?h#YAk4I0eP{JVj=(35GSDMv$fkYSr1h*^_H3F4fb1HP+dF3#V$UMf>F!ja}ms> zT;FWv)E#+TXD3r{?gl(f+POv3UHry&NYGK|RX5Y}m+sBy_R@?RUteQ?oZ;Wo_1(rQ zHB34?J(lr0KL@-Qm@bgxmtm96KoUsP0iQ#c>}UK7k;TjoMp|7W*KBDmY&9AIdyUR= z*PKAHQMsC|hUdj6Y9#;zKVi;;XAw_{Baa)tZpKI&>JvtE|`d+uuEdBhRr+ zCbNXg(`2IJIm!xvdhm7r&0jnYA=?;s&QFg3-<)tw;@%MjP^_zQBi5h<~?HVu#9*AIjHwc1*yO`p|ihary^jUM$l; zovK7OZu>9z*JyWaEqZ~(ge3m5;jpFLj(*qB(|yWnAuB|J)kXrl0yE1npDJxKr6;PQ z65p}v)Vq4cd4CZY{U7m>#I6Z#Lz7)oXmF+6xXbrHHT+uFwYutSrDYmd%>Quy9S|ze zFb+CB=34m0W#F>xp?mCuq9vO#P~Ndm;LR-WmHV}G$&nEW#Un3_2@Y2^|5L24$rk^) zF_}puEtL7Lgx;e*JO*bj(mfoV4TyjF0)0d@#03{3Xp&zu>W#+XP-TD6D)K;Hla7ex zNr;WCPoHNF+1Bt^L3*3M3ci63wqacK;r+)(AB1hZE^@AEZ~fdEV2q>L-KnnP+dR?g zM+_qpHXCcj6V#&~ewlqk<#3f~UDqi$`-xgz&k)2m+vQGT4DWc^d=(Y^7M!`+miJ7_ z4Yg%JTN)s17-hJT>gH!Pz0xOadB{VnpVK>%byQzqfZ_6JFkgLP6qOw(4R2t-fn5Q+ z`CSa={g=jfqI{3_P^d^W^kJB-!1f71izsA6izG@gW*-ZMBL{RnUFB<}dpG(Ki_0C0 zlfRRSH1&yFRDA|nyUOlW)=?C0F~#`l8i{+p(Te8cf`BgQQb18QsrCI-I#iSoH1=X_UtD>YoZ`bOAobSAu?e063NFyTFB(ByB+1% z31Yo8&Hun|n6xO-q8*@RuF=YAo#Wx1?2zxo=)sQTp*n>Q~ZN2HYhsZ z$3`bD)u4up7Dbe`faOmxSt`M8nhY2Hs|!)6EZwR+jq8DTlWuJo}Q z(S^@T!O_t+C<>uI;(?p{+lXe1=X=f8vBKxcFitd7PnvC90}T z1AaZs?N_j*jXlx1Zx8Rfua(fNZcl^fURCXLA_-9@YajVq&r9FSzA)*p^AfV&FgsOn zrvSQ&6d$IWIVXz7&SJ)P121h#heP|k$FqyIh1)nssrN#vHafIBx}g-l5~I$5F=?O@ zY7!QbTyx0@>?#R!d^&t-__2oBI-qZzJG_k`{N`aCov&*SZ$`<5D0!-M$l!S%WHoX7 z!-bv`6Le&3jwF|gar!s=H-Mgn_kUN`Kc$wAWQ@Oj@k>y=^BOP z4~V&=Pz|C6&8VxY_lvomSbI00)2#WNLYSmeT9y>A>=XY1ZyV%3+d*<1*{9+*+7tVd zq;~~c3~>(5+8wv<&|vSW3%An^>&xG1j08&t!&RKRYv2J(b;i^$mA0I!U1vi!=v}%i zM)GZ!F@<(er&8N3BPp_!&>Ie#$`S$B&ekTp^cTYifIsJ2Ex~bWfAg}6c*x4Ll$Oda zq_TnA%>mr9ny@o%V_rQWY0YH;>WPwdBNMp8UE$H{TlG;21-ux%ah|iCh0~?~oXc7& zKnY-yo@h0_tf64hGx+7lVID`(zL-)Y;*Y5iQRQf`5XOgHQM4xunBU*a3yk~mUPJI< zm?^k=Y|Y|&5m&cf7I)Hv{_B&{^43Lc>Sep@@>8e&iA0DvS%9)y?8fJuH7s#Hyv$hb zHzAIy)q3q5MZifok?n9SZ)^s1{1)-Ab7Pr;72UXWZ9pXEJ=88okgqeF(eVA+f%n56 zbf^+qxJ5y`@V}5h617{8D3Q1Qy_}G$Vh(7bY|rhuzs+tt8a=axtzHgS-f_2HrbUGl zS#Gss{)l)$BG_sX!io9gRnXU}AQtUg;(>25qU zpB&|@tC@;XOyBgzZKN1P!}q=OM~R+raZlH(ucjlUCRFl$T1JQ5e0|#R9H24arfG%> za8dKuR}aj6a&WZHhRvPgKGKQQ0F1lHv~W}&}NFWISV_K}=Xg2DP){y_DBN2AwWzPXJnC0P^(jAy1Eh7A$S|Vew}Ya?VOFtb zw!djzS6>FXzBfSbaPXJ!yw@~i`y*ydka^*1GO6enQ|~k-JzLT&rac|DY$W?=knE4Jguh$KLWUcw+@@$7Q-I<8NSB{ zhO0mysjpGkqvyV8KK85JIS1+0O&7M*w?bdQ{2uLw2N!G?8}CK|9~S+If}-4gAFk%S zaroh{KLe&-dv1Qd-BP%Ia3{3-ZhXAUUw$}?$u8P-v%#?XmGeyC*egHf?1*O#F1QEj z7BrA@uTPZU0_1%5CN_wJM^Gj=W@-~y{Dtb#4vz6~sjsH~JPO+|x6d|+H%%RazB{jcG_Pb-wZFmE*-q?-V@dA&jSprwBn{6 zQHe$#<6Q9Ax4Xg}DxS~%200r|9rWj?h%ZXoSUzn6R*lVvhFw-6Z@#&EV&O86-^PYB zDXW#E7o17V_5TP7ZufYwR4yn+KmF(Vbh8TVB?^Q60Eg!(+gKRul7Z<(PKEKyUh+QN zo~HK(w~vpr*5KQfh&m6X(P#1z44=HwKR&KLVqr;-6Lx(r>?&xMgOs;I#rZf8l&h|s zY%%QbcNPDNhr@SU?OMRE=k{fmo@8k6n?2^cb|qYjzFW&n`l~aEA+kJpIAhY>!~)2* z-bV2I=S_9f^mYC|p@I6K1ic@z{Jy2UpqHp$4GQ86F16^MKJd2@*opgUL||`-78u|e9AsI4%VSyQ zVkZ14R*R9~8UUhKBKLG#U;*D9di>JP)I4Ko>;5phnXT)jt0NuA^}1i_8>D&n7DkBv z*+q$}`b_fzn$FaGs-%KDIlbC71a&N$m|9VL#qQnIvEw>f{;jqIaqe(lRFh!H zf#~q(FQ1-Cj?X>}*j-;^OTT6)DZ)vn!0!#FfL$m3>4iwY|?8<|R_in_V zHplBSgH0KYs`4vj$3pS?C&m2-w6UR_fhJP|$vK8jq6QzCs;ILn)vYvN!E(GO*03XI z+SOVp)JL6QZ&iQ#{)nUav(sNOs+`!Q)drGk)n7*2$OfHgnbV4{%?q({F3%^NvzSQf zUqviCoR`84SMZdDY(Asz!IzUh)P z{3VUSC8ndlLEc9c_&|{10Hlw>ku-=A#P%_e$P*C^F2_)s zvly-L;JTd3*(?8gg@~IF;{VZ2V^;MwY<8*mzFJB(vrRZUDr$ZFgD8~*a96z;Yn%iFR1GNJwo>R`pMW`gaXUi^L6eDD+GQqOjG)-EXi z)nQ!1-rRVk9}%V5)bj4OvPS#*}ysO3?lt(pC{ zZdnb&7oeubq~OIvYlOIwW7cy#6idJ>l!pajnz-+eD!4UKoB09W9f}0v2hU?r9U98m zz2-5v42QSY=7wqJLGkhd=O@&=QgFcIeD&Ca8JeSSPiqk!G3^}UD9<20(g94|G!lHclVv|USY0nDG(tMm z^OkQ7yOGtTz)jahW7}M4$7k>8mcK$ofWL%`;cnJI)bMi<*6(%fB=6;sOh7{#G|}Ya zUAZ&X^I`A}CHh|d;A1*wqUEV4K=p0q*_AI(Q`W~-_;gpF0HcZPH&aD$7uPvt&I-

    =iv^NoiWta2Ch^9G9)>_;bomBYw-@ZP`_u&L!XSQC+b#9+rVseeqJWyCZ^@vC z7}*>Ado+*oC={4~>1(WcTn3+@;YE8jK%F)Y-$Q2mT`s)nMPt&0!v$ zXO82V@dHb7pzeH+TrFDuLGNu#{9>buA}_v4r-opM+r~AHA7`cPdTecp(v~eCH1p{oIoBhM&g0dMmAQFy#?7 z(o-JA$S+YuXO)Mt+_U_Ru9^hDm4gN8FVX)P`&qAye6&==Dh20(mfgou>$_tFa}Gwj zj_tsOzk>Q{S`QrckY)8t#H%q5fIUK z>RR%E^w3F(bJty0m$)L3(B>&F^Ow}3JJ(GXaxStMD|p!Xmcl*17UfdiiD+$AL{w>Q z;wW9^N3^;e4kz1zJe!7OFPp5EX~{2nye$V5*3wpQYF)o6X(yevEiJcO?}DJ zHm9Dt|5aucEm>Wdjhs}?$$I}fCqUhKCbNc?K}++CPS2q;zl>vSWdm6^NR15Y1YaoGI;+7 zZa|U0D?&35xLo^cMY~{{TKilwonmRWlfnN*Z7+4?4tRW;Dv=(bP9%Fg!U&`8dx-j? z5o@Z}mD|6dhMc8+tI{!rqg=m3_TgZK(_F*jY9GU8r0aO(p!mlDZ$8eOkMri^e3P~N z%{e-{({H}UX}-q)1n1y&_s(^{JbojHKY}4kt%iw4d{}%9w4Va$$3A1Kkn8sHYu-~< z?;o=}qjYDm<7VZQh!rD{N=&_PsJW|5DHt#O`=hKq0Y7&{`o?YJYw>zbcN^n%N3C0( zK%Kj?lKRoayVXivFIA&b*KT3jLszLg2-YoP`k=zXt9wm%Ta*5GJzup6-iPcfeHuXS)*Dky!bwE}eoq+p=#5bJj0N?rS_wyW>&kkWUimAcj>*e>05-5oWC zlfW3}GEg_a3F%J00dmgdm3H%HfM>j$TX;H3RzaS{J?N0m;`o-8@vRy4qsC}J?W+B? z^2f>f3*G5msXCeenmoToR(LnM@OTu@N9u-!b-UL7c@)tuOQo95s&k?K^>}_&-B;*F zu7PvG2+OL0vf4ivURIagtLHcae63Ki3nEhe`r{|BGn)j~sd;JYsBWU+sCDT+x=5|- z*WK0$m!Yb*8>}l*+o|i@GuAO%a@}gY(Nyc&RM!o*`-pYE7)sseV7nY%_n>Vwzou=x zZs%zI+6HvVKtEtrP*N%zq4i6oPY&?hK%P~7n3!L$-D|RMsqoyX;oJ$Nf$kmUN7TrV z=m+Lba2*+={-1~CjQa29Rr_WhxAu9yl-zF6&Y%udRX;7)$kAMsQ&;cW!PM0pTSU>t zbDVoOBAxDzrFzEtmeEVX9OU>Yj1EtCSmtS3S-NP%cp(48^)Y9FMs)%{YVld%YFyR` z2c{(OMi$WSx-n~Hy)j^TGzp-K?=ZzPVS)@MC2#ICY?$#;bv&F6s)JY@d|rq&&(1Sp zV3-_x!~z+3>432grUUlimN`Up0B;A=CyTX#wUfzuw*0|MuNrDcV5zWno^^FR=;s#M z{E}x&I6h9+n=?BugDuE_Qe#)S45~|u=6suD>VQ7`I=gF33T1@Z4#`%m+l&|RlQtW| z3dsxnn$ohC$MwI#>g?KCZ!MrYRh&;A77C?no|J^{AWetsFum(%pHo=Y=4CO>XGlIi z9un5yO5=@mje5MU?j?frE4W5-3?Qic*vLtC;7td0I!NQ)K=^TCYgw5KC=*AWv$)P- zx>(_NFuIFeSWi8hLv_BV4uB391i~3^a`xhSGkcwB-)TQPY^Nc_9<}Cm2=@GaMjC^YU? zh&6|&H*{7p=rrs`T>|nT_uNMVo2Om~Azj6)dpDq>q z)36hN8cxKye>5%}m2*NV#Bch>;kp7-PR6opP1|Ekw{1<^MR>L{57NOjq48ZP)p(%{ z@@%-~p*|#eIY*lYJu@t}w^qIkf51Is5BpY-9~-T&1n14FJfAu z_>`5a2fwe)qPvOE!#t+?X%SC|Dd*3TJ?(6;KcM5m??=qB#*>vuEkVYUyJ8yj=9o6q z$>H?*sn@B?pI1X(zmo82Ryz0&Z3?C!_4F%b>u{bmJX($Xpj&pC?Q7|Dk#Ov&y{!B> zHIeFR+h}$`R}b1Q7kE8?8erKY_-1l**L~v6i!bZESR*V%B3^sT2O=6bEytzo+DaX)`Z9`Ui6#PqwMC-UdRZQNL$xC8d! zkj+}Na?poad(}gH*Tb~yKzB9h)+n|>w)HyMn3xu~)?Bcu4}&yo^Xrp0{BL5l0TxM-3-w)6Eb}_xV zn-+i{YfP!jC$%`NB~QZ^;`p}9;IFL?>8b@ZDxK6A*2)=T&f@xyn9}fkRUtg!7OV*{ z-6wU5f3+B z>0o{1>GiyjfA7AQry=?5Emby&IQjLUOES-gebaX1$;``Rl6nbGnrAQ2DR=)|IkMdY z^QMpcOlYI94CwO#yWrOg>M*QfTcGjK>ugSz!Cj|-81Rc;=efpXDFc0v<6a1CAGGVm zMTYb(4?ft+-m`ZF8Zgh$7fwq&HFgzjvlCBwe~-{>SRajMN4qaG@E!Tb$;<-$HdxzX z-AmS2gO0Kv!*sLKna!BtOc(iBT~{wkg%#={=z2=XWy$tZzC2()O)QvCm29R7J}q0r zTkL#Bem6|EQO2B3+p5qxR0jMV#Dp)iv6@kv94GtGSuJ%OP%jqAkzUzO-rRUkHy?6W0P5%jk0Kd_G$5q;v1+H6`+#I54hJ zdoiVt;d4=?t*SU%+_#SQ6Y1zRv{Tq&4j$0KeQQ_f+)3?A#)UbwFq1XZ&po!L2EOI< za*yp|XJLERYt+}?w4j&k!FlkuuI^h`-`1^t=ROKO-8pwaj{37IjX$mYW+mIu`=$$f z(e^pti}IXaygy)j#ePNP>R~yS8e5CyIGbC%Kf*qP9oC&OVXmLI96kS6=l^*f_;xsD z(BAw%apUsxJdpn5I&-~=^@9eenNwu(_f(8}nJ2-zR&$~CWP}fId$DHt} z8TGaO=-3QF9CO6mkE?BMFa_S;1r-OV-aC&=paa@ZfRMI@7x$s;ukWnwY%q1qcfa8% zEMdM|gBiBZih{;jKZRy6bZZ42Fj*-=90&}*Jzcoez`Ota%coC&pP^=EJ!|v9{2^>{ zSRsw6Is5zU)2F}vefIa+f6hjq1nJnnbI$+vpFc{Eq1?Og1JQV_W*-1=j6jhP=#7#B zy+1;M-v8re{}Ln$M4KR>(nU^^mof!3K$c8^wBY=k3Wo79WIXo}@RzDk0X_=vd3Qm& ze;hj{0vvrCG!5;qpvtdDuRz#{MBDfVzse$FM`>Ad&exS~#D6Rj_sL9_ANKsRr*A94 ze|6sTD`#aoHin&z(`{}XptjKlj<|iqGRp_+yAuB*BR#+Q zq}-z5w{l&)+2Gw~zDX9!^=>2EZu-&qc54hW>gS{z(eb-hp>IlZspQHzyvZ@h*OxI?R8u{DQ@;VJ?WQj>#7Iy(&{{qO>U#;*L!HUuACt9 zUy84JG#t+oP8qbjjVCi3U&|+Ym5$b4%=pO+p73pk_{%}Ny~V89_)Gaww)ncS8fFh< znAb#BFq;;SIPJ^eFYO|G`VPmh*-0%ha^V$O-Mw+*Ct8@z8c*9Wf@;HTZAOXsu!`fc zg}){g({UKPQE%EB^@}b=c-fuyq;zd9Ftaz*GX_OygUhQ_BzcXvyrQzdFDT2q=rhP1 z#yu64xt{EIGm~JtlmWSy!)Lh|uf_+l5sAutg!N4rp z(C&jGmxQ|Yhp?UQ5?>aVQ-^Kzn*!oCbT)ma52QLf8wuT#H>m={aXZv%Cv zx0{bJb2~;ysXzW zwmBn`4j(I7$LBmVy*$3uj-27Vk}Z8MHI0>MyDr<-?Dzr3W6zB!JQXgWzBK9f)O8ha z8c}3Yzf;HltSWaY8iQMqa|P#27fEJDefYU^``SFp4_l9?8{5f`~umQ{}AVRY|jOZ z!*0!njo4teL=E;H;{nH`v!MOwRSdSI=M4)v61s+&tfsqC@-ZjdrqbKN2Cv1z^zwsY9q+x{65@aUWA=g zdYpeC20n6n^0}pRAN%kZdMiK0|MC6z`}h7)E7%ltZVO;uDw41dio8HSM(PHQ@_(ug}4aaEsSW)wjPAXQK&H6Nvo`3sqEpzI7^Iu50w1uwge@QfPr)`DHfDHy&@Kf4Maod7 zOj||*FVP%37zBQk7xfU}3PI&KU>kv!cw2AU;#xUDhaZJ_pbSj{tSm7wtljFi-ilw- z_T3n%AT9Y70dUBmT0M5$@C;jb&NDwAz%~UqLL6wt1At1^jLq@;}6E4+6H^ZWykyK9n<9S*gyb%eKD-eU{Y@T zKq|`w9+wPM@SGyN`&|aUK=6`g&f>sflS=|W5Wp|STsaotK(v=cFWJccvmFz#pur9M z+iq-oNN1Yf4o|tHUyQSh7ugL4px3}azm@8WaT9K)yQ#gY_w}Ri}W%cFUX=)+PZ27-E|Q+p9%rTMk>gF>Ia49_`u2W^hXl zTa~B2zb*A;*sbDL-7OU@yhOJy6&tjbwO|WpK^w3IGKSmC*q2|1+dt`;;5st~o>#Di z8xODBZmB@qUb0!x)>Elic4^y;w(GjV0UX%Y+=TJ!b&OG;%Z1k!HWqmMJi_DF;k7IE zALNC>p40R+DriQ?qr$dhh9uKD@7qNw&-;{j*XDH_kDElh7r1o>8Ls==iS#++Z8rz7 zHT{w;Bzm1^*j7*c?JNc(Pum8p1@PUR-H7McaS<%E=sQ>Ql4r}+x}F?zc;UkI+PiQ2 z+gFdiHzs4j$6D0?QuOHaqb_KFhCGz5`}!}x92NgTdp@4uUHZH)%;RPIzts6fD!Bhk z#EtmH+y3u=Q2a-JW)2oh*vQd_>%jK#j~M!S_>+zl6|z1iN)@1dbkb>;nTfiyH>DHDzXm669kK21dEe+ zgQYG-e)h8;9TWU!{71D7`9Jic3 z!gk&HhIr*gnatVo$I_<55>NcT(nm8d$h@BS0kU>yKd-_ClrD6}_Ka8srm4-3tm-nh zUg9{+V=J(dBR(W_y2CmV8*V}Q;UnxcaZsl7C;W6jH`hz5Hnv$jPmEMV&Y*Q&;cwM zo7me=Oa_aA^SC7aKEbr??}5Y+^x=;`#W7j%fK#UdUay1{{w>~V$d?H=L70c|ihw4KQD*b>j{Wz4OG~KtOH*Kn^1Xg;3g)bQanQTI58oulUCVbMq+L2FQo`4z@qm)j zHz?%}hBiK>zwn*>(DB^0Y@{lEgLnQm3|{$P-hK4;L-1UDgs0F=cmV(6=fN|69z4Tm zzQVnuzt~B(&wwZV)4PuWrxn{%9zY4%J%#u3S9mLyZR{}rNCErbCptdhh5qUb>$hM2 zE{X2%?_$5sMzr|j3&|CLH?*0Dr-7kmb?BEwtn&wpMwbeFn$170Kv17Z1K$4>`%7R4 z@aNy({SA9TY|_BT{$G&GJy4@>@cNHGm}bQO{PRD5^op@sM3zYb-jw`r|Lz%U_Wjqv zYV~+FcytD=`fs8EGzXGu{rw#;59D&57xEkHy07?tF=vJ^;g3}FnH~+Ey+=Y3@wxcy zy_8zV_c~_oeWQp)q-i6He4y>+5AZT5;s5o&VhZbL=sbP+K~%)wL1BoNE5{0tFB>*i z^hYLf=2)=0LM!kHD8rt=^9JJ+KK&#Y|5a!|^?`quYBbmP_s%o#54j6J1mzxJUZ~1n zl>H%$=wD>JPae;4{YCPubLyl&Mn`@L9|441B zg#E_I7Z5DZMxRWUftD|0G<|s?BIB3f%*!;`H{ZtMjhBz?TmYByci_4}rTr)CtiYb5 zbu94XSwQ}0d(ACdc7GbrVKx7FT2)r*4|Dyvge843C&%m0V4c{R+VM~KuKoPSz;#A5 zx_7kv3A&@J7_8^7Lhu0k9(=zfh5rM5`=36Yo!iq>2=XJ^eKgPFDGkkiHH>3R$IgV- z|1ky6&6$0oPMj~E{{$_e>vdpqKod-HZExbtn5V!K1ACsA6F;l5wN~-AyaibDvwnR? zCI_Cp<8R;nh91Wu>ZSW2>C(MQ7oRY)rF+=h&BW)tyR?sMgM5l$GtBJ>v_uaBMExHc zJfexS>R`pJszR387hK4>aRq5h&mIR3*c9z6$sofE`F~QO`@vAH1wMcie!2vcI+5Fn zBIo*iDsu2##*d!+*l-pL7sU$VaOaPxM(jtIE2=RS;y5h3B+AbBa}@chrt@8>4Zqsq zfe*C9*Cwek>Tkg5QpBJ(_)+-s+>KXX7aVtG>%m|o@;O)Tf;3rBhQRc8Cdg~ zyVVTpk(zyRmb32%Yj;H+Wm3{%v%*k;6{M!%mh6Jyd|Mt-n zQ|QfcRP+?~)}D>3bIX=%dQX1EqYmnwH&}<|0gEduj3coQEV7|)NsY-2AJLAOu^@QI z!uVLFC4FDL4P=;+6Dk}oEIOs=wx_a3D3x@4mlN+JC8;(ey^z*Ai+LEt7HT`VbH0Z_ zPqX8}Y-9&#!fb@B95%?8XZf{*yP)W^EQcNA_?*(z1mkNl|A)VSw{&*ot{^9JkP98* zg+gD>YS7yEi_F#>G=5zS0?8MC9}{#S`&>_%Dtp)>3|#Jh86)yXA>h{U0_@tVq9oo>~WgBR#PW|1I^zTHY_Nr%E#L ztL%x@)t_untnB}yds4-30{65pfna62*va>}TGRBCl`UPAl%%aycBjiZf71O2^tSzG zdS_0nJP91#4T3fpkag($DG*LkcOL!ZLV@o(=#(|UV)!Gw1XTT8m@*A6FD=kQ2$Urs<8;k~*zyi;hl z;a!{2e5!|GmHa!E+q810^3H36-}e(`>8>RE5ARx<6Yu^YYu8WAT&_1)*MmtF?OlAHvY?lTVZRZSg&i4t|>yNy^UUVkWLiNCm&X|_xTC&iM^ z--`Q_{EjBSKM8cY3tb&birw34pr?qJ)>Hj~?u~ZqE%zGf)D45(h4i7Mg8ZfG53ZaX zzQGetKd`<>@Yi|HayeXcIg~Us2!5&U@vFdHmFul`QM%jtJ3?+zpN%y28Si_7KH^>0 zF^A$3cSRfQz9+S_4c>RxuiZ4lmE&@r36v9<@Q>-Ydwl(Dm-5M%WxOpI$4u*v(OBEcz>n)&5Zv}nE&M^=vAd5`sdG~ zGM_^VkI0Yd!P4}(jCExRw<<$(y3v2_f zReY`pcsKfv5Plp|4&_nT&jY2e{LVS!Q!d9K^A@@9*}fttYQOKbf0Ia;>fKBQ)?I?j zGbu4W(CRj_-umWj675!PI)wFaxEtqSt;@msZZsy1c|DO|nm9MQwJd|^OD*|)@FDvA zbrsk4>yCeCUhqqE`(~FZfL(|~IkIgGp0BWm@1#373Dn{AHTM@TsojnO?|0kS9;nOa zEwB5W6|``E-x;Q`cMLi(AEHh3kJIi2>yqAb*uhTrB%aBi;B==!x;=w17>KSF<_XvP zKCin8^!HZSS~f-*(O(58gTarX|40y|;@&&nYkwFfGbxjB1L_D7=$7)BY&K;Kx{XvR zSK3q`%AzbL4F^B5=0?M3(fxJ0A09|frzCJF`FF!_hZA=_=z1`Oh2gXYzGe+E2M8um zPGVOt7S{b_dx=SLnI9cWf=Bn&slV4yC%YN7rv>1yN0QmY9At>_ZEdJm*q9`Lf}&mDO%b00 z>dlM=i~~lNF&dW&r2Iv!EMzjcr1N2}svbr@F zu^fim%&ON(jr$40CXf>{?tx8I+XcC+dYF3_I)sTvNq24^Ruasgj6+dFS~IAh67xjr z2kpy%{<7C8yF&@{0h795A};fq#^$0_Xux=ItcPfrNW^7Wf$lr~&c=sY^ysFEuR7-g z;R$(JAHQMus(v8E=R?0UhP`mZHQg8Xhrvgxw4BUSpF>IxNMB(7f*!-W=yAM8xz^l4 zF}=hjI>6r!#t#$8Gu#rWC$L(0KOS&D-3MD_H#wa`03!2lPFNfL4q|eo9{TM)eas`q z5GF7ztTE9l*qKSc>GuOMC>UOmv0{CxA2nu5`^~F#DQi8!{8=ItWBGOCx9xWeaZL2n z->Zu?7uN|ZF-FW3S3rHrcBlm7iO`!S*bH-uW18NUim9i4{ep7ORtJ;*)DhBh+Uq>; z`ggDD&kAHB)xo4zwe6srp|uF!-}Sp-tBUajt`Ann7=gY#^t%XGTler?5HBPQQ@YQ7 z06nlt-nug37$mvZ^`+MxAJdnyUHqzj8QZz9-j^h-;l|(?9Yfq5uy1|f8FXlR67Rg; z*P8dR-p6~1aeJ_T&M$|>bdvLFfY0_YD6~_6^owTvuj& z@N>9KIOdT!v&=X)jwks-v__*$R+vB%#tZfJ!6N*n&m4n^^#R&kfUTSaFpRF4FHxU= zX=?hE1zUNIiN0E|(*x*RJ@Jf5_b3_fKEDKfX||3*ADG{k5q=xO928-|68UXV*U#K>9O{~$2lLhyR|szz!G?l!GlBVWu>;WWB)V4 zV^7mh*w>*W;Y|U3klDJMklN1~;cd%(fZSZ@HTw=@7{r6~aoseK z^`tA$ant4N$-X^Dz8@b>S<*|;RkW|TM@$Zi?KQU}Y%I`Dd%vk=fHz#9(mV2_!2X)x z*II1P`vm?y{!RyWwg&qD{4`8v!kB+-KgsM6^tavwKfBWhy=>FI;JCGI-#C?*FfVvg z+|r!*Z!ub6YfJ5XyxQ1J6AFHB$|~ewpUW@O(lD^tLCm2 zx_PLv{|s{8W%FUL?U{j$k~Dsx!{}Q{>l>|srBQDNcAzNSBIZ~L_WVm{8EeW|1e?F7zgpwVJJUpkI9zK6f3&O5|uf}v3 z^zn}PXcw4H>*hJ*yD~%Dk*UMFwdr~3gVeME5o;8ViHmEnTo(P1HtbdU&_28a+i{h? zbrky{_hC)*oVUmH)>xK~*SUGGTPv8e@{>8M?b}B+VILKTHDgD5)&;wOz8dpEl(ie| z37#+d--}*K1hDP=Y%+fIIw(YGqtUC+pB;@m>wsqUyIO^Hc#wit6>wdgu*kIqgcX6{6SZll4k~qIj zce5~doykf)KQ5akCo>#QtsLR-#tkfYS;|_PvZd8<`WaJXoLkxWg89|vMJZd*?6qJ% zW=nr1Ipm&|bIC8$)U4U*VLSZXbK~63R+q4Tf-l})g8b9B*|c0o&{@cPGCZ5G)IG+i zl#te1QLeB;OxVzyDP_%=Z-XxE1wt&%V5!4Cyi1^~CcN z@MD%9&OcWWH@z8W@AzD(B>35o7$cNTHa?MUQYl*t=_ZpG?Ohhsj=WcL6d!ScYegq1 z&K6x77yrx?Y&51w3Y}A`HlFz({8<+HOwB4C4<8?WK9EbzV0IB{vGttm;<~?$KcHVg zzo~hBr@pea8vF0@p{$omx~A`z|J|BzX6}4oc_03N_TId|Z5&A$e*f-I!FJCxl4m4E zhvjq9yS|S&P9ocK;&gr)N~9#ll&BFUUs-?mx2gb;00`>v)ib;5BcVv3P$(1%1)z>R z{(-^3)!)+u1Rop!yIiW4%6k0orAl>W9{>A4KmPX*w<#xppB(r*3hIz7s)g5AxHvifu(|Uc|Jbd4-~Mp2cetO6-`93Oo$sEWeLp?lI^C`vempz; za1uc)6e7+qU{qs2{LhFj-X8>QjJuc*`(Cd%MTGIDbM?k9mG08QiX&M~@xD26j!7zv zi}{Tn4Q@D;$1H~hT3$O5Mb=Q(dTSZpY5^Y^I4H^<8K@U0hQ9v+a z7JV(WSOZB+Sdc|CTf9o3MRU_pu*IL&Ft~C7)C2*5p5%H-MT9Vimf7Mqrjq4lVmGFd zLXY35uI&pfclxIhh!P&B2tBdf!SL>cWgLsx0E)J}K{#YN&(UMcb{ILqJF5G>6xJyaAfOoR{c&CkThkU-fpF<&KJjtNgIz zcHKqhk*E#w&jx6`?Ljc=IeCh(v;N!C($ezM%7XzI{utQsb}YbPfKGv>{;d@TzUNrK zwdkLXWJ~2%rCh1}$`)3b0uM%jFd)GGckAe5x`BV>dDIP<-vDUT?QQ%3wbg6g30Gb2 zeY%l!NHrjVsP%0JIdi>I?B8y%4&(>GtfO$f+P^iTW%XshPO8X%Hv$;#?s{>f1=!>< zAjW!WH4RE3$*wxw#|24y)-Y!Ch-1$maqJ_PVW&(8CPGT-s%p-XM5Z}1mg6!1VG6`T z6u96aeHTzkkE16gQP;4UCK%SXv^c1|CNCRWNIvNcQBwN7IT{Arc7He;BoI`peG@q? zUp{6`y3X{>abr}ekeRRf^EH3I=Ko(`^B)%@;%6KwP(4%_BeZn4eLAQzmf#X>>?ZM> zAs;c{I1+pq2)E_+T<3*wQnsUJWYPj@MDu=3RDSU-zQht)+PIWb`+(;rnJcyYY`4oD29*C-L@KvVP|U_#KR49Z+6giA6@2q zwQUyKz-BJNJMJ!Xm48>HG}621vg}YhrELmHa8cbp-Y=mm<&e9v{~*`mN{6}F0$%9m zdFDxJr9b=3ExdBHC%g5YdMrgZ3zx7I)>(K9?vk8LZ>_nk>tQewDXUM4vP*M)*Wlv) zBf`HFrJq*Z=qW`t^*wgAKRMUjxK(;YuEvSf+(0AYE-&HrF;1gR?#tyUOoB)wF1Mwo z^X^cH27?>5!s{$NLQvZ_hHHq^n)47N8qV7)&f$tv>})xh{#)>rcRPTwIC@_^jCmD9 zbKEFrd36}io&D1Br}AYP`ceH-+`Hs1(+6KpZ*FjG-|w=N;b#Xm(Vvxf zlqwwN2#(8V3h#ksYbPS@`&oF0bwAzRl=1JAD@^H*c+xy0p8Rlsv`u}MaD%?RJNLL- zHggpYA~)?yeOnsWe|y(pyIcQ(*YU!X_;`Ek!oH|iK9xItG;?a5Zgrd8wc+8mv-#zs z+Cx{>rnd(89{HNqc0ee3-6 zeC-4DpHiJiYtt^SMK$J5i{@LhJ2S0uwQHwbrS{ll{jRYSw3(anbnE1JSLKN?U<^*~k4nW5`m^?~ zemlDS+~MiyPr@&sPwsj8@`wg!9L^`z-4NZZnTa#-so*tX3iye+qwm=Jet5av?tLkf zNnQA)y|VEwP{t)15Dd-YoVgDyJ%LNkhY<9QNY zU`t=Rpcj$ra~1T$=JFVNjxIqyuzp>&-HI?7-5OmMg*!KyU6vbV|4K5m1es7fx6$>x zg07tH{^3sX@4`eC&3r#e^sO#sEEEMm&%Tw6|S#wc1*t)YnUy@r)YQNEith?5~+}=`Mhqm{)yM&Mf)yO?b zz&YIh(iQm1JZpBl5Hvd~LLa(~@=1xzW(~NLD~NaFecaw19&`7`!(Gs=5Bxil{o9+t z7nmnw)(vcTtFeCrYXq(_wRld^)Duhs_j zgQHG!mzgFCvmi17`h0R@UsOkEqJ2@`D>?^~<+_bdF%)}V)!~DgtXH}53 zXbQUbp2}=*t+uu|du$${3!=l#u*mG_9`${YRd=G@=1z6Rjpx(IMtKal*2yfE!K!sZ z&YW&ZGItBz^KW2%=>ebJgZyr{J{MPyE1Q~$-BO$P3r(X3mq3fiy+Jd5BNO0@+jt#; zd583pO%K2DIUT#1)pvNk=ApOwL*}8#MC|}gaU&iSrhDW@$V?X<4&$a>i^r^oX1lB} zH`fAZg!vKnVKCk=Yo7Ju|4eQFRfvwn(+$1;zem`ARV$^Xl5YQ1ESBc>U;ml*UmvdB zfp6dC#KSf-#YtLzIahB2Rz$YaitZ6U;%TXGu16=SzFh5KIP7ox9+_AqZOqWb>P-iV zDE44+rh;9Tq`T&};2DER?{>Z65O1Ikf^c~3g+rI_qu7~TKu;8M`UB-9m~7S-+Sl%8 z7?o>zzMIE)1G&(!GYD=d?M$i-TN5*d@XRzVuV?$-y^GgmeKbJnE7jhhp#~lE$pFS! zYDJcA)0=!gqj}v+TG!FgPc*TU7;=n#Tf{X6%Qj4tgH7eEKuiLUb4SKc?rlkCMYPPF221nV6;YzR?vFa)$2?U8RJS=-0wY5?XeTC1H+p zc}I6xO%5THKxj$s^~Ru6J@-bLgtBefGj{J3#Qsp^cz;aqaNQV&g(%%IepCz(8QGOoSmerO*QT)*|*ngTZ;K#VKQNPH(!sgB%P+Es@GCG z+Oj==3T|OSa(tJlg3AOu6m?T`T1S1Af;Wp!x$(p|<+`@m;x-!4?S&Q4%g|~C1GQVR z>SUd|E`9s@RT3&6SjBJOEV3qT*-e*#bV0_!D-5;H@~0@tu|szlHNhcdISL7JBT##* z8FP*X{<@XPs24k3ci0IWc)!1UrhN)K!3|qDxTT+(E1lgc^X1f3qEHa1#P1&_+SCTU zZM@sgCc5QBcib`zC(ZcwSA`asJVSm_0AeJKU13dTe1<%i&79YctuE+{IA!~T;M#Ls zx~xx*CQfFU)bf{@5i$vb*=RAb%tp`As-e=87tSgjVFQ@6^xol(WY8e34Mun1hOmr> zZU&>wv&S>K@5|VOfqmB)wOVAE0b`~B;!TQfJ}jyj^}W8E1(hV56;NY~>W9NEt0;YwZN3D=pAN(x8trAQ0YRmRje#@C)wKDZUNIpMicak z={uknE-q@FG}>URb;Ou8T$sOZ1lVNzEi-Q#i6q8kY=ZqEA@x=rXVFjOZ~D-7hkLy2 z9;iGAE+Qz=sl#4K9bpYL{Gh>w>=ry`zeY70fphmQXPNAP5~#fQy2Mt9j@~4qmd(h_ zmsw0Nx6SMx@~oUBKP1e#O#mf`u-B;zIZIGvJ*L@1lH`oPO!Q8!Jp~sQoVaYF{aBUP z3$YechD3~n+%_ysDxKNja3hc%51@x0lA8fRozg@!sh})-NaVh;_F*YO^AcK`A|jFL zoYe;fg6YcmkpVX$Vz1!no(%9k`~BV6aC%svDw>!f@bqK~dvf2S8s- z-&8139rgg?l~Rpl-<+TAsRuINxcK@Fz8bnU@a2(z83p|HFSr~&%bA25Aw*J-;v8Q&1wQ`iM|Rkqb0d5+dS z!h_*(UOS9k8CZW8;|?#pX=`1TmPTA2EU_~DG&PYCQ#50CilCczaa zA0Y%)rO4<_!`0M6k5Y~DlIVW4IRyS`jD~JDBkXh0R1(xGBasqq$Ld-N&3I|I$4X7; zn@ml0xr|pzlfTnsbl5r%$`r>VhBs9|A5CM%<0dj|6K)KQ6c4D>Juc%SWj&ZM0*SRh z@^8b%SvhFSs$CZn_;fhHZO+}ga>h^)pFu*kVX3rzcwjb!2f@I*2SEpARzZZ+icvlO1u=C@2!)fL41N z9dfutv;CHGJ|q)9CV9ag4((8Aiu*ujyeZoh0kNh0uC@xUBdRdZmJVXf1y!7xGQh*LSTU`@E4#$bYQW7=C3LPy{;#R!kZI(IO4KK z9}c4_vgFsHjBO@oFhhQdakpV23E!{8JQ5CD>NFB?q*;`fT`<8(skYJj0jbCpr*qk3 z0dN+4Z1s3HjZImXZrCl2X~MKSCl2PufLAWi(#^*a%B!1>k1qEyD*H*%{(R}bP}aQI z#7!}Gt6}u3AI`pCzC1;9@aM^9rp@LEHjbGIA+N?O=jEN> z^Ndka-%oV2_PAc$ciyICg1#$fOWQ5RnWL0?v1vB1cXF&O`^DS|uJE2lV05?u zSQp6*X&*lTAFAf=YY~lVS_Z&V;`c+v#NV97kWAFM?1(c8zQ3Ze+G$*!r?+`ert_Z0 z=W*t>(x#SKkY%PqH-RtO+@m(QDZX$$Fnqh=<95LDpe%(KQg*^m#bBIU!^fze$yGtl zyeMZpE8lL*t{G={l50j;9}~q5gY&KOPH{8fawX~3!TMWFWP_73ULGI#NY|?F-odgz zexa;-AnUo@iQF)fSvo}qwKB>0XpAT0%j7es*L3}gctMd_3NI-9FRh1h2165#S-X_& zOq&Z|XfDVuAh>=ooHz{A_{%UfmzEQfds5cVnvx}u+9#J1B{QLv$*{uZ_jk>bq{&BF0XlftFwRU#0qqQaP$+UhcdoiVbX&jc&jS~6L<$UM@A3Eokz;pF|#!Hvc zKFTKDez>h=$4;lMDo;!}oRRDF4()9s87^m>7MY3-^PJ>bPTzT%AYnWH+cqZpA%e;NhXj$K#0ykN= zB;3#ym(y9*w`3P<-ECRct&8u?V}bgB>|%^rjZ1V^v-4Oy)%{5#YxtRgHYM&Vz5CMR zrtp)Bn zRn`51B8#Onj_c?f4;!SNLy#s>lt#<8jV{~lzihM1wr$(CZ5v&-ZQHi1re`K%b`!Ih zh+N(EdyyIWo%FsOLe6plQF*2{f8s8yD`FXJq&tb;}wGpN>n}zeL`wYo{ zz!v2Vlk6{i%{h)m?*u`@1um*w4#`nC)Esi1_~+kJY;s42&e;ZlvdKA4Qhy0V_N$vi z$2v3bq$5&T?RqvBpS_%#vFUG@tV(g!IP+iAL1^hE=a==L*5{UcUv_qXJ2d}k%?}#K z$H#zY%zR`lahrS_JjWW+Zfc2ZwF0vSXW>Gh>33YW5zXOO zFTE?%Z*~`WP8CuX3v0*u$SHjG_!*BK+_#XKh=52Bu`ElakY~r)@a{Tqqon-oV2eDs zE8d#1PVM)YhcHt+hI)AfY4XOFtW&M1b#74aj605957Ig1Zd|T4WaMjgHT?Lcs0Ip2 z`c_Rs+^vV_GjP%A+NbQm%I6QlOxK&jhBUSc-hMd6a&?o@E<)|HN)5_Dw$2ym9C9mCh?iJ4IQQ&>Ofox&5hwKR3M$c`b6>D4}Ha)kXz`8Bkn`D308$`qi1@;dq2Ojz@Utqk< zu{un`p2skb(dsNadF=xsCk99_YTC^Cy~8@Jq`L>w-6Nq%ozR+(=M&z3LZ7$JaK_(L z*5$Uzg=8Hs1dT_)H<##4mP!tAB~TwkPamtER&AwV(T9u(Xd3w{d=}o+HQr^~Z;-R4 zR09B_+{KUjNT(~3Li;CP{G0PSg^)L&+nnL|#Qsox0{T6$Mj;ek?^||HOygwPT)9l8 z(D^cnm%qPA`_rP@2(xF{#urgd5e>0b9<3}xKkRX>I&HkuFw50ffNJw))+%2_e{E!q z-jA?^iQKxS%-y1}t5Ew?a|^gCG%`mX6M>ATHU63pQbTmyuYA@3~b!f7fKJLiKK<5 zuVP>u6uvEg&v)#r<5D#`{)!r|=i7SCR^|73v`8veP30eoy)9fa*kx~W)EDGR?$1QW_mY-nBcM%NbCk);|`3u#PTY$K8rWDja(;#V;f~M{9AD|a1d@z}$f|o$n#db`;nqW+rs1-y> zcG-IBS@1H;RZ>t(0UPNl{`KDFHRy(~VWG#pak{zcr_^dcExC4hZg)ITP0eCfsDJ(XdTh0vZY!VmaVV87a;krOy{iH(OL8u97T)D@Clke5`TGtf^O&+R~ zf)5t}Od8dwcl{J~0?!hTij-Mrd{6(eg=|}Of=meT#LzXhd)p{$3*)-5XDxES+Xm^h z(>>pq8kl7Pqb{u8lgIb;P?_m+;P^%0#H*!h6GT5LbX+usp2GIV5>lr0CVcc%f^$td zzCV08k#?)eS^K6%k&Y6}XWVFfvEKpq^9S5ESYo>>C1WcS>FHVYEi8C0(EfMD;74j< zM<#nPWI%oJ)6?cx=TTt{q$T&H^Nu4ueFs{LwWp)go6r5%&oYog&m(|z=>(5Eg8o#o;i$u$~t8)WOFFaFyY)371w#kQ6G3({)^ds{bO z_wfc9M*5FJjf{H{@-FVGnvFGNS| zLlsoB{&lnu3hZh7RK1|k@eVB6hMqegF+}g@qkWV{Rw?2PH?s!%R0iH_irRM+z?=Ib z8u!LfJi`V39XIKKz}m=0@DuU?g`@+AIHGMysJ_zjQoSJ}s|Y^m(NIJ}Gs^2bYRd;n z0-=$r$1qEaAr=qr^S2;@gagEYMLuoby|ix32ia6H);85RkpSW(lC+`7yE^=f+6jKH z*`g=mpyLJJfXf|AKxH!L0A?SNg%o-;vY3rK5(%i%7y*7 z=7p$}DFKD4ZhYeeghD36uWs`N?EdyqIQ#`vJ?Z0QNBWIFyb_rojH)XD4042(#fLv? zgyU&{n9Ci>oVMr4&KoxH!(&v3rPt=&Lnc8FmWA?6t@-x*909GA_z_GV|IUBXEZ2c8 zitmIs|CZcwa@dOSsLJLAXjeuXA}9f-sajc2EUxM5fT8cTbqVbAcDBU(%=7uv9{v5o za*tj$twXk4hNdR%1#MMFn=RT2i?r{d_oEEw3U9qP`82Y>l=aH6eOcC{M2*(nyAJwo z$Ixti7ozLD2iy;+F1j&xw0E@r0bZ?6*T(hc?bGRT8|=sE*ZaKsn-ox`>0s)O51K&j z=I6(r%U#Ml!``G2jpV%`KBNeHwxVy%^vlb2R^SU3w=LMa{OsoO#gGfSk@u9V>&oA} zjzK5D!g}oEOhN$cQ|hq@k5fy1b=%Dd&tba3?KNx3idb3?=8I{r`?f2;DRJM}$F>hkv3`ucOh{M}2I#0;Uh9Yq9)Rj$Ow z96t2BB45>_d3bO0c6NhpU5FpgfF6p(MIO0mo-+R13oYv+88h{tW@@j=rKi#Ff^bVs z*nYPuk*_1=SYmm_qo49G>yoU~4SmD!>k{lryBaWfBe-dP!;?FQdSQQ5&%!N@ z)?OrxBU4y=tWTqUtQ5F8IGGdURIz<@j9rYYYkZP8z3_g0&dK$KymyzP&E&K#X+;gr zi5{V>&lURnW-uA6e1o(MuR~cmCgLET2Gy(f?(9}jO@ps1#o=g5vlvzSA zYSgV^h}wdbn}AfB8sns8+OZYY|3k9Hybp@(^Oo)4gM0yclBYC_Z45p@5P64kqPFC= z^|bCiOPqfrmOaeQYe?w|$FSWFp_O`fjlBFh%ah#w22`qgv7mm{hh8Oc?=DulKuh4< zofN7{1Zs<7il3oF^G4_qVyV z()qc$H=V1~sxVi*r;iEl32MZz=;x1cmdC&XubQR+X1~3#7dX`Zp-OAg=X-cMT8`jt z9;})%Yad>z%glWi>7sTo$Tgn!j={$7g_t0ULSq(*2~U77I1k*3)}XD67kPxInY(pc z%F!CrB$=9_&*}y~cWCO$uA|S$hfTx>Pp|$VP%Qz?*I(uv!{_974x8KrYC^tkDbs<$ z)^g%uWA~a6)Sc9qLsBt&oBJ=%P8a*P#^+pojJKajzJ(EA6MJ=2gl_=Vx1&9Hx5Ztq z6iu?jKNRAPkNKPBq2?uE8#|<096mZL?12*GT9GvAP9RWy6}LIx%ESsE?u5lS(Zc2i z+L|huh2gvkAyZ>DYkRw=rtt6R#J!j7d4*y28q-I^>zM|#BH4+#=Zidxw2`ynfZUJ( zjmv3y4_lghuumV?>-;#U4C5f!;E{JhEPyv2JUVjwmk->Ymx)v55w6P|55FIVV-R4E! zl3qpX`1HRM9hbkc0DK!C&Z|y9H;miw#10<9Z=wjY0T8z@WCLV%3>K%iR>e{@Uq3sIYPd!@l+eOW#(~tmCsRM5^%5cIdeJo3pQAqD$p|tDN$U`!F zE9tyj?v5yW-#y4|H_ph=_|Pl4r|Lo>)=RKeDAj`BI_LBU}`x`5|hs1 z=vqC)jo}~Mt>#~ul_;?znEJLwutwEMn;hC)jl47ML6rFh%`*~@VQNg$uL`0 z7sZO0_|STar0@V}Yv;na;pX9Iadw;4xjytcUVx6jfQoP_;+`gUKFIXkpTQG8A&$Y*Y1;w--yW{%;?;IN z-@zl_LJoK|-w#!7RnpU^?va7H&-X*F`*)%=WpV<#rI!u`+0Q(}y*AwI2?JtJS*;FW zy>eX(?ZjCTOC=mD5?3NCbE_Npgj4YS5?IX{P&`}N<-(iMKBn`xZhQ^vjM>oGAqA7* z*{k-XL2bGgsh(A02fAMJpkY|8*dlaswvYi?`96==%Bvg4JD$NkXD>^ZuTtm$-2~9^ zEaV{A$w$8;86By}_O3Z4@@Zx23Mf;2U&GHXXS3xq_y0Mayy4a2%HMp>eZA2~#P48e zeZyY=UZ+2$x_N!WacrO?jA%I3>-hNoly|P{V&OJ-6!YwV+u@3RJ;dAN<(?Qb3{TC< zTk##{F^Y~VLu}2Q#L`%HzKgoDv0Q1Vgx_*(|6YdCo)_WH?f!m1dTGfebazi0ifzA5 zH~(U&QI357no%@1Ht+uK*?;eey>qAfqiq;8W=A{juUO{-Qi%yiw{jN}tXuRuu}8!m z_oEOZY~sdcX9CcnjQ;!dtLqlaC13>ekRH(Bd2^)hy-qn`gE2lapHj5BwRgIzdGyn$ z?yQAD0mioKoy-^r@I+L6oE0k%EB*E43CRBO@;G3lf3~>=yKewVSQlD(>7t8sAksgF zbW`#t?t6_6!4tHSEI)|*fKBh&m7r~h$~u51ymZ)bdv}KKkXK`C`JC|Xq0EMmY{cJ% zdO7GQwv6}xa&*5LE=l~jTe&s(ZWRYgs$d`n8lL=7bS_q|NkVz((a_GB`B`}#NkaW2 zmt9%nzQya?VsLm%ha^NKQsC9$Jkzyy#dhTb z)vS;bmesj$JGoVGa%)UH@95C4`^1YGA)n^75vt=1#O6AJ-*EHGHX;Z5wQ$81n|lL) z#`SQqw_4B65D_m$T1}ExI+&>t=5z_v!*O1=RL7yTsS2~dDNfR1hsVvI4i4mWbnN@( z{rK+f`eo|sYHMKuu^G>5)#{ut1$H50Iq!b(uW$M35k#L^*)aoeeQg(e^tcTorD7q7 z`PAuBGFZ2LJ-xi|?%H=|9b^FYPF*s_j_rSfe`}jQFW#1o&)%jFRxGAnt)ZoAE)%lW zo_O-S$lnPu5{9gJ6^PJ=3oVld0-ZFVem%A*htx=_8-IFHG(sy%vgG>s}{hhkYjzkt?6TmSu)2w$r4gGQxV}mc%8M zyKs4R2wlBm0$(F-BJ2GY@#dAWG!7TS)}7HkJO`b(d`Z=n)yexW#emf5h%Uf(jMKL$ z-NQ$~G?U;-k)StS<3R)_?Q1|xiy`MyK}S{M0E|ew2yMPYTJ2~3?g}=sDZi#}5tS-78 zA&a|Aui{w79xJ-g05|L7yHd4~ylgGcKl3*xj6j!e&V^#?R`+!bAZh>p%QC6aiLqZO zwyKis#%Rq!JwTOX97>X^)S1MqSd!)xSZK%4!e)|#+nTMj0$^8O81iq0hByH%)-j+D z|F?o7Z$0TU|ESl9qo2yS*hutCM=3oLjFN66*qK12k2o8hCMjBqo*Ad%9jMAX-ByE5 z*-lTa2f_8zo+Wvq_rTLVNm)P*kxI!0_jXxkJWDN(#ImLDDgHC#SDkrN)8H`cCnYLu z%YhLSIuX9WXnA~Tr3Jr-g3wc{Jt!#zq`;>EPCQES8RKtXL|mUoj*F@pC^7y2kNWM@$MI(*H$PG z(kYl9K6$gf$75Od$Kq?8<)?r8W%u%{o@>ojgZv87=~b!C;ikXJ3!_;rPbv?QZt#;( zg(+Rd6KPY;DJJpjMAydyvFf*uxT>f(t}tdU4qkI+O-y@$?& z7Qa@!KGX}m7@*WvK^j~a>m6OKR>_Gk%}OB<+VAb=1}haI|9eH{-f<8k&qGAagM#kl zr@37)NfqfloBUpD9W-@~rO3gk2>h{q!p1Sk6jAR<0L3fEcHLS%6aenn-tGXQ#ajBj z%25S%TO*yZF-Mx(0>f8$bTXv9t*Oi?Zr=PThiLfF7YB5ud!6yI^tZP!nmuoe&?vUA zO6cd=Z{bc38DDDOeW0!BSz_Mok~5U))|DHSRFn(UyMePb>KODX$?|sMQeD-@ffezt z8dgrGt9L6CkC1ObPrgnAVnTV&Y*P~0S$%(4`y81ys$<~@A!c5q8fLE@5@+u%?2n>D zs^PY!E90Y9N@rHgeZk%k?eVyqAx)L|B&q`O89G{|%E77UCxkutQ5(?#gQP^Zc!`Xv z71|FRstD=|&y={mqTrMG-ZZup^`qOI)rGnHJh-j&=ntLEozjADWtHhD3&F$611tIf z3o8cGh0;a@5H`-gl7>W$xzfaKwP_Ed^A{#Y5^NUUYOexC&Kz~=WH*%86TXGjM}b%C zHBQlk7t;ulse=;jUSJYEqD-JDP)!38yxx1kUT5W86)|39RUb*m?H*YlSyb1O{-MnvehE#UXc69r)Ro~ z??RIW_<<<*8Q7gIV%6ZN?7bnBUXGGJ)ZgNfQ2|w}CzOn(+mExdCf?&$ai^p;Xsmi~ z5KK|kK5zu~;CmNs7n0HBB6UT8lL zR=mDr2@sB4n&M0{Bgcl4(3z_Wg84k&K5u*VwyBT(^+}O(Km7*&(9@j@8&=SO0yE)0miGSlHWB{2BqFdE&sTO$kEG z^>r(wjWEj0ThpQw%r}FGl+!gtpB0ngzfP|p3Bze49#70HWdUy8Q4e;LzD2~5qh|I$ z{Pe)}`2?LZ*}Va`VF^HW0R}@u!>wJc2Qh5oroAokyW)P{rRKZr?H;1u)e}C>W_2@i zt?Y4C;Ko1!^Sg8Y%7v#~CIBnU`5!`Fr~tp~e8yyVpy+eTyj|-0{_s9H2|cQkZ45?O zdv1JP!_nOMX{`Fw3Jf&V?NdE(KY>9gUo&;J|x1k?o}bBD)4El52KI$2o61 zI{Ztipz|Gy3CMBveMV!;^B_BGr*RtR2!so#S2?zt27Prh`;@f|3oONwdw2TlV9N01 z@Q7fJy(n*SI#c6)y`E`qx}25y4EK6#G! ztcmA9sA=v7-TMi#GeN3mvP1Fx?WChixqdB%X=sIls|uyk<-`fu4nt!i2xfO$?)-zzi@$NN-OtJjOm!3fmi@pASmQWXpRPMvq{ z)`Vx>63h?{z<9bb^4VEAjw7IZ3#`kftI6MV%bgpZ4s%av$K^K8wM#4HjUC;16?kR_ z3t`);k`83IoT%Or4|}l!p~4Ep7z=qF{qwTFWbNX}yLG5;)hq^r7%6QtWwUQUbp*E) zAMVR``9KeYvbN!jOm!Evms*}(A*{J^Q!id!cb9dbR)cv{PF z065Ul!erWX18Fy{bHTo;$2sDau@`<*TMaT;_y*zS{g@<=(s- z4@PwnF336&J|Um~x>0or2zV*|yy)j}sbV8|*O!9yURB)N$Ax&Vb6(b88GG%#2(4KT z!Q&Hcy2IqQGGxDzRIuIfd+;#4vEv~G z(6nc>+WAD43KFCtxWOF|slT!~{^`eTvfE8-tb@u_E~FV{iuY*50Vb{adUJJY{fVAt z(q7}qh+#pMT?j@syK=UfTtKkO#o7|* za-?{iNa@79ij`+?AfrnVJ;!E*maEv(ZEcXw{iYswT3(6!DNLWH9hYsw3tAZw=) zcuh!uuv-O{J7S}#s#fVRYAjjv3I|TW>X0NAxBk1y%=|TC#e{VxLOj1BGnefAY^`6NqmKc zr>YgLX}Gmn-;mmTPBUbhWv+_WEi&6%MQfJy6V@o9pt`R%tW}L;lyPm1nbAG2tJy;* zu`=1S(mEPBBEg+^V9KP0YF1oIrGT6=3;E147cj!c$R%YRx|ghd|7X z{Zv`FxRP&BWE6)q=CAEkDQRX!dIb>7@MML9tTOX8bGA z86*zwHXTCOHdr=W3O}-XTVo~geful>tu#>HbWXgxS!95A6vM>6(m8UeGjJGNj zZw%7UvSC7mxSOc^-A|Bx&H0Y@SE=WO?3Y|Mj$w%oNMHk#mAbr=O*wW?ltb}3+vXhq zz!R6zC3S-Xlt76 zSojxcu)1)Ry0Aw)m}2mSjJ5Q7@seyzWLRR#1Yy#ORD_?HBh7QB@wyQ;i`Vj%swL{g z_83oPK{cqSdGk|@)?4f<#*gAlDHc+jN!*vHubU>LU6`eyhHe>1w@_$HWKD!lJH#8% zwUA6fr00R3p0wq1Gk~Xq-X`9nWN$J46inFZXrHiK8{J?`A$UyW7OG&}GQ5(hAH`uC zJi-!FPS6D?=;%Qk$bAYT-a@ECy+->gv}O1$YYQ?PM70s~L&5fGpouC*2M4_=W$XQ@ zg;k~cB)@JMeFs0#>jRmveoAV{*uyex{ko*d3049%SgiVKV0KH$s$X`WWDL|+jM&rI z-LzNElPg>v%eFzrW z2Xfr9XCI@cxEXC^0r+3$3ejbR{$rsI9ItQkyPQa$`iTlsh{jeL-ODMXzbO!mYmft2 zsw?BN3Xh@W68@A?emIUs+4ro0YZNTCak>p?M#k9Y`7jM>C?LVoCwm) z8cl83qCp9uZT{Zr_Idt$iG|uT{PBmZNLC;5%~II3!s{iT8VB9{zE%J*N+q6YG0qWi zRBy5Jy0P|_bLKB~4I$OI5JRN|qXUT%6SMQlG#;p-e=S5&~ z@!N38te7=xAk$fm;08kxnI}f9QQwo=tx8pXyp09C^dfp(_)V2*ht&KUIoP8ZX#(j6V{Xn8jQsJH3xik>g%QGdlulH zlmelKtZd4rht!v)ozfJKsc5smnU2mMU>$r?Jt>x4gd-uDB_e}gEKd} zaMAgdABtEGX*15p^C;pT*%~atsX0;DLWwbNtT0ysO|zKIsL?cUnn!?A zb)1k&6q`Cc6}|X;CH9P(9>PB@!KpQ!tws6v_@{ARSjw?U(_7i3E`?KKQq`WWt|~%Q za)PG;6s55&zBU|S-khb%lJGlA&<{&FC=CSw|D+EaImrWXqjD+x8gpk>! zTB3JmeF93Pp^9>|8h)e7i9diK^iB=rEWXw44+f=C$+O#R6NhaTzP<{Y2Iz|}$*TzP zFlAo(mdTwqYU^AdKWw54e$y0aJ;R|m+nA1@8|&jQ>boE} zHt0zi1_&nsjn#u>@Z zaOuN)Ghwkq?bWqlEc)s`#_%AoEXSscwLtpxY?@nmF zf;-<^xZTHpC=I~3X^L*cyn{t}BMa>eDez2x2M3Dd;gvG3=(Z@tAK)AcxNemvR|kiy zoZc3?P_)LLZP^+)jVJc2W1{`7gjW^gX{oK`BmuVI2wtYL`_Tta0Q0Ed86p&;(MCUT ziP%}g(>9^*(kStq=7td0h{GEKJb)|r%-VYh)LY)g{%K~Y6PD$C^2=-Xt#ccF@xo2$ z-2}AmxojnP?0|&mlrjk${{1^`Hzf*!5d<%nV%8U`vzuoLOK*%X^*xJQxWj2*m`4zV z$Dg@PEKMAZmKC1Mg;JDaXjnIIlL^+y*qRNU85=r4rp$>5h%3@KW=x&8hW6}{2#qO$ zayf$=#exq?2r+0+CDTkIe;mCJ{Vs=khS|#G)Yd-d^v15{^kxume#g*F>Iywm_gyo? z`dy0s<*}6$71iyREt&p$xJ?9C<|W##Spiwb%>0IJBf>zso&^R=PV2ARZ2C>wDN2nB zbbW^Xt;pD4d8L>(3t3whg?o)q%$C(szs!VUSw3dWB=jJ6sFP5 zi;_n`Me@N6>~gl*LvFZ~9cspbqFywV>^|YWJPXlCAz@G5Ski+Ca`oVtdOg{|-I<_uBOdc+^q@HMRo1+%iF2xtsOevvZaV3Df;3bna&ZtPnL z9*NJv_K+?P{Be(O?4WU6p$GoP>vZ^uanxeZKUt#br(3-jzRA*4CYk+G@hSH_Ec|E7 z9A2zj869-a@Q|R#HarSTj?GdDa_r@dMbUr#8AkxR;PeO%Bla17IYmT`&-gYIAJh0XmnH;Ic|(jo zJ2c-b?-u>W(Ni6#N!~w557d6RaFvS1W+)lSIQ`qC5$*ZIxhpNf2Bb@e8TpL52JCFT zP*#l*NfS*GVDb@%nXzc~`{5JL)F47k5^`08=R(=ggAtWm&cF9Ce>yQkV3~A}xBIop zYz9U|AR9Y$2F9%4V_L3fk8)ZNO78ihowM?HbgEUw}G5lY#^Fq!M!SS zAu+#{K6W$odJMjZE`F2cWb9T+wXN8|_=*chT>B^`C35I|orP6T=d8l-OYsc5cjoW< z)MkGb&2}zDqlwxZL8OsY$vvYKzQW(D!Xqoka%i|VCREBs zX=4-r#(2^{KFpD`YktLJk|v+*Y*izPoPW~(wkWBz!pb3K!N+~tIJ3_eL5*QpLE=oX z1W00r#inVM_uGm>h@(2iVpy=)J4R3gI)-Z|0Qz+|Pov${dyrF=*id~_H>pL^52s6Y z6(4*_q(1@UA){@X6uN%SlTFmvcVtmlvthQ(lJl8>4sl#l>@WrsFv(U2=E*ZWk%tm@526?bA;1rf3vX*@pO;QPF5G;-vvaejXJk)IOaJfjyO(JxDo@p2 zm|fKG8(^ZpM^8u&^GcC~E+$ao$C-WbnN|v>&V4b}YNl0Vms*4e8J}JRCPr#qo<6T% zmwGQ>*Du*yT~iMSEEm;FjUKxZ4e7$|aNJ%NMC>y&yk2~~n|x_-Wb_sw zP9D$sE$uxYUt8Cy;c-O`qVhKgd_H_zRX4H_q>?28|5;+ef{#TTu2*vfoU@jj57Kfc z)xvhJKt@BO1Eb`6_i@obZE}S_8QMCT#LerewmJ)g^0c488)GjycZEn{+B~IH-c*50 zPQ80O7<@Iy7zV>jD>`bp`usYgd2uqZ|KLb@!Xc_{CfuZ&_ibxdY|x$25HN1x1S-fg zMG7Mswb<}A%Z9N_+YbvRIZ9ymfu_`JL?Wp0M;opILTuiXUDUVy8e z#=C9GORY}rjXr~e?oO7qw`t_W;BX2w6pK^~`tG)D0-M#6a>`{YPSLd*>U!QLtXxHV z>DI~?adq8=$lKd-H-(xfqqofEml**=nO_zzC5F>1F{4LQ(V-`$$uLYq3enSIP0OQ+ zNijrJm7>FYWX>+sz*m6nbxx^WRVN#p!&bHSXs##guVbOlwrBjI0pfSV)c8T4p-a-} zH4wz1ucBRBqN1kB4erfZneFdL%J0#Y`G*w~0R74B3D8Z;>_& zC~Ejm|GL_?eOm5jkOQ$Dqrg-Q_S4|ug3c$5@Nl{9*HdkY+=~B+nn+&Zv-MYe;y>9` zYxXNrbCs8Rt`3|y-(g78iUQ00$J3gy_+uF>Nlz3mvh9i~GGMN7oBvVK+;6)^4o#JV zQk6I17Mg5sphzWcsrVHrDR@u4SF0)X-ZZPbhnkatJbfv21=_?KVhiF@HO5+cB;hOL zmyyGn!~KRq{>{_Y&K%Uu*>jl&m=?PEN^!-zQ0MRXa;_Wgk;Xq~ z@vm7^M(LDLZ~iLcr&UTu@k5ipPW5H--J|Cw4hg8ag*I_F<$PLEbEaozh0u1_E?sfu zy_oAH9@Uif3^PUBcC7QwsRJ3Pu-7?%Dyjm{^WFp&p5@jeDp+%0)!e%pupa;{J3d8rFzb;-XsK8& z@|2(rLxk}iDq129=J}1+>VIJd!wG};so|ite`K^Hf|ppkJZNV+Jz7cQ-+L-`1#f?DF3{=a z&bmtI|*Xc5?!>6<=Tf!;>fh`=)?Alq3` zu5Z1{ zboJlYob&T3hJ5-6(%!Ei#x8AK`JVlK>3-hqZw^9DiSby8`$VIi!ev7O1mQXZpp@4d zL@#F8vBr%d>){XsmA;{|p$?&XIUXZWWWZ!&oxeGnblROvCk^iJ0LR2)kJS7bw6~mW z-iL9X+mxYIvJ-YZPGoFP9A>$@i9H~637hCIG10An9aGOjny*h7oRQOix?AT_%fZ!| z!G^eaw@^4;!@BZK?V@b@*Q>O7?baQL(<~V;vasI^Nk1&P2a`;znCp#Poi5^eyu6Ba zlfJ>cK++goDrS--8#`H)MUXDR$-~@wILSeBm5fc4S(0ZwX3(ERJ{(!xVPvhqtmR>3 zF8`+KY8_3|-EwY#Wa|~VWjq9W<2#WSz2x zCec*g{TshP*x>w&T1$>o6 ziP05FcPM(qsLvb*js-3S zk2sF13FqjkrNtshSy1Kxu~`$zYzA{04C0FQD;u0gIvSh9`c^{Hhu8+q75J2b*&5Ht zIT+ELTN=UU*uH2gDs}x^zT#R?Oq}fItB>*~W@RC^`>1|yGXr2|Y=7A5YWL}!k4+x% zud{=X;s(2Bvm<-AgyOR14}P}#AKmhB)Tz}*Oo?%m^XQ^|FX!T4JJM%J-Snd(d0;cKw=%NcyPz+7*P+I|Kt6VU zv5YVNdgVQgIT}c?@ktcGXomu%q=jD4bCH`(>1aA)wM>p9utqV7k2ub8%nX$#MO3f` z{5j`aWpJ%y6L)g1`O=Uyv4Ozcrq9r$gb(cr+iWF`&sWWl`S@x|F98B8 z1U`@Nf|!zFc3y4@0<>E<>>veb*7S|HVi{*pK)4VX z?7fDnD56JHBvUxAUWuXMfA;?M5|)qkFV=Z2H4TDs)a5`rY8E|y- zlE)3Bs(~)QI+r-xOD4sStO4_X8t*w{q>(<6)6y$jy*mdx(-k^h$w}fyKzV`L!~708 za}1qMFtNuk?Sd7|Uy+__X|u5wHP%z%Qb-WalOmu{?mlYoF1&`7#uT(y;&ct1Ly9#g z$o=KOBYBn`^HvVq)OF@p<-B%Wj6FA(s2E^~ajOS+tk5?~@jAze7^u+bcpXj5F3PL# zLsUgs$d!27HiPoPNXiHE!OJw77L|oJxnSRl%mz1-L7V5aS8&h}$Wr&fikaxh(hkLV#Kz@e`cCP%j(>kx`H-$Q56&Qw*R7oqvtcS^+r+1Wa` z|5Zn2B`Wlzvg1FG;(4VQ4cE?@zmDNU`qPb>Uv;vflGR#91g!cw+(BKYBSjrtw z98!V}nF%+gdMg;Zk3=fd;Anu_WPOy>nD{;^g0%2km76$T=IA44?0I}rxy2=k)Qe`< z9?>mqXWrZXbZ~w)SnpN(MdnotIkNQ+ld#m(Z)^qTDWi)H$u9NUk;09?xHH%;QBBKO zQw0g1qKP@xq2^R8w_<^@3GyrEtrRYmX2;}%LJlJQ$a9aNXhcM0v*@6yU3oXp+q0Gv zhymR#EWPWjpnCWXqi+*KN8B=xF}SI1m}^iK(p*mZkALaQfYp^I{mNv4fvK!g8>xr( z_lMPR5{Rk`mDBx0BBCJ9fv5VBikYBi<%_0m)aN_vshyK*5ZsTUMI1@4W z*9Z`KJ3k2x=lcNFrOqVa2%Z#e>|HDvQR~tO3=vU9g^QIta_K5nqSlf#bd3gwx;iST z41)ADdqXl;5Q-Sg%tqHs-)}Ju!NRG=79sa){HEp0gT||jkK11_XQG|Wu+BxEIpKCk zZR$9PlvH0Dy`+!um^<@3x0(N-ja@@Lc}szJ@SS~YEUyUPUd;L_|CfE_Z9$Gb@Xzp> zXFA>uxARHWHt=`c-(%0%ZZK0h7!Dcp5m!_Uc|lb<{jP5mUg#6-E@^!9ojL(}GO%Ab zsIU)8gFTGyBDFG+d_Hl?z^{Ut?rxRvbd^G(Bx)xV9eW8dhn~QZ*5Y_^>a9LYE|y>YuxqQY*593K@d@Ov`j%!dS# zBgGd)(Z=SV9gum?(Y`Nq>A;^rsO8o~6p#^{?y>X-9TN^FLZZ>V2Pmh}U{zG@f+4-S zhqf7n1LH?p-P>PP`@R+-ziF2^@tZZa>246qVI#S>*bc!fKPxT~^@V+tk9f@i3s0DR zjS0VqVN-f@)LtP?!s@+SPgWV(dwvf7-K>Siy6KXIaMoo^k|cGxeN_kUA+!Mfp!|`! z$n`9K#>+=i3vG1D7-4HW<%FSM_JOq=q{)XlE5&n%}lCR9xi>F%1X>E>C zjM4sWipk1Rn_4PMd#Bb|bmI^3=Rwy_^8GT`cIPRfx}7)_f4Kh_@V6{ixPBM_r#x2G zelqiz(%sg=ZVK1|9tTno-s_6{hdAIa^;AqYNM*N!jT_z1-UJdvk2fM{J=!yu%z#TA-T4DQj(+a z8$uUMo8la2wXCS0y2WT7z#Msc_ChZJ+j~!PD8SP3)xFh{a{U67kb?C|>`t;b(k-Jz_9g>aYcD*hb!`1SL=$|6(TVmWCXH)3>_P!7WS}V=Ls) zy{ilKz=U5m^60%EhdB_BYBFY@qbp~^-lJMaX2F2E;c`2xZ8EyHYzmhC#Viy&7A#VV zwjHD90#lNJaH|-FjBYVDB~Dn>Jgv_SksrKC@TTj9ZkyiK&5P<`Eo@xCzm4zS1}(`q ze!og38$~`P71xQNQOH?B`)Sbr?ET(1xpnYYB9_{pn#A}6&dwWS8w-g( zik*Ad9aQp@BC1O`g!)8q(bDZUm@=<`_F?5w1^z(bfPxEzZ<38wRG~MBAUPbrE;he! z59@ujou!*|b-iAU6@+6JEFcUXa}pTl6sky%ST~A*BsR8*ff(Sbe(V zgVh1-s5$ya=2k9)Tz(i#AqD6<;tkVRgM%?SOxpZhk+RbtI=j8&e1BaI1@qli#u?{U zi`P`)Guj+sW_i8;X0bXF_5EM+>Xq-8$@b=hbWfChcdcRb&MaYHw>l%z1)>)vcym|* zT({%sn@>$w_uoWUa4NQio>;aVOs@R1$xVK0&r?$SH5Nw@-x#*$(s%e>|LD=^TU{d- z%r^*GIwlYo5xGsb1`Y!HR`mju5}Q>Q?kTjT>d0sr`V}xv*46J|z>F*^M%er`&dtH2 zrVJIXb)^nfN_DC}ui;AuP`nrb(G|_DbDKSUPrp0pM{I!D&YoC&;x(GKo8hp;+d#IY z%|ck`UhBm07NugHW~bH-DjRGW3r*jDvR2ghTQPv5ZC!f1@^$@b1t>|k<$b=J(jU#+ zh11oYS>NmF^4G-424yk`WcF;K8A!>@CXxor-h5Y{*5nduz`_C0HdHRh$1!u*Sz0pO+TmVqmoc%kQ3qQdDfc5dtQy{bAU&B^q*ZM1_p`&ok;MXDjM6cO zjIAyNz>v_t#&G;pV=-iX9l=da@dr;0{Z6$;E_Y#*JU5I5+}h}=r3^fQ*Pj^40-W8{ zGGsKjCztc7F!W{ri=H=_f11oKYAb`h!HXH;*s2j~$8#ThpVBJXf(ffJsE$alD>4z$ ziFyqTwNfFS`C474Pg*b-+~xmiHm~V0Y1atwg95d4*>EQ4;gbDytWKCg)X!Xi6za5U zY!DB|ceaqv(ezj0uDj10jDJYZVQ9(Sk!Z}77cZGc&WLOy$DE zpfhS*nPYYe?CWvetLK7h;6R0Rhlh-1>>Y0>R_WcKF&H-bL_E8;1*dIk#@c5ToDMc`CCR42@#12n_(?t@wM^6 zL$Ai%^}*0W@Z-|~`B@f3St<%?!aS4IrNm=@@M_o)6Gi&72N>k!X9BVjocIc(hUf%i z%TW!QAXO%9&L9lvf+MVVp(OfwdC9Y{7h$f^DHe{x)!2yVJ~y=u(spZnB!fqT9wNu> zB&^uHl__a?NxT4qc^?#m5o}Syfa{<;(Qml`KD0hs3q&!FT-Sgl)EfoHdpY?xC+p0Z z?7MMjI>s5RL^C~WvIDnoiw0lo6albUL`CB`=1XGn=rq?*aVN;j2T+jKu=PV3HZ#p2 zrE#O(t3k}xT{r01=kScYp}N*G(A#+*aFhW=!-hPs8G5x%zI9``yYEVCTvfHm96jrY zCk*1|DM~FyedKvV3FNY$bQsYV`DBBr+irv)DzoNb3{#ieHxAly18G$f4^PBrxy80bAFi3)a_)MhxiTaG&dOt&|T$l<5^{3I8c zk6oksMWFN;T-()2Dl^1~54eF&F6K+OtE4#68w)sH>CXNMrx$Nb?=dSs6KoD?hGN1S zW%DDX7@7&5nA*st*vKa#J7Tp{H|db_+QKP27K;W-x>(q^>}{TlhVx&1P*EbBI}4d2 zVYqaQ)^VjcACti`68g2Fg6%7lL}wz+FGTss@2mDn3>Y*LT*dzhgNOCgZ58t_Qq*L! zcQ5sCtq5me55B3xw5-^d3hkp+g&!3D4l1VCcPEQlLAU-Nm`DcLfU1qYRd&J;z0*A?HgD5XV6K`t>wSZUt2So@tr=C zk4=@0KR&#&G;bUr`FS+{`Zl?>zkho;TfcIQ)N*Rxnc8H%lm2iRn`v)-kh@XMqo0X9 zRf`NP4)l#eRkUU55Wp5Oboo{lSkoJ=WnIOY&0jPDLHnnLQrh!3S|{-;j;*JO;21Ly zytCI=&viY!EJjfhq@_t)lX??RpB)%#aVTpD#;^-~{VPO!lR`5kXL#x@GV;x2zN_TQ zA4e*`d(uSdttpXr+{v{rcoI5e^7)FEP8M%4uM3?>x-sw^+PnA(l1uM4e`1~c5cA?R zz?kTmn07L-V?kaqB=eXN4r(e%K?JoD>cQI*c}RP4*yrwS8A0`3Yx@p(q|6OC=0hMw z;f6gTqe(3RU_3*iaaRSp8O(VB>Uu7s^OWCH6ah!a5COo@K1Eb zy)!$fRo9q>*!;nFCi5u&x1aKl&6m-K!HMII9cE7ZdJ;inH0=(*@JKRKiu!bC}Kp7czg2Qpinp+>0VG13sB5}7<{K_QvaP>&v_#i zXH|-uWc~$aoyX6BHj55C&!iwfb>wQ=Mxex&vWc3o`eD}W?xyg-3dZvkJ?lXB+mYZGRc)sZ1>I(ThzAkNw(;NS1GYGwUTKr^*R6!$1kLJZu!~B9%i9#$kCK>dgct%l5XR{5wmtYBuPK%np_O(jdy>a7bnAV?vA|o)o zS~YHI0^JE^7L^bx(|6O}K{3L4!Id^rgI*)l&#+~v5~;YK2yYE7;H-=0LtwCfMW;p} zEa`rr5mn@o%OxeMRn_PbAy?IWLEifu6;1u%&47BYMB|}frHYkUctP)ida|AML&y*w5A05EjQpoNsdckw5UJCWc z`7x*Ge5eST8a?`C z!2#*p11ZGv`Y__g90VL{0uBR^z$h7q6ypI!P2zDyB~kGpnZME0l-=zr8oGGIJZZ6w zL$mZlS-OM#=@TTpwN=&vCFjNA@u&|aLycZg~P8G*~e%S;GmCPWo0v#16S z%i~w|ol0O#`oO9LCrEl^*LMmb?2iI(GJxdfS`0&rAL^GnL8PAh2>IQ;znT%`*{&d@+0p68(fm`EI^lT~EKs6DQ;SR=<9s9f)(swMRK5wcIl&E2K{+rvP(|jXLfyS%$z`{Y zRtVuyLj*`EbJ|RR;{tH-sn^uAI#n2;Y{#skGBxGKWIvZIF#Y{x&FPU=O<-dPw?&A& z!v_bJzx&-_jR1U>j`P*L4sZyqfHmFgJ461`s8Lr>UG;nkZczf)LQyCenw`!<<`KBcPY5x8qyGSqQQ{4&q~{M)CIVCL0}v|wc?zH$0^_STkY0FGTO|Sd1y=n+@3r~% zoUWsKKuIv{x#WzyTZyt$$i9w%N+} z3hT@LcdE_nv1Z4oihcKD`hObEtI4y<%6{-Pz)pb3=hD`Nx80n_@jSr(8PJc|e*CUj zM=k7ndUfL%E=ObDD&uGULcLKPH?)$GU`z+?Yuo`Zn%h<#iZb+N8L?r)FedVrq?L`k zU_BY-k8&4gQyrl!WXFw8YogIkwrij^9K|`%Y=}&Vg+ztnAj8@>j0d}0xo!!^Jx1am z0I73K%(Hm9Pk$%-(mxW~4QO(!*gYmqiS~_usE^QznwmmW-e@d5J1Xqan#1ufNeo$7 zs0&@~x-oCCN1=zE*K`ah@^*~4^>i9wI7N$@fWR_YK}Ly6f_ktqkpOsMp79sMoY?90 zwKfH!-;IRHW=45};kRR;mhajfYvv%r&NB5iUC1&W6&gOueCkqd{+XP(^U=h#-k#u~ zd9)G>0|3IcPE$Wj7w!^7^YqX|>zmf=a6e1c%EvQ0GSF1BsMtQzaWIa$7qO8*q5RD> z0KR13Iot)EqbSJs0Oak@+vPw#Jjn~@K%;dR$@!`I+K|c5lw=`IBx3Spq@;k($ya7_ z&7qXWc_jE4!)C+OAK{~ zwGDgJA<@)=3;om(CE#M2|p``c7D zkh`=Yla{CdZ#`>`o%(dz(}|MvaZ0|DYu)Y)>t4G*!@AWG#=Yurign}P8OHryzw0gI zb#!#TUG3R%+|<2Jl-09F+dp2uiIFGaQOONZGo)x0fyae&0~&mTN2cU2k4*l2_8T|+0 z2QHV178|7;rpv0o9~Q%}5Iz4k`?Q{89wmrVq>RTV;$VKRY8Ox}*_00o5i+|la#u5_ zBrpwl>+Q|`ybV>1XtabHF}`=@70tZFl;TN%dz)c{y&2}Vzy86w!fw{Td3q?Rkn%&iVxW!acG5`0Wm`9Bf0U1={%0SZ8Qph(PSh;+3Fjhf# z^Ximwv1hG0p0P73NL3=$KJ}4eWhv_&q=W(tCog_~tF>6?N?@_;U0li6tuW&;DqF7w zd>7a16+kb-+qtTt+g$Mcdc0*3qa6G^7AK*LY8_78r1C_xmyVZDvrz7Mbmf1 zQ~wVg_!6Rh-@H!8QLc1C(+AxIsQ2uy`BNW;kL~2in(zn|$ek)-&=rQHEC$E}6RN&6 zfl(%d0AL_K)cyOX7>y~B@HoAN-~zeOBi*v&+zFt7rkNJe&*7j&NIn5u*0>s3LTgOR zGPV}R5L2;1Eu1r44H=?$!~MZ~G&(f#=+J^rJ6GZ(Tu+zsCrAJTgIL_qX%=xCEec#K zHQkmj)Vpf}}z)5yjv_KZC|9gyi@90g)dCp_| zrgSbT{Y{902c0T7V$Q7d)6k_J?h=D)ht{)m8!XScoCysMvA@Stm6TIS3@Ei8p zu|Uo6whg)?+kKY%U@q45(`)%-#pf-X8m!3K$7*<#gkTaM*A)8UQYjSz`FdYl$=5hZ zHlr;QwO}Ne(5~ij*#~q_ z1{;lOXoetJSh+2aefmrM%G000fk3C;%c151_{CB9CPC&B#7KscZ`vr&wGA8Y)ZemC z5bq6-Fv$>#rkrH12peuOWlQ(cO?qGzHxqCRLb>npa45@Ic?`f`;|Kl46d&2qJWfi) zjfkBn;J6k&{^*h9?0AWN#YBX@;uXXg7RgMz`F4;5VHef*kUZdjtSc%&gRZ)9s0kb& zF62??5W+YB7KHA6DQHf-#DNJIYyaxL!-uyMURsj{l^qoFc%-mz)o@ck=7@^8pp0DE zPZ4Wa`RV&xjXS`fQM-M8qj_T<0{`&wfexU|y?2Fgp7UINbjT_QsI%drpO$dVHxlcU zfL@E+CXh1Wt!+8-acAong;d?Cy0{gJNf z>@(KoYSaS!i~GyxcmH3Pf75f|Heb)Hj$=kx>UX+cPnJuQvhOfJEpC~v z-G}boTn%zPx<+dnJnb(ZYZ^JNL2q)WAxAnB+01RfdpB}aM?zaYu~AlcPO8 ziToqSJi47gm@zY5J{5ZmEUtUHbt-#4np;2p@K46%MEF~`Z*Sw}-nf76eE2{9=I!6U z6m5p>;DNa_<+>MUZ;mo?)9ouX16Z63GvO6;;)zE#FPN1>oIb`FAo|FAEy^^crQgOOLm?x|8uB!oJ+#s|1SL`l z4CN%~S;4C|vgP&?R;;uW zYN-4B=uyo1-7?9xwRr<(V_#x>IQj(x!Q*0xaDmpR4i~WpfbkV~+Pj(6w}Su+?(yka z+UyVocJgAHqn^F#edcO3YjZmsrtc)=>XTZ?HR=swhh=hDtjHk$z$$i=G;0go@j%6vXE*4o&LQdAgcV-8z-=7O+%EGHlin6?r&{%xkO z6Otv$%ne6j?dH)LJS8?@4x^WhC=!#w15scxsZAd<;p5y7XGeI)Xx_G&9ag0I{r9n- zz^L3!P!fG64LmO6sw6;a@Q6dv+ia33mZ~^Hr2h@2R2pAFLpn-Lk!!W1y0`bWkl_gE zUW?LEz*Sawu!D1i>}lR7FN*$jd6IzwwvUaXC>e;A4eCK zKO!Fq!>w^2j^Men{0UO(k5=;oN-&ZeY13DYxsT>86M7c|Adm5_zNn4uqUC^3fpA{> zH*JHVjFM$$~`2G@s2c&P#Kq3z{;P^>K7*gC4YnP7P22h4Q0 zBA*)|lT|QU&hzo|jroap#xtGrZ!NR`Ny8<{i)`4hWwf?q*plQ=|ht`dv=ZPR81$1KjNO+ z_d(V9VPy$DY)qhg>o#N{Ct3`5etolPu@6CW2NHsy(F#)ro19+WTci0&P;%x|&wEB> zsmEgGQ{YHJlni|$_@q9Pl%~j~3Nw~@CQ3s;4@&P1*&t7X#d4HgI-k$u<@VWl0^Buf z00{2hO+y zY5THpZ94tFe)E)IE6eDQ@Fiuc;yHUr9apY^4?eEkFzEqL(1PBHHwt6agwK1=2`YXW zM&-|^NL_oAo3cT`%3C}1mjZW>uJ?3mk%cX~evPO{pCS=a_9In<2h@KpfV19 zcucSH)jaPyMYrP=1)R(l?b>aSnX4yP`yr9h@_hZ^NQFn^#5#mAkJaUJ>vnMQ<9a>F zGWPt8wZ4Nswo=!kyb-ZzwPC^YTJ-Nz82}_rk#~Ntg5xsTP}v@fT#|3K;O~hdw5qJEA4XGq0w%wm=%}DSNE0S9+*foQ{1Jg=;0APt ztKE2JW3MqxU@Du%nR0-vhH)LPVgyy@NyuIW0>->HDvK|FAf4&zfXRr6>qeR6jU@;R zJ?ST&+UtTH6ZG{ZS(Zs2vfNbbDTG9)6AhGyFXfqQf>MPVy&fO=9a=XFoRICE)X}8wO;qclpDJN3-Gi zRI>iqw^xltBdAUq*|rvOdA|j*SZ{4pSnTTV90NF-;=y9Lu0VyP`+ZIio1M>V^LHZW z*9#pQ{Q4<)t9yjs@6QSxE5L3@jq#4E)d`hJ{rF3x>35H&X&j~7fL`MKU#T%y9snaf zF`X+OJaKiOu>hzONhDo4GKQjDo{r8=D|qqXUl79t*xZu47zPG0-6^((4E3O3=EU%uz%`4#c1_}u6Fyt@HSsC!Zwl`mrwUT0+#)K3H} zr*PwT2DX+F?wwQ9)JJI8;2ND@>Kt5A>9Xp0W#h_RZ{=({NC@8zLd=K_ZnR_=O z?i`3|i&b8M;~dp3jBqC?4)ITP_1Gb*zqcWQQ&+OM7W~5nm6mL&6Al+fpcs7 z^V&Pwa4GOD{dcfsWw$rEM+@Fcc*C(_63h0uLz1U@Lv2wmG+>8e(G5YpL}Jz7jhNbO zP(AK>FJ)GN)#|iS*+4Q?=f}qNeTSq10!ni>1v!shkS_I3>`1tG%_q`n^;SG*zBC@%yDn+5#mQeU|uY4^kf!sFHBsk=~HC?LL^z-89y#ImwZntexcO>5TgE)^HRrL7hyyESCq|DazWYuI)BUz5(Rx z&JqbABQImCWTO-)r(9tf>2Yc=SIkpXuI0PZz(2v&Z~F7)0(DYDE1K36!qqMOeh^(b z%f+t>m)|451GsP3Tbjn(KU>l(8fEZmYkGLthXLbj-VRVJ2cELB_HRUfitWZRydvT# zSEJ&H_x41HlXw$orQxj2+|x2AR*bTiOzQviqe@J3Ufu})wwADmMJw%L%A!1ltx6GE81v6fc*_<(j(Dr9*>C>W zv7;Qvl8Nt!Zx<;Z`>^;i`xo3Ai^~p$;@}(*A9xU#sOo zp}75#VyiQG{I65b0U2~+;t3PDX>kEw$Ao_$LR;7@78zRB2CB6tRL9kdFxQ> z8q`k38w;iRPakp{^q+y5BlX>Ct0qT`G(yjkTUMGN(^8Ah!~t6mO%M3KQ>;fNhYcYZ zmk&&ZEox96-es-Fw>oGH+8j4y@>Q}W9s9cpKrW} zoc#O59XkWyPm>3h>^)Wl<-`aUT=D!)>>-PM=Z^eFC%tlkw6=(1IeK1pi@-0cdosn$n*#8+b zG0|{q&XUxhI-%opU#VEheh014y82T?8X6^?0Bro)xta!uHvc0*}gu(b5 zx82d3x{JoQ9^vM~JAf|qttU9=y3E$y!9BHI zzq+Wr5#-|5YC4SP;xf_oF5CN;sfSgi?pv9*Yhl)^{olj$FzU_p+dg|a*-I7gf{hJ9 zxBA{|Lo&d*f_LEJ;qJCM@Oi&K`^95v7yt zk-;W}3wMawq!WCk2XfeOvvE4Q4~)y?C`XCv`lh^~Q!kC_Sgc+&8{A>I;Akd9hVDUv zq={lR!Mabv$r0P@`SSQ)R0v>Oat2Anly1&hf@C`pDNDTteOSr;_40N0t24&OqyX|V zFb0`$#RW<4RWQW6I1ck*BdvpxB@d*5FqW>uJxIrNt_(NHlNR$12P+Sc&dTln!py5^&|T@6 zHGHHcN~Cr?d%c=iz!AT>-}ei4krrxCnCq83*fDiYhc-Zn3FnGKB_XS$Q>R+=?9Y9} zT8Xdl>n#^Z&G^ei8sDnIrdQUG8TzJb6|^EP12Pg>xyJrtuR*NGoGn|I@9uLTdyXnY zLg|PfJV4W67&n`})C~>4B%R%)(8tI?CuGyA1}!-wbWAaS#(fVI;X3gj2bVNM4x8BiTnT;;b1xRL%ja3^fXBH`fXhf&ziV8|&=c@K;*!BH^IRzT%V$Kv zEt=n_&}KuEgJA0vxEp1~&fffYcc(I4ZA;XMhC+hJ!1pi}kq-|Vx$WL{Depww0~`SA z%aeHG&b<6@_|HGDLW4mdg6iKIEG?qa9_h7TfKdp2`G)Pp+nUOuD`L|mK-;nxK4eN8 zCw+H8%QRlG&;hC>-%%J?|E3*3x!Tz#k1bR~ZHD@h8;)4Sww!QQJYyqDDMWB$zL>sZ zbc_M9!#%A<$zco#}ZwEmP6F*C4nW1Rn=fy=%i? z=fH8k5hF644N0iSk>1Q#r)D#=-Kh@m*${`^Hhm%Nbfa3K-I%bOK6A{g_)6EPu8?C- zde$yx(5uhev5-WXK1{PGk*i)aJ>W$`{$USA$l%xjrkeQ)*c z#wgJUYF_vC7%9$bSpISBN^UihyNAx=Up43iEjS4>ay}*8yTC7(jf_LRJdK4DQlqlD zvz>D8ZEueW#QsV**G#!2Edra=auR6un}9hNzXRV7Ig$fA$|0PIhg}ZU_ZjPfVjq>2 zT$8bsgW{clygnlV=6hilgYaVxTOpm0-5()*wpH zoY2Tyg-}Dz{bO1k(6;5Oqif3Bt~D~co=KJg4xVb(JhRe+sub=8JCXnrd*7j&^wZp} zm-|REM;$+X5|{>*ter`}&o4zfsS358_8Tg~rA*hHgq|#oQY5n&y|ScLv^6w=uW>}) zq9Y*#W5FK8Zh5cQ@@Y|rqmE!QYwLus=Q@APNktE!nN?ulZ74TjXw-Xj1Ls8O;PL`w zXln{`Bc_3SKV*^6cREmQMJecANw#awL8ND7|IWQsEaY{1> zME`fjC(#|Wousx1A)TO>*CpG~RP!K_x*}Nfq$$88_n~V?q0%j{2FW^B zQ)pTXL2cm4#)Kd7@2>2^=gm=nmBP*~Hy(&-OtN)uq2a{0w+f?65G-CADwT8pH?vMx z8`BsE?7yv>nKFlbs1?}*Lz_h|DN9}BoEBPtjz~g*E@8Vpd5{o^N4@}9Y09$&`|3we zk5>0du2)@QrzQjz-4^mg_D8pjYItt|o8bCEm}w^6XS%zf z_&-%pq+P^cfM!_I*X>y(P|d@UqU`xmFJ9Z7(Zl_pr_rT z?$B))Gh(aG#tS3{QY0%4B1Cbl#=(p*Oi1vjuI=@ej=z0qc);Jjd_HS+ah#^Tk^3%aRM#Do|hRvGGN4r$2Mqmmu*;ic^z9ED64V9#w!>(}{l)mAWGA z1GHM0n|K_J@0zVT-1jIpi9Is18P@%YW}Ad>%1WiRAc^eKrRVjjs6R30k^mg%EKi?X*R|iI`!kqgytW{ZL0xk*y!VC_U)0pzp9Iw`Zu~(_Cwc}Q zBvA^syJ(Yztnf6QuZ7YMx8e^KWT>9Fa-*NbSDt*Ud57u1Vio0F)~$Ex!rw+Qg&n4V z-NIq#T@#2jRLwKh38~k@V0^1k`htaTyDZa-7|Fd9NGI@wd(Xnqa$}6{eVZoMgwssx zPr)qXoc&>PTd%qGt^tNv8xgE|bu+zkY3`_DYYe44p+P{97BWV!xe>c!xQxKxx)(fm zfQ4Z(7R?SjeE;N=ASaP$nMax$$?jcMF3A7E!+(|pX}0ibKmP3J#_B?jm6TKlsbbK& zHFEezU!1i#=N1{L^8LNqWF8{6Xn9c5=cfOJ=$!=H7sI^hEr`w6FyiDZ(9)>QF`)Rt zmA;Zwu^~sboQZjsS%cFNplafs$G8Q=iPreZJo0n_Z8FTbp;lGHT|?O2l4jXprwCV0 zqk&OlqW?@>IvrIz^55TaISBooMM~})bizWJYr9E6mMgFRdIIOElHNn6);28Nd;5YD zJq#�^tJ3-j0(u{kT|BTdhQOKB9Jtlb-ePZ;hqJGwC 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 @0(mxl*Ki7E}q+w3-?75kGWPhpwrx15+y7;`G0B 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

    ?Gb_1yz3UKw!mM2 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

    8((_E+OMp)Ypl)5c?s+4K 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 diff --git a/imxweb/imx-modules/imx-api-APC.tgz-hash b/imxweb/imx-modules/imx-api-APC.tgz-hash new file mode 100644 index 000000000..d5d8189bf --- /dev/null +++ b/imxweb/imx-modules/imx-api-APC.tgz-hash @@ -0,0 +1,8 @@ +E6573E34E07D56A25D5A5E5AE4B4B8944C02BAC5479D6A7870003C698401BC6E7D3B8FC6E11FA25628D36EAA6DD0F9A71021A0114B808ADF1FC86E7A17246DCE tsconfig.json +52822F64AEA2B42445A1A01278F864061078D3E60DF1F530F19FEA5E077643DE3CAC8B4A4F065F238F2ED260EF8A0AEC94E5711DF64D75DC9CEB1A4C35A865D8 rollup.config.js +565D30DE7CA344FE6BB6724E1208DEE942D0CEDCE31BDD06F11B8C9E8DA76466100FA64B33FB780C2822F4EAC1B170EF1A2E73BDE93498BCFA185923278A07EE .npmrc +616A2983C375DD7F53176DBF8536C3577236C80EACCC3039DFCA06C20EDD44495C0C77EB405A6FA5854BAAB94016AA603E0EEF7DD9B4FF8646E744091E4CF39A package-lock.json +605B864ADAD5C8F41B700A4D885B1ED0256D2826844C5374820CA8B28D6BE2AE599EF2F8E3FE4B7C5EA8EE4204E68DA5E56072E81F89F6C67896572669CC71FE imx-api-apc.es5.js +7EDF257327F7610C453C0823AEE7A38FE25495D9558BCA21807A803208282D4E604BCF36B27DD5E44D9D30E9947736B919E6A90977BB90CB10D70B044BD35F31 imx-api-apc.umd.js +A9C0B61DDB3B45B9F836C8BF15DA912EC954166DEEC833354ADD50790761401B38B559EDFCF7794D6FD4747F668376F6FF86DC5AB0DE5415BFAC3FC5451815A9 index.d.ts +F0AD6A0E89D6B7F4E107491BEB533BB5427BEB7F604B47E045F8F5AEA7B438397A37BB96758D5E3E79E5FAF52B94625D9A453F3CA28FB6E5D50B16A834F70E88 TypedClient.d.ts \ No newline at end of file diff --git a/imxweb/imx-modules/imx-api-APC.tgz-version b/imxweb/imx-modules/imx-api-APC.tgz-version new file mode 100644 index 000000000..dd5a52084 --- /dev/null +++ b/imxweb/imx-modules/imx-api-APC.tgz-version @@ -0,0 +1 @@ +9.3.12 \ No newline at end of file diff --git a/imxweb/imx-modules/imx-api-aad.tgz b/imxweb/imx-modules/imx-api-aad.tgz index b9da9f74a6a7306a737e89df8303dd05a0e47638..4432de77f9a89ddfbe381caf5ee1f93af17910f8 100644 GIT binary patch literal 190239 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%0Dw*YGGs0Y6}*g|y1C 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

    38G(H_U92@n~BjUbdPRnMzA{>L_ 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 z%0D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 X_=7+AgFpCd_V@n-Z3;*706ZE1ef5(m literal 43355 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 diff --git a/imxweb/imx-modules/imx-api-aad.tgz-hash b/imxweb/imx-modules/imx-api-aad.tgz-hash new file mode 100644 index 000000000..65e565fd0 --- /dev/null +++ b/imxweb/imx-modules/imx-api-aad.tgz-hash @@ -0,0 +1,8 @@ +E6573E34E07D56A25D5A5E5AE4B4B8944C02BAC5479D6A7870003C698401BC6E7D3B8FC6E11FA25628D36EAA6DD0F9A71021A0114B808ADF1FC86E7A17246DCE tsconfig.json +52822F64AEA2B42445A1A01278F864061078D3E60DF1F530F19FEA5E077643DE3CAC8B4A4F065F238F2ED260EF8A0AEC94E5711DF64D75DC9CEB1A4C35A865D8 rollup.config.js +565D30DE7CA344FE6BB6724E1208DEE942D0CEDCE31BDD06F11B8C9E8DA76466100FA64B33FB780C2822F4EAC1B170EF1A2E73BDE93498BCFA185923278A07EE .npmrc +507EA85D039F06742AEBA49AFC07F8F74ED8914BE94546CF741E75DD613EA1C5A672D1904EBB6C301885DB0C9343C891D75B9F6EC281D51303A29B7E6B01E51B package-lock.json +9A2E8B6035879F27E699CB0D886311D42BE245C585F66BFF47B0FD35DCAB0502415FDB31002BD79C7637D4C1105F289F6E11E401D9A66454E1A44A0C09F78F1B imx-api-aad.es5.js +06BAB4D8CDE952E267A312D85C482E1E89BCF1F67371EECB4571AC988DE599F34C5EB9BCF24B942D312C5184111BD7D856B303298987BA63AAE36F261C2BBB0A imx-api-aad.umd.js +A9C0B61DDB3B45B9F836C8BF15DA912EC954166DEEC833354ADD50790761401B38B559EDFCF7794D6FD4747F668376F6FF86DC5AB0DE5415BFAC3FC5451815A9 index.d.ts +A9D47CD5E9766CB8D1E86A27FFC593869C554F1916DFBDF4D1CCE1DA7DD089F3FFDC95A2754C2A50362509401563E49F16FDDBCC0EA77F1F82F3BA970E88EAA3 TypedClient.d.ts \ No newline at end of file diff --git a/imxweb/imx-modules/imx-api-aad.tgz-version b/imxweb/imx-modules/imx-api-aad.tgz-version new file mode 100644 index 000000000..b83a0529d --- /dev/null +++ b/imxweb/imx-modules/imx-api-aad.tgz-version @@ -0,0 +1 @@ +9.3.14 \ No newline at end of file diff --git a/imxweb/imx-modules/imx-api-aob.tgz b/imxweb/imx-modules/imx-api-aob.tgz index c47c2f7cdefde14ca5cab49cda353cb66e57f545..526d51237cfe8844e6dc4f3468d9ac7661dba000 100644 GIT binary patch literal 205337 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

    )}d8aJ%4JbQSff9(eQ4K zFz{|Iut*1W%{G7eJ$~c2R?s|CI;<++P$Xh`naT!QEzkVK962ew$?9BWJ{5Ix@?Ta{ zhC~cRRmGl=19CE@l}Tdh+7UT&(gbVDxk&wgXb!3q(Sb)>`q)88MVXFvI6`8^x;wGd z?EANyX%>?!k>%Cf)O;k}@(Qz%p$ZF=V^#Ta_GzjIr752BjDWyzk!Jo!rTR)X^~ zG9gPm4*kie@f;5J_eSTMhSbhyRTu0K&sPG$*A|)4e|tj88eVkmhH6KFfEHTsFao@v zfo>X8IrGH*?QgJbTSADF~%TJ%osCdwpq`7KDWFdp``|+Z}JP_tz%DFyHU{? ze!SnC%z~q@{y-wHd*Muk3QIrAV<0>Hje}uPsHZJ;WyXD4ldl}=bQb-<1|1ixnDEs$ z1PfFOJ<{5)qP(#ryEfrc4OaGHRVa3D40@;NrYASA;!?#{(XvjwC7{mlg|xIo@Xk4{ z=*O5eU(V2wG;25@(6sM7e6`61``Y_tV*H=#~B~M9t8t+p!jRfT<-NS0z*3Lf`V{hsznTLQDc`RxF1 zlp>k6+KDH(zyz>U0ih)I1d0u#En86KSJ`kcui|qu%N7LrL@~9-YjA6+ zRuwn3(sXo4V-rIM9!Wvh+U!H?rn2b*n=2Es+*8t40x5<$`z&p_J#0`FFw?a4_U}gC z*}PjA2zN)Mm}NsAYlDrCZ_#xbhE3X`Kdb9l=X^G&E3PD~Me)^wk7fDJL>dNFcJ+RN zZJ^FnR#m&{ADjyG(_(BY2 zp?(F979`wR_hNnGIy^#^WxtW6J!9R6|J98wgJ_i)V)NA!o)IU^fZ%_7q2hd3#7-Wu zOW-l#my)Qoi-h^f2xA-O6$Ac7g_m2!HSypDoa+GC2)?C;Zus>4n@{0ZjwehdsF?Mju!?Ze z09d{Ys8R`4SRVsJ3RBPwPd;oUQ4CSn%i%HQyR}i3lz#?bDFdwJSo5IRO0ZE6UU2~& zfR-B2ii?&H2dfwp^&rJn;sIEx0V}Rt`f$+Vuu%_QOsQ=Emm1(=O0*9LEe030fki7g z0jiWi6)j>jD5NMNYU7F29S1lm11C~kZcsE4JX8S_Qv?TKG$4#nqKCfm!$6>HyFXWh zUXA_yxzyLJObu3`h7}CFFDDltjX?%)n^eZyfG?iP(9#%ruo9;(?gm?wD@ICV%)wHf z+PE8Z)vg>djqwLdF3Li0sMVK3oYVvy6ed!kFcCKwRCHP@RfK3PjHC+=jcI+L&~c4u z`GP4c4z5R$6+Ac5$$-&~K}Ht((w>wXMHyqs<*i0peJ~pZYgTgR6su}TYl?}e0=S^c zJs_-)x?dJ`U`&x-Ii%TCMSUYH07exk(R%)Xqya-bsa)GTP^j87ILT`w@$=W1j6gww zRNv@Cdru*fi1c*Qz5<&|C_&92bJtsaUDR+QXV3_R!VU(DTf@X7KkSSnE$qIvuhC{g zubvXiTzWd`sklMEA8A1kt$po6ze7vo50rco40WWvq5qRAQ@?)L*FGBFJ(e)G2U5X0 z8Pi3&v%Zi1#%c(tj`}Fs&bN`^(=sO`e=AdJRlxG5tTI|(glzTQ&5jhfsz%DAZEOlg zQTjIMvUqEkX+K%LyV>Q;i%486uwP~YFsX!hep_V0a`bHS*NU>w zq}PTu`1&W6N!eY`);Alf|G=2oWb6Sw#fT;5 z@S|&SL$mprX)wd{7}RH>j{$L_XG%P%qU6Zq1YI*HixdfdTSZAqV@rIYi5dfBM$WmM z-BIal+J3l%SH(4zS7bk3w0|<{N*Jabx;Jav^tYCP>3q3{v_Ji5xL*FFj4c*N#cA9t z(_WR0NMV#W1s0)(3@UmUo;?*jEAC09(yBrymq#9q+rAqmh>KX3Y29@ak*y-Uyl^^ zJRkT&eQRUC#=P9&NfSMieDjXnCH)-5l{*Q|jz-+k*{^ZRnNqK|fU{+aClf4Etf{Ss zu&(c9girWUTjEI-+;KXWkbbp=%vFaSr<@ZOlovI7bak}Cj+q#NxWi(iBbGJcU>t%D zYHW^M)R+h5h0WKU9Id<=Hq;h5cl3Ll;!aplThy7;&f^p}&xYC}PgU+4r@&bzloxk= zsCu-r4meO=&{46s(aM=JprDvj#n471UzYMsS?RPEp244to4}@gPW7tqA!mtY_ec_w zMPmtf6HAVnw=ccgKFKB&w6_zz2^HxL-I8|Iu9a^-0&>vSi9xyrYyYn?e#vnqpKB@#EeMRKQ4Q=}JaoBbrA~ z;(c~GKYi$)lixTYFxFRNW!&_kenxiVRQ{M>*2!?x2MAI!948Qley6psk;-E3PG6%= zU=j1z2O>nT*Ychw$TFLxjzX384M|C5N}`lIc!}heq6G&pGb2U^FNF)1%?@5h1%E1) z_DO2wm6qBYkCWc{E7NfAxihwl^AK@* zh9~dtB9Ivm82*}HKU68-h^Q0ZWNJ9x#Wfs7PZSk(RJ!sYTOpDZge)l%IY?2$zG)=* zppp;Z!2~#MiwVaRVUxAjDD)rX8h3}*#;t+z!f=*=rd|caihQ#M!a`g(O)V)NsNL(2 zgads|8SrdP_cRPY*VAl^XV$)@yvcH;ZuP~g04j*fX~D7u<*>A{EO|IYl^U_w-9+Y+ zavW8m$F78&aQsCm*0uJ-#TgFM*!Z^Puq>_~S&?cr3rkjHqUD;CHQlpfgg9Z;!}#T(XD#~BkNwnIj2hgq>5CSt?kcC)kbAXX~g+PoYGKJC+Z9~z2wx5&M>QP?d*Zl z=|muhIReQ~qm`)J-C_D%jygJLD3pt8mBAH&85M~fs`@HIJ}8K|I8rDMCCZ(5gdnmd zTcdljIRNP^+xIj)Hg-gIFt`v@oM`00Rki4PMaDC`#p~KjW7Z~aKa$2XS<9({rK&)h z4T{M5%_2z*c_Mar+z{@i0Mk<){vnaV7rQSKhO!m^hX)id8YyV?-eh1%kexesMY2$< zhr#f0!t#*9P(QsAh6GN~tDr~*!**jB9xDO=QgG?5@xzdaiMuWoNn-Hs62s#r7J(FW z`s`&fFnXfe7bW5ty2OYQ2#SOti=iG{bPSFn-z|sGfNek&!4H;zJb3!)Iidn`u9q^x z7_PI4I_SAxR>Ds&jZ_9kP}0GqL?Xj?Y*7M7i5O&|)N7BJA<+~UgDMip;MKN!50!u{c>3zRG%#{VpH-!Y^xNpFq6GTyfz=~{678|tq^5^csH5)6HBcmHWY)NDhPoZX zx=IHWZywfh-0q^USbro}Z8_G`F}WJs#913T;999w65$A1&nXCGPHK%|JYXX{#XwBk%2kz}!p-;8gf10W8>k(i3!qAX z&2-nRBtI2f5Gsh*jF=h&ci^Uots(e$vvE_U%Sjm%3w_kET+#0s)}%&!ut2Jj71DhT zGpgz2K3WPQ`6j}5QB8>Unlm<-3@O{UQJr(aLfMp@VQbVrvgx!>!OoK1EOyUgM|f+9 zmD(@fMhnbN@jGaD%+6sv)vbK3fmmXrU-KrOodS5k{+^w~cgp(+TZ6FVF2i-BK$=)I|`?OnSu@3PLX&8yS4(-gLTby^nR zcX%Y-Ot%ILI(#z4d+tavbxXGdr*5N8VGTQiu|(0Pv_f-BifOVf_fiz8-P5-HSLR)` zyKP+iShY^LEs6a(ZfzSkyv^xVdZRmcZq(bALwC^YHon-UOi>ejG;A~c?DIn{Zg%>8 z>;)NPIlnwPz0_X)o%Gfvhjj4`p`_zJu*}s|++@-H)^J=;3)?GtHkJyZirk&3<@-nr z%mDA{2V{h}Cnk4yq(ITVfeJ}mVUfbKP{)LOMs%bCc=&b=$0UZ-y zSZmYYkk}kFrA4l9dKe8j;$ArTdA}zGda0DjUtefz?0)n$4eYjteh-EqUttn;GC=YW z;_p(Z6Ulc;@u%S-x8#NZj_ie!z~S40W-tUwpSIHZ-ld@aS*SnGr8D}@lSkOKfjo63 zRQ-jqLxTJ0lgK+NMlEz^hX=wRiAJiW#}xADW9tEr-dX{6X8|@`jm{p(2;?c4Es9$;!7hPp7wyftUr%KXo^!udUXh<&YIaYqVN^!f8>!b-bF!uFDYQkVtE14eOFXZl77 z0MFdUyoy0HQ|AugIR|(acKcNfqNz5#0MI!Aw4jZ!dhmRkTNeYcIZbQ|yA-Pj%&3Jh z;BqFo6tzKC0hXy=$AHJl;xWGiGbnu)N{1q0qbL$qucZlO(I#mZ+%eHhD=?Tnhl6g^H@8r%7^E7B|3@#rkZPiBi_$qGIZHWwK z0+~^(m>QpLh}tcKS%6uz1*ef&L|GeWFpb$I`&FAvD+X~m#ynFH7j}N`W73-2_8AtL zN3zHa$8f-fl=a~5*^>wxaDzh`pF@HD)pK?yIsMRkb|!*m=-^7m=SpBd{M_A1L0|fw zT}n<5UCMle35Z1bbi0)li`}ynR zo$=Z<@EyUswl|nL+j)xMBIF*xGSlXOYq`kIH6VdXSM9<$cb&R9y$mf?x-+cGo%Uq&yHh?^|AYx=j zAmXAMu(}U z@(@L^-6ib2S85>!%EgP`8{RSgm*~gnr1@I9s z5*zb{V{CPtIgsh;qi$lm&IX=718!$JEp0Kpkk+PLx8lB{m^5LjO;~ca`-@{_O}9-l z8p$e{N?hTwYDr0S6tE5qa*q@aih;6YX?*}d>S$c&+9$1Wb2%3HHR_{$Oqo5^@IVLJWWA#V(hs1`FNNR{d)Z8fYG}5wK!KS>2dld~29bBsQ5${O1 zYQ&MersOn}CajY6O0ujNf311?%A{+x^cTsgLt*ptp46VuKq+@`!WTzEegkcw4SgfD z(p?$8>j&3BU*Y=f(~pMh<@14OH+M*lrHfaly(%MAetj^HQjz_UC%40cZao#S5O-f+ z)L9BlHE-_+=ix)if=nLG_;Yeiv4~q+xhYN_GwSiT*MbWKRG0ri8pskS(gAu-RlU ziU?asmTQ6SHQA#I1Pu>cm49AC#lD0ev`Lf_KhsgMUj<~_`n9csoW_AYD1mPWSf&R- z^T6Izk>A0tMQxO{$?IAnTycg%Wn{}Z^rMK}UTtkDp|}}b*9yoSX)jcQ_yBxAiYV+# z)|N8LTc35UkW@pnLUo9mpY@}Rf(~45siLgOR}YGKo4*6T==gSTDiAiBYEl0AjjVbQ ze$<|-O!izGtKLK}>ZR18-v8d-zU*U~;be@aj&wIz(`8L@$LuKyX z8`!bq+rJwoP&1sYeDfin9iEL>_}b3)`bl*Fk_Sikdo~(04Jr`!59rC2Fz7m6iUvSe zkH>ae?6K3U%PZ@gv#7*rX%C)(Kp@-4r85XrY9uoR07UI!D(gPC$INhQFY8m%rN*Ut zr1Y-rvd$;fv@X?0WgzueY39)x4k~vP=^hZt`b9D4!SzdeIZ4=Q&e%r=Cbc_IqV-8X zxGU_xQHkzev&P)69o0nL=UP*hO)c`>EqX^uZi|IFTnvR7VSk2NY8VJXC9l3^n;Gf>_TSr@=p;%-}B`K6tMy3TPaXUBLXbz~f*Z*0qa z()6hE^Gp5$cYTkx`h{aZVykk#f0=XpmaP{ZUbM!vdyY>&TExRs{(@ik(}N#H)RCWf z=-?uk`;z?p`hcDyWq*j4hL-f=m&ujS;qT9T;V-m!elX->j~ldnz-Tbj);GZy3sbl5 zeC(g%`r3F*%+S_w5x1s-AN%GZ;`EF(09XVv`yqKKzLmd*D`b92YoxnDeR7|;#Yj7} zl>qsenDr*q1t~ZlKRP5<^h5!hJ=FP*L^SI1-mNh~E5DPn`EJGmZ!u@2J;u(l*T{8a zRl7U1CJ}GLZl+3fu3DXNkx8(i)=g7O3Q}wL`XgalUsIkvThl$wL^`S5Z}IX8W0tHC zMo@n|MpZ#bOpA^!1dQc@rNv_;E*XBWyNOgKB{lsr=9NXBJpYSO$ZPF~i!+>NVEf#b z!*Hm&=MkfWmphLLQK8Ct+Ko@4xOs0psaMmSGv@J@GH*|Voac)B-vpgw!f3J9Ep3Iu zDq=WZ;D}2CNZ7vSNy}D4Esh-{D3D&&=Ld^R8d+Up-F%#oF+?9SL?32}K1_(lfqS#F z@#QUvbNsc~BejSZ;97+;-FjI=@T!z|?;pXG;+Eh$wKDR>z#XD`eC4dRfkE*bDhuJD zW>NYsjR{kGD4@2oAx*aMeUDCGDt}S2oPI9=ZI-7@v|_(fDT!K50Qv)Ez0_lJO$J)W zB3TcN)Ut~>FO=z+x)oH#XVP?lQq1&-&91vsUL++obgu&*HmbKch^QT5XM>1z^%@$; znnF+)4|@fRlO=fvqmkzpA%5tt2l;QAwm2Wi@N|nWm*;B8<_Kl4&*J9P*qMZN_Fd8- zV56;`>b)*hpua*L=iQwUlyA`>E3OmLJ{^VWK*}Nr!^9$@cUmFsvNBS5Nh3){qI8H_ zKY>LMXLC9kWLQ_HQ$*XzcS7M|4u$zi_oO;d)Jd|-@kQqXg@Ws{e?^yIp#;fcL-95k z-DsW*7lq>KvzbO!M38xjMz@D^fY4XA?`e2!>>fg5g&^VImr8+U=yn~EgfhF?>l#X9 z87SZVqZmtD<8x%}6@I1v&3pB%aP1nREyNLXMQ~Rqlq;iMIK^AVs3- zwWmslSl|hhLdDoxv~+@$bLXx|Mjdr`=@1B*8Y%6o+aabCJqJBhiUiVWf0+&y9uOp@ zbJg3_bfWpVe@l^Mdgyc0Ap~NYq);%9jyYXnAu3%_BB4H-?sSWYh$>l3jHH22cewD~ za!_>H0H|v?V3Opqpm-;tPEl~Zlo3y-y@-0i!u7He8dPs<)DZ>>MhzpJ`DQt|Z4^<}^ zVOld4Nvfw-Rvn^)p-KuH<7tc46)waFV)|^W)h!$-NwQc_zCTx2C?M^tN@UYzd#`RG zKq!($fZ}b!q)zd5*&R$qQ$scdt4ZGodV$sCtjiW)GF38K?)()!as&;(+8}j+k{n}i z?SX6mv8;#_%K?%=Lv| z+9$25xRq#F*E3)#xou!|DqZnM)a% z2^RXOVRfM2G1y5->tKCSBMX%K8YWHC$$j*6dh$(#`l4g%12+&9&7lVG8`#5r6j#ij2-8xal$JE<(6bVY%PG+()lUlm07rD=J-|4=>J+WZROfGV{y8D~sI^7l%OCS&k1OkCTVC?lj zdzZ34@RPLek8W4JvA^n#`!$(t)c&6QKUo$}#L;0#boV=lC*6}@ z#oM=gHSzBF=-qL*bJ9NkRdf$u9~~dGPr65k%L2=vT=|JeqG5XD#Zvf*=ttquAILEE zy`UzNJ){;x3wqNjQ+PNM$@q0Hy~p0>3ZAL<;XRmU1M+v?{_V9Qa8;h>}TcWdJr8 zQF>M5{`?wE#K^l7VU&t~G`_0}t|hBbbdtyn7V@?)$Eol`;r07bJn+K46gPf)1<=x~ z2r2+>+yJERMdQ2Jzr0FCtI=9_NQ4xEGVQl-#c}tiHzz%D-05|WKXmpLiuoZrX#Z!Y zCk~IqapxVBK0Lu8>WQOcsPJ?9__%#|((Uv_`_<9=6LIpUBYN+O#`r_Mp=@C2AEM~U7WARM6dssokYcH6Jsb_n+2uVTM_(Eh2@6TSDZ zUw4i>`{LEF;%#@YbJ*)(@pezNf!^=mo&dVpIs^Z{izx(=E=?Oea0D-#PAnXrFXHbb35$_2uR76YTp0`#!<`ya`r+@MLI^0a7llb0Px>&w44~-Z@3Nl?4-)%VelURfl3q!1>0ir`+r?G@j)uGk zMLz(}2Mno9MOBONA54lGW4_Cvc66>k6lImUE5b<-RCFHIj-wk9${W#%<0vkd+VSNC zr>CD_@mi@u(C+cyBkW0SAcuY^-^I~b#_3%-k7#WiM`@Jajb&AoknBVm&kxg5)k6PL zrrW}yrHExZi9@?%wG4zEabMLCWH=eg*t-biwitRrB25;G#LEe1rtw5lSGY^F(5~%y zVNXi2EAj&k{}mufHOh)!i?z`i`02bx9$_nfaxA^UQ5f8b$B(lO1DJ=j{F6-gWzvuR zF}Au$F9%lnFJBx4Txbu)!%xP6cefZ0T(+Qn%K5ssv4n%bwHMepz%;TEzzXkJJh(He z09~gvg5H_MM;W}V3XAs2OXce*9(n0Q*w?A}KsvtlM}8`)L^8F}YcCe#z#mTT4n{$w9(5S7dA#sWAudihzFZi2I7_<4e)l(K2tr0e$`XSOy-n zG-o)6pJN&1$J44`IGRHn{_L^D7N!m+<}Ny#R;%A|EG?*WMv{=7Gn6N=S{-^L9!~T5 z_^}w*_M%`i3Qe~8{zF6FO%5hO>c92F2Q7J4werJT%ZuH`nj^9Jp!SZv@bZC8VU-8U z!IQhOe4xyQDi3Vsz`K3R3_ojXj=bCa#ME`|X$i&CK!&RLNH_51i)duDNdWr-CR*V% z3uKs??f`dcd4QH%3=h2Ysy6aNtXsu04b2Xb$(exD%d8qbR5?Glf93Bw$BD zlg7{wB-%du9+)}&uph-SY#1-(m3Qq&vGBryxbcHPTu2c_NxIC;1A9np&`(4xb&Iv- z7xgTH-;j z)L+(~)R$pqF_a?)va@WhjhQ@aug#hunu30tctMS~&zTyh+3!*ZN|!!~UD1Gl_e;|5kxmKUbuy~Q2OM`3$ck7Heu4HwQ(6sFMU8O zKT&zz&KkC3r|Op8`k$rf2f(_Ecf$WH5$-zS51%v1117+SjRexBHmq;{i4iT|3X-e(GeF1`3JPy*G$Cv4jXjB%( z3>xam6j6GHD5(^UOEm+RPsBKCr8YQL1{o zrF+YXxGrRB!8)Ex+ZDgx!}3uM$hDaKhY*KTG*Ju|x%Z&#kua-6ht<$IrQy-b54b8%=Bap5He=oTM_bCaFr9 zTeXLblvoo@r7X~D5cr8z{~0%JB_pTU)sRh`1jQruCr^4~+4qM&EbLcOTzTOj@WV?y z8nKtd*RUME@)8LbQ15k!42z_PX3ZNE?Z4rz$}?NrSZY++Lzp$%@DA8<2>qdx$2 zV^I36vBmu*l*tXR&apQqw*pXdE6y1YB(_$!^kI zGJN~i0jz0#Lw7yXI`;ieda>JhG!*~gg%dBnbMaW?%zfFHqYD{7j2f_JTT6~ka%u6; zzy=!9*gVt3aj`j3gkNg_?UUM~kk=Yo4S23$b7CI)<^!Q`8t7XZ`sOs~TMvZ3WuP}3 z8vNEY@XhBBgx`E_HPF-zsN@3TZ*Dx0`kNc3g_fZ|C+l@cSJO+8Nl~j29Pl1^2{USJW@~KDtFe`>u{Ey-bFWo}Q)cyq_|fhPrA(;< zng|z$pHS)(=}T{9FqW|(AB!{+H&OhVl)QmI97=RzAis^fF(}!w7bavL4DM=cDUGf_jRU{$r>qtyplhZPSDAqXLQtoRjCiKmAi_qeM{`?*(hq5m`m&QPm2K?={8$q4 z!SA3~7&Nwu77}gKA-^)*6ZjW_bOFAoprC!+a$YiqUHT3u_9GGR1^*={w+ zNM0&&rKr6>*((F2s%SQ=Vy#gX=6{vSH}bRLma*eI%lBn%Q}KtxW0_2XG`|gUvb0^r zNj=ScmJa2OwJ(9Mokgnkypg?s#m|K*9{7oETES0RmYssMF1tzAHnDR%juM&ZK?hs^ z$h*bg*JO(ZX;nMyoRH+x27)L(r1L}L8I?SYX^S8%#>7Q6tD@8m;e-+AZ)GbkT61mv`DSaax$&&?bgl6(rNvkA!MC8r z>c15+WZxfo!B=tyRkp}M2@j*kv#nO^Io=;yZ*8uxtv%b=TH9D(+uCTXt!?~EiSl(U z@=b`c`tL`Tw^4Zc)vLzlx*-SvdKfjfTCKIUXRXHC=JSp9XU{gCH=h0LNbt1_$R8uY zYMuuF8i~=nisG-=9-5nm2ngw6R9I_0+kEyf?Dp4={U7Z1D)jqbGu*H4(y!DTpr+|H zd_7QC+}QZn_4um>`j7Uw@vm9!_{{7pbpWnyt#{r-`<>tHZf)t!ZnG*{YgMtaMgRYH z``xdk($^^ke+reFXaQ*csn&oZa@f{^4&KXq9e9_CV;Zp1)lSt)I<JxR`Zd|7f74JLsUUXu8iA>5Brl%3l29)jFQa0ghstt(sBhMC3C zm|#IgOM?Avd#JodxAL4N#Uxv&$?WL@_tBW8Ev63;7?ewY{~VMuc_5~uK-PYa z{Z!(O2PlmVWJ`L@eUo(^h_u{?AVn%c^++M~~$D7DgU-zy(|wY9CjAB7>^98z7j z>YduZOH|eN!J-5$#@gd?BI9c~6XlQ0As93sVnJIw~B-l_e&bW9a2 z?ouh5z5Z(=ClVK3&Aoq*E)r-iNu%*t4(7J9e}O=HRNQt0bTf3D{}Ek?->}^WwDKQO zz8T_!Y>w?BNIjy)Zah%qpsV27><2OiiZ0r{pFKZ)9mRWG)#8pR1so;Q%w6U2ljvc+ zh@;PPJ|24-#4D^|IpyTCoVNAA`U$v6jzG}0#WnEbi@ z@Y)OffuK9#pf=0VMF3u)en<-pqcykvEcD=(41O4xvr2N-cdKC_^42qTq(TY#`;we$w7;9`rcIZ0%kJOq;? zRL|K(=y?_u&MiQNg~>yjI#$zeV>8>%u|4lhBLnpGuo;l2-k>UE+J9i$||cI0XeLQJPX}=`nb9IH$$vRBM@`Wtc#5A9S%(^Q(kEZQoz~Hdm*7 zc_U!32ObqsBGyM^sQTgcpd0J&yWHCS>WD>YSYP5C8Ygk4%}R#sz@Q0)2vQH z9@Ax!!_1eh!q6^H4s53@M_1tOzq|KIq$J0yjAIpge}G#RGbfv?9M`sB6c>J4 znL9z6o3kkjKrJtG`nFv4<4dVrC%Ne)jbb@~)q!%!!h*W1l6}e4_D2Kji?VcaW71Bo~rNEW$L{s*q6f^T|2UGQ=_q?;NqB-?yUT($%Joe z4NT8e`BVG%Y@>Sjo$v+&u$9*4!RfwRw?*W;bpz#~z1Q8J3*f-(ckR6(eH&pA``1zg zGPN!~PlbhrZP9|?*;zj1>+8rIKFRU<{iJdh+pClvV~C zD>Wa~7K~D+!0+7lG5mv|Se-+EfhJTP-5s?Fb24;;&p>dBaqNerI+F=j+hh}TF{R!m z^P0xG&bEtE?A~Dz3pz8Hg#K?6Ik!Xau^5ZVmezJ5%>^vg`4m&nyGWv7l1lMD_UASd z`$Vk9I&Y0*e-8MO=LbrD{WxFz_(7Y>lHh1;Y2%2_(Cxj86eJv%L!znQHo<-hq6;r@&GMY42*#hM zrT=<$aE9lu;T;GIy=^Gvg5WZ;(`p)h%Bec1)`{$2g|GxIT9X6yQt^+IMx(toC1~%= z`e#3Tv9^NGh9khTgO$K6hsQ31Lg2hHhFMNv6H5476iS~V*80&XSNF~S*}FIzO!_I1 za`{E*&*S@D^C$!T&$QC8x_B!@P67HydpxaGUA(ZL!S|eM-DY8{t z%jUDy`Yv0p)<9VI6*aF>7O3A!7JQE&{yl>D_Xy&Das=^XWz8bJkxq71bPrG2)=Yd4 zFMq_VQ|*Z1>X42#QJ6I3iY7xr%Kbo?E8|rE)ch*F54n`32AQ;-S?xG&V59b>-&1}eLeWT9{dy51J|wZ zE8Y3Z%A;1h&E=kTxK{DhuQTz-G1s`;?HU+6Ga=+-Pv2V3cefB?`nE8Jv|7{#9WXI#Yu`hrVBir@yZEy(K(OKkdw@8%4p? zn&`njqcWVVPpu5A&8)iUg)p^tqt=*F8O)*6tInv{4b!ix$DRvcRTmD;zp5gd-4?CM zPW@AhmrA*1d&go=j&37%RWu!yVi!6Dmo>kyyr)k!K#RQ9%m`NSE z+Gwse*G^ik?Z(!2>v`?@`t$!Tm1Yy8mPXy)5e-YZQdpLoSY3T-HzVw3N>eM=VmS`H zzATqcN>x!3rOEwVAinrm;b{wu>#PraR zVa=+@vMIF(81t`%@VJa?0+@go5~8BxIvh>tmW%jD6v~%DGpm|m*Fg!ay3?DzpPJM6P_UnQVCX6?cK_h1 zQy@&Mq6F7bzRje`Z7b$(b>=Dh^LHO}Hbe_-K^`!v8#@cFoO7m#VOHWcu`B3D=8?@s zn3IxbuqPpI7hYtfA0nn$PpBG=VXlz6&sq(yy}&W}S=y1o!qJPoembFHt%?y$7T9u3 z(}R$DTx!ls!XMOmSgF>J!oHU}EtO0gqEt~O>}IQ?R4WymFHNWP&J9?hAB{#)`1geT zBjBwzBJd@C<1X#d?ygvwsBj1?;zv7kTUEI6!$EXYP?$5eUC2|Rnu3W8h6Tkid0YH` zzq7ooN90mlb|5rpoPynW@9zoO>X(;XWBu8gOek&$d~+-SW7)p)lB1hYTZj8z5R`8* z{4zGMQV~Cj+f)7dNo5|x9yXg}-+lL5duj0Wujc~W#>=j zXj`0A3Bzrn06>lHgvj%f7#<3jueJ_=Ed+*?msTaI>=l4IqK&bjj@+dxC(Ic|* zsVY`rR90TT{PA9R{oI(H!!vHo7`RDYT3TAd&_m$*4t$1wsiHqgQg9uBh#ez!+XwI0 z$^>3aePV(|{C*<72t5Jr75Tv<{VGkz$#%Uykk>MRL930TfA~S*)uQ;aF2mLLz4{>P zC-tA@Mg2d#Ymc0;>cd?bn8)<)St0t4W?2o+GW~)Ae(~z-u zDeE{iax!SQPyiB zV8#-piVXdCmY43S4#2}Vze$#OeQX-xtf;nE2oMVgE<*D?gHDA2!!#|!r1o(+7QT3a ztjNcIJHmhZlwbl13keo#$gfbfB?J!loOcoMssCvQlJSj9g$z~H)Tm;Gs_N%`(S~wx=<)zr=_2FJbebwh#vpkJ>qN_R1&G!v>l=cM^ z9d4TfSzesH{Bx%{{jFac#uMjokNi^JsA&Clt8-T~h;E6^B@M}j& zU^Ppa5e%n;PXq2ReHYGA7>lnm8EaZEUTJfR`CybjF)S5^~^(QxESZ=hasL}kqx0&SJgY)D*(zSl8wlj8Y-=B)tch?^`3yl zMcL(-gSTg1I5-1(xolHkUV_Z_yLWH9dw86@EmksJaHgIkf4xw6f$z~3{v5rhP;s$N zwq|s4@#%K^O=jC%@||>kIZ?tYM=*yh(A%fPjE-z_7AI{1vIAA(l!q(h$=K`5D#E^) zpt?jBTUgUFkiHooE3_X(%t18D$qFR|TwBU2Z5}lNcum+pI?zkPLgSPdi#$M>GmFbr z2i>9bMq{E4KR`_f(u1f7;BVFt_{nj-_u;2zvo3yK+Y`MHKZ$0oxhQdZeGhm0 zXCEYNYtMd)z44XbPYUVP`|#6Q7n~@z#fpRaN_F|ZVoaikiXScQ7YzbFIS~s86N_Q8 zYFRBe*R|u$-s^qC$B=&JBwCGf{ z7y_AqVHPJ+tI=q{s52(L4?h)BNEKVjwsw9y3bxN5(BLlzZ-L&=>$-|z$ik-c6$+6E z6B~``bJ*?>R;!!#4|~%)Pi57_a1Ic7Gc9&`2fdTYCL<>sRdbnagkh%7X4~5&{X1Jo zbA@m?q~NdvPC=ZyT!v9}iXz@Snd#ZemC|`eUbMkT8_VA&J_dh4wc+#=-`M~KEfRw` z8VgB_gC$iYybiuxFqLqJydlp(GPf-VprGD@eWk3^Pxqn>_O=VARK@K(B6t*HV3VJ9D;5dr zb@BdbqtVzBC+$~N`rQ_9U-QpB@ml@d7kkI_v(*qdycq)iNPqbPNB#6;`Z4@C{1}T* zPwN$RJ;xmkup^#+vMnovL86!d^%}JLz(#Kp<14AWy<<~R06|9Y1Ycjx8U>Ffcx=8P zN>v4OhiwCVd9MH$QJwL~nt$g5b;ls0z!yE49?QX`50S&U(W+`fo75h0PR58;R^@03 z;6kUI3ic}q67HCGxy+75+(j6YkzGw>`cOu6d!0r{y5APRVJG?1a=OP86+8^uoz1g5 zx`S-@`z-GgJf5k=NZoRd+*Q0gYSDoXMz9W^iX9El@jyVSrXq>J!T`bo&NK2yzI5Iy zlXE;)prhXcyZ41e3zRx;$+D*x-ofMasPB|Y_L3P|MT(Y=|=$?nJGNxA&vcJ0Z>-#;c#emwmc ze+)mJeoQ|0K0W#If9@+^KK5!)ek}jEd%A;JmCDYK^C1>haz@}x-lj4fB;`GD@~!qJ zV;KVtkS4&$nC_f<`or?0GP;v%2P>+Ev@>(3T>1TeX~`m?*rkFFw561t$BX!djXZ-EZF5sC!Lh3~{Fi~6i(VVyF7k+klwBO0P4(;j+wb{j*1gm{QPTrk@ zViv5~#aaXlYygF=xv*vzTO(L|`|XqVS+BDPTh&Zy3)bvn>r5~7n?F15fGhmrp3?`L zUNehrIIs%Q&%>HhY?ENUJ3iX$^uYE0tb5oyIeu^T!h$us*fXZr(ZM1-F}v7vezN&! z@BOq=7OdIDwlc6lH=jO^vx_ww8DOuE+dpNRE&^6qtjU~zctn>+=JaxQu_kO1>UE)C zB;Sh$k{HEKu_v!eKadH&gF{(P@mlwAzw^skulwJfv(E8xw$XAq3*@xoH{ z3+%2-h}!J31?{hW+AY2DWeiV0-3iz@$t2Y%tmQiR^YPK)PiLA1=67)Y({AbK7~Z#6 z#+ES&u#eL}>zVCI; z%<|^aKFb2L$`;Ma#;4sWAPAy@`sS~egWa6Nz{s@4=f>z%aSCYFkuXj*KB z!F&LIe%|+fJv?duQZNWpz{0fe-G!-lYlKN_>ZEYE4BD6ibLl0kb4 z@O2BgHg*Bz>65v=2P>-qKLxTqmC5N8z;0MpV6fA_h2az}ytzoOHv2~h8rW>hFPhQ7 z{JVd2u!?|ITdR9fELS0?*=(+%FUu+g?_9lrlaufg4;AN|lnuv*0Yv z-tIveEZJ2tBC7Bnw#=WlB9G22s2alzL-rB7svc;%GDsxuc2pi1%0WTKnzSo|q-t)p zJOvy+p)!q5_anWC7MI*14PL<=r;}LrAjs-T?1Agdlnid&?mc@{N~%C>I{ewOsZbFa ztenrMqO>ha;;BUn-i9L7o#lJGL1)84cv@Q?+~GJ(UCm&dvvqt8)AgfR($RHye|2MR zv$gfC`Rv&;+m@A&HAcyfhhAU1v(dqwcL9ewZ2K9aKNFcGgz>$Fj4&F2^R~Lggw`X_ zHt-=Qem4}puc8}urlPCElSj&2AqO>sQ)B|V11>N_!HOFA*W?rm9ROcbT|(DH2PT~6 zJ~*yl`yQZdNsg)L*BisO>&1%u*YQZS113t^fcMJ&#vf=szK*blj73tii*1xE=JmT&}smR{;~dK@Lb_I0>uOB!-vX3TOVtIHF zKusND;k5v5iNZX`4nq{vAtD-}jmao69*v40JB8kPz#Q2>n#uRypCNl*-otwdt7s@vy;#u?tGbpFx` z)U($d*NJ`}+JMD9&W#Lu#O(?_wk_KDL7kbXaUB~stV3uy*NNWx*HVid7?Wx&hp|kq zU?_2P&q7+WLRzyZjSGog!M}Evm(C{mBNtgYkZp+b$?vp52KX5 zVV(8{kt9*=hgUN8Q(C|k`a8<0LzOoXM)6%m4-U343QBkfZbzx#p9Ee^noZ5_bw6@S ztBVy5F&xAo91A|HmFW=aO&G3~bdP0re8M#o?gju%JRGFkF?0xxcLl5$)LKTZ~b&tY%2nvcwde(L)|812o-GS}0MaBnr>x<)xb|KagdAbyZpZc`A})KUP)i z^?mkG=*$}oG&W@!RH;3A1N;AK6b#^Rh4xI=7f#{RB2-nOPjs{azn#4kR{`vw%N%0MHI z0_-db+k-)_4C7O=PPYstV}zS0rpGj^*VTzj5M7p6s5tV@_R3Q%WCpm1vL3hW56k|` z-G<(&240eq;^;62o&YM|c%cgsMKp(y*naxdS0{E$76`~z^_ZqSFms6SP=9GU%{@)< zC9hzdSy?o9>NFRbYbefE-!a=&&4q6n)Kc#fhUV$Y-eE<){3;erB#r`GbJRV5CXZ1&i>oh1d$k&t;*s;J_6 zwz%9e$}uNtm0a%?@w^mNY@1Nvt(GNKy)I(UPh_$!@`nV~8Mg9j0Uc)2y=r0mrwzai z;ve>y{K^XY{TtpyQ3m+`GfqJg2 z+l-NiZq-3CVN-p!Lx(-H=XQu~=sd5FhrMYvzd^@wu3S!=7f!pvG_1#EF@eY%OIslN zL)?TKb^~c=J{~{DN)CTwKpE@X6^y)VHCrJ^ti$?ab{!|AVs^8!3e+wmHjg|Qt(@$Z zppw&-s>Jv+DfNFK$8f(KLMi67e{uy~G&dWq=4Nw!t6`n1GzD0uMY$XL5c{Gsr=_e(yFRyp7B;Xj*tG@0 zt`&owb~7XsVFTg#*T9!OHiYI5Xxvfwp~?H8<$|nP_UBx2Fj~Bp9-NGnE9$1967il; zuQm?@?^505!4PGztGx8DWhjPJo35|(*=tQVsF*g*gcV7|(DUQqP7M5O8DG-=8OS6) zgC}-0RB#h7{z@Ka%!$odclo%m*^<)@kCZ3 z@?lK#Op)Egs1P^cmfP=7VhHF!VQFA1Yq|LkK-7RKaUi-V2&@FCFp35eOr>zA9xm%z z&7#pD2rwj9GW{9_lVZv}P9ngxo1Ch%&|LAQfUg$@b;CTx_b9(gFl_8~_P5sepXKDj zAG&&V8lE-|Am%PkAT`6##6@@M__;}Qq!Cbm)j`YI**1b)g{ef7 zH;l~kS*Jj*=f51hRoKH#zSNQodUZS3r@}P`dCtZsFzK9E#kmao5v;oK8zuw%rMHRT z*CYADpi9F;N5 zDO@Ln!Z1cOn-aP@+iU+qcMW5adY@sn1-v3U0;)`zrC&fxxp%ai!uhH(0wu{QVOzp> z3ECj)19N1iwkml4&F3@SPt**%z?`131UrY#P%Z;KyDGy~6<+qg;T_BT;$KX(q6V0w z@qu$tz;n(#Qr(V%`d<%ER`K0LI9J}g^5{Y~T>jjqONI*op__yC zzlO;wFca}QfHAiex5aQlQb08gS9;V>d^}5+P$L06qLA>@yKbn6%ibzw(-NH$_(_c{!X(&r_KrC(vhoe? z4je@h8xrDcg9A{O9+M}74GIx+`mcMALBbi{m6z;kwlWZNkSxZ3v}=31^@Auxj}udQ zAm!Kwpo@^H++o=-U$C3_57tv!*es?C;VBDngUcX{;R6uI-7MC|P~JC#hw@O~f?|oO zHEVimqdDY*bzI)2DE;W>->!AF?(t()y(pWl<~c?IfP6kowP|SKSy{}h!Cew6V9thB zSxtem4Fcu*ZJIf*6auK(4O4swzHkyJIw7%O~4VFp@I z;>t_(!Me+ycsIaC$4F5=8+pmW?ro+1Z4`YLlQAlCEc(18iTXa;|5(E#?Ow}Ef%^*A zw-^<0T+I;dlP4!uP$W~6>>+GI#Yd_x!zfmV4%*6DW9)iT8bv_7Bm4m6$rycc1~T>h z00Q5VFL!Vm#eRAfY)9g6F>1vyttKBU_BEi?1o~-agIHf>uH{2Iw&n!%1>X>8T zY))!tQ?>*g-L%NqlDVd@N-nOl<}CgoW!6>$B$=ip5%R%MHNMHJ?mR~(Eo`72Tt*Mj zfq{D%)A1ApFa7jta#8C?BhVcO=8vBw6PeW4S}jrzfz1gNp;CMVs%DKoC8y0krjcw! z4;cK$LL+ZXPB3R-a^Q`*sO4KR@Z<8x8&^03Ze4g|4MKZ2qg|77(5rHBhs=>Tu8Ob% zB6j4BPebvXk=O2Z>L0V7KVlmy7_E$Haqq|>^Hkz| z0k^hojoP8rAv1Qw7XS27^M?-@8^+PpR~ zpj&0fK~B}$wb7(~j&ZoV9R(dQ#LKvhu4YP=LU*bcD=;Be9tY{pium%yyaz(rFFE_N zIQubYd!un-eu?vcn?zXvE06!W@)Qh%UJUn}+G)A+bY%zP5-rp9Cv`^~U5_g}1&M~K z>T}Lq1%wI9Ho9ZkyU(@3X||b7ArJ~4t4{Twkca&Lqw;YOk@m9M0FIs z@>Qek2&z6Yv*IW{I*JYZQn2g3rDbCALG(N8j#Hb`POAXZyd`r_^BKzS(r(-6qZP#` z%Ql}Fi>|s<;7%4LEgZMl+5VruFN47pSODy%;K}~c zQ-)-z*U7Klj(WDFrPQecOS9ug^{Mxx+bb)UGcCOXo(lsr-5XPR{gMX$&+Q~%B6wI| zcid+d-XqvVoXfzn%b!;Twx^u<`5g_uM2F|!=}MwsY(ZC;cM$b0ycFkZKX@)i(hCzf zFuZ|>WWd!Ow<2(k2hQ{Q5e5Y2CCOxj52AV)4;}9?KwQuZDMLZ@9cZ_8z!&ES;CpVN zWb^iU_L{+s7knnic#f=vL4l&7b;B+fWnZ7O!H_QJt^>&+pLVK9@M+n;OXP}+C?wj` z<`?-%$iNs9)UDeLKd~sVn9DGS89=pZO=ul78S4DRX=Q1tpPcrStarKI;6g9eM$z62 zt1-|8m&^ks@P%SW@XlE6Gm}%FTIlOqdY4(eTfQd@jf1sM$1lYGHtM+$N_gG^oRg^g z5TUwUav{?j;H-1A<`W;CBNpe1)4=^p-uekn2Fj~t>~Lg^&mn(aEAqOUr+hcpHXdGQ zeIvuQ#E7PA`8-5-Id{$Oo(P2lf>RM(UwHP_X0Wqmf)HiXZdI7kXVnHNrw2PjN+m3( zTTl4C8LUK1rM~Qf#$;hJuR+VUJDHNpJT-1Pau}LRvNqRU-G`~bjpf!Y%%)aL%QO!A zh1AGqXF5n(t|YN&@2=TZiyN$KUpx!#`9j=q4mt$BopT=I+)($g7!GPnCg^#d!9vA$ zb3#>Kc?nuY-)Z#l-~ja`E4W*k?fl~LgO zmF1<%Lr6wck^_ED8&}nc*DKZ1`5&WT7n^{Hdy5j#Pt;Mj(jzONlY@qtoXFdvWImzG zi-m9vvSJ;rEaBFs^J^C?pphfg;)%$}`pH@}iE2H4FJv zU0?Unx6F>$`IV^W`Cwtx?OCy7!pP1dIK++r!_>|&=)(AF>$y!~3~&u-N=;6Jlbya7 zc;KNF1dI#7wV^)dVRXD@zO-{+vcjqlFl?Vz!MF zo)(qklE0PV1s9_|+fymyy7c7>1#tzH z0d5|avsJ3@)B<6dkrULU6BvMB#|B-2eXLYz4xL@tj0MzM+8E#&n{{^#%rpEUf^pF{3oo9cOIkdcFt1{dO);qcK(r$7XrF^!jq`eNNQm}Zj z^vA#wYL9upJaeMXZ1sQ31hx62m&$P>nyVW+QUE>jz&ypAfKQ2OMk7}Vek2z0_V}(u z!eJPuZ9r+p(odQ=5jUYVgD{PX^#Ns?jhlWrvF3Xu|G}jMMZLi(Mzv#gK4JG22YqO($kh9^}1+c%qi7D z(|5C}Rli=x-X&kijYY>=f6(hRcwhjO$;1)vMKQ_&O@o z>pCCvpsJ#LWeb+Li? zvcs~?BPVLJMV3u#9(h{VsS*ql%oBFE$yZTrUyTwr$OUN%n=EgF+K%IQpe|Lv7k;J4X&Y3+ZJUOG*Y`+mUp zze>ZheR!Q~-397U6^bZ1)lL|iI;%U01T`j{#)N8&yfgR}8;HNBI7acHY9yY79ArL$ zW9seYrLO>EK%BogKxEabJG73X?9%|{+O6WS!Fy_?E?vkVx~Yof#!vfKa-dvDOjJ?o zf;tmR=vFzNg<}lCuRU&D@C*cHK)GljK&e{9idvaMFqHb}-#=Cgt9>61Z!ytb%l_EC za*jf>URUAS!vS3%k@l@7w_{VZSgpj$o7do>oxciYU0~o6rT*}{xBLDS9ep8MwBv`h*mY*iJftCpigyJH)WUk&YJ1F?f6a~P>!#sDe{9Rq6Xmc zV>8qSd*=dMWr_=YHXwvzdOkGX$-XX-?YB!}CQ$L#Ow8Jph57pi*-HXCwz12s$$bE&s6Vyr@6ae2iWC*w+IKtecV6+9#x1G%0FRN=%m z;^;(T<*!OhSm7L;<=eu2ExVeDscgqbBiGZR6W7fO>y{%{(;q9E{80WKVS^Zp@0rJUee)^m6T;kDQbv{;BO@l`Rl78+C+q4{CBip*L{ zIz41`RdA}A;gm)YONnE*nYZ0W6k!QPV>U#VsX{c&7v5Q@=}W0Fe|6U#i0viQya@pq zr`HyzSV0PkC{Q(Gi681(D%vTy(?vbIN5w8>YVPB&_=A-SRPdFQSz>(DdlK1z3(k{! z_JbO6dTm}hF%tgV5FvSWw+FGYF+QsbDGwWUI~=xogn|RUhQfnqA6GG`Cxrn=;IJ=- z@b5T-rLx*nAW{hPEuK8_g5b#$wW3fQDGJUF@c_z6#VjtzrZqVlr+0M49nB3;0av-? zTwNZ+5*#H797e%B#E;n}0$%+DG*Sq~1U=Dj+nXr$*yhh(43G9gEGT-V&cg@aoTn-& zpw-?Lylm?{4~Oo9u^a~YfCfjP0y+tgFKu(32;%P(n67g%B9Q^4Bp>Y z?85Y6n(GHjRHOxGR6$uEd1?P@M~o&x>W>4v07d>vB(%i6FSmPp-R^1y2aUr-{IO`T z%+K{=-d`{*l`=?O%2cuU#T|AeWFU20#MmuZg3gf89Cn$so%nXPK)M5tD)i>SYi(#<;0$F<(`T%r9!{J-WTc>-(f7! z9jupm_6(2l9@CYOi26!Jg|VvF)hUH}+*q1-8O_U(82!MCu;sR817hnHP`ohyS_>cy8btxm(Qu>PWmnn{doq_ zUVQBSg;PWe6rR?PrL0_Gq>Dm`FJ;ngapGi{w|92+o?u!}I`Ag(-Ld4i*B0qdrpm%y z%XcG>)ST^F<|&ITw)$0z{G%AN#62E>1lb7fHC*fQan`Suz>5gF2dy>5A>x1LYXq6}bOY#axt4N?|!yf+R`n-rkRMANF*A?T#4tl#d<)y*M% z{}l_@LQJEl>>ptpGnE(OnQt(*;U5^-slwpjZo~^7F*uXADI5)zwW*w4R;=)adKL>6 z&5;5If>r!}XZfD^VthluTE zxl|HQg^FHDgPdfEq+X6SR^x9)bwzH=UOKgDdT4hNi&%Prh{n<*?*-bIEbdodnTGp((A9S`Qwve>wdM2$*@A-KAnK z(|scW>f0~ByOoRIg#U_R(Bl9aZ{EA3R>;Y_BB$3D7F-zOVQ*oWhdofhwQjDA|E!v8 z#hms@@G2O`?N%_&h-Ka_uoQlbJDykeoya2u+)2u6`Dn`77AxTFl1wh>U}~Qd&C)*{ zCKB#QL=zQn#g;(;qoynC()9N!RdODh0{FJ1(IIzJatqN=pQh~Efho4M)kWa9T}X$C zhE)FI#!2tXG|t#sIM9NP{sc%wF43Sez>bSOnPnXH(d)OYJ$?^ll6aT$w9sY$Q-$DD zeCuLl?SYtvE*7blN*QmASpciTPyr+mK2BuQ+8X3Wm8$A(K1A=^oxu-=57a0V_@{I= z>nQ;EHY4rqiyh|A%|Nn!!z4MOV9&W7Ft3WGzd|D=*CR~Fuz|S)CJnp_m!qyBXqLTq zjDPY8X8{^n(%D4I6lkbvR?%cpq{`880oo~S*hO)w)?@;(66Wd^JFH-NOBxRt%e61N z{W|3ENWK%oJNuL_7t9SXG+%W_*&bkhvVek+K4uPcpUPxL+Kx-?vKJN4Az)$P94H_f zR?2K#U?^7;Dw)LyfSmO@ChW0`m(@ldx%^8X^jIfgXQvb|NksvRb9N~Exfc5!Ome-X zrqow)GlxefZQVJm1yw5#olNcon|>EV?i`+UPkzn9r5e+qT84ZBUMJ3M=eYB_bKE)H z>lC-Bf#jRcpBmaDq*61DllHSz(tfO~>iTBM=sHvC65>n6hLnO)*0Ip?ipZ3MDtrUA zFt3<~Gva((_!I)nN&8<8-u7hd;|qszx$^t{vXf#Vkf_9ys7J0kyRPR()lc4}qo4}E zU*mo1iW`NxmxVyDTTQ9E1C!T%$EcQ?rV9aD9V^T)7orFP{$eszTMKmDlS5nH+uN-z zZNbQTFn;->O!Ur^RSb(w+?+d!eJjhgzvC?wC;-E^+fx<=$BJJr{`gTtt>vxUy_9XVJ1aX_+6$EI-1y)ut+dNFNl;bSg z171vqdA6wLkjYQO5z)qTY&lw|L~=Jqkb z1@WvPa#iyLvLE;0V-4$sL>Y7pAB1@(fU~K#9pm}bfQOSRc*?q2YkVpfzp)4}G`p{0 zPZGT6z<2Y)0Yx(4Lmu+)TM$%#^)MoidLP2On_?Sbz7*XMt}_jhMlL5OYUQc2Oi2#6$yGq4I;Qys!%DDcg)b%71YJvbKPys_^f`tyWx1%6Twg<^> zsl+#O$8@xbk4J@g>lDdkUBE!cFpvvVB0BTiG9)W@Md@}Flt3;a-{v3Z0^XjIb=aHI z#NKa+z?7V{YegcNzLjN%TV{eWMU>H+K(o& zZ$y^kH?1Fe_}ScZ2A|<1jXgh1x5Z&3UI2@lvnAYsBv9uidQ!*6SD$u7-~kQKETK9C z(p<*;MC`ziWgnuD;$t)Fi$K9N33H65S&aRdg(qI*FHYz995{RrqOSwmAG{!0tjgiZ zYCBD_gM3%+EqXf!!ua5d2&08yP!dX@H_paz^o6}}yMRrTZ!a$u1NMdXV~0kdGbUA- zGwGGQ(}7sgr8rjaHI=&|k|Kudl<)?c!7CtCwL7*SjwdNQo(}@~pdaD;xbM6e1XTU6*4$t9!d3PbUQJewl{*vLXE4xukM;H-tfs}s0>JjL z`l01(SsB9Ch*FY>UA z&RpdA`r)JErFJQotduzlb6<89z9s8TNlG;qS1zotUx3~jadb&A=8|Y$VT-M%n`N;j z*Gr*Q9R#od*I>tly>0s(iJZ@o zGHC=d@^1mw+Fg?d_0u$`1nThY$6e;tAdLJ;&wr+ziJuy|XOvp=FQW z^n<@ITp|k3fBICpF9W`m3y(LJJ-@4;C)(Glh(RK6@8n7Hb$LieGA+qTD z3gXN@`eA$cmHW6uQ3K`CtmgjJ1Y4LYMRd0O?2D#ec2u5ZbEh!SuAm3cl z6zz1OWOe#RSJTbj>{=xL@&&iLT!MDHUiQ6TDlkiNVbDJ^-H-=4Z5uZwVN$9JW#3qU zplk~ej)}r1W`R`#NwKKHV#f?~n3kT|W`T^4Dw#V(`ph^t7xD7+!|f2(`d4I%(4#Zk z6!A^R<_`@GQdGxi(dq;00`>nX|F}JpsrM!D!_Qy*(dCzm_{&xN1(o>94|Ttm$|Ti< z=2LeglV0*ouzKAe!kt7sYp@Id-N8ar7kWO%{gBN!ZeBaAwmac7wzG-ONyGMhwlK1D8Hx}Zea+C}<}hP6|HPtWk5_Az3ld@E|3yBCzhwm1L9R z9bpfq(xmT=`=09#&5=&hAhLFsNFn;?ja42TZhqp%qR*VFZRJeeGD;?>IbPoUUrNQwBp~N2(3v z)phAvED8#VxT{0-)qW5q(lBt9$YXbDws8whesG=+N9jcsrW?1wn(i35R>AnW%8M;t zg166Sw50_XNDxT2J?imGFhtpQD1O=p1xMaFV7magSb6d26pNm&RCP<$l~12&eIQVl z=R+Zo(u+r{t0k*`X?68wsgjfW+F3ve_wnSy*TQ`~xd{AzSKD2ZyToKBcS$NolxeMd zkJRJMjJ>{&07rfRJgf7Fckf@l?e2lqkMi|qfSP;!nA&}`yHeAeB-dJq`Ih3GQ>gSV zs0d^hpWd&%lg@#LTNMS%Hd149p=g1DMM5v=O)e6;q6ytiCKp*FT}hmls>$S{TKZHf zLbybORIrlGIC7uD0YCEi^WD{waQNXziyaDGB8r*wu^Lvb)9kG9`KJYm>vN*xGqSy` zY$Mwabpq>5wOD=xk*yom8UO)(MwxX4o1CT>gSdIYSC(FHJPz_{jHjH9EAHOjnlx zm~|SjO1s0IV;s(&&9n777qc}gPAZg@D$f;u^}0e*9q85TSv<2^ZZ_E#gOC@haOxbI zsrCQ{|Ns8q|A&F#s(0mM1RZ>*Zw+HVF!z%qsy^f_qb0ee4+o~RWWA0*D2U+<-lRMy zx}lCkSk^(Q9;(qZiyJ@NEHjdVZ={`6jxZLL<#}}FB}X^myBI z9_@+}1-UBO=L495*q(-;v^`cOfGs#1n#&0yY{+Q1ch1%EIjn1o@YVt{e8vTL=l*+Z zDKDd^-hiJjwh30@EpJ$WW?4XsMS9ugBv+n;?5$|6fF#>u;`;tuPjwf~Z!y!YK(J?t zOwZ2B#GlpA@~)~cjZxa^XL*O*NM}(XCI*oh+=brA?=PqE9UjrDnL`f&sriCED$FT6 z5z+K~tFF*^uT+s1monXUW63Nnol!t-sITu0IVZ5>r1!%QhI4dayQ$c?{)W{R*pBSc zPHqM&+}@=`Z+9+lA%u6!z#L;$wakBfvgGbjkzF>*@CWV z5ZD;@t6#ndwj&|-E;yT0=R3(00Jj-d8}s`J24^3>)YP zkQqGV12FB}ecIs69h;21>5}7)kPQ{f18Lo9%f*Czw7dH(f3fY+?(XxvdAX>UnNhHj zDK@qiyG&*W&5|`{EZnmy7CN>gagqGVy1Y^bq_bpN`Qe9^r>=NfTDqqlOdsNjl_kXW z_2qL6AYM0a9kKjv;>UC%r*ObM=^z^Y(5yKjjCY-z0Xw>k{fNb`^NfLArt8L8#)59z z4^3U(tZMvA=ddct*FH=dh(JzxZ%El1#!~(R9|DNNYp5E9$q%g>CGTXyhAPnP^hM8O@XK+aiedP; ztfOL4&_>r3)oL_0m9uKIxeA|+=gm!Uq3W-i7FL06x<^gTw zfy%IUJN%*S6Se-?~vtJJ0o_XQm3@q|z+6s6^u5D+=Z2Q-Dy2&#|#xp;J z`r>B=p2J7-AOQ=U;l`=k0e=V@lQPUJZ#3RUqXPUMN6EG*t-zg{rOR|1>@M&#fS)h$ z=Wmk;K1%RG;!}-kTa3K1irShV-hoUh94YxH;_;a?w7?d3#yydM#2B6wU2*I#oM)K9 z&NHd|M+d~yHGIAObsUXo>2iv=6VOukX|)1G)tt|d=v6uj@{v8k;x<^-L%3?0+<$)4 zKKc14?0$KpB6?%lUl6JyY3=Vx6pH`o9UU&ux67^)_psl#=1#g{gBo`-4+btm5-A~W3Ndw)K2SATKgiF*PPaDw5Xhuwnk}v{BE_@I{ZCQ z39mV!qf308G}hLrUc2wdeT4>tw~{(4$sqP>oh#l^!g{m8WmLi%CA2$%f2lxkQWKb-;bDvk`_I=lK2G-c8|z%mO>R;*+n2F-t;xuU*l8V33*<1l8&OluwGEXx zzH*b=!T8Ffs%u+3Dpt}f#&P8JV?}>%z)otaq<}ixYV#np58g3eE$%%EXe*%|^0>7( zcwkjRtMyDJc&5;XO4BKODkXt%$13%?O1)MoZBDsV;2SD|D{ZycRZ1Xpg+__St7)Zq zo~r!ZPQ6g6TXt$+rMB(Vfl7U4r)s43?9`!3-M3RORcgmhy;7;KRcf4a7n)YmHRIZP z)v*&5R$IEIL@`gR)zWFH;zczum;dl$VvN?>Gs3+cT}Gke6{fMB#H<*NhYriHF-5cK z8{GPsv03MGW0=T1+MC?LF$;nAGag9AA+2>DgR!s1b^Vp4HxQ2!2e!eP`8Df`?(Fr( z<2bs_A_8ghH@Bg7?1z^bVp&NYCPLD8=KbCl4}UiO6;Gce@h=&t)&|p74@!&snB0xB z#DXM)B8_o7^@D*HE<7FWv<}PA$tX~zxJi@J;gp+x6yjYGlEDn^MklqKM8ONM|G6LO zS-HNaQ{_1E1H~n4uQzqZIQB<8j187!kev7<)!M$DsJppG$*&+e@Djz%%}q{@m8|GI zVDXEpp5c3pyW!4`ioLPT3Ves1| zVzTgZaUuKOBvDkM7GGhSbQ3R%6X9wW6J_gFgA>PzpBWPwhtY%=mKLLnX+hv8+4NMe zH!ZHMQ(oy5y-cYV(i$W zt?49HG3qm{jpqzLRAO*#AEp>f?28aAF4u}Rn|9WrW|s~jm(h=IFVsr4wWk`n-G9ry+<2yw0+qC>k_NiehE7tYxFb;U zSe07WNwG>=(-n28mQGTo8ha|~jVh#}U#T)W<;^}PZE8f{3{;Xv;Yyd%xL>JKEz{n6 zRZ5fQ%|s<>(p>3Mny6Q*)S7N_ooumgv_jRI6>53Cos;N8nK^1DMlxsC8dMrPvk=xXWeo#ZVsS&-_ zr8HL8s??gPsCu}mx#xrG;ihi!T9-0tsZuS2yXxVlCi4eP2R%sFnhtu1t~DJPuLAYs zmD!-S_L+i3N!J%F>>G_XYaL3l(<|gfPSs=fOXSGsX4e_vyvmbk+?2X=kwi*2Q@oQz zf!d(3Dhf$g$%Ip%DVZ?|n2-%t`5{H7*)*eFc65qTyxS&8tKNkDtBI|GTE%{I%k5da z@g^^veJAZ1ms4o$x44i>Xll><8qA~k8dEH@|*7ssf-1VkPQYvt3PxbRIkat?IqEYS}m~B?) z_pG{2maKgzO_h@aUn}(7FFTFZ;XPv~X*Qm7F)L|{OF4Q!cdS1#*zK95WTbZIOgcr( zMzcYJp>L(|Fj$!J%D)Fmf#)XnUG0@wLWXK{)NXNIaJJi5tu%PH^)Y#nP2L;E8MgMrz2v1wrsGxoJ& zv$bWHKUTxlu~U1j=dqw75C`_UyJ=;-vzFcsEB(Y;eYZ44I!ZLIsT7%`+Ay>>vJI6w zQnrLP?bbjuq*k#J}kP2z5t%FEab)RfVs61g{tgS-7`auLY?nnbBu zb(;H`B2FfgFPL0#-!^&q#H5Lzx~Y4S+GMv{YurJd)M%`=O(|tvd$w+hN!R#5X}@I? zMmd6mN?HMv-Dg19*$(?A-#QRT`8@>UI~G9KGI=?$G?g!U%WG72x_ zi2=&G#GWn8TCY`oE3Ko-6%3`$WL@4uDy!WqLP3BN)!&AyjX_V+O!CpYU)9vuQkC!W zDTxwTO_pE~p;5;3n2y);-#LuXT#z zxBaF{Qp@jtL#OCMOxjeBZA;C<$-s+a?%Ecc6)90oP1fW36FH8R646mfiIQad3SMB5 zWz$Lhisnd)`q9GarJlAz2Wf@hI zU}98|wylCp>>+<!myV?pLTs7u zPvYzRYPFfka~3PrgMxOo%}zI&u~{-h-B?M?h<8Chz2l8MD+2r8<)w_3W=!PZqryMDPcdO|Ej~ACiC%NP((bd$9rvt6Q!}IcJEtFRWM2uwdAy) z(TESEvaGY+a$hRh#@mH`85mO}BW@+VQb~>$$t@23M6uY`Gp0h;8p(KM^+Sg6Mp^x~ z*eo%)@|1{bvgQFvngYa(`@YwYeSE&Ooj;?raJsemPbCu1e`IN+0E^O-$W*6Y0-~Y)#Q1#W1dPy3SLas>=V9C5xurqk;2>wd>MCA!wQMh>W^>a zAa_2typQ{E%s3^UdL<6&%pqospOSd!wZ6Rlyrh8N!}4~=D^)D9!b%iJ*!I7gA+{aN zydOK&7MxE7v^`^=zn7`v5F5nb+HLym)>>IK;Gnn$eGkk^t42)oD+}Hicj();bEczP zq?04Lj7?9Od)5H_EJ(*m5;I|AbJ73Er43@z$z^QT?|bzKH4gS!%PDXurTe+-eCFR4 z(Ej6ovuJp>WIofvx=nAp-<`HM7s@`e#+S`^Mleq~kRu(H6#di@G*CwAr<~_)6O8dZ z&3U#8HwY|SxIrMvA6S0-j7l1QOOS+a0cg71%JMWhM|p-u=)jOt*sWrlKxs$@sBHro zxF)Us#2(>Di~Y%&J^QiZB{P<-pk{dM&vrss>}NY6f`mgWuP<+FXxH(z(&&+nuNA?v zTpEuFJ>V`E@D}t|kPd7EVWie*Bk6UyXH~}(GM-fgV(JE5maf&6ZDAp!Dnr1QIhjbn z>srMi8t|D42@fU7%II1|y$h&=lLJ;s@7}I2$UVoBo*<`7OY(R^EmzlZ(88*YgBHQ) z5{;TFIn1n5Vg(CD^jj}j*VTJaAr&r+%`Kv`R+8p^0U4x>Ooz`1z&b>vGOw-$oFE5b zQy>!4Af8!JCUY0s1?a&jh@t~-DBj+%buLP3d@s|IS{?y&p z?cLWn544ZnJX z9=$Q~u(M3fPJ$>iR&`s<-Y-~x6KQnK$o{$?Ct(zxrs0G<9XB_rFf++p5M4w&%ea;w zFC4_tPbq*G|Mwy_`Pq=nSYoU{m%lEV^1l({f@1zA-B>mf%- z>0XVKSl`aN9`ChZJgz(lB8br8_j=;a+xD!`JAGi!3IxcJX>bWO%Y#8kj=0+!IO4&8 zfv8x-V7j?&|2SB|qTX?Ujq-jp0=L5m3>HN$xXC_GVR@QQ4Sup-#7j%+zxW{v%!PRi zA*}y4g7P>csYDNH5GMoVVCWUIUEpBYUV(!xWBIfb8HEaBFG+(E*g0{!rv^egD!h1Z zCzCXkX`Ygn9Mx=tF+3Y;>@0X09;87JoqAfW4FqKY{YLfaN(Ts{!#EpS04d))XbKv#qp0(|#b5~m z+Z<>H`;?$|w9H%paML?#QD6HUQ`79w=a^WUtaHc=hV&bqg@!}FKsX}IEug*fHPf}> z5;9#ILTLPWe;A^_K)ZuZb3;0xI>-};(N9zYkq}$r>==l30Jl&>3piwBIYnQ>p)rwi z$Vb1H6%0_Se_deHxZnjgjja~7xUW?pSjv@kNN)Vg8za6Eb>i3UNfbGCm-$!xhtSsM z-&m8&PNf5&Xh%Bi^3PlrM2YFO&z`WSp=D%5bQXnJcW6DNI?uZXWNuoBrQD^$*M}sf zVwK$gZ8zL9K}zU@NOWCs;{8sr(of z7FB^6-0-G6jS9;(%+n$^FJziKq|2GZ1=|P={%z2c=dMrFSrDf7?$tq9G;ojkvtSfP zq-;ZXpl>_-)&SL}nyIxx;brfPS=63VDPvKy5bLgi##jIv&DIu9fR-Q6*)#I%Ym-sz zTXxPMr#s^yz0_y$FuE~ta2PX%5IBlL!Vm^eoyoLku4EgizpOg;O`KH(G zTjn@{6i{Gv)JkfWptXQAOw#aYh`^2Bgv5Z!d-z+%DR77dkq3KZp(18+xrUH1;lMOi ze>)i|ZTYta4@rPAbb#z@U z!gO?9EM)|u=UB!FL>jPT#UH%p?N}uqqCd1+yhVc8+a;QJ!ok4Zlskre7pR0sz8c*- zj-E|Zdg$oc5Ejza5~mV|>_$Olm_H99E{q3cC0yB}VhLWu+Y9JWy7LEfGh0A+f$%2= zLadM6DeW+o8gi_VgEk06G9;@w4C5fZ-ti_i3WkxPanfT06mC!+K1Ttm3P{=yM|d4< zw^6+ij>hO5(IUSeh%66{a}`>Wj3E_ukzw33w^xemW0-8C{H{PILSY3(|1eG%S>cTB z!r&rUzy<+&W*edBA}B6$y z>Ti3|z%INVau4M!%yFSjWjG8s{N&uOjpjrl1EC6Fhw0w7v5?ihX~-X#G=Oe0KXK4A zEM>Ur3YIZURRjLu-?sE-`pIXTnofVRyPupr|4^V2O<_M3Xhd(AKNN&-J=C8H%Zn4u zWNLBt9Lq8o-c|mP}tALOOBL~(&nCm(96rsa3APq5EnBD}V)4o~L4J^lC zsC;^3V)vK3)Q5#UHxLuKzF@$9 zNk!CJCl5kuZGn2=FzSI^&pVwh1IY}CUHrf+gl<>3X`)jG+C-3vhhARB!9hxPlI)f@ zEbN@_VFq?iQpIx%$|9nP=i3Z8A)p@i8*b)C{deTRx>$}g4eZ5%Z4!)dwTOH#>Y77xryyUsqebIg~5htuYg+oB~`qI0ObDZ_|T zFPOD~588*xo6-{dtbAP@#~L&*(r4GNX0hZObE{b~pSPogYAvGr1LlA}MmAKM+<@3e zasXdI8wY$c^EXaS%ciRW&Q>f^3m0*`l|^OWR?5C*#f4BGaj@p|hWk1DI0=W224Kq_ zu!D2FL_0oqE*YTwXgnV* zE&y!dgfvimD++M5<5Ua27L@8s=961z*$%*Vzidle9ebx^P?IsOZQB$rYTdWYH%H}; zq~N%`Bc~Y@xz-zBHpXT1Wn+{bhTg=6#s-7KXMXZH5K!)V%>-sYej49ENxMXp~IIda$^`VL|UqdT?gZS}_p54G3z)0YrkeXe|@qV-fPvuf;4{ zxZ(+u;Wr6nb;`KHi4_UyJTCL1er7&-xF!edsO-}-r@^96^|I5de-4sYb~N?-viUv= z#u+iMWpn^3_v5ycEVj2|+ADq|tR`bWPKv~O`otZVJA`@Tn6^R}qrweyk&1dZOj;@C zwbmvWPl$ucjwrdbvBL|5qDz|~0e!sQB$r@2^yJAE`>iO?&{F?QA#I6xbZ_b3aj;E(sa zH%!fj46<;SN14Kk__+Ct0RNzfxUqE0fQ(c?<-Rf2*iD<#)%k5ji6w$qYb@@cym+uH8PFB~B1a^osu8ogQeDStOO*{5$GZSP zq$>(W%xxT%%u${)voLlrN&Ecf)*&eOC&!|`RrWa-f0$L4!>t9Pg&706A6=UubS-MP z3`A1mFao}%Q)LBh0HeUDDwYUf7@-SecOA5(YdGg*PZ``?e>&7vdQN-r872)F*#Pu* z2Sty!_Ts&Xh0Mhp0X)DGyR?4jZPas(WROi#*>|!=YEphH`{887EUd)S-hwSRX8vxP zHs1P~%MiuB?1UYk5&lrOI|_R#>8j9ZV-gay(LZq%_6z9&M`7P?4pf$o!hRw51&`!H zUZX&#ZmJ^%>$?$O8aAO7(EX}(4J%rg#qDR5WBM3z(DNRyNH?Szz?NKo{9gMI^ZF@fF~3O||@Kyh$N z-bxg`y319rcqYdV>?y)n!c!I4*G9OpNUspU=E_tFbE$8hA=CXpi82>#8$2B*0dqBLu_cWn8B%9c=9s?Y71j~~6h9i^T-N>8`ve$1x9&2GXj znU2LN$tVlA6T1p<%8GKYMJsu?yB!N6tfHzReq+h4!+U0e6K>gL10M4suYncX{F`$;`(r89bQcRb3u{Psx{%Q6c*I{OEp$2y?&8?f zXw!o1dU2pxuPy_c^)j3MT`GIBZxj^ITmA<=@s77rRK~|pyK9=+hqsF|>2V6Pk~-Ib zM=u+tUoF9GwcKGi#hhW7Y3i^z{T?z+)td}2;xy9sON?PgCfi`Eycu1{X=u@uamLYR z2a);6D?Yc4PkKEm`)0Kk{11G!HvExcnc`{{nsKPv$CEq%=ZpUEi!*<2*rmh%7aXX= z-JUw1d@hbRB>L<$YPu>pxKIWd`$ri-f+#WpRSZmFOPy_=v^%zbvF#S$$niLdSY}7+ zFm<F$+yoXWCo7PAa#wz@Q_IK9#-6C+V1W}0U7j#40cOk{D3^}=K*29oaXj7@qxBJG%rYJ8a#yx z*adLGK%`5lF@Gn*z)Jcl(q8t_W-26Rqku*i(WS9dj>Gozrv^ewmrdt{XH7o0pealT zKbi5nHH_?D=%QCxIA9+i%hoA2sTbR57y^hH`;u2wx{L!rQ#cNOvSVLy!5>Sz$Za$q z@(cb<3Fa$`Ic%F?*5piW6&@TgHwOO6jF3e1l9vd~HgUe$ns}TUwIFUFqZXv!BT~>V z57Elv&O}C0RFLo47u6QfB`J{% zgh&|Jm_4+V?)eHftn4e;bT>9`g5o0gcq9=nd%|Jc1S7LB8d(z?3AlnbnB;6k$-8l; zh3vrz&nMeK5StX0Vu^NF&?!2xaX%D`niyL(dU5Zu;3CYvo^TK@=12|$Z=?)_rq4ZP zWit6@wy_)sZWy3h&Lx5r5_InsEHqfwhoc^Xc_^S+YHuv#X?e0Y-4f0>B*d{aS$i?S zB^ejeh40a=52FwgBLrY8JZUa2Oln@J+aiE8#-yhflne?$3VX#c$RzF4i9pnmhC>^( zg&0eX1Kcx$I8Wj&Bhb8vhXeI;sqYm;GVGJt!jNa!(8yK`y`vHi+a?&L6KJDv#-4Lr z<34eY>t|GsIgTt-xkA=<4GT<3q%9kCgFHF05L9_2=1GqBA{tuuE~IsZq)nxO#tFT> zxaES4yD;UAg%9rnNK1MqGtxOz;)}7L91$c}THz%F;j*kLXVVAa8Q@-W2xMyxxg(0DKXVJSv@FcyYH=0@) z;`h$y)i^DmSL><0vri!)qU=)$20)QNNLk}ElWX4CamQySb^Q{0+`Ka_U(^gHjJ z6%*QwZFe|;D2VA{2Z|WhFcU`HH9*RRV+&5q>w_Bx!d^B+fdinY?sGx_V&&Qf*iYP4 zs|sd}@y`s*r1wYah$fkRQlZttrwhO7qucA4UWn*m zZX15{CqU0{SoR#pO4GdTVZwB`6Hl*)&6F$koKFSqkk_E28tR%sFm;51xvrpiI;s!$ zUWP)Bf->jM=LX75IJnLD^GSq225MVS<}Gw;-BrzK;;uiEvT>M46-ALvIZ3^xslT8pk?rnNO6b8nVxM%N~8umw@VQa4P(P!9toF5C}_J3qM zSd;a~!VcC*{>TXf<(EGe=BQi!SeWAyzVQx9`#7|*Cm10M9~gI`(l(G8k3a>oY3MZY zkMH-$2N4-9z9r8fDG#313tz?KPSgDjCcS&-!xHfEx&5l1%I8UZZG z5*zMEJbDtF=8>0M7L@uh>spQb(d6bpgvlT(LRboq4FlvUJZw=z2iT*e!|WMq?)JN{ z-Iudc^CAWU%1wJ4&bMNMRpFoZ4HgfBQd{~W>gSR@cKNEQi% z>X(#70-@BNI*~xSi+yyRZ7p`F9sx{4iAf)TELw#bltjF)u+Ln(*S7GWn1jD)bZL9- zu&CE(-X}jC0-w>aZSt_!MO)d6du1ap4SZeZ-;0s2$PUbRH}th#_K`&xvN>%Rse;Fh zGLLXt9ro4uf75!yw_^P3Q}?4Ej=E_-m&CHJ*sp~^)fI*X7L3|flT-z3bY+M_a zVsUMF?(i5aBo!twQ&Yacyhv~seMNmZN;F(+xEnhuomSA_CS~DID+Xfp+!*woj$K1J zGBq9)h1{hWQjRq41T&#D!-AQplrPmIQ?dsvE+!gfr zG6$y7nVm8e=wb&HDTOu{W6j49rp)@z;{*=4xQ1%^%z-T+jHynx5M*xaPZ40<0Jl*_ zohO_YmJBrZL02R>;GN~bR}^4D4~**KtRyov#Ji0tOau}BEq_}V$9TqH*ImJKw$yVf zWy&BWgV)HEhl$j;DS1qMCzM4CE!W$t#-@pg>ZAK?5k|jfXXZgqP0t76&?MGI!7gK< zO$HhetZiWzKFr#;3BUqYIs`MmGK&WCu>dmfpmYtyJOSP!kjb*UWgsTtf15xiss&Af zSvcaS+EW7Z%(pn9V%{Z{RA0aL>pml!!G|ftJqofjVjHMh$VToH9XN_25sX6WY0-d8 zW~B}RjKX-+K#b4mCJV|u*xNp|bc}_QL2fCTVCLC|Z337l-k%zXHFe=;Dp+4}ga!Em z+ZYE%C%r_hU%^0g`aXPeKhtiJk^v_ zmT?rdAR+?VU>{wts%-~qsGOBHV`^EDX|!!&+`-g=+D57Lgf8w2I2rx|1od2m>2f8B zDv5!Wxy%;6@O!|@g7evPlP&q?RBp2Z?_)Ncr*;Yh_hF0dT>E%9yvF!LJq)-ww; zVabHOo-Zp;dY+Z75;(1)f^*fV70|1tPWrfUeC;D1aQ;N3^MkaYdzt7%z}Df`&9UFT@aa zjTZ@GYO$TvH88gJw0g|Zl^|w2EE@>hUQcP{uBW{Nb%@ura%OyGmN!={(2mKJ=?7iFU-hy;azs19}Bp1H|T~7{#Y0*+n{Da7($*} znAxD%mE)*MFm{7lF~w3hu}tPVY7#JJwz@A|_c3nnGYVN=mv78YssgRK>5zx2q0qbSTWn_FC z7SSW)(7)#C_0Rolo+hCDOs4WF-8*n*02?Ic?Oz1v<>13J`y3ixZgU3OV4&=pd@r{a zEcC*Mg}rk(bHQ`_p>Rnm#I!%#W{+0nXCZq;aD{5PA?!#OXXn;on|dti@7uloT_UkA z7NaLrTP@Tia)yr;^Wr1j#Xy}!3ok_JJhR`N5FH$=QHix$$dwexXf|35X2PF3xA%-zzyfmjeiC0n`C@SM7oH2hdddxgeJPf!@^BxgUWh0oo5DaT)jG|WX_W; zaJ3`38Mr|xKHr2(POg183%8R`oOYHc3$xNI>@fl>;UMkyfApl?PezUhEj z>;fq<%R?9J@C-|M)-`R(LhI~S-9hEOVk#J;YPU(uS^^_ zBJDCclR>`_&fn!%4d31vI`VPP{+|%h{7o<7C2)!v(Bo%Pg2$340euW9|JZ zOY5#jIbk5w-M;5fwc%7J4ooladmg2rkvZW}3L99;EYu>FG3$hYJ~KgRqJ7UJ641&q zabP%cZtuqlIYw-pk$>Dh$D-bGr)lxM6G@;kH*q2f5XQ{gIFqv=jokdM6PEG;*a^avrTon!qy}e5nx9`V}#S7`n z0h*Hjd-iP(_m$H`(&K{Gnm(BK?5Xo-*t!3~)F^S`K-wCknVjWbBTA%CJc}feGD_UjXiW z=SBN12DAIkK-qpn)L2{g0^yy55Z}z&h#cd6;k^yq{)JNxw=93c9*+(F!U>udCk_mm z6Ek%_GZ16f)S||O9UO?6_bdPdcM%J~K*%K%gI3TqbrHnF)R>$%5tf$f*DivTzW{<$ zy9m-a0bzXTJ}`a}qyhiEjuBsx*aEi6?@~Q+O{Go)-av$_txZ(NH74rdR$0pCf7!<*9$4F zXx%}OeW$OD&LH1Q{yH5}n1!`k=%WuQ4+^F7Vi_+j!lLtm3M$di$S;oz8Itjcfs;85h3w-cplDv!Gq0ttoZkZqZxN);b=xKQgp|^ z;8}GMZv{Sz1W@3kxaO{cobM)APwsxaAKghlbteUbxYc}|&!a^eE z3k$i0aBDv9pxy3j!bkKJVQl5F$qWA^xVkKElOLT6x9;@Xxo~UPj~#ns-KJ9J%Bmqh z^3AHpdd)%0SjsfCfn`iP2%uNSS}3so=o6t{?`xk3b)P@lXFoBa#I=3*6TR(!EF`eg z=(sLWfu`ag3+txweqC5MO~OC23%-V2vl~8^F(Tvwrtr9CLZwFOpSkZF+97{-V0wIi z=IV1aq5bT@x>(N0C(BsK$R`@`XZsEVT4R1@5RLesC3|2DrHVhxH2ERy=Vv83PXEmG z+)LPkRdZ{|pN;!GHu$r@x;Q?ozCzLBXREzJ3iufwP_+WCM#rD6^C`OC{9IUU9ByH; zH5vX~SZuvWKVSYt^F_>G#s;D=c2irMnR(Rw=9`&E;v4ageW}7IbJ-V@Op3pLd-(Rv zhwkp-&f!k?;IAT#vs?y!T{e?aINt%>oOvX#AnYz{$T$!4>$kyJtP6rU<=4c_ji{<( zq0GKosKHn+f>dO|)mIB*U3|Jhz;5Sl_uyS;v#Y?pB)))JNt}JvZkTUtGc(QR(bE$l z#G~C{B*D`l-#iP_M?#3z)pdZ+uFi_j;;1wK=M(W+%zjY6g884}*U^)!&DQ*rtF0yc zwe@`d$<;Rf+J;~4?QQ(IxC~_%m$%IC?fEBH3)`juV0d2rvt=NvPJ7|GDYMy9knOH% zw$)mIF)W*QwpUb{?X67%+1gf+?QLp#q194_y4%pdLPKEi;Gw`l4Ip72kTBa&sA$cv zK$B0dHkNhEtwq&vYjMfWYjIo6>uF2%^vrZLwUa6hqxOwj&e-|7E}F0)AAJya^k6Kb7 znWjlv9|U<2b=9AjK^jBFAkWkAbdpP5O!uJwMr^QF)Emk!2wq%3RBUc_4m%1}hg%9u zY$E!bp3~tLPDg#OG_r9N=G98QQUl(3@ZqrYy8h_kL+9{tAO7wBk$!#H-Gg}C58rp* zyzi=_3aa?7DbwBEg1-+tuknM>KQ`a&9ds2jtKVW>wAPxGS*+bJmHz6j#JP!yo6VU_M5#kyErYc|)_w^zI+K0UE6o>G$+K{S!o zI1vzgtbd6lj;?FGa(8!2tczz(9W#zN(L<@K7G&J7Sxo2&h;^~F)@)Y2%AY^O&QpKZ z#MfVoDw`2+Lt$5}i{-Uuvlk_q>9zRN+c*0%=*v_D=Yh!2q&VpONhq>T8#6++_m80E7>Q3=4oh+) zM)0=VQ1VYfeEsT1M0$gXy|Iq1t&3g|i*cG?&he<5LSpC)< zNwwQca1STx49FRSNv!s>cn3pMTkETZDvqR1J=esi8Sog$8u&%5(`eW51C4Q=>a5K? z3I|oyVxt#~^GOOkvv+<7CY73)@}UZi)t%AQ)@E*IIG{03lRU|<#}XO2f>Q%W@y zNv}JND%jeLoxfSIuNJDcPct(&Gcye2bopsU<+72hRJp1VT<^<4Fp2WrgSWxBZUnd5 zC#{VX{baN;0o@f~Ng>Tb)@B|(vcDP*^Msi_di0@}jIXP_3*mIABt2D94es_affUO- ztgGQDs{U4=Fg0&P>;zHcxtY0Hv)G&3ET5TiEIjSW(eWWTti_IEsO=tSh|~ZE<=Hn|Bh2(42t7F%$g|0+OR^ zc=>!FR7c{aXk85kgMsexk%G;yiM zaorYd>w-O2@N3b!S{w}2^#LNE^GO=h4EemOwm06OTBI8xqfF|--qM0XqACxIXVI+} zXJ4v!rPFF)$n{*Ti+~GVYlx-2)1PE7Z=40$-enB=L1da=H+n%7RqaZP^IFXrllgRX zexin<)QaU8pruJ%eiHs#34C zt}3-!&Ge$0;{>Nky;{+OQUo(lS$HaQftn|E9+Y4#7>{M#Ka^K_6;7g0&E{E>z3b93rLvk6C863IrC467CRJ~y{osYfJ?Dj73TqVKyTtLYh<_IgP)8O6Fqu`b5* zW)O1=io2;5<70=NPcS`h4q*DBBZ<2yTfnuhsK4-l-!G@K{LWcmtGB$9%czHUJYEkm^+E8U43~7o;n`({r2Gz=o zN}bV5IH*$D7cITE0DJ6EG?HRt6y&|LYV$A0**9M`krL<>?78#rC%v^9xb+GekyJaS zpY$3%C33-5+f`h!q^p{(3^nxT+&l}Teia&WKHIIKv5FTGIF992u4bvIgtote+<24c z+xijX1@ygUYh{;^ij9ViY>vv!Eg)WcK_*3|Sy`PS97#oA{&Kvm)J@$*-OD3(wJc*U zW^w04yDnTNb0m)QmhtCcxD{00{B+E%!= zi$D!ou4BrYBZ`V3RUcWVxt#%G#u?o6^pM?;hP!f-y1WJ$Fvp>iWHh0YP5=$du%+lE7V03*(x4ASg^1kMQu$q zn_@Q+=W%iwi(F>8048WhOQW*ln;9qPNR#Xg7t*1L8zoJ{hCpHA(J8!sr2lL-6?>Ht zkbz~tuPUp}rg-tH(P+GSsR|awESJOMhC^Z0XvXLkM1|R%r{)hvcl}s*{kWg>fH>+e z9v^9S(~HOR^A8@%*5>9dL#P+-czir4U##A*Q?=hCx`XR|)gg6UR^`VD6Jnf0<%q4O zW>fPECkvyIHaGi7OFDhyM@z?S-1iVlFjDl`2x!VK((RT;tIr<9_W zn9YI1_SU!gC^{I+UKm81Nu0ysSx({Jo+|J?uBdRh^9>2iH$5d_=}U?lxK!5CAnwUz z;A#c2o%}3KE`_u*cj+}B<$N_Ct-M_ol{q}&^<3u{@D^Nhd-t!(b{@^<;ojEXs`$76 z^iO~L&;P6c`+xo~|MkE9=YRXp{v`{p{`G(QU;g$V{=@(Ke**CT`j`Lu|M{2y__zQ5 zpZ@Ki|M_qK>wojNfBN5M+`GfuAU|u2f-A#f@!~bNU{y9ZR^7%oz@V-MnX@ahSQi8K z6I8VRg?Hcp)@DfGk%O|86yC}>{lpO=fNj#+xK+#A3-WA{i19T&X-u>`bJAfJ8-K* zTffyT_50=kt*WN$x}7?!q$yu*j;LXHFzmq0lPh%-Bt=dW@G7QDQ4w=`Mq*A>L@N7o z5XQ1!AtHn`E9m#XSN0reQ;$(^1Whhyc|Oioo6XD1%f{tmBT0wN!~N#fC~7|Ge7~Ed zqaX@@mRKVTIBw$q0NF&`4r6xwFb@H%?_fE4B`|RPjL)Mag9t4@m}v)GKPe zWq%bLpBJg@P0}p9kOD7biU}kGQQbP+s-Z?wq;eor8TVvnDnek`2wDf*Q!k04U<~$8 zp&r5>M^YQ3G7-jkA_ADkFand7RHSLvB-0k6Al3IaAabxEDB(`4U!sX~QPlTwbsHCz zQhlJOuC3J#dqRSGRI}fON|dv= zd(>x)6?LGhqo)dLxprM^G{QkOQ;J<}=&PaRu&Xu>utEI6)CNlDtT*Zy4-Y-O?jJRy zr;9mnSla>dbSx?U2_;EO`l~`h7^xUdvRnj%Tw0U~U@^*6=)&2VV=Ye=D+x_)uyWg_ zM;%;74Ak^6irTIoS3Sar$1ht}T7`j>b|l7TK%AG-=v;P+HVs2AWQQ&h z(Oj~L6Lo4SW3;;c>O!~Bg&s22JFZmbdUKWIimqJY$Z<%!%&?9~xDO8QfdaZe-m&zv zl{u{FvraSmF{4Pv4e+C$*7IRapJZy^vcV%!lna)W4F- zmZ@eHSJZc688tGQA8LWOT1x1(HCB=4yXrQkccu?iJ_xIXEe2bgnR;L3{ctK-^**lp zY7k!0j%M1e)K+XZv1a#=s|A&Tzeclmjo`W8DC}!Xg|fa@E6qx6w)U`90#ylYp+4H8 zr%C*iSYC}~4_q)&h79BJB(E4#25zsz&THII_g>l?W*!{dk-hx)L_Zp9&1S3wu3HJE z+1yM<;~)=DL9WSzT$Yl~E&OI|nY5N@^vC%HwC6S}MU{uE^Pt9g^;X@m=bM@71bdqh zVA^GZ5Z8s=!D8>j6;%(6B`Rh(TYFr2z%f)SR|z~WxwP{;%Tc9rQUf92u|^x2+^Vlu z`(Xx7eErY8Gub5doR=%5YSZHn*BRWq`*b)$3~QMppjW0 z8TtML`guQ^ej=Gfu1WWIcTg=MUq0~FTjr%G?~d;-`4kJ^ zBGx#zN~J%!KZhkUc>t3Y58$#TvNdD0{44U>_8rXDlC}MdQ?`}Q3w!wX-D|hOUDMK> zGR#COKTg6__T8D-36yV^;)whq7e`3@igP4RFZXW9-(dy078R12Kyk*nT7k5qv__Se z6@4QCx8Nj>wJe$^vo&Amtp(a-0=4zdnJKt8jpybn^)Z}DW2H0)Z7?ZmNpqV{;NB>} z7Y#-VnmN4&T8rnZNFQKt_%!2rnK*l?;7SlrqG)aAkq%e*b%sAOA29eyG*eOIP^!^55phP%7+yh`erKB>1W_in zYh~~J@#7ia4TD<6BgUaXl3=$xy4s+}+V$GR~p-qO@U&0GqdvxBB{VlYzx z8#;UxfGtj}^ANqppWeRNJ@9=xi=i_HZz#erAK$z8PhsyA=o_~IdYC9tqOg9N=OmWp z;BtAiOxM6Elhwkzt@hZGs8`X!GnW4RSyU<~+K>8Cv-!zkpHH4Vsmvies27d1jqEzh zSRi+b|fFk!2ZF(PtWbJHe{4pKcYyKrAzGcYU)N zj=%vvh;y}l?rvGz4fq0+*%X!+uPuCyH6C<(cP~tVipioFXZ3>XRbAV%)zRosyN*gK zYyxo>TxcUp5MPTk8I2XY0h7|H?h_g-oKtG4tnvF(A>`q@A4+FCgr<53O=c&Q*wCLOT%&g z89aD{R0be@dslgq6lBzm`{e9g^mcAmtZ&=P3L8(2xFdQd7ra|-(Yb}X?S&|$dGz&* zlO_%de3Hq(q1yb59)0mRWS5u+^pow~`4*%f6 zU|oAydlV9BS|fwKnIIjGn#P(3AFd)z8b7X2GkSSQFb-qEzp2wS0rp7HBP@BMj|laVNinXBL4=^*ht3$iMnR@+ zy(KhD1UF8y7mR#AHJktXpZ>>x`;Y&}-~NaH{a^pP|6=A5wRuOA#_V61fmk0W*&4^I z+oj^&u=y>1m8>NQu|g-CR_x4p(yD+(j2_#^XxN zX)?RjV-nPKlT@PV>oUyGMCHZf3Lb{?D)+798G601&5&9IO2L9_E#bUU5P~wgSWV1{ zMbx3sSL_|6JUU>0{w0QM%ss6k`RiMrz!>Ku-+HRzj+#w!G%b2QIU7+o;~;A8sSPWd zf9mbVxIed8u=JIAy}u_HM(kqNZAiOj=|haWUa8tMez}_&u4A>BjF3Ca;KtPi5%LTY) zHp#`APCH%tsC9DGI;q(uz<6E!x&U9zRe3x)4Pk-Q1K$AIM`EAzUu^t8jzcrLJdEP-P(|BC_5ef z`uMFrzSTyik6Pb8N2Y!o|G|Wr8~ye`)+j_wfjCj0c|`t&c1Rx`0}c9xi`xeH@jk;d zSX-^keJl*m#p%&U6nk{sz9kO$dBk9Ib5Q7$D!!@*uExEpN3RFJs{gsc8S9#>t@_NP zp;XyaB6m%~+9$eJL3iPay}sYrN{}z}jw*SQVue56)x$^D`uqKz+lo%o5DR(>S1hWq zpbWH-uSUt7wm8IMStTMY9~g4Y4O>%Xv#Fr^rlBppT<1GUL;W58dsB!17RTibt3ltZ z^h*s30!gE5osJ?%hsxO`tJO@Chu3524xNqirnFF4`*c%>vTULH5sPv+KNeXbriUma)Py!`y4 zrUH;tIkb{K@J_rZ0i4Hega7AwI2JERSxC&*FR1p{>13eq|C)(%j(W6kQbR-CaU{go%vov;@cnoly>Q_=48GVW)qn2Y8mbgd8WzQq-IE+>Or#v;p;RQA;! zHyMqUt!fZPG830)VehQ2n}Ca)?1wpwLZcxBzv{YfCmjZH__JyxPt@46hOT#bCNrra zs%U;ahCIK~wa9cPVA+S9Ix53LFBzSNu|mGCjG+To&K8@U{r#QJ>#o@E9=_k-71bwK zTQ#LPe6zFL72DnJ7Qi|+-93&W5$gTUaB!{K%Y*DZgT{dmggT#2R#%@CrnDfCq-5j+ z1*C2%$iNI2<|3w*>Wd(X^lB+vBRGx=N>5cldNquD(L^uhnKYhm==oj4S;yL;t&T2| zsujqG1&GSiAkLydtpoIoD6&rT+-v>GRmUQ4m0@I|p%HPJ%vhF-ouKk>qV!=5e$Mxkv;MuQdf?5$9Y;wfod`_knvcW9GoAX zNsDfwf?ozOHO%*wsm&3bh7km>uAWxf}cRNkfPoaskd=xccrj5(9Aio@{7IffGFqF;ybsUVs-ux&?&nM&g zFwP(=eG)gI-jjYZnn!Y*4?w>o(-0P$&MU?}%m}_(sNxjOg${pU_mw|jIhuTStU`*;uo5!eBsnct~^>K`yEv|kyH zJIaQ&Po@m?R|nAA&8h)9h{1WQ-hp$gj@{OD*VW1qp464Ob9p^iIXTWNbE9lH_aX8a zfHvZN{>-!=HyYg<2^I9+RHTF;H5d-C!C4AQdQFEHgJ|k{Ej~Gp`Tw7Q8%~YHoViWs z9GK&zslL01!dw^4#46`;+J++Ykii$f&u<-W+1l`ROYb-YuDbQ>!j`WKcPMq?kHu}O zz3Tq1yCba&HmtfR8TUU%VSKIx4!omh!PPiTl${f#jbI%1lU@`4guv-6xN3q+i%heo z+p`in3SxyhY{jP;NQa}2^718X7SZW)wwgHmb4kSX%h%p>^M%_>mL#%m&!LfRf z6UMs6_K4#!XNQUY&O&9z`DCVZYiU!k)Huj3Yv7Vn7r=-Ol_@f`moK~A?@BF=P8)o0 z+)4gnoYijGYWNwZQSt_WokZ^p14-%v9k6KjRsqXP2WeJT;gL?iye>ZE2_`EpwYRJl z{GwFFnwHG;-zHa(J?F?vQc=`dkizO0QLH>H4kQ~Y1`zT*MYlI$GL!P^lrOYMmNm** zRQTfLEv5cyZn6u^rmC-`x)EQB?)udIy&{ zS9ntzA732k!`U*W@bq!9%qz$I4taGBUpS{JB!8%~hT#JI!ikF5>yn zEA?IyDImXX%~eh+p8vh!KFFywqe4EV$AOwIW)>eTWBZFeUiNFBN4x8dxjWu%n`K@P zmvhZw-JGMSdoR<*8TEI;Uk@~BVEn8pcPQ~L4KIRRXDteQ0(GP!SAtnzoXRM<1b3V< zmZLL;WYxOJ646iMN-kol{Ro179}Lx*gdbqB)(asz?{?P2CFGic2fiQ{IuQFZQbHV5 zi?T!vWiHZC(MX)c;M*VfgS1agptk_H_)Lw&7gc!RPofSMb%H8Yg@*h0Nv1W#0{$&9 z*4H*A3(~#Tt8&Xtl-HiQp@0(gO-EvKb1H#?n; zH(lNK?vG-t^S1N4dms+pZ*Ozh0KVV9IfUW9KiJuQT^Dcn zwsy9Eg!%66i>;l5!~LC&_lG;Xuho3N-8nFrQ)oIo5L?~-o$ot`JKuK?aMhY>7b=bN zeh{no1DoG~J5Lm3zz#*#YIumL8HlY`JyfEX&X6r2w2^T$b>%wL_h0yD&HX}gzZf3s zeADkasklYW>fpb&TjpM~%X|xpLndx*8hyd~=7r#Y>~g|pXl7A2L#y*f?8t9syq2I8 zPGD{N4CoR#bpqJh>XjyK_f7y%)V$IynNBUPydP*?%TV<>D_&IU%ogj^o`Yy%sQPED;~al z(bUMBy?Z@y8qRWDl&nYf0xsnGa^KkPzE=C|!_MyZ&hF0PkIo=Ie-^y(yS;;*y9=v) z2xT9(PQMSL#@jI73UVV16egq&QfCsz6SiO=gY(?4s{T|!@}XUGwvh4%V-S7SeT zb;}xfXUAU926t?TtMzH zV6}kC-|8{WJ^LZd&#K5{W^2FEa*j#HL+iYj?y9x5LP>4o#`kzVpUG-gQXz$bf{2Vp zS-1*e60nVH%EUN}(@|lZehbDn51};F+LU$*^WV3FH%UDFeS0`KOVZzY68ex_on8Q(B7XBBn3NuV*+Op4_cryr_GwaL z_H60R2@VY{-|kLEG7Wn$fy_AbYX0&&+t~m|dn!w}@&qZF2V7vTlGdI;*?Thm5i}LM@^6ht5zHNos zI0~+9tq^wG2* zTvjg_Zq~$2Nuxg{VO*W9i|J=HLzNaB3Rp7N|9**bNzJr)-0Jd1rR25flT*pmumPVc?=RX8`@!Y?c7)Odnbq73;sXhb zIWrCE_t?Xq#CP&~Rm?tlvvu&~#aYK>94|`?bv9grhK*eWG@E zcdGJ`dOI9l7;hudDx*7aOeS%@ z6%Ir17<=G^N>v_YMKEFMfqs>!CSLePjuNuN@n&am*-Y{?l~AJOe`GzIE#7KxiZ{d( zs)GS+gOxEa(w;M0TX4#Ri-=P(>%Ab7PyvO2lIwR_7u~pj7>=g&QZ}CHrKgPPVdHt9 z_a4~G`@_xYUEJJH*|(_yC@baX(2N^m*JoMWxRx*{ATfT21ti#^7&xdNe*+9wf+$dhv!lT&(8 z6=O91B>rOjl2gs0r&|Vr?#RXdr|E#O!VY>iW8pIL^?Rj58&JNVB= zs=S4|z;bKu+VC=E9$C7U*(|ViG>AtN3L8!cf-dt3Q~%|C6!A)Ex*fj-i_308$;nbN zNG5S#v83bKS=cSTASV);J)UjM)=II@#|4=8SA$kUxgP(zrEr>ejUTiHd4>KdVkaVF>>gnDGaHMV*oU!mWZsFI2XZp}9M2cSqOv zqb7AY=qaybz-FOL$*!J6dA0N=@AuPCd@n2yp1>=HuuYj(`jNFak}i( zAf6{g-6;`NcO_b1#uTmIstuob-^jxAVa7fsZuoi#|bOx z@71kNwaF&Lyf%T!3@0kt%c1$mk5w*1LoLn$og>z{9#m)b%x3jPhU2|hP8d; zvpbWTKUfLL*WZL$E@P>3ZXBKPlgUGpYtb?^b@%Z^I5C0*P1%)@ZtbpMk^d##dN{jp z_wO^d;;w*ZaXX!W8etsE)M>$fT$^!B*I^vuOIgeoVlUaGy!fE9an;3#fbw>@OSuLm zUWg9?>6*V(L4OF=u~2mOt%ArDqTJ*)B-rfHyfnd(SpSum8~dlSpFO9`^> zr+>0aVr-^Hzin&a7Sj+r@LSJ$Rm>JkHK+lxDk_!QR9zNpcbyISZmkx=`P@N@&=dZ0 z(tkPWznt{H?@4bIyPBZ^Q737hk^2}hCU~Yn<$5&E(qsKFWCn?V`f?D)I(KD$rryRe zRP#271GxMnH&vOt6d7&EUH~+!ULV88RKSaVs|=_d2O|6WeK0nhK@din7^Xo_4kl4_ z4Go@NBPXF3zVrwxkn=8tJ@5K?H#`S^eCYC*IPhcDD*g+3m_cXZpV|?sLBK^d3H!>K zQxI^<{l}_Lsx^K*DvoQ1jDLAL8`E}#3b8^+0KM*6ray5cIbxFoe5(P=_~#L6B4po= zjSuy%I zU2Cnhk}=(v#iFag2c9_)%v3h9IY@B#VTVS>> z{3$YuG5Xf(WnIkv5Tx;Jtu(Cpj*+|0?xid0UKff))ohA=IZ7_1^UNQl$jXD$%oi=N z0si1ye4HNV>Y=yU*-{_;;ub*qDkj~4cZkz-Fl}K6ey%W;_!df1v>`070+`T8-9k;g z@SV?DDz-I0#9FL7j;|^aZ~sasQ#Jx~QbHTCyi$2}ONLN~CQ6*-Rh5_OV`;4E95siT zO2htDUH3D8TZ=GXSj{*Q|Dc^2+}1zcx3j5n8B>hZY7`1tY8-Q7p}0pMh^7)$!PNdi z^N)Why3Lk*8{->V;z0=Im9KLwD(B9>+6<&|6%6N{?^KygW9)M_6c0fi-lV^ z^0Xa$gGZWb1ma=tjEwZ{O(YJ%b%v&zw4bqfZzuXv$yH)R zC$T&NQp7{k({Kdmj&n?@H|-_7k5z|Q1EHuWAB!?|B;$kF zfHfQH;}hd-bGGJuWZSeD4s;uCw}L!)3w9X?$-fe@L)PvC5X`H&i2n6xRko+U8&Le2c^?l$v8`7iW@m7}3f(#f3A`He+mbR4z{UL+ar29~`9<9P zd!@WP)#3%aLq5P}?p5X@C$N6?hn6nuWY9w|e4knNJx71XuciR`-ErOS4~Pci4#qbtcfUy#nar-YiM9S> zI)ZJOy-%Y%BwFX7>LpR*;5yEOEB$x?Je2r;|4n7>w-H@`!4#C%Xj6G924S2(a58{> zotDft@f*!$`lvDa+g*B{$5m&PJK47?!5jJ`WM1lk+q>)b!~DVh?aQFAENZ4l{Y<5y zgt8*{9h8&r>0T->=+RbrKtE2hyQy8_qZpPB$T7yFFn4RaHNO7ZZKC0HUFuD6OZl~_ zXecRmKaAg!$8#FmUB*`Mr&0M1RnY$f#^L4LyLC-i%04rHufF%(2GuCVH#ZB?Q>RWd z_d}%3ICy{B^|KT{WXbN^%a%?qsYk|+nTF#4bg!Pb&-d~EfBOPWPxERzw@ppC1s%aL z=PA0Jdyi>q)7SR6?L*d6c$3;*Po@_tG^MmrC(|;qnufjyCCa`W$W+EX*;jpKw_We1 zRw_vtU`;$Ikzmwoz_QB5CcY3?!R%wDt?<672?F+9K`t(!4 z4lheb$=dz6b)rC!>`9Z$FMQFx*;1H=7WIWa$ghrJEsa!k1M2(H*XR2As3 zb#eKJyt@HVFS)S$lc78t{K%xK0srLD^ zFaF*(-3ML~^?aw?5dc>}sK0OP=K&W)-ABny@b31DB6ctNr8)x;SFER2nfl!tn7L-y%+m_>fJ5h zebFg2KQi};*1da~c8R#97kgE>Z!h=Ni52=f^(sDyOWpf|V*AUe$}N3tp2^;MshSa< z)+~D-rKG+hYzQhV)LXl)n)|lN!>X!fo>FJ}M9o0&J6ZQF7{+F*O2v-JBPi$rGDu`9 z--F5@p+n|QnvGm$IhHBA*#l*L1ws{7aR~)C_s=J8$8k`Olx7ca9)j=XO$PHsQ(-mw#o- zg+NywWTv;MZynMP9+B0zY$p^p0-BL@&DruN!q>{*mY?#ln$y6m>2IP|S`@h(DNC{#I1POR%@1AS;kv9*FjGG}Jnxmkr{Ux0p&vdXPj> zatU}xG%A&rZgEv5+i{z>&nexJJ=xg`UleX%6mDM>Zhxf#x6pvNDaV58`O8`QhY!0#of$fO%DN|@Li3VX5$-W)A z%8VtlT#l<|whhRHLE4x#al;crVe?frOvdX?ANu=UT^!A-`^)UfFYQJ(XVR}=Zk0wK zINK|OPlVz~R&muFXd^$9an&HEZpQCe2~}@)^kUtT279*2BO$H5tkpC+OhI+y}<5DtKOaHZ~0;#lWwYvCFE6IPSh9K6(LS3kY##LAgtSs8%mAGbzU&Sv9 zN{a-{NY!E`waQm#hP|%UL2I!puGLbL!!-!sSU`<-0d@%N+nQOCVvd??J-NIl5(r{A zG6Ss(+{j)UD0-7u6)cl<)l0OkRsHY6s?gJ4D@#{nia%Wy9~x@!&CRV@=}+~)s^?M{ zFcmbE^MuS!L(iOst~KUiQ|j5ZPS%uaJB-WnPpKA`S9RGBjbxlP#>p7G8a^~&N7JwA zElhnF*QgWKGU?{(LNA%sM5#4CGLU((px0d^TW!WApbq=94N85*yIO2qw`8TVRTovu zkCn~5s<0$piX3TN|9&Czqs5b&?n9&1ViXf<-KVQ1^%fsC@ItXkw@J-7T}rv7<=k(t zU1+a;vPMe?cg|#7yHC5SA-?kE_qcmdgWHLsC^&I!YG-|<@k_aLN^5#ustb9d=@=B6 zVi3kb6v3en941HbOcCo}i)X|Iak)x1mEt>krB~7ahjtlwoS6F+ovPr=@k1KsQs)OT zIbH65T`X+@J(lPy1=?x-p)SUlS7l2^av0?D-&s7_bnm9yBhBm-Q5(;*;+RtY3x`$qP1u!d zW3X^R57R488nuktmSJ(K9Ao{FBxyK=okWeehuHUegV=8B&S&nVf~7d9prg6P?W}Y= zIPPcnPATD7;Mw$wM)AV`T*m0`qh!IAAEXZlm9&OhdYE@nIo3dG&6geqBcxmq$>txLH5l|VT++@Z% zQ^q=cr(CX=iMy-@5 zoAtfbFb9QTGre-kHX!by90HA2hURB2TTeHYf#0o(s< zcPDEKv6~M3TXpoY(8STzjS+VNWRY1eKhLQs$)U7xynKk@>cqdf`IoH)D01r5Bx(C0TlAYW^JfD6f~cpOE2| zkFjn$mvl+m2PH2ZG{aDa!>_%Vb~eM{l12=7u{-zT(dN$?P)D@!t$<%eUu(?~ulF{BF8t`C)=N^xs%Ay=lZPHDRpQ!3FQvmm!t zGf0uKis$pSzj|^skHwK|-Gz0d$KgD`&;M3s^o`;az%PhvX z^$CWG{Vh6w|?j>2lrG)SCQiA2Bw9ag*w&BJyWIb)`4CD0|?xWrxAaiglMVq{0@~v?kXC^s}MCk z8?A~6m~SD{6ts+p+d-2zu~)l}k2d_kO0{Vh&=aO9+i;jo&bhr_bKf^Z39ODa8(y>F zH5-0cX}KAJXD2V7r;s)8YUu*ZmmR34otyfPnb6*BAMCx~__YTod~5&kSC`$8^A^1o zPF5_9gsGmCjXRvNFl{*ESAZWj&xRnZEeDL*AEe*`Gq@n4ePSg63mH#d7##e{O~Cz&&bm1} zX*z6u^tq<1OP2oo^@ry_zWm|kk1IcJZT;|{FTVfV#@}9Vz1-S*{p!W$4_lkxzxdDB zOOIT7^K2k!$ThGFXghmlbuf!)itjq0$#jyU3F(sVjO{T3NBN^8H>8XmKNcQ*nX-40 zJtu96Q5*}CzuJ$SHq@?Gx?L2AZ>8Ises_*8rpZIEmqZExplx#j$WkZee!&e+;T*7I z-R6fMBW`&}>_R!RMjE{yZ`jD~mIAxc7na{pWvw)_L7+ett6D`R8RAs4jb5vbQL z&MH*4UUF5c<^5#D?K0HQP5eGExiN}2Vf4sx_X1_lpohD`$C!%G2&1M`L*gD1X;#gq z*KB&trr&n4#*0l+C`;7ks#dWv-M?v;_=+p!SP;X;{66~N8R09|z>XXeW($qZ^th&& zX;Z1)P&4DPT59Rf(o`*0ZALp)q*jzt)n~MTkid%%-b89+#FxY1+92ul60+yI{1f{a zlXWvvi06No1ds7WDVVyQj?FKy%Dg#0i0PYJj*6Ias5oz^Hcl?_#2R_fIrrjbsuraJ zQb7u^w_0^bRZMOo4v7f89MJyAi|D|tDwnfny}n%D>NLff3k+J@HnFkURiQ4u^R+&# zzG&-<_D;*vqt$2ik#=Kg&jo2k_Wzs;OTd*E6DaixG)DM%G9OdKOFzMrBIwa6r2!ly zbmAPqNm1>ku%JzPr2oD29_PVWdWd=@;=yXx!dU44fQ&*ks~69($vWT^D>#LC;+z9M z4L@l>(TA3VL8T9R!@A*gFL65YWcAT?ONTy25bM9e(p;0rnmpFz@lI0jQ1tbP|MESg zvrS7J(1AC$7mDY zay6aAK(*qEUX~(Vc*4H9CpB1fr2+dGm4KopTuc-K=(Xb52T6xE_S4;zJ5Q(|cC*s1 zYdx)|xb3jU-pM*w=ECH2yZy#sAgrMrCt3bpW81iCEY?LwW954u#PtOBq;Jf(P<+IA z(%FKX&-_RJ(A@r)Gd#8^J4LY#i4_KHn;=i?OnM4Ku4OQh!hVh3Za|>2#2R(nSS5f| zv~K3c#Lg|zLYbViLzRLu4rCge+F=}e`SH`=mhTg&pP3TlSE|usB7tTGW4mgdPJv3T zs*B-hS#?2ZZ!TOEv=R%`{oSNRuiR=k!|}MdDp5NApw!?Wyy)U>7@_D>qDar2vy=>T zzu6>M7RRNt&YjE}4#|yEBUW+=|DvS6mOOP=xRr3%&1nIc~}45z`MW8|V2WsS>yq@vc2 zuQcowk~#1BEVUeOgU&(x?^SsDclAb;+#o&w*)x}uOkV(4b~)<#R@kFz$N7VP%5yxG z{Vr=CTIt+y&MaSQPL6R+8+8TL)=9=2eOkz63fm3D@bk5EDz3ISH;TI)Fe`im}b7mn+0Z*ut1{ESqN<@BS zrwF@0Q6DaN*pVN%o0Tii!MP}bR%+$QEoNY(Bgp>8kOWOw*N1x^86!YV<~7I6*;O0qcU!T;HeR9xS7`qAes< zw9kbEO69_82M7Ei#ifNdx_rG1Z4dcz|_YD!o^ zKlt)2abIcb1de>1fM6RRUC^1e*$TIY9JjOr5ElRfV@yalKLjK@Q%E*UBbig>(K|cp z4ISyAl=478@#w`dWBE4ov``kl3VzI3uii5&c^%a97M;a7tNFF9q`N0#SIX&C0rivv zwQmE}+!&@)0pOkjaQh0lr|uJcf#r^S{iEKg1rdHsnkIs{j?&9a-dpnD%%_IcR^~s{ zfmkg(cP|%p?$knV@AwUb7QNg7R7-LYKI6-ICAHLZQMygT`j%N~&4q0*bFgi|v5jg+ zUl<2sc}WZa#i&BDfg8nyXVx0&(WBnLiDoaG1qDRytB;w^YmUF>_-l^;_PwtT{W1OD zFreGPFs!76);n5(+WIR92`Hs1O8yPa4PAmU4tr15$aav7Am1g0*KfmU>?O^Xuq6(5 zCrHVftxm#w8^lH*veqorbf%^=cV1xeuXTaNy1?RnDzNz1y1-&xV6iT+SQl8V3oO4BLn(x^SG85g`5P zj)@FF=u0dC5qM*Us;9~p>eWW%=$ikMnH5M2g4dhBz1Z`hE{ckfH+oIH$Q#pyM(`@u zJMM`$vDpK{Z@Z3cRTI^ogp(xJcS?ymB1oZpagmGyBY!PfV5CZsk#dDbIhHdvN9cTvMrOnFB$=qG?dCtpxAyRYxM~hG zhP4k&zd2^%1d@#?d=$A}Y=0%Qy>=&b!Hvz%U+OwirI-NX;Nr18g;MzcmSQaYF} z=4p%$?KU{`kV?Va*8dAvrJ-fbN&xzn-A=pi;_YVGSr{zTTgnYM&?QxP1+fM-B& z_`zhF?CGplqx~pj2gG{Q4G{hy5;d}Gfj!F2MG5Dxi~rBy0^_dE$33!&TAqi4u68ud z_vh3b-~eeTH2m?W=U{#McNow{H)RfUCAe&Cdi`_y97M$^95uS65rohC@XP|8b))qo z$}LVY0v->a)g?T|lqp@(h-f?sgV=5$9)l{ZOB%n&VbDmG0WU#9-N;^+nrg)6b9FL` zO0{yN>~n^9lkPcJYN&GFbkZLu!d%Fkq0nbPeDuZ%s$Eeyd zs&k{~3&Gy1`q8i?$|`zs%$ z5>W5rXy;yxG6!pqGsELaL@)ht8e^jvUiU*-U_v`&dq_MnDy&BE9&PN|pGKe|8O>l= zdkwfYZxn~JQ%AD7oIU(+gg_OiFukJ{XQaQ-uio{lnHnamfLE$vP7Sa4vJXXq`xCnkK%0!h zvorWN)+>UM6u8M&22-gJAJkQ5A(G=U&1M z90>_11gUwEKbm1~*U*Qjy6oCrmtE80UZVC|ig4X^`L(dI z1|elSIj}T@Q6jU~8p7apI%$QtLXG>9m+CHD2+xw z@t7uhqV%WBt=o4PS(I-<9@ZWpe4v(*+@lhF4+m-nEb&MAC9u&Dnr(BV;2os|_@53|6 zcJPhi8TR#h0nDK!03W$CKTc>w2NvhH)Fw;6cu}yFgXa}+Jv*dXJ6A%txH9+2)Lg4p z+T;~@SN(9@nxF2>$7)T&I1x?rcTQb`J*$FlVK;RR_sZSFuK(D@I&h}Gu>V_LCVtY0 zi9ZHL-U|{dl%Fxm9wW0OFHXofL_eUba~cpd!-1b>a!$)kg%O64pyO@g#l%n0f9Tx1 zq#UOQWEh2G+mn>92NgkuQ*kDu=j0-afg+e2PU;HVBjHmQXWX@kqE;U8$a*Cz+m@My zWsGBlH@7*O>s#|XGtT8a`9r>IVdh{IYuJ>S70GAD?c!X~Uvp>{ApQ`AH;^?**hlxo zL0iyQk8Kz)i1ub5AT8a=1t;}{)l=3KS<$F=U0-DoB~&qL_WPlKj>h< zJgiw_NxfM=9Oupha5;~{!2dTL@CCwUz%`vSqpl45j7H4AeGE;`lvtk&GZs56uOHN_ z;^7q#Bw?UUBEI324#P;FJ#P{!_EiqrnSmu(#Ay7=U-Mm!nX)3q zgBs0#=-#Q+5UFeEFx-v&Gq8F(rC*1Nr<5e2b*(5!xOpx!?<;Hab{h0=L0Y&EfJn8_W5%qjI`kqq27b5@h~M`DUo0vDBUFaWN9dB*wf5QB3VWDNWq{SpW-6z ztjHUv<&e2GC|>D-vP1$%Q7wP0&OIF0PDYx_ah_p>r6yv3%|DQ`nMLC7`3KXCQ8=LX zyZoT)#NZhG?@E{eK@zCrW=2JD{Rmlz1Y2w)=2RAq*|hY~=s3=^a;jyPJz6@8t$JI2 z=B(f;_*!XNepj2Sv#JmwZaIL|ncR(4tp=Y~IClA(iTPVrRF0IJ;5z5Silw=SquFGl zwRP`eANRdz;9}+O&t|4!`cpYWd2iH_@V|L-Q2C~?;&xxyd1V)O-EE^_GW(&~gVIjWS=Qc` zqsp<%*;CEQ4VF#&))w$wCmC-H12og5wOBo4=Turjadi5U6=ETys9Fj;zXJF=mi5ta z*d~`L9kH-9YE4*7gD@1giNmALRkz#$QMMoX)oxR$38AX&FGw+qL8}0UQ8@78^PV5m zKc<*k^)vkh%3sJ*cYTeKtr$1?9@~-T<}^;iF~J45$loDtaok;AX2W#);duEU&>Y`) z$q9Q7ZmiRh7y18&kWUeKEI%W7q`iqu#cfPo1<_#zz^FFE@_T>I)gk95VIIg5`XOf8-W<3!|`{39q%{x-);3E3ia3C!S?@dku~!2#f#NP+So}5 zDym@c+z*gmod9%(en1B&5Py8mSz9&cPa6k6^*-*r*?POZv-O6okw&k_zYyB@WdB~T zVb28VBOoaF)KA7)+h{u(z?l)x*HpjrYB`?>F9IRLP_7P_@rr zf85#Ke*+<{qQOgJVh^%Y3~5AzJ{40&XpK18nT}6sbi$$$y&%!%{;=^sy@QRnTfOa_ z!>xB)`(%y$?Zt~9SN`_5mw)~K$M0YK?Qbh$mJ{Y$_#a8gf*ntIz?e3z8rO@?;zJJ{ z^%_SZ_9Gi2rt7%DzYKRZ)hhC4ss$+i>=y9sEypR@@-z%bR>Rj}2+B#>1bk(zCQvz7 zzDIqb)c~(x*#a=xYLHsU84au^G8!q>cI-{8wjaESd>i1lSq<1;YHdcNREyC_zGu&@ z7HlJB8=kSmYQ%k(^;Vx|={BF#W<~UjezHGkpPp@fQr{F)doc%8tt3XovK!z-)doY- z>^AsNwvngPYW7h)mo2ZTckv;$3%{_Z$9S|EI!AE-4Tq`y*idhDMDu?3=~Wup@UcRt zQRpSFUfLMNo|*>%oBr^%f8D@RsGKY?l)y|Sj8su5G&ES%5iojL2&m^K1&#BRc`TF1!Zesv9OQZz?r zexbVhYV^&~kzcc}j^c)OZ5g{-UA@>X>F6UbNLMd;^Eo=oo66OZT~Ur+@^*6dQWpsZ zNrUl89EUgTYz-qyktajG_T+37o_eDbrd;2F2)f_3GXRa>VGF*FaEQJgVeoq_p0AMx z`^W}pIIXv-CmnX{qmMoRGu0-4#W5WXPs}AA(9uvWFvefzvhW%I*S!RIV{@{eVk(7o zn!$@RG#Wt)L)6VFczyYzmiFa~WYC%o&0g5RbQXCZ%S9CHd$-tA2r}Y-K|nVDyAy;1 zOf?PV+{!LqI8VOYk!fX&+2>a7m2YX~K11p|{6OeY%b0`e{dBBp9 z#2}~fb#>A(U@sIDwDm$l8Tm_e#jV!9BOe^R6kFbz*ket|nza-@J4baskbNI{ee65* zz|&BSPtNIR0(AuBJOI9ri9gcw_n?CBJHnFye5dD~(N@J*!GCs6{a^sDX70z$#x(Iq zjn*m*XM_Y_Kl+Ym?D}r`skKh0v;`~Pjt?b80-cfgh$m0v-yL6TqccMrB%aW|?~TB} z0&+GW8iYe~((AB711Bt9BHq-P`zoBOSejuN;V>*s1f?WC52NJV3kET=Klt*$CXs&$ z9`Wo4R3;#waV6J;-A2a*0(Y3G58MMAjfCKoV)PP6`Wig$27Vt}L0740@Po_nf({74 ziwy&jK5PuOZLyqtpZ|t40g5*Ey@D+f?3+qj15a74k0$=zR*T>`0z2Xd1Nw=qk>^5+ zCxnOkukkNb*?AzwiA~0u$Q}`mxA{0P^oJmHvzj3AkY})X_KeN>cRo=|;3+Rigf100 z%@H;{Uga!4loJtOz%t3S+49@0c}tEYCO;Ajd-e3B84wP8<2b6UG{z!1kZuTk0FeYg(>ax~{&e1z{n7Lh~G%5f#rx0wth_h+ym(Af#0pZqu}!gD5K0cY7iXDG`4N3~FA& zrv~I>a??pk$Z;hCyMVYZtupi`+|LMlp3%ex-%}I!WNTb}3NmM+ek5Cs12mzKvBk|G zmEn+r3}2#Kl8tp?a7jUuIvIPD6L!zWF#2-_#fj%fWf5-dO%Mq1FWSR!=n@prHJ$$T zpa}{YB^!H_N|bNxO*&v&z_Bx$lhM#Uc&Ou=%u;t?}Q=9` zEB|z6y$`PfaT)kJm`&$Z$fKv=WqGz{z>4i*OvYXeH<^bzDlaAhI(TTxJ}wn`epH}a{<2E=|`RIt=``L?%^&dYa0y%Az}P= z(rhsEZZnSht=>wfL7u@INQ>EMtm?Wl)3m2;9JA{gW~k~mz0l5SorLV#Z!vjfXdQRd z%ppt}5^D&d?^zZ~@ZCZ_kRLlgy-8q@+hLwLYuwo0Z2Vt?JOeQ5XviWpOay6lB03p) zeaP~wOp|TW`0cm9JZZpZ5!qtd?D|C_M62_3y}7>j+i$-$TVD`$JJ0xo7Bi z(s{bxfYjKHzce0wCpGV{1yx~pzKf_Z3sp+pyN>6#!{2rlkHcw*$Z5-(v0wa^vP+BC z>WOl7z;E1+w}R=IMyQ=OH_g>VI4DfOS4)WKtT}t8JQxlYB9b+++I9X%M?+Kn+qgdX zbtWxF;Io1R$V8w!6}U!1JzO~9%tej+yPXI^(6O);@=M`Dw1o3#G|@JnzZO0y*lRnM zd&U1)=YMqkICG;|UmnIG_yayCP=~h2fn5CYGGE>$jr^g{4$&!1ofzSUfeEM+c6OS8 z2yN03?;0(>z7O8S)$W5gkxjUxjH?-cC7T|gJ}=emfF`mDcRg`6_F;^-G}`ZS z*`UF4PB&Uv7lAj4A^kPTW8mlqHcWV?U?nWQ;8GxoR}voJ-PaV*YAJUncf$|fq-8oA zx!Z}H?8;fl-R^)UEz^O=-Ht=7mG;m>29Em@q0VO#`C}iT7b7SbVb>tRnhLJOKCvp3 zej3GDPn6nr!C0z~w66bRN&9w(=`(Lj5$LkWucHhOR`V5cYF0rm_i21Aq*Yz+VyY96 zux-ZmCoev4@~$NnmAtj3s^m`%WhL_@9#Ic6nU=L|F#Up@#ba8X?)df<4rCgJh1}%4s&S+A!KV?8(tfpe{b?c~L)$eFx0dm0PE(2T$ z2@K%V5ZgH368z9XLDzyGx*1q5+os}6!r4?_yQmo@R>h}vrxRnq5_La&6*0hP=QB+7l>N^##kG0V4N5B8DK%ieaJsB@nQ~4 zEDsFt^psnfm66$OCO1crOZ{-+XNU?oPS_u?j{&Hd9-&W}Zr* zc-)J?+^co_;B__ql3pK#@7Xfh7!0Hi0=5Yt4!Z>Z>Xj?uVkB$ol3cZ$95omXZXEMw zjDn}yf%L*#yrW6_HB_Km6F8lI9n0Pa(A&X~1!Uxde=eF=z6M|R-j9<_cvCZHY9}hQ zXcCGxct_$zF0*!YyckBTEyLs#7p9=Kw~eC!#;W+?GBAALGTg+ zA77-b2iz-xvj7-a=*5X}u|jjRs>iZwj<>d^8q0yP3ojpnPJH z{`|Q_7lU9j=L#oNsF9kRv4->G%FXygi3H`C#A+D80Vt8c;sf!1V`K1Yl|Rw z&z_l7MNleCNUGVdU1ZBVA*QvkG)pJ93HDe1a4>h~&ARGrY_NIO4dU*>89trRWHe-~ zpN{$&4P$e}EKU%89&|pCg&sq8xRSmUx5FTUinQhr6XujsnK2a5bNHiVu!S1`mu3_> z1R5YxG+0qn5IH#b8)I+6pMv5X%%Tz@h1R>lD4y2YK)vQg@`%;cg3{EC<;Cn)8O#_2J#L5wXD z+Ah3ew1LywGT8~PLHt+On3dv(1h`?F#NQ5X$hc2dT}=&M$fR@5_M8*a4zar#1)K2=xrf5|Zb#Q8v92p9fQkzcn)84Z!cu@d8i>TpZMvt~v)` zHeluAF*X(hgDTU5AP*;cbn8M z;_RAvtAv1+LBR6mDa0dWPVml1OH%3rTTL}GWGIb9r(1IANst{!1J20sGv;Uzs}Zuj z2V`UtqY%>PTm}Qeaf(F)Z2f%XLx^(zDa<`CjwnV+e*EB^LbBNbIe_s0;f!w!_}8j; z=JKjUI6Hc#qT}ED7w8zSa#HYlb>S`Eh+w<%UvI|wT4h3sHzIHde$3iEdBUEsc;Iwn z@KQHgKV}19Kjy-o?u3bU+?^itA+f*8ykd_LU-%QW?_f%5HqMtXeDU}Pj)H$3syHc) zPtZqL*TTfvEz0vs@I;E>T?G|PZCRHMW{9;ivolZ9Z^o4Ym1-(v`0~Z+w57#Vg4d*& zmXOCyebrB%kfwUa>JG33cjRv{u6`;`WJot(?FlRnE)wu*hio~zH&wtDAM4=(%(u@_`6z-M`482RTq z57nTRPA$W3E~$Din@~n_wrn{b6#Mi0ECPnHEJBh7RN+}%fDly+aL&#);|Gu@CC#Sj zY)vIyfch9t^)XQ;Kp^YZ)p9YhN5(v&L#rAJV%}1buVm&e>-@8)FWzR*T3NeJGuPl{hM&tD6 zgnvxiwO89Ie$)`r{g{CbcwzDW$rHyeudRuc>lJ~t1=;!q9p#yL zVlwff#P>#ezIq%DOE^Y|`$^fLxO#Mr5M1!P2ZN!ihu|x3ixQ4cXYg>I})Mf&% zgV?OGUN*Ur$-}Ol)Cssyw(r`5=HrahU_NK_wcG>_;!N0IPoD4@9*Z@m$eIR%HxJbKtGJJl|7;YmEb(w0?33wiFxS+9umRj<((1<8VeXNsmQaIUQ5(!)?L-V*2R=L5a2XH0A74u{JOePAV$a8N%Yr zcs>LdLv`7!*E5BHawN75Wk)oj^0+Ao;1g##p_XBLz%TzLVi^wC6u_T6ajNjdIvc&- z73T*b7KVkTh`g$=mRiLL8@+x(M=+p+`^{5=(e$dT<$8RPvHlTABci*r^2P`%VgKi zoXB2L0%1u@lz4sW4KQ<8xn!=3m)&@nvb?j)r1NFBAWy$y3*M4H6>pH>eDLB6DmuI36Mj;q|YxxkJgvLozCQ0EdsJLs2UaFlFdUUf++nw*9rVlU0 zyre8MB}8yetYW4%Hw-OICV6a^Q?W(%<4OR(Km{mc{|6zBg9fB#q+UYei5JCG3JWnA zK%Kxv=_(gt&4aJfG=S#G*b|o06kA~=4bc0W=fcQ`?=V{Nqvv8;@-91(GEbFP#3qoOIOM`P8G@OzbZ*I$L`JMiZ;u^bR)501zJl$MY6UV)Z zsHStVoI1`arTMW?ldX|_##6FdUKG7|nVodOMK)kumu`xN zby=!APCt0HJ-UG6MbXcWiY2DVAzI){Wayxx?h2PJnL+5Ykd@+SqefoW4nb2))0Rt; zQT#dpY%vc6J#7@#SB!}Msx>E8%a>ah}te2svm*0LX~QWzWx zGSjSr7D#1A<^{c`_hXqZ9){N&>;5LvCqf|?J96yDmoJ)t=Gw3v!K{^9mO9;(28=t9 zt6DXiUh6-v&7m^($lN741drop`T%{@tS>efGWX}}4jndURE%FrIMqCzHF9dd(x}k_ zc`ME$Xo~T0h~vl{s%g6`zJL03CroJfDKPNhVWujt-|uNLU~I*&k3(q ze9|T-P?Z?|#p1*82QT29Ef#Z&Us<)E zt*T7Q>nRyQh_8ICZkK3ksy+z2S}D=4ek<@9JIXbUGkrADp4nb$dN1a=X7*ywY#N(V zPisV3RMQZuMCLuWsxhsY@t9A+UuxfHmRViECq7nW8rV3MyIR^ai2d9$h!%geVWibQ zhL?oxn)^qsN3trb{MzMZvKdmyme0|YIdQL?AQgMT5PX2n(2yt8AC3H&_CsDKOboFd zTzVs4Gz3iU&)u#k!55Z@WBoY3_JrdH|L_JhdpWAxr+JWZfnDV<0#53NGy4x`>U&~ zPU&R#Z0U|<_u4EjvYUn@fQTU>B!F+2Tfl1jc1`x2C1+mK%DotUSb<)nPkDhN8ZDsm~@R~xty5VOMM`vz*MuP6qxA?B-;`wbb@j?-E|*dYM%ST5~98@ zUH(^BpRNnL2|I7yJPSTL|CjLeSb%<2C&dd@uo~J_TgREck5UTIP?aa)tH1EE8ilT1 zbmst(`zKeNw^7{NL25l!CBHniD9f0BTS`%}9z+G*kp;n)s}ogS)o^SOlT^4=qKo1^ z81Abt*OjZf%(YIM3i6psL)RDODGl`*x)T03Q>GDxe(33;a8U$x8Foz5iHJ`Eqz;j37)59+^{D zoR`s7{8QKeHjPh53dd%B@`R*cF{foSUJ=BgaHznrMjGO_YjDXBUud!4;*qI{76S=D zr3T_J^nuu;LY&A}sp=GTPMxYNVj0TR1aWG?c0 zb+jUD2K>b}JPpR^I;iukP~;mG?6CIhM=9pkRfbag2*p>6!3{qt1cJdYx>uWUA9p*Y zG!eCuGJsLRWhyIahII{n?K{W1U|=uK^s0)FQ|voVJtpEk+fBojpi*60LHr${&any4}rLSIY5=UHDRVSI?#EKJZlDF)lQBq+Sb-uJrq^iVaR~$WU z$5*XhMlDX+fo-|nHdT|etDSAW({>-DHfLA4yCjabsT!TKz1ruLGmE3lo4eGzE5D~l zn5|Gtm4wQa8#|+0dS;#rW9`Gn|MU(v-fs1_cMiASZSAv&;OS&SBXSC9NAM~Vt5Qpu z!@FG@qCf*HlCN++#Yj0TQ-Fv+WQtq+Q%F}&=fU^m@#B%uUGg){`Fa_~+h8EVgfbA1 z00wCmcmTdYLBAj(9%NV62kM8YB4huLtiUKQ)DxLAx6J;>Q$ImQ04Ve{#^T33=P8Zm)WH9p0JhpF`vC~LwKyt zP$epn=Kw}Hi2DDcGt9E2{qzG|WGQ?F3N@M$kElYz`DNs8FM390taBsC5CCOE{=WYVf3J!g)>=HpH*89j9g78pPS+j2CTjm1g6H*J#761!H0} zF8@R8qG5Nuoi^F=cAUeS)_o%#ib;g57sNcSgM4$FFGr8BkpY^h9YG! z(#UGnl#+0Zd{!DA{&tmIH(Pnwp^tR5(k3t4%nF0?P{yxxkhQhv}*XX1&4Dz%uP=wy0o$5|76RmlSg}t%YsW$>!HO^ zylfRv8P-i&+P1}mFJI8E^Om`2xFiAFm$nMmE@(uGbGM?>xJ}v-j>dvGc^s-pYTcG` z8jLl8hzl8Iz@jG9PiFIA+NHQ{`}D+Z5!1kiVzv<($-wPo%vxgPu}%%dBR-^;)KhXg z13>r@82{Qxcx5*7w!$ z2+S*ooG7tT@&IuL?p6Nr;jIL3zrEA@dE@=Ztpd@A_u3AIe&8pwa;+P$8fA{B&Ujk2 zq_WI^LJTiyiW8@?4De97cRyJR>P8i2?!cy>|GQZJiowOc=@<3eHC6S%e?a$Zw z*v^}kl<0VChm4igR2V0VaNJDQSJw8LlG2nhR@@M}kyTo^O0gMigtRt7d#*f4!-Sl` zB2Hw&cCLRAcN_P735R5f4Y2e82(9+16%h~R>T<|eMWvwi$P@Hk?WMPyC`6(aW=%J;3G^PFgjn}#z73s@WThI)I10&fa*M@%#ylB?6UxNRb zot<*Ex*u%1fLz)gR2Vne;wRYU>Wsuq z<6i3ivyoBa9y>yJoBA@1ZSqXN4MSc}_o*!UP1aZ;dHLj&tdW=O$+aBfZ5ZlR4#^sM zrOVL(Ld4>?VQApw5i=B?HjYWtPe7^x_y5 zB>dOPaq(3n7t%Dh?&!D#_;o_NXrQObe*smupo?l(6M#5Co5A7O1qke80YXo!Fb)UP z5$(`VOqIGObWE${(KTs~!hsi`_xzZ$8X)Fx(F?T6kFXM(@p?;+>F&1rh+Qi2WP9iB?*503!|mOjM+Dm=3dG?sxq`canZ$k{FXEA(@3! z^v8|}Xv3LPEsQbp`;hgRcxMsC+{vI14hDYQABFKW(q6!7PD4;_uVA z<@W}N5JJ#qYv9r7Le0%5Z{`Sth ztq)r}hk#ruNF4kGfP*Ey-hxi=w>MtD-(q9${7T+zeAsxmbwCb2zI_WxY{=_h$@}fi zt(}7{Y`$?oHUQoq-ygzqKOSuFylayWyKlDN{tDl_yHDP19~|y)zy5f*z4H#g_owXx z2{{DQ;Q@KGwZHxI#^LtQTL*mCmhr42^R|UMy`?I|;n4-s2V6IKx=f_=1VO?B`V#rX zJ%ns0OFH+@z2J;)eM%rsWS@Eis5?yqidCk8l4rO61#Bj+=GXXt_X;$2Bn&pia5Nau zfmneStwE&gUdctXq?z1H57)x};og}nBty7>G>ewlCQH;>+)`UxOiYumw$@9QheOYf z$;w{S^cP-2dI!CwOhDfA$r^dlCOug;JNt82q4nQM&l5>QNY8)v%wB{DbQ$q(z)^Td zJ^y$$)l4*Lw#;|e^4E1+{;4E}F1zd0D-iK5}>5PDsd3dSZ{x1(@i*7u zxS3)#yg@ionr~ClsO2Kr(-H)L47{hYFFa6`b!Rc7+^`8(2LE;ut3aIJpPBPMi4!_$%CGGN^pmt6ubQ6weE23VQ`;ap z2YX*M#nDo79)(v+$Ma5u!!i9lhaeOe8NeN~F5$_a@|AS?t{G1|$vF+05-@GKez^rK z-65Sc)#@=@gaDSpISYkgyN-@qEe6h(xPEnXl%r%JB>3Kmt;88J|~Q%nPm z9Ycp=IEe|UHlC1`7C|tR7s+v@RO5QJr-&OzL7QA21I`Gv zF)=lq=m!!5a>U-i*#<5QQ5P3`(jwsmgf6+zHsJ@^x}QX}I5u?2 z1{iJqqRakW=@Rz&t0GUBv-$U3((B;ad-hD8rq7JPciFeJ3496{4a7Z_8tAXaKr;q; zIF#(`UL3D#)hL`J{Mcn}dmYH0I0+}s)+#9VqM7`aJ;Hz~zq+XxD$`rSG_VmE>)Do# zM41@$K}e3|ljmfG?K=ZD9>yOq?oj@G2~J2zyIyGP(&($b0M+#sj{KM#5dd%?n1zgudKk!B)xb%U-B>eHC zG}NDvzX~eIx65&;knXUZ?h?+~7PSGI1BR{3(icb8%*9%5^+l33W6f5};YEMKi)6mN*z|&d4{p$6q4pQG z?0NinGV-(ya)69iVtQjVZ8{pleZzJ82Q<3$`*ff2f>GxkO|1ScU3Hhc*_upq3Qs^G zg=!XTllESHITt_(^c;%9W0L7`A)l$8Mi8tB|r@$1h zw2fEW@q5VVxlf@2&>*F}g8x8y)FnsEvPTea)Qh#nvaRtbHaM_pYSA$Tn)93zpe$1NbZtXN30Tj7} zGiqYD#OWFT&NSk&^&8mML~XJ50=E>SWQC(o&tq}4NI%Is{O*#^*KPT|ZAHP_E^^e? zavJf?GMBCL#?dQ9eVanJ37>0jPNtUEaTAIEmY2!ZImEe~Q+Yt(yYVZ8Pexxr-5-zX z0F+p4u!VOHrl(^+*_n<;Y_&RyUAN4$CtztRb;Q$- z+*pyB$eK}qY$|qgPn%FtXJ7doGZ%2>3mmu5+kx4i@8Z5?^neDJ#rGFqxkj2MQ0-VQ zNP&W*kNyctzb3S1T(u^+F!66T=BgvI>cTcd1HuPagY`U@2lk#J53H+ME`d*;dBS&XQ^LoYJUP15in~Lz4IAO@IYfm*jB4`yqdkf z6}J#(BrWcFo!FxCDeWoxM}ZTsX5_K(u&V1`+O1}w8Q7Irz8SR)9G#vhkX;Ut9!I7`Ff7kZ!+WviK_HTA=#ApO_ zaOWrC3 zBm05!6f8;h*y&ED_58Gg_52jA=VZXF<)>gR*Hs}xh|@v9W_6LkY#5?Sg_+n+QGzzD zYo}7kZdrVQ!=SZ^au?rXZVg`|&qOfaX^T7~OTxq6(?fuPw!kF1%`5ZM3`qBSXyW5s zz8Y|i40LVjKtUUzDKm4Db<6U33Ob8suV=Q`o#x=9VO9m`>lWOKmguQrcQ2k!Xr#P6 zHP0($>tXI#-4;QML;4Nt(t+fy18MgvH&doG~LO+MG4n zoqtejI}wRYT{C}EGbc53QZpxa!JK%jkC>wQGxq}Sc}G8cBe>u?+d*<{*kHzf&?Rre zWQQiuU=yz%&j*jY?I8K!2dvncYVUo@Ywvx+_K!3lWNr30;q-JwOD}*mue1ifo+agR0vcCZ z0d{aMpuUjm3#q=4ZvR38?cHWL8c{CLl(%geJ+q>s(lJd&H%&a<7z~){#9>Ct8l1T~ z@ivA?nl;NljcJmp`psH+{+REm(*owuDeL3ABxqxXT4`95!I})-xzcc@RvOky!*5Gz zXvQk7)Uir+tkQjoRa&WImFiffI##KURjOl^>R6>ZR%y;yB~aY#(@8{QynsCdEN}vnsgK$KYCT zyV8%svorWN74(3HW-AQHG&$QbLKR|stleabu*Me;bH;s-P157x$5_MhXN3Ed!LQEy z&>K)gkU$;@RUm6ATef8;#$D4~`WWER30(bjH|1Wn>WAHoM{mJD_Ny2JLgLH5{UWs= z<^#LA1TXs|H4O(B{%gPNqrE$}+-{ebNt}cc z#iD6yoqY(Oa!n|{+f=?X4*^51YIgy4X~!E=YqR8YyFI8?*$RYk&k~FpN3O%0v|1TE zv*#s{RMejIjrsP=7h*o?Y(bJn{v&^AFo)$2k1fhh!5i`K>KxEyIx(L$d(6ory;ZH0 zE~96ASXlH+S7U=nB+ru~nQ)5%hm8NNBsR|^D2!ag#iAGm0%u}3C5`38eR1}&+HIC@2vpQ1blVG=Koivugt zktXqFpAX!eH!`F|K!|g}-{;NuGA}$P#!%JfXR?o|08QavQOq|M5$#6g%P~Zr=gj!( zMqem4pRAGZb0+ydfBUmHpQW@PWZ{;^B!BRt3n5L$A>)j}EKL8Hg2|ReKtfrk(FiTF zdmj%;1TW(x&K=ue+#PaGX6NhtKp~U-p!L65F-Yhp!9m%y2O#-2jPQ8C`7a%fcBka$ zMtGBE0lWb2c^-e~1)5$0!W;Q;Ol~u@z1f?czd%9N7PLSY}g^P1P5a?}K7Wv-VXY1#f3rv0q4=>-CP{EEMYo}*iR!!$&m{5Sz!hF( zr?l@e-z3W1u!0aulR-LVD0V9DQl=nWYLlg3yeL@8xuPmuQ^j{=KJT`fN@$>R6wDjx zTQ0~~CHd%xlt^G2%0ID|tR=Ncn&efcuhO6J?)*Xd5j1^-8by1UJ(4;hsw01p-D!Cl z9pdmJDLM*pZd7X*wMDzx4JdLpWo9l2YIb~D zaD1+Ba8hocGgK-;hcYKlC3oT)e^a@i%7o8*_f{}#3_~cE_+Gxr&415QU~mnS?2=A^ zui9}XHT$87_-PAwmY%8Q$eH1?*NCD4vlJUk+eRX*rwJ%>%sX6#mTvhK3 zrE99CFj6Xjuis;RU2zi7tDh}zDyEbcT9=IG%#kHG-;{L_vLMa&DI={0Uy}8);GN79 zD0$$HRr@K|e#*6<^4%r(f0>`$|7D%rKR>zu%cA7|H%#_gXL$YAGrZnzTGwpe?lu#? z+F4yO8>act%&(e2bs}cT!M2CucRMqYENdqpxN^p_Jgp+N>e!oTCr!`IY4J-ApsN(K zY-HWFC_D8m^FnVuq*St1vC;GoP+<8b@+K3fSCuQ3Y?(Z-Zo3TrYE<}`URjMOPsOY5llBV`&`J|v`plaEVd6S#DWn4{bRsqMVdi&9xU+m+%zRuA9yIL#t^-<4G9An3>dUufNgn zL)a{4kB`Y8QyR^Pgb5kY{>WqX>|-SA-e{y=$AVCR#XJl|^5Lhv8xXgUoKj&^hyCmD zCd>G*z5AUH-Ua<{Si_#0L%*`r)NOJRgja!Tm*QVXVL0inxVzhqlHv+1rK->uVUCzp zN>;WKo^@)7BVz=InE{q%eQIauj}j1`)rV;U(xelhK7P$y97s7@cvI_9j_G4bXy2F8 z>#^5@Aw6z$PJqIqv5L0aiXU`I197k6ZouPYOgN@3GTCK#9rhAqU4Ww#CoZ9`jp34o zKRI%n1tf!mNg=(K)Lf%#2I7u+9~W(8-+~?NW=JwkL5iJlvsg8tn4@bJG;*4DhGDej z_0OA*GneIbq*`>qf6NEE@#Tx!jgB9nqN@QP(?I*8ddD0^Gt?uQjO!s%BSGYTTaup2 zYT$r*EC04c#?v?fD#oQY(`z}~nh3zYw2wPmZ@T;PGJpd3vq=OB82^%XoxnN*DMN3F+md^(V)FS#HDAveZj4SQ&S= zEpTR&7&ttfcbnv0dm3$#*I#N=VW5VCY`~3}0=T7u%%4FHleTnYfT?!fW)MGU2C<)7 zHjUS#@H7jh_zHNhGI-8=Scjbt&?>Ik!23(3l}i}6aiSK#Yw^1lzwbc&UVi%2hyx!` zEK32d)otPjULULt{^>|Wt#;Vi;@&;p=*pYn=}J65fc~iRMuQVlHW@GeG4L)ue*^{} z-T$SMq@OW{REuspBiJ;Zpj6sh67Qz&gXD5P(poWHEC}=&%jp0Jwk~OqSp9|lhl_&T zqIPYy8q>t%NzQ@YL^0(9e`X0uEb8-LbSCUkD&F@QS?WN_D(mx1(Mb99bn_d+-P|QI z(JbBpW(z+C8_I4lnz3X9_S>KQ!GH$rUE0YF|DOd;GtkXTyi!4tvSH_Az^fh^_fDzV z9Ja6g(7ozYa3xFb1Sa6C&+$Q_RPl!h{Hs1qI_A$YhqB968Jb(xOU9Fr%lFe;so^?>;B5f4KVT9p(8q)#sg4sBX7}IQ-WFV>-kOR`C>0A?sI1{a9 zgoL(SJ>};TdnA1U4*cM31aU;_Q_iTCCXv|r|1{gW3TIvwdH7i@&U8#8xJ^=3zVQk; zoAQ^E6BJzFjlQJd8(c1LY4wPR;dWFfR|}LO-A-5@o7xZ!k?$TvsXErofn!c^sWav( z@u-z`ykFmZ6AaNmnJ`x#nXvHTKmetnst{OSCWpIkcDp1ALo)V)nIKrcRUfvHIDAc5 zutyNkH!qFQ^QEZIV`)LN`M{5I`GVU_W3`EpCEI6N=*fnP&qjrmcbOK){kzSS^6Pu>20(qxAKf2_Q=+U z^D*^da^Xya$nT#s{r09e8fCa8q;i>SEQO}oPn~X;*+V1{C~+vI^*80*tpaQPL6;{n zU{h`n(s$zp9uw9IPDi>0z7tK5CS_ff+Fndt`{c02`Y|^tlfD;_Fc={+0k_FL34H}O z=@Bhm3Ul{Q_nj=I+yJBxLg@gG%FujQ+FI7GW$jwlzVq50Ki0K7>e?OOWbF>78_H89 z)rzECMN*L(Nu{~@v96C&*GIWe^-+GT>!Z~5QR@0Ab$yh&K1y95rLK>1gZe0%Ww1mw zlOM5~$=0VtQ|#mwG%;IBA2u3XW+is8%XEmG1Ucn8F3}u$X~t~q^1qHI6P=SOvCrdJX1sW^R zES=7nrWvB#qE6cK3YtO%gQsK?PNpL-$x|9?&6g`$69jxaJ^Nc1Y)Ht1bSLC4j9bs6X^I@ z(_Y3mHP3X4+HKQc0TM89?}j-otTK&(vMpO{Xtl{_4}oK6F-@5bC%7K|m0(YFoJ zDyHiP1Z90qbC`DVy9`3?{3_dd=OfF`3zv{_{c!UWsBEY=Fg$o-b3K>d$eG#48WGzq z7|^*OwHILfrsigQ{&B8s&pjX19Bnd!1jm71n=2#7^N;Bq&!@RLo=J^Iz;d;LO$xH;p#I2C+8pW)vq8;DoBup0j zgXx&lXh zB;O8#HyJ#~qQIhUF?jPzR26u+jOLu5`&5CU6CJYIx=)O+`;^7leahhMKHZ{lRprL~ zwk51jcOqitpT-->S)b+4MHl{^-aycqVGAd2KcS_N?ZN zmCZc_yiH3tm)BO`+UonYt-iTPtD&JAZNH{%*tF&1#PGdcWzOYW-BqSsVI}MeGcL|k z8**zyZf(e|4Y{=;w>IP|LoVEB8>k51i^6mN)KBQ(^=$Q##`>gR3-XYDbL4omv=ast zy@~*B2>ZEOWq|GA(i{1M58+@sqMPCP)DJLWCJwrSgJw2CCN@1No({)j$T%YGZ72+G zj(nCRpkgpA>(}h#Kh8oFDY@n)%kvlOePIy>va;&5gy1g33uJ6M|v zSCw3NABST)$r$wtkj8%k%x>b3WhkM{8IQUdp*}3NdKC}Ji+W_~&sF_6JAIQVmBy3R zhysUiwh#8+Z~WSWAg-XODrzrPoS zgK0l$v{j`F@#RiKKq){2wr6M~vuv&94u#zF(&xw|I=6GAv^j2cy0md_>!4NHMQu5- zp{4p1(>U{@Ti}Lh16SV#t#dQqhBPnym4)cz_M4u06|v`Lw05&$wQIEOf&PanNB>1< znPaFXuI`b4<_9@_@x7zt8!w^TK}@lTM`m}um1B_Ycstk{4k>2H${0emaSZUmi!SKk zZ5YV{Bbno*nx=;XXz$S|F4z#(B(M7~UXaAQ(OHRMMAP(eyU~C~A_<;*7}X@*eLLQ# ze@tndY=V|~gyHg;1GyTfhx{2tlaE2-k1_{RO&TR^oVR%AYo~eMJKqqIQ%AAu&@F9h znHEzW(y{V~h4~g)`L(>9i`V8){j?XZP-}Zvi(}-Z#L8I1qGfH{rQ+sTlR=}3S7tOX zS|2pN@d7mpSiC%~ana&lhvDePi%XN$;x(rG+`&F;l)Kc?ko4b`EbU-dfX1LePxDMyS)#;6I`C9yTRjs-(SoP}Bk#nA_#-L5^t0mh|vlvQN z&xl`8p{C z^x~9K3QnaYM%Daou9&=kq_KB> zpH*3qy5S0YRq|!v?h}>#j~3<|lyRk**Aoj+5MEM!?y_OLb&L(eq@UWOVqmtc5UoC0 zWCOX9;qMvI-rC|i69h{y5^(8x3NXD`L8dpECQUW+YAU+VdEZ6TzD8mUzXp#tbO~k_U%?F$~jkiI`v0`*YH0YZ4Y-S9ne8;HfNSS z`;_%?MM4iR1d41YbS#ii`_Q*$gX&*w7By!pNyj4ck1FdfWG%a$M(cLw3E^)BSd@S@ zPNn6(**3kSNfA29kRF?Qxl?}75~?j&(mARQQa1=3YZ#X#t8%w_~H zT2}+`HL~1uVJvL{)*!|kNAGleeLA|{%Z;x0N=4VZW5Va6TxT>X+=b)$V&!>(w4PTO zX|7I?MFR3Vxgx>a#$jatsvu4t4%>u<@s?WN{nkyw$mcvydsFi~`N3qG?CAx~dn-3R zW9c#5q&|0F``iJ?klvY2M!ulp9jni1;Tf&sjmM8_Wk=$)JN4rE@QNI1q^Q6ha#%SjdKxYGrR5)}hl zAFlk6K6Ob8Ej_F z#IRu0K8Uw+897c(;pMX^|D_wGnEY1#l}wz!bN8hD9l8A*wT$;s={4Tti}rS$i|)_; zTRRWcS9VawSE%+8x*JVV6~dn36I9z@zSXm7Isw)8mpfy)%Xs~i&4fM&3%-yf>wgl@ zpZGkS^jLAi9@U^_(8V0*A1!;vy>b01^-a0nKUrT@%~vSj0jMmN)-FKBBHkRZT#%#( zxVFr2ZCS@P=Jz7;=z4jhK)*W2C)^`J@FrlGM=M(*Khd4aiSr>~iW!xFS_~^HhpQRU z+h#;d-8q66t*|dOCt6Y%oZ|#KeSx$iczd2e8UoZBoqKv%r7KYGX4Q^B_vu7uxB?kx z`c{-a8jjRDp!;~5HJ_lH>{Weut0{)co?)RM%F65a^UIBi&+6MTcKode)!k==sf9o~ z^axM*%p^pDn!usgS9$(2hNz-oat|TfF(A1cX=JKOf+B;MVU>f|vo<+MyeQcY2J};# z?0IMO!2dUGlc7IKKzOeOoX`k187gjjQUBaQ=gb2*@sjf{X)Kq{1=hB@i?h=u zM=AVqpY=ei-tgL$k(yCNEY&JL-d(pg=#s`CQyR@0Y1D03Ta5y4{(`hkxb-!OP0nAD zM1@;l4@0&5)o^sY^|hGjp1&sRXx#eR*wM>h6KiwhwH%v285!)7#=EUUYyNZU4e*$z zm)`KlpPqx_?cZSl`PvWtG5y~#pxePP1O-sDm79jQAJGBa!QLqDl7=7jN7I3gv*9Vw z5C9HXZ^9t98;Hj&|8C=V2&_zLQdbvDYA1!(`+H13(~Hf=IET>r$jw;%G4&%la3x?i zFcgY<&yApaA8Q0HM$psg=;CW&=`u`QqiT(+8moeAB#TA!+IXvxchvaObW8IxGeDX zC2^OR!~>U0b`R=fST=!1{y|j9H16O4vL|f1`ZSs!z%x%4uAOH-`HCXdo2~a-hga~ng0NUu4VOs%jyH`b1grB?_~bM#dhC1`&7tM6ZMmD)=d^b2td&!DNdYT{84Wu|_J`r8wm;fs8O9@@3cn z>%cM{C4fd=a5nYMXom#Q5kJ7OvyO*0KUu?;M;CNmsWIv%fT;YLMfv0bd-qC7bjmfKel*l*1VO=RyRHd7eROx zs7sVQBWeMuU14M9Bf-}x#-W#$fkmjY4D%{@2)m~YtSs2a{fVsRD5G~xazbO3p}BL^s211spy6tL>RnQvim9=`88C})wNrmD z5YBg)zxknUiw&AZr?bATU7ROv>Vw`JS(~*eH|%Xeyjq6L2Mueja%NTn(DHneM@D{} zkZ?#sv}%A<>LsM_1>}?xFOL1QfDT9!B8xQP#tv<+`FNrGlU?yaqe3R+ZY>vOdCX!1 z5pZNMSnynSd!7VcH)PAdZd$W%5dAD@-8k{v+*iikWK6o>JD7sO;xa|uwlHpl?N>VF z)sm<@qzzoGWPOtaArA>^w<$N@EStqcg`z1IYY}nt!SSmnT)4;kP!=|ejexqveXJhq z{LpttvO)O~-M0wy%Au_f9psvjoD;u$CvvhjVIlK!pQ9olI!fe&?JmjZ4SC}QM;w%A zt?xKs>KjHllaF_Yi!Dyo@?a5W(Xl<>Fh;qwE|o){@==a|q44-;@eANs^z%!%yMCoW zgseeiO9tw!W{Yqj;)J#cOF}1lg!y=Jv&z6Zp-MadVqpBYx}%DjMK&a zYUH}Fzt(Xxmr){tqXP9^)7g%bDE99_Lqd5tEwiY5=q z*gQ`$^4hjs+m;tyy*$U1e2+!s#Z*kM<>2~qS!jv%TtPQJr=y`bNm}H?S35@wuDE;a zr|G^Hh^bG~E!3Bu>nPnTCa*qTwH~O}1HHWM3fOZI3g~nY4wEY{qW6orz4a2@H68ip zIQH6fd`sCWzI}dvzAE1}t6#JFcU!RdPkj<^!?sYL$@)y*IK|1IQ%JvYapal>uSNL> zTP-+?@|gK{<|yda-@4#$UGTRq z_*)nJb)DF6rQolF2dGQ_=9T<)1MJ}!{dIiT{mR<;AWHu7#TTS)y$P(pnw#$ft^6yY zaf^HMb#p8}^YTxsZ=V9!HMM)NJzj;@Y7U$OY} z;*ss)=U(|%D@otdh4vK^X57b0(RZaRDJb+@VXOXhs*t?u&DWXx-~O*|i7es{QR0$-blgeb|Ap-%Nq-J62n`Ds|rwksf3;sV1?L&q8m`^d$Bd;35j*#Bqm zU$@)1l>|_D{+%U11*~M5WK8jO|A3YYHYMYc1UJ5HHn7`J|*E zls;PcZ9ZC1NP|H?fu--`D?cef$I9GPAK>MX$lyYQRS-`W)nr&izo2{ApzkZn)6pWD z?%AKBG)|;Q(%A2(rL9Mg7V1AeS`a^p!-J0K?sg82yT`wYH*a=o0{oMXx}D?p(Ql%A zuy=U0-#+dh9zbcVfe0q7C-D>VB~?CjH6ac|sZBnr1Tu<66iSf%{4^2X#f2aED5yp; zf=tHei9hhY*atri@Q+Q#u;9bd-)Sw4#9cH-PvBUjG9D%X)I%VF-*Jm{>hwBC z?>oB&)BJetxBsKl699KF{-Kfvl$2W!3QwqL#J5cGrJ z#BO`P{d1=$dhho3I!B#d@#;76rn}QQ=yj-kyC>Q}_;+uP0p)kS?!nJhv46PR-TMtX zeRw2xyS?M1?yGml-GiU0)33WdO+X~paZl`aj=JyL$KCgxo*uvY_nG&7=6#=ef6L5U z0DZ*kC>SK_ighSc4^@Y#bdIiN9Qy+)JaAG6X4Uy4j<%q|SYbReaXc1S`Lh#+Ng9tq zsqGn1B%TNl68l$vFkpSirGG6$)iSl?L;_{ov< z28UsAhf=TGHo$pU<3G!ES0??~NA1vjeH~a8K7V#_aKSws74rL@6Ae|k00qkV(&n** zgTu8KIB3A!vT?u~Iz)^+%?eO?e(<=bgm;@)^ zaxu_)ook?FOCqWNunpWqB9UoQOnwJ+jnu!^-V<00CE=VaGO~-*6iaW5fPQX?`wI8- zg=lP<6>;9N-TQPT1CO=k(?<5d?It4PmSVoG~G=Ujo`8?Dg|RN(kh3vAuY_`Mz7*eO2rB z{s>4!O=Y|&>Mv>l1ty#VbEu$fJzB6f(@ds)pjXl)>Y)A@dqIuQ=$Sev+3&>;6h}>c z1O8FpTSbsT4fa6j2T^JoXkr68$+WTO$4RR69)2Q%=tjo#xA6vwA76PPHqydIOxna& zE@SDX4{7ITs-Rn1#+K|<)7BgRlN9{`IQan`@jpp~yh43|&*?-0E#w171SxYEn^9Rc z1momcH2Z>P6`AaY*KGRbn|=jK;pjpnvLA&5g#)l*B2mM7fvA;9$Z8+#3RsuLlOWxC za+z+4MrCf?prxKn5vg@Vic<_W-S8UZW)a}PA_PB)!iP)*J-p9&9%M#%Vvk|sP3`se zL%VwrrQG8U-D8zV+eW4uZ2Gx0zTLy63(noU{>8<+&`;fU%g)h@mYsOwd@TMZy*RO! zB>LW(S#LiI)2qZy6 z3MbajMfeSIzb&@ZNn0-5C=BlAfM)S2ei|r-HXeF0B9b#8cEW*1k9e3FV zotpRsL@J8;3<~IL8K-2{9z=aFz_PU&t-nkA4uNPo*r|p;lva-ywcZQ?%&Vb>5=&~p7*Wy7GQa6@ZVhL?B9!CT3PF%#%P&68w zjRugawX)f0%mo~4TUZ5wHQ+;S>h5j@K>V(jc8PeLv>PyDnr;f2p3qMnn`LffCP=j!w7-<09rt$ zzmc`@o3som{(|-au4#W&cR$-c_Ww?LvD z6#j;R-)!gxHYPUEeD=^5n$N5znz{*2E*gZj)rXG4+Nx=zWyV1zn|(^x(_58E(YqDg zM(=y0@(H!>Hdw>8y(&s@0g1m$AFG80_42F=>+eYwcnxLX>T^KZ#Cl>pt*7|B?Wl}H+in<)N7a^b+gxR7XqL8d2nBM{JIFHA@g z8Qj%eZLQdiKuisi2t>!!^FxuOUh4OSiphd*L|GM>EzqMZPg*m)W_q;n98`HPGVLhS zl<55TUK+zmVOuPAOGDwI*=TrKTilvhql*S7tC<4Xj-0>u0x^UeYxSHArj&Jym23ml zuo&KHjIj3BLcK1!LvRW3QzcL*AfTp^sxlQ1gu(Zp3j1u!L4@s6zh*WHr61NLb!aPB zEZg8QSmY$)z28B*H)wAOl`mRhM3!@Srtr@LnSuDcjzg_wdm#9a%~_8Txwc0%N;-Y2 zYPOb^8zg;L zBF1zpA>=DBmAIeO-W~6h0aR5qn^m#gs0#DHO641x4XM_#|FFZAjn>A$xH!VF>IDZX zC(meZoaB?t=i-69v5q(JwKZ40o;S45#P~U1&3!+yl{fgQ_Hm~qZRBo}eeUesj-o^+ zng!s#Vd&lB?`u+n!)jJL=p571XtWPedO&xa#_B71ARiZjn3u1M>Q=>KH-uYIoY*;D z2NBBYobUqBDG#uZ-7sBlp_&nQlP;L@5eaJZF?y@HvcB?cd2MC=8?y1kd+&!+das80 zFX;V}?*6mCt^2#t_&ktbIQ~@Gkbu4)NQGu?ePexXW4XD!@@%cO++1DnJY8=5?G*Vk zp7fcV9FJzZ*Lz<=kowRuqg_mExv#hNcvH+w9(qyC6T3%jnHI~<&t*)%EuRd$6|Gk9x z;!Wl&39*!?#NW4)^sb`#E2NF)njr;(dLS*9TkC7ny6uD{^i<+BBHq32aKX|w-SLF^CRjsLgUvg;f*1@rZ(1kRCe`iG(MU$-LLq z?Rp{sD;6&h{VNZm=zxRjuDtNz4N0A}DcZfAZda_=9xc2}yi4$)_J*TCZo1Hlt^|yy z1TVv4cs)|O`+R13(L3*d9>|N&mskE`Rg^xLvKsy2^{Cb!49bhYe+m|}nXraMfvo)! z`>8~i5GamKWQ%6h+69O{NHbW_m-*C!`HFa~#WCp7$VG9H5}b^(25PhtE@};BMjw7W zy|^f=VXn-%XO;e+(zoA_^5ig^k!5w1(6raO-5!1Cms=~tu`Tn_YF*zS^rJ8&e=FU2 ztLBOQdy(qeHfEGy7P|Imgim|N4}#ksje1ziT1ZS9tqxWNTqEpnXNl|m5s+&ZWM%ek zH&2trO+LwdE*^jlm}?`B30rg3-un-0&D;BrIcx17Sav}B2XofiIkL=mc8-{IPAQ_E zo8*{2-X-vKBixfpaRJ-A;WfM;?hH?unkV+}#UrX= zF&n2CZu`%%9827%H9P+vohQ&>l18JE9L#QK_Z*@0sJw0U=w_H!{}G)-U{tz6oV%TW zMEQn@C$c$?MI`l#n!E8p2!!r}g|{Eb80b287k}~mbT5i`R9%ZxCKPamR5PL3m?_c2 zdmcxhq zV-m{S)HR2lhzdb@d*vnaHwh;?GIAqs$Y&Nc55d(^uxt?4ESKJ33G9oJNymwdlLz5) zh$6nSeR`HfM&%YEqn4KkHFm_4aCI%)(vdR@O)~?uTCrJCO~gS}$h7~^=6{Z*ngXlJ z)T=1p+FXM`(3uDq=Q(J52&I)t-1_qRO7mHZ#+Wi((74DX;>x?0;#|sb{B7iy=F1Uy=-4O+wpE!UR4C;_<`|VoNtR_9%P}-#0lP8gR;3+tc~vFaocbz? z0_la+Tn!92(f-XbPoqgwQ$@9NCI+e|h$sAa5eixSjGwm4SSl}BzcRfwG&q>vR@YG{ zb;Is;LXrSb}0khN*g8 zVQR}%XGYVikR`3Dl&oJ*EKnJ%n00!~?DsOgX?6ozEp!7Sv%-0rqoUIrQ)Mg%FiNof z4@0o0&o=1AG5K2*&Xc=zMkfiX<6MaeR=aQ+GEXDt2MUdDmT}} zxt~^MPM7A|47vhT%j%xKZ3l+A1%jG9rY+h4tG|DD-;nM7-JFn%Ta4@NnM&fQlv3u?{O&rGx#I2?xXZ%>8^DYBfC-jq@nmWl9F zx)|{X;^0_>5PhhO2dgTcJ;o{igu_SWYfuZLIyso{RV^Q*hHWjADq_Ls3E;_@s_%@c;;M`#i2R&&OjRUv~ zrI;nC|B9m|5s9BlrI^99PMUiCPjf7{zb1)lijN}Cnj18LZkBU_r#A>}aCR&7msB}w zELWbbt`h;AOuaXbZSQ0I+fi`;dKmkc7=Fmw*Hoh3)719~|DCp5<;q%m{$_!mKUcmR z4onT!WDTa**}V(Bq2ISR8I>}r#$h~=u~IP*!*U7{P!&Yt@o$H4KV$s&%$0yj)Pz&t zCyW32YX1~(hr>HqMD(#^F&F=sF`iV_h+t0LS=EkZ|0;w%YVN8kOf!}LFm5#38xuk{ zPX}=Nix+F<`*c78G)Gto)PH#QGbo0xj@dBv32s6O{~m?XS0HQsXqd13diV5g91X_( z6v(nS4hkqD_Px-9L*{EAq}Myay7O7!tihS9svZ@+<#4^p)w=uhcVJfS3CuLLdT;Ef zW{aG`N!|UTK63eK&9u+YV|nd+dRc{*y8F4ZwCwG{`%2*3_nv&gs75H$XSGJIic@Bz zwwx=Vl;wBXg0%)gyRYy}$Mu1K^ZM{Tvi$eR^4}xN|80@wk63F)GAG?VbBGm>wRl#L z6|dkDS|>Z9Mm$jDBHf{q9SVR`2hgcI{?@m;8jS<;h9+nU;v(+UQNz!+L6 zn|Oih=hW7BthSY@UcP16gH6j;oW1F=(c&bLf$UpR@Ra%>n>DeYnb>=CxA-oUy3OTm zo18hBx)@^48!%ZtafO>O9_f{9^;Aq=>*98#E0d@LEqLa_%6xs_Hok8g-?xpwb=z=F z7r)eGvCOu_+AJ{tCdf6%+rQ36rpIh!P`GWNY)yxek3@cJnHSzd!13GSh~gZd*lKk` zEcYC8c>}{**4i>3o?ZPhb=`Quv)&@Gg9SU}drR^_=2hQoDZ%A`GqaLaxIrIgwKti_OFWb(6k(kQ?!>J-dkrp6Rg$c5orSi0@-7x*an#u~}3v0vG{})z81>pR3 zmEXhU3X6*cyZ)BVwkjTx*ya#OoZ^%^05d(m&j#fu2B<~sYG%x<4n?YNC#zXvSDhiJ z20l)UA@qIw{JwpD-#-7g?UP(Y(a7~dd#I_G+el4TP1%UxR+@YB=NeWEc{`H*R1PL? ztP>05S6w_M6s)57SPZ>TeGRh0He6z$0l{JpqV?XDiaMuk4JHNOGmqT_baoU^-SxWQ zF)bT0sNtg(RUZ)CwUwh&kiyk|21@n1xVe&{xQTtdeRu0@;bOu*cirBhx;>u=Yq8a6 zK3i%umzvARt=48^W3%4n{pup3&OT(cI- zQQ-AudGUC$Di+0JWuCJC1!Z%7niB@AUWXMH*4l%2Z{C18m2HtXd2k<3IQ%4_`Dsa28XT51unR=?)N{XCZ5r!SB#xevw9sk-A_B!E7&f9J|(x@vwF^>Ai)Cdj(; z4oPmoF!Y{O1$!FbP0LnHq_~E}mBdH$2$+@U5`yXD)*X$>OGx}P3gvWw_$HSZCvw2@ zAH-%_QuwH+w81qW7wD2PizbN zk$od}9(JXqX$(uq+ok6l_lK-uO0uXL8DowW>^`T*y!L{O3eu9R3@VO9<@M7sjd4{B zVGh9|W}*OvWK_jwJ(T^PZ}b*x{V42vsngb?X+yPCn;4;$E;H!a7I5G z4x{k*giJx;89}1;C4S@a@A3AwD2+KxMM=E0GdH=yjUNu8n}WhBW7CB^5vnPe$l#)& z7$$FuKkuOndSEWKQV9aY#wqBucYaUkO5xGMf_tfOdMXnN@B-f|FoV&&UwO&lO{g{3 zeJ=>gw-~4!TPRh;OL2RmKR=310WU`0E1C|XAqGe$6p6~AvZhRaZ0Vf(Pjt+C8-;fl z@V*Neb)L1slfy#h!Vd>$;^xZlUjcWZQb~AGV6~9FBr-TBA zd*NMr1sfvTkzV1;@n>|ea%SR)fX%NT4&*J$U`fI`cue=helQ*YjDu((-}p&tTKe}? z4o3lOjem~APhoTu-iu?(0agD{{E1z9e*8jw7Ue&w;Z2&kRdGT;K5mNR`^vote0(y{ z)V1y-QaRid$5p~|Q!oUmvN?AXl}#n~+>22x2Y%m6rPJVB@aXk|=WqS~r{@TkA|s9a z@Gw_N4@~J}Rg_?GN-ti#ycb?SH*{z4vY=uTI{hvzEG%H`C~y=2rbCNe(H|!%SVcfk zl_7ggp+mDw@YUa+OcaklkHu%9C&axO1u);gO4CuYS+5V|wG3eNYQyNCeh_%ID88)A zaOqvIK8X5B{TF#&|A%+&kr7(`NMc0!zO2(aaH@P=>e!mvdPs>JP=6fCu9s4}z;WN@l5Y?!-c znCm|7-NF~oku%i==9ciEK2=}=jk(qwYRj*vdbpIpED+lW`ossdp8}{cqN73#>>-U?+STVT*OlTQznb>;+3*4Nh1+URM7dU@Q1@OIuwv< z3&TB~sg6?JGuRRJ;ze@;op5h_)VfKA;Rm24t@+>W{S~z$$=cOE1K>+Dq<5)aR~GT?NueEd;y< zC7%$Y>RWR& z>MOR%%ueyrWT|E=VpEaM<=vi-x>^ZQ3q{kL#( zi%Gp<3`5Sof_K_)yLAn?o&o$rJH8yl*f&~YfA=8Y1TaDk+)-;cS6+H^i7go38IZfo z($I@PjYms<2&XpiIY$N>U|d6R6y)dzKn3y3>-O<4Ka1DL`)>ri<7is72%v{5gRyOS z)!px$9{={X14l$!j$qV~^Z@cKmA5JO;H*m93+!fkG-xo=*uT6)FE7}|P#_G&ulsMr zAnGG!V2A+K8UiKA8Dw?v22?)y2^6;qGA(azZfd?4(kPkunMr*p2fnw298%Xfi*Ea% zE%yB(-7CcM(uV+{DK3XO*fOl$_@Dd{KtlNNRYwy4!s!LozMg}KZN53*ENR|Z!arbO ztMrO__92#7fRs&9(iALJAKC1no^%?@^eQ5`G~;zV%zZjDUW1;Kc)rabO3s7mcL$RRf-B_hG}HMp2N|e3@Qg8$i8!e9>QDZY;x= z4z-pxYE5ypw<92NZqE62|IMiv4o-n=84d#CLw5V^+c(`EycFLQrA#+6^U+zJy-;|8 z?@^eA9Ni~UbH2W|ruB9H8F>3`Cg2=oJnsB@%qv*|;T-ZnpPv$QIt!PxhiTQ59kdiz z0`TTfMqVF|g8=+|jDi+vkYVr3fcl1v&6q!osDo&jTSRzua8)=p=K_Rq-6DG_HHY23ivWil(DjAQ>}7G1Z#MlipP zj$_~5M8~m@Tc}0037aU84VdX6L~At~4PXe3QSbfFg%sn0rF@%bx5Hrb>_N@`y8i~o z;8|T)vU#=;fqaz-sDz1)%(UrlcMU7nZ7dFYlLA_=fRgj%V@AC*7$nRWC@i503eJ|}7~cq1CrYKc z3LrS`olt(pd4=VX1OwOSM6#+-3}dS&U)(e3!U0gIf82ez_kajx3;JA@|NkU(o24lcM0A$)ncS|IY;~|`ue&Qp$i_YhBtnP7iV~( z!7{K&BG7ffk^+}9`KxWZRhG#a-HXs2cY(70T%uZx?~U?o>xFkPzs=>brY=*n?1gug zO)+ToJpLWeF1o%K(HaX622`A*R$g((TE=2COZT&(Fw*054>wOg7`Pv5<&)D7Hy@u?J|sVF ze@K2RmtStye){m|hvcW1Cm-Su;m4B?$%o#@pI-j=edY6qUhSus<(JzhTbNa;Y`vTV zWMM6LL{8;xD#Jli-T`CjYHvJ}F;WA`13Zoy?j^5(QGQ%TQ+;iMMiq&UW@?oyf8H-F zSmYGjRMLgFkSe3Qw2ZT60Y_|4PHoaI=0c#(V34N!aoCR!pv6cb`x{1Q}Twv3SEh}Ibr;y1)v1kOwxQ*qQ?N_ULe@(*y5@)9yj<_~@P0 z5ewM#V(Uz^!~Jbw&bvv)EMU`%ZDfIg>_2%lrx$BBve5R9+COI+FM?KB ztjTlW;E;TEW^{CVu_hiu>UD?{DMzqO>_h{p7{*R=rZQ*j%LLzVQh82=TK8bL^XqA^ z`(K^Y&e2h};c__(<)ry>8v@+PTaozxlmgeM#Y(kV$${QI+y@_;gP#k)7lLkm++KuA zbRKcQw>Xa7>u%?$eYEo$CenYt>-3H-xZ5r|yl=nh?w;7hU8+Ux|)Z5aCnOATKmnL!(TeP4%UUR*FJ799z+y@MqMB;R;p`-kkN@s=_H*N z3L&o(zVrW8!YTqV;wmg+og*JWov*nPZA~KjcpHIc&rdSkDZIY-{Ey4vQh~27l*db)? z6BC|~97eBZa4t}&dW^ zm6TF6U7$r5X*`6nS%!=-8i4sbdyJv73PcioeN4TV3*T4K4POQ6>hMMvt3u?UW^jtk zLjr&cOk2?92L83OoP{2MU9K*otD@x=PJbV)|F3-yaL1tYF}hw2JSiVtCJLj5Iu9&hzf6m=haU{EEL{sre37mJ8X_`@UTTtCK|=i| zmSD>U+?|^G-a%RPH>x&PM@q?qcEix~^oq=*6>4TIYNC6goE!W^T;i>43|e#;cNMZv zJ?A#1n^hWO)-8ca;WWHiJ4Nk^aR`?lav%bX+5iQFAo4hT{caD0$Y}&3Dp1vupcV3 zc+%1*8n8mRY+w>!o}MN$Jv}8KkP`8FsTwfbSGHI&{1|Kg_@kP7fS#U*$_0fpSugDP zs_4?-v*MF7+xAxZ3V#*QK*L+=uD1$JIpc0ZLPL;Lk@#4~&<-i5wU-MvhuCaJPBCUd z!7-e~01H;cyc7Q;kW4L5$c|d`Y&TZrAC3s4p9JE4p1kZNnv4vf%Dy+UWDvF-A$Nkv zypv_E{E69n=-mgpv!q=gAMwVs1xX4AQL4;{ofZd?q&40TuVn0}BnWU9wzO3XS1{pg z@kvn+ZsaiDO?U@}SgGG12VP7vQqAdkKXQt*|B6Ep2Q`SigAc}K`a~ia1_UN4<`El% z;ie027XTFRHpv}{F4oZv!+ISN-%O;3T2s6$#{kMU3IrM49SxZX@|D_BK_cT9kPtu?9Ts5o1&(@%GJd@hHuNP^c7)WKtfAYYpX8KKQ;NeOQDLI(B+kc$!p%|u*G z^kT*M!^97 zR@C9l{>1rxQiL*>`bhUK@H=xz!>U$Co<7Z%rS@b%O{pAOs5|Ona$880N0hs69~0cQ zoKI?lNL|7$DBM8iIgP?2IgGBQ)~`Uhstj}oXsJ7m!uDX0E2MC$xc6}uVPgcIr>(~n ztk?NkD2Oi0B`S|xwOM+KrL18uBDBZt`xj;Z#dgD-kpnMDNi203hHfyKXP)a)ia45c zXsv(x)Hk<{3lv1%Om zWl&4KOBk!CrGHn%ujnzgXKn6$WuIzL?4Gc-LH?!0hc53tt_6{L1?Ddpn@NLX zZ2=Red~UkAOa;XV-Ry2M4PysWnrn{`QHvSem2e6lVCU)}@9ZcPq3E5vlv~-`pzt% zd~&u=VD3(UTbF&zIVNGYn~hJw$C}tYTw;y@q;CcJpB&y2%f^dO8v{9l=m8L=Gk4gq z{5`;tdkodg`GVDOba()1`%It0T_+3^;>6gEot_?(=FGqL2cY~@D2joEJBf3OMKJI$ zl&dp6aqp=xV(5Z3lKrH1dTLD3EUTNZcb3hNy3jLr`UMNlxTPqROOC3%*=RM_nkyR( z>$a#VK({W+-Oz`~CzV-EWwrA4nJu)ih56ww&k1*V0^CV1I++M72*|$%9_=XwZo##a zI~G4S`SA5gUg#`=KrQhJtlOgt2Aqf+8RHbsf`(ukNy-rt z_}mR-7l};MfF{dD6!%p?UE}!b1vlPZqF*kE$Fd4>G-H}~OneW6fZTvpbH6{1A$A7^ zDS~sf<4rMu1qk$>1JT9B!AgKC!)PEuzYC!fz}4Dn81)uGfZ^McY5psU9+RAJi3$_l zZ@J6R&m-^2g3u1 z_Kb6iCmrhD$mLNz(P}Pe0_rzk9i5(T63iu-T{NS^$n3IpiW+?O>;4<=0C-%c)^ee@ zz%zXZUSpVNN+AY1rn9OzlVLxC-5Gwv^nkzgBp3V|$HAGn@MSO{)u1wo5AM{q-49?h z)WAtamk|$0wT5?0v}&PH0{SkvZzD=8CpfwcD`O~KaQuYQFj6$V67qWPwSOhA&{(A2 zC)kq#vxqLWDide!XOL>{9f_!T4r{DHvT}>q3c78AH;DScCfWJUCGY=&NlxCRntSJ& z=u@_8=UyGkWx!{5Z*U7@`QRJ+#1=>i69`w-gyJr_&!vje0%n^AVEOCcLDbLh9Y=a~ zRrr!M2(CyZft@)m!sC2WRfqfdMpe^Y9^V)AS8QZ5nv) zu(pc-%`5NJB~?pKOstO+@|k!aCoQ$GDBr7tC0v$CA0o=>m(p>x&hnDCJIl_*cocW(CCLQK!AMq5Ry8z>MMzi$}MFk72OW|!dURuw$4%!a|X71oY{v6yM8)QTpt z?M`efSF7$PmEh*VRf>P&%W2x~8tEcXE4`Eov$X1_ezOv>|jIu2K~gCH!qHkEj(O zDlQ~`de;q^%xtVvHf^aJ3_q!ndYU!?oxkPWZCOQ34_sJG8XFp7?SMpRmLQa;hXW1q za|oeHfZ^*k$SW_|(adIm=7CwW;_5Y25&{ehGt2Zk;~N_>ZxKYzyl;y+l? z$Z}IzF@z^sz-lmyH^zfNRJXIpTPpm%HJ-SJ%3F|AF}Y^VV58250-(2-w<#`|xq>>rw%__d#_@e#2ba-9WNY9fh3jY%ikE(RH9oKP zqag^S1M|mElCezc%dHkmoWS)2jnFB+#MRSC-}@^a118e)NwzwVEVmcZprdl(O_u9?9kR{5KT z(Z6`WSSd`c>P!_FKg#_mw*H02#ZT0GCVFV*m}F|dVRHj(hPrjOTnxF|wu37ltc+RW z?J(%TwSkPwWQE6K8CsV;FTs2%JqgmSlKA}DdhUkuU#R@c3HeV{zBe2d7g$sU{uoC& z5Tz$Sl%9g#(u=|CteuuCPfJ@EtLl+*OJf&%H07>r6{Q+hb3N5)p8<9|_xhil>%$9j z1xx*KEUWlH8z$lFLv}109rOrlZBo9thJasNxzHz=jAAZ2L2$clO3UAvTXBUaE1Hoq z9Z}8_mh?(B2GO4^l1^+;+y4Sw>j9;En)Oh4n-2a)(5)EudE~Huf|Ax*g2abpJc`N^j$UB6ch%*^jmkVcA zfsL};gnBqeIX~iMe_BfPV?|^N^cKPghL_@u52I&dD7`R&yU-hWMhQF%@Zf_tl;EtO zpBO=KUXqN5_}s9E!TiyC1Y*;kOBo6x^}u)u0LnOd0Od0aE1T=ja=slmUhs)L5mY2L zj1m=HSdNheFGlG5Lm1#kc~31F6eON7B|biKJ-ssPN)*yC&;cBIOvu0}Hnb;ohR1lp zusP1~iy2ORYEEb`H97i9$Zcw2p`V=eldLJfIb%bI^)b~xkn@ zKIkSVJ~h)f74R3899P@ z>0m)7BK;`u zD0xo=!vVti3g$p+iq@ucyQLZtWz%?7SS+E0CM2R}fDBdj`Z`6kqh4UbYKqzT(=KYM zQf$sP$k_@qtL!75JhvQq4%InX)$z9O%aj(34mwkuHO7`iYxznPk|vj*>8r|f7anUY zTmhhJv54)b$5YjvPQ)Zhs1@9v&nV|cn3`O{j>-o2vy}%@j|e6Q>cM;5 zo+GvEacgH^Ps}bh10fwBKubU2n}3#9D|i%u4JJ93w}t8Ielnl+P>N5h0>l$6@ip`hXEBB9k=|Y7k~JsSc_(qZ26yGVswd&xsuSZ$B0w0P zB3U6C2hh2GG$hMndwWtG$aLYdnkW;7%~~@J(@r9&CDm9`%5-%tJnbt-DXDB_n2ck& zG>WBpj%MjvT`*2${w^1N8&RMb67{ok5AI?+wxw6b^y~9y6X?>6%<+=j)lHwTf7lDLQ*QFO1qwws@*a3 z2a}l>qYqmZ9tu#|9ThxTN)|(UlV*FNW*V)k2~P4<;#X0UE}56=b#OTWjxY&CL${dZ3n@{r>wqyT zu-{`!T_$u4vxZT)gkjf6VVrOW)v!&%;~+}+ApY!>k#VTT~Ou}tu zIp$LvDO;^c_k*H_YLMBa*@iQ0OiLMQJ&7Hs6r`TJ21;$Kiq}G zCG1mC!Yyl_H3k4z3U07+;)7WGYS}^ic}zP2{|^Ze?i=LaWr=@jS;E*JPnIYqoL1Cy zC{hEkkAPDiXIkO$re4o&4SbRD5Ur~fNkcc@;g`_1GYIj^S*}__U0A|afE)&wy~7BF zcZewwnj@=XfEbI|y9DjE`WiEf2;U995KW)}9)?`Zs+NY&Jn#N6acRF0=P0I~#}CDY zqI1deZmZYL1$fm`UP2G^T}SU1wO#Ulapfh>!5l5X6=-WpSuS$=9x^WqnLP>A9ub7{ zGdG%NvndSR(u7Us@f3X*GrgmIdMLG7aJJ~GpQb8MOsH;^oUm^ARtIagv10{icZDBN zb1KP;iEVBCUq|x4oS=sxzUL*gDjshzP=OjEDB)c|bmocVw1rDe)0`MGiKdzqhKr|a zH*M|3*LK?)1@*Q?DHA1(FtAlJ(=;nZOWZ^rFwBIzpX|$l#RQrV`fxE(yOPJTBA(Aw z#(Wv+c6qRH$qVj^=AG$TX4T8g2&Tl;Ic6q9h7fLlzq&JO4PiSak@%qCbw?<1yYyWi z{VtFGi^!u>z2Uw~q^?A2iDTbo(yx+9ok_@Z3+~*$y~tT~9rS-v==@5W{tr;>Z;&eO zi#xTe&$zfVH+O{!v;55+UER%+UyDX(mP|Vp=YI(q7uavQI9vNaCeBWi{k~r}{$CWy z98+e;2fsjkszMQ7!P<#}r!NkVBSGy6r#->#ku8aOstLj~GV3r)ax3vTR8JrzaDNUC z-d}K^$)Z^I!nzZ)FC*C8odfg1yMiQKoy#D)sfy&rPy1JLz$Pyy6fJdvZ|4%_{*U+c z7-jN{uRrI!g`st!Tr?aYgUzF{txO=A+7i$UV#H#u<9&$EVangNKXPLO;QCpw^GgBY zfIM%c>n!H>Z-Vq|gkO2H2lncD7c<-6Llq%&@XU6ogAw0bFyD9vq_$SiJOg1j?bNUh zR7SC6gMIO`*tlP8^6|oI>5+k7Y-7JgC7{`i$-COWAF0Q`V-><|6w90+05y>5mqI4v z24EFcqfA+frglx+ykDW1X=0)!zg7B?_760Ku)PB41B)tGKpqbeVt7QJJTVMly5Tqr zRwlUzWP^L~oKV->Te(Ltvi*1Ittd6&v?r#X^TNDiM%IzSikzKcZF}2pqqZlpJ=fC6 z@%*8^1P_I}2uf11^agkAI7HzRJlAK)$7K}JWCs}vB;lujga6M%e1EvBlVyTQE-phjP~_;7^=mWkXBIbWhnieYCb-It6-Vb$VFf)gcs({{@~cRJM~+ja*pxNW+{3DPMh3{5toTN%7nG%(N*qx(txj0ag~i zi?%76_;!RX8A74CV`*U|B4)MOD`DOPQ`gS=Vdmo^%@G)BAs=h1pAYCYIV4d5r>LB% zk-UTpUiWE&V>-=0L^V4=+iHuU&`x>6ZVSgLOIQ)Wa-g!kcvRfKY-})R{N33D$ zMNv$$0*pAW>-__xjXB}hthXZz0*IY%{Rswq~;0LR-|a-wd`TzZQ_FCa40-@KXnO%$5L>5f)3|%c%uMkx#XJ$ z3V92$=fzJyc|q{gPrMybcrgkX58)ijNyXloj!c7cI7;s*Gyy664nOa#2C3y7o;p9?zEX9G|BF$HS&7cYj#vLQwoz3AxS(}>QquPWHt&J{c+ z?YyLjwv@5F2=M(E6`TynB|PO-uj)kbScHPpbv#NE8IbhMQOu}*7~z}D(u7A&P~(KU z2domsRf5MMCcJSP4ZYNdNGYhrW0!RCN(%2rhe!4alArSHl%sJxie|ht(Pz$4L{hZZ zuk3KN3}<}dL@@Ny{?(Qkj)T-61$F_743|h~NfDsj?(KBDOBEbEj`#7E0f-fI*NZ2@ zyaCHtQFbX)=JoSC>`TZ{>dyLOH)5@XhK|;Sok{FTT=k@Rz`=00*oJ84a)LhFobX*E+Sp;CYWl^~6q7FXBF@E6G4Hb)>M2jR3`~K4K zn>yOMD=1=Ls_5`$^*Ud%m}kYMdD7H8tBT<&?BHu|YjzB^dYzSx$tdtsZLXkZPIxJP zA15h?3xo!TdX5ew${9u>KI5W+QY13a6k>1(tDEY5Q-h1{9Nk)}S~i9S4`#FHomliYw}b=QI_?1T0V2u zQwRL?T(Y1hhZTTXRd8PB#Y$MgePqs-II=OUtGOWFY@T3~a%!M%t}s6_XLWosl58?y zBZr}7ix7mu^CM+NtTn-ECu6b`4YO35h=?lt*Wt3;K5q9YuFrf3Srz^=tlq{EJhJVF zmtFNfT?W0>i!Wtborq;2fceoi(=t1QRW`Ja^AdizQ=Q_GtCD~qIMaHmH>1mX>$1BU zPFjSZ^u+EgX_W64m=8ecO=z&gmZN)Q|AGFEa*-V zYO@ZAnRi;UNb4tC3Z8tKx>4ZOPLO?LpoW42zIy!S>-Jm=U9We%Jt1t*}3X@yzjqo z>zj{}^tApeROP>7d3hw6#&1>x-bpN%I4q|sY)yg=3;UPDhnL{8Effr--2^|+ zt}Y&Ia{|=e(e+3>`&xZv3Pza+&bbM_N7(vxkbIGWjP3*{94J1Np^l$|uCAaP1)b}O zIi4lg^CB`2n_T9`VPbV;kBCevCr*{fTmWU(-Ur|~Z9$%b;FMMRfdrbiaLl66yz6-~ zCwiGjyuNfnp69W|Z@yArPM_uT^1y_RY{p0s3p%ReVEnTrY zL(p8N`}zmex8&eVWjn{B$(N0YH6$cP=gnVgg$%wea*}dk!TCWR^yUV7&_l6ai~M|( z!G`==-lqc@KBcDu%QILrdYP9v?4tyR$1gZWIDuvqd?zh;d_V=$rYNCJP%=KJYqwoW zH6p{sMIymvB^v7}JN7aKP-?oiE>3@+QmxEWY|wUnYrnDNhQ$ zCq7oV35vR2jIuKmMMI#%O<=v>WwPZHF^dBhCq40i1)ZX zg+naP;8CXro{}HkQ-JWzMm}>KcjiTYhLQ#!XV5W)9nYV;)sDLO12namv8vPIjBsXw zdIfzLbELMYo8|m1%Rc;AfSJg?guQ+c z5^GqtsFszGWi6RK=N+i9S-uloKL4P#Dq1w;fJN0AcW21;T?wt5^fi6p`&1}9_I6P0 zEZb3y92zzr&J_tEV) zBdexu*R-YTC$H0CP=()n=r~`=#6j<6LC`aB6Dn`ftacyws->p&LXdXv3Ja8r(S+^b ze0-tLFK7TMFYN8XKHY6-ElSoT^z&zZ#o)Z_rhqBcJZFz%-^z2Z56E8#N`Mor^Uzz7 z+Dkp8r>{q{4LfhjjbmT$WJRFC9zQ_~LF>u_;lim7qBiPhFSk!H?@x{V<~a7N1ay<% z>I8trB}ygAcb?x_$Z;DTJkQ4$c}}V3P%7{-D*f=o52dOzj#YyN0IvNW`C++KLdPb4 z`OQkszHSyu(!F4lyBO_+SXmI|s(Dg5FW0CG8tb}8E0_#tgn72WOSiTiY5c^r09SDE z_I$I}_*gD}!4#fRcb}~vC+LF09+%;OqFJbGD>9Uv6IOreAR-of7sB(lVv~Tr5Zw?Q zRg2!fMQbpRNpe!F)jn1;c4?&4+JDzOhD{Od*U+|Ag?04-bm9;F0IkNtP{zeHX-=Yv z?nAR_QRLzD$iV3@9rSjwqjF#($#~{?d{i>Ln?vb>e^IumqsaHzd>V?2_eU zQnNazR@sa%Y+~jps8}3w*fc;1xPuP_ga_L$YR8KLKGa}=H^+qctTUudN-1xzO z^ctxkrl51CHN3=%Wlcd_u}sT`W#gN_7PbR30gNPyQ!q3P?(i-rshTO#19zd=gd?C( z46cI?q63!Lj?R74vC0xTt1PWh31q0Qo|3GtrEfc6XB-dN(8o0|R2puiCd;DsenE-l zoQR~JvVlyhZ3Hed8nc?wwl6B;5jF$iqHMWL-$@j_B95}Kde?R5sCr=T@ zZFh&FIhh@xr=qmUQQ`Gub$lYG6PH|Y&HnVfRL!jgbO{2aMaufyjV=FqAj2(~YR#wuGfW+{^=vh)mz$*d(L|*GR2Xm4rM|wEtQveaZ9@g^7J|Ele^K^q zGZwqydD|_OX0~OBJ&lgDNmO*KhN9KUr)on#`($m=`txTxS1;H{YcKoQwkk1A0#d+V zDgq*BsOT&fl*Ly#czN(vYP-mBOB3vepMs}buZa+WVmtM&g*`msMsCqgfZ z^PqcBGwvh~CRQe|!L~G7$fhdx7>)|Fg~h4`yH^tUaJOKZP=9B<^UW(hAVk{8$sPSG z(3}&!%-BA!m#W#hRn;SIQ`gj~zsLk*<*;BFGE-q{?Nd~0qL`rWs^4exEmOEHJ`p$p zRyK2~&i%;dJYs)-biV!AOdpy1f^ND7E1R}W;FLv2uT$zL9ga0neUFatDE0scAMl1F z87H7-)E@Yv{G@`4N6;h$@*));SpACg*z13isVG0M7!8flevn#2X(C{4A68X65-l~v z4aCqJC!_=!dNBy@0~z>3sFL904>x{#h3X!4D_lj@EZ-(UP)U8AM8Rb7wpFOR+L~&w zdqH{>)O<(@yb0`lb0w9!^N#QbO>WZnMsgrf=gPr?!|_nYe&3>q(b5QZ@J9|wREuX% zyy0l;jN-&U3DT`I5lc|nrv9}I?rIjnWB>9hN6{A*G4xbG0OhT(kut4`Me*b^-4crw z>Ja)+rA-vvn^XVX58(P#H8!btX8=RR;w|VQ4U^9!t5r%0g|m+zUqBEF)I{-HSK=qC zMX@}opbC5mTPpIw3 z+ohU0eYr|ZEZ~UYd7(@nu!_LuuhOKbln_^ioi7#F%u27E1i^AcOmo}3W+JH=8+b2BK zS|-{m@s+Lxiy^2~$699dk=D*^x(xO5Wd^!=G0u8B*u+|bmx4nlAQNjVTU%O*nu$wE zELE&V#hUu5gCGjY@E&ivjN4)>=eIbB`s%hStB7r7HL+A=f-V-kpQh4qxW5$vOf7~;&b%ewNC!<+DJ48f+- zJIk<3gpS^a!?&G;R*)riH+C%^Z;M5Wp0?=Ra$pXkd=h>%Dr8Op4R%5Bw@iR+LsN^j zXN3%y$=CJ<(3)!pm=fN=4S&#D$S?4d10YOU^9fp^XFqOYQ&qOb8$#J-Fn2eAMZ022 z8nhVByVT$R6-$DP?l)Tz?2yK%iA+yV%f!FcPx7v6oc$>Apt%xS|XqF}Mr8 zq2GVBkj8g(Pt6mIUeV%dMZGJ`Dm$V0^t`N=hz&|rBFv>sH#1R*78Xt^o;*O%K3?t> zG?_a7_@l*BCcxrkoLt+@Y6*@-J9Mm^ijZpbQlhtks$ru=zJch3xmggcN8fEb_I{jK zJS%65ESl30s^LMSEX{=)&6donHG$3H9R2yTQ2H+HLbC(UKpJ{MNzeV#e=6v+&zWgs!p7GdIW%^t0+Nv~_MkqdsT2G{mZ%*8K# zyuH1icTs%2z5T2}V_wwT+_=~nP0|}rutv=dq_sMk(aBxUsddUW-!5FTvKF+IgBfZy zEB*Lm>1k$3TR@|2JWur@z+G8F@M>Q^Q}Oic#uO%&e~kT@?jso$IyMiY;g8Ll6S8~T zan{%}h3rRQww?DsoI+hUx;U0}(|&B43TBT~zf6{rUD-RwB*N0EGT^7lbS&z{wrg|` zGX!l&qTyS5qn=`=JW{@Ash|2X`LU^!%O()Byah2A?U$5PcM(hZPkcEe3a_DZ6ed5m zYLvW{3wz7pl@%SmGNT@D1fdTD9Of)S3nPuX3bj_FvBt*1&E^t(Hl8)tz#^@`WZGB) z8vnAq!{)j3z*W-457|(Abo5#(BfhCaOR1 zV-zKuVzGqoPYajnCg_XscL2Yi)9*jV5qvG;ms)W37`MgH8*vEY{9q4cN|~x%?Z=B?e)j0+!Un`<3?krsiv)+*inh? z^H^T1#Ac(VN;-+lDzT3Vt=4jf69$~J$0;3M=EJzLysWCW`+nSKY`6_8t)tTng0EJ% z?j5D9G#gxsQGz%A~b}(UnKFmp6E*th85*>(J}RJSN69=7DMNzg76Pm=w66+bQi(4QG3mN1Rhyt#zH^nPRItQ77%_qy(aSbMiBte9cL1 zPP*ha8ahSQ+i0)oq(J724HJ!D(@yj}uK&zQKIh~OC%MnbZ6|ra$*-JbjoXfse8I`P zPVyxucbw!aPTteWajN>#w9~E?&aGD+CzX-gFwG^*S*=#fB&N))day44>BYn|t>tyq ziFR}uh0I4xbUTfCH5y$w6JwbvoXuEe97YPM6)rh~nXkBDjr%%M3rBmMhnJbBwZg+P z@_D#dUfF^Oak1jiHW--iDM2(d+r7~!j&5`KK%)F3(^@4`t& zCU>1w-QyjV{tD6qFJXpnu5o(I>q}>yLB!XRS?QIoAKysDOv??8nw_|6C-Q=1lF#E$ zD(RJ#lv>FQwSYXY%$CM{4E`8Lib%ZsoXfs9PMAij-B*|>GpXkjQo#jJk!a&p zgHuO|pB*O|htXK=R4v9E6NA7{av7=K!CDMJC%rOBdhgTCq&HIXWLRTx*+!Sm(JqPs zJkte2HQQENOr79Uv!%*uP7FRZS2(Sy)0TCbt{e3gywzviM#xL(@-ECoUiHsI&=6fS z-!`4R1ILZKXth^$N*WDwi8raQhn)Kn-JbK#x3QyJ zy4`)FI=s4W(gIFf(`f@;Zq=l5IqnkFJ>qgJCN1W)Wm8v|Yne1I*Vxf%ueq3M;)+X| zq}RJDZOvf(dcbK0lPg`$^x}%kwX9a(aXCY&*JDmIl)BR844JRE+_GtR=!bgQ-q_R0 zW*WCPIy%)_TUu??$9H-Jc1@ZdDTDi1mwRQ>^hg;z-{}!(n>0OArr%>-&eR=qxu)sk zdoI@0N!L75W{ltSfUX&g-}8vB8H}%WIfLCbms_^#a&OlRZ@uTnB(uticUO_ z&BniC%4z^@KCnQdDY>o_jr6h7(CGN77wq~Ms6$G9FHoyjb7fW6OEiKX#(N!J68m1P zslC$FX)KJlc668T0(qx}IW_uy1Gmjbj2)|blh^0Ilc-C|fv*o4+(SE&CG#Dl0BSa# zaX~9>gUdOm5$^R9iC1&yxM^N_dZGFwod28+L zt9Hh*wYhH?;&garUDio5Pr{4PI)FEH@{rXcZ9e4m{W#HswZQ`Q4#>ARej?%8HyX#? zFqN0F7x2U~#S*zQj)S}1XnY>X{~SjtZ(_~eY#Aq)X&H>qRVUYYU&getpJtMGB32Q! zTFcy1oz`e9x2=sHNV;GoS%QK@ zW#*PI9mrcAWvx=T)c~s|$t?V9Oxq~DjK>BrODsF~D%jf7AgsiWE?F?XCRd#=Y}~R( z4ox-)!^2%~XaE?SC(WiGzWt4-&xWplSCEwOI@jct58{-{cov5;FU4Ac*<|g@P8=n? z9cbd1v~}H5PF=?{Jts%;NNWkFy|ZVMm>GAQI*s@B-G)ih#hBEo9`Tl*uH%6h$Eueb ztWl*@p2RFZ_Q!G*vz*e=X$h}@yBcO-5oyg%95F~{IIR!aWdiFIRz~*6AmbQu=9#W) z#3q&%`eR%0Su=@7@G(#gHJ+L35vzywOc@(Vr|n2OW1AP&?ZhE>b4RBJck+)>Ec-e7 zVNNpc=cyP6ca~nouHa}^O!-*y+QpX_{c(Jq-}~0Gna4{wGa6fFwi_#r z`SdR6r*}#j!E(l~cX=semd{nmfs@$a#K6+xJ>%+n4BA||t&^Cm2By@8PT~!^!K=uw zmt1Kb?useKx|TLqb+uS~oEms6k?eBk95GcY`Da@D|oySG+KgeD%P3+g-^kBcEY*WndJs+yyJ`l}>X+ zSZ?>iPnZQa)|n<*T`Z%M6-^n)YgTq{u$E|=9z(%MxE$iVmb@VsMC8b?!ZrcmRt5(oOZ3??yc(-UtbitiBV`PqjpSQ6y9bM zcmJVh3QHA(-*pme`36BhibK|fc64GKjrf9vagTyPt3OylvzybIzT(nZ0cMqJq!}^} z@~ji3`aICkgB_(th-_GCX2W7l*KU+{Ag)-xw5|7BHtkz_KfTUGsjXmd>17moIeQ7U z#tlQ}1Zi*2E|Vt%r{9F_STCb`sixdF@*;I|8`<0=*t47>E7>B)yn*S}T;)aKWu}4k zy=O%wvW=|owX?j8jCDFT)Q?cph@H@@ITnqlX zDPS?tij!)O04rDqu_MB;05pj0HF8fUT5F_Qqjqy=87`eW%kXsQnN@mKm;L{<_ioK? zB+0_qv-B%U)SLk@1ObqgM3EGw1CpSII})iSDb3E3Tx}C5fIVzHv{`*ac^cU}=cPyDbaqdltdo*vbS*roHj0l_#+7C9^j! zqi%fjk9KZY@E1Eb0)+#6WmwuW;Ev-jXRsw5e>nnXxg_@$Gx83XCg;s&kq&SjfvA^R zK*H>B=eV{lM$T~rW6Ba-tBzF!ZelUg10rOT&Nq@KJ5~dV&J#>4hDV!ZrA$Sn@OjiS z%08=SwtB}G8lPiXPiQpdCHkwO0k zrlQ(SlZ&XTmT1wKNA4;k>h>u?Sht8~=ASo@ljSgM4&-qh%Tor+WbT1G0Nx)4QMAuZ z@>}by)B#O*QR=z;V-S$q6N(_BJc?VK0zS1zw_Em2(R`M9i`^c^dV#00g?&x zFhj+fPmN3>Z7)&N;~>h&pMe#$*B##J zSdz*e*=Of`97f?u8jjJkbz_5yGk*vM!wYkJ30L_1!dVI&on_0*v=k}hEoR9&)&`2U zAj!<4TL@x;dJAhJX4^}+{zYVW>wm$gYpb=$aREo4(Ti6@(wZkpIeC-I7 zqL&vsl*+3vmcmQ5yb5V4aCde9mU%#V1!;u>>-$JJ>RgSISl=EyJ_om-eCFN{B8d6o z3JGHJTlVNNyrFN89)!ptHTn#7?EQX-uGw4bIP!jx(^?$bh<xxs)>vE)+*e1^bf27Hddbqidej-D_ewfW2f7peCS z15(K)2BePIIG<3-=N9;s#@S{-s?HFyL_pg+a>f>IqLjSn7Exl_Vq6dxqagJggbcX5 z10G4QnZgKflU#{}{)Vbt4>e00tYFVmHw{SX|J>mBH4h^}bTGnSb9!Q8C@+)N!v`e(nh&EuyTl;y70~3TUI8Yk(69U^|bBhXmpfR8h`L)k; z4P6g>o{Qzt)QKEqfB^LI8Vm|W!XaXE9!$O!F#&I=W-1cJAX*9DG`q)_1a*m8+B z`?ZQiOu1?j$&r70L$V{$ulc++jv}Y_lJnX8gGgL(KC)Jq+-mzk^p14ealUg=6s5G+ zK4-(;29^sFNm_hj^?`M9Yd`N;7+nbwW4TA9uMbdI##(s+VE5({fhfFX2?xcLBAZk$ zdPk}a6x#Xz~UqY4SF4Do7W2jGv0XJdzwgPp4AqCHKJzwheji3BGR^mOLUjklr)QaDDoYyjS$4_6 zIF5wr^R^H+%umTCjm;*>8R(O_h8vGM_@=bU&PTJ5-!oqpB#i=(q=r&jl-4}XHA%x? zAcj186Cw*I&+_jXcfpYsWGw8Kg(KM|=L%B7iUTx+|NVHVYzf~NePRK`*)V#xo?bIY z+b4?%9Gzk~4Vl!p9p$DOaOfyE5!l6uIn&-Y*G+b?5YtU|upEhC&#@GVU&wu1IM0mx~0lH)1r5h5f#_gSUym=c$ZG;ARE39p$3g4WXl4L|};bVVqSMvg;0& zVm?@i$uRDt@pXBV3MNLCurQA<#oNE5YveroZG=BF7_P+7o82~3BOurC2!(b56P9RM`fZ?j=BX}5~+JkN(;n3V*7Zy-k5)MbkW2Hs@T985^Bquqv z$C0@j^|4{xrJFYep)%Ai;H^TzDDGt$?<8TIFsj4Z+ttE_v5<9wbZN_>qblfz2c#V) zF7BINZ4)vrHnOc0%#y{YQpj2u=TVTJo}rKD5`nE7UK@3v+p$S7zCpf?Y~SKX=5X4= zc!=#?D^=sFC043NEHOna`VNL1wuR+9hKp*Ru)v8C1Bq3!En``$V?$8MoI@)ewOVLO z+O}+(=(WJ6aROP9#Ii7ECab3wigF7YlL3Yj(bf|NL%rwLq6J>~-Q@l%umIip1uDgX z$RfsPcEJn}3mFX68QV#%nFCzHlC%iepj`w5`N3ZVL+fY$BA6+j4N?rb zZIKJ#4=kd^^R`<#l4 zhH7$Fkkk=Ru>+Ne-Rfa+j8TBW;;mMjMq_U@9YmVN8RC(ZVj$!3Jl}c3VEqhT6}BwY z0yixXk1&$r0T_)CxNd5jRKcT9lhs2yt4tWgr97Tb9cVvFLLJdX41=>GQbAzPq}MeBu3XVz6Rzu5H@v;*yTajK zdE?z$XvdPOakePm8i%l7+LlwiF@)ak%fjH{SU4M473>?_6$%%gD#z7ZnGKW)i&S3ut~ zLvTTpfVan}?BjCj$E;*o)K@cP`o8Xc&(6o;z)@ptdc$@W02Kg^7bW?>8>r)0_Qd(* zI=L~#=clQZj%V*WtLS8NSXf^uezMDqVkZB}brtJuMA})>9n?JkTp+*}|LXeuZ52N; z;$xKWR@?ADuu8-#&=-k#uq0CjA@ST}9}!c35?Qzg9-{562(e1!=LE9`9(2WzTm#R% z14Whd^F;#NVLOMJ%&d`V*_O^+74uX3fvJ<9S*ScGe-wrofZGp*L$C)Z!f>nxR1ZEE z%ni@%H@DUj8-*Ri5-V@b5AC)^Q^s`H3$}34BC%;dI_3x@5hqRp`BJ}x&AstOb6iPZ zG)Jjq;7@Ttb}O6*i?6`(fRfv1p{GGQ_E{&uP!K|Ah3NDoqO2#lU747VBV%Gd@^&&H zBGJ;)VcSf)L>3*X5CB|D3IcfJpO{2aYAFd3tb zWpUjB2HjKXe_&?8Weehag}@|cAV#cNaET!2C7|;{MP?R6T1ePsVuN5-#g0p#SSgea z`7&?&r}mqNee%SQ%Dz2y+blZYFS!l-=PEhyM-vMy*#g60lp)hwLI<64r++rtVw20Z z$>K*saWe8F_2_Pa-?(pko7RCG4wvb+R=5T)Qep2JOe@FS5f=!^vrVDKCQ2@CK>R$R z>(b^7L6^NZ$tBohJ^6K+eJn~$wEDkbz(1`ROAy7OeJ^KJG_uh<&n*azcFT0|u=q_9 zs8W|j;9gEi*0-`%%DDq#3}ZiAbXiM@Uo4>P5M_bAecA|^y}?pCy8tV$ zJR^{`dE-XQOXLP6dU{f4-wzzO;tDpCUR@ zzda1QDeB?S(naYx7SJPg81{ zMKQgrR3bGN5<|4HrV4VQKlPIwPW`Y=wi?BF2L1#0H!rtL3XFT*{2lxbm zEc>wvKV85Nk&zj*ma0!}YPPbD35;N6WNi2 z0G=H#az}J=!4e0jVfXBo0`au(;66X8jGI0aiC%(t5hCI_0a=KKJC!V#y)th^a^TZN zT#W!pIy>@`oPJv5Z5BJR7Ed@Z^PoHad0|eT*gr3D(#*ZsAujSV#<-W*x)5{F`K0Qe zE3x-AEC0ZpblnO}X2ng!Tq7MeH6ZvFK~f*|I=^7GSx?Ll51or*=7`rO7+tQ~n8zSS zah@nDB-8u`L69%vg)=6aBVuK$4lKk}9SCBUGjyPex#^6`*|QN*$7~PI%hTpDu#3*639URJ3U*MyPICDk(7u;r{Zza;uOx=Sk+F&IT(|;1mYx zP)E!8LK-*w2yL=9mmaoI1 zw0xEiyh~+Q_DH+(yjA$ZG0^rG4h#9XTIkq@_TVYDOnU6ZuB^_v;gQgK`DaT*n=NlB zPB~{NcD6cBQ@=-#Gxn#%%Q(#}6pD;sUX&=bHK8G0%4urR7IMb2zz;F{%BwzS?T@=% zDSNbZ^Mx;b>DCLwGlhyvS8T{3@&dwKJUm}4OrnT^=a#iPC&s)BcKF~E_nXi5@tTI; zopx<^B}X0#6QjZ@2%sQ}D1eW{F+8rlK$n3VZO6Y=WMeWBP* zx44+VZO%)VE~ezE3urw95Y6G4Us!sK24ItTl=)`ouKTq*Jw{-zS90*g6t zi-6XYPwf@nIPS)!Zw!`7M#UEgcJW4v zF)Im)8Q2m}o{fu@(p#RJ1d(KMd%|EzzX-)hZH&-O(jFc!L^x?UurY#&z?3`~pAyJ< zLUakC^nxgk*ngd2w;%{&&&+g)tj5Oewp!@OmT=$}0Wpcj0{X}7I`RN+C`TT6N+p>O z&k~g^z6POz0hL9{vw>X5+!G5zg-t?l1}!Y24Qls7S~pkPe+o*G2@8vx9-REdDQ7f% zc^5ze;!~NSvYj%*j0!1EL43xQe`Y~kqP8V%W-dHY+$$Kt?A=R)-a!H)N{DR1_5?9o zd}L1$gvhi@Z?@1_WEz^V!&VE~-${Bcjf-fit8)T+j)df*0eEC6jxvnq+4iR zb{*GQ+lTC$XBfPmJPjtcRIa{szZFzpew&Wot7AvPbSoC<`uyU-tG?JPBuZ5Z%v^Y% zTQD;t)q0D(piHJnePg+ z0q%r?k_h)4Wdp_F44WSmC63WJ?%Lb20sh|S`-T;r`+VPw_q>={;`eO78^S*??019p zb51fSE&aYQUDNV;VY-HSosYqm5r;O834^-f3u8%C-bUo($*N#BU!;Nl{{1fcmLjV@ zACtWkK`9UHHEUz#l!ZmDk2E}Pk2_VNn43DlrwHs}a+3u_W$Hx%FJhzC&7KBeLCY3I zVY~|#Mro;^T9^&(rOGy57g_Nhb9`taE-Wgj3wxnwAoBlQdTN0b#LHn6uZzB;t|HjN zY+!H40&QS#+X8K1?}i0ZVDA&wI}7Z6VrQLGaPBi()JFTVF3 z8jH^uEN0GZrtBUI_eCGjl!pKtf=+n|Fph|a0OQD=5a3M)q!3^Wv?0J77REw=I~)Bb%09*v?0JqzbpiJ6C0%b0f;i2J^&#s1Q=WIMLe<> z+vkD7n+%o~fY#+6w=X5HK?KSmDgm)9H|rM4v)r)4L?YO)#53|KDlPXquf4|uQ+lxn zA?3Exb@yX2#j;!A{islcQsbviXc`XI2~ESsY`P?zr++SCn=IlCSuBeFrU zkEy|jer&TmPJ5A6_X4%~1WF^dmz)B{P;F!%RKShZUMT&_LSOmRwn}J)M>n%r0a`5f znF0fd1mI&aVEc*p)sLOtVBbqZub0{9LRj@OM+b|XUU0!q==3x9n~PqKhGOva2CwQx zPcN2y<4z7GpPl$=zA_~N)R+s-d@l@q!};vSLU&5OF`9V7KD*@9Dtuwp@W?~*Zc&VH z3R#i7OyXFY$B80kL@e41sUf1kF62#4DCax}@=#9v5VN;ZkxBEY%1wgVs7flwqAKz5 z;!%G{K}=+)=6sQTkv_0^KkCTQ6(R+|ZQe-S21|XQ6Jmyh<7`+YNcJkt zvIR+R@1^{un&%c~Jx-U=<92Tx$xRsr*Z4r=GFr6Kam0hiu$e2wnrUF)xw@EfW)9Hc zH#=eYFa`H9EDudp7c3%}DG+ElB+?QJNTfxGwHl(r06-_+ zJ8l3&ykO{H=EQwqWghqO+!jo|(A><8`ygnS{D+qiGz{^2j#MBaT`P8sc#+O?b@R_G zI4;1hP&C1-)V{Clz@i=;mFHPmPJ0Nt9AUf>uEF>Gt#cgfDSz#J8B5x7@hLUISs zo=LB-sgILV{rJ8@iwr!$u%X(UD3_|Q?&EBj*13QnEdHrYKyqzbw4n1MjNWkSSP*VW)M)Um+nW|dNiMbsMqyHDV$H%KKP{gS zl;^<4xs{|fQ!jbwSJ=I`yfgSRiT;N{c8a_P)g#%^eM|_)QbHZW5W8EnFiKn2CI~6d zH!O&Jg*SNU@c!=Bfu(dTp7e7|>jb2CWVQ%$f@jtf3$ivt+;s&zH;%L*%3w32fRyyl z=onEzmbKc#eQRNMPDj%MZbt-=5bp5T^j1Y1gJ}vq@E?#SLQlh z{KPLO%k%Dc&t1Cgqf>o>mv|quF+E{3>3h%aWar}os6;8cUr>A_S1Jgm$OTG|y3!4t zE~&neD|E^#J0Sz)&{(3zr>lBL|~t28t;~j$`=S? z**tmyIv%40A~(xt7G&$vnKM3th-rk*6O<$})L;RO+H4by@pbgb$;Ky~uP@W|EQzrh za`#mZv_7BDT=2O!*Ah>Br$%gBYJ2eW;vB6>7;ilQ#D!>YK4m}(uP0=73sU>I>sd{o z+Yg@A6vYKMcmP`}j~sBn6|JUTn{Kp#9SQU8wLs5m+Gbyv)$|zymx%1+ZkcpG?w%f; z2EG<`A9bP&^F)Y62wwT0p_sEzJbRN0kxMcy&1fEtHZ-&my>msBH(ErHt;lv<#{wBm z(2_E*X9CflS+XFu51-H++(-=<>`=FD=#>1LmNu3d)DF#-HnUwLhMgx2NShh^a~yRE$gX(H zwqWYzX3AVgU4q8!@`n5A7yB07rr93{0qRgt!JG%_fZV$9ggXe(AsjQjj&hO#@QQ>6!KLr*6wS{eE|E2MMr)1@Rs0RtvSL{OrKG z%wKW=-3g1~VTdwgbvV~Va@%u3_s`+Pj85wI9fDuZ^nrJjnu2-IF^GMo7PV z?M-|fl(t|RAUYY0TREPhrWC=}L`2Vh7h_*2S66B13$hvfNEU+)7tSJLNQqk>5W@yZ zEaYj&HYbZcFnvH9Row?^IEw5`*_H_b+?KXO$>_qpNwC~zfLo;cBl!#2a~Cn>>!5Ir zL4+2rF}RhP*76yZB{qs&pJ~fba>|*y4AsmBJZIc9YL5ePJ6(oXl%N1{c$u8apjSv= z(Q!T(Q&gA@_TC9UF$*wu!cW>*(w?3ML1T8v&SOr7Q{n z8yskpNLnztAugg7am>@nnpwVQp(l7r7;_jdB01rsd*J)HXFcw19!?GBF8BTi=5zm) zeJXLfN1|d%6J)0f#xl8~!_a&7bPuXY#~gjI*93<-E)&#*SyXb)Kt7T3 zZMn&Tc3WC7+m?tY>qRh63&CNy0L+q$EarXTDIjDPg@Y3}H_KOw`4`{w=a|rHJ9dD` z(wH&%sRfbY*vK!ATTZ0C0+z6f1?Oz zc@d;>0`~$8S#H_#MYSUULoW;jU}bLE7wizW)l+Zd0f;=nQ1-ompde=7TCm`PMvklc zc>$}ME0pl{0Fw$>g@9Lr-|IH*m`j4Z*B1(3c_23`i9XnC2f7_!tXt4?3&H?6)Q^3z z!A{tf4R$gRCm`E2@5E!9ww!Qm?30&UV0BT2h*`!zSjP**2tn{ZbRi{8bOC*zFQl|0 zej8!-Y10Mt*7+d$Bc4co7T9WGj0YqFDVEDiN_pu*7Tqr_MWA14AFO}@c}6Xv!!3Sy zZlW#vR!oX$X8geyxNuE;fy)f>f+am8BID^GoKy}MJjsHSAmKyd$j9wlIP#J0l*Dpe z@EqHS!~z#ax+rjAqy*P&;A}eAdf(!|T{IRg$hQ=-n3vM>km9_gKkG~?sE+H3@EB-cL_77=k%Sj1)eV09As)aO;g)DIXhdzG@$W9^iU-muU=6xJ6P zqp-f4_`#a$+h_*88uNiYK_FXCZ1$pXq+DH=Y^R?bRe|aH+EEo4;7@IP!``BDbj3EH zpZMN3gTCglB`imctz#)_3nBQ}Vhcs)pL{AcgmCRsspPlYs- z207OS`Y@FKQ(-mDQd}2S(@^MY4AmQF!^IOp_nOUVd7Z)A)}} z`TqW$T;c6>o8|3`adLg5y)Gq}pz;PF- zz>w)L1u8Hr_siwaICor(%a}kKfj70)hYue-XnyzI!v_zECSvf%2Qd9fxw-5_MA{kF6JuD#Jw@NN=cK)oc+zFBC{Hz?d} z9zHo1LOj?Bh7x=}@{Q9VeISHbSy==4%*u@TEDqaqe>@hS#mqTE&(8V>;>!oz`s8^FRGU}2`A zaM7AuhBhBxtuN`OTZ^jY*5WfevBfPlu_rCv)l=$eVlP!3N9{Ykq_OjPO*COmJ_d8Y z9Kj+SU2Q%)0{kCcZ9UUzKIXsxwWYG@Ew$#>iB)yYSyF^#c&wTx~Xw#u~9lV})2dax>^yUWz?A z=vjf4)m)KfHPyj7DKRsE30%NrRI}{&*VZGJ}Jl zK1!3W%pksHJI?ZStUT=Mnar`pH%S*RiuLR)9F1hpj0e2IsEGcB-KrmM$8nOYfYnXe zjp}2SqY_(EAep8~TJHyW5Ovg_mq8js#URhq@MN4zT}=0&|2EiQt*BS)T@bwDVo<$qA;&k>Xn+}q5B^X+OO*m_CK}{4));R&hPQp z$DLgW6#w|4{pNi~msMcJfvHeuXA}NDXumceg#NMdW_Q1%DOv%Qthk#EBkFRW%{wUX9^HPeQDTXRFO- z)vNvaGweb2XH9(jt*EkDIgKbRi#4&d+H7{CB$GWMqZcv~&6lveaO8{c#D+?XoQWV7 ziZn%j8sy?Kj3N;yxj2!c8;l31xj4BNe|Y<5PX;}iir_2|`Kc89?LP=b;%Ng~Q!V}@ z=v#*3Q%%nVASql5wtj zQ{}@X7GbP@YZj#&?j~kWC+R~ig!IR;+Tr3I3{Y*hZ|19JG{uWuod=hIo zBF16{*f@Fnb5Rilk=Fv`a%u+r|?0ho?zV#0?iv{rWp1f2Ee;R6n8jM5}e^6QZ_ z9A3ezP_n#OLs9vf)2@PnEJSFa)%#|?TKn`6x_$V70iA9EDQaO?uzpozyWW%iU>xN; z`)`9$o#eaPC!;(Sy=1sP2Avw9OJUDK0BsNK&xXTV)dU|r_}EQG*Hzw&aQajdp)RTh zIDK47?&W>f)sPgaf3J_Anm;Ob#^^EKJbZAo$}l;x-;HE+&H84&IvoP8sIh){C3{*axDBuvy zL@$J(_~;sng?*v=5-&yTs^9PTO{WhOaBfYsv_Prwqeb#@nkIuFmmq()u6oZ~EisFY zycF}TnnrismR!&!yR785qII>{@9V1v1mNf6G{$-I*;Q?SyhXiWH$q04G$WqUhQg+< zp_kI4Ua!<1I3wMZa}{}R%66&j5RF&C4&ldX+%8?h0Ml$Xl$g8{x$JeK3 z^EAjrmJFph84ogzFZlFQ?Q%0GK<-s8)&xq!YW!h5sH##Rt=OqFzkU4b=yG-N@weZOk}T9bN_C~bvK?&&$m&&IZ$U3}yr}vcuBdUZe6rNRs6Ny)xjYRcSslGx zgA^5=xTlWdA)F9ljM8yKUdgWE6SbPb0DRv!{S6yo+>=+U^Z^>uP3R)CVtCj(ZbUL3 zJf^yN?J{n5dAL6YB*DBvYSNX zVXPY!YhpA<1DTySd{8YQpMv5J2-L%OKQ1^oLD1P<%D6V~OeD_UrKt<_}TWZaN0nXLX ztXi|(ezo$VQs-0@_N!RCc3njDk}h;1 z;6iOiCDktKCEZ3>NpP?ccNEVo>8!?TLlwPuH%`N-SA~|`?{?d01e@Cq9Ov>X*K^f` zgFHgRZhR~_JO2S=7+9djD`uCF&=ALOm?D;(oktXPgG`D_v$FD#@Ff-5`K$A?Qm5LB zrYC-jE@MKp*t24xE?j1GD30=@_$WP|{iZpni%NyJ*-hepIDkzJ$9+_2y!l=QU zg{?Y-`4%Q`i_wH>#%}R#&|Aoj063PaM@@YG?6vXjx9;yoo~VbSp>nmxdT>9e{&4b| zEZt7^J|pzFg0bNRRnzr24eJg9f}yN)5;C-Ju|tgRK|e`FRk3xYK!HmgD<-HM7rU$! zTqc0o>UGm-jkn`X#nIbTP5D(See=-!7s#dl;?beje7$%yH}?g@+1%KeGK_lhKIx3f2q!Cd?N~8`2yg#-%e7HIm{pyF zhY3N>@pH&lS2MD?`QrvJPAe#*eXR!U`DdzX!wf)`flST?M98Sl+x3L?QsgK$DnTri z5%JlFR%DV<*;aZ@+~}I^zJTew zZW$x;#G=q{b!7_-@mdBn1oh2)RYrUlaU!zoSYT5!x>x^rezS}4Z#kA5qGC~H2Fpg6 zf#I_%BRDjb=GGFqJ*C*T`#v8=`y<&6gJ>g(b2xR&N#EOUMegXRN?cZcV+HV=u9DNt z9Y~E|DuZtjcV*IdwU*deewrqiLUK92RLfwl5Ncvt(YzumvnV6zS3@6ZT}<8v`DtSqToFe$7rfbdM}>65l!1JQ z^y_-CIlG;UHPL53l}_2eY4;rf6fwG&d{wJyQCqJ}?vEYHC88iE4*WPHemR*u>Xw*c zcF;U&t9l~oD^W!H%-?)7@J`$Vr~qNk_99UjK#<5o@bOfa+Jz^Mr4EnQty%gk#=rxNz7nNme-LuSp$AUk?X0mC%EnASpR z%JnWD;jyDf+4;RW98fL5+t!v&JYLHxd_p1BZi*ElA*@&o$5}3del9Hn1+XDy4|U=E zu(B4liWRLUwpf{Z$_*cU)8><=|mF(wbqAjEX9_uA?4>agScMm^2K-DeX;+?65fB z#WA|97tJ$7L1=z2mHb>viW7C%DJ#6Xf16TMNJWp^R6MFwX1lYMql&Iwana<^e3@4P zBI8cDxC1Ka=6VY$%v5Hvf!WH87={^~+Imp|7gaT@+M`D_q2hv<;d;uR1%#o3ZN#ubD?-Pn%to)wx<} zR%$b~d#@a*aA1%1j4^)V?P46utC8%2)2fk9!+12#E7mS!_TNGKHSV~(FZT^MhK|_y zUj7|Ymd0VT87o0sX2{bi@JB=7~*OHR{IyY~u+09CcLdMg` zVEep*R^77on}^e=d8$Z3ZF3RJ(be3>n(x9(RVR#*Di%6ZdsMm4F;<(TsCZPOM&S3P z!%F421_H$+jX<<4R$s03!VH`sd!M_fvU?_bpEDV$jZ*uj8P;yodrh6A`u*sU^U1h} zvtxraG!6pHv`c4SuF$oN=niLw8lWA-4LB$&w-#$1N8O3*&g%Va0GGm|+MUAX1I_P1 zBd7(=%F)$AtD=0Sm(_na)qmTo`XY&<;kea$-ZG2>r1OfXX#XS5U&DU2`$ByK(NDE+ z4i1;q6nV|vn2qwav~uwSx=(yGF7ywkoh2*xlNh<6aF^ywjyZNKx>aEOE4J&G?blMK zeJ7mKA?xw>;^}K41@_l$KDbE2UbVJ5v1xulJZLtRZ?qH!H${2%6C5A8Fl6`J`vI2` zHXr}WwD~E5ysdysQYEFQNlLDrRw;Mx&XJLH?!lDBeYkRo6weql|7v*i!mZ5NQoH@j zA$WTiDDLpv_BPufx6Mwo)i4vOJRgUt?70(S^O&%UN`_S!dC53w&vC}Z3FtnJ6}DeN zayE+8Oc>dSeAPg9Qp&B$%Zk1Sfirdz$6C_OlbKqH5?_nV$ru{Yo9bcFHEc9HTd9xK zfi}{n0Ik#}H8ZN8(=l9M1$g$skU^WMmqjZdeI4&TOe&uq`p!7+Rx9{f#N#M}4?2A0 zuQYq2!HgLnQGpiD%~}1KYc~VPxfyNHI47>a52v6($~zqBr{j4OpMbgMKx zT$u+CSSJQgZXcD3)l~z7jQ{W&<~cJ>SIv&AqcLZA_eTnFpB?5^U@ zDo{Rd5#ySp#FD~-YTlGs)`ZLFQ8`^hCrsO16>P;vmUR894$@8W&!0u5a%^1MA2gev z9ESV&@#D&@VHx$JvAU66XSp11_hu^<*94}ztZ@djHw zg>N=kMfTIJW7!Pj7%pdMHp3x=CIoS=H`ncrqiuw*IGT`Qz0GCGS#*sM-Q?}dRHSb- zr^Z>m;L27vW`1?JIvYX9l@<1fI1MheK`Dr@#i@)&iYI{q?L>E~S}PoIdfBXBz^7tp z%CvFPsZ#K_Q_gl%9qoP{FT1L^I99Z(kfY&A7lRoE$-_%|GcGOc=MiRQ9Wnnn%Y+$1h8oP_!U)mfYXCq?j~DSB*< z74?;iM6R@g#G&7}&lnv?L8dL>CA3U*I7+e?jIKX5oB#Ts{>Oj&kN?MC{)hklU;n%R z;^6~o^_E7NUqoRdVr`UUt1gn=el@$l(e5{dZ6&}7M6=Mj+BNqhcV-oyYJz^OKggX} zE4CXGN7X$X#>X_@!}!>BMe_LV^&NY8oW#kqeYeTi=$W7qy6t{N7;AP z!=vnI|M!BSk9M?o)V=r*s(sU+Qf@F*0 zl8^|>;^2B+qJrk;;e$e@Lc#-UII~#~P?#_WdG*m$6QMb@eG4V}MA%3kE+gHT7eBH_ zAskMLDBwPbZk={u=Z;0n`0$IV!#uy!APIphmD%%>LAnS&JU0TB&h@}(27Vth;Os1v z`lQOQ=+Udeujnc08La4kZfN4V?n(>(9!Qmf_f zDc1P?ZGD{c_TTSqPb)i4LoDenVzI13hPGHkCL|@;+VT)@XSJVdDZ#W&H-1B@&8CLy z8;&u5bM5sw4NVF44~(waEE%6Oyas-+;x9Eih$fD%b!w9!9Vl0wtX8va9$b&4I|Vk_ zoAOd&?GrQrso(gE*y8V-JA40?_20WDzo7=1${;6_2TlqY5_@|lU*_qFW ze>%!uygX{I9nY@4`dmF~zB|%5G?KXOQ>x4b3xkdqANbKj1$W7`8 z1)bSt!4;dX84kw}6rkU$ER2HO+%uJ<0L~_*%jLG3 z2)^%i-B3CR;_w&MN}j0UXAM*F;8bQ(gH+l4dITA+qid1rB-pYCX`ED!j&3qM31hVi zrnU+Au;RSfXz%T9w_kU}UgzNb-j1j~zS^uQjpv)~osQV*bT$Fju9*SgFcP7j0S^1u zs>M9W&N65o7)7X4IAwM9Nuf*26G@6jPSBm2rh*L2k6|uiT(O=AqDZfrGPi<*zrYM> z1=Lr=xEqc2lAcQPBs32CHJo{@9R};hH&rzQIoSYPc^br76sXmJt__-Od;4(i8qtyV^~||F7)`SZOSg(q3rXgrtqRJY(`+qvm#F>7FlR5JU4}& zHk7g&TDK)sa0Eqg3}r72av5El>1%p|Nhi9$$yvY@g1K=yqi?b*s;Zdp!KyJl_=e(E`Xa!O9 zC|A|!uZgvn0$1s<4EM*73Kkp=Fh++n&CJ^~su!cu)q08yYW}&b;XnIBGROvm>Awnt z-jl$hU+D4H&A4CQh(l$mJGSHpp-yFe`shD6l@{|t1v2$viY5zPrZ!G+5=Ib*lqV*F z5%^Y;s^quk3ML@Wlxh*OPXR~JItCMdw7L6M{28-~{n>7lk0z`tgw$Mp73Gxc7Sx6v z$*xXz2fHu_{*zp)Tz!8|G?DySsC_1Lnd;*sPegJ7c@cX$Yzs|gimir8+W1)5qCVl> zh(pu*acOQni(ot>d-6g?utbev@=F*+fjTZ_JokRT*-N@v^GA8oY`@!XQdh+`PV-^Z zfC)D)PlNn&pqkLZT){v#d)IL=47+o~AUzw8=E69G_ZyP90rejDlHr^oz_|dlPBIN) z<>`Fm{DlVb&3x5N)LtJAK&%P;>+|PNh8kBs-Q1X~C~Jf1bQN(xsxG5oS`&WuykR($ zAnB6WYWw5eQ=pd;uGB4!1R1R`E2P>pHCeVjFm^&s%Q&hasdlwd%YgK8F0VjPFd$S* zFy_J9=ip-YCM?BbuhmH11b$dbZQ9SDZCWPnO9!I*QS<5*EbXgrj6I1kx7uvt-)?3T zt2=>;m6~{|RR=;?A=c!gHvPOJNx{uZEmrJ@Kk#hT4|#Zh!8%(^B}+xM91l8%;Hu$a zR#}8Q3|8d@xcZ*A1`XYT0Nmt@VZW-UZpO}*1$-8{TZF<0nn-v-STzvnebDF6tg`W_ zP%2L3!fcFXoLP};30#jGjV_>uguRyZk?|^fg66grqW}Ti=p>EWEeTu2TUeckv}jYd zi9oJE+t=+fpHymy=I&0s+8XsciL)W%&^mBIOiYdKS2E z_rIH1(96rIBZ#q0Cjpt@!Kxnh^3A&uMA3;(&t@B9BSFywY83J`ARlniQazK`R_)o3 zdDDky^7lym^DCYlv430}RD=p1#IETk9Ct6*=JxXRf##*ite5VVl%pBya zHU;K34>nnS^?g(CO9NhUo2Uz0qb}Ux)J0)DZd(g0?(e!g+PYvPtBbO+|6>%!XG&%< zs(~!H8l{P{?SjA(jKW^hZNi@rQlAA^P4NDaY1VYRR&q;;WI`u3@El0Mq{M=5FUSLC z@^PG2Fp~@BXNe)>DUcuh;bx*JCXZaja$ZV`vYe2su9GlGZ%H};<_~CSxQp@FN$&fl z$aCA|NVB*q>hXEcV#V%DLh1vPn7C_lEEP0U)tbqxNST1a+o3M(e^ts1XbR3Io+X+( zaXM}tu29@93G0o~m$?NU?-Zs+)*TuPY+t18NXwymJKrr_m<(RTL zBu!5{`(78S-Orz`)|R)S&7rDKFB_nnrbMT{Hhx%^u>BO1GSYTAC-3&R-&!i?AL^_* z^1o1tki@D8#S0kRs(@@rg6ADX!z<2^#;;ZR)zC>0=y-QyF|7wL79{s@ET{|#rl3vs z;Gmr>Qssy@RXv2*{7u*sikx9hy(M6(!JiF2{08jy4?N=1#u`rHOPs(DW?@IIZ|)$!iZO$o#VJ4+OZm6bD{DuePXkkTAmdx zwSaPyA^7an1@LT3c#1UbMb9q(yHb0q(}=TWZrv1NoYki7LHw@fQu0uSok{o9g#Ofp zabL4YuzF%%K1j3DDi3t}@ip-=PfV8XQnS%&(Va}ytQjd!|F9XV?CD58sEW!?gB0kY zh;8L_vM2+D2Eo=*Ik6qgma`wGv{755-!W4AXnOPR&nG}RYX=k*4Y$+Y~b z25@sz+17MMY%R%D&xwc-a#u)VEv0W$2kCk)A|Vm4rJbTpV3-P-&tHLPZZwr3s}c4~@$ZcU!z( z?o=vUzMc)&!!3D>u+Oi*1AC5S@qHvN35yM65{jcN~Jbid8|xNE0x)ZKNwJ{caul~`SotLa$G6KL=cxUEKPGX z!_drNj6%*ZHl~i_V^m)qH&txqA@d0XCrzdHHj%F45?*q|>~l#h($g?bs+THh8@vp( zB4%D`{;s=c>Lxwz+KeMSpa$rr@#mN|zajk=a}qX#hV}COM#~T}%R?LagqZ_J^Sdv- z1*X@lrv=XtlPG&gnqkIGOj zhDi_o`DjA+6*z-oC=}7>!ozUW*FlKK#fRgnESF{NuR)ckF1stb%Cv0avGXKgm3w&m zZr$ehNsy_#XVJC0q`k@bDLg)C&|{kaVgy;G&NA6b5N&~7p(?mT0&CV7rY!n zucs`$HSH}X-lgG1kn8MNVOJPcuE>>i*Api)N-n`kX=KXb;e(QIU1W*qC2=JevD7{k zL9Yjf`AotOu+Zz(5bbx{tKt%}7r|?L5Ck8HJsBxM5UNF4A_g)SX{bmgPGX3yhP%C@zi!6na;OAKx<`AJrd)fS`VS#C zkA2l4wp=x}ue{qpEd$p^K=+xve)tefvDzr#`1sK-yjWv;^;KS~)C##a$p~rdS$~l= z?o7bkAL(;RrBy2m?Cx~L_NKBf|0LeL*=UG&d%N%UwmS#yy`RMP&erbU+xEfs?hYMe z2d5!CvenNo0R>^E-vsG_;WCICLhQy;Z1=Psv#y&=QkC@Sgn3e}U3#;XY= zvalBhX(+S03a^H@i`_j{iUVBIR6tvfO-yevB?>l1u{q{k7eftfxvb&{0yITi8 zw)Z;PiKnxD@O@`bbp8NsLR(_{?YlSIoz1$~-r0Ebesg>0wOD_DAa-^S#GCE6+XtOZ zO&+_dHB*}RzPlyfcJ?;DZ|`8&x~r}2gB|E&Yj;ny#k=<2!S=@cH|;&~?)~1o-Th7- zXR@=qGq=67wYR~fIk@3dPmiIv)x{Q)6uQ({3JHpZ`-ds`(pq7 z)>a43zV)BPo9&Ix&VEOiZ|{pXApZTE0~qrA{q3FCb@6t0b9?J2nDp+R*xcSf*xO!z zf3UstT2K1>?R`R^Le{~)*zD|We`p_Uf9UMf`Ze|bRLbwYAXZO(HopT0rzpsPXNs!T zFcIG)kgZoeP!gNY5HBD~mGe7wn>)}KZTM%^`-IWm829UZ)K94C093;c;UC*Kb2r*y zo)sknN4`$&zF_@3rQm<;!owy?bE(tt>bw;;{2Tix3mU*_tWKE+-Y_Rm!!$VaLREeF zV*llgJNj8O%`oc>N4eIe;Y44FnHjNS%(?49Cc#p9AyaL{QMwshybeQDzD4HtSo1rY zdC}Z|`J!{D5h&8QYyS$jcj&$I^2I^1cT@3@R_wT>>cPtwO^w2tyDW^Ei?c2lWeZci zfNQ^2BQ$n8uhqu;xV^Kry|aDrlRJ>lp9L@dZg+qC4yAQ=jIuAACm({S@ivS%gWO6H z#c8S2*O`j-DK6OhKo0Qhsy`JF-H}(_ji&Q&f{vpLy7pS>2Kyw;=M}BZq@gMnkY4-y z(hSM)6I^A}6Rgtl>TUgiuC*>wnL*SrpO$|785->A?QS|U*TJk|6a(fLL=`&2Wm{f7 z9wMqAgGr2K>b!5JuNuR=vw)e?S+j}m9`1r>9-lQammVZ{Ikj3(<&*ZvpdtG)%ulO^ z1LwymV_{1@)z)W&|%94iMO_1EH|xfW2QiS+_Baq z&ZlO!f?7@)_tbE--fczqHJz);Uzw@-eAi)WS{rBwTR5On$+?-%!=bAchN+Trph&Tv zB+*JKMH$}1hem(8NW!S5~E>InB z;FBxU;o((<6TvcPr3O$iS8KJedcd!Gz^{71zo8y*Gt5R&aBU-~?x72G>sBd9 zJb{dE5IC9^Re~jjlp|CD>Z<aY9t>Egv7Nnz5K!%IT`QbR%_dH*r^kTW8}J4X<6d|X z_TbGaOtM}o#M>Sk>^6N7l$}X1U84dj`#KCpRaaGpov6wB$l41os}~GItKz1t)t{3v zuFllOw1b^tOp6>vWRb3+SEAff^DQ}|bp=vs`EB~dRWd=-f>uAFl9i@hY|bbv#hjR# z^zm+8DSfKNt=rhmZHnvCwQ}hB3wOv~aCyf~qI6KSup2?VFJWCviTJKt`;+)VUayFm z$8R?GAHO&adp#MyoDnxQPaPJ8!wbl}hP}U*`I~SU=CX(6?`>IC0rJR)!wd4U60K4y zREchsE>D&2hfyw5wsEf5#<^-3zM`TPR^5>j_3H+CzZ2=ylm$h?rqp?Dwclq6J*Zql zVLlA9vu;3<+8inCVg5GA&Nj@~0$Tjq-+t>iI1O2t2*|5ZK$!UgzWw+N?S$F4#0y1o z;#;9#J02yM)dj3rD{Pb6t=tC{5F9H?Os;*YI^qlH8D{j#Q1wqT1AB}9v6IXcN#<@B zV;BasJ1b^p?yo4g{f>Xz)%i}h-eyzeNiSIu5>7twLD@*galRQ2LjSnC@3hL5ENJMU z>;i#)(5oh1__mlbGBjh(PT?k-6y∓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 literal 16821 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 z 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 V{dV(o4>;t_!Q<-7!uLk(p)Zne>)*OF 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 O_UC`;HlnrwU=jcrSoP`v diff --git a/imxweb/imx-modules/imx-api-att.tgz-hash b/imxweb/imx-modules/imx-api-att.tgz-hash new file mode 100644 index 000000000..c2c48f0ee --- /dev/null +++ b/imxweb/imx-modules/imx-api-att.tgz-hash @@ -0,0 +1,8 @@ +E6573E34E07D56A25D5A5E5AE4B4B8944C02BAC5479D6A7870003C698401BC6E7D3B8FC6E11FA25628D36EAA6DD0F9A71021A0114B808ADF1FC86E7A17246DCE tsconfig.json +52822F64AEA2B42445A1A01278F864061078D3E60DF1F530F19FEA5E077643DE3CAC8B4A4F065F238F2ED260EF8A0AEC94E5711DF64D75DC9CEB1A4C35A865D8 rollup.config.js +565D30DE7CA344FE6BB6724E1208DEE942D0CEDCE31BDD06F11B8C9E8DA76466100FA64B33FB780C2822F4EAC1B170EF1A2E73BDE93498BCFA185923278A07EE .npmrc +650E93B82E1A115D0AB586DF3CD5DC1B8AD97440B674233F028E6E60211D1695C871D3FCFD17A1438B5E1A9AC686C2766A5DA5E41564D580BC181C8B51DEAA25 package-lock.json +D592D0D46B7F3E2D414AC57346585076D1348FEB583CF518DFB3B5318FC712AAEECD4EECB10BD04A50BD1DB3181B5AA27EFD29D2CD060DD8EB27B87778F5D611 imx-api-att.es5.js +9FA5D239DE9D86A4EABAF8CD3416967917C5F77A88F2DDB8D0F48F28E72EB14B2D754B78A3CF972428227A06813FAFDA48F80253BB8EC1D49677AA2FE569B8D6 imx-api-att.umd.js +A9C0B61DDB3B45B9F836C8BF15DA912EC954166DEEC833354ADD50790761401B38B559EDFCF7794D6FD4747F668376F6FF86DC5AB0DE5415BFAC3FC5451815A9 index.d.ts +6AEA9388D02C74B1291133E9912F11230EDF939B38C78096D3EA7B7A23FC1DB58989314C0C685DE1657BB53D377D4A523D77C06E13E8C7918402C7B8A6DE6758 TypedClient.d.ts \ No newline at end of file diff --git a/imxweb/imx-modules/imx-api-att.tgz-version b/imxweb/imx-modules/imx-api-att.tgz-version new file mode 100644 index 000000000..f6d8051fb --- /dev/null +++ b/imxweb/imx-modules/imx-api-att.tgz-version @@ -0,0 +1 @@ +9.3.22 \ No newline at end of file diff --git a/imxweb/imx-modules/imx-api-cpl.tgz b/imxweb/imx-modules/imx-api-cpl.tgz index ccdd8c8bb172e2890c68eb0ef5611a2540f83a78..023ffb3889d25d6e6620a3cddef23a71a7a5381e 100644 GIT binary patch literal 173960 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 z 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⁡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�yJbbpBwxMxN~^UMPQP zq$9A1p_KUf$R~T#a9UY)%&~=+_<5PE%m)Gp5T&&4Op}zI*wA)LDkpXo5LO9a;tDNq z5hNVNwl8L>LojNhTW6?4mR4_(&?1zg{{$P%HWk&zNp=jJwLiu@)z*j z*2p*cnvXg9Q{8UVLJCvbWbw{~3iL66Jd$TL&P1VQ8l_tCRgbA;p4lVhHmN(~_AI;% zpQMN!LR*iB2+8}mswzGP*p_hTXXQicX%5s#vnxhZYmnIgl}_hy*B%DXDC2yQFR5oj zfZi;}1lMNuKi4NU@(D_owzpJKl!*P|LGb7uyiAP-OOE_#2jMG-zkV>@S-*H`l7|}$ zsxpc~aB<`QTW~uXwvjS=c~>4W%kF6g;n!I8$Ejjxhwn@f>p^q;E^dA9@tY(%efw&h z;38s+$K+jB-tA4<3?D1i>~QlkqyeG3qU!;}bmCQ1sMeTb^`dJc3*%d2&53a>PdT?# zWtfiCMRA&tj$+1Oj_%mJKFjz5%-By;TUS%Fme>cO_{S=)wpsxe;=JR&mWw7kJQ)mC zu!<3r=@e8xQZy{l5G{QUnHqp(FC?vD^bP-^P1fszMqrN}H^{}ao4ojeO z5ydtaT2Ye=cgf)Vjnjh;@0rx5XshIe(Jl7u`aXJYZpVP4WLU&NXaGw zO+FR035_r^5fHh4ZDg8WTQ%R)6wJXUJyu~b4J5Fszc+2=zH}pZZi|tens;D>i76$C zpv<8nKkBKApzSC}M$Y`C>A&1FlFoy9|H2V8+pBx>z5Vdj_=L$ojE%d@g%jHo!YD2; z4&mhd;VDMkQ9JvW&a7FU*Yj;*{hr8!PALZ1@;35g|y9 z?ba~D`*p^Pd%Gk4hTSOrMoRuh44LJp-``ipk^)yIwv>|_8-ZfiY zdu_;f7gv0SE9aIrgd}lu`>ANg!p6n!az3wOX7+~*FE|P}u}ALo{8#}p$kg;t0M2bYm$CV|T-w=DSvmdFi5d(`1F6igl$P4dRd!6pqAju0W4*7@w z_dR#)-=EefFRZdKs6uh<;Vlf& zq|j48SyY88Z3*YO>F=YD66`TE`{~)}z4qnz#=`yw_*bh7wtT{kR=p}Q(5j(ClYX%? z5`8~x2OQa}e)z>A+WpNT!7@kVFqn*lqRH5D1`v0$l(S}YEuC=2zfJ1#;h!6P_rAImKUXHQuQ|@Ce+VuX4I-BNjo+Ve1=oao zb-y!Td|}Y?OO0IZ;lpbeyq{SrH$&KCmd$gCLykbS6}`+QfFF^~6UIYBfcfrCi@L4} z=6{ZMcQzhME}ZoVP!toNw8AIw;(uwTvF6oG{DKK4XIR=10_XNQ5bYAC`_~}AyE2wg z<}8iIfa?5M4}XPY^=|jSxzl=+dV%%grh~AU5sQMHut~5{561dcqLnYK3$^t4T?zSu zT5Ql26$sr^4@bc*EGJ~c0`fJ2`lzvfTE5a8lAVLKAX2Hb5JFTK>MbVE(wTg8*t+ZZ zZ6?RcMXE|%V=)XU-~z7DS1Jf#tmyT6daceYB21)zuM^s~N; zcJN0T_AtG&4GNSFD-l1)mdb{mF1qQymli+Sb&+}9QLPY znW9aXnbhe{{}8|JQl&Sx?W1+FeuW&N&GE^0H;plu%&8`Xmzuh-HEJXew!+#>S%8Mv zf#GLh-QN_G)-&I2O*h~2s^;}dD%x7Pd2WC&+uBG;nS<*DpPSgAGn>c1lyQB9(2s(^_|=oitCQE=W9 zc0Eg6Hd%^4EJw6|Bo*@%6GDV#4j+Kz3OsM|ToX0Zca7u}PNS4@aJU|*(eQJGDs|;4f4DLM^ zc6>W7(}~{39caxwcX`2!ba*_^H>DR;DXMTo5OVvPP^65FE)Fc z<@-$B;l?o~=e5mt+Q|(Za)7`=NgctJtIP9cm|JJk-41@nY^u>+L7nbrf=-3b2F3&L zM6nv^lzZM)^7}n}Pdf6vsBrkJ2Ov%ik;d0spP6x1Cx4A*_W5prIr`jH4habv9HXPX zwh(qDoQh0Nw78u8p@zD3`@9&~LC91ah8JUN$A*tEv~nagVw-}nbyD1Oonv#X@Z(4R zXPrEe(|D$)v5dwbt)!117}GQVZfVJ;6XTxk1b3`i*BwaxMXlF=M9%|EiE7pc^@2DE zQ?KvK(JzmJ5k}x2NL5^b$n3~4kgd^4-QJzo@G~{gl`1zKWJ~Im|2uJp6ML3>z31n_ z!R%x$2mzw$bFeOB>Ta!ZcX6>0HU=8K2Gl6CM~{}^ImB4Vw!(C8sxKS}{LDJ9r|bYx zZM2VAXqX8*^;t*y>% zz+oww8CAuQk#znhoMUhzLC2Pa_l0^rrxLmYKO=w$CLqO!0(CO>`f>|RW7&rv?fwnc zqsMYjMg1;;PJIzQ+UmjfkE!LYhV7@g00}5z32Z*FP(AUalHs1=9uW!VV4iv5hlx!S zDrcJL5ULwYMEo7Jz^+4gDt}c2M@Gr_Dafa_e?!tj&yK&-BK{ZXW|_R*VhWO>oIz&o3AuW)OX+fH7pLa}n=FXpMgr~w+p9rSRj?qfE$KFG+&T__8O_V!GC zeDDIN7JC1Tr&i`b3)ZIf9o$v)u;gJ&*o0RVVBGg}ejAR(WqbXb1KAKLx09aePlJpS_gvh+(Nm6on{=qDjMX50gKM(YZU7QIqyx>0bd*In*`4mhV7@Y_Q8Mgj1`$25S+S!= zCF&F4j|)l{9#??jvG(&rHIN9_Ah&Pbu;E=9hqI0|5FU;?sAs#3C2WeJBR(B4jJ505 zlpqN8(4q)?^SII*#aQrHl8=;QfhTCMr-Cg6I0RTKLYuf!nwPUAo3ojWANCGCtRPGu zKF}w%(*1!Qoc8sZD*ND?-}`Is)Y3hkr{U>namnf1owhjKj;HBC@x!^1je?Ef!;FBs zU7nt2`1eb*eeOE5gR{fAF%m(;Xk-VUCYfyapi&(i94rIeIha#t3c|99Vq?SL4kDUW z(~7~HdqL_F3)CW5($o4O(!SF8G%KXtMqXhUwfYb>W4|w1v*8|lpQxW1O~Ucl7@Y`P9r*xy9(P=A~HPJoiet(#zyLbP~ErEEn&;W6Z`hWN#~AQm2$d%cvLy!$U62PDi4JuI?jiti~u zgcZGrO|~kT>sUy*z)(4I17= zcu{%ZhZ7psOB?F@;kCp2u(c6p#UFnRg+e$Br%g9HXh9m9=eX9src0+)YO9HZ?J&LE z*9F#gxb&jjuU;P8bs`Z}3C`M%d>a}$J0OgQLuY3iHntGHD~%Kpeb8%y zJgAq8@hHXG1v6PFapUC(e(0wVxe$AT9gi)C!AS&1 zW-)bHt9mU`sE`7y&!jtUM|b%hJ2nrkUN&8X{MMK7eA}wf$HrB6Uqjv_Vr@4}Nw6h4 zyYDM{CdRDOX;y-78pKn@%!^wjl8tyd!POx&AwKG=2$FgZu5Q|e%PL!Vw?~aDI$ydL zT~1y2;cv`2?Ne`Goqv0Wq=@+0*zdE)Hg2vi!Hs5ZPt}1adb*@>&G(|l4tsAln>SZ> zmP#tObg=w+kE$&fuAK4VNgo3O%>GVa-Q2#`K94)b^;~$5wV}Iyiy;@Q@yH2;8#1wN z5Gb`6zoqEFEvasv1!6+&?r0Sa)4A?7`2FJUkk!I6RVM#+y>GVIv-i zkWvqkWK3;<*Hs9O^G!M>@IU7OTVDVtNzN+nw%PegEQNj(w$Ni@L!7tqHaHua7R$>T zPvn$8NCc-8rFfoAw#*+;yX7a{i;+Uw0T ztuPJWuq$>>X1Yj4sP5<5_=yEs&l# zE)lNdzCfU!oLFnf=HjXDz1<)9f@zYec%R}1>*yf7c-{56{d2jpuloD} zq-*HkNNFFk6BqYDIW|bA1oGocHI-F<-jf^5=SkeySftZ?P90&R#wp6Kj38P@a%qli z!ZhmB-skEmk5Rv}rI+adVcW5u4PM)^!HqW;3TuvK6z8ta;{m)=&<%Mkd(iG4-L|7& z1iilv{s4eGkdeNzzP`S3CxeOSYoohwRvm1%3@m~D#qOc9{wLp&8hGgMZ#qW0hQAIx zcs&ci4I5St@IUSu0)RQ7PzAxJ0f09E?0@;1WY$CsMnus)TSL>T$%u@M4Ae}ej0_uG zePt8AfnqsXhUEPb2ss^R9qVtW+7&^@Huhjo1YfUJRbY zPQg57tl+{`;J1HM3Q8iSMvMnv%X)T^!V($pvQ#+bf~sf8x^z@E@<4sOKJy!9X0~{c z4`I~cAt&e?_LKi7f(+wQ>4?7aaz}+u+-mrErL+m%nXbj5n6V@4b!-*N!~Tlupl2Xg zoQm0f#2k{1`O3qjOIXHcT)FCKC@t%yBR+dk!lo9ZQ=^h^gk1r&i$vGyQ|=@AGx6HB z!Bf^W=4)dBR*{$Cu*L?mDaZLW+~3M4%j3^gGnaBb%4*^_4Ev}_*Ft;(R{FzCRwmbG zZTFV`aVG)~pUTOw%Ts3GiEr40s!W8H&*+~~u(<@e_bQt>w}ASdk!|pQ#pFrY`!9>B3|5Q^kwEoE>33tBe=fn(7Qq;b8);5K_z$&ZXtD5 zuVmFW-&@3KWV%ovMRI1Tdo&BedB*?t4$c4w>X85{puf*S$qu)OZ>!bjzjjmBWV6-E z3j%oeLz0mYG#!TvDPU0v-JHkJ5;i-B3o>Al3Eim2P#ZE`hx^*c$PTiyN5~!Eeh-Bt zA&3?+E<~M-b}Ygw=g*9lD~uEIHAHTR>*T0qtpXgUH^klfosH%>looh8ItJmJBx^{X+Ps^d6bUAu;uyaSqi>m8q-#>eR z_;3^QEU0A=dNQ$9mHV>=@}V@|uIy1G2qy6HSz-459i-k#bP z-?rmfPnuZjXI^&#Q|92N3&}d%b;r?-p+8*H9ns$E8Z3K<{@VNq{d#@({cQTW`WpL8 z`-=P20~HF`4fqkH(xBp?XlHS!cxN$&Ie}t@nSr}O@PR>xe}nTwrftaOP}(NyP12wY zQW3GFj!9^hlt0ebQK+SjORS^hBaKp$wWxztE2YR&{aaJ{s&rP>wK8-`3&)a|s##SE zx4e6mOn24sa`~y?6ZUUeAsTDc-YDu}J$ZW26yK@DWAWS2LJg=YprwD)&LsSle3e^!Q%DU%%_Y)!mN3n_^9;Q7+(M)b0-#u1)gi*~-ET3JLy9COKt(Eb5#`2{1 ziR~5dEBa*u%cz~!Fa>kU_!vGlL2D)M3hSBrcXp^lY)kkSIyXn`&F%~C_m_guUP#-Z z)n3D$))XbFkeCkfPWppH$&wf@-gJubBfL=}r<6_|p|Y)IT1y9}IbqZFCRbPH?Rnyp zk~r=FqbY{jR4|E+JHu)E>Xf`HTvR)zhHw@7s`X{3*1XEq%PW|7YuCijevvaCg`+7) z+t#)%wrkVpFy&dxeXARx_hjykA8aJ3b0B+P=bm92%@vwn{DX)By6|*iG}8if00e;g ze`?Zdv*o+Bx?%c%snUXmgNN_yDAIv+i{vDRgZVJJ&q@*M6FN7#J&HF*mkY0-Ak(~-Dgv^otl?KP7}%Sl^8!xv?#Y29HuV`O9JqA9NRrp><&zK*&jwx#Ta z)-^)6&c4CVS;-a3A;#^>oy+kvD_)yO*Jf35)yQ4vRnL8$d$oJ^@AP6n!fVuP*9%T} zvTNXLXl<(OL+-QbE9*nncfpTdff^CY8o?W86&gH{InXNzL0D5rR(MFbNl0A?f5>FW z)7|S`ve-u?0w>NpJT-c=P{djJS-IMrTU^1_J4y}WX2WoT={7#~TcoAwp zu6E3r33C(ccuq+}y^5O^_;(cMu*LzR_R#8nO9X9DtbEvjiG3sFIf;B6K}EEZIHlNB zvFyU|8POB9C(d^$*;tE-fH|pSQcXXs31tK1+T|5jJ>6>Rqn&Zv`xc!)dF`V~$ibkV zL28|d2i+=y&!N;^mx>ZDSxrK`*v-+UqbfUIeNz0mPYQ*!s9Hg{vSzuNOLeD0SNYeX zq<|0x7uvE#%;9PZ0T;jva|oEOFA)KuFh;&+hR8U zY`uDW_1#3Zb#2w%P&635!yArq52;fGFp|;sW;ym=v7MS(<^7 z^HJ=9+KIN2a^b4(8A-SoF)`yb#x+@(H-SeMy3WyQ=vR@l;w;uhuPJjO>cSC5(2tOP z!Tm&yi7gSg!bu$RXk_7uBp<;)!YYN~N>>#PE=m6;FnZAY)S_^>&}w9C9F++9ivN; zn#2oHt0&)CTD0_V>4d0?^A__hMOxXgNOskot!-Uexybh!9W#Ps#T#JuIt;kmo-$Nr zfy`{2{!wO?�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

  • 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 -sv@nqZiKZ8(g$#aNpSrqw2<~ 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 NXUR=xuCZSw=O7}^fYqo1Wz7U7j;L}gX%oK|% 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 Aq5uE@ literal 0 HcmV?d00001 diff --git a/imxweb/imx-modules/elemental-ui-core-18.0.14.tgz b/imxweb/imx-modules/elemental-ui-core-18.0.14.tgz new file mode 100644 index 0000000000000000000000000000000000000000..3b35826d90688ab51cb97a8f26dc1f5d0f99e7d5 GIT binary patch literal 1259482 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ʣ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%0A&=@Rka(YZtc1LfYp2s}UEj*EXcO zUifF&S;Wov#l=cNZK2+4+vAn^Ry9`YuTeTS)er4mYM|js)CnLka&ls6-fEogn{Wf(mebmqB{wfZju*Y>kRt zCTu$>=_R0s@cX@g>95DOzb*Y!&kp)d8F5q9vzD|uVMO|v>z!Y-xzd|p+i1y_OG%Y& z5v0wj1HM*su0=L8O4)R4TKanuLBrmw`n3<<4lI*iOm;vHSKk61Y57a3E%VtOps}8t zK5G2dn>zJa^PKv`{r>P%AoJHmwK)6G0-y}BodfHa7C&J5PE6Yg$jS=Sg6UfLIZTAj zP5a@%VSA90y*~BxIMr4~*y2@5;M<@n2GgWc%@p^wcAbvTcn0&!az^!d^9$vEw!h0vSQ_^sdYX(m$M8@hI8DM3r}`gE5C1| zIhB*3$(0V+a{sgL!*P-E&JpR%z{twS#A4BIwJoz1JMb zEAkd`Sg&U{i6pTnp=(geHD5T+N!h+xClS|p>!ZKtRo3m}@Y~#3;$zpv?B67C6q*nX z*desCps@OMSg(VHm&pnU3wgTerh0^KTh{GZu|$3eoo$p^YMDo~ZSP+{;pA=h<5>n5 zSeqJ-=H)+ksnd6mIG71?94lZV{&SeI!B`!W*)_ibJY?$mbLt^BOX%gOpH!vfCs)iE zceuXQv_G@i5S915(Lq3?z*lO;@v75E_=iA2I0rCPow~issk{5Du96PEQqjy@rI{!- z>f>0mjmL#)n;gK-Nl2%G@yIk46!_i~yq=&�h9*bW}^XvK?7A;QN`{!{*@SC=v9e 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%0DWIF)W2m;J zCwFyiL`0HbK7A>P~Dd(v=IxGya(C zDljJUDDUXYBiSt2M}Iyu-Z~dhiwOt*)%M-f*eh(%6@Km*vy0yES@_HzZ6UfWtHoyh zT|S!DTKs#jd$>wJiPSr1HQ^_1|HRM9q*zU|({d#dyDFwZ3<_hsRM_fAB zM$xNToViPrD||uC{uViR&gbb>DP8fkhSid7a&?#KY%JH&rGf8Pm@2z&;K<&F^d*v# ze@D4PwUM@h;U2C6g5){oe?b1hPo@yYyya>!DDxOsz`?i+srj?0{{qS-_cY_e-{tk% zR=K9^(3yJhU8b=0C4P87?#nZ1x>TTV zIo-lYi%=0P-Wtl$4?DoqEXRbw{4}(IXkVsg0AH}r$RTps2nR@oA&Vhwf!#T`?2&p* zr)g0@3+#a!RW;YbsD~7^$!kuRF4hz2$;qI>Hvn~|f^O@*!6lcTOq`A8=V+dNYgeJn zN_otojOsRFKw$0cimx~~VknREC~`7)1HIz?3;#k9yP>-byKvPUS{KpG->g^Q1_b;= zfdqhqrv`k14m;p%BMy-+)* z*IM!XaCkQ}k3`?uq+o5Zv$MT!lQ=&t@0_#donSjj;+K7ai#VlK-Q-cp)x6HPGv{Gw zM6--Rq(f!L@_qhJF%f1Gd-5-$YtE)Q+5auZ+k!zu1#Xoy$6S-Dsa5ZqX;J7}7fR6i z#9_q>wr0m&5BER^<@ z`Wu?uvV^3nIXH1XDCMSd8_KpoXxB;GvrTXmeebS@jSx)0-$LfA0RB1l9=wYGxXk2* z3`kceyAAHUy^5b*R;}v=#%rF^@<-ugkC50eI51^7R-qEYi${3+6Vj|QshS~C8`vE@w#g9FvCj(euPWx zE;sG@Qm0)!hH%O6P8@Xk^I$1>CRJc66QwF_kz_z`N`7p=PUKdZUKT~iUS=iO``UuT zYsYndEtuPO3*t4K=!_i4_K+D~m|0X`u&a)6?pq+wP2!OY|K4Sg>)zKD)LPN~<{=ob znvmuLv-K0GZIsUD(AYG=-Kuti`|U_64J^c}dxQ7UD%dbOVB5K7cycSQn(S=bE#i(Z(7xfN~@SBvn&3yqerp)gsmrsVAC2K46o=gnOkOir6B zGq&@dsxYh2gryjs`n@@9MoKvD=W=wTU2l~XzLhnJ$=!C^l99<5aX#8%0 zwOuW&^|3W(ukc+jUE(j>lk(a9w$v|^&BXwU?=vUOLPn z^>h*lW8+ZaH|$!}cdO!Twks|5<>u~XLReKRct-H?yTSy8VBF;fb*nzQ%kx+`oxv55 z9(a^61N*$@{Mpw-=7~Z^CzK8hGd-`x&d-!!5;$80y2>Jok4*bZy^{qaj zFl-Zq`*?rkK9(j2y(P9gU3dsMiSvFuU)88_f5vnk&xOg4?|LDUesOzCyaNpU{d}>q zd_Hn(?an`dP$S-bCw<;OUOq?T(P>gF2XhRq$hmd6#H`EECO9QPZzV1Bv(&D0if=S; zhjpx$8Tn1W!fx4JBD=Sp)n1J2n^&w2N?EH;%iHeJGwH_)#Ac)?F{W5AYPwW$2M}(Z z1^_uNE9C<@S_G@9VH|ZlRY80BhKNjpTWW-c1&*2~@yf((QG^inaA&^ztR17j3esS$ zVCq!|JqWjpQG+<(+E%r!)wr9bSUco3#9vW{sbh6W?#0lP*!Uk=oc;dYk$C++Ejuh- zR@^7IA$PVVaX0S?UU5O+YZK4Y{I9l|!8fAKPWA*<5$)^xB)`QJe-d9`rA%0EXZ2@G z`RSH}J`D;zJm9=2uC>n