From c6508a008244a1847137504e77e575ed8156cbef Mon Sep 17 00:00:00 2001 From: Diamantis Tziotzios Date: Wed, 20 Dec 2023 09:20:38 +0200 Subject: [PATCH] description editor refactor - WIP --- dmp-frontend/src/app/app-routing.module.ts | 19 +- dmp-frontend/src/app/app.module.ts | 4 +- .../src/app/core/core-service.module.ts | 2 - .../model/dataset-profile-definition/rule.ts | 1 - .../description-template-persist.ts | 8 +- .../description-template.ts | 8 +- .../quick-wizard/quick-wizard.service.ts | 26 - .../final-preview/final-preview.component.ts | 2 +- .../dataset-profile-editor.component.ts | 2 +- ...late-editor-composite-field.component.html | 5 +- ...mplate-editor-composite-field.component.ts | 4 +- .../final-preview/final-preview.component.ts | 2 +- ...plate-editor-section-fieldset.component.ts | 12 +- ...ption-template-editor-section.component.ts | 4 +- .../description-template-editor.component.ts | 8 +- .../description-template-editor.model.ts | 8 +- .../dataset-create-wizard.component.html | 37 - .../dataset-create-wizard.component.scss | 11 - .../dataset-create-wizard.component.ts | 163 ---- .../dataset-create-wizard.model.ts | 43 - .../dataset-create-wizard.module.ts | 37 - .../dataset-create-wizard.routing.ts | 32 - .../dataset-dmp-selector.component.html | 20 - .../dataset-dmp-selector.component.scss | 0 .../dataset-dmp-selector.component.ts | 104 --- .../dataset-wizard.component.ts | 2 +- .../dataset-listing-item.component.ts | 4 +- .../overview/dataset-overview.component.ts | 4 +- .../dataset-editor.component.html | 107 --- .../dataset-editor.component.ts | 145 ---- .../description-editor.component.html | 150 ---- .../description-editor.resolver.ts | 67 -- .../app/ui/description/description.module.ts | 65 -- .../app/ui/description/description.routing.ts | 135 +--- ...cription-base-fields-editor.component.html | 58 ++ ...ription-base-fields-editor.component.scss} | 2 +- ...escription-base-fields-editor.component.ts | 90 +++ .../editor/description-editor.component.html | 143 ++++ .../description-editor.component.scss | 0 .../description-editor.component.ts | 649 +++++++++++++-- .../description-editor.model.ts | 32 +- .../editor/description-editor.module.ts | 37 + .../editor/description-editor.resolver.ts | 112 +++ .../editor/description-editor.routing.ts | 101 +++ .../description-editor.service.ts | 0 ...form-composite-field-dialog.component.html | 15 + .../form-composite-field-dialog.component.ts | 31 + .../form-composite-title.component.html | 25 + .../form-composite-title.component.scss | 31 + .../form-composite-title.component.ts | 21 + .../form-field-set.component.html | 54 ++ .../form-field-set.component.scss | 17 + .../form-field-set.component.ts | 115 +++ .../form-field/form-field.component.html | 473 +++++++++++ .../form-field/form-field.component.scss | 105 +++ .../form-field/form-field.component.ts | 764 ++++++++++++++++++ .../form-section/form-section.component.html | 176 ++++ .../form-section/form-section.component.scss | 46 ++ .../form-section/form-section.component.ts | 266 ++++++ .../description-form.component.html | 54 ++ .../description-form.component.scss | 47 ++ .../description-form.component.ts | 371 +++++++++ .../description-form.module.ts | 41 + .../models/visibility-rule-source.ts | 4 + .../models/visibility-rule.ts | 6 + .../models/visibility-rules-context.ts | 47 ++ .../visibility-rules.service.ts | 453 +++++++++++ ...-external-references-editor.component.html | 0 ...-external-references-editor.component.scss | 0 ...et-external-references-editor.component.ts | 0 ...ta-repository-dialog-editor.component.html | 0 ...ta-repository-dialog-editor.component.scss | 0 ...data-repository-dialog-editor.component.ts | 0 ...ernal-dataset-dialog-editor.component.html | 0 ...ernal-dataset-dialog-editor.component.scss | 0 ...xternal-dataset-dialog-editor.component.ts | 0 ...rnal-registry-dialog-editor.component.html | 0 ...rnal-registry-dialog-editor.component.scss | 0 ...ternal-registry-dialog-editor.component.ts | 0 ...ernal-service-dialog-editor.component.html | 0 ...ernal-service-dialog-editor.component.scss | 0 ...xternal-service-dialog-editor.component.ts | 0 .../form-progress-indication.component.html | 5 + .../form-progress-indication.component.scss | 16 + .../form-progress-indication.component.ts | 211 +++++ .../form-progress-indication.module.ts | 18 + .../prefill-description.component.html} | 0 .../prefill-description.component.scss} | 0 .../prefill-description.component.ts} | 0 .../models/toc-entry-type.enum.ts | 6 + .../table-of-contents/models/toc-entry.ts | 14 + .../table-of-contents-internal.html | 50 ++ .../table-of-contents-internal.scss | 33 + .../table-of-contents-internal.ts | 168 ++++ .../table-of-contents.component.html | 24 + .../table-of-contents.component.scss | 80 ++ .../table-of-contents.component.ts | 514 ++++++++++++ .../table-of-contents.module.ts | 15 + .../listing/description-listing.module.ts | 27 + .../listing/description-listing.routing.ts | 30 + .../description-listing-item.component.ts | 4 +- .../description-overview.component.ts | 4 +- .../overview/description-overview.module.ts | 6 +- .../overview/description-overview.routing.ts | 29 + .../dmp-listing-item.component.html | 4 +- .../dmp/overview/dmp-overview.component.html | 2 +- .../ui/dmp/overview/dmp-overview.component.ts | 4 +- .../form-composite-field-dialog.component.ts | 2 +- .../form-composite-field.component.ts | 2 +- .../form-field/form-field.component.ts | 2 +- .../form-progress-indication.component.ts | 2 +- .../form-section-inner.component.ts | 2 +- .../form-section/form-section.component.ts | 8 +- .../dataset-description-form.component.ts | 2 +- .../dataset-description-form.module.ts | 2 +- .../dataset-description.component.ts | 2 +- .../form-focus/form-focus.service.ts | 2 +- .../table-of-contents-internal.ts | 2 +- .../table-of-contents.module.ts | 2 +- .../table-of-contents.ts | 194 ++--- .../visibility-rules.service.ts | 742 +++++++++-------- .../src/app/ui/navbar/navbar.component.html | 1 - .../dataset-editor-wizard-model.ts | 40 - .../dataset-editor-wizard.component.html | 64 -- .../dataset-editor-wizard.component.scss | 10 - .../dataset-editor-wizard.component.ts | 130 --- .../quick-wizard-dataset-description-model.ts | 20 - .../dmp-editor/dmp-editor-wizard-model.ts | 56 -- .../dmp-editor-wizard.component.html | 94 --- .../dmp-editor-wizard.component.scss | 4 - .../dmp-editor/dmp-editor-wizard.component.ts | 141 ---- .../funder-editor-wizard.component.html | 48 -- .../funder-editor-wizard.component.scss | 0 .../funder-editor-wizard.component.ts | 67 -- .../grant-editor/grant-editor-wizard-model.ts | 51 -- .../grant-editor-wizard.component.html | 65 -- .../grant-editor-wizard.component.scss | 0 .../grant-editor-wizard.component.ts | 151 ---- .../project-editor-wizard.component.html | 57 -- .../project-editor-wizard.component.scss | 0 .../project-editor-wizard.component.ts | 69 -- .../quick-wizard-editor.component.html | 68 -- .../quick-wizard-editor.component.scss | 11 - .../quick-wizard-editor.component.ts | 203 ----- .../quick-wizard-editor.model.ts | 70 -- .../ui/quick-wizard/quick-wizard.module.ts | 48 -- .../ui/quick-wizard/quick-wizard.routing.ts | 44 - .../src/app/ui/sidebar/sidebar.component.ts | 2 - 148 files changed, 6125 insertions(+), 3246 deletions(-) delete mode 100644 dmp-frontend/src/app/core/services/quick-wizard/quick-wizard.service.ts delete mode 100644 dmp-frontend/src/app/ui/dataset-create-wizard/dataset-create-wizard.component.html delete mode 100644 dmp-frontend/src/app/ui/dataset-create-wizard/dataset-create-wizard.component.scss delete mode 100644 dmp-frontend/src/app/ui/dataset-create-wizard/dataset-create-wizard.component.ts delete mode 100644 dmp-frontend/src/app/ui/dataset-create-wizard/dataset-create-wizard.model.ts delete mode 100644 dmp-frontend/src/app/ui/dataset-create-wizard/dataset-create-wizard.module.ts delete mode 100644 dmp-frontend/src/app/ui/dataset-create-wizard/dataset-create-wizard.routing.ts delete mode 100644 dmp-frontend/src/app/ui/dataset-create-wizard/dmp-selector/dataset-dmp-selector.component.html delete mode 100644 dmp-frontend/src/app/ui/dataset-create-wizard/dmp-selector/dataset-dmp-selector.component.scss delete mode 100644 dmp-frontend/src/app/ui/dataset-create-wizard/dmp-selector/dataset-dmp-selector.component.ts delete mode 100644 dmp-frontend/src/app/ui/description/dataset-wizard/dataset-editor/dataset-editor.component.html delete mode 100644 dmp-frontend/src/app/ui/description/dataset-wizard/dataset-editor/dataset-editor.component.ts delete mode 100644 dmp-frontend/src/app/ui/description/dataset-wizard/description-editor.component.html delete mode 100644 dmp-frontend/src/app/ui/description/dataset-wizard/description-editor.resolver.ts create mode 100644 dmp-frontend/src/app/ui/description/editor/description-base-fields-editor/description-base-fields-editor.component.html rename dmp-frontend/src/app/ui/description/{dataset-wizard/dataset-editor/dataset-editor.component.scss => editor/description-base-fields-editor/description-base-fields-editor.component.scss} (98%) create mode 100644 dmp-frontend/src/app/ui/description/editor/description-base-fields-editor/description-base-fields-editor.component.ts create mode 100644 dmp-frontend/src/app/ui/description/editor/description-editor.component.html rename dmp-frontend/src/app/ui/description/{dataset-wizard => editor}/description-editor.component.scss (100%) rename dmp-frontend/src/app/ui/description/{dataset-wizard => editor}/description-editor.component.ts (72%) rename dmp-frontend/src/app/ui/description/{dataset-wizard => editor}/description-editor.model.ts (97%) create mode 100644 dmp-frontend/src/app/ui/description/editor/description-editor.module.ts create mode 100644 dmp-frontend/src/app/ui/description/editor/description-editor.resolver.ts create mode 100644 dmp-frontend/src/app/ui/description/editor/description-editor.routing.ts rename dmp-frontend/src/app/ui/description/{dataset-wizard => editor}/description-editor.service.ts (100%) create mode 100644 dmp-frontend/src/app/ui/description/editor/description-form/components/form-composite-field-dialog/form-composite-field-dialog.component.html create mode 100644 dmp-frontend/src/app/ui/description/editor/description-form/components/form-composite-field-dialog/form-composite-field-dialog.component.ts create mode 100644 dmp-frontend/src/app/ui/description/editor/description-form/components/form-composite-title/form-composite-title.component.html create mode 100644 dmp-frontend/src/app/ui/description/editor/description-form/components/form-composite-title/form-composite-title.component.scss create mode 100644 dmp-frontend/src/app/ui/description/editor/description-form/components/form-composite-title/form-composite-title.component.ts create mode 100644 dmp-frontend/src/app/ui/description/editor/description-form/components/form-field-set/form-field-set.component.html create mode 100644 dmp-frontend/src/app/ui/description/editor/description-form/components/form-field-set/form-field-set.component.scss create mode 100644 dmp-frontend/src/app/ui/description/editor/description-form/components/form-field-set/form-field-set.component.ts create mode 100644 dmp-frontend/src/app/ui/description/editor/description-form/components/form-field/form-field.component.html create mode 100644 dmp-frontend/src/app/ui/description/editor/description-form/components/form-field/form-field.component.scss create mode 100644 dmp-frontend/src/app/ui/description/editor/description-form/components/form-field/form-field.component.ts create mode 100644 dmp-frontend/src/app/ui/description/editor/description-form/components/form-section/form-section.component.html create mode 100644 dmp-frontend/src/app/ui/description/editor/description-form/components/form-section/form-section.component.scss create mode 100644 dmp-frontend/src/app/ui/description/editor/description-form/components/form-section/form-section.component.ts create mode 100644 dmp-frontend/src/app/ui/description/editor/description-form/description-form.component.html create mode 100644 dmp-frontend/src/app/ui/description/editor/description-form/description-form.component.scss create mode 100644 dmp-frontend/src/app/ui/description/editor/description-form/description-form.component.ts create mode 100644 dmp-frontend/src/app/ui/description/editor/description-form/description-form.module.ts create mode 100644 dmp-frontend/src/app/ui/description/editor/description-form/visibility-rules/models/visibility-rule-source.ts create mode 100644 dmp-frontend/src/app/ui/description/editor/description-form/visibility-rules/models/visibility-rule.ts create mode 100644 dmp-frontend/src/app/ui/description/editor/description-form/visibility-rules/models/visibility-rules-context.ts create mode 100644 dmp-frontend/src/app/ui/description/editor/description-form/visibility-rules/visibility-rules.service.ts rename dmp-frontend/src/app/ui/description/{dataset-wizard => editor}/external-references/dataset-external-references-editor.component.html (100%) rename dmp-frontend/src/app/ui/description/{dataset-wizard => editor}/external-references/dataset-external-references-editor.component.scss (100%) rename dmp-frontend/src/app/ui/description/{dataset-wizard => editor}/external-references/dataset-external-references-editor.component.ts (100%) rename dmp-frontend/src/app/ui/description/{dataset-wizard => editor}/external-references/editors/data-repository/dataset-external-data-repository-dialog-editor.component.html (100%) rename dmp-frontend/src/app/ui/description/{dataset-wizard => editor}/external-references/editors/data-repository/dataset-external-data-repository-dialog-editor.component.scss (100%) rename dmp-frontend/src/app/ui/description/{dataset-wizard => editor}/external-references/editors/data-repository/dataset-external-data-repository-dialog-editor.component.ts (100%) rename dmp-frontend/src/app/ui/description/{dataset-wizard => editor}/external-references/editors/external-dataset/dataset-external-dataset-dialog-editor.component.html (100%) rename dmp-frontend/src/app/ui/description/{dataset-wizard => editor}/external-references/editors/external-dataset/dataset-external-dataset-dialog-editor.component.scss (100%) rename dmp-frontend/src/app/ui/description/{dataset-wizard => editor}/external-references/editors/external-dataset/dataset-external-dataset-dialog-editor.component.ts (100%) rename dmp-frontend/src/app/ui/description/{dataset-wizard => editor}/external-references/editors/registry/dataset-external-registry-dialog-editor.component.html (100%) rename dmp-frontend/src/app/ui/description/{dataset-wizard => editor}/external-references/editors/registry/dataset-external-registry-dialog-editor.component.scss (100%) rename dmp-frontend/src/app/ui/description/{dataset-wizard => editor}/external-references/editors/registry/dataset-external-registry-dialog-editor.component.ts (100%) rename dmp-frontend/src/app/ui/description/{dataset-wizard => editor}/external-references/editors/service/dataset-external-service-dialog-editor.component.html (100%) rename dmp-frontend/src/app/ui/description/{dataset-wizard => editor}/external-references/editors/service/dataset-external-service-dialog-editor.component.scss (100%) rename dmp-frontend/src/app/ui/description/{dataset-wizard => editor}/external-references/editors/service/dataset-external-service-dialog-editor.component.ts (100%) create mode 100644 dmp-frontend/src/app/ui/description/editor/form-progress-indication/form-progress-indication.component.html create mode 100644 dmp-frontend/src/app/ui/description/editor/form-progress-indication/form-progress-indication.component.scss create mode 100644 dmp-frontend/src/app/ui/description/editor/form-progress-indication/form-progress-indication.component.ts create mode 100644 dmp-frontend/src/app/ui/description/editor/form-progress-indication/form-progress-indication.module.ts rename dmp-frontend/src/app/ui/description/{dataset-wizard/prefill-dataset/prefill-dataset.component.html => editor/prefill-description/prefill-description.component.html} (100%) rename dmp-frontend/src/app/ui/description/{dataset-wizard/prefill-dataset/prefill-dataset.component.scss => editor/prefill-description/prefill-description.component.scss} (100%) rename dmp-frontend/src/app/ui/description/{dataset-wizard/prefill-dataset/prefill-dataset.component.ts => editor/prefill-description/prefill-description.component.ts} (100%) create mode 100644 dmp-frontend/src/app/ui/description/editor/table-of-contents/models/toc-entry-type.enum.ts create mode 100644 dmp-frontend/src/app/ui/description/editor/table-of-contents/models/toc-entry.ts create mode 100644 dmp-frontend/src/app/ui/description/editor/table-of-contents/table-of-contents-internal/table-of-contents-internal.html create mode 100644 dmp-frontend/src/app/ui/description/editor/table-of-contents/table-of-contents-internal/table-of-contents-internal.scss create mode 100644 dmp-frontend/src/app/ui/description/editor/table-of-contents/table-of-contents-internal/table-of-contents-internal.ts create mode 100644 dmp-frontend/src/app/ui/description/editor/table-of-contents/table-of-contents.component.html create mode 100644 dmp-frontend/src/app/ui/description/editor/table-of-contents/table-of-contents.component.scss create mode 100644 dmp-frontend/src/app/ui/description/editor/table-of-contents/table-of-contents.component.ts create mode 100644 dmp-frontend/src/app/ui/description/editor/table-of-contents/table-of-contents.module.ts create mode 100644 dmp-frontend/src/app/ui/description/listing/description-listing.module.ts create mode 100644 dmp-frontend/src/app/ui/description/listing/description-listing.routing.ts create mode 100644 dmp-frontend/src/app/ui/description/overview/description-overview.routing.ts delete mode 100644 dmp-frontend/src/app/ui/quick-wizard/dataset-editor/dataset-editor-wizard-model.ts delete mode 100644 dmp-frontend/src/app/ui/quick-wizard/dataset-editor/dataset-editor-wizard.component.html delete mode 100644 dmp-frontend/src/app/ui/quick-wizard/dataset-editor/dataset-editor-wizard.component.scss delete mode 100644 dmp-frontend/src/app/ui/quick-wizard/dataset-editor/dataset-editor-wizard.component.ts delete mode 100644 dmp-frontend/src/app/ui/quick-wizard/dataset-editor/quick-wizard-dataset-description-model.ts delete mode 100644 dmp-frontend/src/app/ui/quick-wizard/dmp-editor/dmp-editor-wizard-model.ts delete mode 100644 dmp-frontend/src/app/ui/quick-wizard/dmp-editor/dmp-editor-wizard.component.html delete mode 100644 dmp-frontend/src/app/ui/quick-wizard/dmp-editor/dmp-editor-wizard.component.scss delete mode 100644 dmp-frontend/src/app/ui/quick-wizard/dmp-editor/dmp-editor-wizard.component.ts delete mode 100644 dmp-frontend/src/app/ui/quick-wizard/funder-editor/funder-editor-wizard.component.html delete mode 100644 dmp-frontend/src/app/ui/quick-wizard/funder-editor/funder-editor-wizard.component.scss delete mode 100644 dmp-frontend/src/app/ui/quick-wizard/funder-editor/funder-editor-wizard.component.ts delete mode 100644 dmp-frontend/src/app/ui/quick-wizard/grant-editor/grant-editor-wizard-model.ts delete mode 100644 dmp-frontend/src/app/ui/quick-wizard/grant-editor/grant-editor-wizard.component.html delete mode 100644 dmp-frontend/src/app/ui/quick-wizard/grant-editor/grant-editor-wizard.component.scss delete mode 100644 dmp-frontend/src/app/ui/quick-wizard/grant-editor/grant-editor-wizard.component.ts delete mode 100644 dmp-frontend/src/app/ui/quick-wizard/project-editor/project-editor-wizard.component.html delete mode 100644 dmp-frontend/src/app/ui/quick-wizard/project-editor/project-editor-wizard.component.scss delete mode 100644 dmp-frontend/src/app/ui/quick-wizard/project-editor/project-editor-wizard.component.ts delete mode 100644 dmp-frontend/src/app/ui/quick-wizard/quick-wizard-editor/quick-wizard-editor.component.html delete mode 100644 dmp-frontend/src/app/ui/quick-wizard/quick-wizard-editor/quick-wizard-editor.component.scss delete mode 100644 dmp-frontend/src/app/ui/quick-wizard/quick-wizard-editor/quick-wizard-editor.component.ts delete mode 100644 dmp-frontend/src/app/ui/quick-wizard/quick-wizard-editor/quick-wizard-editor.model.ts delete mode 100644 dmp-frontend/src/app/ui/quick-wizard/quick-wizard.module.ts delete mode 100644 dmp-frontend/src/app/ui/quick-wizard/quick-wizard.routing.ts diff --git a/dmp-frontend/src/app/app-routing.module.ts b/dmp-frontend/src/app/app-routing.module.ts index c8c054f8d..88977f96b 100644 --- a/dmp-frontend/src/app/app-routing.module.ts +++ b/dmp-frontend/src/app/app-routing.module.ts @@ -71,16 +71,6 @@ const appRoutes: Routes = [ } }, - - - { - path: 'datasetcreatewizard', - loadChildren: () => import('./ui/dataset-create-wizard/dataset-create-wizard.module').then(m => m.DatasetCreateWizardModule), - data: { - breadcrumb: true, - title: 'GENERAL.TITLES.DATASETCREATEWIZARD' - } - }, { path: 'about', @@ -100,14 +90,7 @@ const appRoutes: Routes = [ // } // }, - { - path: 'quick-wizard', - loadChildren: () => import('./ui/quick-wizard/quick-wizard.module').then(m => m.OuickWizardModule), - data: { - breadcrumb: true, - title: "GENERAL.TITLES.QUICK-WIZARD" - } - }, + { path: 'dataset-profiles', loadChildren: () => import('./ui/admin/dataset-profile/dataset-profile.module').then(m => m.DatasetProfileModule), diff --git a/dmp-frontend/src/app/app.module.ts b/dmp-frontend/src/app/app.module.ts index c99d555bd..fe62ce072 100644 --- a/dmp-frontend/src/app/app.module.ts +++ b/dmp-frontend/src/app/app.module.ts @@ -1,5 +1,5 @@ import { OverlayModule } from '@angular/cdk/overlay'; -import { HttpClient, HttpClientModule } from '@angular/common/http'; +import { HttpClientModule } from '@angular/common/http'; import { APP_INITIALIZER, LOCALE_ID, NgModule } from '@angular/core'; import { FormsModule, ReactiveFormsModule } from '@angular/forms'; import { MAT_MOMENT_DATE_FORMATS, MatMomentDateModule } from '@angular/material-moment-adapter'; @@ -12,7 +12,6 @@ import { AppComponent } from '@app/app.component'; 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 { HelpContentModule } from '@app/ui/misc/help-content/help-content.module'; import { NavigationModule } from '@app/ui/misc/navigation/navigation.module'; @@ -143,7 +142,6 @@ export function InstallationConfigurationFactory(appConfig: ConfigurationService HelpContentModule, ReactiveFormsModule, FormsModule, - DatasetCreateWizardModule, NavbarModule, SidebarModule, NgcCookieConsentModule.forRoot(cookieConfig), diff --git a/dmp-frontend/src/app/core/core-service.module.ts b/dmp-frontend/src/app/core/core-service.module.ts index deca49579..e8e34418b 100644 --- a/dmp-frontend/src/app/core/core-service.module.ts +++ b/dmp-frontend/src/app/core/core-service.module.ts @@ -39,7 +39,6 @@ import { UiNotificationService } from './services/notification/ui-notification-s import { OrganisationService } from './services/organisation/organisation.service'; import { ProgressIndicationService } from './services/progress-indication/progress-indication-service'; 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'; @@ -119,7 +118,6 @@ export class CoreServiceModule { UserServiceOld, DmpInvitationService, DatasetExternalAutocompleteService, - QuickWizardService, OrganisationService, EmailConfirmationService, ContactSupportService, diff --git a/dmp-frontend/src/app/core/model/dataset-profile-definition/rule.ts b/dmp-frontend/src/app/core/model/dataset-profile-definition/rule.ts index b17886989..9e60b6de8 100644 --- a/dmp-frontend/src/app/core/model/dataset-profile-definition/rule.ts +++ b/dmp-frontend/src/app/core/model/dataset-profile-definition/rule.ts @@ -2,5 +2,4 @@ export class Rule { sourceField: string; targetField: string; requiredValue: any; - type: string; } \ No newline at end of file diff --git a/dmp-frontend/src/app/core/model/description-template/description-template-persist.ts b/dmp-frontend/src/app/core/model/description-template/description-template-persist.ts index b70557e07..77addc8e2 100644 --- a/dmp-frontend/src/app/core/model/description-template/description-template-persist.ts +++ b/dmp-frontend/src/app/core/model/description-template/description-template-persist.ts @@ -30,13 +30,13 @@ export interface DescriptionTemplateDefinitionPersist { export interface DescriptionTemplatePagePersist { - id: Guid; + id: string; ordinal: number; title: string; } export interface DescriptionTemplateSectionPersist { - id: Guid; + id: string; ordinal: number; defaultVisibility: boolean; multiplicity: boolean; @@ -49,7 +49,7 @@ export interface DescriptionTemplateSectionPersist { } export interface DescriptionTemplateFieldSetPersist { - id: Guid; + id: string; ordinal: number; numbering: string; title: string; @@ -62,7 +62,7 @@ export interface DescriptionTemplateFieldSetPersist { } export interface DescriptionTemplateFieldPersist { - id: Guid; + id: string; ordinal: number; schematics: string[]; defaultValue: string; diff --git a/dmp-frontend/src/app/core/model/description-template/description-template.ts b/dmp-frontend/src/app/core/model/description-template/description-template.ts index 19ceb9801..e652a7041 100644 --- a/dmp-frontend/src/app/core/model/description-template/description-template.ts +++ b/dmp-frontend/src/app/core/model/description-template/description-template.ts @@ -34,13 +34,13 @@ export interface DescriptionTemplateDefinition { export interface DescriptionTemplatePage { - id: Guid; + id: string; ordinal: number; title: string; } export interface DescriptionTemplateSection { - id: Guid; + id: string; ordinal: number; defaultVisibility: boolean; multiplicity: boolean; @@ -55,7 +55,7 @@ export interface DescriptionTemplateSection { } export interface DescriptionTemplateFieldSet { - id: Guid; + id: string; ordinal: number; numbering: string; title: string; @@ -68,7 +68,7 @@ export interface DescriptionTemplateFieldSet { } export interface DescriptionTemplateField { - id: Guid; + id: string; ordinal: number; numbering?: string; schematics?: string[]; diff --git a/dmp-frontend/src/app/core/services/quick-wizard/quick-wizard.service.ts b/dmp-frontend/src/app/core/services/quick-wizard/quick-wizard.service.ts deleted file mode 100644 index 4a6d3579d..000000000 --- a/dmp-frontend/src/app/core/services/quick-wizard/quick-wizard.service.ts +++ /dev/null @@ -1,26 +0,0 @@ -import { HttpHeaders } from '@angular/common/http'; -import { Injectable } from '@angular/core'; -import { Observable } from 'rxjs'; -import { environment } from '../../../../environments/environment'; -import { QuickWizardEditorWizardModel } from '../../../ui/quick-wizard/quick-wizard-editor/quick-wizard-editor.model'; -import { BaseHttpService } from '../http/base-http.service'; -import { DatasetCreateWizardModel } from '../../../ui/dataset-create-wizard/dataset-create-wizard.model'; -import { ConfigurationService } from '../configuration/configuration.service'; - -@Injectable() -export class QuickWizardService { - private actionUrl: string; - private headers: HttpHeaders; - - constructor(private http: BaseHttpService, private configurationService: ConfigurationService) { - this.actionUrl = configurationService.server + 'quick-wizard/'; - } - - createQuickWizard(quickWizard: QuickWizardEditorWizardModel): Observable { - return this.http.post(this.actionUrl, quickWizard, { headers: this.headers }); - } - - createQuickDatasetWizard(datasetCreateWizardModel: DatasetCreateWizardModel): Observable { - return this.http.post(this.actionUrl + 'datasetcreate', datasetCreateWizardModel, { headers: this.headers }); - } -} diff --git a/dmp-frontend/src/app/ui/admin/dataset-profile/editor/components/final-preview/final-preview.component.ts b/dmp-frontend/src/app/ui/admin/dataset-profile/editor/components/final-preview/final-preview.component.ts index 25afc4373..d2ba708e6 100644 --- a/dmp-frontend/src/app/ui/admin/dataset-profile/editor/components/final-preview/final-preview.component.ts +++ b/dmp-frontend/src/app/ui/admin/dataset-profile/editor/components/final-preview/final-preview.component.ts @@ -1,6 +1,6 @@ import { Component, Input, OnInit} from '@angular/core'; import { Rule } from '@app/core/model/dataset-profile-definition/rule'; -import { VisibilityRulesService } from '@app/ui/misc/dataset-description-form/visibility-rules/visibility-rules.service'; +import { VisibilityRulesService } from '@app/ui/description/editor/description-form/visibility-rules/visibility-rules.service'; @Component({ 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 75a254984..3ba2002a4 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 @@ -33,7 +33,7 @@ import { EnumUtils } from '@app/core/services/utilities/enum-utils.service'; import { FieldSetEditorModel } from '../admin/field-set-editor-model'; import { Guid } from '@common/types/guid'; import { FieldEditorModel } from '../admin/field-editor-model'; -import { VisibilityRulesService } from '@app/ui/misc/dataset-description-form/visibility-rules/visibility-rules.service'; +import { VisibilityRulesService } from '@app/ui/description/editor/description-form/visibility-rules/visibility-rules.service'; import { CdkStep, StepperSelectionEvent } from '@angular/cdk/stepper'; import { DatasetDescriptionCompositeFieldEditorModel, DatasetDescriptionFieldEditorModel, DatasetDescriptionSectionEditorModel } from '@app/ui/misc/dataset-description-form/dataset-description-form.model'; import { Rule } from '@app/core/model/dataset-profile-definition/rule'; diff --git a/dmp-frontend/src/app/ui/admin/description-template/editor/components/composite-field/description-template-editor-composite-field.component.html b/dmp-frontend/src/app/ui/admin/description-template/editor/components/composite-field/description-template-editor-composite-field.component.html index 4318649bd..89762f754 100644 --- a/dmp-frontend/src/app/ui/admin/description-template/editor/components/composite-field/description-template-editor-composite-field.component.html +++ b/dmp-frontend/src/app/ui/admin/description-template/editor/components/composite-field/description-template-editor-composite-field.component.html @@ -92,8 +92,9 @@
- - + +
diff --git a/dmp-frontend/src/app/ui/admin/description-template/editor/components/composite-field/description-template-editor-composite-field.component.ts b/dmp-frontend/src/app/ui/admin/description-template/editor/components/composite-field/description-template-editor-composite-field.component.ts index 7775b1e19..3b9a313f4 100644 --- a/dmp-frontend/src/app/ui/admin/description-template/editor/components/composite-field/description-template-editor-composite-field.component.ts +++ b/dmp-frontend/src/app/ui/admin/description-template/editor/components/composite-field/description-template-editor-composite-field.component.ts @@ -341,7 +341,7 @@ export class DescriptionTemplateEditorCompositeFieldComponent extends BaseCompon addNewField() { const field: DescriptionTemplateFieldEditorModel = new DescriptionTemplateFieldEditorModel(); - field.id = Guid.create(); + field.id = Guid.create().toString(); field.ordinal = (this.form.get('fields') as UntypedFormArray).length; @@ -494,7 +494,7 @@ export class DescriptionTemplateEditorCompositeFieldComponent extends BaseCompon } const field = { - id: Guid.create(), + id: Guid.create().toString(), ordinal: targetOrdinal, validations: [], includeInExport: true diff --git a/dmp-frontend/src/app/ui/admin/description-template/editor/components/final-preview/final-preview.component.ts b/dmp-frontend/src/app/ui/admin/description-template/editor/components/final-preview/final-preview.component.ts index 25afc4373..d2ba708e6 100644 --- a/dmp-frontend/src/app/ui/admin/description-template/editor/components/final-preview/final-preview.component.ts +++ b/dmp-frontend/src/app/ui/admin/description-template/editor/components/final-preview/final-preview.component.ts @@ -1,6 +1,6 @@ import { Component, Input, OnInit} from '@angular/core'; import { Rule } from '@app/core/model/dataset-profile-definition/rule'; -import { VisibilityRulesService } from '@app/ui/misc/dataset-description-form/visibility-rules/visibility-rules.service'; +import { VisibilityRulesService } from '@app/ui/description/editor/description-form/visibility-rules/visibility-rules.service'; @Component({ diff --git a/dmp-frontend/src/app/ui/admin/description-template/editor/components/section-fieldset/description-template-editor-section-fieldset.component.ts b/dmp-frontend/src/app/ui/admin/description-template/editor/components/section-fieldset/description-template-editor-section-fieldset.component.ts index 77a8e8e44..c3b1d5580 100644 --- a/dmp-frontend/src/app/ui/admin/description-template/editor/components/section-fieldset/description-template-editor-section-fieldset.component.ts +++ b/dmp-frontend/src/app/ui/admin/description-template/editor/components/section-fieldset/description-template-editor-section-fieldset.component.ts @@ -22,7 +22,7 @@ export class DescriptionTemplateEditorSectionFieldSetComponent implements OnInit @Input() datasetProfileId?: string; - @Output() selectedEntryId = new EventEmitter(); + @Output() selectedEntryId = new EventEmitter(); @Output() dataNeedsRefresh = new EventEmitter(); @Output() removeFieldSet = new EventEmitter(); @Output() addNewFieldSet = new EventEmitter(); @@ -101,11 +101,11 @@ export class DescriptionTemplateEditorSectionFieldSetComponent implements OnInit - private _selectedFieldSetId: Guid = null; + private _selectedFieldSetId: string = null; get selectedFieldSetId() { return this._selectedFieldSetId; } - set selectedFieldSetId(id: Guid) { + set selectedFieldSetId(id: string) { if (id === this._selectedFieldSetId) return; this._selectedFieldSetId = id; @@ -140,7 +140,7 @@ export class DescriptionTemplateEditorSectionFieldSetComponent implements OnInit } else { // console.warn('!not found numbering'); } - this._selectedFieldSetId = Guid.parse(this.tocentry.id); + this._selectedFieldSetId = this.tocentry.id; // this._scrollToElement(this.selectedFieldSetId); this.scroller.next(this.tocentry.id); @@ -194,13 +194,13 @@ export class DescriptionTemplateEditorSectionFieldSetComponent implements OnInit addFieldSetAfter(afterOrdinal: number, afterIndex: number): void { const field: DescriptionTemplateFieldEditorModel = new DescriptionTemplateFieldEditorModel(); - field.id = Guid.create(); + field.id = Guid.create().toString(); field.ordinal = 0;//first filed in the fields list const fieldForm = field.buildForm(); //give fieldset id and ordinal const fieldSet: DescriptionTemplateFieldSetEditorModel = new DescriptionTemplateFieldSetEditorModel(); - const fieldSetId = Guid.create(); + const fieldSetId = Guid.create().toString(); fieldSet.id = fieldSetId; fieldSet.ordinal = afterOrdinal < 0 ? 0 : afterOrdinal; diff --git a/dmp-frontend/src/app/ui/admin/description-template/editor/components/section/description-template-editor-section.component.ts b/dmp-frontend/src/app/ui/admin/description-template/editor/components/section/description-template-editor-section.component.ts index 77df70aed..90d7edc70 100644 --- a/dmp-frontend/src/app/ui/admin/description-template/editor/components/section/description-template-editor-section.component.ts +++ b/dmp-frontend/src/app/ui/admin/description-template/editor/components/section/description-template-editor-section.component.ts @@ -28,10 +28,10 @@ export class DescriptionTemplateEditorSectionComponent extends BaseComponent imp fieldSet.ordinal = (this.form.get('fieldSets') as UntypedFormArray).length; const field: DescriptionTemplateFieldEditorModel = new DescriptionTemplateFieldEditorModel(); - field.id = Guid.create(); + field.id = Guid.create().toString(); field.ordinal = 0;//first field in fields fieldSet.fields.push(field); - fieldSet.id = Guid.create(); + fieldSet.id = Guid.create().toString(); const fieldsetsArray = this.form.get('fieldSets') as UntypedFormArray; fieldsetsArray.push(fieldSet.buildForm()); diff --git a/dmp-frontend/src/app/ui/admin/description-template/editor/description-template-editor.component.ts b/dmp-frontend/src/app/ui/admin/description-template/editor/description-template-editor.component.ts index e75c7eaed..5d4848553 100644 --- a/dmp-frontend/src/app/ui/admin/description-template/editor/description-template-editor.component.ts +++ b/dmp-frontend/src/app/ui/admin/description-template/editor/description-template-editor.component.ts @@ -566,7 +566,7 @@ export class DescriptionTemplateEditorComponent extends BaseEditor -
-
-

{{ 'QUICKWIZARD.CREATE-ADD.ADD.DATASET-WIZARD' | translate }}

-

{{ 'QUICKWIZARD.CREATE-ADD.ADD.POST-SELECTION-INFO' | translate }}

- - - {{'DATASET-CREATE-WIZARD.FIRST-STEP.TITLE'| translate}} -
- - -
-
-
-
-
-
-
-
- - - {{'QUICKWIZARD.CREATE-ADD.CREATE.QUICKWIZARD_CREATE.THIRD-STEP.TITLE' | translate}} - -
- - -
- -
-
-
-
- diff --git a/dmp-frontend/src/app/ui/dataset-create-wizard/dataset-create-wizard.component.scss b/dmp-frontend/src/app/ui/dataset-create-wizard/dataset-create-wizard.component.scss deleted file mode 100644 index ea2e9bba1..000000000 --- a/dmp-frontend/src/app/ui/dataset-create-wizard/dataset-create-wizard.component.scss +++ /dev/null @@ -1,11 +0,0 @@ -.saveAndFinalizeButton{ - float:right; -} -.finalizeButton{ - float: right; - text-transform: uppercase; -} -.saveButton{ - float:right; - margin-right: 15px; -} 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 deleted file mode 100644 index 931cd2e2f..000000000 --- a/dmp-frontend/src/app/ui/dataset-create-wizard/dataset-create-wizard.component.ts +++ /dev/null @@ -1,163 +0,0 @@ - -import { Component, OnInit, ViewChild } from '@angular/core'; -import { UntypedFormArray, UntypedFormBuilder, UntypedFormGroup } from '@angular/forms'; -import { MatDialog } from '@angular/material/dialog'; -import { MatStepper } from '@angular/material/stepper'; -import { Router } from '@angular/router'; -import { DatasetStatus } from '@app/core/common/enum/dataset-status'; -import { SnackBarNotificationLevel, UiNotificationService } from '@app/core/services/notification/ui-notification-service'; -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 { 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 { takeUntil } from 'rxjs/operators'; - -@Component({ - selector: 'dataset-create-wizard.component', - templateUrl: 'dataset-create-wizard.component.html', - styleUrls: ['./dataset-create-wizard.component.scss'], -}) -export class DatasetCreateWizard extends CheckDeactivateBaseComponent implements OnInit { //IBreadCrumbComponent - //breadCrumbs: Observable; - @ViewChild(DatasetEditorWizardComponent) datasetEditorWizardComponent: DatasetEditorWizardComponent; - isLinear = false; - isNew = true; - isSubmitted = false; - formGroup: UntypedFormGroup; - - - datasetCreateWizardModel: DatasetCreateWizardModel; - @ViewChild('stepper', { static: true }) stepper: MatStepper; - - constructor( - private router: Router, - private formBuilder: UntypedFormBuilder, - public quickWizardService: QuickWizardService, - public language: TranslateService, - private uiNotificationService: UiNotificationService, - private dialog: MatDialog - ) { - super(); - } - - ngOnInit() { - 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' - // }] - // ); - }) - - } - - save() { - if (this.formGroup.get('datasets') && this.formGroup.get('datasets').get('datasetsList') && (this.formGroup.get('datasets').get('datasetsList') as UntypedFormArray).length > 0) { - for (let control of (this.formGroup.get('datasets').get('datasetsList') as UntypedFormArray).controls) { - control.get('status').setValue(DatasetStatus.Draft); - } - // this.onSubmitSave(); - const dmpId = this.formGroup.get('dmpMeta').get('dmp').value.id; - this.quickWizardService.createQuickDatasetWizard(this.formGroup.value) - .pipe(takeUntil(this._destroyed)) - .subscribe( - complete => this.onCallbackSuccess(dmpId) - ); - } else { - return; - } - } - - saveFinalize() { - const dialogRef = this.dialog.open(ConfirmationDialogComponent, { - maxWidth: '300px', - restoreFocus: false, - data: { - message: this.language.instant('GENERAL.CONFIRMATION-DIALOG.FINALIZE-ITEM'), - confirmButton: this.language.instant('GENERAL.CONFIRMATION-DIALOG.ACTIONS.CONFIRM'), - cancelButton: this.language.instant('GENERAL.CONFIRMATION-DIALOG.ACTIONS.CANCEL'), - isDeleteConfirmation: false - } - }); - dialogRef.afterClosed().pipe(takeUntil(this._destroyed)).subscribe(result => { - if (result) { - if (!this.isFormValid()) { return; } - if (this.formGroup.get('datasets') && this.formGroup.get('datasets').get('datasetsList') && (this.formGroup.get('datasets').get('datasetsList') as UntypedFormArray).length > 0) { - for (let control of (this.formGroup.get('datasets').get('datasetsList') as UntypedFormArray).controls) { - control.get('status').setValue(DatasetStatus.Finalized); - } - this.onSubmitSaveAndFinalize(); - } else { - return; - } - } - }); - } - - // onSubmitSave() { - // const dialogRef = this.dialog.open(ConfirmationDialogComponent, { - // data: { - // message: this.language.instant('QUICKWIZARD.SAVE-DIALOG.TITLE'), - // confirmButton: this.language.instant('QUICKWIZARD.SAVE-DIALOG.ACTIONS.AFFIRMATIVE'), - // cancelButton: this.language.instant('QUICKWIZARD.SAVE-DIALOG.ACTIONS.NEGATIVE') - // } - // }); - // dialogRef.afterClosed().pipe(takeUntil(this._destroyed)).subscribe(result => { - // if (result) { - // this.datasetEditorWizardComponent.addDataset(); - // } else if (result === false) { - // this.quickWizardService.createQuickDatasetWizard(this.formGroup.value) - // .pipe(takeUntil(this._destroyed)) - // .subscribe( - // complete => this.onCallbackSuccess() - // ) - // } - // }); - // } - - onSubmitSaveAndFinalize() { - const dmpId = this.formGroup.get('dmpMeta').get('dmp').value.id; - this.quickWizardService.createQuickDatasetWizard(this.formGroup.value) - .pipe(takeUntil(this._destroyed)) - .subscribe( - complete => this.onCallbackSuccess(dmpId) - ); - } - - hasDatasets() { - if ((this.formGroup.get('datasets').get('datasetsList') as UntypedFormArray).length > 0) { - return true; - } else { - return false; - } - } - - public isFormValid() { - return this.formGroup.valid; - } - - onCallbackSuccess(dmpId: string): void { - this.isSubmitted = true; - 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(['/plans/overview/' + dmpId]); - } - - isActive(step: string): boolean { - switch (step) { - case 'step1': - return this.stepper.selectedIndex == 0; - case 'step2': - return this.stepper.selectedIndex == 1; - } - } - - canDeactivate(): boolean { - return this.isSubmitted || !this.formGroup.dirty; - } -} diff --git a/dmp-frontend/src/app/ui/dataset-create-wizard/dataset-create-wizard.model.ts b/dmp-frontend/src/app/ui/dataset-create-wizard/dataset-create-wizard.model.ts deleted file mode 100644 index a331a0f01..000000000 --- a/dmp-frontend/src/app/ui/dataset-create-wizard/dataset-create-wizard.model.ts +++ /dev/null @@ -1,43 +0,0 @@ -import { UntypedFormBuilder, UntypedFormGroup, Validators } from "@angular/forms"; -import { DmpCreateWizardFormModel } from '@app/core/model/dmp/dmp-create-wizard/dmp-create-wizard-form.model'; -import { DatasetWizardEditorModel } from '@app/ui/dataset/dataset-wizard/dataset-wizard-editor.model'; -import { DatasetEditorWizardModel } from '@app/ui/quick-wizard/dataset-editor/dataset-editor-wizard-model'; -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'; - - -export class DatasetCreateWizardModel { - public dmpMeta: DmpCreateWizardFormModel; - public datasets: DatasetEditorWizardModel; - public validationErrorModel: ValidationErrorModel = new ValidationErrorModel(); - - fromModelDmp(item: DmpCreateWizardFormModel): DatasetCreateWizardModel { - this.dmpMeta.fromModel(item); - return this; - } - - fromModelDataset(item: DatasetWizardEditorModel[]): DatasetCreateWizardModel { - this.datasets.fromModel(item); - return this; - } - - buildForm(context: ValidationContext = null): UntypedFormGroup { - if (context == null) { context = this.createValidationContext(); } - const formBuilder = new UntypedFormBuilder(); - const formGroup = formBuilder.group({ - dmpMeta: new DmpCreateWizardFormModel().buildForm(), - datasets: new DatasetEditorWizardModel().buildForm() - }); - - return formGroup; - } - - createValidationContext(): ValidationContext { - const baseContext: ValidationContext = new ValidationContext(); - baseContext.validation.push({ key: 'label', validators: [Validators.required, BackendErrorValidator(this.validationErrorModel, 'label')] }); - baseContext.validation.push({ key: 'status', validators: [BackendErrorValidator(this.validationErrorModel, 'status')] }); - - return baseContext; - } -} diff --git a/dmp-frontend/src/app/ui/dataset-create-wizard/dataset-create-wizard.module.ts b/dmp-frontend/src/app/ui/dataset-create-wizard/dataset-create-wizard.module.ts deleted file mode 100644 index 7bac0da77..000000000 --- a/dmp-frontend/src/app/ui/dataset-create-wizard/dataset-create-wizard.module.ts +++ /dev/null @@ -1,37 +0,0 @@ -import { NgModule } from '@angular/core'; -import { FormattingModule } from '@app/core/formatting.module'; -import { AutoCompleteModule } from '@app/library/auto-complete/auto-complete.module'; -import { ConfirmationDialogModule } from '@common/modules/confirmation-dialog/confirmation-dialog.module'; -import { CanDeactivateGuard } from '@app/library/deactivate/can-deactivate.guard'; -import { UrlListingModule } from '@app/library/url-listing/url-listing.module'; -import { DatasetCreateWizard } from '@app/ui/dataset-create-wizard/dataset-create-wizard.component'; -import { DatasetCreateWizardRoutingModule } from '@app/ui/dataset-create-wizard/dataset-create-wizard.routing'; -import { DatasetDmpSelector } from '@app/ui/dataset-create-wizard/dmp-selector/dataset-dmp-selector.component'; -import { DatasetDescriptionFormModule } from '@app/ui/misc/dataset-description-form/dataset-description-form.module'; -import { OuickWizardModule } from '@app/ui/quick-wizard/quick-wizard.module'; -import { QuickWizardRoutingModule } from '@app/ui/quick-wizard/quick-wizard.routing'; -import { CommonFormsModule } from '@common/forms/common-forms.module'; -import { CommonUiModule } from '@common/ui/common-ui.module'; - -@NgModule({ - imports: [ - DatasetCreateWizardRoutingModule, - CommonUiModule, - CommonFormsModule, - AutoCompleteModule, - FormattingModule, - UrlListingModule, - ConfirmationDialogModule, - QuickWizardRoutingModule, - DatasetDescriptionFormModule, - OuickWizardModule, - ], - declarations: [ - DatasetCreateWizard, - DatasetDmpSelector, - ], - providers: [ - CanDeactivateGuard - ] -}) -export class DatasetCreateWizardModule { } diff --git a/dmp-frontend/src/app/ui/dataset-create-wizard/dataset-create-wizard.routing.ts b/dmp-frontend/src/app/ui/dataset-create-wizard/dataset-create-wizard.routing.ts deleted file mode 100644 index 97f9a4fb8..000000000 --- a/dmp-frontend/src/app/ui/dataset-create-wizard/dataset-create-wizard.routing.ts +++ /dev/null @@ -1,32 +0,0 @@ -import { NgModule } from '@angular/core'; -import { RouterModule, Routes } from '@angular/router'; -import { DatasetCreateWizard } from './dataset-create-wizard.component'; -import { DatasetDmpSelector } from './dmp-selector/dataset-dmp-selector.component'; -import { CanDeactivateGuard } from '../../library/deactivate/can-deactivate.guard'; -import { AuthGuard } from '@app/core/auth-guard.service'; - -const routes: Routes = [ - { - path: '', - component: DatasetCreateWizard, - canActivate: [AuthGuard], - data: { - breadcrumb: true - }, - canDeactivate: [CanDeactivateGuard] - }, - { - path: '', - component: DatasetDmpSelector, - canActivate: [AuthGuard], - data: { - breadcrumb: true - }, - }, -]; - -@NgModule({ - imports: [RouterModule.forChild(routes)], - exports: [RouterModule] -}) -export class DatasetCreateWizardRoutingModule { } diff --git a/dmp-frontend/src/app/ui/dataset-create-wizard/dmp-selector/dataset-dmp-selector.component.html b/dmp-frontend/src/app/ui/dataset-create-wizard/dmp-selector/dataset-dmp-selector.component.html deleted file mode 100644 index 70f480dda..000000000 --- a/dmp-frontend/src/app/ui/dataset-create-wizard/dmp-selector/dataset-dmp-selector.component.html +++ /dev/null @@ -1,20 +0,0 @@ -
- -
- - - - -
-
- - - - {{datasetProfile.label}} - - - -
-
-
diff --git a/dmp-frontend/src/app/ui/dataset-create-wizard/dmp-selector/dataset-dmp-selector.component.scss b/dmp-frontend/src/app/ui/dataset-create-wizard/dmp-selector/dataset-dmp-selector.component.scss deleted file mode 100644 index e69de29bb..000000000 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 deleted file mode 100644 index e16b96423..000000000 --- a/dmp-frontend/src/app/ui/dataset-create-wizard/dmp-selector/dataset-dmp-selector.component.ts +++ /dev/null @@ -1,104 +0,0 @@ - -import { Component, Input, OnInit } from '@angular/core'; -import { UntypedFormArray, UntypedFormControl, UntypedFormGroup } from '@angular/forms'; -import { MatStepper } from '@angular/material/stepper'; -import { ActivatedRoute, Router } from '@angular/router'; -import { DmpStatus } from '@app/core/common/enum/dmp-status'; -import { DataTableRequest } from '@app/core/model/data-table/data-table-request'; -import { DatasetProfileModel } from '@app/core/model/dataset/dataset-profile'; -import { DmpListingModel } from '@app/core/model/dmp/dmp-listing'; -import { DatasetProfileCriteria } from '@app/core/query/dataset-profile/dataset-profile-criteria'; -import { DmpCriteria } from '@app/core/query/dmp/dmp-criteria'; -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 { BaseComponent } from '@common/base/base.component'; -import { Observable } from 'rxjs'; -import { map, takeUntil } from 'rxjs/operators'; -import { DatePipe } from "@angular/common"; -import { TranslateService } from "@ngx-translate/core"; - -@Component({ - selector: 'dataset-dmp-selector-component', - templateUrl: 'dataset-dmp-selector.component.html', - styleUrls: ['./dataset-dmp-selector.component.scss'], -}) - -export class DatasetDmpSelector extends BaseComponent implements OnInit { - - dmpAutoCompleteConfiguration: SingleAutoCompleteConfiguration; - @Input() formGroup: UntypedFormGroup; - @Input() datasetFormGroup: UntypedFormGroup; - @Input() stepper: MatStepper; - formControl: UntypedFormControl; - availableProfiles: DatasetProfileModel[] = []; - - constructor( - public dmpService: DmpService, - private datasetWizardService: DatasetWizardService, - private language: TranslateService, - private datepipe: DatePipe - ) { - super(); - } - - ngOnInit() { - this.dmpAutoCompleteConfiguration = { - filterFn: this.searchDmp.bind(this), - initialItems: (extraData) => this.searchDmp(''), - displayFn: (item) => item['label'], - titleFn: (item) => item['label'], - subtitleFn: (item) => this.language.instant('QUICKWIZARD.CREATE-ADD.ADD.CREATED') + " " + this.datepipe.transform(item['creationTime'], 'yyyy-MM-dd') - }; - - this.formGroup.get('dmp').valueChanges - .pipe(takeUntil(this._destroyed)) - .subscribe(x => { - if (x) { this.loadDatasetProfiles(); } - else { - this.availableProfiles = []; - this.formGroup.get('datasetProfile').reset(); - } - }); - - this.formGroup.get('datasetProfile').valueChanges - .pipe(takeUntil(this._destroyed)) - .subscribe(x => { - (this.datasetFormGroup.get('datasetsList') as UntypedFormArray).controls.length = 0; - }); - } - - searchDmp(query: string): Observable { - const fields: Array = new Array(); - fields.push('-created'); - const dmpDataTableRequest: DataTableRequest = new DataTableRequest(0, null, { fields: fields }); - dmpDataTableRequest.criteria = new DmpCriteria(); - dmpDataTableRequest.criteria.status = DmpStatus.Draft; - dmpDataTableRequest.criteria.like = query; - - return this.dmpService.getPaged(dmpDataTableRequest, "autocomplete").pipe( - map(y => y.data)); - } - - loadDatasetProfiles() { - const datasetProfileRequestItem: RequestItem = new RequestItem(); - datasetProfileRequestItem.criteria = new DatasetProfileCriteria(); - datasetProfileRequestItem.criteria.id = this.formGroup.get('dmp').value.id; - if (datasetProfileRequestItem.criteria.id) { - this.datasetWizardService.getAvailableProfiles(datasetProfileRequestItem) - .pipe(takeUntil(this._destroyed)) - .subscribe(items => { - this.availableProfiles = items; - if (this.availableProfiles.length === 1) { - this.formGroup.get('datasetProfile').patchValue(this.availableProfiles[0]); - this.stepper.next(); - } - }); - } - } - - datasetChanged($event) { - this.stepper.next(); - } -} 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 0bc56e515..370100898 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 @@ -50,7 +50,7 @@ import { LinkToScroll, TableOfContents } from '@app/ui/misc/dataset-description-form/tableOfContentsMaterial/table-of-contents'; -import { VisibilityRulesService } from '@app/ui/misc/dataset-description-form/visibility-rules/visibility-rules.service'; +import { VisibilityRulesService } from '@app/ui/description/editor/description-form/visibility-rules/visibility-rules.service'; import { isNullOrUndefined } from '@app/utilities/enhancers/utils'; import { FormService } from '@common/forms/form-service'; import { diff --git a/dmp-frontend/src/app/ui/dataset/listing/listing-item/dataset-listing-item.component.ts b/dmp-frontend/src/app/ui/dataset/listing/listing-item/dataset-listing-item.component.ts index 2b3aded48..fa61a8994 100644 --- a/dmp-frontend/src/app/ui/dataset/listing/listing-item/dataset-listing-item.component.ts +++ b/dmp-frontend/src/app/ui/dataset/listing/listing-item/dataset-listing-item.component.ts @@ -85,11 +85,11 @@ export class DatasetListingItemComponent extends BaseComponent implements OnInit getItemLink(): string[] { // return this.isPublic ? [`/datasets/publicEdit/${this.dataset.id}`] : [`/datasets/edit/${this.dataset.id}`]; - return this.isPublic ? ['/datasets/publicOverview/' + this.dataset.id] : ['/datasets/overview/' + this.dataset.id]; + return this.isPublic ? ['/datasets/overview/public/' + this.dataset.id] : ['/datasets/overview/' + this.dataset.id]; } getDmpLink(): string[] { - return this.isPublic ? [`/explore-plans/publicOverview/${this.dataset.dmpId}`] : [`/plans/edit/${this.dataset.dmpId}`]; + return this.isPublic ? [`/explore-plans/overview/public/${this.dataset.dmpId}`] : [`/plans/edit/${this.dataset.dmpId}`]; } downloadPDF(dataset: DatasetListingModel): void { 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 5fcb6c281..c2d7f854a 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 @@ -123,7 +123,7 @@ export class DatasetOverviewComponent extends BaseComponent implements OnInit { 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 }); + // breadCrumbs.push({ parentComponentName: 'DatasetListingComponent', label: this.dataset.label, url: '/datasets/overview/public/' + this.dataset.id }); // this.breadCrumbs = observableOf(breadCrumbs); }, (error: any) => { if (error.status === 404) { @@ -290,7 +290,7 @@ export class DatasetOverviewComponent extends BaseComponent implements OnInit { dmpClicked(dmp: DmpOverviewModel) { if (this.isPublicView) { - this.router.navigate(['/explore-plans/publicOverview/' + dmp.id]); + this.router.navigate(['/explore-plans/overview/public/' + dmp.id]); } else { this.router.navigate(['/plans/overview/' + dmp.id]); } diff --git a/dmp-frontend/src/app/ui/description/dataset-wizard/dataset-editor/dataset-editor.component.html b/dmp-frontend/src/app/ui/description/dataset-wizard/dataset-editor/dataset-editor.component.html deleted file mode 100644 index c56c214e4..000000000 --- a/dmp-frontend/src/app/ui/description/dataset-wizard/dataset-editor/dataset-editor.component.html +++ /dev/null @@ -1,107 +0,0 @@ -
-
-

{{'DATASET-EDITOR.TITLE.INTRO' | translate}}

- {{'DATASET-EDITOR.TITLE.INTRO-TIP' | translate}} -
-
- -
-
-
1.1 {{'DATASET-EDITOR.FIELDS.TITLE' | translate}}*
- - -
- - - {{formGroup.get('label').getError('backendError').message}} - {{'GENERAL.VALIDATION.REQUIRED' | translate}} - -
-
-
- -
-
-
1.2 {{'DATASET-EDITOR.FIELDS.DESCRIPTION' | translate}}
- {{'DATASET-EDITOR.HINT.DESCRIPTION' | translate}} - -
- - -
- {{formGroup.get('description').getError('backendError').message}} - {{'GENERAL.VALIDATION.REQUIRED' | translate}} -
-
-
-
- - - - - -
1.4 {{'DATASET-EDITOR.FIELDS.PROFILE' | translate}}*
-
- - - -
- {{profile.label}} -
-
-
- {{formGroup.get('profile').getError('backendError').message}} - {{'GENERAL.VALIDATION.REQUIRED' | translate}} -
-
-
-
- - - - diff --git a/dmp-frontend/src/app/ui/description/dataset-wizard/dataset-editor/dataset-editor.component.ts b/dmp-frontend/src/app/ui/description/dataset-wizard/dataset-editor/dataset-editor.component.ts deleted file mode 100644 index e9b339ad4..000000000 --- a/dmp-frontend/src/app/ui/description/dataset-wizard/dataset-editor/dataset-editor.component.ts +++ /dev/null @@ -1,145 +0,0 @@ -import { Component, Input } from '@angular/core'; -import { UntypedFormGroup } from '@angular/forms'; -import { Router } from '@angular/router'; -import { BaseComponent } from '@common/base/base.component'; -import { GuidedTourService } from '@app/library/guided-tour/guided-tour.service'; -import { GuidedTour, Orientation } from '@app/library/guided-tour/guided-tour.constants'; -import { TranslateService } from '@ngx-translate/core'; -import { DatasetProfileModel } from '@app/core/model/dataset/dataset-profile'; -import { takeUntil } from 'rxjs/operators'; -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'; -import { Guid } from '@common/types/guid'; -import { nameof } from 'ts-simple-nameof'; -import { DescriptionTemplatesInSection, DmpBlueprint, DmpBlueprintDefinition, DmpBlueprintDefinitionSection, FieldInSection } from '@app/core/model/dmp-blueprint/dmp-blueprint'; - -@Component({ - selector: 'app-dataset-editor-component', - templateUrl: 'dataset-editor.component.html', - styleUrls: ['./dataset-editor.component.scss'] -}) -export class DatasetEditorComponent extends BaseComponent { - - @Input() formGroup: UntypedFormGroup; - // @Input() formGroup: FormGroup = null; - @Input() availableProfiles: DatasetProfileModel[]; - @Input() dmpId: string; - showUri: boolean = false; - dmpText: string = null; - viewOnly = false; - - constructor( - private router: Router, - private dmpBlueprintService: DmpBlueprintService, - private dialog: MatDialog, - private guidedTourService: GuidedTourService, - private language: TranslateService - ) { super(); } - - public dashboardTourDmp: GuidedTour = { - tourId: 'only-dmp-tour', - useOrb: true, - steps: [ - { - title: this.dmpText, - content: 'Step 1', - orientation: Orientation.Bottom, - highlightPadding: 3, - isStepUnique: true, - customTopOffset: 8 - } - ] - }; - - checkMinMax(event, profile: DatasetProfileModel) { - event.stopPropagation(); - const dmpSectionIndex = this.formGroup.get('dmpSectionIndex').value; - const blueprintId = this.formGroup.get('dmp').value.profile.id; - this.dmpBlueprintService.getSingle(blueprintId, - [ - [nameof(x => x.definition), nameof(x => x.sections), nameof(x => x.id)].join('.'), - [nameof(x => x.definition), nameof(x => x.sections), nameof(x => x.label)].join('.'), - [nameof(x => x.definition), nameof(x => x.sections), nameof(x => x.description)].join('.'), - [nameof(x => x.definition), nameof(x => x.sections), nameof(x => x.ordinal)].join('.'), - [nameof(x => x.definition), nameof(x => x.sections), nameof(x => x.hasTemplates)].join('.'), - - [nameof(x => x.definition), nameof(x => x.sections), nameof(x => x.fields), nameof(x => x.id)].join('.'), - [nameof(x => x.definition), nameof(x => x.sections), nameof(x => x.fields), nameof(x => x.category)].join('.'), - [nameof(x => x.definition), nameof(x => x.sections), nameof(x => x.fields), nameof(x => x.dataType)].join('.'), - [nameof(x => x.definition), nameof(x => x.sections), nameof(x => x.fields), nameof(x => x.systemFieldType)].join('.'), - [nameof(x => x.definition), nameof(x => x.sections), nameof(x => x.fields), nameof(x => x.label)].join('.'), - [nameof(x => x.definition), nameof(x => x.sections), nameof(x => x.fields), nameof(x => x.placeholder)].join('.'), - [nameof(x => x.definition), nameof(x => x.sections), nameof(x => x.fields), nameof(x => x.description)].join('.'), - [nameof(x => x.definition), nameof(x => x.sections), nameof(x => x.fields), nameof(x => x.required)].join('.'), - [nameof(x => x.definition), nameof(x => x.sections), nameof(x => x.fields), nameof(x => x.ordinal)].join('.'), - - [nameof(x => x.definition), nameof(x => x.sections), nameof(x => x.descriptionTemplates), nameof(x => x.id)].join('.'), - [nameof(x => x.definition), nameof(x => x.sections), nameof(x => x.descriptionTemplates), nameof(x => x.descriptionTemplateId)].join('.'), - [nameof(x => x.definition), nameof(x => x.sections), nameof(x => x.descriptionTemplates), nameof(x => x.label)].join('.'), - [nameof(x => x.definition), nameof(x => x.sections), nameof(x => x.descriptionTemplates), nameof(x => x.minMultiplicity)].join('.'), - [nameof(x => x.definition), nameof(x => x.sections), nameof(x => x.descriptionTemplates), nameof(x => x.maxMultiplicity)].join('.'), - ] - ) - .pipe(takeUntil(this._destroyed)) - .subscribe(result => { - const section = result.definition.sections[dmpSectionIndex]; - if(section.hasTemplates){ - const foundTemplate = section.descriptionTemplates.find(template => template.descriptionTemplateId === Guid.parse(profile.id)); - if (foundTemplate !== undefined) { - let count = 0; - if(this.formGroup.get('dmp').value.datasets != null){ - for(let dataset of this.formGroup.get('dmp').value.datasets){ - if(dataset.dmpSectionIndex === dmpSectionIndex && dataset.profile.id === foundTemplate.descriptionTemplateId){ - count++; - } - } - if(count === foundTemplate.maxMultiplicity){ - this.dialog.open(PopupNotificationDialogComponent, { - data: { - title: this.language.instant('DATASET-EDITOR.MAX-DESCRIPTION-DIALOG.TITLE'), - message: this.language.instant('DATASET-EDITOR.MAX-DESCRIPTION-DIALOG.MESSAGE') - }, maxWidth: '30em' - }); - } - else{ - this.formGroup.get('profile').setValue(profile); - } - } - } - else { - this.formGroup.get('profile').setValue(profile); - } - } - else { - this.formGroup.get('profile').setValue(profile); - } - }); - } - - getDmpText(): string { - return this.language.instant('DMP-LISTING.TEXT-INFO') + '\n\n' + - this.language.instant('DMP-LISTING.TEXT-INFO-QUESTION') + ' ' + - this.language.instant('DMP-LISTING.LINK-ZENODO') + ' ' + - this.language.instant('DMP-LISTING.GET-IDEA'); - } - - setDashboardTourDmp(label: string): void { - this.dashboardTourDmp.steps[0].title = this.getDmpText(); - this.dashboardTourDmp.steps[0].selector = '.dmp-tour-' + label; - } - - public restartTour(label: string): void { - this.setDashboardTourDmp(label); - this.guidedTourService.startTour(this.dashboardTourDmp); - - } - - public cancel(): void { - this.router.navigate(['/datasets']); - } - - public compareWith(object1: any, object2: any) { - return object1 && object2 && object1.id === object2.id; - } -} diff --git a/dmp-frontend/src/app/ui/description/dataset-wizard/description-editor.component.html b/dmp-frontend/src/app/ui/description/dataset-wizard/description-editor.component.html deleted file mode 100644 index 33a12bf33..000000000 --- a/dmp-frontend/src/app/ui/description/dataset-wizard/description-editor.component.html +++ /dev/null @@ -1,150 +0,0 @@ -
-
-
- - -
-
-
-
-
- -
{{'DMP-EDITOR.TITLE.ADD-DATASET' | translate}}
-
{{'DMP-EDITOR.TITLE.EDIT-DESCRIPTION' | translate}}
-
{{ formGroup.get('label').value }} ({{'DMP-EDITOR.CHANGES' | translate}})
-
- -
{{'DMP-EDITOR.TITLE.PREVIEW-DATASET' | translate}}
-
-
-
{{'DATASET-LISTING.TOOLTIP.TO-DMP' | translate}}
-
: {{ formGroup.get('dmp').value.label }}
- -
-
-
-
- - - - - - -
- - - -
- -
-
- - - - - - - - - - - - -
-
-
-
-
-
-
-
-
-
- chevron_left - {{'DATASET-WIZARD.ACTIONS.BACK-TO' | translate}} -
-
{{'DATASET-LISTING.TOOLTIP.DMP' | translate}}
-
-
{{'DMP-EDITOR.STEPPER.USER-GUIDE' | translate}}
-
-
-
0. {{'DMP-EDITOR.STEPPER.MAIN-INFO' | translate}} (2)
-
0. {{'DMP-EDITOR.STEPPER.MAIN-INFO' | translate}} (done)
-
-
- -
-
-
-
- - -
-
{{'DMP-EDITOR.STEPPER.NEXT' | translate}}
- chevron_right -
-
-
{{'DMP-EDITOR.STEPPER.NEXT' | translate}}
- chevron_right -
- -
-
- -
-
-
- - -
-
-
-
-
\ No newline at end of file diff --git a/dmp-frontend/src/app/ui/description/dataset-wizard/description-editor.resolver.ts b/dmp-frontend/src/app/ui/description/dataset-wizard/description-editor.resolver.ts deleted file mode 100644 index 633ed936d..000000000 --- a/dmp-frontend/src/app/ui/description/dataset-wizard/description-editor.resolver.ts +++ /dev/null @@ -1,67 +0,0 @@ -import { Injectable } from '@angular/core'; -import { ActivatedRouteSnapshot, RouterStateSnapshot } from '@angular/router'; -import { DescriptionTemplate } from '@app/core/model/description-template/description-template'; -import { Description, DescriptionField, DescriptionReference, DescriptionTag, PropertyDefinition } from '@app/core/model/description/description'; -import { Dmp, DmpDescriptionTemplate } from '@app/core/model/dmp/dmp'; -import { Reference } from '@app/core/model/reference/reference'; -import { Tag } from '@app/core/model/tag/tag'; -import { DescriptionService } from '@app/core/services/description/description.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 DescriptionEditorResolver extends BaseEditorResolver { - - constructor(private descriptionService: DescriptionService, private breadcrumbService: BreadcrumbService) { - super(); - } - - public static lookupFields(): string[] { - return [ - ...BaseEditorResolver.lookupFields(), - nameof(x => x.id), - nameof(x => x.label), - nameof(x => x.status), - nameof(x => x.description), - nameof(x => x.status), - [nameof(x => x.dmp), nameof(x => x.id)].join('.'), - - [nameof(x => x.dmpDescriptionTemplate), nameof(x => x.id)].join('.'), - - [nameof(x => x.descriptionTemplate), nameof(x => x.id)].join('.'), - - [nameof(x => x.properties), nameof(x => x.fields), nameof(x => x.key)].join('.'), - [nameof(x => x.properties), nameof(x => x.fields), nameof(x => x.value)].join('.'), - - [nameof(x => x.descriptionTags), nameof(x => x.id),].join('.'), - [nameof(x => x.descriptionTags), nameof(x => x.tag), nameof(x => x.label)].join('.'), - - [nameof(x => x.descriptionReferences), nameof(x => x.reference), nameof(x => x.id)].join('.'), - [nameof(x => x.descriptionReferences), nameof(x => x.reference), nameof(x => x.label)].join('.'), - [nameof(x => x.descriptionReferences), nameof(x => x.reference), nameof(x => x.type)].join('.'), - [nameof(x => x.descriptionReferences), nameof(x => x.reference), nameof(x => x.reference)].join('.'), - nameof(x => x.createdAt), - nameof(x => x.hash), - nameof(x => x.isActive) - ] - } - - resolve(route: ActivatedRouteSnapshot, state: RouterStateSnapshot) { - - const fields = [ - ...DescriptionEditorResolver.lookupFields() - ]; - const id = route.paramMap.get('id'); - // const cloneid = route.paramMap.get('cloneid'); - if (id != null) { - return this.descriptionService.getSingle(Guid.parse(id), fields).pipe(tap(x => this.breadcrumbService.addIdResolvedValue(x.id?.toString(), x.label)), takeUntil(this._destroyed)); - } - //TODO: check this - // else if (cloneid != null) { - // return this.descriptionService.clone(Guid.parse(cloneid), fields).pipe(tap(x => this.breadcrumbService.addIdResolvedValue(x.id?.toString(), x.label)), takeUntil(this._destroyed)); - // } - } -} diff --git a/dmp-frontend/src/app/ui/description/description.module.ts b/dmp-frontend/src/app/ui/description/description.module.ts index 6d15033b4..d24d8bab1 100644 --- a/dmp-frontend/src/app/ui/description/description.module.ts +++ b/dmp-frontend/src/app/ui/description/description.module.ts @@ -1,84 +1,19 @@ import { NgModule } from '@angular/core'; import { FormattingModule } from '@app/core/formatting.module'; -import { AutoCompleteModule } from '@app/library/auto-complete/auto-complete.module'; -import { ExportMethodDialogModule } from '@app/library/export-method-dialog/export-method-dialog.module'; -import { RichTextEditorModule } from "@app/library/rich-text-editor/rich-text-editor.module"; -import { UrlListingModule } from '@app/library/url-listing/url-listing.module'; -// import { DescriptionEditorComponent } from '@app/ui/description/description-wizard/description-editor/description-editor.component'; -// import { DescriptionWizardComponent } from '@app/ui/description/description-wizard/description-wizard.component'; -// import { DescriptionExternalReferencesEditorComponent } from '@app/ui/description/description-wizard/external-references/description-external-references-editor.component'; -// import { DescriptionExternalDataRepositoryDialogEditorComponent } from '@app/ui/description/description-wizard/external-references/editors/data-repository/description-external-data-repository-dialog-editor.component'; -// import { DescriptionExternalDescriptionDialogEditorComponent } from '@app/ui/description/description-wizard/external-references/editors/external-description/description-external-description-dialog-editor.component'; -// import { DescriptionExternalRegistryDialogEditorComponent } from '@app/ui/description/description-wizard/external-references/editors/registry/description-external-registry-dialog-editor.component'; -// import { DescriptionExternalServiceDialogEditorComponent } from '@app/ui/description/description-wizard/external-references/editors/service/description-external-service-dialog-editor.component'; -// import { PrefillDescriptionComponent } from "@app/ui/description/description-wizard/prefill-description/prefill-description.component"; import { DescriptionRoutingModule } from '@app/ui/description/description.routing'; -// import { DescriptionCriteriaComponent } from '@app/ui/description/listing/criteria/description-criteria.component'; -// import { DescriptionUploadDialogue } from '@app/ui/description/listing/criteria/description-upload-dialogue/description-upload-dialogue.component'; -import { DescriptionListingComponent } from '@app/ui/description/listing/description-listing.component'; -import { DescriptionListingItemComponent } from '@app/ui/description/listing/listing-item/description-listing-item.component'; -// import { DescriptionDescriptionFormModule } from '@app/ui/misc/description-description-form/description-description-form.module'; -// import { TableOfContentsModule } from '@app/ui/misc/description-description-form/tableOfContentsMaterial/table-of-contents.module'; -import { ExternalSourcesModule } from '@app/ui/misc/external-sources/external-sources.module'; import { CommonFormsModule } from '@common/forms/common-forms.module'; -import { FormValidationErrorsDialogModule } from '@common/forms/form-validation-errors-dialog/form-validation-errors-dialog.module'; -import { ConfirmationDialogModule } from '@common/modules/confirmation-dialog/confirmation-dialog.module'; import { CommonUiModule } from '@common/ui/common-ui.module'; -import { AngularStickyThingsModule } from '@w11k/angular-sticky-things'; -import { DescriptionCopyDialogModule } from './description-copy-dialog/description-copy-dialog.module'; -import { DescriptionOverviewModule } from './overview/description-overview.module'; -import { DescriptionEditorComponent } from './dataset-wizard/description-editor.component'; -// import { FormProgressIndicationModule } from '../misc/description-description-form/components/form-progress-indication/form-progress-indication.module'; -// import { DescriptionCopyDialogModule } from './description-wizard/description-copy-dialogue/description-copy-dialogue.module'; -// import { DescriptionCriteriaDialogComponent } from './listing/criteria/description-criteria-dialogue/description-criteria-dialog.component'; -// import { DescriptionOverviewModule } from './overview/description-overview.module'; @NgModule({ imports: [ CommonUiModule, CommonFormsModule, - UrlListingModule, FormattingModule, - ConfirmationDialogModule, - AutoCompleteModule, - ExternalSourcesModule, - ExportMethodDialogModule, - // DescriptionDescriptionFormModule, - // TableOfContentsModule, - AngularStickyThingsModule, DescriptionRoutingModule, - FormValidationErrorsDialogModule, - // DescriptionCopyDialogModule, - // DescriptionOverviewModule, - // FormProgressIndicationModule, - RichTextEditorModule, - - DescriptionCopyDialogModule, - DescriptionOverviewModule, ], declarations: [ - DescriptionListingComponent, - // DescriptionCriteriaComponent, - // DescriptionWizardComponent, - DescriptionEditorComponent, - // DescriptionExternalReferencesEditorComponent, - // DescriptionExternalDataRepositoryDialogEditorComponent, - // DescriptionExternalDescriptionDialogEditorComponent, - // DescriptionExternalRegistryDialogEditorComponent, - // DescriptionExternalServiceDialogEditorComponent, - // DescriptionUploadDialogue, - DescriptionListingItemComponent, - // DescriptionCriteriaDialogComponent, - // PrefillDescriptionComponent ], exports: [ - // DescriptionExternalReferencesEditorComponent, - // DescriptionExternalDataRepositoryDialogEditorComponent, - // DescriptionExternalDescriptionDialogEditorComponent, - // DescriptionExternalRegistryDialogEditorComponent, - // DescriptionExternalServiceDialogEditorComponent, - // DescriptionEditorComponent, - // DescriptionDescriptionFormModule ] }) export class DescriptionModule { } diff --git a/dmp-frontend/src/app/ui/description/description.routing.ts b/dmp-frontend/src/app/ui/description/description.routing.ts index 08f511956..2b2b32dc9 100644 --- a/dmp-frontend/src/app/ui/description/description.routing.ts +++ b/dmp-frontend/src/app/ui/description/description.routing.ts @@ -1,136 +1,35 @@ import { NgModule } from '@angular/core'; import { RouterModule, Routes } from '@angular/router'; -import { AuthGuard } from '../../core/auth-guard.service'; // import { DescriptionWizardComponent } from './description-wizard/description-wizard.component'; -import { DescriptionListingComponent } from './listing/description-listing.component'; -import { DescriptionOverviewComponent } from './overview/description-overview.component'; -import { CanDeactivateGuard } from '@app/library/deactivate/can-deactivate.guard'; -import { DescriptionEditorComponent } from './dataset-wizard/description-editor.component'; -import { AppPermission } from '@app/core/common/enum/permission.enum'; -import { DescriptionEditorResolver } from './dataset-wizard/description-editor.resolver'; -import { PendingChangesGuard } from '@common/forms/pending-form-changes/pending-form-changes-guard.service'; // import { DescriptionOverviewComponent } from './overview/description-overview.component'; -import { BreadcrumbService } from '@app/ui/misc/breadcrumb/breadcrumb.service'; const routes: Routes = [ { - path: '', - component: DescriptionListingComponent, - // canActivate: [AuthGuard], + path: 'overview', + loadChildren: () => import('./overview/description-overview.module').then(m => m.DescriptionOverviewModule), data: { breadcrumb: true - }, - }, - { - path: 'dmp/:dmpId', - component: DescriptionListingComponent, - canActivate: [AuthGuard], - data: { - breadcrumb: true - }, - }, - { - path: 'overview/:id', - component: DescriptionOverviewComponent, - data: { - breadcrumb: true, - title: 'GENERAL.TITLES.DATASET-OVERVIEW' - }, - }, - { - path: 'publicOverview/:publicId', - component: DescriptionOverviewComponent, - data: { - breadcrumb: true, - title: 'GENERAL.TITLES.DATASET-OVERVIEW' - }, - }, - { - path: 'edit/:id', - canActivate: [AuthGuard], - component: DescriptionEditorComponent, - canDeactivate: [PendingChangesGuard], - resolve: { - 'entity': DescriptionEditorResolver - }, - data: { - ...BreadcrumbService.generateRouteDataConfiguration({ - title: 'BREADCRUMBS.EDIT-DESCRIPTION' - }), - authContext: { - permissions: [AppPermission.EditDescription] - } } }, - // { - // path: 'new/:dmpId/:dmpSectionIndex', - // component: DescriptionWizardComponent, - // canActivate: [AuthGuard], - // data: { - // breadcrumb: true, - // title: 'GENERAL.TITLES.DATASET-NEW' - // }, - // canDeactivate:[CanDeactivateGuard] - // }, - - // { - // path: 'edit/:id/finalize', - // component: DescriptionWizardComponent, - // canActivate: [AuthGuard], - // data: { - // breadcrumb: true, - // public: false, - // title: 'GENERAL.TITLES.DATASET-EDIT', - // finalize: true - // }, - // canDeactivate:[CanDeactivateGuard] - // }, - // { - // path: 'publicEdit/:publicId', - // component: DescriptionWizardComponent, - // //canActivate: [AuthGuard], - // data: { - // public: true, - // title: 'GENERAL.TITLES.DATASET-PUBLIC-EDIT' - // }, - // canDeactivate:[CanDeactivateGuard] - // }, - // { - // path: 'new', - // component: DescriptionWizardComponent, - // canActivate: [AuthGuard], - // data: { - // breadcrumb: true, - // title: 'GENERAL.TITLES.DATASET-NEW' - // }, - // canDeactivate:[CanDeactivateGuard] - // }, - // { - // path: 'copy/:id', - // component: DescriptionWizardComponent, - // canActivate: [AuthGuard], - // data: { - // breadcrumb: true, - // title: 'GENERAL.TITLES.DATASET-COPY' - // }, - // canDeactivate:[CanDeactivateGuard] - // }, - // { - // path: 'profileupdate/:updateId', - // component: DescriptionWizardComponent, - // canActivate: [AuthGuard], - // data: { - // breadcrumb: true, - // title: 'GENERAL.TITLES.DATASET-UPDATE' - // }, - // canDeactivate:[CanDeactivateGuard] - // }, - + { + path: 'edit', + loadChildren: () => import('./editor/description-editor.module').then(m => m.DescriptionEditorModule), + data: { + breadcrumb: true + } + }, + { + path: '', + loadChildren: () => import('./listing/description-listing.module').then(m => m.DescriptionListingModule), + data: { + breadcrumb: true + }, + }, ]; @NgModule({ imports: [RouterModule.forChild(routes)], exports: [RouterModule], - providers: [DescriptionEditorResolver] + providers: [] }) export class DescriptionRoutingModule { } diff --git a/dmp-frontend/src/app/ui/description/editor/description-base-fields-editor/description-base-fields-editor.component.html b/dmp-frontend/src/app/ui/description/editor/description-base-fields-editor/description-base-fields-editor.component.html new file mode 100644 index 000000000..db8d56585 --- /dev/null +++ b/dmp-frontend/src/app/ui/description/editor/description-base-fields-editor/description-base-fields-editor.component.html @@ -0,0 +1,58 @@ +
+
+

{{'DATASET-EDITOR.TITLE.INTRO' | translate}}

+ {{'DATASET-EDITOR.TITLE.INTRO-TIP' | translate}} +
+
+ +
+
+
1.1 {{'DATASET-EDITOR.FIELDS.TITLE' | translate}}*
+
+ + + {{formGroup.get('label').getError('backendError').message}} + {{'GENERAL.VALIDATION.REQUIRED' | translate}} + +
+
+
+ +
+
+
1.2 {{'DATASET-EDITOR.FIELDS.DESCRIPTION' | translate}}
+ {{'DATASET-EDITOR.HINT.DESCRIPTION' | translate}} +
+ + +
+ {{formGroup.get('description').getError('backendError').message}} + {{'GENERAL.VALIDATION.REQUIRED' | translate}} +
+
+
+
+ + + + +
1.4 {{'DATASET-EDITOR.FIELDS.PROFILE' | translate}}*
+ +
+
\ No newline at end of file diff --git a/dmp-frontend/src/app/ui/description/dataset-wizard/dataset-editor/dataset-editor.component.scss b/dmp-frontend/src/app/ui/description/editor/description-base-fields-editor/description-base-fields-editor.component.scss similarity index 98% rename from dmp-frontend/src/app/ui/description/dataset-wizard/dataset-editor/dataset-editor.component.scss rename to dmp-frontend/src/app/ui/description/editor/description-base-fields-editor/description-base-fields-editor.component.scss index b006bc845..76fe2f2df 100644 --- a/dmp-frontend/src/app/ui/description/dataset-wizard/dataset-editor/dataset-editor.component.scss +++ b/dmp-frontend/src/app/ui/description/editor/description-base-fields-editor/description-base-fields-editor.component.scss @@ -1,4 +1,4 @@ -.dataset-editor { +.description-base-fields-editor { .intro { text-align: left; font-weight: 400; diff --git a/dmp-frontend/src/app/ui/description/editor/description-base-fields-editor/description-base-fields-editor.component.ts b/dmp-frontend/src/app/ui/description/editor/description-base-fields-editor/description-base-fields-editor.component.ts new file mode 100644 index 000000000..478f45437 --- /dev/null +++ b/dmp-frontend/src/app/ui/description/editor/description-base-fields-editor/description-base-fields-editor.component.ts @@ -0,0 +1,90 @@ +import { Component, Input } from '@angular/core'; +import { UntypedFormGroup } from '@angular/forms'; +import { DescriptionTemplate } from '@app/core/model/description-template/description-template'; +import { BaseComponent } from '@common/base/base.component'; + +@Component({ + selector: 'app-description-base-fields-editor-component', + templateUrl: 'description-base-fields-editor.component.html', + styleUrls: ['./description-base-fields-editor.component.scss'] +}) +export class DescriptionBaseFieldsEditorComponent extends BaseComponent { + + @Input() formGroup: UntypedFormGroup; + @Input() availableDescriptionTemplates: DescriptionTemplate[]; + @Input() dmpId: string; + viewOnly = false; //TODO: not used. + + constructor( + ) { super(); } + + checkMinMax(event, profile: DescriptionTemplate) { + //TODO: Add logic for validating description templates. + // event.stopPropagation(); + // const dmpSectionIndex = this.formGroup.get('dmpSectionIndex').value; + // const blueprintId = this.formGroup.get('dmp').value.profile.id; + // this.dmpBlueprintService.getSingle(blueprintId, + // [ + // [nameof(x => x.definition), nameof(x => x.sections), nameof(x => x.id)].join('.'), + // [nameof(x => x.definition), nameof(x => x.sections), nameof(x => x.label)].join('.'), + // [nameof(x => x.definition), nameof(x => x.sections), nameof(x => x.description)].join('.'), + // [nameof(x => x.definition), nameof(x => x.sections), nameof(x => x.ordinal)].join('.'), + // [nameof(x => x.definition), nameof(x => x.sections), nameof(x => x.hasTemplates)].join('.'), + + // [nameof(x => x.definition), nameof(x => x.sections), nameof(x => x.fields), nameof(x => x.id)].join('.'), + // [nameof(x => x.definition), nameof(x => x.sections), nameof(x => x.fields), nameof(x => x.category)].join('.'), + // [nameof(x => x.definition), nameof(x => x.sections), nameof(x => x.fields), nameof(x => x.dataType)].join('.'), + // [nameof(x => x.definition), nameof(x => x.sections), nameof(x => x.fields), nameof(x => x.systemFieldType)].join('.'), + // [nameof(x => x.definition), nameof(x => x.sections), nameof(x => x.fields), nameof(x => x.label)].join('.'), + // [nameof(x => x.definition), nameof(x => x.sections), nameof(x => x.fields), nameof(x => x.placeholder)].join('.'), + // [nameof(x => x.definition), nameof(x => x.sections), nameof(x => x.fields), nameof(x => x.description)].join('.'), + // [nameof(x => x.definition), nameof(x => x.sections), nameof(x => x.fields), nameof(x => x.required)].join('.'), + // [nameof(x => x.definition), nameof(x => x.sections), nameof(x => x.fields), nameof(x => x.ordinal)].join('.'), + + // [nameof(x => x.definition), nameof(x => x.sections), nameof(x => x.descriptionTemplates), nameof(x => x.id)].join('.'), + // [nameof(x => x.definition), nameof(x => x.sections), nameof(x => x.descriptionTemplates), nameof(x => x.descriptionTemplateId)].join('.'), + // [nameof(x => x.definition), nameof(x => x.sections), nameof(x => x.descriptionTemplates), nameof(x => x.label)].join('.'), + // [nameof(x => x.definition), nameof(x => x.sections), nameof(x => x.descriptionTemplates), nameof(x => x.minMultiplicity)].join('.'), + // [nameof(x => x.definition), nameof(x => x.sections), nameof(x => x.descriptionTemplates), nameof(x => x.maxMultiplicity)].join('.'), + // ] + // ) + // .pipe(takeUntil(this._destroyed)) + // .subscribe(result => { + // const section = result.definition.sections[dmpSectionIndex]; + // if(section.hasTemplates){ + // const foundTemplate = section.descriptionTemplates.find(template => template.descriptionTemplateId === Guid.parse(profile.id)); + // if (foundTemplate !== undefined) { + // let count = 0; + // if(this.formGroup.get('dmp').value.datasets != null){ + // for(let dataset of this.formGroup.get('dmp').value.datasets){ + // if(dataset.dmpSectionIndex === dmpSectionIndex && dataset.profile.id === foundTemplate.descriptionTemplateId){ + // count++; + // } + // } + // if(count === foundTemplate.maxMultiplicity){ + // this.dialog.open(PopupNotificationDialogComponent, { + // data: { + // title: this.language.instant('DATASET-EDITOR.MAX-DESCRIPTION-DIALOG.TITLE'), + // message: this.language.instant('DATASET-EDITOR.MAX-DESCRIPTION-DIALOG.MESSAGE') + // }, maxWidth: '30em' + // }); + // } + // else{ + // this.formGroup.get('profile').setValue(profile); + // } + // } + // } + // else { + // this.formGroup.get('profile').setValue(profile); + // } + // } + // else { + // this.formGroup.get('profile').setValue(profile); + // } + // }); + } + + public compareWith(object1: any, object2: any) { + return object1 && object2 && object1.id === object2.id; + } +} diff --git a/dmp-frontend/src/app/ui/description/editor/description-editor.component.html b/dmp-frontend/src/app/ui/description/editor/description-editor.component.html new file mode 100644 index 000000000..209e71324 --- /dev/null +++ b/dmp-frontend/src/app/ui/description/editor/description-editor.component.html @@ -0,0 +1,143 @@ +
+
+
+ + +
+
+
+
+
+ +
{{'DESCRIPTION-EDITOR.TITLE.ADD-DATASET' | translate}}
+
{{'DESCRIPTION-EDITOR.TITLE.EDIT-DESCRIPTION' | translate}}
+
{{ formGroup.get('label').value }} ({{'DESCRIPTION-EDITOR.CHANGES' | translate}})
+
+ +
{{'DESCRIPTION-EDITOR.TITLE.PREVIEW-DATASET' | translate}}
+
+
+
{{'DESCRIPTION-EDITOR.TOOLTIP.TO-DMP' | translate}}
+
: {{ item.dmp.label }}
+ +
+
+
+
+ + + + + + +
+ + + +
+ +
+
+ + + + + + + + + + +
+
+
+
+
+
+
+
+
+
+ chevron_left + {{'DESCRIPTION-EDITOR.ACTIONS.BACK-TO' | translate}} +
+
{{'DESCRIPTION-EDITOR.TOOLTIP.DMP' | translate}}
+
+
{{'DESCRIPTION-EDITOR.STEPPER.USER-GUIDE' | translate}}
+
+
+
0. {{'DESCRIPTION-EDITOR.STEPPER.MAIN-INFO' | translate}} (2)
+
0. {{'DESCRIPTION-EDITOR.STEPPER.MAIN-INFO' | translate}} (done)
+
+
+ +
+
+
+
+ + +
+
{{'DESCRIPTION-EDITOR.STEPPER.NEXT' | translate}}
+ chevron_right +
+
+
{{'DESCRIPTION-EDITOR.STEPPER.NEXT' | translate}}
+ chevron_right +
+ +
+
+ +
+
+
+ + +
+
+
+
+
\ No newline at end of file diff --git a/dmp-frontend/src/app/ui/description/dataset-wizard/description-editor.component.scss b/dmp-frontend/src/app/ui/description/editor/description-editor.component.scss similarity index 100% rename from dmp-frontend/src/app/ui/description/dataset-wizard/description-editor.component.scss rename to dmp-frontend/src/app/ui/description/editor/description-editor.component.scss diff --git a/dmp-frontend/src/app/ui/description/dataset-wizard/description-editor.component.ts b/dmp-frontend/src/app/ui/description/editor/description-editor.component.ts similarity index 72% rename from dmp-frontend/src/app/ui/description/dataset-wizard/description-editor.component.ts rename to dmp-frontend/src/app/ui/description/editor/description-editor.component.ts index 371c917b2..cf2760644 100644 --- a/dmp-frontend/src/app/ui/description/dataset-wizard/description-editor.component.ts +++ b/dmp-frontend/src/app/ui/description/editor/description-editor.component.ts @@ -1,27 +1,11 @@ -import { Location } from '@angular/common'; -import { HttpClient } from '@angular/common/http'; import { Component, OnInit, ViewChild } from '@angular/core'; -import { AbstractControl, UntypedFormArray, UntypedFormControl, UntypedFormGroup } from '@angular/forms'; +import { UntypedFormGroup } from '@angular/forms'; import { MatDialog } from '@angular/material/dialog'; -import { MatSnackBar } from '@angular/material/snack-bar'; -import { ActivatedRoute, Router } from '@angular/router'; +import { ActivatedRoute, Params, Router } from '@angular/router'; import { DescriptionStatus } from '@app/core/common/enum/description-status'; import { DmpStatus } from '@app/core/common/enum/dmp-status'; -import { SaveType } from '@app/core/common/enum/save-type'; -import { DataTableRequest } from '@app/core/model/data-table/data-table-request'; -import { DmpModel } from '@app/core/model/dmp/dmp'; -import { DmpListingModel } from '@app/core/model/dmp/dmp-listing'; -import { LockModel } from '@app/core/model/lock/lock.model'; -import { UserInfoListingModel } from '@app/core/model/user/user-info-listing'; -import { DmpCriteria } from '@app/core/query/dmp/dmp-criteria'; -import { RequestItem } from '@app/core/query/request-item'; import { AuthService } from '@app/core/services/auth/auth.service'; -import { ConfigurationService } from '@app/core/services/configuration/configuration.service'; import { DmpService } from '@app/core/services/dmp/dmp.service'; -import { - ExternalSourcesConfigurationService -} from '@app/core/services/external-sources/external-sources-configuration.service'; -import { ExternalSourcesService } from '@app/core/services/external-sources/external-sources.service'; import { LockService } from '@app/core/services/lock/lock.service'; import { MatomoService } from '@app/core/services/matomo/matomo-service'; import { @@ -29,37 +13,34 @@ import { UiNotificationService } from '@app/core/services/notification/ui-notification-service'; import { FileUtils } from '@app/core/services/utilities/file-utils.service'; -import { SingleAutoCompleteConfiguration } from '@app/library/auto-complete/single/single-auto-complete-configuration'; -import { CheckDeactivateBaseComponent } from '@app/library/deactivate/deactivate.component'; import { PopupNotificationDialogComponent } from '@app/library/notification/popup/popup-notification.component'; // 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 { 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, interval, of as observableOf } from 'rxjs'; -import { catchError, debounceTime, filter, map, takeUntil } from 'rxjs/operators'; -import { DescriptionEditorService } from './description-editor.service'; -import { BaseEditor } from '@common/base/base-editor'; -import { DescriptionEditorModel } from './description-editor.model'; -import { Description, DescriptionPersist } from '@app/core/model/description/description'; +import { DatePipe } from '@angular/common'; +import { IsActive } from '@app/core/common/enum/is-active.enum'; import { AppPermission } from '@app/core/common/enum/permission.enum'; -import { HttpErrorHandlingService } from '@common/modules/errors/error-handling/http-error-handling.service'; -import { QueryParamsService } from '@app/core/services/utilities/query-params.service'; -import { FilterService } from '@common/modules/text-filter/filter-service'; -import { EnumUtils } from '@app/core/services/utilities/enum-utils.service'; +import { Rule } from '@app/core/model/dataset-profile-definition/rule'; +import { Description, DescriptionPersist } from '@app/core/model/description/description'; import { DescriptionService } from '@app/core/services/description/description.service'; import { LoggingService } from '@app/core/services/logging/logging-service'; +import { EnumUtils } from '@app/core/services/utilities/enum-utils.service'; +import { QueryParamsService } from '@app/core/services/utilities/query-params.service'; +import { VisibilityRulesService } from '@app/ui/description/editor/description-form/visibility-rules/visibility-rules.service'; +import { isNullOrUndefined } from '@app/utilities/enhancers/utils'; +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 { DescriptionEditorModel } from './description-editor.model'; import { DescriptionEditorResolver } from './description-editor.resolver'; -import { IsActive } from '@app/core/common/enum/is-active.enum'; -import { DatePipe } from '@angular/common'; +import { DescriptionEditorService } from './description-editor.service'; +import { ToCEntry } from './table-of-contents/models/toc-entry'; +import { TableOfContentsComponent } from './table-of-contents/table-of-contents.component'; +import { ToCEntryType } from './table-of-contents/models/toc-entry-type.enum'; @Component({ selector: 'app-description-editor-component', @@ -72,6 +53,7 @@ export class DescriptionEditorComponent extends BaseEditor = []; // DescriptionSectionFieldCategory = DescriptionSectionFieldCategory; @@ -89,6 +71,14 @@ export class DescriptionEditorComponent extends BaseEditor { + const isPublicDescription = params['public']; + const itemId = params['id']; + const newDmpId = params['newDmpId']; + // const publicId = params['publicId']; + // this.dmpId = params['dmpId']; + // this.dmpSectionIndex = parseInt(params['dmpSectionIndex']); + // this.newDmpId = queryParams['newDmpId']; + // this.publicId = params['publicId']; + // this.profileUpdateId = params['updateId']; + // this.finalize = data.finalize; + // this.itemId ? this.downloadDocumentId = this.itemId : this.downloadDocumentId = this.publicId + + this.viewOnly = isPublicDescription; + // if (itemId != null) { + // this.isNew = false; + // this.isPublicView = false; + // this.descriptionService.getSingle(itemId, this.lookupFields()) + // .pipe(takeUntil(this._destroyed)) + // .subscribe(data => { + // this.description = data; + // this.researchers = this.referenceService.getReferencesForTypes(this.description?.dmp?.dmpReferences, [ReferenceType.Researcher]); + // // this.users = this.description.dmp.users; + // this.checkLockStatus(this.description.id); + // this.setIsUserOwner(); + // }, (error: any) => { + // if (error.status === 404) { + // return this.onFetchingDeletedCallbackError('/descriptions/'); + // } + // if (error.status === 403) { + // return this.onFetchingForbiddenCallbackError('/descriptions/'); + // } + // }); + // } + // else if (publicId != null) { + // this.isNew = false; + // this.isFinalized = true; + // this.isPublicView = true; + // this.descriptionService.getPublicSingle(publicId, this.lookupFields()) + // .pipe(takeUntil(this._destroyed)) + // .subscribe(data => { + // this.description = data; + // this.researchers = this.referenceService.getReferencesForTypes(this.description?.dmp?.dmpReferences, [ReferenceType.Researcher]); + // // this.users = this.description.dmp.users; + // // const breadCrumbs = []; + // // breadCrumbs.push({ parentComponentName: null, label: this.language.instant('NAV-BAR.PUBLIC DESCRIPTIONS'), url: "/explore" }); + // // breadCrumbs.push({ parentComponentName: 'DescriptionListingComponent', label: this.description.label, url: '/descriptions/overview/public/' + this.description.id }); + // // this.breadCrumbs = observableOf(breadCrumbs); + // }, (error: any) => { + // if (error.status === 404) { + // return this.onFetchingDeletedCallbackError('/explore-descriptions'); + // } + // if (error.status === 403) { + // return this.onFetchingForbiddenCallbackError('/explore-descriptions'); + // } + // }); + // } + if (itemId != null && newDmpId == null) { + this.isNew = false; + this.lockService.checkLockStatus(itemId).pipe(takeUntil(this._destroyed)).subscribe(lockStatus => { + this.lockStatus = lockStatus; + if (this.item.status === DescriptionStatus.Finalized || lockStatus) { + this.formGroup.disable(); + this.viewOnly = true; + } + if (lockStatus) { + this.dialog.open(PopupNotificationDialogComponent, { + data: { + title: this.language.instant('DATASET-WIZARD.LOCKED.TITLE'), + message: this.language.instant('DATASET-WIZARD.LOCKED.MESSAGE') + }, maxWidth: '30em' + }); + } + + if (!lockStatus && !isNullOrUndefined(this.authService.currentAccountIsAuthenticated())) { + //TODO: lock it. + // const lockedBy: UserInfoListingModel = { + // email: this.authService.getUserProfileEmail(), + // id: this.authService.userId()?.toString(), + // name: this.authService.getPrincipalName(), + // role: 0 //TODO + // //role: this.authService.getRoles()?.at(0) + // } + // this.lock = new LockModel(data.id, lockedBy); + + // this.lockService.createOrUpdate(this.lock).pipe(takeUntil(this._destroyed)).subscribe(async result => { + // this.lock.id = Guid.parse(result); + // interval(this.configurationService.lockInterval).pipe(takeUntil(this._destroyed)).subscribe(() => this.pumpLock()); + // }); + } + // this.loadDescriptionProfiles(); + // this.registerFormListeners(); + }); + } + + // if (this.itemId != null && this.newDmpId == null) { + // this.isNew = false; + // this.descriptionService.getSingle(this.itemId) + // .pipe(takeUntil(this._destroyed)) + // .subscribe(data => { + // this.lockService.checkLockStatus(data.id).pipe(takeUntil(this._destroyed)).subscribe(lockStatus => { + // this.lockStatus = lockStatus; + // this.descriptionModel = new DescriptionEditorModel().fromModel(data); + // this.dmpSectionIndex = this.descriptionModel.dmpSectionIndex; + // this.needsUpdate(); + // // this.breadCrumbs = observableOf([ + // // { + // // parentComponentName: null, + // // label: this.descriptionModel.label, + // // url: '/descriptions/edit/' + this.descriptionModel.id, + // // notFoundResolver: [ + // // { + // // parentComponentName: null, + // // label: this.language.instant('NAV-BAR.MY-DATASET-DESCRIPTIONS').toUpperCase(), + // // url: '/descriptions' + // // }, + // // ] + // // }]); + // this.formGroup = this.descriptionModel.buildForm(); + // let profiles = this.descriptionModel.dmp.profiles.filter(profile => profile.data.dmpSectionIndex.includes(this.descriptionModel.dmpSectionIndex)); + // for (var profile of profiles) { + // this.availableDescriptionTemplates.push({ id: profile.descriptionTemplateId, label: profile.label, description: "" }) + // } + // this.formGroupRawValue = JSON.parse(JSON.stringify(this.formGroup.getRawValue())); + // this.editMode = this.descriptionModel.status === DescriptionStatus.Draft; + // if (this.descriptionModel.status === DescriptionStatus.Finalized || lockStatus) { + // this.formGroup.disable(); + // this.viewOnly = true; + // } + // if (!lockStatus && !isNullOrUndefined(this.authService.currentAccountIsAuthenticated())) { + // const lockedBy: UserInfoListingModel = { + // email: this.authService.getUserProfileEmail(), + // id: this.authService.userId()?.toString(), + // name: this.authService.getPrincipalName(), + // role: 0 //TODO + // //role: this.authService.getRoles()?.at(0) + // } + // this.lock = new LockModel(data.id, lockedBy); + + // this.lockService.createOrUpdate(this.lock).pipe(takeUntil(this._destroyed)).subscribe(async result => { + // this.lock.id = Guid.parse(result); + // interval(this.configurationService.lockInterval).pipe(takeUntil(this._destroyed)).subscribe(() => this.pumpLock()); + // }); + // } + // // if (this.viewOnly) { this.formGroup.disable(); } // For future use, to make Description edit like DMP. + // this.loadDescriptionProfiles(); + // this.registerFormListeners(); + + // if (lockStatus) { + // this.dialog.open(PopupNotificationDialogComponent, { + // data: { + // title: this.language.instant('DATASET-WIZARD.LOCKED.TITLE'), + // message: this.language.instant('DATASET-WIZARD.LOCKED.MESSAGE') + // }, maxWidth: '30em' + // }); + // } + // if (this.finalize && !this.lockStatus && !this.viewOnly) { + // setTimeout(() => { + // this.saveFinalize(); + // }, 0); + // } + // // this.availableProfiles = this.descriptionModel.dmp.profiles; + // }); + // }, + // error => { + // switch (error.status) { + // case 403: + // this.uiNotificationService.snackBarNotification(this.language.instant('DATASET-WIZARD.MESSAGES.DATASET-NOT-ALLOWED'), SnackBarNotificationLevel.Error); + // break; + // case 404: + // this.uiNotificationService.snackBarNotification(this.language.instant('DATASET-WIZARD.MESSAGES.DATASET-NOT-FOUND'), SnackBarNotificationLevel.Error); + // break; + // default: + // this.uiNotificationService.snackBarNotification(this.language.instant('GENERAL.ERRORS.HTTP-REQUEST-ERROR'), SnackBarNotificationLevel.Error); + // } + // this.router.navigate(['/descriptions/']); + // return observableOf(null); + // }); + // } else if (this.dmpId != null) { + // this.isNew = true; + // this.dmpService.getSingle(this.dmpId).pipe(map(data => data as DmpModel)) + // .pipe(takeUntil(this._destroyed)) + // .subscribe(data => { + // this.descriptionModel = new DescriptionEditorModel(); + // setTimeout(() => { + // this.descriptionModel.dmp = data; + // this.descriptionModel.dmpSectionIndex = this.dmpSectionIndex; + // this.formGroup = this.descriptionModel.buildForm(); + // let profiles = this.descriptionModel.dmp.profiles.filter(profile => profile.data.dmpSectionIndex.includes(this.dmpSectionIndex)); + // for (var profile of profiles) { + // this.availableDescriptionTemplates.push({ id: profile.descriptionTemplateId, label: profile.label, description: "" }) + // } + // this.formGroupRawValue = JSON.parse(JSON.stringify(this.formGroup.getRawValue())); + // this.editMode = this.descriptionModel.status === DescriptionStatus.Draft; + // this.formGroup.get('dmp').disable(); + // const dialogRef = this.dialog.open(PrefillDescriptionComponent, { + // width: '590px', + // minHeight: '200px', + // restoreFocus: false, + // data: { + // availableProfiles: this.availableDescriptionTemplates, + // descriptionFormGroup: this.formGroup + // }, + // panelClass: 'custom-modalbox' + // }); + // dialogRef.afterClosed().subscribe(result => { + // if (result) { + // this.descriptionModel = this.descriptionModel.fromModel(result); + // this.descriptionModel.dmp = data; + // this.descriptionModel.dmpSectionIndex = this.dmpSectionIndex; + // this.formGroup = this.descriptionModel.buildForm(); + // this.formGroupRawValue = JSON.parse(JSON.stringify(this.formGroup.getRawValue())); + // this.formGroup.get('dmp').disable(); + // this.loadDescriptionProfiles(); + // this.registerFormListeners(); + // } + // }) + // this.loadDescriptionProfiles(); + // this.registerFormListeners(); + // // this.availableProfiles = data.profiles; + + // // this.breadCrumbs = observableOf([ + // // { + // // parentComponentName: null, + // // label: this.language.instant('NAV-BAR.MY-DATASET-DESCRIPTIONS'), + // // url: '/descriptions', + // // notFoundResolver: [ + // // // { + // // // parentComponentName: null, + // // // label: this.descriptionModel.dmp.grant.label, + // // // url: '/grants/edit/' + this.descriptionModel.dmp.grant.id + // // // }, + // // { + // // parentComponentName: null, + // // label: this.descriptionModel.dmp.label, + // // url: '/plans/edit/' + this.descriptionModel.dmp.id, + // // }] + // // }]); + // }); + // }); + // } else if (this.newDmpId != null) { + // this.isNew = false; + // this.isCopy = true; + // this.descriptionService.getSingle(this.itemId) + // .pipe(takeUntil(this._destroyed)) + // .subscribe(data => { + // this.lockService.checkLockStatus(data.id).pipe(takeUntil(this._destroyed)).subscribe(lockStatus => { + // this.lockStatus = lockStatus; + // this.descriptionModel = new DescriptionEditorModel().fromModel(data); + // this.dmpSectionIndex = this.descriptionModel.dmpSectionIndex; + // this.descriptionModel.status = 0; + // this.formGroup = this.descriptionModel.buildForm(); + // this.formGroup.get('id').setValue(null); + // this.dmpService.getSingleNoDescriptions(this.newDmpId).pipe(map(data => data as DmpModel)) + // .pipe(takeUntil(this._destroyed)) + // .subscribe(data => { + // setTimeout(() => { + // this.descriptionModel.dmp = data; + // this.formGroup.get('dmp').setValue(this.descriptionModel.dmp); + // this.formGroupRawValue = JSON.parse(JSON.stringify(this.formGroup.getRawValue())); + + // this.loadDescriptionProfiles(); + // // this.breadCrumbs = observableOf([ + // // { + // // parentComponentName: null, + // // label: this.language.instant('NAV-BAR.MY-DATASET-DESCRIPTIONS'), + // // url: '/descriptions', + // // notFoundResolver: [ + // // // { + // // // parentComponentName: null, + // // // label: this.descriptionModel.dmp.grant.label, + // // // url: '/grants/edit/' + this.descriptionModel.dmp.grant.id + // // // }, + // // { + // // parentComponentName: null, + // // label: this.descriptionModel.dmp.label, + // // url: '/plans/edit/' + this.descriptionModel.dmp.id, + // // } + // // ] + // // }]); + // }); + // }); + // this.editMode = this.descriptionModel.status === DescriptionStatus.Draft; + // if (this.descriptionModel.status === DescriptionStatus.Finalized || lockStatus) { + // this.formGroup.disable(); + // this.viewOnly = true; + // } + // if (!lockStatus && !isNullOrUndefined(this.authService.currentAccountIsAuthenticated())) { + // const lockedBy: UserInfoListingModel = { + // email: this.authService.getUserProfileEmail(), + // id: this.authService.userId()?.toString(), + // name: this.authService.getPrincipalName(), + // role: 0 //TODO + // //role: this.authService.getRoles()?.at(0) + // } + // this.lock = new LockModel(data.id, lockedBy); + + // this.lockService.createOrUpdate(this.lock).pipe(takeUntil(this._destroyed)).subscribe(async result => { + // this.lock.id = Guid.parse(result); + // interval(this.configurationService.lockInterval).pipe(takeUntil(this._destroyed)).subscribe(() => this.pumpLock()); + // }); + // } + // // if (this.viewOnly) { this.formGroup.disable(); } // For future use, to make Description edit like DMP. + // this.loadDescriptionProfiles(); + // // this.availableProfiles = data.dmp.profiles; + // }) + // }); + // } else if (this.publicId != null) { // For Finalized -> Public Descriptions + // this.isNew = false; + // this.descriptionService.getSinglePublic(this.publicId) + // .pipe(takeUntil(this._destroyed)).pipe( + // catchError((error: any) => { + // this.uiNotificationService.snackBarNotification(error.error.message, SnackBarNotificationLevel.Error); + // this.router.navigate(['/descriptions/publicEdit/' + this.publicId]); + // return observableOf(null); + // })) + // .subscribe(data => { + // if (data) { + // this.descriptionModel = new DescriptionEditorModel().fromModel(data); + // this.formGroup = this.descriptionModel.buildForm(); + // this.formGroupRawValue = JSON.parse(JSON.stringify(this.formGroup.getRawValue())); + // this.formGroup.disable(); + // this.viewOnly = true; + // this.editMode = this.descriptionModel.status === DescriptionStatus.Draft; + // this.formGroup.get('dmp').setValue(this.descriptionModel.dmp); + // const breadcrumbs = []; + // breadcrumbs.push({ + // parentComponentName: null, + // label: this.language.instant('NAV-BAR.PUBLIC DATASETS'), + // url: '/explore-descriptions' + // }); + // breadcrumbs.push({ + // parentComponentName: null, + // label: this.descriptionModel.label, + // url: '/descriptions/publicEdit/' + this.descriptionModel.id + // }); + // // this.breadCrumbs = observableOf(breadcrumbs); + // } + // }); + // this.publicMode = true; + // } else if (this.profileUpdateId != null) { + // this.descriptionService.updateDescriptionProfile(this.profileUpdateId) + // .pipe(takeUntil(this._destroyed)) + // .subscribe(data => { + // this.descriptionModel = new DescriptionEditorModel().fromModel(data); + // 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: '/descriptions', + // // notFoundResolver: [ + // // // { + // // // parentComponentName: null, + // // // label: this.descriptionModel.dmp.grant.label, + // // // url: '/grants/edit/' + this.descriptionModel.dmp.grant.id + // // // }, + // // { + // // parentComponentName: null, + // // label: this.descriptionModel.dmp.label, + // // url: '/plans/edit/' + this.descriptionModel.dmp.id, + // // }, + // // ] + // // }]); + // this.formGroup = this.descriptionModel.buildForm(); + // this.editMode = this.descriptionModel.status === DescriptionStatus.Draft; + // if (this.descriptionModel.status === DescriptionStatus.Finalized) { + // this.formGroup.disable(); + // this.viewOnly = true; + // } + // // if (this.viewOnly) { this.formGroup.disable(); } // For future use, to make Description edit like DMP. + // this.loadDescriptionProfiles(); + // }); + + // } else { + // this.descriptionModel = new DescriptionEditorModel(); + // this.formGroup = this.descriptionModel.buildForm(); + // this.formGroupRawValue = JSON.parse(JSON.stringify(this.formGroup.getRawValue())); + + // this.editMode = this.descriptionModel.status === DescriptionStatus.Draft; + // if (this.descriptionModel.status === DescriptionStatus.Finalized) { + // this.formGroup.disable(); + // this.viewOnly = true; + // } + // //if (this.viewOnly) { this.formGroup.disable(); } // For future use, to make Description edit like DMP. + // this.registerFormListeners(); + // this.dmpValueChanged(null); + // // this.breadCrumbs = observableOf([ + // // { + // // parentComponentName: null, + // // label: this.language.instant('DATASET-LISTING.ACTIONS.CREATE-NEW').toUpperCase(), + // // url: '/descriptions/new/' + // // }]); + // } + }); + } getItem(itemId: Guid, successFunction: (item: Description) => void) { @@ -148,6 +552,7 @@ export class DescriptionEditorComponent extends BaseEditor entry.id === fieldSet.id); + this.step = index + (selected.type === ToCEntryType.FieldSet ? 1 : 0.5); + } else { + this.step = 0; + this.resetScroll(); + } + } + } + + getFirstFieldSet(entry: ToCEntry): ToCEntry { + if (entry.type === ToCEntryType.FieldSet && !this.table0fContents.internalTable.hiddenEntries.find(hiddenEntry => hiddenEntry === entry.id.toString())) { + return entry; + } else { + let subEntries = entry.subEntries.filter(subEntry => !this.table0fContents.internalTable.hiddenEntries.find(hiddenEntry => hiddenEntry === subEntry.id.toString())); + if (subEntries.length > 0) { + return this.getFirstFieldSet(subEntries[0]); + } else { + return null; + } + } + } + + private resetScroll() { + document.getElementById('description-editor-form').scrollTop = 0; + } + + get visibleFieldSets(): ToCEntry[] { + let fieldSets = []; + let arrays = this.table0fContents ? this.table0fContents.tocentries. + filter(entry => !this.table0fContents.internalTable.hiddenEntries.find(hiddenEntry => hiddenEntry === entry.id.toString())).map(entry => { + return this.getEntryVisibleFieldSets(entry); + }) + : []; + arrays.forEach(array => { + fieldSets = fieldSets.concat(array); + }); + return fieldSets; + } + + getEntryVisibleFieldSets(entry: ToCEntry): ToCEntry[] { + let fieldSets = []; + if (entry.type === ToCEntryType.FieldSet && !this.table0fContents.internalTable.hiddenEntries.find(hiddenEntry => hiddenEntry === entry.id.toString())) { + fieldSets.push(entry); + } else if (entry.type !== ToCEntryType.FieldSet) { + entry.subEntries.forEach(subEntry => { + fieldSets = fieldSets.concat(this.getEntryVisibleFieldSets(subEntry)); + }); + } + return fieldSets; + } + + // registerFormListeners() { + // // const dmpSubscription = + // this.formGroup.get('dmp').valueChanges + // .pipe(takeUntil(this._destroyed)) + // .subscribe(x => { + // this.dmpValueChanged(x); + // }); + // // const profileSubscription = + // this.formGroup.get('profile').valueChanges + // .pipe(takeUntil(this._destroyed)) + // .subscribe(x => { + // if (x) { + // this.showtocentriesErrors = false; + // this.descriptionProfileValueChanged(x.id); + // this.formChanged(); + // } + // }); + // // const labelSubscription = + // this.formGroup.get('label').valueChanges + // .pipe(takeUntil(this._destroyed)) + // .subscribe(x => { + // this.formChanged(); + // }); + // // const descriptionSubscription = + // this.formGroup.get('description').valueChanges + // .pipe(takeUntil(this._destroyed)) + // .subscribe(x => { + // this.formChanged(); + // }); + // // const uriSubscription = + // this.formGroup.get('uri').valueChanges + // .pipe(takeUntil(this._destroyed)) + // .subscribe(x => { + // this.formChanged(); + // }); + // // const tagsSubscription = + // this.formGroup.get('tags').valueChanges + // .pipe(takeUntil(this._destroyed)) + // .subscribe(x => { + // this.formChanged(); + // }); + // if (this.formGroup.get('descriptionProfileDefinition')) { + // // const descriptionProfileDefinitionSubscription = + // this.formGroup.get('descriptionProfileDefinition').valueChanges + // .pipe(takeUntil(this._destroyed)) + // .subscribe(x => { + // this.formChanged(); + // }); + // // this._listenersSubscription.add(descriptionProfileDefinitionSubscription); + // } + + // // this._listenersSubscription.add(dmpSubscription); + // // this._listenersSubscription.add(profileSubscription); + // // this._listenersSubscription.add(labelSubscription); + // // this._listenersSubscription.add(descriptionSubscription); + // // this._listenersSubscription.add(uriSubscription); + // // this._listenersSubscription.add(tagsSubscription); + // } + // // // // // // Sections @@ -1167,13 +1716,7 @@ export class DescriptionEditorComponent extends BaseEditor new DescriptionFieldEditorModel( - this.validationErrorModel - ).fromModel(item).buildForm({ - rootPath: `${rootPath}fields[${index}].` - }), context.getValidation('fields') - ) - ), - }); + const formGroup = this.formBuilder.group({}); + (this.fields ?? []).map( + (item, index) => formGroup.addControl(item.key, new DescriptionFieldEditorModel( + this.validationErrorModel + ).fromModel(item).buildForm({ + rootPath: `${rootPath}fields[${index}].` + })), context.getValidation('fields') + ) + return formGroup; + + // return this.formBuilder.group({ + // fields: this.formBuilder.array( + // (this.fields ?? []).map( + // (item, index) => new DescriptionFieldEditorModel( + // this.validationErrorModel + // ).fromModel(item).buildForm({ + // rootPath: `${rootPath}fields[${index}].` + // }), context.getValidation('fields') + // ) + // ) + // }); } static createValidationContext(params: { diff --git a/dmp-frontend/src/app/ui/description/editor/description-editor.module.ts b/dmp-frontend/src/app/ui/description/editor/description-editor.module.ts new file mode 100644 index 000000000..17d972825 --- /dev/null +++ b/dmp-frontend/src/app/ui/description/editor/description-editor.module.ts @@ -0,0 +1,37 @@ +import { NgModule } from '@angular/core'; +import { FormattingModule } from '@app/core/formatting.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 { CommonUiModule } from '@common/ui/common-ui.module'; +import { DescriptionBaseFieldsEditorComponent } from './description-base-fields-editor/description-base-fields-editor.component'; +import { DescriptionEditorComponent } from './description-editor.component'; +import { DescriptionEditorRoutingModule } from './description-editor.routing'; +import { DescriptionFormModule } from './description-form/description-form.module'; +import { VisibilityRulesService } from './description-form/visibility-rules/visibility-rules.service'; +import { DescriptionFormProgressIndicationModule } from './form-progress-indication/form-progress-indication.module'; +import { TableOfContentsModule } from './table-of-contents/table-of-contents.module'; + +@NgModule({ + imports: [ + CommonUiModule, + CommonFormsModule, + UrlListingModule, + FormattingModule, + ConfirmationDialogModule, + TableOfContentsModule, + DescriptionFormProgressIndicationModule, + DescriptionFormModule, + DescriptionEditorRoutingModule + ], + declarations: [ + DescriptionEditorComponent, + DescriptionBaseFieldsEditorComponent + ], + exports: [ + ], + providers: [ + VisibilityRulesService + ] +}) +export class DescriptionEditorModule { } diff --git a/dmp-frontend/src/app/ui/description/editor/description-editor.resolver.ts b/dmp-frontend/src/app/ui/description/editor/description-editor.resolver.ts new file mode 100644 index 000000000..62e5478c2 --- /dev/null +++ b/dmp-frontend/src/app/ui/description/editor/description-editor.resolver.ts @@ -0,0 +1,112 @@ +import { Injectable } from '@angular/core'; +import { ActivatedRouteSnapshot, RouterStateSnapshot } from '@angular/router'; +import { DescriptionTemplate, DescriptionTemplateBaseFieldData, DescriptionTemplateDefinition, DescriptionTemplateField, DescriptionTemplateFieldSet, DescriptionTemplatePage, DescriptionTemplateRule, DescriptionTemplateSection } from '@app/core/model/description-template/description-template'; +import { Description, DescriptionField, DescriptionReference, DescriptionTag, PropertyDefinition } from '@app/core/model/description/description'; +import { Dmp, DmpDescriptionTemplate } from '@app/core/model/dmp/dmp'; +import { Reference } from '@app/core/model/reference/reference'; +import { Tag } from '@app/core/model/tag/tag'; +import { DescriptionService } from '@app/core/services/description/description.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 DescriptionEditorResolver extends BaseEditorResolver { + + constructor(private descriptionService: DescriptionService, private breadcrumbService: BreadcrumbService) { + super(); + } + + public static lookupFields(): string[] { + return [ + ...BaseEditorResolver.lookupFields(), + nameof(x => x.id), + nameof(x => x.label), + nameof(x => x.status), + nameof(x => x.description), + nameof(x => x.status), + [nameof(x => x.dmp), nameof(x => x.id)].join('.'), + [nameof(x => x.dmp), nameof(x => x.label)].join('.'), + + [nameof(x => x.dmpDescriptionTemplate), nameof(x => x.id)].join('.'), + + [nameof(x => x.descriptionTemplate), nameof(x => x.id)].join('.'), + [nameof(x => x.descriptionTemplate), nameof(x => x.definition), nameof(x => x.pages), nameof(x => x.id)].join('.'), + [nameof(x => x.descriptionTemplate), nameof(x => x.definition), nameof(x => x.pages), nameof(x => x.ordinal)].join('.'), + [nameof(x => x.descriptionTemplate), nameof(x => x.definition), nameof(x => x.pages), nameof(x => x.title)].join('.'), + + [nameof(x => x.descriptionTemplate), nameof(x => x.definition), nameof(x => x.sections), nameof(x => x.id)].join('.'), + [nameof(x => x.descriptionTemplate), nameof(x => x.definition), nameof(x => x.sections), nameof(x => x.ordinal)].join('.'), + // [nameof(x => x.definition), nameof(x => x.sections), nameof(x => x.defaultVisibility)].join('.'), + // [nameof(x => x.definition), nameof(x => x.sections), nameof(x => x.multiplicity)].join('.'), + // [nameof(x => x.definition), nameof(x => x.sections), nameof(x => x.numbering)].join('.'), + [nameof(x => x.descriptionTemplate), nameof(x => x.definition), nameof(x => x.sections), nameof(x => x.page)].join('.'), + [nameof(x => x.descriptionTemplate), nameof(x => x.definition), nameof(x => x.sections), nameof(x => x.title)].join('.'), + [nameof(x => x.descriptionTemplate), nameof(x => x.definition), nameof(x => x.sections), nameof(x => x.description)].join('.'), + [nameof(x => x.descriptionTemplate), nameof(x => x.definition), nameof(x => x.sections), nameof(x => x.extendedDescription)].join('.'), + // [nameof(x => x.definition), nameof(x => x.sections), nameof(x => x.ordinal)].join('.'), // TODO: need to sort based on that + // [nameof(x => x.definition), nameof(x => x.sections), nameof(x => x.sections)].join('.'), // TODO: it is recursive here + + [nameof(x => x.descriptionTemplate), nameof(x => x.definition), nameof(x => x.sections), nameof(x => x.fieldSets), nameof(x => x.id)].join('.'), + [nameof(x => x.descriptionTemplate), nameof(x => x.definition), nameof(x => x.sections), nameof(x => x.fieldSets), nameof(x => x.ordinal)].join('.'), + // [nameof(x => x.definition), nameof(x => x.sections), nameof(x => x.fieldSets), nameof(x => x.numbering)].join('.'), + [nameof(x => x.descriptionTemplate), nameof(x => x.definition), nameof(x => x.sections), nameof(x => x.fieldSets), nameof(x => x.title)].join('.'), + [nameof(x => x.descriptionTemplate), nameof(x => x.definition), nameof(x => x.sections), nameof(x => x.fieldSets), nameof(x => x.description)].join('.'), + [nameof(x => x.descriptionTemplate), nameof(x => x.definition), nameof(x => x.sections), nameof(x => x.fieldSets), nameof(x => x.extendedDescription)].join('.'), + [nameof(x => x.descriptionTemplate), nameof(x => x.definition), nameof(x => x.sections), nameof(x => x.fieldSets), nameof(x => x.additionalInformation)].join('.'), + [nameof(x => x.descriptionTemplate), nameof(x => x.definition), nameof(x => x.sections), nameof(x => x.fieldSets), nameof(x => x.hasCommentField)].join('.'), + // [nameof(x => x.definition), nameof(x => x.sections), nameof(x => x.fieldSets), nameof(x => x.multiplicity), nameof(x => x.min)].join('.'), + // [nameof(x => x.definition), nameof(x => x.sections), nameof(x => x.fieldSets), nameof(x => x.multiplicity), nameof(x => x.max)].join('.'), + // [nameof(x => x.definition), nameof(x => x.sections), nameof(x => x.fieldSets), nameof(x => x.multiplicity), nameof(x => x.placeholder)].join('.'), + // [nameof(x => x.definition), nameof(x => x.sections), nameof(x => x.fieldSets), nameof(x => x.multiplicity), nameof(x => x.tableView)].join('.'), + [nameof(x => x.descriptionTemplate), nameof(x => x.definition), nameof(x => x.sections), nameof(x => x.fieldSets), nameof(x => x.fields), nameof(x => x.id)].join('.'), + // [nameof(x => x.definition), nameof(x => x.sections), nameof(x => x.fieldSets), nameof(x => x.fields), nameof(x => x.ordinal)].join('.'), + // [nameof(x => x.definition), nameof(x => x.sections), nameof(x => x.fieldSets), nameof(x => x.fields), nameof(x => x.numbering)].join('.'), + // [nameof(x => x.definition), nameof(x => x.sections), nameof(x => x.fieldSets), nameof(x => x.fields), nameof(x => x.schematics)].join('.'), + // [nameof(x => x.definition), nameof(x => x.sections), nameof(x => x.fieldSets), nameof(x => x.fields), nameof(x => x.defaultValue)].join('.'), + [nameof(x => x.descriptionTemplate), nameof(x => x.definition), nameof(x => x.sections), nameof(x => x.fieldSets), nameof(x => x.fields), nameof(x => x.defaultValue)].join('.'), + // [nameof(x => x.definition), nameof(x => x.sections), nameof(x => x.fieldSets), nameof(x => x.fields), nameof(x => x.fieldType)].join('.'), + // [nameof(x => x.definition), nameof(x => x.sections), nameof(x => x.fieldSets), nameof(x => x.fields), nameof(x => x.includeInExport)].join('.'), + [nameof(x => x.descriptionTemplate), nameof(x => x.definition), nameof(x => x.sections), nameof(x => x.fieldSets), nameof(x => x.fields), nameof(x => x.validations)].join('.'), + + [nameof(x => x.descriptionTemplate), nameof(x => x.definition), nameof(x => x.sections), nameof(x => x.fieldSets), nameof(x => x.fields), nameof(x => x.visibilityRules), nameof(x => x.target)].join('.'), + [nameof(x => x.descriptionTemplate), nameof(x => x.definition), nameof(x => x.sections), nameof(x => x.fieldSets), nameof(x => x.fields), nameof(x => x.visibilityRules), nameof(x => x.value)].join('.'), + [nameof(x => x.descriptionTemplate), nameof(x => x.definition), nameof(x => x.sections), nameof(x => x.fieldSets), nameof(x => x.fields), nameof(x => x.data), nameof(x => x.label)].join('.'), + [nameof(x => x.descriptionTemplate), nameof(x => x.definition), nameof(x => x.sections), nameof(x => x.fieldSets), nameof(x => x.fields), nameof(x => x.data), nameof(x => x.fieldType)].join('.'), + + + [nameof(x => x.properties), nameof(x => x.fields), nameof(x => x.key)].join('.'), + [nameof(x => x.properties), nameof(x => x.fields), nameof(x => x.value)].join('.'), + + [nameof(x => x.descriptionTags), nameof(x => x.id),].join('.'), + [nameof(x => x.descriptionTags), nameof(x => x.tag), nameof(x => x.label)].join('.'), + + [nameof(x => x.descriptionReferences), nameof(x => x.reference), nameof(x => x.id)].join('.'), + [nameof(x => x.descriptionReferences), nameof(x => x.reference), nameof(x => x.label)].join('.'), + [nameof(x => x.descriptionReferences), nameof(x => x.reference), nameof(x => x.type)].join('.'), + [nameof(x => x.descriptionReferences), nameof(x => x.reference), nameof(x => x.reference)].join('.'), + nameof(x => x.createdAt), + nameof(x => x.hash), + nameof(x => x.isActive) + + ] + } + + resolve(route: ActivatedRouteSnapshot, state: RouterStateSnapshot) { + + const fields = [ + ...DescriptionEditorResolver.lookupFields() + ]; + const id = route.paramMap.get('id'); + // const cloneid = route.paramMap.get('cloneid'); + if (id != null) { + return this.descriptionService.getSingle(Guid.parse(id), fields).pipe(tap(x => this.breadcrumbService.addIdResolvedValue(x.id?.toString(), x.label)), takeUntil(this._destroyed)); + } + //TODO: check this + // else if (cloneid != null) { + // return this.descriptionService.clone(Guid.parse(cloneid), fields).pipe(tap(x => this.breadcrumbService.addIdResolvedValue(x.id?.toString(), x.label)), takeUntil(this._destroyed)); + // } + } +} diff --git a/dmp-frontend/src/app/ui/description/editor/description-editor.routing.ts b/dmp-frontend/src/app/ui/description/editor/description-editor.routing.ts new file mode 100644 index 000000000..7a513afba --- /dev/null +++ b/dmp-frontend/src/app/ui/description/editor/description-editor.routing.ts @@ -0,0 +1,101 @@ +import { NgModule } from '@angular/core'; +import { RouterModule, Routes } from '@angular/router'; +// import { DescriptionWizardComponent } from './description-wizard/description-wizard.component'; +import { AppPermission } from '@app/core/common/enum/permission.enum'; +import { PendingChangesGuard } from '@common/forms/pending-form-changes/pending-form-changes-guard.service'; +// import { DescriptionOverviewComponent } from './overview/description-overview.component'; +import { BreadcrumbService } from '@app/ui/misc/breadcrumb/breadcrumb.service'; +import { DescriptionEditorComponent } from './description-editor.component'; +import { DescriptionEditorResolver } from './description-editor.resolver'; +import { AuthGuard } from '@app/core/auth-guard.service'; + +const routes: Routes = [ + { + path: ':id', + canActivate: [AuthGuard], + component: DescriptionEditorComponent, + canDeactivate: [PendingChangesGuard], + resolve: { + 'entity': DescriptionEditorResolver + }, + data: { + ...BreadcrumbService.generateRouteDataConfiguration({ + title: 'BREADCRUMBS.EDIT-DESCRIPTION' + }), + authContext: { + permissions: [AppPermission.EditDescription] + } + } + }, + // { + // path: 'new/:dmpId/:dmpSectionIndex', + // component: DescriptionWizardComponent, + // canActivate: [AuthGuard], + // data: { + // breadcrumb: true, + // title: 'GENERAL.TITLES.DATASET-NEW' + // }, + // canDeactivate:[CanDeactivateGuard] + // }, + + // { + // path: 'edit/:id/finalize', + // component: DescriptionWizardComponent, + // canActivate: [AuthGuard], + // data: { + // breadcrumb: true, + // public: false, + // title: 'GENERAL.TITLES.DATASET-EDIT', + // finalize: true + // }, + // canDeactivate:[CanDeactivateGuard] + // }, + // { + // path: 'publicEdit/:publicId', + // component: DescriptionWizardComponent, + // //canActivate: [AuthGuard], + // data: { + // public: true, + // title: 'GENERAL.TITLES.DATASET-PUBLIC-EDIT' + // }, + // canDeactivate:[CanDeactivateGuard] + // }, + // { + // path: 'new', + // component: DescriptionWizardComponent, + // canActivate: [AuthGuard], + // data: { + // breadcrumb: true, + // title: 'GENERAL.TITLES.DATASET-NEW' + // }, + // canDeactivate:[CanDeactivateGuard] + // }, + // { + // path: 'copy/:id', + // component: DescriptionWizardComponent, + // canActivate: [AuthGuard], + // data: { + // breadcrumb: true, + // title: 'GENERAL.TITLES.DATASET-COPY' + // }, + // canDeactivate:[CanDeactivateGuard] + // }, + // { + // path: 'profileupdate/:updateId', + // component: DescriptionWizardComponent, + // canActivate: [AuthGuard], + // data: { + // breadcrumb: true, + // title: 'GENERAL.TITLES.DATASET-UPDATE' + // }, + // canDeactivate:[CanDeactivateGuard] + // }, + +]; + +@NgModule({ + imports: [RouterModule.forChild(routes)], + exports: [RouterModule], + providers: [DescriptionEditorResolver] +}) +export class DescriptionEditorRoutingModule { } diff --git a/dmp-frontend/src/app/ui/description/dataset-wizard/description-editor.service.ts b/dmp-frontend/src/app/ui/description/editor/description-editor.service.ts similarity index 100% rename from dmp-frontend/src/app/ui/description/dataset-wizard/description-editor.service.ts rename to dmp-frontend/src/app/ui/description/editor/description-editor.service.ts diff --git a/dmp-frontend/src/app/ui/description/editor/description-form/components/form-composite-field-dialog/form-composite-field-dialog.component.html b/dmp-frontend/src/app/ui/description/editor/description-form/components/form-composite-field-dialog/form-composite-field-dialog.component.html new file mode 100644 index 000000000..567ff7d61 --- /dev/null +++ b/dmp-frontend/src/app/ui/description/editor/description-form/components/form-composite-field-dialog/form-composite-field-dialog.component.html @@ -0,0 +1,15 @@ +
+
+
+ close +
+
+
+ +
+
+
+
+
+
diff --git a/dmp-frontend/src/app/ui/description/editor/description-form/components/form-composite-field-dialog/form-composite-field-dialog.component.ts b/dmp-frontend/src/app/ui/description/editor/description-form/components/form-composite-field-dialog/form-composite-field-dialog.component.ts new file mode 100644 index 000000000..ac15f6dff --- /dev/null +++ b/dmp-frontend/src/app/ui/description/editor/description-form/components/form-composite-field-dialog/form-composite-field-dialog.component.ts @@ -0,0 +1,31 @@ +import {Component, Inject} from "@angular/core"; +import {MAT_DIALOG_DATA, MatDialogRef} from "@angular/material/dialog"; +import { VisibilityRulesService } from "../../visibility-rules/visibility-rules.service"; + +@Component({ + selector: 'app-form-composite-field-dialog', + templateUrl: 'form-composite-field-dialog.component.html' +}) +export class FormCompositeFieldDialogComponent { + + public visibilityRulesService: VisibilityRulesService; + + constructor( + private dialogRef: MatDialogRef, + @Inject(MAT_DIALOG_DATA) public data: any + ) { + this.visibilityRulesService = data.visibilityRulesService; + } + + cancel() { + this.dialogRef.close(); + } + + save() { + this.dialogRef.close(this.data.formGroup); + } + + public close() { + this.dialogRef.close(false); + } +} diff --git a/dmp-frontend/src/app/ui/description/editor/description-form/components/form-composite-title/form-composite-title.component.html b/dmp-frontend/src/app/ui/description/editor/description-form/components/form-composite-title/form-composite-title.component.html new file mode 100644 index 000000000..c6bebfe74 --- /dev/null +++ b/dmp-frontend/src/app/ui/description/editor/description-form/components/form-composite-title/form-composite-title.component.html @@ -0,0 +1,25 @@ +
+
+
+ + + {{fieldSet.title}} +
+ info +
+
+ + +
+ +
+
+ {{'DATASET-EDITOR.QUESTION.EXTENDED-DESCRIPTION.VIEW-MORE' | translate}} +
+
+
+ + {{'DATASET-EDITOR.QUESTION.EXTENDED-DESCRIPTION.VIEW-LESS' | translate}} + +
+
diff --git a/dmp-frontend/src/app/ui/description/editor/description-form/components/form-composite-title/form-composite-title.component.scss b/dmp-frontend/src/app/ui/description/editor/description-form/components/form-composite-title/form-composite-title.component.scss new file mode 100644 index 000000000..356217a1e --- /dev/null +++ b/dmp-frontend/src/app/ui/description/editor/description-form/components/form-composite-title/form-composite-title.component.scss @@ -0,0 +1,31 @@ +.compositeField { + // font-weight: bold; + // color: #3a3737; + // max-width: 100%; + // padding-top: 1em; + text-align: left; + font-weight: 700; + font-size: 18px; + letter-spacing: 0px; + color: #212121; + opacity: 0.81; + margin-top: 1.625rem; + margin-bottom: 0.625rem; +} + +.info-icon{ + margin-top: 1.625rem; +} + +h6 { + text-transform: none; + font-weight: 400; +} + +.more { + text-decoration: underline; + color: var(--secondary-color); + cursor: pointer; + font-size: 1rem; + font-weight: 400; +} diff --git a/dmp-frontend/src/app/ui/description/editor/description-form/components/form-composite-title/form-composite-title.component.ts b/dmp-frontend/src/app/ui/description/editor/description-form/components/form-composite-title/form-composite-title.component.ts new file mode 100644 index 000000000..ef6c0d57f --- /dev/null +++ b/dmp-frontend/src/app/ui/description/editor/description-form/components/form-composite-title/form-composite-title.component.ts @@ -0,0 +1,21 @@ +import { Component, Input, OnInit } from '@angular/core'; +import { DescriptionTemplateFieldSet } from '@app/core/model/description-template/description-template'; + +@Component({ + selector: 'app-form-composite-title', + templateUrl: './form-composite-title.component.html', + styleUrls: ['./form-composite-title.component.scss'] +}) +export class DescriptionFormCompositeTitleComponent implements OnInit { + + @Input() fieldSet: DescriptionTemplateFieldSet; + @Input() isChild: Boolean = false; + + public showExtendedDescription: boolean = false; + + constructor() { } + + ngOnInit() { + } + +} diff --git a/dmp-frontend/src/app/ui/description/editor/description-form/components/form-field-set/form-field-set.component.html b/dmp-frontend/src/app/ui/description/editor/description-form/components/form-field-set/form-field-set.component.html new file mode 100644 index 000000000..36d519d48 --- /dev/null +++ b/dmp-frontend/src/app/ui/description/editor/description-form/components/form-field-set/form-field-set.component.html @@ -0,0 +1,54 @@ +
+
+
+
+ +
+
+
+ +
+ +
+
+
+
+
+
+
+
+ +
+
+
+ +
+
{{field.label}}
+
+ +
+
+
+
+ +
+
+
+
+ + + {{propertiesFormGroup.get(field.id).get('value').getRawValue() | fieldValue | translate}} + + + + + + \ No newline at end of file diff --git a/dmp-frontend/src/app/ui/description/editor/description-form/components/form-field-set/form-field-set.component.scss b/dmp-frontend/src/app/ui/description/editor/description-form/components/form-field-set/form-field-set.component.scss new file mode 100644 index 000000000..a6df1bcca --- /dev/null +++ b/dmp-frontend/src/app/ui/description/editor/description-form/components/form-field-set/form-field-set.component.scss @@ -0,0 +1,17 @@ +.compositeField { + padding-left: 0em !important; +// padding-top: 2em !important; +} + +// ::ng-deep .mat-form-field-appearance-outline .mat-form-field-outline { +// background: #fafafa !important; +// } + +// ::ng-deep .mat-form-field-appearance-outline .mat-form-field-infix { +// font-size: 1rem; +// padding: 0.6em 0 1em 0 !important; +// } + +.actions { + width: 110px; +} diff --git a/dmp-frontend/src/app/ui/description/editor/description-form/components/form-field-set/form-field-set.component.ts b/dmp-frontend/src/app/ui/description/editor/description-form/components/form-field-set/form-field-set.component.ts new file mode 100644 index 000000000..ebb1ea80b --- /dev/null +++ b/dmp-frontend/src/app/ui/description/editor/description-form/components/form-field-set/form-field-set.component.ts @@ -0,0 +1,115 @@ +import { ChangeDetectionStrategy, ChangeDetectorRef, Component, Input } from '@angular/core'; +import { UntypedFormGroup } from '@angular/forms'; +import { MatDialog } from "@angular/material/dialog"; +import { DescriptionTemplateFieldSet } from '@app/core/model/description-template/description-template'; +import { BaseComponent } from '@common/base/base.component'; +import { takeUntil } from 'rxjs/operators'; +import { ToCEntry } from '../../../table-of-contents/models/toc-entry'; +import { VisibilityRulesService } from '../../visibility-rules/visibility-rules.service'; + +@Component({ + selector: 'app-form-field-set', + templateUrl: './form-field-set.component.html', + styleUrls: ['./form-field-set.component.scss'], + changeDetection: ChangeDetectionStrategy.OnPush +}) +export class DescriptionFormFieldSetComponent extends BaseComponent { + + @Input() fieldSet: DescriptionTemplateFieldSet; + @Input() propertiesFormGroup: UntypedFormGroup; + isVisibleByVisibilityService: boolean = true; + @Input() visibilityRulesService: VisibilityRulesService; + + + @Input() datasetProfileId: String; + // @Input() form: UntypedFormGroup; + @Input() isChild: Boolean = false; + @Input() showDelete: Boolean = false; + @Input() tocentry: ToCEntry; + @Input() tableRow: boolean = false; + @Input() showTitle: boolean = true; + @Input() placeholderTitle: boolean = false; + + constructor( + private dialog: MatDialog, + private changeDetector: ChangeDetectorRef + ) { + super(); + } + + ngOnInit() { + this.visibilityRulesService.getElementVisibilityMapObservable().pipe(takeUntil(this._destroyed)).subscribe(x => { + if (x.has(this.fieldSet.id)) { + this.isVisibleByVisibilityService = x.get(this.fieldSet.id); + // this.changeDetector.markForCheck(); + } + }); + // if (this.tocentry) { + // this.form = this.tocentry.form as UntypedFormGroup; + // } + } + + // editCompositeFieldInDialog() { + // const dialogRef = this.dialog.open(FormCompositeFieldDialogComponent, { + // width: '750px', + // disableClose: true, + // data: { + // formGroup: cloneAbstractControl(this.form), + // datasetProfileId: this.datasetProfileId, + // visibilityRulesService: this.visibilityRulesService + // } + // }); + // dialogRef.afterClosed().pipe(takeUntil(this._destroyed)).subscribe(data => { + // if (data) { + // this.form.patchValue(data.value); + // this.changeDetector.detectChanges(); + // } + // }); + // } + + // deleteCompositeField() { + // if (this.isChild) { + // this.deleteMultipeFieldFromCompositeFormGroup(); + // } else { + // this.deleteCompositeFieldFormGroup(); + // } + // } + + // deleteCompositeFieldFormGroup() { + + // const compositeFieldId = ((this.form.get('multiplicityItems') as UntypedFormArray).get('' + 0) as UntypedFormGroup).getRawValue().id; + // const fieldIds = (this.form.get('fields') as UntypedFormArray).controls.map(control => control.get('id').value) as string[]; + + // const numberOfItems = this.form.get('multiplicityItems').get('' + 0).get('fields').value.length; + // for (let i = 0; i < numberOfItems; i++) { + // const multiplicityItem = this.form.get('multiplicityItems').get('' + 0).get('fields').get('' + i).value; + // this.form.get('fields').get('' + i).patchValue(multiplicityItem); + // } + // ((this.form.get('multiplicityItems'))).removeAt(0); + + + // this.visibilityRulesService.removeAllIdReferences(compositeFieldId); + // fieldIds.forEach(x => this.visibilityRulesService.removeAllIdReferences(x)); + // } + + // deleteMultipeFieldFromCompositeFormGroup() { + // const parent = this.form.parent; + // const index = (parent as UntypedFormArray).controls.indexOf(this.form); + + // const currentId = this.form.get('id').value; + // const fieldIds = (this.form.get('fields') as UntypedFormArray).controls.map(control => control.get('id').value) as string[]; + + + // this.visibilityRulesService.removeAllIdReferences(currentId); + // fieldIds.forEach(x => this.visibilityRulesService.removeAllIdReferences(x)); + + // (parent as UntypedFormArray).removeAt(index); + // (parent as UntypedFormArray).controls.forEach((control, i) => { + // try { + // control.get('ordinal').setValue(i); + // } catch { + // throw 'Could not find ordinal'; + // } + // }); + // } +} diff --git a/dmp-frontend/src/app/ui/description/editor/description-form/components/form-field/form-field.component.html b/dmp-frontend/src/app/ui/description/editor/description-form/components/form-field/form-field.component.html new file mode 100644 index 000000000..3d8f03f6f --- /dev/null +++ b/dmp-frontend/src/app/ui/description/editor/description-form/components/form-field/form-field.component.html @@ -0,0 +1,473 @@ +
+ +
{{fieldSet.title}}
+ info + +
{{fieldSet.description}} +
+
+ {{fieldSet.extendedDescription}} +
+ + + {{'GENERAL.VALIDATION.REQUIRED' | translate}} + {{'GENERAL.VALIDATION.URL.MESSAGE' | translate}} + + +
+
+ + + + + + + + + + {{'GENERAL.VALIDATION.REQUIRED' | translate}} + + {{ "TYPES.DATASET-PROFILE-COMBO-BOX-TYPE.EXTERNAL-SOURCE-HINT" | translate }} + +
+
+
+
+ + + {{opt.label}} + + + {{'GENERAL.VALIDATION.REQUIRED' | translate}} + + +
+
+
+
+ + + + + + + + + + {{'GENERAL.VALIDATION.REQUIRED' | translate}} + + {{ "TYPES.DATASET-PROFILE-COMBO-BOX-TYPE.EXTERNAL-SOURCE-HINT" | translate }} + +
+
+
+
+ + + + + + + + + + {{'GENERAL.VALIDATION.REQUIRED' | translate}} + + {{ "TYPES.DATASET-PROFILE-COMBO-BOX-TYPE.EXTERNAL-SOURCE-HINT" | translate }} + +
+
+
+
+ + + + + + + + + + {{'GENERAL.VALIDATION.REQUIRED' | translate}} + + {{ "TYPES.DATASET-PROFILE-COMBO-BOX-TYPE.EXTERNAL-SOURCE-HINT" | translate }} + +
+
+
+ + {{field.data.label}} +
+ + + + {{'GENERAL.VALIDATION.REQUIRED' | translate}} + + + + +
+
+ {{'GENERAL.VALIDATION.REQUIRED' | translate}} +
+
+
+ +
+ + + {{ propertiesFormGroup.get(field.id).get('value').value.name }} + + +
+
+ + + +
+
+
+ + {{ "TYPES.DATASET-PROFILE-COMBO-BOX-TYPE.ACTIONS.YES" | translate }} + {{ "TYPES.DATASET-PROFILE-COMBO-BOX-TYPE.ACTIONS.NO" | translate }} + + {{'GENERAL.VALIDATION.REQUIRED' | translate}} + + {{'GENERAL.VALIDATION.REQUIRED' | translate}} +
+ +
+ + {{option.label}} + + {{'GENERAL.VALIDATION.REQUIRED' | translate}} + + {{'GENERAL.VALIDATION.REQUIRED' | translate}} * +
+ + + + + + + {{'GENERAL.VALIDATION.REQUIRED' | translate}} + + + +
+
+ + + + + + + + + + {{'GENERAL.VALIDATION.REQUIRED' | translate}} + + {{ "TYPES.DATASET-PROFILE-COMBO-BOX-TYPE.EXTERNAL-SOURCE-HINT" | translate }} + +
+
+ +
+
+ + + + + + + + + + {{'GENERAL.VALIDATION.REQUIRED' | translate}} + + {{ "TYPES.DATASET-PROFILE-COMBO-BOX-TYPE.EXTERNAL-SOURCE-HINT" | translate }} + +
+
+
+
+ + + + + + + + + + {{'GENERAL.VALIDATION.REQUIRED' | translate}} + + {{ "TYPES.DATASET-PROFILE-COMBO-BOX-TYPE.EXTERNAL-SOURCE-HINT" | translate }} + +
+
+
+
+ + + + + + + + + + {{'GENERAL.VALIDATION.REQUIRED' | translate}} + + {{ "TYPES.DATASET-PROFILE-COMBO-BOX-TYPE.EXTERNAL-SOURCE-HINT" | translate }} + +
+
+ +
+
+ + + + + + + + + + {{'GENERAL.VALIDATION.REQUIRED' | translate}} + + {{ "TYPES.DATASET-PROFILE-COMBO-BOX-TYPE.EXTERNAL-SOURCE-HINT" | translate }} + +
+
+ +
+
+ + + + + + + + + + {{'GENERAL.VALIDATION.REQUIRED' | translate}} + + {{ "TYPES.DATASET-PROFILE-COMBO-BOX-TYPE.EXTERNAL-SOURCE-HINT" | translate }} + +
+
+ +
+
+ + + + + + + + + + {{'GENERAL.VALIDATION.REQUIRED' | translate}} + + {{ "TYPES.DATASET-PROFILE-COMBO-BOX-TYPE.EXTERNAL-SOURCE-HINT" | translate }} + +
+
+ +
+
+ + + + + + + + + + {{'GENERAL.VALIDATION.REQUIRED' | translate}} + + {{ "TYPES.DATASET-PROFILE-COMBO-BOX-TYPE.EXTERNAL-SOURCE-HINT" | translate }} + +
+
+ +
+
+ + + + + + + + + + {{'GENERAL.VALIDATION.REQUIRED' | translate}} + + {{ "TYPES.DATASET-PROFILE-COMBO-BOX-TYPE.EXTERNAL-SOURCE-HINT" | translate }} + +
+
+ +
+
+ + + +
+
+ +
+
+ + + + + + + + + + {{'GENERAL.VALIDATION.REQUIRED' | translate}} + + {{ "TYPES.DATASET-PROFILE-COMBO-BOX-TYPE.EXTERNAL-SOURCE-HINT" | translate }} + +
+
+ +
+
+ + + + + + + + + {{'GENERAL.VALIDATION.REQUIRED' | translate}} + + + + {{ "TYPES.DATASET-PROFILE-COMBO-BOX-TYPE.EXTERNAL-SOURCE-HINT" | translate }} + +
+
+ +
+
+ + + {{'GENERAL.VALIDATION.REQUIRED' | translate}} + + + + + + {{ type.name }} + + + {{'GENERAL.VALIDATION.REQUIRED' | translate}} + + +
+
+ +
+
+ + + + {{'GENERAL.VALIDATION.REQUIRED' | translate}} + + +
+
+ +
+
+ + + {{'GENERAL.VALIDATION.REQUIRED' | translate}} + + + + + + {{ type.name }} + + + {{'GENERAL.VALIDATION.REQUIRED' | translate}} + + +
+ + {{'GENERAL.VALIDATION.REQUIRED' | translate}} + +
+
+ + {{validationIcon}} +
+
+
+
diff --git a/dmp-frontend/src/app/ui/description/editor/description-form/components/form-field/form-field.component.scss b/dmp-frontend/src/app/ui/description/editor/description-form/components/form-field/form-field.component.scss new file mode 100644 index 000000000..0213cb51f --- /dev/null +++ b/dmp-frontend/src/app/ui/description/editor/description-form/components/form-field/form-field.component.scss @@ -0,0 +1,105 @@ +.dynamic-form-field { + .radio-button-item { + margin-right: 1em; + } + + .full-width { + width: 100%; + } + + .text-area { + box-sizing: content-box; + } + + .success { + color: green; + } + + .fail { + color: red; + } +} + +::ng-deep .mat-form-field-appearance-outline .mat-form-field-outline { + background: #fafafa !important; +} + +::ng-deep .mat-form-field-appearance-outline .mat-form-field-infix { + font-size: 1rem; + padding: 0.6em 0 1em 0 !important; +} + + +.attach-btn { + top: -20px; +} + +.attach-file-btn { + min-width: 156px; + height: 44px; + color: #ffffff; + background: var(--primary-color) 0% 0% no-repeat padding-box; + box-shadow: 0px 3px 6px #1e202029; + border-radius: 30px; +} + +.attach-file-btn:hover { + background-color: #ffffff; + border: 1px solid var(--primary-color); + color: var(--primary-color); +} + +.attach-file-btn.mdc-button-disabled, .attach-file-btn.mdc-button-disabled:hover { + background-color: #ffffff; + border: 1px solid darkgray; + color: darkgrey !important; +} +// +//.mdc-button-disabled .attach-file-btn > ::ng-deep mdc-button-wrapper:hover > * { +// color: darkgrey !important; +//} + +.drop-file { + background-color: #fafafa; + border: 1px dashed #d1d1d1; + border-radius: 4px; + //max-width: 480px; + height: 98px; + margin-top: 0.5rem; +} + +.file-preview { + height: auto !important; + width: auto !important; + max-width: 500px !important; + min-height: 1rem !important; + + background-color: #e0e0e0 !important; + background-image: none !important; + color: rgba(0, 0, 0, 0.87) !important; + font-weight: 500 !important; + border-radius: 24px !important; + line-height: 1.25 !important; +} + +.file-label { + white-space: nowrap; + overflow: hidden; + text-overflow: ellipsis; + font-size: 14px !important; +} + +::ng-deep ngx-dropzone-remove-badge { + opacity: 1 !important; + margin-left: .5rem !important; + position: initial !important; +} + +::ng-deep .upload-form .mat-form-field-appearance-outline .mat-form-field-outline { + background: #fafafa !important; +} + +::ng-deep .upload-form .mat-form-field-appearance-outline .mat-form-field-infix { + font-size: 1rem; + padding: 0.6em 0 1em 0 !important; +} diff --git a/dmp-frontend/src/app/ui/description/editor/description-form/components/form-field/form-field.component.ts b/dmp-frontend/src/app/ui/description/editor/description-form/components/form-field/form-field.component.ts new file mode 100644 index 000000000..4ba26734f --- /dev/null +++ b/dmp-frontend/src/app/ui/description/editor/description-form/components/form-field/form-field.component.ts @@ -0,0 +1,764 @@ + +import { COMMA, ENTER } from '@angular/cdk/keycodes'; +import { ChangeDetectionStrategy, ChangeDetectorRef, Component, Input, OnInit, SimpleChanges } from '@angular/core'; +import { FormControl, UntypedFormControl, UntypedFormGroup } from '@angular/forms'; +import { MatDialog } from "@angular/material/dialog"; +import { DescriptionTemplateFieldType } from '@app/core/common/enum/description-template-field-type'; +import { ReferenceType } from '@app/core/common/enum/reference-type'; +import { DataTableRequest } from '@app/core/model/data-table/data-table-request'; +import { DescriptionTemplateAutoCompleteData, DescriptionTemplateAutoCompleteSingleData, DescriptionTemplateField, DescriptionTemplateFieldSet, DescriptionTemplateUploadData, DescriptionTemplateWordListData } from '@app/core/model/description-template/description-template'; +import { ExternalSourceItemModel } from '@app/core/model/external-sources/external-source-item'; +import { LocalFetchModel } from '@app/core/model/local-fetch/local-fetch.model'; +import { FetcherReference, Reference } from '@app/core/model/reference/reference'; +import { DatasetExternalAutocompleteCriteria, DatasetExternalAutocompleteOptionsCriteria } from '@app/core/query/dataset/daatset-external-autocomplete-criteria'; +import { DatasetCriteria } from '@app/core/query/dataset/dataset-criteria'; +import { DmpCriteria } from '@app/core/query/dmp/dmp-criteria'; +import { ReferenceSearchLookup } from '@app/core/query/reference-search.lookup'; +import { RegistryCriteria } from '@app/core/query/registry/registry-criteria'; +import { RequestItem } from '@app/core/query/request-item'; +import { ResearcherCriteria } from '@app/core/query/researcher/researcher-criteria'; +import { ServiceCriteria } from '@app/core/query/service/service-criteria'; +import { TagCriteria } from '@app/core/query/tag/tag-criteria'; +import { TaxonomyCriteria } from "@app/core/query/taxonomy/taxonomy-criteria"; +import { CurrencyService } from '@app/core/services/currency/currency.service'; +import { DatasetExternalAutocompleteService } from '@app/core/services/dataset/dataset-external-autocomplete.service'; +import { DatasetService } from '@app/core/services/dataset/dataset.service'; +import { DmpService } from '@app/core/services/dmp/dmp.service'; +import { ExternalSourcesService } from '@app/core/services/external-sources/external-sources.service'; +import { FileService } from "@app/core/services/file/file.service"; +import { + SnackBarNotificationLevel, + UiNotificationService +} from "@app/core/services/notification/ui-notification-service"; +import { ReferenceService } from '@app/core/services/reference/reference.service'; +import { FileUtils } from '@app/core/services/utilities/file-utils.service'; +import { MultipleAutoCompleteConfiguration } from '@app/library/auto-complete/multiple/multiple-auto-complete-configuration'; +import { SingleAutoCompleteConfiguration } from '@app/library/auto-complete/single/single-auto-complete-configuration'; +import { ExternalTagEditorModel } from '@app/ui/dataset/dataset-wizard/dataset-wizard-editor.model'; +import { VisibilityRulesService } from '@app/ui/description/editor/description-form/visibility-rules/visibility-rules.service'; +import { isNullOrUndefined } from '@app/utilities/enhancers/utils'; +import { BaseComponent } from '@common/base/base.component'; +import { TranslateService } from '@ngx-translate/core'; +import { Observable } from 'rxjs'; +import { distinctUntilChanged, map, takeUntil } from 'rxjs/operators'; +import { DescriptionFieldEditorModel } from '../../../description-editor.model'; +import { DescriptionTemplateFieldValidationType } from '@app/core/common/enum/description-template-field-validation-type'; + +@Component({ + selector: 'app-form-field', + templateUrl: './form-field.component.html', + styleUrls: ['./form-field.component.scss'], + changeDetection: ChangeDetectionStrategy.OnPush +}) +export class DescriptionFormFieldComponent extends BaseComponent implements OnInit { + + @Input() field: DescriptionTemplateField; + @Input() fieldSet: DescriptionTemplateFieldSet; + @Input() propertiesFormGroup: UntypedFormGroup; + @Input() visibilityRulesService: VisibilityRulesService; + isRequired: boolean = false; + + + // @Input() field: Field; + // @Input() form: UntypedFormGroup; + @Input() datasetProfileId: any; + @Input() isChild: Boolean = false; + autocompleteOptions: DescriptionTemplateAutoCompleteSingleData[]; + + visible: boolean = true; + + // change: Subscription; + // trackByFn = (index, item) => item ? item['id'] : null; + + descriptionTemplateFieldTypeEnum = DescriptionTemplateFieldType; + + + + public singleAutoCompleteConfiguration: SingleAutoCompleteConfiguration; + public multipleAutoCompleteConfiguration: MultipleAutoCompleteConfiguration; + + externalDatasetAutoCompleteConfiguration: SingleAutoCompleteConfiguration; + dataRepositoriesAutoCompleteConfiguration: SingleAutoCompleteConfiguration; + pubRepositoriesAutoCompleteConfiguration: SingleAutoCompleteConfiguration; + journalRepositoriesAutoCompleteConfiguration: SingleAutoCompleteConfiguration; + taxonomiesAutoCompleteConfiguration: SingleAutoCompleteConfiguration; + licensesAutoCompleteConfiguration: SingleAutoCompleteConfiguration; + publicationsAutoCompleteConfiguration: SingleAutoCompleteConfiguration; + registriesAutoCompleteConfiguration: SingleAutoCompleteConfiguration; + servicesAutoCompleteConfiguration: SingleAutoCompleteConfiguration; + tagsAutoCompleteConfiguration: SingleAutoCompleteConfiguration; + researchersAutoCompleteConfiguration: MultipleAutoCompleteConfiguration; + organisationsAutoCompleteConfiguration: MultipleAutoCompleteConfiguration; + currencyAutoCompleteConfiguration: SingleAutoCompleteConfiguration; + + readonly separatorKeysCodes: number[] = [ENTER, COMMA]; + + tags: ExternalTagEditorModel[] = []; + + datasetIdInitialized: boolean = false; + + validationIcon; + + readonly datasetIdTypes: any[] = [ + { name: 'Handle', value: 'handle' }, + { name: 'DOI', value: 'doi' }, + { name: 'Ark', value: 'ark' }, + { name: 'Url', value: 'url' }, + { name: 'Other', value: 'other' } + ]; + + + readonly validationTypes: any[] = [ + { name: 'Zenodo', value: 'zenodo' } + ]; + + filesToUpload: FileList; + + constructor( + private datasetExternalAutocompleteService: DatasetExternalAutocompleteService, + private externalSourcesService: ExternalSourcesService, + private language: TranslateService, + private datasetService: DatasetService, + private dmpService: DmpService, + private currencyService: CurrencyService, + private fileService: FileService, + private cdr: ChangeDetectorRef, + private uiNotificationService: UiNotificationService, + public dialog: MatDialog, + private fileUtils: FileUtils, + private referenceService: ReferenceService + ) { + super(); + } + + ngOnChanges(changes: SimpleChanges) { + if (changes['form']) { + } + } + + ngOnInit() { + + this.visibilityRulesService.getElementVisibilityMapObservable().pipe(takeUntil(this._destroyed)).subscribe(x => { + if (x.has(this.field.id)){ + this.visible = x.get(this.field.id); + } + }); + + //TODO: validate that this logic is correct. Validation contenxt path might need to be fixed. + if (this.propertiesFormGroup.get(this.field.id).get('value') == null) { + const item: DescriptionFieldEditorModel = new DescriptionFieldEditorModel(); + item.key = this.field.id; + this.propertiesFormGroup.addControl(this.field.id, item.buildForm()); + } + + if (this.propertiesFormGroup.get(this.field.id).get('value').value) { + this.visibilityRulesService.updateValueAndVisibility(this.field?.id, this.propertiesFormGroup.get(this.field.id).get('value').value); + } + + this.isRequired = this.field.validations?.includes(DescriptionTemplateFieldValidationType.Required); + + if (this.field?.data?.fieldType === DescriptionTemplateFieldType.WORD_LIST) { + if ((this.field.data as DescriptionTemplateWordListData).multiList) { + const originalValue = this.propertiesFormGroup.get(this.field.id).get('value').value; + if (originalValue !== null && typeof originalValue === 'string') { + let values = (this.propertiesFormGroup.get(this.field.id).get('value').value).slice(1, -1).split(', ').filter((value) => !value.includes('"')); + let specialValue = (this.propertiesFormGroup.get(this.field.id).get('value').value).split('"').filter((value) => !value.startsWith('[') && !value.endsWith(']') && !values.includes(value) && value !== ', '); + specialValue.forEach(value => values.push(value)); + if (!originalValue.startsWith('[') && !originalValue.endsWith(']')) { + values = undefined; + values = [originalValue]; + } + this.propertiesFormGroup.get(this.field.id).get('value').patchValue(values); + values.forEach(element => { + this.visibilityRulesService.updateValueAndVisibility(this.field?.id, element); + }); + } + } + } + + // Setup autocomplete configuration if needed + if (this.field?.data?.fieldType === DescriptionTemplateFieldType.AUTO_COMPLETE) { + if (!((this.field.data as DescriptionTemplateAutoCompleteData).multiAutoComplete)) { + this.singleAutoCompleteConfiguration = { + filterFn: this.searchFromAutocomplete.bind(this), + initialItems: () => this.searchFromAutocomplete(''), + displayFn: (item) => { try { return (item != null && item.length > 1) ? JSON.parse(item).label : item['label'] } catch { return '' } }, + titleFn: (item) => { try { return item['label'] } catch { return '' } }, + valueAssign: (item) => { try { return JSON.stringify(item) } catch { return '' } }, + subtitleFn: (item) => { try { return item['source'] ? this.language.instant('DATASET-WIZARD.EDITOR.FIELDS.EXTERNAL-AUTOCOMPLETE-SUBTITLE') + item['source'] : this.language.instant('DATASET-WIZARD.EDITOR.FIELDS.EXTERNAL-AUTOCOMPLETE-NO-SOURCE') } catch { return '' } } + }; + } + else { + this.multipleAutoCompleteConfiguration = { + filterFn: this.searchFromAutocomplete.bind(this), + initialItems: () => this.searchFromAutocomplete(''), + displayFn: (item) => { try { return typeof (item) == 'string' ? JSON.parse(item)['label'] : item['label'] } catch { return '' } }, + titleFn: (item) => { try { return typeof (item) == 'string' ? JSON.parse(item)['label'] : item['label'] } catch { return '' } }, + valueAssign: (item) => { try { return typeof (item) == 'string' ? item : JSON.stringify(item) } catch { return '' } }, + subtitleFn: (item) => { try { return item['source'] ? this.language.instant('DATASET-WIZARD.EDITOR.FIELDS.EXTERNAL-AUTOCOMPLETE-SUBTITLE') + item['source'] : this.language.instant('DATASET-WIZARD.EDITOR.FIELDS.EXTERNAL-AUTOCOMPLETE-NO-SOURCE') } catch { return '' } } + } + } + if (isNullOrUndefined(this.datasetProfileId)) { + this.autocompleteOptions = (this.field.data as DescriptionTemplateAutoCompleteData).autoCompleteSingleDataList; + } + } + + switch (this.field?.data?.fieldType) { + case DescriptionTemplateFieldType.EXTERNAL_DATASETS: + this.externalDatasetAutoCompleteConfiguration = { + filterFn: this.searchDatasetExternalDatasets.bind(this), + initialItems: () => this.searchDatasetExternalDatasets(''),//.filter(resultItem => (excludedItems || []).map(x => x.id).indexOf(resultItem.id) === -1), + displayFn: (item) => { try { return typeof (item) == 'string' ? JSON.parse(item)['name'] : item.name } catch { return '' } }, + titleFn: (item) => { try { return typeof (item) == 'string' ? JSON.parse(item)['name'] : item.name } catch { return '' } }, + subtitleFn: (item) => { try { return item.source ? this.language.instant('TYPES.EXTERNAL-DATASET-TYPE.SOURCE:') + item.source : item.tag ? this.language.instant('TYPES.EXTERNAL-DATASET-TYPE.SOURCE:') + item.tag : this.language.instant('TYPES.EXTERNAL-DATASET-TYPE.NO-SOURCE') } catch { return '' } }, + valueAssign: (item) => { try { return typeof (item) == 'string' ? item : JSON.stringify(item) } catch { return '' } } + }; + break; + case DescriptionTemplateFieldType.DATA_REPOSITORIES: + this.dataRepositoriesAutoCompleteConfiguration = { + filterFn: this.searchDatasetExternalDataRepositories.bind(this), + initialItems: () => this.searchDatasetExternalDataRepositories(''), + displayFn: (item) => { try { return typeof (item) == 'string' ? JSON.parse(item)['name'] : item.name } catch { return '' } }, + titleFn: (item) => { try { return typeof (item) == 'string' ? JSON.parse(item)['name'] : item.name } catch { return '' } }, + subtitleFn: (item) => { try { return item.source ? this.language.instant('TYPES.EXTERNAL-DATASET-TYPE.SOURCE:') + item.source : item.tag ? this.language.instant('TYPES.EXTERNAL-DATASET-TYPE.SOURCE:') + item.tag : this.language.instant('TYPES.EXTERNAL-DATASET-TYPE.NO-SOURCE') } catch { return '' } }, + valueAssign: (item) => { try { return typeof (item) == 'string' ? item : JSON.stringify(item) } catch { return '' } } + }; + break; + case DescriptionTemplateFieldType.PUB_REPOSITORIES: + this.pubRepositoriesAutoCompleteConfiguration = { + filterFn: this.searchDatasetExternalPubRepositories.bind(this), + initialItems: () => this.searchDatasetExternalPubRepositories(''), + displayFn: (item) => { try { return typeof (item) == 'string' ? JSON.parse(item)['name'] : item.name } catch { return '' } }, + titleFn: (item) => { try { return typeof (item) == 'string' ? JSON.parse(item)['name'] : item.name } catch { return '' } }, + subtitleFn: (item) => { try { return item.source ? this.language.instant('TYPES.EXTERNAL-DATASET-TYPE.SOURCE:') + item.source : item.tag ? this.language.instant('TYPES.EXTERNAL-DATASET-TYPE.SOURCE:') + item.tag : this.language.instant('TYPES.EXTERNAL-DATASET-TYPE.NO-SOURCE') } catch { return '' } }, + valueAssign: (item) => { try { return typeof (item) == 'string' ? item : JSON.stringify(item) } catch { return '' } } + }; + break; + case DescriptionTemplateFieldType.JOURNAL_REPOSITORIES: + this.journalRepositoriesAutoCompleteConfiguration = { + filterFn: this.searchDatasetExternalJournalRepositories.bind(this), + initialItems: () => this.searchDatasetExternalJournalRepositories(''), + displayFn: (item) => { try { return typeof (item) == 'string' ? JSON.parse(item)['name'] : item.name } catch { return '' } }, + titleFn: (item) => { try { return typeof (item) == 'string' ? JSON.parse(item)['name'] : item.name } catch { return '' } }, + subtitleFn: (item) => { try { return item.source ? this.language.instant('TYPES.EXTERNAL-DATASET-TYPE.SOURCE:') + item.source : item.tag ? this.language.instant('TYPES.EXTERNAL-DATASET-TYPE.SOURCE:') + item.tag : this.language.instant('TYPES.EXTERNAL-DATASET-TYPE.NO-SOURCE') } catch { return '' } }, + valueAssign: (item) => { try { return typeof (item) == 'string' ? item : JSON.stringify(item) } catch { return '' } } + }; + break; + case DescriptionTemplateFieldType.TAXONOMIES: + this.taxonomiesAutoCompleteConfiguration = { + filterFn: this.searchDatasetExternalTaxonomies.bind(this), + initialItems: () => this.searchDatasetExternalTaxonomies(''), + displayFn: (item) => { try { return typeof (item) == 'string' ? JSON.parse(item)['name'] : item.name } catch { return '' } }, + titleFn: (item) => { try { return typeof (item) == 'string' ? JSON.parse(item)['name'] : item.name } catch { return '' } }, + subtitleFn: (item) => { try { return item.source ? this.language.instant('TYPES.EXTERNAL-DATASET-TYPE.SOURCE:') + item.source : item.tag ? this.language.instant('TYPES.EXTERNAL-DATASET-TYPE.SOURCE:') + item.tag : this.language.instant('TYPES.EXTERNAL-DATASET-TYPE.NO-SOURCE') } catch { return '' } }, + valueAssign: (item) => { try { return typeof (item) == 'string' ? item : JSON.stringify(item) } catch { return '' } } + }; + break; + case DescriptionTemplateFieldType.LICENSES: + this.licensesAutoCompleteConfiguration = { + filterFn: this.searchDatasetExternalLicences.bind(this), + initialItems: () => this.searchDatasetExternalLicences(''), + displayFn: (item) => { try { return typeof (item) == 'string' ? JSON.parse(item)['name'] : item.name } catch { return '' } }, + titleFn: (item) => { try { return typeof (item) == 'string' ? JSON.parse(item)['name'] : item.name } catch { return '' } }, + subtitleFn: (item) => { try { return item.source ? this.language.instant('TYPES.EXTERNAL-DATASET-TYPE.SOURCE:') + item.source : item.tag ? this.language.instant('TYPES.EXTERNAL-DATASET-TYPE.SOURCE:') + item.tag : this.language.instant('TYPES.EXTERNAL-DATASET-TYPE.NO-SOURCE') } catch { return '' } }, + valueAssign: (item) => { try { return typeof (item) == 'string' ? item : JSON.stringify(item) } catch { return '' } } + }; + break; + case DescriptionTemplateFieldType.PUBLICATIONS: + this.publicationsAutoCompleteConfiguration = { + filterFn: this.searchDatasetExternalPublications.bind(this), + initialItems: () => this.searchDatasetExternalPublications(''), + displayFn: (item) => { try { return typeof (item) == 'string' ? JSON.parse(item)['name'] : item.name } catch { return '' } }, + titleFn: (item) => { try { return typeof (item) == 'string' ? JSON.parse(item)['name'] : item.name } catch { return '' } }, + subtitleFn: (item) => { try { return item.source ? this.language.instant('TYPES.EXTERNAL-DATASET-TYPE.SOURCE:') + item.source : item.tag ? this.language.instant('TYPES.EXTERNAL-DATASET-TYPE.SOURCE:') + item.tag : this.language.instant('TYPES.EXTERNAL-DATASET-TYPE.NO-SOURCE') } catch { return '' } }, + valueAssign: (item) => { try { return typeof (item) == 'string' ? item : JSON.stringify(item) } catch { return '' } } + }; + break; + case DescriptionTemplateFieldType.REGISTRIES: + this.registriesAutoCompleteConfiguration = { + filterFn: this.searchDatasetExternalRegistries.bind(this), + initialItems: () => this.searchDatasetExternalRegistries(''), + displayFn: (item) => { try { return typeof (item) == 'string' ? JSON.parse(item)['name'] : item.name } catch { return '' } }, + titleFn: (item) => { try { return typeof (item) == 'string' ? JSON.parse(item)['name'] : item.name } catch { return '' } }, + subtitleFn: (item) => { try { return item.source ? this.language.instant('TYPES.EXTERNAL-DATASET-TYPE.SOURCE:') + item.source : item.tag ? this.language.instant('TYPES.EXTERNAL-DATASET-TYPE.SOURCE:') + item.tag : this.language.instant('TYPES.EXTERNAL-DATASET-TYPE.NO-SOURCE') } catch { return '' } }, + valueAssign: (item) => { try { return typeof (item) == 'string' ? item : JSON.stringify(item) } catch { return '' } } + }; + break; + case DescriptionTemplateFieldType.SERVICES: + this.servicesAutoCompleteConfiguration = { + filterFn: this.searchDatasetExternalServices.bind(this), + initialItems: () => this.searchDatasetExternalServices(''), + displayFn: (item) => { try { return typeof (item) == 'string' ? JSON.parse(item)['name'] : item.name } catch { return '' } }, + titleFn: (item) => { try { return typeof (item) == 'string' ? JSON.parse(item)['name'] : item.name } catch { return '' } }, + subtitleFn: (item) => { try { return item.source ? this.language.instant('TYPES.EXTERNAL-DATASET-TYPE.SOURCE:') + item.source : item.tag ? this.language.instant('TYPES.EXTERNAL-DATASET-TYPE.SOURCE:') + item.tag : this.language.instant('TYPES.EXTERNAL-DATASET-TYPE.NO-SOURCE') } catch { return '' } }, + valueAssign: (item) => { try { return typeof (item) == 'string' ? item : JSON.stringify(item) } catch { return '' } } + }; + break; + case DescriptionTemplateFieldType.TAGS: + this.tagsAutoCompleteConfiguration = { + filterFn: this.filterTags.bind(this), + initialItems: (excludedItems: any[]) => this.filterTags('').pipe(map(result => result.filter(resultItem => (excludedItems || []).map(x => x.id).indexOf(resultItem.id) === -1))), + displayFn: (item) => { try { return this.showTag(item) } catch { return '' } }, + titleFn: (item) => { try { return item['name'] } catch { return '' } }, + valueAssign: (item) => { try { return this.addTag(item) } catch { return '' } } + }; + this.parseTags(); + break; + case DescriptionTemplateFieldType.RESEARCHERS: + this.researchersAutoCompleteConfiguration = { + filterFn: this.filterResearchers.bind(this), + initialItems: (excludedItems: any[]) => this.filterResearchers('').pipe(map(result => result.filter(resultItem => (excludedItems || []).map(x => x.id).indexOf(resultItem.id) === -1))), + displayFn: (item) => { try { return typeof (item) == 'string' ? JSON.parse(item)['name'] : item.name } catch { return '' } }, + titleFn: (item) => { try { return typeof (item) == 'string' ? JSON.parse(item)['name'] : item.name } catch { return '' } }, + subtitleFn: (item) => { try { return 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')) } catch { return '' } }, + valueAssign: (item) => { try { return typeof (item) == 'string' ? item : JSON.stringify(item) } catch { return '' } } + }; + break; + case DescriptionTemplateFieldType.ORGANIZATIONS: + this.organisationsAutoCompleteConfiguration = { + filterFn: this.filterOrganisations.bind(this), + initialItems: (excludedItems: any[]) => this.filterOrganisations('').pipe(map(result => result.filter(resultItem => (excludedItems || []).map(x => x.id).indexOf(resultItem.id) === -1))), + displayFn: (item) => { try { return typeof (item) == 'string' ? JSON.parse(item)['name'] : item.name } catch { return '' } }, + titleFn: (item) => { try { return typeof (item) == 'string' ? JSON.parse(item)['name'] : item.name } catch { return '' } }, + subtitleFn: (item) => { try { return 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')) } catch { return '' } }, + valueAssign: (item) => { try { return typeof (item) == 'string' ? item : JSON.stringify(item) } catch { return '' } } + }; + break; + case DescriptionTemplateFieldType.DATASET_IDENTIFIER: + const value = this.propertiesFormGroup.get(this.field.id).get('value').value; + const disabled = this.propertiesFormGroup.get(this.field.id).disabled; + //TODO: Refactor this. + // this.form.removeControl('value'); + // this.form.addControl('value', new DatasetIdModel(value).buildForm()); + // if (disabled) { + // this.form.disable(); + // } + this.datasetIdInitialized = true; + break; + case DescriptionTemplateFieldType.CURRENCY: + this.currencyAutoCompleteConfiguration = { + filterFn: this.searchCurrency.bind(this), + initialItems: () => this.searchCurrency(''), + displayFn: (item) => { try { return typeof (item) == 'string' ? JSON.parse(item)['name'] : item.name } catch { return '' } }, + titleFn: (item) => { try { return typeof (item) == 'string' ? JSON.parse(item)['name'] : item.name } catch { return '' } }, + valueAssign: (item) => { try { return typeof (item) == 'string' ? item : JSON.stringify(item) } catch { return '' } } + }; + break; + case DescriptionTemplateFieldType.VALIDATION: + const value1 = this.propertiesFormGroup.get(this.field.id).get('value').value; + const disabled1 = this.propertiesFormGroup.get(this.field.id).disabled; + //TODO: Refactor this. + // this.form.removeControl('value'); + // this.form.addControl('value', new DatasetIdModel(value1).buildForm()); + // if (disabled1) { + // this.form.disable(); + // } + break; + case DescriptionTemplateFieldType.INTERNAL_DMP_ENTRIES_RESEARCHERS: + this.makeAutocompleteConfiguration(this.searchResearchers.bind(this), "name", "tag"); + break; + case DescriptionTemplateFieldType.INTERNAL_DMP_ENTRIES_DATASETS: + this.makeAutocompleteConfiguration(this.searchDatasets.bind(this), "label"); + break; + case DescriptionTemplateFieldType.INTERNAL_DMP_ENTRIES_DMPS: + this.makeAutocompleteConfiguration(this.searchDmps.bind(this), "label"); + break; + } + + // this.form = this.visibilityRulesService.getFormGroup(this.field.id); + this.propertiesFormGroup.get(this.field.id).get('value').valueChanges + .pipe( + takeUntil(this._destroyed), + distinctUntilChanged() + ) + .subscribe(item => { + // if (this.field?.data?.fieldType === DescriptionTemplateFieldType.ComboBox && this.form.get('data').value.type === DatasetProfileComboBoxType.WordList && this.form.get('data').value.multiList) { + // item.forEach(element => { + // this.visibilityRulesService.updateValueAndVisibility(this.field?.id, element); + // }); + + // } else { + this.visibilityRulesService.updateValueAndVisibility(this.field?.id, item); + // } + }); + } + + // _optionRemove(event) { + // const array = JSON.parse(this.propertiesFormGroup.get(this.field.id).get('value').value); + // if (array) { + // const index = array.map(x => x.id).indexOf(event.id); + // if (index >= 0) { + // array.splice(index, 1); + // } + // this.propertiesFormGroup.get(this.field.id).get('value').patchValue(JSON.stringify(array)); + // } + // } + + searchFromAutocomplete(query: string) { + + if (this.autocompleteOptions) { + const autocompleteRequestItem: RequestItem = new RequestItem(); + autocompleteRequestItem.criteria = new DatasetExternalAutocompleteOptionsCriteria(); + //TODO: refactor this + //autocompleteRequestItem.criteria.autoCompleteSingleDataList = this.autocompleteOptions; + autocompleteRequestItem.criteria.like = query; + return this.datasetExternalAutocompleteService.queryApi(autocompleteRequestItem); + } + else { + const autocompleteRequestItem: RequestItem = new RequestItem(); + autocompleteRequestItem.criteria = new DatasetExternalAutocompleteCriteria(); + let parseIdArray: string[] = this.field?.id.split('_'); + if (parseIdArray.length > 1) { + autocompleteRequestItem.criteria.fieldID = parseIdArray[parseIdArray.length - 1]; + } else { + autocompleteRequestItem.criteria.fieldID = this.field?.id; + } + if (typeof this.datasetProfileId === 'string') { + autocompleteRequestItem.criteria.profileID = this.datasetProfileId; + } + else if (this.datasetProfileId != null) { + autocompleteRequestItem.criteria.profileID = this.datasetProfileId.id; + } + autocompleteRequestItem.criteria.like = query; + return this.datasetExternalAutocompleteService.queryAutocomplete(autocompleteRequestItem); + } + } + + searchResearchers(query: string) { + const reasearcherAutocompleteRequestItem: RequestItem = new RequestItem(); + reasearcherAutocompleteRequestItem.criteria = new ResearcherCriteria; + reasearcherAutocompleteRequestItem.criteria.name = query; + return this.externalSourcesService.searchDMPResearchers(reasearcherAutocompleteRequestItem); + } + + searchDatasets(query: string) { + let fields: Array = new Array(); + const datasetsAutocompleteRequestItem: DataTableRequest = new DataTableRequest(0, 25, { fields: fields }); + datasetsAutocompleteRequestItem.criteria = new DatasetCriteria(); + datasetsAutocompleteRequestItem.criteria.like = query; + return this.datasetService.getPaged(datasetsAutocompleteRequestItem).pipe(map(item => item.data)); + } + + searchDmps(query: string) { + let fields: Array = new Array(); + const dmpsAutocompleteRequestItem: DataTableRequest = new DataTableRequest(0, 25, { fields: fields }); + dmpsAutocompleteRequestItem.criteria = new DmpCriteria(); + dmpsAutocompleteRequestItem.criteria.like = query; + return this.dmpService.getPaged(dmpsAutocompleteRequestItem).pipe(map(item => item.data)); + } + + makeAutocompleteConfiguration(myfunc: Function, title: string, subtitle?: string): void { + if (!((this.field.data as DescriptionTemplateAutoCompleteData).multiAutoComplete)) { + this.singleAutoCompleteConfiguration = { + filterFn: myfunc.bind(this), + initialItems: (extraData) => myfunc(''), + displayFn: (item) => { try { return (item != null && item.length > 1) ? JSON.parse(item)[title] : item[title] } catch { return '' } }, + titleFn: (item) => { try { return item[title] } catch { return '' } }, + valueAssign: (item) => JSON.stringify(item), + subtitleFn: (item) => { try { return item[subtitle] } catch { return '' } } + }; + } + else { + this.multipleAutoCompleteConfiguration = { + filterFn: myfunc.bind(this), + initialItems: (extraData) => myfunc(''), + displayFn: (item) => { try { return typeof (item) == 'string' ? JSON.parse(item)[title] : item[title] } catch { return '' } }, + titleFn: (item) => { try { return typeof (item) == 'string' ? JSON.parse(item)[title] : item[title] } catch { return '' } }, + valueAssign: (item) => { try { return typeof (item) == 'string' ? item : JSON.stringify(item) } catch { return '' } }, + subtitleFn: (item) => { try { return item[subtitle] } catch { return '' } } + } + } + } + + searchDatasetExternalDatasets(query: string): Observable { + // const requestItem: RequestItem = new RequestItem(); + // requestItem.criteria = new ExternalDatasetCriteria(); + // requestItem.criteria.like = query; + // requestItem.criteria.type = ''; + // //return this.externalSourcesService.searchDatasetSExternalDatasetservice(requestItem); + // return this.externalSourcesService.listExternal(ReferenceType.Datasets, requestItem.criteria.like, requestItem.criteria.type); + const lookup = new ReferenceSearchLookup(); + lookup.like = query; + lookup.key = ''; + lookup.type = ReferenceType.Datasets; + return this.referenceService.search(lookup); + } + + searchDatasetExternalDataRepositories(query: string): Observable { + // const requestItem: RequestItem = new RequestItem(); + // requestItem.criteria = new DataRepositoryCriteria(); + // requestItem.criteria.like = query; + // requestItem.criteria.type = ''; + // return this.externalSourcesService.listExternal(ReferenceType.DataRepositories, requestItem.criteria.like, requestItem.criteria.type); + const lookup = new ReferenceSearchLookup(); + lookup.like = query; + lookup.key = ''; + lookup.type = ReferenceType.DataRepositories; + return this.referenceService.search(lookup); + } + searchDatasetExternalPubRepositories(query: string): Observable { + // const requestItem: RequestItem = new RequestItem(); + // requestItem.criteria = new DataRepositoryCriteria(); + // requestItem.criteria.like = query; + // requestItem.criteria.type = ''; + // return this.externalSourcesService.listExternal(ReferenceType.PubRepositories, requestItem.criteria.like, requestItem.criteria.type); + const lookup = new ReferenceSearchLookup(); + lookup.like = query; + lookup.key = ''; + lookup.type = ReferenceType.PubRepositories; + return this.referenceService.search(lookup); + } + searchDatasetExternalJournalRepositories(query: string): Observable { + // const requestItem: RequestItem = new RequestItem(); + // requestItem.criteria = new DataRepositoryCriteria(); + // requestItem.criteria.like = query; + // requestItem.criteria.type = ''; + // return this.externalSourcesService.listExternal(ReferenceType.Journals, requestItem.criteria.like, requestItem.criteria.type); + const lookup = new ReferenceSearchLookup(); + lookup.like = query; + lookup.key = ''; + lookup.type = ReferenceType.Journals; + return this.referenceService.search(lookup); + } + searchDatasetExternalTaxonomies(query: string): Observable { + const requestItem: RequestItem = new RequestItem(); + requestItem.criteria = new TaxonomyCriteria(); + requestItem.criteria.like = query; + requestItem.criteria.type = ''; + return this.externalSourcesService.listExternal(ReferenceType.Taxonomies, requestItem.criteria.like, requestItem.criteria.type); + } + searchDatasetExternalLicences(query: string): Observable { + // const requestItem: RequestItem = new RequestItem(); + // requestItem.criteria = new LicenseCriteria(); + // requestItem.criteria.like = query; + // requestItem.criteria.type = ''; + // return this.externalSourcesService.listExternal(ReferenceType.Licenses, requestItem.criteria.like, requestItem.criteria.type); + const lookup = new ReferenceSearchLookup(); + lookup.like = query; + lookup.key = ''; + lookup.type = ReferenceType.Licenses; + return this.referenceService.search(lookup); + } + searchDatasetExternalPublications(query: string): Observable { + // const requestItem: RequestItem = new RequestItem(); + // requestItem.criteria = new PublicationCriteria(); + // requestItem.criteria.like = query; + // requestItem.criteria.type = ''; + //return this.externalSourcesService.listExternal(ReferenceType.Publications, requestItem.criteria.like, requestItem.criteria.type); + + const lookup = new ReferenceSearchLookup(); + lookup.like = query; + lookup.key = ''; + lookup.type = ReferenceType.Publications; + return this.referenceService.search(lookup); + } + + searchDatasetExternalRegistries(query: string): Observable { + const requestItem: RequestItem = new RequestItem(); + requestItem.criteria = new RegistryCriteria(); + requestItem.criteria.like = query; + requestItem.criteria.type = ''; + return this.externalSourcesService.listExternal(ReferenceType.Registries, requestItem.criteria.like, requestItem.criteria.type); + } + + searchDatasetExternalServices(query: string): Observable { + const requestItem: RequestItem = new RequestItem(); + requestItem.criteria = new ServiceCriteria(); + requestItem.criteria.like = query; + requestItem.criteria.type = ''; + return this.externalSourcesService.listExternal(ReferenceType.Services, requestItem.criteria.like, requestItem.criteria.type); + } + + searchDatasetTags(query: string): Observable { + const requestItem: RequestItem = new RequestItem(); + requestItem.criteria = new TagCriteria(); + requestItem.criteria.like = query; + requestItem.criteria.type = ''; + return this.externalSourcesService.searchDatasetTags(requestItem); + } + + parseTags() { + try { + + + let stringValue = this.propertiesFormGroup.get(this.field.id).get('value').value; + if (typeof stringValue === 'string') { + stringValue = (stringValue).replace(new RegExp('{', 'g'), '{"').replace(new RegExp('=', 'g'), '":"').replace(new RegExp(',', 'g'), '",').replace(new RegExp(', ', 'g'), ', "').replace(new RegExp('}', 'g'), '"}'); + stringValue = stringValue.replace(new RegExp('}"', 'g'), '}').replace(new RegExp('"{', 'g'), '{'); + } else if (stringValue instanceof Array) { + const tempArray = new Array(); + for (let stringTag of stringValue) { + tempArray.push(JSON.parse(stringTag)); + } + stringValue = JSON.stringify(tempArray); + } + const tagArray = JSON.parse(stringValue); + this.propertiesFormGroup.get(this.field.id).get('value').patchValue(tagArray); + } catch (e) { + console.warn('Could not parse tags'); + } + } + + filterTags(value: string): Observable { + const requestItem: RequestItem = new RequestItem(); + const criteria: TagCriteria = new TagCriteria(); + criteria.like = value; + requestItem.criteria = criteria; + return this.externalSourcesService.searchDatasetTags(requestItem); + } + + showTag(ev: any) { + if (typeof ev === 'string') { + return ev; + } else { + return ev.name; + } + } + + addTag(ev: any) { + let item: ExternalTagEditorModel; + //this.filteredTags = this.formGroup.get('tags').value; + if (typeof ev === 'string') { + item = new ExternalTagEditorModel('', ev); + } else { + item = ev; + } + if (item.name !== '') { + return item; + } + } + + filterOrganisations(value: string): Observable { + //return this.externalSourcesService.searchDMPOrganizations(value); + //return this.externalSourcesService.listExternal(ReferenceType.Organizations, value, ''); + const lookup = new ReferenceSearchLookup(); + lookup.like = value; + lookup.key = ''; + lookup.type = ReferenceType.Organizations; + return this.referenceService.search(lookup); + } + + filterResearchers(value: string): Observable { + //return this.externalSourcesService.searchDMPResearchers({ criteria: { name: value, like: null } }); + //return this.externalSourcesService.listExternal(ReferenceType.Researcher, value, ''); + const lookup = new ReferenceSearchLookup(); + lookup.like = value; + lookup.key = ''; + lookup.type = ReferenceType.Researcher; + return this.referenceService.search(lookup); + } + + getDatasetIdControl(name: string): UntypedFormControl { + return this.propertiesFormGroup.get(this.field.id).get(name) as UntypedFormControl; + } + + searchCurrency(query: string): Observable { + return this.currencyService.get(query); + } + + validateId() { + const identifier = this.getDatasetIdControl('identifier').value; + const type = this.getDatasetIdControl('type').value; + this.validationIcon = 'loading'; + this.externalSourcesService.validateIdentifier(identifier, type).pipe(takeUntil(this._destroyed)).subscribe(result => { + this.validationIcon = result === true ? 'done' : 'clear'; + }); + + } + + public upload() { + //TODO: refactor this + // this.fileService.upload(this.filesToUpload[0], this.datasetProfileId.id, this.form.value.id).subscribe((fileId: string) => { + // this.form.get("value").patchValue( + // { "name": this.filesToUpload[0].name, "id": fileId + "", "type": this.filesToUpload[0].type }); + // this.cdr.detectChanges(); + // }, error => { + // this.onCallbackUploadFail(error.error); + // }) + } + + + private onCallbackUploadFail(error: any) { + this.makeFilesNull(); + this.uiNotificationService.snackBarNotification(this.language.instant(error.message), SnackBarNotificationLevel.Error); + } + + fileChangeEvent(fileInput: any, dropped: boolean = false) { + //TODO: refactor this + // if (this.form.value.value) { + // this.onRemove(false); + // } + + // if (dropped) { + // this.filesToUpload = fileInput.addedFiles; + // } else { + // this.filesToUpload = fileInput.target.files; + // } + + + // let messages: string[] = []; + // if (this.filesToUpload.length == 0) { + // messages.push(this.language.instant('DATASET-WIZARD.MESSAGES.NO-FILES-SELECTED')); + // return; + // } else { + // let fileToUpload = this.filesToUpload[0]; + // if (this.form.get("data") && this.form.get("data").value.types + // && this.form.get("data").value.types.map(type => type.value).includes(fileToUpload.type) + // && this.form.get("data").value.maxFileSizeInMB + // && this.form.get("data").value.maxFileSizeInMB * 1048576 >= fileToUpload.size) { + // this.upload(); + // } else { + // this.filesToUpload = null; + // messages.push(this.language.instant('DATASET-WIZARD.MESSAGES.LARGE-FILE-OR-UNACCEPTED-TYPE')); + // messages.push(this.language.instant('DATASET-WIZARD.MESSAGES.MAX-FILE-SIZE', { 'maxfilesize': this.form.get("data").value.maxFileSizeInMB })); + // messages.push(this.language.instant('DATASET-WIZARD.MESSAGES.ACCEPTED-FILE-TYPES') + this.form.get("data").value.types.map(type => type.value).join(", ")); + // } + + // if (messages && messages.length > 0) { + // this.dialog.open(FormValidationErrorsDialogComponent, { + // data: { + // errorMessages: messages + // } + // }) + // } + // } + } + + onRemove(makeFilesNull: boolean = true) { + //TODO: refactor this + // delete from tmp folder - subscribe call + // this.fileService.deleteFromTempFolder(this.form.value.value.id).subscribe(res => { + // if (makeFilesNull) { + // this.makeFilesNull(); + // } + // this.cdr.detectChanges(); + // }, error => { + // if (makeFilesNull) { + // this.makeFilesNull(); + // } + // }) + } + + makeFilesNull() { + //TODO: refactor this + // this.filesToUpload = null; + // this.form.value.value = null; + // this.form.get("value").patchValue(null); + } + + typesToString() { + return (this.field.data as DescriptionTemplateUploadData).types.map(type => type.value).toString(); + } + + download(): void { + //TODO: refactor this + // this.fileService.download(this.form.value.value.id) + // .pipe(takeUntil(this._destroyed)) + // .subscribe(response => { + // const blob = new Blob([response.body], { type: this.form.value.value.type }); + // const filename = this.fileUtils.getFilenameFromContentDispositionHeader(response.headers.get('Content-Disposition')); + + // FileSaver.saveAs(blob, filename); + // }); + } +} diff --git a/dmp-frontend/src/app/ui/description/editor/description-form/components/form-section/form-section.component.html b/dmp-frontend/src/app/ui/description/editor/description-form/components/form-section/form-section.component.html new file mode 100644 index 000000000..2b853b6df --- /dev/null +++ b/dmp-frontend/src/app/ui/description/editor/description-form/components/form-section/form-section.component.html @@ -0,0 +1,176 @@ +
+ + + + + +
+
+ +
+ +
+ +
+
+ + +
+
+ +
+
+ +
+ + +
+
+
+ +
+
+
+
+ +
+
+
+
+
+
+ + + + + + + + + + + + + + + + +
+
+ +
+
+ +
+ +
+
+ +
+
+ + + + + + + + + + + + + + +
{{fieldFormGroup.get('data').value.label}}
+ + + {{fieldsetEntry.form.get('multiplicity').value.placeholder}} + {{('DATASET-PROFILE-EDITOR.STEPS.FORM.COMPOSITE-FIELD.FIELDS.MULTIPLICITY-ADD-ONE-FIELD' + (fieldsetEntry.form.get('multiplicity').value.tableView?'-TABLEVIEW':'')) | translate}} + +
+
+
+ +
+
+
+
+ +
+
+
+ + + {{fieldsetEntry.form.get('multiplicity').value.placeholder}} + {{('DATASET-PROFILE-EDITOR.STEPS.FORM.COMPOSITE-FIELD.FIELDS.MULTIPLICITY-ADD-ONE-FIELD' + (fieldsetEntry.form.get('multiplicity').value.tableView?'-TABLEVIEW':'')) | translate}} + +
+
+ + +
+
+
+ +
+
+ +
+ + + + +
+ +
+ +
+
+
+
+ +
+ +
diff --git a/dmp-frontend/src/app/ui/description/editor/description-form/components/form-section/form-section.component.scss b/dmp-frontend/src/app/ui/description/editor/description-form/components/form-section/form-section.component.scss new file mode 100644 index 000000000..cb676cf4c --- /dev/null +++ b/dmp-frontend/src/app/ui/description/editor/description-form/components/form-section/form-section.component.scss @@ -0,0 +1,46 @@ +.dynamic-form-section { + .expansion-panel { + // background-color: #eeeeee54; + background-color: white; + margin-top: 1em; + margin-bottom: 1em; + // margin-bottom: 1em; + } + .addOneFieldButton { + margin-top: -15px; + margin-left: -11px; + color: var(--primary-color); + } + .panel-title, + .panel-desc { + text-align: left; + font-weight: 700; + font-size: 1rem; + letter-spacing: 0px; + color: #212121; + opacity: 0.81; + margin-top: 1.625rem; + margin-bottom: 0.625rem; + } + + .panel-desc { + // text-transform: capitalize; + text-transform: none; + font-weight: 400; + margin-top: .5rem; + } +} +.styleBorder { + border: 0.2em solid lightgray; + border-radius: 0.5em; + margin-bottom: 0.5em; +} +.mat-expansion-panel-header-description { + padding-bottom: 18px; + color: black; +} + +::ng-deep .mat-expansion-panel-header { + height: auto !important; + min-height: 48px; +} diff --git a/dmp-frontend/src/app/ui/description/editor/description-form/components/form-section/form-section.component.ts b/dmp-frontend/src/app/ui/description/editor/description-form/components/form-section/form-section.component.ts new file mode 100644 index 000000000..068dd0729 --- /dev/null +++ b/dmp-frontend/src/app/ui/description/editor/description-form/components/form-section/form-section.component.ts @@ -0,0 +1,266 @@ +import { + ChangeDetectionStrategy, + ChangeDetectorRef, + Component, + EventEmitter, + Input, + OnChanges, + OnInit, + Output, + SimpleChanges +} from '@angular/core'; +import { UntypedFormGroup } from '@angular/forms'; +import { DescriptionTemplateSection } from '@app/core/model/description-template/description-template'; +import { BaseComponent } from '@common/base/base.component'; +import { takeUntil } from 'rxjs/operators'; +import { DescriptionFieldEditorModel } from '../../../description-editor.model'; +import { ToCEntry } from '../../../table-of-contents/models/toc-entry'; +import { ToCEntryType } from '../../../table-of-contents/models/toc-entry-type.enum'; +import { LinkToScroll } from '../../../table-of-contents/table-of-contents.component'; +import { VisibilityRulesService } from '../../visibility-rules/visibility-rules.service'; + + +@Component({ + selector: 'app-form-section', + templateUrl: './form-section.component.html', + styleUrls: ['./form-section.component.scss'], + changeDetection: ChangeDetectionStrategy.OnPush +}) +export class DescriptionFormSectionComponent extends BaseComponent implements OnInit, OnChanges { + + @Input() section: DescriptionTemplateSection; + @Input() propertiesFormGroup: UntypedFormGroup; + @Input() visibilityRulesService: VisibilityRulesService; + + // @Input() datasetProfileId: String; + // @Input() form: UntypedFormGroup; + @Input() tocentry: ToCEntry; + @Input() pathName: string; + @Input() path: string; + @Input() linkToScroll: LinkToScroll; + @Input() hiddenEntriesIds: string[] = []; + panelExpanded = true; + subsectionLinkToScroll: LinkToScroll; + @Output() askedToScroll = new EventEmitter(); + tocentriesType = ToCEntryType; + @Input() TOCENTRY_ID_PREFIX = ""; + + constructor( + private changeDetector: ChangeDetectorRef + ) { + super(); + + } + + ngOnInit() { + + this.visibilityRulesService.getElementVisibilityMapObservable().pipe(takeUntil(this._destroyed)).subscribe(x => { + this.changeDetector.markForCheck(); + }); + // Set comment fields to properties + this.section.fieldSets.forEach(fieldSet => { + if (fieldSet.hasCommentField && !this.propertiesFormGroup.contains('commentFieldValue' + fieldSet.id)) { + const item: DescriptionFieldEditorModel = new DescriptionFieldEditorModel(); + item.key = 'commentFieldValue' + fieldSet.id; + this.propertiesFormGroup.addControl('commentFieldValue' + fieldSet.id, item.buildForm()); + } + }); + + //TODO uncomment + // if (this.tocentry) {//maybe not needed as well + // this.form = this.tocentry.form as UntypedFormGroup; + // } + // this.initMultipleFieldsVisibility(); + } + + ngOnChanges(changes: SimpleChanges) { + + if (changes['linkToScroll']) { + if (changes['linkToScroll'].currentValue && changes['linkToScroll'].currentValue.section) { + + if (this.pathName === changes['linkToScroll'].currentValue.section) { + this.panelExpanded = true; + } else if (changes['linkToScroll'].currentValue.section.includes(this.pathName)) { + this.subsectionLinkToScroll = changes['linkToScroll'].currentValue; + this.panelExpanded = true; + } + } + } + } + + // setMultipleFieldVisibility(parentCompositeField, compositeField: DatasetDescriptionCompositeFieldEditorModel, idMappings: { old: string, new: string }[]) { + // // ** COMPOSITE FIELD IS SHOWN OR HIDDEN FROM ANOTHER ELEMENT + // const compositeFieldVisibilityDependencies = this.visibilityRulesService.getVisibilityDependency(parentCompositeField); + // if (compositeFieldVisibilityDependencies && compositeFieldVisibilityDependencies.length) { + + // compositeFieldVisibilityDependencies.forEach(x => { + // const visRule: Rule = { + // targetField: compositeField.id, + // sourceField: x.sourceControlId, + // requiredValue: x.sourceControlValue + // } + // this.visibilityRulesService.addNewRule(visRule); + // }); + // } + + // // console.log('idMappings ', idMappings); + // parentCompositeField.fields.forEach(element => { + // // console.log(this.visibilityRulesService.getVisibilityDependency(element.id)); + // const dependency = this.visibilityRulesService.getVisibilityDependency(element.id); + // if (dependency && dependency.length) { + // // * INNER VISIBILITY DEPENDENCIES + // // * IF INNER INPUT HIDES ANOTHER INNER INPUT + // const innerDependency = parentCompositeField.fields.reduce((innerD, currentElement) => { + // const innerDependecies = dependency.filter(d => d.sourceControlId === currentElement.id); + // return [...innerD, ...innerDependecies]; + // }, []) as VisibilityRuleSource[]; + // if (innerDependency.length) { + // //Build visibility source + // const updatedRules = innerDependency.map(x => { + // const newId = idMappings.find(y => y.old === x.sourceControlId); + // return { ...x, sourceControlId: newId.new }; + // }); + // // const visRule: VisibilityRule = { + // // targetControlId: idMappings.find(x => x.old === element.id).new, + // // sourceVisibilityRules: updatedRules + // // } + + + // const rules = updatedRules.map(x => { + // return { + // requiredValue: x.sourceControlValue, + // sourceField: x.sourceControlId, + // targetField: idMappings.find(l => l.old === element.id).new, + // type: '' + // } as Rule; + // }); + + // rules.forEach(rule => { + // this.visibilityRulesService.addNewRule(rule); + // }) + + // // this.visibilityRulesService.appendVisibilityRule(visRule); + // } + + // } + + + // // * OUTER DEPENDENCIES + + // // * IF INNER INPUT HIDES OUTER INPUTS + // const innerIds = idMappings.map(x => x.old) as string[]; + + // const outerTargets = this.visibilityRulesService.getVisibilityTargets(element.id).filter(x => !innerIds.includes(x)); + + // outerTargets.forEach(target => { + + // const outerRules = (this.visibilityRulesService.getVisibilityDependency(target) as VisibilityRuleSource[]).filter(x => x.sourceControlId === element.id); + // const updatedRules = outerRules.map(x => { + // return { ...x, sourceControlId: idMappings.find(y => y.old === element.id).new }; + // }); + + // // const visRule: VisibilityRule = { + // // targetControlId: target, + // // sourceVisibilityRules: updatedRules + // // } + + + // const rules = updatedRules.map(x => { + // return { + // requiredValue: x.sourceControlValue, + // sourceField: x.sourceControlId, + // targetField: target, + // type: '' + // } as Rule; + // }) + // rules.forEach(rule => { + // this.visibilityRulesService.addNewRule(rule); + // }) + // // this.visibilityRulesService.appendVisibilityRule(visRule); + // }); + // // * IF INNER INPUT IS HIDDEN BY OUTER INPUT + // if (dependency && dependency.length) { + // const fieldsThatHideInnerElement = dependency.filter(x => !innerIds.includes(x.sourceControlId)); + // if (fieldsThatHideInnerElement.length) { + // fieldsThatHideInnerElement.forEach(x => { + // const visRule: Rule = { + // targetField: idMappings.find(l => l.old === element.id).new, + // sourceField: x.sourceControlId, + // requiredValue: x.sourceControlValue + // } + // const shouldBeVisibile = this.visibilityRulesService.checkTargetVisibilityProvidedBySource(x.sourceControlId, element.id); + // this.visibilityRulesService.addNewRule(visRule, shouldBeVisibile); + // }); + // } + // } + // // console.log(`for ${element.id} targets are`, outerTargets); + // }); + // } + + // initMultipleFieldsVisibility() { + // (this.form.get('compositeFields') as UntypedFormArray).controls.forEach(control => { + // let parentCompositeField = (control as UntypedFormGroup).getRawValue(); + // if (parentCompositeField.multiplicityItems && parentCompositeField.multiplicityItems.length > 0) { + // parentCompositeField.multiplicityItems.forEach(compositeField => { + // let idMappings: { old: string, new: string }[] = [{ old: parentCompositeField.id, new: compositeField.id }]; + // parentCompositeField.fields.forEach((field, index) => { + // idMappings.push({ old: field.id, new: compositeField.fields[index].id }); + // }); + // this.setMultipleFieldVisibility(parentCompositeField, compositeField, idMappings); + // }) + // } + // }); + // } + + // addMultipleField(fieldsetIndex: number) { + // if (this.form.get('compositeFields').get('' + fieldsetIndex).disabled) { + // return; + // } + // const compositeFieldToBeCloned = (this.form.get('compositeFields').get('' + fieldsetIndex) as UntypedFormGroup).getRawValue(); + // const multiplicityItemsArray = ((this.form.get('compositeFields').get('' + fieldsetIndex).get('multiplicityItems'))); + + // const ordinal = multiplicityItemsArray.length ? multiplicityItemsArray.controls.reduce((ordinal, currentControl) => { + // const currentOrdinal = currentControl.get('ordinal').value as number; + + // if (currentOrdinal >= ordinal) { + // return currentOrdinal + 1; + // } + // return ordinal as number; + // }, 0) : 0; + // const idMappings = [] as { old: string, new: string }[]; + // const compositeField: DatasetDescriptionCompositeFieldEditorModel = new DatasetDescriptionCompositeFieldEditorModel().cloneForMultiplicity(compositeFieldToBeCloned, ordinal, idMappings); + + // this.setMultipleFieldVisibility(compositeFieldToBeCloned, compositeField, idMappings); + // multiplicityItemsArray.push(compositeField.buildForm()); + // } + + // deleteCompositeFieldFormGroup(compositeFildIndex: number) { + // const numberOfItems = this.form.get('compositeFields').get('' + compositeFildIndex).get('multiplicityItems').get('' + 0).get('fields').value.length; + // for (let i = 0; i < numberOfItems; i++) { + // const multiplicityItem = this.form.get('compositeFields').get('' + compositeFildIndex).get('multiplicityItems').get('' + 0).get('fields').get('' + i).value; + // this.form.get('compositeFields').get('' + compositeFildIndex).get('fields').get('' + i).patchValue(multiplicityItem); + // } + // ((this.form.get('compositeFields').get('' + compositeFildIndex).get('multiplicityItems'))).removeAt(0); + // } + + // deleteMultipeFieldFromCompositeFormGroup(compositeFildIndex: number, fildIndex: number) { + // const multiplicityItemsArray = ((this.form.get('compositeFields').get('' + compositeFildIndex).get('multiplicityItems'))); + // multiplicityItemsArray.removeAt(fildIndex); + // multiplicityItemsArray.controls.forEach((control, i) => { + // try { + // control.get('ordinal').setValue(i); + // } catch { + // throw 'Could not find ordinal'; + // } + // }); + // } + + // onAskedToScroll(id: string) { + // this.panelExpanded = true; + // this.askedToScroll.emit(id); + // } + + // visibleControls(controls: any[]) { + // return controls.filter(control => this.visibilityRulesService.isVisibleMap[control.get('id').value)); + // } +} diff --git a/dmp-frontend/src/app/ui/description/editor/description-form/description-form.component.html b/dmp-frontend/src/app/ui/description/editor/description-form/description-form.component.html new file mode 100644 index 000000000..407d1d64b --- /dev/null +++ b/dmp-frontend/src/app/ui/description/editor/description-form/description-form.component.html @@ -0,0 +1,54 @@ + +
+
+
+
+
+ +
+
+
+ +
+
+
+
+ + + + + + + + + + +

+ {{pageEntry.numbering}}. {{pageEntry.label |uppercase}} +

+
+
+ + +
+ +
+
+
+
+
+
+ +
+
+
+
diff --git a/dmp-frontend/src/app/ui/description/editor/description-form/description-form.component.scss b/dmp-frontend/src/app/ui/description/editor/description-form/description-form.component.scss new file mode 100644 index 000000000..3b8872d71 --- /dev/null +++ b/dmp-frontend/src/app/ui/description/editor/description-form/description-form.component.scss @@ -0,0 +1,47 @@ +@media (max-width: 768px) { + .dynamic-form-editor { + .form-container { + padding: 0px; + } + } +} + +.form-container { +} + +.intro { + text-align: left; + font-weight: 400; + letter-spacing: 0px; + color: #212121; + opacity: 1; + margin: 3rem 0rem 3rem 0rem; +} + +.dynamic-form-editor { + mat-vertical-stepper { + background-color: #ffffff; + } +} + +// ::ng-deep .mat-form-field-flex > .mat-form-field-infix {padding: 0.4em 0px !important;} +// ::ng-deep .mat-form-field-label-wrapper { +// top: -1.5em; +// } + +// ::ng-deep +// .mat-form-field-appearance-outline.mat-form-field-can-float.mat-form-field-should-float +// .mat-form-field-label { +// transform: translateY(-1.1em) scale(0.75); +// width: 133.33333%; +// } + +// ::ng-deep .mat-form-field-appearance-outline .mat-form-field-outline { +// background: #fafafa !important; +// } + +// ::ng-deep .mat-step-header .mat-step-icon-selected, +// .mat-step-header .mat-step-icon-state-done, +// .mat-step-header .mat-step-icon-state-edit { +// background-color: var(--primary-color) !important; +// } diff --git a/dmp-frontend/src/app/ui/description/editor/description-form/description-form.component.ts b/dmp-frontend/src/app/ui/description/editor/description-form/description-form.component.ts new file mode 100644 index 000000000..a3cd19334 --- /dev/null +++ b/dmp-frontend/src/app/ui/description/editor/description-form/description-form.component.ts @@ -0,0 +1,371 @@ +import { AfterViewInit, Component, EventEmitter, Input, OnChanges, OnInit, Output, SimpleChanges } from '@angular/core'; +import { UntypedFormGroup } from '@angular/forms'; +import { MatExpansionPanel } from '@angular/material/expansion'; +import { Rule } from '@app/core/model/dataset-profile-definition/rule'; +import { BaseComponent } from '@common/base/base.component'; +import { LinkToScroll } from '../table-of-contents/table-of-contents.component'; +import { VisibilityRulesService } from './visibility-rules/visibility-rules.service'; +import { DescriptionTemplate, DescriptionTemplateSection } from '@app/core/model/description-template/description-template'; +import { Guid } from '@common/types/guid'; + +@Component({ + selector: 'app-description-form', + templateUrl: './description-form.component.html', + styleUrls: ['./description-form.component.scss'] +}) +export class DescriptionFormComponent extends BaseComponent implements OnInit, AfterViewInit, OnChanges { + + @Input() propertiesFormGroup: UntypedFormGroup; + @Input() descriptionTemplate: DescriptionTemplate; + @Input() visibilityRulesService: VisibilityRulesService; + + // @ViewChild('stepper', { static: false }) stepper: MatStepper; + @Input() path: string; + @Input() visibilityRules: Rule[] = []; + @Input() datasetDescription: String; + @Input() linkToScroll: LinkToScroll; + @Output() formChanged: EventEmitter = new EventEmitter(); + @Output() fieldsetFocusChange: EventEmitter = new EventEmitter(); + + // tocentries: ToCEntry[]; + + + @Input() TOCENTRY_ID_PREFIX = ""; + @Output() visibilityRulesInstance = new EventEmitter(); + + // public hiddenEntriesIds: string[] = []; + + constructor( + ) { + super(); + + } + + ngOnInit() { + this.init(); + } + + ngOnChanges(changes: SimpleChanges) { + this.init(); + // When the form is changed set stepper index to 0. + // if (this.stepper && changes['form'] && !changes['form'].isFirstChange()) { + // this.stepper.selectedIndex = 0; + // } else if (this.stepper && changes['linkToScroll'] && changes['linkToScroll'].currentValue) { + // if (changes['linkToScroll'].currentValue.page >= 0) { + // this.stepper.selectedIndex = changes['linkToScroll'].currentValue.page; + // } + // } + } + + ngAfterViewInit() { + + } + + getSectionsOfPage(pageId: string) : DescriptionTemplateSection[]{ //TODO: change that to something more performant since its used at html page. + return this.descriptionTemplate.definition.sections.filter(x => x.page == pageId); + } + init() { + // this.tocentries = this.getTocEntries(); + // const rules_to_append = this._enrichWithMultiplicityRules(this.tocentries); + + // this.visibilityRulesService.buildVisibilityRules([...this.visibilityRules, ...rules_to_append], this.form); + + // if (this.form) { + // this.form.valueChanges + // .pipe(takeUntil(this._destroyed)) + // .subscribe(val => { + // this.formChanged.emit(val); + // }); + // } + // this.visibilityRulesInstance.emit(this.visibilityRulesService); + + + + + // this.hiddenEntriesIds = this._findHiddenEntries(this.tocentries); + + // this.visibilityRulesService.visibilityChange + // .pipe( + // takeUntil(this._destroyed), + // debounceTime(100) + // ) + // .subscribe(_ => { + // this.hiddenEntriesIds = this._findHiddenEntries(this.tocentries); + // }) + } + + onAskedToScroll(panel: MatExpansionPanel, id?: string) { + panel.open(); + this.fieldsetFocusChange.emit(id); + } + + + + // private _enrichWithMultiplicityRules(tocentries: ToCEntry[]): Rule[] { + // if (tocentries) { + // return tocentries.map(entry => { + // if (entry.type === ToCEntryType.Field) return []; // * TODO Me to tora implementation den tha ftasei pote edo + + + // if (entry.type === ToCEntryType.FieldSet) { + // // if(multiplicity: ) + // try { + // // TODO OTAN KANW HIDE MULTIPLE PEDIO TOTE STO ON SHOW HANO TA VALUES (AUTO MPOREI NA EINAI KAI LEGIT) ('NA DOUME AN ONTOS DIAGRAFONTAI I APLA DEN TA DEIXNOUME') + // // * UPDATE KANEI DESTROY TO COMPONENT H NGIF . PITHANOTATA NA XREIASTEI NA TO KANOUME HIDDEN AN THELOUME KATI ALLO + // const multiplicity = entry.form.get('multiplicity').value; + // if ((multiplicity.max > 1) && (multiplicity.min > 0) && (multiplicity.max >= multiplicity.min)) { // has valid multiplicity + // return this._createAndAppendVisibilityRule(entry); + // } + // } catch { + + // } + // return []; + // } + + // if (entry.subEntries) { + // return this._enrichWithMultiplicityRules(entry.subEntries); + // } + // }) + // .reduce((r, c) => { return [...c, ...r] }, []); + // } + // return []; + // } + + // private _createAndAppendVisibilityRule(entry: ToCEntry): Rule[] { + + + // const rules_to_append = []; + + // if (entry && (entry.type === ToCEntryType.FieldSet)) { + + // //childs that are either target or source + // const childIdsWithVisRules = (entry.form.get('fields') as UntypedFormArray).controls.reduce((all, s) => { + // const sval = s.value as Field; + // return this.visibilityRules.find(x => (x.targetField === sval.id) || (x.sourceField === sval.id)) ? [...all, sval] : all; + // }, []) as Field[]; + + + // const innerCompositeFieldOriginalIds = (entry.form.get('fields') as UntypedFormArray).controls.map(x => x.get('id').value) as string[]; + + // //multiplicity items + // const multiplicityItemsValue = entry.form.get('multiplicityItems').value as CompositeField[]; + + + // // ********* FIELDS OF FIELDSET ARE EITHER TARGETS OR SOURCES ***** + + + // if (childIdsWithVisRules.length && multiplicityItemsValue && multiplicityItemsValue.length) { + // //check each multiplicity item composite field + // multiplicityItemsValue.forEach(mi => { + + // const multiplicityCompositeFieldIds = mi.fields.map(x => x.id); + // const idMappings = multiplicityCompositeFieldIds.map(x => { + // return { + // original: innerCompositeFieldOriginalIds.find(l => x.includes(l)), + // multiplicityIdValue: x + // } + // }) as { original: string, multiplicityIdValue: string }[]; + + // //each field of mutliplicity item + // mi.fields.forEach(field => { + + + // //get original visibility rules (original field) + + // //original id + // const original_id = childIdsWithVisRules.find(x => field.id.includes(x.id)).id; + + + // //get vis rules + + // //as source + // const original_as_source = this.visibilityRules.filter(x => x.sourceField === original_id); + // const original_as_target = this.visibilityRules.filter(x => x.targetField === original_id); + + + + // if (original_as_source.length) { + + // //inner dependencies + // const innerDep = original_as_source.filter(x => innerCompositeFieldOriginalIds.includes(x.targetField)); + // innerDep.forEach(x => { + // const newRule = { ...x, sourceField: field.id, targetField: idMappings.find(l => l.original === x.targetField).multiplicityIdValue } as Rule; + // rules_to_append.push(newRule); + // }) + + + // //outer dependencies + // const outerDep = original_as_source.filter(x => !innerCompositeFieldOriginalIds.includes(x.targetField)); + // outerDep.forEach(x => { + // const newRule = { ...x, sourceField: field.id }; + // rules_to_append.push(newRule); + // }) + // } + + + + // if (original_as_target.length) { + + // //inner dependencies + // const innerDep = original_as_target.filter(x => innerCompositeFieldOriginalIds.includes(x.sourceField)); + // innerDep.forEach(x => { + // const newRule = { ...x, targetField: field.id, sourceField: idMappings.find(l => l.original === x.sourceField).multiplicityIdValue } as Rule; + // rules_to_append.push(newRule); + // }) + + // //outer dependencies + // const outerDep = original_as_target.filter(x => !innerCompositeFieldOriginalIds.includes(x.sourceField)); + // outerDep.forEach(x => { + // const newRule = { ...x, targetField: field.id } as Rule; + // rules_to_append.push(newRule); + // }) + // } + + // }) + // }); + // } + + + + + // // ** FIELDSET ITSELF IS TARGET + // // ** source it can never be + + // const compositeFieldAsTargetRules = this.visibilityRules.filter(x => x.targetField === entry.id); + // const idCompositeFieldMappings = multiplicityItemsValue.map(x => { + // return { + // originalValue: entry.id, + // newValue: x.id + // } + // }) as { originalValue: string, newValue: string }[]; + + + // if (compositeFieldAsTargetRules.length) { + + // compositeFieldAsTargetRules.forEach(x => { + // idCompositeFieldMappings.forEach(l => { + // const newRule = { ...x, targetField: l.newValue }; + // rules_to_append.push(newRule); + // }); + // }); + // } + + + // } + + // return rules_to_append; + // } + + // private _buildRecursively(form: UntypedFormGroup, whatAmI: ToCEntryType): ToCEntry { + // if (!form) return null; + + // switch (whatAmI) { + // case ToCEntryType.Section: + // const sections = form.get('sections') as UntypedFormArray; + // const fieldsets = form.get('compositeFields') as UntypedFormArray; + + + // const tempResult: ToCEntry[] = []; + + // if (sections && sections.length) { + // sections.controls.forEach(section => { + // tempResult.push(this._buildRecursively(section as UntypedFormGroup, ToCEntryType.Section)); + // }); + + // } else if (fieldsets && fieldsets.length) { + // fieldsets.controls.forEach(fieldset => { + // tempResult.push(this._buildRecursively(fieldset as UntypedFormGroup, ToCEntryType.FieldSet)); + // }); + // } + // return { + // // form: form, + // id: form.get('id').value, + // label: form.get('title').value, + // numbering: '', + // subEntries: tempResult, + // subEntriesType: sections && sections.length ? ToCEntryType.Section : ToCEntryType.FieldSet, + // type: ToCEntryType.Section, + // ordinal: form.get('ordinal').value + // } + // case ToCEntryType.FieldSet: + // return { + // // form: form, + // label: form.get('title').value, + // id: form.get('id').value, + // numbering: 's', + // subEntries: [], + // subEntriesType: ToCEntryType.Field, + // type: ToCEntryType.FieldSet, + // ordinal: form.get('ordinal').value + // } + // } + // } + + // private _sortByOrdinal(tocentries: ToCEntry[]) { + + // if (!tocentries || !tocentries.length) return; + + // tocentries.sort(this._customCompare); + // tocentries.forEach(entry => { + // this._sortByOrdinal(entry.subEntries); + // }); + // } + + // private _customCompare(a, b) { + // return a.ordinal - b.ordinal; + // } + + // private _calculateNumbering(tocentries: ToCEntry[], depth: number[] = []) { + // if (!tocentries || !tocentries.length) { + // return; + // } + + // let prefixNumbering = depth.length ? depth.join('.') : ''; + + // if (depth.length) prefixNumbering = prefixNumbering + "."; + // tocentries.forEach((entry, i) => { + // entry.numbering = prefixNumbering + (i + 1); + // this._calculateNumbering(entry.subEntries, [...depth, i + 1]) + // }); + // } + + // getTocEntries(): ToCEntry[] { + // if (!this.form) { return []; } + // const result: ToCEntry[] = []; + + // //build parent pages + // (this.form.get('pages') as UntypedFormArray).controls.forEach((pageElement, i) => { + // result.push({ + // id: i + 'id', + // label: pageElement.get('title').value, + // type: ToCEntryType.Page, + // // form: pageElement, + // numbering: (i + 1).toString(), + // subEntriesType: ToCEntryType.Section, + // subEntries: [], + // ordinal: pageElement.get('ordinal').value + // } as ToCEntry) + // }); + + + + // result.forEach((entry, i) => { + + // const sections = entry.form.get('sections') as UntypedFormArray; + + // sections.controls.forEach(section => { + // const tempResults = this._buildRecursively(section as UntypedFormGroup, ToCEntryType.Section); + // entry.subEntries.push(tempResults); + // }); + + // }); + + // this._sortByOrdinal(result); + // //calculate numbering + // this._calculateNumbering(result); + // return result; + + // } + + +} \ No newline at end of file diff --git a/dmp-frontend/src/app/ui/description/editor/description-form/description-form.module.ts b/dmp-frontend/src/app/ui/description/editor/description-form/description-form.module.ts new file mode 100644 index 000000000..6b3a9994a --- /dev/null +++ b/dmp-frontend/src/app/ui/description/editor/description-form/description-form.module.ts @@ -0,0 +1,41 @@ +import { NgModule } from '@angular/core'; +import { FormattingModule } from "@app/core/formatting.module"; +import { FileService } from "@app/core/services/file/file.service"; +import { AutoCompleteModule } from '@app/library/auto-complete/auto-complete.module'; +import { RichTextEditorModule } from "@app/library/rich-text-editor/rich-text-editor.module"; +import { CommonFormsModule } from '@common/forms/common-forms.module'; +import { CommonUiModule } from '@common/ui/common-ui.module'; +import { NgxDropzoneModule } from "ngx-dropzone"; +import { DescriptionFormCompositeTitleComponent } from './components/form-composite-title/form-composite-title.component'; +import { DescriptionFormFieldSetComponent } from './components/form-field-set/form-field-set.component'; +import { DescriptionFormFieldComponent } from './components/form-field/form-field.component'; +import { DescriptionFormSectionComponent } from './components/form-section/form-section.component'; +import { DescriptionFormComponent } from './description-form.component'; +import { VisibilityRulesService } from './visibility-rules/visibility-rules.service'; + + +@NgModule({ + imports: [ + CommonUiModule, + CommonFormsModule, + AutoCompleteModule, + RichTextEditorModule, + NgxDropzoneModule, + FormattingModule + ], + declarations: [ + DescriptionFormComponent, + DescriptionFormSectionComponent, + DescriptionFormFieldSetComponent, + DescriptionFormFieldComponent, + DescriptionFormCompositeTitleComponent + ], + exports: [ + DescriptionFormComponent + ], + providers: [ + FileService + ] +}) +export class DescriptionFormModule { } + diff --git a/dmp-frontend/src/app/ui/description/editor/description-form/visibility-rules/models/visibility-rule-source.ts b/dmp-frontend/src/app/ui/description/editor/description-form/visibility-rules/models/visibility-rule-source.ts new file mode 100644 index 000000000..2db9978a3 --- /dev/null +++ b/dmp-frontend/src/app/ui/description/editor/description-form/visibility-rules/models/visibility-rule-source.ts @@ -0,0 +1,4 @@ +export class VisibilityRuleSource { + public sourceControlId: string; + public sourceControlValue: string; +} diff --git a/dmp-frontend/src/app/ui/description/editor/description-form/visibility-rules/models/visibility-rule.ts b/dmp-frontend/src/app/ui/description/editor/description-form/visibility-rules/models/visibility-rule.ts new file mode 100644 index 000000000..b2fba603b --- /dev/null +++ b/dmp-frontend/src/app/ui/description/editor/description-form/visibility-rules/models/visibility-rule.ts @@ -0,0 +1,6 @@ +import { VisibilityRuleSource } from "./visibility-rule-source"; + +export class VisibilityRule { + public targetControlId: string; + public sourceVisibilityRules: Array; +} diff --git a/dmp-frontend/src/app/ui/description/editor/description-form/visibility-rules/models/visibility-rules-context.ts b/dmp-frontend/src/app/ui/description/editor/description-form/visibility-rules/models/visibility-rules-context.ts new file mode 100644 index 000000000..547b088ef --- /dev/null +++ b/dmp-frontend/src/app/ui/description/editor/description-form/visibility-rules/models/visibility-rules-context.ts @@ -0,0 +1,47 @@ +import { Rule } from "@app/core/model/dataset-profile-definition/rule"; +import { VisibilityRule } from "./visibility-rule"; + +export class VisibilityRulesContext { + + public rules: Array = new Array(); + + constructor() { } + + public getRulesFromKey(id: string): VisibilityRule { + + for (let i = 0; i < this.rules.length; i++) { + if (id === this.rules[i].targetControlId) { return this.rules[i]; } + } + return null; + } + + public buildVisibilityRuleContext(items: Array) { + items.forEach(item => { + this.addToVisibilityRulesContext(item); + }); + } + + public addToVisibilityRulesContext(item: Rule): void { + for (let i = 0; i < this.rules.length; i++) { + if (this.rules[i].targetControlId === item.targetField) { + + const newRule = { sourceControlId: item.sourceField, sourceControlValue: item.requiredValue }; + const ruleExists = this.rules[i].sourceVisibilityRules.find(x => { + return Object.keys(x).reduce((exact, key) => { + if (!exact) return false; + return x[key] === newRule[key]; + }, true); + }) + + if (!ruleExists) { + this.rules[i].sourceVisibilityRules.push(newRule); + } + + return; + } + } + const newVisibilityRuleArray = [({ sourceControlId: item.sourceField, sourceControlValue: item.requiredValue })]; + this.rules.push({ targetControlId: item.targetField, sourceVisibilityRules: newVisibilityRuleArray }); + return; + } +} diff --git a/dmp-frontend/src/app/ui/description/editor/description-form/visibility-rules/visibility-rules.service.ts b/dmp-frontend/src/app/ui/description/editor/description-form/visibility-rules/visibility-rules.service.ts new file mode 100644 index 000000000..285e2a19d --- /dev/null +++ b/dmp-frontend/src/app/ui/description/editor/description-form/visibility-rules/visibility-rules.service.ts @@ -0,0 +1,453 @@ +import { ApplicationRef, Injectable, NgZone } from '@angular/core'; +import { AbstractControl, UntypedFormArray, UntypedFormGroup } from '@angular/forms'; +import { DatasetProfileFieldViewStyle } from '@app/core/common/enum/dataset-profile-field-view-style'; +import { isNumeric } from '@app/utilities/enhancers/utils'; +import { Observable, Subject } from 'rxjs'; +import { VisibilityRule } from './models/visibility-rule'; +import { VisibilityRuleSource } from './models/visibility-rule-source'; +import { VisibilityRulesContext } from './models/visibility-rules-context'; +import { Rule } from '@app/core/model/dataset-profile-definition/rule'; +import { DescriptionTemplate, DescriptionTemplateSection } from '@app/core/model/description-template/description-template'; + +@Injectable() +export class VisibilityRulesService { + + private readonly VISIBILITY_RULE_LOGIC: 'OR' | 'AND' = 'OR'; + private readonly DEFAULTVISIBILITY = false; + + private visibilityRuleContext: VisibilityRulesContext; + private form: AbstractControl; + public elementVisibilityMap = new MapWithDefault(); + private elementVisibilityMapSubject = new Subject>(); + private elementComputationalMap = new Map>(); /// keep saved the values of each form control validity value + private _changeMade$ = new Subject(); + + + get isVisibleMap(): MapWithDefault { + // console.log('isVisibleMap'); + return this.elementVisibilityMap; + + }; /// keep saved the values of each form control validity value + + constructor( + public applicationReference: ApplicationRef, + public ngZone: NgZone + ) { + + } + + getElementVisibilityMapObservable(): Observable> { + this.isVisibleMap + console.log('getElementVisibilityMapObservable: '); + return this.elementVisibilityMapSubject.asObservable(); + } + + public checkElementVisibility(id: string): boolean { + console.log('checkElementVisibility: ' + id); + return true; + // if (this.visibilityRuleContext.rules.filter(item => item.targetControlId === id).length === 0) { return true; } + // console.log(this.elementVisibilityMap.has(id) ? this.elementVisibilityMap.get(id) : false); + // return this.elementVisibilityMap.has(id) ? this.elementVisibilityMap.get(id) : false; + } + + public buildVisibilityRules(item: Array, form: AbstractControl) { + this.visibilityRuleContext = new VisibilityRulesContext(); + this.visibilityRuleContext.buildVisibilityRuleContext(item || []); + this.form = form; + this.resetVisibilityRules(); + } + + public updateValueAndVisibility(id: string, value: any) { + console.log('updateValueAndVisibility: ' + id + ' value: ' + value); + const visibilityRules = this.visibilityRuleContext.rules.filter(item => item.sourceVisibilityRules.filter(source => source.sourceControlId === id).length > 0); + if (visibilityRules.length > 0) { + visibilityRules.forEach(item => this.evaluateVisibility(item, value, id)); + this.elementVisibilityMapSubject.next(this.elementVisibilityMap); + } + } + + private evaluateVisibility(visibilityRule: VisibilityRule, value: any, sourceId: string) {// source controlId is the same + console.log('evaluateVisibility: ' + visibilityRule + ' value: ' + value + ' sourceId: ' + sourceId); + + const targetId = visibilityRule.targetControlId; + const visibilityMap = this.elementComputationalMap.get(targetId) ? this.elementComputationalMap.get(targetId) : new Map(); + + + if (value instanceof Array) { + + const parsedSourceControlValues = visibilityRule.sourceVisibilityRules.map(e => this.parseValue(e.sourceControlValue)); + const parsedValues = value.map(e => this.parseValue(e)); + + const isVisible = parsedValues.map(v => parsedSourceControlValues.includes(v)).reduce((acc, current) => acc || current, false); + + + // if(isVisible){ + // this._emitChangesIfNeeded(visibilityRule.targetControlId, true); + // this.elementVisibilityMap.set(visibilityRule.targetControlId, true); + // return; + // } + visibilityMap.set(sourceId, isVisible); + + } else { + const visibilityDependencySource = visibilityRule.sourceVisibilityRules.filter(x => x.sourceControlId === sourceId); + + const shouldBeVisible = visibilityDependencySource.reduce((isVisible, x) => { + + const shouldBeHidden = value !== null && (this.parseValue(value) !== this.parseValue(x.sourceControlValue)); + return this.VISIBILITY_RULE_LOGIC === 'OR' ? (isVisible || !shouldBeHidden) : (isVisible && !shouldBeHidden); + // if(value !== null && ) + }, this.VISIBILITY_RULE_LOGIC === 'AND'); + visibilityMap.set(sourceId, shouldBeVisible); + } + + + this.elementComputationalMap.set(targetId, visibilityMap);// unnessecary + + + const isVisible = this._computeVisibility(targetId); + this._emitChangesIfNeeded(targetId, isVisible); + const previousVisibility = this.elementVisibilityMap.get(targetId); + this.elementVisibilityMap.set(targetId, isVisible); + + if (!isVisible && previousVisibility !== isVisible) { + this.resetControlWithId(this.form, targetId); + } + + + // for (let i = 0; i < visibilityRule.sourceVisibilityRules.length; i++) { + // if (value != null && (this.parseValue(value) !== this.parseValue(visibilityRule.sourceVisibilityRules[i].sourceControlValue))) { + // this._emitChangesIfNeeded(visibilityRule.targetControlId, false); + // this.elementVisibilityMap.set(visibilityRule.targetControlId, false); + // this.resetControlWithId(this.form, visibilityRule.targetControlId); + // //this.updateValueAndVisibility(visibilityRule.targetControlId, null); + // // this.clearValues(targetPathKey); + // return; + // } + // } + // this._emitChangesIfNeeded(visibilityRule.targetControlId, true); + // this.elementVisibilityMap.set(visibilityRule.targetControlId, true); + + // this.updateValueAndVisibility(visibilityRule.targetControlId, null); + } + + + private _computeVisibility(targetId: string): boolean { + console.log('_computeVisibility: ' + targetId); + + const visibilityMap = this.elementComputationalMap.get(targetId); + const values = visibilityMap.values(); + let currentVal = values.next(); + let visibilityValues: boolean[] = []; + while (!currentVal.done) { + visibilityValues.push(currentVal.value); + currentVal = values.next(); + } + + + if (visibilityValues.length) { + return visibilityValues.reduce((r, c) => { + if (this.VISIBILITY_RULE_LOGIC === 'OR') { + return r || c; + } else { + return r && c; + } + }, visibilityValues[0]); + } + + return this.DEFAULTVISIBILITY; + } + + private resetVisibilityRules() { + console.log('resetVisibilityRules: '); + + this.elementVisibilityMap.clear(); + this.elementVisibilityMap = new MapWithDefault(); + this.elementComputationalMap.clear(); + this.elementComputationalMap = new Map>(); + this._populateComputationMap(); /// !IMPORTANT FOR THE AND LOGIC + this._changeMade$.next(); + } + + private _populateComputationMap(): void { + console.log('_populateComputationMap: '); + this.visibilityRuleContext.rules.forEach(rule => { + const targetId = rule.targetControlId; + const visibilityMap = this.elementComputationalMap.get(targetId) ? this.elementComputationalMap.get(targetId) : new Map(); + rule.sourceVisibilityRules.forEach(vr => { + visibilityMap.set(vr.sourceControlId, this.DEFAULTVISIBILITY); + }); + this.elementComputationalMap.set(targetId, visibilityMap); + }); + } + + parseValue(value: any) { + if (typeof value === 'string') { + if (isNumeric(value)) { return value; } + else if (value === 'true') { + return true; + } + else if (value === 'false') { + return false; + } + else { return this.translate(value); } + } else { return value; } + } + + search(path, obj, target) { + for (const k in obj) { + if (obj.hasOwnProperty(k)) { + if (obj[k] === target) { + return path + '.' + k; + } else if (typeof obj[k] === 'object') { + const result = this.search(path + '.' + k, obj[k], target); + if (result) { + return result; + } + } + } + } + return false; + } + + scanIfChildsOfCompositeFieldHasVisibleItems(compositeFieldParent: UntypedFormGroup): boolean { + // console.log('scanIfChildsOfCompositeFieldHasVisibleItems: ' + compositeFieldParent); + + //TODO: implement this + return true; + // let isVisible = false; + // ((compositeFieldParent.get('fields'))).controls.forEach(element => { + // if (this.checkElementVisibility(element.get('id').value)) { + // isVisible = true; + // } + // }); + // return isVisible; + } + + private translate(item: any) { + try { + return JSON.parse(item).value; + } catch (error) { + return item; + } + } + + private resetControlWithId(formControl: AbstractControl, id: string) { + console.log('resetControlWithId: ' + id); + //TODO: implement this + // if (formControl instanceof UntypedFormGroup) { + // if ((formControl as UntypedFormGroup).contains('id') && (formControl as UntypedFormGroup).contains('value') && (formControl as UntypedFormGroup).get('id').value === id) { + // this.resetFieldFormGroup(formControl); + // } if ((formControl as UntypedFormGroup).contains('id') && (formControl as UntypedFormGroup).contains('fields') && (formControl as UntypedFormGroup).get('id').value === id) { + // this.resetCompositeFieldFormGroup(formControl); + // } else { + // Object.keys(formControl.controls).forEach(item => { + // const control = formControl.get(item); + // this.resetControlWithId(control, id); + // }); + // } + // } else if (formControl instanceof UntypedFormArray) { + // formControl.controls.forEach(item => { + // this.resetControlWithId(item, id); + // }); + // } + } + + private resetFieldFormGroup(formGroup: UntypedFormGroup) { + console.log('resetFieldFormGroup: ' + formGroup); + //TODO: implement this + // const renderStyle = formGroup.getRawValue().viewStyle.renderStyle; + // if (renderStyle === DatasetProfileFieldViewStyle.Validation || renderStyle === DatasetProfileFieldViewStyle.DatasetIdentifier) { + // formGroup.get('value').setValue({ identifier: '', type: '' }); + // } else { + // formGroup.get('value').setValue(formGroup.get('defaultValue').value ? this.parseValue(formGroup.get('defaultValue').value.value) : undefined); + // } + + } + + private resetCompositeFieldFormGroup(formGroup: UntypedFormGroup) { + console.log('resetCompositeFieldFormGroup: ' + formGroup); + //TODO: implement this + // (formGroup.get('fields') as UntypedFormArray).controls.forEach((element: UntypedFormGroup) => { + // this.resetFieldFormGroup(element); + // }); + // (formGroup.get('multiplicityItems') as UntypedFormArray).controls.splice(0); + } + private _emitChangesIfNeeded(id: string, valueToBeSet: boolean) { + if (this.elementVisibilityMap.has(id)) { + if (this.elementVisibilityMap.get(id) != valueToBeSet) { + this._changeMade$.next(); + } + } else { + this._changeMade$.next(); + } + } + public get visibilityChange() { + return this._changeMade$.asObservable(); + } + public getVisibilityDependency(targetId: string): VisibilityRuleSource[] | null { + console.log('getVisibilityDependency: ' + targetId); + return this.visibilityRuleContext.rules.reduce((hasDependency, rule) => { + if (hasDependency) return hasDependency; + + if (rule.targetControlId === targetId) { + return rule.sourceVisibilityRules; + } + + return null; + }, null) as VisibilityRuleSource[]; + } + + public getVisibilityTargets(sourceId: string): string[] { + console.log('getVisibilityTargets: ' + sourceId); + return this.visibilityRuleContext.rules.filter(x => { + const result = x.sourceVisibilityRules.filter(y => y.sourceControlId === sourceId); + return result.length; + }).map(x => x.targetControlId); + } + + // public appendVisibilityRule(rule: VisibilityRule): void{ + + // const existingTargetRule = this.visibilityRuleContext.rules.find( r => r.targetControlId === rule.targetControlId); + + // if(existingTargetRule){ + // rule.sourceVisibilityRules.forEach(svr =>{ + // existingTargetRule.sourceVisibilityRules.push(svr); + // }); + // }else{ + // this.visibilityRuleContext.rules.push(rule); + // } + + + // } + + + //removes rule that has the specific id either as a source either as a target + public removeAllIdReferences(id: string): void { + console.log('removeAllIdReferences: ' + id); + + // * Remove from visibility rues and visibility rules context + + //remove as a target + const temp = this.visibilityRuleContext.rules.map((x, i) => (x.targetControlId === id) ? i : null); + const indexes = temp.filter(x => x !== null); + indexes.reverse().forEach(index => this.visibilityRuleContext.rules.splice(index, 1)); + this.elementVisibilityMap.delete(id); + + + + //remove as a source + const tbd = this.visibilityRuleContext.rules.reduce((to_be_deleted, rule, ruleIdx) => { + const idxs = rule.sourceVisibilityRules.map((x, i) => (x.sourceControlId === id) ? i : null).filter(x => x !== null); + idxs.reverse().forEach(index => rule.sourceVisibilityRules.splice(index, 1)); + + if (!rule.sourceVisibilityRules.length) { + to_be_deleted.push(ruleIdx); + } + return to_be_deleted + }, []); + + + //clean up empty + tbd.reverse().forEach(index => { + this.visibilityRuleContext.rules.splice(index, 1); + }); + + + + // * Remove from computational map + + // as a target + if (this.elementComputationalMap.get(id)) { + this.elementComputationalMap.delete(id); + } + + + // as a source + const keyIterator = this.elementComputationalMap.keys(); + let currentKey = keyIterator.next(); + + + while (!currentKey.done) { + const currentVals = this.elementComputationalMap.get(currentKey.value); + currentVals.delete(id); + currentKey = keyIterator.next(); + } + } + + + public addNewRule(rule: Rule, currentVisibility = this.DEFAULTVISIBILITY): void { + console.log('addNewRule: ' + rule + ' currentVisibility: ' + currentVisibility); + + const targetId = rule.targetField; + const sourceId = rule.sourceField; + this.visibilityRuleContext.addToVisibilityRulesContext(rule); + + + let visibilityMap = this.elementComputationalMap.get(targetId); + + if (!visibilityMap) { + visibilityMap = new Map(); + this.elementComputationalMap.set(targetId, visibilityMap); + } + + visibilityMap.set(sourceId, currentVisibility); + const isVisible = this._computeVisibility(targetId); + + this._emitChangesIfNeeded(targetId, isVisible); + this.elementVisibilityMap.set(targetId, isVisible); + this.elementVisibilityMapSubject.next(this.elementVisibilityMap); + } + + + /** + * Check what sourceId hides or shows the target field + * return true if no rule found + */ + public checkTargetVisibilityProvidedBySource(sourceId: string, targetId: string): boolean { + console.log('checkTargetVisibilityProvidedBySource: ' + sourceId + ' targetId: ' + targetId); + + const computationalMap = this.elementComputationalMap.get(targetId); + if (computationalMap) { + return !!computationalMap.get(sourceId); + } + + return true; + } + + public getVisibilityRulesFromDescriptionTempalte(descriptionTemplate: DescriptionTemplate): Rule[] { + console.log('getVisibilityRulesFromDescriptionTempalte: ' + descriptionTemplate); + const result: Rule[] = this.getVisibilityRulesFromDescriptionTempalteSections(descriptionTemplate?.definition?.sections); + return result; + } + + public getVisibilityRulesFromDescriptionTempalteSections(sections: DescriptionTemplateSection[]): Rule[] { + console.log('getVisibilityRulesFromDescriptionTempalteSections: ' + sections); + const result: Rule[] = []; + + sections.forEach(section => { + if (section.sections != null) { result.push(...this.getVisibilityRulesFromDescriptionTempalteSections(section.sections)); }; + section?.fieldSets?.forEach(fieldSet => { + fieldSet?.fields?.forEach(field => { + field.visibilityRules?.forEach(visibilityRule => { + result.push({ + sourceField: field.id.toString(), + targetField: visibilityRule.target, + requiredValue: visibilityRule.value + }) + }); + }); + }); + }); + return result; + } +} + +class MapWithDefault extends Map { + get(key) { + console.log('MapWithDefault'); + if (!this.has(key)) { + this.set(key, true); + } + return super.get(key); + } +} \ No newline at end of file diff --git a/dmp-frontend/src/app/ui/description/dataset-wizard/external-references/dataset-external-references-editor.component.html b/dmp-frontend/src/app/ui/description/editor/external-references/dataset-external-references-editor.component.html similarity index 100% rename from dmp-frontend/src/app/ui/description/dataset-wizard/external-references/dataset-external-references-editor.component.html rename to dmp-frontend/src/app/ui/description/editor/external-references/dataset-external-references-editor.component.html diff --git a/dmp-frontend/src/app/ui/description/dataset-wizard/external-references/dataset-external-references-editor.component.scss b/dmp-frontend/src/app/ui/description/editor/external-references/dataset-external-references-editor.component.scss similarity index 100% rename from dmp-frontend/src/app/ui/description/dataset-wizard/external-references/dataset-external-references-editor.component.scss rename to dmp-frontend/src/app/ui/description/editor/external-references/dataset-external-references-editor.component.scss diff --git a/dmp-frontend/src/app/ui/description/dataset-wizard/external-references/dataset-external-references-editor.component.ts b/dmp-frontend/src/app/ui/description/editor/external-references/dataset-external-references-editor.component.ts similarity index 100% rename from dmp-frontend/src/app/ui/description/dataset-wizard/external-references/dataset-external-references-editor.component.ts rename to dmp-frontend/src/app/ui/description/editor/external-references/dataset-external-references-editor.component.ts diff --git a/dmp-frontend/src/app/ui/description/dataset-wizard/external-references/editors/data-repository/dataset-external-data-repository-dialog-editor.component.html b/dmp-frontend/src/app/ui/description/editor/external-references/editors/data-repository/dataset-external-data-repository-dialog-editor.component.html similarity index 100% rename from dmp-frontend/src/app/ui/description/dataset-wizard/external-references/editors/data-repository/dataset-external-data-repository-dialog-editor.component.html rename to dmp-frontend/src/app/ui/description/editor/external-references/editors/data-repository/dataset-external-data-repository-dialog-editor.component.html diff --git a/dmp-frontend/src/app/ui/description/dataset-wizard/external-references/editors/data-repository/dataset-external-data-repository-dialog-editor.component.scss b/dmp-frontend/src/app/ui/description/editor/external-references/editors/data-repository/dataset-external-data-repository-dialog-editor.component.scss similarity index 100% rename from dmp-frontend/src/app/ui/description/dataset-wizard/external-references/editors/data-repository/dataset-external-data-repository-dialog-editor.component.scss rename to dmp-frontend/src/app/ui/description/editor/external-references/editors/data-repository/dataset-external-data-repository-dialog-editor.component.scss diff --git a/dmp-frontend/src/app/ui/description/dataset-wizard/external-references/editors/data-repository/dataset-external-data-repository-dialog-editor.component.ts b/dmp-frontend/src/app/ui/description/editor/external-references/editors/data-repository/dataset-external-data-repository-dialog-editor.component.ts similarity index 100% rename from dmp-frontend/src/app/ui/description/dataset-wizard/external-references/editors/data-repository/dataset-external-data-repository-dialog-editor.component.ts rename to dmp-frontend/src/app/ui/description/editor/external-references/editors/data-repository/dataset-external-data-repository-dialog-editor.component.ts diff --git a/dmp-frontend/src/app/ui/description/dataset-wizard/external-references/editors/external-dataset/dataset-external-dataset-dialog-editor.component.html b/dmp-frontend/src/app/ui/description/editor/external-references/editors/external-dataset/dataset-external-dataset-dialog-editor.component.html similarity index 100% rename from dmp-frontend/src/app/ui/description/dataset-wizard/external-references/editors/external-dataset/dataset-external-dataset-dialog-editor.component.html rename to dmp-frontend/src/app/ui/description/editor/external-references/editors/external-dataset/dataset-external-dataset-dialog-editor.component.html diff --git a/dmp-frontend/src/app/ui/description/dataset-wizard/external-references/editors/external-dataset/dataset-external-dataset-dialog-editor.component.scss b/dmp-frontend/src/app/ui/description/editor/external-references/editors/external-dataset/dataset-external-dataset-dialog-editor.component.scss similarity index 100% rename from dmp-frontend/src/app/ui/description/dataset-wizard/external-references/editors/external-dataset/dataset-external-dataset-dialog-editor.component.scss rename to dmp-frontend/src/app/ui/description/editor/external-references/editors/external-dataset/dataset-external-dataset-dialog-editor.component.scss diff --git a/dmp-frontend/src/app/ui/description/dataset-wizard/external-references/editors/external-dataset/dataset-external-dataset-dialog-editor.component.ts b/dmp-frontend/src/app/ui/description/editor/external-references/editors/external-dataset/dataset-external-dataset-dialog-editor.component.ts similarity index 100% rename from dmp-frontend/src/app/ui/description/dataset-wizard/external-references/editors/external-dataset/dataset-external-dataset-dialog-editor.component.ts rename to dmp-frontend/src/app/ui/description/editor/external-references/editors/external-dataset/dataset-external-dataset-dialog-editor.component.ts diff --git a/dmp-frontend/src/app/ui/description/dataset-wizard/external-references/editors/registry/dataset-external-registry-dialog-editor.component.html b/dmp-frontend/src/app/ui/description/editor/external-references/editors/registry/dataset-external-registry-dialog-editor.component.html similarity index 100% rename from dmp-frontend/src/app/ui/description/dataset-wizard/external-references/editors/registry/dataset-external-registry-dialog-editor.component.html rename to dmp-frontend/src/app/ui/description/editor/external-references/editors/registry/dataset-external-registry-dialog-editor.component.html diff --git a/dmp-frontend/src/app/ui/description/dataset-wizard/external-references/editors/registry/dataset-external-registry-dialog-editor.component.scss b/dmp-frontend/src/app/ui/description/editor/external-references/editors/registry/dataset-external-registry-dialog-editor.component.scss similarity index 100% rename from dmp-frontend/src/app/ui/description/dataset-wizard/external-references/editors/registry/dataset-external-registry-dialog-editor.component.scss rename to dmp-frontend/src/app/ui/description/editor/external-references/editors/registry/dataset-external-registry-dialog-editor.component.scss diff --git a/dmp-frontend/src/app/ui/description/dataset-wizard/external-references/editors/registry/dataset-external-registry-dialog-editor.component.ts b/dmp-frontend/src/app/ui/description/editor/external-references/editors/registry/dataset-external-registry-dialog-editor.component.ts similarity index 100% rename from dmp-frontend/src/app/ui/description/dataset-wizard/external-references/editors/registry/dataset-external-registry-dialog-editor.component.ts rename to dmp-frontend/src/app/ui/description/editor/external-references/editors/registry/dataset-external-registry-dialog-editor.component.ts diff --git a/dmp-frontend/src/app/ui/description/dataset-wizard/external-references/editors/service/dataset-external-service-dialog-editor.component.html b/dmp-frontend/src/app/ui/description/editor/external-references/editors/service/dataset-external-service-dialog-editor.component.html similarity index 100% rename from dmp-frontend/src/app/ui/description/dataset-wizard/external-references/editors/service/dataset-external-service-dialog-editor.component.html rename to dmp-frontend/src/app/ui/description/editor/external-references/editors/service/dataset-external-service-dialog-editor.component.html diff --git a/dmp-frontend/src/app/ui/description/dataset-wizard/external-references/editors/service/dataset-external-service-dialog-editor.component.scss b/dmp-frontend/src/app/ui/description/editor/external-references/editors/service/dataset-external-service-dialog-editor.component.scss similarity index 100% rename from dmp-frontend/src/app/ui/description/dataset-wizard/external-references/editors/service/dataset-external-service-dialog-editor.component.scss rename to dmp-frontend/src/app/ui/description/editor/external-references/editors/service/dataset-external-service-dialog-editor.component.scss diff --git a/dmp-frontend/src/app/ui/description/dataset-wizard/external-references/editors/service/dataset-external-service-dialog-editor.component.ts b/dmp-frontend/src/app/ui/description/editor/external-references/editors/service/dataset-external-service-dialog-editor.component.ts similarity index 100% rename from dmp-frontend/src/app/ui/description/dataset-wizard/external-references/editors/service/dataset-external-service-dialog-editor.component.ts rename to dmp-frontend/src/app/ui/description/editor/external-references/editors/service/dataset-external-service-dialog-editor.component.ts diff --git a/dmp-frontend/src/app/ui/description/editor/form-progress-indication/form-progress-indication.component.html b/dmp-frontend/src/app/ui/description/editor/form-progress-indication/form-progress-indication.component.html new file mode 100644 index 000000000..56966d9ab --- /dev/null +++ b/dmp-frontend/src/app/ui/description/editor/form-progress-indication/form-progress-indication.component.html @@ -0,0 +1,5 @@ +
+
{{progressSoFar}} {{'GENERAL.PREPOSITIONS.OF' | translate}} {{total}}
+ +
{{value}}%
+
diff --git a/dmp-frontend/src/app/ui/description/editor/form-progress-indication/form-progress-indication.component.scss b/dmp-frontend/src/app/ui/description/editor/form-progress-indication/form-progress-indication.component.scss new file mode 100644 index 000000000..a15510639 --- /dev/null +++ b/dmp-frontend/src/app/ui/description/editor/form-progress-indication/form-progress-indication.component.scss @@ -0,0 +1,16 @@ +.percentage { + color: #212121; + opacity: 0.7; + font-weight: 400; + font-size: 0.875rem; +} + +.progress-bar { + border-radius: 20px; + height: 11px; + +} + +::ng-deep .mat-progress-bar .mat-progress-bar-fill::after { + border-radius: 20px !important; +} diff --git a/dmp-frontend/src/app/ui/description/editor/form-progress-indication/form-progress-indication.component.ts b/dmp-frontend/src/app/ui/description/editor/form-progress-indication/form-progress-indication.component.ts new file mode 100644 index 000000000..908acd641 --- /dev/null +++ b/dmp-frontend/src/app/ui/description/editor/form-progress-indication/form-progress-indication.component.ts @@ -0,0 +1,211 @@ +import {ChangeDetectorRef, Component, ElementRef, Input, OnChanges, OnInit, SimpleChanges} from '@angular/core'; +import { AbstractControl, UntypedFormArray, UntypedFormControl, UntypedFormGroup } from '@angular/forms'; +import { VisibilityRulesService } from '@app/ui/description/editor/description-form/visibility-rules/visibility-rules.service'; +import { BaseComponent } from '@common/base/base.component'; +import { takeUntil } from 'rxjs/operators'; + +@Component({ + selector: 'app-form-progress-indication', + templateUrl: './form-progress-indication.component.html', + styleUrls: ['./form-progress-indication.component.scss'] +}) +export class FormProgressIndicationComponent extends BaseComponent implements OnInit, OnChanges { + @Input() formGroup: UntypedFormGroup; + @Input() isDmpEditor: boolean; + @Input() isDatasetEditor: boolean; + @Input() public progressValueAccuracy = 2; + determinateProgressValue: number; + progressSoFar: number; + total: number; + percent: number; + + constructor(private visibilityRulesService: VisibilityRulesService) { super(); } + + public value = 0; + ngOnInit() { + this.init(); + } + + ngOnChanges(changes: SimpleChanges) { + if(changes.formGroup) { + this.init(); + } + } + + init() { + setTimeout(() => {this.calculateValueForProgressbar();}); + this.formGroup + .valueChanges + .pipe(takeUntil(this._destroyed)) + .subscribe(control => { + setTimeout(() => {this.calculateValueForProgressbar();}); + }); + } + + calculateValueForProgressbar() { + if (this.isDmpEditor) { + this.progressSoFar = this.countFormControlsValidForProgress(this.formGroup); + this.total = this.countFormControlsRequiredFieldsForTotal(this.formGroup); + } else if (this.isDatasetEditor) { + this.progressSoFar = this.countFormControlsValidForProgress(this.formGroup) + this.countFormControlsWithValueForProgress(this.formGroup); + this.total = this.countFormControlsRequiredFieldsForTotal(this.formGroup, true) + this.CountFormControlDepthLengthFotTotal(this.formGroup); + } else { + this.progressSoFar = this.countFormControlsWithValueForProgress(this.formGroup); + this.total = this.CountFormControlDepthLengthFotTotal(this.formGroup); + } + this.percent = (this.progressSoFar / this.total) * 100; + this.value = Number.parseFloat(this.percent.toPrecision(this.progressValueAccuracy)); + } + + countFormControlsWithValueForProgress(formControl: AbstractControl): number { + let valueCurent = 0; + if (formControl instanceof UntypedFormGroup) { + if (this.checkFormsIfIsFieldsAndVisible(formControl) && this.checkIfIsRequired((formControl as UntypedFormGroup))) { + if (this.hasValue(formControl)) + valueCurent++; + } + if (this.chechFieldIfIsFieldSetAndVisible((formControl as UntypedFormGroup)) && this.checkIfIsRequired((formControl as UntypedFormGroup))) { + valueCurent = valueCurent + this.compositeFieldsGetChildsForProgress(formControl); + } else { + Object.keys(formControl.controls).forEach(item => { + const control = formControl.get(item); + valueCurent = valueCurent + this.countFormControlsWithValueForProgress(control); + }); + } + } else if (formControl instanceof UntypedFormArray) { + formControl.controls.forEach(item => { + valueCurent = valueCurent + this.countFormControlsWithValueForProgress(item); + }); + } + return valueCurent; + } + private hasValue(formGroup: UntypedFormGroup): boolean { + return formGroup.get('value').valid && formGroup.get('value').value != null && formGroup.get('value').value !== '' && (this.visibilityRulesService.isVisibleMap[formGroup.get('id').value] ?? true); + } + + private compositeFieldsGetChildsForProgress(formGroup: UntypedFormGroup): number { + let valueCurent = 0; + if (this.visibilityRulesService.isVisibleMap[formGroup.get('id').value] ?? true) { + (formGroup.get('fields') as UntypedFormArray).controls.forEach((element: UntypedFormGroup) => { + valueCurent = valueCurent + this.countFormControlsWithValueForProgress(element); + }); + + (formGroup.get('multiplicityItems') as UntypedFormArray).controls.forEach((element: UntypedFormGroup) => { + valueCurent = valueCurent + this.countFormControlsWithValueForProgress(element); + }); + } + return valueCurent; + } + + private checkIfIsRequired(formControl: UntypedFormGroup): boolean { + return !!(formControl.get('validationRequired') && formControl.get('validationRequired').value); + + } + + private checkFormsIfIsFieldsAndVisible(formControl: UntypedFormGroup): boolean { + if (formControl.contains('id') && formControl.contains('value')) { + return true; + } + return false; + } + private chechFieldIfIsFieldSetAndVisible(formControl: UntypedFormGroup): boolean { + if (formControl.contains('id') && formControl.contains('fields')) { + return true; + } + return false; + } + + CountFormControlDepthLengthFotTotal(formControl: AbstractControl): number { + let valueCurent = 0; + if (formControl instanceof UntypedFormArray) { + formControl.controls.forEach(item => { + valueCurent = valueCurent + this.CountFormControlDepthLengthFotTotal(item); + }); + } else if (formControl instanceof UntypedFormGroup) { + if ((formControl as UntypedFormGroup).contains('id') && (formControl as UntypedFormGroup).contains('value') && (this.visibilityRulesService.isVisibleMap[(formControl as UntypedFormGroup).get('id').value] ?? true) && this.checkIfIsRequired((formControl as UntypedFormGroup))) { + valueCurent++; + } else if ((formControl as UntypedFormGroup).contains('id') && (formControl as UntypedFormGroup).contains('fields')) { + valueCurent = valueCurent + this.compositeFieldsGetChildsForTotal(formControl); + } else { + Object.keys(formControl.controls).forEach(item => { + const control = formControl.get(item); + valueCurent = valueCurent + this.CountFormControlDepthLengthFotTotal(control); + }); + } + } + + return valueCurent; + } + + private compositeFieldsGetChildsForTotal(formGroup: UntypedFormGroup): number { + let valueCurent = 0; + if (this.visibilityRulesService.isVisibleMap[formGroup.get('id').value] ?? true) { + (formGroup.get('fields') as UntypedFormArray).controls.forEach((element: UntypedFormGroup) => { + valueCurent = valueCurent + this.CountFormControlDepthLengthFotTotal(element); + }); + (formGroup.get('multiplicityItems') as UntypedFormArray).controls.forEach((element: UntypedFormGroup) => { + valueCurent = valueCurent + this.CountFormControlDepthLengthFotTotal(element); + }); + } + return valueCurent; + } + + countFormControlsValidForProgress(formControl: AbstractControl): number { + let valueCurrent = 0; + if (formControl instanceof UntypedFormControl) { + if (this.controlRequired(formControl) && this.controlEnabled(formControl) && formControl.valid) { + valueCurrent++; + } + } else if (formControl instanceof UntypedFormGroup) { + Object.keys(formControl.controls).forEach(item => { + const control = formControl.get(item); + valueCurrent = valueCurrent + this.countFormControlsValidForProgress(control); + }); + } else if (formControl instanceof UntypedFormArray) { + formControl.controls.forEach(item => { + valueCurrent = valueCurrent + this.countFormControlsValidForProgress(item); + }); + } + return valueCurrent; + } + + countFormControlsRequiredFieldsForTotal(formControl: AbstractControl, checkVisibility = false): number { + let valueCurrent = 0; + if (formControl instanceof UntypedFormControl) { + if (this.controlRequired(formControl) && this.controlEnabled(formControl)) { + valueCurrent++; + } + } else if (formControl instanceof UntypedFormGroup) { + if(!checkVisibility || (!formControl.get('id')?.value || (this.visibilityRulesService.isVisibleMap[formControl.get('id').value] ?? true))) { + Object.keys(formControl.controls).forEach(item => { + const control = formControl.get(item); + valueCurrent = valueCurrent + this.countFormControlsRequiredFieldsForTotal(control, checkVisibility); + }); + } + } else if (formControl instanceof UntypedFormArray) { + formControl.controls.forEach(item => { + valueCurrent = valueCurrent + this.countFormControlsRequiredFieldsForTotal(item, checkVisibility); + }); + } + return valueCurrent; + } + + controlRequired(formControl: AbstractControl) { + if (formControl.validator) { + const validator = formControl.validator({} as AbstractControl); + if (validator && validator.required) { + return true; + } + } else { return false } + } + + controlEnabled(formControl: AbstractControl) { + if (formControl.enabled) { + return true; + } else { return false } + } + + isEditor(): boolean { + return this.isDmpEditor || this.isDatasetEditor; + } +} diff --git a/dmp-frontend/src/app/ui/description/editor/form-progress-indication/form-progress-indication.module.ts b/dmp-frontend/src/app/ui/description/editor/form-progress-indication/form-progress-indication.module.ts new file mode 100644 index 000000000..5a834c683 --- /dev/null +++ b/dmp-frontend/src/app/ui/description/editor/form-progress-indication/form-progress-indication.module.ts @@ -0,0 +1,18 @@ +import { NgModule } from '@angular/core'; +import { CommonFormsModule } from '@common/forms/common-forms.module'; +import { CommonUiModule } from '@common/ui/common-ui.module'; +import { FormProgressIndicationComponent } from './form-progress-indication.component'; + +@NgModule({ + imports: [ + CommonUiModule, + CommonFormsModule + ], + declarations: [ + FormProgressIndicationComponent + ], + exports: [ + FormProgressIndicationComponent + ] +}) +export class DescriptionFormProgressIndicationModule { } diff --git a/dmp-frontend/src/app/ui/description/dataset-wizard/prefill-dataset/prefill-dataset.component.html b/dmp-frontend/src/app/ui/description/editor/prefill-description/prefill-description.component.html similarity index 100% rename from dmp-frontend/src/app/ui/description/dataset-wizard/prefill-dataset/prefill-dataset.component.html rename to dmp-frontend/src/app/ui/description/editor/prefill-description/prefill-description.component.html diff --git a/dmp-frontend/src/app/ui/description/dataset-wizard/prefill-dataset/prefill-dataset.component.scss b/dmp-frontend/src/app/ui/description/editor/prefill-description/prefill-description.component.scss similarity index 100% rename from dmp-frontend/src/app/ui/description/dataset-wizard/prefill-dataset/prefill-dataset.component.scss rename to dmp-frontend/src/app/ui/description/editor/prefill-description/prefill-description.component.scss diff --git a/dmp-frontend/src/app/ui/description/dataset-wizard/prefill-dataset/prefill-dataset.component.ts b/dmp-frontend/src/app/ui/description/editor/prefill-description/prefill-description.component.ts similarity index 100% rename from dmp-frontend/src/app/ui/description/dataset-wizard/prefill-dataset/prefill-dataset.component.ts rename to dmp-frontend/src/app/ui/description/editor/prefill-description/prefill-description.component.ts diff --git a/dmp-frontend/src/app/ui/description/editor/table-of-contents/models/toc-entry-type.enum.ts b/dmp-frontend/src/app/ui/description/editor/table-of-contents/models/toc-entry-type.enum.ts new file mode 100644 index 000000000..395c8ff33 --- /dev/null +++ b/dmp-frontend/src/app/ui/description/editor/table-of-contents/models/toc-entry-type.enum.ts @@ -0,0 +1,6 @@ +export enum ToCEntryType { + Page = 0, + Section = 1, + FieldSet = 2, + Field = 3 +} diff --git a/dmp-frontend/src/app/ui/description/editor/table-of-contents/models/toc-entry.ts b/dmp-frontend/src/app/ui/description/editor/table-of-contents/models/toc-entry.ts new file mode 100644 index 000000000..353f72d7e --- /dev/null +++ b/dmp-frontend/src/app/ui/description/editor/table-of-contents/models/toc-entry.ts @@ -0,0 +1,14 @@ +import { Guid } from "@common/types/guid"; +import { ToCEntryType } from "./toc-entry-type.enum"; + +export interface ToCEntry { + id: string; + label: string; + subEntriesType: ToCEntryType; + subEntries: ToCEntry[]; + type: ToCEntryType; + // form: AbstractControl; + numbering: string; + ordinal: number; + hidden?: boolean +} \ No newline at end of file diff --git a/dmp-frontend/src/app/ui/description/editor/table-of-contents/table-of-contents-internal/table-of-contents-internal.html b/dmp-frontend/src/app/ui/description/editor/table-of-contents/table-of-contents-internal/table-of-contents-internal.html new file mode 100644 index 000000000..3ffaf7c2c --- /dev/null +++ b/dmp-frontend/src/app/ui/description/editor/table-of-contents/table-of-contents-internal/table-of-contents-internal.html @@ -0,0 +1,50 @@ +
+ + + + + + + + + + {{entry.numbering}}. {{entry.label}} + + + + + +
+ + + +
+
+ + + +
+ +
\ No newline at end of file diff --git a/dmp-frontend/src/app/ui/description/editor/table-of-contents/table-of-contents-internal/table-of-contents-internal.scss b/dmp-frontend/src/app/ui/description/editor/table-of-contents/table-of-contents-internal/table-of-contents-internal.scss new file mode 100644 index 000000000..91152786d --- /dev/null +++ b/dmp-frontend/src/app/ui/description/editor/table-of-contents/table-of-contents-internal/table-of-contents-internal.scss @@ -0,0 +1,33 @@ + +.internal-table{ + margin-left: 1em; + padding-left: 0.2rem; + +} +.table-entry{ + + text-overflow: ellipsis; + overflow: hidden; + padding-left: 0.2rem; + color: rgba(0, 0, 0, 0.54); + transition: color 100ms; + + display: block; + span{ + white-space: nowrap; + } +} + +.table-entry:hover{ + background-color: #ececec; + border-radius: 6px; +} +.selected { + color: #212121 !important; + font-weight: 700 !important; + opacity: 1 !important; +} + +.section{ + line-height: 1.7em; +} \ No newline at end of file diff --git a/dmp-frontend/src/app/ui/description/editor/table-of-contents/table-of-contents-internal/table-of-contents-internal.ts b/dmp-frontend/src/app/ui/description/editor/table-of-contents/table-of-contents-internal/table-of-contents-internal.ts new file mode 100644 index 000000000..a6c554fb7 --- /dev/null +++ b/dmp-frontend/src/app/ui/description/editor/table-of-contents/table-of-contents-internal/table-of-contents-internal.ts @@ -0,0 +1,168 @@ +import { Component, EventEmitter, Input, OnInit, Output, QueryList, SimpleChanges, ViewChildren } from '@angular/core'; +import { UntypedFormGroup } from '@angular/forms'; +import { VisibilityRulesService } from '@app/ui/description/editor/description-form/visibility-rules/visibility-rules.service'; +import { Guid } from '@common/types/guid'; +import { ToCEntry } from '../models/toc-entry'; +import { ToCEntryType } from '../models/toc-entry-type.enum'; + +@Component({ + selector: 'table-of-contents-internal', + styleUrls: ['./table-of-contents-internal.scss'], + templateUrl: './table-of-contents-internal.html' +}) +export class TableOfContentsInternal implements OnInit { + + @Input() tocentries: ToCEntry[] = null; + @Input() selected: ToCEntry = null; + // @Input() visibilityRules:Rule[] = []; + @Output() entrySelected = new EventEmitter(); + @Input() propertiesFormGroup: UntypedFormGroup; + + expandChildren: boolean[]; + tocEntryTypeEnum = ToCEntryType; + @Input() TOCENTRY_ID_PREFIX = ""; + @Input() showErrors: boolean = false; + @Input() hiddenEntries: string[] = []; + @Input() visibilityRulesService: VisibilityRulesService; + @ViewChildren(TableOfContentsInternal) internalTables: QueryList; + + constructor() { + } + ngOnInit(): void { + // console.log('component created'); + if (this.tocentries) { + this.expandChildren = this.tocentries.map(() => false); + if (this.selected) { + for (let i = 0; i < this.tocentries.length; i++) { + if (this._findTocEntryById(this.selected.id, this.tocentries[i].subEntries)) { + if (this.expandChildren) { + this.expandChildren[i] = true; + } + break; + } + } + } + } + } + + ngOnChanges(changes: SimpleChanges) { + if (changes.selected && this.selected) { + for (let i = 0; i < this.tocentries.length; i++) { + if (this._findTocEntryById(this.selected.id, this.tocentries[i].subEntries)) { + if (this.expandChildren) { + this.expandChildren[i] = true; + } + break; + } + } + } + // if (!this.isActive && this.links && this.links.length > 0) { + // this.links.forEach(link => { + // link.selected = false; + // }) + // this.links[0].selected = true; + // } + } + + toggleExpand(index) { + this.expandChildren[index] = !this.expandChildren[index]; + // console.log(this.expandChildren); + } + + navigateToFieldSet(entry: ToCEntry, event) { + if (entry.type === ToCEntryType.FieldSet) { + + const fieldSetId = entry.id; + const element = document.getElementById(this.TOCENTRY_ID_PREFIX + fieldSetId); + if (element) { + element.click();//open mat expansion panel + + //scroll asyn in 200 ms so the expansion panel is expanded and the element coordinates are updated + setTimeout(() => { + const element = document.getElementById(this.TOCENTRY_ID_PREFIX + fieldSetId); + if (element) { + element.scrollIntoView({ behavior: 'smooth' }); + } + }, 300); + } + + } + } + + + onEntrySelected(entry: ToCEntry) { + this.entrySelected.emit(entry); + } + + + calculateStyle(entry: ToCEntry) { + const style = {}; + style['font-size'] = entry.type === this.tocEntryTypeEnum.FieldSet ? '.9em' : '1em'; + return style; + } + + calculateClass(entry: ToCEntry) { + const myClass = {}; + + if (this.selected && entry.id === this.selected.id) { + myClass['selected'] = true; + } + + if (entry.type != this.tocEntryTypeEnum.FieldSet) { + myClass['section'] = true; + } + + return myClass; + } + + private _findTocEntryById(id: string, tocentries: ToCEntry[]): ToCEntry { + if (!tocentries || !tocentries.length) { + return null; + } + + let tocEntryFound = tocentries.find(entry => entry.id === id); + + if (tocEntryFound) { + return tocEntryFound; + } + + for (let entry of tocentries) { + const result = this._findTocEntryById(id, entry.subEntries); + if (result) { + tocEntryFound = result; + break; + } + } + + return tocEntryFound ? tocEntryFound : null; + } + public invalidChildsVisible(entry: ToCEntry): boolean { + if (!entry || !this.visibilityRulesService) { + return false; + } + + if (entry.type != this.tocEntryTypeEnum.FieldSet) { + return entry.subEntries.some(_ => this.invalidChildsVisible(_)); + } + if (entry.type === this.tocEntryTypeEnum.FieldSet) { + const id = entry.id; + if (!(this.visibilityRulesService.isVisibleMap[id.toString()] ?? true)) { + return false; + } + // const fieldsArray = entry.form.get('fields') as UntypedFormArray; + const hasError = !entry.subEntries.every(field => {//every invalid field should be invisible + //TODO: check this + // if (field.invalid) { + // const id = field.id; + // const isVisible = this.visibilityRulesService.isVisibleMap[id); + // if (isVisible) { + // return false; + // } + // } + return true; + }); + return hasError; + } + return false; + } +} diff --git a/dmp-frontend/src/app/ui/description/editor/table-of-contents/table-of-contents.component.html b/dmp-frontend/src/app/ui/description/editor/table-of-contents/table-of-contents.component.html new file mode 100644 index 000000000..b94d4efd7 --- /dev/null +++ b/dmp-frontend/src/app/ui/description/editor/table-of-contents/table-of-contents.component.html @@ -0,0 +1,24 @@ +
+
+ + {{link.name}} + +
+
+ +
+ +
+ + + +
+
+{{hiddenEntries | json}} diff --git a/dmp-frontend/src/app/ui/description/editor/table-of-contents/table-of-contents.component.scss b/dmp-frontend/src/app/ui/description/editor/table-of-contents/table-of-contents.component.scss new file mode 100644 index 000000000..7dbc877af --- /dev/null +++ b/dmp-frontend/src/app/ui/description/editor/table-of-contents/table-of-contents.component.scss @@ -0,0 +1,80 @@ +.docs-toc-container { + width: 100%; + padding: 5px 0 10px 0px; + cursor: pointer; + // border-left: solid 4px #0c7489; + + .scroll-container { + overflow-y: auto; + // calc(100vh - 250px) + // height: calc(100vh - 250px); + } + + .docs-link { + color: rgba(0, 0, 0, 0.54); + // color: mat-color($app-blue-theme-foreground, secondary-text); + transition: color 100ms; + + &:hover, + &.docs-active { + .link-name { + background-color: #ececec; + border-radius: 6px; + // color: #0c7489; + } + // color: mat-color($primary, if($is-dark-theme, 200, default)); + } + } +} + +.docs-toc-heading { + margin: 0; + padding: 0; + font-size: 13px; + font-weight: bold; +} + +span { + line-height: 16px; + margin: 6px 0 0; + position: relative; + text-decoration: none; + display: block; + overflow: hidden; + color: #21212194; + font-weight: 400; + max-width: 290px; + min-width: 290px; + padding: 0rem .4rem; + span { + white-space: nowrap; + overflow: hidden; + text-overflow: ellipsis; + display: inline-block; + width: 100%; + } +} + +.selected { + color: #212121 !important; + font-weight: 700 !important; + opacity: 1 !important; +} + +// .docs-level-mat-expansion-panel { +// margin-left: 12px; +// } + +.docs-level-h5 { + margin-left: 24px; +} + +// .internal-table-outer{ +// padding-left: 1.1em; +// width: 100%; +// } + +.internal-table{ + max-width: 320px; + min-width: 320px; +} \ No newline at end of file diff --git a/dmp-frontend/src/app/ui/description/editor/table-of-contents/table-of-contents.component.ts b/dmp-frontend/src/app/ui/description/editor/table-of-contents/table-of-contents.component.ts new file mode 100644 index 000000000..8f107d4b7 --- /dev/null +++ b/dmp-frontend/src/app/ui/description/editor/table-of-contents/table-of-contents.component.ts @@ -0,0 +1,514 @@ +import { DOCUMENT } from '@angular/common'; +import { Component, EventEmitter, Inject, Input, OnChanges, OnInit, Output, SimpleChanges, ViewChild } from '@angular/core'; +import { UntypedFormGroup } from '@angular/forms'; +import { DescriptionTemplate, DescriptionTemplateField, DescriptionTemplateFieldSet, DescriptionTemplateSection } from '@app/core/model/description-template/description-template'; +import { VisibilityRulesService } from '@app/ui/description/editor/description-form/visibility-rules/visibility-rules.service'; +import { BaseComponent } from '@common/base/base.component'; +import { Subject, Subscription, interval } from 'rxjs'; +import { debounceTime, distinctUntilChanged, takeUntil } from 'rxjs/operators'; +import { ToCEntry } from './models/toc-entry'; +import { ToCEntryType } from './models/toc-entry-type.enum'; +import { TableOfContentsInternal } from './table-of-contents-internal/table-of-contents-internal'; + +export interface Link { + /* id of the section*/ + id: string; + /* header type h3/h4 */ + type: string; + /* If the anchor is in view of the page */ + active: boolean; + /* name of the anchor */ + name: string; + /* top offset px of the anchor */ + top: number; + page: number; + section: number; + show: boolean; + selected: boolean; +} + +@Component({ + selector: 'app-table-of-contents', + styleUrls: ['./table-of-contents.component.scss'], + templateUrl: './table-of-contents.component.html' +}) +export class TableOfContentsComponent extends BaseComponent implements OnInit, OnChanges { + + @ViewChild('internalTable') internalTable: TableOfContentsInternal; + + + @Input() links: Link[]; + container: string; + headerSelectors = '.toc-page-header, .toc-section-header, .toc-compositeField-header'; + @Output() stepFound = new EventEmitter(); + @Output() currentLinks = new EventEmitter(); + @Output() entrySelected = new EventEmitter(); + subscription: Subscription; + linksSubject: Subject = new Subject(); + + @Input() isActive: boolean; + + tocentries: ToCEntry[] = null; + @Input() TOCENTRY_ID_PREFIX = ''; + @Input() showErrors: boolean = false; + @Input() selectedFieldsetId: string; + + private _tocentrySelected: ToCEntry = null; + private isSelecting: boolean = false; + private _intersectionObserver: IntersectionObserver; + private _actOnObservation: boolean = true; + public hiddenEntries: string[] = []; + get tocentrySelected() { + return this.hasFocus ? this._tocentrySelected : null; + } + set tocentrySelected(value) { + this._tocentrySelected = value; + } + + @Input() propertiesFormGroup: UntypedFormGroup; + @Input() descriptionTemplate: DescriptionTemplate; + @Input() hasFocus: boolean = false; + @Input() visibilityRulesService: VisibilityRulesService; + show: boolean = false; + + constructor( + @Inject(DOCUMENT) private _document: Document, + // public visibilityRulesService: VisibilityRulesService + ) { + super(); + } + + + ngOnInit(): void { + + if (this.descriptionTemplate) { + this.tocentries = this.getTocEntries(this.descriptionTemplate); + if (this.visibilityRulesService) { + this.hiddenEntries = this._findHiddenEntries(this.tocentries); + } + + } else { + + //emit value every 500ms + const source = interval(500); + this.subscription = source.subscribe(val => { + const headers = Array.from(this._document.querySelectorAll(this.headerSelectors)) as HTMLElement[]; + this.linksSubject.next(headers); + }); + + if (!this.links || this.links.length === 0) { + this.linksSubject.asObservable() + .pipe(distinctUntilChanged((p: HTMLElement[], q: HTMLElement[]) => JSON.stringify(p) == JSON.stringify(q))) + .subscribe(headers => { + const links: Array = []; + + if (headers.length) { + let page; + let section; + let show + for (const header of headers) { + let name; + let id; + if (header.classList.contains('toc-page-header')) { // deprecated after removing stepper + name = header.innerText.trim().replace(/^link/, ''); + id = header.id; + page = header.id.split('_')[1]; + section = undefined; + show = true; + } else if (header.classList.contains('toc-section-header')) { + name = header.childNodes[0].childNodes[0].childNodes[0].childNodes[0].childNodes[0].nodeValue.trim().replace(/^link/, ''); + id = header.id; + page = header.id.split('.')[1]; + section = header.id; + if (header.id.split('.')[4]) { show = false; } + else { show = true; } + } else if (header.classList.contains('toc-compositeField-header')) { + name = (header.childNodes[0]).nodeValue.trim().replace(/^link/, ''); + id = header.id; + // id = header.parentElement.parentElement.parentElement.id; + show = false; + } + const { top } = header.getBoundingClientRect(); + links.push({ + name, + id, + type: header.tagName.toLowerCase(), + top: top, + active: false, + page: page, + section: section, + show: show, + selected: false + }); + } + } + this.links = links; + // Initialize selected for button next on dataset wizard component editor + this.links.length > 0 ? this.links[0].selected = true : null; + }) + } + } + + } + + private _findHiddenEntries(tocentries: ToCEntry[]): string[] { + if (!tocentries) return []; + + const invisibleEntries: string[] = [] + tocentries.forEach(entry => { + if (entry.type === ToCEntryType.FieldSet) { + const isVisible = this.visibilityRulesService.isVisibleMap[entry.id.toString()] ?? true; + if (!isVisible) { + invisibleEntries.push(entry.id.toString()); + } else { + //check field inputs + const oneFieldAtLeastIsVisible = entry.subEntries.some(field => this.visibilityRulesService.isVisibleMap[field.id.toString()] ?? true); + if (!oneFieldAtLeastIsVisible) { + invisibleEntries.push(entry.id.toString()); + } + } + } else { + const hiddenEntries = this._findHiddenEntries(entry.subEntries); + + if (entry.subEntries && (entry.subEntries.every(e => hiddenEntries.includes(e.id.toString())))) { + //all children all hidden then hide parent node; + invisibleEntries.push(entry.id.toString()); + } else { + invisibleEntries.push(...hiddenEntries); + } + } + }) + + return invisibleEntries; + } + + private _visibilityRulesSubscription: Subscription; + ngOnChanges(changes: SimpleChanges) { + + if (this.selectedFieldsetId) { + this.onToCentrySelected(this._findTocEntryById(this.selectedFieldsetId, this.tocentries), false); + this._actOnObservation = false; + setTimeout(() => { + this._actOnObservation = true; + }, 1000); + + } + + + if (changes['hasFocus'] && changes.hasFocus.currentValue) { + this._resetObserver(); + + } + + if ('visibilityRulesService') { + if (this._visibilityRulesSubscription) { + this._visibilityRulesSubscription.unsubscribe(); + this._visibilityRulesSubscription = null; + } + + if (!this.visibilityRulesService) return; + + this._visibilityRulesSubscription = this.visibilityRulesService.visibilityChange + .pipe(takeUntil(this._destroyed)) + .pipe(debounceTime(200)) + .subscribe(_ => { + if (this.hasFocus) { + this._resetObserver(); + this.hiddenEntries = this._findHiddenEntries(this.tocentries); + } + }); + this.hiddenEntries = this._findHiddenEntries(this.tocentries); + } + // if (!this.isActive && this.links && this.links.length > 0) { + // this.links.forEach(link => { + // link.selected = false; + // }) + // this.links[0].selected = true; + // } + } + + + private _resetObserver() { + if (this._intersectionObserver) {//clean up + this._intersectionObserver.disconnect(); + this._intersectionObserver = null; + } + + const options = { + root: null, + rootMargin: '-38% 0px -60% 0px', + threshold: 0 + } + + this._intersectionObserver = new IntersectionObserver((entries, observer) => { + if (!this._actOnObservation) { + return; + } + + entries.forEach(ie => { + if (ie.isIntersecting) { + try { + const target_id = ie.target.id.replace(this.TOCENTRY_ID_PREFIX, ''); + if (this.visibilityRulesService.isVisibleMap[target_id] ?? true) { + this.onToCentrySelected(this._findTocEntryById(target_id, this.tocentries)); + } + } catch { + + } + } + }) + }, options); + + const fieldsetsEtries = this._getAllFieldSets(this.tocentries); + + fieldsetsEtries.forEach(e => { + if (e.type === ToCEntryType.FieldSet) { + try { + const targetElement = document.getElementById(this.TOCENTRY_ID_PREFIX + e.id); + this._intersectionObserver.observe(targetElement); + } catch { + console.log('element not found'); + } + } + }); + } + + goToStep(link: Link) { + this.stepFound.emit({ + page: link.page, + section: link.section + }); + this.currentLinks.emit(this.links); + + setTimeout(() => { + const target = document.getElementById(link.id); + target.scrollIntoView(true); + + var scrolledY = window.scrollY; + if (scrolledY) { + window.scroll(0, scrolledY - 70); + } + }, 500); + } + + toggle(headerLink: Link) { + const headerPage = +headerLink.name.split(" ", 1); + let innerPage; + for (const link of this.links) { + link.selected = false; + if (link.type === 'mat-expansion-panel') { + innerPage = +link.name.split(".", 1)[0]; + if (isNaN(innerPage)) { innerPage = +link.name.split(" ", 1) } + } else if (link.type === 'h5') { + innerPage = +link.name.split(".", 1)[0]; + } + if (headerPage === innerPage && (link.type !== 'mat-expansion-panel' || (link.type === 'mat-expansion-panel' && link.id.split(".")[4]))) { + link.show = !link.show; + } + } + headerLink.selected = true; + } + + // getIndex(link: Link): number { + // return +link.id.split("_", 2)[1]; + // } + + + private _buildRecursivelySection(item: DescriptionTemplateSection): ToCEntry { + if (!item) return null; + + const sections = item.sections; + const fieldsets = item.fieldSets; + + + const tempResult: ToCEntry[] = []; + + if (sections && sections.length) { + sections.forEach(section => { + tempResult.push(this._buildRecursivelySection(section)); + }); + + } else if (fieldsets && fieldsets.length) { + fieldsets.forEach(fieldset => { + tempResult.push(this._buildRecursivelyFieldSet(fieldset)); + }); + } + return { + // form: form, + id: item.id, + label: item.title, + numbering: '', + subEntries: tempResult, + subEntriesType: sections && sections.length ? ToCEntryType.Section : ToCEntryType.FieldSet, + type: ToCEntryType.Section, + ordinal: item.ordinal + } + } + + private _buildRecursivelyFieldSet(item: DescriptionTemplateFieldSet): ToCEntry { + if (!item) return null; + const tempResult: ToCEntry[] = []; + if (item && item.fields.length > 0) { + item.fields.forEach(field => { + tempResult.push(this._buildRecursivelyField(field)); + }); + } + + return { + // form: form, + id: item.id, + label: item.title, + numbering: 's', + subEntries: tempResult, + subEntriesType: ToCEntryType.Field, + type: ToCEntryType.FieldSet, + ordinal: item.ordinal + }; + } + + private _buildRecursivelyField(item: DescriptionTemplateField): ToCEntry { + if (!item) return null; + return { + // form: form, + id: item.id, + label: null, + numbering: 's', + subEntries: null, + subEntriesType: null, + type: ToCEntryType.Field, + ordinal: item.ordinal, + hidden: true + }; + } + + private _sortByOrdinal(tocentries: ToCEntry[]) { + + if (!tocentries || !tocentries.length) return; + + tocentries.sort(this._customCompare); + tocentries.forEach(entry => { + this._sortByOrdinal(entry.subEntries); + }); + } + + private _customCompare(a, b) { + return a.ordinal - b.ordinal; + } + + private _calculateNumbering(tocentries: ToCEntry[], depth: number[] = []) { + if (!tocentries || !tocentries.length) { + return; + } + + let prefixNumbering = depth.length ? depth.join('.') : ''; + + if (depth.length) prefixNumbering = prefixNumbering + "."; + tocentries.forEach((entry, i) => { + entry.numbering = prefixNumbering + (i + 1); + this._calculateNumbering(entry.subEntries, [...depth, i + 1]) + }); + } + + + getTocEntries(descriptionTemplate: DescriptionTemplate): ToCEntry[] { + if (descriptionTemplate == null) { return []; } + const result: ToCEntry[] = []; + + //build parent pages + descriptionTemplate.definition.pages.forEach((pageElement, i) => { + const tocEntry: ToCEntry = { + // id: i + 'id', + id: pageElement.id, + label: pageElement.title, + type: ToCEntryType.Page, + // form: pageElement, + numbering: (i + 1).toString(), + subEntriesType: ToCEntryType.Section, + subEntries: [], + ordinal: pageElement.ordinal + }; + + const sections = descriptionTemplate.definition.sections.filter(x => x.page == pageElement.id); + + sections.forEach(section => { + const tempResults = this._buildRecursivelySection(section); + tocEntry.subEntries.push(tempResults); + }); + result.push(tocEntry) + }); + + this._sortByOrdinal(result); + //calculate numbering + this._calculateNumbering(result); + return result; + + } + + onToCentrySelected(entry: ToCEntry = null, execute: boolean = true) { + if (!this.isSelecting) { + this.isSelecting = true; + this.tocentrySelected = entry; + this.entrySelected.emit({ entry: entry, execute: execute }); + setTimeout(() => { + this.isSelecting = false; + }, 600); + } + } + + private _findTocEntryById(id: string, tocentries: ToCEntry[]): ToCEntry { + if (!tocentries || !tocentries.length) { + return null; + } + + let tocEntryFound = tocentries.find(entry => entry.id === id); + + if (tocEntryFound) { + return tocEntryFound; + } + + for (let entry of tocentries) { + const result = this._findTocEntryById(id, entry.subEntries); + if (result) { + tocEntryFound = result; + break; + } + } + + return tocEntryFound ? tocEntryFound : null; + } + /** + * Get all filedsets in a tocentry array; + * @param entries Tocentries to search in + * @returns The tocentries that are Fieldsets provided in the entries + */ + private _getAllFieldSets(entries: ToCEntry[]): ToCEntry[] { + + const fieldsets: ToCEntry[] = []; + if (!entries || !entries.length) return fieldsets; + + + entries.forEach(e => { + if (e.type === ToCEntryType.FieldSet) { + fieldsets.push(e); + } else { + fieldsets.push(...this._getAllFieldSets(e.subEntries)); + } + }); + return fieldsets; + } + + + public hasVisibleInvalidFields(): boolean { + if (!this.internalTable || !this.tocentries) { + return false; + } + return this.tocentries.some(e => this.internalTable.invalidChildsVisible(e)); + } + + protected readonly console = console; +} + +export interface LinkToScroll { + page: number; + section: number; +} diff --git a/dmp-frontend/src/app/ui/description/editor/table-of-contents/table-of-contents.module.ts b/dmp-frontend/src/app/ui/description/editor/table-of-contents/table-of-contents.module.ts new file mode 100644 index 000000000..2a7bc3749 --- /dev/null +++ b/dmp-frontend/src/app/ui/description/editor/table-of-contents/table-of-contents.module.ts @@ -0,0 +1,15 @@ +import {CommonModule} from '@angular/common'; +import {NgModule} from '@angular/core'; +import {RouterModule} from '@angular/router'; +import { TableOfContentsInternal } from './table-of-contents-internal/table-of-contents-internal'; +import { MatIconModule } from '@angular/material/icon'; +import { VisibilityRulesService } from '@app/ui/description/editor/description-form/visibility-rules/visibility-rules.service'; +import { TableOfContentsComponent } from './table-of-contents.component'; + +@NgModule({ + imports: [CommonModule, RouterModule, MatIconModule], + declarations: [TableOfContentsComponent, TableOfContentsInternal], + exports: [TableOfContentsComponent], + providers: [VisibilityRulesService] +}) +export class TableOfContentsModule { } diff --git a/dmp-frontend/src/app/ui/description/listing/description-listing.module.ts b/dmp-frontend/src/app/ui/description/listing/description-listing.module.ts new file mode 100644 index 000000000..0422f9ac3 --- /dev/null +++ b/dmp-frontend/src/app/ui/description/listing/description-listing.module.ts @@ -0,0 +1,27 @@ +import { NgModule } from '@angular/core'; +import { FormattingModule } from '@app/core/formatting.module'; +import { UrlListingModule } from '@app/library/url-listing/url-listing.module'; +import { DescriptionListingComponent } from '@app/ui/description/listing/description-listing.component'; +import { DescriptionListingItemComponent } from '@app/ui/description/listing/listing-item/description-listing-item.component'; +import { CommonFormsModule } from '@common/forms/common-forms.module'; +import { CommonUiModule } from '@common/ui/common-ui.module'; +import { DescriptionListingRoutingModule } from './description-listing.routing'; +import { DescriptionCopyDialogModule } from '../description-copy-dialog/description-copy-dialog.module'; + +@NgModule({ + imports: [ + CommonUiModule, + CommonFormsModule, + UrlListingModule, + FormattingModule, + DescriptionCopyDialogModule, + DescriptionListingRoutingModule + ], + declarations: [ + DescriptionListingComponent, + DescriptionListingItemComponent, + ], + exports: [ + ] +}) +export class DescriptionListingModule { } diff --git a/dmp-frontend/src/app/ui/description/listing/description-listing.routing.ts b/dmp-frontend/src/app/ui/description/listing/description-listing.routing.ts new file mode 100644 index 000000000..38230cad5 --- /dev/null +++ b/dmp-frontend/src/app/ui/description/listing/description-listing.routing.ts @@ -0,0 +1,30 @@ +import { NgModule } from '@angular/core'; +import { RouterModule, Routes } from '@angular/router'; +import { AuthGuard } from '@app/core/auth-guard.service'; +import { DescriptionListingComponent } from './description-listing.component'; + +const routes: Routes = [ + { + path: '', + component: DescriptionListingComponent, + // canActivate: [AuthGuard], + data: { + breadcrumb: true + }, + }, + { + path: 'dmp/:dmpId', + component: DescriptionListingComponent, + canActivate: [AuthGuard], + data: { + breadcrumb: true + }, + }, +]; + +@NgModule({ + imports: [RouterModule.forChild(routes)], + exports: [RouterModule], + providers: [] +}) +export class DescriptionListingRoutingModule { } diff --git a/dmp-frontend/src/app/ui/description/listing/listing-item/description-listing-item.component.ts b/dmp-frontend/src/app/ui/description/listing/listing-item/description-listing-item.component.ts index b4769f897..ddb8adde0 100644 --- a/dmp-frontend/src/app/ui/description/listing/listing-item/description-listing-item.component.ts +++ b/dmp-frontend/src/app/ui/description/listing/listing-item/description-listing-item.component.ts @@ -96,11 +96,11 @@ export class DescriptionListingItemComponent extends BaseComponent implements On getItemLink(): string[] { // return this.isPublic ? [`/descriptions/publicEdit/${this.description.id}`] : [`/descriptions/edit/${this.description.id}`]; - return this.isPublic ? ['/descriptions/publicOverview/' + this.description.id] : ['/descriptions/overview/' + this.description.id]; + return this.isPublic ? ['/descriptions/overview/public/' + this.description.id] : ['/descriptions/overview/' + this.description.id]; } getDmpLink(): string[] { - return this.isPublic ? [`/explore-plans/publicOverview/${this.description.dmp.id}`] : [`/plans/edit/${this.description.dmp.id}`]; + return this.isPublic ? [`/explore-plans/overview/public/${this.description.dmp.id}`] : [`/plans/edit/${this.description.dmp.id}`]; } downloadPDF(description: Description): void { diff --git a/dmp-frontend/src/app/ui/description/overview/description-overview.component.ts b/dmp-frontend/src/app/ui/description/overview/description-overview.component.ts index e2a401b2a..1aa72bb5c 100644 --- a/dmp-frontend/src/app/ui/description/overview/description-overview.component.ts +++ b/dmp-frontend/src/app/ui/description/overview/description-overview.component.ts @@ -126,7 +126,7 @@ export class DescriptionOverviewComponent extends BaseComponent implements OnIni // this.users = this.description.dmp.users; // const breadCrumbs = []; // breadCrumbs.push({ parentComponentName: null, label: this.language.instant('NAV-BAR.PUBLIC DESCRIPTIONS'), url: "/explore" }); - // breadCrumbs.push({ parentComponentName: 'DescriptionListingComponent', label: this.description.label, url: '/descriptions/publicOverview/' + this.description.id }); + // breadCrumbs.push({ parentComponentName: 'DescriptionListingComponent', label: this.description.label, url: '/descriptions/overview/public/' + this.description.id }); // this.breadCrumbs = observableOf(breadCrumbs); }, (error: any) => { if (error.status === 404) { @@ -249,7 +249,7 @@ export class DescriptionOverviewComponent extends BaseComponent implements OnIni dmpClicked(dmp: Dmp) { if (this.isPublicView) { - this.router.navigate(['/explore-plans/publicOverview/' + dmp.id]); + this.router.navigate(['/explore-plans/overview/public/' + dmp.id]); } else { this.router.navigate(['/plans/overview/' + dmp.id]); } diff --git a/dmp-frontend/src/app/ui/description/overview/description-overview.module.ts b/dmp-frontend/src/app/ui/description/overview/description-overview.module.ts index 31a9bc4d8..4dbd3315d 100644 --- a/dmp-frontend/src/app/ui/description/overview/description-overview.module.ts +++ b/dmp-frontend/src/app/ui/description/overview/description-overview.module.ts @@ -6,7 +6,9 @@ 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 { CommonUiModule } from '@common/ui/common-ui.module'; +import { DescriptionCopyDialogModule } from '../description-copy-dialog/description-copy-dialog.module'; import { DescriptionOverviewComponent } from './description-overview.component'; +import { DescriptionOverviewRoutingModule } from './description-overview.routing'; @NgModule({ imports: [ @@ -16,7 +18,9 @@ import { DescriptionOverviewComponent } from './description-overview.component'; ConfirmationDialogModule, ExportMethodDialogModule, FormattingModule, - AutoCompleteModule + AutoCompleteModule, + DescriptionCopyDialogModule, + DescriptionOverviewRoutingModule ], declarations: [ DescriptionOverviewComponent diff --git a/dmp-frontend/src/app/ui/description/overview/description-overview.routing.ts b/dmp-frontend/src/app/ui/description/overview/description-overview.routing.ts new file mode 100644 index 000000000..05cf0c095 --- /dev/null +++ b/dmp-frontend/src/app/ui/description/overview/description-overview.routing.ts @@ -0,0 +1,29 @@ +import { NgModule } from '@angular/core'; +import { RouterModule, Routes } from '@angular/router'; +import { DescriptionOverviewComponent } from './description-overview.component'; + +const routes: Routes = [ + { + path: ':id', + component: DescriptionOverviewComponent, + data: { + breadcrumb: true, + title: 'GENERAL.TITLES.DATASET-OVERVIEW' + }, + }, + { + path: 'public/:publicId', + component: DescriptionOverviewComponent, + data: { + breadcrumb: true, + title: 'GENERAL.TITLES.DATASET-OVERVIEW' + }, + } +]; + +@NgModule({ + imports: [RouterModule.forChild(routes)], + exports: [RouterModule], + providers: [] +}) +export class DescriptionOverviewRoutingModule { } 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 3d8a5bd20..02af5a640 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 @@ -1,5 +1,5 @@ - {{'GENERAL.ACTIONS.SHOW-MORE' | translate}} + {{'GENERAL.ACTIONS.SHOW-MORE' | translate}}
open_in_new{{'DMP-LISTING.ACTIONS.EXPORT' | translate}} diff --git a/dmp-frontend/src/app/ui/dmp/overview/dmp-overview.component.html b/dmp-frontend/src/app/ui/dmp/overview/dmp-overview.component.html index e7580d2a2..9ecc87d09 100644 --- a/dmp-frontend/src/app/ui/dmp/overview/dmp-overview.component.html +++ b/dmp-frontend/src/app/ui/dmp/overview/dmp-overview.component.html @@ -84,7 +84,7 @@
{{'DMP-OVERVIEW.DESCRIPTIONS' | translate}}
- +
- {{ 'FAQ.TITLE' | translate }} -
-
- -
-
- - -
- - - -
-
- - - {{'QUICKWIZARD.HINT' | translate}} - -
-
- - -
-
-
- -
-
-
-
- diff --git a/dmp-frontend/src/app/ui/quick-wizard/dataset-editor/dataset-editor-wizard.component.scss b/dmp-frontend/src/app/ui/quick-wizard/dataset-editor/dataset-editor-wizard.component.scss deleted file mode 100644 index 3d2ff8cf7..000000000 --- a/dmp-frontend/src/app/ui/quick-wizard/dataset-editor/dataset-editor-wizard.component.scss +++ /dev/null @@ -1,10 +0,0 @@ -.toc-pane-container { - &.is-sticky~.nav-spacer { - height: 500px; // the container size } - // height: calc(100vh - 100px); // the container size } - } -} - -.is-sticky { - margin-top: 70px !important; -} 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 deleted file mode 100644 index bd212cc49..000000000 --- a/dmp-frontend/src/app/ui/quick-wizard/dataset-editor/dataset-editor-wizard.component.ts +++ /dev/null @@ -1,130 +0,0 @@ -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 { 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'; -import { TranslateService } from "@ngx-translate/core"; -import { Observable } from "rxjs"; -import { takeUntil } from "rxjs/operators"; -import { LinkToScroll } from '@app/ui/misc/dataset-description-form/tableOfContentsMaterial/table-of-contents'; - -@Component({ - selector: 'app-dataset-editor-wizard-component', - templateUrl: 'dataset-editor-wizard.component.html', - styleUrls: ['./dataset-editor-wizard.component.scss'] -}) -export class DatasetEditorWizardComponent extends BaseComponent implements OnInit { - - @Input() formGroup: UntypedFormGroup; - @Input() datasetProfile: UntypedFormGroup; // DatasetProfileModel; - @Input() datasetLabel: string; - editedDataset: boolean = false; - dataset: DatasetDescriptionFormEditorModel; - public datasetProfileDefinition: DatasetDescriptionFormEditorModel; - public lastIndexOfDataset = 0; - public toggleButton = 0; - public _inputValue: string; - - isFirst: boolean; - - constructor( - private datasetWizardService: DatasetWizardService, - public language: TranslateService, - ) { - super(); - } - - ngOnInit(): void { - this.datasetWizardService.getDefinition(this.datasetProfile.value["id"]) - .pipe(takeUntil(this._destroyed)) - .subscribe(item => { - this.datasetProfileDefinition = new DatasetDescriptionFormEditorModel().fromModel(item); - this.onValChange("list"); - const length = (this.formGroup.get('datasets').get('datasetsList') as UntypedFormArray).length; - if (length == 0) { - this.lastIndexOfDataset = length; - this.isFirst = true; - this.addDataset(this.isFirst); - this.onValChange("dataset"); - } - }); - } - - onValChange(event: any) { - if (event == "list") { - this.toggleButton = 0; - this.editedDataset = false; - this._inputValue = "list"; - } else if (event == "add") { - this.addDataset(this.isFirst); - this.toggleButton = 2; - this._inputValue = "dataset"; - } else if (event == "dataset") { - this.toggleButton = 2; - this._inputValue = "dataset"; - } - } - - editDataset(index: number) { - // this.lastIndexOfDataset = index; - this.toggleButton = 2; - this.editedDataset = true; - this._inputValue = "dataset" - } - - deleteDataset(index: number) {//TODO: delete Dataset From List - this.lastIndexOfDataset = index; - this.toggleButton = 0; - this.editedDataset = false; - this._inputValue = "list"; - (this.formGroup.get('datasets').get('datasetsList') as UntypedFormArray).removeAt(index); - if (index == 0) { - this.isFirst = true; - } - } - - addDataset(isFirst: boolean) { - const formArray: UntypedFormArray = (this.formGroup.get('datasets').get('datasetsList') as UntypedFormArray); - let dataset = new QuickWizardDatasetDescriptionModel().fromModel(this.datasetProfileDefinition); - let formGroup = dataset.buildForm(); - - if (isFirst) { - formGroup.get('datasetLabel').setValue( - this.datasetProfile.value["label"] + " " + - this.language.instant('GENERAL.NAMES.DATASET') - ); - this.isFirst = false; - } - else { - formGroup.get('datasetLabel').setValue( - this.datasetProfile.value["label"] + " " + - this.language.instant('GENERAL.NAMES.DATASET') + - " (" + - this.lastIndexOfDataset + ")" - ); - } - formArray.push(formGroup); - this.lastIndexOfDataset = formArray.length - 1; - this.editedDataset = true; - this.scrollToTop(); - } - - listingMode() { - if (this.toggleButton === 0) return true; - } - - scrollToTop() { - var currentScroll = document.documentElement.scrollTop || document.body.scrollTop; - if (currentScroll > 0) { - window.scrollTo(0, 0); - } - } - - linkToScroll: LinkToScroll; - onStepFound(linkToScroll: LinkToScroll) { - this.linkToScroll = linkToScroll; - } -} diff --git a/dmp-frontend/src/app/ui/quick-wizard/dataset-editor/quick-wizard-dataset-description-model.ts b/dmp-frontend/src/app/ui/quick-wizard/dataset-editor/quick-wizard-dataset-description-model.ts deleted file mode 100644 index 75b30d1f8..000000000 --- a/dmp-frontend/src/app/ui/quick-wizard/dataset-editor/quick-wizard-dataset-description-model.ts +++ /dev/null @@ -1,20 +0,0 @@ -import { UntypedFormControl, UntypedFormGroup } from "@angular/forms"; -import { DatasetProfileDefinitionModel } from "../../../core/model/dataset-profile-definition/dataset-profile-definition"; -import { DatasetDescriptionFormEditorModel } from "../../misc/dataset-description-form/dataset-description-form.model"; - -export class QuickWizardDatasetDescriptionModel extends DatasetDescriptionFormEditorModel { - - public datasetLabel: string; - - fromModel(item: DatasetProfileDefinitionModel): DatasetDescriptionFormEditorModel { - super.fromModel(item); - return this; - } - - buildForm(): UntypedFormGroup { - const formGroup: UntypedFormGroup = super.buildForm(); - formGroup.addControl('datasetLabel', new UntypedFormControl({ value: this.datasetLabel })); - formGroup.addControl('status', new UntypedFormControl({ value: this.status })); - return formGroup; - } -} 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 deleted file mode 100644 index 576bf9458..000000000 --- a/dmp-frontend/src/app/ui/quick-wizard/dmp-editor/dmp-editor-wizard-model.ts +++ /dev/null @@ -1,56 +0,0 @@ -import { UntypedFormBuilder, UntypedFormGroup, Validators } from '@angular/forms'; -import { DmpStatus } from '@app/core/common/enum/dmp-status'; -import { DatasetProfileModel } from '@app/core/model/dataset/dataset-profile'; -import { DmpBlueprintDefinition } from '@app/core/model/dmp-blueprint/dmp-blueprint'; -import { DmpModel } from '@app/core/model/dmp/dmp'; -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'; - -export class DmpEditorWizardModel { - public id: string; - public label: string; - public status: DmpStatus = DmpStatus.Draft; - public description: String; - public datasetProfile: DatasetProfileModel; - public definition: DmpBlueprintDefinition; - public validationErrorModel: ValidationErrorModel = new ValidationErrorModel(); - public language: String; - - fromModel(item: DmpModel): DmpEditorWizardModel { - this.id = item.id; - 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.language = item.language; - return this; - } - - buildForm(context: ValidationContext = null, disabled: boolean = false): UntypedFormGroup { - if (context == null) { context = this.createValidationContext(); } - const formGroup = new UntypedFormBuilder().group({ - id: [{ value: this.id, disabled: disabled }, context.getValidation('id').validators], - label: [{ value: this.label, disabled: disabled }, context.getValidation('label').validators], - status: [{ value: this.status, disabled: disabled }, context.getValidation('status').validators], - description: [{ value: this.description, disabled: disabled }, context.getValidation('description').validators], - datasetProfile: [{ value: this.datasetProfile, disabled: disabled }, context.getValidation('datasetProfile').validators], - language: [{ value: this.language, disabled: disabled }, context.getValidation('language').validators], - }); - return formGroup; - } - - createValidationContext(): ValidationContext { - const baseContext: ValidationContext = new ValidationContext(); - baseContext.validation.push({ key: 'id', validators: [BackendErrorValidator(this.validationErrorModel, 'id')] }); - baseContext.validation.push({ key: 'label', validators: [Validators.required, BackendErrorValidator(this.validationErrorModel, 'label')] }); - baseContext.validation.push({ key: 'status', validators: [Validators.required, BackendErrorValidator(this.validationErrorModel, 'status')] }); - baseContext.validation.push({ key: 'description', validators: [BackendErrorValidator(this.validationErrorModel, 'description')] }); - baseContext.validation.push({ key: 'datasetProfile', validators: [Validators.required, ValidJsonValidator, BackendErrorValidator(this.validationErrorModel, 'datasetProfile')] }); - baseContext.validation.push({ key: 'language', validators: [Validators.required, ValidJsonValidator, BackendErrorValidator(this.validationErrorModel, 'language')] }); - return baseContext; - } -} - - 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 deleted file mode 100644 index a9313f047..000000000 --- a/dmp-frontend/src/app/ui/quick-wizard/dmp-editor/dmp-editor-wizard.component.html +++ /dev/null @@ -1,94 +0,0 @@ -
-
- - {{'QUICKWIZARD.CREATE-ADD.CREATE.QUICKWIZARD_CREATE.SECOND-STEP.NEW-TITLE' | translate}} - -

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

-
-
-
- - -
-

- {{'QUICKWIZARD.CREATE-ADD.CREATE.QUICKWIZARD_CREATE.SECOND-STEP.ABOUT' | translate}}

- - - - {{formGroup.get('label').getError('backendError').message}} - - {{'GENERAL.VALIDATION.REQUIRED' | translate}} - - - - - {{'QUICKWIZARD.CREATE-ADD.CREATE.QUICKWIZARD_CREATE.SECOND-STEP.FIELDS.DESCRIPTION-HINT' | translate}} - - - - - - - - {{'QUICKWIZARD.CREATE-ADD.CREATE.QUICKWIZARD_CREATE.SECOND-STEP.FIELDS.PROFILE-HINT' | translate}} - - - {{formGroup.get('datasetProfile').getError('backendError').message}} - - {{'GENERAL.VALIDATION.REQUIRED' | translate}} - - - - - - {{ lang.name }} - - - - {{formGroup.get('language').getError('backendError').message}} - - {{'GENERAL.VALIDATION.REQUIRED' | translate}} - - -
- {{'QUICKWIZARD.CREATE-ADD.CREATE.QUICKWIZARD_CREATE.SECOND-STEP.FIELDS.HELP' | translate}} -
- -
- -
-
-
-
diff --git a/dmp-frontend/src/app/ui/quick-wizard/dmp-editor/dmp-editor-wizard.component.scss b/dmp-frontend/src/app/ui/quick-wizard/dmp-editor/dmp-editor-wizard.component.scss deleted file mode 100644 index 441021760..000000000 --- a/dmp-frontend/src/app/ui/quick-wizard/dmp-editor/dmp-editor-wizard.component.scss +++ /dev/null @@ -1,4 +0,0 @@ -.help { - font-size: 12px; - margin-top: 3em; -} diff --git a/dmp-frontend/src/app/ui/quick-wizard/dmp-editor/dmp-editor-wizard.component.ts b/dmp-frontend/src/app/ui/quick-wizard/dmp-editor/dmp-editor-wizard.component.ts deleted file mode 100644 index 43afaf15a..000000000 --- a/dmp-frontend/src/app/ui/quick-wizard/dmp-editor/dmp-editor-wizard.component.ts +++ /dev/null @@ -1,141 +0,0 @@ - -import { Component, Input, OnInit } from '@angular/core'; -import { UntypedFormArray, UntypedFormGroup } from '@angular/forms'; -import { MatSnackBar } from '@angular/material/snack-bar'; -import { ActivatedRoute, Router } from '@angular/router'; -import { DatasetProfileModel } from '@app/core/model/dataset/dataset-profile'; -import { DatasetProfileCriteria } from '@app/core/query/dataset-profile/dataset-profile-criteria'; -import { RequestItem } from '@app/core/query/request-item'; -import { DmpService } from '@app/core/services/dmp/dmp.service'; -import { SnackBarNotificationLevel, UiNotificationService } from '@app/core/services/notification/ui-notification-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 { FormService } from '@common/forms/form-service'; -import { ValidationErrorModel } from '@common/forms/validation/error-model/validation-error-model'; -import { TranslateService } from '@ngx-translate/core'; -import { Observable, of as observableOf } from 'rxjs'; -import { DmpEditorWizardModel } from './dmp-editor-wizard-model'; -import { DataTableRequest } from '@app/core/model/data-table/data-table-request'; -import { LanguageInfo } from '@app/core/model/language-info'; -import { LanguageService } from '@app/core/services/language/language.service'; -import { LanguageInfoService } from '@app/core/services/culture/language-info-service'; - - -@Component({ - selector: 'app-quick-wizard-dmp-editor-component', - templateUrl: 'dmp-editor-wizard.component.html', - styleUrls: ['./dmp-editor-wizard.component.scss'] -}) -export class DmpEditorWizardComponent extends BaseComponent implements OnInit { //IBreadCrumbComponent - - // breadCrumbs: Observable = observableOf([]); - - isNew = true; - dmp: DmpEditorWizardModel; - @Input() formGroup: UntypedFormGroup; - @Input() dmpLabel: string; - @Input() datasetFormGroup: UntypedFormGroup; - private uiNotificationService: UiNotificationService - - profilesAutoCompleteConfiguration: SingleAutoCompleteConfiguration; - filteredProfiles: DatasetProfileModel[]; - filteredProfilesAsync = false; - - - constructor( - public snackBar: MatSnackBar, - public router: Router, - private route: ActivatedRoute, - private _service: DmpService, - public language: TranslateService, - private formService: FormService, - private languageInfoService: LanguageInfoService - ) { - super(); - } - - ngOnInit(): void { - - this.profilesAutoCompleteConfiguration = { - filterFn: this.filterProfiles.bind(this), - initialItems: (extraData) => this.filterProfiles(''), - displayFn: (item) => item['label'], - titleFn: (item) => item['label'], - subtitleFn: (item) => item['description'] - }; - - if (this.formGroup == null) { - this.dmp = new DmpEditorWizardModel(); - this.formGroup = this.dmp.buildForm(); - } - this.formGroup.get('label').setValue(this.language.instant('QUICKWIZARD.CREATE-ADD.CREATE.QUICKWIZARD_CREATE.SECOND-STEP.DMP-NAME') + this.dmpLabel); - this.formGroup.get('label').setValue(this.language.instant('QUICKWIZARD.CREATE-ADD.CREATE.QUICKWIZARD_CREATE.SECOND-STEP.DMP-NAME') + this.dmpLabel); - - // this.breadCrumbs = observableOf([{ - // parentComponentName: 'grant', - // label: this.language.instant('NAV-BAR.DMP'), - // url: '/quick-wizard/dmp' - // }]); - } - - formSubmit(): void { - this.formService.touchAllFormFields(this.formGroup); - if (!this.isFormValid()) { return; } - this.onSubmit(); - } - - public isFormValid() { - return this.formGroup.valid; - } - - onSubmit(): void { - // this.grantService.createGrant(this.formGroup.value) - // .pipe(takeUntil(this._destroyed)) - // .subscribe( - // complete => this.onCallbackSuccess(), - // error => this.onCallbackError(error) - // ); - } - - - 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']); - } - - onCallbackError(errorResponse: any) { - this.setErrorModel(errorResponse.error.payload); - this.formService.validateAllFormFields(this.formGroup); - } - - public setErrorModel(validationErrorModel: ValidationErrorModel) { - Object.keys(validationErrorModel).forEach(item => { - (this.dmp.validationErrorModel)[item] = (validationErrorModel)[item]; - }); - } - - filterProfiles(value: string): Observable { - - this.filteredProfiles = undefined; - this.filteredProfilesAsync = true; - - const request = new DataTableRequest(null, null, { fields: ['+label']}); - const criteria = new DatasetProfileCriteria(); - criteria.like = value; - request.criteria = criteria; - return this._service.searchDmpBlueprints(request); - } - - datasetIsEmpty() { - if (this.datasetFormGroup && this.datasetFormGroup.get('datasetsList') && (this.datasetFormGroup.get('datasetsList') as UntypedFormArray).length != 0) { - return true; - } - return false; - } - - getLanguageInfos(): LanguageInfo[] { - return this.languageInfoService.getLanguageInfoValues(); - } -} diff --git a/dmp-frontend/src/app/ui/quick-wizard/funder-editor/funder-editor-wizard.component.html b/dmp-frontend/src/app/ui/quick-wizard/funder-editor/funder-editor-wizard.component.html deleted file mode 100644 index 80acc2f60..000000000 --- a/dmp-frontend/src/app/ui/quick-wizard/funder-editor/funder-editor-wizard.component.html +++ /dev/null @@ -1,48 +0,0 @@ -
-
- - - -
-

{{'QUICKWIZARD.CREATE-ADD.CREATE.QUICKWIZARD_CREATE.FIRST-STEP.ABOUT-FUNDER' | translate}}

- - - - {{'DMP-EDITOR.FIELDS.EXTERNAL-SOURCE-HINT' | translate}} - {{'GENERAL.VALIDATION.REQUIRED' | translate}} - -
- -
-

{{'QUICKWIZARD.CREATE-ADD.CREATE.QUICKWIZARD_CREATE.FIRST-STEP.ABOUT-NEW-FUNDER' | translate}}

- - - {{funderFormGroup.get('label').getError('backendError').message}} - {{'GENERAL.VALIDATION.REQUIRED' | translate}} - -
- -
-
-
-
-

- {{'QUICKWIZARD.CREATE-ADD.CREATE.QUICKWIZARD_CREATE.FIRST-STEP.OR' | translate}} -

-
-
-
-
-
-
- - - - -
-
- -
-
-
-
diff --git a/dmp-frontend/src/app/ui/quick-wizard/funder-editor/funder-editor-wizard.component.scss b/dmp-frontend/src/app/ui/quick-wizard/funder-editor/funder-editor-wizard.component.scss deleted file mode 100644 index e69de29bb..000000000 diff --git a/dmp-frontend/src/app/ui/quick-wizard/funder-editor/funder-editor-wizard.component.ts b/dmp-frontend/src/app/ui/quick-wizard/funder-editor/funder-editor-wizard.component.ts deleted file mode 100644 index 569e5f433..000000000 --- a/dmp-frontend/src/app/ui/quick-wizard/funder-editor/funder-editor-wizard.component.ts +++ /dev/null @@ -1,67 +0,0 @@ -import { Component, Input, OnInit } from '@angular/core'; -import { UntypedFormGroup } from '@angular/forms'; -import { FunderModel } from '@app/core/model/funder/funder'; -import { TranslateService } from '@ngx-translate/core'; -import { FunderCriteria } from '../../../core/query/funder/funder-criteria'; -import { RequestItem } from '../../../core/query/request-item'; -import { FunderService } from '../../../core/services/funder/funder.service'; -import { SingleAutoCompleteConfiguration } from '../../../library/auto-complete/single/single-auto-complete-configuration'; -import { FunderFormModel } from '../../dmp/editor/grant-tab/funder-form-model'; - -@Component({ - selector: 'app-quick-wizard-funder-editor-component', - templateUrl: './funder-editor-wizard.component.html', - styleUrls: ['./funder-editor-wizard.component.scss'] -}) -export class FunderEditorWizardComponent implements OnInit { - - isNew = false; - funder: FunderFormModel; - funderLabelCleared = true; - @Input() funderFormGroup: UntypedFormGroup; - funderAutoCompleteConfiguration: SingleAutoCompleteConfiguration; - - constructor( - private funderService: FunderService, - private language: TranslateService - ) { } - - ngOnInit() { - - this.funderAutoCompleteConfiguration = { - filterFn: this.searchFunder.bind(this), - initialItems: (extraData) => this.searchFunder(''), - displayFn: (item) => item['label'], - titleFn: (item) => item['label'], - subtitleFn: (item) => item['source'] ? this.language.instant('TYPES.EXTERNAL-DATASET-TYPE.SOURCE:') + item['source'] : (item['key'] ? this.language.instant('TYPES.EXTERNAL-DATASET-TYPE.SOURCE:') + item['key'] : this.language.instant('TYPES.EXTERNAL-DATASET-TYPE.NO-SOURCE')) - }; - - if (!this.funderFormGroup) { - this.funder = new FunderFormModel(); - this.funderFormGroup = this.funder.buildForm(); - } - - this.funderFormGroup.get('existFunder').enable(); - this.funderFormGroup.get('label').disable(); - } - - searchFunder(query: string) { - const funderRequestItem: RequestItem = new RequestItem(); - funderRequestItem.criteria = new FunderCriteria(); - funderRequestItem.criteria.like = query; - return this.funderService.getWithExternal(funderRequestItem); - } - - create() { - this.isNew = !this.isNew; - if (this.isNew) { - this.funderFormGroup.get('existFunder').reset(); - this.funderFormGroup.get('existFunder').disable(); - this.funderFormGroup.get('label').enable(); - } else { - this.funderFormGroup.get('label').reset(); - this.funderFormGroup.get('label').disable(); - this.funderFormGroup.get('existFunder').enable(); - } - } -} diff --git a/dmp-frontend/src/app/ui/quick-wizard/grant-editor/grant-editor-wizard-model.ts b/dmp-frontend/src/app/ui/quick-wizard/grant-editor/grant-editor-wizard-model.ts deleted file mode 100644 index 7a243c40e..000000000 --- a/dmp-frontend/src/app/ui/quick-wizard/grant-editor/grant-editor-wizard-model.ts +++ /dev/null @@ -1,51 +0,0 @@ -import { UntypedFormBuilder, UntypedFormGroup, Validators } from "@angular/forms"; -import { Status } from '@app/core/common/enum/status'; -import { GrantListingModel } from '@app/core/model/grant/grant-listing'; -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'; - -export class GrantEditorWizardModel { - public id: string; - public label: string; - public status: Status = Status.Active; - public description: String; - public existGrant: GrantListingModel; - public validationErrorModel: ValidationErrorModel = new ValidationErrorModel(); - - - fromModel(item: GrantListingModel): GrantEditorWizardModel { - this.id = item.id; - this.label = item.label; - this.status = item.status; - this.description = item.description; - return this; - } - - buildForm(context: ValidationContext = null, disabled: boolean = false): UntypedFormGroup { - if (context == null) { context = this.createValidationContext(); } - - const formGroup = new UntypedFormBuilder().group({ - id: [{ value: this.id, disabled: disabled }, context.getValidation('id').validators], - label: [{ value: this.label, disabled: disabled }, context.getValidation('label').validators], - status: [{ value: this.status, disabled: disabled }, context.getValidation('status').validators], - description: [{ value: this.description, disabled: disabled }, context.getValidation('description').validators], - existGrant: [{ value: this.existGrant, disabled: disabled }, context.getValidation('existGrant').validators], - }); - return formGroup; - } - - createValidationContext(): ValidationContext { - const baseContext: ValidationContext = new ValidationContext(); - baseContext.validation.push({ key: 'id', validators: [] }); - baseContext.validation.push({ key: 'label', validators: [Validators.required, BackendErrorValidator(this.validationErrorModel, 'label')] }); - baseContext.validation.push({ key: 'status', validators: [] }); - baseContext.validation.push({ key: 'description', validators: [Validators.required, BackendErrorValidator(this.validationErrorModel, 'description')] }); - baseContext.validation.push({ key: 'existGrant', validators: [Validators.required, ValidJsonValidator, BackendErrorValidator(this.validationErrorModel, 'existGrant')] }); - return baseContext; - } - - -} - diff --git a/dmp-frontend/src/app/ui/quick-wizard/grant-editor/grant-editor-wizard.component.html b/dmp-frontend/src/app/ui/quick-wizard/grant-editor/grant-editor-wizard.component.html deleted file mode 100644 index f55f3f3c1..000000000 --- a/dmp-frontend/src/app/ui/quick-wizard/grant-editor/grant-editor-wizard.component.html +++ /dev/null @@ -1,65 +0,0 @@ -
- -
- - - - -
-

{{'QUICKWIZARD.CREATE-ADD.CREATE.QUICKWIZARD_CREATE.FIRST-STEP.ABOUT-GRANT' | translate}}

- - - - {{'DMP-EDITOR.FIELDS.EXTERNAL-SOURCE-HINT' | translate}} - - {{grantformGroup.get('grant').getError('backendError').message}} - - {{'GENERAL.VALIDATION.REQUIRED' | translate}} - -
- -
-

{{'QUICKWIZARD.CREATE-ADD.CREATE.QUICKWIZARD_CREATE.FIRST-STEP.ABOUT-NEW-GRANT' | translate}}

- - - {{'QUICKWIZARD.CREATE-ADD.CREATE.QUICKWIZARD_CREATE.FIRST-STEP.FIELDS.LABEL-HINT' | translate}} - - {{grantformGroup.get('label').getError('backendError').message}} - - {{'GENERAL.VALIDATION.REQUIRED' | translate}} - - - - {{'QUICKWIZARD.CREATE-ADD.CREATE.QUICKWIZARD_CREATE.FIRST-STEP.FIELDS.DESCRIPTION-HINT' | translate}} - - {{grantformGroup.get('description').getError('backendError').message}} - - {{'GENERAL.VALIDATION.REQUIRED' | translate}} - -
- -
-
-
-
-

- {{'QUICKWIZARD.CREATE-ADD.CREATE.QUICKWIZARD_CREATE.FIRST-STEP.OR' | translate}} -

-
-
-
-
-
-
- - - -
-
- -
-
-
-
diff --git a/dmp-frontend/src/app/ui/quick-wizard/grant-editor/grant-editor-wizard.component.scss b/dmp-frontend/src/app/ui/quick-wizard/grant-editor/grant-editor-wizard.component.scss deleted file mode 100644 index e69de29bb..000000000 diff --git a/dmp-frontend/src/app/ui/quick-wizard/grant-editor/grant-editor-wizard.component.ts b/dmp-frontend/src/app/ui/quick-wizard/grant-editor/grant-editor-wizard.component.ts deleted file mode 100644 index 118ceda70..000000000 --- a/dmp-frontend/src/app/ui/quick-wizard/grant-editor/grant-editor-wizard.component.ts +++ /dev/null @@ -1,151 +0,0 @@ - -import { Component, Input, OnInit } from '@angular/core'; -import { AbstractControl, FormArray, FormControl, UntypedFormGroup } from '@angular/forms'; -import { MatSnackBar } from '@angular/material/snack-bar'; -import { Router } from '@angular/router'; -import { GrantCriteria } from '@app/core/query/grant/grant-criteria'; -import { RequestItem } from '@app/core/query/request-item'; -import { GrantService } from '@app/core/services/grant/grant.service'; -import { SnackBarNotificationLevel, UiNotificationService } from '@app/core/services/notification/ui-notification-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 { GrantEditorWizardModel } from '@app/ui/quick-wizard/grant-editor/grant-editor-wizard-model'; -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'; -import { TranslateService } from '@ngx-translate/core'; -import { Observable, of as observableOf } from 'rxjs'; -import { takeUntil } from 'rxjs/operators'; -import { strict } from 'assert'; - -@Component({ - selector: 'app-quick-wizard-grant-editor-component', - templateUrl: 'grant-editor-wizard.component.html', - styleUrls: ['./grant-editor-wizard.component.scss'] -}) -export class GrantEditorWizardComponent extends BaseComponent implements OnInit { //IBreadCrumbComponent - // breadCrumbs: Observable = observableOf([]); - - isNew = false; - grant: GrantEditorWizardModel; - @Input() grantformGroup: UntypedFormGroup; - @Input() funderFormGroup: UntypedFormGroup; - private uiNotificationService: UiNotificationService - - grantAutoCompleteConfiguration: SingleAutoCompleteConfiguration; - - constructor( - public snackBar: MatSnackBar, - public router: Router, - public language: TranslateService, - private grantService: GrantService, - private formService: FormService - ) { - super(); - } - - getGrantIdText(item) { - if (item.reference != null && typeof item.reference == 'string') { - const parts = (item.reference as String).split('::'); - return parts.length > 1 ? ' (' + parts[parts.length - 1] + ')' : ''; - } - return ''; - } - - ngOnInit() { - // this.breadCrumbs = observableOf([{ - // parentComponentName: 'QuickCreate', - // label: this.language.instant('NAV-BAR.GRANT'), - // url: '/quick-wizard/grant' - // }]); - - const grantRequestItem: RequestItem = new RequestItem(); - grantRequestItem.criteria = new GrantCriteria(); - - this.grantAutoCompleteConfiguration = { - filterFn: this.searchGrant.bind(this), - initialItems: (extraData) => this.searchGrant(''), - displayFn: (item) => item['label'] + this.getGrantIdText(item), - titleFn: (item) => item['label'] + this.getGrantIdText(item), - subtitleFn: (item) => item['source'] ? this.language.instant('TYPES.EXTERNAL-DATASET-TYPE.SOURCE:') + item['source'] : (item['key'] ? this.language.instant('TYPES.EXTERNAL-DATASET-TYPE.SOURCE:') + item['key'] : this.language.instant('TYPES.EXTERNAL-DATASET-TYPE.NO-SOURCE')) - }; - - if (this.funderFormGroup && this.funderFormGroup.valid) { - this.grantformGroup.get('existGrant').enable(); - this.grantformGroup.get('label').disable(); - this.grantformGroup.get('description').disable(); - } else { - this.grantformGroup.get('existGrant').disable(); - } - - this.funderFormGroup.statusChanges - .pipe(takeUntil(this._destroyed)) - .subscribe(x => { - this.grantformGroup.reset(); - if (x == 'INVALID') { - this.grantformGroup.get('existGrant').reset(); - this.grantformGroup.get('label').reset(); - this.grantformGroup.get('description').reset(); - this.grantformGroup.get('existGrant').disable(); - this.grantformGroup.get('label').disable(); - this.grantformGroup.get('description').disable(); - } else if (x == 'VALID') { - if (!this.isNew) { - this.grantformGroup.get('label').reset(); - this.grantformGroup.get('description').reset(); - this.grantformGroup.get('label').disable(); - this.grantformGroup.get('description').disable(); - this.grantformGroup.get('existGrant').enable(); - - } - } - }) - } - - isFunderFormInvalid() { - return !this.funderFormGroup.valid; - } - - 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(['/grant']); - } - - onCallbackError(errorResponse: any) { - this.setErrorModel(errorResponse.error.payload); - this.formService.validateAllFormFields(this.grantformGroup); - } - - public setErrorModel(validationErrorModel: ValidationErrorModel) { - Object.keys(validationErrorModel).forEach(item => { - (this.grant.validationErrorModel)[item] = (validationErrorModel)[item]; - }); - } - - searchGrant(query: string) { - const grantRequestItem: RequestItem = new RequestItem(); - grantRequestItem.criteria = new GrantCriteria(); - grantRequestItem.criteria.like = query; - if (this.funderFormGroup.get('existFunder').value) { - grantRequestItem.criteria.funderReference = this.funderFormGroup.controls['existFunder'].value.reference; - } - return this.grantService.getWithExternal(grantRequestItem); - } - - create() { - this.isNew = !this.isNew; - if (this.isNew) { - this.grantformGroup.get('existGrant').reset(); - this.grantformGroup.get('existGrant').disable(); - this.grantformGroup.get('label').enable(); - this.grantformGroup.get('description').enable(); - } else { - this.grantformGroup.get('label').reset(); - this.grantformGroup.get('label').disable(); - this.grantformGroup.get('description').reset(); - this.grantformGroup.get('description').disable(); - this.grantformGroup.get('existGrant').enable(); - } - } -} diff --git a/dmp-frontend/src/app/ui/quick-wizard/project-editor/project-editor-wizard.component.html b/dmp-frontend/src/app/ui/quick-wizard/project-editor/project-editor-wizard.component.html deleted file mode 100644 index 208838c21..000000000 --- a/dmp-frontend/src/app/ui/quick-wizard/project-editor/project-editor-wizard.component.html +++ /dev/null @@ -1,57 +0,0 @@ -
- -
- - - -
-

{{'QUICKWIZARD.CREATE-ADD.CREATE.QUICKWIZARD_CREATE.FIRST-STEP.ABOUT-PROJECT' | translate}}

- - - - {{'DMP-EDITOR.FIELDS.EXTERNAL-SOURCE-HINT' | translate}} - -
- -
-

{{'QUICKWIZARD.CREATE-ADD.CREATE.QUICKWIZARD_CREATE.FIRST-STEP.ABOUT-NEW-PROJECT' | translate}}

- - - - {{formGroup.get('label').getError('backendError').message}} - - {{'GENERAL.VALIDATION.REQUIRED' | translate}} - - - - - {{formGroup.get('description').getError('backendError').message}} - - {{'GENERAL.VALIDATION.REQUIRED' | translate}} - -
- -
-
-
-
-

- {{'QUICKWIZARD.CREATE-ADD.CREATE.QUICKWIZARD_CREATE.FIRST-STEP.OR' | translate}} -

-
-
-
-
-
-
- - - - -
-
- -
-
-
-
diff --git a/dmp-frontend/src/app/ui/quick-wizard/project-editor/project-editor-wizard.component.scss b/dmp-frontend/src/app/ui/quick-wizard/project-editor/project-editor-wizard.component.scss deleted file mode 100644 index e69de29bb..000000000 diff --git a/dmp-frontend/src/app/ui/quick-wizard/project-editor/project-editor-wizard.component.ts b/dmp-frontend/src/app/ui/quick-wizard/project-editor/project-editor-wizard.component.ts deleted file mode 100644 index dcfb6dee4..000000000 --- a/dmp-frontend/src/app/ui/quick-wizard/project-editor/project-editor-wizard.component.ts +++ /dev/null @@ -1,69 +0,0 @@ -import { Component, OnInit, Input } from '@angular/core'; -import { SingleAutoCompleteConfiguration } from '../../../library/auto-complete/single/single-auto-complete-configuration'; -import { UntypedFormGroup } from '@angular/forms'; -import { ProjectService } from '../../../core/services/project/project.service'; -import { RequestItem } from '../../../core/query/request-item'; -import { ProjectCriteria } from '../../../core/query/project/project-criteria'; -import { ProjectFormModel } from '../../dmp/editor/grant-tab/project-form-model'; -import { TranslateService } from '@ngx-translate/core'; - -@Component({ - selector: 'app-quick-wizard-project-editor-component', - templateUrl: './project-editor-wizard.component.html', - styleUrls: ['./project-editor-wizard.component.scss'] -}) -export class ProjectEditorWizardComponent implements OnInit { - - isNew = false; - project: ProjectFormModel; - @Input() formGroup: UntypedFormGroup; - projectAutoCompleteConfiguration: SingleAutoCompleteConfiguration; - - constructor( - private projectService: ProjectService, - private language: TranslateService - ) { } - - ngOnInit() { - this.projectAutoCompleteConfiguration = { - filterFn: this.searchProject.bind(this), - initialItems: (extraData) => this.searchProject(''), - displayFn: (item) => item['label'], - titleFn: (item) => item['label'], - subtitleFn: (item) => item['source'] ? this.language.instant('TYPES.EXTERNAL-DATASET-TYPE.SOURCE:') + item['source'] : (item['key'] ? this.language.instant('TYPES.EXTERNAL-DATASET-TYPE.SOURCE:') + item['key'] : this.language.instant('TYPES.EXTERNAL-DATASET-TYPE.NO-SOURCE')) - }; - - if (!this.formGroup) { - this.project = new ProjectFormModel(); - this.formGroup = this.project.buildForm(); - } - - this.formGroup.get('existProject').enable(); - this.formGroup.get('label').disable(); - this.formGroup.get('description').disable(); - } - - searchProject(query: string) { - const projectRequestItem: RequestItem = new RequestItem(); - projectRequestItem.criteria = new ProjectCriteria(); - projectRequestItem.criteria.like = query; - return this.projectService.getWithExternal(projectRequestItem); - } - - create() { - this.isNew = !this.isNew; - if (this.isNew) { - this.formGroup.get('existProject').disable(); - this.formGroup.get('existProject').reset(); - this.formGroup.get('label').enable(); - this.formGroup.get('description').enable(); - } else { - this.formGroup.get('existProject').enable(); - this.formGroup.get('label').disable(); - this.formGroup.get('label').reset(); - this.formGroup.get('description').disable(); - this.formGroup.get('description').reset(); - } - } - -} diff --git a/dmp-frontend/src/app/ui/quick-wizard/quick-wizard-editor/quick-wizard-editor.component.html b/dmp-frontend/src/app/ui/quick-wizard/quick-wizard-editor/quick-wizard-editor.component.html deleted file mode 100644 index 166f4b99b..000000000 --- a/dmp-frontend/src/app/ui/quick-wizard/quick-wizard-editor/quick-wizard-editor.component.html +++ /dev/null @@ -1,68 +0,0 @@ -
-
-
-
-

{{ 'QUICKWIZARD.CREATE-ADD.CREATE.QUICKWIZARD_CREATE.TITLE' | translate }}

-

{{ 'QUICKWIZARD.CREATE-ADD.CREATE.QUICKWIZARD_CREATE.POST-SELECTION-INFO' | translate }}

-
- - - - {{'QUICKWIZARD.CREATE-ADD.CREATE.QUICKWIZARD_CREATE.FIRST-STEP.TITLE' | translate}} - -
-
- - -
-
-
- -
- -
- - - {{'QUICKWIZARD.CREATE-ADD.CREATE.QUICKWIZARD_CREATE.SECOND-STEP.TITLE' | translate}} - - -
- - -
- -
-
- - - {{'QUICKWIZARD.CREATE-ADD.CREATE.QUICKWIZARD_CREATE.THIRD-STEP.TITLE' | translate}} - - - -
- - - - - -
- -
-
-
-
-
-
-
-
diff --git a/dmp-frontend/src/app/ui/quick-wizard/quick-wizard-editor/quick-wizard-editor.component.scss b/dmp-frontend/src/app/ui/quick-wizard/quick-wizard-editor/quick-wizard-editor.component.scss deleted file mode 100644 index ea2e9bba1..000000000 --- a/dmp-frontend/src/app/ui/quick-wizard/quick-wizard-editor/quick-wizard-editor.component.scss +++ /dev/null @@ -1,11 +0,0 @@ -.saveAndFinalizeButton{ - float:right; -} -.finalizeButton{ - float: right; - text-transform: uppercase; -} -.saveButton{ - float:right; - margin-right: 15px; -} diff --git a/dmp-frontend/src/app/ui/quick-wizard/quick-wizard-editor/quick-wizard-editor.component.ts b/dmp-frontend/src/app/ui/quick-wizard/quick-wizard-editor/quick-wizard-editor.component.ts deleted file mode 100644 index 9c1bf928f..000000000 --- a/dmp-frontend/src/app/ui/quick-wizard/quick-wizard-editor/quick-wizard-editor.component.ts +++ /dev/null @@ -1,203 +0,0 @@ - -import { Component, OnInit, ViewChild } from '@angular/core'; -import { AbstractControl, UntypedFormArray, FormControl, UntypedFormGroup } from '@angular/forms'; -import { MatDialog } from '@angular/material/dialog'; -import { MatSnackBar } from '@angular/material/snack-bar'; -import { MatStepper } from '@angular/material/stepper'; -import { Router } from '@angular/router'; -import { DatasetStatus } from '@app/core/common/enum/dataset-status'; -import { DmpStatus } from '@app/core/common/enum/dmp-status'; -import { DatasetService } from '@app/core/services/dataset/dataset.service'; -import { SnackBarNotificationLevel, UiNotificationService } from '@app/core/services/notification/ui-notification-service'; -import { QuickWizardService } from '@app/core/services/quick-wizard/quick-wizard.service'; -import { CheckDeactivateBaseComponent } from '@app/library/deactivate/deactivate.component'; -import { DmpFinalizeDialogComponent, DmpFinalizeDialogDataset, 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 { ProjectFormModel } from '@app/ui/dmp/editor/grant-tab/project-form-model'; -import { DatasetEditorWizardComponent } from '@app/ui/quick-wizard/dataset-editor/dataset-editor-wizard.component'; -import { GrantEditorWizardModel } from '@app/ui/quick-wizard/grant-editor/grant-editor-wizard-model'; -import { QuickWizardEditorWizardModel } from '@app/ui/quick-wizard/quick-wizard-editor/quick-wizard-editor.model'; -import { FormService } from '@common/forms/form-service'; -import { ValidationErrorModel } from '@common/forms/validation/error-model/validation-error-model'; -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({ - selector: 'app-quick-wizard-editor-component', - templateUrl: 'quick-wizard-editor.component.html', - styleUrls: ['./quick-wizard-editor.component.scss'] -}) -export class QuickWizardEditorComponent extends CheckDeactivateBaseComponent implements OnInit { - - // breadCrumbs: Observable = observableOf([]); - @ViewChild('stepper', { static: true }) stepper: MatStepper; - @ViewChild(DatasetEditorWizardComponent) datasetEditorWizardComponent: DatasetEditorWizardComponent; - isNew = true; - isSubmitted = false; - quickWizard: QuickWizardEditorWizardModel; - allDatasets: DmpFinalizeDialogDataset[] = []; - formGroup: UntypedFormGroup = null; - - constructor( - public snackBar: MatSnackBar, - public router: Router, - public language: TranslateService, - public datasetService: DatasetService, - public quickWizardService: QuickWizardService, - private uiNotificationService: UiNotificationService, - private dialog: MatDialog, - private formService: FormService - ) { - super(); - } - - ngOnInit(): void { - this.quickWizard = new QuickWizardEditorWizardModel(); - this.quickWizard.grant = new GrantEditorWizardModel(); - this.quickWizard.funder = new FunderFormModel(); - this.quickWizard.project = new ProjectFormModel(); - this.formGroup = this.quickWizard.buildForm(); - this.language.get('NAV-BAR.DMP-WIZARD').pipe(takeUntil(this._destroyed)).subscribe(x => { - // this.breadCrumbs = observableOf([ - // { - // parentComponentName: 'Dashboard', - // label: x, - // url: '/quick-wizard' - // }] - // ); - }) - } - - isActive(step: string): boolean { - switch (step) { - case 'step1': - return this.stepper.selectedIndex == 0; - case 'step2': - return this.stepper.selectedIndex == 1; - case 'step3': - return this.stepper.selectedIndex == 2; - } - } - - formSubmit(): void { - this.formService.touchAllFormFields(this.formGroup); - if (this.formGroup.get('datasets') && this.formGroup.get('datasets').get('datasetsList') && (this.formGroup.get('datasets').get('datasetsList') as UntypedFormArray).length > 0) { - for (let control of (this.formGroup.get('datasets').get('datasetsList') as UntypedFormArray).controls) { - control.get('status').setValue(DatasetStatus.Draft); - } - this.onSubmitSave(); - } else { - this.uiNotificationService.popupNotification(this.language.instant('GENERAL.NOTIFICATION-DIALOG.POPUP.TITLE'), this.language.instant('GENERAL.NOTIFICATION-DIALOG.POPUP.MESSAGE')); - return; - } - } - - saveFinalize() { - if (!this.isFormValid()) { return; } - - const dialogInputModel: DmpFinalizeDialogInput = { - dmpLabel: this.formGroup.get('dmp').get('label').value, - dmpDescription: this.formGroup.get('dmp').get('description').value, - datasets: (this.formGroup.get('datasets').get('datasetsList') as UntypedFormArray).controls.map(x => { - return { label: x.get('datasetLabel').value, status: DatasetStatus.Finalized }; - }), - accessRights: false - } - - const dialogRef = this.dialog.open(DmpFinalizeDialogComponent, { - maxWidth: '500px', - restoreFocus: false, - autoFocus: false, - data: { - dialogInputModel: dialogInputModel, - confirmButton: this.language.instant('DMP-FINALISE-DIALOG.SUBMIT'), - cancelButton: this.language.instant('GENERAL.CONFIRMATION-DIALOG.ACTIONS.CANCEL'), - } - }); - dialogRef.afterClosed().pipe(takeUntil(this._destroyed)).subscribe(result => { - if (result && !result.cancelled) { - if (this.formGroup.get('datasets') && this.formGroup.get('datasets').get('datasetsList') && (this.formGroup.get('datasets').get('datasetsList') as UntypedFormArray).length > 0) { - for (let control of (this.formGroup.get('datasets').get('datasetsList') as UntypedFormArray).controls) { - control.get('status').setValue(DatasetStatus.Finalized); - } - this.formGroup.get('dmp').get('status').setValue(DmpStatus.Finalized); - this.onSubmitSaveAndFinalize(); - } else { - this.uiNotificationService.popupNotification(this.language.instant('GENERAL.NOTIFICATION-DIALOG.POPUP.TITLE'), this.language.instant('GENERAL.NOTIFICATION-DIALOG.POPUP.MESSAGE')); - } - } - }); - } - - hasDatasets() { - return this.formGroup.get('datasets').get('datasetsList').valid; - } - - public isFormValid() { - return this.formGroup.get('grant').valid && this.formGroup.get('funder').valid; - } - - onSubmitSaveAndFinalize() { - this.quickWizardService.createQuickWizard(this.formGroup.getRawValue()) - .pipe(takeUntil(this._destroyed)) - .subscribe( - complete => this.onCallbackSuccess(), - error => this.onCallbackError(error) - ); - } - - onSubmitSave(): void { - const dialogRef = this.dialog.open(ConfirmationDialogComponent, { - restoreFocus: false, - data: { - message: this.language.instant('QUICKWIZARD.SAVE-DIALOG.TITLE'), - confirmButton: this.language.instant('QUICKWIZARD.SAVE-DIALOG.ACTIONS.AFFIRMATIVE'), - cancelButton: this.language.instant('QUICKWIZARD.SAVE-DIALOG.ACTIONS.NEGATIVE'), - isDeleteConfirmation: false - } - }); - dialogRef.afterClosed().pipe(takeUntil(this._destroyed)).subscribe(result => { - if (result) { - this.datasetEditorWizardComponent.addDataset(false); - } else if (result === false) { - this.quickWizardService.createQuickWizard(this.formGroup.value) - .pipe(takeUntil(this._destroyed)) - .subscribe( - complete => this.onCallbackSuccess() - ) - } - }); - } - - onCallbackSuccess(): void { - this.isSubmitted = true; - 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(['/home']); - } - - onCallbackError(errorResponse: any) { - this.setErrorModel(errorResponse.error.payload); - this.formService.validateAllFormFields(this.formGroup); - } - - public setErrorModel(validationErrorModel: ValidationErrorModel) { - Object.keys(validationErrorModel).forEach(item => { - (this.quickWizard.validationErrorModel)[item] = (validationErrorModel)[item]; - }); - } - - getGrantLabel(): string { - if (this.formGroup.get('grant').get('existGrant').value) { - return this.formGroup.get('grant').get('existGrant').value['label']; - } else { - return this.formGroup.get('grant').get('label').value; - } - } - - canDeactivate(): boolean { - return this.isSubmitted || !this.formGroup.dirty; - } - -} diff --git a/dmp-frontend/src/app/ui/quick-wizard/quick-wizard-editor/quick-wizard-editor.model.ts b/dmp-frontend/src/app/ui/quick-wizard/quick-wizard-editor/quick-wizard-editor.model.ts deleted file mode 100644 index 069011166..000000000 --- a/dmp-frontend/src/app/ui/quick-wizard/quick-wizard-editor/quick-wizard-editor.model.ts +++ /dev/null @@ -1,70 +0,0 @@ -import { UntypedFormBuilder, UntypedFormGroup } from '@angular/forms'; -import { DmpModel } from '@app/core/model/dmp/dmp'; -import { FunderModel } from '@app/core/model/funder/funder'; -import { GrantListingModel } from '@app/core/model/grant/grant-listing'; -import { ProjectModel } from '@app/core/model/project/project'; -import { DatasetWizardEditorModel } from '@app/ui/dataset/dataset-wizard/dataset-wizard-editor.model'; -import { FunderFormModel } from '@app/ui/dmp/editor/grant-tab/funder-form-model'; -import { ProjectFormModel } from '@app/ui/dmp/editor/grant-tab/project-form-model'; -import { ValidationErrorModel } from '@common/forms/validation/error-model/validation-error-model'; -import { ValidationContext } from '@common/forms/validation/validation-context'; -import { DatasetEditorWizardModel } from '../dataset-editor/dataset-editor-wizard-model'; -import { DmpEditorWizardModel } from '../dmp-editor/dmp-editor-wizard-model'; -import { GrantEditorWizardModel } from '../grant-editor/grant-editor-wizard-model'; - - -export class QuickWizardEditorWizardModel { - public grant: GrantEditorWizardModel; - public funder: FunderFormModel; - public project: ProjectFormModel; - public dmp: DmpEditorWizardModel; - public datasets: DatasetEditorWizardModel; - public validationErrorModel: ValidationErrorModel = new ValidationErrorModel(); - - fromModelGrant(item: GrantListingModel): QuickWizardEditorWizardModel { - this.grant.fromModel(item); - return this; - } - - fromModelFunder(item: FunderModel): QuickWizardEditorWizardModel { - this.funder.fromModel(item); - return this; - } - - fromModelProject(item: ProjectModel): QuickWizardEditorWizardModel { - this.project.fromModel(item); - return this; - } - - fromModelDmp(item: DmpModel): QuickWizardEditorWizardModel { - this.dmp.fromModel(item); - return this; - } - - fromModelDataset(item: DatasetWizardEditorModel[]): QuickWizardEditorWizardModel { - this.datasets.fromModel(item); - return this; - } - - buildForm(context: ValidationContext = null): UntypedFormGroup { - // if (context == null) { context = this.createValidationContext(); } - const formGroup = new UntypedFormBuilder().group({ - grant: new GrantEditorWizardModel().buildForm(), - funder: new FunderFormModel().buildForm(), - project: new ProjectFormModel().buildForm(), - dmp: new DmpEditorWizardModel().buildForm(), - datasets: new DatasetEditorWizardModel().buildForm() - - }); - return formGroup; - } - - // createValidationContext(): ValidationContext { - // const baseContext: ValidationContext = new ValidationContext(); - // baseContext.validation.push({ key: 'grant', validators: [Validators.required, BackendErrorValidator(this.validationErrorModel, 'grant')] }); - // baseContext.validation.push({ key: 'dmp', validators: [Validators.required, BackendErrorValidator(this.validationErrorModel, 'dmp')] }); - // baseContext.validation.push({ key: 'datasets', validators: [Validators.required, BackendErrorValidator(this.validationErrorModel, 'datasets')] }); - // return baseContext; - // } - -} diff --git a/dmp-frontend/src/app/ui/quick-wizard/quick-wizard.module.ts b/dmp-frontend/src/app/ui/quick-wizard/quick-wizard.module.ts deleted file mode 100644 index 0811a1e48..000000000 --- a/dmp-frontend/src/app/ui/quick-wizard/quick-wizard.module.ts +++ /dev/null @@ -1,48 +0,0 @@ -import { NgModule } from '@angular/core'; -import { AutoCompleteModule } from '@app/library/auto-complete/auto-complete.module'; -import { ConfirmationDialogModule } from '@common/modules/confirmation-dialog/confirmation-dialog.module'; -import { CanDeactivateGuard } from '@app/library/deactivate/can-deactivate.guard'; -import { UrlListingModule } from '@app/library/url-listing/url-listing.module'; -import { DmpModule } from '@app/ui/dmp/dmp.module'; -import { DatasetDescriptionFormModule } from '@app/ui/misc/dataset-description-form/dataset-description-form.module'; -import { DatasetEditorWizardComponent } from '@app/ui/quick-wizard/dataset-editor/dataset-editor-wizard.component'; -import { DmpEditorWizardComponent } from '@app/ui/quick-wizard/dmp-editor/dmp-editor-wizard.component'; -import { FunderEditorWizardComponent } from '@app/ui/quick-wizard/funder-editor/funder-editor-wizard.component'; -import { GrantEditorWizardComponent } from '@app/ui/quick-wizard/grant-editor/grant-editor-wizard.component'; -import { ProjectEditorWizardComponent } from '@app/ui/quick-wizard/project-editor/project-editor-wizard.component'; -import { QuickWizardEditorComponent } from '@app/ui/quick-wizard/quick-wizard-editor/quick-wizard-editor.component'; -import { QuickWizardRoutingModule } from '@app/ui/quick-wizard/quick-wizard.routing'; -import { CommonFormsModule } from '@common/forms/common-forms.module'; -import { CommonUiModule } from '@common/ui/common-ui.module'; -import { TableOfContentsModule } from '../misc/dataset-description-form/tableOfContentsMaterial/table-of-contents.module'; -import { AngularStickyThingsModule } from '@w11k/angular-sticky-things'; - -@NgModule({ - imports: [ - CommonUiModule, - CommonFormsModule, - UrlListingModule, - AutoCompleteModule, - ConfirmationDialogModule, - QuickWizardRoutingModule, - DatasetDescriptionFormModule, - // DmpModule, - TableOfContentsModule, - AngularStickyThingsModule - ], - declarations: [ - GrantEditorWizardComponent, - DmpEditorWizardComponent, - QuickWizardEditorComponent, - DatasetEditorWizardComponent, - FunderEditorWizardComponent, - ProjectEditorWizardComponent - ], - exports: [ - DatasetEditorWizardComponent, - ], - providers: [ - CanDeactivateGuard - ] -}) -export class OuickWizardModule { } diff --git a/dmp-frontend/src/app/ui/quick-wizard/quick-wizard.routing.ts b/dmp-frontend/src/app/ui/quick-wizard/quick-wizard.routing.ts deleted file mode 100644 index 22f849a67..000000000 --- a/dmp-frontend/src/app/ui/quick-wizard/quick-wizard.routing.ts +++ /dev/null @@ -1,44 +0,0 @@ -import { NgModule } from '@angular/core'; -import { RouterModule, Routes } from '@angular/router'; -import { QuickWizardEditorComponent } from './quick-wizard-editor/quick-wizard-editor.component'; -import { CanDeactivateGuard } from '../../library/deactivate/can-deactivate.guard'; -import { AuthGuard } from '@app/core/auth-guard.service'; - -const routes: Routes = [ - { - path: '', - component: QuickWizardEditorComponent, - canActivate: [AuthGuard], - data: { - breadcrumb: true - }, - canDeactivate: [CanDeactivateGuard] - }, - // { - // path: 'grant', - // component: GrantEditorWizardComponent, - // data: { - // breadcrumb: true - // }, - // }, - // { - // path: 'dmp', - // component: DmpEditorWizardComponent, - // data: { - // breadcrumb: true - // }, - // }, - // { - // path: 'dataset', - // component: DatasetEditorWizardComponent, - // data: { - // breadcrumb: true - // }, - // } -]; - -@NgModule({ - imports: [RouterModule.forChild(routes)], - exports: [RouterModule] -}) -export class QuickWizardRoutingModule { } diff --git a/dmp-frontend/src/app/ui/sidebar/sidebar.component.ts b/dmp-frontend/src/app/ui/sidebar/sidebar.component.ts index 011c90d49..25b94beb0 100644 --- a/dmp-frontend/src/app/ui/sidebar/sidebar.component.ts +++ b/dmp-frontend/src/app/ui/sidebar/sidebar.component.ts @@ -31,13 +31,11 @@ export const GENERAL_ROUTES: RouteInfo[] = [ export const DMP_ROUTES: RouteInfo[] = [ { path: '/plans', title: 'SIDE-BAR.MY-DMPS', icon: 'library_books' }, { path: '/descriptions', title: 'SIDE-BAR.MY-DESCRIPTIONS', icon: 'dns' }, - // { path: '/quick-wizard', title: 'SIDE-BAR.QUICK-WIZARD', icon: 'play_circle_outline' }, // { path: '/plans/new', title: 'SIDE-BAR.ADD-EXPERT', icon: 'playlist_add' } ]; export const DATASETS_ROUTES: RouteInfo[] = [ { path: '/explore-plans', title: 'SIDE-BAR.PUBLIC-DMPS', icon: 'library_books' }, { path: '/explore-descriptions', title: 'SIDE-BAR.PUBLIC-DESC', icon: 'dns' }, - // { path: '/datasetcreatewizard', title: 'SIDE-BAR.QUICK-WIZARD-DATASET', icon: "play_circle_outline" }, ]; export const PUBLIC_ROUTES: RouteInfo[] = [