From 4d3098860da0817989113e11cbcf8ae6c1bb5df7 Mon Sep 17 00:00:00 2001 From: Diamantis Tziotzios Date: Fri, 20 Oct 2023 18:01:09 +0300 Subject: [PATCH] description template type and dmp blueprint frontend changes --- .../java/eu/eudat/audit/AuditableAction.java | 5 + .../eu/eudat/authorization/Permission.java | 6 + .../eudat/commons/enums/UserSettingsType.java | 28 + .../eu/eudat/data/UserSettingsEntity.java | 112 +++ .../enums/UserSettingsTypeConverter.java | 11 + .../java/eu/eudat/model/UserSettings.java | 97 +++ .../model/builder/UserSettingsBuilder.java | 65 ++ .../model/censorship/UserSettingsCensor.java | 41 + .../model/persist/UserSettingsPersist.java | 80 ++ .../eu/eudat/query/UserSettingsQuery.java | 234 ++++++ .../query/lookup/UserSettingsLookup.java | 52 ++ .../DescriptionTemplateTypeServiceImpl.java | 1 - .../user/settings/UserSettingsService.java | 15 + .../settings/UserSettingsServiceImpl.java | 103 +++ .../v2/UserSettingsController.java | 120 +++ ...ame_DatasetProfile_and_add_Type_column.sql | 2 +- ...01.001_Align_Description_Template_Type.sql | 13 +- .../00.01.002_Align_Entity_Doi_table.sql | 13 +- .../00.01.003_Add_UserSettings_table.sql | 23 + dmp-frontend/src/app/app-routing.module.ts | 21 +- dmp-frontend/src/app/app.component.ts | 9 +- dmp-frontend/src/app/app.module.ts | 4 +- .../enum/description-template-type-status.ts | 5 +- ...ld-type.ts => dmp-blueprint-field-type.ts} | 2 +- .../core/common/enum/dmp-blueprint-status.ts | 4 + .../core/common/enum/dmp-blueprint-type.ts | 3 + .../core/common/enum/dmp-profile-status.ts | 5 - .../app/core/common/enum/dmp-profile-type.ts | 3 - .../app/core/common/enum/is-active.enum.ts | 4 + .../src/app/core/core-service.module.ts | 33 +- .../src/app/core/formatting.module.ts | 4 +- .../description-template-type.ts | 13 +- .../dmp-associated-profile.ts | 0 .../dmp-blueprint-external-autocomplete.ts} | 2 +- .../dmp-blueprint/dmp-blueprint-field.ts | 13 + .../dmp-blueprint/dmp-blueprint-listing.ts | 10 + .../core/model/dmp-blueprint/dmp-blueprint.ts | 19 + .../model/dmp-profile/dmp-profile-field.ts | 13 - .../model/dmp-profile/dmp-profile-listing.ts | 10 - .../app/core/model/dmp-profile/dmp-profile.ts | 16 - .../model/dmp/dmp-blueprint/dmp-blueprint.ts | 82 +- .../src/app/core/model/dmp/dmp-listing.ts | 2 +- .../src/app/core/model/dmp/dmp-overview.ts | 2 +- dmp-frontend/src/app/core/model/dmp/dmp.ts | 21 +- .../recent-dmp-activity.model.ts | 2 +- .../user-settings/user-settings.model.ts | 47 ++ .../query/description-template-type.lookup.ts | 21 + .../description-template-type.lookup.ts | 14 - .../app/core/query/dmp-blueprint.lookup.ts | 23 + .../core/query/dmp/dmp-blueprint-criteria.ts | 3 +- .../core/query/dmp/dmp-profile-criteria.ts | 2 +- ...-profile-external-autocomplete-criteria.ts | 2 +- .../app/core/services/auth/auth.service.ts | 1 + .../configuration/configuration.service.ts | 12 + .../description-template-type.service.ts | 65 +- .../services/dmp/dmp-blueprint.service.ts | 107 +++ .../core/services/dmp/dmp-profile.service.ts | 81 -- .../src/app/core/services/dmp/dmp.service.ts | 8 +- .../external-sources.service.ts | 2 +- .../services/timezone/timezone-service.ts | 57 ++ .../user-settings-http.service.ts | 45 ++ .../user-settings/user-settings.service.ts | 332 ++++++++ .../services/utilities/enum-utils.service.ts | 26 +- .../utilities/query-params.service.ts | 59 ++ .../dataset-profile-editor.component.ts | 16 +- .../dataset-profile-listing.component.html | 2 +- .../dataset-profile-listing.component.ts | 14 +- .../description-template-type.module.ts | 32 + .../description-template-type.routing.ts | 57 ++ .../description-types.module.ts | 21 - .../description-types.routing.ts | 45 -- ...iption-template-type-editor.component.html | 99 +++ ...ption-template-type-editor.component.scss} | 10 +- ...cription-template-type-editor.component.ts | 173 ++++ .../description-template-type-editor.model.ts | 54 ++ ...scription-template-type-editor.resolver.ts | 38 + ...escription-template-type-editor.service.ts | 15 + .../description-type-editor.component.html | 38 - .../description-type-editor.component.ts | 161 ---- ...ption-template-type-listing.component.html | 108 +++ ...tion-template-type-listing.component.scss} | 15 +- ...ription-template-type-listing.component.ts | 177 +++++ .../listing/description-types.component.html | 54 -- .../listing/description-types.component.ts | 173 ---- ...mplate-type-listing-filters.component.html | 36 + ...mplate-type-listing-filters.component.scss | 25 + ...template-type-listing-filters.component.ts | 94 +++ .../dmp-blueprint/dmp-blueprint.module.ts | 43 + .../dmp-blueprint/dmp-blueprint.routing.ts | 18 + .../dmp-blueprint-editor.component.html} | 120 +-- .../dmp-blueprint-editor.component.scss} | 2 +- .../editor/dmp-blueprint-editor.component.ts} | 347 ++++---- .../editor/dmp-blueprint-editor.model.ts | 3 +- .../editor/dmp-profile-editor.model.ts | 49 +- ...l-autocomplete-field-editor.component.html | 22 + ...-autocomplete-field-editor.component.scss} | 0 ...nal-autocomplete-field-editor.component.ts | 17 + ...ternal-autocomplete-field-editor.model.ts} | 16 +- ...irmation-upload-blueprints.component.html} | 10 +- ...irmation-upload-blueprints.component.scss} | 0 ...nfirmation-upload-blueprints.component.ts} | 10 +- .../dmp-blueprint-criteria.component.html} | 0 .../dmp-blueprint-criteria.component.scss} | 0 .../dmp-blueprint-criteria.component.ts} | 22 +- .../dmp-blueprint-listing.component.html | 223 ++++++ .../dmp-blueprint-listing.component.scss} | 2 +- .../dmp-blueprint-listing.component.ts | 388 +++++++++ ...p-blueprint-listing-filters.component.html | 36 + ...p-blueprint-listing-filters.component.scss | 25 + ...dmp-blueprint-listing-filters.component.ts | 99 +++ .../admin/dmp-profile/dmp-profile.module.ts | 35 - .../admin/dmp-profile/dmp-profile.routing.ts | 19 - ...l-autocomplete-field-editor.component.html | 22 - ...nal-autocomplete-field-editor.component.ts | 17 - .../dmp-profile-listing.component.html | 89 --- .../listing/dmp-profile-listing.component.ts | 272 ------- .../user/listing/user-listing.component.ts | 14 +- .../app/ui/dashboard/dashboard.component.ts | 9 +- .../dmp-info-counter.component.html | 2 +- .../ui/dashboard/drafts/drafts.component.ts | 8 +- .../recent-edited-activity.component.ts | 8 +- ...ecent-edited-dataset-activity.component.ts | 3 +- .../recent-edited-dmp-activity.component.ts | 8 +- .../dataset-create-wizard.component.ts | 21 +- .../dataset-dmp-selector.component.ts | 5 +- .../dataset-copy-dialogue.component.ts | 2 +- .../dataset-editor.component.ts | 6 +- .../dataset-wizard.component.ts | 154 ++-- .../prefill-dataset.component.ts | 8 +- .../listing/dataset-listing.component.ts | 28 +- .../overview/dataset-overview.component.ts | 20 +- .../clone-dialog/clone-dialog.component.ts | 2 +- .../app/ui/dmp/clone/dmp-clone.component.ts | 18 +- .../dmp-editor-blueprint.component.ts | 20 +- .../dataset-editor-details.component.ts | 2 +- .../dataset-info/dataset-info.component.ts | 26 +- .../app/ui/dmp/editor/dmp-editor.component.ts | 240 +++--- .../src/app/ui/dmp/editor/dmp-editor.model.ts | 20 +- .../dynamic-dmp-field-resolver.component.html | 12 +- .../dynamic-dmp-field-resolver.component.ts | 51 +- .../general-tab/general-tab.component.html | 6 +- .../general-tab/general-tab.component.ts | 42 +- .../dmp-invitation-dialog.component.ts | 3 +- .../ui/dmp/listing/dmp-listing.component.ts | 38 +- .../dmp-listing-item.component.html | 4 +- .../dmp-listing-item.component.ts | 6 +- .../dmp-upload-dialogue.component.html | 4 +- .../dmp-upload-dialogue.component.ts | 12 +- .../ui/dmp/overview/dmp-overview.component.ts | 28 +- .../start-new-dmp-dialog.component.ts | 2 +- .../app/ui/dmp/wizard/dmp-wizard.component.ts | 22 +- .../editor/dmp-wizard-editor.component.ts | 2 +- .../explore-dataset-listing.component.ts | 22 +- .../explore-dmp-listing.component.ts | 22 +- .../explore-dmp-listing-item.component.html | 2 +- .../ui/grant/editor/grant-editor.component.ts | 34 +- .../grant/listing/grant-listing.component.ts | 18 +- .../misc/breadcrumb/breadcrumb.component.html | 15 - .../misc/breadcrumb/breadcrumb.component.scss | 159 ---- .../misc/breadcrumb/breadcrumb.component.ts | 50 -- .../ui/misc/breadcrumb/breadcrumb.module.ts | 20 - .../ui/misc/breadcrumb/breadcrumb.service.ts | 91 +++ .../definition/IBreadCrumbComponent.ts | 6 - .../breadcrumb/definition/breadcrumb-item.ts | 9 - .../navigation-breadcrumb.component.html | 26 + .../navigation-breadcrumb.component.scss | 13 + .../navigation-breadcrumb.component.ts | 181 +++++ .../breadcrumb/service/breadcrumb.service.ts | 86 -- .../misc/navigation/navigation.component.html | 2 +- .../src/app/ui/navbar/navbar.component.html | 2 +- .../src/app/ui/navbar/navbar.module.ts | 2 - .../dataset-editor-wizard.component.ts | 7 +- .../dmp-editor/dmp-editor-wizard-model.ts | 9 +- .../dmp-editor-wizard.component.html | 2 +- .../dmp-editor/dmp-editor-wizard.component.ts | 20 +- .../grant-editor-wizard.component.ts | 18 +- .../quick-wizard-editor.component.ts | 20 +- .../src/app/ui/sidebar/sidebar.component.ts | 4 +- dmp-frontend/src/assets/i18n/de.json | 4 +- dmp-frontend/src/assets/i18n/en.json | 90 ++- dmp-frontend/src/assets/i18n/es.json | 4 +- dmp-frontend/src/assets/i18n/gr.json | 4 +- dmp-frontend/src/assets/i18n/hr.json | 4 +- dmp-frontend/src/assets/i18n/pl.json | 4 +- dmp-frontend/src/assets/i18n/pt.json | 4 +- dmp-frontend/src/assets/i18n/sk.json | 4 +- dmp-frontend/src/assets/i18n/sr.json | 4 +- dmp-frontend/src/assets/i18n/tr.json | 4 +- .../src/common/base/base-editor.resolver.ts | 19 + dmp-frontend/src/common/base/base-editor.ts | 154 ++++ .../src/common/base/base-entity.model.ts | 15 + .../src/common/base/base-form-editor-model.ts | 30 +- .../src/common/base/base-form-editor.ts | 6 +- .../src/common/base/base-listing-component.ts | 228 ++++++ .../base/base-pending-changes.component.ts | 10 +- .../formatting/common-formatting.module.ts | 47 ++ .../src/common/formatting/pipe.service.ts | 10 + .../formatting/pipes/array-to-string.pipe.ts | 21 + .../formatting/pipes/date-format.pipe.ts | 49 ++ .../formatting/pipes/date-only-format.pipe.ts | 46 ++ .../formatting/pipes/date-time-format.pipe.ts | 47 ++ .../pipes/lowercase-first-letter.pipe.ts | 19 + dmp-frontend/src/common/forms/form-service.ts | 3 +- .../src/common/material/material.module.ts | 19 +- .../directives/batch-actions.directive.ts | 20 + .../download-listing-report.directive.ts | 7 + .../hybrid-listing-filters.directive.ts | 7 + .../user-filter-settings.directive.ts | 7 + .../hybrid-listing.component.html | 207 +++++ .../hybrid-listing.component.scss | 66 ++ .../hybrid-listing.component.ts | 744 ++++++++++++++++++ .../hybrid-listing/hybrid-listing.module.ts | 43 + .../pipes/nullify-value.pipe.ts | 19 + .../pipes/visible-fields.pipe.ts | 58 ++ .../notification/ui-notification-service.ts | 60 -- .../expandable-search-field.component.html | 6 + .../expandable-search-field.component.scss | 23 + .../expandable-search-field.component.ts | 83 ++ .../modules/text-filter/filter-service.ts | 40 + .../text-filter/text-filter.component.html | 4 + .../text-filter/text-filter.component.scss | 3 + .../text-filter/text-filter.component.ts | 60 ++ .../modules/text-filter/text-filter.module.ts | 23 + .../user-settings-picker.component.html | 43 + .../user-settings-picker.component.scss | 0 .../user-settings-picker.component.ts | 193 +++++ .../user-settings-selector.component.html | 23 + .../user-settings-selector.component.scss | 24 + .../user-settings-selector.component.ts | 157 ++++ .../user-settings/user-settings.module.ts | 29 + .../src/common/ui/common-ui.module.ts | 7 +- dmp-frontend/src/styles.scss | 29 + 232 files changed, 7547 insertions(+), 2576 deletions(-) create mode 100644 dmp-backend/core/src/main/java/eu/eudat/commons/enums/UserSettingsType.java create mode 100644 dmp-backend/core/src/main/java/eu/eudat/data/UserSettingsEntity.java create mode 100644 dmp-backend/core/src/main/java/eu/eudat/data/converters/enums/UserSettingsTypeConverter.java create mode 100644 dmp-backend/core/src/main/java/eu/eudat/model/UserSettings.java create mode 100644 dmp-backend/core/src/main/java/eu/eudat/model/builder/UserSettingsBuilder.java create mode 100644 dmp-backend/core/src/main/java/eu/eudat/model/censorship/UserSettingsCensor.java create mode 100644 dmp-backend/core/src/main/java/eu/eudat/model/persist/UserSettingsPersist.java create mode 100644 dmp-backend/core/src/main/java/eu/eudat/query/UserSettingsQuery.java create mode 100644 dmp-backend/core/src/main/java/eu/eudat/query/lookup/UserSettingsLookup.java create mode 100644 dmp-backend/core/src/main/java/eu/eudat/service/user/settings/UserSettingsService.java create mode 100644 dmp-backend/core/src/main/java/eu/eudat/service/user/settings/UserSettingsServiceImpl.java create mode 100644 dmp-backend/web/src/main/java/eu/eudat/controllers/v2/UserSettingsController.java create mode 100644 dmp-db-scema/updates/00.01.003_Add_UserSettings_table.sql rename dmp-frontend/src/app/core/common/enum/{dmp-profile-field-type.ts => dmp-blueprint-field-type.ts} (61%) create mode 100644 dmp-frontend/src/app/core/common/enum/dmp-blueprint-status.ts create mode 100644 dmp-frontend/src/app/core/common/enum/dmp-blueprint-type.ts delete mode 100644 dmp-frontend/src/app/core/common/enum/dmp-profile-status.ts delete mode 100644 dmp-frontend/src/app/core/common/enum/dmp-profile-type.ts create mode 100644 dmp-frontend/src/app/core/common/enum/is-active.enum.ts rename dmp-frontend/src/app/core/model/{dmp-profile => dmp-blueprint}/dmp-associated-profile.ts (100%) rename dmp-frontend/src/app/core/model/{dmp-profile/dmp-profile-external-autocomplete.ts => dmp-blueprint/dmp-blueprint-external-autocomplete.ts} (63%) create mode 100644 dmp-frontend/src/app/core/model/dmp-blueprint/dmp-blueprint-field.ts create mode 100644 dmp-frontend/src/app/core/model/dmp-blueprint/dmp-blueprint-listing.ts create mode 100644 dmp-frontend/src/app/core/model/dmp-blueprint/dmp-blueprint.ts delete mode 100644 dmp-frontend/src/app/core/model/dmp-profile/dmp-profile-field.ts delete mode 100644 dmp-frontend/src/app/core/model/dmp-profile/dmp-profile-listing.ts delete mode 100644 dmp-frontend/src/app/core/model/dmp-profile/dmp-profile.ts create mode 100644 dmp-frontend/src/app/core/model/user-settings/user-settings.model.ts create mode 100644 dmp-frontend/src/app/core/query/description-template-type.lookup.ts delete mode 100644 dmp-frontend/src/app/core/query/description-template/description-template-type.lookup.ts create mode 100644 dmp-frontend/src/app/core/query/dmp-blueprint.lookup.ts create mode 100644 dmp-frontend/src/app/core/services/dmp/dmp-blueprint.service.ts delete mode 100644 dmp-frontend/src/app/core/services/dmp/dmp-profile.service.ts create mode 100644 dmp-frontend/src/app/core/services/user-settings/user-settings-http.service.ts create mode 100644 dmp-frontend/src/app/core/services/user-settings/user-settings.service.ts create mode 100644 dmp-frontend/src/app/core/services/utilities/query-params.service.ts create mode 100644 dmp-frontend/src/app/ui/admin/description-types/description-template-type.module.ts create mode 100644 dmp-frontend/src/app/ui/admin/description-types/description-template-type.routing.ts delete mode 100644 dmp-frontend/src/app/ui/admin/description-types/description-types.module.ts delete mode 100644 dmp-frontend/src/app/ui/admin/description-types/description-types.routing.ts create mode 100644 dmp-frontend/src/app/ui/admin/description-types/editor/description-template-type-editor.component.html rename dmp-frontend/src/app/ui/admin/description-types/editor/{description-type-editor.component.scss => description-template-type-editor.component.scss} (82%) create mode 100644 dmp-frontend/src/app/ui/admin/description-types/editor/description-template-type-editor.component.ts create mode 100644 dmp-frontend/src/app/ui/admin/description-types/editor/description-template-type-editor.model.ts create mode 100644 dmp-frontend/src/app/ui/admin/description-types/editor/description-template-type-editor.resolver.ts create mode 100644 dmp-frontend/src/app/ui/admin/description-types/editor/description-template-type-editor.service.ts delete mode 100644 dmp-frontend/src/app/ui/admin/description-types/editor/description-type-editor.component.html delete mode 100644 dmp-frontend/src/app/ui/admin/description-types/editor/description-type-editor.component.ts create mode 100644 dmp-frontend/src/app/ui/admin/description-types/listing/description-template-type-listing.component.html rename dmp-frontend/src/app/ui/admin/description-types/listing/{description-types.component.scss => description-template-type-listing.component.scss} (76%) create mode 100644 dmp-frontend/src/app/ui/admin/description-types/listing/description-template-type-listing.component.ts delete mode 100644 dmp-frontend/src/app/ui/admin/description-types/listing/description-types.component.html delete mode 100644 dmp-frontend/src/app/ui/admin/description-types/listing/description-types.component.ts create mode 100644 dmp-frontend/src/app/ui/admin/description-types/listing/filters/description-template-type-listing-filters.component.html create mode 100644 dmp-frontend/src/app/ui/admin/description-types/listing/filters/description-template-type-listing-filters.component.scss create mode 100644 dmp-frontend/src/app/ui/admin/description-types/listing/filters/description-template-type-listing-filters.component.ts create mode 100644 dmp-frontend/src/app/ui/admin/dmp-blueprint/dmp-blueprint.module.ts create mode 100644 dmp-frontend/src/app/ui/admin/dmp-blueprint/dmp-blueprint.routing.ts rename dmp-frontend/src/app/ui/admin/{dmp-profile/editor/dmp-profile-editor.component.html => dmp-blueprint/editor/dmp-blueprint-editor.component.html} (68%) rename dmp-frontend/src/app/ui/admin/{dmp-profile/editor/dmp-profile-editor.component.scss => dmp-blueprint/editor/dmp-blueprint-editor.component.scss} (98%) rename dmp-frontend/src/app/ui/admin/{dmp-profile/editor/dmp-profile-editor.component.ts => dmp-blueprint/editor/dmp-blueprint-editor.component.ts} (64%) rename dmp-frontend/src/app/ui/admin/{dmp-profile => dmp-blueprint}/editor/dmp-blueprint-editor.model.ts (99%) rename dmp-frontend/src/app/ui/admin/{dmp-profile => dmp-blueprint}/editor/dmp-profile-editor.model.ts (51%) create mode 100644 dmp-frontend/src/app/ui/admin/dmp-blueprint/editor/external-autocomplete/dmp-blueprint-external-autocomplete-field-editor.component.html rename dmp-frontend/src/app/ui/admin/{dmp-profile/editor/external-autocomplete/dmp-profile-external-autocomplete-field-editor.component.scss => dmp-blueprint/editor/external-autocomplete/dmp-blueprint-external-autocomplete-field-editor.component.scss} (100%) create mode 100644 dmp-frontend/src/app/ui/admin/dmp-blueprint/editor/external-autocomplete/dmp-blueprint-external-autocomplete-field-editor.component.ts rename dmp-frontend/src/app/ui/admin/{dmp-profile/editor/external-autocomplete/dmp-profile-external-autocomplete-field-editor.model.ts => dmp-blueprint/editor/external-autocomplete/dmp-blueprint-external-autocomplete-field-editor.model.ts} (54%) rename dmp-frontend/src/app/ui/admin/{dmp-profile/listing/criteria/dialog-confirmation-upload-profile/dialog-confirmation-upload-profiles.component.html => dmp-blueprint/listing/criteria/dialog-confirmation-upload-blueprint/dialog-confirmation-upload-blueprints.component.html} (73%) rename dmp-frontend/src/app/ui/admin/{dmp-profile/listing/criteria/dialog-confirmation-upload-profile/dialog-confirmation-upload-profiles.component.scss => dmp-blueprint/listing/criteria/dialog-confirmation-upload-blueprint/dialog-confirmation-upload-blueprints.component.scss} (100%) rename dmp-frontend/src/app/ui/admin/{dmp-profile/listing/criteria/dialog-confirmation-upload-profile/dialog-confirmation-upload-profiles.component.ts => dmp-blueprint/listing/criteria/dialog-confirmation-upload-blueprint/dialog-confirmation-upload-blueprints.component.ts} (81%) rename dmp-frontend/src/app/ui/admin/{dmp-profile/listing/criteria/dmp-profile-criteria.component.html => dmp-blueprint/listing/criteria/dmp-blueprint-criteria.component.html} (100%) rename dmp-frontend/src/app/ui/admin/{dmp-profile/listing/criteria/dmp-profile-criteria.component.scss => dmp-blueprint/listing/criteria/dmp-blueprint-criteria.component.scss} (100%) rename dmp-frontend/src/app/ui/admin/{dmp-profile/listing/criteria/dmp-profile-criteria.component.ts => dmp-blueprint/listing/criteria/dmp-blueprint-criteria.component.ts} (68%) create mode 100644 dmp-frontend/src/app/ui/admin/dmp-blueprint/listing/dmp-blueprint-listing.component.html rename dmp-frontend/src/app/ui/admin/{dmp-profile/listing/dmp-profile-listing.component.scss => dmp-blueprint/listing/dmp-blueprint-listing.component.scss} (98%) create mode 100644 dmp-frontend/src/app/ui/admin/dmp-blueprint/listing/dmp-blueprint-listing.component.ts create mode 100644 dmp-frontend/src/app/ui/admin/dmp-blueprint/listing/filters/dmp-blueprint-listing-filters.component.html create mode 100644 dmp-frontend/src/app/ui/admin/dmp-blueprint/listing/filters/dmp-blueprint-listing-filters.component.scss create mode 100644 dmp-frontend/src/app/ui/admin/dmp-blueprint/listing/filters/dmp-blueprint-listing-filters.component.ts delete mode 100644 dmp-frontend/src/app/ui/admin/dmp-profile/dmp-profile.module.ts delete mode 100644 dmp-frontend/src/app/ui/admin/dmp-profile/dmp-profile.routing.ts delete mode 100644 dmp-frontend/src/app/ui/admin/dmp-profile/editor/external-autocomplete/dmp-profile-external-autocomplete-field-editor.component.html delete mode 100644 dmp-frontend/src/app/ui/admin/dmp-profile/editor/external-autocomplete/dmp-profile-external-autocomplete-field-editor.component.ts delete mode 100644 dmp-frontend/src/app/ui/admin/dmp-profile/listing/dmp-profile-listing.component.html delete mode 100644 dmp-frontend/src/app/ui/admin/dmp-profile/listing/dmp-profile-listing.component.ts delete mode 100644 dmp-frontend/src/app/ui/misc/breadcrumb/breadcrumb.component.html delete mode 100644 dmp-frontend/src/app/ui/misc/breadcrumb/breadcrumb.component.scss delete mode 100644 dmp-frontend/src/app/ui/misc/breadcrumb/breadcrumb.component.ts delete mode 100644 dmp-frontend/src/app/ui/misc/breadcrumb/breadcrumb.module.ts create mode 100644 dmp-frontend/src/app/ui/misc/breadcrumb/breadcrumb.service.ts delete mode 100644 dmp-frontend/src/app/ui/misc/breadcrumb/definition/IBreadCrumbComponent.ts delete mode 100644 dmp-frontend/src/app/ui/misc/breadcrumb/definition/breadcrumb-item.ts create mode 100644 dmp-frontend/src/app/ui/misc/breadcrumb/navigation-breadcrumb.component.html create mode 100644 dmp-frontend/src/app/ui/misc/breadcrumb/navigation-breadcrumb.component.scss create mode 100644 dmp-frontend/src/app/ui/misc/breadcrumb/navigation-breadcrumb.component.ts delete mode 100644 dmp-frontend/src/app/ui/misc/breadcrumb/service/breadcrumb.service.ts create mode 100644 dmp-frontend/src/common/base/base-editor.resolver.ts create mode 100644 dmp-frontend/src/common/base/base-editor.ts create mode 100644 dmp-frontend/src/common/base/base-entity.model.ts create mode 100644 dmp-frontend/src/common/base/base-listing-component.ts create mode 100644 dmp-frontend/src/common/formatting/common-formatting.module.ts create mode 100644 dmp-frontend/src/common/formatting/pipe.service.ts create mode 100644 dmp-frontend/src/common/formatting/pipes/array-to-string.pipe.ts create mode 100644 dmp-frontend/src/common/formatting/pipes/date-format.pipe.ts create mode 100644 dmp-frontend/src/common/formatting/pipes/date-only-format.pipe.ts create mode 100644 dmp-frontend/src/common/formatting/pipes/date-time-format.pipe.ts create mode 100644 dmp-frontend/src/common/formatting/pipes/lowercase-first-letter.pipe.ts create mode 100644 dmp-frontend/src/common/modules/hybrid-listing/directives/batch-actions.directive.ts create mode 100644 dmp-frontend/src/common/modules/hybrid-listing/directives/download-listing-report.directive.ts create mode 100644 dmp-frontend/src/common/modules/hybrid-listing/directives/hybrid-listing-filters.directive.ts create mode 100644 dmp-frontend/src/common/modules/hybrid-listing/directives/user-filter-settings.directive.ts create mode 100644 dmp-frontend/src/common/modules/hybrid-listing/hybrid-listing.component.html create mode 100644 dmp-frontend/src/common/modules/hybrid-listing/hybrid-listing.component.scss create mode 100644 dmp-frontend/src/common/modules/hybrid-listing/hybrid-listing.component.ts create mode 100644 dmp-frontend/src/common/modules/hybrid-listing/hybrid-listing.module.ts create mode 100644 dmp-frontend/src/common/modules/hybrid-listing/pipes/nullify-value.pipe.ts create mode 100644 dmp-frontend/src/common/modules/hybrid-listing/pipes/visible-fields.pipe.ts delete mode 100644 dmp-frontend/src/common/modules/notification/ui-notification-service.ts create mode 100644 dmp-frontend/src/common/modules/text-filter/expandable-search-field/expandable-search-field.component.html create mode 100644 dmp-frontend/src/common/modules/text-filter/expandable-search-field/expandable-search-field.component.scss create mode 100644 dmp-frontend/src/common/modules/text-filter/expandable-search-field/expandable-search-field.component.ts create mode 100644 dmp-frontend/src/common/modules/text-filter/filter-service.ts create mode 100644 dmp-frontend/src/common/modules/text-filter/text-filter.component.html create mode 100644 dmp-frontend/src/common/modules/text-filter/text-filter.component.scss create mode 100644 dmp-frontend/src/common/modules/text-filter/text-filter.component.ts create mode 100644 dmp-frontend/src/common/modules/text-filter/text-filter.module.ts create mode 100644 dmp-frontend/src/common/modules/user-settings/user-settings-picker/user-settings-picker.component.html create mode 100644 dmp-frontend/src/common/modules/user-settings/user-settings-picker/user-settings-picker.component.scss create mode 100644 dmp-frontend/src/common/modules/user-settings/user-settings-picker/user-settings-picker.component.ts create mode 100644 dmp-frontend/src/common/modules/user-settings/user-settings-selector/user-settings-selector.component.html create mode 100644 dmp-frontend/src/common/modules/user-settings/user-settings-selector/user-settings-selector.component.scss create mode 100644 dmp-frontend/src/common/modules/user-settings/user-settings-selector/user-settings-selector.component.ts create mode 100644 dmp-frontend/src/common/modules/user-settings/user-settings.module.ts diff --git a/dmp-backend/core/src/main/java/eu/eudat/audit/AuditableAction.java b/dmp-backend/core/src/main/java/eu/eudat/audit/AuditableAction.java index 2c7da92db..d18029d9e 100644 --- a/dmp-backend/core/src/main/java/eu/eudat/audit/AuditableAction.java +++ b/dmp-backend/core/src/main/java/eu/eudat/audit/AuditableAction.java @@ -20,4 +20,9 @@ public class AuditableAction { public static final EventId EntityDoi_Delete = new EventId(2003, "EntityDoi_Delete"); + public static final EventId User_Settings_Query = new EventId(3000, "User_Settings_Query"); + public static final EventId User_Settings_Lookup = new EventId(3001, "User_Settings_Lookup"); + public static final EventId User_Settings_Persist = new EventId(3002, "User_Settings_Persist"); + public static final EventId User_Settings_Delete = new EventId(3003, "User_Settings_Delete"); + } diff --git a/dmp-backend/core/src/main/java/eu/eudat/authorization/Permission.java b/dmp-backend/core/src/main/java/eu/eudat/authorization/Permission.java index 49607f58f..e4a33b910 100644 --- a/dmp-backend/core/src/main/java/eu/eudat/authorization/Permission.java +++ b/dmp-backend/core/src/main/java/eu/eudat/authorization/Permission.java @@ -33,6 +33,12 @@ public final class Permission { public static String EditEntityDoi = "EditEntityDoi"; public static String DeleteEntityDoi = "DeleteEntityDoi"; + //UserSettings + public static String BrowseUserSettings = "BrowseUserSettings"; + public static String EditUserSettings = "EditUserSettings"; + public static String DeleteUserSettings = "DeleteUserSettings"; + + // UI Pages public static String ViewDescriptionTemplateTypePage = "ViewDescriptionTemplateTypePage"; diff --git a/dmp-backend/core/src/main/java/eu/eudat/commons/enums/UserSettingsType.java b/dmp-backend/core/src/main/java/eu/eudat/commons/enums/UserSettingsType.java new file mode 100644 index 000000000..4e0edbd26 --- /dev/null +++ b/dmp-backend/core/src/main/java/eu/eudat/commons/enums/UserSettingsType.java @@ -0,0 +1,28 @@ +package eu.eudat.commons.enums; + +import eu.eudat.data.converters.enums.DatabaseEnum; + +import java.util.Map; + +public enum UserSettingsType implements DatabaseEnum { + + Settings((short) 0), + Config((short) 1); + + private final Short value; + + UserSettingsType(Short value) { + this.value = value; + } + + public Short getValue() { + return value; + } + + private static final Map map = EnumUtils.getEnumValueMap(UserSettingsType.class); + + public static UserSettingsType of(Short i) { + return map.get(i); + } +} + diff --git a/dmp-backend/core/src/main/java/eu/eudat/data/UserSettingsEntity.java b/dmp-backend/core/src/main/java/eu/eudat/data/UserSettingsEntity.java new file mode 100644 index 000000000..dda975019 --- /dev/null +++ b/dmp-backend/core/src/main/java/eu/eudat/data/UserSettingsEntity.java @@ -0,0 +1,112 @@ +package eu.eudat.data; + + +import eu.eudat.commons.enums.UserSettingsType; +import eu.eudat.data.converters.enums.UserSettingsTypeConverter; +import jakarta.persistence.*; + +import java.time.Instant; +import java.util.UUID; + +@Entity +@Table(name = "UserSettings") +public class UserSettingsEntity { + + @Id + @Column(name = "id", columnDefinition = "uuid", updatable = false, nullable = false) + private UUID id; + public static final String _id = "id"; + + @Column(name = "key", length = 500, nullable = false) + private String key; + public static final String _key = "key"; + + @Column(name = "value", nullable = false) + private String value; + public static final String _value = "value"; + + @Column(name = "name", nullable = false) + private String name; + public static final String _name = "name"; + + @Column(name = "entity_id", columnDefinition = "uuid", nullable = true) + private UUID entityId; + public static final String _entityId = "entityId"; + + @Column(name = "created_at", nullable = false) + private Instant createdAt; + public static final String _createdAt = "createdAt"; + + @Column(name = "updated_at", nullable = false) + private Instant updatedAt; + public static final String _updatedAt = "updatedAt"; + + @Column(name = "type", nullable = false) + @Convert(converter = UserSettingsTypeConverter.class) + private UserSettingsType type; + public static final String _type = "type"; + + public UUID getId() { + return id; + } + + public void setId(UUID id) { + this.id = id; + } + + public String getKey() { + return key; + } + + public void setKey(String key) { + this.key = key; + } + + public UUID getEntityId() { + return entityId; + } + + public void setEntityId(UUID entityId) { + this.entityId = entityId; + } + + public Instant getCreatedAt() { + return createdAt; + } + + public void setCreatedAt(Instant createdAt) { + this.createdAt = createdAt; + } + + public Instant getUpdatedAt() { + return updatedAt; + } + + public void setUpdatedAt(Instant updatedAt) { + this.updatedAt = updatedAt; + } + + public UserSettingsType getType() { + return type; + } + + public void setType(UserSettingsType type) { + this.type = type; + } + + public String getValue() { + return value; + } + + public void setValue(String value) { + this.value = value; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } +} diff --git a/dmp-backend/core/src/main/java/eu/eudat/data/converters/enums/UserSettingsTypeConverter.java b/dmp-backend/core/src/main/java/eu/eudat/data/converters/enums/UserSettingsTypeConverter.java new file mode 100644 index 000000000..02247e851 --- /dev/null +++ b/dmp-backend/core/src/main/java/eu/eudat/data/converters/enums/UserSettingsTypeConverter.java @@ -0,0 +1,11 @@ +package eu.eudat.data.converters.enums; + +import eu.eudat.commons.enums.UserSettingsType; +import jakarta.persistence.Converter; + +@Converter +public class UserSettingsTypeConverter extends DatabaseEnumConverter { + public UserSettingsType of(Short i) { + return UserSettingsType.of(i); + } +} diff --git a/dmp-backend/core/src/main/java/eu/eudat/model/UserSettings.java b/dmp-backend/core/src/main/java/eu/eudat/model/UserSettings.java new file mode 100644 index 000000000..0a06a375e --- /dev/null +++ b/dmp-backend/core/src/main/java/eu/eudat/model/UserSettings.java @@ -0,0 +1,97 @@ +package eu.eudat.model; + +import eu.eudat.commons.enums.UserSettingsType; + +import java.time.Instant; +import java.util.UUID; + +public class UserSettings { + + private UUID id; + public static final String _id = "id"; + + private String key; + public static final String _key = "key"; + + private String value; + public static final String _value = "value"; + + private UUID entityId; + public static final String _entityId = "entityId"; + + private Instant createdAt; + public static final String _createdAt = "createdAt"; + + private Instant updatedAt; + public static final String _updatedAt = "updatedAt"; + + private UserSettingsType type; + public static final String _type = "type"; + + private String hash; + public static final String _hash = "hash"; + + public UUID getId() { + return id; + } + + public void setId(UUID id) { + this.id = id; + } + + public String getKey() { + return key; + } + + public void setKey(String key) { + this.key = key; + } + + public UUID getEntityId() { + return entityId; + } + + public void setEntityId(UUID entityId) { + this.entityId = entityId; + } + + public Instant getCreatedAt() { + return createdAt; + } + + public void setCreatedAt(Instant createdAt) { + this.createdAt = createdAt; + } + + public Instant getUpdatedAt() { + return updatedAt; + } + + public void setUpdatedAt(Instant updatedAt) { + this.updatedAt = updatedAt; + } + + public UserSettingsType getType() { + return type; + } + + public void setType(UserSettingsType type) { + this.type = type; + } + + public String getHash() { + return hash; + } + + public void setHash(String hash) { + this.hash = hash; + } + + public String getValue() { + return value; + } + + public void setValue(String value) { + this.value = value; + } +} diff --git a/dmp-backend/core/src/main/java/eu/eudat/model/builder/UserSettingsBuilder.java b/dmp-backend/core/src/main/java/eu/eudat/model/builder/UserSettingsBuilder.java new file mode 100644 index 000000000..89c9cec38 --- /dev/null +++ b/dmp-backend/core/src/main/java/eu/eudat/model/builder/UserSettingsBuilder.java @@ -0,0 +1,65 @@ +package eu.eudat.model.builder; + +import eu.eudat.authorization.AuthorizationFlags; +import eu.eudat.convention.ConventionService; +import eu.eudat.data.UserSettingsEntity; +import eu.eudat.model.UserSettings; +import gr.cite.tools.data.builder.BuilderFactory; +import gr.cite.tools.data.query.QueryFactory; +import gr.cite.tools.exception.MyApplicationException; +import gr.cite.tools.fieldset.FieldSet; +import gr.cite.tools.logging.DataLogEntry; +import gr.cite.tools.logging.LoggerService; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.config.ConfigurableBeanFactory; +import org.springframework.context.annotation.Scope; +import org.springframework.stereotype.Component; + +import java.time.Instant; +import java.util.*; + +@Component +@Scope(value = ConfigurableBeanFactory.SCOPE_PROTOTYPE) +public class UserSettingsBuilder extends BaseBuilder { + + private final BuilderFactory builderFactory; + private final QueryFactory queryFactory; + + private EnumSet authorize = EnumSet.of(AuthorizationFlags.None); + + public UserSettingsBuilder(ConventionService conventionService, BuilderFactory builderFactory, QueryFactory queryFactory) { + super(conventionService, new LoggerService(LoggerFactory.getLogger(UserSettingsBuilder.class))); + this.builderFactory = builderFactory; + this.queryFactory = queryFactory; + } + + public UserSettingsBuilder authorize(EnumSet values) { + this.authorize = values; + return this; + } + + @Override + public List build(FieldSet fields, List data) throws MyApplicationException { + this.logger.debug("building for {} items requesting {} fields", Optional.ofNullable(data).map(List::size).orElse(0), Optional.ofNullable(fields).map(FieldSet::getFields).map(Set::size).orElse(0)); + this.logger.trace(new DataLogEntry("requested fields", fields)); + if (fields == null || data == null || fields.isEmpty()) return new ArrayList<>(); + + List models = new ArrayList<>(); + + for (UserSettingsEntity d : data) { + UserSettings m = new UserSettings(); + if (fields.hasField(this.asIndexer(UserSettings._id))) m.setId(d.getId()); + if (fields.hasField(this.asIndexer(UserSettings._value))) m.setValue(d.getValue()); + if (fields.hasField(this.asIndexer(UserSettings._key))) m.setKey(d.getKey()); + if (fields.hasField(this.asIndexer(UserSettings._type))) m.setType(d.getType()); + if (fields.hasField(this.asIndexer(UserSettings._entityId))) m.setEntityId(d.getEntityId()); + if (fields.hasField(this.asIndexer(UserSettings._createdAt))) m.setCreatedAt(d.getCreatedAt()); + if (fields.hasField(this.asIndexer(UserSettings._updatedAt))) m.setUpdatedAt(d.getUpdatedAt()); + if (fields.hasField(this.asIndexer(UserSettings._hash))) m.setHash(this.hashValue(Instant.ofEpochMilli(d.getUpdatedAt().toEpochMilli()))); + models.add(m); + } + this.logger.debug("build {} items", Optional.of(models).map(List::size).orElse(0)); + return models; + } + +} diff --git a/dmp-backend/core/src/main/java/eu/eudat/model/censorship/UserSettingsCensor.java b/dmp-backend/core/src/main/java/eu/eudat/model/censorship/UserSettingsCensor.java new file mode 100644 index 000000000..9632d41c9 --- /dev/null +++ b/dmp-backend/core/src/main/java/eu/eudat/model/censorship/UserSettingsCensor.java @@ -0,0 +1,41 @@ +package eu.eudat.model.censorship; + +import eu.eudat.authorization.OwnedResource; +import eu.eudat.authorization.Permission; +import eu.eudat.convention.ConventionService; +import gr.cite.commons.web.authz.service.AuthorizationService; +import gr.cite.tools.data.censor.CensorFactory; +import gr.cite.tools.exception.MyForbiddenException; +import gr.cite.tools.fieldset.FieldSet; +import gr.cite.tools.logging.DataLogEntry; +import gr.cite.tools.logging.LoggerService; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.config.ConfigurableBeanFactory; +import org.springframework.context.annotation.Scope; +import org.springframework.stereotype.Component; + +import java.util.List; +import java.util.UUID; + +@Component +@Scope(value = ConfigurableBeanFactory.SCOPE_PROTOTYPE) +public class UserSettingsCensor extends BaseCensor { + + private static final LoggerService logger = new LoggerService(LoggerFactory.getLogger(UserSettingsCensor.class)); + + protected final AuthorizationService authService; + protected final CensorFactory censorFactory; + + public UserSettingsCensor(ConventionService conventionService, AuthorizationService authService, CensorFactory censorFactory) { + super(conventionService); + this.authService = authService; + this.censorFactory = censorFactory; + } + + public void censor(FieldSet fields, UUID userId) throws MyForbiddenException { + logger.debug(new DataLogEntry("censoring fields", fields)); + if (this.isEmpty(fields)) return; + this.authService.authorizeAtLeastOneForce(userId != null ? List.of(new OwnedResource(userId)) : null, Permission.BrowseUserSettings); + } + +} diff --git a/dmp-backend/core/src/main/java/eu/eudat/model/persist/UserSettingsPersist.java b/dmp-backend/core/src/main/java/eu/eudat/model/persist/UserSettingsPersist.java new file mode 100644 index 000000000..2e065fd4f --- /dev/null +++ b/dmp-backend/core/src/main/java/eu/eudat/model/persist/UserSettingsPersist.java @@ -0,0 +1,80 @@ +package eu.eudat.model.persist; + +import eu.eudat.commons.enums.UserSettingsType; +import eu.eudat.commons.validation.FieldNotNullIfOtherSet; +import eu.eudat.commons.validation.ValidId; +import jakarta.validation.constraints.NotEmpty; +import jakarta.validation.constraints.NotNull; + +import java.util.UUID; + +@FieldNotNullIfOtherSet(message = "{validation.hashempty}") +public class UserSettingsPersist { + + @ValidId(message = "{validation.invalidid}") + private UUID id; + + @NotNull(message = "{validation.empty}") + @NotEmpty(message = "{validation.empty}") + private String key; + + @NotNull(message = "{validation.empty}") + @NotEmpty(message = "{validation.empty}") + private String value; + + @ValidId(message = "{validation.invalidid}") + private UUID entityId; + + @NotNull(message = "{validation.empty}") + private UserSettingsType type; + + private String hash; + + public UUID getId() { + return id; + } + + public void setId(UUID id) { + this.id = id; + } + + public String getKey() { + return key; + } + + public void setKey(String key) { + this.key = key; + } + + public UUID getEntityId() { + return entityId; + } + + public void setEntityId(UUID entityId) { + this.entityId = entityId; + } + + public UserSettingsType getType() { + return type; + } + + public void setType(UserSettingsType type) { + this.type = type; + } + + public String getHash() { + return hash; + } + + public void setHash(String hash) { + this.hash = hash; + } + + public String getValue() { + return value; + } + + public void setValue(String value) { + this.value = value; + } +} diff --git a/dmp-backend/core/src/main/java/eu/eudat/query/UserSettingsQuery.java b/dmp-backend/core/src/main/java/eu/eudat/query/UserSettingsQuery.java new file mode 100644 index 000000000..9fd7f2baa --- /dev/null +++ b/dmp-backend/core/src/main/java/eu/eudat/query/UserSettingsQuery.java @@ -0,0 +1,234 @@ +package eu.eudat.query; + +import eu.eudat.authorization.AuthorizationFlags; +import eu.eudat.authorization.Permission; +import eu.eudat.commons.enums.UserSettingsType; +import eu.eudat.commons.scope.user.UserScope; +import eu.eudat.data.UserSettingsEntity; +import eu.eudat.model.UserSettings; +import gr.cite.commons.web.authz.service.AuthorizationService; +import gr.cite.tools.data.query.FieldResolver; +import gr.cite.tools.data.query.QueryBase; +import gr.cite.tools.data.query.QueryContext; +import jakarta.persistence.Tuple; +import jakarta.persistence.criteria.CriteriaBuilder; +import jakarta.persistence.criteria.Predicate; +import org.springframework.beans.factory.config.ConfigurableBeanFactory; +import org.springframework.context.annotation.Scope; +import org.springframework.stereotype.Component; + +import java.time.Instant; +import java.util.*; + +@Component +@Scope(value = ConfigurableBeanFactory.SCOPE_PROTOTYPE) +public class UserSettingsQuery extends QueryBase { + + private String like; + private Collection ids; + private Collection userSettingsTypes; + private Collection keys; + private Collection types; + private Collection entityIds; + + private EnumSet authorize = EnumSet.of(AuthorizationFlags.None); + + private final UserScope userScope; + private final AuthorizationService authService; + + public UserSettingsQuery( + UserScope userScope, + AuthorizationService authService + ) { + this.userScope = userScope; + this.authService = authService; + } + + public UserSettingsQuery like(String like) { + this.like = like; + return this; + } + + public UserSettingsQuery ids(UUID value) { + this.ids = List.of(value); + return this; + } + + public UserSettingsQuery ids(UUID... value) { + this.ids = Arrays.asList(value); + return this; + } + + public UserSettingsQuery ids(Collection values) { + this.ids = values; + return this; + } + + public UserSettingsQuery userSettingsTypes(UserSettingsType value) { + this.userSettingsTypes = List.of(value); + return this; + } + + public UserSettingsQuery userSettingsTypes(UserSettingsType... value) { + this.userSettingsTypes = Arrays.asList(value); + return this; + } + + public UserSettingsQuery userSettingsTypes(Collection values) { + this.userSettingsTypes = values; + return this; + } + + public UserSettingsQuery keys(String value) { + this.keys = List.of(value); + return this; + } + + public UserSettingsQuery keys(String... value) { + this.keys = Arrays.asList(value); + return this; + } + + public UserSettingsQuery keys(Collection values) { + this.keys = values; + return this; + } + + + public UserSettingsQuery types(UserSettingsType value) { + this.types = List.of(value); + return this; + } + + public UserSettingsQuery types(UserSettingsType... value) { + this.types = Arrays.asList(value); + return this; + } + + public UserSettingsQuery types(Collection values) { + this.types = values; + return this; + } + + public UserSettingsQuery entityIds(UUID value) { + this.entityIds = List.of(value); + return this; + } + + public UserSettingsQuery entityIds(UUID... value) { + this.entityIds = Arrays.asList(value); + return this; + } + + public UserSettingsQuery entityIds(Collection values) { + this.entityIds = values; + return this; + } + + public UserSettingsQuery authorize(EnumSet values) { + this.authorize = values; + return this; + } + + @Override + protected Boolean isFalseQuery() { + return this.isEmpty(this.ids) || this.isEmpty(this.keys) || this.isEmpty(this.types) || this.isEmpty(this.entityIds); + } + + @Override + protected Class entityClass() { + return UserSettingsEntity.class; + } + + @Override + protected Predicate applyAuthZ(QueryContext queryContext) { + if (this.authorize.contains(AuthorizationFlags.None)) return null; + if (this.authorize.contains(AuthorizationFlags.Permission) && this.authService.authorize(Permission.BrowseUserSettings)) return null; + UUID ownerId = null; + if (this.authorize.contains(AuthorizationFlags.Owner)) ownerId = this.userScope.getUserIdSafe(); + + List predicates = new ArrayList<>(); + if (ownerId != null) { + predicates.add(queryContext.CriteriaBuilder.equal(queryContext.Root.get(UserSettingsEntity._entityId), ownerId)); + } + if (predicates.size() > 0) { + Predicate[] predicatesArray = predicates.toArray(new Predicate[0]); + return queryContext.CriteriaBuilder.and(predicatesArray); + } else { + return queryContext.CriteriaBuilder.or(); //Creates a false query + } + } + + @Override + protected Predicate applyFilters(QueryContext queryContext) { + List predicates = new ArrayList<>(); + if (this.like != null && !this.like.isEmpty()) { + predicates.add(queryContext.CriteriaBuilder.or(queryContext.CriteriaBuilder.like(queryContext.Root.get(UserSettingsEntity._key), this.like), + queryContext.CriteriaBuilder.like(queryContext.Root.get(UserSettingsEntity._value), this.like) + )); + } + if (this.ids != null) { + CriteriaBuilder.In inClause = queryContext.CriteriaBuilder.in(queryContext.Root.get(UserSettingsEntity._id)); + for (UUID item : this.ids) inClause.value(item); + predicates.add(inClause); + } + + if (this.userSettingsTypes != null) { + CriteriaBuilder.In inClause = queryContext.CriteriaBuilder.in(queryContext.Root.get(UserSettingsEntity._type)); + for (UserSettingsType item : this.userSettingsTypes) inClause.value(item); + predicates.add(inClause); + } + + if (this.keys != null) { + CriteriaBuilder.In inClause = queryContext.CriteriaBuilder.in(queryContext.Root.get(UserSettingsEntity._key)); + for (String item : this.keys) inClause.value(item); + predicates.add(inClause); + } + + if (this.entityIds != null) { + CriteriaBuilder.In inClause = queryContext.CriteriaBuilder.in(queryContext.Root.get(UserSettingsEntity._entityId)); + for (UUID item : this.entityIds) inClause.value(item); + predicates.add(inClause); + } + + if (this.types != null) { + CriteriaBuilder.In inClause = queryContext.CriteriaBuilder.in(queryContext.Root.get(UserSettingsEntity._type)); + for (UserSettingsType item : this.types) inClause.value(item); + predicates.add(inClause); + } + + + if (predicates.size() > 0) { + Predicate[] predicatesArray = predicates.toArray(new Predicate[0]); + return queryContext.CriteriaBuilder.and(predicatesArray); + } else { + return null; + } + } + + @Override + protected String fieldNameOf(FieldResolver item) { + if (item.match(UserSettings._id)) return UserSettingsEntity._id; + else if (item.match(UserSettings._entityId)) return UserSettingsEntity._entityId; + else if (item.match(UserSettings._value)) return UserSettingsEntity._value; + else if (item.match(UserSettings._key)) return UserSettingsEntity._key; + else if (item.match(UserSettings._type)) return UserSettingsEntity._type; + else if (item.match(UserSettings._createdAt)) return UserSettingsEntity._createdAt; + else if (item.match(UserSettings._updatedAt)) return UserSettingsEntity._updatedAt; + else if (item.match(UserSettings._hash)) return UserSettingsEntity._updatedAt; + else return null; + } + + @Override + protected UserSettingsEntity convert(Tuple tuple, Set columns) { + UserSettingsEntity item = new UserSettingsEntity(); + item.setId(QueryBase.convertSafe(tuple, columns, UserSettingsEntity._id, UUID.class)); + item.setEntityId(QueryBase.convertSafe(tuple, columns, UserSettingsEntity._entityId, UUID.class)); + item.setKey(QueryBase.convertSafe(tuple, columns, UserSettingsEntity._key, String.class)); + item.setValue(QueryBase.convertSafe(tuple, columns, UserSettingsEntity._value, String.class)); + item.setType(QueryBase.convertSafe(tuple, columns, UserSettingsEntity._type, UserSettingsType.class)); + item.setCreatedAt(QueryBase.convertSafe(tuple, columns, UserSettingsEntity._createdAt, Instant.class)); + item.setUpdatedAt(QueryBase.convertSafe(tuple, columns, UserSettingsEntity._updatedAt, Instant.class)); + return item; + } +} diff --git a/dmp-backend/core/src/main/java/eu/eudat/query/lookup/UserSettingsLookup.java b/dmp-backend/core/src/main/java/eu/eudat/query/lookup/UserSettingsLookup.java new file mode 100644 index 000000000..febc9e00e --- /dev/null +++ b/dmp-backend/core/src/main/java/eu/eudat/query/lookup/UserSettingsLookup.java @@ -0,0 +1,52 @@ +package eu.eudat.query.lookup; + +import eu.eudat.commons.enums.UserSettingsType; +import eu.eudat.query.UserSettingsQuery; +import gr.cite.tools.data.query.Lookup; +import gr.cite.tools.data.query.QueryFactory; + +import java.util.List; +import java.util.UUID; + +public class UserSettingsLookup extends Lookup { + + private String like; + private List ids; + private List userSettingsTypes; + + public String getLike() { + return like; + } + + public void setLike(String like) { + this.like = like; + } + + public List getIds() { + return ids; + } + + public void setIds(List ids) { + this.ids = ids; + } + + public List getUserSettingsTypes() { + return userSettingsTypes; + } + + public void setUserSettingsTypes(List userSettingsTypes) { + this.userSettingsTypes = userSettingsTypes; + } + + public UserSettingsQuery enrich(QueryFactory queryFactory) { + UserSettingsQuery query = queryFactory.query(UserSettingsQuery.class); + if (this.like != null) query.like(this.like); + if (this.ids != null) query.ids(this.ids); + if (this.userSettingsTypes != null) query.userSettingsTypes(this.userSettingsTypes); + + this.enrichCommon(query); + + return query; + } + +} diff --git a/dmp-backend/core/src/main/java/eu/eudat/service/DescriptionTemplateTypeServiceImpl.java b/dmp-backend/core/src/main/java/eu/eudat/service/DescriptionTemplateTypeServiceImpl.java index 993021564..ee142e740 100644 --- a/dmp-backend/core/src/main/java/eu/eudat/service/DescriptionTemplateTypeServiceImpl.java +++ b/dmp-backend/core/src/main/java/eu/eudat/service/DescriptionTemplateTypeServiceImpl.java @@ -39,7 +39,6 @@ import java.util.List; import java.util.UUID; @Service -@RequestScope public class DescriptionTemplateTypeServiceImpl implements DescriptionTemplateTypeService { private static final LoggerService logger = new LoggerService(LoggerFactory.getLogger(DescriptionTemplateTypeServiceImpl.class)); diff --git a/dmp-backend/core/src/main/java/eu/eudat/service/user/settings/UserSettingsService.java b/dmp-backend/core/src/main/java/eu/eudat/service/user/settings/UserSettingsService.java new file mode 100644 index 000000000..06bfe57e5 --- /dev/null +++ b/dmp-backend/core/src/main/java/eu/eudat/service/user/settings/UserSettingsService.java @@ -0,0 +1,15 @@ +package eu.eudat.service.user.settings; + +import eu.eudat.model.UserSettings; +import eu.eudat.model.persist.UserSettingsPersist; +import gr.cite.tools.exception.MyApplicationException; +import gr.cite.tools.exception.MyForbiddenException; +import gr.cite.tools.exception.MyNotFoundException; +import gr.cite.tools.exception.MyValidationException; +import gr.cite.tools.fieldset.FieldSet; + +import javax.management.InvalidApplicationException; + +public interface UserSettingsService { + UserSettings persist(UserSettingsPersist model, FieldSet fields) throws MyForbiddenException, MyValidationException, MyApplicationException, MyNotFoundException, InvalidApplicationException; +} diff --git a/dmp-backend/core/src/main/java/eu/eudat/service/user/settings/UserSettingsServiceImpl.java b/dmp-backend/core/src/main/java/eu/eudat/service/user/settings/UserSettingsServiceImpl.java new file mode 100644 index 000000000..d67ed0967 --- /dev/null +++ b/dmp-backend/core/src/main/java/eu/eudat/service/user/settings/UserSettingsServiceImpl.java @@ -0,0 +1,103 @@ +package eu.eudat.service.user.settings; + +import eu.eudat.authorization.AuthorizationFlags; +import eu.eudat.authorization.Permission; +import eu.eudat.commons.scope.user.UserScope; +import eu.eudat.convention.ConventionService; +import eu.eudat.data.UserSettingsEntity; +import eu.eudat.errorcode.ErrorThesaurusProperties; +import eu.eudat.model.UserSettings; +import eu.eudat.model.builder.UserSettingsBuilder; +import eu.eudat.model.persist.UserSettingsPersist; +import gr.cite.commons.web.authz.service.AuthorizationService; +import gr.cite.tools.data.builder.BuilderFactory; +import gr.cite.tools.data.deleter.DeleterFactory; +import gr.cite.tools.exception.MyApplicationException; +import gr.cite.tools.exception.MyForbiddenException; +import gr.cite.tools.exception.MyNotFoundException; +import gr.cite.tools.exception.MyValidationException; +import gr.cite.tools.fieldset.BaseFieldSet; +import gr.cite.tools.fieldset.FieldSet; +import gr.cite.tools.logging.LoggerService; +import gr.cite.tools.logging.MapLogEntry; +import jakarta.persistence.EntityManager; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.context.MessageSource; +import org.springframework.context.i18n.LocaleContextHolder; +import org.springframework.stereotype.Service; +import org.springframework.web.context.annotation.RequestScope; + +import javax.management.InvalidApplicationException; +import java.time.Instant; +import java.util.UUID; + +@Service +public class UserSettingsServiceImpl implements UserSettingsService { + + private static final LoggerService logger = new LoggerService(LoggerFactory.getLogger(UserSettingsServiceImpl.class)); + private final EntityManager entityManager; + private final AuthorizationService authorizationService; + private final DeleterFactory deleterFactory; + private final BuilderFactory builderFactory; + private final ConventionService conventionService; + private final ErrorThesaurusProperties errors; + private final MessageSource messageSource; + + private final UserScope userScope; + + @Autowired + public UserSettingsServiceImpl( + EntityManager entityManager, + AuthorizationService authorizationService, + DeleterFactory deleterFactory, + BuilderFactory builderFactory, + ConventionService conventionService, + ErrorThesaurusProperties errors, + MessageSource messageSource, + UserScope userScope) { + this.entityManager = entityManager; + this.authorizationService = authorizationService; + this.deleterFactory = deleterFactory; + this.builderFactory = builderFactory; + this.conventionService = conventionService; + this.errors = errors; + this.messageSource = messageSource; + this.userScope = userScope; + } + + @Override + public UserSettings persist(UserSettingsPersist model, FieldSet fields) throws MyForbiddenException, MyValidationException, MyApplicationException, MyNotFoundException, InvalidApplicationException { + logger.debug(new MapLogEntry("persisting data access request").And("model", model).And("fields", fields)); + + this.authorizationService.authorizeForce(Permission.EditUserSettings); + + boolean isUpdate = this.conventionService.isValidGuid(model.getId()); + + UserSettingsEntity data; + if (isUpdate) { + data = this.entityManager.find(UserSettingsEntity.class, model.getId()); + if (data == null) throw new MyNotFoundException(messageSource.getMessage("General_ItemNotFound", new Object[]{model.getId(), UserSettings.class.getSimpleName()}, LocaleContextHolder.getLocale())); + } else { + data = new UserSettingsEntity(); + data.setCreatedAt(Instant.now()); + data.setId(UUID.randomUUID()); + + } + + data.setName(model.getKey()); + data.setType(model.getType()); + data.setKey(model.getKey()); + data.setValue(model.getValue()); + data.setEntityId(model.getEntityId()); + data.setUpdatedAt(Instant.now()); + + if (isUpdate) this.entityManager.merge(data); + else this.entityManager.persist(data); + + this.entityManager.flush(); + + return this.builderFactory.builder(UserSettingsBuilder.class).authorize(AuthorizationFlags.OwnerOrPermission).build(BaseFieldSet.build(fields, UserSettings._id, UserSettings._key), data); + } + +} diff --git a/dmp-backend/web/src/main/java/eu/eudat/controllers/v2/UserSettingsController.java b/dmp-backend/web/src/main/java/eu/eudat/controllers/v2/UserSettingsController.java new file mode 100644 index 000000000..c1ab218a5 --- /dev/null +++ b/dmp-backend/web/src/main/java/eu/eudat/controllers/v2/UserSettingsController.java @@ -0,0 +1,120 @@ +package eu.eudat.controllers.v2; +import eu.eudat.audit.AuditableAction; +import eu.eudat.authorization.AuthorizationFlags; +import eu.eudat.data.UserSettingsEntity; +import eu.eudat.model.UserSettings; +import eu.eudat.model.builder.UserSettingsBuilder; +import eu.eudat.model.censorship.UserSettingsCensor; +import eu.eudat.model.persist.UserSettingsPersist; +import eu.eudat.model.result.QueryResult; +import eu.eudat.query.UserSettingsQuery; +import eu.eudat.query.lookup.UserSettingsLookup; +import eu.eudat.service.user.settings.UserSettingsService; +import gr.cite.tools.auditing.AuditService; +import gr.cite.tools.data.builder.BuilderFactory; +import gr.cite.tools.data.censor.CensorFactory; +import gr.cite.tools.data.query.QueryFactory; +import gr.cite.tools.exception.MyApplicationException; +import gr.cite.tools.exception.MyForbiddenException; +import gr.cite.tools.exception.MyNotFoundException; +import gr.cite.tools.fieldset.BaseFieldSet; +import gr.cite.tools.fieldset.FieldSet; +import gr.cite.tools.logging.LoggerService; +import gr.cite.tools.logging.MapLogEntry; +import gr.cite.tools.validation.MyValidate; +import jakarta.transaction.Transactional; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.context.MessageSource; +import org.springframework.context.i18n.LocaleContextHolder; +import org.springframework.web.bind.annotation.*; + +import javax.management.InvalidApplicationException; +import java.util.*; + +@RestController +@CrossOrigin +@RequestMapping(path = "api/user-settings") +public class UserSettingsController { + + private static final LoggerService logger = new LoggerService(LoggerFactory.getLogger(UserSettingsController.class)); + + private final BuilderFactory builderFactory; + private final AuditService auditService; + private final UserSettingsService settingsService; + private final CensorFactory censorFactory; + private final QueryFactory queryFactory; + private final MessageSource messageSource; + + @Autowired + public UserSettingsController( + BuilderFactory builderFactory, + AuditService auditService, + UserSettingsService settingsService, + CensorFactory censorFactory, + QueryFactory queryFactory, + MessageSource messageSource) { + this.builderFactory = builderFactory; + this.auditService = auditService; + this.settingsService = settingsService; + this.censorFactory = censorFactory; + this.queryFactory = queryFactory; + this.messageSource = messageSource; + } + + @PostMapping("query") + public QueryResult Query(@RequestBody UserSettingsLookup lookup) throws MyApplicationException, MyForbiddenException { + logger.debug("querying {}", UserSettings.class.getSimpleName()); + this.censorFactory.censor(UserSettingsCensor.class).censor(lookup.getProject(), null); + UserSettingsQuery query = lookup.enrich(this.queryFactory).authorize(AuthorizationFlags.OwnerOrPermission); + List data = query.collectAs(lookup.getProject()); + List models = this.builderFactory.builder(UserSettingsBuilder.class).authorize(AuthorizationFlags.OwnerOrPermission).build(lookup.getProject(), data); + long count = (lookup.getMetadata() != null && lookup.getMetadata().getCountAll()) ? query.count() : models.size(); + + this.auditService.track(AuditableAction.User_Settings_Query, "lookup", lookup); + //this.auditService.trackIdentity(AuditableAction.IdentityTracking_Action); + + return new QueryResult<>(models, count); + } + + @GetMapping("{key}") + @Transactional + public UserSettings Get(@PathVariable("key") String key) throws MyApplicationException, MyForbiddenException, MyNotFoundException { + logger.debug(new MapLogEntry("retrieving" + UserSettings.class.getSimpleName()).And("key", key)); + + BaseFieldSet fieldSet = new BaseFieldSet(); + fieldSet.setFields(Set.of( + UserSettings._id, + UserSettings._key, + UserSettings._value, + UserSettings._entityId, + UserSettings._createdAt, + UserSettings._updatedAt, + UserSettings._type + )); + UserSettingsQuery query = this.queryFactory.query(UserSettingsQuery.class).authorize(AuthorizationFlags.OwnerOrPermission).keys(key); + UserSettings model = this.builderFactory.builder(UserSettingsBuilder.class).authorize(AuthorizationFlags.OwnerOrPermission).build(fieldSet, query.firstAs(fieldSet)); + + this.auditService.track(AuditableAction.User_Settings_Lookup, Map.ofEntries( + new AbstractMap.SimpleEntry("key", key) + )); + + return model; + } + + @PostMapping("persist") + @Transactional + public UserSettings Persist(@MyValidate @RequestBody UserSettingsPersist model, FieldSet fieldSet) throws MyApplicationException, MyForbiddenException, MyNotFoundException, InvalidApplicationException { + logger.debug(new MapLogEntry("persisting" + UserSettings.class.getSimpleName()).And("model", model).And("fieldSet", fieldSet)); + + UserSettings persisted = this.settingsService.persist(model, fieldSet); + + this.auditService.track(AuditableAction.User_Settings_Persist, Map.ofEntries( + new AbstractMap.SimpleEntry("model", model), + new AbstractMap.SimpleEntry("fields", fieldSet) + )); + //this.auditService.trackIdentity(AuditableAction.IdentityTracking_Action); + return persisted; + } + +} diff --git a/dmp-db-scema/updates/00.00.014_Rename_DatasetProfile_and_add_Type_column.sql b/dmp-db-scema/updates/00.00.014_Rename_DatasetProfile_and_add_Type_column.sql index 1be73da3c..9531c7e91 100644 --- a/dmp-db-scema/updates/00.00.014_Rename_DatasetProfile_and_add_Type_column.sql +++ b/dmp-db-scema/updates/00.00.014_Rename_DatasetProfile_and_add_Type_column.sql @@ -13,7 +13,7 @@ ADD COLUMN "Type" uuid; INSERT INTO public."DescriptionTemplateType" ("ID", "Name", "Status") VALUES ('709a8400-10ca-11ee-be56-0242ac120002', 'Dataset', 1); -UPDATE public."DescriptionTemplate" SET ("Type") = '709a8400-10ca-11ee-be56-0242ac120002'; +UPDATE public."DescriptionTemplate" SET "Type" = '709a8400-10ca-11ee-be56-0242ac120002'; ALTER TABLE public."DescriptionTemplate" ALTER COLUMN "Type" SET NOT NULL; diff --git a/dmp-db-scema/updates/00.01.001_Align_Description_Template_Type.sql b/dmp-db-scema/updates/00.01.001_Align_Description_Template_Type.sql index 48bcce7e2..fe8321e98 100644 --- a/dmp-db-scema/updates/00.01.001_Align_Description_Template_Type.sql +++ b/dmp-db-scema/updates/00.01.001_Align_Description_Template_Type.sql @@ -1,3 +1,9 @@ +DO $$DECLARE + this_version CONSTANT varchar := '00.01.001'; +BEGIN + PERFORM * FROM "DBVersion" WHERE version = this_version; + IF FOUND THEN RETURN; END IF; + ALTER TABLE public."DescriptionTemplateType" RENAME "ID" TO id; @@ -31,4 +37,9 @@ UPDATE public."DescriptionTemplateType" SET is_active = 0 where status = 99; UPDATE public."DescriptionTemplateType" SET status = 0 where is_active = 0; ALTER TABLE public."DescriptionTemplateType" - ALTER COLUMN is_active SET NOT NULL; \ No newline at end of file + ALTER COLUMN is_active SET NOT NULL; + + +INSERT INTO public."DBVersion" VALUES ('DMPDB', '00.01.001', '2023-10-19 12:00:00.000000+02', now(), 'Align Description Template Type.'); + +END$$; \ No newline at end of file diff --git a/dmp-db-scema/updates/00.01.002_Align_Entity_Doi_table.sql b/dmp-db-scema/updates/00.01.002_Align_Entity_Doi_table.sql index b85c9c7f3..b591c6648 100644 --- a/dmp-db-scema/updates/00.01.002_Align_Entity_Doi_table.sql +++ b/dmp-db-scema/updates/00.01.002_Align_Entity_Doi_table.sql @@ -1,3 +1,9 @@ +DO $$DECLARE + this_version CONSTANT varchar := '00.01.002'; +BEGIN + PERFORM * FROM "DBVersion" WHERE version = this_version; + IF FOUND THEN RETURN; END IF; + ALTER TABLE public."EntityDoi" RENAME "ID" TO id; @@ -20,4 +26,9 @@ ALTER TABLE public."EntityDoi" RENAME "EntityId" TO entity_id; ALTER TABLE public."EntityDoi" - ADD COLUMN is_active smallint NOT NULL DEFAULT 1 \ No newline at end of file + ADD COLUMN is_active smallint NOT NULL DEFAULT 1 + + +INSERT INTO public."DBVersion" VALUES ('DMPDB', '00.01.002', '2023-10-19 12:00:00.000000+02', now(), 'Align Entity Doi table.'); + +END$$; \ No newline at end of file diff --git a/dmp-db-scema/updates/00.01.003_Add_UserSettings_table.sql b/dmp-db-scema/updates/00.01.003_Add_UserSettings_table.sql new file mode 100644 index 000000000..055ee67a3 --- /dev/null +++ b/dmp-db-scema/updates/00.01.003_Add_UserSettings_table.sql @@ -0,0 +1,23 @@ +DO $$DECLARE + this_version CONSTANT varchar := '00.01.003'; +BEGIN + PERFORM * FROM "DBVersion" WHERE version = this_version; + IF FOUND THEN RETURN; END IF; + +CREATE TABLE IF NOT EXISTS public.UserSettings +( + id uuid NOT NULL, + key character varying(500) COLLATE pg_catalog."default" NOT NULL, + entity_id uuid, + created_at timestamp without time zone NOT NULL, + updated_at timestamp without time zone NOT NULL, + type character varying(200) COLLATE pg_catalog."default" NOT NULL, + value text COLLATE pg_catalog."default" NOT NULL, + name character varying(500) COLLATE pg_catalog."default" NOT NULL, + CONSTRAINT user_settings_pkey PRIMARY KEY (id) +) + + +INSERT INTO public."DBVersion" VALUES ('DMPDB', '00.01.003', '2023-10-19 12:00:00.000000+02', now(), 'Add UserSettings table.'); + +END$$; \ No newline at end of file diff --git a/dmp-frontend/src/app/app-routing.module.ts b/dmp-frontend/src/app/app-routing.module.ts index d418c98f7..6d94faf13 100644 --- a/dmp-frontend/src/app/app-routing.module.ts +++ b/dmp-frontend/src/app/app-routing.module.ts @@ -4,6 +4,7 @@ import { ReloadHelperComponent } from '@app/ui/misc/reload-helper/reload-helper. import { Oauth2DialogComponent } from './ui/misc/oauth2-dialog/oauth2-dialog.component'; import { AppComponent } from './app.component'; import { AppPermission } from './core/common/enum/permission.enum'; +import { BreadcrumbService } from './ui/misc/breadcrumb/breadcrumb.service'; const appRoutes: Routes = [ { @@ -11,7 +12,10 @@ const appRoutes: Routes = [ component: AppComponent, data: { breadcrumbs: false, - title: 'GENERAL.TITLES.GENERAL' + title: 'GENERAL.TITLES.GENERAL', + ...BreadcrumbService.generateRouteDataConfiguration({ + title: 'BREADCRUMBS.HOME' + }) }, pathMatch: 'full' }, @@ -75,8 +79,8 @@ const appRoutes: Routes = [ } }, { - path: 'dmp-profiles', - loadChildren: () => import('./ui/admin/dmp-profile/dmp-profile.module').then(m => m.DmpProfileModule), + path: 'dmp-blueprints', + loadChildren: () => import('./ui/admin/dmp-blueprint/dmp-blueprint.module').then(m => m.DmpBlueprintModule), data: { breadcrumb: true, title: 'GENERAL.TITLES.DMP-BLUEPRINTS' @@ -99,14 +103,17 @@ const appRoutes: Routes = [ } }, { - path: 'description-types', - loadChildren: () => import('./ui/admin/description-types/description-types.module').then(m => m.DescriptionTypesModule), + path: 'description-template-type', + loadChildren: () => import('./ui/admin/description-types/description-template-type.module').then(m => m.DescriptionTemplateTypesModule), data: { breadcrumb: true, - title: 'GENERAL.TITLES.DESCRIPTION-TYPES', + title: 'GENERAL.TITLES.DESCRIPTION-TEMPLATE-TYPES', authContext: { permissions: [AppPermission.ViewDescriptionTemplateTypePage] - } + }, + ...BreadcrumbService.generateRouteDataConfiguration({ + title: 'BREADCRUMBS.DESCRIPTION-TEMPLATE-TYPES' + }) }, }, { diff --git a/dmp-frontend/src/app/app.component.ts b/dmp-frontend/src/app/app.component.ts index cd4d2c008..46b681c47 100644 --- a/dmp-frontend/src/app/app.component.ts +++ b/dmp-frontend/src/app/app.component.ts @@ -8,7 +8,7 @@ import { TranslateService } from '@ngx-translate/core'; import { environment } from '../environments/environment'; import { AuthService } from './core/services/auth/auth.service'; import { CultureService } from './core/services/culture/culture-service'; -import { BreadCrumbResolverService } from './ui/misc/breadcrumb/service/breadcrumb.service'; +// import { BreadCrumbResolverService } from './ui/misc/breadcrumb/service/breadcrumb.service'; import { Title } from '@angular/platform-browser'; import { NgcCookieConsentService, NgcStatusChangeEvent } from "ngx-cookieconsent"; import { CookieService } from "ngx-cookie-service"; @@ -19,6 +19,7 @@ import { Location } from '@angular/common'; import { MatomoService } from './core/services/matomo/matomo-service'; import { SideNavService } from './core/services/sidenav/side-nav.sevice'; import { MatSidenav } from '@angular/material/sidenav'; +import { TimezoneService } from './core/services/timezone/timezone-service'; declare const gapi: any; @@ -45,9 +46,10 @@ export class AppComponent implements OnInit, AfterViewInit { private route: ActivatedRoute, private authentication: AuthService, private translate: TranslateService, - private breadCrumbResolverService: BreadCrumbResolverService, + // private breadCrumbResolverService: BreadCrumbResolverService, private titleService: Title, private cultureService: CultureService, + private timezoneService: TimezoneService, private cookieService: CookieService, private ccService: NgcCookieConsentService, private language: LanguageService, @@ -96,7 +98,7 @@ export class AppComponent implements OnInit, AfterViewInit { } onActivate(event: any) { - this.breadCrumbResolverService.push(event); + // this.breadCrumbResolverService.push(event); } onDeactivate(event: any) { @@ -225,6 +227,7 @@ export class AppComponent implements OnInit, AfterViewInit { initializeServices() { this.translate.setDefaultLang(this.configurationService.defaultLanguage || 'en'); this.authentication.currentAccountIsAuthenticated() && this.authentication.getUserProfileCulture() ? this.cultureService.cultureSelected(this.authentication.getUserProfileCulture()) : this.cultureService.cultureSelected(this.configurationService.defaultCulture); + this.authentication.currentAccountIsAuthenticated() && this.authentication.getUserProfileTimezone() ? this.timezoneService.timezoneSelected(this.authentication.getUserProfileTimezone()) : this.timezoneService.timezoneSelected(this.configurationService.defaultTimezone); this.authentication.currentAccountIsAuthenticated() && this.authentication.getUserProfileLanguage() ? this.language.changeLanguage(this.authentication.getUserProfileLanguage()) : (this.configurationService.defaultLanguage || 'en'); } diff --git a/dmp-frontend/src/app/app.module.ts b/dmp-frontend/src/app/app.module.ts index 9e5277467..8eb218add 100644 --- a/dmp-frontend/src/app/app.module.ts +++ b/dmp-frontend/src/app/app.module.ts @@ -13,7 +13,7 @@ import { CoreServiceModule } from '@app/core/core-service.module'; import { NotificationModule } from '@app/library/notification/notification.module'; import { LoginModule } from '@app/ui/auth/login/login.module'; import { DatasetCreateWizardModule } from '@app/ui/dataset-create-wizard/dataset-create-wizard.module'; -import { BreadcrumbModule } from '@app/ui/misc/breadcrumb/breadcrumb.module'; +// import { BreadcrumbModule } from '@app/ui/misc/breadcrumb/breadcrumb.module'; import { HelpContentModule } from '@app/ui/misc/help-content/help-content.module'; import { NavigationModule } from '@app/ui/misc/navigation/navigation.module'; import { ReloadHelperComponent } from '@app/ui/misc/reload-helper/reload-helper.component'; @@ -137,7 +137,7 @@ export function InstallationConfigurationFactory(appConfig: ConfigurationService //Ui NotificationModule, NavigationModule, - BreadcrumbModule, + // BreadcrumbModule, HelpContentModule, ReactiveFormsModule, FormsModule, diff --git a/dmp-frontend/src/app/core/common/enum/description-template-type-status.ts b/dmp-frontend/src/app/core/common/enum/description-template-type-status.ts index e41dc95b9..c13e31ddb 100644 --- a/dmp-frontend/src/app/core/common/enum/description-template-type-status.ts +++ b/dmp-frontend/src/app/core/common/enum/description-template-type-status.ts @@ -1,5 +1,4 @@ export enum DescriptionTemplateTypeStatus { - Draft = 0, - Finalized = 1, - Deleted = 99 + Draft = 'Draft', + Finalized = 'Finalized' } \ No newline at end of file diff --git a/dmp-frontend/src/app/core/common/enum/dmp-profile-field-type.ts b/dmp-frontend/src/app/core/common/enum/dmp-blueprint-field-type.ts similarity index 61% rename from dmp-frontend/src/app/core/common/enum/dmp-profile-field-type.ts rename to dmp-frontend/src/app/core/common/enum/dmp-blueprint-field-type.ts index c3c780501..50389f68b 100644 --- a/dmp-frontend/src/app/core/common/enum/dmp-profile-field-type.ts +++ b/dmp-frontend/src/app/core/common/enum/dmp-blueprint-field-type.ts @@ -1,4 +1,4 @@ -export enum DmpProfileFieldDataType { +export enum DmpBlueprintFieldDataType { Date = 0, Number = 1, Text = 2, diff --git a/dmp-frontend/src/app/core/common/enum/dmp-blueprint-status.ts b/dmp-frontend/src/app/core/common/enum/dmp-blueprint-status.ts new file mode 100644 index 000000000..ee173ee82 --- /dev/null +++ b/dmp-frontend/src/app/core/common/enum/dmp-blueprint-status.ts @@ -0,0 +1,4 @@ +export enum DmpBlueprintStatus { + Draft = 'Draft', + Finalized = 'Finalized' +} \ No newline at end of file diff --git a/dmp-frontend/src/app/core/common/enum/dmp-blueprint-type.ts b/dmp-frontend/src/app/core/common/enum/dmp-blueprint-type.ts new file mode 100644 index 000000000..669badd81 --- /dev/null +++ b/dmp-frontend/src/app/core/common/enum/dmp-blueprint-type.ts @@ -0,0 +1,3 @@ +export enum DmpBlueprintType { + Input = 0 +} \ No newline at end of file diff --git a/dmp-frontend/src/app/core/common/enum/dmp-profile-status.ts b/dmp-frontend/src/app/core/common/enum/dmp-profile-status.ts deleted file mode 100644 index d04da4327..000000000 --- a/dmp-frontend/src/app/core/common/enum/dmp-profile-status.ts +++ /dev/null @@ -1,5 +0,0 @@ -export enum DmpProfileStatus { - Draft = 0, - Finalized = 1, - Deleted = 99 -} \ No newline at end of file diff --git a/dmp-frontend/src/app/core/common/enum/dmp-profile-type.ts b/dmp-frontend/src/app/core/common/enum/dmp-profile-type.ts deleted file mode 100644 index 33ba71e7a..000000000 --- a/dmp-frontend/src/app/core/common/enum/dmp-profile-type.ts +++ /dev/null @@ -1,3 +0,0 @@ -export enum DmpProfileType { - Input = 0 -} \ No newline at end of file diff --git a/dmp-frontend/src/app/core/common/enum/is-active.enum.ts b/dmp-frontend/src/app/core/common/enum/is-active.enum.ts new file mode 100644 index 000000000..cdadd23b4 --- /dev/null +++ b/dmp-frontend/src/app/core/common/enum/is-active.enum.ts @@ -0,0 +1,4 @@ +export enum IsActive { + Inactive = 0, + Active = 1 +} diff --git a/dmp-frontend/src/app/core/core-service.module.ts b/dmp-frontend/src/app/core/core-service.module.ts index c485bc969..9e8d69031 100644 --- a/dmp-frontend/src/app/core/core-service.module.ts +++ b/dmp-frontend/src/app/core/core-service.module.ts @@ -1,10 +1,9 @@ -import { HttpClient } from '@angular/common/http'; -import { APP_INITIALIZER, ModuleWithProviders, NgModule, Optional, SkipSelf } from '@angular/core'; +import { ModuleWithProviders, NgModule, Optional, SkipSelf } from '@angular/core'; +import { PrefillingService } from "@app/core/services/prefilling.service"; import { CookieService } from 'ngx-cookie-service'; import { AdminAuthGuard } from './admin-auth-guard.service'; import { AuthGuard } from './auth-guard.service'; import { AuthService } from './services/auth/auth.service'; -import { ConfigurationService } from './services/configuration/configuration.service'; import { ContactSupportService } from './services/contact-support/contact-support.service'; import { CultureService } from './services/culture/culture-service'; import { LanguageInfoService } from './services/culture/language-info-service'; @@ -14,8 +13,10 @@ import { DatasetProfileService } from './services/dataset-profile/dataset-profil import { DatasetWizardService } from './services/dataset-wizard/dataset-wizard.service'; import { DatasetExternalAutocompleteService } from './services/dataset/dataset-external-autocomplete.service'; import { DatasetService } from './services/dataset/dataset.service'; +import { DepositRepositoriesService } from './services/deposit-repositories/deposit-repositories.service'; +import { DescriptionTemplateTypeService } from './services/description-template-type/description-template-type.service'; +import { DmpBlueprintService } from './services/dmp/dmp-blueprint.service'; import { DmpInvitationService } from './services/dmp/dmp-invitation.service'; -import { DmpProfileService } from './services/dmp/dmp-profile.service'; import { DmpService } from './services/dmp/dmp.service'; import { EmailConfirmationService } from './services/email-confirmation/email-confirmation.service'; import { ExternalDataRepositoryService } from './services/external-sources/data-repository/extternal-data-repository.service'; @@ -28,6 +29,7 @@ import { ExternalServiceService } from './services/external-sources/service/exte import { FunderService } from './services/funder/funder.service'; import { GrantFileUploadService } from './services/grant/grant-file-upload.service'; import { GrantService } from './services/grant/grant.service'; +import { BaseHttpV2Service } from './services/http/base-http-v2.service'; import { BaseHttpService } from './services/http/base-http.service'; import { LanguageService } from './services/language/language.service'; import { LockService } from './services/lock/lock.service'; @@ -40,21 +42,19 @@ import { ProjectService } from './services/project/project.service'; import { QuickWizardService } from './services/quick-wizard/quick-wizard.service'; import { SearchBarService } from './services/search-bar/search-bar.service'; import { TimezoneService } from './services/timezone/timezone-service'; +import { UnlinkAccountEmailConfirmationService } from './services/unlink-account-email-confirmation/unlink-account-email-confirmation.service'; import { UserService } from './services/user/user.service'; import { CollectionUtils } from './services/utilities/collection-utils.service'; import { TypeUtils } from './services/utilities/type-utils.service'; import { SpecialAuthGuard } from './special-auth-guard.service'; -import {PrefillingService} from "@app/core/services/prefilling.service"; -import { DepositRepositoriesService } from './services/deposit-repositories/deposit-repositories.service'; -import { UnlinkAccountEmailConfirmationService } from './services/unlink-account-email-confirmation/unlink-account-email-confirmation.service'; -import { DescriptionTemplateTypeService } from './services/description-template-type/description-template-type.service'; -import { BaseHttpV2Service } from './services/http/base-http-v2.service'; //import { KeycloakService } from 'keycloak-angular'; +import { HttpErrorHandlingService } from '@common/modules/errors/error-handling/http-error-handling.service'; +import { FilterService } from '@common/modules/text-filter/filter-service'; import { PrincipalService } from './services/http/principal.service'; -import { InterceptorType } from '@common/http/interceptors/interceptor-type'; -import { BaseHttpParams } from '@common/http/base-http-params'; -import { from } from 'rxjs'; import { SupportiveMaterialService } from './services/supportive-material/supportive-material.service'; +import { UserSettingsHttpService } from './services/user-settings/user-settings-http.service'; +import { UserSettingsService } from './services/user-settings/user-settings.service'; +import { QueryParamsService } from './services/utilities/query-params.service'; // // // This is shared module that provides all the services. Its imported only once on the AppModule. @@ -96,7 +96,7 @@ export class CoreServiceModule { GrantFileUploadService, DmpService, DepositRepositoriesService, - DmpProfileService, + DmpBlueprintService, ExternalSourcesService, ExternalSourcesConfigurationService, DatasetService, @@ -123,7 +123,12 @@ export class CoreServiceModule { UnlinkAccountEmailConfirmationService, LanguageInfoService, PrefillingService, - DescriptionTemplateTypeService + DescriptionTemplateTypeService, + HttpErrorHandlingService, + QueryParamsService, + UserSettingsService, + UserSettingsHttpService, + FilterService ], }; } diff --git a/dmp-frontend/src/app/core/formatting.module.ts b/dmp-frontend/src/app/core/formatting.module.ts index fc082e27b..efa153368 100644 --- a/dmp-frontend/src/app/core/formatting.module.ts +++ b/dmp-frontend/src/app/core/formatting.module.ts @@ -10,6 +10,7 @@ import { DateTimeCultureFormatPipe } from './pipes/date-time-culture-format.pipe import {FieldValuePipe} from "@app/core/pipes/field-value.pipe"; import {ColumnClassPipe} from "@app/core/pipes/column-class.pipe"; import { DatasetInSectioPipe } from './pipes/dataset-in-section.pipe'; +import { PipeService } from '@common/formatting/pipe.service'; // // @@ -27,7 +28,7 @@ import { DatasetInSectioPipe } from './pipes/dataset-in-section.pipe'; JsonParserPipe, FieldValuePipe, ColumnClassPipe, - DatasetInSectioPipe + DatasetInSectioPipe, ], exports: [ NgForLimitPipe, @@ -43,6 +44,7 @@ import { DatasetInSectioPipe } from './pipes/dataset-in-section.pipe'; providers: [ EnumUtils, DatePipe, + PipeService, NgForLimitPipe, TimezoneInfoDisplayPipe, DateFormatPipe, diff --git a/dmp-frontend/src/app/core/model/description-template-type/description-template-type.ts b/dmp-frontend/src/app/core/model/description-template-type/description-template-type.ts index 67af2f190..9e5cd6123 100644 --- a/dmp-frontend/src/app/core/model/description-template-type/description-template-type.ts +++ b/dmp-frontend/src/app/core/model/description-template-type/description-template-type.ts @@ -1,5 +1,12 @@ -export interface DescriptionTemplateType { - id: string; +import { DescriptionTemplateTypeStatus } from "@app/core/common/enum/description-template-type-status"; +import { BaseEntity, BaseEntityPersist } from "@common/base/base-entity.model"; + +export interface DescriptionTemplateType extends BaseEntity { name: string; - status: number; + status: DescriptionTemplateTypeStatus; } + +export interface DescriptionTemplateTypePersist extends BaseEntityPersist { + name: string; + status: DescriptionTemplateTypeStatus; +} \ No newline at end of file diff --git a/dmp-frontend/src/app/core/model/dmp-profile/dmp-associated-profile.ts b/dmp-frontend/src/app/core/model/dmp-blueprint/dmp-associated-profile.ts similarity index 100% rename from dmp-frontend/src/app/core/model/dmp-profile/dmp-associated-profile.ts rename to dmp-frontend/src/app/core/model/dmp-blueprint/dmp-associated-profile.ts diff --git a/dmp-frontend/src/app/core/model/dmp-profile/dmp-profile-external-autocomplete.ts b/dmp-frontend/src/app/core/model/dmp-blueprint/dmp-blueprint-external-autocomplete.ts similarity index 63% rename from dmp-frontend/src/app/core/model/dmp-profile/dmp-profile-external-autocomplete.ts rename to dmp-frontend/src/app/core/model/dmp-blueprint/dmp-blueprint-external-autocomplete.ts index 955ba48bf..de6f53f7a 100644 --- a/dmp-frontend/src/app/core/model/dmp-profile/dmp-profile-external-autocomplete.ts +++ b/dmp-frontend/src/app/core/model/dmp-blueprint/dmp-blueprint-external-autocomplete.ts @@ -1,4 +1,4 @@ -export interface DmpProfileExternalAutoCompleteField { +export interface DmpBlueprintExternalAutoCompleteField { url: string; optionsRoot: string; multiAutoComplete: boolean; diff --git a/dmp-frontend/src/app/core/model/dmp-blueprint/dmp-blueprint-field.ts b/dmp-frontend/src/app/core/model/dmp-blueprint/dmp-blueprint-field.ts new file mode 100644 index 000000000..7ebff3e36 --- /dev/null +++ b/dmp-frontend/src/app/core/model/dmp-blueprint/dmp-blueprint-field.ts @@ -0,0 +1,13 @@ +import { DmpBlueprintFieldDataType } from '../../common/enum/dmp-blueprint-field-type'; +import { DmpBlueprintType } from '../../common/enum/dmp-blueprint-type'; +import { DmpBlueprintExternalAutoCompleteFieldDataEditorModel } from '../../../ui/admin/dmp-blueprint/editor/external-autocomplete/dmp-blueprint-external-autocomplete-field-editor.model'; + +export interface DmpBlueprintField { + id: string; + type: DmpBlueprintType; + dataType: DmpBlueprintFieldDataType; + required: boolean; + label: string; + value: any; + externalAutocomplete?: DmpBlueprintExternalAutoCompleteFieldDataEditorModel; +} diff --git a/dmp-frontend/src/app/core/model/dmp-blueprint/dmp-blueprint-listing.ts b/dmp-frontend/src/app/core/model/dmp-blueprint/dmp-blueprint-listing.ts new file mode 100644 index 000000000..52e0a6484 --- /dev/null +++ b/dmp-frontend/src/app/core/model/dmp-blueprint/dmp-blueprint-listing.ts @@ -0,0 +1,10 @@ +import { DmpBlueprintDefinition } from "../dmp/dmp-blueprint/dmp-blueprint"; + +export interface DmpBlueprintListing { + id: string; + label: string; + definition: DmpBlueprintDefinition; + status: number; + created: Date; + modified: Date; +} diff --git a/dmp-frontend/src/app/core/model/dmp-blueprint/dmp-blueprint.ts b/dmp-frontend/src/app/core/model/dmp-blueprint/dmp-blueprint.ts new file mode 100644 index 000000000..4abf1d439 --- /dev/null +++ b/dmp-frontend/src/app/core/model/dmp-blueprint/dmp-blueprint.ts @@ -0,0 +1,19 @@ +import { DmpBlueprintStatus } from "@app/core/common/enum/dmp-blueprint-status"; +import { BaseEntity, BaseEntityPersist } from "@common/base/base-entity.model"; +import { DmpBlueprintDefinition } from "../dmp/dmp-blueprint/dmp-blueprint"; + + +export interface DmpBlueprint extends BaseEntity { + label: string; + definition: DmpBlueprintDefinition; + status: DmpBlueprintStatus; + description: string; +} + +export interface DmpBlueprintPersist extends BaseEntityPersist { + label: string; + definition: DmpBlueprintDefinition; + status: number; + description: string; +} + diff --git a/dmp-frontend/src/app/core/model/dmp-profile/dmp-profile-field.ts b/dmp-frontend/src/app/core/model/dmp-profile/dmp-profile-field.ts deleted file mode 100644 index 1e9a70317..000000000 --- a/dmp-frontend/src/app/core/model/dmp-profile/dmp-profile-field.ts +++ /dev/null @@ -1,13 +0,0 @@ -import { DmpProfileFieldDataType } from '../../common/enum/dmp-profile-field-type'; -import { DmpProfileType } from '../../common/enum/dmp-profile-type'; -import { DmpProfileExternalAutoCompleteFieldDataEditorModel } from '../../../ui/admin/dmp-profile/editor/external-autocomplete/dmp-profile-external-autocomplete-field-editor.model'; - -export interface DmpProfileField { - id: string; - type: DmpProfileType; - dataType: DmpProfileFieldDataType; - required: boolean; - label: string; - value: any; - externalAutocomplete?: DmpProfileExternalAutoCompleteFieldDataEditorModel; -} diff --git a/dmp-frontend/src/app/core/model/dmp-profile/dmp-profile-listing.ts b/dmp-frontend/src/app/core/model/dmp-profile/dmp-profile-listing.ts deleted file mode 100644 index eecb6a995..000000000 --- a/dmp-frontend/src/app/core/model/dmp-profile/dmp-profile-listing.ts +++ /dev/null @@ -1,10 +0,0 @@ -import { DmpProfileDefinition } from "./dmp-profile"; - -export interface DmpProfileListing { - id: string; - label: string; - definition: DmpProfileDefinition; - status: number; - created: Date; - modified: Date; -} diff --git a/dmp-frontend/src/app/core/model/dmp-profile/dmp-profile.ts b/dmp-frontend/src/app/core/model/dmp-profile/dmp-profile.ts deleted file mode 100644 index baad4115f..000000000 --- a/dmp-frontend/src/app/core/model/dmp-profile/dmp-profile.ts +++ /dev/null @@ -1,16 +0,0 @@ -import { DmpProfileField } from "./dmp-profile-field"; - - -export interface DmpProfile { - id: string; - label: string; - definition: DmpProfileDefinition; - status: number; - created: Date; - modified: Date; - description: string; -} - -export interface DmpProfileDefinition { - fields: DmpProfileField[]; -} diff --git a/dmp-frontend/src/app/core/model/dmp/dmp-blueprint/dmp-blueprint.ts b/dmp-frontend/src/app/core/model/dmp/dmp-blueprint/dmp-blueprint.ts index eda8fd506..ff0220fa6 100644 --- a/dmp-frontend/src/app/core/model/dmp/dmp-blueprint/dmp-blueprint.ts +++ b/dmp-frontend/src/app/core/model/dmp/dmp-blueprint/dmp-blueprint.ts @@ -1,68 +1,72 @@ +import { DmpBlueprintStatus } from "@app/core/common/enum/dmp-blueprint-status"; +import { DmpBlueprintField } from "../../dmp-blueprint/dmp-blueprint-field"; + export interface DmpBlueprint { id: string; label: string; definition: DmpBlueprintDefinition; - status: number; + status: DmpBlueprintStatus; created: Date; modified: Date; description: string; } export interface DmpBlueprintDefinition { - sections: SectionDmpBlueprint[]; + sections: SectionDmpBlueprint[]; + fields: DmpBlueprintField[]; } export interface SectionDmpBlueprint { - id: string; - label: string; - description: string; - ordinal: number; - fields: FieldInSection[]; - hasTemplates: boolean; - descriptionTemplates?: DescriptionTemplatesInSection[]; + id: string; + label: string; + description: string; + ordinal: number; + fields: FieldInSection[]; + hasTemplates: boolean; + descriptionTemplates?: DescriptionTemplatesInSection[]; } export interface FieldInSection { - id: string; - category: FieldCategory; - type: number; - label: string; - placeholder: string; - description: string; - required: boolean; - ordinal: number; + id: string; + category: FieldCategory; + type: number; + label: string; + placeholder: string; + description: string; + required: boolean; + ordinal: number; } export enum FieldCategory { - SYSTEM = 0, - EXTRA = 1 + SYSTEM = 0, + EXTRA = 1 } export enum SystemFieldType { - TEXT = 0, - HTML_TEXT = 1, - RESEARCHERS= 2, - ORGANIZATIONS = 3, - LANGUAGE = 4, - CONTACT = 5, - FUNDER = 6, - GRANT = 7, - PROJECT = 8, - LICENSE = 9, - ACCESS_RIGHTS = 10 + TEXT = 0, + HTML_TEXT = 1, + RESEARCHERS = 2, + ORGANIZATIONS = 3, + LANGUAGE = 4, + CONTACT = 5, + FUNDER = 6, + GRANT = 7, + PROJECT = 8, + LICENSE = 9, + ACCESS_RIGHTS = 10 } export interface DescriptionTemplatesInSection { - id: string; - descriptionTemplateId: string; - label: string; - minMultiplicity: number; - maxMultiplicity: number; + id: string; + descriptionTemplateId: string; + label: string; + minMultiplicity: number; + maxMultiplicity: number; } export enum ExtraFieldType { - TEXT = 0, - RICH_TEXT = 1, - DATE = 2, - NUMBER = 3 + TEXT = 0, + RICH_TEXT = 1, + DATE = 2, + NUMBER = 3 } \ No newline at end of file diff --git a/dmp-frontend/src/app/core/model/dmp/dmp-listing.ts b/dmp-frontend/src/app/core/model/dmp/dmp-listing.ts index 3425e0ce1..65179ce21 100644 --- a/dmp-frontend/src/app/core/model/dmp/dmp-listing.ts +++ b/dmp-frontend/src/app/core/model/dmp/dmp-listing.ts @@ -1,5 +1,5 @@ import { DmpStatus } from "../../common/enum/dmp-status"; -import { DmpAssociatedProfileModel } from '../dmp-profile/dmp-associated-profile'; +import { DmpAssociatedProfileModel } from '../dmp-blueprint/dmp-associated-profile'; export interface DmpListingModel { id: string; diff --git a/dmp-frontend/src/app/core/model/dmp/dmp-overview.ts b/dmp-frontend/src/app/core/model/dmp/dmp-overview.ts index a5171ad61..d8679633e 100644 --- a/dmp-frontend/src/app/core/model/dmp/dmp-overview.ts +++ b/dmp-frontend/src/app/core/model/dmp/dmp-overview.ts @@ -1,6 +1,6 @@ import { OrganizationModel } from "../organisation/organization"; import { UserInfoListingModel } from "../user/user-info-listing"; -import { DmpAssociatedProfileModel } from "../dmp-profile/dmp-associated-profile"; +import { DmpAssociatedProfileModel } from "../dmp-blueprint/dmp-associated-profile"; import { ResearcherModel } from "../researcher/researcher"; import { GrantOverviewModel } from "../grant/grant-overview"; import { DatasetOverviewModel } from "../dataset/dataset-overview"; diff --git a/dmp-frontend/src/app/core/model/dmp/dmp.ts b/dmp-frontend/src/app/core/model/dmp/dmp.ts index a186597c1..9fb11b66e 100644 --- a/dmp-frontend/src/app/core/model/dmp/dmp.ts +++ b/dmp-frontend/src/app/core/model/dmp/dmp.ts @@ -1,22 +1,21 @@ -import { DmpProfileDefinition } from "../dmp-profile/dmp-profile"; -import { OrganizationModel } from "../organisation/organization"; -import { GrantListingModel } from "../grant/grant-listing"; -import { ResearcherModel } from "../researcher/researcher"; -import { UserModel } from "../user/user"; -import { DmpDynamicField } from "./dmp-dynamic-field"; -import { UserInfoListingModel } from "../user/user-info-listing"; -import { ProjectModel } from "../project/project"; -import { FunderModel } from "../funder/funder"; import { DmpStatus } from '@app/core/common/enum/dmp-status'; import { DatasetWizardModel } from '../dataset/dataset-wizard'; +import { FunderModel } from "../funder/funder"; +import { GrantListingModel } from "../grant/grant-listing"; +import { OrganizationModel } from "../organisation/organization"; +import { ProjectModel } from "../project/project"; +import { ResearcherModel } from "../researcher/researcher"; +import { UserModel } from "../user/user"; +import { UserInfoListingModel } from "../user/user-info-listing"; import { DmpDatasetProfile } from "./dmp-dataset-profile/dmp-dataset-profile"; +import { DmpDynamicField } from "./dmp-dynamic-field"; import { DmpExtraField } from "./dmp-extra-field"; export interface DmpModel { id: string; label: string; groupId: String; - profile: DmpProfile; + profile: DmpBlueprint; version: number; status: DmpStatus; lockable: boolean; @@ -40,7 +39,7 @@ export interface DmpModel { } -export interface DmpProfile { +export interface DmpBlueprint { id: string; label: string; } \ No newline at end of file diff --git a/dmp-frontend/src/app/core/model/recent-activity/recent-dmp-activity.model.ts b/dmp-frontend/src/app/core/model/recent-activity/recent-dmp-activity.model.ts index b416e4cb0..77fdf6486 100644 --- a/dmp-frontend/src/app/core/model/recent-activity/recent-dmp-activity.model.ts +++ b/dmp-frontend/src/app/core/model/recent-activity/recent-dmp-activity.model.ts @@ -1,6 +1,6 @@ import { RecentActivityModel } from './recent-activity.model'; import { RecentDatasetModel } from './recent-dataset-activity.model'; -import { DmpAssociatedProfileModel } from '../dmp-profile/dmp-associated-profile'; +import { DmpAssociatedProfileModel } from '../dmp-blueprint/dmp-associated-profile'; import { UserInfoListingModel } from '../user/user-info-listing'; import { DatasetUrlListing } from '../dataset/dataset-url-listing'; diff --git a/dmp-frontend/src/app/core/model/user-settings/user-settings.model.ts b/dmp-frontend/src/app/core/model/user-settings/user-settings.model.ts new file mode 100644 index 000000000..7a789f9ff --- /dev/null +++ b/dmp-frontend/src/app/core/model/user-settings/user-settings.model.ts @@ -0,0 +1,47 @@ +import { UserSettingsType } from '@app/core/services/user-settings/user-settings.service'; +import { Guid } from '@common/types/guid'; + +export interface UserSetting { + id: Guid; + name: string; + type: UserSettingsType; + value: any; + createdAt: Date; + updatedAt: Date; + hash: string; + userId: Guid; + isDefault?: boolean; +} + +export interface UserSettings { + key: string; + settings: UserSetting[]; + defaultSetting: UserSetting; +} + +export interface UserSettingPersist { + id: Guid; + name: string; + key: string; + type: UserSettingsType; + value: string; + hash: string; + isDefault: boolean; +} + +export interface UserSettingsKey { + key: string; +} + +//TODO possible move these +export interface UserSettingsInformation { + key: string; + type: UserSettingsBuilder; +} + +export type UserSettingsBuilder = new () => T; + +export interface UserSettingsLookupBuilder { + update(lookup: T); + apply(lookup: T): T; +} diff --git a/dmp-frontend/src/app/core/query/description-template-type.lookup.ts b/dmp-frontend/src/app/core/query/description-template-type.lookup.ts new file mode 100644 index 000000000..51f263c12 --- /dev/null +++ b/dmp-frontend/src/app/core/query/description-template-type.lookup.ts @@ -0,0 +1,21 @@ +import { Lookup } from "@common/model/lookup"; +import { Guid } from "@common/types/guid"; +import { IsActive } from "../common/enum/is-active.enum"; + +export class DescriptionTemplateTypeLookup extends Lookup implements DescriptionTemplateTypeFilter { + ids: Guid[]; + excludedIds: Guid[]; + like: string; + isActive: IsActive[]; + + constructor() { + super(); + } +} + +export interface DescriptionTemplateTypeFilter { + ids: Guid[]; + excludedIds: Guid[]; + like: string; + isActive: IsActive[]; +} \ No newline at end of file diff --git a/dmp-frontend/src/app/core/query/description-template/description-template-type.lookup.ts b/dmp-frontend/src/app/core/query/description-template/description-template-type.lookup.ts deleted file mode 100644 index 2acefc395..000000000 --- a/dmp-frontend/src/app/core/query/description-template/description-template-type.lookup.ts +++ /dev/null @@ -1,14 +0,0 @@ -import { Status } from "@app/core/common/enum/status"; -import { Lookup } from "@common/model/lookup"; -import { Guid } from "@common/types/guid"; - -export class DescriptionTemplateTypeLookup extends Lookup { - ids: Guid[]; - excludedIds: Guid[]; - like: string; - isActive: Status[]; - - constructor() { - super(); - } -} \ No newline at end of file diff --git a/dmp-frontend/src/app/core/query/dmp-blueprint.lookup.ts b/dmp-frontend/src/app/core/query/dmp-blueprint.lookup.ts new file mode 100644 index 000000000..e4286e349 --- /dev/null +++ b/dmp-frontend/src/app/core/query/dmp-blueprint.lookup.ts @@ -0,0 +1,23 @@ +import { Lookup } from '@common/model/lookup'; +import { Guid } from '@common/types/guid'; +import { IsActive } from '../common/enum/is-active.enum'; + +export class DmpBlueprintLookup extends Lookup implements DmpBlueprintFilter { + ids: Guid[]; + excludedIds: Guid[]; + like: string; + isActive: IsActive[]; + typeIds: Guid[]; + + constructor() { + super(); + } +} + +export interface DmpBlueprintFilter { + ids: Guid[]; + excludedIds: Guid[]; + like: string; + isActive: IsActive[]; + typeIds: Guid[]; +} diff --git a/dmp-frontend/src/app/core/query/dmp/dmp-blueprint-criteria.ts b/dmp-frontend/src/app/core/query/dmp/dmp-blueprint-criteria.ts index 0d460ba89..f3e1a430a 100644 --- a/dmp-frontend/src/app/core/query/dmp/dmp-blueprint-criteria.ts +++ b/dmp-frontend/src/app/core/query/dmp/dmp-blueprint-criteria.ts @@ -1,5 +1,6 @@ +import { DmpBlueprintStatus } from "@app/core/common/enum/dmp-blueprint-status"; import { BaseCriteria } from "../base-criteria"; export class DmpBlueprintCriteria extends BaseCriteria { - public status?: number; + public status?: DmpBlueprintStatus; } \ No newline at end of file diff --git a/dmp-frontend/src/app/core/query/dmp/dmp-profile-criteria.ts b/dmp-frontend/src/app/core/query/dmp/dmp-profile-criteria.ts index 9855ca785..71f660eae 100644 --- a/dmp-frontend/src/app/core/query/dmp/dmp-profile-criteria.ts +++ b/dmp-frontend/src/app/core/query/dmp/dmp-profile-criteria.ts @@ -1,5 +1,5 @@ import { BaseCriteria } from "../base-criteria"; -export class DmpProfileCriteria extends BaseCriteria { +export class DmpBlueprintCriteria extends BaseCriteria { } diff --git a/dmp-frontend/src/app/core/query/dmp/dmp-profile-external-autocomplete-criteria.ts b/dmp-frontend/src/app/core/query/dmp/dmp-profile-external-autocomplete-criteria.ts index 16a4ba5b8..1e57f9192 100644 --- a/dmp-frontend/src/app/core/query/dmp/dmp-profile-external-autocomplete-criteria.ts +++ b/dmp-frontend/src/app/core/query/dmp/dmp-profile-external-autocomplete-criteria.ts @@ -1,6 +1,6 @@ import { BaseCriteria } from "../base-criteria"; -export class DmpProfileExternalAutocompleteCriteria extends BaseCriteria { +export class DmpBlueprintExternalAutocompleteCriteria extends BaseCriteria { public profileID: String; public fieldID: String; } diff --git a/dmp-frontend/src/app/core/services/auth/auth.service.ts b/dmp-frontend/src/app/core/services/auth/auth.service.ts index a69d35d4d..be4e7ebfc 100644 --- a/dmp-frontend/src/app/core/services/auth/auth.service.ts +++ b/dmp-frontend/src/app/core/services/auth/auth.service.ts @@ -33,6 +33,7 @@ export enum LoginStatus { @Injectable() export class AuthService extends BaseService { + public permissionEnum = AppPermission; public authenticationStateSubject: Subject; private accessToken: string; private appAccount: AppAccount; diff --git a/dmp-frontend/src/app/core/services/configuration/configuration.service.ts b/dmp-frontend/src/app/core/services/configuration/configuration.service.ts index 27e951622..c0913f82d 100644 --- a/dmp-frontend/src/app/core/services/configuration/configuration.service.ts +++ b/dmp-frontend/src/app/core/services/configuration/configuration.service.ts @@ -36,6 +36,11 @@ export class ConfigurationService extends BaseComponent { return this._defaultCulture; } + private _defaultTimezone: string; + get defaultTimezone(): string { + return this._defaultTimezone || 'UTC'; + } + private _defaultLanguage: string; get defaultLanguage(): string { return this._defaultLanguage; @@ -102,6 +107,11 @@ export class ConfigurationService extends BaseComponent { return this._keycloak; } + private _userSettingsVersion: string; + get userSettingsVersion(): string { + return this._userSettingsVersion; + } + public loadConfiguration(): Promise { return new Promise((r, e) => { @@ -143,6 +153,7 @@ export class ConfigurationService extends BaseComponent { this._app = config.App; this._helpService = HelpService.parseValue(config.HelpService); this._defaultCulture = config.defaultCulture; + this._defaultTimezone = config.defaultTimezone; this._defaultLanguage = config.defaultLanguage; this._availableLanguages = config.availableLanguages; this._keycloak = KeycloakConfiguration.parseValue(config.keycloak); @@ -158,6 +169,7 @@ export class ConfigurationService extends BaseComponent { this._matomoSiteId = config.matomo.siteId; } this._maxFileSizeInMB = config.maxFileSizeInMB; + this._userSettingsVersion = config.userSettingsVersion; } } diff --git a/dmp-frontend/src/app/core/services/description-template-type/description-template-type.service.ts b/dmp-frontend/src/app/core/services/description-template-type/description-template-type.service.ts index 6ca3b1ab4..6f95d24cf 100644 --- a/dmp-frontend/src/app/core/services/description-template-type/description-template-type.service.ts +++ b/dmp-frontend/src/app/core/services/description-template-type/description-template-type.service.ts @@ -1,42 +1,49 @@ -import { HttpHeaders } from '@angular/common/http'; import { Injectable } from '@angular/core'; -import { ConfigurationService } from '../configuration/configuration.service'; -import { Observable } from 'rxjs'; -import { DescriptionTemplateType } from '@app/core/model/description-template-type/description-template-type'; +import { DescriptionTemplateType, DescriptionTemplateTypePersist } from '@app/core/model/description-template-type/description-template-type'; +import { DescriptionTemplateTypeLookup } from '@app/core/query/description-template-type.lookup'; import { QueryResult } from '@common/model/query-result'; -import { DescriptionTemplateTypeLookup } from '@app/core/query/description-template/description-template-type.lookup'; +import { Guid } from '@common/types/guid'; +import { Observable, throwError } from 'rxjs'; +import { catchError } from 'rxjs/operators'; +import { ConfigurationService } from '../configuration/configuration.service'; import { BaseHttpV2Service } from '../http/base-http-v2.service'; @Injectable() export class DescriptionTemplateTypeService { - private get apiBase(): string { return `${this.configurationService.server}description-template-type`; } - private headers = new HttpHeaders(); - - constructor(private http: BaseHttpV2Service, private configurationService: ConfigurationService) {} + constructor(private http: BaseHttpV2Service, private installationConfiguration: ConfigurationService) { } - query(lookup: DescriptionTemplateTypeLookup): Observable> { - const url = `${this.apiBase}/query`; - return this.http.post>(url, lookup, { headers: this.headers }); - } + private get apiBase(): string { return `${this.installationConfiguration.server}description-template-type`; } - get(id: string): Observable> { - const url = `${this.apiBase}/${id}`; - return this.http.get>(url , { headers: this.headers }); - } + query(q: DescriptionTemplateTypeLookup): Observable> { + const url = `${this.apiBase}/query`; + return this.http + .post>(url, q).pipe( + catchError((error: any) => throwError(error))); + } - persist(payload: DescriptionTemplateType): Observable> { - const url = `${this.apiBase}/persist`; - return this.http.post>(url, payload, { headers: this.headers }); - } + getSingle(id: Guid, reqFields: string[] = []): Observable { + const url = `${this.apiBase}/${id}`; + const options = { params: { f: reqFields } }; - update(payload: DescriptionTemplateType): Observable> { - const url = `${this.apiBase}/update`; - return this.http.post>(url, payload, { headers: this.headers }); - } + return this.http + .get(url, options).pipe( + catchError((error: any) => throwError(error))); + } - delete(id: string): Observable { - const url = `${this.apiBase}/delete/${id}`; - return this.http.delete(url, { headers: this.headers }); - } + persist(item: DescriptionTemplateTypePersist): Observable { + const url = `${this.apiBase}/persist`; + + return this.http + .post(url, item).pipe( + catchError((error: any) => throwError(error))); + } + + delete(id: Guid): Observable { + const url = `${this.apiBase}/${id}`; + + return this.http + .delete(url).pipe( + catchError((error: any) => throwError(error))); + } } diff --git a/dmp-frontend/src/app/core/services/dmp/dmp-blueprint.service.ts b/dmp-frontend/src/app/core/services/dmp/dmp-blueprint.service.ts new file mode 100644 index 000000000..61190db51 --- /dev/null +++ b/dmp-frontend/src/app/core/services/dmp/dmp-blueprint.service.ts @@ -0,0 +1,107 @@ +import { HttpClient, HttpHeaders, HttpResponse } from '@angular/common/http'; +import { Injectable } from '@angular/core'; +import { DataTableData } from '@app/core/model/data-table/data-table-data'; +import { DataTableRequest } from '@app/core/model/data-table/data-table-request'; +import { DatasetListingModel } from '@app/core/model/dataset/dataset-listing'; +import { DmpBlueprint, DmpBlueprintPersist } from '@app/core/model/dmp-blueprint/dmp-blueprint'; +import { DmpBlueprintListing } from '@app/core/model/dmp/dmp-blueprint/dmp-blueprint-listing'; +import { DmpBlueprintLookup } from '@app/core/query/dmp-blueprint.lookup'; +import { DmpBlueprintCriteria } from '@app/core/query/dmp/dmp-blueprint-criteria'; +import { DmpBlueprintExternalAutocompleteCriteria } from '@app/core/query/dmp/dmp-profile-external-autocomplete-criteria'; +import { RequestItem } from '@app/core/query/request-item'; +import { BaseHttpParams } from '@common/http/base-http-params'; +import { InterceptorType } from '@common/http/interceptors/interceptor-type'; +import { QueryResult } from '@common/model/query-result'; +import { Observable, throwError } from 'rxjs'; +import { catchError } from 'rxjs/operators'; +import { ConfigurationService } from '../configuration/configuration.service'; +import { BaseHttpV2Service } from '../http/base-http-v2.service'; +import { Guid } from '@common/types/guid'; + +@Injectable() +export class DmpBlueprintService { + + private actionUrl: string; + private headers = new HttpHeaders(); + + constructor(private http: BaseHttpV2Service, private httpClient: HttpClient, private configurationService: ConfigurationService) { + this.actionUrl = configurationService.server + 'dmpprofile/'; + } + + private get apiBase(): string { return `${this.configurationService.server}dmpprofile`; } + + query(q: DmpBlueprintLookup): Observable> { + const url = `${this.apiBase}/query`; + return this.http.post>(url, q).pipe(catchError((error: any) => throwError(error))); + } + + getSingle(id: Guid, reqFields: string[] = []): Observable { + const url = `${this.apiBase}/${id}`; + const options = { params: { f: reqFields } }; + + return this.http + .get(url, options).pipe( + catchError((error: any) => throwError(error))); + } + + persist(item: DmpBlueprintPersist): Observable { + const url = `${this.apiBase}/persist`; + + return this.http + .post(url, item).pipe( + catchError((error: any) => throwError(error))); + } + + delete(id: Guid): Observable { + const url = `${this.apiBase}/${id}`; + + return this.http + .delete(url).pipe( + catchError((error: any) => throwError(error))); + } + + + + getPaged(dataTableRequest: DataTableRequest): Observable> { + return this.http.post>(this.actionUrl + 'getPaged', dataTableRequest, { headers: this.headers }); + } + + getPagedBlueprint(dataTableRequest: DataTableRequest): Observable> { + return this.http.post>(this.actionUrl + 'getPagedBlueprint', dataTableRequest, { headers: this.headers }); + } + + getSingleBlueprint(id: String): Observable { + return this.http.get(this.actionUrl + 'getSingleBlueprint/' + id, { headers: this.headers }); + } + + createDmp(dataManagementPlanModel: DmpBlueprint): Observable { + return this.http.post(this.actionUrl, dataManagementPlanModel, { headers: this.headers }); + } + + createBlueprint(dmpBlueprint: DmpBlueprint): Observable { + return this.http.post(this.actionUrl + 'blueprint', dmpBlueprint, { headers: this.headers }); + } + + public downloadXML(id: string): Observable> { + let headerXml: HttpHeaders = this.headers.set('Content-Type', 'application/xml') + return this.httpClient.get(this.actionUrl + 'getXml/' + id, { responseType: 'blob', observe: 'response', headers: headerXml }); + } + + uploadFile(file: FileList, labelSent: string): Observable> { + const params = new BaseHttpParams(); + params.interceptorContext = { + excludedInterceptors: [InterceptorType.JSONContentType] + }; + const formData = new FormData(); + formData.append('file', file[0], labelSent); + return this.http.post(this.actionUrl + "upload", formData, { params: params }); + } + + clone(id: string): Observable { + return this.http.post(this.actionUrl + 'clone/' + id, { headers: this.headers }); + } + + externalAutocomplete(lookUpItem: RequestItem): Observable { + return this.httpClient.post(this.actionUrl + 'search/autocomplete', lookUpItem); + } +} diff --git a/dmp-frontend/src/app/core/services/dmp/dmp-profile.service.ts b/dmp-frontend/src/app/core/services/dmp/dmp-profile.service.ts deleted file mode 100644 index de242c230..000000000 --- a/dmp-frontend/src/app/core/services/dmp/dmp-profile.service.ts +++ /dev/null @@ -1,81 +0,0 @@ -import { HttpClient, HttpHeaders, HttpResponse } from '@angular/common/http'; -import { Injectable } from '@angular/core'; -import { Observable } from 'rxjs'; -import { environment } from '../../../../environments/environment'; -import { DataTableRequest } from '../../model/data-table/data-table-request'; -import { DmpProfile } from '../../model/dmp-profile/dmp-profile'; -import { BaseHttpService } from '../http/base-http.service'; -import { DmpProfileListing } from '../../model/dmp-profile/dmp-profile-listing'; -import { RequestItem } from '../../query/request-item'; -import { DataTableData } from '../../model/data-table/data-table-data'; -import { DmpProfileCriteria } from '../../query/dmp/dmp-profile-criteria'; -import { DatasetListingModel } from '../../model/dataset/dataset-listing'; -import { BaseHttpParams } from '../../../../common/http/base-http-params'; -import { InterceptorType } from '../../../../common/http/interceptors/interceptor-type'; -import { DmpProfileExternalAutocompleteCriteria } from '../../query/dmp/dmp-profile-external-autocomplete-criteria'; -import { ConfigurationService } from '../configuration/configuration.service'; -import { DmpBlueprintCriteria } from '@app/core/query/dmp/dmp-blueprint-criteria'; -import { DmpBlueprintListing } from '@app/core/model/dmp/dmp-blueprint/dmp-blueprint-listing'; -import { DmpBlueprint } from '@app/core/model/dmp/dmp-blueprint/dmp-blueprint'; - -@Injectable() -export class DmpProfileService { - - private actionUrl: string; - private headers = new HttpHeaders(); - - constructor(private http: BaseHttpService, private httpClient: HttpClient, private configurationService: ConfigurationService) { - this.actionUrl = configurationService.server + 'dmpprofile/'; - } - - getPaged(dataTableRequest: DataTableRequest): Observable> { - return this.http.post>(this.actionUrl + 'getPaged', dataTableRequest, { headers: this.headers }); - } - - getPagedBlueprint(dataTableRequest: DataTableRequest): Observable> { - return this.http.post>(this.actionUrl + 'getPagedBlueprint', dataTableRequest, { headers: this.headers }); - } - - getSingle(id: String): Observable { - return this.http.get(this.actionUrl + 'getSingle/' + id, { headers: this.headers }); - } - - getSingleBlueprint(id: String): Observable { - return this.http.get(this.actionUrl + 'getSingleBlueprint/' + id, { headers: this.headers }); - } - - createDmp(dataManagementPlanModel: DmpProfile): Observable { - return this.http.post(this.actionUrl, dataManagementPlanModel, { headers: this.headers }); - } - - createBlueprint(dmpBlueprint: DmpBlueprint): Observable { - return this.http.post(this.actionUrl + 'blueprint', dmpBlueprint, { headers: this.headers }); - } - - public downloadXML(id: string): Observable> { - let headerXml: HttpHeaders = this.headers.set('Content-Type', 'application/xml') - return this.httpClient.get(this.actionUrl + 'getXml/' + id, { responseType: 'blob', observe: 'response', headers: headerXml }); - } - - uploadFile(file: FileList, labelSent: string): Observable> { - const params = new BaseHttpParams(); - params.interceptorContext = { - excludedInterceptors: [InterceptorType.JSONContentType] - }; - const formData = new FormData(); - formData.append('file', file[0], labelSent); - return this.http.post(this.actionUrl + "upload", formData, { params: params }); - } - - clone(id: string): Observable { - return this.http.post(this.actionUrl + 'clone/' + id, { headers: this.headers }); - } - - delete(id: string): Observable { - return this.http.delete(this.actionUrl + id, { headers: this.headers }); - } - - externalAutocomplete(lookUpItem: RequestItem): Observable { - return this.httpClient.post(this.actionUrl + 'search/autocomplete', lookUpItem); - } -} diff --git a/dmp-frontend/src/app/core/services/dmp/dmp.service.ts b/dmp-frontend/src/app/core/services/dmp/dmp.service.ts index c85650c00..0c75c0738 100644 --- a/dmp-frontend/src/app/core/services/dmp/dmp.service.ts +++ b/dmp-frontend/src/app/core/services/dmp/dmp.service.ts @@ -82,7 +82,7 @@ export class DmpService { return this.http.delete(this.actionUrl + 'inactivate/' + id, { headers: this.headers }); } - searchDMPProfiles(dataSetProfileRequest: RequestItem): Observable { + searchDmpBlueprints(dataSetProfileRequest: RequestItem): Observable { return this.http.post(this.actionUrl + 'datasetprofiles/get', dataSetProfileRequest, { headers: this.headers }); } @@ -137,7 +137,7 @@ export class DmpService { return this.httpClient.get(this.actionUrl + 'rda/' + id, { responseType: 'blob', observe: 'response' }); } - public uploadXml(fileList: FileList, dmpTitle: string, dmpProfiles: any[]): Observable { + public uploadXml(fileList: FileList, dmpTitle: string, dmpBlueprints: any[]): Observable { const formData: FormData = new FormData(); if (fileList instanceof FileList) { for (let i = 0; i < fileList.length; i++) { @@ -148,8 +148,8 @@ export class DmpService { } else { formData.append('file', fileList, dmpTitle); } - for (let j = 0; j < dmpProfiles.length; j++) { - formData.append('profiles', dmpProfiles[j].id); + for (let j = 0; j < dmpBlueprints.length; j++) { + formData.append('profiles', dmpBlueprints[j].id); } const params = new BaseHttpParams(); params.interceptorContext = { diff --git a/dmp-frontend/src/app/core/services/external-sources/external-sources.service.ts b/dmp-frontend/src/app/core/services/external-sources/external-sources.service.ts index 7aa2644fd..6a28bed28 100644 --- a/dmp-frontend/src/app/core/services/external-sources/external-sources.service.ts +++ b/dmp-frontend/src/app/core/services/external-sources/external-sources.service.ts @@ -91,7 +91,7 @@ export class ExternalSourcesService { } // TODO: currently not used. - public searchDMPProfiles(like: string): Observable { + public searchDmpBlueprints(like: string): Observable { return this.http.get(this.actionUrl + 'datasetprofiles/get' + '?query=' + like, { headers: this.headers }); } diff --git a/dmp-frontend/src/app/core/services/timezone/timezone-service.ts b/dmp-frontend/src/app/core/services/timezone/timezone-service.ts index 095e144b6..c4ae63ac0 100644 --- a/dmp-frontend/src/app/core/services/timezone/timezone-service.ts +++ b/dmp-frontend/src/app/core/services/timezone/timezone-service.ts @@ -35,4 +35,61 @@ export class TimezoneService { getCurrentTimezone(): string { return this.currentTimezone; } + + public buildDateTime(params: { + time: string, + date: moment.Moment + }): moment.Moment { + + const { time, date } = params; + + if (!time || !date) { + return null; + } + + const momentTime = moment.duration(time); + const momentDate = moment(date.toString()); + + const toReturn = moment.utc({ + year: momentDate.year(), + month: momentDate.month(), + date: momentDate.date(), + hour: momentTime.hours(), + minute: momentTime.minutes() + }) + + return toReturn.tz(this.getCurrentTimezone(), true); + } + + + public splitDateTime(params: { + dateTime: moment.Moment, + }): { date: moment.Moment, time: string } | null { + + const { dateTime } = params + + if (!dateTime) { + return null; + } + + const dateTimeMoment = moment(dateTime.toString()).tz(this.getCurrentTimezone()); + + const date = + moment.utc({ + year: dateTimeMoment.year(), + month: dateTimeMoment.month(), + date: dateTimeMoment.date(), + }); + + const hours = dateTimeMoment.hour(); + const minutes = dateTimeMoment.minute(); + + const hoursString = hours > 10 ? hours.toString() : `0${hours}` + const minutesString = hours > 10 ? minutes.toString() : `0${minutes}` + + return { + date, + time: `${hoursString}:${minutesString}:00` + }; + } } diff --git a/dmp-frontend/src/app/core/services/user-settings/user-settings-http.service.ts b/dmp-frontend/src/app/core/services/user-settings/user-settings-http.service.ts new file mode 100644 index 000000000..5d161b6fa --- /dev/null +++ b/dmp-frontend/src/app/core/services/user-settings/user-settings-http.service.ts @@ -0,0 +1,45 @@ +import { Injectable } from '@angular/core'; +import { Guid } from '@common/types/guid'; +import { Observable } from 'rxjs'; +import { UserSettingPersist, UserSettings } from '@app/core/model/user-settings/user-settings.model'; +import { BaseHttpV2Service } from '../http/base-http-v2.service'; +import { ConfigurationService } from '../configuration/configuration.service'; + +@Injectable() +export class UserSettingsHttpService { + constructor( + private installationConfiguration: ConfigurationService, + private http: BaseHttpV2Service) { } + + private get apiBase(): string { return `${this.installationConfiguration.server}user-settings`; } + + getSingle(key: string): Observable { + const url = `${this.apiBase}/${key}`; + + return this.http.get(url); + } + + persist(item: UserSettingPersist): Observable { + const url = `${this.apiBase}/persist`; + + return this.http.post(url, item); + } + + persistAll(items: UserSettingPersist[]): Observable { + const url = `${this.apiBase}/persist-all-default`; + + return this.http.post(url, items); + } + + delete(id: Guid): Observable { + const url = `${this.apiBase}/${id}`; + return this.http + .delete(url); + } + + share(item: UserSettingPersist, targetId: Guid): Observable{ + const url = `${this.apiBase}/share/${targetId}`; + + return this.http.post(url, item); + } +} diff --git a/dmp-frontend/src/app/core/services/user-settings/user-settings.service.ts b/dmp-frontend/src/app/core/services/user-settings/user-settings.service.ts new file mode 100644 index 000000000..9e34f7ac9 --- /dev/null +++ b/dmp-frontend/src/app/core/services/user-settings/user-settings.service.ts @@ -0,0 +1,332 @@ +import { Injectable } from '@angular/core'; +import { UserSettingPersist, UserSettingsInformation, UserSettings as UserSettingsObject } from '@app/core/model/user-settings/user-settings.model'; +import { BaseService } from '@common/base/base.service'; +import { Guid } from '@common/types/guid'; +import * as moment from 'moment'; +import { Moment } from 'moment'; +import { Observable, Subject, of as observableOf } from 'rxjs'; +import { map, takeUntil } from 'rxjs/operators'; +import { AuthService, LoginStatus } from '../auth/auth.service'; +import { ConfigurationService } from '../configuration/configuration.service'; +import { UserSettingsHttpService } from './user-settings-http.service'; + +export enum UserSettingsType { + Setting = 0, + Config = 1 +} + +@Injectable() +export class UserSettingsService extends BaseService { + static CACHE_SETTINGS_LIFETIME = 7200; // (value is in seconds) 2 hours + + public userSettingUpdated: Subject; + private userSettingsMap: Map = new Map(); + private userSettingsLastAccessMap: Map = new Map(); + + constructor( + private userSettingsHttpService: UserSettingsHttpService, + private authService: AuthService, + private installationConfigurationService: ConfigurationService + ) { + super(); + this.userSettingUpdated = new Subject(); + + this.authService.getAuthenticationStateObservable().pipe(takeUntil(this._destroyed)).subscribe(authenticationState => { + if (authenticationState.loginStatus === LoginStatus.LoggedOut) { + localStorage.clear(); + this.userSettingsMap = new Map(); + this.userSettingsLastAccessMap = new Map(); + } + }); + } + + public getUserSettingUpdatedObservable(): Observable { + return this.userSettingUpdated.asObservable(); + } + + get(userSettingsInformation: UserSettingsInformation): Observable> { + if (this.userSettingsLastAccessMap.has(userSettingsInformation.key)) { + const lastAccess = this.userSettingsLastAccessMap.get(userSettingsInformation.key); + const difference = moment.utc().diff(lastAccess, 'seconds'); + + if (difference > UserSettingsService.CACHE_SETTINGS_LIFETIME) { + this.clearSetting(userSettingsInformation.key); + } + } + + this.userSettingsLastAccessMap.set(userSettingsInformation.key, moment.utc()); + + if (this.userSettingsMap.has(userSettingsInformation.key)) { return observableOf(this.userSettingsMap.get(userSettingsInformation.key)); } + + return this.loadUserSettings(userSettingsInformation); + } + + set(setting: UserSetting, isDefault: boolean = false, userSettingsInformation: UserSettingsInformation = null) { + const userSetting = this.buildUserSetting(setting, userSettingsInformation.key, isDefault); + let userSettings: UserSettings = this.buildUserSettings(userSetting, userSettingsInformation.key); + + if (this.userSettingsMap.has(userSettingsInformation.key)) { + userSettings = this.userSettingsMap.get(userSettingsInformation.key); + if (userSettings == null) { userSettings = this.buildUserSettings(userSetting, userSettingsInformation.key); } + const itemIndex = userSettings.settings.findIndex(item => item.id === userSetting.id); + if (itemIndex < 0) { + userSettings.settings.push(userSetting); + } else { + userSettings.settings[itemIndex] = userSetting; + } + if (isDefault) { + userSettings.defaultSetting = userSetting; + } + } else { + userSetting.isDefault = isDefault; + if (isDefault) { userSettings.defaultSetting = userSetting; } + } + + userSettings.settings.forEach((element) => { + if (!(element.id === userSettings.defaultSetting.id)) { + element.isDefault = false; + } + }); + + this.persistUserSettings(userSettingsInformation.key, userSettings, userSettingsInformation, true); + this.userSettingsLastAccessMap.set(userSettingsInformation.key, moment.utc()); + } + + remove(id: Guid, userSettingsInformation: UserSettingsInformation = null) { + this.deleteFromWebServer(id, userSettingsInformation); + } + + share(userSettings: UserSetting, targetId: Guid, newName: string): Observable { + const userSettingsToPersist: UserSettingPersist = { + id: null, + key: userSettings.key, + isDefault: false, + name: newName, + type: userSettings.type, + value: JSON.stringify(userSettings.value), + hash: null + }; + return this.userSettingsHttpService.share(userSettingsToPersist, targetId); + } + + private deleteFromWebServer(id: Guid, userSettingsInformation: UserSettingsInformation) { + this.userSettingsHttpService.delete(id).pipe(takeUntil(this._destroyed)).subscribe(item => { + const result: UserSettings = (item ? this.toTypedUserSettings(item as UserSettingsObject) : null); + this.persistUserSettings(userSettingsInformation.key, result, userSettingsInformation, false); + this.userSettingUpdated.next(userSettingsInformation.key); + }); + } + + private buildUserSettings(setting: UserSetting, key: string): UserSettings { + const userSettings: UserSettings = { + key: key, + settings: [setting], + defaultSetting: setting + }; + return userSettings; + } + + private buildUserSetting(setting: UserSetting, key: string, isDefault: boolean): UserSetting { + const userSettings: UserSetting = { + id: setting.id, + key: key, + name: setting.name, + value: setting.value, + type: UserSettingsType.Setting, + isDefault: isDefault, + hash: setting.hash + }; + return userSettings; + } + + private loadUserSettings(userSettingsInformation: UserSettingsInformation): Observable> { + const localStorageItem = this.loadFromLocalStorage(userSettingsInformation.key); + if (localStorageItem) { + const jsonLocalStorageItem = JSON.parse(localStorageItem); + if (jsonLocalStorageItem) { return observableOf((jsonLocalStorageItem as UserSettings)); } + } + + return this.userSettingsHttpService.getSingle(userSettingsInformation.key).pipe( + // catchError(() => { + // const result: UserSettings = this.defaultValue(userSettingsInformation); + // this.persistUserSettings(userSettingsInformation.key, result, userSettingsInformation, false); + // return observableOf(result); + // }), + map(x => { + const result: UserSettings = (x ? this.toTypedUserSettings(x as UserSettingsObject) : null); + this.persistUserSettings(userSettingsInformation.key, result, userSettingsInformation, false); + return result; + })); + } + + private persistUserSettings(key: string, userSettings: UserSettings, userSettingsInformation: UserSettingsInformation, pushChangeToServer: boolean = true) { + this.userSettingsMap.set(key, userSettings); + this.storeToLocalStorage(key, userSettings); + + if (pushChangeToServer) { + this.persistSettingsChanges(key, userSettings, userSettingsInformation); + } + } + + private persistSettingsChanges(key: string, userSettings: UserSettings, userSettingsInformation: UserSettingsInformation, updateLocalAfterPush: boolean = true) { + const changesToPush: UserSettingPersist[] = []; + const userSettingsPersist = this.prepareSettingsToPushToWebServer(userSettings); + userSettingsPersist.forEach(element => { + changesToPush.push(element); + }); + this.pushToWebServer(changesToPush, userSettingsInformation, updateLocalAfterPush); + } + + private buildPersistModel(element: any): UserSettingPersist { + const userSettingsToPersist: UserSettingPersist = { + id: element.id, + key: element.key, + isDefault: element.isDefault, + name: element.name, + type: element.type, + value: JSON.stringify(element.value), + hash: element.hash + }; + + return userSettingsToPersist; + } + + private prepareSettingsToPushToWebServer(userSettings: UserSettings): UserSettingPersist[] { + + const userSettingsArray: UserSettingPersist[] = []; + if (userSettings && userSettings.settings && userSettings.settings.length !== 0) { + userSettings.settings.forEach(element => { + userSettingsArray.push(this.buildPersistModel(element)); + }); + } + return userSettingsArray; + } + + private toTypedUserSettings(userSettings: UserSettingsObject): UserSettings { + const settingsArray: UserSetting[] = []; + if (userSettings && userSettings.settings && userSettings.settings.length !== 0) { + userSettings.settings.forEach(element => { + const settingElement: UserSetting = { + id: element.id, + key: userSettings.key, + name: element.name, + value: JSON.parse(element.value), + userId: element.userId, + updatedAt: element.updatedAt, + createdAt: element.createdAt, + hash: element.hash, + type: element.type, + isDefault: element.isDefault + }; + settingsArray.push(settingElement); + }); + } + let defaultSetting: UserSetting = null; + if (userSettings.defaultSetting) { + const defaultSettingValue = userSettings.defaultSetting; + defaultSetting = { + id: defaultSettingValue.id, + key: userSettings.key, + name: defaultSettingValue.name, + value: userSettings.defaultSetting ? JSON.parse(defaultSettingValue.value) : defaultSettingValue.value, + userId: defaultSettingValue.userId, + updatedAt: defaultSettingValue.updatedAt, + createdAt: defaultSettingValue.createdAt, + hash: defaultSettingValue.hash, + type: defaultSettingValue.type, + isDefault: defaultSettingValue.isDefault + }; + } + const result: UserSettings = { + key: userSettings.key, + settings: settingsArray, + defaultSetting: defaultSetting + }; + return result; + } + + private pushToWebServer(userSettingsToPersist: UserSettingPersist[], userSettingsInformation: UserSettingsInformation, updateLocalAfterPush: boolean) { + if (!userSettingsToPersist || userSettingsToPersist.length === 0) { return; } + this.userSettingsHttpService.persistAll(userSettingsToPersist).pipe(takeUntil(this._destroyed)).subscribe(items => { + if (updateLocalAfterPush) { + const result: UserSettings[] = items ? items.map(x => this.toTypedUserSettings(x as UserSettingsObject)) : []; + result.forEach(item => { + if (item.defaultSetting != null) { + this.userSettingsMap.set(item.key, item); + this.storeToLocalStorage(item.key, item); + } else { + this.clearSetting(item.key); + } + this.userSettingUpdated.next(item.key); + }); + } + }); + } + + private clearSetting(key: string) { + this.userSettingsMap.delete(key); + this.userSettingsLastAccessMap.delete(key); + this.deleteFromLocalStorage(key); + } + + private loadFromLocalStorage(key: string) { + return localStorage.getItem(this.generateLocalStorageKey(key)); + } + + private storeToLocalStorage(key: string, value: any) { + return localStorage.setItem(this.generateLocalStorageKey(key), JSON.stringify(value)); + } + + private deleteFromLocalStorage(key: string) { + return localStorage.removeItem(this.generateLocalStorageKey(key)); + } + + private generateLocalStorageKey(key: string): string { + return `${this.getUserSettingsVersion()}_${this.getUserId()}_${key}`; + } + + // private defaultValue(userSettingsInformation: UserSettingsInformation): UserSettings { + // const defaultSetting: UserSetting = { + // id: null, + // name: null, + // userId: this.getUserId(), + // key: userSettingsInformation.key, + // type: UserSettingsType.Config, + // isDefault: true, + // value: new userSettingsInformation.type() + // }; + // const userSettings: UserSettings = { + // defaultSetting: defaultSetting, + // key: userSettingsInformation.key, + // settings: [defaultSetting] + // }; + // return userSettings; + // } + + private getUserId(): Guid { + return this.authService.userId(); + } + + private getUserSettingsVersion(): string { + return this.installationConfigurationService.userSettingsVersion; + } +} + +export interface UserSettings { + key: string; + settings: UserSetting[]; + defaultSetting: UserSetting; +} + +export interface UserSetting { + id: Guid; + name: string; + key: string; + type: UserSettingsType; + value: T; + createdAt?: Date; + updatedAt?: Date; + hash?: string; + userId?: Guid; + isDefault?: boolean; +} diff --git a/dmp-frontend/src/app/core/services/utilities/enum-utils.service.ts b/dmp-frontend/src/app/core/services/utilities/enum-utils.service.ts index b33a781c5..2735a2995 100644 --- a/dmp-frontend/src/app/core/services/utilities/enum-utils.service.ts +++ b/dmp-frontend/src/app/core/services/utilities/enum-utils.service.ts @@ -4,8 +4,8 @@ import { AppRole } from '../../common/enum/app-role'; import { DatasetProfileComboBoxType } from '../../common/enum/dataset-profile-combo-box-type'; import { DatasetProfileFieldViewStyle } from '../../common/enum/dataset-profile-field-view-style'; import { DatasetStatus } from '../../common/enum/dataset-status'; -import { DmpProfileFieldDataType } from '../../common/enum/dmp-profile-field-type'; -import { DmpProfileType } from '../../common/enum/dmp-profile-type'; +import { DmpBlueprintFieldDataType } from '../../common/enum/dmp-blueprint-field-type'; +import { DmpBlueprintType } from '../../common/enum/dmp-blueprint-type'; import { DmpStatus } from '../../common/enum/dmp-status'; import { ValidationType } from '../../common/enum/validation-type'; import { DatasetProfileInternalDmpEntitiesType } from '../../common/enum/dataset-profile-internal-dmp-entities-type'; @@ -13,6 +13,7 @@ import { RecentActivityOrder } from '@app/core/common/enum/recent-activity-order import { Role } from '@app/core/common/enum/role'; import { RoleOrganizationType } from '@app/core/common/enum/role-organization-type'; import { ViewStyleType } from '@app/ui/admin/dataset-profile/editor/components/field/view-style-enum'; +import { DescriptionTemplateTypeStatus } from '@app/core/common/enum/description-template-type-status'; @Injectable() export class EnumUtils { @@ -34,18 +35,18 @@ export class EnumUtils { } } - toDmpProfileFieldDataTypeString(type: DmpProfileFieldDataType): string { + toDmpBlueprintFieldDataTypeString(type: DmpBlueprintFieldDataType): string { switch (type) { - case DmpProfileFieldDataType.Date: return this.language.instant('TYPES.DMP-PROFILE-FIELD.DATA-TYPE.DATE'); - case DmpProfileFieldDataType.Number: return this.language.instant('TYPES.DMP-PROFILE-FIELD.DATA-TYPE.NUMBER'); - case DmpProfileFieldDataType.Text: return this.language.instant('TYPES.DMP-PROFILE-FIELD.DATA-TYPE.TEXT'); - case DmpProfileFieldDataType.ExternalAutocomplete: return this.language.instant('TYPES.DMP-PROFILE-FIELD.DATA-TYPE.EXTERNAL-AUTOCOMPLETE'); + case DmpBlueprintFieldDataType.Date: return this.language.instant('TYPES.DMP-PROFILE-FIELD.DATA-TYPE.DATE'); + case DmpBlueprintFieldDataType.Number: return this.language.instant('TYPES.DMP-PROFILE-FIELD.DATA-TYPE.NUMBER'); + case DmpBlueprintFieldDataType.Text: return this.language.instant('TYPES.DMP-PROFILE-FIELD.DATA-TYPE.TEXT'); + case DmpBlueprintFieldDataType.ExternalAutocomplete: return this.language.instant('TYPES.DMP-PROFILE-FIELD.DATA-TYPE.EXTERNAL-AUTOCOMPLETE'); } } - toDmpProfileTypeString(type: DmpProfileType): string { + toDmpBlueprintTypeString(type: DmpBlueprintType): string { switch (type) { - case DmpProfileType.Input: return this.language.instant('TYPES.DMP-PROFILE-FIELD.TYPE.INPUT'); + case DmpBlueprintType.Input: return this.language.instant('TYPES.DMP-PROFILE-FIELD.TYPE.INPUT'); } } @@ -185,4 +186,11 @@ export class EnumUtils { case RoleOrganizationType.Other: return this.language.instant('USER-PROFILE.ROLE-ORGANIZATION.OTHER'); } } + + toDescriptionTemplateTypeStatusString(status: DescriptionTemplateTypeStatus): string { + switch (status) { + case DescriptionTemplateTypeStatus.Draft: return this.language.instant('TYPES.DESCRIPTION-TEMPLATE-TYPE-STATUS.DRAFT'); + case DescriptionTemplateTypeStatus.Finalized: return this.language.instant('TYPES.DESCRIPTION-TEMPLATE-TYPE-STATUS.FINALIZED'); + } + } } diff --git a/dmp-frontend/src/app/core/services/utilities/query-params.service.ts b/dmp-frontend/src/app/core/services/utilities/query-params.service.ts new file mode 100644 index 000000000..20260db4a --- /dev/null +++ b/dmp-frontend/src/app/core/services/utilities/query-params.service.ts @@ -0,0 +1,59 @@ +import { Injectable } from '@angular/core'; +import { Lookup } from '@common/model/lookup'; +import { nameof } from 'ts-simple-nameof'; + +@Injectable() +export class QueryParamsService { + + constructor() { } + + + serializeLookup(lookup: Lookup): string { + return JSON.stringify(lookup, (key: string, value: any) => { + switch (key) { + // case nameof(x => x.page): + // case nameof(x => x.order): + case nameof(x => x.metadata): + case nameof(x => x.project): + return undefined; + default: + return value == null ? undefined : value; + } + }); + } + + deSerializeLookup(serializedLookup: string): any { + const json = JSON.parse(serializedLookup); + // delete json[nameof(x => x.page)]; + // delete json[nameof(x => x.order)]; + delete json[nameof(x => x.metadata)]; + delete json[nameof(x => x.project)]; + return json; + } + + + serializeObject(object: Record): string | null{ + if(!object){ + return null + } + return JSON.stringify(object); + } + + deserializeObject(object: string):T | null { + if(!object){ + return null; + } + return JSON.parse(object); + } + + + deSerializeAndApplyLookup(serializedLookup: string, targetLookup: Lookup) { + this.applyLookup(targetLookup, this.deSerializeLookup(serializedLookup)); + } + + private applyLookup(target: Lookup, source: Lookup) { + Object.keys(source).forEach(key => { + target[key] = source[key]; + }); + } +} diff --git a/dmp-frontend/src/app/ui/admin/dataset-profile/editor/dataset-profile-editor.component.ts b/dmp-frontend/src/app/ui/admin/dataset-profile/editor/dataset-profile-editor.component.ts index 6c40f6568..e46b8d802 100644 --- a/dmp-frontend/src/app/ui/admin/dataset-profile/editor/dataset-profile-editor.component.ts +++ b/dmp-frontend/src/app/ui/admin/dataset-profile/editor/dataset-profile-editor.component.ts @@ -12,7 +12,7 @@ import * as FileSaver from 'file-saver'; import { BaseComponent } from '@common/base/base.component'; import { DatasetProfileEditorModel } from '@app/ui/admin/dataset-profile/editor/dataset-profile-editor-model'; import { DatasetWizardModel } from '@app/core/model/dataset/dataset-wizard'; -import { BreadcrumbItem } from '@app/ui/misc/breadcrumb/definition/breadcrumb-item'; +// import { BreadcrumbItem } from '@app/ui/misc/breadcrumb/definition/breadcrumb-item'; import { DatasetProfileService } from '@app/core/services/dataset-profile/dataset-profile.service'; import { LoggingService } from '@app/core/services/logging/logging-service'; import { UiNotificationService, SnackBarNotificationLevel } from '@app/core/services/notification/ui-notification-service'; @@ -48,7 +48,7 @@ import { CheckDeactivateBaseComponent } from '@app/library/deactivate/deactivate import { DescriptionTemplateTypeService } from '@app/core/services/description-template-type/description-template-type.service'; import { DescriptionTemplateType } from '@app/core/model/description-template-type/description-template-type'; import { DescriptionTemplateTypeStatus } from '@app/core/common/enum/description-template-type-status'; -import { DescriptionTemplateTypeLookup } from '@app/core/query/description-template/description-template-type.lookup'; +import { DescriptionTemplateTypeLookup } from '@app/core/query/description-template-type.lookup'; import { nameof } from 'ts-simple-nameof'; const skipDisable: any[] = require('../../../../../assets/resources/skipDisable.json'); @@ -76,7 +76,7 @@ export class DatasetProfileEditorComponent extends CheckDeactivateBaseComponent private datasetProfileId: string; newVersionId: string; dataWizardModel: DatasetWizardModel; - breadCrumbs: Observable; + // breadCrumbs: Observable; @ViewChild('stepper') stepper: MatStepper; viewOnly = false; nestedCount: number[] = []; @@ -166,11 +166,11 @@ export class DatasetProfileEditorComponent extends CheckDeactivateBaseComponent }, error => this.onCallbackError(error) ); - this.breadCrumbs = observableOf([{ - parentComponentName: 'DatasetProfileListingComponent', - label: this.language.instant('NAV-BAR.TEMPLATE'), - url: '/dataset-profiles/' + this.datasetProfileId - }]); + // this.breadCrumbs = observableOf([{ + // parentComponentName: 'DatasetProfileListingComponent', + // label: this.language.instant('NAV-BAR.TEMPLATE'), + // url: '/dataset-profiles/' + this.datasetProfileId + // }]); } else if (cloneId != null) { this.isClone = true; this.datasetProfileService.clone(cloneId) diff --git a/dmp-frontend/src/app/ui/admin/dataset-profile/listing/dataset-profile-listing.component.html b/dmp-frontend/src/app/ui/admin/dataset-profile/listing/dataset-profile-listing.component.html index adb990e47..b1c49f61c 100644 --- a/dmp-frontend/src/app/ui/admin/dataset-profile/listing/dataset-profile-listing.component.html +++ b/dmp-frontend/src/app/ui/admin/dataset-profile/listing/dataset-profile-listing.component.html @@ -72,7 +72,7 @@ + +
+ +
+
+ +
+
+ +
+ + + + + {{'DESCRIPTION-TEMPLATE-TYPE-EDITOR.NEW' | translate}} + + + +
+
+
+ + {{'DESCRIPTION-TEMPLATE-TYPE-EDITOR.FIELDS.NAME' | translate}} + +
+
+ + + + {{formGroup.get('name').getError('backendError').message}} + + {{'GENERAL.VALIDATION.REQUIRED' | translate}} + +
+
+
+
+
+ + + + \ No newline at end of file diff --git a/dmp-frontend/src/app/ui/admin/description-types/editor/description-type-editor.component.scss b/dmp-frontend/src/app/ui/admin/description-types/editor/description-template-type-editor.component.scss similarity index 82% rename from dmp-frontend/src/app/ui/admin/description-types/editor/description-type-editor.component.scss rename to dmp-frontend/src/app/ui/admin/description-types/editor/description-template-type-editor.component.scss index 93d519a62..dd84a6aa7 100644 --- a/dmp-frontend/src/app/ui/admin/description-types/editor/description-type-editor.component.scss +++ b/dmp-frontend/src/app/ui/admin/description-types/editor/description-template-type-editor.component.scss @@ -1,7 +1,9 @@ -.description-type-editor { - margin-top: 1.3rem; - margin-left: 1em; - margin-right: 3em; +.description-template-type-editor { + padding-top: 1em; + + .editor-actions { + margin-top: 30px; + } } .action-btn { diff --git a/dmp-frontend/src/app/ui/admin/description-types/editor/description-template-type-editor.component.ts b/dmp-frontend/src/app/ui/admin/description-types/editor/description-template-type-editor.component.ts new file mode 100644 index 000000000..4a62698d1 --- /dev/null +++ b/dmp-frontend/src/app/ui/admin/description-types/editor/description-template-type-editor.component.ts @@ -0,0 +1,173 @@ +import { DatePipe } from '@angular/common'; +import { Component, OnInit } from '@angular/core'; +import { UntypedFormGroup } from '@angular/forms'; +import { MatDialog } from '@angular/material/dialog'; +import { ActivatedRoute, Router } from '@angular/router'; +import { IsActive } from '@app/core/common/enum/is-active.enum'; +import { AppPermission } from '@app/core/common/enum/permission.enum'; +import { DescriptionTemplateType, DescriptionTemplateTypePersist } from '@app/core/model/description-template-type/description-template-type'; +import { AuthService } from '@app/core/services/auth/auth.service'; +import { DescriptionTemplateTypeService } from '@app/core/services/description-template-type/description-template-type.service'; +import { LoggingService } from '@app/core/services/logging/logging-service'; +import { SnackBarNotificationLevel, UiNotificationService } from '@app/core/services/notification/ui-notification-service'; +import { EnumUtils } from '@app/core/services/utilities/enum-utils.service'; +import { QueryParamsService } from '@app/core/services/utilities/query-params.service'; +import { BaseEditor } from '@common/base/base-editor'; +import { FormService } from '@common/forms/form-service'; +import { ConfirmationDialogComponent } from '@common/modules/confirmation-dialog/confirmation-dialog.component'; +import { HttpErrorHandlingService } from '@common/modules/errors/error-handling/http-error-handling.service'; +import { FilterService } from '@common/modules/text-filter/filter-service'; +import { Guid } from '@common/types/guid'; +import { TranslateService } from '@ngx-translate/core'; +import { map, takeUntil } from 'rxjs/operators'; +import { DescriptionTemplateTypeEditorModel } from './description-template-type-editor.model'; +import { DescriptionTemplateTypeEditorResolver } from './description-template-type-editor.resolver'; +import { DescriptionTemplateTypeEditorService } from './description-template-type-editor.service'; + +@Component({ + templateUrl: './description-template-type-editor.component.html', + styleUrls: ['./description-template-type-editor.component.scss'], + providers: [DescriptionTemplateTypeEditorService] +}) +export class DescriptionTemplateTypeEditorComponent extends BaseEditor implements OnInit { + + isNew = true; + isDeleted = false; + formGroup: UntypedFormGroup = null; + showInactiveDetails = false; + + + protected get canDelete(): boolean { + return !this.isDeleted && !this.isNew && this.hasPermission(this.authService.permissionEnum.DeleteDescriptionTemplateType); + } + + protected get canSave(): boolean { + return !this.isDeleted && this.hasPermission(this.authService.permissionEnum.EditDescriptionTemplateType); + } + + protected get canFinalize(): boolean { + return !this.isDeleted && this.hasPermission(this.authService.permissionEnum.EditDescriptionTemplateType); + } + + + private hasPermission(permission: AppPermission): boolean { + return this.authService.hasPermission(permission) || this.editorModel?.permissions?.includes(permission); + } + + constructor( + // BaseFormEditor injected dependencies + protected dialog: MatDialog, + protected language: TranslateService, + protected formService: FormService, + protected router: Router, + protected uiNotificationService: UiNotificationService, + protected httpErrorHandlingService: HttpErrorHandlingService, + protected filterService: FilterService, + protected datePipe: DatePipe, + protected route: ActivatedRoute, + protected queryParamsService: QueryParamsService, + // Rest dependencies. Inject any other needed deps here: + public authService: AuthService, + public enumUtils: EnumUtils, + private descriptionTemplateTypeService: DescriptionTemplateTypeService, + private logger: LoggingService, + private descriptionTemplateTypeEditorService: DescriptionTemplateTypeEditorService + ) { + super(dialog, language, formService, router, uiNotificationService, httpErrorHandlingService, filterService, datePipe, route, queryParamsService); + } + + ngOnInit(): void { + super.ngOnInit(); + } + + getItem(itemId: Guid, successFunction: (item: DescriptionTemplateType) => void) { + this.descriptionTemplateTypeService.getSingle(itemId, DescriptionTemplateTypeEditorResolver.lookupFields()) + .pipe(map(data => data as DescriptionTemplateType), takeUntil(this._destroyed)) + .subscribe( + data => successFunction(data), + error => this.onCallbackError(error) + ); + } + + prepareForm(data: DescriptionTemplateType) { + try { + this.editorModel = data ? new DescriptionTemplateTypeEditorModel().fromModel(data) : new DescriptionTemplateTypeEditorModel(); + this.isDeleted = data ? data.isActive === IsActive.Inactive : false; + this.buildForm(); + } catch (error) { + this.logger.error('Could not parse descriptionTemplateType item: ' + data + error); + this.uiNotificationService.snackBarNotification(this.language.instant('COMMONS.ERRORS.DEFAULT'), SnackBarNotificationLevel.Error); + } + } + + buildForm() { + this.formGroup = this.editorModel.buildForm(null, this.isDeleted || !this.authService.hasPermission(AppPermission.EditDescriptionTemplateType)); + this.descriptionTemplateTypeEditorService.setValidationErrorModel(this.editorModel.validationErrorModel); + } + + refreshData(): void { + this.getItem(this.editorModel.id, (data: DescriptionTemplateType) => this.prepareForm(data)); + } + + refreshOnNavigateToData(id?: Guid): void { + this.formGroup.markAsPristine(); + let route = []; + + if (id === null) { + route.push('../..'); + } else if (this.isNew) { + route.push('../' + id); + } else { + route.push('..'); + } + + this.router.navigate(route, { queryParams: { 'lookup': this.queryParamsService.serializeLookup(this.lookupParams), 'lv': ++this.lv }, replaceUrl: true, relativeTo: this.route }); + } + + persistEntity(onSuccess?: (response) => void): void { + const formData = this.formService.getValue(this.formGroup.value) as DescriptionTemplateTypePersist; + + this.descriptionTemplateTypeService.persist(formData) + .pipe(takeUntil(this._destroyed)).subscribe( + complete => onSuccess ? onSuccess(complete) : this.onCallbackSuccess(complete), + error => this.onCallbackError(error) + ); + } + + formSubmit(): void { + this.formService.touchAllFormFields(this.formGroup); + if (!this.isFormValid()) { + return; + } + + this.persistEntity(); + } + + public delete() { + const value = this.formGroup.value; + if (value.id) { + const dialogRef = this.dialog.open(ConfirmationDialogComponent, { + maxWidth: '300px', + data: { + message: this.language.instant('GENERAL.CONFIRMATION-DIALOG.DELETE-ITEM'), + confirmButton: this.language.instant('GENERAL.CONFIRMATION-DIALOG.ACTIONS.CONFIRM'), + cancelButton: this.language.instant('GENERAL.CONFIRMATION-DIALOG.ACTIONS.CANCEL') + } + }); + dialogRef.afterClosed().pipe(takeUntil(this._destroyed)).subscribe(result => { + if (result) { + this.descriptionTemplateTypeService.delete(value.id).pipe(takeUntil(this._destroyed)) + .subscribe( + complete => this.onCallbackSuccess(), + error => this.onCallbackError(error) + ); + } + }); + } + } + + clearErrorModel() { + this.editorModel.validationErrorModel.clear(); + this.formService.validateAllFormFields(this.formGroup); + } +} diff --git a/dmp-frontend/src/app/ui/admin/description-types/editor/description-template-type-editor.model.ts b/dmp-frontend/src/app/ui/admin/description-types/editor/description-template-type-editor.model.ts new file mode 100644 index 000000000..6f280477b --- /dev/null +++ b/dmp-frontend/src/app/ui/admin/description-types/editor/description-template-type-editor.model.ts @@ -0,0 +1,54 @@ +import { UntypedFormBuilder, UntypedFormGroup, Validators } from '@angular/forms'; +import { DescriptionTemplateTypeStatus } from '@app/core/common/enum/description-template-type-status'; +import { DescriptionTemplateType, DescriptionTemplateTypePersist } from '@app/core/model/description-template-type/description-template-type'; +import { BaseEditorModel } from '@common/base/base-form-editor-model'; +import { BackendErrorValidator } from '@common/forms/validation/custom-validator'; +import { ValidationErrorModel } from '@common/forms/validation/error-model/validation-error-model'; +import { Validation, ValidationContext } from '@common/forms/validation/validation-context'; + +export class DescriptionTemplateTypeEditorModel extends BaseEditorModel implements DescriptionTemplateTypePersist { + name: string; + status: DescriptionTemplateTypeStatus = DescriptionTemplateTypeStatus.Draft; + permissions: string[]; + + public validationErrorModel: ValidationErrorModel = new ValidationErrorModel(); + protected formBuilder: UntypedFormBuilder = new UntypedFormBuilder(); + + constructor() { super(); } + + public fromModel(item: DescriptionTemplateType): DescriptionTemplateTypeEditorModel { + if (item) { + this.id = item.id; + this.name = item.name; + this.status = item.status; + this.isActive = item.isActive; + this.hash = item.hash; + if (item.createdAt) { this.createdAt = item.createdAt; } + if (item.updatedAt) { this.updatedAt = item.updatedAt; } + } + return this; + } + + buildForm(context: ValidationContext = null, disabled: boolean = false): UntypedFormGroup { + if (context == null) { context = this.createValidationContext(); } + + return this.formBuilder.group({ + id: [{ value: this.id, disabled: disabled }, context.getValidation('id').validators], + name: [{ value: this.name, disabled: disabled }, context.getValidation('name').validators], + status: [{ value: this.status, disabled: disabled }, context.getValidation('status').validators], + hash: [{ value: this.hash, disabled: disabled }, context.getValidation('hash').validators] + }); + } + + createValidationContext(): ValidationContext { + const baseContext: ValidationContext = new ValidationContext(); + const baseValidationArray: Validation[] = new Array(); + baseValidationArray.push({ key: 'id', validators: [BackendErrorValidator(this.validationErrorModel, 'id')] }); + baseValidationArray.push({ key: 'name', validators: [Validators.required, BackendErrorValidator(this.validationErrorModel, 'RenameourceId')] }); + baseValidationArray.push({ key: 'status', validators: [Validators.required, BackendErrorValidator(this.validationErrorModel, 'status')] }); + baseValidationArray.push({ key: 'hash', validators: [] }); + + baseContext.validation = baseValidationArray; + return baseContext; + } +} diff --git a/dmp-frontend/src/app/ui/admin/description-types/editor/description-template-type-editor.resolver.ts b/dmp-frontend/src/app/ui/admin/description-types/editor/description-template-type-editor.resolver.ts new file mode 100644 index 000000000..0e47a57da --- /dev/null +++ b/dmp-frontend/src/app/ui/admin/description-types/editor/description-template-type-editor.resolver.ts @@ -0,0 +1,38 @@ +import { Injectable } from '@angular/core'; +import { ActivatedRouteSnapshot, RouterStateSnapshot } from '@angular/router'; +import { AppPermission } from '@app/core/common/enum/permission.enum'; +import { DescriptionTemplateType } from '@app/core/model/description-template-type/description-template-type'; +import { DescriptionTemplateTypeService } from '@app/core/services/description-template-type/description-template-type.service'; +import { BreadcrumbService } from '@app/ui/misc/breadcrumb/breadcrumb.service'; +import { BaseEditorResolver } from '@common/base/base-editor.resolver'; +import { Guid } from '@common/types/guid'; +import { takeUntil, tap } from 'rxjs/operators'; +import { nameof } from 'ts-simple-nameof'; + +@Injectable() +export class DescriptionTemplateTypeEditorResolver extends BaseEditorResolver { + + constructor(private descriptionTemplateTypeService: DescriptionTemplateTypeService, private breadcrumbService: BreadcrumbService) { + super(); + } + + public static lookupFields(): string[] { + return [ + ...BaseEditorResolver.lookupFields(), + nameof(x => x.id), + nameof(x => x.name), + nameof(x => x.status), + nameof(x => x.createdAt), + nameof(x => x.hash), + nameof(x => x.isActive) + ] + } + + resolve(route: ActivatedRouteSnapshot, state: RouterStateSnapshot) { + + const fields = [ + ...DescriptionTemplateTypeEditorResolver.lookupFields() + ]; + return this.descriptionTemplateTypeService.getSingle(Guid.parse(route.paramMap.get('id')), fields).pipe(tap(x => this.breadcrumbService.addIdResolvedValue(x.id?.toString(), x.name)), takeUntil(this._destroyed)); + } +} diff --git a/dmp-frontend/src/app/ui/admin/description-types/editor/description-template-type-editor.service.ts b/dmp-frontend/src/app/ui/admin/description-types/editor/description-template-type-editor.service.ts new file mode 100644 index 000000000..dbc42f46a --- /dev/null +++ b/dmp-frontend/src/app/ui/admin/description-types/editor/description-template-type-editor.service.ts @@ -0,0 +1,15 @@ +import { Injectable } from "@angular/core"; +import { ValidationErrorModel } from "@common/forms/validation/error-model/validation-error-model"; + +@Injectable() +export class DescriptionTemplateTypeEditorService { + private validationErrorModel: ValidationErrorModel; + + public setValidationErrorModel(validationErrorModel: ValidationErrorModel): void { + this.validationErrorModel = validationErrorModel; + } + + public getValidationErrorModel(): ValidationErrorModel { + return this.validationErrorModel; + } +} diff --git a/dmp-frontend/src/app/ui/admin/description-types/editor/description-type-editor.component.html b/dmp-frontend/src/app/ui/admin/description-types/editor/description-type-editor.component.html deleted file mode 100644 index e5c13bec2..000000000 --- a/dmp-frontend/src/app/ui/admin/description-types/editor/description-type-editor.component.html +++ /dev/null @@ -1,38 +0,0 @@ -
-
-
-
-

{{'DESCRIPTION-TYPE-EDITOR.NEW' | translate}}

-
-
-
- - -
- - - - {{formGroup.get('name').getError('backendError').message}} - - {{'GENERAL.VALIDATION.REQUIRED' | translate}} - -
-
-
- -
-
-
- - -
-
-
-
-
-
-
diff --git a/dmp-frontend/src/app/ui/admin/description-types/editor/description-type-editor.component.ts b/dmp-frontend/src/app/ui/admin/description-types/editor/description-type-editor.component.ts deleted file mode 100644 index 02115aec4..000000000 --- a/dmp-frontend/src/app/ui/admin/description-types/editor/description-type-editor.component.ts +++ /dev/null @@ -1,161 +0,0 @@ -import { AfterViewInit, Component, OnInit } from '@angular/core'; -import { UntypedFormBuilder, UntypedFormGroup, Validators } from '@angular/forms'; -import { ActivatedRoute, ParamMap, Router } from '@angular/router'; -import { DescriptionTemplateTypeStatus } from '@app/core/common/enum/description-template-type-status'; -import { DescriptionTemplateType } from '@app/core/model/description-template-type/description-template-type'; -import { DescriptionTemplateTypeService } from '@app/core/services/description-template-type/description-template-type.service'; -import { SnackBarNotificationLevel, UiNotificationService } from '@app/core/services/notification/ui-notification-service'; -import { BaseComponent } from '@common/base/base.component'; -import { FormService } from '@common/forms/form-service'; -import { BackendErrorValidator } from '@common/forms/validation/custom-validator'; -import { ValidationErrorModel } from '@common/forms/validation/error-model/validation-error-model'; -import { ValidationContext } from '@common/forms/validation/validation-context'; -import { TranslateService } from '@ngx-translate/core'; -import { takeUntil } from 'rxjs/operators'; - -@Component({ - selector: 'app-description-type-editor', - templateUrl: './description-type-editor.component.html', - styleUrls: ['./description-type-editor.component.scss'] -}) -export class DescriptionTypeEditorComponent extends BaseComponent implements OnInit { - - formGroup: UntypedFormGroup = null; - descriptionTypeModel: DescriptionTypeEditorModel; - - isNew = true; - viewOnly = false; - descriptionTemplateTypeId: string; - - constructor( - private descriptionTemplateTypeService: DescriptionTemplateTypeService, - private formService: FormService, - private uiNotificationService: UiNotificationService, - private language: TranslateService, - private route: ActivatedRoute, - private router: Router - ) { - super(); - } - - ngOnInit(): void { - this.route.paramMap.pipe(takeUntil(this._destroyed)).subscribe((paramMap: ParamMap) => { - this.descriptionTemplateTypeId = paramMap.get('id'); - - if (this.descriptionTemplateTypeId != null) { - this.isNew = false; - this.descriptionTemplateTypeService.get(this.descriptionTemplateTypeId) - .pipe(takeUntil(this._destroyed)).subscribe( - type => { - this.descriptionTypeModel = new DescriptionTypeEditorModel().fromModel(type.items[0]); - if (this.descriptionTypeModel.status === DescriptionTemplateTypeStatus.Finalized) { - this.formGroup = this.descriptionTypeModel.buildForm(null, true); - this.viewOnly = true; - } - else { - this.formGroup = this.descriptionTypeModel.buildForm(); - } - }, - error => this.uiNotificationService.snackBarNotification(error.message, SnackBarNotificationLevel.Error) - ); - } - else { - this.descriptionTypeModel = new DescriptionTypeEditorModel(); - this.descriptionTypeModel.status = DescriptionTemplateTypeStatus.Draft; - this.formGroup = this.descriptionTypeModel.buildForm(); - } - }); - } - - formSubmit(): void { - this.formService.touchAllFormFields(this.formGroup); - if (!this.isFormValid()) { return; } - this.onSubmit(); - } - - public isFormValid() { - return this.formGroup.valid; - } - - finalize() { - this.formGroup.get('status').setValue(DescriptionTemplateTypeStatus.Finalized); - this.onSubmit(); - } - - onSubmit(): void { - if (this.isNew) { - this.descriptionTemplateTypeService.persist(this.formGroup.value) - .pipe(takeUntil(this._destroyed)) - .subscribe( - complete => this.onCallbackSuccess(true), - error => this.onCallbackError(error) - ); - } - else { - this.descriptionTemplateTypeService.update(this.formGroup.value) - .pipe(takeUntil(this._destroyed)) - .subscribe( - complete => this.onCallbackSuccess(false), - error => this.onCallbackError(error) - ); - } - } - - onCallbackSuccess(creation: boolean): void { - if (creation) { - this.uiNotificationService.snackBarNotification(this.language.instant('GENERAL.SNACK-BAR.SUCCESSFUL-CREATION'), SnackBarNotificationLevel.Success); - } - else { - this.uiNotificationService.snackBarNotification(this.language.instant('GENERAL.SNACK-BAR.SUCCESSFUL-UPDATE'), SnackBarNotificationLevel.Success); - } - this.router.navigate(['/description-types']); - } - - onCallbackError(errorResponse: any) { - this.setErrorModel(errorResponse.error); - this.formService.validateAllFormFields(this.formGroup); - this.uiNotificationService.snackBarNotification(errorResponse.error.message, SnackBarNotificationLevel.Error); - } - - public setErrorModel(validationErrorModel: ValidationErrorModel) { - Object.keys(validationErrorModel).forEach(item => { - (this.descriptionTypeModel.validationErrorModel)[item] = (validationErrorModel)[item]; - }); - } - - public cancel(): void { - this.router.navigate(['/description-types']); - } - -} - -export class DescriptionTypeEditorModel { - public id: string; - public name: string; - public status: DescriptionTemplateTypeStatus; - public validationErrorModel: ValidationErrorModel = new ValidationErrorModel(); - - fromModel(item: DescriptionTemplateType): DescriptionTypeEditorModel { - this.id = item.id; - this.name = item.name; - this.status = item.status; - return this; - } - - buildForm(context: ValidationContext = null, disabled: boolean = false): UntypedFormGroup { - if (context == null) { context = this.createValidationContext(); } - const formGroup = new UntypedFormBuilder().group({ - id: [this.id], - name: [{ value: this.name, disabled: disabled }, context.getValidation('name').validators], - status: [{ value: this.status, disabled: disabled }, context.getValidation('status').validators] - }); - return formGroup; - } - - createValidationContext(): ValidationContext { - const baseContext: ValidationContext = new ValidationContext(); - baseContext.validation.push({ key: 'name', validators: [Validators.required, BackendErrorValidator(this.validationErrorModel, 'name')] }); - baseContext.validation.push({ key: 'status', validators: [Validators.required, BackendErrorValidator(this.validationErrorModel, 'status')] }); - return baseContext; - } -} diff --git a/dmp-frontend/src/app/ui/admin/description-types/listing/description-template-type-listing.component.html b/dmp-frontend/src/app/ui/admin/description-types/listing/description-template-type-listing.component.html new file mode 100644 index 000000000..2e9a96d09 --- /dev/null +++ b/dmp-frontend/src/app/ui/admin/description-types/listing/description-template-type-listing.component.html @@ -0,0 +1,108 @@ +
+
+ +
+
+

{{'DESCRIPTION-TEMPLATE-TYPE-LISTING.TITLE' | translate}}

+ + +
+
+ +
+
+ + + + + + + + + +
+
+ + + + +
+
+ + {{item?.name | nullifyValue}} +
+
+ + +
+
+ {{enumUtils.toDescriptionTemplateTypeStatusString(item.status) | nullifyValue}} +
+
+
+ + + + {{'DESCRIPTION-TEMPLATE-TYPE-LISTING.FIELDS.CREATED-AT' | translate}}: + + {{item?.createdAt | dateTimeFormatter : 'short' | nullifyValue}} + + +
+
+ + + {{'DESCRIPTION-TEMPLATE-TYPE-LISTING.FIELDS.UPDATED-AT' | translate}}: + + {{item?.updatedAt | dateTimeFormatter : 'short' | nullifyValue}} + + + +
+
+
+ + +
+
+ {{enumUtils.toDescriptionTemplateTypeStatusString(row.status) | nullifyValue}} +
+
+
+ + +
+
+ + + + + + +
+
+
\ No newline at end of file diff --git a/dmp-frontend/src/app/ui/admin/description-types/listing/description-types.component.scss b/dmp-frontend/src/app/ui/admin/description-types/listing/description-template-type-listing.component.scss similarity index 76% rename from dmp-frontend/src/app/ui/admin/description-types/listing/description-types.component.scss rename to dmp-frontend/src/app/ui/admin/description-types/listing/description-template-type-listing.component.scss index 245b6aa81..6e1b48814 100644 --- a/dmp-frontend/src/app/ui/admin/description-types/listing/description-types.component.scss +++ b/dmp-frontend/src/app/ui/admin/description-types/listing/description-template-type-listing.component.scss @@ -1,8 +1,4 @@ -.mat-table { - margin-top: 47px; - border-radius: 4px; -} -.description-types-listing { +.description-template-type-listing { margin-top: 1.3rem; margin-left: 1rem; margin-right: 2rem; @@ -28,13 +24,6 @@ z-index: 5; } } -// PAGINATOR -:host ::ng-deep .mat-paginator-container { - flex-direction: row-reverse !important; - justify-content: space-between !important; - background-color: #f6f6f6; - align-items: center; -} .create-btn { border-radius: 30px; background-color: var(--secondary-color); @@ -68,4 +57,4 @@ .status-chip-draft{ color: #00c4ff; background: #d3f5ff 0% 0% no-repeat padding-box; -} \ No newline at end of file +} diff --git a/dmp-frontend/src/app/ui/admin/description-types/listing/description-template-type-listing.component.ts b/dmp-frontend/src/app/ui/admin/description-types/listing/description-template-type-listing.component.ts new file mode 100644 index 000000000..7282e2bde --- /dev/null +++ b/dmp-frontend/src/app/ui/admin/description-types/listing/description-template-type-listing.component.ts @@ -0,0 +1,177 @@ +import { Component, OnInit, TemplateRef, ViewChild } from '@angular/core'; +import { MatDialog } from '@angular/material/dialog'; +import { ActivatedRoute, Router } from '@angular/router'; +import { DescriptionTemplateTypeStatus } from '@app/core/common/enum/description-template-type-status'; +import { IsActive } from '@app/core/common/enum/is-active.enum'; +import { DescriptionTemplateType } from '@app/core/model/description-template-type/description-template-type'; +import { DescriptionTemplateTypeLookup } from '@app/core/query/description-template-type.lookup'; +import { AuthService } from '@app/core/services/auth/auth.service'; +import { DescriptionTemplateTypeService } from '@app/core/services/description-template-type/description-template-type.service'; +import { SnackBarNotificationLevel, UiNotificationService } from '@app/core/services/notification/ui-notification-service'; +import { EnumUtils } from '@app/core/services/utilities/enum-utils.service'; +import { QueryParamsService } from '@app/core/services/utilities/query-params.service'; +import { BaseListingComponent } from '@common/base/base-listing-component'; +import { PipeService } from '@common/formatting/pipe.service'; +import { DataTableDateTimeFormatPipe } from '@common/formatting/pipes/date-time-format.pipe'; +import { QueryResult } from '@common/model/query-result'; +import { ConfirmationDialogComponent } from '@common/modules/confirmation-dialog/confirmation-dialog.component'; +import { HttpErrorHandlingService } from '@common/modules/errors/error-handling/http-error-handling.service'; +import { ColumnDefinition, ColumnsChangedEvent, HybridListingComponent, PageLoadEvent } from '@common/modules/hybrid-listing/hybrid-listing.component'; +import { Guid } from '@common/types/guid'; +import { TranslateService } from '@ngx-translate/core'; +import { Observable } from 'rxjs'; +import { takeUntil } from 'rxjs/operators'; +import { nameof } from 'ts-simple-nameof'; + +@Component({ + templateUrl: './description-template-type-listing.component.html', + styleUrls: ['./description-template-type-listing.component.scss'] +}) +export class DescriptionTemplateTypeListingComponent extends BaseListingComponent implements OnInit { + publish = false; + userSettingsKey = { key: 'DescriptionTemplateTypeListingUserSettings' }; + propertiesAvailableForOrder: ColumnDefinition[]; + descriptionTemplateTypeStatuses = DescriptionTemplateTypeStatus; + + @ViewChild('descriptionTemplateTypeStatus', { static: true }) descriptionTemplateTypeStatus?: TemplateRef; + @ViewChild('actions', { static: true }) actions?: TemplateRef; + @ViewChild(HybridListingComponent, { static: true }) hybridListingComponent: HybridListingComponent; + + private readonly lookupFields: string[] = [ + nameof(x => x.id), + nameof(x => x.name), + nameof(x => x.status), + nameof(x => x.updatedAt), + nameof(x => x.createdAt), + nameof(x => x.hash), + nameof(x => x.isActive) + ]; + + rowIdentity = x => x.id; + + constructor( + protected router: Router, + protected route: ActivatedRoute, + protected uiNotificationService: UiNotificationService, + protected httpErrorHandlingService: HttpErrorHandlingService, + protected queryParamsService: QueryParamsService, + private descriptionTemplateTypeService: DescriptionTemplateTypeService, + public authService: AuthService, + private pipeService: PipeService, + public enumUtils: EnumUtils, + private language: TranslateService, + private dialog: MatDialog + ) { + super(router, route, uiNotificationService, httpErrorHandlingService, queryParamsService); + // Lookup setup + // Default lookup values are defined in the user settings class. + this.lookup = this.initializeLookup(); + } + + ngOnInit() { + super.ngOnInit(); + } + + protected initializeLookup(): DescriptionTemplateTypeLookup { + const lookup = new DescriptionTemplateTypeLookup(); + lookup.metadata = { countAll: true }; + lookup.page = { offset: 0, size: this.ITEMS_PER_PAGE }; + lookup.isActive = [IsActive.Active]; + lookup.order = { items: [this.toDescSortField(nameof(x => x.createdAt))] }; + this.updateOrderUiFields(lookup.order); + + lookup.project = { + fields: this.lookupFields + }; + + return lookup; + } + + protected setupColumns() { + this.gridColumns.push(...[{ + prop: nameof(x => x.name), + sortable: true, + languageName: 'DESCRIPTION-TEMPLATE-TYPE-LISTING.FIELDS.NAME' + }, { + prop: nameof(x => x.status), + sortable: true, + languageName: 'DESCRIPTION-TEMPLATE-TYPE-LISTING.FIELDS.STATUS', + cellTemplate: this.descriptionTemplateTypeStatus + }, + // { + // prop: nameof(x => x.isExclude), + // languageName: 'DESCRIPTION-TEMPLATE-TYPE-LISTING.FIELDS.IS-EXCLUDE', + // pipe: this.pipeService.getPipe(IsExcludeTypePipe) + // }, + { + prop: nameof(x => x.createdAt), + sortable: true, + languageName: 'DESCRIPTION-TEMPLATE-TYPE-LISTING.FIELDS.CREATED-AT', + pipe: this.pipeService.getPipe(DataTableDateTimeFormatPipe).withFormat('short') + }, + { + prop: nameof(x => x.updatedAt), + sortable: true, + languageName: 'DESCRIPTION-TEMPLATE-TYPE-LISTING.FIELDS.UPDATED-AT', + pipe: this.pipeService.getPipe(DataTableDateTimeFormatPipe).withFormat('short') + }, + { + alwaysShown: true, + cellTemplate: this.actions, + maxWidth: 120 + } + ]); + this.propertiesAvailableForOrder = this.gridColumns.filter(x => x.sortable); + } + + // + // Listing Component functions + // + onColumnsChanged(event: ColumnsChangedEvent) { + super.onColumnsChanged(event); + this.onColumnsChangedInternal(event.properties.map(x => x.toString())); + } + + private onColumnsChangedInternal(columns: string[]) { + // Here are defined the projection fields that always requested from the api. + const fields = new Set(this.lookupFields); + this.gridColumns.map(x => x.prop) + .filter(x => !columns?.includes(x as string)) + .forEach(item => { + fields.delete(item as string) + }); + this.lookup.project = { fields: [...fields] }; + this.onPageLoad({ offset: 0 } as PageLoadEvent); + } + + protected loadListing(): Observable> { + return this.descriptionTemplateTypeService.query(this.lookup); + } + + public deleteType(id: Guid) { + if (id) { + const dialogRef = this.dialog.open(ConfirmationDialogComponent, { + maxWidth: '300px', + data: { + message: this.language.instant('GENERAL.CONFIRMATION-DIALOG.DELETE-ITEM'), + confirmButton: this.language.instant('GENERAL.CONFIRMATION-DIALOG.ACTIONS.CONFIRM'), + cancelButton: this.language.instant('GENERAL.CONFIRMATION-DIALOG.ACTIONS.CANCEL') + } + }); + dialogRef.afterClosed().pipe(takeUntil(this._destroyed)).subscribe(result => { + if (result) { + this.descriptionTemplateTypeService.delete(id).pipe(takeUntil(this._destroyed)) + .subscribe( + complete => this.onCallbackSuccess(), + error => this.onCallbackError(error) + ); + } + }); + } + } + + onCallbackSuccess(): void { + this.uiNotificationService.snackBarNotification(this.language.instant('GENERAL.SNACK-BAR.SUCCESSFUL-DELETE'), SnackBarNotificationLevel.Success); + this.ngOnInit(); + } +} diff --git a/dmp-frontend/src/app/ui/admin/description-types/listing/description-types.component.html b/dmp-frontend/src/app/ui/admin/description-types/listing/description-types.component.html deleted file mode 100644 index 2ee578c4e..000000000 --- a/dmp-frontend/src/app/ui/admin/description-types/listing/description-types.component.html +++ /dev/null @@ -1,54 +0,0 @@ -
-
-
-
-

{{'DESCRIPTION-TYPES-LISTING.TITLE' | translate}}

-
-
-
- -
-
- - -
- - - - - - {{'DESCRIPTION-TYPES-LISTING.COLUMNS.NAME' | translate}} - {{row.name}} - - - - {{'DESCRIPTION-TYPES-LISTING.COLUMNS.STATUS' | - translate}} - -
{{parseStatus(row.status) | translate}}
-
-
- - - - - - - - - - - -
- - -
-
-
\ No newline at end of file diff --git a/dmp-frontend/src/app/ui/admin/description-types/listing/description-types.component.ts b/dmp-frontend/src/app/ui/admin/description-types/listing/description-types.component.ts deleted file mode 100644 index 3e5176d97..000000000 --- a/dmp-frontend/src/app/ui/admin/description-types/listing/description-types.component.ts +++ /dev/null @@ -1,173 +0,0 @@ -import { DataSource } from '@angular/cdk/table'; -import { HttpErrorResponse } from '@angular/common/http'; -import { Component, EventEmitter, OnInit, ViewChild } from '@angular/core'; -import { MatDialog } from '@angular/material/dialog'; -import { MatPaginator } from '@angular/material/paginator'; -import { MatSort } from '@angular/material/sort'; -import { Router } from '@angular/router'; -import { DescriptionTemplateType } from '@app/core/model/description-template-type/description-template-type'; -import { DescriptionTemplateTypeLookup } from '@app/core/query/description-template/description-template-type.lookup'; -import { DescriptionTemplateTypeService } from '@app/core/services/description-template-type/description-template-type.service'; -import { SnackBarNotificationLevel, UiNotificationService } from '@app/core/services/notification/ui-notification-service'; -import { BaseComponent } from '@common/base/base.component'; -import { ConfirmationDialogComponent } from '@common/modules/confirmation-dialog/confirmation-dialog.component'; -import { TranslateService } from '@ngx-translate/core'; -import { Observable, merge } from 'rxjs'; -import { map, startWith, switchMap, takeUntil } from 'rxjs/operators'; -import { nameof } from 'ts-simple-nameof'; - -@Component({ - selector: 'app-description-types', - templateUrl: './description-types.component.html', - styleUrls: ['./description-types.component.scss'] -}) -export class DescriptionTypesComponent extends BaseComponent implements OnInit { - - @ViewChild(MatPaginator, { static: true }) _paginator: MatPaginator; - @ViewChild(MatSort, { static: true }) _sort: MatSort; - - dataSource: DescriptionTypesDataSource | null; - displayedColumns: String[] = ['label', 'status', 'delete']; - - statuses = [ - { value: '0', viewValue: 'DESCRIPTION-TYPES-LISTING.STATUS.DRAFT' }, - { value: '1', viewValue: 'DESCRIPTION-TYPES-LISTING.STATUS.FINALIZED' } - ]; - - constructor( - private descriptionTemplateTypeService: DescriptionTemplateTypeService, - private dialog: MatDialog, - private language: TranslateService, - private uiNotificationService: UiNotificationService, - private router: Router - ) { - super(); - } - - ngOnInit(): void { - this.refresh(); - } - - refresh() { - this.dataSource = new DescriptionTypesDataSource(this.descriptionTemplateTypeService, this._paginator, this._sort); - } - - rowClick(rowId: String) { - this.router.navigate(['description-types/' + rowId]); - } - - parseStatus(value: number): string { - const stringVal = value.toString() - try { - return this.statuses.find(status => status.value === stringVal).viewValue; - } catch { - return stringVal; - } - } - - deleteTemplate(id: string) { - if (id) { - const dialogRef = this.dialog.open(ConfirmationDialogComponent, { - restoreFocus: false, - data: { - message: this.language.instant('GENERAL.CONFIRMATION-DIALOG.DELETE-ITEM'), - confirmButton: this.language.instant('GENERAL.CONFIRMATION-DIALOG.ACTIONS.CONFIRM'), - cancelButton: this.language.instant('GENERAL.CONFIRMATION-DIALOG.ACTIONS.CANCEL'), - isDeleteConfirmation: true - } - }); - - dialogRef.afterClosed().pipe(takeUntil(this._destroyed)).subscribe(result => { - if (result) { - this.descriptionTemplateTypeService.delete(id) - .pipe(takeUntil(this._destroyed)) - .subscribe( - complete => { - this.uiNotificationService.snackBarNotification(this.language.instant('GENERAL.SNACK-BAR.SUCCESSFUL-DATASET-PROFILE-DELETE'), SnackBarNotificationLevel.Success); - this.refresh(); - }, - error => { - this.onCallbackError(error); - if (error.error.statusCode == 674) { - this.uiNotificationService.snackBarNotification(this.language.instant('GENERAL.SNACK-BAR.UNSUCCESSFUL-DATASET-PROFILE-DELETE'), SnackBarNotificationLevel.Error); - } else { - this.uiNotificationService.snackBarNotification(this.language.instant(error.message), SnackBarNotificationLevel.Error); - } - } - ); - } - }); - - } - } - - onCallbackError(errorResponse: HttpErrorResponse) { - this.uiNotificationService.snackBarNotification(errorResponse.message, SnackBarNotificationLevel.Warning); - } - - getStatusClass(status: number): string { - - if (status == 1) { - return 'status-chip-finalized' - } - - return 'status-chip-draft'; - } - -} - -export class DescriptionTypesDataSource extends DataSource { - - data: DescriptionTemplateType[] = []; - loadData: EventEmitter = new EventEmitter(); - - constructor( - private _service: DescriptionTemplateTypeService, - private _paginator: MatPaginator, - private _sort: MatSort - ) { - super(); - } - - connect(): Observable { - const dataChanges = [ - this._paginator.page, - this._sort.sortChange - ]; - - return merge(...dataChanges).pipe( - startWith(null), - switchMap(() => { - let lookup: DescriptionTemplateTypeLookup = new DescriptionTemplateTypeLookup(); - lookup.page = { - offset: this._paginator.pageIndex * this._paginator.pageSize, - size: this._paginator.pageSize - }, - lookup.project = { - fields: [ - nameof(x => x.id), - nameof(x => x.name), - nameof(x => x.status) - ] - }; - lookup.order = { - items: ['name'] - }; - return this._service.query(lookup) - }), - map(result => { - return result; - }), - map(result => { - if (!result) { return []; } - - this.data = result.items; - this._paginator.length = result.count; - return result.items; - })); - } - - disconnect() { - // No-op - } -} diff --git a/dmp-frontend/src/app/ui/admin/description-types/listing/filters/description-template-type-listing-filters.component.html b/dmp-frontend/src/app/ui/admin/description-types/listing/filters/description-template-type-listing-filters.component.html new file mode 100644 index 000000000..ad2bc860b --- /dev/null +++ b/dmp-frontend/src/app/ui/admin/description-types/listing/filters/description-template-type-listing-filters.component.html @@ -0,0 +1,36 @@ +
+ + + + + +
+
+
+

{{'DESCRIPTION-TEMPLATE-TYPE-LISTING.FILTER.TITLE' | translate}}

+ +
+ + + {{'DESCRIPTION-TEMPLATE-TYPE-LISTING.FILTER.IS-ACTIVE' | translate}} + + +
+ + +
+
+
+
+ + +
diff --git a/dmp-frontend/src/app/ui/admin/description-types/listing/filters/description-template-type-listing-filters.component.scss b/dmp-frontend/src/app/ui/admin/description-types/listing/filters/description-template-type-listing-filters.component.scss new file mode 100644 index 000000000..999f5a7c6 --- /dev/null +++ b/dmp-frontend/src/app/ui/admin/description-types/listing/filters/description-template-type-listing-filters.component.scss @@ -0,0 +1,25 @@ +.description-template-type-listing-filters { + +} + +::ng-deep.mat-mdc-menu-panel { + max-width: 100% !important; + height: 100% !important; +} + +:host::ng-deep.mat-mdc-menu-content:not(:empty) { + padding-top: 0 !important; +} + + +.filter-button{ + padding-top: .6rem; + padding-bottom: .6rem; + // .mat-icon{ + // font-size: 1.5em; + // width: 1.2em; + // height: 1.2em; + // } +} + + diff --git a/dmp-frontend/src/app/ui/admin/description-types/listing/filters/description-template-type-listing-filters.component.ts b/dmp-frontend/src/app/ui/admin/description-types/listing/filters/description-template-type-listing-filters.component.ts new file mode 100644 index 000000000..b03e6cbaf --- /dev/null +++ b/dmp-frontend/src/app/ui/admin/description-types/listing/filters/description-template-type-listing-filters.component.ts @@ -0,0 +1,94 @@ +import { Component, EventEmitter, Input, OnChanges, OnInit, Output, SimpleChanges } from '@angular/core'; +import { IsActive } from '@app/core/common/enum/is-active.enum'; +import { DescriptionTemplateTypeFilter } from '@app/core/query/description-template-type.lookup'; +import { EnumUtils } from '@app/core/services/utilities/enum-utils.service'; +import { BaseComponent } from '@common/base/base.component'; +import { nameof } from 'ts-simple-nameof'; + +@Component({ + selector: 'app-description-template-type-listing-filters', + templateUrl: './description-template-type-listing-filters.component.html', + styleUrls: ['./description-template-type-listing-filters.component.scss'] +}) +export class DescriptionTemplateTypeListingFiltersComponent extends BaseComponent implements OnInit, OnChanges { + + @Input() readonly filter: DescriptionTemplateTypeFilter; + @Output() filterChange = new EventEmitter(); + + // * State + internalFilters: DescriptionTemplateTypeListingFilters = this._getEmptyFilters(); + + protected appliedFilterCount: number = 0; + constructor( + public enumUtils: EnumUtils, + ) { super(); } + + ngOnInit() { + } + + ngOnChanges(changes: SimpleChanges): void { + const filterChange = changes[nameof(x => x.filter)]?.currentValue as DescriptionTemplateTypeFilter; + if (filterChange) { + this.updateFilters() + } + } + + + onSearchTermChange(searchTerm: string): void { + this.applyFilters() + } + + + protected updateFilters(): void { + this.internalFilters = this._parseToInternalFilters(this.filter); + this.appliedFilterCount = this._computeAppliedFilters(this.internalFilters); + } + + protected applyFilters(): void { + const { isActive, like } = this.internalFilters ?? {} + this.filterChange.emit({ + ...this.filter, + like, + isActive: isActive ? [IsActive.Active] : [IsActive.Inactive] + }) + } + + + private _parseToInternalFilters(inputFilter: DescriptionTemplateTypeFilter): DescriptionTemplateTypeListingFilters { + if (!inputFilter) { + return this._getEmptyFilters(); + } + + let { excludedIds, ids, isActive, like } = inputFilter; + + return { + isActive: (isActive ?? [])?.includes(IsActive.Active) || !isActive?.length, + like: like + } + + } + + private _getEmptyFilters(): DescriptionTemplateTypeListingFilters { + return { + isActive: true, + like: null, + } + } + + private _computeAppliedFilters(filters: DescriptionTemplateTypeListingFilters): number { + let count = 0; + if (filters?.isActive) { + count++ + } + return count; + } + + clearFilters() { + this.internalFilters = this._getEmptyFilters(); + } +} + +interface DescriptionTemplateTypeListingFilters { + isActive: boolean; + like: string; +} diff --git a/dmp-frontend/src/app/ui/admin/dmp-blueprint/dmp-blueprint.module.ts b/dmp-frontend/src/app/ui/admin/dmp-blueprint/dmp-blueprint.module.ts new file mode 100644 index 000000000..6560808e7 --- /dev/null +++ b/dmp-frontend/src/app/ui/admin/dmp-blueprint/dmp-blueprint.module.ts @@ -0,0 +1,43 @@ +import { DragDropModule } from '@angular/cdk/drag-drop'; +import { NgModule } from "@angular/core"; +import { AutoCompleteModule } from "@app/library/auto-complete/auto-complete.module"; +import { UrlListingModule } from '@app/library/url-listing/url-listing.module'; +import { CommonFormsModule } from '@common/forms/common-forms.module'; +import { ConfirmationDialogModule } from '@common/modules/confirmation-dialog/confirmation-dialog.module'; +import { HybridListingModule } from "@common/modules/hybrid-listing/hybrid-listing.module"; +import { TextFilterModule } from "@common/modules/text-filter/text-filter.module"; +import { UserSettingsModule } from "@common/modules/user-settings/user-settings.module"; +import { CommonUiModule } from '@common/ui/common-ui.module'; +import { NgxDropzoneModule } from "ngx-dropzone"; +import { DmpBlueprintRoutingModule } from './dmp-blueprint.routing'; +import { DmpBlueprintEditorComponent } from './editor/dmp-blueprint-editor.component'; +import { DmpBlueprintExternalAutocompleteFieldEditorComponent } from './editor/external-autocomplete/dmp-blueprint-external-autocomplete-field-editor.component'; +import { DialodConfirmationUploadDmpBlueprints } from './listing/criteria/dialog-confirmation-upload-blueprint/dialog-confirmation-upload-blueprints.component'; +import { DmpBlueprintCriteriaComponent } from './listing/criteria/dmp-blueprint-criteria.component'; +import { DmpBlueprintListingComponent } from './listing/dmp-blueprint-listing.component'; +import { DmpBlueprintListingFiltersComponent } from "./listing/filters/dmp-blueprint-listing-filters.component"; + +@NgModule({ + imports: [ + CommonUiModule, + CommonFormsModule, + UrlListingModule, + ConfirmationDialogModule, + DmpBlueprintRoutingModule, + NgxDropzoneModule, + DragDropModule, + AutoCompleteModule, + HybridListingModule, + TextFilterModule, + UserSettingsModule + ], + declarations: [ + DmpBlueprintEditorComponent, + DmpBlueprintListingComponent, + DmpBlueprintListingFiltersComponent, + DmpBlueprintCriteriaComponent, + DialodConfirmationUploadDmpBlueprints, + DmpBlueprintExternalAutocompleteFieldEditorComponent + ] +}) +export class DmpBlueprintModule { } diff --git a/dmp-frontend/src/app/ui/admin/dmp-blueprint/dmp-blueprint.routing.ts b/dmp-frontend/src/app/ui/admin/dmp-blueprint/dmp-blueprint.routing.ts new file mode 100644 index 000000000..1df605221 --- /dev/null +++ b/dmp-frontend/src/app/ui/admin/dmp-blueprint/dmp-blueprint.routing.ts @@ -0,0 +1,18 @@ +import { NgModule } from '@angular/core'; +import { RouterModule, Routes } from '@angular/router'; +import { AdminAuthGuard } from '@app/core/admin-auth-guard.service'; +import { DmpBlueprintEditorComponent } from './editor/dmp-blueprint-editor.component'; +import { DmpBlueprintListingComponent } from './listing/dmp-blueprint-listing.component'; + +const routes: Routes = [ + { path: '', component: DmpBlueprintListingComponent, canActivate: [AdminAuthGuard] }, + { path: 'new', component: DmpBlueprintEditorComponent, canActivate: [AdminAuthGuard], data: { title: 'GENERAL.TITLES.DMP-BLUEPRINT-NEW' } }, + { path: 'clone/:cloneid', component: DmpBlueprintEditorComponent, canActivate: [AdminAuthGuard], data: { title: 'GENERAL.TITLES.DMP-BLUEPRINT-CLONE' } }, + { path: ':id', component: DmpBlueprintEditorComponent, canActivate: [AdminAuthGuard], data: { title: 'GENERAL.TITLES.DMP-BLUEPRINT-EDIT' } }, +]; + +@NgModule({ + imports: [RouterModule.forChild(routes)], + exports: [RouterModule] +}) +export class DmpBlueprintRoutingModule { } diff --git a/dmp-frontend/src/app/ui/admin/dmp-profile/editor/dmp-profile-editor.component.html b/dmp-frontend/src/app/ui/admin/dmp-blueprint/editor/dmp-blueprint-editor.component.html similarity index 68% rename from dmp-frontend/src/app/ui/admin/dmp-profile/editor/dmp-profile-editor.component.html rename to dmp-frontend/src/app/ui/admin/dmp-blueprint/editor/dmp-blueprint-editor.component.html index b044c607b..cb42939f1 100644 --- a/dmp-frontend/src/app/ui/admin/dmp-profile/editor/dmp-profile-editor.component.html +++ b/dmp-frontend/src/app/ui/admin/dmp-blueprint/editor/dmp-blueprint-editor.component.html @@ -1,10 +1,10 @@
-
+
-

{{'DMP-PROFILE-EDITOR.TITLE.NEW' | translate}}

+

{{'DMP-BLUEPRINT-EDITOR.TITLE.NEW' | translate}}

- {{'DMP-PROFILE-EDITOR.TITLE.NEW-PROFILE-CLONE' | translate}} + {{'DMP-BLUEPRINT-EDITOR.TITLE.CLONE' | translate}} {{formGroup.get('label').value}}

{{formGroup.get('label').value}}

@@ -13,23 +13,23 @@
+ type="button">{{'DMP-BLUEPRINT-EDITOR.ACTIONS.DOWNLOAD-XML' | translate }}
+ [disabled]="!this.isFormValid()" type="button">{{'DMP-BLUEPRINT-EDITOR.ACTIONS.FINALIZE' | translate }}
@@ -267,7 +267,7 @@
-->
delete - {{'DATASET-PROFILE-EDITOR.STEPS.TOOLKIT.DELETE' | translate}} + {{'DMP-BLUEPRINT-EDITOR.STEPS.TOOLKIT.DELETE' | translate}}
@@ -285,105 +285,15 @@
- -
- +
- -
diff --git a/dmp-frontend/src/app/ui/admin/dmp-profile/editor/dmp-profile-editor.component.scss b/dmp-frontend/src/app/ui/admin/dmp-blueprint/editor/dmp-blueprint-editor.component.scss similarity index 98% rename from dmp-frontend/src/app/ui/admin/dmp-profile/editor/dmp-profile-editor.component.scss rename to dmp-frontend/src/app/ui/admin/dmp-blueprint/editor/dmp-blueprint-editor.component.scss index 6cc8ea3a0..fa59f8200 100644 --- a/dmp-frontend/src/app/ui/admin/dmp-profile/editor/dmp-profile-editor.component.scss +++ b/dmp-frontend/src/app/ui/admin/dmp-blueprint/editor/dmp-blueprint-editor.component.scss @@ -1,4 +1,4 @@ -.dmp-profile-editor { +.dmp-blueprint-editor { margin-top: 1.3rem; margin-left: 1em; margin-right: 3em; diff --git a/dmp-frontend/src/app/ui/admin/dmp-profile/editor/dmp-profile-editor.component.ts b/dmp-frontend/src/app/ui/admin/dmp-blueprint/editor/dmp-blueprint-editor.component.ts similarity index 64% rename from dmp-frontend/src/app/ui/admin/dmp-profile/editor/dmp-profile-editor.component.ts rename to dmp-frontend/src/app/ui/admin/dmp-blueprint/editor/dmp-blueprint-editor.component.ts index bb0a2d8a0..7dff3cc02 100644 --- a/dmp-frontend/src/app/ui/admin/dmp-profile/editor/dmp-profile-editor.component.ts +++ b/dmp-frontend/src/app/ui/admin/dmp-blueprint/editor/dmp-blueprint-editor.component.ts @@ -1,85 +1,80 @@ -import { AfterViewInit, Component, ViewChild } from '@angular/core'; -import { UntypedFormArray, UntypedFormBuilder, FormControl, UntypedFormGroup, Validators } from '@angular/forms'; +import { CdkDragDrop, moveItemInArray } from '@angular/cdk/drag-drop'; +import { HttpClient } from '@angular/common/http'; +import { AfterViewInit, Component } from '@angular/core'; +import { UntypedFormArray, UntypedFormBuilder, UntypedFormGroup } from '@angular/forms'; +import { MatDialog } from '@angular/material/dialog'; import { ActivatedRoute, Params, Router } from '@angular/router'; -import { DmpProfileFieldDataType } from '@app/core/common/enum/dmp-profile-field-type'; -import { DmpProfileStatus } from '@app/core/common/enum/dmp-profile-status'; -import { DmpProfileType } from '@app/core/common/enum/dmp-profile-type'; -import { DmpProfile } from '@app/core/model/dmp-profile/dmp-profile'; -import { DmpProfileService } from '@app/core/services/dmp/dmp-profile.service'; +import { DmpBlueprintFieldDataType } from '@app/core/common/enum/dmp-blueprint-field-type'; +import { DmpBlueprintStatus } from '@app/core/common/enum/dmp-blueprint-status'; +import { DmpBlueprintType } from '@app/core/common/enum/dmp-blueprint-type'; +import { DataTableRequest } from '@app/core/model/data-table/data-table-request'; +import { DatasetProfileModel } from '@app/core/model/dataset/dataset-profile'; +import { DmpBlueprint, ExtraFieldType, FieldCategory, SystemFieldType } from '@app/core/model/dmp/dmp-blueprint/dmp-blueprint'; +import { DatasetProfileCriteria } from '@app/core/query/dataset-profile/dataset-profile-criteria'; +import { ConfigurationService } from '@app/core/services/configuration/configuration.service'; +import { DmpBlueprintService } from '@app/core/services/dmp/dmp-blueprint.service'; +import { DmpService } from '@app/core/services/dmp/dmp.service'; +import { MatomoService } from '@app/core/services/matomo/matomo-service'; import { SnackBarNotificationLevel, UiNotificationService } from '@app/core/services/notification/ui-notification-service'; import { EnumUtils } from '@app/core/services/utilities/enum-utils.service'; -import { DmpProfileEditorModel, DmpProfileFieldEditorModel } from '@app/ui/admin/dmp-profile/editor/dmp-profile-editor.model'; -import { DmpProfileExternalAutoCompleteFieldDataEditorModel } from '@app/ui/admin/dmp-profile/editor/external-autocomplete/dmp-profile-external-autocomplete-field-editor.model'; -import { BreadcrumbItem } from '@app/ui/misc/breadcrumb/definition/breadcrumb-item'; +import { MultipleAutoCompleteConfiguration } from '@app/library/auto-complete/multiple/multiple-auto-complete-configuration'; +import { DmpBlueprintExternalAutoCompleteFieldDataEditorModel } from '@app/ui/admin/dmp-blueprint/editor/external-autocomplete/dmp-blueprint-external-autocomplete-field-editor.model'; +// import { BreadcrumbItem } from '@app/ui/misc/breadcrumb/definition/breadcrumb-item'; +import { isNullOrUndefined } from '@app/utilities/enhancers/utils'; import { BaseComponent } from '@common/base/base.component'; import { FormService } from '@common/forms/form-service'; +import { FormValidationErrorsDialogComponent } from '@common/forms/form-validation-errors-dialog/form-validation-errors-dialog.component'; import { ValidationErrorModel } from '@common/forms/validation/error-model/validation-error-model'; +import { ConfirmationDialogComponent } from '@common/modules/confirmation-dialog/confirmation-dialog.component'; +import { Guid } from '@common/types/guid'; import { TranslateService } from '@ngx-translate/core'; -import { environment } from 'environments/environment'; import * as FileSaver from 'file-saver'; import { Observable, of as observableOf } from 'rxjs'; import { map, takeUntil } from 'rxjs/operators'; -import { ConfigurationService } from '@app/core/services/configuration/configuration.service'; -import { HttpClient } from '@angular/common/http'; -import { MatomoService } from '@app/core/services/matomo/matomo-service'; -import { MatDialog } from '@angular/material/dialog'; -import { ConfirmationDialogComponent } from '@common/modules/confirmation-dialog/confirmation-dialog.component'; -import { MultipleAutoCompleteConfiguration } from '@app/library/auto-complete/multiple/multiple-auto-complete-configuration'; -import { DatasetProfileModel } from '@app/core/model/dataset/dataset-profile'; -import { DataTableRequest } from '@app/core/model/data-table/data-table-request'; -import { DatasetProfileCriteria } from '@app/core/query/dataset-profile/dataset-profile-criteria'; -import { DmpService } from '@app/core/services/dmp/dmp.service'; -import { AvailableProfilesComponent } from '@app/ui/dmp/editor/available-profiles/available-profiles.component'; -import { DatasetPreviewDialogComponent } from '@app/ui/dmp/dataset-preview/dataset-preview-dialog.component'; -import { CdkDragDrop, CdkDropList, CdkDrag, moveItemInArray } from '@angular/cdk/drag-drop'; -import { DmpBlueprint, DmpBlueprintDefinition, ExtraFieldType, FieldCategory, SystemFieldType } from '@app/core/model/dmp/dmp-blueprint/dmp-blueprint'; import { DescriptionTemplatesInSectionEditor, DmpBlueprintEditor, FieldInSectionEditor, SectionDmpBlueprintEditor } from './dmp-blueprint-editor.model'; -import { Guid } from '@common/types/guid'; -import { isNullOrUndefined } from '@app/utilities/enhancers/utils'; -import { DmpBlueprintListing } from '@app/core/model/dmp/dmp-blueprint/dmp-blueprint-listing'; -import { FormValidationErrorsDialogComponent } from '@common/forms/form-validation-errors-dialog/form-validation-errors-dialog.component'; +import { DmpBlueprintEditorModel } from './dmp-profile-editor.model'; @Component({ - selector: 'app-dmp-profile-editor-component', - templateUrl: 'dmp-profile-editor.component.html', - styleUrls: ['./dmp-profile-editor.component.scss'] + selector: 'app-dmp-blueprint-editor-component', + templateUrl: 'dmp-blueprint-editor.component.html', + styleUrls: ['./dmp-blueprint-editor.component.scss'] }) -export class DmpProfileEditorComponent extends BaseComponent implements AfterViewInit { +export class DmpBlueprintEditorComponent extends BaseComponent implements AfterViewInit { isNew = true; isClone = false; viewOnly = false; - dmpProfileModel: DmpProfileEditorModel; - dmpBlueprintModel: DmpBlueprintEditor; + dmpBlueprintEditorModel = new DmpBlueprintEditorModel(); + dmpBlueprintEditor = new DmpBlueprintEditor(); formGroup: UntypedFormGroup = null; host: string; - dmpProfileId: string; - breadCrumbs: Observable; + dmpBlueprintId: string; + // breadCrumbs: Observable; dmpBlueprintsFormGroup: UntypedFormGroup = null; - profilesAutoCompleteConfiguration: MultipleAutoCompleteConfiguration; + blueprintsAutoCompleteConfiguration: MultipleAutoCompleteConfiguration; fieldList = [ - {label: 'Title', type: SystemFieldType.TEXT}, - {label: 'Description', type: SystemFieldType.HTML_TEXT}, - {label: 'Researchers', type: SystemFieldType.RESEARCHERS}, - {label: 'Organizations', type: SystemFieldType.ORGANIZATIONS}, - {label: 'Language', type: SystemFieldType.LANGUAGE}, - {label: 'Contact', type: SystemFieldType.CONTACT}, - {label: 'Funder', type: SystemFieldType.FUNDER}, - {label: 'Grant', type: SystemFieldType.GRANT}, - {label: 'Project', type: SystemFieldType.PROJECT}, - {label: 'License', type: SystemFieldType.LICENSE}, - {label: 'Access Rights', type: SystemFieldType.ACCESS_RIGHTS} + { label: 'Title', type: SystemFieldType.TEXT }, + { label: 'Description', type: SystemFieldType.HTML_TEXT }, + { label: 'Researchers', type: SystemFieldType.RESEARCHERS }, + { label: 'Organizations', type: SystemFieldType.ORGANIZATIONS }, + { label: 'Language', type: SystemFieldType.LANGUAGE }, + { label: 'Contact', type: SystemFieldType.CONTACT }, + { label: 'Funder', type: SystemFieldType.FUNDER }, + { label: 'Grant', type: SystemFieldType.GRANT }, + { label: 'Project', type: SystemFieldType.PROJECT }, + { label: 'License', type: SystemFieldType.LICENSE }, + { label: 'Access Rights', type: SystemFieldType.ACCESS_RIGHTS } ]; systemFieldListPerSection: Array> = new Array(); descriptionTemplatesPerSection: Array> = new Array>(); constructor( - private dmpProfileService: DmpProfileService, + private dmpBlueprintService: DmpBlueprintService, private _service: DmpService, private route: ActivatedRoute, private router: Router, @@ -100,7 +95,7 @@ export class DmpProfileEditorComponent extends BaseComponent implements AfterVie ngAfterViewInit() { this.matomoService.trackPageView('Admin: DMP Profile Edit'); - this.profilesAutoCompleteConfiguration = { + this.blueprintsAutoCompleteConfiguration = { filterFn: this.filterProfiles.bind(this), initialItems: (excludedItems: any[]) => this.filterProfiles('').pipe(map(result => result.filter(resultItem => (excludedItems || []).map(x => x.id).indexOf(resultItem.id) === -1))), displayFn: (item) => item['label'], @@ -112,67 +107,67 @@ export class DmpProfileEditorComponent extends BaseComponent implements AfterVie this.route.params .pipe(takeUntil(this._destroyed)) .subscribe((params: Params) => { - this.dmpProfileId = params['id']; + this.dmpBlueprintId = params['id']; const cloneId = params['cloneid']; - if (this.dmpProfileId != null) { + if (this.dmpBlueprintId != null) { this.isNew = false; - this.dmpProfileService.getSingleBlueprint(this.dmpProfileId).pipe(map(data => data as DmpBlueprint)) + this.dmpBlueprintService.getSingleBlueprint(this.dmpBlueprintId).pipe(map(data => data as any)) .pipe(takeUntil(this._destroyed)) .subscribe(data => { - this.dmpBlueprintModel = new DmpBlueprintEditor().fromModel(data); - this.formGroup = this.dmpBlueprintModel.buildForm(); + this.dmpBlueprintEditor = new DmpBlueprintEditor().fromModel(data); + this.formGroup = this.dmpBlueprintEditor.buildForm(); this.buildSystemFields(); this.fillDescriptionTemplatesInMultAutocomplete(); - if (this.dmpBlueprintModel.status == DmpProfileStatus.Finalized) { + if (this.dmpBlueprintEditor.status == DmpBlueprintStatus.Finalized) { this.formGroup.disable(); this.viewOnly = true } - this.breadCrumbs = observableOf([{ - parentComponentName: 'DmpProfileListingComponent', - label: this.language.instant('NAV-BAR.TEMPLATE'), - url: '/dmp-profiles/' + this.dmpProfileId - }]); + // this.breadCrumbs = observableOf([{ + // parentComponentName: 'DmpBlueprintListingComponent', + // label: this.language.instant('NAV-BAR.TEMPLATE'), + // url: '/dmp-blueprints/' + this.dmpBlueprintId + // }]); }); } else if (cloneId != null) { this.isClone = true; - this.dmpProfileService.clone(cloneId).pipe(map(data => data as DmpBlueprint), takeUntil(this._destroyed)) + this.dmpBlueprintService.clone(cloneId).pipe(map(data => data as any), takeUntil(this._destroyed)) .subscribe( data => { - this.dmpBlueprintModel = new DmpBlueprintEditor().fromModel(data); - this.dmpBlueprintModel.id = null; - this.dmpBlueprintModel.status = DmpProfileStatus.Draft; - this.formGroup = this.dmpBlueprintModel.buildForm(); + this.dmpBlueprintEditor = new DmpBlueprintEditor().fromModel(data); + this.dmpBlueprintEditor.id = null; + this.dmpBlueprintEditor.status = DmpBlueprintStatus.Draft; + this.formGroup = this.dmpBlueprintEditor.buildForm(); this.buildSystemFields(); this.fillDescriptionTemplatesInMultAutocomplete(); }, error => this.onCallbackError(error) ); } else { - this.dmpProfileModel = new DmpProfileEditorModel(); - this.dmpBlueprintModel = new DmpBlueprintEditor(); + this.dmpBlueprintEditorModel = new DmpBlueprintEditorModel(); + this.dmpBlueprintEditor = new DmpBlueprintEditor(); setTimeout(() => { - // this.formGroup = this.dmpProfileModel.buildForm(); + // this.formGroup = this.dmpBlueprintModel.buildForm(); // this.addField(); - this.dmpBlueprintModel.status = DmpProfileStatus.Draft; - this.formGroup = this.dmpBlueprintModel.buildForm(); + this.dmpBlueprintEditor.status = DmpBlueprintStatus.Draft; + this.formGroup = this.dmpBlueprintEditor.buildForm(); }); - this.breadCrumbs = observableOf([{ - parentComponentName: 'DmpProfileListingComponent', - label: this.language.instant('NAV-BAR.TEMPLATE'), - url: '/dmp-profiles/' + this.dmpProfileId - }]); + // this.breadCrumbs = observableOf([{ + // parentComponentName: 'DmpBlueprintListingComponent', + // label: this.language.instant('NAV-BAR.TEMPLATE'), + // url: '/dmp-blueprints/' + this.dmpBlueprintId + // }]); } }); } - buildSystemFields(){ + buildSystemFields() { const sections = this.sectionsArray().controls.length; - for(let i = 0; i < sections; i++){ + for (let i = 0; i < sections; i++) { let systemFieldsInSection = new Array(); this.fieldsArray(i).controls.forEach((field) => { - if((field.get('category').value == FieldCategory.SYSTEM || field.get('category').value == 'SYSTEM')){ + if ((field.get('category').value == FieldCategory.SYSTEM || field.get('category').value == 'SYSTEM')) { systemFieldsInSection.push(this.fieldList.find(f => f.type == field.get('type').value).type); } }) @@ -180,12 +175,12 @@ export class DmpProfileEditorComponent extends BaseComponent implements AfterVie } } - fillDescriptionTemplatesInMultAutocomplete(){ + fillDescriptionTemplatesInMultAutocomplete() { const sections = this.sectionsArray().controls.length; - for(let i = 0; i < sections; i++){ + for (let i = 0; i < sections; i++) { let descriptionTemplatesInSection = new Array(); this.descriptionTemplatesArray(i).controls.forEach((template) => { - descriptionTemplatesInSection.push({id: template.value.descriptionTemplateId, label: template.value.label, description: ""}); + descriptionTemplatesInSection.push({ id: template.value.descriptionTemplateId, label: template.value.label, description: "" }); }) this.descriptionTemplatesPerSection.push(descriptionTemplatesInSection); } @@ -203,7 +198,7 @@ export class DmpProfileEditorComponent extends BaseComponent implements AfterVie const criteria = new DatasetProfileCriteria(); criteria.like = value; request.criteria = criteria; - return this._service.searchDMPProfiles(request); + return this._service.searchDmpBlueprints(request); } sectionsArray(): UntypedFormArray { @@ -231,19 +226,19 @@ export class DmpProfileEditorComponent extends BaseComponent implements AfterVie fieldsArray(sectionIndex: number): UntypedFormArray { return this.sectionsArray().at(sectionIndex).get('fields') as UntypedFormArray; } - + addField(sectionIndex: number, fieldCategory: FieldCategory, fieldType?: number): void { const field: FieldInSectionEditor = new FieldInSectionEditor(); field.id = Guid.create().toString(); field.ordinal = this.fieldsArray(sectionIndex).length + 1; field.category = fieldCategory; - if(!isNullOrUndefined(fieldType)){ + if (!isNullOrUndefined(fieldType)) { field.type = fieldType } field.required = (!isNullOrUndefined(fieldType) && (fieldType == 0 || fieldType == 1)) ? true : false; this.fieldsArray(sectionIndex).push(field.buildForm()); } - + removeField(sectionIndex: number, fieldIndex: number): void { this.fieldsArray(sectionIndex).removeAt(fieldIndex); } @@ -263,12 +258,12 @@ export class DmpProfileEditorComponent extends BaseComponent implements AfterVie ordinal: this.fb.control('') }); } - + addSystemField(sectionIndex: number, systemField?: SystemFieldType): void { this.addField(sectionIndex, FieldCategory.SYSTEM, systemField); } - transfromEnumToString(type: SystemFieldType): string{ + transfromEnumToString(type: SystemFieldType): string { return this.fieldList.find(f => f.type == type).label; } @@ -277,7 +272,7 @@ export class DmpProfileEditorComponent extends BaseComponent implements AfterVie if (index == -1) { this.systemFieldListPerSection[sectionIndex].push(type); this.addSystemField(sectionIndex, type); - } + } else { this.systemFieldListPerSection[sectionIndex].splice(index, 1); this.removeSystemField(sectionIndex, type); @@ -298,7 +293,7 @@ export class DmpProfileEditorComponent extends BaseComponent implements AfterVie } return false; } - + removeSystemFieldWithIndex(sectionIndex: number, fieldIndex: number): void { let type: SystemFieldType = this.fieldsArray(sectionIndex).at(fieldIndex).get('type').value; let index = this.systemFieldListPerSection[sectionIndex].indexOf(type); @@ -308,8 +303,8 @@ export class DmpProfileEditorComponent extends BaseComponent implements AfterVie removeSystemField(sectionIndex: number, systemField: SystemFieldType): void { let i = 0; - for(let f of this.fieldsArray(sectionIndex).controls){ - if((f.get('category').value == FieldCategory.SYSTEM || f.get('category').value == 'SYSTEM') && f.get('type').value == systemField){ + for (let f of this.fieldsArray(sectionIndex).controls) { + if ((f.get('category').value == FieldCategory.SYSTEM || f.get('category').value == 'SYSTEM') && f.get('type').value == systemField) { this.fieldsArray(sectionIndex).removeAt(i); return; } @@ -326,19 +321,19 @@ export class DmpProfileEditorComponent extends BaseComponent implements AfterVie label: this.fb.control(descriptionTemplate.value) })); } - + removeDescriptionTemplate(sectionIndex: number, templateIndex: number): void { this.descriptionTemplatesArray(sectionIndex).removeAt(templateIndex); } extraFieldsArray(sectionIndex: number): UntypedFormArray { return this.sectionsArray().at(sectionIndex).get('extraFields') as UntypedFormArray; - } + } addExtraField(sectionIndex: number): void { this.addField(sectionIndex, FieldCategory.EXTRA); } - + removeExtraField(sectionIndex: number, fieldIndex: number): void { this.fieldsArray(sectionIndex).removeAt(fieldIndex); } @@ -361,12 +356,12 @@ export class DmpProfileEditorComponent extends BaseComponent implements AfterVie drop(event: CdkDragDrop, sectionIndex: number) { moveItemInArray(this.fieldsArray(sectionIndex).controls, event.previousIndex, event.currentIndex); - moveItemInArray(this.fieldsArray(sectionIndex).value, event.previousIndex, event.currentIndex); + moveItemInArray(this.fieldsArray(sectionIndex).value, event.previousIndex, event.currentIndex); } dropSections(event: CdkDragDrop) { moveItemInArray(this.sectionsArray().controls, event.previousIndex, event.currentIndex); - moveItemInArray(this.sectionsArray().value, event.previousIndex, event.currentIndex); + moveItemInArray(this.sectionsArray().value, event.previousIndex, event.currentIndex); this.sectionsArray().controls.forEach((section, index) => { section.get('ordinal').setValue(index + 1); }); @@ -374,22 +369,22 @@ export class DmpProfileEditorComponent extends BaseComponent implements AfterVie moveItemInFormArray(formArray: UntypedFormArray, fromIndex: number, toIndex: number): void { const dir = toIndex > fromIndex ? 1 : -1; - + const item = formArray.at(fromIndex); for (let i = fromIndex; i * dir < toIndex * dir; i = i + dir) { - const current = formArray.at(i + dir); - formArray.setControl(i, current); + const current = formArray.at(i + dir); + formArray.setControl(i, current); } formArray.setControl(toIndex, item); } - + // clearForm(): void{ // this.dmpBlueprintsFormGroup.reset(); // } onRemoveTemplate(event, sectionIndex: number) { - const profiles = this.descriptionTemplatesArray(sectionIndex).controls; - const foundIndex = profiles.findIndex(profile => profile.get('descriptionTemplateId').value === event.id); + const blueprints = this.descriptionTemplatesArray(sectionIndex).controls; + const foundIndex = blueprints.findIndex(blueprint => blueprint.get('descriptionTemplateId').value === event.id); foundIndex !== -1 && this.descriptionTemplatesArray(sectionIndex).removeAt(foundIndex); } @@ -405,14 +400,14 @@ export class DmpProfileEditorComponent extends BaseComponent implements AfterVie // }); // dialogRef.afterClosed().pipe(takeUntil(this._destroyed)).subscribe(result => { // if (result) { - // let profiles = this.sectionsArray().at(sectionIndex).get('descriptionTemplates').value;//this.formGroup.get('profiles').value; - // const profile: DescriptionTemplatesInSectionEditor = new DescriptionTemplatesInSectionEditor(); - // profile.id = Guid.create().toString(); - // profile.descriptionTemplateId = event.id; - // profile.label = event.label; - // profiles.push(profile.buildForm()); - // this.sectionsArray().at(sectionIndex).get('descriptionTemplates').setValue(profiles);//this.formGroup.get('profiles').setValue(profiles); - // this.profilesAutoCompleteConfiguration = { + // let blueprints = this.sectionsArray().at(sectionIndex).get('descriptionTemplates').value;//this.formGroup.get('blueprints').value; + // const blueprint: DescriptionTemplatesInSectionEditor = new DescriptionTemplatesInSectionEditor(); + // blueprint.id = Guid.create().toString(); + // blueprint.descriptionTemplateId = event.id; + // blueprint.label = event.label; + // blueprints.push(blueprint.buildForm()); + // this.sectionsArray().at(sectionIndex).get('descriptionTemplates').setValue(blueprints);//this.formGroup.get('blueprints').setValue(blueprints); + // this.blueprintsAutoCompleteConfiguration = { // filterFn: this.filterProfiles.bind(this), // initialItems: (excludedItems: any[]) => this.filterProfiles('').pipe(map(result => result.filter(resultItem => (excludedItems || []).map(x => x.id).indexOf(resultItem.id) === -1))), // displayFn: (item) => item['label'], @@ -424,28 +419,28 @@ export class DmpProfileEditorComponent extends BaseComponent implements AfterVie // }); // } - onOptionSelected(item, sectionIndex){ - const profile: DescriptionTemplatesInSectionEditor = new DescriptionTemplatesInSectionEditor(); - profile.id = Guid.create().toString(); - profile.descriptionTemplateId = item.id; - profile.label = item.label; - this.descriptionTemplatesArray(sectionIndex).push(profile.buildForm()); + onOptionSelected(item, sectionIndex) { + const blueprint: DescriptionTemplatesInSectionEditor = new DescriptionTemplatesInSectionEditor(); + blueprint.id = Guid.create().toString(); + blueprint.descriptionTemplateId = item.id; + blueprint.label = item.label; + this.descriptionTemplatesArray(sectionIndex).push(blueprint.buildForm()); } checkValidity() { this.formService.touchAllFormFields(this.formGroup); if (!this.isFormValid()) { return false; } let errorMessages = []; - if(!this.hasTitle()) { + if (!this.hasTitle()) { errorMessages.push("Title should be set."); } - if(!this.hasDescription()) { + if (!this.hasDescription()) { errorMessages.push("Description should be set."); } - if(!this.hasDescriptionTemplates()) { + if (!this.hasDescriptionTemplates()) { errorMessages.push("At least one section should have description templates."); } - if(errorMessages.length > 0) { + if (errorMessages.length > 0) { this.showValidationErrorsDialog(undefined, errorMessages); return false; } @@ -483,7 +478,7 @@ export class DmpProfileEditorComponent extends BaseComponent implements AfterVie autoFocus: false, restoreFocus: false, data: { - errorMessages:errmess, + errorMessages: errmess, projectOnly: projectOnly }, }); @@ -491,7 +486,7 @@ export class DmpProfileEditorComponent extends BaseComponent implements AfterVie } onSubmit(): void { - this.dmpProfileService.createBlueprint(this.formGroup.value) + this.dmpBlueprintService.createBlueprint(this.formGroup.value) .pipe(takeUntil(this._destroyed)) .subscribe( complete => this.onCallbackSuccess(), @@ -501,7 +496,7 @@ export class DmpProfileEditorComponent extends BaseComponent implements AfterVie onCallbackSuccess(): void { this.uiNotificationService.snackBarNotification(this.isNew ? this.language.instant('GENERAL.SNACK-BAR.SUCCESSFUL-CREATION') : this.language.instant('GENERAL.SNACK-BAR.SUCCESSFUL-UPDATE'), SnackBarNotificationLevel.Success); - this.router.navigate(['/dmp-profiles']); + this.router.navigate(['/dmp-blueprints']); } onCallbackError(errorResponse: any) { @@ -511,32 +506,32 @@ export class DmpProfileEditorComponent extends BaseComponent implements AfterVie public setErrorModel(validationErrorModel: ValidationErrorModel) { Object.keys(validationErrorModel).forEach(item => { - (this.dmpProfileModel.validationErrorModel)[item] = (validationErrorModel)[item]; + (this.dmpBlueprintEditor.validationErrorModel)[item] = (validationErrorModel)[item]; }); } public cancel(): void { - this.router.navigate(['/dmp-profiles']); + this.router.navigate(['/dmp-blueprints']); } // addField() { - // (this.formGroup.get('definition').get('fields')).push(new DmpProfileFieldEditorModel().buildForm()); + // (this.formGroup.get('definition').get('fields')).push(new DmpBlueprintFieldEditorModel().buildForm()); // } // removeField(index: number) { // (this.formGroup.get('definition').get('fields')).controls.splice(index, 1); // } - getDMPProfileFieldDataTypeValues(): Number[] { - let keys: string[] = Object.keys(DmpProfileFieldDataType); + getDmpBlueprintFieldDataTypeValues(): Number[] { + let keys: string[] = Object.keys(DmpBlueprintFieldDataType); keys = keys.slice(0, keys.length / 2); const values: Number[] = keys.map(Number); return values; } - getDMPProfileFieldDataTypeWithLanguage(fieldType: DmpProfileFieldDataType): string { + getDmpBlueprintFieldDataTypeWithLanguage(fieldType: DmpBlueprintFieldDataType): string { let result = ''; - this.language.get(this.enumUtils.toDmpProfileFieldDataTypeString(fieldType)) + this.language.get(this.enumUtils.toDmpBlueprintFieldDataTypeString(fieldType)) .pipe(takeUntil(this._destroyed)) .subscribe((value: string) => { result = value; @@ -544,16 +539,16 @@ export class DmpProfileEditorComponent extends BaseComponent implements AfterVie return result; } - getDMPProfileFieldTypeValues(): Number[] { - let keys: string[] = Object.keys(DmpProfileType); + getDmpBlueprintFieldTypeValues(): Number[] { + let keys: string[] = Object.keys(DmpBlueprintType); keys = keys.slice(0, keys.length / 2); const values: Number[] = keys.map(Number); return values; } - getDMPProfileFieldTypeWithLanguage(profileType: DmpProfileType): string { + getDmpBlueprintFieldTypeWithLanguage(blueprintType: DmpBlueprintType): string { let result = ''; - this.language.get(this.enumUtils.toDmpProfileTypeString(profileType)) + this.language.get(this.enumUtils.toDmpBlueprintTypeString(blueprintType)) .pipe(takeUntil(this._destroyed)) .subscribe((value: string) => { result = value; @@ -562,54 +557,56 @@ export class DmpProfileEditorComponent extends BaseComponent implements AfterVie } delete() { - this.dialog.open(ConfirmationDialogComponent,{data:{ - isDeleteConfirmation: true, - confirmButton: this.language.instant('DMP-PROFILE-EDITOR.CONFIRM-DELETE-DIALOG.CONFIRM-BUTTON'), - cancelButton: this.language.instant("DMP-PROFILE-EDITOR.CONFIRM-DELETE-DIALOG.CANCEL-BUTTON"), - message: this.language.instant("DMP-PROFILE-EDITOR.CONFIRM-DELETE-DIALOG.MESSAGE") - }}) - .afterClosed() - .subscribe( - confirmed =>{ - if(confirmed){ - if(this.formGroup.get('status').value == DmpProfileStatus.Draft) { - this.formGroup.get('status').setValue(DmpProfileStatus.Deleted); - this.dmpProfileService.createBlueprint(this.formGroup.value) - .pipe(takeUntil(this._destroyed)) - .subscribe( - complete => this.onCallbackSuccess(), - error => this.onCallbackError(error) - ); - } - else { - this.dmpProfileService.delete(this.dmpProfileId) - .pipe(takeUntil(this._destroyed)) - .subscribe( - complete => this.onCallbackSuccess(), - error => { - if (error.error.statusCode == 674) { - this.uiNotificationService.snackBarNotification(this.language.instant('GENERAL.SNACK-BAR.UNSUCCESSFUL-DMP-BLUEPRINT-DELETE'), SnackBarNotificationLevel.Error); - } else { - this.uiNotificationService.snackBarNotification(this.language.instant(error.message), SnackBarNotificationLevel.Error); - } - } - ); + this.dialog.open(ConfirmationDialogComponent, { + data: { + isDeleteConfirmation: true, + confirmButton: this.language.instant('DMP-BLUEPRINT-EDITOR.CONFIRM-DELETE-DIALOG.CONFIRM-BUTTON'), + cancelButton: this.language.instant("DMP-BLUEPRINT-EDITOR.CONFIRM-DELETE-DIALOG.CANCEL-BUTTON"), + message: this.language.instant("DMP-BLUEPRINT-EDITOR.CONFIRM-DELETE-DIALOG.MESSAGE") + } + }) + .afterClosed() + .subscribe( + confirmed => { + if (confirmed) { + if (this.formGroup.get('status').value == DmpBlueprintStatus.Draft) { + // this.formGroup.get('status').setValue(DmpBlueprintStatus.Deleted); + this.dmpBlueprintService.createBlueprint(this.formGroup.value) + .pipe(takeUntil(this._destroyed)) + .subscribe( + complete => this.onCallbackSuccess(), + error => this.onCallbackError(error) + ); + } + else { + // this.dmpBlueprintService.delete(this.dmpBlueprintId) + // .pipe(takeUntil(this._destroyed)) + // .subscribe( + // complete => this.onCallbackSuccess(), + // error => { + // if (error.error.statusCode == 674) { + // this.uiNotificationService.snackBarNotification(this.language.instant('GENERAL.SNACK-BAR.UNSUCCESSFUL-DMP-BLUEPRINT-DELETE'), SnackBarNotificationLevel.Error); + // } else { + // this.uiNotificationService.snackBarNotification(this.language.instant(error.message), SnackBarNotificationLevel.Error); + // } + // } + // ); + } } } - } - ) + ) } finalize() { if (this.checkValidity()) { - this.formGroup.get('status').setValue(DmpProfileStatus.Finalized); + this.formGroup.get('status').setValue(DmpBlueprintStatus.Finalized); this.onSubmit(); - } + } } downloadXML(): void { - this.dmpProfileService.downloadXML(this.dmpProfileId) + this.dmpBlueprintService.downloadXML(this.dmpBlueprintId) .pipe(takeUntil(this._destroyed)) .subscribe(response => { const blob = new Blob([response.body], { type: 'application/xml' }); @@ -639,7 +636,7 @@ export class DmpProfileEditorComponent extends BaseComponent implements AfterVie } isExternalAutocomplete(formGroup: UntypedFormGroup) { - if (formGroup.get('dataType').value == DmpProfileFieldDataType.ExternalAutocomplete) { + if (formGroup.get('dataType').value == DmpBlueprintFieldDataType.ExternalAutocomplete) { this.addControl(formGroup); return true; } else { @@ -650,7 +647,7 @@ export class DmpProfileEditorComponent extends BaseComponent implements AfterVie addControl(formGroup: UntypedFormGroup) { if (formGroup.get('dataType').value == 3) - formGroup.addControl('externalAutocomplete', new DmpProfileExternalAutoCompleteFieldDataEditorModel().buildForm()); + formGroup.addControl('externalAutocomplete', new DmpBlueprintExternalAutoCompleteFieldDataEditorModel().buildForm()); } removeControl(formGroup: UntypedFormGroup) { diff --git a/dmp-frontend/src/app/ui/admin/dmp-profile/editor/dmp-blueprint-editor.model.ts b/dmp-frontend/src/app/ui/admin/dmp-blueprint/editor/dmp-blueprint-editor.model.ts similarity index 99% rename from dmp-frontend/src/app/ui/admin/dmp-profile/editor/dmp-blueprint-editor.model.ts rename to dmp-frontend/src/app/ui/admin/dmp-blueprint/editor/dmp-blueprint-editor.model.ts index 7ceef0376..ab99ca39b 100644 --- a/dmp-frontend/src/app/ui/admin/dmp-profile/editor/dmp-blueprint-editor.model.ts +++ b/dmp-frontend/src/app/ui/admin/dmp-blueprint/editor/dmp-blueprint-editor.model.ts @@ -1,4 +1,5 @@ import { UntypedFormBuilder, UntypedFormGroup, Validators } from "@angular/forms"; +import { DmpBlueprintStatus } from "@app/core/common/enum/dmp-blueprint-status"; import { DescriptionTemplatesInSection, DmpBlueprint, DmpBlueprintDefinition, FieldCategory, FieldInSection, SectionDmpBlueprint } from "@app/core/model/dmp/dmp-blueprint/dmp-blueprint"; import { BackendErrorValidator } from "@common/forms/validation/custom-validator"; import { ValidationErrorModel } from "@common/forms/validation/error-model/validation-error-model"; @@ -8,7 +9,7 @@ export class DmpBlueprintEditor { public id: string; public label: string; public definition: DmpBlueprintDefinitionEditor = new DmpBlueprintDefinitionEditor(); - public status: number; + public status: DmpBlueprintStatus; public created: Date; public modified: Date; public validationErrorModel: ValidationErrorModel = new ValidationErrorModel(); diff --git a/dmp-frontend/src/app/ui/admin/dmp-profile/editor/dmp-profile-editor.model.ts b/dmp-frontend/src/app/ui/admin/dmp-blueprint/editor/dmp-profile-editor.model.ts similarity index 51% rename from dmp-frontend/src/app/ui/admin/dmp-profile/editor/dmp-profile-editor.model.ts rename to dmp-frontend/src/app/ui/admin/dmp-blueprint/editor/dmp-profile-editor.model.ts index 8270f7e89..8d4d23181 100644 --- a/dmp-frontend/src/app/ui/admin/dmp-profile/editor/dmp-profile-editor.model.ts +++ b/dmp-frontend/src/app/ui/admin/dmp-blueprint/editor/dmp-profile-editor.model.ts @@ -1,28 +1,29 @@ import { UntypedFormBuilder, UntypedFormGroup } from '@angular/forms'; -import { DmpProfileFieldDataType } from '@app/core/common/enum/dmp-profile-field-type'; -import { DmpProfileType } from '@app/core/common/enum/dmp-profile-type'; -import { DmpProfile, DmpProfileDefinition } from '@app/core/model/dmp-profile/dmp-profile'; -import { DmpProfileField } from '@app/core/model/dmp-profile/dmp-profile-field'; -import { DmpProfileExternalAutoCompleteFieldDataEditorModel } from '@app/ui/admin/dmp-profile/editor/external-autocomplete/dmp-profile-external-autocomplete-field-editor.model'; +import { DmpBlueprintFieldDataType } from '@app/core/common/enum/dmp-blueprint-field-type'; +import { DmpBlueprintType } from '@app/core/common/enum/dmp-blueprint-type'; +import { DmpBlueprint } from '@app/core/model/dmp-blueprint/dmp-blueprint'; +import { DmpBlueprintField } from '@app/core/model/dmp-blueprint/dmp-blueprint-field'; +import { DmpBlueprintDefinition } from '@app/core/model/dmp/dmp-blueprint/dmp-blueprint'; +import { DmpBlueprintExternalAutoCompleteFieldDataEditorModel } from '@app/ui/admin/dmp-blueprint/editor/external-autocomplete/dmp-blueprint-external-autocomplete-field-editor.model'; import { ValidationErrorModel } from '@common/forms/validation/error-model/validation-error-model'; -export class DmpProfileEditorModel { +export class DmpBlueprintEditorModel { public id: string; public label: string; - public definition: DmpProfileDefinitionEditorModel = new DmpProfileDefinitionEditorModel(); + public definition: DmpBlueprintDefinitionEditorModel = new DmpBlueprintDefinitionEditorModel(); public status: number; public created: Date; public modified: Date; public validationErrorModel: ValidationErrorModel = new ValidationErrorModel(); - fromModel(item: DmpProfile): DmpProfileEditorModel { - this.id = item.id; - this.label = item.label; - this.definition = new DmpProfileDefinitionEditorModel().fromModel(item.definition); - this.status = item.status; - this.created = item.created; - this.modified = item.modified; + fromModel(item: DmpBlueprint): DmpBlueprintEditorModel { + // this.id = item.id; + // this.label = item.label; + // this.definition = new DmpBlueprintDefinitionEditorModel().fromModel(item.definition); + // this.status = item.status; + // this.created = item.created; + // this.modified = item.modified; return this; } @@ -39,12 +40,12 @@ export class DmpProfileEditorModel { } } -export class DmpProfileDefinitionEditorModel { +export class DmpBlueprintDefinitionEditorModel { - public fields: DmpProfileFieldEditorModel[] = new Array(); + public fields: DmpBlueprintFieldEditorModel[] = new Array(); - fromModel(item: DmpProfileDefinition): DmpProfileDefinitionEditorModel { - if (item.fields) { item.fields.map(x => this.fields.push(new DmpProfileFieldEditorModel().fromModel(x))); } + fromModel(item: DmpBlueprintDefinition): DmpBlueprintDefinitionEditorModel { + if (item.fields) { item.fields.map(x => this.fields.push(new DmpBlueprintFieldEditorModel().fromModel(x))); } return this; } @@ -61,16 +62,16 @@ export class DmpProfileDefinitionEditorModel { } } -export class DmpProfileFieldEditorModel { +export class DmpBlueprintFieldEditorModel { public id: string; - public type: DmpProfileType; - public dataType: DmpProfileFieldDataType; + public type: DmpBlueprintType; + public dataType: DmpBlueprintFieldDataType; public required = false; public label: string; public value: any; - public externalAutocomplete?: DmpProfileExternalAutoCompleteFieldDataEditorModel; + public externalAutocomplete?: DmpBlueprintExternalAutoCompleteFieldDataEditorModel; - fromModel(item: DmpProfileField): DmpProfileFieldEditorModel { + fromModel(item: DmpBlueprintField): DmpBlueprintFieldEditorModel { this.type = item.type; this.dataType = item.dataType; this.required = item.required; @@ -78,7 +79,7 @@ export class DmpProfileFieldEditorModel { this.id = item.id; this.value = item.value; if (item.externalAutocomplete) - this.externalAutocomplete = new DmpProfileExternalAutoCompleteFieldDataEditorModel().fromModel(item.externalAutocomplete); + this.externalAutocomplete = new DmpBlueprintExternalAutoCompleteFieldDataEditorModel().fromModel(item.externalAutocomplete); return this; } diff --git a/dmp-frontend/src/app/ui/admin/dmp-blueprint/editor/external-autocomplete/dmp-blueprint-external-autocomplete-field-editor.component.html b/dmp-frontend/src/app/ui/admin/dmp-blueprint/editor/external-autocomplete/dmp-blueprint-external-autocomplete-field-editor.component.html new file mode 100644 index 000000000..cdcf65d61 --- /dev/null +++ b/dmp-frontend/src/app/ui/admin/dmp-blueprint/editor/external-autocomplete/dmp-blueprint-external-autocomplete-field-editor.component.html @@ -0,0 +1,22 @@ +
+
+
{{'DMP-BLUEPRINT-EDITOR.FIELDS.EXTERNAL-AUTOCOMPLETE.TITLE' | translate}}
+ + {{'DMP-BLUEPRINT-EDITOR.FIELDS.EXTERNAL-AUTOCOMPLETE.MULTIPLE-AUTOCOMPLETE' | translate}} + + + + + + + + + + + + + + +
+
diff --git a/dmp-frontend/src/app/ui/admin/dmp-profile/editor/external-autocomplete/dmp-profile-external-autocomplete-field-editor.component.scss b/dmp-frontend/src/app/ui/admin/dmp-blueprint/editor/external-autocomplete/dmp-blueprint-external-autocomplete-field-editor.component.scss similarity index 100% rename from dmp-frontend/src/app/ui/admin/dmp-profile/editor/external-autocomplete/dmp-profile-external-autocomplete-field-editor.component.scss rename to dmp-frontend/src/app/ui/admin/dmp-blueprint/editor/external-autocomplete/dmp-blueprint-external-autocomplete-field-editor.component.scss diff --git a/dmp-frontend/src/app/ui/admin/dmp-blueprint/editor/external-autocomplete/dmp-blueprint-external-autocomplete-field-editor.component.ts b/dmp-frontend/src/app/ui/admin/dmp-blueprint/editor/external-autocomplete/dmp-blueprint-external-autocomplete-field-editor.component.ts new file mode 100644 index 000000000..cf297e202 --- /dev/null +++ b/dmp-frontend/src/app/ui/admin/dmp-blueprint/editor/external-autocomplete/dmp-blueprint-external-autocomplete-field-editor.component.ts @@ -0,0 +1,17 @@ +import { Component, Input, OnInit } from '@angular/core'; +import { UntypedFormGroup } from '@angular/forms'; +import { DmpBlueprintExternalAutoCompleteFieldDataEditorModel } from './dmp-blueprint-external-autocomplete-field-editor.model'; + +@Component({ + selector: 'app-dmp-blueprint-external-autocomplete-field-editor-component', + styleUrls: ['./dmp-blueprint-external-autocomplete-field-editor.component.scss'], + templateUrl: './dmp-blueprint-external-autocomplete-field-editor.component.html' +}) +export class DmpBlueprintExternalAutocompleteFieldEditorComponent implements OnInit { + + @Input() form: UntypedFormGroup + private externalAutocomplete: DmpBlueprintExternalAutoCompleteFieldDataEditorModel; + + ngOnInit() { + } +} diff --git a/dmp-frontend/src/app/ui/admin/dmp-profile/editor/external-autocomplete/dmp-profile-external-autocomplete-field-editor.model.ts b/dmp-frontend/src/app/ui/admin/dmp-blueprint/editor/external-autocomplete/dmp-blueprint-external-autocomplete-field-editor.model.ts similarity index 54% rename from dmp-frontend/src/app/ui/admin/dmp-profile/editor/external-autocomplete/dmp-profile-external-autocomplete-field-editor.model.ts rename to dmp-frontend/src/app/ui/admin/dmp-blueprint/editor/external-autocomplete/dmp-blueprint-external-autocomplete-field-editor.model.ts index 9aafc1506..35c4bf1e2 100644 --- a/dmp-frontend/src/app/ui/admin/dmp-profile/editor/external-autocomplete/dmp-profile-external-autocomplete-field-editor.model.ts +++ b/dmp-frontend/src/app/ui/admin/dmp-blueprint/editor/external-autocomplete/dmp-blueprint-external-autocomplete-field-editor.model.ts @@ -1,7 +1,7 @@ import { UntypedFormGroup, UntypedFormBuilder } from "@angular/forms"; -import { DmpProfileExternalAutoCompleteField } from "../../../../../core/model/dmp-profile/dmp-profile-external-autocomplete"; +import { DmpBlueprintExternalAutoCompleteField } from "../../../../../core/model/dmp-blueprint/dmp-blueprint-external-autocomplete"; -export class DmpProfileExternalAutoCompleteFieldDataEditorModel { +export class DmpBlueprintExternalAutoCompleteFieldDataEditorModel { public url: string; public optionsRoot: string; @@ -11,17 +11,17 @@ export class DmpProfileExternalAutoCompleteFieldDataEditorModel { buildForm(disabled: boolean = false, skipDisable: Array = []): UntypedFormGroup { const formGroup = new UntypedFormBuilder().group({ - url: [{ value: this.url, disabled: (disabled && !skipDisable.includes('DmpProfileExternalAutoCompleteFieldDataEditorModel.url')) }], - optionsRoot: [{ value: this.optionsRoot, disabled: (disabled && !skipDisable.includes('DmpProfileExternalAutoCompleteFieldDataEditorModel.optionsRoot')) }], - multiAutoComplete: [{ value: this.multiAutoComplete, disabled: (disabled && !skipDisable.includes('DmpProfileExternalAutoCompleteFieldDataEditorModel.multiAutoComplete')) }], - label: [{ value: this.label, disabled: (disabled && !skipDisable.includes('DmpProfileExternalAutoCompleteFieldDataEditorModel.label')) }], - value: [{ value: this.value, disabled: (disabled && !skipDisable.includes('DmpProfileExternalAutoCompleteFieldDataEditorModel.value')) }], + url: [{ value: this.url, disabled: (disabled && !skipDisable.includes('DmpBlueprintExternalAutoCompleteFieldDataEditorModel.url')) }], + optionsRoot: [{ value: this.optionsRoot, disabled: (disabled && !skipDisable.includes('DmpBlueprintExternalAutoCompleteFieldDataEditorModel.optionsRoot')) }], + multiAutoComplete: [{ value: this.multiAutoComplete, disabled: (disabled && !skipDisable.includes('DmpBlueprintExternalAutoCompleteFieldDataEditorModel.multiAutoComplete')) }], + label: [{ value: this.label, disabled: (disabled && !skipDisable.includes('DmpBlueprintExternalAutoCompleteFieldDataEditorModel.label')) }], + value: [{ value: this.value, disabled: (disabled && !skipDisable.includes('DmpBlueprintExternalAutoCompleteFieldDataEditorModel.value')) }], }); return formGroup; } - fromModel(item: DmpProfileExternalAutoCompleteField): DmpProfileExternalAutoCompleteFieldDataEditorModel { + fromModel(item: DmpBlueprintExternalAutoCompleteField): DmpBlueprintExternalAutoCompleteFieldDataEditorModel { this.url = item.url; this.optionsRoot = item.optionsRoot; this.multiAutoComplete = item.multiAutoComplete; diff --git a/dmp-frontend/src/app/ui/admin/dmp-profile/listing/criteria/dialog-confirmation-upload-profile/dialog-confirmation-upload-profiles.component.html b/dmp-frontend/src/app/ui/admin/dmp-blueprint/listing/criteria/dialog-confirmation-upload-blueprint/dialog-confirmation-upload-blueprints.component.html similarity index 73% rename from dmp-frontend/src/app/ui/admin/dmp-profile/listing/criteria/dialog-confirmation-upload-profile/dialog-confirmation-upload-profiles.component.html rename to dmp-frontend/src/app/ui/admin/dmp-blueprint/listing/criteria/dialog-confirmation-upload-blueprint/dialog-confirmation-upload-blueprints.component.html index c07d4eca4..eee25cbd2 100644 --- a/dmp-frontend/src/app/ui/admin/dmp-profile/listing/criteria/dialog-confirmation-upload-profile/dialog-confirmation-upload-profiles.component.html +++ b/dmp-frontend/src/app/ui/admin/dmp-blueprint/listing/criteria/dialog-confirmation-upload-blueprint/dialog-confirmation-upload-blueprints.component.html @@ -10,7 +10,7 @@
- + {{ selectedFileName }} @@ -20,22 +20,22 @@
- +
- +
diff --git a/dmp-frontend/src/app/ui/admin/dmp-profile/listing/criteria/dialog-confirmation-upload-profile/dialog-confirmation-upload-profiles.component.scss b/dmp-frontend/src/app/ui/admin/dmp-blueprint/listing/criteria/dialog-confirmation-upload-blueprint/dialog-confirmation-upload-blueprints.component.scss similarity index 100% rename from dmp-frontend/src/app/ui/admin/dmp-profile/listing/criteria/dialog-confirmation-upload-profile/dialog-confirmation-upload-profiles.component.scss rename to dmp-frontend/src/app/ui/admin/dmp-blueprint/listing/criteria/dialog-confirmation-upload-blueprint/dialog-confirmation-upload-blueprints.component.scss diff --git a/dmp-frontend/src/app/ui/admin/dmp-profile/listing/criteria/dialog-confirmation-upload-profile/dialog-confirmation-upload-profiles.component.ts b/dmp-frontend/src/app/ui/admin/dmp-blueprint/listing/criteria/dialog-confirmation-upload-blueprint/dialog-confirmation-upload-blueprints.component.ts similarity index 81% rename from dmp-frontend/src/app/ui/admin/dmp-profile/listing/criteria/dialog-confirmation-upload-profile/dialog-confirmation-upload-profiles.component.ts rename to dmp-frontend/src/app/ui/admin/dmp-blueprint/listing/criteria/dialog-confirmation-upload-blueprint/dialog-confirmation-upload-blueprints.component.ts index 65dea8f6c..6e8151659 100644 --- a/dmp-frontend/src/app/ui/admin/dmp-profile/listing/criteria/dialog-confirmation-upload-profile/dialog-confirmation-upload-profiles.component.ts +++ b/dmp-frontend/src/app/ui/admin/dmp-blueprint/listing/criteria/dialog-confirmation-upload-blueprint/dialog-confirmation-upload-blueprints.component.ts @@ -4,10 +4,10 @@ import { Inject, Component } from '@angular/core'; @Component({ selector: 'app-dialog-confirmation-upload', - templateUrl: './dialog-confirmation-upload-profiles.component.html', - styleUrls: ['./dialog-confirmation-upload-profiles.component.scss'] + templateUrl: './dialog-confirmation-upload-blueprints.component.html', + styleUrls: ['./dialog-confirmation-upload-blueprints.component.scss'] }) -export class DialodConfirmationUploadDmpProfiles { +export class DialodConfirmationUploadDmpBlueprints { sizeError = false; selectFile =false; @@ -15,7 +15,7 @@ export class DialodConfirmationUploadDmpProfiles { selectedFileName: string; constructor( - public dialogRef: MatDialogRef, + public dialogRef: MatDialogRef, @Inject(MAT_DIALOG_DATA) public data: any ) { } @@ -50,7 +50,7 @@ export class DialodConfirmationUploadDmpProfiles { this.dialogRef.close(this.data); } - hasProfile():boolean{ + hasBlueprint():boolean{ return (this.selectFile && !this.sizeError); } //remove selected file diff --git a/dmp-frontend/src/app/ui/admin/dmp-profile/listing/criteria/dmp-profile-criteria.component.html b/dmp-frontend/src/app/ui/admin/dmp-blueprint/listing/criteria/dmp-blueprint-criteria.component.html similarity index 100% rename from dmp-frontend/src/app/ui/admin/dmp-profile/listing/criteria/dmp-profile-criteria.component.html rename to dmp-frontend/src/app/ui/admin/dmp-blueprint/listing/criteria/dmp-blueprint-criteria.component.html diff --git a/dmp-frontend/src/app/ui/admin/dmp-profile/listing/criteria/dmp-profile-criteria.component.scss b/dmp-frontend/src/app/ui/admin/dmp-blueprint/listing/criteria/dmp-blueprint-criteria.component.scss similarity index 100% rename from dmp-frontend/src/app/ui/admin/dmp-profile/listing/criteria/dmp-profile-criteria.component.scss rename to dmp-frontend/src/app/ui/admin/dmp-blueprint/listing/criteria/dmp-blueprint-criteria.component.scss diff --git a/dmp-frontend/src/app/ui/admin/dmp-profile/listing/criteria/dmp-profile-criteria.component.ts b/dmp-frontend/src/app/ui/admin/dmp-blueprint/listing/criteria/dmp-blueprint-criteria.component.ts similarity index 68% rename from dmp-frontend/src/app/ui/admin/dmp-profile/listing/criteria/dmp-profile-criteria.component.ts rename to dmp-frontend/src/app/ui/admin/dmp-blueprint/listing/criteria/dmp-blueprint-criteria.component.ts index e80bea6b3..5d832395c 100644 --- a/dmp-frontend/src/app/ui/admin/dmp-profile/listing/criteria/dmp-profile-criteria.component.ts +++ b/dmp-frontend/src/app/ui/admin/dmp-blueprint/listing/criteria/dmp-blueprint-criteria.component.ts @@ -1,22 +1,22 @@ import { Component, Input, OnInit } from '@angular/core'; import { MatDialog } from '@angular/material/dialog'; import { DmpBlueprintCriteria } from '@app/core/query/dmp/dmp-blueprint-criteria'; -import { DmpProfileService } from '@app/core/services/dmp/dmp-profile.service'; +import { DmpBlueprintService } from '@app/core/services/dmp/dmp-blueprint.service'; import { BaseCriteriaComponent } from '@app/ui/misc/criteria/base-criteria.component'; import { ValidationErrorModel } from '@common/forms/validation/error-model/validation-error-model'; import { TranslateService } from '@ngx-translate/core'; @Component({ - selector: 'app-dmp-profile-criteria-component', - templateUrl: './dmp-profile-criteria.component.html', - styleUrls: ['./dmp-profile-criteria.component.scss'], + selector: 'app-dmp-blueprint-criteria-component', + templateUrl: './dmp-blueprint-criteria.component.html', + styleUrls: ['./dmp-blueprint-criteria.component.scss'], }) -export class DmpProfileCriteriaComponent extends BaseCriteriaComponent implements OnInit { +export class DmpBlueprintCriteriaComponent extends BaseCriteriaComponent implements OnInit { public criteria: DmpBlueprintCriteria = new DmpBlueprintCriteria(); constructor( - private dmpProfileService: DmpProfileService, + private dmpBlueprintService: DmpBlueprintService, private dialog: MatDialog, private language: TranslateService ) { @@ -47,12 +47,12 @@ export class DmpProfileCriteriaComponent extends BaseCriteriaComponent implement // openDialog(): void { - // const dialogRef = this.dialog.open(DialodConfirmationUploadDmpProfiles, { + // const dialogRef = this.dialog.open(DialodConfirmationUploadDmpBlueprints, { // restoreFocus: false, // data: { - // message: this.language.instant('DMP-PROFILE-LISTING.UPLOAD.UPLOAD-XML-FILE-TITLE'), - // confirmButton: this.language.instant('DMP-PROFILE-LISTING.UPLOAD.UPLOAD-XML'), - // cancelButton: this.language.instant('DMP-PROFILE-LISTING.UPLOAD.UPLOAD-XML-FILE-CANCEL'), + // message: this.language.instant('DMP-BLUEPRINT-LISTING.UPLOAD.UPLOAD-XML-FILE-TITLE'), + // confirmButton: this.language.instant('DMP-BLUEPRINT-LISTING.UPLOAD.UPLOAD-XML'), + // cancelButton: this.language.instant('DMP-BLUEPRINT-LISTING.UPLOAD.UPLOAD-XML-FILE-CANCEL'), // name: '', // file: FileList, // sucsess: false @@ -60,7 +60,7 @@ export class DmpProfileCriteriaComponent extends BaseCriteriaComponent implement // }); // dialogRef.afterClosed().pipe(takeUntil(this._destroyed)).subscribe(data => { // if (data && data.sucsess && data.name != null && data.file != null) { - // this.dmpProfileService.uploadFile(data.file, data.name) + // this.dmpBlueprintService.uploadFile(data.file, data.name) // .pipe(takeUntil(this._destroyed)) // .subscribe(); // } diff --git a/dmp-frontend/src/app/ui/admin/dmp-blueprint/listing/dmp-blueprint-listing.component.html b/dmp-frontend/src/app/ui/admin/dmp-blueprint/listing/dmp-blueprint-listing.component.html new file mode 100644 index 000000000..aa3a376da --- /dev/null +++ b/dmp-frontend/src/app/ui/admin/dmp-blueprint/listing/dmp-blueprint-listing.component.html @@ -0,0 +1,223 @@ +
+
+ +
+
+

{{'DMP-BLUEPRINT-LISTING.TITLE' | translate}}

+ + +
+
+ +
+
+ + + + + + + + + +
+
+ + + + +
+
+ + {{item?.label | nullifyValue}} +
+
+ + +
+
+ {{enumUtils.toDescriptionTemplateTypeStatusString(item.status) | nullifyValue}} +
+
+
+ + + + {{'DMP-BLUEPRINT-LISTING.FIELDS.CREATED-AT' | translate}}: + + {{item?.createdAt | dateTimeFormatter : 'short' | nullifyValue}} + + +
+
+ + + {{'DMP-BLUEPRINT-LISTING.FIELDS.UPDATED-AT' | translate}}: + + {{item?.updatedAt | dateTimeFormatter : 'short' | nullifyValue}} + + + +
+
+
+ + +
+
+ {{enumUtils.toDescriptionTemplateTypeStatusString(row.status) | nullifyValue}} +
+
+
+ + +
+
+ + + + + + +
+
+
+ + \ No newline at end of file diff --git a/dmp-frontend/src/app/ui/admin/dmp-profile/listing/dmp-profile-listing.component.scss b/dmp-frontend/src/app/ui/admin/dmp-blueprint/listing/dmp-blueprint-listing.component.scss similarity index 98% rename from dmp-frontend/src/app/ui/admin/dmp-profile/listing/dmp-profile-listing.component.scss rename to dmp-frontend/src/app/ui/admin/dmp-blueprint/listing/dmp-blueprint-listing.component.scss index 55aaa2ee6..1887bb1f2 100644 --- a/dmp-frontend/src/app/ui/admin/dmp-profile/listing/dmp-profile-listing.component.scss +++ b/dmp-frontend/src/app/ui/admin/dmp-blueprint/listing/dmp-blueprint-listing.component.scss @@ -2,7 +2,7 @@ margin-top: 47px; border-radius: 4px; } -.dmp-profile-listing { +.dmp-blueprint-listing { margin-top: 1.3rem; margin-left: 1rem; margin-right: 2rem; diff --git a/dmp-frontend/src/app/ui/admin/dmp-blueprint/listing/dmp-blueprint-listing.component.ts b/dmp-frontend/src/app/ui/admin/dmp-blueprint/listing/dmp-blueprint-listing.component.ts new file mode 100644 index 000000000..b17e03e48 --- /dev/null +++ b/dmp-frontend/src/app/ui/admin/dmp-blueprint/listing/dmp-blueprint-listing.component.ts @@ -0,0 +1,388 @@ + +import { Component, OnInit, TemplateRef, ViewChild } from '@angular/core'; +import { MatDialog } from '@angular/material/dialog'; +import { ActivatedRoute, Router } from '@angular/router'; +import { DmpBlueprintStatus } from '@app/core/common/enum/dmp-blueprint-status'; +import { IsActive } from '@app/core/common/enum/is-active.enum'; +import { DmpBlueprint } from '@app/core/model/dmp-blueprint/dmp-blueprint'; +import { DmpBlueprintLookup } from '@app/core/query/dmp-blueprint.lookup'; +import { AuthService } from '@app/core/services/auth/auth.service'; +import { DmpBlueprintService } from '@app/core/services/dmp/dmp-blueprint.service'; +import { SnackBarNotificationLevel, UiNotificationService } from '@app/core/services/notification/ui-notification-service'; +import { EnumUtils } from '@app/core/services/utilities/enum-utils.service'; +import { QueryParamsService } from '@app/core/services/utilities/query-params.service'; +import { BaseListingComponent } from '@common/base/base-listing-component'; +import { PipeService } from '@common/formatting/pipe.service'; +import { DataTableDateTimeFormatPipe } from '@common/formatting/pipes/date-time-format.pipe'; +import { QueryResult } from '@common/model/query-result'; +import { ConfirmationDialogComponent } from '@common/modules/confirmation-dialog/confirmation-dialog.component'; +import { HttpErrorHandlingService } from '@common/modules/errors/error-handling/http-error-handling.service'; +import { ColumnDefinition, ColumnsChangedEvent, HybridListingComponent, PageLoadEvent } from '@common/modules/hybrid-listing/hybrid-listing.component'; +import { Guid } from '@common/types/guid'; +import { TranslateService } from '@ngx-translate/core'; +import { Observable } from 'rxjs'; +import { takeUntil } from 'rxjs/operators'; +import { nameof } from 'ts-simple-nameof'; + + +@Component({ + selector: 'app-dmp-blueprint-listing-component', + templateUrl: './dmp-blueprint-listing.component.html', + styleUrls: ['./dmp-blueprint-listing.component.scss'] +}) +export class DmpBlueprintListingComponent extends BaseListingComponent implements OnInit { + publish = false; + userSettingsKey = { key: 'DmpBlueprintListingUserSettings' }; + propertiesAvailableForOrder: ColumnDefinition[]; + DmpBlueprintStatuses = DmpBlueprintStatus; + + @ViewChild('DmpBlueprintStatus', { static: true }) DmpBlueprintStatus?: TemplateRef; + @ViewChild('actions', { static: true }) actions?: TemplateRef; + @ViewChild(HybridListingComponent, { static: true }) hybridListingComponent: HybridListingComponent; + + private readonly lookupFields: string[] = [ + nameof(x => x.id), + nameof(x => x.label), + nameof(x => x.description), + nameof(x => x.status), + nameof(x => x.updatedAt), + nameof(x => x.createdAt), + nameof(x => x.hash), + nameof(x => x.isActive) + ]; + + rowIdentity = x => x.id; + + constructor( + protected router: Router, + protected route: ActivatedRoute, + protected uiNotificationService: UiNotificationService, + protected httpErrorHandlingService: HttpErrorHandlingService, + protected queryParamsService: QueryParamsService, + private dmpBlueprintService: DmpBlueprintService, + public authService: AuthService, + private pipeService: PipeService, + public enumUtils: EnumUtils, + private language: TranslateService, + private dialog: MatDialog + ) { + super(router, route, uiNotificationService, httpErrorHandlingService, queryParamsService); + // Lookup setup + // Default lookup values are defined in the user settings class. + this.lookup = this.initializeLookup(); + } + + ngOnInit() { + super.ngOnInit(); + } + + protected initializeLookup(): DmpBlueprintLookup { + const lookup = new DmpBlueprintLookup(); + lookup.metadata = { countAll: true }; + lookup.page = { offset: 0, size: this.ITEMS_PER_PAGE }; + lookup.isActive = [IsActive.Active]; + lookup.order = { items: [this.toDescSortField(nameof(x => x.createdAt))] }; + this.updateOrderUiFields(lookup.order); + + lookup.project = { + fields: this.lookupFields + }; + + return lookup; + } + + protected setupColumns() { + this.gridColumns.push(...[{ + prop: nameof(x => x.label), + sortable: true, + languageName: 'DMP-BLUEPRINT.FIELDS.NAME' + }, { + prop: nameof(x => x.status), + sortable: true, + languageName: 'DMP-BLUEPRINT.FIELDS.STATUS', + cellTemplate: this.DmpBlueprintStatus + }, + // { + // prop: nameof(x => x.isExclude), + // languageName: 'DMP-BLUEPRINT.FIELDS.IS-EXCLUDE', + // pipe: this.pipeService.getPipe(IsExcludeTypePipe) + // }, + { + prop: nameof(x => x.createdAt), + sortable: true, + languageName: 'DMP-BLUEPRINT.FIELDS.CREATED-AT', + pipe: this.pipeService.getPipe(DataTableDateTimeFormatPipe).withFormat('short') + }, + { + prop: nameof(x => x.updatedAt), + sortable: true, + languageName: 'DMP-BLUEPRINT.FIELDS.UPDATED-AT', + pipe: this.pipeService.getPipe(DataTableDateTimeFormatPipe).withFormat('short') + }, + { + alwaysShown: true, + cellTemplate: this.actions, + maxWidth: 120 + } + ]); + this.propertiesAvailableForOrder = this.gridColumns.filter(x => x.sortable); + } + + // + // Listing Component functions + // + onColumnsChanged(event: ColumnsChangedEvent) { + super.onColumnsChanged(event); + this.onColumnsChangedInternal(event.properties.map(x => x.toString())); + } + + private onColumnsChangedInternal(columns: string[]) { + // Here are defined the projection fields that always requested from the api. + const fields = new Set(this.lookupFields); + this.gridColumns.map(x => x.prop) + .filter(x => !columns?.includes(x as string)) + .forEach(item => { + fields.delete(item as string) + }); + this.lookup.project = { fields: [...fields] }; + this.onPageLoad({ offset: 0 } as PageLoadEvent); + } + + protected loadListing(): Observable> { + return this.dmpBlueprintService.query(this.lookup); + } + + public deleteType(id: Guid) { + if (id) { + const dialogRef = this.dialog.open(ConfirmationDialogComponent, { + maxWidth: '300px', + data: { + message: this.language.instant('GENERAL.CONFIRMATION-DIALOG.DELETE-ITEM'), + confirmButton: this.language.instant('GENERAL.CONFIRMATION-DIALOG.ACTIONS.CONFIRM'), + cancelButton: this.language.instant('GENERAL.CONFIRMATION-DIALOG.ACTIONS.CANCEL') + } + }); + dialogRef.afterClosed().pipe(takeUntil(this._destroyed)).subscribe(result => { + if (result) { + this.dmpBlueprintService.delete(id).pipe(takeUntil(this._destroyed)) + .subscribe( + complete => this.onCallbackSuccess(), + error => this.onCallbackError(error) + ); + } + }); + } + } + + onCallbackSuccess(): void { + this.uiNotificationService.snackBarNotification(this.language.instant('GENERAL.SNACK-BAR.SUCCESSFUL-DELETE'), SnackBarNotificationLevel.Success); + this.ngOnInit(); + } +} + + + // ngOnInit() { + // this.matomoService.trackPageView('Admin: DMP Templates'); + // this.route.params + // .pipe(takeUntil(this._destroyed)) + // .subscribe((params: Params) => { + // this.dmpId = params['dmpId']; + // this.criteria.setCriteria(this.getDefaultCriteria()); + // this.refresh(); + // this.criteria.setRefreshCallback(() => this.refresh()); + // this.breadCrumbs = observableOf([{ + // parentComponentName: null, + // label: this.languageService.instant('NAV-BAR.DMP-BLUEPRINTS-CAPS'), + // url: '/dmp-blueprints' + // }]); + // }); + // } + + // refresh() { + // this.dataSource = new DatasetDataSource(this.dmpBlueprintService, this._paginator, this.sort, this.criteria); + // } + + // clone(id: string) { + // this.router.navigate(['dmp-blueprints/clone/' + id]); + // } + + // rowClick(rowId: String) { + // this.router.navigate(['dmp-blueprints/' + rowId]); + // } + + // downloadXML(dmpBlueprintId: string): void { + // this.dmpBlueprintService.downloadXML(dmpBlueprintId) + // .pipe(takeUntil(this._destroyed)) + // .subscribe(response => { + // const blob = new Blob([response.body], { type: 'application/xml' }); + // const filename = this.getFilenameFromContentDispositionHeader(response.headers.get('Content-Disposition')); + // FileSaver.saveAs(blob, filename); + // }); + // } + // getFilenameFromContentDispositionHeader(header: string): string { + // const regex: RegExp = new RegExp(/filename[^;=\n]*=((['"]).*?\2|[^;\n]*)/g); + + // const matches = header.match(regex); + // let filename: string; + // for (let i = 0; i < matches.length; i++) { + // const match = matches[i]; + // if (match.includes('filename="')) { + // filename = match.substring(10, match.length - 1); + // break; + // } else if (match.includes('filename=')) { + // filename = match.substring(9); + // break; + // } + // } + // return filename; + // } + + // deleteTemplate(id: string) { + // if (id) { + // this.dialog.open(ConfirmationDialogComponent, { + // data: { + // isDeleteConfirmation: true, + // confirmButton: this.languageService.instant('DMP-BLUEPRINT-EDITOR.CONFIRM-DELETE-DIALOG.CONFIRM-BUTTON'), + // cancelButton: this.languageService.instant("DMP-BLUEPRINT-EDITOR.CONFIRM-DELETE-DIALOG.CANCEL-BUTTON"), + // message: this.languageService.instant("DMP-BLUEPRINT-EDITOR.CONFIRM-DELETE-DIALOG.MESSAGE") + // } + // }) + // .afterClosed() + // .subscribe( + // confirmed => { + // if (confirmed) { + // this.dmpBlueprintService.delete(id) + // .pipe(takeUntil(this._destroyed)) + // .subscribe( + // complete => { + // this.uiNotificationService.snackBarNotification(this.languageService.instant('GENERAL.SNACK-BAR.SUCCESSFUL-DMP-BLUEPRINT-DELETE'), SnackBarNotificationLevel.Success); + // this.refresh(); + // }, + // error => { + // this.onCallbackError(error); + // if (error.error.statusCode == 674) { + // this.uiNotificationService.snackBarNotification(this.languageService.instant('GENERAL.SNACK-BAR.UNSUCCESSFUL-DMP-BLUEPRINT-DELETE'), SnackBarNotificationLevel.Error); + // } else { + // this.uiNotificationService.snackBarNotification(this.languageService.instant(error.message), SnackBarNotificationLevel.Error); + // } + // } + // ); + // } + // } + // ) + // } + // } + + // onCallbackError(errorResponse: HttpErrorResponse) { + // this.uiNotificationService.snackBarNotification(errorResponse.message, SnackBarNotificationLevel.Warning); + // } + + // getDefaultCriteria(): DmpBlueprintCriteria { + // const defaultCriteria = new DmpBlueprintCriteria(); + // return defaultCriteria; + // } + + // // makeItPublic(id: String) { + // // debugger; + // // this.datasetService.makeDatasetPublic(id).pipe(takeUntil(this._destroyed)).subscribe(); + // // } + + // parseStatus(value: number): string { + // const stringVal = value.toString() + // try { + // return this.statuses.find(status => status.value === stringVal).viewValue; + // } catch { + // return stringVal; + // } + // } + + // openDialog(): void { + // const dialogRef = this.dialog.open(DialodConfirmationUploadDmpBlueprints, { + // restoreFocus: false, + // data: { + // message: this.languageService.instant('DMP-BLUEPRINT-LISTING.UPLOAD.UPLOAD-XML-FILE-TITLE'), + // confirmButton: this.languageService.instant('DMP-BLUEPRINT-LISTING.UPLOAD.UPLOAD-XML'), + // cancelButton: this.languageService.instant('DMP-BLUEPRINT-LISTING.UPLOAD.UPLOAD-XML-FILE-CANCEL'), + // name: '', + // file: FileList, + // sucsess: false + // } + // }); + // dialogRef.afterClosed().pipe(takeUntil(this._destroyed)).subscribe(data => { + // if (data && data.sucsess && data.name != null && data.file != null) { + // this.dmpBlueprintService.uploadFile(data.file, data.name) + // .pipe(takeUntil(this._destroyed)) + // .subscribe(_ => { + // this.uiNotificationService.snackBarNotification(this.languageService.instant('DMP-BLUEPRINT-LISTING.MESSAGES.TEMPLATE-UPLOAD-SUCCESS'), SnackBarNotificationLevel.Success); + // this.refresh(); + // }, + // error => { + // this.uiNotificationService.snackBarNotification(error.message, SnackBarNotificationLevel.Error); + // }); + // } + // }); + // } + // getStatusClass(status: number): string { + + // if (status === 1) {//finalized + // return 'status-chip-finalized' + // } + // if (status === 0) { + // return 'status-chip-draft'; + // } + // return ''; + // } + // } + + // export class DatasetDataSource extends DataSource { + + // totalCount = 0; + + // constructor( + // private _service: dmpBlueprintService, + // private _paginator: MatPaginator, + // private _sort: MatSort, + // private _criteria: DmpBlueprintCriteriaComponent + // ) { + // super(); + + // } + + // connect(): Observable { + // const displayDataChanges = [ + // this._paginator.page + // //this._sort.matSortChange + // ]; + + // return observableMerge(...displayDataChanges).pipe( + // startWith(null), + // switchMap(() => { + // const startIndex = this._paginator.pageIndex * this._paginator.pageSize; + // let fields: Array = new Array(); + // if (this._sort.active) { fields = this._sort.direction === 'asc' ? ['+' + this._sort.active] : ['-' + this._sort.active]; } + // const request = new DataTableRequest(startIndex, this._paginator.pageSize, { fields: fields }); + // request.criteria = this._criteria.criteria; + // return this._service.getPagedBlueprint(request); + // }), + // /*.catch((error: any) => { + // this._snackBar.openFromComponent(SnackBarNotificationComponent, { + // data: { message: 'GENERAL.SNACK-BAR.FORMS-BAD-REQUEST', language: this._languageService }, + // duration: 3000, + // extraClasses: ['snackbar-warning'] + // }); + // //this._criteria.criteria.onCallbackError(error); + // return Observable.of(null); + // })*/ + // map(result => { + // return result; + // }), + // map(result => { + // if (!result) { return []; } + // if (this._paginator.pageIndex === 0) { this.totalCount = result.totalCount; } + // return result.data; + // })); + // } + + // disconnect() { + // // No-op + // } diff --git a/dmp-frontend/src/app/ui/admin/dmp-blueprint/listing/filters/dmp-blueprint-listing-filters.component.html b/dmp-frontend/src/app/ui/admin/dmp-blueprint/listing/filters/dmp-blueprint-listing-filters.component.html new file mode 100644 index 000000000..91b1f2f48 --- /dev/null +++ b/dmp-frontend/src/app/ui/admin/dmp-blueprint/listing/filters/dmp-blueprint-listing-filters.component.html @@ -0,0 +1,36 @@ +
+ + + + + +
+
+
+

{{'DMP-BLUEPRINT-LISTING.FILTER.TITLE' | translate}}

+ +
+ + + {{'DMP-BLUEPRINT-LISTING.FILTER.IS-ACTIVE' | translate}} + + +
+ + +
+
+
+
+ + +
diff --git a/dmp-frontend/src/app/ui/admin/dmp-blueprint/listing/filters/dmp-blueprint-listing-filters.component.scss b/dmp-frontend/src/app/ui/admin/dmp-blueprint/listing/filters/dmp-blueprint-listing-filters.component.scss new file mode 100644 index 000000000..36949fa32 --- /dev/null +++ b/dmp-frontend/src/app/ui/admin/dmp-blueprint/listing/filters/dmp-blueprint-listing-filters.component.scss @@ -0,0 +1,25 @@ +.dmp-blueprint-listing-filters { + +} + +::ng-deep.mat-mdc-menu-panel { + max-width: 100% !important; + height: 100% !important; +} + +:host::ng-deep.mat-mdc-menu-content:not(:empty) { + padding-top: 0 !important; +} + + +.filter-button{ + padding-top: .6rem; + padding-bottom: .6rem; + // .mat-icon{ + // font-size: 1.5em; + // width: 1.2em; + // height: 1.2em; + // } +} + + diff --git a/dmp-frontend/src/app/ui/admin/dmp-blueprint/listing/filters/dmp-blueprint-listing-filters.component.ts b/dmp-frontend/src/app/ui/admin/dmp-blueprint/listing/filters/dmp-blueprint-listing-filters.component.ts new file mode 100644 index 000000000..a16fd4b42 --- /dev/null +++ b/dmp-frontend/src/app/ui/admin/dmp-blueprint/listing/filters/dmp-blueprint-listing-filters.component.ts @@ -0,0 +1,99 @@ +import { Component, EventEmitter, Input, OnChanges, OnInit, Output, SimpleChanges } from '@angular/core'; +import { IsActive } from '@app/core/common/enum/is-active.enum'; +import { DmpBlueprintFilter } from '@app/core/query/dmp-blueprint.lookup'; +import { EnumUtils } from '@app/core/services/utilities/enum-utils.service'; +import { BaseComponent } from '@common/base/base.component'; +import { Guid } from '@common/types/guid'; +import { nameof } from 'ts-simple-nameof'; + +@Component({ + selector: 'app-dmp-blueprint-listing-filters', + templateUrl: './dmp-blueprint-listing-filters.component.html', + styleUrls: ['./dmp-blueprint-listing-filters.component.scss'] +}) +export class DmpBlueprintListingFiltersComponent extends BaseComponent implements OnInit, OnChanges { + + @Input() readonly filter: DmpBlueprintFilter; + @Output() filterChange = new EventEmitter(); + + // * State + internalFilters: DmpBlueprintListingFilters = this._getEmptyFilters(); + + protected appliedFilterCount: number = 0; + constructor( + public enumUtils: EnumUtils, + ) { super(); } + + ngOnInit() { + } + + ngOnChanges(changes: SimpleChanges): void { + const filterChange = changes[nameof(x => x.filter)]?.currentValue as DmpBlueprintFilter; + if (filterChange) { + this.updateFilters() + } + } + + + onSearchTermChange(searchTerm: string): void { + this.applyFilters() + } + + + protected updateFilters(): void { + this.internalFilters = this._parseToInternalFilters(this.filter); + this.appliedFilterCount = this._computeAppliedFilters(this.internalFilters); + } + + protected applyFilters(): void { + const { isActive, like, typeIds } = this.internalFilters ?? {} + this.filterChange.emit({ + ...this.filter, + like, + isActive: isActive ? [IsActive.Active] : [IsActive.Inactive], + typeIds + }) + } + + + private _parseToInternalFilters(inputFilter: DmpBlueprintFilter): DmpBlueprintListingFilters { + if (!inputFilter) { + return this._getEmptyFilters(); + } + + let { excludedIds, ids, isActive, like, typeIds } = inputFilter; + + return { + isActive: (isActive ?? [])?.includes(IsActive.Active) || !isActive?.length, + like: like, + typeIds: typeIds + } + + } + + private _getEmptyFilters(): DmpBlueprintListingFilters { + return { + isActive: true, + like: null, + typeIds: null, + } + } + + private _computeAppliedFilters(filters: DmpBlueprintListingFilters): number { + let count = 0; + if (filters?.isActive) { + count++ + } + return count; + } + + clearFilters() { + this.internalFilters = this._getEmptyFilters(); + } +} + +interface DmpBlueprintListingFilters { + isActive: boolean; + like: string; + typeIds: Guid[]; +} diff --git a/dmp-frontend/src/app/ui/admin/dmp-profile/dmp-profile.module.ts b/dmp-frontend/src/app/ui/admin/dmp-profile/dmp-profile.module.ts deleted file mode 100644 index 565095377..000000000 --- a/dmp-frontend/src/app/ui/admin/dmp-profile/dmp-profile.module.ts +++ /dev/null @@ -1,35 +0,0 @@ -import { NgModule } from "@angular/core"; -import { ConfirmationDialogModule } from '@common/modules/confirmation-dialog/confirmation-dialog.module'; -import { UrlListingModule } from '@app/library/url-listing/url-listing.module'; -import { CommonFormsModule } from '@common/forms/common-forms.module'; -import { CommonUiModule } from '@common/ui/common-ui.module'; -import { DmpProfileRoutingModule } from './dmp-profile.routing'; -import { DmpProfileEditorComponent } from './editor/dmp-profile-editor.component'; -import { DmpProfileExternalAutocompleteFieldEditorComponent } from './editor/external-autocomplete/dmp-profile-external-autocomplete-field-editor.component'; -import { DialodConfirmationUploadDmpProfiles } from './listing/criteria/dialog-confirmation-upload-profile/dialog-confirmation-upload-profiles.component'; -import { DmpProfileCriteriaComponent } from './listing/criteria/dmp-profile-criteria.component'; -import { DmpProfileListingComponent } from './listing/dmp-profile-listing.component'; -import { NgxDropzoneModule } from "ngx-dropzone"; -import { DragDropModule } from '@angular/cdk/drag-drop'; -import { AutoCompleteModule } from "@app/library/auto-complete/auto-complete.module"; - -@NgModule({ - imports: [ - CommonUiModule, - CommonFormsModule, - UrlListingModule, - ConfirmationDialogModule, - DmpProfileRoutingModule, - NgxDropzoneModule, - DragDropModule, - AutoCompleteModule - ], - declarations: [ - DmpProfileEditorComponent, - DmpProfileListingComponent, - DmpProfileCriteriaComponent, - DialodConfirmationUploadDmpProfiles, - DmpProfileExternalAutocompleteFieldEditorComponent - ] -}) -export class DmpProfileModule { } diff --git a/dmp-frontend/src/app/ui/admin/dmp-profile/dmp-profile.routing.ts b/dmp-frontend/src/app/ui/admin/dmp-profile/dmp-profile.routing.ts deleted file mode 100644 index 9014940a1..000000000 --- a/dmp-frontend/src/app/ui/admin/dmp-profile/dmp-profile.routing.ts +++ /dev/null @@ -1,19 +0,0 @@ -import { NgModule } from '@angular/core'; -import { RouterModule, Routes } from '@angular/router'; -import { AuthGuard } from '../../../core/auth-guard.service'; -import { DmpProfileEditorComponent } from './editor/dmp-profile-editor.component'; -import { DmpProfileListingComponent } from './listing/dmp-profile-listing.component'; -import { AdminAuthGuard } from '@app/core/admin-auth-guard.service'; - -const routes: Routes = [ - { path: '', component: DmpProfileListingComponent, canActivate: [AdminAuthGuard] }, - { path: 'new', component: DmpProfileEditorComponent, canActivate: [AdminAuthGuard], data: { title: 'GENERAL.TITLES.DMP-BLUEPRINT-NEW' } }, - { path: 'clone/:cloneid', component: DmpProfileEditorComponent, canActivate: [AdminAuthGuard], data: { title: 'GENERAL.TITLES.DMP-BLUEPRINT-CLONE' } }, - { path: ':id', component: DmpProfileEditorComponent, canActivate: [AdminAuthGuard], data: { title: 'GENERAL.TITLES.DMP-BLUEPRINT-EDIT' } }, -]; - -@NgModule({ - imports: [RouterModule.forChild(routes)], - exports: [RouterModule] -}) -export class DmpProfileRoutingModule { } diff --git a/dmp-frontend/src/app/ui/admin/dmp-profile/editor/external-autocomplete/dmp-profile-external-autocomplete-field-editor.component.html b/dmp-frontend/src/app/ui/admin/dmp-profile/editor/external-autocomplete/dmp-profile-external-autocomplete-field-editor.component.html deleted file mode 100644 index 395527ab7..000000000 --- a/dmp-frontend/src/app/ui/admin/dmp-profile/editor/external-autocomplete/dmp-profile-external-autocomplete-field-editor.component.html +++ /dev/null @@ -1,22 +0,0 @@ -
-
-
{{'DMP-PROFILE-EDITOR.FIELDS.EXTERNAL-AUTOCOMPLETE.TITLE' | translate}}
- - {{'DMP-PROFILE-EDITOR.FIELDS.EXTERNAL-AUTOCOMPLETE.MULTIPLE-AUTOCOMPLETE' | translate}} - - - - - - - - - - - - - - -
-
diff --git a/dmp-frontend/src/app/ui/admin/dmp-profile/editor/external-autocomplete/dmp-profile-external-autocomplete-field-editor.component.ts b/dmp-frontend/src/app/ui/admin/dmp-profile/editor/external-autocomplete/dmp-profile-external-autocomplete-field-editor.component.ts deleted file mode 100644 index 4cf02ad06..000000000 --- a/dmp-frontend/src/app/ui/admin/dmp-profile/editor/external-autocomplete/dmp-profile-external-autocomplete-field-editor.component.ts +++ /dev/null @@ -1,17 +0,0 @@ -import { Component, Input, OnInit } from '@angular/core'; -import { UntypedFormGroup } from '@angular/forms'; -import { DmpProfileExternalAutoCompleteFieldDataEditorModel } from './dmp-profile-external-autocomplete-field-editor.model'; - -@Component({ - selector: 'app-dmp-profile-external-autocomplete-field-editor-component', - styleUrls: ['./dmp-profile-external-autocomplete-field-editor.component.scss'], - templateUrl: './dmp-profile-external-autocomplete-field-editor.component.html' -}) -export class DmpProfileExternalAutocompleteFieldEditorComponent implements OnInit { - - @Input() form: UntypedFormGroup - private externalAutocomplete: DmpProfileExternalAutoCompleteFieldDataEditorModel; - - ngOnInit() { - } -} diff --git a/dmp-frontend/src/app/ui/admin/dmp-profile/listing/dmp-profile-listing.component.html b/dmp-frontend/src/app/ui/admin/dmp-profile/listing/dmp-profile-listing.component.html deleted file mode 100644 index e138c7d8a..000000000 --- a/dmp-frontend/src/app/ui/admin/dmp-profile/listing/dmp-profile-listing.component.html +++ /dev/null @@ -1,89 +0,0 @@ -
-
-
-
-

{{titlePrefix}} {{'DMP-PROFILE-LISTING.TITLE' | translate}}

-
-
-
- - -
-
- -
-
- -
-
- -
- - - - - - {{'DMP-PROFILE-LISTING.COLUMNS.NAME' | translate}} - {{row.label}} - - - - - - {{'DMP-PROFILE-LISTING.COLUMNS.CREATED' | translate}} - {{row.created | date:'short'}} - - - - - - {{'DMP-PROFILE-LISTING.COLUMNS.STATUS' | translate}} - -
- {{parseStatus(row.status) | translate}} -
-
-
- - - - - - - - - - - - - - - - - - - -
- - -
-
-
diff --git a/dmp-frontend/src/app/ui/admin/dmp-profile/listing/dmp-profile-listing.component.ts b/dmp-frontend/src/app/ui/admin/dmp-profile/listing/dmp-profile-listing.component.ts deleted file mode 100644 index 181a74020..000000000 --- a/dmp-frontend/src/app/ui/admin/dmp-profile/listing/dmp-profile-listing.component.ts +++ /dev/null @@ -1,272 +0,0 @@ - -import { DataSource } from '@angular/cdk/table'; -import { HttpClient, HttpErrorResponse } from '@angular/common/http'; -import { Component, OnInit, ViewChild } from '@angular/core'; -import { MatDialog } from '@angular/material/dialog'; -import { MatPaginator, PageEvent } from '@angular/material/paginator'; -import { MatSnackBar } from '@angular/material/snack-bar'; -import { MatSort } from '@angular/material/sort'; -import { ActivatedRoute, Params, Router } from '@angular/router'; -import { DmpProfileStatus } from '@app/core/common/enum/dmp-profile-status'; -import { DataTableRequest } from '@app/core/model/data-table/data-table-request'; -import { DmpBlueprintListing } from '@app/core/model/dmp/dmp-blueprint/dmp-blueprint-listing'; -import { DmpBlueprintCriteria } from '@app/core/query/dmp/dmp-blueprint-criteria'; -import { DmpProfileService } from '@app/core/services/dmp/dmp-profile.service'; -import { MatomoService } from '@app/core/services/matomo/matomo-service'; -import { UiNotificationService } from '@app/core/services/notification/ui-notification-service'; -import { DmpProfileCriteriaComponent } from '@app/ui/admin/dmp-profile/listing/criteria/dmp-profile-criteria.component'; -import { BreadcrumbItem } from '@app/ui/misc/breadcrumb/definition/breadcrumb-item'; -import { BaseComponent } from '@common/base/base.component'; -import { ConfirmationDialogComponent } from '@common/modules/confirmation-dialog/confirmation-dialog.component'; -import { SnackBarNotificationLevel } from '@common/modules/notification/ui-notification-service'; -import { TranslateService } from '@ngx-translate/core'; -import * as FileSaver from 'file-saver'; -import { Observable, merge as observableMerge, of as observableOf } from 'rxjs'; -import { map, startWith, switchMap, takeUntil } from 'rxjs/operators'; -import { DialodConfirmationUploadDmpProfiles } from './criteria/dialog-confirmation-upload-profile/dialog-confirmation-upload-profiles.component'; - - -@Component({ - selector: 'app-dmp-profile-listing-component', - templateUrl: 'dmp-profile-listing.component.html', - styleUrls: ['./dmp-profile-listing.component.scss'] -}) -export class DmpProfileListingComponent extends BaseComponent implements OnInit { - - @ViewChild(MatPaginator, { static: true }) _paginator: MatPaginator; - @ViewChild(MatSort, { static: true }) sort: MatSort; - @ViewChild(DmpProfileCriteriaComponent, { static: true }) criteria: DmpProfileCriteriaComponent; - - dataSource: DatasetDataSource | null; - displayedColumns: String[] = ['label', 'created', 'status', 'actions']; - pageEvent: PageEvent; - titlePrefix: String; - dmpId: String; - breadCrumbs: Observable; - dmpBlueprintStatus = DmpProfileStatus; - - statuses = [ - { value: '0', viewValue: 'DMP-PROFILE-LISTING.STATUS.DRAFT' },// active - { value: '1', viewValue: 'DMP-PROFILE-LISTING.STATUS.FINALIZED' }// inactive - ]; - - constructor( - private router: Router, - private languageService: TranslateService, - public snackBar: MatSnackBar, - public route: ActivatedRoute, - public dmpProfileService: DmpProfileService, - private httpClient: HttpClient, - private matomoService: MatomoService, - private dialog: MatDialog, - private uiNotificationService: UiNotificationService, - ) { - super(); - } - - ngOnInit() { - this.matomoService.trackPageView('Admin: DMP Templates'); - this.route.params - .pipe(takeUntil(this._destroyed)) - .subscribe((params: Params) => { - this.dmpId = params['dmpId']; - this.criteria.setCriteria(this.getDefaultCriteria()); - this.refresh(); - this.criteria.setRefreshCallback(() => this.refresh()); - this.breadCrumbs = observableOf([{ - parentComponentName: null, - label: this.languageService.instant('NAV-BAR.DMP-BLUEPRINTS-CAPS'), - url: '/dmp-profiles' - }]); - }); - } - - refresh() { - this.dataSource = new DatasetDataSource(this.dmpProfileService, this._paginator, this.sort, this.criteria); - } - - clone(id: string) { - this.router.navigate(['dmp-profiles/clone/' + id]); - } - - rowClick(rowId: String) { - this.router.navigate(['dmp-profiles/' + rowId]); - } - - downloadXML(dmpProfileId: string): void { - this.dmpProfileService.downloadXML(dmpProfileId) - .pipe(takeUntil(this._destroyed)) - .subscribe(response => { - const blob = new Blob([response.body], { type: 'application/xml' }); - const filename = this.getFilenameFromContentDispositionHeader(response.headers.get('Content-Disposition')); - FileSaver.saveAs(blob, filename); - }); - } - getFilenameFromContentDispositionHeader(header: string): string { - const regex: RegExp = new RegExp(/filename[^;=\n]*=((['"]).*?\2|[^;\n]*)/g); - - const matches = header.match(regex); - let filename: string; - for (let i = 0; i < matches.length; i++) { - const match = matches[i]; - if (match.includes('filename="')) { - filename = match.substring(10, match.length - 1); - break; - } else if (match.includes('filename=')) { - filename = match.substring(9); - break; - } - } - return filename; - } - - deleteTemplate(id: string) { - if (id) { - this.dialog.open(ConfirmationDialogComponent, { - data: { - isDeleteConfirmation: true, - confirmButton: this.languageService.instant('DMP-PROFILE-EDITOR.CONFIRM-DELETE-DIALOG.CONFIRM-BUTTON'), - cancelButton: this.languageService.instant("DMP-PROFILE-EDITOR.CONFIRM-DELETE-DIALOG.CANCEL-BUTTON"), - message: this.languageService.instant("DMP-PROFILE-EDITOR.CONFIRM-DELETE-DIALOG.MESSAGE") - } - }) - .afterClosed() - .subscribe( - confirmed => { - if (confirmed) { - this.dmpProfileService.delete(id) - .pipe(takeUntil(this._destroyed)) - .subscribe( - complete => { - this.uiNotificationService.snackBarNotification(this.languageService.instant('GENERAL.SNACK-BAR.SUCCESSFUL-DMP-BLUEPRINT-DELETE'), SnackBarNotificationLevel.Success); - this.refresh(); - }, - error => { - this.onCallbackError(error); - if (error.error.statusCode == 674) { - this.uiNotificationService.snackBarNotification(this.languageService.instant('GENERAL.SNACK-BAR.UNSUCCESSFUL-DMP-BLUEPRINT-DELETE'), SnackBarNotificationLevel.Error); - } else { - this.uiNotificationService.snackBarNotification(this.languageService.instant(error.message), SnackBarNotificationLevel.Error); - } - } - ); - } - } - ) - } - } - - onCallbackError(errorResponse: HttpErrorResponse) { - this.uiNotificationService.snackBarNotification(errorResponse.message, SnackBarNotificationLevel.Warning); - } - - getDefaultCriteria(): DmpBlueprintCriteria { - const defaultCriteria = new DmpBlueprintCriteria(); - return defaultCriteria; - } - - // makeItPublic(id: String) { - // debugger; - // this.datasetService.makeDatasetPublic(id).pipe(takeUntil(this._destroyed)).subscribe(); - // } - - parseStatus(value: number): string { - const stringVal = value.toString() - try { - return this.statuses.find(status => status.value === stringVal).viewValue; - } catch { - return stringVal; - } - } - - openDialog(): void { - const dialogRef = this.dialog.open(DialodConfirmationUploadDmpProfiles, { - restoreFocus: false, - data: { - message: this.languageService.instant('DMP-PROFILE-LISTING.UPLOAD.UPLOAD-XML-FILE-TITLE'), - confirmButton: this.languageService.instant('DMP-PROFILE-LISTING.UPLOAD.UPLOAD-XML'), - cancelButton: this.languageService.instant('DMP-PROFILE-LISTING.UPLOAD.UPLOAD-XML-FILE-CANCEL'), - name: '', - file: FileList, - sucsess: false - } - }); - dialogRef.afterClosed().pipe(takeUntil(this._destroyed)).subscribe(data => { - if (data && data.sucsess && data.name != null && data.file != null) { - this.dmpProfileService.uploadFile(data.file, data.name) - .pipe(takeUntil(this._destroyed)) - .subscribe(_ => { - this.uiNotificationService.snackBarNotification(this.languageService.instant('DMP-PROFILE-LISTING.MESSAGES.TEMPLATE-UPLOAD-SUCCESS'), SnackBarNotificationLevel.Success); - this.refresh(); - }, - error => { - this.uiNotificationService.snackBarNotification(error.message, SnackBarNotificationLevel.Error); - }); - } - }); - } - getStatusClass(status: number): string { - - if (status === 1) {//finalized - return 'status-chip-finalized' - } - if (status === 0) { - return 'status-chip-draft'; - } - return ''; - } -} - -export class DatasetDataSource extends DataSource { - - totalCount = 0; - - constructor( - private _service: DmpProfileService, - private _paginator: MatPaginator, - private _sort: MatSort, - private _criteria: DmpProfileCriteriaComponent - ) { - super(); - - } - - connect(): Observable { - const displayDataChanges = [ - this._paginator.page - //this._sort.matSortChange - ]; - - return observableMerge(...displayDataChanges).pipe( - startWith(null), - switchMap(() => { - const startIndex = this._paginator.pageIndex * this._paginator.pageSize; - let fields: Array = new Array(); - if (this._sort.active) { fields = this._sort.direction === 'asc' ? ['+' + this._sort.active] : ['-' + this._sort.active]; } - const request = new DataTableRequest(startIndex, this._paginator.pageSize, { fields: fields }); - request.criteria = this._criteria.criteria; - return this._service.getPagedBlueprint(request); - }), - /*.catch((error: any) => { - this._snackBar.openFromComponent(SnackBarNotificationComponent, { - data: { message: 'GENERAL.SNACK-BAR.FORMS-BAD-REQUEST', language: this._languageService }, - duration: 3000, - extraClasses: ['snackbar-warning'] - }); - //this._criteria.criteria.onCallbackError(error); - return Observable.of(null); - })*/ - map(result => { - return result; - }), - map(result => { - if (!result) { return []; } - if (this._paginator.pageIndex === 0) { this.totalCount = result.totalCount; } - return result.data; - })); - } - - disconnect() { - // No-op - } -} diff --git a/dmp-frontend/src/app/ui/admin/user/listing/user-listing.component.ts b/dmp-frontend/src/app/ui/admin/user/listing/user-listing.component.ts index 87caba526..82f8119b6 100644 --- a/dmp-frontend/src/app/ui/admin/user/listing/user-listing.component.ts +++ b/dmp-frontend/src/app/ui/admin/user/listing/user-listing.component.ts @@ -17,7 +17,7 @@ import { UserListingModel } from '../../../../core/model/user/user-listing'; import { UserCriteria } from '../../../../core/query/user/user-criteria'; import { UserService } from '../../../../core/services/user/user.service'; import { SnackBarNotificationComponent } from '../../../../library/notification/snack-bar/snack-bar-notification.component'; -import { BreadcrumbItem } from '../../../misc/breadcrumb/definition/breadcrumb-item'; +// import { BreadcrumbItem } from '../../../misc/breadcrumb/definition/breadcrumb-item'; import { UserCriteriaComponent } from './criteria/user-criteria.component'; export class UsersDataSource extends DataSource { @@ -102,7 +102,7 @@ export class UserListingComponent extends BaseComponent implements OnInit, After @ViewChild(MatSort, { static: true }) sort: MatSort; @ViewChild(UserCriteriaComponent, { static: true }) criteria: UserCriteriaComponent; - breadCrumbs: Observable; + // breadCrumbs: Observable; dataSource: UsersDataSource | null; displayedColumns: String[] = ['avatar', 'name', 'email', 'lastloggedin', 'roles']; @@ -118,11 +118,11 @@ export class UserListingComponent extends BaseComponent implements OnInit, After ngOnInit() { this.matomoService.trackPageView('Admin: Users'); - this.breadCrumbs = observableOf([{ - parentComponentName: null, - label: this.languageService.instant('NAV-BAR.USERS-BREADCRUMB'), - url: "/users" - }]); + // this.breadCrumbs = observableOf([{ + // parentComponentName: null, + // label: this.languageService.instant('NAV-BAR.USERS-BREADCRUMB'), + // url: "/users" + // }]); //this.refresh(); //called on ngAfterViewInit with default criteria } diff --git a/dmp-frontend/src/app/ui/dashboard/dashboard.component.ts b/dmp-frontend/src/app/ui/dashboard/dashboard.component.ts index 999c1684c..87622ab45 100644 --- a/dmp-frontend/src/app/ui/dashboard/dashboard.component.ts +++ b/dmp-frontend/src/app/ui/dashboard/dashboard.component.ts @@ -21,8 +21,6 @@ import { SingleAutoCompleteConfiguration } from '@app/library/auto-complete/sing import { BaseComponent } from '@common/base/base.component'; import { Observable, of as observableOf } from 'rxjs'; import { mergeMap, takeUntil } from 'rxjs/operators'; -import { BreadcrumbItem } from '../misc/breadcrumb/definition/breadcrumb-item'; -import { IBreadCrumbComponent } from '../misc/breadcrumb/definition/IBreadCrumbComponent'; import { DmpCriteria } from '@app/core/query/dmp/dmp-criteria'; import { DatasetCriteria } from '@app/core/query/dataset/dataset-criteria'; import { MatDialog } from '@angular/material/dialog'; @@ -42,9 +40,7 @@ import { MatomoService } from '@app/core/services/matomo/matomo-service'; templateUrl: './dashboard.component.html', styleUrls: ['./dashboard.component.scss'], }) -export class DashboardComponent extends BaseComponent implements OnInit, IBreadCrumbComponent { - - breadCrumbs: Observable; +export class DashboardComponent extends BaseComponent implements OnInit { public isVisible = true @@ -127,9 +123,6 @@ export class DashboardComponent extends BaseComponent implements OnInit, IBreadC // titleFn: (item) => item['label'] // }; - const breadCrumbs = []; - this.breadCrumbs = observableOf(breadCrumbs); - if (!this.isAuthenticated()) { this.dashboardService.getStatistics() .pipe(takeUntil(this._destroyed)) diff --git a/dmp-frontend/src/app/ui/dashboard/dmp-info-counter/dmp-info-counter.component.html b/dmp-frontend/src/app/ui/dashboard/dmp-info-counter/dmp-info-counter.component.html index a7ea65a4e..a0aa2a65c 100644 --- a/dmp-frontend/src/app/ui/dashboard/dmp-info-counter/dmp-info-counter.component.html +++ b/dmp-frontend/src/app/ui/dashboard/dmp-info-counter/dmp-info-counter.component.html @@ -26,7 +26,7 @@
-

{{'DMP-PROFILE-LISTING.COLUMNS.PUBLISHED' | translate}} {{dmp.creationTime | date: "shortDate"}}

+

{{'DMP-BLUEPRINT-LISTING.COLUMNS.PUBLISHED' | translate}} {{dmp.creationTime | date: "shortDate"}}

diff --git a/dmp-frontend/src/app/ui/dashboard/drafts/drafts.component.ts b/dmp-frontend/src/app/ui/dashboard/drafts/drafts.component.ts index 13fbe2de3..98396352e 100644 --- a/dmp-frontend/src/app/ui/dashboard/drafts/drafts.component.ts +++ b/dmp-frontend/src/app/ui/dashboard/drafts/drafts.component.ts @@ -43,7 +43,7 @@ import {ExtraPropertiesFormModel} from "@app/ui/dmp/editor/general-tab/extra-pro import {CloneDialogComponent} from "@app/ui/dmp/clone/clone-dialog/clone-dialog.component"; import { isNullOrUndefined } from '@app/utilities/enhancers/utils'; import { DmpBlueprintDefinition, SystemFieldType } from '@app/core/model/dmp/dmp-blueprint/dmp-blueprint'; -import { DmpProfileService } from '@app/core/services/dmp/dmp-profile.service'; +import { DmpBlueprintService } from '@app/core/services/dmp/dmp-blueprint.service'; @Component({ selector: 'app-drafts', @@ -84,7 +84,7 @@ export class DraftsComponent extends BaseComponent implements OnInit { public enumUtils: EnumUtils, private authentication: AuthService, private dmpService: DmpService, - private dmpProfileService: DmpProfileService, + private dmpBlueprintService: DmpBlueprintService, private dashboardService: DashboardService, private language: TranslateService, private dialog: MatDialog, @@ -238,7 +238,7 @@ export class DraftsComponent extends BaseComponent implements OnInit { this.dmpFormGroup = this.dmpModel.buildForm(); if (!isNullOrUndefined(this.formGroup.get('profile').value)) { - this.dmpProfileService.getSingleBlueprint(this.formGroup.get('profile').value) + this.dmpBlueprintService.getSingleBlueprint(this.formGroup.get('profile').value) .pipe(takeUntil(this._destroyed)) .subscribe(result => { this.checkForGrant(result.definition); @@ -477,7 +477,7 @@ export class DraftsComponent extends BaseComponent implements OnInit { } } - // dmpProfileDisplay(value: any) { + // dmpBlueprintDisplay(value: any) { // if (value != null) { // return value; // } diff --git a/dmp-frontend/src/app/ui/dashboard/recent-edited-activity/recent-edited-activity.component.ts b/dmp-frontend/src/app/ui/dashboard/recent-edited-activity/recent-edited-activity.component.ts index e9a29e357..e56fd9c63 100644 --- a/dmp-frontend/src/app/ui/dashboard/recent-edited-activity/recent-edited-activity.component.ts +++ b/dmp-frontend/src/app/ui/dashboard/recent-edited-activity/recent-edited-activity.component.ts @@ -42,7 +42,7 @@ import { CloneDialogComponent } from '@app/ui/dmp/clone/clone-dialog/clone-dialo import { MatomoService } from '@app/core/services/matomo/matomo-service'; import { HttpClient } from '@angular/common/http'; import { isNullOrUndefined } from '@app/utilities/enhancers/utils'; -import { DmpProfileService } from '@app/core/services/dmp/dmp-profile.service'; +import { DmpBlueprintService } from '@app/core/services/dmp/dmp-blueprint.service'; import { DmpBlueprintDefinition, SystemFieldType } from '@app/core/model/dmp/dmp-blueprint/dmp-blueprint'; @Component({ @@ -84,7 +84,7 @@ export class RecentEditedActivityComponent extends BaseComponent implements OnIn public enumUtils: EnumUtils, private authentication: AuthService, private dmpService: DmpService, - private dmpProfileService: DmpProfileService, + private dmpBlueprintService: DmpBlueprintService, private dashboardService: DashboardService, private language: TranslateService, private dialog: MatDialog, @@ -304,7 +304,7 @@ export class RecentEditedActivityComponent extends BaseComponent implements OnIn this.dmpFormGroup = this.dmpModel.buildForm(); if (!isNullOrUndefined(this.formGroup.get('profile').value)) { - this.dmpProfileService.getSingleBlueprint(this.formGroup.get('profile').value) + this.dmpBlueprintService.getSingleBlueprint(this.formGroup.get('profile').value) .pipe(takeUntil(this._destroyed)) .subscribe(result => { this.checkForGrant(result.definition); @@ -547,7 +547,7 @@ export class RecentEditedActivityComponent extends BaseComponent implements OnIn } } - // dmpProfileDisplay(value: any) { + // dmpBlueprintDisplay(value: any) { // if (value != null) { // return value; // } diff --git a/dmp-frontend/src/app/ui/dashboard/recent-edited-dataset-activity/recent-edited-dataset-activity.component.ts b/dmp-frontend/src/app/ui/dashboard/recent-edited-dataset-activity/recent-edited-dataset-activity.component.ts index a26d4d39c..d509a03f4 100644 --- a/dmp-frontend/src/app/ui/dashboard/recent-edited-dataset-activity/recent-edited-dataset-activity.component.ts +++ b/dmp-frontend/src/app/ui/dashboard/recent-edited-dataset-activity/recent-edited-dataset-activity.component.ts @@ -16,8 +16,7 @@ import { DatasetWizardService } from '@app/core/services/dataset-wizard/dataset- import * as FileSaver from 'file-saver'; import { ConfirmationDialogComponent } from '@common/modules/confirmation-dialog/confirmation-dialog.component'; import { ValidationErrorModel } from '@common/forms/validation/error-model/validation-error-model'; -import { UiNotificationService } from '@app/core/services/notification/ui-notification-service'; -import { SnackBarNotificationLevel } from '@common/modules/notification/ui-notification-service'; +import { SnackBarNotificationLevel, UiNotificationService } from '@app/core/services/notification/ui-notification-service'; import { DatasetStatus } from '@app/core/common/enum/dataset-status'; import { DmpInvitationDialogComponent } from '@app/ui/dmp/invitation/dmp-invitation-dialog.component'; import { RecentActivityOrder } from '@app/core/common/enum/recent-activity-order'; diff --git a/dmp-frontend/src/app/ui/dashboard/recent-edited-dmp-activity/recent-edited-dmp-activity.component.ts b/dmp-frontend/src/app/ui/dashboard/recent-edited-dmp-activity/recent-edited-dmp-activity.component.ts index 1d71a7cb2..3d5f407e8 100644 --- a/dmp-frontend/src/app/ui/dashboard/recent-edited-dmp-activity/recent-edited-dmp-activity.component.ts +++ b/dmp-frontend/src/app/ui/dashboard/recent-edited-dmp-activity/recent-edited-dmp-activity.component.ts @@ -34,7 +34,7 @@ import { ProjectFormModel } from '@app/ui/dmp/editor/grant-tab/project-form-mode import { MatomoService } from '@app/core/services/matomo/matomo-service'; import { HttpClient } from '@angular/common/http'; import { isNullOrUndefined } from '@app/utilities/enhancers/utils'; -import { DmpProfileService } from '@app/core/services/dmp/dmp-profile.service'; +import { DmpBlueprintService } from '@app/core/services/dmp/dmp-blueprint.service'; import { DmpBlueprintDefinition, SystemFieldType } from '@app/core/model/dmp/dmp-blueprint/dmp-blueprint'; @Component({ @@ -77,7 +77,7 @@ export class RecentEditedDmpActivityComponent extends BaseComponent implements O public enumUtils: EnumUtils, private authentication: AuthService, private dmpService: DmpService, - private dmpProfileService: DmpProfileService, + private dmpBlueprintService: DmpBlueprintService, private datasetService: DatasetService, private language: TranslateService, private dialog: MatDialog, @@ -257,7 +257,7 @@ export class RecentEditedDmpActivityComponent extends BaseComponent implements O this.dmpFormGroup = this.dmpModel.buildForm(); if (!isNullOrUndefined(this.formGroup.get('profile').value)) { - this.dmpProfileService.getSingleBlueprint(this.formGroup.get('profile').value) + this.dmpBlueprintService.getSingleBlueprint(this.formGroup.get('profile').value) .pipe(takeUntil(this._destroyed)) .subscribe(result => { this.checkForGrant(result.definition); @@ -476,7 +476,7 @@ export class RecentEditedDmpActivityComponent extends BaseComponent implements O } } - // dmpProfileDisplay(value: any) { + // dmpBlueprintDisplay(value: any) { // if (value != null) { // return value; // } diff --git a/dmp-frontend/src/app/ui/dataset-create-wizard/dataset-create-wizard.component.ts b/dmp-frontend/src/app/ui/dataset-create-wizard/dataset-create-wizard.component.ts index 4599943a9..931cd2e2f 100644 --- a/dmp-frontend/src/app/ui/dataset-create-wizard/dataset-create-wizard.component.ts +++ b/dmp-frontend/src/app/ui/dataset-create-wizard/dataset-create-wizard.component.ts @@ -9,12 +9,9 @@ import { SnackBarNotificationLevel, UiNotificationService } from '@app/core/serv import { QuickWizardService } from '@app/core/services/quick-wizard/quick-wizard.service'; import { CheckDeactivateBaseComponent } from '@app/library/deactivate/deactivate.component'; import { DatasetCreateWizardModel } from '@app/ui/dataset-create-wizard/dataset-create-wizard.model'; -import { BreadcrumbItem } from '@app/ui/misc/breadcrumb/definition/breadcrumb-item'; -import { IBreadCrumbComponent } from '@app/ui/misc/breadcrumb/definition/IBreadCrumbComponent'; import { DatasetEditorWizardComponent } from '@app/ui/quick-wizard/dataset-editor/dataset-editor-wizard.component'; import { ConfirmationDialogComponent } from '@common/modules/confirmation-dialog/confirmation-dialog.component'; import { TranslateService } from '@ngx-translate/core'; -import { Observable, of as observableOf } from 'rxjs'; import { takeUntil } from 'rxjs/operators'; @Component({ @@ -22,8 +19,8 @@ import { takeUntil } from 'rxjs/operators'; templateUrl: 'dataset-create-wizard.component.html', styleUrls: ['./dataset-create-wizard.component.scss'], }) -export class DatasetCreateWizard extends CheckDeactivateBaseComponent implements OnInit, IBreadCrumbComponent { - breadCrumbs: Observable; +export class DatasetCreateWizard extends CheckDeactivateBaseComponent implements OnInit { //IBreadCrumbComponent + //breadCrumbs: Observable; @ViewChild(DatasetEditorWizardComponent) datasetEditorWizardComponent: DatasetEditorWizardComponent; isLinear = false; isNew = true; @@ -49,13 +46,13 @@ export class DatasetCreateWizard extends CheckDeactivateBaseComponent implements this.datasetCreateWizardModel = new DatasetCreateWizardModel(); this.formGroup = this.datasetCreateWizardModel.buildForm(); this.language.get('NAV-BAR.DATASET-DESCRIPTION-WIZARD').pipe(takeUntil(this._destroyed)).subscribe(x => { - this.breadCrumbs = observableOf([ - { - parentComponentName: 'Dashboard', - label: x, - url: '/datasetcreatewizard' - }] - ); + // this.breadCrumbs = observableOf([ + // { + // parentComponentName: 'Dashboard', + // label: x, + // url: '/datasetcreatewizard' + // }] + // ); }) } diff --git a/dmp-frontend/src/app/ui/dataset-create-wizard/dmp-selector/dataset-dmp-selector.component.ts b/dmp-frontend/src/app/ui/dataset-create-wizard/dmp-selector/dataset-dmp-selector.component.ts index 68b3a704d..e16b96423 100644 --- a/dmp-frontend/src/app/ui/dataset-create-wizard/dmp-selector/dataset-dmp-selector.component.ts +++ b/dmp-frontend/src/app/ui/dataset-create-wizard/dmp-selector/dataset-dmp-selector.component.ts @@ -13,8 +13,6 @@ import { RequestItem } from '@app/core/query/request-item'; import { DatasetWizardService } from '@app/core/services/dataset-wizard/dataset-wizard.service'; import { DmpService } from '@app/core/services/dmp/dmp.service'; import { SingleAutoCompleteConfiguration } from '@app/library/auto-complete/single/single-auto-complete-configuration'; -import { BreadcrumbItem } from '@app/ui/misc/breadcrumb/definition/breadcrumb-item'; -import { IBreadCrumbComponent } from '@app/ui/misc/breadcrumb/definition/IBreadCrumbComponent'; import { BaseComponent } from '@common/base/base.component'; import { Observable } from 'rxjs'; import { map, takeUntil } from 'rxjs/operators'; @@ -27,9 +25,8 @@ import { TranslateService } from "@ngx-translate/core"; styleUrls: ['./dataset-dmp-selector.component.scss'], }) -export class DatasetDmpSelector extends BaseComponent implements OnInit, IBreadCrumbComponent { +export class DatasetDmpSelector extends BaseComponent implements OnInit { - breadCrumbs: Observable; dmpAutoCompleteConfiguration: SingleAutoCompleteConfiguration; @Input() formGroup: UntypedFormGroup; @Input() datasetFormGroup: UntypedFormGroup; diff --git a/dmp-frontend/src/app/ui/dataset/dataset-wizard/dataset-copy-dialogue/dataset-copy-dialogue.component.ts b/dmp-frontend/src/app/ui/dataset/dataset-wizard/dataset-copy-dialogue/dataset-copy-dialogue.component.ts index 37b53eb00..d0ba0a000 100644 --- a/dmp-frontend/src/app/ui/dataset/dataset-wizard/dataset-copy-dialogue/dataset-copy-dialogue.component.ts +++ b/dmp-frontend/src/app/ui/dataset/dataset-wizard/dataset-copy-dialogue/dataset-copy-dialogue.component.ts @@ -11,7 +11,7 @@ import { DmpService } from "../../../../core/services/dmp/dmp.service"; import { Inject } from "@angular/core"; import { DmpModel } from "../../../../core/model/dmp/dmp"; import { TranslateService } from "@ngx-translate/core"; -import { DmpAssociatedProfileModel } from '../../../../core/model/dmp-profile/dmp-associated-profile'; +import { DmpAssociatedProfileModel } from '../../../../core/model/dmp-blueprint/dmp-associated-profile'; @Component({ selector: 'dataset-copy-dialogue-component', diff --git a/dmp-frontend/src/app/ui/dataset/dataset-wizard/dataset-editor/dataset-editor.component.ts b/dmp-frontend/src/app/ui/dataset/dataset-wizard/dataset-editor/dataset-editor.component.ts index aafb6fe66..b5ed1f52e 100644 --- a/dmp-frontend/src/app/ui/dataset/dataset-wizard/dataset-editor/dataset-editor.component.ts +++ b/dmp-frontend/src/app/ui/dataset/dataset-wizard/dataset-editor/dataset-editor.component.ts @@ -7,7 +7,7 @@ import { GuidedTour, Orientation } from '@app/library/guided-tour/guided-tour.co import { TranslateService } from '@ngx-translate/core'; import { DatasetProfileModel } from '@app/core/model/dataset/dataset-profile'; import { takeUntil } from 'rxjs/operators'; -import { DmpProfileService } from '@app/core/services/dmp/dmp-profile.service'; +import { DmpBlueprintService } from '@app/core/services/dmp/dmp-blueprint.service'; import { MatDialog } from '@angular/material/dialog'; import { PopupNotificationDialogComponent } from '@app/library/notification/popup/popup-notification.component'; @@ -28,7 +28,7 @@ export class DatasetEditorComponent extends BaseComponent { constructor( private router: Router, - private dmpProfileService: DmpProfileService, + private dmpBlueprintService: DmpBlueprintService, private dialog: MatDialog, private guidedTourService: GuidedTourService, private language: TranslateService @@ -53,7 +53,7 @@ export class DatasetEditorComponent extends BaseComponent { event.stopPropagation(); const dmpSectionIndex = this.formGroup.get('dmpSectionIndex').value; const blueprintId = this.formGroup.get('dmp').value.profile.id; - this.dmpProfileService.getSingleBlueprint(blueprintId) + this.dmpBlueprintService.getSingleBlueprint(blueprintId) .pipe(takeUntil(this._destroyed)) .subscribe(result => { const section = result.definition.sections[dmpSectionIndex]; diff --git a/dmp-frontend/src/app/ui/dataset/dataset-wizard/dataset-wizard.component.ts b/dmp-frontend/src/app/ui/dataset/dataset-wizard/dataset-wizard.component.ts index 5ab11ac9b..e9f3c2e1a 100644 --- a/dmp-frontend/src/app/ui/dataset/dataset-wizard/dataset-wizard.component.ts +++ b/dmp-frontend/src/app/ui/dataset/dataset-wizard/dataset-wizard.component.ts @@ -40,8 +40,8 @@ import { } from '@app/ui/dataset/dataset-wizard/dataset-copy-dialogue/dataset-copy-dialogue.component'; import { DatasetWizardEditorModel } from '@app/ui/dataset/dataset-wizard/dataset-wizard-editor.model'; import { PrefillDatasetComponent } from "@app/ui/dataset/dataset-wizard/prefill-dataset/prefill-dataset.component"; -import { IBreadCrumbComponent } from '@app/ui/misc/breadcrumb/definition/IBreadCrumbComponent'; -import { BreadcrumbItem } from '@app/ui/misc/breadcrumb/definition/breadcrumb-item'; +// import { IBreadCrumbComponent } from '@app/ui/misc/breadcrumb/definition/IBreadCrumbComponent'; +// import { BreadcrumbItem } from '@app/ui/misc/breadcrumb/definition/breadcrumb-item'; import { DatasetDescriptionFormEditorModel } from '@app/ui/misc/dataset-description-form/dataset-description-form.model'; import { ToCEntry, ToCEntryType } from "@app/ui/misc/dataset-description-form/dataset-description.component"; import { @@ -68,12 +68,12 @@ import { catchError, debounceTime, filter, map, takeUntil } from 'rxjs/operators templateUrl: 'dataset-wizard.component.html', styleUrls: ['./dataset-wizard.component.scss'] }) -export class DatasetWizardComponent extends CheckDeactivateBaseComponent implements OnInit, IBreadCrumbComponent { +export class DatasetWizardComponent extends CheckDeactivateBaseComponent implements OnInit {//IBreadCrumbComponent canDeactivate(): boolean { return !this.isDirty(); } - breadCrumbs: Observable; + // breadCrumbs: Observable; viewOnly = false; editMode = false; publicMode = false; @@ -200,19 +200,19 @@ export class DatasetWizardComponent extends CheckDeactivateBaseComponent impleme this.datasetWizardModel = new DatasetWizardEditorModel().fromModel(data); this.dmpSectionIndex = this.datasetWizardModel.dmpSectionIndex; this.needsUpdate(); - this.breadCrumbs = observableOf([ - { - parentComponentName: null, - label: this.datasetWizardModel.label, - url: '/datasets/edit/' + this.datasetWizardModel.id, - notFoundResolver: [ - { - parentComponentName: null, - label: this.language.instant('NAV-BAR.MY-DATASET-DESCRIPTIONS').toUpperCase(), - url: '/datasets' - }, - ] - }]); + // this.breadCrumbs = observableOf([ + // { + // parentComponentName: null, + // label: this.datasetWizardModel.label, + // url: '/datasets/edit/' + this.datasetWizardModel.id, + // notFoundResolver: [ + // { + // parentComponentName: null, + // label: this.language.instant('NAV-BAR.MY-DATASET-DESCRIPTIONS').toUpperCase(), + // url: '/datasets' + // }, + // ] + // }]); this.formGroup = this.datasetWizardModel.buildForm(); let profiles = this.datasetWizardModel.dmp.profiles.filter(profile => profile.data.dmpSectionIndex.includes(this.datasetWizardModel.dmpSectionIndex)); for (var profile of profiles) { @@ -315,23 +315,23 @@ export class DatasetWizardComponent extends CheckDeactivateBaseComponent impleme this.registerFormListeners(); // this.availableProfiles = data.profiles; - this.breadCrumbs = observableOf([ - { - parentComponentName: null, - label: this.language.instant('NAV-BAR.MY-DATASET-DESCRIPTIONS'), - url: '/datasets', - notFoundResolver: [ - // { - // parentComponentName: null, - // label: this.datasetWizardModel.dmp.grant.label, - // url: '/grants/edit/' + this.datasetWizardModel.dmp.grant.id - // }, - { - parentComponentName: null, - label: this.datasetWizardModel.dmp.label, - url: '/plans/edit/' + this.datasetWizardModel.dmp.id, - }] - }]); + // this.breadCrumbs = observableOf([ + // { + // parentComponentName: null, + // label: this.language.instant('NAV-BAR.MY-DATASET-DESCRIPTIONS'), + // url: '/datasets', + // notFoundResolver: [ + // // { + // // parentComponentName: null, + // // label: this.datasetWizardModel.dmp.grant.label, + // // url: '/grants/edit/' + this.datasetWizardModel.dmp.grant.id + // // }, + // { + // parentComponentName: null, + // label: this.datasetWizardModel.dmp.label, + // url: '/plans/edit/' + this.datasetWizardModel.dmp.id, + // }] + // }]); }); }); } else if (this.newDmpId != null) { @@ -356,24 +356,24 @@ export class DatasetWizardComponent extends CheckDeactivateBaseComponent impleme this.formGroupRawValue = JSON.parse(JSON.stringify(this.formGroup.getRawValue())); this.loadDatasetProfiles(); - this.breadCrumbs = observableOf([ - { - parentComponentName: null, - label: this.language.instant('NAV-BAR.MY-DATASET-DESCRIPTIONS'), - url: '/datasets', - notFoundResolver: [ - // { - // parentComponentName: null, - // label: this.datasetWizardModel.dmp.grant.label, - // url: '/grants/edit/' + this.datasetWizardModel.dmp.grant.id - // }, - { - parentComponentName: null, - label: this.datasetWizardModel.dmp.label, - url: '/plans/edit/' + this.datasetWizardModel.dmp.id, - } - ] - }]); + // this.breadCrumbs = observableOf([ + // { + // parentComponentName: null, + // label: this.language.instant('NAV-BAR.MY-DATASET-DESCRIPTIONS'), + // url: '/datasets', + // notFoundResolver: [ + // // { + // // parentComponentName: null, + // // label: this.datasetWizardModel.dmp.grant.label, + // // url: '/grants/edit/' + this.datasetWizardModel.dmp.grant.id + // // }, + // { + // parentComponentName: null, + // label: this.datasetWizardModel.dmp.label, + // url: '/plans/edit/' + this.datasetWizardModel.dmp.id, + // } + // ] + // }]); }); }); this.editMode = this.datasetWizardModel.status === DatasetStatus.Draft; @@ -429,7 +429,7 @@ export class DatasetWizardComponent extends CheckDeactivateBaseComponent impleme label: this.datasetWizardModel.label, url: '/datasets/publicEdit/' + this.datasetWizardModel.id }); - this.breadCrumbs = observableOf(breadcrumbs); + // this.breadCrumbs = observableOf(breadcrumbs); } }); this.publicMode = true; @@ -441,24 +441,24 @@ export class DatasetWizardComponent extends CheckDeactivateBaseComponent impleme this.formGroupRawValue = JSON.parse(JSON.stringify(this.formGroup.getRawValue())); this.needsUpdate(); - this.breadCrumbs = observableOf([ - { - parentComponentName: null, - label: this.language.instant('NAV-BAR.MY-DATASET-DESCRIPTIONS'), - url: '/datasets', - notFoundResolver: [ - // { - // parentComponentName: null, - // label: this.datasetWizardModel.dmp.grant.label, - // url: '/grants/edit/' + this.datasetWizardModel.dmp.grant.id - // }, - { - parentComponentName: null, - label: this.datasetWizardModel.dmp.label, - url: '/plans/edit/' + this.datasetWizardModel.dmp.id, - }, - ] - }]); + // this.breadCrumbs = observableOf([ + // { + // parentComponentName: null, + // label: this.language.instant('NAV-BAR.MY-DATASET-DESCRIPTIONS'), + // url: '/datasets', + // notFoundResolver: [ + // // { + // // parentComponentName: null, + // // label: this.datasetWizardModel.dmp.grant.label, + // // url: '/grants/edit/' + this.datasetWizardModel.dmp.grant.id + // // }, + // { + // parentComponentName: null, + // label: this.datasetWizardModel.dmp.label, + // url: '/plans/edit/' + this.datasetWizardModel.dmp.id, + // }, + // ] + // }]); this.formGroup = this.datasetWizardModel.buildForm(); this.editMode = this.datasetWizardModel.status === DatasetStatus.Draft; if (this.datasetWizardModel.status === DatasetStatus.Finalized) { @@ -482,12 +482,12 @@ export class DatasetWizardComponent extends CheckDeactivateBaseComponent impleme //if (this.viewOnly) { this.formGroup.disable(); } // For future use, to make Dataset edit like DMP. this.registerFormListeners(); this.dmpValueChanged(null); - this.breadCrumbs = observableOf([ - { - parentComponentName: null, - label: this.language.instant('DATASET-LISTING.ACTIONS.CREATE-NEW').toUpperCase(), - url: '/datasets/new/' - }]); + // this.breadCrumbs = observableOf([ + // { + // parentComponentName: null, + // label: this.language.instant('DATASET-LISTING.ACTIONS.CREATE-NEW').toUpperCase(), + // url: '/datasets/new/' + // }]); } } diff --git a/dmp-frontend/src/app/ui/dataset/dataset-wizard/prefill-dataset/prefill-dataset.component.ts b/dmp-frontend/src/app/ui/dataset/dataset-wizard/prefill-dataset/prefill-dataset.component.ts index 7849631b2..fa896a0b3 100644 --- a/dmp-frontend/src/app/ui/dataset/dataset-wizard/prefill-dataset/prefill-dataset.component.ts +++ b/dmp-frontend/src/app/ui/dataset/dataset-wizard/prefill-dataset/prefill-dataset.component.ts @@ -3,7 +3,7 @@ import { UntypedFormBuilder, UntypedFormGroup, Validators } from "@angular/forms import { MAT_DIALOG_DATA, MatDialog, MatDialogRef } from "@angular/material/dialog"; import { DatasetProfileModel } from "@app/core/model/dataset/dataset-profile"; import { Prefilling } from "@app/core/model/dataset/prefilling"; -import { DmpProfileService } from "@app/core/services/dmp/dmp-profile.service"; +import { DmpBlueprintService } from "@app/core/services/dmp/dmp-blueprint.service"; import { PrefillingService } from "@app/core/services/prefilling.service"; import { ProgressIndicationService } from "@app/core/services/progress-indication/progress-indication-service"; import { SingleAutoCompleteConfiguration } from "@app/library/auto-complete/single/single-auto-complete-configuration"; @@ -27,7 +27,7 @@ export class PrefillDatasetComponent extends BaseComponent implements OnInit { constructor(public dialogRef: MatDialogRef, private prefillingService: PrefillingService, - private dmpProfileService: DmpProfileService, + private dmpBlueprintService: DmpBlueprintService, private dialog: MatDialog, private language: TranslateService, private progressIndicationService: ProgressIndicationService, @@ -60,7 +60,7 @@ export class PrefillDatasetComponent extends BaseComponent implements OnInit { addProfileIfUsedLessThanMax(profile: DatasetProfileModel) { const dmpSectionIndex = this.data.datasetFormGroup.get('dmpSectionIndex').value; const blueprintId = this.data.datasetFormGroup.get('dmp').value.profile.id; - this.dmpProfileService.getSingleBlueprint(blueprintId) + this.dmpBlueprintService.getSingleBlueprint(blueprintId) .pipe(takeUntil(this._destroyed)) .subscribe(result => { const section = result.definition.sections[dmpSectionIndex]; @@ -93,7 +93,7 @@ export class PrefillDatasetComponent extends BaseComponent implements OnInit { event.stopPropagation(); const dmpSectionIndex = this.data.datasetFormGroup.get('dmpSectionIndex').value; const blueprintId = this.data.datasetFormGroup.get('dmp').value.profile.id; - this.dmpProfileService.getSingleBlueprint(blueprintId) + this.dmpBlueprintService.getSingleBlueprint(blueprintId) .pipe(takeUntil(this._destroyed)) .subscribe(result => { const section = result.definition.sections[dmpSectionIndex]; diff --git a/dmp-frontend/src/app/ui/dataset/listing/dataset-listing.component.ts b/dmp-frontend/src/app/ui/dataset/listing/dataset-listing.component.ts index bb8d55e53..2f922dd7d 100644 --- a/dmp-frontend/src/app/ui/dataset/listing/dataset-listing.component.ts +++ b/dmp-frontend/src/app/ui/dataset/listing/dataset-listing.component.ts @@ -21,8 +21,8 @@ import { GuidedTourService } from '@app/library/guided-tour/guided-tour.service' import { DatasetCriteriaComponent } from '@app/ui/dataset/listing/criteria/dataset-criteria.component'; import { StartNewDatasetDialogComponent } from '@app/ui/dmp/start-new-dataset-dialogue/start-new-dataset-dialog.component'; import { StartNewDmpDialogComponent } from '@app/ui/dmp/start-new-dmp-dialogue/start-new-dmp-dialog.component'; -import { IBreadCrumbComponent } from '@app/ui/misc/breadcrumb/definition/IBreadCrumbComponent'; -import { BreadcrumbItem } from '@app/ui/misc/breadcrumb/definition/breadcrumb-item'; +// import { IBreadCrumbComponent } from '@app/ui/misc/breadcrumb/definition/IBreadCrumbComponent'; +// import { BreadcrumbItem } from '@app/ui/misc/breadcrumb/definition/breadcrumb-item'; import { isNullOrUndefined } from '@app/utilities/enhancers/utils'; import { BaseComponent } from '@common/base/base.component'; import { TranslateService } from '@ngx-translate/core'; @@ -36,13 +36,13 @@ import { DatasetCriteriaDialogComponent } from './criteria/dataset-criteria-dial templateUrl: 'dataset-listing.component.html', styleUrls: ['./dataset-listing.component.scss'] }) -export class DatasetListingComponent extends BaseComponent implements OnInit, IBreadCrumbComponent { +export class DatasetListingComponent extends BaseComponent implements OnInit {//IBreadCrumbComponent @ViewChild(MatPaginator, { static: true }) _paginator: MatPaginator; @ViewChild(MatSort) sort: MatSort; // @ViewChild(DatasetCriteriaComponent, { static: true }) criteria: DatasetCriteriaComponent; - breadCrumbs: Observable; + // breadCrumbs: Observable; titlePrefix: String; dmpId: string; @@ -112,11 +112,11 @@ export class DatasetListingComponent extends BaseComponent implements OnInit, IB // this.criteria.setCriteria(this.getDefaultCriteria(dmp)); this.refresh(); // this.criteria.setRefreshCallback((resetPages) => this.refresh(resetPages)); - this.breadCrumbs = observableOf([{ - parentComponentName: 'DmpEditorComponent', - label: dmp.label, - url: '/plans/edit/' + this.dmpId - }]); + // this.breadCrumbs = observableOf([{ + // parentComponentName: 'DmpEditorComponent', + // label: dmp.label, + // url: '/plans/edit/' + this.dmpId + // }]); if (params['dmpLabel'] !== undefined) { this.titlePrefix = 'for ' + params['dmpLabel']; } @@ -125,11 +125,11 @@ export class DatasetListingComponent extends BaseComponent implements OnInit, IB // this.criteria.setCriteria(this.getDefaultCriteria()); this.refresh(); // this.criteria.setRefreshCallback((resetPages) => this.refresh(resetPages)); - this.breadCrumbs = observableOf([{ - parentComponentName: null, - label: this.language.instant('NAV-BAR.MY-DATASET-DESCRIPTIONS'), - url: this.isPublic ? "/explore" : "/datasets" - }]); + // this.breadCrumbs = observableOf([{ + // parentComponentName: null, + // label: this.language.instant('NAV-BAR.MY-DATASET-DESCRIPTIONS'), + // url: this.isPublic ? "/explore" : "/datasets" + // }]); } if (this.status != null && this.status == DatasetStatus.Draft) { diff --git a/dmp-frontend/src/app/ui/dataset/overview/dataset-overview.component.ts b/dmp-frontend/src/app/ui/dataset/overview/dataset-overview.component.ts index d208828d3..db028f03d 100644 --- a/dmp-frontend/src/app/ui/dataset/overview/dataset-overview.component.ts +++ b/dmp-frontend/src/app/ui/dataset/overview/dataset-overview.component.ts @@ -1,7 +1,7 @@ import { Component, OnInit } from '@angular/core'; import { BaseComponent } from '@common/base/base.component'; import { DatasetOverviewModel } from '@app/core/model/dataset/dataset-overview'; -import { BreadcrumbItem } from '@app/ui/misc/breadcrumb/definition/breadcrumb-item'; +// import { BreadcrumbItem } from '@app/ui/misc/breadcrumb/definition/breadcrumb-item'; import { Observable, of as observableOf } from 'rxjs'; import { ActivatedRoute, Router, Params } from '@angular/router'; import { DatasetService } from '@app/core/services/dataset/dataset.service'; @@ -49,7 +49,7 @@ export class DatasetOverviewComponent extends BaseComponent implements OnInit { isFinalized = false; isPublicView = true; hasPublishButton: boolean = true; - breadCrumbs: Observable = observableOf(); + // breadCrumbs: Observable = observableOf(); isUserOwner: boolean; expand = false; researchers: ResearcherModel[]; @@ -97,10 +97,10 @@ export class DatasetOverviewComponent extends BaseComponent implements OnInit { this.users = this.dataset.dmp.users; this.checkLockStatus(this.dataset.id); this.setIsUserOwner(); - const breadCrumbs = []; - breadCrumbs.push({ parentComponentName: null, label: this.language.instant('NAV-BAR.MY-DATASET-DESCRIPTIONS'), url: "/datasets" }); - breadCrumbs.push({ parentComponentName: 'DatasetListingComponent', label: this.dataset.label, url: '/datasets/overview/' + this.dataset.id }); - this.breadCrumbs = observableOf(breadCrumbs); + // const breadCrumbs = []; + // breadCrumbs.push({ parentComponentName: null, label: this.language.instant('NAV-BAR.MY-DATASET-DESCRIPTIONS'), url: "/datasets" }); + // breadCrumbs.push({ parentComponentName: 'DatasetListingComponent', label: this.dataset.label, url: '/datasets/overview/' + this.dataset.id }); + // this.breadCrumbs = observableOf(breadCrumbs); }, (error: any) => { if (error.status === 404) { return this.onFetchingDeletedCallbackError('/datasets/'); @@ -120,10 +120,10 @@ export class DatasetOverviewComponent extends BaseComponent implements OnInit { this.dataset = data; this.researchers = this.dataset.dmp.researchers; this.users = this.dataset.dmp.users; - const breadCrumbs = []; - breadCrumbs.push({ parentComponentName: null, label: this.language.instant('NAV-BAR.PUBLIC DATASETS'), url: "/explore" }); - breadCrumbs.push({ parentComponentName: 'DatasetListingComponent', label: this.dataset.label, url: '/datasets/publicOverview/' + this.dataset.id }); - this.breadCrumbs = observableOf(breadCrumbs); + // const breadCrumbs = []; + // breadCrumbs.push({ parentComponentName: null, label: this.language.instant('NAV-BAR.PUBLIC DATASETS'), url: "/explore" }); + // breadCrumbs.push({ parentComponentName: 'DatasetListingComponent', label: this.dataset.label, url: '/datasets/publicOverview/' + this.dataset.id }); + // this.breadCrumbs = observableOf(breadCrumbs); }, (error: any) => { if (error.status === 404) { return this.onFetchingDeletedCallbackError('/explore'); diff --git a/dmp-frontend/src/app/ui/dmp/clone/clone-dialog/clone-dialog.component.ts b/dmp-frontend/src/app/ui/dmp/clone/clone-dialog/clone-dialog.component.ts index 58b67ae5f..804b42942 100644 --- a/dmp-frontend/src/app/ui/dmp/clone/clone-dialog/clone-dialog.component.ts +++ b/dmp-frontend/src/app/ui/dmp/clone/clone-dialog/clone-dialog.component.ts @@ -77,7 +77,7 @@ export class CloneDialogComponent extends BaseComponent { const criteria = new DatasetProfileCriteria(); criteria.like = value; request.criteria = criteria; - return this.dmpService.searchDMPProfiles(request); + return this.dmpService.searchDmpBlueprints(request); } onPreviewTemplate(event) { diff --git a/dmp-frontend/src/app/ui/dmp/clone/dmp-clone.component.ts b/dmp-frontend/src/app/ui/dmp/clone/dmp-clone.component.ts index ecad37b22..927fbba6d 100644 --- a/dmp-frontend/src/app/ui/dmp/clone/dmp-clone.component.ts +++ b/dmp-frontend/src/app/ui/dmp/clone/dmp-clone.component.ts @@ -10,7 +10,7 @@ import { FunderFormModel } from '@app/ui/dmp/editor/grant-tab/funder-form-model' import { GrantTabModel } from '@app/ui/dmp/editor/grant-tab/grant-tab-model'; import { ProjectFormModel } from '@app/ui/dmp/editor/grant-tab/project-form-model'; import { DmpWizardEditorModel } from '@app/ui/dmp/wizard/dmp-wizard-editor.model'; -import { BreadcrumbItem } from '@app/ui/misc/breadcrumb/definition/breadcrumb-item'; +// import { BreadcrumbItem } from '@app/ui/misc/breadcrumb/definition/breadcrumb-item'; import { BaseComponent } from '@common/base/base.component'; import { ValidationErrorModel } from '@common/forms/validation/error-model/validation-error-model'; import { TranslateService } from '@ngx-translate/core'; @@ -27,7 +27,7 @@ import { DatasetWizardEditorModel } from '@app/ui/dataset/dataset-wizard/dataset import { ConfirmationDialogComponent } from '@common/modules/confirmation-dialog/confirmation-dialog.component'; import { MatDialog } from '@angular/material/dialog'; import { isNullOrUndefined } from '@app/utilities/enhancers/utils'; -import { DmpProfileService } from '@app/core/services/dmp/dmp-profile.service'; +import { DmpBlueprintService } from '@app/core/services/dmp/dmp-blueprint.service'; import { DmpBlueprintDefinition, SystemFieldType } from '@app/core/model/dmp/dmp-blueprint/dmp-blueprint'; @@ -38,7 +38,7 @@ import { DmpBlueprintDefinition, SystemFieldType } from '@app/core/model/dmp/dmp }) export class DmpCloneComponent extends BaseComponent implements OnInit { - breadCrumbs: Observable; + // breadCrumbs: Observable; // dmp: DmpWizardEditorModel; dmp: DmpEditorModel; formGroup: UntypedFormGroup; @@ -65,7 +65,7 @@ export class DmpCloneComponent extends BaseComponent implements OnInit { private router: Router, private language: TranslateService, private dmpService: DmpService, - private dmpProfileService: DmpProfileService, + private dmpBlueprintService: DmpBlueprintService, private authentication: AuthService, private uiNotificationService: UiNotificationService, private datasetService: DatasetService, @@ -92,7 +92,7 @@ export class DmpCloneComponent extends BaseComponent implements OnInit { this.formGroup = this.dmp.buildForm(); if (!isNullOrUndefined(this.formGroup.get('profile').value)) { - this.dmpProfileService.getSingleBlueprint(this.formGroup.get('profile').value) + this.dmpBlueprintService.getSingleBlueprint(this.formGroup.get('profile').value) .pipe(takeUntil(this._destroyed)) .subscribe(result => { this.checkForGrant(result.definition); @@ -130,10 +130,10 @@ export class DmpCloneComponent extends BaseComponent implements OnInit { // }); - const breadCrumbs = []; - breadCrumbs.push({ parentComponentName: null, label: this.language.instant('NAV-BAR.MY-DMPS'), url: "/plans" }); - breadCrumbs.push({ parentComponentName: 'DmpListingComponent', label: this.dmp.label, url: '/plans/clone/' + this.dmp.id }); - this.breadCrumbs = observableOf(breadCrumbs); + // const breadCrumbs = []; + // breadCrumbs.push({ parentComponentName: null, label: this.language.instant('NAV-BAR.MY-DMPS'), url: "/plans" }); + // breadCrumbs.push({ parentComponentName: 'DmpListingComponent', label: this.dmp.label, url: '/plans/clone/' + this.dmp.id }); + // this.breadCrumbs = observableOf(breadCrumbs); }); }); diff --git a/dmp-frontend/src/app/ui/dmp/dmp-editor-blueprint/dmp-editor-blueprint.component.ts b/dmp-frontend/src/app/ui/dmp/dmp-editor-blueprint/dmp-editor-blueprint.component.ts index 62a44c21a..09d3fe54f 100644 --- a/dmp-frontend/src/app/ui/dmp/dmp-editor-blueprint/dmp-editor-blueprint.component.ts +++ b/dmp-frontend/src/app/ui/dmp/dmp-editor-blueprint/dmp-editor-blueprint.component.ts @@ -3,9 +3,9 @@ import { AbstractControl, UntypedFormArray, UntypedFormBuilder, UntypedFormContr import { DataTableRequest } from '@app/core/model/data-table/data-table-request'; import { DmpBlueprintDefinition, ExtraFieldType, FieldCategory, SystemFieldType } from '@app/core/model/dmp/dmp-blueprint/dmp-blueprint'; import { DmpBlueprintCriteria } from '@app/core/query/dmp/dmp-blueprint-criteria'; -import { DmpProfileService } from '@app/core/services/dmp/dmp-profile.service'; +import { DmpBlueprintService } from '@app/core/services/dmp/dmp-blueprint.service'; import { SingleAutoCompleteConfiguration } from '@app/library/auto-complete/single/single-auto-complete-configuration'; -import { DmpBlueprintEditor } from '@app/ui/admin/dmp-profile/editor/dmp-blueprint-editor.model'; +import { DmpBlueprintEditor } from '@app/ui/admin/dmp-blueprint/editor/dmp-blueprint-editor.model'; import { debounceTime, filter, map, switchMap, takeUntil, tap } from 'rxjs/operators'; import { DmpEditorModel, DmpExtraFieldEditorModel } from '../editor/dmp-editor.model'; import { ExtraPropertiesFormModel } from '../editor/general-tab/extra-properties-form.model'; @@ -54,7 +54,7 @@ import { Guid } from '@common/types/guid'; import { PopupNotificationDialogComponent } from '@app/library/notification/popup/popup-notification.component'; import { GrantEditorModel } from '@app/ui/grant/editor/grant-editor.model'; import { CheckDeactivateBaseComponent } from '@app/library/deactivate/deactivate.component'; -import { DmpProfileStatus } from '@app/core/common/enum/dmp-profile-status'; +import { DmpBlueprintStatus } from '@app/core/common/enum/dmp-blueprint-status'; import { DatasetService } from '@app/core/services/dataset/dataset.service'; interface Visible { @@ -131,7 +131,7 @@ export class DmpEditorBlueprintComponent extends CheckDeactivateBaseComponent im readonly defaultBlueprintId = '86635178-36a6-484f-9057-a934e4eeecd5'; constructor( - private dmpProfileService: DmpProfileService, + private dmpBlueprintService: DmpBlueprintService, private datasetService: DatasetService, private authService: AuthService, private route: ActivatedRoute, @@ -178,7 +178,7 @@ export class DmpEditorBlueprintComponent extends CheckDeactivateBaseComponent im this.formGroupRawValue = JSON.parse(JSON.stringify(this.formGroup.getRawValue())); if (!isNullOrUndefined(this.formGroup.get('profile').value)) { - this.dmpProfileService.getSingleBlueprint(this.formGroup.get('profile').value) + this.dmpBlueprintService.getSingleBlueprint(this.formGroup.get('profile').value) .pipe(takeUntil(this._destroyed)) .subscribe(result => { this.selectedDmpBlueprintDefinition = result.definition; @@ -249,7 +249,7 @@ export class DmpEditorBlueprintComponent extends CheckDeactivateBaseComponent im this.formGroupRawValue = JSON.parse(JSON.stringify(this.formGroup.getRawValue())); if (!isNullOrUndefined(this.formGroup.get('profile').value)) { - this.dmpProfileService.getSingleBlueprint(this.formGroup.get('profile').value) + this.dmpBlueprintService.getSingleBlueprint(this.formGroup.get('profile').value) .pipe(takeUntil(this._destroyed)) .subscribe(result => { this.selectedDmpBlueprintDefinition = result.definition; @@ -431,7 +431,7 @@ export class DmpEditorBlueprintComponent extends CheckDeactivateBaseComponent im } selectDefaultBlueprint() { - this.dmpProfileService.getSingleBlueprint(this.defaultBlueprintId) + this.dmpBlueprintService.getSingleBlueprint(this.defaultBlueprintId) .pipe(takeUntil(this._destroyed)) .subscribe(result => { this.selectedDmpBlueprintDefinition = result.definition; @@ -827,7 +827,7 @@ export class DmpEditorBlueprintComponent extends CheckDeactivateBaseComponent im const criteria = new DatasetProfileCriteria(); criteria.like = value; request.criteria = criteria; - return this.dmpService.searchDMPProfiles(request); + return this.dmpService.searchDmpBlueprints(request); } registerFormEventsForDmpBlueprint(): void { @@ -972,8 +972,8 @@ export class DmpEditorBlueprintComponent extends CheckDeactivateBaseComponent im var request = new DataTableRequest(0, 20, { fields: fields }); request.criteria = new DmpBlueprintCriteria(); request.criteria.like = query; - request.criteria.status = DmpProfileStatus.Finalized; - return this.dmpProfileService.getPagedBlueprint(request).pipe(map(x => x.data)); + request.criteria.status = DmpBlueprintStatus.Finalized; + return this.dmpBlueprintService.getPagedBlueprint(request).pipe(map(x => x.data)); } getLanguageInfos(): LanguageInfo[] { diff --git a/dmp-frontend/src/app/ui/dmp/editor/dataset-editor-details/dataset-editor-details.component.ts b/dmp-frontend/src/app/ui/dmp/editor/dataset-editor-details/dataset-editor-details.component.ts index 9983eb487..fdddbe051 100644 --- a/dmp-frontend/src/app/ui/dmp/editor/dataset-editor-details/dataset-editor-details.component.ts +++ b/dmp-frontend/src/app/ui/dmp/editor/dataset-editor-details/dataset-editor-details.component.ts @@ -270,7 +270,7 @@ export class DatasetEditorDetailsComponent extends BaseComponent implements OnIn const criteria = new DatasetProfileCriteria(); criteria.like = value; request.criteria = criteria; - return this.dmpService.searchDMPProfiles(request); + return this.dmpService.searchDmpBlueprints(request); } allAvailableProfiles(event: MouseEvent) { diff --git a/dmp-frontend/src/app/ui/dmp/editor/dataset-info/dataset-info.component.ts b/dmp-frontend/src/app/ui/dmp/editor/dataset-info/dataset-info.component.ts index 1d88e6a52..cdf9e9e86 100644 --- a/dmp-frontend/src/app/ui/dmp/editor/dataset-info/dataset-info.component.ts +++ b/dmp-frontend/src/app/ui/dmp/editor/dataset-info/dataset-info.component.ts @@ -12,8 +12,7 @@ import { DatasetProfileModel } from '@app/core/model/dataset/dataset-profile'; import { DatasetProfileCriteria } from '@app/core/query/dataset-profile/dataset-profile-criteria'; import { DataTableRequest } from '@app/core/model/data-table/data-table-request'; import { DmpService } from '@app/core/services/dmp/dmp.service'; -import { DmpProfileDefinition } from '@app/core/model/dmp-profile/dmp-profile'; -import { DmpProfileService } from '@app/core/services/dmp/dmp-profile.service'; +import { DmpBlueprintService } from '@app/core/services/dmp/dmp-blueprint.service'; import { AvailableProfilesComponent } from '../available-profiles/available-profiles.component'; import { DmpEditorModel } from '../dmp-editor.model'; import { Router, Params, ActivatedRoute } from '@angular/router'; @@ -22,6 +21,7 @@ import { DatasetWizardService } from '@app/core/services/dataset-wizard/dataset- import { DatasetDescriptionFormEditorModel } from '@app/ui/misc/dataset-description-form/dataset-description-form.model'; import { UiNotificationService, SnackBarNotificationLevel } from '@app/core/services/notification/ui-notification-service'; import { DatasetPreviewDialogComponent } from '../../dataset-preview/dataset-preview-dialog.component'; +import { DmpBlueprintDefinition } from '@app/core/model/dmp/dmp-blueprint/dmp-blueprint'; @Component({ selector: 'dataset-info', @@ -43,7 +43,7 @@ export class DatasetInfoComponent extends BaseComponent implements OnInit { availableProfiles: DatasetProfileModel[] = []; - selectedDmpProfileDefinition: DmpProfileDefinition; + selectedDmpBlueprintDefinition: DmpBlueprintDefinition; profilesAutoCompleteConfiguration: MultipleAutoCompleteConfiguration; datasetProfileDefinitionModel: DatasetDescriptionFormEditorModel; @@ -56,7 +56,7 @@ export class DatasetInfoComponent extends BaseComponent implements OnInit { private datasetWizardService: DatasetWizardService, private dialog: MatDialog, private _service: DmpService, - private dmpProfileService: DmpProfileService, + private dmpBlueprintService: DmpBlueprintService, private router: Router, private route: ActivatedRoute, private uiNotificationService: UiNotificationService @@ -85,8 +85,8 @@ export class DatasetInfoComponent extends BaseComponent implements OnInit { popupItemActionIcon: 'visibility' }; - if (this.formGroup.get('definition')) { this.selectedDmpProfileDefinition = this.formGroup.get('definition').value; } - this.registerFormEventsForDmpProfile(); + if (this.formGroup.get('definition')) { this.selectedDmpBlueprintDefinition = this.formGroup.get('definition').value; } + this.registerFormEventsForDmpBlueprint(); if (this.hasDmpId) { this.loadDatasetProfiles(); @@ -107,25 +107,25 @@ export class DatasetInfoComponent extends BaseComponent implements OnInit { const criteria = new DatasetProfileCriteria(); criteria.like = value; request.criteria = criteria; - return this._service.searchDMPProfiles(request); + return this._service.searchDmpBlueprints(request); } - registerFormEventsForDmpProfile(definitionProperties?: DmpProfileDefinition): void { + registerFormEventsForDmpBlueprint(definitionProperties?: DmpBlueprintDefinition): void { this.formGroup.get('profile').valueChanges .pipe( takeUntil(this._destroyed)) .subscribe(Option => { if (Option instanceof Object) { - this.selectedDmpProfileDefinition = null; - this.dmpProfileService.getSingle(Option.id) + this.selectedDmpBlueprintDefinition = null; + this.dmpBlueprintService.getSingle(Option.id) .pipe(takeUntil(this._destroyed)) .subscribe(result => { - this.selectedDmpProfileDefinition = result.definition; + this.selectedDmpBlueprintDefinition = result.definition; }); } else { - this.selectedDmpProfileDefinition = null; + this.selectedDmpBlueprintDefinition = null; } - this.selectedDmpProfileDefinition = definitionProperties; + this.selectedDmpBlueprintDefinition = definitionProperties; }) } diff --git a/dmp-frontend/src/app/ui/dmp/editor/dmp-editor.component.ts b/dmp-frontend/src/app/ui/dmp/editor/dmp-editor.component.ts index 8a80c4333..3abd6c700 100644 --- a/dmp-frontend/src/app/ui/dmp/editor/dmp-editor.component.ts +++ b/dmp-frontend/src/app/ui/dmp/editor/dmp-editor.component.ts @@ -1,59 +1,59 @@ -import { Component, OnInit} from '@angular/core'; -import { UntypedFormGroup, AbstractControl, UntypedFormControl, UntypedFormArray} from '@angular/forms'; +import { Component, OnInit } from '@angular/core'; +import { AbstractControl, UntypedFormArray, UntypedFormControl, UntypedFormGroup } from '@angular/forms'; import { MatDialog } from '@angular/material/dialog'; import { ActivatedRoute, Params, Router } from '@angular/router'; import { DmpStatus } from '@app/core/common/enum/dmp-status'; +import { Role } from "@app/core/common/enum/role"; import { DataTableRequest } from '@app/core/model/data-table/data-table-request'; -import { DmpProfileDefinition } from '@app/core/model/dmp-profile/dmp-profile'; -import { DmpProfileListing } from '@app/core/model/dmp-profile/dmp-profile-listing'; +import { DmpBlueprintListing } from '@app/core/model/dmp-blueprint/dmp-blueprint-listing'; import { DmpModel } from '@app/core/model/dmp/dmp'; +import { DmpBlueprintDefinition } from '@app/core/model/dmp/dmp-blueprint/dmp-blueprint'; +import { LockModel } from '@app/core/model/lock/lock.model'; import { UserModel } from '@app/core/model/user/user'; import { UserInfoListingModel } from '@app/core/model/user/user-info-listing'; import { BaseCriteria } from '@app/core/query/base-criteria'; -import { DmpProfileCriteria } from '@app/core/query/dmp/dmp-profile-criteria'; +import { DmpBlueprintCriteria } from '@app/core/query/dmp/dmp-blueprint-criteria'; import { GrantCriteria } from '@app/core/query/grant/grant-criteria'; import { RequestItem } from '@app/core/query/request-item'; import { AuthService } from '@app/core/services/auth/auth.service'; -import { DmpProfileService } from '@app/core/services/dmp/dmp-profile.service'; +import { ConfigurationService } from '@app/core/services/configuration/configuration.service'; +import { DatasetWizardService } from '@app/core/services/dataset-wizard/dataset-wizard.service'; +import { DatasetService } from '@app/core/services/dataset/dataset.service'; +import { DmpBlueprintService } from '@app/core/services/dmp/dmp-blueprint.service'; import { DmpService } from '@app/core/services/dmp/dmp.service'; +import { LockService } from '@app/core/services/lock/lock.service'; +import { MatomoService } from '@app/core/services/matomo/matomo-service'; import { SnackBarNotificationLevel, UiNotificationService } from '@app/core/services/notification/ui-notification-service'; -import { ConfirmationDialogComponent } from '@common/modules/confirmation-dialog/confirmation-dialog.component'; +import { CheckDeactivateBaseComponent } from '@app/library/deactivate/deactivate.component'; +import { PopupNotificationDialogComponent } from '@app/library/notification/popup/popup-notification.component'; +import { DatasetWizardEditorModel } from '@app/ui/dataset/dataset-wizard/dataset-wizard-editor.model'; import { DmpEditorModel } from '@app/ui/dmp/editor/dmp-editor.model'; import { DmpFinalizeDialogComponent, DmpFinalizeDialogInput } from '@app/ui/dmp/editor/dmp-finalize-dialog/dmp-finalize-dialog.component'; import { FunderFormModel } from '@app/ui/dmp/editor/grant-tab/funder-form-model'; import { GrantTabModel } from '@app/ui/dmp/editor/grant-tab/grant-tab-model'; import { ProjectFormModel } from '@app/ui/dmp/editor/grant-tab/project-form-model'; -import { BreadcrumbItem } from '@app/ui/misc/breadcrumb/definition/breadcrumb-item'; -import { IBreadCrumbComponent } from '@app/ui/misc/breadcrumb/definition/IBreadCrumbComponent'; +import { GrantEditorModel } from '@app/ui/grant/editor/grant-editor.model'; +// import { IBreadCrumbComponent } from '@app/ui/misc/breadcrumb/definition/IBreadCrumbComponent'; +// import { BreadcrumbItem } from '@app/ui/misc/breadcrumb/definition/breadcrumb-item'; import { FormService } from '@common/forms/form-service'; import { FormValidationErrorsDialogComponent } from '@common/forms/form-validation-errors-dialog/form-validation-errors-dialog.component'; import { ValidationErrorModel } from '@common/forms/validation/error-model/validation-error-model'; +import { ConfirmationDialogComponent } from '@common/modules/confirmation-dialog/confirmation-dialog.component'; +import { Guid } from '@common/types/guid'; import { TranslateService } from '@ngx-translate/core'; import * as FileSaver from 'file-saver'; -import { Observable, of as observableOf, interval } from 'rxjs'; +import { Observable, interval, of as observableOf } from 'rxjs'; import { map, takeUntil } from 'rxjs/operators'; -import { Role } from "@app/core/common/enum/role"; -import { LockService } from '@app/core/services/lock/lock.service'; -import { LockModel } from '@app/core/model/lock/lock.model'; -import { Guid } from '@common/types/guid'; -import { ConfigurationService } from '@app/core/services/configuration/configuration.service'; -import { ExtraPropertiesFormModel } from './general-tab/extra-properties-form.model'; -import { DatasetWizardEditorModel } from '@app/ui/dataset/dataset-wizard/dataset-wizard-editor.model'; -import { DatasetWizardService } from '@app/core/services/dataset-wizard/dataset-wizard.service'; -import { DatasetService } from '@app/core/services/dataset/dataset.service'; import { DmpToDatasetDialogComponent } from '../dmp-to-dataset/dmp-to-dataset-dialog.component'; -import { GrantEditorModel } from '@app/ui/grant/editor/grant-editor.model'; -import { MatomoService } from '@app/core/services/matomo/matomo-service'; -import { PopupNotificationDialogComponent } from '@app/library/notification/popup/popup-notification.component'; -import { CheckDeactivateBaseComponent } from '@app/library/deactivate/deactivate.component'; +import { ExtraPropertiesFormModel } from './general-tab/extra-properties-form.model'; @Component({ selector: 'app-dmp-editor-component', templateUrl: 'dmp-editor.component.html', styleUrls: ['./dmp-editor.component.scss'] }) -export class DmpEditorComponent extends CheckDeactivateBaseComponent implements OnInit, IBreadCrumbComponent { +export class DmpEditorComponent extends CheckDeactivateBaseComponent implements OnInit { //IBreadCrumbComponent canDeactivate(): boolean { return !this.isDirty(); } @@ -62,7 +62,7 @@ export class DmpEditorComponent extends CheckDeactivateBaseComponent implements // editMode = false; saving = false; - breadCrumbs: Observable; + // breadCrumbs: Observable; isNew = true; isPublic = false; isFinalized = false; @@ -83,8 +83,8 @@ export class DmpEditorComponent extends CheckDeactivateBaseComponent implements associatedUsers: Array; people: Array; - filteredOptions: DmpProfileListing[]; - selectedDmpProfileDefinition: DmpProfileDefinition; + filteredOptions: DmpBlueprintListing[]; + selectedDmpBlueprintDefinition: DmpBlueprintDefinition; DynamicDmpFieldResolverComponent: any; lock: LockModel; @@ -96,10 +96,10 @@ export class DmpEditorComponent extends CheckDeactivateBaseComponent implements maxStep: number = 4; scrollTop: number; - hintErrors:boolean = false; + hintErrors: boolean = false; constructor( - private dmpProfileService: DmpProfileService, + private dmpBlueprintService: DmpBlueprintService, private datasetWizardService: DatasetWizardService, private datasetService: DatasetService, private dmpService: DmpService, @@ -182,7 +182,7 @@ export class DmpEditorComponent extends CheckDeactivateBaseComponent implements this.setIsUserOwner(); if (!this.isUserOwner) { - if(this.isUserMember()){ + if (this.isUserMember()) { this.router.navigate(['plans', 'overview', itemId]); return; } @@ -194,7 +194,7 @@ export class DmpEditorComponent extends CheckDeactivateBaseComponent implements this.step = this.formGroup.get('datasets')['controls'].findIndex((dataset) => { return this.datasetId === dataset.get('id').value; }) + this.stepsBeforeDatasets; } - //this.registerFormEventsForDmpProfile(this.dmp.definition); + //this.registerFormEventsForDmpBlueprint(this.dmp.definition); if (!this.editMode || this.dmp.status === DmpStatus.Finalized || lockStatus) { this.isFinalized = true; this.formGroup.disable(); @@ -209,21 +209,20 @@ export class DmpEditorComponent extends CheckDeactivateBaseComponent implements interval(this.configurationService.lockInterval).pipe(takeUntil(this._destroyed)).subscribe(() => this.pumpLock()); }); } - // if (!this.isAuthenticated) { - const breadCrumbs = []; - breadCrumbs.push({ - parentComponentName: null, - label: this.language.instant('NAV-BAR.MY-DMPS'), - url: "/plans" - }); - breadCrumbs.push({ - parentComponentName: 'DmpListingComponent', - label: this.dmp.label, - url: '/plans/edit/' + this.dmp.id, - // notFoundResolver: [await this.grantService.getSingle(this.dmp.grant.id).map(x => ({ label: x.label, url: '/grants/edit/' + x.id }) as BreadcrumbItem).toPromise()] - } - ); - this.breadCrumbs = observableOf(breadCrumbs); + // const breadCrumbs = []; + // breadCrumbs.push({ + // parentComponentName: null, + // label: this.language.instant('NAV-BAR.MY-DMPS'), + // url: "/plans" + // }); + // breadCrumbs.push({ + // parentComponentName: 'DmpListingComponent', + // label: this.dmp.label, + // url: '/plans/edit/' + this.dmp.id, + // // notFoundResolver: [await this.grantService.getSingle(this.dmp.grant.id).map(x => ({ label: x.label, url: '/grants/edit/' + x.id }) as BreadcrumbItem).toPromise()] + // } + // ); + // this.breadCrumbs = observableOf(breadCrumbs); } this.associatedUsers = data.associatedUsers; this.people = data.users; @@ -231,11 +230,13 @@ export class DmpEditorComponent extends CheckDeactivateBaseComponent implements .subscribe(x => { this.formChanged(); }); - if(this.lockStatus){ - this.dialog.open(PopupNotificationDialogComponent,{data:{ - title:this.language.instant('DMP-EDITOR.LOCKED.TITLE'), - message:this.language.instant('DMP-EDITOR.LOCKED.MESSAGE') - }, maxWidth:'30em'}); + if (this.lockStatus) { + this.dialog.open(PopupNotificationDialogComponent, { + data: { + title: this.language.instant('DMP-EDITOR.LOCKED.TITLE'), + message: this.language.instant('DMP-EDITOR.LOCKED.MESSAGE') + }, maxWidth: '30em' + }); } }) }); @@ -265,13 +266,15 @@ export class DmpEditorComponent extends CheckDeactivateBaseComponent implements this.formGroupRawValue = JSON.parse(JSON.stringify(this.formGroup.getRawValue())); this.maxStep = this.formGroup.get('datasets') ? this.maxStep + this.formGroup.get('datasets').value.length - 1 : this.maxStep; - //this.registerFormEventsForDmpProfile(this.dmp.definition); + //this.registerFormEventsForDmpBlueprint(this.dmp.definition); this.formGroup.disable(); // if (!this.isAuthenticated) { - const breadcrumbs = []; - breadcrumbs.push({ parentComponentName: null, label: this.language.instant('NAV-BAR.PUBLIC-DMPS').toUpperCase(), url: '/plans' }); - breadcrumbs.push({ parentComponentName: null, label: this.dmp.label, url: '/plans/publicEdit/' + this.dmp.id }); - this.breadCrumbs = observableOf(breadcrumbs); + // const breadcrumbs = []; + // breadcrumbs.push({ parentComponentName: null, label: this.language.instant('NAV-BAR.PUBLIC-DMPS').toUpperCase(), url: '/plans' }); + // breadcrumbs.push({ parentComponentName: null, label: this.dmp.label, url: '/plans/publicEdit/' + this.dmp.id }); + // this.breadCrumbs = observableOf(breadcrumbs); + + // this.breadCrumbs = Observable.of([ // { // parentComponentName: 'DmpListingComponent', @@ -312,18 +315,18 @@ export class DmpEditorComponent extends CheckDeactivateBaseComponent implements this.registerFormEventsForNewItem(); if (this.isAuthenticated) { this.language.get('NAV-BAR.MY-DMPS').pipe(takeUntil(this._destroyed)).subscribe(x => { - this.breadCrumbs = observableOf([ - { - parentComponentName: null, - label: x, - url: '/plans' - }, - { - parentComponentName: null, - label: "CREATE NEW DMP", - url: "/plans/new" - } - ]); + // this.breadCrumbs = observableOf([ + // { + // parentComponentName: null, + // label: x, + // url: '/plans' + // }, + // { + // parentComponentName: null, + // label: "CREATE NEW DMP", + // url: "/plans/new" + // } + // ]); }) } this.formGroup.valueChanges.pipe(takeUntil(this._destroyed)) @@ -372,14 +375,14 @@ export class DmpEditorComponent extends CheckDeactivateBaseComponent implements setIsUserOwner() { if (this.dmp) { const principalId: string = this.authentication.userId()?.toString(); - this.isUserOwner = !!this.dmp.users.find(x => (x.role === Role.Owner) && (x.id === principalId) ); + this.isUserOwner = !!this.dmp.users.find(x => (x.role === Role.Owner) && (x.id === principalId)); } } - isUserMember(): boolean{ - try{ + isUserMember(): boolean { + try { const principalId: string = this.authentication.userId()?.toString(); - return !!this.dmp.users.find(x => (x.role === Role.Member) && (x.id === principalId) ); - }catch{ + return !!this.dmp.users.find(x => (x.role === Role.Member) && (x.id === principalId)); + } catch { return false; } } @@ -392,20 +395,20 @@ export class DmpEditorComponent extends CheckDeactivateBaseComponent implements } registerFormEventsForNewItem() { - this.breadCrumbs = observableOf([ - { - parentComponentName: 'DmpListingComponent', - label: this.language.instant('NAV-BAR.MY-DMPS'), - url: 'plans', - } - ]); + // this.breadCrumbs = observableOf([ + // { + // parentComponentName: 'DmpListingComponent', + // label: this.language.instant('NAV-BAR.MY-DMPS'), + // url: 'plans', + // } + // ]); } - dmpProfileSearch(query: string) { + dmpBlueprintSearch(query: string) { let fields: Array = new Array(); - var request = new DataTableRequest(0, 10, { fields: fields }); - request.criteria = new DmpProfileCriteria(); - return this.dmpProfileService.getPaged(request).pipe(map(x => x.data)); + var request = new DataTableRequest(0, 10, { fields: fields }); + request.criteria = new DmpBlueprintCriteria(); + return this.dmpBlueprintService.getPaged(request).pipe(map(x => x.data)); } // searchGrant(query: string) { @@ -437,7 +440,7 @@ export class DmpEditorComponent extends CheckDeactivateBaseComponent implements // if(!this.formval) - if(!this._isDMPDescriptionValid()){ + if (!this._isDMPDescriptionValid()) { const errmess = this._buildDMPDescriptionErrorMessages(); this.showValidationErrorsDialog(undefined, errmess); this.hintErrors = true; @@ -461,18 +464,18 @@ export class DmpEditorComponent extends CheckDeactivateBaseComponent implements private showValidationErrorsDialog(projectOnly?: boolean, errmess?: string[]) { - if(errmess){ + if (errmess) { const dialogRef = this.dialog.open(FormValidationErrorsDialogComponent, { disableClose: true, autoFocus: false, restoreFocus: false, data: { - errorMessages:errmess, + errorMessages: errmess, projectOnly: projectOnly }, }); - }else{ + } else { const dialogRef = this.dialog.open(FormValidationErrorsDialogComponent, { disableClose: true, autoFocus: false, @@ -559,7 +562,8 @@ export class DmpEditorComponent extends CheckDeactivateBaseComponent implements this.formGroup.valueChanges.pipe(takeUntil(this._destroyed)) .subscribe(x => { this.formChanged(); - });}); + }); + }); setTimeout(() => { document.getElementById('editor-form').scrollTop = this.scrollTop; }); this.saving = false; this.isNew = false; @@ -792,20 +796,20 @@ export class DmpEditorComponent extends CheckDeactivateBaseComponent implements } //checks if the dpm is valid not taking into account the datasets validity - private _isDMPDescriptionValid():boolean{ + private _isDMPDescriptionValid(): boolean { const form: UntypedFormGroup = this.formGroup; - if(form.controls){ + if (form.controls) { return Object.keys(form.controls) - .map(controlName=>{//get validity of each control - if(controlName === 'datasets'){//we dont care if datasets are valid - return true; - } - return !form.get(controlName).invalid;//!! in case the control is disabled, we consider it valid - }) - .reduce((isFormValid,isControlValid)=>{//aggregate validities - return isControlValid && isFormValid; - }, true); + .map(controlName => {//get validity of each control + if (controlName === 'datasets') {//we dont care if datasets are valid + return true; + } + return !form.get(controlName).invalid;//!! in case the control is disabled, we consider it valid + }) + .reduce((isFormValid, isControlValid) => {//aggregate validities + return isControlValid && isFormValid; + }, true); } return true; } @@ -838,10 +842,10 @@ export class DmpEditorComponent extends CheckDeactivateBaseComponent implements - private _buildDMPDescriptionErrorMessages(): string[]{//not including datasets + private _buildDMPDescriptionErrorMessages(): string[] {//not including datasets const errmess: string[] = []; - Object.keys(this.formGroup.controls).forEach(controlName=>{ - if(controlName != 'datasets' && this.formGroup.get(controlName).invalid){ + Object.keys(this.formGroup.controls).forEach(controlName => { + if (controlName != 'datasets' && this.formGroup.get(controlName).invalid) { errmess.push(...this._buildErrorMessagesForAbstractControl(this.formGroup.get(controlName), controlName)); } }) @@ -850,16 +854,16 @@ export class DmpEditorComponent extends CheckDeactivateBaseComponent implements } // takes as an input an abstract control and gets its error messages[] - private _buildErrorMessagesForAbstractControl(aControl: AbstractControl, controlName: string):string[]{ - const errmess:string[] = []; + private _buildErrorMessagesForAbstractControl(aControl: AbstractControl, controlName: string): string[] { + const errmess: string[] = []; - if(aControl.invalid){ + if (aControl.invalid) { - if(aControl.errors){ + if (aControl.errors) { //check if has placeholder - if( (aControl).nativeElement !== undefined && (aControl).nativeElement !== null){ + if ((aControl).nativeElement !== undefined && (aControl).nativeElement !== null) { const placeholder = this._getPlaceHolder(aControl); - if(placeholder){ + if (placeholder) { controlName = placeholder; } } @@ -870,19 +874,19 @@ export class DmpEditorComponent extends CheckDeactivateBaseComponent implements /*in case the aControl is FormControl then the it should have provided its error messages above. No need to check case of FormControl below*/ - if(aControl instanceof UntypedFormGroup){ + if (aControl instanceof UntypedFormGroup) { const fg = aControl as UntypedFormGroup; //check children - Object.keys(fg.controls).forEach(controlName=>{ + Object.keys(fg.controls).forEach(controlName => { errmess.push(...this._buildErrorMessagesForAbstractControl(fg.get(controlName), controlName)); }); - }else if(aControl instanceof UntypedFormArray){ + } else if (aControl instanceof UntypedFormArray) { const fa = aControl as UntypedFormArray; - fa.controls.forEach((control,index)=>{ - errmess.push(... this._buildErrorMessagesForAbstractControl(control, `${controlName} --> ${index+1}`)); + fa.controls.forEach((control, index) => { + errmess.push(... this._buildErrorMessagesForAbstractControl(control, `${controlName} --> ${index + 1}`)); }); } @@ -899,7 +903,7 @@ export class DmpEditorComponent extends CheckDeactivateBaseComponent implements addDataset() { this.saving = true; - if(!this._isDMPDescriptionValid()){ + if (!this._isDMPDescriptionValid()) { const errmess = this._buildDMPDescriptionErrorMessages(); this.showValidationErrorsDialog(undefined, errmess); this.hintErrors = true; @@ -952,10 +956,10 @@ export class DmpEditorComponent extends CheckDeactivateBaseComponent implements }); } - editDataset(id: string, isNew: boolean, showModal:boolean = false) { + editDataset(id: string, isNew: boolean, showModal: boolean = false) { - if(showModal){ + if (showModal) { const dialogRef = this.dialog.open(DmpToDatasetDialogComponent, { width: '500px', autoFocus: false, @@ -970,7 +974,7 @@ export class DmpEditorComponent extends CheckDeactivateBaseComponent implements } } }); - }else{ + } else { if (isNew) { this.router.navigate(['/datasets', 'new', id]); } else { diff --git a/dmp-frontend/src/app/ui/dmp/editor/dmp-editor.model.ts b/dmp-frontend/src/app/ui/dmp/editor/dmp-editor.model.ts index 74363593e..6cfacea36 100644 --- a/dmp-frontend/src/app/ui/dmp/editor/dmp-editor.model.ts +++ b/dmp-frontend/src/app/ui/dmp/editor/dmp-editor.model.ts @@ -1,8 +1,8 @@ import { UntypedFormBuilder, UntypedFormGroup, Validators } from "@angular/forms"; -import { DmpProfileFieldDataType } from '@app/core/common/enum/dmp-profile-field-type'; -import { DmpProfileType } from '@app/core/common/enum/dmp-profile-type'; +import { DmpBlueprintFieldDataType } from '@app/core/common/enum/dmp-blueprint-field-type'; +import { DmpBlueprintType } from '@app/core/common/enum/dmp-blueprint-type'; import { DmpStatus } from '@app/core/common/enum/dmp-status'; -import { DmpProfileField } from '@app/core/model/dmp-profile/dmp-profile-field'; +import { DmpBlueprintField } from '@app/core/model/dmp-blueprint/dmp-blueprint-field'; import { DmpModel } from '@app/core/model/dmp/dmp'; import { DmpDynamicField } from '@app/core/model/dmp/dmp-dynamic-field'; import { DmpDynamicFieldDependency } from '@app/core/model/dmp/dmp-dynamic-field-dependency'; @@ -11,7 +11,7 @@ import { ResearcherModel } from '@app/core/model/researcher/researcher'; import { UserModel } from '@app/core/model/user/user'; import { UserInfoListingModel } from '@app/core/model/user/user-info-listing'; import { ValidJsonValidator } from '@app/library/auto-complete/auto-complete-custom-validator'; -import { DmpProfileExternalAutoCompleteFieldDataEditorModel } from '@app/ui/admin/dmp-profile/editor/external-autocomplete/dmp-profile-external-autocomplete-field-editor.model'; +import { DmpBlueprintExternalAutoCompleteFieldDataEditorModel } from '@app/ui/admin/dmp-blueprint/editor/external-autocomplete/dmp-blueprint-external-autocomplete-field-editor.model'; import { FunderFormModel } from '@app/ui/dmp/editor/grant-tab/funder-form-model'; import { GrantTabModel } from '@app/ui/dmp/editor/grant-tab/grant-tab-model'; import { ProjectFormModel } from '@app/ui/dmp/editor/grant-tab/project-form-model'; @@ -215,16 +215,16 @@ export class DmpDynamicFieldDependencyEditorModel { } } -export class DmpDefinitionFieldEditorModel implements DmpProfileField { +export class DmpDefinitionFieldEditorModel implements DmpBlueprintField { public id: string; - public type: DmpProfileType; - public dataType: DmpProfileFieldDataType; + public type: DmpBlueprintType; + public dataType: DmpBlueprintFieldDataType; public required = false; public label: string; public value: any; - public externalAutocomplete?: DmpProfileExternalAutoCompleteFieldDataEditorModel; + public externalAutocomplete?: DmpBlueprintExternalAutoCompleteFieldDataEditorModel; - fromModel(item: DmpProfileField): DmpDefinitionFieldEditorModel { + fromModel(item: DmpBlueprintField): DmpDefinitionFieldEditorModel { this.type = item.type; this.dataType = item.dataType; this.required = item.required; @@ -232,7 +232,7 @@ export class DmpDefinitionFieldEditorModel implements DmpProfileField { this.id = item.id; this.value = item.value; if (item.externalAutocomplete) - this.externalAutocomplete = new DmpProfileExternalAutoCompleteFieldDataEditorModel().fromModel(item.externalAutocomplete); + this.externalAutocomplete = new DmpBlueprintExternalAutoCompleteFieldDataEditorModel().fromModel(item.externalAutocomplete); return this; } diff --git a/dmp-frontend/src/app/ui/dmp/editor/dynamic-field-resolver/dynamic-dmp-field-resolver.component.html b/dmp-frontend/src/app/ui/dmp/editor/dynamic-field-resolver/dynamic-dmp-field-resolver.component.html index 04ce615da..f12101db5 100644 --- a/dmp-frontend/src/app/ui/dmp/editor/dynamic-field-resolver/dynamic-dmp-field-resolver.component.html +++ b/dmp-frontend/src/app/ui/dmp/editor/dynamic-field-resolver/dynamic-dmp-field-resolver.component.html @@ -1,7 +1,7 @@ -
+
- - + + @@ -10,21 +10,21 @@ {{'GENERAL.VALIDATION.REQUIRED' | translate}} - + {{'GENERAL.VALIDATION.REQUIRED' | translate}} - + {{'GENERAL.VALIDATION.REQUIRED' | translate}} -
+
{ if (field.externalAutocomplete) { if (field.externalAutocomplete.multiAutoComplete) { @@ -63,24 +62,24 @@ export class DynamicDmpFieldResolverComponent implements OnInit, OnDestroy { } ngOnChanges(changes: SimpleChanges) { - if (changes['dmpProfileDefinition'] && !changes['dmpProfileDefinition'].isFirstChange()) { + if (changes['dmpBlueprintDefinition'] && !changes['dmpBlueprintDefinition'].isFirstChange()) { this.createControleFields(); } } createControleFields(): void { - if (this.dmpProfileDefinition != null) { + if (this.dmpBlueprintDefinition != null) { const diasableBoolean = this.formGroup.disabled; this.formGroup.addControl('properties', new UntypedFormBuilder().group([])); (this.formGroup.get('properties')).addControl('fields', new UntypedFormBuilder().array([])); - this.dmpProfileDefinition.fields.forEach(item => { + this.dmpBlueprintDefinition.fields.forEach(item => { (this.formGroup.get('properties').get('fields')).push(new UntypedFormBuilder().group({ id: [{ value: item.id, disabled: diasableBoolean }], value: [{ value: item.value, disabled: diasableBoolean }] })); }); } - if (this.dmpProfileDefinition == null) { + if (this.dmpBlueprintDefinition == null) { this.formGroup.removeControl('properties'); } } @@ -90,19 +89,19 @@ export class DynamicDmpFieldResolverComponent implements OnInit, OnDestroy { } externalAutocomplete(query: any, extFieldID: any) { - const autocompleteRequestItem: RequestItem = new RequestItem(); - autocompleteRequestItem.criteria = new DmpProfileExternalAutocompleteCriteria(); + const autocompleteRequestItem: RequestItem = new RequestItem(); + autocompleteRequestItem.criteria = new DmpBlueprintExternalAutocompleteCriteria(); if (typeof extFieldID == "string" && typeof query == "string") { autocompleteRequestItem.criteria.like = query; - autocompleteRequestItem.criteria.profileID = this.dmpProfileId; + autocompleteRequestItem.criteria.profileID = this.dmpBlueprintId; autocompleteRequestItem.criteria.fieldID = extFieldID; } else { autocompleteRequestItem.criteria.like = extFieldID; - autocompleteRequestItem.criteria.profileID = this.dmpProfileId; + autocompleteRequestItem.criteria.profileID = this.dmpBlueprintId; autocompleteRequestItem.criteria.fieldID = query.id; } - return this.dmpProfileService.externalAutocomplete(autocompleteRequestItem); + return this.dmpBlueprintService.externalAutocomplete(autocompleteRequestItem); } } diff --git a/dmp-frontend/src/app/ui/dmp/editor/general-tab/general-tab.component.html b/dmp-frontend/src/app/ui/dmp/editor/general-tab/general-tab.component.html index 78852a3a6..ba6bb6838 100644 --- a/dmp-frontend/src/app/ui/dmp/editor/general-tab/general-tab.component.html +++ b/dmp-frontend/src/app/ui/dmp/editor/general-tab/general-tab.component.html @@ -149,11 +149,11 @@
- +
- +
@@ -163,7 +163,7 @@ - +
{{ 'DATASET-EDITOR.VERSION-DIALOG.ABOUT' | translate }}
diff --git a/dmp-frontend/src/app/ui/dmp/editor/general-tab/general-tab.component.ts b/dmp-frontend/src/app/ui/dmp/editor/general-tab/general-tab.component.ts index 223446719..1bb346b94 100644 --- a/dmp-frontend/src/app/ui/dmp/editor/general-tab/general-tab.component.ts +++ b/dmp-frontend/src/app/ui/dmp/editor/general-tab/general-tab.component.ts @@ -4,12 +4,11 @@ import { UntypedFormGroup, UntypedFormArray } from '@angular/forms'; import { MatDialog } from '@angular/material/dialog'; import { DataTableRequest } from '@app/core/model/data-table/data-table-request'; import { DatasetProfileModel } from '@app/core/model/dataset/dataset-profile'; -import { DmpProfileDefinition } from '@app/core/model/dmp-profile/dmp-profile'; import { ExternalSourceItemModel } from '@app/core/model/external-sources/external-source-item'; import { DatasetProfileCriteria } from '@app/core/query/dataset-profile/dataset-profile-criteria'; -import { DmpProfileCriteria } from '@app/core/query/dmp/dmp-profile-criteria'; +import { DmpBlueprintCriteria } from '@app/core/query/dmp/dmp-blueprint-criteria'; import { RequestItem } from '@app/core/query/request-item'; -import { DmpProfileService } from '@app/core/services/dmp/dmp-profile.service'; +import { DmpBlueprintService } from '@app/core/services/dmp/dmp-blueprint.service'; import { DmpService } from '@app/core/services/dmp/dmp.service'; import { ExternalSourcesService } from '@app/core/services/external-sources/external-sources.service'; import { MultipleAutoCompleteConfiguration } from '@app/library/auto-complete/multiple/multiple-auto-complete-configuration'; @@ -28,6 +27,7 @@ import { LanguageInfo } from '@app/core/model/language-info'; import { LicenseCriteria } from '@app/core/query/license/license-criteria'; import { AddCostComponent } from '../cost-editor/add-cost/add-cost.component'; import { CostEditorModel } from '../cost-editor/add-cost/add-cost.model'; +import { DmpBlueprintDefinition } from '@app/core/model/dmp/dmp-blueprint/dmp-blueprint'; interface Visible { value: boolean; @@ -69,9 +69,9 @@ export class GeneralTabComponent extends BaseComponent implements OnInit { titleFn: (item) => item['name'], subtitleFn: (item) => item['tag'] ? this.language.instant('TYPES.EXTERNAL-DATASET-TYPE.SOURCE:') + item['tag'] : (item['key'] ? this.language.instant('TYPES.EXTERNAL-DATASET-TYPE.SOURCE:') + item['key'] : this.language.instant('TYPES.EXTERNAL-DATASET-TYPE.NO-SOURCE')) }; - dmpProfileAutoCompleteConfiguration: SingleAutoCompleteConfiguration = { - filterFn: this.dmpProfileSearch.bind(this), - initialItems: (extraData) => this.dmpProfileSearch(''), + dmpBlueprintAutoCompleteConfiguration: SingleAutoCompleteConfiguration = { + filterFn: this.dmpBlueprintSearch.bind(this), + initialItems: (extraData) => this.dmpBlueprintSearch(''), displayFn: (item) => item['label'], titleFn: (item) => item['label'] }; @@ -83,7 +83,7 @@ export class GeneralTabComponent extends BaseComponent implements OnInit { titleFn: (item) => item['name'] }; - selectedDmpProfileDefinition: DmpProfileDefinition; + selectedDmpBlueprintDefinition: DmpBlueprintDefinition; visibles: Visible[] = [ { value: true, name: 'DMP-EDITOR.VISIBILITY.PUBLIC' }, @@ -91,7 +91,7 @@ export class GeneralTabComponent extends BaseComponent implements OnInit { ] constructor( - private dmpProfileService: DmpProfileService, + private dmpBlueprintService: DmpBlueprintService, private externalSourcesService: ExternalSourcesService, private _service: DmpService, private dialog: MatDialog, @@ -103,8 +103,8 @@ export class GeneralTabComponent extends BaseComponent implements OnInit { } ngOnInit() { - if (this.formGroup.get('definition')) { this.selectedDmpProfileDefinition = this.formGroup.get('definition').value; } - this.registerFormEventsForDmpProfile(); + if (this.formGroup.get('definition')) { this.selectedDmpBlueprintDefinition = this.formGroup.get('definition').value; } + this.registerFormEventsForDmpBlueprint(); if (this.isNewVersion) { this.formGroup.get('label').disable(); @@ -118,30 +118,30 @@ export class GeneralTabComponent extends BaseComponent implements OnInit { } } - registerFormEventsForDmpProfile(definitionProperties?: DmpProfileDefinition): void { + registerFormEventsForDmpBlueprint(definitionProperties?: DmpBlueprintDefinition): void { this.formGroup.get('profile').valueChanges .pipe( takeUntil(this._destroyed)) .subscribe(Option => { if (Option instanceof Object) { - this.selectedDmpProfileDefinition = null; - this.dmpProfileService.getSingle(Option.id) + this.selectedDmpBlueprintDefinition = null; + this.dmpBlueprintService.getSingle(Option.id) .pipe(takeUntil(this._destroyed)) .subscribe(result => { - this.selectedDmpProfileDefinition = result.definition; + this.selectedDmpBlueprintDefinition = result.definition; }); } else { - this.selectedDmpProfileDefinition = null; + this.selectedDmpBlueprintDefinition = null; } - this.selectedDmpProfileDefinition = definitionProperties; + this.selectedDmpBlueprintDefinition = definitionProperties; }) } - dmpProfileSearch(query: string) { + dmpBlueprintSearch(query: string) { let fields: Array = new Array(); - var request = new DataTableRequest(0, 10, { fields: fields }); - request.criteria = new DmpProfileCriteria(); - return this.dmpProfileService.getPaged(request).pipe(map(x => x.data)); + var request = new DataTableRequest(0, 10, { fields: fields }); + request.criteria = new DmpBlueprintCriteria(); + return this.dmpBlueprintService.getPaged(request).pipe(map(x => x.data)); } licenseSearch(query: string): Observable { @@ -182,7 +182,7 @@ export class GeneralTabComponent extends BaseComponent implements OnInit { const criteria = new DatasetProfileCriteria(); criteria.like = value; request.criteria = criteria; - return this._service.searchDMPProfiles(request); + return this._service.searchDmpBlueprints(request); } addResearcher(event: MouseEvent) { diff --git a/dmp-frontend/src/app/ui/dmp/invitation/dmp-invitation-dialog.component.ts b/dmp-frontend/src/app/ui/dmp/invitation/dmp-invitation-dialog.component.ts index 27e4e19c3..5c061918d 100644 --- a/dmp-frontend/src/app/ui/dmp/invitation/dmp-invitation-dialog.component.ts +++ b/dmp-frontend/src/app/ui/dmp/invitation/dmp-invitation-dialog.component.ts @@ -16,8 +16,7 @@ import { Observable } from 'rxjs'; import { map, takeUntil } from 'rxjs/operators'; import { Role } from '@app/core/common/enum/role'; import { EnumUtils } from '@app/core/services/utilities/enum-utils.service'; -import { UiNotificationService } from '@app/core/services/notification/ui-notification-service'; -import { SnackBarNotificationLevel } from '@common/modules/notification/ui-notification-service'; +import { SnackBarNotificationLevel, UiNotificationService } from '@app/core/services/notification/ui-notification-service'; import { TranslateService } from '@ngx-translate/core'; @Component({ diff --git a/dmp-frontend/src/app/ui/dmp/listing/dmp-listing.component.ts b/dmp-frontend/src/app/ui/dmp/listing/dmp-listing.component.ts index 3d82295ae..c5df69442 100644 --- a/dmp-frontend/src/app/ui/dmp/listing/dmp-listing.component.ts +++ b/dmp-frontend/src/app/ui/dmp/listing/dmp-listing.component.ts @@ -21,8 +21,8 @@ import { GuidedTour, Orientation } from '@app/library/guided-tour/guided-tour.co import { GuidedTourService } from '@app/library/guided-tour/guided-tour.service'; import { DmpInvitationDialogComponent } from '@app/ui/dmp/invitation/dmp-invitation-dialog.component'; import { DmpCriteriaComponent } from '@app/ui/dmp/listing/criteria/dmp-criteria.component'; -import { IBreadCrumbComponent } from '@app/ui/misc/breadcrumb/definition/IBreadCrumbComponent'; -import { BreadcrumbItem } from '@app/ui/misc/breadcrumb/definition/breadcrumb-item'; +// import { IBreadCrumbComponent } from '@app/ui/misc/breadcrumb/definition/IBreadCrumbComponent'; +// import { BreadcrumbItem } from '@app/ui/misc/breadcrumb/definition/breadcrumb-item'; import { isNullOrUndefined } from '@app/utilities/enhancers/utils'; import { BaseComponent } from '@common/base/base.component'; import { TranslateService } from '@ngx-translate/core'; @@ -37,13 +37,13 @@ import { DmpUploadDialogue } from './upload-dialogue/dmp-upload-dialogue.compone templateUrl: 'dmp-listing.component.html', styleUrls: ['./dmp-listing.component.scss'], }) -export class DmpListingComponent extends BaseComponent implements OnInit, IBreadCrumbComponent { +export class DmpListingComponent extends BaseComponent implements OnInit { //IBreadCrumbComponent @ViewChild(MatPaginator, { static: true }) _paginator: MatPaginator; @ViewChild(MatSort) sort: MatSort; // @ViewChild(DmpCriteriaComponent, { static: true }) criteria: DmpCriteriaComponent; - breadCrumbs: Observable = observableOf([{ parentComponentName: null, label: 'DMPs', url: "/plans" }]); + // breadCrumbs: Observable = observableOf([{ parentComponentName: null, label: 'DMPs', url: "/plans" }]); itemId: string; grantId: string; showGrant: boolean; @@ -128,13 +128,13 @@ export class DmpListingComponent extends BaseComponent implements OnInit, IBread this.allVersions = true; this.language.get('NAV-BAR.MY-DMPS').pipe(takeUntil(this._destroyed)).subscribe(x => { - this.breadCrumbs = observableOf([ - { - parentComponentName: null, - label: x, - url: '/plans' - }] - ); + // this.breadCrumbs = observableOf([ + // { + // parentComponentName: null, + // label: x, + // url: '/plans' + // }] + // ); }) this.groupLabel = this.route.snapshot.queryParams.groupLabel; @@ -159,13 +159,13 @@ export class DmpListingComponent extends BaseComponent implements OnInit, IBread // else this.language.get('NAV-BAR.MY-DMPS').pipe(takeUntil(this._destroyed)).subscribe(x => { - this.breadCrumbs = observableOf([ - { - parentComponentName: null, - label: x, - url: '/plans' - }] - ); + // this.breadCrumbs = observableOf([ + // { + // parentComponentName: null, + // label: x, + // url: '/plans' + // }] + // ); }) // this.criteria.setCriteria(this.getDefaultCriteria()); this.criteria = this.getDefaultCriteria(); @@ -367,7 +367,7 @@ export class DmpListingComponent extends BaseComponent implements OnInit, IBread }); dialogRef.afterClosed().pipe(takeUntil(this._destroyed)).subscribe(result => { if (result && result.success) { - this.dmpService.uploadXml(result.fileList[0], result.dmpTitle, result.dmpProfiles) + this.dmpService.uploadXml(result.fileList[0], result.dmpTitle, result.dmpBlueprints) .pipe(takeUntil(this._destroyed)) .subscribe((complete) => this.onCallbackImportComplete(), (error) => this.onCallbackImportFail(error.error)); diff --git a/dmp-frontend/src/app/ui/dmp/listing/listing-item/dmp-listing-item.component.html b/dmp-frontend/src/app/ui/dmp/listing/listing-item/dmp-listing-item.component.html index 1527c2c8d..4736f77ff 100644 --- a/dmp-frontend/src/app/ui/dmp/listing/listing-item/dmp-listing-item.component.html +++ b/dmp-frontend/src/app/ui/dmp/listing/listing-item/dmp-listing-item.component.html @@ -146,9 +146,9 @@
-

{{'DMP-PROFILE-LISTING.COLUMNS.LAST-EDITED' | translate}} {{dmp.modifiedTime | date: "shortDate"}}

+

{{'DMP-BLUEPRINT-LISTING.COLUMNS.LAST-EDITED' | translate}} {{dmp.modifiedTime | date: "shortDate"}}

{{'TYPES.DMP.FINALISED' | translate}} {{dmp.finalizedAt | date: "shortDate"}}

-

{{'DMP-PROFILE-LISTING.COLUMNS.PUBLISHED' | translate}} {{dmp.publishedAt | date: "shortDate"}}

+

{{'DMP-BLUEPRINT-LISTING.COLUMNS.PUBLISHED' | translate}} {{dmp.publishedAt | date: "shortDate"}}

diff --git a/dmp-frontend/src/app/ui/dmp/listing/listing-item/dmp-listing-item.component.ts b/dmp-frontend/src/app/ui/dmp/listing/listing-item/dmp-listing-item.component.ts index 44d45b01e..47ef4410c 100644 --- a/dmp-frontend/src/app/ui/dmp/listing/listing-item/dmp-listing-item.component.ts +++ b/dmp-frontend/src/app/ui/dmp/listing/listing-item/dmp-listing-item.component.ts @@ -27,7 +27,7 @@ import { GrantTabModel } from '../../editor/grant-tab/grant-tab-model'; import { MatomoService } from '@app/core/services/matomo/matomo-service'; import { HttpClient } from '@angular/common/http'; import { isNullOrUndefined } from '@app/utilities/enhancers/utils'; -import { DmpProfileService } from '@app/core/services/dmp/dmp-profile.service'; +import { DmpBlueprintService } from '@app/core/services/dmp/dmp-blueprint.service'; import { DmpBlueprintDefinition, SystemFieldType } from '@app/core/model/dmp/dmp-blueprint/dmp-blueprint'; @Component({ @@ -54,7 +54,7 @@ export class DmpListingItemComponent extends BaseComponent implements OnInit { private authentication: AuthService, public enumUtils: EnumUtils, private dmpService: DmpService, - private dmpProfileService: DmpProfileService, + private dmpBlueprintService: DmpBlueprintService, private language: TranslateService, private uiNotificationService: UiNotificationService, private lockService: LockService, @@ -176,7 +176,7 @@ export class DmpListingItemComponent extends BaseComponent implements OnInit { this.dmpFormGroup = this.dmpModel.buildForm(); if (!isNullOrUndefined(this.dmpFormGroup.get('profile').value)) { - this.dmpProfileService.getSingleBlueprint(this.dmpFormGroup.get('profile').value) + this.dmpBlueprintService.getSingleBlueprint(this.dmpFormGroup.get('profile').value) .pipe(takeUntil(this._destroyed)) .subscribe(result => { this.checkForGrant(result.definition); diff --git a/dmp-frontend/src/app/ui/dmp/listing/upload-dialogue/dmp-upload-dialogue.component.html b/dmp-frontend/src/app/ui/dmp/listing/upload-dialogue/dmp-upload-dialogue.component.html index 66874939c..19e93d958 100644 --- a/dmp-frontend/src/app/ui/dmp/listing/upload-dialogue/dmp-upload-dialogue.component.html +++ b/dmp-frontend/src/app/ui/dmp/listing/upload-dialogue/dmp-upload-dialogue.component.html @@ -33,8 +33,8 @@ diff --git a/dmp-frontend/src/app/ui/dmp/listing/upload-dialogue/dmp-upload-dialogue.component.ts b/dmp-frontend/src/app/ui/dmp/listing/upload-dialogue/dmp-upload-dialogue.component.ts index 15cd4b718..259f2be3d 100644 --- a/dmp-frontend/src/app/ui/dmp/listing/upload-dialogue/dmp-upload-dialogue.component.ts +++ b/dmp-frontend/src/app/ui/dmp/listing/upload-dialogue/dmp-upload-dialogue.component.ts @@ -19,7 +19,7 @@ import { HttpClient } from '@angular/common/http'; }) export class DmpUploadDialogue extends BaseComponent { dmpTitle: string; - dmpProfiles: any[] = []; + dmpBlueprints: any[] = []; files: File[] = []; profilesAutoCompleteConfiguration: MultipleAutoCompleteConfiguration = { @@ -59,7 +59,7 @@ export class DmpUploadDialogue extends BaseComponent { confirm() { this.data.success = true; this.data.dmpTitle = this.dmpTitle; - this.data.dmpProfiles = this.dmpProfiles; + this.data.dmpBlueprints = this.dmpBlueprints; this.dialogRef.close(this.data); } @@ -104,10 +104,10 @@ export class DmpUploadDialogue extends BaseComponent { }); dialogRef.afterClosed().pipe(takeUntil(this._destroyed)).subscribe(result => { if (result) { - if(!this.dmpProfiles) { - this.dmpProfiles = []; + if(!this.dmpBlueprints) { + this.dmpBlueprints = []; } - this.dmpProfiles.push(event); + this.dmpBlueprints.push(event); this.profilesAutoCompleteConfiguration = { filterFn: this.filterProfiles.bind(this), initialItems: (excludedItems: any[]) => this.filterProfiles('').pipe(map(result => result.filter(resultItem => (excludedItems || []).map(x => x.id).indexOf(resultItem.id) === -1))), @@ -125,7 +125,7 @@ export class DmpUploadDialogue extends BaseComponent { const criteria = new DatasetProfileCriteria(); criteria.like = value; request.criteria = criteria; - return this._service.searchDMPProfiles(request); + return this._service.searchDmpBlueprints(request); } hasFile(): boolean { diff --git a/dmp-frontend/src/app/ui/dmp/overview/dmp-overview.component.ts b/dmp-frontend/src/app/ui/dmp/overview/dmp-overview.component.ts index bb9fb4868..ac586d17b 100644 --- a/dmp-frontend/src/app/ui/dmp/overview/dmp-overview.component.ts +++ b/dmp-frontend/src/app/ui/dmp/overview/dmp-overview.component.ts @@ -19,7 +19,7 @@ import { DmpFinalizeDialogInput, DmpFinalizeDialogOutput } from '@app/ui/dmp/editor/dmp-finalize-dialog/dmp-finalize-dialog.component'; -import {BreadcrumbItem} from '@app/ui/misc/breadcrumb/definition/breadcrumb-item'; +// import {BreadcrumbItem} from '@app/ui/misc/breadcrumb/definition/breadcrumb-item'; import {BaseComponent} from '@common/base/base.component'; import {TranslateService} from '@ngx-translate/core'; import * as FileSaver from 'file-saver'; @@ -47,7 +47,7 @@ import {DepositConfigurationModel} from '@app/core/model/deposit/deposit-configu import {DoiModel} from '@app/core/model/doi/doi'; import {isNullOrUndefined} from '@app/utilities/enhancers/utils'; import { DmpBlueprintDefinition, FieldCategory, SystemFieldType } from '@app/core/model/dmp/dmp-blueprint/dmp-blueprint'; -import { DmpProfileService } from '@app/core/services/dmp/dmp-profile.service'; +import { DmpBlueprintService } from '@app/core/services/dmp/dmp-blueprint.service'; @Component({ selector: 'app-dmp-overview', @@ -62,7 +62,7 @@ export class DmpOverviewComponent extends BaseComponent implements OnInit { isFinalized = false; isPublicView = true; hasPublishButton: boolean = true; - breadCrumbs: Observable = observableOf(); + // breadCrumbs: Observable = observableOf(); isUserOwner: boolean; expand = false; lockStatus: Boolean; @@ -82,7 +82,7 @@ export class DmpOverviewComponent extends BaseComponent implements OnInit { private route: ActivatedRoute, private router: Router, private dmpService: DmpService, - private dmpProfileService: DmpProfileService, + private dmpBlueprintService: DmpBlueprintService, private depositRepositoriesService: DepositRepositoriesService, private translate: TranslateService, private authentication: AuthService, @@ -118,10 +118,10 @@ export class DmpOverviewComponent extends BaseComponent implements OnInit { this.checkLockStatus(this.dmp.id); this.setIsUserOwner(); this.getAllVersions(this.dmp); - const breadCrumbs = []; - breadCrumbs.push({ parentComponentName: null, label: this.language.instant('NAV-BAR.MY-DMPS'), url: "/plans" }); - breadCrumbs.push({ parentComponentName: 'DmpListingComponent', label: this.dmp.label, url: '/plans/overview/' + this.dmp.id }); - this.breadCrumbs = observableOf(breadCrumbs); + // const breadCrumbs = []; + // breadCrumbs.push({ parentComponentName: null, label: this.language.instant('NAV-BAR.MY-DMPS'), url: "/plans" }); + // breadCrumbs.push({ parentComponentName: 'DmpListingComponent', label: this.dmp.label, url: '/plans/overview/' + this.dmp.id }); + // this.breadCrumbs = observableOf(breadCrumbs); }, (error: any) => { if (error.status === 404) { return this.onFetchingDeletedCallbackError('/plans/'); @@ -144,10 +144,10 @@ export class DmpOverviewComponent extends BaseComponent implements OnInit { } // this.checkLockStatus(this.dmp.id); this.getAllVersions(this.dmp); - const breadCrumbs = []; - breadCrumbs.push({ parentComponentName: null, label: this.language.instant('NAV-BAR.PUBLIC-DMPS'), url: "/explore-plans" }); - breadCrumbs.push({ parentComponentName: 'DmpListingComponent', label: this.dmp.label, url: '/plans/publicOverview/' + this.dmp.id }); - this.breadCrumbs = observableOf(breadCrumbs); + // const breadCrumbs = []; + // breadCrumbs.push({ parentComponentName: null, label: this.language.instant('NAV-BAR.PUBLIC-DMPS'), url: "/explore-plans" }); + // breadCrumbs.push({ parentComponentName: 'DmpListingComponent', label: this.dmp.label, url: '/plans/publicOverview/' + this.dmp.id }); + // this.breadCrumbs = observableOf(breadCrumbs); }, (error: any) => { if (error.status === 404) { return this.onFetchingDeletedCallbackError('/explore-plans'); @@ -210,7 +210,7 @@ export class DmpOverviewComponent extends BaseComponent implements OnInit { this.formGroup = this.dmpModel.buildForm(); if (!isNullOrUndefined(this.formGroup.get('profile').value)) { - this.dmpProfileService.getSingleBlueprint(this.formGroup.get('profile').value) + this.dmpBlueprintService.getSingleBlueprint(this.formGroup.get('profile').value) .pipe(takeUntil(this._destroyed)) .subscribe(result => { this.checkForGrant(result.definition); @@ -643,7 +643,7 @@ export class DmpOverviewComponent extends BaseComponent implements OnInit { private checkIfAnyProfileIsUsedLessThanMin(dmpModel: DmpModel): Observable { const blueprintId = dmpModel.profile.id; - return this.dmpProfileService.getSingleBlueprint(blueprintId) + return this.dmpBlueprintService.getSingleBlueprint(blueprintId) .pipe(map(result => { return result.definition.sections.some(section => { if(!section.hasTemplates) diff --git a/dmp-frontend/src/app/ui/dmp/start-new-dmp-dialogue/start-new-dmp-dialog.component.ts b/dmp-frontend/src/app/ui/dmp/start-new-dmp-dialogue/start-new-dmp-dialog.component.ts index f9b46a8d4..61e7880fc 100644 --- a/dmp-frontend/src/app/ui/dmp/start-new-dmp-dialogue/start-new-dmp-dialog.component.ts +++ b/dmp-frontend/src/app/ui/dmp/start-new-dmp-dialogue/start-new-dmp-dialog.component.ts @@ -66,7 +66,7 @@ export class StartNewDmpDialogComponent extends BaseComponent { }); dialogRef.afterClosed().pipe(takeUntil(this._destroyed)).subscribe(result => { if (result && result.success) { - this.dmpService.uploadXml(result.fileList[0], result.dmpTitle, result.dmpProfiles) + this.dmpService.uploadXml(result.fileList[0], result.dmpTitle, result.dmpBlueprints) .pipe(takeUntil(this._destroyed)) .subscribe( (complete) => { diff --git a/dmp-frontend/src/app/ui/dmp/wizard/dmp-wizard.component.ts b/dmp-frontend/src/app/ui/dmp/wizard/dmp-wizard.component.ts index 0d3e9ee3a..bf4841909 100644 --- a/dmp-frontend/src/app/ui/dmp/wizard/dmp-wizard.component.ts +++ b/dmp-frontend/src/app/ui/dmp/wizard/dmp-wizard.component.ts @@ -6,15 +6,15 @@ import { MatSnackBar } from '@angular/material/snack-bar'; import { ActivatedRoute, Params, Router } from '@angular/router'; import { DmpModel } from '@app/core/model/dmp/dmp'; import { DmpBlueprintDefinition, SystemFieldType } from '@app/core/model/dmp/dmp-blueprint/dmp-blueprint'; -import { DmpProfileService } from '@app/core/services/dmp/dmp-profile.service'; +import { DmpBlueprintService } from '@app/core/services/dmp/dmp-blueprint.service'; import { DmpService } from '@app/core/services/dmp/dmp.service'; import { SnackBarNotificationLevel, UiNotificationService } from '@app/core/services/notification/ui-notification-service'; import { FunderFormModel } from '@app/ui/dmp/editor/grant-tab/funder-form-model'; import { GrantTabModel } from '@app/ui/dmp/editor/grant-tab/grant-tab-model'; import { ProjectFormModel } from '@app/ui/dmp/editor/grant-tab/project-form-model'; import { DmpWizardEditorModel } from '@app/ui/dmp/wizard/dmp-wizard-editor.model'; -import { BreadcrumbItem } from '@app/ui/misc/breadcrumb/definition/breadcrumb-item'; -import { IBreadCrumbComponent } from '@app/ui/misc/breadcrumb/definition/IBreadCrumbComponent'; +// import { BreadcrumbItem } from '@app/ui/misc/breadcrumb/definition/breadcrumb-item'; +// import { IBreadCrumbComponent } from '@app/ui/misc/breadcrumb/definition/IBreadCrumbComponent'; import { isNullOrUndefined } from '@app/utilities/enhancers/utils'; import { BaseComponent } from '@common/base/base.component'; import { ValidationErrorModel } from '@common/forms/validation/error-model/validation-error-model'; @@ -27,9 +27,9 @@ import { map, takeUntil } from 'rxjs/operators'; templateUrl: 'dmp-wizard.component.html', styleUrls: ['./dmp-wizard.component.scss'], }) -export class DmpWizardComponent extends BaseComponent implements OnInit, IBreadCrumbComponent { +export class DmpWizardComponent extends BaseComponent implements OnInit { //IBreadCrumbComponent - breadCrumbs: Observable; + // breadCrumbs: Observable; itemId: string; dmp: DmpWizardEditorModel; formGroup: UntypedFormGroup; @@ -38,7 +38,7 @@ export class DmpWizardComponent extends BaseComponent implements OnInit, IBreadC constructor( private dmpService: DmpService, - private dmpProfileService: DmpProfileService, + private dmpBlueprintService: DmpBlueprintService, private language: TranslateService, private snackBar: MatSnackBar, private route: ActivatedRoute, @@ -63,7 +63,7 @@ export class DmpWizardComponent extends BaseComponent implements OnInit, IBreadC this.formGroup = this.dmp.buildForm(); if (!isNullOrUndefined(this.formGroup.get('profile').value)) { - this.dmpProfileService.getSingleBlueprint(this.formGroup.get('profile').value) + this.dmpBlueprintService.getSingleBlueprint(this.formGroup.get('profile').value) .pipe(takeUntil(this._destroyed)) .subscribe(result => { this.checkForGrant(result.definition); @@ -81,10 +81,10 @@ export class DmpWizardComponent extends BaseComponent implements OnInit, IBreadC this.formGroup.get('label').setValue(this.dmp.label + " New"); this.isClone = true; } - const breadCrumbs = []; - breadCrumbs.push({ parentComponentName: null, label: this.language.instant('NAV-BAR.MY-DMPS'), url: "/plans" }); - breadCrumbs.push({ parentComponentName: 'DmpListingComponent', label: this.dmp.label, url: '/plans/clone/' + this.dmp.id }); - this.breadCrumbs = observableOf(breadCrumbs); + // const breadCrumbs = []; + // breadCrumbs.push({ parentComponentName: null, label: this.language.instant('NAV-BAR.MY-DMPS'), url: "/plans" }); + // breadCrumbs.push({ parentComponentName: 'DmpListingComponent', label: this.dmp.label, url: '/plans/clone/' + this.dmp.id }); + // this.breadCrumbs = observableOf(breadCrumbs); }); }); } diff --git a/dmp-frontend/src/app/ui/dmp/wizard/editor/dmp-wizard-editor.component.ts b/dmp-frontend/src/app/ui/dmp/wizard/editor/dmp-wizard-editor.component.ts index 74767095c..64c566bb1 100644 --- a/dmp-frontend/src/app/ui/dmp/wizard/editor/dmp-wizard-editor.component.ts +++ b/dmp-frontend/src/app/ui/dmp/wizard/editor/dmp-wizard-editor.component.ts @@ -173,7 +173,7 @@ export class DmpWizardEditorComponent extends BaseComponent implements OnInit { const criteria = new DatasetProfileCriteria(); criteria.like = value; request.criteria = criteria; - return this._service.searchDMPProfiles(request); + return this._service.searchDmpBlueprints(request); } } diff --git a/dmp-frontend/src/app/ui/explore-dataset/explore-dataset-listing.component.ts b/dmp-frontend/src/app/ui/explore-dataset/explore-dataset-listing.component.ts index c3d83154b..1a480f821 100644 --- a/dmp-frontend/src/app/ui/explore-dataset/explore-dataset-listing.component.ts +++ b/dmp-frontend/src/app/ui/explore-dataset/explore-dataset-listing.component.ts @@ -11,8 +11,8 @@ import { BaseComponent } from '@common/base/base.component'; import { TranslateService } from '@ngx-translate/core'; import { Observable, of as observableOf } from 'rxjs'; import { takeUntil } from 'rxjs/operators'; -import { BreadcrumbItem } from '../misc/breadcrumb/definition/breadcrumb-item'; -import { IBreadCrumbComponent } from '../misc/breadcrumb/definition/IBreadCrumbComponent'; +// import { BreadcrumbItem } from '../misc/breadcrumb/definition/breadcrumb-item'; +// import { IBreadCrumbComponent } from '../misc/breadcrumb/definition/IBreadCrumbComponent'; @Component({ @@ -20,7 +20,7 @@ import { IBreadCrumbComponent } from '../misc/breadcrumb/definition/IBreadCrumbC templateUrl: 'explore-dataset-listing.component.html', styleUrls: ['./explore-dataset-listing.component.scss'], }) -export class ExploreDatasetListingComponent extends BaseComponent implements OnInit, IBreadCrumbComponent { +export class ExploreDatasetListingComponent extends BaseComponent implements OnInit { //IBreadCrumbComponent @ViewChild(MatPaginator, { static: true }) _paginator: MatPaginator; @ViewChild(MatSort, { static: false }) sort: MatSort; @@ -28,7 +28,7 @@ export class ExploreDatasetListingComponent extends BaseComponent implements OnI totalCount: number; listingItems: DatasetListingModel[] = []; exploreDatasetCriteriaModel: ExploreDatasetCriteriaModel; - breadCrumbs: Observable; + // breadCrumbs: Observable; dmpId: string; dmpSearchEnabled = true; titlePrefix: String; @@ -70,13 +70,13 @@ export class ExploreDatasetListingComponent extends BaseComponent implements OnI } }); - const breadCrumbs = []; - breadCrumbs.push({ - parentComponentName: null, - label: this.language.instant('NAV-BAR.PUBLIC DATASETS'), - url: "/explore" - }) - this.breadCrumbs = observableOf(breadCrumbs); + // const breadCrumbs = []; + // breadCrumbs.push({ + // parentComponentName: null, + // label: this.language.instant('NAV-BAR.PUBLIC DATASETS'), + // url: "/explore" + // }) + // this.breadCrumbs = observableOf(breadCrumbs); } refresh(resetPages = false) { diff --git a/dmp-frontend/src/app/ui/explore-dmp/explore-dmp-listing.component.ts b/dmp-frontend/src/app/ui/explore-dmp/explore-dmp-listing.component.ts index 9ca409955..360e6abde 100644 --- a/dmp-frontend/src/app/ui/explore-dmp/explore-dmp-listing.component.ts +++ b/dmp-frontend/src/app/ui/explore-dmp/explore-dmp-listing.component.ts @@ -7,8 +7,8 @@ import { DataTableRequest } from '@app/core/model/data-table/data-table-request' import { DmpListingModel } from '@app/core/model/dmp/dmp-listing'; import { ExploreDmpCriteriaModel } from '@app/core/query/explore-dmp/explore-dmp-criteria'; import { DmpService } from '@app/core/services/dmp/dmp.service'; -import { BreadcrumbItem } from '@app/ui/misc/breadcrumb/definition/breadcrumb-item'; -import { IBreadCrumbComponent } from '@app/ui/misc/breadcrumb/definition/IBreadCrumbComponent'; +// import { BreadcrumbItem } from '@app/ui/misc/breadcrumb/definition/breadcrumb-item'; +// import { IBreadCrumbComponent } from '@app/ui/misc/breadcrumb/definition/IBreadCrumbComponent'; import { BaseComponent } from '@common/base/base.component'; import { TranslateService } from '@ngx-translate/core'; import { Observable, of as observableOf } from 'rxjs'; @@ -19,7 +19,7 @@ import { takeUntil } from 'rxjs/operators'; templateUrl: 'explore-dmp-listing.component.html', styleUrls: ['./explore-dmp-listing.component.scss'], }) -export class ExploreDmpListingComponent extends BaseComponent implements OnInit, IBreadCrumbComponent { +export class ExploreDmpListingComponent extends BaseComponent implements OnInit { //IBreadCrumbComponent @ViewChild(MatPaginator, { static: true }) _paginator: MatPaginator; sort = new MatSort(); @@ -28,7 +28,7 @@ export class ExploreDmpListingComponent extends BaseComponent implements OnInit, titlePrefix: string; totalCount: number; listingItems: DmpListingModel[] = []; - breadCrumbs: Observable; + // breadCrumbs: Observable; linkToDmpId: string; groupId: string; allVersions: boolean = false; @@ -64,13 +64,13 @@ export class ExploreDmpListingComponent extends BaseComponent implements OnInit, } this.refresh(); - const breadCrumbs = []; - breadCrumbs.push({ - parentComponentName: null, - label: this.language.instant('NAV-BAR.PUBLIC-DMPS'), - url: "/explore-plans" - }) - this.breadCrumbs = observableOf(breadCrumbs); + // const breadCrumbs = []; + // breadCrumbs.push({ + // parentComponentName: null, + // label: this.language.instant('NAV-BAR.PUBLIC-DMPS'), + // url: "/explore-plans" + // }) + // this.breadCrumbs = observableOf(breadCrumbs); }) } diff --git a/dmp-frontend/src/app/ui/explore-dmp/listing-item/explore-dmp-listing-item.component.html b/dmp-frontend/src/app/ui/explore-dmp/listing-item/explore-dmp-listing-item.component.html index 407534416..e7bf1a5d0 100644 --- a/dmp-frontend/src/app/ui/explore-dmp/listing-item/explore-dmp-listing-item.component.html +++ b/dmp-frontend/src/app/ui/explore-dmp/listing-item/explore-dmp-listing-item.component.html @@ -41,7 +41,7 @@
-

{{'DMP-PROFILE-LISTING.COLUMNS.PUBLISHED' | translate}} {{dmp.finalizedAt | date: "shortDate"}}

+

{{'DMP-BLUEPRINT-LISTING.COLUMNS.PUBLISHED' | translate}} {{dmp.finalizedAt | date: "shortDate"}}

diff --git a/dmp-frontend/src/app/ui/grant/editor/grant-editor.component.ts b/dmp-frontend/src/app/ui/grant/editor/grant-editor.component.ts index eb5325f52..5cafef539 100644 --- a/dmp-frontend/src/app/ui/grant/editor/grant-editor.component.ts +++ b/dmp-frontend/src/app/ui/grant/editor/grant-editor.component.ts @@ -10,8 +10,8 @@ import { GrantFileUploadService } from '@app/core/services/grant/grant-file-uplo import { GrantService } from '@app/core/services/grant/grant.service'; import { SnackBarNotificationLevel, UiNotificationService } from '@app/core/services/notification/ui-notification-service'; import { GrantEditorModel } from '@app/ui/grant/editor/grant-editor.model'; -import { BreadcrumbItem } from '@app/ui/misc/breadcrumb/definition/breadcrumb-item'; -import { IBreadCrumbComponent } from '@app/ui/misc/breadcrumb/definition/IBreadCrumbComponent'; +// import { BreadcrumbItem } from '@app/ui/misc/breadcrumb/definition/breadcrumb-item'; +// import { IBreadCrumbComponent } from '@app/ui/misc/breadcrumb/definition/IBreadCrumbComponent'; import { BaseComponent } from '@common/base/base.component'; import { FormService } from '@common/forms/form-service'; import { ValidationErrorModel } from '@common/forms/validation/error-model/validation-error-model'; @@ -28,9 +28,9 @@ import { ConfigurationService } from '@app/core/services/configuration/configura templateUrl: 'grant-editor.component.html', styleUrls: ['./grant-editor.component.scss'] }) -export class GrantEditorComponent extends BaseComponent implements OnInit, IBreadCrumbComponent { +export class GrantEditorComponent extends BaseComponent implements OnInit { //IBreadCrumbComponent - breadCrumbs: Observable = observableOf([]); + // breadCrumbs: Observable = observableOf([]); isNew = true; grant: GrantEditorModel; formGroup: FormGroup = null; @@ -78,22 +78,22 @@ export class GrantEditorComponent extends BaseComponent implements OnInit, IBrea label: this.grant.label, url: '/grants/edit/' + this.grant.id }); - this.breadCrumbs = observableOf(breadCrumbs); + //this.breadCrumbs = observableOf(breadCrumbs); }); } else { this.language.get('QUICKWIZARD.CREATE-ADD.CREATE.QUICKWIZARD_CREATE.ACTIONS.CREATE-NEW-GRANT').pipe(takeUntil(this._destroyed)).subscribe(x => { - this.breadCrumbs = observableOf([ - { - parentComponentName: null, - label: this.language.instant('NAV-BAR.GRANTS').toUpperCase(), - url: '/grants' - }, - { - parentComponentName: 'GrantListingComponent', - label: x, - url: '/grants/new/' - }] - ); + // this.breadCrumbs = observableOf([ + // { + // parentComponentName: null, + // label: this.language.instant('NAV-BAR.GRANTS').toUpperCase(), + // url: '/grants' + // }, + // { + // parentComponentName: 'GrantListingComponent', + // label: x, + // url: '/grants/new/' + // }] + // ); }); this.grant = new GrantEditorModel(); diff --git a/dmp-frontend/src/app/ui/grant/listing/grant-listing.component.ts b/dmp-frontend/src/app/ui/grant/listing/grant-listing.component.ts index 212414819..d7a46710c 100644 --- a/dmp-frontend/src/app/ui/grant/listing/grant-listing.component.ts +++ b/dmp-frontend/src/app/ui/grant/listing/grant-listing.component.ts @@ -8,8 +8,8 @@ import { GrantListingModel } from '@app/core/model/grant/grant-listing'; import { GrantCriteria } from '@app/core/query/grant/grant-criteria'; import { GrantService } from '@app/core/services/grant/grant.service'; import { GrantCriteriaComponent } from '@app/ui/grant/listing/criteria/grant-criteria.component'; -import { BreadcrumbItem } from '@app/ui/misc/breadcrumb/definition/breadcrumb-item'; -import { IBreadCrumbComponent } from '@app/ui/misc/breadcrumb/definition/IBreadCrumbComponent'; +// import { BreadcrumbItem } from '@app/ui/misc/breadcrumb/definition/breadcrumb-item'; +// import { IBreadCrumbComponent } from '@app/ui/misc/breadcrumb/definition/IBreadCrumbComponent'; import { BaseComponent } from '@common/base/base.component'; import { TranslateService } from '@ngx-translate/core'; import { Observable, of as observableOf } from 'rxjs'; @@ -20,13 +20,13 @@ import { takeUntil } from 'rxjs/operators'; templateUrl: 'grant-listing.component.html', styleUrls: ['./grant-listing.component.scss'] }) -export class GrantListingComponent extends BaseComponent implements OnInit, IBreadCrumbComponent { +export class GrantListingComponent extends BaseComponent implements OnInit { //IBreadCrumbComponent @ViewChild(MatPaginator, { static: true }) _paginator: MatPaginator; @ViewChild(MatSort, { static: false }) sort: MatSort; @ViewChild(GrantCriteriaComponent, { static: true }) criteria: GrantCriteriaComponent; - breadCrumbs: Observable; + // breadCrumbs: Observable; totalCount: number; listingItems: GrantListingModel[] = []; @@ -45,11 +45,11 @@ export class GrantListingComponent extends BaseComponent implements OnInit, IBre this.refresh(); this.criteria.setRefreshCallback((resetPages) => this.refresh(resetPages)); - this.breadCrumbs = observableOf([{ - parentComponentName: null, - label: this.language.instant('NAV-BAR.GRANTS').toUpperCase(), - url: '/grants' - }]); + // this.breadCrumbs = observableOf([{ + // parentComponentName: null, + // label: this.language.instant('NAV-BAR.GRANTS').toUpperCase(), + // url: '/grants' + // }]); } diff --git a/dmp-frontend/src/app/ui/misc/breadcrumb/breadcrumb.component.html b/dmp-frontend/src/app/ui/misc/breadcrumb/breadcrumb.component.html deleted file mode 100644 index e4ce76eb5..000000000 --- a/dmp-frontend/src/app/ui/misc/breadcrumb/breadcrumb.component.html +++ /dev/null @@ -1,15 +0,0 @@ - diff --git a/dmp-frontend/src/app/ui/misc/breadcrumb/breadcrumb.component.scss b/dmp-frontend/src/app/ui/misc/breadcrumb/breadcrumb.component.scss deleted file mode 100644 index b045dae51..000000000 --- a/dmp-frontend/src/app/ui/misc/breadcrumb/breadcrumb.component.scss +++ /dev/null @@ -1,159 +0,0 @@ -.app-breadcrumb { - // padding: 0.75rem 0.1rem; - // margin-bottom: 1rem; - // background-color: #e9ecef; - // border-radius: 0.25rem; - // margin-top: 2em; - - .arrow { - padding-right: 0; - padding-left: 0; - font-size: 1.7em; - } - - .link { - font-size: 1.1em; - } - - .navbar-brand { - display: flex; - justify-content: center; - align-items: center; - background-color: #f8f8f8; - font-size: 16px; - font-weight: 400; - padding: 0.5em 0.5em; - margin-right: 0rem; - } - - .breadcrumb-title { - height: auto; - line-height: 1em; - } - - .breadcrumb-item { - display: flex; - align-items: center; - } - - .breadcrumb-label { - max-width: auto; - white-space: nowrap; - overflow: hidden; - text-overflow: ellipsis; - } - - .active { - color: var(--primary-color-3); - } - - .icon { - font-size: 1em; - width: auto; - height: auto; - } -} - -@media screen and (max-width: 1668px) { - .app-breadcrumb { - .breadcrumb-box { - padding: 0px; - } - - .navbar-brand { - display: flex; - justify-content: center; - align-items: center; - background-color: #f8f8f8; - font-size: 15px; - font-weight: 400; - padding: 0.5em 0.5em; - margin-left: 2rem; - } - - .breadcrumb-label { - max-width: 170px; - white-space: nowrap; - overflow: hidden; - text-overflow: ellipsis; - } - } -} - -@media screen and (max-width: 1446px) { - .app-breadcrumb { - .breadcrumb-box { - padding: 0px; - } - - .navbar-brand { - display: flex; - justify-content: center; - align-items: center; - background-color: #f8f8f8; - font-size: 14px; - font-weight: 400; - padding: 0.5em 0.5em; - margin-left: 2rem; - } - - .breadcrumb-label { - max-width: 130px; - white-space: nowrap; - overflow: hidden; - text-overflow: ellipsis; - } - } -} - -@media screen and (max-width: 1280px) { - .app-breadcrumb { - .breadcrumb-box { - padding: 0px; - } - - .navbar-brand { - display: flex; - justify-content: center; - align-items: center; - background-color: #f8f8f8; - font-size: 14px; - font-weight: 400; - padding: 0.5em 0.5em; - margin-left: 2rem; - } - - .breadcrumb-label { - max-width: 90px; - white-space: nowrap; - overflow: hidden; - text-overflow: ellipsis; - } - } -} - -@media screen and (max-width: 570px) { - .app-breadcrumb { - .breadcrumb-box { - padding: 0px; - } - - .navbar-brand { - display: flex; - justify-content: center; - align-items: center; - background-color: #f8f8f8; - font-size: 12px; - font-weight: 400; - padding: 0.5em 0.5em; - margin-left: 2rem; - } - - .breadcrumb-label { - max-width: 70px; - white-space: nowrap; - overflow: hidden; - text-overflow: ellipsis; - } - } -} diff --git a/dmp-frontend/src/app/ui/misc/breadcrumb/breadcrumb.component.ts b/dmp-frontend/src/app/ui/misc/breadcrumb/breadcrumb.component.ts deleted file mode 100644 index b84757738..000000000 --- a/dmp-frontend/src/app/ui/misc/breadcrumb/breadcrumb.component.ts +++ /dev/null @@ -1,50 +0,0 @@ - -import {of as observableOf, Observable } from 'rxjs'; - -import {filter, mergeMap, distinctUntilChanged, map} from 'rxjs/operators'; -import { Component, OnInit } from '@angular/core'; -import { ActivatedRoute, NavigationEnd, Router } from '@angular/router'; -import { BreadcrumbItem } from './definition/breadcrumb-item'; -import { BreadCrumbResolverService } from './service/breadcrumb.service'; -import { TranslateService } from '@ngx-translate/core'; - -@Component({ - selector: 'app-breadcrumb', - templateUrl: './breadcrumb.component.html', - styleUrls: ['./breadcrumb.component.scss'] -}) -export class BreadcrumbComponent implements OnInit { - breadcrumbs$ = this.router.events.pipe( - filter(event => event instanceof NavigationEnd), - distinctUntilChanged(), - mergeMap(event => this.buildBreadCrumb(this.activatedRoute.root)),); - - - constructor( - public activatedRoute: ActivatedRoute, - private router: Router, - private breadCrumbService: BreadCrumbResolverService, - private language: TranslateService, - ) { - } - - ngOnInit() { - } - - buildBreadCrumb(route: ActivatedRoute): Observable { - if (this.breadCrumbService.resolve(route)) { - return this.breadCrumbService.resolve(route).pipe(map(x => { - x.unshift({ - label: this.language.instant('NAV-BAR.HOME'), - url: '/home', - icon: 'dashboard' - }); return x; - })); - } - return observableOf([]); - } - - navigate(url, params) { - this.router.navigate([url, params]); - } -} diff --git a/dmp-frontend/src/app/ui/misc/breadcrumb/breadcrumb.module.ts b/dmp-frontend/src/app/ui/misc/breadcrumb/breadcrumb.module.ts deleted file mode 100644 index ef0517c0b..000000000 --- a/dmp-frontend/src/app/ui/misc/breadcrumb/breadcrumb.module.ts +++ /dev/null @@ -1,20 +0,0 @@ -import { NgModule } from '@angular/core'; -import { RouterModule } from '@angular/router'; -import { BreadcrumbComponent } from '@app/ui/misc/breadcrumb/breadcrumb.component'; -import { BreadCrumbResolverService } from '@app/ui/misc/breadcrumb/service/breadcrumb.service'; -import { CommonUiModule } from '@common/ui/common-ui.module'; - -@NgModule({ - imports: [ - CommonUiModule, - RouterModule - ], - declarations: [ - BreadcrumbComponent - ], - providers: [ - BreadCrumbResolverService - ], - exports: [BreadcrumbComponent] -}) -export class BreadcrumbModule { } diff --git a/dmp-frontend/src/app/ui/misc/breadcrumb/breadcrumb.service.ts b/dmp-frontend/src/app/ui/misc/breadcrumb/breadcrumb.service.ts new file mode 100644 index 000000000..0da932625 --- /dev/null +++ b/dmp-frontend/src/app/ui/misc/breadcrumb/breadcrumb.service.ts @@ -0,0 +1,91 @@ +import { Injectable } from "@angular/core"; +import { BehaviorSubject, Observable } from 'rxjs'; + +@Injectable({ + providedIn: 'root' +}) +export class BreadcrumbService { //todo maybe some memory management + + private paramToStringDictionary: Record = {}; + private pathOverrideMap = new Map(); + + private resolvedValues$ = new BehaviorSubject>({ ...this.paramToStringDictionary }) + + + public addIdResolvedValue(param: string, value: string) { + if (!param) { + return; + } + if (this.paramToStringDictionary[param] === value) { // value already in dictionary + return; + } + + this.paramToStringDictionary[param] = value; + + this.resolvedValues$.next({ ...this.paramToStringDictionary }) + } + + + public resolvedValues(): Observable> { + return this.resolvedValues$.asObservable(); + } + + public addPathOverride(pathOverride: PathOverride): void { + if (!pathOverride) { + return; + } + + this.pathOverrideMap.set(pathOverride.target, pathOverride.redirectTo); + } + + public getPathOverrideFor(pathString: string): string { + return this.pathOverrideMap.get(pathString); + } + + public emptyPathOverrides(): void { + this.pathOverrideMap.clear(); + } + + + + + public static readonly ROUTE_DATA_KEY: string = 'breadcrumb'; // TODO USE IT ELSEWHERE + + // For the moment only to make data params typed + public static generateRouteDataConfiguration(params: BreadCrumbRouteData): Record { + return { + [BreadcrumbService.ROUTE_DATA_KEY]: params + }; + } +} + + +export interface BreadCrumbRouteData { + title?: string; + skipNavigation?: boolean; + hideNavigationItem?: boolean; + titleFactory?: (resolutions: BreadcrumbTitlePathResolutions) => { languageKey: string, translateParams?: Record } +} + + + +interface BreadcrumbTitlePathResolutions { + /** + * Resolved path params + * + * for example: somePath/:id => somepath/ + */ + pathResolutions?: Record; + /** + * Resolved values that we have registered into breadcrumb service + * + * for example: => John Doe + */ + valueResolutions?: Record; +} + + +export interface PathOverride { + target: string; + redirectTo: string; +} \ No newline at end of file diff --git a/dmp-frontend/src/app/ui/misc/breadcrumb/definition/IBreadCrumbComponent.ts b/dmp-frontend/src/app/ui/misc/breadcrumb/definition/IBreadCrumbComponent.ts deleted file mode 100644 index 0c95ac8a0..000000000 --- a/dmp-frontend/src/app/ui/misc/breadcrumb/definition/IBreadCrumbComponent.ts +++ /dev/null @@ -1,6 +0,0 @@ -import { BreadcrumbItem } from './breadcrumb-item'; -import { Observable } from 'rxjs'; - -export interface IBreadCrumbComponent { - breadCrumbs: Observable; -} diff --git a/dmp-frontend/src/app/ui/misc/breadcrumb/definition/breadcrumb-item.ts b/dmp-frontend/src/app/ui/misc/breadcrumb/definition/breadcrumb-item.ts deleted file mode 100644 index f3452eb60..000000000 --- a/dmp-frontend/src/app/ui/misc/breadcrumb/definition/breadcrumb-item.ts +++ /dev/null @@ -1,9 +0,0 @@ - -export class BreadcrumbItem { - parentComponentName?: string; - label: string; - url: string; - params?: any = {}; - icon?: string; - notFoundResolver?: any[]; -} diff --git a/dmp-frontend/src/app/ui/misc/breadcrumb/navigation-breadcrumb.component.html b/dmp-frontend/src/app/ui/misc/breadcrumb/navigation-breadcrumb.component.html new file mode 100644 index 000000000..6ad691535 --- /dev/null +++ b/dmp-frontend/src/app/ui/misc/breadcrumb/navigation-breadcrumb.component.html @@ -0,0 +1,26 @@ + + + + + + home + \ No newline at end of file diff --git a/dmp-frontend/src/app/ui/misc/breadcrumb/navigation-breadcrumb.component.scss b/dmp-frontend/src/app/ui/misc/breadcrumb/navigation-breadcrumb.component.scss new file mode 100644 index 000000000..ab8449363 --- /dev/null +++ b/dmp-frontend/src/app/ui/misc/breadcrumb/navigation-breadcrumb.component.scss @@ -0,0 +1,13 @@ +.hidden{ + visibility: hidden; + width: 0; +} + +.text-black{ + color: #000; +} + +.mat-icon{ + font-size: 1rem; + height: 1rem; +} \ No newline at end of file diff --git a/dmp-frontend/src/app/ui/misc/breadcrumb/navigation-breadcrumb.component.ts b/dmp-frontend/src/app/ui/misc/breadcrumb/navigation-breadcrumb.component.ts new file mode 100644 index 000000000..90188367c --- /dev/null +++ b/dmp-frontend/src/app/ui/misc/breadcrumb/navigation-breadcrumb.component.ts @@ -0,0 +1,181 @@ +import { ChangeDetectionStrategy, ChangeDetectorRef, Component } from "@angular/core"; +import { ActivatedRouteSnapshot, NavigationEnd, Router } from "@angular/router"; +import { BaseComponent } from "@common/base/base.component"; +import { combineLatest, of } from "rxjs"; +import { debounceTime, distinctUntilChanged, filter, map, startWith, takeUntil, tap } from "rxjs/operators"; +import { BreadCrumbRouteData, BreadcrumbService } from "./breadcrumb.service"; + + +@Component({ + selector: 'app-navigation-breadcrumb', + styleUrls: [ + './navigation-breadcrumb.component.scss' + ], + templateUrl: './navigation-breadcrumb.component.html', + changeDetection: ChangeDetectionStrategy.OnPush, +}) +export class NavigationBreadcrumbComponent extends BaseComponent { + + breadCrumbs: BreadCrumbItem[] = []; + + paramToStringDictionary: Record = {}; + + + protected readonly HOME_SYMBOL = Symbol('home') + + + constructor(private router: Router, private breadcrumbService: BreadcrumbService, private cdr: ChangeDetectorRef) { + super(); + combineLatest([ + this.breadcrumbService.resolvedValues().pipe( + tap(x => this.paramToStringDictionary = x), + ), + router.events.pipe( + filter(event => event instanceof NavigationEnd), + map((x: NavigationEnd) => x.url?.split('?')?.[0]), + distinctUntilChanged(), + debounceTime(200), + startWith(of()) + ) + ]) + .pipe( + map(() => { + const routeSnapshot = this.router.routerState.snapshot.root; + const breadcrumbs = this._buildBreadCrumbs(routeSnapshot).filter(x => !!x.title); + return breadcrumbs; + }), + takeUntil(this._destroyed), + ) + .subscribe(breadCrumbs => { + this.breadCrumbs = breadCrumbs + this.cdr.markForCheck(); + }); + } + + + public computePath(index: number): string[] { + if (!this.breadCrumbs?.length) { + return null; + } + if (index < 0 || index >= this.breadCrumbs?.length) { + return null; + } + + if (this.breadCrumbs[index].skipNavigation) { + return null; + } + + const path = this.breadCrumbs.slice(0, index + 1) + .map(x => x.path) + .reduce((aggr, current) => [...aggr, ...current.split('/')], ['/']) + .filter(x => !!x); + + + return this.breadcrumbService.getPathOverrideFor( + path?.join('/').replace('//', '/') + )?.split('/') ?? path; + } + + private _buildBreadCrumbs(activatedRoute: ActivatedRouteSnapshot): BreadCrumbItem[] { + + if (!activatedRoute) { + return []; + } + + let path = activatedRoute.routeConfig?.path ?? '/'; // undefined path is the root path + + const breadcrumbData: BreadCrumbRouteData | undefined = activatedRoute.routeConfig?.data?.[BreadcrumbService.ROUTE_DATA_KEY]; + + const [title, translateParams] = this._composeBreadCrumbTitle({ + path, + breadcrumbData, + pathParams: activatedRoute.params + }); + + path = this._enrichPathParamNames(path, activatedRoute.params); // somepath/:id => somepath/1239dfg123-123-123...etc + + const skipNavigation = activatedRoute.routeConfig?.data?.breadcrumb?.skipNavigation ?? false; + const hideItem = breadcrumbData?.hideNavigationItem ?? false + + + const currentItem: BreadCrumbItem = { + title, + path, + translateParams, + skipNavigation, + hideItem + } + + return [currentItem, ...this._buildBreadCrumbs(activatedRoute.firstChild)]; + } + + + private _composeBreadCrumbTitle( + params: { + breadcrumbData?: BreadCrumbRouteData, + path: string, + pathParams: Record + }) + : [string, Record] | [string] { + + const { path, pathParams, breadcrumbData } = params; + + if (breadcrumbData?.title) {// higher priority if title exists + return [breadcrumbData.title, null]; + } + + if (breadcrumbData?.titleFactory) { + const { languageKey, translateParams } = breadcrumbData.titleFactory({ + pathResolutions: pathParams, + valueResolutions: this.paramToStringDictionary + }); + return [languageKey, translateParams]; + } + + + if (path === '/') { + return [this.HOME_SYMBOL as unknown as string, null]; + } + + if (!pathParams) { + return [path, null]; + } + + + const title = Object.keys(pathParams) + .sort((a, b) => b.length - a.length) // avoid param overlapping => :id2 (length 3) should be replaced before :id (length 2) + .reduce( + (aggr, current) => aggr.replace(`:${current}`, this.paramToStringDictionary[pathParams[current]] ?? pathParams[current]) + , path ?? '' + ); + + return [title, null]; + } + + + private _enrichPathParamNames(path: string, pathParams: Record): string { + if (!pathParams || !path) { + return path; + } + + path = Object.keys(pathParams) + .sort((a, b) => b.length - a.length) // avoid param overlapping => :id2 (length 3) should be replaced before :id (length 2) + .reduce( + (aggr, current) => aggr.replace(`:${current}`, pathParams[current]) + , path ?? '' + ); + + return path; + } +} + + + + +interface BreadCrumbItem { + title: string; + path: string; + skipNavigation: boolean; + hideItem: boolean; + translateParams?: Record; +} \ No newline at end of file diff --git a/dmp-frontend/src/app/ui/misc/breadcrumb/service/breadcrumb.service.ts b/dmp-frontend/src/app/ui/misc/breadcrumb/service/breadcrumb.service.ts deleted file mode 100644 index 659234653..000000000 --- a/dmp-frontend/src/app/ui/misc/breadcrumb/service/breadcrumb.service.ts +++ /dev/null @@ -1,86 +0,0 @@ - -import { Injectable, NgZone } from '@angular/core'; -import { ActivatedRoute, Router } from '@angular/router'; -import { BreadcrumbItem } from '@app/ui/misc/breadcrumb/definition/breadcrumb-item'; -import { IBreadCrumbComponent } from '@app/ui/misc/breadcrumb/definition/IBreadCrumbComponent'; -import { BaseService } from '@common/base/base.service'; -import { Observable, of as observableOf } from 'rxjs'; -import { takeUntil } from 'rxjs/operators'; - -@Injectable() -export class BreadCrumbResolverService extends BaseService { - - private activeComponents = []; - private parentComponents = []; - private breadCrumbs: Observable = observableOf([]); - constructor( - private router: Router, - private zone: NgZone - ) { super(); } - - public push(component: any) { - const existingComponentIndex = this.activeComponents.map(x => x.constructor.name).indexOf(component.constructor.name); - if (existingComponentIndex !== -1) { this.activeComponents.splice(existingComponentIndex, 1); } - this.activeComponents.push(component); - } - - public clear() { - this.activeComponents.length = 0; - this.breadCrumbs = observableOf([]); - } - - public resolve(activatedRoute: ActivatedRoute): Observable { - this.breadCrumbs = null; - const routeComponents = this.getComponentsFromRoute(activatedRoute, []); - this.activeComponents.filter(x => routeComponents.indexOf(x.constructor.name) !== -1).forEach(x => { - if (x.hasOwnProperty('breadCrumbs')) { - const componentItems = this.resolveDependentComponents((x).breadCrumbs, []); - this.breadCrumbs = observableOf(componentItems); - } - }); - return this.breadCrumbs; - } - - private getComponentsFromRoute(activatedRoute: ActivatedRoute, routeComponents: any[]): any[] { - activatedRoute.children.forEach(x => { - if (x.children.length > 0) { this.getComponentsFromRoute(x.children[0], routeComponents); } - if (x.component) { routeComponents.push(x.component['name']); } - }); - if (activatedRoute.component) { routeComponents.push(activatedRoute.component['name']); } - - return routeComponents; - } - - resolveDependentComponents(items: Observable, components: any[]): any[] { - items - .pipe(takeUntil(this._destroyed)) - .subscribe(breadCrumbs => { - breadCrumbs.forEach(async item => { - const parentComponent = item.parentComponentName ? this.findComponent(item.parentComponentName) : null; - if (parentComponent && parentComponent.hasOwnProperty('breadCrumbs')) { - components = this.pushToStart(components, this.resolveDependentComponents((parentComponent).breadCrumbs, components)); - } else if (item.notFoundResolver) { - components = this.pushToStart(components, item.notFoundResolver); - //components = this.pushToStart(components, [unresolvedComponentItems]) - } - }); - components = this.pushToEnd(components, breadCrumbs); - }); - return components; - } - - private findComponent(componentName: string): any { - for (let i = 0; i < this.activeComponents.length; i++) { - if (this.activeComponents[i].constructor.name === componentName) { return this.activeComponents[i]; } - } - return null; - } - - pushToStart(first: any[], second: any[]) { - return [].concat(second.filter(x => first.map(firstX => firstX.label).indexOf(x.label) === -1), first); - } - - pushToEnd(first: any[], second: any[]) { - return [].concat(first, second.filter(x => first.map(firstX => firstX.label).indexOf(x.label) === -1)); - } -} diff --git a/dmp-frontend/src/app/ui/misc/navigation/navigation.component.html b/dmp-frontend/src/app/ui/misc/navigation/navigation.component.html index 937ccc065..73803bc87 100644 --- a/dmp-frontend/src/app/ui/misc/navigation/navigation.component.html +++ b/dmp-frontend/src/app/ui/misc/navigation/navigation.component.html @@ -11,7 +11,7 @@ {{'NAV-BAR.DMPS' | translate}} {{'NAV-BAR.DATASETS' | translate}} {{'NAV-BAR.USERS' | translate}} - {{'NAV-BAR.DMP-BLUEPRINTS' | + {{'NAV-BAR.DMP-BLUEPRINTS' | translate}} {{'NAV-BAR.DATASETS-ADMIN' | translate}} diff --git a/dmp-frontend/src/app/ui/navbar/navbar.component.html b/dmp-frontend/src/app/ui/navbar/navbar.component.html index 5d8f62fd5..e3d6fae92 100644 --- a/dmp-frontend/src/app/ui/navbar/navbar.component.html +++ b/dmp-frontend/src/app/ui/navbar/navbar.component.html @@ -101,7 +101,7 @@ diff --git a/dmp-frontend/src/app/ui/navbar/navbar.module.ts b/dmp-frontend/src/app/ui/navbar/navbar.module.ts index fb0c74970..f0be977ae 100644 --- a/dmp-frontend/src/app/ui/navbar/navbar.module.ts +++ b/dmp-frontend/src/app/ui/navbar/navbar.module.ts @@ -1,6 +1,5 @@ import { NgModule } from '@angular/core'; import { RouterModule } from '@angular/router'; -import { BreadcrumbModule } from '@app/ui/misc/breadcrumb/breadcrumb.module'; import { SearchComponent } from '@app/ui/misc/search/search.component'; import { NavbarComponent } from '@app/ui/navbar/navbar.component'; import { CommonFormsModule } from '@common/forms/common-forms.module'; @@ -12,7 +11,6 @@ import { LanguageModule } from '../language/language.module'; CommonUiModule, CommonFormsModule, RouterModule, - BreadcrumbModule, LanguageModule ], declarations: [ diff --git a/dmp-frontend/src/app/ui/quick-wizard/dataset-editor/dataset-editor-wizard.component.ts b/dmp-frontend/src/app/ui/quick-wizard/dataset-editor/dataset-editor-wizard.component.ts index 3d554d5ba..bd212cc49 100644 --- a/dmp-frontend/src/app/ui/quick-wizard/dataset-editor/dataset-editor-wizard.component.ts +++ b/dmp-frontend/src/app/ui/quick-wizard/dataset-editor/dataset-editor-wizard.component.ts @@ -1,8 +1,8 @@ import { Component, Input, OnInit } from "@angular/core"; import { UntypedFormArray, UntypedFormGroup } from "@angular/forms"; import { DatasetWizardService } from '@app/core/services/dataset-wizard/dataset-wizard.service'; -import { BreadcrumbItem } from '@app/ui/misc/breadcrumb/definition/breadcrumb-item'; -import { IBreadCrumbComponent } from '@app/ui/misc/breadcrumb/definition/IBreadCrumbComponent'; +// import { BreadcrumbItem } from '@app/ui/misc/breadcrumb/definition/breadcrumb-item'; +// import { IBreadCrumbComponent } from '@app/ui/misc/breadcrumb/definition/IBreadCrumbComponent'; import { DatasetDescriptionFormEditorModel } from '@app/ui/misc/dataset-description-form/dataset-description-form.model'; import { QuickWizardDatasetDescriptionModel } from '@app/ui/quick-wizard/dataset-editor/quick-wizard-dataset-description-model'; import { BaseComponent } from '@common/base/base.component'; @@ -16,8 +16,7 @@ import { LinkToScroll } from '@app/ui/misc/dataset-description-form/tableOfConte templateUrl: 'dataset-editor-wizard.component.html', styleUrls: ['./dataset-editor-wizard.component.scss'] }) -export class DatasetEditorWizardComponent extends BaseComponent implements OnInit, IBreadCrumbComponent { - breadCrumbs: Observable; +export class DatasetEditorWizardComponent extends BaseComponent implements OnInit { @Input() formGroup: UntypedFormGroup; @Input() datasetProfile: UntypedFormGroup; // DatasetProfileModel; diff --git a/dmp-frontend/src/app/ui/quick-wizard/dmp-editor/dmp-editor-wizard-model.ts b/dmp-frontend/src/app/ui/quick-wizard/dmp-editor/dmp-editor-wizard-model.ts index 95acbcab8..643d8c139 100644 --- a/dmp-frontend/src/app/ui/quick-wizard/dmp-editor/dmp-editor-wizard-model.ts +++ b/dmp-frontend/src/app/ui/quick-wizard/dmp-editor/dmp-editor-wizard-model.ts @@ -1,13 +1,12 @@ import { UntypedFormBuilder, UntypedFormGroup, Validators } from '@angular/forms'; -import { Status } from '@app/core/common/enum/status'; +import { DmpStatus } from '@app/core/common/enum/dmp-status'; import { DatasetProfileModel } from '@app/core/model/dataset/dataset-profile'; -import { DmpProfileDefinition } from '@app/core/model/dmp-profile/dmp-profile'; import { DmpModel } from '@app/core/model/dmp/dmp'; +import { DmpBlueprintDefinition } from '@app/core/model/dmp/dmp-blueprint/dmp-blueprint'; import { ValidJsonValidator } from '@app/library/auto-complete/auto-complete-custom-validator'; import { BackendErrorValidator } from '@common/forms/validation/custom-validator'; import { ValidationErrorModel } from '@common/forms/validation/error-model/validation-error-model'; import { ValidationContext } from '@common/forms/validation/validation-context'; -import { DmpStatus } from '@app/core/common/enum/dmp-status'; export class DmpEditorWizardModel { public id: string; @@ -15,7 +14,7 @@ export class DmpEditorWizardModel { public status: DmpStatus = DmpStatus.Draft; public description: String; public datasetProfile: DatasetProfileModel; - public definition: DmpProfileDefinition; + public definition: DmpBlueprintDefinition; public validationErrorModel: ValidationErrorModel = new ValidationErrorModel(); public language: String; @@ -24,7 +23,7 @@ export class DmpEditorWizardModel { this.label = item.label; this.status = item.status; this.description = item.description; - this.datasetProfile = {id: item.profiles[0].descriptionTemplateId, label: item.profiles[0].label, description: ""}; + this.datasetProfile = { id: item.profiles[0].descriptionTemplateId, label: item.profiles[0].label, description: "" }; this.language = item.language; return this; } diff --git a/dmp-frontend/src/app/ui/quick-wizard/dmp-editor/dmp-editor-wizard.component.html b/dmp-frontend/src/app/ui/quick-wizard/dmp-editor/dmp-editor-wizard.component.html index a225b7db9..a9313f047 100644 --- a/dmp-frontend/src/app/ui/quick-wizard/dmp-editor/dmp-editor-wizard.component.html +++ b/dmp-frontend/src/app/ui/quick-wizard/dmp-editor/dmp-editor-wizard.component.html @@ -63,7 +63,7 @@ + + +
+
+
+ +
+
+ + + + + + + + + + + {{'HYBRID-LISTING.ORDER-BY' | translate}} {{getPropertyName(_defaultSort?.[0].prop)}} + + + + + + + + + + + + + + + +
+ +
+ + +
+
+ display_settings + {{'HYBRID-LISTING.DISPLAY-SETTINGS' | translate}} +
+
    +
  • + {{column.name}} +
  • +
+
+
+ + + + +
+
+ + +
+
+ +
+
+ + {{batchActions?.selectedCount}} {{'HYBRID-LISTING.SELECTED' | translate}} + cancel + +
+
+
+
+
+
+ + + + + +
+ +
+
+
+ +
+ + + +
+ +
+
+ +
+
+ +
+
+
+
+ {{'HYBRID-LISTING.NO-DATA-TO-DISPLAY' | translate}} +
+
+ +
+ +
+ +
+
+
+ + + +
+ + + +
+ +
+
+ +
+
+
+
+
+
+ {{'HYBRID-LISTING.NO-DATA-TO-DISPLAY' | translate}} +
+
+ +
+
+ + + + + + + + + + + + + + + + + + + + + + + {{column.valueFunction(row)}} + diff --git a/dmp-frontend/src/common/modules/hybrid-listing/hybrid-listing.component.scss b/dmp-frontend/src/common/modules/hybrid-listing/hybrid-listing.component.scss new file mode 100644 index 000000000..6ad1a1a13 --- /dev/null +++ b/dmp-frontend/src/common/modules/hybrid-listing/hybrid-listing.component.scss @@ -0,0 +1,66 @@ +.hybrid-listing-component { + box-shadow: unset !important; +} + +.hybrid-listing-component-row-cursor { + .datatable-body-row { + cursor: pointer; + + } +} + + +.actions-bar-container{ + gap: .6rem; +} + +.rotate-180{ + transform: rotate(180deg); +} + +.bg-gray{ + background-color: #f5f5f5; +} + + +.mat-mdc-paginator-container{ + justify-content: space-between !important; +} + + +.datatable-footer-inner{ + height: auto !important; + min-height: 56px; +} + + +.flex-grow-1{ + flex-grow: 1; +} + + +.item-listing-container{ + display: flex; + flex-direction: column; + gap: 1rem; + + .listing-item{ + display: flex; + align-items: center; + padding: 1rem; + } +} + + +.item-card-container{ + display: grid; + grid-gap: 1rem; + grid-template-columns: repeat(3, 1fr); +} + + + +.negate-card{ + background-color: transparent !important; + box-shadow: unset !important; +} \ No newline at end of file diff --git a/dmp-frontend/src/common/modules/hybrid-listing/hybrid-listing.component.ts b/dmp-frontend/src/common/modules/hybrid-listing/hybrid-listing.component.ts new file mode 100644 index 000000000..ea20f34bd --- /dev/null +++ b/dmp-frontend/src/common/modules/hybrid-listing/hybrid-listing.component.ts @@ -0,0 +1,744 @@ +import { ChangeDetectorRef, Component, ContentChild, ElementRef, EventEmitter, Input, NgZone, OnChanges, OnInit, Output, PipeTransform, SimpleChanges, TemplateRef, ViewChild, ViewEncapsulation, inject } from '@angular/core'; +import { BaseComponent } from '@common/base/base.component'; +import { TranslateService } from '@ngx-translate/core'; +import { DatatableComponent, SelectionType, TableColumn } from '@swimlane/ngx-datatable'; +import { debounceTime, filter, takeUntil } from 'rxjs/operators'; +import { MatCheckboxChange } from '@angular/material/checkbox'; +import { BatchActionsDirective } from '@common/modules/hybrid-listing/directives/batch-actions.directive'; +import { PageEvent } from '@angular/material/paginator'; +import { nameof } from 'ts-simple-nameof'; +import { Subject } from 'rxjs'; +import { CollectionUtils } from '@app/core/services/utilities/collection-utils.service'; + +@Component({ + selector: 'app-hybrid-listing', + templateUrl: './hybrid-listing.component.html', + styleUrls: ['./hybrid-listing.component.scss'], + encapsulation: ViewEncapsulation.None, +}) +export class HybridListingComponent extends BaseComponent implements OnInit, OnChanges { + + + + + @ViewChild('wrapperCard', {static: true, read: ElementRef}) wrapperCard: ElementRef; + @ViewChild(DatatableComponent) table: DatatableComponent; + + private changeDetectorRef = inject(ChangeDetectorRef); + private ngZone = inject(NgZone); + + + @ViewChild('functionValueTemplate', { static: true }) functionValueTemplate: TemplateRef; + + private _batchActions?: BatchActionsDirective + @ContentChild(BatchActionsDirective) set batchActions(batchActions: BatchActionsDirective){ + this._batchActions = batchActions; + this.refreshColumnDefinitionData(); + if(this._batchActions){ + this._batchActions.getSelections = () =>{ + return this.selected; + } + } + } + get batchActions(): BatchActionsDirective{ + return this._batchActions; + } + + + private _listItemTemplate: TemplateRef; + @Input() public set listItemTemplate(value: TemplateRef){ + if(!value){ + this.mode = HybridListingMode.Table; + } + this._listItemTemplate = value; + } + public get listItemTemplate(): TemplateRef{ + return this._listItemTemplate; + } + + + private _cardItemTemplate: TemplateRef; + @Input() public set cardItemTemplate(value: TemplateRef){ + if(!value){ + this.mode = HybridListingMode.Table; + } + this._cardItemTemplate = value; + } + public get cardItemTemplate(): TemplateRef{ + return this._cardItemTemplate; + } + + protected _rowIdentity = x => x + + @Input() + trackBy: ((item: any) => any ) = this._rowIdentity; + + @Input() class: TableClass = TableClass.Material; + @Input() forceShowShorting = false; + @Input() columns: ColumnDefinition[]; + @Input() rows: any[]; + @Input() columnMode: ColumnMode = ColumnMode.Force; + @Input() headerHeight = 50; + @Input() footerHeight = 50; + @Input() rowHeight: number | string = 'auto'; + @Input() messages: StaticTableMessages; + @Input() externalPaging = true; + @Input() count = 0; + @Input() offset = 0; + @Input() limit: number = undefined; + @Input() propertySelectable: boolean = true; + + @Input() hideModeSelection: boolean = false; + + public _defaultSort: any; + @Input() set defaultSort(input: string[]) { + if (input && input.length > 0) { + this._defaultSort = input.map(x => { + let sortProp: String = x; + let sortDir: String = SortDirection.Ascending; + if (x.startsWith('+')) { + sortProp = x.substring(1); + sortDir = SortDirection.Ascending; + } else if (x.startsWith('-')) { + sortProp = x.substring(1); + sortDir = SortDirection.Descending; + } + return { prop: sortProp, dir: sortDir }; + }); + } else { + this._defaultSort = undefined; + } + } + @Input() loadingIndicator = false; + @Input() externalSorting = false; + @Input() initialMode: HybridListingMode; + + @Output() rowActivated: EventEmitter = new EventEmitter(); + @Output() pageLoad: EventEmitter = new EventEmitter(); + @Output() columnSort: EventEmitter = new EventEmitter(); + @Output() columnsChanged: EventEmitter = new EventEmitter(); + @Output() modeChanged: EventEmitter = new EventEmitter(); + + public internalColumns: TableColumn[]; + @Input() visibleColumns: TableColumnProp[]; + private columnSortKeys: Map; + + protected sortableListColumns: {property: TableColumnProp, name: string}[]; + protected availableColumns: {property: TableColumnProp, name: string}[]; + protected columnSelections: Set; + + + + + + SelectionType = SelectionType; + protected selected=[] + + + + get rowIdentity(){ + return this.batchActions?.rowIdentity ?? this.trackBy ?? this._rowIdentity; + } + + HybridListingMode = HybridListingMode; + SortDirection = SortDirection; + protected mode: HybridListingMode = HybridListingMode.Table; + constructor( + private collectionUtils: CollectionUtils, + private language: TranslateService, + ) { + super(); + } + + ngOnChanges(changes: SimpleChanges) { + if (changes['columns']) { + this.refreshColumnDefinitionData(); + } + if (changes['visibleColumns'] && !changes['visibleColumns'].isFirstChange()) { + this.refreshColumnDefinitionData(); + } + + const modeChanges = changes[nameof(x => x.initialMode)]; + if(modeChanges?.isFirstChange){ + if(![null, undefined].includes(this.initialMode)){ + this.mode = this.initialMode; + } + } + + } + + + ngOnDestroy(): void { + super.ngOnDestroy(); + this.resizeObserver?.unobserve(this.wrapperCard.nativeElement) + this.resizeObserver?.disconnect(); + this.resizeObserver = null; + this.resizeSubject$.complete(); + } + + private resizeObserver: ResizeObserver; + private resizeSubject$: Subject; + + ngOnInit() { + this.setTableMessages(); + + this.language.onLangChange.pipe(takeUntil(this._destroyed)).subscribe(event => { + this.setTableMessages(); + this.refreshColumnDefinitionData(); + }); + + this.ngZone.runOutsideAngular(() => { + this.resizeSubject$ = new Subject; + + this.resizeSubject$.pipe( + debounceTime(500), + filter(() => !!this.table) + ).subscribe(() => { + this.table.recalculate(); + this.changeDetectorRef.detectChanges(); + }) + + + this.resizeObserver = new ResizeObserver( + (resize) => { + this.resizeSubject$.next(); + }, + ) + this.resizeObserver.observe(this.wrapperCard.nativeElement) + }) + + + } + + + public setModeSilently(mode: HybridListingMode):void{ + this.mode = mode; + } + + public getMode(): HybridListingMode{ + return this.mode; + } + + public isColumnSelected = (columnProp: string) => !!this.columnSelections?.has(columnProp) + + protected onListItemActivated(row: any){ + this.rowActivated.emit({ + type: 'click', + row: row, + } as any); + } + + protected emptySelections(): void{ + this.selected = []; + } + + protected toggleMode(): void{ + if(!this.listItemTemplate && !this.cardItemTemplate){ + this.mode = HybridListingMode.Table; + this.modeChanged.emit(this.mode); + return; + } + + + switch(this.mode){ + case HybridListingMode.Table:{ + if(this.listItemTemplate){ + this.mode = HybridListingMode.List; + this.modeChanged.emit(this.mode); + return; + } + } + case HybridListingMode.List:{ + if(this.cardItemTemplate){ + this.mode = HybridListingMode.Card; + this.modeChanged.emit(this.mode); + return; + } + } + case HybridListingMode.Card: + default: { + this.mode = HybridListingMode.Table; + this.modeChanged.emit(this.mode); + return; + } + } + + + } + + + onsomePage(event: PageEvent){ + if(!event){ + return; + } + this.pageLoad.emit({ + count: event.length, + pageSize: event.pageSize, + limit: event.pageSize, + offset: event.pageIndex, + }); + } + + protected isListingItemSelected(item: any){ + return !!this.selected?.find(x => this.rowIdentity && (this.rowIdentity(item) === this.rowIdentity(x))); + } + + onSelectionListChange(event: MatCheckboxChange, item: any){ + this.selected = this.selected?.filter(x => this.rowIdentity && (this.rowIdentity(item) !== this.rowIdentity(x))) + if(event.checked){ + this.selected = [ ...(this.selected ?? []), item].filter(x => x); + } + } + + private setTableMessages() { + this.messages = { + emptyMessage: this.language.instant('COMMONS.LISTING-COMPONENT.MESSAGE.EMPTY'), + totalMessage: this.language.instant('COMMONS.LISTING-COMPONENT.MESSAGE.TOTAL'), + selectedMessage: this.language.instant('COMMONS.LISTING-COMPONENT.MESSAGE.SELECTED') + }; + } + + private refreshColumnDefinitionData() { + const visibleColumns = this.getVisibleColumns(); + this.internalColumns = this.columns.filter(x => x.alwaysShown || visibleColumns.includes(x.prop)).map(x => { + const item = { + checkboxable: x.checkboxable, + frozenLeft: x.frozenLeft, + frozenRight: x.frozenRight, + flexGrow: x.flexGrow, + minWidth: x.minWidth, + maxWidth: x.maxWidth, + width: x.width, + resizeable: x.resizeable, + comparator: x.comparator, + pipe: x.pipe, + sortable: x.sortable, + draggable: x.draggable, + canAutoResize: x.canAutoResize, + name: x.languageName ? this.language.instant(x.languageName) : x.name, + prop: x.prop, + cellTemplate: x.cellTemplate, + headerTemplate: x.headerTemplate, + cellClass: x.cellClass, + headerClass: x.headerClass, + headerCheckboxable: x.headerCheckboxable, + summaryFunc: x.summaryFunc, + summaryTemplate: x.summaryTemplate + } as TableColumn; + + if (x.valueFunction) { + item.cellTemplate = this.functionValueTemplate; + item['valueFunction'] = x.valueFunction; + } + return item; + }); + this.internalColumns = [ this.batchActions?.rowIdentity && { + checkboxable: true, + sortable: false, + width: 30, + maxWidth: 30, + canAutoRisize: false, + headerCheckboxable: false + } ,...this.internalColumns].filter(x => !!x) + this.columnSortKeys = new Map(this.columns.map(buildColumnSortKeys)); + + this.availableColumns = this.columns?.filter(x => !x?.alwaysShown).map(x => ({ + name: x.languageName ? this.language.instant(x.languageName) : x.name, + property: x.prop + })); + this.sortableListColumns = this.internalColumns.filter(x => x?.sortable).map(x => ({ + name: x.name, + property: x.prop + })) + this.columnSelections = new Set(visibleColumns); + } + + + protected getPropertyName(string): string{ + return this.sortableListColumns?.find(x => x.property === string)?.name; + } + + protected onColumnSelectionChange(event: MatCheckboxChange, property: TableColumnProp){ + + if(event.checked){ + this.columnSelections.add(property) + }else{ + this.columnSelections.delete(property) + } + this.visibleColumns = [...this.columnSelections].filter(x => x); + this.refreshColumnDefinitionData(); + const visibleColumns = this.getVisibleColumns(); + this.columnSelections = new Set(visibleColumns); + this.columnsChanged.emit({ + properties: visibleColumns + }) + } + onRowActivated(event) { + if (this.rowActivated && event) { + this.rowActivated.emit({ + type: event.type, + event: event.event, + row: event.row, + column: event.column, + value: event.value, + cellElement: event.cellElement, + rowElement: event.rowElement, + }); + } + } + + onColumnSort(event) { + if (this.columnSort && event) { + const sortDescriptorsCollection: SortDescriptor[][] = event.sorts.map(x => getColumnSortDescriptors(x, this.columnSortKeys.get(x.prop))); + const sortEvent = { + column: event.column, + previousValue: event.prevValue, + newValue: event.newValue, + sortDescriptors: this.collectionUtils.flatten(sortDescriptorsCollection) + }; + this.columnSort.emit(sortEvent); + } + } + + protected toggleSortListViewSort(): void{ + if(this.columnSort){ + const previousSort = this._defaultSort?.[0]?.dir as SortDirection; + const sortField = this._defaultSort?.[0]?.prop as string; + if(!sortField){ + return ; + } + + switch(previousSort){ + case SortDirection.Ascending:{ + this.columnSort.emit({ + newValue: SortDirection.Descending, + previousValue: SortDirection.Ascending, + sortDescriptors: [{ + direction: SortDirection.Descending, + property: sortField + }] + }) + return; + } + case SortDirection.Descending:{ + this.columnSort.emit({ + newValue: SortDirection.Ascending, + previousValue: SortDirection.Descending, + sortDescriptors: [{ + direction: SortDirection.Ascending, + property: sortField + }] + }) + return; + } + default: return; + } + } + } + + protected onListViewSort(byProperty: string): void{ + + if(!byProperty){ + return; + } + + if(!this.columnSort){ + return; + } + + + + + const previousSort = this._defaultSort?.[0]?.dir; + const sort = previousSort ?? SortDirection.Descending; + + + this.columnSort.emit({ + newValue: sort, + previousValue: previousSort, + sortDescriptors:[ + { + direction: sort, + property: byProperty + } + ] + }) + + + } + + + getVisibleColumns(): TableColumnProp[] { + if (!this.visibleColumns || this.visibleColumns.length === 0) { return this.columns.map(x => x.prop).filter(x => x); } + return this.visibleColumns; + } +} + + +export enum TableClass { + Material = 'material', + Bootstrap = 'bootstrap', + Dark = 'dark' +} + +export enum ColumnMode { + Standard = 'standard', + Flex = 'flex', + Force = 'force' +} + +export interface RowActivateEvent { + type: 'keydown' | 'click' | 'dblclick' | 'mouseenter'; + event: MouseEvent; + row: T; + column: ColumnDefinition; + value: any; + cellElement: Element; + rowElement: Element; +} + +export interface PageLoadEvent { + count: number; + pageSize: number; + limit: number; + offset: number; +} + +export interface ColumnSortEvent { + sortDescriptors: SortDescriptor[]; + column?: ColumnDefinition; + previousValue: SortDirection; + newValue: SortDirection; +} + +export interface ColumnsChangedEvent { + properties: TableColumnProp[]; +} + +export interface SortDescriptor { + direction: SortDirection; + property: string; +} + +export enum SortDirection { + Ascending = 'asc', + Descending = 'desc' +} + + +export declare type TableColumnProp = string | number; +export interface ColumnDefinition { + /** + * Determines if column is checkbox + * + * @type {boolean} + * @memberOf TableColumn + */ + checkboxable?: boolean; + /** + * Determines if the column is frozen to the left + * + * @type {boolean} + * @memberOf TableColumn + */ + frozenLeft?: boolean; + /** + * Determines if the column is frozen to the right + * + * @type {boolean} + * @memberOf TableColumn + */ + frozenRight?: boolean; + /** + * The grow factor relative to other columns. Same as the flex-grow + * API from http =//www.w3.org/TR/css3-flexbox/. Basically; + * take any available extra width and distribute it proportionally + * according to all columns' flexGrow values. + * + * @type {number} + * @memberOf TableColumn + */ + flexGrow?: number; + /** + * Min width of the column + * + * @type {number} + * @memberOf TableColumn + */ + minWidth?: number; + /** + * Max width of the column + * + * @type {number} + * @memberOf TableColumn + */ + maxWidth?: number; + /** + * The default width of the column, in pixels + * + * @type {number} + * @memberOf TableColumn + */ + width?: number; + /** + * Can the column be resized + * + * @type {boolean} + * @memberOf TableColumn + */ + resizeable?: boolean; + /** + * Custom sort comparator + * + * @type {*} + * @memberOf TableColumn + */ + comparator?: any; + /** + * Custom pipe transforms + * + * @type {PipeTransform} + * @memberOf TableColumn + */ + pipe?: PipeTransform; + /** + * Can the column be sorted + * + * @type {boolean} + * @memberOf TableColumn + */ + sortable?: boolean; + /** + * Can the column be re-arranged by dragging + * + * @type {boolean} + * @memberOf TableColumn + */ + /** + * Override for the sort property that will be used (default is column.prop) + * + * @type {string} + * @memberOf TableColumn + */ + sortKeys?: string[]; + draggable?: boolean; + /** + * Whether the column can automatically resize to fill space in the table. + * + * @type {boolean} + * @memberOf TableColumn + */ + canAutoResize?: boolean; + /** + * Column name or label + * + * @type {string} + * @memberOf TableColumn + */ + name?: string; + /** + * Language Key Column name or label + * + * @type {string} + * @memberOf TableColumn + */ + languageName?: string; + /** + * Property to bind to the row. Example: + * + * `someField` or `some.field.nested`, 0 (numeric) + * + * If left blank, will use the name as camel case conversion + * + * @type {TableColumnProp} + * @memberOf TableColumn + */ + prop?: TableColumnProp; + /** + * Cell template ref + * + * @type {*} + * @memberOf TableColumn + */ + cellTemplate?: any; + /** + * Header template ref + * + * @type {*} + * @memberOf TableColumn + */ + headerTemplate?: any; + /** + * CSS Classes for the cell + * + * + * @memberOf TableColumn + */ + cellClass?: string | ((data: any) => string | any); + /** + * CSS classes for the header + * + * + * @memberOf TableColumn + */ + headerClass?: string | ((data: any) => string | any); + /** + * Header checkbox enabled + * + * @type {boolean} + * @memberOf TableColumn + */ + headerCheckboxable?: boolean; + /** + * Summary function + * + * @type {(cells: any[]) => any} + * @memberOf TableColumn + */ + summaryFunc?: (cells: any[]) => any; + /** + * Summary cell template ref + * + * @type {*} + * @memberOf TableColumn + */ + summaryTemplate?: any; + alwaysShown?: boolean; + valueFunction?: (cell: any) => any; +} +export interface StaticTableMessages { + emptyMessage: string; + totalMessage: string; + selectedMessage: string; +} + +function getColumnSortDescriptors(internalSortDescriptor, sortKeys: string[]): SortDescriptor[] { + const direction = internalSortDescriptor.dir; + return sortKeys.map(x => ({ + direction: direction, + property: x + })); +} + +function buildColumnSortKeys(column: ColumnDefinition): [TableColumnProp, string[]] { + return [column.prop, getColumnSortKeys(column)]; +} + +function getColumnSortKeys(column: ColumnDefinition): string[] { + const sortKeys = extractSortKeys(column.sortKeys); + if (sortKeys.length === 0) { sortKeys.push(String(column.prop)); } + return sortKeys; +} + +function extractSortKeys(sortKeys: string[]): string[] { + sortKeys = sortKeys || []; + return sortKeys.filter(x => Boolean(x)); +} + + + +export enum HybridListingMode{ + Table, + List, + Card +} diff --git a/dmp-frontend/src/common/modules/hybrid-listing/hybrid-listing.module.ts b/dmp-frontend/src/common/modules/hybrid-listing/hybrid-listing.module.ts new file mode 100644 index 000000000..3080be171 --- /dev/null +++ b/dmp-frontend/src/common/modules/hybrid-listing/hybrid-listing.module.ts @@ -0,0 +1,43 @@ +import { NgModule } from '@angular/core'; +import { FormsModule } from '@angular/forms'; +import { BatchActionsDirective } from '@common/modules/hybrid-listing/directives/batch-actions.directive'; +import { HybridListingFiltersDirective } from '@common/modules/hybrid-listing/directives/hybrid-listing-filters.directive'; +import { UserFilterSettingsDirective } from '@common/modules/hybrid-listing/directives/user-filter-settings.directive'; +import { HybridListingComponent } from '@common/modules/hybrid-listing/hybrid-listing.component'; +import { CommonUiModule } from '@common/ui/common-ui.module'; +import { NgxDatatableModule } from '@swimlane/ngx-datatable'; +import { MatPaginatorModule } from '@angular/material/paginator' +import { DownloadListingReportDirective } from '@common/modules/hybrid-listing/directives/download-listing-report.directive'; +import { NullifyValuePipe } from './pipes/nullify-value.pipe'; +import { FormattingModule } from '@app/core/formatting.module'; + +@NgModule({ + imports: [ + CommonUiModule, + FormsModule, + FormattingModule, + NgxDatatableModule, + MatPaginatorModule + ], + declarations: [ + HybridListingComponent, + BatchActionsDirective, + UserFilterSettingsDirective, + HybridListingFiltersDirective, + DownloadListingReportDirective, + NullifyValuePipe + ], + exports: [ + HybridListingComponent, + BatchActionsDirective, + UserFilterSettingsDirective, + HybridListingFiltersDirective, + DownloadListingReportDirective, + NullifyValuePipe + ], + providers:[ + ] +}) +export class HybridListingModule { + constructor() { } +} diff --git a/dmp-frontend/src/common/modules/hybrid-listing/pipes/nullify-value.pipe.ts b/dmp-frontend/src/common/modules/hybrid-listing/pipes/nullify-value.pipe.ts new file mode 100644 index 000000000..44122cfd3 --- /dev/null +++ b/dmp-frontend/src/common/modules/hybrid-listing/pipes/nullify-value.pipe.ts @@ -0,0 +1,19 @@ +import { Pipe, PipeTransform } from '@angular/core'; + + +const nullSet = new Set([null, undefined]); + + +@Pipe({ + name: 'nullifyValue' +}) +export class NullifyValuePipe implements PipeTransform { + + transform(value: any, returnSpace: boolean): any { + if(!nullSet.has(value) || returnSpace){ + return value; + } + return '-' + } + +} diff --git a/dmp-frontend/src/common/modules/hybrid-listing/pipes/visible-fields.pipe.ts b/dmp-frontend/src/common/modules/hybrid-listing/pipes/visible-fields.pipe.ts new file mode 100644 index 000000000..aa570cbec --- /dev/null +++ b/dmp-frontend/src/common/modules/hybrid-listing/pipes/visible-fields.pipe.ts @@ -0,0 +1,58 @@ +import { Pipe, PipeTransform } from '@angular/core'; +import { TableColumnProp } from '@common/modules/hybrid-listing/hybrid-listing.component'; +import { string } from 'yargs'; + + +@Pipe({ + name: 'visibleFields' +}) +export class VisibleFieldsPipe implements PipeTransform { + + transform(value: Record, visibleColumns: TableColumnProp[]): Record { + + + + + if(!visibleColumns || !value){ + return value; + } + + if(!(typeof value === 'object')){ + return value; + } + + const clone = JSON.parse(JSON.stringify(value)); + + this.cleanUpRecursively(clone, '', visibleColumns); + + return clone; + + } + + + private cleanUpRecursively(target: any, currentPath: string, whitelisted: TableColumnProp[]){ + + + if(!target || !whitelisted){ + return; + } + + if(!(typeof target === 'object')){ + return + } + + for(const [key,value] of Object.entries(target)){ + + const nextPath = `${currentPath}${key}`; + + const isWhitelisted = whitelisted.some(x => (x === nextPath) || (typeof x === 'string' && x.startsWith(nextPath))); + + if(!isWhitelisted){ + delete target[key]; + continue; + } + this.cleanUpRecursively(value, `${nextPath}.`, whitelisted); + } + } + +} diff --git a/dmp-frontend/src/common/modules/notification/ui-notification-service.ts b/dmp-frontend/src/common/modules/notification/ui-notification-service.ts deleted file mode 100644 index 3219daa45..000000000 --- a/dmp-frontend/src/common/modules/notification/ui-notification-service.ts +++ /dev/null @@ -1,60 +0,0 @@ -import { Injectable } from '@angular/core'; -import { Observable, Subject } from 'rxjs'; - -@Injectable() -export class UiNotificationService { - - private notificationSubject = new Subject(); - - constructor() { - } - - public snackBarNotification(message: string, level: SnackBarNotificationLevel, duration: number = 5000) { - const notification: SnackBarNotification = new SnackBarNotification(); - notification.level = level; - notification.message = message; - notification.duration = duration; - this.notificationSubject.next(notification); - } - - public popupNotification(title: string, message: string) { - const notification: PopupNotification = new PopupNotification(); - notification.title = title; - notification.message = message; - this.notificationSubject.next(notification); - } - - public getNotificationObservable(): Observable { - return this.notificationSubject.asObservable(); - } -} - -export enum UiNotificationType { - SnackBar = 0, - Popup = 1 -} - -export interface UiNotification { - type: UiNotificationType; - -} - -export enum SnackBarNotificationLevel { - Info = 0, - Warning = 1, - Success = 2, - Error = 3 -} - -export class SnackBarNotification implements UiNotification { - type: UiNotificationType = UiNotificationType.SnackBar; - message: string; - level: SnackBarNotificationLevel; - duration: number; -} - -export class PopupNotification implements UiNotification { - type: UiNotificationType = UiNotificationType.Popup; - message: string; - title: string; -} diff --git a/dmp-frontend/src/common/modules/text-filter/expandable-search-field/expandable-search-field.component.html b/dmp-frontend/src/common/modules/text-filter/expandable-search-field/expandable-search-field.component.html new file mode 100644 index 000000000..e06cfb759 --- /dev/null +++ b/dmp-frontend/src/common/modules/text-filter/expandable-search-field/expandable-search-field.component.html @@ -0,0 +1,6 @@ + + + + \ No newline at end of file diff --git a/dmp-frontend/src/common/modules/text-filter/expandable-search-field/expandable-search-field.component.scss b/dmp-frontend/src/common/modules/text-filter/expandable-search-field/expandable-search-field.component.scss new file mode 100644 index 000000000..ef3720738 --- /dev/null +++ b/dmp-frontend/src/common/modules/text-filter/expandable-search-field/expandable-search-field.component.scss @@ -0,0 +1,23 @@ +:host::ng-deep{ + + .mdc-notched-outline{ + transition: 600ms opacity ease-out; + } + .mat-mdc-form-field-infix{ + transition: 600ms width ease-out; + } + + + + .hidden-element{ + .mat-mdc-text-field-wrapper{ + padding: 0px; + } + .mat-mdc-form-field-infix{ + width: 0px !important; + } + .mdc-notched-outline{ + opacity: 0; + } + } +} \ No newline at end of file diff --git a/dmp-frontend/src/common/modules/text-filter/expandable-search-field/expandable-search-field.component.ts b/dmp-frontend/src/common/modules/text-filter/expandable-search-field/expandable-search-field.component.ts new file mode 100644 index 000000000..0e582af76 --- /dev/null +++ b/dmp-frontend/src/common/modules/text-filter/expandable-search-field/expandable-search-field.component.ts @@ -0,0 +1,83 @@ + +import { Component, EventEmitter, Input, OnChanges, OnInit, Output, SimpleChanges } from '@angular/core'; +import { BaseComponent } from '@common/base/base.component'; +import { FilterService } from '@common/modules/text-filter/filter-service'; +import { TranslateService } from '@ngx-translate/core'; +import { Subject } from 'rxjs'; +import { debounceTime, shareReplay, startWith, takeUntil } from 'rxjs/operators'; + +@Component({ + selector: 'app-expandable-search-field', + templateUrl: './expandable-search-field.component.html', + styleUrls: ['./expandable-search-field.component.scss'] +}) +export class ExpandableSearchFieldComponent extends BaseComponent implements OnInit, OnChanges { + @Input() typeaheadMS = 700; + @Input() disableTransform = false; + @Input() placeholder: string; + @Input() value: string; + @Output() valueChange = new EventEmitter(); + + private valueSubject: Subject; + + private _inputValue: string; + public get inputValue(): string { return this._inputValue; } + public set inputValue(value: string) { + this._inputValue = value; + this.valueSubject.next(this.disableTransform ? value : this.filterService.transformLike(value)); + } + + constructor( + private language: TranslateService, + private filterService: FilterService + ) { + super(); + } + + ngOnInit() { + this.valueSubject = new Subject(); + this.valueSubject.pipe( + debounceTime(this.typeaheadMS), + takeUntil(this._destroyed)) + .subscribe(value => { + if (value === '') { value = null; } + if (this.value !== value) { + this.value = value; + this.valueChange.emit(value); + } + }); + } + + + private subject$ = new Subject(); + + + + protected a$ = this.subject$.asObservable().pipe( + debounceTime(200), + // delayWhen(x => interval( x ? 0: 3000).pipe(take(1))), + takeUntil(this._destroyed), + shareReplay(), + startWith(false) + ); + + + protected onOpen(){ + this.subject$.next(true); + } + + protected onClose(){ + this.subject$.next(false); + } + + + ngOnChanges(changes: SimpleChanges): void { + if (changes['value']) { + this._inputValue = this.filterService.reverseLikeTransformation(this.value); + } + } + + getPlaceholder(): string { + return this.placeholder ? this.language.instant(this.placeholder) : this.language.instant('COMMONS.TEXT-FILTER.LIKE'); + } +} diff --git a/dmp-frontend/src/common/modules/text-filter/filter-service.ts b/dmp-frontend/src/common/modules/text-filter/filter-service.ts new file mode 100644 index 000000000..69d62b023 --- /dev/null +++ b/dmp-frontend/src/common/modules/text-filter/filter-service.ts @@ -0,0 +1,40 @@ +import { Injectable } from '@angular/core'; + +@Injectable() +export class FilterService { + + constructor() { + + } + + transformLike(value: string): string { + if (!value) { + return undefined; + } else { + // We replace * with %. We also escape the _ operator. If % or _ is found in the query, we suppose that the user entered it on purpose. + // Otherwise we append the % operator at the end. + let transformedValue = value.split('*').join('%'); + if (!transformedValue.includes('%')) { transformedValue = transformedValue + '%'; } + transformedValue = transformedValue.split('_').join('\_'); + return transformedValue; + } + } + + reverseLikeTransformation(value: string): string { + if (!value) { + return undefined; + } else { + let transformedValue = this.replaceAll(value, '\\_', '_'); + if (transformedValue.endsWith('%')) { transformedValue = transformedValue.substring(0, transformedValue.length - 1); } + return transformedValue; + } + } + + private replaceAll(str: string, find: string, replace: string) { + return str.replace(new RegExp(this.escapeRegExp(find), 'g'), replace); + } + + private escapeRegExp(str: string) { + return str.replace(/([.*+?^=!:${}()|\[\]\/\\])/g, '\\$1'); + } +} diff --git a/dmp-frontend/src/common/modules/text-filter/text-filter.component.html b/dmp-frontend/src/common/modules/text-filter/text-filter.component.html new file mode 100644 index 000000000..0e046fc20 --- /dev/null +++ b/dmp-frontend/src/common/modules/text-filter/text-filter.component.html @@ -0,0 +1,4 @@ + + {{getPlaceholder()}} + + diff --git a/dmp-frontend/src/common/modules/text-filter/text-filter.component.scss b/dmp-frontend/src/common/modules/text-filter/text-filter.component.scss new file mode 100644 index 000000000..a2527e2ea --- /dev/null +++ b/dmp-frontend/src/common/modules/text-filter/text-filter.component.scss @@ -0,0 +1,3 @@ +.search-box { + color: #3f51b5; +} diff --git a/dmp-frontend/src/common/modules/text-filter/text-filter.component.ts b/dmp-frontend/src/common/modules/text-filter/text-filter.component.ts new file mode 100644 index 000000000..52388ed5a --- /dev/null +++ b/dmp-frontend/src/common/modules/text-filter/text-filter.component.ts @@ -0,0 +1,60 @@ + +import { Component, EventEmitter, Input, OnChanges, OnInit, Output, SimpleChanges } from '@angular/core'; +import { BaseComponent } from '@common/base/base.component'; +import { FilterService } from '@common/modules/text-filter/filter-service'; +import { TranslateService } from '@ngx-translate/core'; +import { Subject } from 'rxjs'; +import { debounceTime, takeUntil } from 'rxjs/operators'; + +@Component({ + selector: 'app-text-filter', + templateUrl: './text-filter.component.html', + styleUrls: ['./text-filter.component.scss'] +}) +export class TextFilterComponent extends BaseComponent implements OnInit, OnChanges { + @Input() typeaheadMS = 700; + @Input() disableTransform = false; + @Input() placeholder: string; + @Input() value: string; + @Output() valueChange = new EventEmitter(); + + private valueSubject: Subject; + + private _inputValue: string; + public get inputValue(): string { return this._inputValue; } + public set inputValue(value: string) { + this._inputValue = value; + this.valueSubject.next(this.disableTransform ? value : this.filterService.transformLike(value)); + } + + constructor( + private language: TranslateService, + private filterService: FilterService + ) { + super(); + } + + ngOnInit() { + this.valueSubject = new Subject(); + this.valueSubject.pipe( + debounceTime(this.typeaheadMS), + takeUntil(this._destroyed)) + .subscribe(value => { + if (value === '') { value = null; } + if (this.value !== value) { + this.value = value; + this.valueChange.emit(value); + } + }); + } + + ngOnChanges(changes: SimpleChanges): void { + if (changes['value']) { + this._inputValue = this.filterService.reverseLikeTransformation(this.value); + } + } + + getPlaceholder(): string { + return this.placeholder ? this.language.instant(this.placeholder) : this.language.instant('COMMONS.TEXT-FILTER.LIKE'); + } +} diff --git a/dmp-frontend/src/common/modules/text-filter/text-filter.module.ts b/dmp-frontend/src/common/modules/text-filter/text-filter.module.ts new file mode 100644 index 000000000..2a6bf1bc4 --- /dev/null +++ b/dmp-frontend/src/common/modules/text-filter/text-filter.module.ts @@ -0,0 +1,23 @@ +import { NgModule } from '@angular/core'; +import { FormsModule } from '@angular/forms'; +import { ExpandableSearchFieldComponent } from '@common/modules/text-filter/expandable-search-field/expandable-search-field.component'; +import { TextFilterComponent } from '@common/modules/text-filter/text-filter.component'; +import { CommonUiModule } from '@common/ui/common-ui.module'; + +@NgModule({ + imports: [ + CommonUiModule, + FormsModule + ], + declarations: [ + TextFilterComponent, + ExpandableSearchFieldComponent + ], + exports: [ + TextFilterComponent, + ExpandableSearchFieldComponent + ] +}) +export class TextFilterModule { + constructor() { } +} diff --git a/dmp-frontend/src/common/modules/user-settings/user-settings-picker/user-settings-picker.component.html b/dmp-frontend/src/common/modules/user-settings/user-settings-picker/user-settings-picker.component.html new file mode 100644 index 000000000..b72771a24 --- /dev/null +++ b/dmp-frontend/src/common/modules/user-settings/user-settings-picker/user-settings-picker.component.html @@ -0,0 +1,43 @@ + + + + + + + + +
+ + + + + +
diff --git a/dmp-frontend/src/common/modules/user-settings/user-settings-picker/user-settings-picker.component.scss b/dmp-frontend/src/common/modules/user-settings/user-settings-picker/user-settings-picker.component.scss new file mode 100644 index 000000000..e69de29bb diff --git a/dmp-frontend/src/common/modules/user-settings/user-settings-picker/user-settings-picker.component.ts b/dmp-frontend/src/common/modules/user-settings/user-settings-picker/user-settings-picker.component.ts new file mode 100644 index 000000000..564075b95 --- /dev/null +++ b/dmp-frontend/src/common/modules/user-settings/user-settings-picker/user-settings-picker.component.ts @@ -0,0 +1,193 @@ +import { Component, EventEmitter, Input, OnChanges, OnInit, Output, SimpleChanges } from '@angular/core'; +import { MatDialog } from '@angular/material/dialog'; +import { UserSettingsInformation } from '@app/core/model/user-settings/user-settings.model'; +import { UserSetting, UserSettingsService } from '@app/core/services/user-settings/user-settings.service'; +import { BaseComponent } from '@common/base/base.component'; +import { ConfirmationDialogComponent } from '@common/modules/confirmation-dialog/confirmation-dialog.component'; +import { Guid } from '@common/types/guid'; +import { TranslateService } from '@ngx-translate/core'; +import { isNullOrUndefined } from '@swimlane/ngx-datatable'; +import { takeUntil } from 'rxjs/operators'; +import { nameof } from 'ts-simple-nameof'; + +@Component({ + selector: 'app-user-settings-picker', + templateUrl: './user-settings-picker.component.html', + styleUrls: ['./user-settings-picker.component.scss'] +}) +export class UserSettingsPickerComponent extends BaseComponent implements OnInit, OnChanges { + + @Input() key: UserSettingsInformation; + @Input() userPreference: any; + @Input() autoSelectUserSettings: boolean; + @Output() onSettingSelected = new EventEmitter(); + + settings: any; + availableUserSettings: UserSetting[] = []; + currentUserSetting: UserSetting; + + constructor( + private userSettingsService: UserSettingsService, + private dialog: MatDialog, + private language: TranslateService + ) { super(); } + + ngOnInit() { + + this.userSettingsService.getUserSettingUpdatedObservable().pipe(takeUntil(this._destroyed)).subscribe(key => { + if (key === this.key.key) { this.getSettings(); } + }); + } + + ngOnChanges(changes: SimpleChanges) { + + + const keyChange = changes[nameof(x => x.key)]; + if (keyChange) { + this.settings = null; + this.availableUserSettings = []; + this.currentUserSetting = null; + + if (this.key?.key) { + this.getSettings(); + + } + + } + + if (changes['autoSelectUserSettings']) { + if (changes['autoSelectUserSettings'].currentValue) { + if (this.currentUserSetting == null && this.settings != null) { + this.currentUserSetting = this.settings.defaultSetting; + this.onSettingSelected.emit(this.currentUserSetting ? this.currentUserSetting.value : null); + } + } + } + } + + public resetToDraft(): void { + this.currentUserSetting = null; + } + + private getSettings() { + this.userSettingsService.get(this.key).pipe(takeUntil(this._destroyed)).subscribe(s => { + if (s != null) { + const settings = JSON.parse(JSON.stringify(s)); + this.settings = settings; + this.availableUserSettings = settings.settings; + if (this.autoSelectUserSettings) { + this.currentUserSetting = settings.defaultSetting; + } else { + if (this.currentUserSetting) { + const filterIndex = this.availableUserSettings.findIndex(x => x.name === this.currentUserSetting.name); + this.currentUserSetting = this.availableUserSettings[filterIndex]; + } + } + } else { + this.settings = null; + this.currentUserSetting = null; + this.availableUserSettings = []; + } + if (this.autoSelectUserSettings) { this.onSettingSelected.emit(s != null ? (this.currentUserSetting ? this.currentUserSetting.value : null) : null); } + }); + } + + getSettingName(setting: UserSetting) { + return !isNullOrUndefined(setting?.name) ? setting.name : 'Default'; + } + + settingSelected(event: UserSetting) { + + const setting = this.availableUserSettings.find(x => x.id === event.id); + if (setting === null) { return; } + + // give time to close menu + setTimeout(() => { + //Persist the active user setting + this.onSettingSelected.emit(setting.value); + this.userSettingsService.set(setting, true, this.key); + this.currentUserSetting = event; + }, 100) + } + + renameCurrentUserSetting(): void { + // this.dialog.open( + // FilterNameDialogComponent, + // { + // maxWidth: '600px', + // maxHeight: '400px', + // restoreFocus: false, + // data: { name: this.currentUserSetting.name}, + // disableClose: false + // } + // ).afterClosed() + // .pipe( + // filter(x => !!x), + // takeUntil(this._destroyed) + // ) + // .subscribe(newName => { + // this.currentUserSetting.name = newName; + // this.persistLookupChangesManually(this.currentUserSetting, true); + // }) + } + + settingDeleted(value: Guid = this.currentUserSetting.id) { + // const value = this.currentUserSetting.id; + if (value) { + const dialogRef = this.dialog.open(ConfirmationDialogComponent, { + maxWidth: '400px', + restoreFocus: false, + data: { + message: this.language.instant('GENERAL.CONFIRMATION-DIALOG.DELETE-USER-SETTING-PROFILE'), + confirmButton: this.language.instant('GENERAL.CONFIRMATION-DIALOG.ACTIONS.CONFIRMATION'), + cancelButton: this.language.instant('GENERAL.CONFIRMATION-DIALOG.ACTIONS.CANCELATION') + } + }); + dialogRef.afterClosed().pipe(takeUntil(this._destroyed)).subscribe(result => { + if (result) { + this.userSettingsService.remove(value, this.key); + } + }); + } + /* this.userSettingsService.remove(this.currentUserSetting.id, this.key); */ + } + + saveFilter() { + // const saveDialogRef = this.dialog.open(FilterNameDialogComponent, { + // maxWidth: '600px', + // maxHeight: '400px', + // restoreFocus: false, + // data: { name: this.currentUserSetting ? this.currentUserSetting.name : '' }, + // disableClose: false + // }); + + // saveDialogRef.afterClosed().subscribe(result => { + // if (result) { this.createNewFilter(result); } + // }); + } + + + private persistLookupChangesManually(setting: UserSetting, isDefault: boolean) { + this.userSettingsService.set(setting, isDefault, this.key); + } + + private createNewFilter(name: string) { + let setting: UserSetting; + setting = this.currentUserSetting ? JSON.parse(JSON.stringify(this.currentUserSetting)) : {}; + setting.value = this.userPreference; + setting.id = null; + setting.hash = null; + setting.name = name; + setting.isDefault = true; + setting.createdAt = null; + setting.updatedAt = null; + setting.userId = null; + this.currentUserSetting = setting; + + this.persistLookupChangesManually(this.currentUserSetting, true); + } + + compareFn(c1: UserSetting, c2: UserSetting): boolean { + return c1 && c2 ? c1.id === c2.id : c1 === c2; + } +} diff --git a/dmp-frontend/src/common/modules/user-settings/user-settings-selector/user-settings-selector.component.html b/dmp-frontend/src/common/modules/user-settings/user-settings-selector/user-settings-selector.component.html new file mode 100644 index 000000000..b6d80abd4 --- /dev/null +++ b/dmp-frontend/src/common/modules/user-settings/user-settings-selector/user-settings-selector.component.html @@ -0,0 +1,23 @@ +
+ + {{'COMMONS.CUSTOM-USER-SETTINGS.LABEL' | translate}} + + {{getSettingName(setting)}} + + +
+ +
+
+ +
+
+ +
+
diff --git a/dmp-frontend/src/common/modules/user-settings/user-settings-selector/user-settings-selector.component.scss b/dmp-frontend/src/common/modules/user-settings/user-settings-selector/user-settings-selector.component.scss new file mode 100644 index 000000000..aee72c3ea --- /dev/null +++ b/dmp-frontend/src/common/modules/user-settings/user-settings-selector/user-settings-selector.component.scss @@ -0,0 +1,24 @@ +.document-listing-filters { + margin: 0 0; + + .filter-actions { + display: flex; + } + + .toggle { + font-weight: 400; + height: 49px; + min-height: 53.59px; + background-color: white; + border-radius: 0.4em; + border: 1px solid #e0e0e0; + } + + .no-padding-right { + padding-right: 0; + } + + .no-padding-left { + padding-left: 0; + } +} diff --git a/dmp-frontend/src/common/modules/user-settings/user-settings-selector/user-settings-selector.component.ts b/dmp-frontend/src/common/modules/user-settings/user-settings-selector/user-settings-selector.component.ts new file mode 100644 index 000000000..7fcbe8c81 --- /dev/null +++ b/dmp-frontend/src/common/modules/user-settings/user-settings-selector/user-settings-selector.component.ts @@ -0,0 +1,157 @@ +import { Component, EventEmitter, Input, OnChanges, OnInit, Output, SimpleChanges } from '@angular/core'; +import { MatDialog } from '@angular/material/dialog'; +import { BaseComponent } from '@common/base/base.component'; +import { Lookup } from '@common/model/lookup'; +import { takeUntil, filter } from 'rxjs/operators'; +import { TranslateService } from '@ngx-translate/core'; +import { ConfirmationDialogComponent } from '@common/modules/confirmation-dialog/confirmation-dialog.component'; +import { isNullOrUndefined } from '@swimlane/ngx-datatable'; +import { UserSetting, UserSettingsService } from '@app/core/services/user-settings/user-settings.service'; + +@Component({ + selector: 'app-user-settings-selector', + templateUrl: './user-settings-selector.component.html', + styleUrls: ['./user-settings-selector.component.scss'] +}) +export class UserSettingsSelectorComponent extends BaseComponent implements OnInit, OnChanges { + + @Input() key: any; + @Input() lookup: Lookup; + @Input() autoSelectUserSettings: boolean; + @Output() onSettingSelected = new EventEmitter(); + + settings: any; + availableUserSettings: UserSetting[] = []; + currentUserSetting: UserSetting; + + constructor( + private userSettingsService: UserSettingsService, + private dialog: MatDialog, + private language: TranslateService, + ) { super(); } + + ngOnInit() { + + this.userSettingsService.getUserSettingUpdatedObservable().pipe(takeUntil(this._destroyed)).subscribe(key => { + if (key === this.key.key) { this.getSettings(); } + }); + + this.getSettings(); + } + + ngOnChanges(changes: SimpleChanges) { + if (changes['autoSelectUserSettings']) { + if (changes['autoSelectUserSettings'].currentValue) { + if (this.currentUserSetting == null && this.settings != null) { + this.currentUserSetting = this.settings.defaultSetting; + this.onSettingSelected.emit(this.currentUserSetting ? this.currentUserSetting.value : null); + } + } + } + if (changes['lookup'] && this.currentUserSetting != null) { + this.currentUserSetting.value = this.lookup; + } + } + + private getSettings() { + this.userSettingsService.get(this.key).pipe(takeUntil(this._destroyed)).subscribe(s => { + if (s != null) { + const settings = JSON.parse(JSON.stringify(s)); + this.settings = settings; + this.availableUserSettings = settings.settings; + if (this.autoSelectUserSettings) { + this.currentUserSetting = settings.defaultSetting; + } else { + if (this.currentUserSetting) { + const filterIndex = this.availableUserSettings.findIndex(x => x.name === this.currentUserSetting.name); + this.currentUserSetting = this.availableUserSettings[filterIndex]; + } else { + this.currentUserSetting = settings.defaultSetting; + } + } + } else { + this.settings = null; + this.currentUserSetting = null; + this.availableUserSettings = []; + } + if (this.autoSelectUserSettings) { this.onSettingSelected.emit(s != null ? (this.currentUserSetting ? this.currentUserSetting.value : null) : null); } + }); + } + + getSettingName(setting: UserSetting) { + return !isNullOrUndefined(setting.name) ? setting.name : 'Default'; + } + + settingSelected(event: UserSetting) { + const setting = this.availableUserSettings.find(x => x.id === event.id); + if (setting === null) { return; } + + //Persist the active user setting + //this.onSettingSelected.emit(setting.value); + this.userSettingsService.set(setting, true, this.key); + } + + settingDeleted() { + const value = this.currentUserSetting.id; + if (value) { + const dialogRef = this.dialog.open(ConfirmationDialogComponent, { + maxWidth: '400px', + restoreFocus: false, + data: { + message: this.language.instant('GENERAL.CONFIRMATION-DIALOG.DELETE-USER-SETTING-PROFILE'), + confirmButton: this.language.instant('GENERAL.CONFIRMATION-DIALOG.ACTIONS.CONFIRMATION'), + cancelButton: this.language.instant('GENERAL.CONFIRMATION-DIALOG.ACTIONS.CANCELATION') + } + }); + dialogRef.afterClosed().pipe(takeUntil(this._destroyed)).subscribe(result => { + if (result) { + this.userSettingsService.remove(this.currentUserSetting.id, this.key); + } + }); + } + /* this.userSettingsService.remove(this.currentUserSetting.id, this.key); */ + } + + saveFilter() { + // const saveDialogRef = this.dialog.open(FilterNameDialogComponent, { + // maxWidth: '600px', + // maxHeight: '400px', + // restoreFocus: false, + // data: { name: this.currentUserSetting ? this.currentUserSetting.name : '' }, + // disableClose: false + // }); + + // saveDialogRef.afterClosed().subscribe(result => { + // if (result) { this.createNewFilter(result); } + // }); + } + + updateFilter() { + this.currentUserSetting.value = this.lookup; + this.persistLookupChangesManually(this.currentUserSetting, true); + } + + private persistLookupChangesManually(setting: UserSetting, isDefault: boolean) { + this.userSettingsService.set(setting, isDefault, this.key); + } + + private createNewFilter(name: string) { + let setting: UserSetting; + setting = this.currentUserSetting ? JSON.parse(JSON.stringify(this.currentUserSetting)) : {}; + setting.value = this.lookup; + setting.id = null; + setting.hash = null; + setting.name = name; + setting.isDefault = true; + setting.createdAt = null; + setting.updatedAt = null; + setting.userId = null; + this.currentUserSetting = setting; + + this.persistLookupChangesManually(this.currentUserSetting, true); + } + + compareFn(c1: UserSetting, c2: UserSetting): boolean { + return c1 && c2 ? c1.id === c2.id : c1 === c2; + } +} diff --git a/dmp-frontend/src/common/modules/user-settings/user-settings.module.ts b/dmp-frontend/src/common/modules/user-settings/user-settings.module.ts new file mode 100644 index 000000000..075b705b6 --- /dev/null +++ b/dmp-frontend/src/common/modules/user-settings/user-settings.module.ts @@ -0,0 +1,29 @@ +import { DialogModule } from '@angular/cdk/dialog'; +import { NgModule } from '@angular/core'; +import { AutoCompleteModule } from '@app/library/auto-complete/auto-complete.module'; +import { CommonFormsModule } from '@common/forms/common-forms.module'; +import { ConfirmationDialogModule } from '@common/modules/confirmation-dialog/confirmation-dialog.module'; +import { UserSettingsPickerComponent } from '@common/modules/user-settings/user-settings-picker/user-settings-picker.component'; +import { UserSettingsSelectorComponent } from '@common/modules/user-settings/user-settings-selector/user-settings-selector.component'; +import { CommonUiModule } from '@common/ui/common-ui.module'; + +@NgModule({ + imports: [ + CommonUiModule, + CommonFormsModule, + ConfirmationDialogModule, + DialogModule, + AutoCompleteModule + ], + declarations: [ + UserSettingsSelectorComponent, + UserSettingsPickerComponent, + ], + exports: [ + UserSettingsSelectorComponent, + UserSettingsPickerComponent + ] +}) +export class UserSettingsModule { + constructor() { } +} diff --git a/dmp-frontend/src/common/ui/common-ui.module.ts b/dmp-frontend/src/common/ui/common-ui.module.ts index 5c16efc7b..282feb3d0 100644 --- a/dmp-frontend/src/common/ui/common-ui.module.ts +++ b/dmp-frontend/src/common/ui/common-ui.module.ts @@ -1,5 +1,6 @@ import { CommonModule } from '@angular/common'; import { NgModule } from '@angular/core'; +import { NavigationBreadcrumbComponent } from '@app/ui/misc/breadcrumb/navigation-breadcrumb.component'; import { SecureImagePipe } from '@common/http/image/secure-image.pipe'; import { MaterialModule } from '@common/material/material.module'; import { TranslateModule } from '@ngx-translate/core'; @@ -11,13 +12,15 @@ import { TranslateModule } from '@ngx-translate/core'; TranslateModule, ], declarations: [ - SecureImagePipe + SecureImagePipe, + NavigationBreadcrumbComponent ], exports: [ CommonModule, MaterialModule, TranslateModule, - SecureImagePipe + SecureImagePipe, + NavigationBreadcrumbComponent ] }) export class CommonUiModule { } diff --git a/dmp-frontend/src/styles.scss b/dmp-frontend/src/styles.scss index f855b65bb..de4bbea81 100644 --- a/dmp-frontend/src/styles.scss +++ b/dmp-frontend/src/styles.scss @@ -1,6 +1,9 @@ // @import "~@covalent/core/theming/all-theme"; @import "@angular/material/theming"; // @import '../node_modules/@angular/material/theming'; @import "@angular/material/prebuilt-themes/indigo-pink.css"; +@import '../node_modules/@swimlane/ngx-datatable/index.css'; +@import '../node_modules/@swimlane/ngx-datatable/themes/material.scss'; +@import '../node_modules/@swimlane/ngx-datatable/assets/icons.css'; @import "~bootstrap/dist/css/bootstrap.css"; @@ -314,3 +317,29 @@ .list-move { transition: transform 1s; } + +.colums-gapped{ + display: flex; + flex-direction: column; + gap: 1rem; +} + +.info-grid{ + display: grid; + grid-template-columns: auto 1fr; + gap: 1rem; + .info-grid-label{ + padding-top: 1rem; + min-width: 14rem; + padding-left: 1rem; + font-weight: bold; + } + .info-grid-value{ + display: flex; + &>*{ + flex-grow: 1; + } + } +} + +.datatable-body-cell { display: flex; margin: auto; } \ No newline at end of file