Adds dataset editor on dmp editor

This commit is contained in:
apapachristou 2020-07-29 18:04:19 +03:00
parent 00aa4ef2c6
commit 10eccf89eb
24 changed files with 1210 additions and 53 deletions

View File

@ -31,6 +31,7 @@ import { TranslateServerLoader } from './core/services/language/server.loader';
import { BaseHttpService } from './core/services/http/base-http.service';
import { ConfigurationService } from './core/services/configuration/configuration.service';
import { Oauth2DialogModule } from './ui/misc/oauth2-dialog/oauth2-dialog.module';
import { MAT_FORM_FIELD_DEFAULT_OPTIONS, MatFormFieldDefaultOptions } from '@angular/material';
// AoT requires an exported function for factories
export function HttpLoaderFactory(http: HttpClient, appConfig: ConfigurationService) {
@ -69,6 +70,11 @@ const cookieConfig: NgcCookieConsentConfig = {
type: 'info'
};
const appearance: MatFormFieldDefaultOptions = {
appearance: 'outline'
// appearance: 'standard'
};
@NgModule({
imports: [
BrowserModule,
@ -118,6 +124,10 @@ const cookieConfig: NgcCookieConsentConfig = {
deps: [CultureService],
useFactory: (cultureService) => cultureService.getCurrentCulture().name
},
{
provide: MAT_FORM_FIELD_DEFAULT_OPTIONS,
useValue: appearance
},
Title,
CookieService
],

View File

@ -11,6 +11,7 @@ import { ProjectModel } from "../project/project";
import { FunderModel } from "../funder/funder";
import { DmpStatus } from '@app/core/common/enum/dmp-status';
import { ExtraPropertiesFormModel } from '@app/ui/dmp/editor/general-tab/extra-properties-form.model';
import { DatasetWizardModel } from '../dataset/dataset-wizard';
export interface DmpModel {
id: string;
@ -24,7 +25,7 @@ export interface DmpModel {
grant: GrantListingModel;
project: ProjectModel;
funder: FunderModel;
datasets: DatasetModel[];
datasets: DatasetWizardModel[];
datasetsToBeFinalized: string[];
profiles: DmpProfile[];
organisations: OrganizationModel[];

View File

@ -1,4 +1,260 @@
<form *ngIf="formGroup" [formGroup]="formGroup" class="dataset-external-references-editor">
<!-- Tags -->
<div class="pt-2">
<div class="row">
<div class="col-12 pl-0 pr-0 pb-2 d-flex flex-row">
<h4 class="col-auto heading">1.4 {{'DATASET-EDITOR.FIELDS.TAGS' | translate}}</h4>
</div>
</div>
<!-- <app-external-item-listing *ngIf="formGroup.get('tags') && tagsTemplate && externalSourcesConfiguration" [options]="externalSourcesConfiguration.tags" placeholder="{{'DATASET-EDITOR.FIELDS.TAGS' | translate}}" [parentTemplate]='tagsTemplate' [formArray]="formGroup.get('tags')" [autoCompleteConfiguration]="tagsAutoCompleteConfiguration" (onItemChange)="tagsOnItemChange($event)">
</app-external-item-listing> -->
<div class="tags-form">
<mat-form-field appearance="outline">
<mat-chip-list #chipList [disabled]="viewOnly">
<mat-chip *ngFor="let tag of formGroup.get('tags').value" [removable]="true" (removed)="removeTag(tag)">
{{tag.name}}
<mat-icon matChipRemove *ngIf="!viewOnly">cancel</mat-icon>
</mat-chip>
<input matInput [disabled]="viewOnly" placeholder="{{'DATASET-EDITOR.FIELDS.TAGS' | translate}}" [matChipInputFor]="chipList" [matChipInputSeparatorKeyCodes]="separatorKeysCodes" [matChipInputAddOnBlur]="true" (matChipInputTokenEnd)="addTag($event)">
</mat-chip-list>
</mat-form-field>
</div>
<ng-template #tagsTemplate let-suggestion let-i="index" let-callback="function">
<div class="col-12 row align-items-center">
<div class="col">
<p>
{{i+1}}) {{suggestion.get('name').value}}
</p>
</div>
<div class="col-auto">
<button mat-icon-button (click)="callback(i)" *ngIf='!viewOnly'>
<mat-icon>close</mat-icon>
</button>
</div>
</div>
</ng-template>
</div>
<!-- Data Repositories -->
<div class="pt-2">
<div class="row">
<div class="col-12 pl-0 pr-0 pb-2 d-flex flex-row">
<h4 class="col-auto heading">1.5 {{'DATASET-EDITOR.FIELDS.DATAREPOSITORIES' | translate}}</h4>
<div class="col"></div>
<div class="col-auto d-flex align-items-center" *ngIf='!viewOnly'>
<button class="col-auto" mat-raised-button (click)="addDataRepository()">
{{'DATASET-EDITOR.FIELDS.CREATE'|translate}}
</button>
</div>
</div>
</div>
<app-external-item-listing class="col-12" *ngIf="formGroup.get('dataRepositories') && dataRepositoriesTemplate && externalSourcesConfiguration" [options]="externalSourcesConfiguration.dataRepositories" placeholder="{{'DATASET-EDITOR.FIELDS.DATAREPOSITORIES' | translate}}" [parentTemplate]='dataRepositoriesTemplate' [formArray]="formGroup.get('dataRepositories')" [autoCompleteConfiguration]="dataRepositoriesAutoCompleteConfiguration" (onItemChange)="dataRepositoriesOnItemChange($event)">
</app-external-item-listing>
<ng-template #dataRepositoriesTemplate let-suggestion let-i="index" let-callback="function">
<div class="col-12 row align-items-center">
<span class="col">
{{i+1}}) {{suggestion.get('name').value}}
</span>
<div class="col-auto" *ngIf="isInternal(suggestion)">
<mat-form-field>
<input matInput placeholder="{{'DATASET-REFERENCED-MODELS.DATA-REPOSITORY.LABEL' | translate}}" type="text" name="name" [formControl]="suggestion.get('name')">
</mat-form-field>
</div>
<div class="col-auto" *ngIf="isInternal(suggestion)">
<mat-form-field>
<input matInput placeholder="{{'DATASET-REFERENCED-MODELS.DATA-REPOSITORY.ABBREVIATION' | translate}}" type="text" name="abbreviation" [formControl]="suggestion.get('abbreviation')">
</mat-form-field>
</div>
<div class="col-auto" *ngIf="isInternal(suggestion)">
<mat-form-field>
<input matInput placeholder="{{'DATASET-REFERENCED-MODELS.DATA-REPOSITORY.URI' | translate}}" type="text" name="uri" [formControl]="suggestion.get('uri')">
</mat-form-field>
</div>
<div class="col-auto">
<mat-form-field>
<input matInput placeholder="{{'DATASET-EDITOR.FIELDS.DATAREPOSITORIES-INFO' | translate}}" type="text" name="info" [formControl]="suggestion.get('info')">
</mat-form-field>
</div>
<div class="col-auto" *ngIf='!viewOnly && isInternal(suggestion)'>
<button mat-raised-button (click)="updateDataRepository(suggestion)" type="button">
{{ 'DATASET-EDITOR.ACTIONS.UPDATE' | translate }}
</button>
</div>
<div class="col-auto" *ngIf='!viewOnly'>
<button mat-icon-button (click)="callback(i)">
<mat-icon>close</mat-icon>
</button>
</div>
</div>
</ng-template>
</div>
<!-- External Datasets -->
<div class="pt-2">
<div class="row">
<div class="col-12 pl-0 pr-0 pb-2 d-flex flex-row">
<h4 class="col-auto heading">1.6 {{'DATASET-EDITOR.FIELDS.EXTERNAL-DATASETS' | translate}}</h4>
<div class="col"></div>
<div class="col-auto d-flex align-items-center" *ngIf='!viewOnly'><button mat-raised-button (click)="addExternalDataset()">
{{'DATASET-EDITOR.FIELDS.CREATE'|translate}}
</button>
</div>
</div>
<div class="col-12">
<span class="hint">{{'DATASET-EDITOR.FIELDS.EXTERNAL-DATASETS-DESCRIPTION' | translate}}</span>
</div>
</div>
<app-external-item-listing class="col-12" *ngIf="formGroup.get('externalDatasets') && externalDatasetsTemplate && externalSourcesConfiguration" [options]="externalSourcesConfiguration.externalDatasets" placeholder="{{'DATASET-EDITOR.FIELDS.EXTERNAL-DATASETS' | translate}}" [parentTemplate]='externalDatasetsTemplate' [formArray]="formGroup.get('externalDatasets')" [autoCompleteConfiguration]="externalDatasetAutoCompleteConfiguration" (onItemChange)="externalDatasetsOnItemChange($event)">
</app-external-item-listing>
<ng-template #externalDatasetsTemplate let-suggestion let-i="index" let-callback="function">
<div class="col-12 row align-items-center">
<div class="col">
<p>
{{i+1}}) {{suggestion.get('name').value}}
</p>
</div>
<div class="col-auto" *ngIf="isInternal(suggestion)">
<mat-form-field>
<input matInput placeholder="{{'DATASET-REFERENCED-MODELS.EXTERNAL-DATASET.LABEL' | translate}}" type="text" name="name" [formControl]="suggestion.get('name')">
</mat-form-field>
</div>
<div class="col-auto" *ngIf="isInternal(suggestion)">
<mat-form-field>
<input matInput placeholder="{{'DATASET-REFERENCED-MODELS.EXTERNAL-DATASET.ABBREVIATION' | translate}}" type="text" name="abbreviation" [formControl]="suggestion.get('abbreviation')">
</mat-form-field>
</div>
<div class="col-auto">
<mat-form-field>
<input matInput placeholder="{{'DATASET-EDITOR.FIELDS.EXTERNAL-DATASET-INFO' | translate}}" type="text" name="info" [formControl]="suggestion.get('info')">
</mat-form-field>
</div>
<div class="col-auto">
<mat-form-field>
<mat-select placeholder="{{'DATASET-WIZARD.EDITOR.FIELDS.EXTERNAL-DATASET-TYPE' | translate}}" [formControl]="suggestion.get('type')" required>
<mat-option [value]="0">{{'TYPES.EXTERNAL-DATASET-TYPE.SOURCE' | translate}}</mat-option>
<mat-option [value]="1">{{'TYPES.EXTERNAL-DATASET-TYPE.OUTPUT' | translate}}</mat-option>
</mat-select>
<mat-error *ngIf="suggestion.get('type').hasError('required')">{{'GENERAL.VALIDATION.REQUIRED' | translate}}</mat-error>
</mat-form-field>
</div>
<div class="col-auto" *ngIf='!viewOnly && isInternal(suggestion)'>
<button mat-raised-button (click)="updateExternalDataset(suggestion)" type="button">
{{ 'DATASET-EDITOR.ACTIONS.UPDATE' | translate }}
</button>
</div>
<div class="col-auto">
<button mat-icon-button (click)="callback(i)" *ngIf='!viewOnly'>
<mat-icon>close</mat-icon>
</button>
</div>
</div>
</ng-template>
</div>
<!-- Registries -->
<div class="pt-2">
<div class="row">
<div class="col-12 pl-0 pr-0 pb-2 d-flex flex-row">
<h4 class="col-auto heading">1.7 {{'DATASET-EDITOR.FIELDS.REGISTRIES' | translate}}</h4>
<div class="col"></div>
<div class="col-auto d-flex align-items-center" *ngIf='!viewOnly'><button mat-raised-button (click)="addRegistry()">
{{'DATASET-EDITOR.FIELDS.CREATE'|translate}}
</button>
</div>
</div>
</div>
<app-external-item-listing class="col-12" *ngIf="formGroup.get('registries') && registriesTemplate && externalSourcesConfiguration" [options]="externalSourcesConfiguration.registries" placeholder="{{'DATASET-EDITOR.FIELDS.REGISTRIES' | translate}}" [parentTemplate]='registriesTemplate' [formArray]="formGroup.get('registries')" [autoCompleteConfiguration]="registriesAutoCompleteConfiguration" (onItemChange)="registriesOnItemChange($event)">
</app-external-item-listing>
<ng-template #registriesTemplate let-suggestion let-i="index" let-callback="function">
<div class="col-12 row align-items-center">
<div class="col">
<p>
{{i+1}}) {{suggestion.get('label').value}}
</p>
</div>
<div class="col-auto" *ngIf="isInternal(suggestion)">
<mat-form-field>
<input matInput placeholder="{{'DATASET-REFERENCED-MODELS.REGISTRY.LABEL' | translate}}" type="text" name="label" [formControl]="suggestion.get('label')">
</mat-form-field>
</div>
<div class="col-auto" *ngIf="isInternal(suggestion)">
<mat-form-field>
<input matInput placeholder="{{'DATASET-REFERENCED-MODELS.REGISTRY.ABBREVIATION' | translate}}" type="text" name="abbreviation" [formControl]="suggestion.get('abbreviation')">
</mat-form-field>
</div>
<div class="col-auto" *ngIf="isInternal(suggestion)">
<mat-form-field>
<input matInput placeholder="{{'DATASET-REFERENCED-MODELS.REGISTRY.URI' | translate}}" type="text" name="uri" [formControl]="suggestion.get('uri')">
</mat-form-field>
</div>
<div class="col-auto" *ngIf='!viewOnly && isInternal(suggestion)'>
<button mat-raised-button (click)="updateRegistry(suggestion)" type="button">
{{ 'DATASET-EDITOR.ACTIONS.UPDATE' | translate }}
</button>
</div>
<div class="col-auto">
<button mat-icon-button (click)="callback(i)" *ngIf='!viewOnly'>
<mat-icon>close</mat-icon>
</button>
</div>
</div>
</ng-template>
</div>
<!-- Services -->
<div class="pt-2">
<div class="row">
<div class="col-12 pl-0 pr-0 pb-2 d-flex flex-row">
<h4 class="col-auto heading">1.8 {{'DATASET-EDITOR.FIELDS.SERVICES' | translate}}</h4>
<div class="col"></div>
<div class="col-auto d-flex align-items-center" *ngIf='!viewOnly'>
<button mat-raised-button (click)="addService()">
{{'DATASET-EDITOR.FIELDS.CREATE'|translate}}
</button>
</div>
</div>
</div>
<app-external-item-listing class="col-12" *ngIf="formGroup.get('services') && servicesTemplate && externalSourcesConfiguration" [options]="externalSourcesConfiguration.services" placeholder="{{'DATASET-EDITOR.FIELDS.SERVICES' | translate}}" [parentTemplate]='servicesTemplate' [formArray]="formGroup.get('services')" [autoCompleteConfiguration]="servicesAutoCompleteConfiguration" (onItemChange)="servicesOnItemChange($event)">
</app-external-item-listing>
<ng-template #servicesTemplate let-suggestion let-i="index" let-callback="function">
<div class="col-12 row align-items-center">
<div class="col">
<p>
{{i+1}}) {{suggestion.get('label').value}}
</p>
</div>
<div class="col-auto" *ngIf="isInternal(suggestion)">
<mat-form-field>
<input matInput placeholder="{{'DATASET-REFERENCED-MODELS.SERVICES.LABEL' | translate}}" type="text" name="label" [formControl]="suggestion.get('label')">
</mat-form-field>
</div>
<div class="col-auto" *ngIf="isInternal(suggestion)">
<mat-form-field>
<input matInput placeholder="{{'DATASET-REFERENCED-MODELS.SERVICES.ABBREVIATION' | translate}}" type="text" name="abbreviation" [formControl]="suggestion.get('abbreviation')">
</mat-form-field>
</div>
<div class="col-auto" *ngIf="isInternal(suggestion)">
<mat-form-field>
<input matInput placeholder="{{'DATASET-REFERENCED-MODELS.SERVICES.URI' | translate}}" type="text" name="uri" [formControl]="suggestion.get('uri')">
</mat-form-field>
</div>
<div class="col-auto" *ngIf='!viewOnly && isInternal(suggestion)'>
<button mat-raised-button (click)="updateRegistry(suggestion)" type="button">
{{ 'DATASET-EDITOR.ACTIONS.UPDATE' | translate }}
</button>
</div>
<div class="col-auto">
<button mat-icon-button (click)="callback(i)" *ngIf='!viewOnly'>
<mat-icon>close</mat-icon>
</button>
</div>
</div>
</ng-template>
</div>
</form>
<!-- <form *ngIf="formGroup" [formGroup]="formGroup" class="dataset-external-references-editor">
<mat-card class="col-12 external-item-card">
<div class="row">
<div class="col-12 row">
@ -220,10 +476,10 @@
<div class="col-12 row">
<h4 class="col-auto">{{'DATASET-EDITOR.FIELDS.TAGS' | translate}}</h4>
</div>
</div>
<!-- <app-external-item-listing *ngIf="formGroup.get('tags') && tagsTemplate && externalSourcesConfiguration" [options]="externalSourcesConfiguration.tags" placeholder="{{'DATASET-EDITOR.FIELDS.TAGS' | translate}}" [parentTemplate]='tagsTemplate' [formArray]="formGroup.get('tags')" [autoCompleteConfiguration]="tagsAutoCompleteConfiguration" (onItemChange)="tagsOnItemChange($event)">
</div> -->
<!-- <app-external-item-listing *ngIf="formGroup.get('tags') && tagsTemplate && externalSourcesConfiguration" [options]="externalSourcesConfiguration.tags" placeholder="{{'DATASET-EDITOR.FIELDS.TAGS' | translate}}" [parentTemplate]='tagsTemplate' [formArray]="formGroup.get('tags')" [autoCompleteConfiguration]="tagsAutoCompleteConfiguration" (onItemChange)="tagsOnItemChange($event)">
</app-external-item-listing> -->
<mat-form-field>
<!-- <mat-form-field>
<mat-chip-list #chipList [disabled]="viewOnly">
<mat-chip *ngFor="let tag of formGroup.get('tags').value"
[removable]="true" (removed)="removeTag(tag)">
@ -253,4 +509,4 @@
</div>
</ng-template>
</mat-card>
</form>
</form> -->

View File

@ -1,5 +1,35 @@
.dataset-external-references-editor {
.external-item-card {
margin-bottom: 1em;
}
.heading {
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;
}
.hint {
text-align: left;
font-weight: 400;
font-size: 16px;
letter-spacing: 0px;
color: #212121;
opacity: 0.81;
margin-bottom: 2.125rem;
}
.external-item-card {
margin-bottom: 1em;
}
}
::ng-deep .tags-form .mat-form-field-appearance-outline .mat-form-field-outline {
background: #fafafa !important;
}
::ng-deep .tags-form .mat-form-field-appearance-outline .mat-form-field-infix {
font-size: 1rem;
padding: 0.6em 0 1em 0 !important;
}

View File

@ -64,6 +64,13 @@ import { DatasetCriteriaDialogComponent } from './listing/criteria/dataset-crite
DatasetExternalServiceDialogEditorComponent,
DatasetUploadDialogue,
DatasetCriteriaDialogComponent
],
exports: [
DatasetExternalReferencesEditorComponent,
DatasetExternalDataRepositoryDialogEditorComponent,
DatasetExternalDatasetDialogEditorComponent,
DatasetExternalRegistryDialogEditorComponent,
DatasetExternalServiceDialogEditorComponent
]
})
export class DatasetModule { }

View File

@ -39,7 +39,9 @@ import { StartNewDmpDialogComponent } from './start-new-dmp-dialogue/start-new-d
import { MainInfoComponent } from './editor/main-info/main-info.component';
import { FundingInfoComponent } from './editor/funding-info/funding-info.component';
import { DatasetInfoComponent } from './editor/dataset-info/dataset-info.component';
import { DatasetEditorDetailsModule } from './editor/dataset-editor-details/dataset-editor-details.module';
import { DatasetEditorDetailsComponent } from './editor/dataset-editor-details/dataset-editor-details.component';
import { DatasetDescriptionFormModule } from '../misc/dataset-description-form/dataset-description-form.module';
@NgModule({
imports: [
@ -53,7 +55,9 @@ import { DatasetInfoComponent } from './editor/dataset-info/dataset-info.compone
DmpRoutingModule,
DmpOverviewModule,
FormValidationErrorsDialogModule,
MultipleChoiceDialogModule
MultipleChoiceDialogModule,
DatasetEditorDetailsModule,
DatasetDescriptionFormModule
],
declarations: [
DmpListingComponent,
@ -97,7 +101,8 @@ import { DatasetInfoComponent } from './editor/dataset-info/dataset-info.compone
DmpCriteriaDialogComponent,
AddOrganizationComponent,
AddCostComponent,
StartNewDmpDialogComponent
StartNewDmpDialogComponent,
DatasetEditorDetailsComponent
]
})
export class DmpModule { }

View File

@ -0,0 +1,93 @@
<form class="dataset-editor-details" *ngIf="formGroup" [formGroup]="formGroup">
<div class="col-12 intro">
{{'DATASET-EDITOR.TITLE.INTRO' | translate}}
</div>
<div class="col-12 card">
<!-- Title Field -->
<div class="row">
<div class="col-12">
<div class="heading">1.1 {{'DATASET-EDITOR.FIELDS.TITLE' | translate}}*</div>
<span class="hint">{{'DATASET-EDITOR.HINT.TITLE' | translate}}</span><a class="dmp-link" target="_blank" [routerLink]="['/overview/' + dmpId]">{{'DATASET-EDITOR.FIELDS.DMP' | translate}}</a><span class="hint">{{'DATASET-EDITOR.HINT.TITLE-REST' | translate}}</span>
<div class="title-form">
<mat-form-field appearance="outline">
<input matInput placeholder="{{'DATASET-EDITOR.FIELDS.TITLE' | translate}}" type="text" name="label" formControlName="label" required>
<mat-error *ngIf="formGroup.get('label').hasError('backendError')">
{{formGroup.get('label').getError('backendError').message}}</mat-error>
<mat-error *ngIf="formGroup.get('label').hasError('required')">
{{'GENERAL.VALIDATION.REQUIRED' | translate}}</mat-error>
</mat-form-field>
</div>
</div>
</div>
<!-- Description field -->
<div class="row">
<div class="col-12">
<div class="heading">1.2 {{'DATASET-EDITOR.FIELDS.DESCRIPTION' | translate}}</div>
<span class="hint">{{'DATASET-EDITOR.HINT.TITLE' | translate}}</span><a class="dmp-link" target="_blank" [routerLink]="['/overview/' + dmpId]">{{'DATASET-EDITOR.FIELDS.DMP' | translate}}</a><span class="hint">{{'DATASET-EDITOR.HINT.TITLE-REST' | translate}}</span>
<div class="description-form">
<mat-form-field appearance="outline">
<textarea rows="3" matInput class="description-area" placeholder="{{'DMP-EDITOR.PLACEHOLDER.DESCRIPTION' | translate}}" formControlName="description"></textarea>
<mat-error *ngIf="formGroup.get('description').hasError('backendError')">{{formGroup.get('description').getError('backendError').message}}</mat-error>
<mat-error *ngIf="formGroup.get('description').hasError('required')">{{'GENERAL.VALIDATION.REQUIRED' | translate}}</mat-error>
</mat-form-field>
</div>
</div>
</div>
<!-- Uri field -->
<div class="row">
<div class="col-12">
<div class="heading">1.3 {{'DATASET-EDITOR.FIELDS.EXTERNAL-LINK' | translate}}</div>
<span class="hint">{{'DATASET-EDITOR.HINT.TITLE' | translate}}</span><a class="dmp-link" target="_blank" [routerLink]="['/overview/' + dmpId]">{{'DATASET-EDITOR.FIELDS.DMP' | translate}}</a><span class="hint">{{'DATASET-EDITOR.HINT.TITLE-REST' | translate}}</span>
<div class="uri-form">
<mat-form-field appearance="outline">
<input matInput placeholder="{{'DATASET-EDITOR.PLACEHOLDER.EXTERNAL-LINK' | translate}}" type="text" name="uri" formControlName="uri">
<mat-error *ngIf="formGroup.get('uri').hasError('backendError')">{{formGroup.get('uri').getError('backendError').message}}</mat-error>
<mat-error *ngIf="formGroup.get('uri').hasError('required')">{{'GENERAL.VALIDATION.REQUIRED' | translate}}</mat-error>
</mat-form-field>
</div>
</div>
</div>
<app-dataset-external-references-editor-component [formGroup]="formGroup" [viewOnly]="viewOnly"></app-dataset-external-references-editor-component>
<app-dataset-description [form]="formGroup.get('datasetProfileDefinition')" [visibilityRules]="formGroup.get('datasetProfileDefinition').get('rules')" [datasetProfileId]="formGroup.get('profile').value">
</app-dataset-description>
<!-- Tags field -->
<!-- <div class="row">
<div class="col-12">
<div class="heading">1.4 {{'DATASET-EDITOR.FIELDS.TAGS' | translate}}</div>
<span class="hint">{{'DATASET-EDITOR.HINT.TITLE' | translate}}</span><a class="dmp-link" target="_blank" [routerLink]="['/overview/' + this.datasetWizardModel.dmp.id]">{{'DATASET-EDITOR.FIELDS.DMP' | translate}}</a><span class="hint">{{'DATASET-EDITOR.HINT.TITLE-REST' | translate}}</span>
<div class="tags-form">
<mat-form-field appearance="outline">
<mat-chip-list #chipList [disabled]="viewOnly">
<mat-chip *ngFor="let tag of formGroup.get('tags').value"
[removable]="true" (removed)="removeTag(tag)">
{{tag.name}}
<mat-icon matChipRemove *ngIf="!viewOnly">cancel</mat-icon>
</mat-chip>
<input matInput [disabled]="viewOnly" placeholder="{{'DATASET-EDITOR.FIELDS.TAGS' | translate}}"
[matChipInputFor]="chipList"
[matChipInputSeparatorKeyCodes]="separatorKeysCodes"
[matChipInputAddOnBlur]="true"
(matChipInputTokenEnd)="addTag($event)">
</mat-chip-list>
</mat-form-field>
<ng-template #tagsTemplate let-suggestion let-i="index" let-callback="function">
<div class="col-12 row align-items-center">
<div class="col">
<p>
{{i+1}}) {{suggestion.get('name').value}}
</p>
</div>
<div class="col-auto">
<button mat-icon-button (click)="callback(i)" *ngIf='!viewOnly'>
<mat-icon>close</mat-icon>
</button>
</div>
</div>
</ng-template>
</div>
</div>
</div> -->
</div>
</form>

View File

@ -0,0 +1,108 @@
.dataset-editor-details {
// position: relative;
// left: 362px;
// width: calc(100% - 366px);
.intro {
text-align: left;
font-weight: 400;
letter-spacing: 0px;
color: #212121;
opacity: 1;
margin: 3rem 0rem 3rem 0rem;
}
.heading {
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;
}
.hint {
text-align: left;
font-weight: 400;
font-size: 16px;
letter-spacing: 0px;
color: #212121;
opacity: 0.81;
margin-bottom: 2.125rem;
}
.title-form,
.description-form {
text-align: left;
font-weight: 400;
font-size: 16px;
letter-spacing: 0.15px;
color: #7d7d7d;
opacity: 1;
margin-bottom: 1rem;
}
// textarea::placeholder {
// font-style: oblique;
// }
.input-btn {
border: none;
color: #aaaaaa;
background-color: #ffffff00;
cursor: pointer;
}
.input-btn :hover {
color: #00b29f !important;
}
.dmp-link {
color: #3fafac;
font-weight: 400;
font-size: 16px;
cursor: pointer;
}
.dmp-link:hover {
text-decoration: underline;
}
}
::ng-deep .title-form .mat-form-field-appearance-outline .mat-form-field-outline {
background: #fafafa !important;
}
::ng-deep .description-form .mat-form-field-appearance-outline .mat-form-field-outline {
background: #fafafa !important;
}
::ng-deep .uri-form .mat-form-field-appearance-outline .mat-form-field-outline {
background: #fafafa !important;
}
::ng-deep .tags-form .mat-form-field-appearance-outline .mat-form-field-outline {
background: #fafafa !important;
}
::ng-deep .title-form .mat-form-field-appearance-outline .mat-form-field-infix {
font-size: 1rem;
padding: 0.6em 0 1em 0 !important;
}
::ng-deep .description-form .mat-form-field-appearance-outline .mat-form-field-infix {
// font-size: 1rem;
padding: 0.6em 0 1em 0 !important;
}
::ng-deep .uri-form .mat-form-field-appearance-outline .mat-form-field-infix {
font-size: 1rem;
padding: 0.6em 0 1em 0 !important;
}
::ng-deep .tags-form .mat-form-field-appearance-outline .mat-form-field-infix {
font-size: 1rem;
padding: 0.6em 0 1em 0 !important;
}

View File

@ -0,0 +1,232 @@
import { BaseComponent } from '@common/base/base.component';
import { OnInit, Component, Input, Output, EventEmitter } from '@angular/core';
import { TranslateService } from '@ngx-translate/core';
import { ConfigurationService } from '@app/core/services/configuration/configuration.service';
import { ExternalSourcesService } from '@app/core/services/external-sources/external-sources.service';
import { MatDialog, MatSnackBar, MatChipInputEvent } from '@angular/material';
import { DatasetWizardService } from '@app/core/services/dataset-wizard/dataset-wizard.service';
import { ActivatedRoute, Router } from '@angular/router';
import { DmpService } from '@app/core/services/dmp/dmp.service';
import { ExternalSourcesConfigurationService } from '@app/core/services/external-sources/external-sources-configuration.service';
import { UiNotificationService, SnackBarNotificationLevel } from '@app/core/services/notification/ui-notification-service';
import { FormService } from '@common/forms/form-service';
import { LockService } from '@app/core/services/lock/lock.service';
import { AuthService } from '@app/core/services/auth/auth.service';
import { DatasetStatus } from '@app/core/common/enum/dataset-status';
import { FormGroup, FormControl, FormArray } from '@angular/forms';
import { DatasetDescriptionFormEditorModel } from '@app/ui/misc/dataset-description-form/dataset-description-form.model';
import { DatasetProfileModel } from '@app/core/model/dataset/dataset-profile';
import { LockModel } from '@app/core/model/lock/lock.model';
import { takeUntil, map, catchError } from 'rxjs/operators';
import { RequestItem } from '@app/core/query/request-item';
import { isNullOrUndefined } from 'util';
import { interval, Observable, of as observableOf } from 'rxjs';
import { Guid } from '@common/types/guid';
import { Location } from '@angular/common';
import { DatasetProfileCriteria } from '@app/core/query/dataset-profile/dataset-profile-criteria';
import { DmpListingModel } from '@app/core/model/dmp/dmp-listing';
import { DatasetWizardEditorModel, ExternalTagEditorModel } from '@app/ui/dataset/dataset-wizard/dataset-wizard-editor.model';
import { ENTER, COMMA } from '@angular/cdk/keycodes';
@Component({
selector: 'dataset-editor-details',
templateUrl: './dataset-editor-details.component.html',
styleUrls: ['./dataset-editor-details.component.scss']
})
export class DatasetEditorDetailsComponent extends BaseComponent implements OnInit {
viewOnly = false;
editMode = false;
// publicMode = false;
// DatasetStatus = DatasetStatus;
// dmpAutoCompleteConfiguration: SingleAutoCompleteConfiguration;
datasetWizardModel: DatasetWizardEditorModel;
// isNew = true;
// isCopy = false;
// formGroup: FormGroup = null;
datasetProfileDefinitionModel: DatasetDescriptionFormEditorModel;
availableProfiles: DatasetProfileModel[] = [];
// itemId: string;
// publicId: string;
// profileUpdateId: string;
// downloadDocumentId: string;
// isLinear = false;
lock: LockModel;
lockStatus: Boolean;
@Input() formGroup: FormGroup;
@Input() dmpId: string;
@Input() datasetId: string;
@Output() formChanged: EventEmitter<any> = new EventEmitter();
readonly separatorKeysCodes: number[] = [ENTER, COMMA];
constructor(
private datasetWizardService: DatasetWizardService,
private route: ActivatedRoute,
public snackBar: MatSnackBar,
public router: Router,
private language: TranslateService,
private configurationService: ConfigurationService,
private externalSourcesService: ExternalSourcesService,
private dialog: MatDialog,
public dmpService: DmpService,
public externalSourcesConfigurationService: ExternalSourcesConfigurationService,
private uiNotificationService: UiNotificationService,
private formService: FormService,
private lockService: LockService,
private location: Location,
private authService: AuthService
) {
super();
}
ngOnInit() {
if (this.datasetId) {
this.datasetWizardService.getSingle(this.datasetId)
.pipe(takeUntil(this._destroyed))
.subscribe(data => {
this.lockService.checkLockStatus(data.id).pipe(takeUntil(this._destroyed)).subscribe(lockStatus => {
this.lockStatus = lockStatus;
this.datasetWizardModel = new DatasetWizardEditorModel().fromModel(data);
this.needsUpdate();
this.formGroup = this.datasetWizardModel.buildForm();
this.editMode = this.datasetWizardModel.status === DatasetStatus.Draft;
if (this.datasetWizardModel.status === DatasetStatus.Finalized || lockStatus) {
this.formGroup.disable();
this.viewOnly = true;
}
if (!lockStatus && !isNullOrUndefined(this.authService.current())) {
this.lock = new LockModel(data.id, this.authService.current());
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 Dataset edit like DMP.
this.loadDatasetProfiles();
this.registerFormListeners();
// this.availableProfiles = this.datasetWizardModel.dmp.profiles;
this.onChanges();
this.formChanged.emit(this.formGroup);
})
},
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(['/datasets/']);
return observableOf(null);
});
}
}
registerFormListeners() {
this.formGroup.get('dmp').valueChanges
.pipe(takeUntil(this._destroyed))
.subscribe(x => {
this.dmpValueChanged(x);
});
this.formGroup.get('profile').valueChanges
.pipe(takeUntil(this._destroyed))
.subscribe(x => {
this.datasetProfileValueChanged(x);
});
}
dmpValueChanged(dmp: DmpListingModel) {
if (dmp) {
this.formGroup.get('profile').enable();
this.loadDatasetProfiles();
}
else {
this.availableProfiles = [];
this.formGroup.get('profile').reset();
this.formGroup.get('profile').disable();
this.formGroup.removeControl('datasetProfileDefinition');
}
}
datasetProfileValueChanged(profiledId: string) {
if (profiledId && profiledId.length > 0) {
this.formGroup.removeControl('datasetProfileDefinition');
this.getDefinition();
}
}
onChanges(): void {
this.formGroup.valueChanges
.pipe(takeUntil(this._destroyed))
.subscribe(val => {
this.formChanged.emit(val);
});
}
getDefinition() {
// if (this.formGroup.invalid) { setTimeout(() => this.stepper.selectedIndex = 0); return; }
this.datasetWizardService.getDefinition(this.formGroup.get('profile').value)
.pipe(takeUntil(this._destroyed))
.subscribe(item => {
this.datasetWizardModel.datasetProfileDefinition = new DatasetDescriptionFormEditorModel().fromModel(item);
this.datasetProfileDefinitionModel = this.datasetWizardModel.datasetProfileDefinition;
this.formGroup.addControl('datasetProfileDefinition', this.datasetProfileDefinitionModel.buildForm());
});
}
loadDatasetProfiles() {
const datasetProfileRequestItem: RequestItem<DatasetProfileCriteria> = 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;
});
}
}
needsUpdate() {
if (this.datasetWizardModel.isProfileLatestVersion || (this.datasetWizardModel.status === DatasetStatus.Finalized)
|| (this.datasetWizardModel.isProfileLatestVersion == undefined && this.datasetWizardModel.status == undefined)) {
return false;
}
else {
return true;
}
}
private pumpLock() {
this.lock.touchedAt = new Date();
this.lockService.createOrUpdate(this.lock).pipe(takeUntil(this._destroyed)).subscribe(async result => {
if (!isNullOrUndefined(result)) {
this.lock.id = Guid.parse(result);
} else {
this.location.back();
}
});
}
removeTag(tag: any) {
(<FormArray>this.formGroup.get('tags')).removeAt(((<FormArray>this.formGroup.get('tags')).value as any[]).indexOf(tag));
}
addTag(ev: MatChipInputEvent) {
if (ev.value !== '' && isNullOrUndefined(((<FormArray>this.formGroup.get('tags')).value as ExternalTagEditorModel[]).find(tag => tag.name === ev.value))) {
(<FormArray>this.formGroup.get('tags')).push(new ExternalTagEditorModel('', ev.value).buildForm());
}
ev.input.value = '';
}
}

View File

@ -0,0 +1,54 @@
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 { ExportMethodDialogModule } from '@app/library/export-method-dialog/export-method-dialog.module';
import { UrlListingModule } from '@app/library/url-listing/url-listing.module';
import { DmpRoutingModule } from '@app/ui/dmp/dmp.routing';
import { DmpOverviewModule } from '@app/ui/dmp/overview/dmp-overview.module';
import { CommonFormsModule } from '@common/forms/common-forms.module';
import { FormValidationErrorsDialogModule } from '@common/forms/form-validation-errors-dialog/form-validation-errors-dialog.module';
import { CommonUiModule } from '@common/ui/common-ui.module';
import { MultipleChoiceDialogModule } from '@common/modules/multiple-choice-dialog/multiple-choice-dialog.module';
import { DatasetEditorDetailsComponent } from './dataset-editor-details.component';
import { DatasetExternalReferencesEditorComponent } from '@app/ui/dataset/dataset-wizard/external-references/dataset-external-references-editor.component';
import { DatasetModule } from '@app/ui/dataset/dataset.module';
import { DatasetExternalServiceDialogEditorComponent } from '@app/ui/dataset/dataset-wizard/external-references/editors/service/dataset-external-service-dialog-editor.component';
import { DatasetExternalRegistryDialogEditorComponent } from '@app/ui/dataset/dataset-wizard/external-references/editors/registry/dataset-external-registry-dialog-editor.component';
import { DatasetExternalDatasetDialogEditorComponent } from '@app/ui/dataset/dataset-wizard/external-references/editors/external-dataset/dataset-external-dataset-dialog-editor.component';
import { DatasetExternalDataRepositoryDialogEditorComponent } from '@app/ui/dataset/dataset-wizard/external-references/editors/data-repository/dataset-external-data-repository-dialog-editor.component';
import { DatasetDescriptionFormModule } from '@app/ui/misc/dataset-description-form/dataset-description-form.module';
@NgModule({
imports: [
CommonUiModule,
CommonFormsModule,
UrlListingModule,
ConfirmationDialogModule,
ExportMethodDialogModule,
FormattingModule,
AutoCompleteModule,
DmpRoutingModule,
DmpOverviewModule,
FormValidationErrorsDialogModule,
MultipleChoiceDialogModule,
DatasetModule,
DatasetDescriptionFormModule
],
declarations: [
DatasetEditorDetailsComponent
],
entryComponents: [
DatasetEditorDetailsComponent,
DatasetExternalReferencesEditorComponent,
DatasetExternalDataRepositoryDialogEditorComponent,
DatasetExternalDatasetDialogEditorComponent,
DatasetExternalRegistryDialogEditorComponent,
DatasetExternalServiceDialogEditorComponent
],
exports: [
DatasetEditorDetailsComponent
]
})
export class DatasetEditorDetailsModule { }

View File

@ -1,16 +1,17 @@
<div class="main-content">
<div *ngIf="dmp" class="container-fluid">
<form *ngIf="formGroup" [formGroup]="formGroup" (ngSubmit)="formSubmit()">
<div class="fixed-editor-header">
<!-- DMP Header -->
<div [hidden]="this.step >= 3" class="fixed-editor-header">
<div class="card editor-header">
<div class="col">
<div class="row">
<div class="col-auto">
<div class="col-auto info">
<div class="title">{{'DMP-EDITOR.TITLE.EDIT-DMP' | translate}}</div>
<div class="subtitle">{{ formGroup.get('label').value }} <span *ngIf="isDirty()" class="changes">({{'DMP-EDITOR.CHANGES' | translate}})</span></div>
</div>
<div class="ml-auto d-flex flex-row">
<button *ngIf="isDirty()" type="button" class="discard-btn mr-3" (click)="discardChanges()">
<button *ngIf="isDirty()" type="button" mat-raised-button class="discard-btn mr-3" (click)="discardChanges()">
{{'DMP-EDITOR.ACTIONS.DISCARD' | translate}}
</button>
<div *ngIf="isNew" mat-raised-button type="button" (click)="addDataset()" class="save-btn">
@ -21,11 +22,41 @@
{{'DMP-EDITOR.ACTIONS.SAVE' | translate}}
</button>
</div>
<!-- <div *ngIf="!isNew && formGroup.enabled && !lockStatus">
<div *ngIf="!isFinalized" mat-raised-button type="submit" mat-raised-button type="button" (click)="addDataset()" class="save-btn">
<div>{{'DMP-EDITOR.ACTIONS.SAVE' | translate}}</div>
</div>
</div>
</div>
</div>
</div>
<!-- Dataset Header -->
<div *ngFor="let dataset of formGroup.get('datasets')['controls']; let i = index" [hidden]="this.step !== i + 3" class="fixed-editor-header">
<div class="card dataset-editor-header">
<div class="col">
<div class="row">
<div class="col info">
<div class="dataset-title">{{'DMP-EDITOR.TITLE.EDIT-DATASET' | translate}}</div>
<div class="dataset-subtitle">{{ dataset.get('label').value }} <span *ngIf="isDirty()" class="dataset-changes">({{'DMP-EDITOR.CHANGES' | translate}})</span></div>
<div class="d-flex flex-direction-row pt-2">
<div class="col-auto dataset-part-of">{{'DATASET-LISTING.TOOLTIP.PART-OF' | translate}}
<div class="col-auto dmp-label ml-3">{{'DATASET-LISTING.TOOLTIP.DMP' | translate}}</div>
</div>
</div> -->
<div class="col-auto dmp-title">{{'DATASET-LISTING.TOOLTIP.DMP-FOR' | translate}}: {{ formGroup.get('label').value }}</div>
<div class="col d-flex align-items-center">
<a [routerLink]="['/overview/' + formGroup.get('id').value]" target="_blank" class="pointer"><span class="material-icons">open_in_new</span></a>
</div>
</div>
</div>
<div class="row">
<div class="col-auto d-flex align-items-center p-0">
<button *ngIf="isDirty()" type="button" mat-raised-button class="dataset-discard-btn" (click)="discardChanges()">
{{'DMP-EDITOR.ACTIONS.DISCARD' | translate}}
</button>
</div>
<div class="col-auto d-flex align-items-center">
<button *ngIf="(dataset.get('status').value == 0 || isNew) && !lockStatus" mat-raised-button class="dataset-save-btn" type="submit">{{ 'DATASET-WIZARD.ACTIONS.SAVE' | translate }}</button>
<!-- <div *ngIf="!isNew && formGroup.enabled && !lockStatus">
<button *ngIf="!isFinalized" mat-raised-button type="submit" class="dataset-save-btn">{{'DMP-EDITOR.ACTIONS.SAVE' | translate}}</button>
</div> -->
</div>
</div>
</div>
</div>
@ -39,6 +70,12 @@
<li (click)="changeStep(0)" [ngClass]="{'active': this.step === 0}">{{'DMP-EDITOR.STEPPER.MAIN-INFO' | translate}} (4)</li>
<li (click)="changeStep(1)" [ngClass]="{'active': this.step === 1}">{{'DMP-EDITOR.STEPPER.FUNDING-INFO' | translate}} (3)</li>
<li (click)="changeStep(2)" [ngClass]="{'active': this.step === 2}">{{'DMP-EDITOR.STEPPER.DATASET-INFO' | translate}}</li>
<li *ngFor="let dataset of formGroup.get('datasets')['controls']; let i = index" (click)="changeStep(i + 3)" [ngClass]="{'active-dataset': this.step === i + 3}">
<div>{{'DMP-EDITOR.STEPPER.DATASET' | translate}}</div>
<ul class="dataset-list">
<li [ngClass]="{'active': this.step === i + 3}">{{ dataset.get('label').value }} (8)</li>
</ul>
</li>
</ol>
</div>
<div class="stepper-actions">
@ -46,7 +83,7 @@
<span class="material-icons">chevron_left</span>
<div>{{'DMP-EDITOR.STEPPER.PREVIOUS' | translate}}</div>
</div>
<div mat-raised-button type="button" class="col-auto next stepper-btn ml-auto" [ngClass]="{'next-disabled': this.step === this.maxStep}" (click)="nextStep()">
<div mat-raised-button type="button" class="col-auto stepper-btn ml-auto" [ngClass]="{ 'next-disabled': this.step === this.maxStep, 'next': this.step < 3, 'dataset-next': this.step >= 3 }" (click)="nextStep()">
<span class="material-icons">chevron_right</span>
<div>{{'DMP-EDITOR.STEPPER.NEXT' | translate}}</div>
</div>
@ -56,6 +93,9 @@
<main-info [hidden]="this.step !== 0" [formGroup]="formGroup" [isUserOwner]="isUserOwner" (onFormChanged)="formChanged()"></main-info>
<funding-info [hidden]="this.step !== 1" [formGroup]="formGroup" [grantformGroup]="formGroup.get('grant')" [projectFormGroup]="formGroup.get('project')" [funderFormGroup]="formGroup.get('funder')" [isFinalized]="isFinalized || lockStatus" [isNew]="isNew" [isUserOwner]="isUserOwner" (onFormChanged)="formChanged()"></funding-info>
<dataset-info [hidden]="this.step !== 2" [formGroup]="formGroup" [dmp]="dmp" [isPublic]="isPublic" [isFinalized]="isFinalized || lockStatus" [isUserOwner]="isUserOwner" (onFormChanged)="formChanged()"></dataset-info>
<div *ngFor="let dataset of formGroup.get('datasets')['controls']; let i = index" [hidden]="this.step !== i + 3">
<dataset-editor-details [formGroup]="dataset" [dmpId]="formGroup.get('id').value" (formChanged)="datasetFormChanged($event)"></dataset-editor-details>
</div>
</div>
</div>
</form>

View File

@ -12,6 +12,14 @@ form {
height: calc(100vh - 124px);
}
a {
color: #000000;
}
a:hover {
color: #00b29f;
}
.main-content {
height: 100vh !important;
}
@ -53,6 +61,31 @@ form {
margin: 30px 0px 0px 0px;
border-radius: 4px;
opacity: 1;
.info {
flex: 2;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
}
.dataset-editor-header {
height: 113px;
background: var(--unnamed-color-129d99) 0% 0% no-repeat padding-box;
background: #f7dd72 0% 0% no-repeat padding-box;
box-shadow: 0px 3px 6px #00000029;
padding: 0.6rem;
margin: 30px 0px 0px 0px;
border-radius: 4px;
opacity: 1;
.info {
flex: 2;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
}
.editor-content {
@ -65,7 +98,7 @@ form {
left: 362px;
width: calc(100% - 366px);
overflow-y: auto;
height: calc(100vh - 172px);
height: calc(100vh - 218px);
}
}
@ -77,12 +110,36 @@ form {
opacity: 0.75;
}
.dataset-title {
text-align: left;
letter-spacing: 0px;
color: #212121;
opacity: 0.9;
font-size: 14px;
font-weight: 400;
}
.subtitle {
text-align: left;
color: #ffffff;
font-weight: 700;
font-size: 16px;
opacity: 1;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
.dataset-subtitle {
text-align: left;
letter-spacing: 0px;
color: #212121;
font-weight: 700;
font-size: 16px;
opacity: 0.9;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
.discard-btn {
@ -113,17 +170,62 @@ form {
cursor: pointer;
}
.dataset-discard-btn {
border: 1px solid #212121;
border-radius: 30px;
opacity: 1;
background-color: transparent;
font-weight: 700;
width: 110px;
height: 40px;
display: flex;
justify-content: center;
align-items: center;
cursor: pointer;
}
.dataset-save-btn {
background: #ffffff 0% 0% no-repeat padding-box;
border-radius: 30px;
opacity: 1;
width: 110px;
height: 40px;
display: flex;
justify-content: center;
align-items: center;
cursor: pointer;
}
.dataset-part-of {
display: flex;
flex-direction: row;
text-align: left;
font-weight: 400;
font-family: "Roboto", sans-serif;
font-size: 0.875rem;
align-items: center;
letter-spacing: 0px;
color: #3d3d3d;
padding: 0;
}
.changes {
font-weight: 400;
color: #ffffff;
}
.dataset-changes {
font-weight: 400;
color: #000000;
}
.stepper {
position: fixed;
// height: 100%;
display: flex;
flex-direction: column;
height: calc(100vh - 205px);
height: calc(100vh - 240px);
overflow-y: auto;
}
.stepper-title {
@ -145,6 +247,7 @@ form {
padding: 0.3rem 0.1rem;
opacity: 0.6;
cursor: pointer;
max-width: 290px;
}
.stepper-list .active {
@ -153,6 +256,24 @@ form {
opacity: 1;
}
.stepper-list .active-dataset {
color: #212121;
font-weight: 700;
opacity: 1;
div {
width: 73px;
height: 27px;
background-color: #f7dd72;
color: #5d5d5d;
border-radius: 4px;
font-weight: 400;
font-size: 14px;
justify-content: center;
display: flex;
align-items: center;
}
}
.stepper-options {
// flex-grow: 1;
}
@ -161,6 +282,7 @@ form {
display: flex;
padding-left: 1rem;
margin-top: auto;
margin-bottom: 0.5rem;
// margin-top: 5rem;
// flex-grow: 8;
}
@ -193,6 +315,14 @@ form {
cursor: pointer;
}
.dataset-next {
background: #f7dd72 0% 0% no-repeat padding-box;
color: #212121;
box-shadow: 0px 3px 6px #1e202029;
font-weight: 700;
cursor: pointer;
}
.previous-disabled {
border: 1px solid #b5b5b5;
color: #b5b5b5;
@ -206,6 +336,37 @@ form {
cursor: auto !important;
}
.dataset-list {
list-style-type: none;
padding-left: 0px;
}
.dmp-label {
width: 67px;
height: 37px;
background: #129d99 0% 0% no-repeat padding-box;
color: white;
border-radius: 4px;
opacity: 1;
display: flex;
align-items: center;
justify-content: center;
}
.dmp-title {
text-align: left;
font-weight: 500;
font-family: "Roboto", sans-serif;
font-size: 1rem;
opacity: 0.81;
padding-top: 0.75rem;
padding-bottom: 0.55rem;
color: #212121;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
::ng-deep .mat-tab-labels {
justify-content: space-between;
}

View File

@ -72,7 +72,7 @@ export class DmpEditorComponent extends BaseComponent implements OnInit, IBreadC
lock: LockModel;
lockStatus: Boolean;
step: number = 0;
maxStep: number = 2;
maxStep: number = 3;
constructor(
private dmpProfileService: DmpProfileService,
@ -139,8 +139,8 @@ export class DmpEditorComponent extends BaseComponent implements OnInit, IBreadC
this.dmp.extraProperties = new ExtraPropertiesFormModel();
this.dmp.fromModel(data);
this.formGroup = this.dmp.buildForm();
this.formGroupRawValue = JSON.parse(JSON.stringify(this.formGroup.getRawValue()));
this.maxStep = this.formGroup.get('datasets') ? this.maxStep + this.formGroup.get('datasets').value.length - 1 : this.maxStep;
this.setIsUserOwner();
if (!this.isUserOwner) {
@ -201,6 +201,7 @@ export class DmpEditorComponent extends BaseComponent implements OnInit, IBreadC
this.formGroup = this.dmp.buildForm();
this.formGroupRawValue = JSON.parse(JSON.stringify(this.formGroup.getRawValue()));
this.maxStep = this.formGroup.get('datasets') ? this.maxStep + this.formGroup.get('datasets').value.length - 1 : this.maxStep;
//this.registerFormEventsForDmpProfile(this.dmp.definition);
this.formGroup.disable();
@ -240,6 +241,7 @@ export class DmpEditorComponent extends BaseComponent implements OnInit, IBreadC
this.formGroup = this.dmp.buildForm();
this.formGroupRawValue = JSON.parse(JSON.stringify(this.formGroup.getRawValue()));
this.maxStep = this.formGroup.get('datasets') ? this.maxStep + this.formGroup.get('datasets').value.length - 1 : this.maxStep;
this.registerFormEventsForNewItem();
if (this.isAuthenticated) {
@ -291,6 +293,11 @@ export class DmpEditorComponent extends BaseComponent implements OnInit, IBreadC
this.hasChanges = true;
}
datasetFormChanged(formGroup: FormGroup) {
// this.datasetFormGroup = formGroup;
// console.log(this.datasetFormGroup);
}
isAuthenticated() {
return this.authService.current() != null;
}
@ -360,7 +367,7 @@ export class DmpEditorComponent extends BaseComponent implements OnInit, IBreadC
}
onSubmit(showAddDatasetDialog?: boolean): void {
this.dmpService.createDmp(this.formGroup.getRawValue())
this.dmpService.createDmpWithDatasets(this.formGroup.getRawValue())
.pipe(takeUntil(this._destroyed))
.subscribe(
complete => {
@ -373,7 +380,21 @@ export class DmpEditorComponent extends BaseComponent implements OnInit, IBreadC
this.formGroup.get('status').setValue(DmpStatus.Draft);
this.onCallbackError(error);
}
);
)
// this.dmpService.createDmp(this.formGroup.getRawValue())
// .pipe(takeUntil(this._destroyed))
// .subscribe(
// complete => {
// if (showAddDatasetDialog) {
// this.addDatasetOpenDialog(complete);
// }
// else { this.onCallbackSuccess(complete) }
// },
// error => {
// this.formGroup.get('status').setValue(DmpStatus.Draft);
// this.onCallbackError(error);
// }
// );
}
@ -625,9 +646,7 @@ export class DmpEditorComponent extends BaseComponent implements OnInit, IBreadC
}
public discardChanges() {
// this.formGroup.reset();
this.formGroup.patchValue(JSON.parse(JSON.stringify(this.formGroupRawValue)));
this.hasChanges = false;
}

View File

@ -22,6 +22,9 @@ import { ValidationErrorModel } from '@common/forms/validation/error-model/valid
import { ValidationContext } from '@common/forms/validation/validation-context';
import { ExtraPropertiesFormModel } from './general-tab/extra-properties-form.model';
import { isNullOrUndefined } from 'util';
import { DatasetWizardEditorModel } from '@app/ui/dataset/dataset-wizard/dataset-wizard-editor.model';
import { DatasetsAutoCompleteFieldDataEditorModel } from '@app/ui/admin/dataset-profile/admin/field-data/datasets-autocomplete-field-data-editor-mode';
import { DatasetWizardModel } from '@app/core/model/dataset/dataset-wizard';
export class DmpEditorModel {
public id: string;
@ -39,7 +42,8 @@ export class DmpEditorModel {
public organisations: OrganizationModel[] = [];
public researchers: ResearcherModel[] = [];
public profiles: DmpProfile[] = [];
public datasets: DatasetModel[] = [];
public datasets: DatasetWizardEditorModel[] = [];
// public datasets: DatasetModel[] = [];
public datasetsToBeFinalized: string[] = [];
public associatedUsers: UserModel[] = [];
public users: UserInfoListingModel[] = [];
@ -64,7 +68,7 @@ export class DmpEditorModel {
this.organisations = item.organisations;
this.researchers = item.researchers;
this.profiles = item.profiles;
this.datasets = item.datasets;
if (item.datasets) { item.datasets.map(x => this.datasets.push(new DatasetWizardEditorModel().fromModel(x))); }
this.datasetsToBeFinalized = item.datasetsToBeFinalized;
this.associatedUsers = item.associatedUsers;
this.users = item.users;
@ -95,7 +99,7 @@ export class DmpEditorModel {
organisations: [{ value: this.organisations, disabled: disabled }, context.getValidation('organisations').validators],
researchers: [{ value: this.researchers, disabled: disabled }, context.getValidation('researchers').validators],
profiles: [{ value: this.profiles, disabled: disabled }, context.getValidation('profiles').validators],
datasets: [{ value: this.datasets, disabled: disabled }, context.getValidation('datasets').validators],
// datasets: [{ value: this.datasets, disabled: disabled }, context.getValidation('datasets').validators],
datasetsToBeFinalized: [{ value: this.datasetsToBeFinalized, disabled: disabled }, context.getValidation('datasetsToBeFinalized').validators],
associatedUsers: [{ value: this.associatedUsers, disabled: disabled }, context.getValidation('associatedUsers').validators],
users: [{ value: this.users, disabled: disabled }, context.getValidation('users').validators],
@ -103,6 +107,10 @@ export class DmpEditorModel {
extraProperties: this.extraProperties.buildForm(),
});
const datasets = new Array<FormGroup>();
if(this.datasets) { this.datasets.forEach(item => datasets.push(item.buildForm())); }
formGroup.addControl('datasets', new FormBuilder().array(datasets));
const dynamicFields = new Array<FormGroup>();
if (this.dynamicFields) { this.dynamicFields.forEach(item => dynamicFields.push(item.buildForm())); }
formGroup.addControl('dynamicFields', new FormBuilder().array(dynamicFields));

View File

@ -98,8 +98,10 @@
</div>
<mat-form-field *ngSwitchCase="datasetProfileFieldViewStyleEnum.TextArea" class="col-12">
<textarea matInput class="text-area" [formControl]="form.get('value')" matTextareaAutosize matAutosizeMinRows="2" matAutosizeMaxRows="10" [required]="form.get('validationRequired').value"
<textarea matInput class="text-area" [formControl]="form.get('value')" matTextareaAutosize matAutosizeMinRows="1" matAutosizeMaxRows="15" [required]="form.get('validationRequired').value"
placeholder="{{ form.get('data').value.label | translate }}"></textarea>
<!-- <textarea matInput class="text-area" [formControl]="form.get('value')" matTextareaAutosize matAutosizeMinRows="2" matAutosizeMaxRows="10" [required]="form.get('validationRequired').value"
placeholder="{{ form.get('data').value.label | translate }}"></textarea> -->
<button mat-icon-button *ngIf="!form.get('value').disabled && form.get('value').value" matSuffix aria-label="Clear" (click)="this.form.patchValue({'value': ''})">
<mat-icon>close</mat-icon>
</button>

View File

@ -1,6 +1,7 @@
.dynamic-form-section {
.expansion-panel {
background-color: #eeeeee54;
// background-color: #eeeeee54;
background-color: white;
margin-bottom: 1em;
}
.addOneFieldButton {

View File

@ -1,16 +1,20 @@
@media (max-width: 768px) {
.dynamic-form-editor {
.form-container {
padding: 0px;
}
}
.dynamic-form-editor {
.form-container {
padding: 0px;
}
}
}
.form-container {
}
.dynamic-form-editor {
mat-vertical-stepper {
background-color: #ffffff;
}
mat-vertical-stepper {
background-color: #ffffff;
}
}
.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: #129D99 !important;
}

View File

@ -11,6 +11,7 @@ import { CommonFormsModule } from '@common/forms/common-forms.module';
import { CommonUiModule } from '@common/ui/common-ui.module';
import { FormCompositeTitleComponent } from './components/form-composite-title/form-composite-title.component';
import { ExternalSourcesModule } from '../external-sources/external-sources.module';
import { DatasetDescriptionComponent } from './dataset-description.component';
@NgModule({
imports: [
@ -21,6 +22,7 @@ import { ExternalSourcesModule } from '../external-sources/external-sources.modu
],
declarations: [
DatasetDescriptionFormComponent,
DatasetDescriptionComponent,
FormProgressIndicationComponent,
FormSectionComponent,
FormCompositeFieldComponent,
@ -28,7 +30,8 @@ import { ExternalSourcesModule } from '../external-sources/external-sources.modu
FormCompositeTitleComponent
],
exports: [
DatasetDescriptionFormComponent
DatasetDescriptionFormComponent,
DatasetDescriptionComponent
],
providers: [
VisibilityRulesService,

View File

@ -0,0 +1,22 @@
<form *ngIf="form" novalidate [formGroup]="form" class="col-12 p-0 form-container">
<!-- <app-form-progress-indication class="col-12" *ngIf="form" [formGroup]="form"></app-form-progress-indication> -->
<div class="row">
<div class="dynamic-form-editor p-0 col-md-12">
<div id="form-container">
<mat-vertical-stepper #stepper [linear]="false">
<div *ngFor="let pageFormGroup of form.get('pages')['controls']; let z = index;">
<div *ngFor="let sectionFormGroup of pageFormGroup.get('sections')['controls']; let i = index;">
<mat-step [stepControl]="sectionFormGroup">
<ng-template matStepLabel><span class="toc-page-header" [id]="'page_' + z">{{pageFormGroup.get('title').value}}</span></ng-template>
<!-- <div *ngIf="stepper.selectedIndex == z" class="row"> -->
<div class="row">
<app-form-section class="col-12" [form]="sectionFormGroup" [path]="z+1" [pathName]="'pages.'+z+'.sections.'+i" [datasetProfileId]="datasetProfileId" [linkToScroll]="linkToScroll"></app-form-section>
</div>
</mat-step>
</div>
</div>
</mat-vertical-stepper>
</div>
</div>
</div>
</form>

View File

@ -0,0 +1,30 @@
@media (max-width: 768px) {
.dynamic-form-editor {
.form-container {
padding: 0px;
}
}
}
.form-container {
}
.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(.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: #129D99 !important;
}

View File

@ -0,0 +1,48 @@
import { AfterViewInit, Component, Input, OnChanges, OnInit, SimpleChanges, ViewChild } from '@angular/core';
import { FormGroup } from '@angular/forms';
import { MatHorizontalStepper } from '@angular/material/stepper';
import { Rule } from '@app/core/model/dataset-profile-definition/rule';
import { LinkToScroll } 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 { BaseComponent } from '@common/base/base.component';
@Component({
selector: 'app-dataset-description',
templateUrl: './dataset-description.component.html',
styleUrls: ['./dataset-description.component.scss']
})
export class DatasetDescriptionComponent extends BaseComponent implements OnInit, AfterViewInit, OnChanges {
@ViewChild('stepper', { static: false }) stepper: MatHorizontalStepper;
@Input() path: string;
@Input() form: FormGroup;
@Input() visibilityRules: Rule[] = [];
@Input() datasetProfileId: String;
@Input() linkToScroll: LinkToScroll;
constructor(
private visibilityRulesService: VisibilityRulesService,
) {
super();
}
ngOnInit() {
this.visibilityRulesService.buildVisibilityRules(this.visibilityRules, this.form);
}
ngOnChanges(changes: SimpleChanges) {
// 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() {
}
}

View File

@ -1,16 +1,20 @@
<div class="row">
<mat-form-field class="col-md-6">
<mat-select placeholder="{{'TYPES.EXTERNAL-DATASET-TYPE.SOURCES' | translate}}" [(ngModel)]="choice" (selectionChange)="selectionChange($event)" [disabled]="formArray.disabled">
<mat-option *ngFor="let option of options" [value]="option.key">
{{ option.label }}
</mat-option>
</mat-select>
</mat-form-field>
<mat-form-field class="col-md-6">
<app-single-auto-complete [placeholder]="placeholder" [formControl]="formControl" [configuration]="autoCompleteConfiguration">
</app-single-auto-complete>
<mat-hint>{{ 'DATASET-WIZARD.SECOND-STEP.EXTERNAL-HINT' | translate }}</mat-hint>
</mat-form-field>
<div class="external-item col">
<mat-form-field appearance="outline">
<mat-select placeholder="{{'TYPES.EXTERNAL-DATASET-TYPE.SELECT' | translate}} {{placeholder}}" [(ngModel)]="choice" (selectionChange)="selectionChange($event)" [disabled]="formArray.disabled">
<mat-option *ngFor="let option of options" [value]="option.key">
{{ option.label }}
</mat-option>
</mat-select>
</mat-form-field>
</div>
<div class="external-item col" *ngIf="formControl.enabled">
<mat-form-field appearance="outline">
<app-single-auto-complete [placeholder]="placeholder" [formControl]="formControl" [configuration]="autoCompleteConfiguration">
</app-single-auto-complete>
<mat-hint>{{ 'DATASET-WIZARD.SECOND-STEP.EXTERNAL-HINT' | translate }}</mat-hint>
</mat-form-field>
</div>
<div class="col-12" *ngIf="formArray">
<div class="row" *ngFor="let suggestion of formArray['controls']; let i = index">
<ng-container *ngTemplateOutlet="parentTemplate; context: { $implicit: suggestion, index: i,function: this.deleteItem.bind(this) }">

View File

@ -0,0 +1,8 @@
::ng-deep .external-item .mat-form-field-appearance-outline .mat-form-field-outline {
background: #fafafa !important;
}
::ng-deep .external-item .mat-form-field-appearance-outline .mat-form-field-infix {
font-size: 1rem;
padding: 0.6em 0 1em 0 !important;
}

View File

@ -170,3 +170,14 @@
display: flex;
flex-grow: 1;
}
// ::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(.75);
// width: 133.33333%;
// }
// ::ng-deep .mat-form-field-appearance-outline .mat-form-field-outline {background: #fafafa !important;}